diff --git a/editions/BUILD b/editions/BUILD index 167dbe5b3a..6a0df77e88 100644 --- a/editions/BUILD +++ b/editions/BUILD @@ -125,6 +125,35 @@ cc_library( ], ) +cc_library( + name = "edition_defaults_test_utils", + testonly = True, + srcs = ["edition_defaults_test_utils.cc"], + hdrs = ["edition_defaults_test_utils.h"], + visibility = [ + "//pkg:__subpackages__", + "//src/google/protobuf/compiler:__subpackages__", + ], + deps = [ + "//src/google/protobuf", + "@abseil-cpp//absl/types:optional", + ], +) + +cc_test( + name = "edition_defaults_test_utils_test", + srcs = ["edition_defaults_test_utils_test.cc"], + deps = [ + ":edition_defaults_test_utils", + "//src/google/protobuf", + "//src/google/protobuf:test_textproto", + "//src/google/protobuf:unittest_features_cc_proto", + "@abseil-cpp//absl/types:optional", + "@googletest//:gtest", + "@googletest//:gtest_main", + ], +) + cc_test( name = "defaults_test", srcs = ["defaults_test.cc"], diff --git a/editions/edition_defaults_test_utils.cc b/editions/edition_defaults_test_utils.cc new file mode 100644 index 0000000000..86a2632fb6 --- /dev/null +++ b/editions/edition_defaults_test_utils.cc @@ -0,0 +1,22 @@ +#include "editions/edition_defaults_test_utils.h" + +#include "google/protobuf/descriptor.pb.h" +#include "absl/types/optional.h" + +namespace google { +namespace protobuf { +namespace compiler { + +absl::optional FindEditionDefault( + const FeatureSetDefaults& defaults, Edition edition) { + for (const auto& edition_default : defaults.defaults()) { + if (edition_default.edition() == edition) { + return edition_default; + } + } + return absl::nullopt; +} + +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/editions/edition_defaults_test_utils.h b/editions/edition_defaults_test_utils.h new file mode 100644 index 0000000000..c9f5b7eabb --- /dev/null +++ b/editions/edition_defaults_test_utils.h @@ -0,0 +1,24 @@ +#ifndef GOOGLE_PROTOBUF_EDITIONS_EDITION_DEFAULTS_TEST_UTILS_H__ +#define GOOGLE_PROTOBUF_EDITIONS_EDITION_DEFAULTS_TEST_UTILS_H__ + +// This file contains test-only helper methods for dealing with +// edition defaults. Only helpers that are specific to +// edition defaults tests should be added here. + +#include "google/protobuf/descriptor.pb.h" +#include "absl/types/optional.h" + +namespace google { +namespace protobuf { +namespace compiler { + +// Returns the FeatureSetEditionDefault for the given edition, or absl::nullopt +// if edition is not found in defaults. +absl::optional FindEditionDefault( + const FeatureSetDefaults& defaults, Edition edition); + +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_EDITIONS_EDITION_DEFAULTS_TEST_UTILS_H__ diff --git a/editions/edition_defaults_test_utils_test.cc b/editions/edition_defaults_test_utils_test.cc new file mode 100644 index 0000000000..41c95193f2 --- /dev/null +++ b/editions/edition_defaults_test_utils_test.cc @@ -0,0 +1,104 @@ +#include "editions/edition_defaults_test_utils.h" + +#include "google/protobuf/descriptor.pb.h" +#include +#include "absl/types/optional.h" +#include "google/protobuf/test_textproto.h" +#include "google/protobuf/unittest_features.pb.h" + +namespace google { +namespace protobuf { +namespace compiler { +namespace { + +TEST(TestUtilsTest, FindEditionDefault) { + FeatureSetDefaults defaults = ParseTextOrDie(R"pb( + defaults { + edition: EDITION_PROTO3 + overridable_features { + [pb.test] { file_feature: VALUE2 } + }, + fixed_features { field_presence: IMPLICIT enum_type: OPEN } + } + defaults { + edition: EDITION_2023 + overridable_features { + [pb.test] { file_feature: VALUE3 } + }, + fixed_features { field_presence: EXPLICIT enum_type: OPEN } + } + )pb"); + + const auto edition_defaults = FindEditionDefault(defaults, EDITION_2023); + ASSERT_TRUE(edition_defaults.has_value()); + EXPECT_EQ(edition_defaults->edition(), EDITION_2023); + EXPECT_EQ(edition_defaults->overridable_features() + .GetExtension(pb::test) + .file_feature(), + pb::EnumFeature::VALUE3); +} + +TEST(TestUtilsTest, FindEditionDefaultNull) { + FeatureSetDefaults defaults = ParseTextOrDie(R"pb( + defaults { + edition: EDITION_PROTO3 + overridable_features { + [pb.test] { file_feature: VALUE2 } + }, + fixed_features { field_presence: IMPLICIT enum_type: OPEN } + } + defaults { + edition: EDITION_2023 + overridable_features { + [pb.test] { file_feature: VALUE3 } + }, + fixed_features { field_presence: EXPLICIT enum_type: OPEN } + } + )pb"); + + EXPECT_EQ(FindEditionDefault(defaults, EDITION_99999_TEST_ONLY), + absl::nullopt); +} + +TEST(TestUtilsTest, FindEditionDefaultEmptyDefaults) { + FeatureSetDefaults defaults = ParseTextOrDie(R"pb()pb"); + + EXPECT_EQ(FindEditionDefault(defaults, EDITION_2023), absl::nullopt); +} + +TEST(TestUtilsTest, FindEditionDefaultDuplicateEditions) { + FeatureSetDefaults defaults = ParseTextOrDie(R"pb( + defaults { + edition: EDITION_PROTO3 + overridable_features { + [pb.test] { file_feature: VALUE2 } + }, + fixed_features { field_presence: IMPLICIT enum_type: OPEN } + } + defaults { + edition: EDITION_2023 + overridable_features { + [pb.test] { file_feature: VALUE3 } + }, + fixed_features { field_presence: EXPLICIT enum_type: OPEN } + }, + defaults { + edition: EDITION_2023 + overridable_features { + [pb.test] { file_feature: VALUE3 } + }, + fixed_features { field_presence: IMPLICIT enum_type: OPEN } + }, + )pb"); + + const auto edition_defaults = FindEditionDefault(defaults, EDITION_2023); + ASSERT_TRUE(edition_defaults.has_value()); + EXPECT_EQ(edition_defaults->edition(), EDITION_2023); + EXPECT_EQ(edition_defaults->fixed_features().field_presence(), + FeatureSet::EXPLICIT); +} + +} // namespace +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/pkg/BUILD.bazel b/pkg/BUILD.bazel index 8292851d7a..b57183804a 100644 --- a/pkg/BUILD.bazel +++ b/pkg/BUILD.bazel @@ -345,6 +345,7 @@ cc_dist_library( ], tags = ["manual"], deps = [ + "//editions:edition_defaults_test_utils", "//src/google/protobuf:descriptor_test_utils", "//src/google/protobuf:lite_test_util", "//src/google/protobuf:test_util", diff --git a/src/google/protobuf/compiler/BUILD.bazel b/src/google/protobuf/compiler/BUILD.bazel index 39320fa2b0..e82a031c9e 100644 --- a/src/google/protobuf/compiler/BUILD.bazel +++ b/src/google/protobuf/compiler/BUILD.bazel @@ -412,6 +412,7 @@ cc_test( deps = [ ":code_generator", ":importer", + "//editions:edition_defaults_test_utils", "//src/google/protobuf", "//src/google/protobuf:cc_test_protos", "//src/google/protobuf:port", @@ -461,6 +462,7 @@ cc_test( ":mock_code_generator", ":test_plugin_paths", "//:protobuf", + "//editions:edition_defaults_test_utils", "//src/google/protobuf", "//src/google/protobuf:any_cc_proto", "//src/google/protobuf:cc_test_protos", diff --git a/src/google/protobuf/compiler/code_generator_unittest.cc b/src/google/protobuf/compiler/code_generator_unittest.cc index 76f9fe681f..9703fdd224 100644 --- a/src/google/protobuf/compiler/code_generator_unittest.cc +++ b/src/google/protobuf/compiler/code_generator_unittest.cc @@ -20,6 +20,7 @@ #include "absl/strings/str_replace.h" #include "absl/strings/string_view.h" #include "google/protobuf/compiler/parser.h" +#include "editions/edition_defaults_test_utils.h" #include "google/protobuf/io/tokenizer.h" #include "google/protobuf/io/zero_copy_stream_impl_lite.h" #include "google/protobuf/test_textproto.h" @@ -86,16 +87,6 @@ class SimpleErrorCollector : public io::ErrorCollector { } }; -const FeatureSetDefaults::FeatureSetEditionDefault* FindEditionDefault( - const FeatureSetDefaults& defaults, Edition edition) { - for (const auto& edition_default : defaults.defaults()) { - if (edition_default.edition() == edition) { - return &edition_default; - } - } - return nullptr; -} - class CodeGeneratorTest : public ::testing::Test { protected: const FileDescriptor* BuildFile(absl::string_view schema) { @@ -404,21 +395,6 @@ MATCHER_P(IsOkAndHolds, matcher, "") { return arg.ok() && ExplainMatchResult(matcher, *arg, result_listener); } -TEST_F(CodeGeneratorTest, FindEditionDefault) { - TestGenerator generator; - auto result = generator.BuildFeatureSetDefaults(); - ASSERT_TRUE(result.ok()) << result.status().message(); - const auto* edition_defaults = FindEditionDefault(*result, EDITION_2023); - ASSERT_THAT(edition_defaults, NotNull()); - EXPECT_EQ(edition_defaults->edition(), EDITION_2023); - EXPECT_EQ(edition_defaults->overridable_features() - .GetExtension(pb::test) - .file_feature(), - pb::EnumFeature::VALUE3); - EXPECT_NE(edition_defaults->edition(), EDITION_2024); - EXPECT_EQ(FindEditionDefault(*result, EDITION_99999_TEST_ONLY), nullptr); -} - TEST_F(CodeGeneratorTest, BuildFeatureSetDefaultsInvalidExtension) { TestGenerator generator; generator.set_feature_extensions({nullptr}); @@ -499,8 +475,8 @@ TEST_F(CodeGeneratorTest, BuildFeatureSetDefaultsWithUnstable) { TestGenerator generator; auto result = generator.BuildFeatureSetDefaults(); ASSERT_TRUE(result.ok()) << result.status().message(); - const auto* unstable_defaults = FindEditionDefault(*result, EDITION_UNSTABLE); - ASSERT_THAT(unstable_defaults, NotNull()); + const auto unstable_defaults = FindEditionDefault(*result, EDITION_UNSTABLE); + ASSERT_TRUE(unstable_defaults.has_value()); EXPECT_EQ(unstable_defaults->overridable_features() .GetExtension(pb::test) .new_unstable_feature(), diff --git a/src/google/protobuf/compiler/command_line_interface_unittest.cc b/src/google/protobuf/compiler/command_line_interface_unittest.cc index 7dd28a1375..9e321dba4a 100644 --- a/src/google/protobuf/compiler/command_line_interface_unittest.cc +++ b/src/google/protobuf/compiler/command_line_interface_unittest.cc @@ -24,6 +24,7 @@ #include "absl/types/span.h" #include "google/protobuf/compiler/command_line_interface_tester.h" #include "google/protobuf/cpp_features.pb.h" +#include "editions/edition_defaults_test_utils.h" #include "google/protobuf/unittest_features.pb.h" #include "google/protobuf/unittest_invalid_features.pb.h" @@ -2358,15 +2359,14 @@ TEST_F(CommandLineInterfaceTest, EditionDefaultsWithUnstable) { ExpectNoErrors(); FeatureSetDefaults defaults = ReadEditionDefaults("defaults"); - EXPECT_EQ(defaults.defaults_size(), 5); - EXPECT_EQ(defaults.defaults(4).edition(), EDITION_UNSTABLE); - EXPECT_EQ(defaults.defaults(4) - .overridable_features() + const auto unstable_defaults = FindEditionDefault(defaults, EDITION_UNSTABLE); + ASSERT_TRUE(unstable_defaults.has_value()); + EXPECT_EQ(unstable_defaults->edition(), EDITION_UNSTABLE); + EXPECT_EQ(unstable_defaults->overridable_features() .GetExtension(pb::test) .new_unstable_feature(), pb::UnstableEnumFeature::UNSTABLE2); - EXPECT_EQ(defaults.defaults(4) - .overridable_features() + EXPECT_EQ(unstable_defaults->overridable_features() .GetExtension(pb::test) .unstable_existing_feature(), pb::UnstableEnumFeature::UNSTABLE3); @@ -2461,40 +2461,45 @@ TEST_F(CommandLineInterfaceTest, EditionDefaultsWithExtension) { FeatureSetDefaults defaults = ReadEditionDefaults("defaults"); EXPECT_EQ(defaults.minimum_edition(), EDITION_PROTO2); EXPECT_EQ(defaults.maximum_edition(), EDITION_99999_TEST_ONLY); - ASSERT_EQ(defaults.defaults_size(), 8); - EXPECT_EQ(defaults.defaults(0).edition(), EDITION_LEGACY); - EXPECT_EQ(defaults.defaults(2).edition(), EDITION_2023); - EXPECT_EQ(defaults.defaults(3).edition(), EDITION_2024); - EXPECT_EQ(defaults.defaults(4).edition(), EDITION_UNSTABLE); - EXPECT_EQ(defaults.defaults(5).edition(), EDITION_99997_TEST_ONLY); - EXPECT_EQ(defaults.defaults(6).edition(), EDITION_99998_TEST_ONLY); - EXPECT_EQ(defaults.defaults(0) - .fixed_features() + EXPECT_EQ(FindEditionDefault(defaults, EDITION_LEGACY)->edition(), + EDITION_LEGACY); + EXPECT_EQ(FindEditionDefault(defaults, EDITION_2023)->edition(), + EDITION_2023); + EXPECT_EQ(FindEditionDefault(defaults, EDITION_2024)->edition(), + EDITION_2024); + EXPECT_EQ(FindEditionDefault(defaults, EDITION_UNSTABLE)->edition(), + EDITION_UNSTABLE); + EXPECT_EQ(FindEditionDefault(defaults, EDITION_99997_TEST_ONLY)->edition(), + EDITION_99997_TEST_ONLY); + EXPECT_EQ(FindEditionDefault(defaults, EDITION_99998_TEST_ONLY)->edition(), + EDITION_99998_TEST_ONLY); + EXPECT_EQ(FindEditionDefault(defaults, EDITION_LEGACY) + ->fixed_features() .GetExtension(pb::test) .file_feature(), pb::EnumFeature::VALUE1); - EXPECT_EQ(defaults.defaults(2) - .overridable_features() + EXPECT_EQ(FindEditionDefault(defaults, EDITION_2023) + ->overridable_features() .GetExtension(pb::test) .file_feature(), pb::EnumFeature::VALUE3); - EXPECT_EQ(defaults.defaults(3) - .overridable_features() + EXPECT_EQ(FindEditionDefault(defaults, EDITION_2024) + ->overridable_features() .GetExtension(pb::test) .file_feature(), pb::EnumFeature::VALUE3); - EXPECT_EQ(defaults.defaults(4) - .overridable_features() + EXPECT_EQ(FindEditionDefault(defaults, EDITION_UNSTABLE) + ->overridable_features() .GetExtension(pb::test) .new_unstable_feature(), pb::UnstableEnumFeature::UNSTABLE2); - EXPECT_EQ(defaults.defaults(5) - .overridable_features() + EXPECT_EQ(FindEditionDefault(defaults, EDITION_99997_TEST_ONLY) + ->overridable_features() .GetExtension(pb::test) .file_feature(), pb::EnumFeature::VALUE4); - EXPECT_EQ(defaults.defaults(6) - .overridable_features() + EXPECT_EQ(FindEditionDefault(defaults, EDITION_99998_TEST_ONLY) + ->overridable_features() .GetExtension(pb::test) .file_feature(), pb::EnumFeature::VALUE5);