Enable conformance tests over editions protos
We transformed the proto2/proto3 protos to editions, and then run the same set of tests over both. This will verify that migrating to editions preserves the same proto2/proto3 behavior. These will not be enabled by default, and require a flag `--maximum_edition=2023`.
Future changes will:
- add more targeted editions-specific tests
- clean up our conformance test framework to allow for more targeted tests
- add wildcards to failure lists in limited cases to reduce noise
- add feature resolution conformance tests
PiperOrigin-RevId: 574570607
diff --git a/cmake/conformance.cmake b/cmake/conformance.cmake
index 7bebade..bfded77 100644
--- a/cmake/conformance.cmake
+++ b/cmake/conformance.cmake
@@ -33,12 +33,22 @@
${protobuf_SOURCE_DIR}/src/google/protobuf/test_messages_proto3.pb.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/test_messages_proto2.pb.h
${protobuf_SOURCE_DIR}/src/google/protobuf/test_messages_proto2.pb.cc
- DEPENDS ${protobuf_PROTOC_EXE} ${protobuf_SOURCE_DIR}/src/google/protobuf/test_messages_proto3.proto
- ${protobuf_PROTOC_EXE} ${protobuf_SOURCE_DIR}/src/google/protobuf/test_messages_proto2.proto
- COMMAND ${protobuf_PROTOC_EXE} ${protobuf_SOURCE_DIR}/src/google/protobuf/test_messages_proto3.proto
- ${protobuf_SOURCE_DIR}/src/google/protobuf/test_messages_proto2.proto
- --proto_path=${protobuf_SOURCE_DIR}/src
- --cpp_out=${protoc_cpp_args}${protobuf_SOURCE_DIR}/src
+ ${protobuf_SOURCE_DIR}/src/google/protobuf/editions/golden/test_messages_proto3_editions.pb.h
+ ${protobuf_SOURCE_DIR}/src/google/protobuf/editions/golden/test_messages_proto3_editions.pb.cc
+ ${protobuf_SOURCE_DIR}/src/google/protobuf/editions/golden/test_messages_proto2_editions.pb.h
+ ${protobuf_SOURCE_DIR}/src/google/protobuf/editions/golden/test_messages_proto2_editions.pb.cc
+ DEPENDS ${protobuf_PROTOC_EXE}
+ ${protobuf_SOURCE_DIR}/src/google/protobuf/test_messages_proto3.proto
+ ${protobuf_SOURCE_DIR}/src/google/protobuf/test_messages_proto2.proto
+ ${protobuf_SOURCE_DIR}/src/google/protobuf/editions/golden/test_messages_proto3_editions.proto
+ ${protobuf_SOURCE_DIR}/src/google/protobuf/editions/golden/test_messages_proto2_editions.proto
+ COMMAND ${protobuf_PROTOC_EXE}
+ ${protobuf_SOURCE_DIR}/src/google/protobuf/test_messages_proto3.proto
+ ${protobuf_SOURCE_DIR}/src/google/protobuf/test_messages_proto2.proto
+ ${protobuf_SOURCE_DIR}/src/google/protobuf/editions/golden/test_messages_proto3_editions.proto
+ ${protobuf_SOURCE_DIR}/src/google/protobuf/editions/golden/test_messages_proto2_editions.proto
+ --proto_path=${protobuf_SOURCE_DIR}/src
+ --cpp_out=${protoc_cpp_args}${protobuf_SOURCE_DIR}/src
)
add_library(libconformance_common ${protobuf_SHARED_OR_STATIC}
@@ -48,6 +58,10 @@
${protobuf_SOURCE_DIR}/src/google/protobuf/test_messages_proto2.pb.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/test_messages_proto3.pb.h
${protobuf_SOURCE_DIR}/src/google/protobuf/test_messages_proto3.pb.cc
+ ${protobuf_SOURCE_DIR}/src/google/protobuf/editions/golden/test_messages_proto3_editions.pb.h
+ ${protobuf_SOURCE_DIR}/src/google/protobuf/editions/golden/test_messages_proto3_editions.pb.cc
+ ${protobuf_SOURCE_DIR}/src/google/protobuf/editions/golden/test_messages_proto2_editions.pb.h
+ ${protobuf_SOURCE_DIR}/src/google/protobuf/editions/golden/test_messages_proto2_editions.pb.cc
)
target_link_libraries(libconformance_common
${protobuf_LIB_PROTOBUF}
@@ -100,6 +114,7 @@
--failure_list ${protobuf_SOURCE_DIR}/conformance/failure_list_cpp.txt
--text_format_failure_list ${protobuf_SOURCE_DIR}/conformance/text_format_failure_list_cpp.txt
--output_dir ${protobuf_TEST_XML_OUTDIR}
+ --maximum_edition 2023
${CMAKE_CURRENT_BINARY_DIR}/conformance_cpp
DEPENDS conformance_test_runner conformance_cpp)
diff --git a/conformance/BUILD.bazel b/conformance/BUILD.bazel
index eafd606..e54eab0 100644
--- a/conformance/BUILD.bazel
+++ b/conformance/BUILD.bazel
@@ -130,6 +130,7 @@
cc_library(
name = "conformance_test",
+ testonly = 1,
srcs = [
"conformance_test.cc",
"conformance_test_runner.cc",
@@ -151,12 +152,15 @@
cc_library(
name = "binary_json_conformance_suite",
+ testonly = 1,
srcs = ["binary_json_conformance_suite.cc"],
hdrs = ["binary_json_conformance_suite.h"],
deps = [
":conformance_test",
":test_messages_proto2_proto_cc",
":test_messages_proto3_proto_cc",
+ "//src/google/protobuf/editions:test_messages_proto2_editions_cc_proto",
+ "//src/google/protobuf/editions:test_messages_proto3_editions_cc_proto",
"@com_google_absl//absl/log:die_if_null",
"@com_google_absl//absl/status",
"@jsoncpp",
@@ -165,12 +169,15 @@
cc_library(
name = "text_format_conformance_suite",
+ testonly = 1,
srcs = ["text_format_conformance_suite.cc"],
hdrs = ["text_format_conformance_suite.h"],
deps = [
":conformance_test",
":test_messages_proto2_proto_cc",
":test_messages_proto3_proto_cc",
+ "//src/google/protobuf/editions:test_messages_proto2_editions_cc_proto",
+ "//src/google/protobuf/editions:test_messages_proto3_editions_cc_proto",
"@com_google_absl//absl/log:absl_log",
"@com_google_absl//absl/log:die_if_null",
"@com_google_absl//absl/strings",
@@ -179,6 +186,7 @@
cc_binary(
name = "conformance_test_runner",
+ testonly = 1,
srcs = ["conformance_test_main.cc"],
visibility = ["//visibility:public"],
deps = [
@@ -199,6 +207,8 @@
"//:protobuf",
"//:test_messages_proto2_cc_proto",
"//:test_messages_proto3_cc_proto",
+ "//src/google/protobuf/editions:test_messages_proto2_editions_cc_proto",
+ "//src/google/protobuf/editions:test_messages_proto3_editions_cc_proto",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor",
],
diff --git a/conformance/bazel_conformance_test_runner.sh b/conformance/bazel_conformance_test_runner.sh
index fcf4a48..c434c1f 100755
--- a/conformance/bazel_conformance_test_runner.sh
+++ b/conformance/bazel_conformance_test_runner.sh
@@ -28,9 +28,10 @@
fi
# --- end runfiles.bash initialization ---
-TESTEE=unset
-FAILURE_LIST=unset
-TEXT_FORMAT_FAILURE_LIST=unset
+TESTEE=
+FAILURE_LIST=
+TEXT_FORMAT_FAILURE_LIST=
+MAXIMUM_EDITION=
while [[ -n "$@" ]]; do
arg="$1"; shift
@@ -39,6 +40,7 @@
"--testee") TESTEE="$val" ;;
"--failure_list") FAILURE_LIST="$val" ;;
"--text_format_failure_list") TEXT_FORMAT_FAILURE_LIST="$val" ;;
+ "--maximum_edition") MAXIMUM_EDITION="$val" ;;
*) echo "Flag $arg is not recognized." && exit 1 ;;
esac
done
@@ -57,4 +59,8 @@
args+=(--text_format_failure_list $text_format_failure_list)
fi
+if [ -n "$MAXIMUM_EDITION" ]; then
+ args+=(--maximum_edition $MAXIMUM_EDITION)
+fi
+
$conformance_test_runner "${args[@]}" $conformance_testee
diff --git a/conformance/binary_json_conformance_suite.cc b/conformance/binary_json_conformance_suite.cc
index dbacc05..628afdc 100644
--- a/conformance/binary_json_conformance_suite.cc
+++ b/conformance/binary_json_conformance_suite.cc
@@ -24,9 +24,12 @@
#include "absl/status/status.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
+#include "absl/strings/substitute.h"
#include "json/json.h"
#include "conformance/conformance.pb.h"
#include "conformance_test.h"
+#include "google/protobuf/editions/golden/test_messages_proto2_editions.pb.h"
+#include "google/protobuf/editions/golden/test_messages_proto3_editions.pb.h"
#include "google/protobuf/endian.h"
#include "google/protobuf/json/json.h"
#include "google/protobuf/test_messages_proto2.pb.h"
@@ -47,6 +50,10 @@
using google::protobuf::util::NewTypeResolverForDescriptorPool;
using protobuf_test_messages::proto2::TestAllTypesProto2;
using protobuf_test_messages::proto3::TestAllTypesProto3;
+using TestAllTypesProto2Editions =
+ protobuf_test_messages::editions::proto2::TestAllTypesProto2;
+using TestAllTypesProto3Editions =
+ protobuf_test_messages::editions::proto3::TestAllTypesProto3;
namespace {
@@ -325,12 +332,17 @@
void BinaryAndJsonConformanceSuite::RunSuiteImpl() {
type_resolver_.reset(NewTypeResolverForDescriptorPool(
kTypeUrlPrefix, DescriptorPool::generated_pool()));
- type_url_ = GetTypeUrl(TestAllTypesProto3::descriptor());
BinaryAndJsonConformanceSuiteImpl<TestAllTypesProto3>(
this, /*run_proto3_tests=*/true);
BinaryAndJsonConformanceSuiteImpl<TestAllTypesProto2>(
this, /*run_proto3_tests=*/false);
+ if (maximum_edition_ >= Edition::EDITION_2023) {
+ BinaryAndJsonConformanceSuiteImpl<TestAllTypesProto3Editions>(
+ this, /*run_proto3_tests=*/true);
+ BinaryAndJsonConformanceSuiteImpl<TestAllTypesProto2Editions>(
+ this, /*run_proto3_tests=*/false);
+ }
}
template <typename MessageType>
@@ -413,8 +425,7 @@
void BinaryAndJsonConformanceSuiteImpl<MessageType>::
RunValidJsonTestWithProtobufInput(
const std::string& test_name, ConformanceLevel level,
- const TestAllTypesProto3& input,
- const std::string& equivalent_text_format) {
+ const MessageType& input, const std::string& equivalent_text_format) {
ConformanceRequestSetting setting(
level, conformance::PROTOBUF, conformance::JSON, conformance::JSON_TEST,
input, test_name, input.SerializeAsString());
@@ -427,7 +438,7 @@
ConformanceLevel level,
const std::string& input_json,
const std::string& equivalent_text_format) {
- TestAllTypesProto3 prototype;
+ MessageType prototype;
ConformanceRequestSetting setting(
level, conformance::JSON, conformance::PROTOBUF,
conformance::JSON_IGNORE_UNKNOWN_PARSING_TEST, prototype, test_name,
@@ -560,7 +571,7 @@
void BinaryAndJsonConformanceSuiteImpl<MessageType>::ExpectParseFailureForJson(
const std::string& test_name, ConformanceLevel level,
const std::string& input_json) {
- TestAllTypesProto3 prototype;
+ MessageType prototype;
// We don't expect output, but if the program erroneously accepts the protobuf
// we let it send its response as this. We must not leave it unspecified.
ConformanceRequestSetting setting(level, conformance::JSON, conformance::JSON,
@@ -568,8 +579,9 @@
test_name, input_json);
const ConformanceRequest& request = setting.GetRequest();
ConformanceResponse response;
- std::string effective_test_name = absl::StrCat(
- setting.ConformanceLevelToString(level), ".Proto3.JsonInput.", test_name);
+ std::string effective_test_name =
+ absl::StrCat(setting.ConformanceLevelToString(level), ".",
+ SyntaxIdentifier(), ".JsonInput.", test_name);
suite_.RunTest(effective_test_name, request, &response);
if (response.result_case() == ConformanceResponse::kParseError) {
@@ -587,18 +599,19 @@
ExpectSerializeFailureForJson(const std::string& test_name,
ConformanceLevel level,
const std::string& text_format) {
- TestAllTypesProto3 payload_message;
+ MessageType payload_message;
ABSL_CHECK(TextFormat::ParseFromString(text_format, &payload_message))
<< "Failed to parse: " << text_format;
- TestAllTypesProto3 prototype;
+ MessageType prototype;
ConformanceRequestSetting setting(
level, conformance::PROTOBUF, conformance::JSON, conformance::JSON_TEST,
prototype, test_name, payload_message.SerializeAsString());
const ConformanceRequest& request = setting.GetRequest();
ConformanceResponse response;
- std::string effective_test_name = absl::StrCat(
- setting.ConformanceLevelToString(level), ".", test_name, ".JsonOutput");
+ std::string effective_test_name =
+ absl::StrCat(setting.ConformanceLevelToString(level), ".",
+ SyntaxIdentifier(), ".", test_name, ".JsonOutput");
suite_.RunTest(effective_test_name, request, &response);
if (response.result_case() == ConformanceResponse::kSerializeError) {
@@ -1330,6 +1343,7 @@
BinaryAndJsonConformanceSuiteImpl(BinaryAndJsonConformanceSuite* suite,
bool run_proto3_tests)
: suite_(*ABSL_DIE_IF_NULL(suite)), run_proto3_tests_(run_proto3_tests) {
+ suite_.SetTypeUrl(GetTypeUrl(MessageType::GetDescriptor()));
RunAllTests();
}
@@ -1666,15 +1680,18 @@
"FieldName13": 0
})",
[](const Json::Value& value) { return value.isMember("FieldName13"); });
- RunValidJsonTestWithValidator(
- "FieldNameExtension", RECOMMENDED,
- R"({
- "[protobuf_test_messages.proto2.extension_int32]": 1
+ std::vector<const FieldDescriptor*> extensions;
+ MessageType::GetDescriptor()->file()->pool()->FindAllExtensions(
+ MessageType::GetDescriptor(), &extensions);
+ RunValidJsonTestWithValidator("FieldNameExtension", RECOMMENDED,
+ absl::Substitute(R"({
+ "[$0]": 1
})",
- [](const Json::Value& value) {
- return value.isMember(
- "[protobuf_test_messages.proto2.extension_int32]");
- });
+ extensions[0]->full_name()),
+ [&](const Json::Value& value) {
+ return value.isMember(absl::StrCat(
+ "[", extensions[0]->full_name(), "]"));
+ });
return;
}
RunValidJsonTest("HelloWorld", REQUIRED,
@@ -2175,7 +2192,7 @@
R"({"optionalFloat": "-Infinity"})", "optional_float: -inf");
// Non-canonical Nan will be correctly normalized.
{
- TestAllTypesProto3 message;
+ MessageType message;
// IEEE floating-point standard 32-bit quiet NaN:
// 0111 1111 1xxx xxxx xxxx xxxx xxxx xxxx
message.set_optional_float(WireFormatLite::DecodeFloat(0x7FA12345));
@@ -2227,7 +2244,7 @@
"optional_double: -inf");
// Non-canonical Nan will be correctly normalized.
{
- TestAllTypesProto3 message;
+ MessageType message;
message.set_optional_double(
WireFormatLite::DecodeDouble(int64_t{0x7FFA123456789ABC}));
RunValidJsonTestWithProtobufInput("DoubleFieldNormalizeQuietNan", REQUIRED,
@@ -3008,54 +3025,61 @@
template <typename MessageType>
void BinaryAndJsonConformanceSuiteImpl<MessageType>::RunJsonTestsForAny() {
+ std::string type_url = GetTypeUrl(MessageType::GetDescriptor());
RunValidJsonTest("Any", REQUIRED,
- R"({
+ absl::Substitute(R"({
"optionalAny": {
- "@type": "type.googleapis.com/protobuf_test_messages.proto3.TestAllTypesProto3",
+ "@type": "$0",
"optionalInt32": 12345
}
})",
- R"(
+ GetTypeUrl(MessageType::GetDescriptor())),
+ absl::Substitute(R"(
optional_any: {
- [type.googleapis.com/protobuf_test_messages.proto3.TestAllTypesProto3] {
+ [$0] {
optional_int32: 12345
- }
- }
- )");
+ }
+ }
+ )",
+ type_url));
RunValidJsonTest("AnyNested", REQUIRED,
- R"({
+ absl::Substitute(R"({
"optionalAny": {
"@type": "type.googleapis.com/google.protobuf.Any",
"value": {
- "@type": "type.googleapis.com/protobuf_test_messages.proto3.TestAllTypesProto3",
+ "@type": "$0",
"optionalInt32": 12345
}
}
})",
- R"(
+ type_url),
+ absl::Substitute(R"(
optional_any: {
- [type.googleapis.com/google.protobuf.Any] {
- [type.googleapis.com/protobuf_test_messages.proto3.TestAllTypesProto3] {
+ [type.googleapis.com/google.protobuf.Any] {
+ [$0] {
optional_int32: 12345
- }
- }
- }
- )");
+ }
+ }
+ }
+ )",
+ type_url));
// The special "@type" tag is not required to appear first.
RunValidJsonTest("AnyUnorderedTypeTag", REQUIRED,
- R"({
+ absl::Substitute(R"({
"optionalAny": {
"optionalInt32": 12345,
- "@type": "type.googleapis.com/protobuf_test_messages.proto3.TestAllTypesProto3"
- }
+ "@type": "$0"
+ }
})",
- R"(
+ type_url),
+ absl::Substitute(R"(
optional_any: {
- [type.googleapis.com/protobuf_test_messages.proto3.TestAllTypesProto3] {
+ [$0] {
optional_int32: 12345
- }
- }
- )");
+ }
+ }
+ )",
+ type_url));
// Well-known types in Any.
RunValidJsonTest("AnyWithInt32ValueWrapper", REQUIRED,
R"({
@@ -3253,8 +3277,13 @@
const {
if constexpr (std::is_same<MessageType, TestAllTypesProto2>::value) {
return "Proto2";
- } else {
+ } else if constexpr (std::is_same<MessageType, TestAllTypesProto3>::value) {
return "Proto3";
+ } else if constexpr (std::is_same<MessageType,
+ TestAllTypesProto2Editions>::value) {
+ return "Editions_Proto2";
+ } else {
+ return "Editions_Proto3";
}
}
diff --git a/conformance/binary_json_conformance_suite.h b/conformance/binary_json_conformance_suite.h
index f6a8708..d777bba 100644
--- a/conformance/binary_json_conformance_suite.h
+++ b/conformance/binary_json_conformance_suite.h
@@ -14,6 +14,7 @@
#include <utility>
#include <vector>
+#include "absl/strings/string_view.h"
#include "json/json.h"
#include "conformance_test.h"
#include "google/protobuf/descriptor.h"
@@ -33,6 +34,9 @@
bool ParseResponse(const conformance::ConformanceResponse& response,
const ConformanceRequestSetting& setting,
Message* test_message) override;
+ void SetTypeUrl(absl::string_view type_url) {
+ type_url_ = std::string(type_url);
+ }
template <typename MessageType>
friend class BinaryAndJsonConformanceSuiteImpl;
@@ -44,8 +48,8 @@
template <typename MessageType>
class BinaryAndJsonConformanceSuiteImpl {
public:
- BinaryAndJsonConformanceSuiteImpl(BinaryAndJsonConformanceSuite* suite,
- bool run_proto3_tests);
+ explicit BinaryAndJsonConformanceSuiteImpl(
+ BinaryAndJsonConformanceSuite* suite, bool run_proto3_tests);
private:
using ConformanceRequestSetting =
@@ -79,8 +83,7 @@
const Message& prototype);
void RunValidJsonTestWithProtobufInput(
const std::string& test_name, ConformanceLevel level,
- const protobuf_test_messages::proto3::TestAllTypesProto3& input,
- const std::string& equivalent_text_format);
+ const MessageType& input, const std::string& equivalent_text_format);
void RunValidJsonIgnoreUnknownTest(const std::string& test_name,
ConformanceLevel level,
const std::string& input_json,
diff --git a/conformance/conformance_cpp.cc b/conformance/conformance_cpp.cc
index 30baafc..86c651c 100644
--- a/conformance/conformance_cpp.cc
+++ b/conformance/conformance_cpp.cc
@@ -21,6 +21,8 @@
#include "absl/status/statusor.h"
#include "conformance/conformance.pb.h"
#include "conformance/conformance.pb.h"
+#include "google/protobuf/editions/golden/test_messages_proto2_editions.pb.h"
+#include "google/protobuf/editions/golden/test_messages_proto3_editions.pb.h"
#include "google/protobuf/endian.h"
#include "google/protobuf/message.h"
#include "google/protobuf/test_messages_proto2.pb.h"
@@ -45,6 +47,10 @@
using ::google::protobuf::util::TypeResolver;
using ::protobuf_test_messages::proto2::TestAllTypesProto2;
using ::protobuf_test_messages::proto3::TestAllTypesProto3;
+using TestAllTypesProto2Editions =
+ ::protobuf_test_messages::editions::proto2::TestAllTypesProto2;
+using TestAllTypesProto3Editions =
+ ::protobuf_test_messages::editions::proto3::TestAllTypesProto3;
absl::Status ReadFd(int fd, char* buf, size_t len) {
while (len > 0) {
@@ -76,6 +82,8 @@
Harness() {
google::protobuf::LinkMessageReflection<TestAllTypesProto2>();
google::protobuf::LinkMessageReflection<TestAllTypesProto3>();
+ google::protobuf::LinkMessageReflection<TestAllTypesProto2Editions>();
+ google::protobuf::LinkMessageReflection<TestAllTypesProto3Editions>();
resolver_.reset(NewTypeResolverForDescriptorPool(
"type.googleapis.com", DescriptorPool::generated_pool()));
diff --git a/conformance/conformance_test.cc b/conformance/conformance_test.cc
index 94efbcc..dbcaf45 100644
--- a/conformance/conformance_test.cc
+++ b/conformance/conformance_test.cc
@@ -149,6 +149,16 @@
return "Proto3";
case FileDescriptorLegacy::Syntax::SYNTAX_PROTO2:
return "Proto2";
+ case FileDescriptorLegacy::Syntax::SYNTAX_EDITIONS: {
+ std::string id = "Editions";
+ if (prototype_message_.GetDescriptor()->name() == "TestAllTypesProto2") {
+ absl::StrAppend(&id, "_Proto2");
+ } else if (prototype_message_.GetDescriptor()->name() ==
+ "TestAllTypesProto3") {
+ absl::StrAppend(&id, "_Proto3");
+ }
+ return id;
+ }
default:
return "Unknown";
}
diff --git a/conformance/conformance_test.h b/conformance/conformance_test.h
index 00559d9..c78f9ea 100644
--- a/conformance/conformance_test.h
+++ b/conformance/conformance_test.h
@@ -132,6 +132,7 @@
: verbose_(false),
performance_(false),
enforce_recommended_(false),
+ maximum_edition_(Edition::EDITION_PROTO3),
failure_list_flag_name_("--failure_list") {}
virtual ~ConformanceTestSuite() {}
@@ -148,6 +149,9 @@
// difference between REQUIRED and RECOMMENDED test cases.
void SetEnforceRecommended(bool value) { enforce_recommended_ = value; }
+ // Sets the maximum edition (inclusive) that should be tests for conformance.
+ void SetMaximumEdition(Edition edition) { maximum_edition_ = edition; }
+
// Gets the flag name to the failure list file.
// By default, this would return --failure_list
std::string GetFailureListFlagName() { return failure_list_flag_name_; }
@@ -284,6 +288,7 @@
bool verbose_;
bool performance_;
bool enforce_recommended_;
+ Edition maximum_edition_;
std::string output_;
std::string output_dir_;
std::string failure_list_flag_name_;
diff --git a/conformance/conformance_test_runner.cc b/conformance/conformance_test_runner.cc
index 44b9a09..5edb3c6 100644
--- a/conformance/conformance_test_runner.cc
+++ b/conformance/conformance_test_runner.cc
@@ -37,12 +37,15 @@
#include <unistd.h>
#include <algorithm>
+#include <cstdio>
#include <cstdlib>
+#include <cstring>
#include <fstream>
#include <future>
#include <vector>
#include "absl/log/absl_log.h"
+#include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h"
#include "conformance/conformance.pb.h"
#include "conformance_test.h"
@@ -120,6 +123,11 @@
" strictly conforming to protobuf\n");
fprintf(stderr, " spec.\n");
fprintf(stderr,
+ " --maximum edition Only run conformance tests up to \n");
+ fprintf(stderr,
+ " and including the specified\n");
+ fprintf(stderr, " edition.\n");
+ fprintf(stderr,
" --output_dir <dirname> Directory to write\n"
" output files.\n");
exit(1);
@@ -200,6 +208,14 @@
suite->SetVerbose(true);
} else if (strcmp(argv[arg], "--enforce_recommended") == 0) {
suite->SetEnforceRecommended(true);
+ } else if (strcmp(argv[arg], "--maximum_edition") == 0) {
+ if (++arg == argc) UsageError();
+ Edition edition = EDITION_UNKNOWN;
+ if (!Edition_Parse(absl::StrCat("EDITION_", argv[arg]), &edition)) {
+ fprintf(stderr, "Unknown edition: %s\n", argv[arg]);
+ UsageError();
+ }
+ suite->SetMaximumEdition(edition);
} else if (strcmp(argv[arg], "--output_dir") == 0) {
if (++arg == argc) UsageError();
suite->SetOutputDir(argv[arg]);
diff --git a/conformance/defs.bzl b/conformance/defs.bzl
index 8daef86..3a7d1d6 100644
--- a/conformance/defs.bzl
+++ b/conformance/defs.bzl
@@ -8,6 +8,7 @@
testee,
failure_list = None,
text_format_failure_list = None,
+ maximum_edition = None,
**kwargs):
"""Conformance test runner.
@@ -27,6 +28,8 @@
if text_format_failure_list:
args = args + ["--text_format_failure_list %s" % _strip_bazel(text_format_failure_list)]
failure_lists = failure_lists + [text_format_failure_list]
+ if maximum_edition:
+ args = args + ["--maximum_edition %s" % maximum_edition]
native.sh_test(
name = name,
diff --git a/conformance/failure_list_cpp.txt b/conformance/failure_list_cpp.txt
index aa18cea..235ae69 100644
--- a/conformance/failure_list_cpp.txt
+++ b/conformance/failure_list_cpp.txt
@@ -7,30 +7,57 @@
# TODO: insert links to corresponding bugs tracking the issue.
# Should we use GitHub issues or the Google-internal bug tracker?
-Recommended.FieldMaskNumbersDontRoundTrip.JsonOutput
-Recommended.FieldMaskPathsDontRoundTrip.JsonOutput
-Recommended.FieldMaskTooManyUnderscore.JsonOutput
+Recommended.Proto3.FieldMaskNumbersDontRoundTrip.JsonOutput
+Recommended.Editions_Proto3.FieldMaskNumbersDontRoundTrip.JsonOutput
+Recommended.Proto3.FieldMaskPathsDontRoundTrip.JsonOutput
+Recommended.Editions_Proto3.FieldMaskPathsDontRoundTrip.JsonOutput
+Recommended.Proto3.FieldMaskTooManyUnderscore.JsonOutput
+Recommended.Editions_Proto3.FieldMaskTooManyUnderscore.JsonOutput
Recommended.Proto3.JsonInput.BoolFieldDoubleQuotedFalse
+Recommended.Editions_Proto3.JsonInput.BoolFieldDoubleQuotedFalse
Recommended.Proto3.JsonInput.BoolFieldDoubleQuotedTrue
+Recommended.Editions_Proto3.JsonInput.BoolFieldDoubleQuotedTrue
Recommended.Proto3.JsonInput.FieldMaskInvalidCharacter
+Recommended.Editions_Proto3.JsonInput.FieldMaskInvalidCharacter
Recommended.Proto3.JsonInput.FieldNameDuplicate
+Recommended.Editions_Proto3.JsonInput.FieldNameDuplicate
Recommended.Proto3.JsonInput.FieldNameDuplicateDifferentCasing1
+Recommended.Editions_Proto3.JsonInput.FieldNameDuplicateDifferentCasing1
Recommended.Proto3.JsonInput.FieldNameDuplicateDifferentCasing2
+Recommended.Editions_Proto3.JsonInput.FieldNameDuplicateDifferentCasing2
Recommended.Proto3.JsonInput.FieldNameNotQuoted
+Recommended.Editions_Proto3.JsonInput.FieldNameNotQuoted
Recommended.Proto3.JsonInput.IgnoreUnknownEnumStringValueInMapValue.ProtobufOutput
+Recommended.Editions_Proto3.JsonInput.IgnoreUnknownEnumStringValueInMapValue.ProtobufOutput
Recommended.Proto3.JsonInput.MapFieldValueIsNull
+Recommended.Editions_Proto3.JsonInput.MapFieldValueIsNull
Recommended.Proto3.JsonInput.RepeatedFieldMessageElementIsNull
+Recommended.Editions_Proto3.JsonInput.RepeatedFieldMessageElementIsNull
Recommended.Proto3.JsonInput.RepeatedFieldPrimitiveElementIsNull
+Recommended.Editions_Proto3.JsonInput.RepeatedFieldPrimitiveElementIsNull
Recommended.Proto3.JsonInput.RepeatedFieldTrailingComma
+Recommended.Editions_Proto3.JsonInput.RepeatedFieldTrailingComma
Recommended.Proto3.JsonInput.RepeatedFieldTrailingCommaWithNewlines
+Recommended.Editions_Proto3.JsonInput.RepeatedFieldTrailingCommaWithNewlines
Recommended.Proto3.JsonInput.RepeatedFieldTrailingCommaWithSpace
+Recommended.Editions_Proto3.JsonInput.RepeatedFieldTrailingCommaWithSpace
Recommended.Proto3.JsonInput.RepeatedFieldTrailingCommaWithSpaceCommaSpace
+Recommended.Editions_Proto3.JsonInput.RepeatedFieldTrailingCommaWithSpaceCommaSpace
Recommended.Proto3.JsonInput.StringFieldSingleQuoteBoth
+Recommended.Editions_Proto3.JsonInput.StringFieldSingleQuoteBoth
Recommended.Proto3.JsonInput.StringFieldSingleQuoteKey
+Recommended.Editions_Proto3.JsonInput.StringFieldSingleQuoteKey
Recommended.Proto3.JsonInput.StringFieldSingleQuoteValue
+Recommended.Editions_Proto3.JsonInput.StringFieldSingleQuoteValue
Recommended.Proto3.JsonInput.StringFieldUppercaseEscapeLetter
+Recommended.Editions_Proto3.JsonInput.StringFieldUppercaseEscapeLetter
Recommended.Proto3.JsonInput.TrailingCommaInAnObject
+Recommended.Editions_Proto3.JsonInput.TrailingCommaInAnObject
Recommended.Proto3.JsonInput.TrailingCommaInAnObjectWithNewlines
+Recommended.Editions_Proto3.JsonInput.TrailingCommaInAnObjectWithNewlines
Recommended.Proto3.JsonInput.TrailingCommaInAnObjectWithSpace
+Recommended.Editions_Proto3.JsonInput.TrailingCommaInAnObjectWithSpace
Recommended.Proto3.JsonInput.TrailingCommaInAnObjectWithSpaceCommaSpace
+Recommended.Editions_Proto3.JsonInput.TrailingCommaInAnObjectWithSpaceCommaSpace
Recommended.Proto2.JsonInput.FieldNameExtension.Validator
+Recommended.Editions_Proto2.JsonInput.FieldNameExtension.Validator
diff --git a/conformance/failure_list_csharp.txt b/conformance/failure_list_csharp.txt
index 6999ff0..6c7c0dd 100644
--- a/conformance/failure_list_csharp.txt
+++ b/conformance/failure_list_csharp.txt
@@ -5,5 +5,5 @@
Required.Proto3.JsonInput.OneofFieldNullFirst.ProtobufOutput
Required.Proto3.JsonInput.OneofFieldNullSecond.JsonOutput
Required.Proto3.JsonInput.OneofFieldNullSecond.ProtobufOutput
-Recommended.ValueRejectInfNumberValue.JsonOutput
-Recommended.ValueRejectNanNumberValue.JsonOutput
\ No newline at end of file
+Recommended.Proto3.ValueRejectInfNumberValue.JsonOutput
+Recommended.Proto3.ValueRejectNanNumberValue.JsonOutput
diff --git a/conformance/failure_list_java.txt b/conformance/failure_list_java.txt
index 808e230..8508abd 100644
--- a/conformance/failure_list_java.txt
+++ b/conformance/failure_list_java.txt
@@ -4,9 +4,9 @@
# By listing them here we can keep tabs on which ones are failing and be sure
# that we don't introduce regressions in other tests.
-Recommended.FieldMaskNumbersDontRoundTrip.JsonOutput
-Recommended.FieldMaskPathsDontRoundTrip.JsonOutput
-Recommended.FieldMaskTooManyUnderscore.JsonOutput
+Recommended.Proto3.FieldMaskNumbersDontRoundTrip.JsonOutput
+Recommended.Proto3.FieldMaskPathsDontRoundTrip.JsonOutput
+Recommended.Proto3.FieldMaskTooManyUnderscore.JsonOutput
Recommended.Proto3.JsonInput.BoolFieldAllCapitalFalse
Recommended.Proto3.JsonInput.BoolFieldAllCapitalTrue
Recommended.Proto3.JsonInput.BoolFieldCamelCaseFalse
diff --git a/conformance/failure_list_jruby.txt b/conformance/failure_list_jruby.txt
index c0d2980..6d511a3 100644
--- a/conformance/failure_list_jruby.txt
+++ b/conformance/failure_list_jruby.txt
@@ -1,6 +1,6 @@
-Recommended.FieldMaskNumbersDontRoundTrip.JsonOutput
-Recommended.FieldMaskPathsDontRoundTrip.JsonOutput
-Recommended.FieldMaskTooManyUnderscore.JsonOutput
+Recommended.Proto3.FieldMaskNumbersDontRoundTrip.JsonOutput
+Recommended.Proto3.FieldMaskPathsDontRoundTrip.JsonOutput
+Recommended.Proto3.FieldMaskTooManyUnderscore.JsonOutput
Recommended.Proto2.JsonInput.FieldNameExtension.Validator
Recommended.Proto3.JsonInput.BoolFieldAllCapitalFalse
Recommended.Proto3.JsonInput.BoolFieldAllCapitalTrue
diff --git a/conformance/text_format_conformance_suite.cc b/conformance/text_format_conformance_suite.cc
index ae39296..1c2c17b 100644
--- a/conformance/text_format_conformance_suite.cc
+++ b/conformance/text_format_conformance_suite.cc
@@ -15,6 +15,8 @@
#include "absl/log/die_if_null.h"
#include "absl/strings/str_cat.h"
#include "conformance_test.h"
+#include "google/protobuf/editions/golden/test_messages_proto2_editions.pb.h"
+#include "google/protobuf/editions/golden/test_messages_proto3_editions.pb.h"
#include "google/protobuf/test_messages_proto2.pb.h"
#include "google/protobuf/test_messages_proto3.pb.h"
#include "google/protobuf/text_format.h"
@@ -25,6 +27,10 @@
using protobuf_test_messages::proto2::TestAllTypesProto2;
using protobuf_test_messages::proto2::UnknownToTestAllTypes;
using protobuf_test_messages::proto3::TestAllTypesProto3;
+using TestAllTypesProto2Editions =
+ protobuf_test_messages::editions::proto2::TestAllTypesProto2;
+using TestAllTypesProto3Editions =
+ protobuf_test_messages::editions::proto3::TestAllTypesProto3;
namespace google {
namespace protobuf {
@@ -113,6 +119,10 @@
void TextFormatConformanceTestSuite::RunSuiteImpl() {
TextFormatConformanceTestSuiteImpl<TestAllTypesProto2>(this);
TextFormatConformanceTestSuiteImpl<TestAllTypesProto3>(this);
+ if (maximum_edition_ >= Edition::EDITION_2023) {
+ TextFormatConformanceTestSuiteImpl<TestAllTypesProto2Editions>(this);
+ TextFormatConformanceTestSuiteImpl<TestAllTypesProto3Editions>(this);
+ }
}
template <typename MessageType>
diff --git a/conformance/text_format_failure_list_cpp.txt b/conformance/text_format_failure_list_cpp.txt
index a25f04f..fd2d7ad 100644
--- a/conformance/text_format_failure_list_cpp.txt
+++ b/conformance/text_format_failure_list_cpp.txt
@@ -1,20 +1,40 @@
Recommended.Proto3.TextFormatInput.StringLiteralLongUnicodeEscapeSurrogateFirstOnlyBytes
+Recommended.Editions_Proto3.TextFormatInput.StringLiteralLongUnicodeEscapeSurrogateFirstOnlyBytes
Recommended.Proto3.TextFormatInput.StringLiteralLongUnicodeEscapeSurrogateFirstOnlyString
+Recommended.Editions_Proto3.TextFormatInput.StringLiteralLongUnicodeEscapeSurrogateFirstOnlyString
Recommended.Proto3.TextFormatInput.StringLiteralLongUnicodeEscapeSurrogatePairBytes
+Recommended.Editions_Proto3.TextFormatInput.StringLiteralLongUnicodeEscapeSurrogatePairBytes
Recommended.Proto3.TextFormatInput.StringLiteralLongUnicodeEscapeSurrogatePairString
+Recommended.Editions_Proto3.TextFormatInput.StringLiteralLongUnicodeEscapeSurrogatePairString
Recommended.Proto3.TextFormatInput.StringLiteralLongUnicodeEscapeSurrogateSecondOnlyBytes
+Recommended.Editions_Proto3.TextFormatInput.StringLiteralLongUnicodeEscapeSurrogateSecondOnlyBytes
Recommended.Proto3.TextFormatInput.StringLiteralLongUnicodeEscapeSurrogateSecondOnlyString
+Recommended.Editions_Proto3.TextFormatInput.StringLiteralLongUnicodeEscapeSurrogateSecondOnlyString
Recommended.Proto3.TextFormatInput.StringLiteralShortUnicodeEscapeSurrogateFirstOnlyBytes
+Recommended.Editions_Proto3.TextFormatInput.StringLiteralShortUnicodeEscapeSurrogateFirstOnlyBytes
Recommended.Proto3.TextFormatInput.StringLiteralShortUnicodeEscapeSurrogateFirstOnlyString
+Recommended.Editions_Proto3.TextFormatInput.StringLiteralShortUnicodeEscapeSurrogateFirstOnlyString
Recommended.Proto3.TextFormatInput.StringLiteralShortUnicodeEscapeSurrogatePairBytes
+Recommended.Editions_Proto3.TextFormatInput.StringLiteralShortUnicodeEscapeSurrogatePairBytes
Recommended.Proto3.TextFormatInput.StringLiteralShortUnicodeEscapeSurrogatePairString
+Recommended.Editions_Proto3.TextFormatInput.StringLiteralShortUnicodeEscapeSurrogatePairString
Recommended.Proto3.TextFormatInput.StringLiteralShortUnicodeEscapeSurrogateSecondOnlyBytes
+Recommended.Editions_Proto3.TextFormatInput.StringLiteralShortUnicodeEscapeSurrogateSecondOnlyBytes
Recommended.Proto3.TextFormatInput.StringLiteralShortUnicodeEscapeSurrogateSecondOnlyString
+Recommended.Editions_Proto3.TextFormatInput.StringLiteralShortUnicodeEscapeSurrogateSecondOnlyString
Recommended.Proto3.TextFormatInput.StringLiteralUnicodeEscapeSurrogatePairLongShortBytes
+Recommended.Editions_Proto3.TextFormatInput.StringLiteralUnicodeEscapeSurrogatePairLongShortBytes
Recommended.Proto3.TextFormatInput.StringLiteralUnicodeEscapeSurrogatePairLongShortString
+Recommended.Editions_Proto3.TextFormatInput.StringLiteralUnicodeEscapeSurrogatePairLongShortString
Recommended.Proto3.TextFormatInput.StringLiteralUnicodeEscapeSurrogatePairShortLongBytes
+Recommended.Editions_Proto3.TextFormatInput.StringLiteralUnicodeEscapeSurrogatePairShortLongBytes
Recommended.Proto3.TextFormatInput.StringLiteralUnicodeEscapeSurrogatePairShortLongString
+Recommended.Editions_Proto3.TextFormatInput.StringLiteralUnicodeEscapeSurrogatePairShortLongString
Required.Proto3.TextFormatInput.StringFieldBadUTF8Hex
+Required.Editions_Proto3.TextFormatInput.StringFieldBadUTF8Hex
Required.Proto3.TextFormatInput.StringFieldBadUTF8Octal
+Required.Editions_Proto3.TextFormatInput.StringFieldBadUTF8Octal
Required.Proto3.TextFormatInput.StringLiteralLongUnicodeEscapeTooLargeBytes
+Required.Editions_Proto3.TextFormatInput.StringLiteralLongUnicodeEscapeTooLargeBytes
Required.Proto3.TextFormatInput.StringLiteralLongUnicodeEscapeTooLargeString
+Required.Editions_Proto3.TextFormatInput.StringLiteralLongUnicodeEscapeTooLargeString
diff --git a/src/BUILD.bazel b/src/BUILD.bazel
index 2ce3449..7c42d0b 100644
--- a/src/BUILD.bazel
+++ b/src/BUILD.bazel
@@ -38,6 +38,7 @@
conformance_test(
name = "conformance_test",
failure_list = "//conformance:failure_list_cpp.txt",
+ maximum_edition = "2023",
testee = "//conformance:conformance_cpp",
text_format_failure_list = "//conformance:text_format_failure_list_cpp.txt",
)
diff --git a/src/google/protobuf/editions/BUILD b/src/google/protobuf/editions/BUILD
index 0fa11a8..4489ffd 100644
--- a/src/google/protobuf/editions/BUILD
+++ b/src/google/protobuf/editions/BUILD
@@ -85,22 +85,23 @@
)
proto_library(
- name = "test_messages_proto2_proto",
+ name = "test_messages_proto2_editions_proto",
testonly = True,
- srcs = ["golden/test_messages_proto2.proto"],
+ srcs = ["golden/test_messages_proto2_editions.proto"],
strip_import_prefix = "/src",
)
cc_proto_library(
- name = "test_messages_proto2_cc_proto",
+ name = "test_messages_proto2_editions_cc_proto",
testonly = True,
- deps = [":test_messages_proto2_proto"],
+ visibility = ["//conformance:__pkg__"],
+ deps = [":test_messages_proto2_editions_proto"],
)
proto_library(
- name = "test_messages_proto3_proto",
+ name = "test_messages_proto3_editions_proto",
testonly = True,
- srcs = ["golden/test_messages_proto3.proto"],
+ srcs = ["golden/test_messages_proto3_editions.proto"],
strip_import_prefix = "/src",
deps = [
"//:any_proto",
@@ -113,9 +114,10 @@
)
cc_proto_library(
- name = "test_messages_proto3_cc_proto",
+ name = "test_messages_proto3_editions_cc_proto",
testonly = True,
- deps = [":test_messages_proto3_proto"],
+ visibility = ["//conformance:__pkg__"],
+ deps = [":test_messages_proto3_editions_proto"],
)
proto_library(
@@ -136,8 +138,8 @@
srcs = ["generated_files_test.cc"],
deps = [
":test_editions_default_features_cc_proto",
- ":test_messages_proto2_cc_proto",
- ":test_messages_proto3_cc_proto",
+ ":test_messages_proto2_editions_cc_proto",
+ ":test_messages_proto3_editions_cc_proto",
"//:protobuf",
"//src/google/protobuf:test_textproto",
"@com_google_googletest//:gtest_main",
@@ -148,7 +150,7 @@
name = "generated_reflection_test",
srcs = ["generated_reflection_test.cc"],
deps = [
- ":test_messages_proto2_cc_proto",
+ ":test_messages_proto2_editions_cc_proto",
"@com_google_googletest//:gtest_main",
],
)
diff --git a/src/google/protobuf/editions/generated_files_test.cc b/src/google/protobuf/editions/generated_files_test.cc
index f74aa97..fe2bf0f 100644
--- a/src/google/protobuf/editions/generated_files_test.cc
+++ b/src/google/protobuf/editions/generated_files_test.cc
@@ -9,8 +9,8 @@
#include <gtest/gtest.h>
#include "google/protobuf/descriptor.h"
#include "google/protobuf/descriptor.pb.h"
-#include "google/protobuf/editions/golden/test_messages_proto2.pb.h"
-#include "google/protobuf/editions/golden/test_messages_proto3.pb.h"
+#include "google/protobuf/editions/golden/test_messages_proto2_editions.pb.h"
+#include "google/protobuf/editions/golden/test_messages_proto3_editions.pb.h"
#include "google/protobuf/editions/proto/test_editions_default_features.pb.h"
#include "google/protobuf/test_textproto.h"
@@ -22,9 +22,9 @@
namespace {
using ::protobuf_editions_test::EditionsDefaultMessage;
-using ::protobuf_test_messages::proto2::TestAllRequiredTypesProto2;
-using ::protobuf_test_messages::proto2::TestAllTypesProto2;
-using ::protobuf_test_messages::proto3::TestAllTypesProto3;
+using ::protobuf_test_messages::editions::proto2::TestAllRequiredTypesProto2;
+using ::protobuf_test_messages::editions::proto2::TestAllTypesProto2;
+using ::protobuf_test_messages::editions::proto3::TestAllTypesProto3;
using ::testing::NotNull;
TEST(Generated, Parsing) {
diff --git a/src/google/protobuf/editions/generated_reflection_test.cc b/src/google/protobuf/editions/generated_reflection_test.cc
index ede6c6e..a4161b9 100644
--- a/src/google/protobuf/editions/generated_reflection_test.cc
+++ b/src/google/protobuf/editions/generated_reflection_test.cc
@@ -6,13 +6,13 @@
// https://developers.google.com/open-source/licenses/bsd
#include <gtest/gtest.h>
-#include "google/protobuf/editions/golden/test_messages_proto2.pb.h"
+#include "google/protobuf/editions/golden/test_messages_proto2_editions.pb.h"
namespace google {
namespace protobuf {
namespace {
-using ::protobuf_test_messages::proto2::TestAllTypesProto2;
+using ::protobuf_test_messages::editions::proto2::TestAllTypesProto2;
// It's important that no calls that would initialize the generated pool occur
// in any tests in this file. This test guarantees that there's no mutex
diff --git a/src/google/protobuf/editions/golden/test_messages_proto2.proto b/src/google/protobuf/editions/golden/test_messages_proto2_editions.proto
similarity index 98%
rename from src/google/protobuf/editions/golden/test_messages_proto2.proto
rename to src/google/protobuf/editions/golden/test_messages_proto2_editions.proto
index 32da385..d13376b 100644
--- a/src/google/protobuf/editions/golden/test_messages_proto2.proto
+++ b/src/google/protobuf/editions/golden/test_messages_proto2_editions.proto
@@ -13,13 +13,13 @@
edition = "2023";
-package protobuf_test_messages.proto2;
+package protobuf_test_messages.editions.proto2;
option features.enum_type = CLOSED;
option features.repeated_field_encoding = EXPANDED;
option features.utf8_validation = NONE;
option features.json_format = LEGACY_BEST_EFFORT;
-option java_package = "com.google.protobuf_test_messages.proto2";
+option java_package = "com.google.protobuf_test_messages.editions.proto2";
option objc_class_prefix = "Proto2";
// This is the default, but we specify it here explicitly.
diff --git a/src/google/protobuf/editions/golden/test_messages_proto3.proto b/src/google/protobuf/editions/golden/test_messages_proto3_editions.proto
similarity index 98%
rename from src/google/protobuf/editions/golden/test_messages_proto3.proto
rename to src/google/protobuf/editions/golden/test_messages_proto3_editions.proto
index be9ca14..9dbf63e 100644
--- a/src/google/protobuf/editions/golden/test_messages_proto3.proto
+++ b/src/google/protobuf/editions/golden/test_messages_proto3_editions.proto
@@ -13,7 +13,7 @@
edition = "2023";
-package protobuf_test_messages.proto3;
+package protobuf_test_messages.editions.proto3;
import "google/protobuf/any.proto";
import "google/protobuf/duration.proto";
@@ -23,7 +23,7 @@
import "google/protobuf/wrappers.proto";
option features.field_presence = IMPLICIT;
-option java_package = "com.google.protobuf_test_messages.proto3";
+option java_package = "com.google.protobuf_test_messages.editions.proto3";
option objc_class_prefix = "Proto3";
// This is the default, but we specify it here explicitly.