|  | // Protocol Buffers - Google's data interchange format | 
|  | // Copyright 2008 Google Inc.  All rights reserved. | 
|  | // | 
|  | // Use of this source code is governed by a BSD-style | 
|  | // license that can be found in the LICENSE file or at | 
|  | // https://developers.google.com/open-source/licenses/bsd | 
|  |  | 
|  | #include "text_format_conformance_suite.h" | 
|  |  | 
|  | #include <cstddef> | 
|  | #include <string> | 
|  | #include <utility> | 
|  | #include <vector> | 
|  |  | 
|  | #include "absl/log/absl_log.h" | 
|  | #include "absl/log/die_if_null.h" | 
|  | #include "absl/strings/str_cat.h" | 
|  | #include "absl/strings/str_format.h" | 
|  | #include "conformance_test.h" | 
|  | #include "conformance/test_protos/test_messages_edition2023.pb.h" | 
|  | #include "editions/golden/test_messages_proto2_editions.pb.h" | 
|  | #include "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" | 
|  |  | 
|  | using conformance::ConformanceRequest; | 
|  | using conformance::ConformanceResponse; | 
|  | using conformance::TestStatus; | 
|  | using conformance::WireFormat; | 
|  | using protobuf_test_messages::editions::TestAllTypesEdition2023; | 
|  | 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 { | 
|  |  | 
|  | // The number of repetitions to use for performance tests. | 
|  | // Corresponds approx to 500KB wireformat bytes. | 
|  | static const size_t kPerformanceRepeatCount = 50000; | 
|  |  | 
|  | TextFormatConformanceTestSuite::TextFormatConformanceTestSuite() { | 
|  | SetFailureListFlagName("--text_format_failure_list"); | 
|  | } | 
|  |  | 
|  | bool TextFormatConformanceTestSuite::ParseTextFormatResponse( | 
|  | const ConformanceResponse& response, | 
|  | const ConformanceRequestSetting& setting, Message* test_message) { | 
|  | TextFormat::Parser parser; | 
|  | const ConformanceRequest& request = setting.GetRequest(); | 
|  | if (request.print_unknown_fields()) { | 
|  | parser.AllowFieldNumber(true); | 
|  | } | 
|  | if (!parser.ParseFromString(response.text_payload(), test_message)) { | 
|  | ABSL_LOG(ERROR) << "INTERNAL ERROR: internal text->protobuf transcode " | 
|  | << "yielded unparseable proto. Text payload: " | 
|  | << response.text_payload(); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool TextFormatConformanceTestSuite::ParseResponse( | 
|  | const ConformanceResponse& response, | 
|  | const ConformanceRequestSetting& setting, Message* test_message) { | 
|  | const ConformanceRequest& request = setting.GetRequest(); | 
|  | WireFormat requested_output = request.requested_output_format(); | 
|  | const std::string& test_name = setting.GetTestName(); | 
|  | ConformanceLevel level = setting.GetLevel(); | 
|  |  | 
|  | TestStatus test; | 
|  | test.set_name(test_name); | 
|  | switch (response.result_case()) { | 
|  | case ConformanceResponse::kProtobufPayload: { | 
|  | if (requested_output != conformance::PROTOBUF) { | 
|  | test.set_failure_message(absl::StrCat( | 
|  | "Test was asked for ", WireFormatToString(requested_output), | 
|  | " output but provided PROTOBUF instead.")); | 
|  | ReportFailure(test, level, request, response); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | if (!test_message->ParseFromString(response.protobuf_payload())) { | 
|  | test.set_failure_message( | 
|  | "Protobuf output we received from test was unparseable."); | 
|  | ReportFailure(test, level, request, response); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | break; | 
|  | } | 
|  |  | 
|  | case ConformanceResponse::kTextPayload: { | 
|  | if (requested_output != conformance::TEXT_FORMAT) { | 
|  | test.set_failure_message(absl::StrCat( | 
|  | "Test was asked for ", WireFormatToString(requested_output), | 
|  | " output but provided TEXT_FORMAT instead.")); | 
|  | ReportFailure(test, level, request, response); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | if (!ParseTextFormatResponse(response, setting, test_message)) { | 
|  | test.set_failure_message( | 
|  | "TEXT_FORMAT output we received from test was unparseable."); | 
|  | ReportFailure(test, level, request, response); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | break; | 
|  | } | 
|  |  | 
|  | default: | 
|  | ABSL_LOG(FATAL) << test_name | 
|  | << ": unknown payload type: " << response.result_case(); | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | void TextFormatConformanceTestSuite::RunSuiteImpl() { | 
|  | TextFormatConformanceTestSuiteImpl<TestAllTypesProto2>(this); | 
|  | TextFormatConformanceTestSuiteImpl<TestAllTypesProto3>(this); | 
|  | if (maximum_edition_ >= Edition::EDITION_2023) { | 
|  | TextFormatConformanceTestSuiteImpl<TestAllTypesProto2Editions>(this); | 
|  | TextFormatConformanceTestSuiteImpl<TestAllTypesProto3Editions>(this); | 
|  | TextFormatConformanceTestSuiteImpl<TestAllTypesEdition2023>(this); | 
|  | } | 
|  | } | 
|  |  | 
|  | template <typename MessageType> | 
|  | TextFormatConformanceTestSuiteImpl<MessageType>:: | 
|  | TextFormatConformanceTestSuiteImpl(TextFormatConformanceTestSuite* suite) | 
|  | : suite_(*ABSL_DIE_IF_NULL(suite)) { | 
|  | // Flag control performance tests to keep them internal and opt-in only | 
|  | if (suite_.performance_) { | 
|  | if (MessageType::GetDescriptor()->name() == "TestAllTypesEdition2023") { | 
|  | // There are no editions-sensitive performance tests. | 
|  | return; | 
|  | } | 
|  | RunTextFormatPerformanceTests(); | 
|  | } else { | 
|  | if (MessageType::GetDescriptor()->name() == "TestAllTypesProto2") { | 
|  | RunGroupTests(); | 
|  | RunClosedEnumTests(); | 
|  | } | 
|  | if (MessageType::GetDescriptor()->name() == "TestAllTypesEdition2023") { | 
|  | RunDelimitedTests(); | 
|  | } | 
|  | if (MessageType::GetDescriptor()->name() == "TestAllTypesProto3") { | 
|  | RunAnyTests(); | 
|  | RunOpenEnumTests(); | 
|  | // TODO Run these over proto2 also. | 
|  | RunAllTests(); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | template <typename MessageType> | 
|  | void TextFormatConformanceTestSuiteImpl<MessageType>::ExpectParseFailure( | 
|  | const std::string& test_name, ConformanceLevel level, | 
|  | const std::string& input) { | 
|  | 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::TEXT_FORMAT, conformance::TEXT_FORMAT, | 
|  | conformance::TEXT_FORMAT_TEST, prototype, test_name, input); | 
|  | const ConformanceRequest& request = setting.GetRequest(); | 
|  | ConformanceResponse response; | 
|  | std::string effective_test_name = absl::StrCat( | 
|  | setting.ConformanceLevelToString(level), ".", | 
|  | setting.GetSyntaxIdentifier(), ".TextFormatInput.", test_name); | 
|  |  | 
|  | if (!suite_.RunTest(effective_test_name, request, &response)) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | TestStatus test; | 
|  | test.set_name(effective_test_name); | 
|  | if (response.result_case() == ConformanceResponse::kParseError) { | 
|  | suite_.ReportSuccess(test); | 
|  | } else if (response.result_case() == ConformanceResponse::kSkipped) { | 
|  | suite_.ReportSkip(test, request, response); | 
|  | } else { | 
|  | test.set_failure_message("Should have failed to parse, but didn't."); | 
|  | suite_.ReportFailure(test, level, request, response); | 
|  | } | 
|  | } | 
|  |  | 
|  | template <typename MessageType> | 
|  | void TextFormatConformanceTestSuiteImpl<MessageType>::RunValidTextFormatTest( | 
|  | const std::string& test_name, ConformanceLevel level, | 
|  | const std::string& input_text) { | 
|  | MessageType prototype; | 
|  | RunValidTextFormatTestWithMessage(test_name, level, input_text, prototype); | 
|  | } | 
|  |  | 
|  | template <typename MessageType> | 
|  | void TextFormatConformanceTestSuiteImpl<MessageType>:: | 
|  | RunValidTextFormatTestWithMessage(const std::string& test_name, | 
|  | ConformanceLevel level, | 
|  | const std::string& input_text, | 
|  | const Message& message) { | 
|  | ConformanceRequestSetting setting1( | 
|  | level, conformance::TEXT_FORMAT, conformance::PROTOBUF, | 
|  | conformance::TEXT_FORMAT_TEST, message, test_name, input_text); | 
|  | suite_.RunValidInputTest(setting1, input_text); | 
|  | ConformanceRequestSetting setting2( | 
|  | level, conformance::TEXT_FORMAT, conformance::TEXT_FORMAT, | 
|  | conformance::TEXT_FORMAT_TEST, message, test_name, input_text); | 
|  | suite_.RunValidInputTest(setting2, input_text); | 
|  | } | 
|  |  | 
|  | template <typename MessageType> | 
|  | void TextFormatConformanceTestSuiteImpl<MessageType>:: | 
|  | RunValidTextFormatTestWithExpected(const std::string& test_name, | 
|  | ConformanceLevel level, | 
|  | const std::string& input_text, | 
|  | const std::string& expected_text) { | 
|  | MessageType prototype; | 
|  | ConformanceRequestSetting setting1( | 
|  | level, conformance::TEXT_FORMAT, conformance::PROTOBUF, | 
|  | conformance::TEXT_FORMAT_TEST, prototype, test_name, input_text); | 
|  | suite_.RunValidInputTest(setting1, expected_text); | 
|  | ConformanceRequestSetting setting2( | 
|  | level, conformance::TEXT_FORMAT, conformance::TEXT_FORMAT, | 
|  | conformance::TEXT_FORMAT_TEST, prototype, test_name, input_text); | 
|  | suite_.RunValidInputTest(setting2, expected_text); | 
|  | } | 
|  |  | 
|  | template <typename MessageType> | 
|  | void TextFormatConformanceTestSuiteImpl< | 
|  | MessageType>::RunValidUnknownTextFormatTest(const std::string& test_name, | 
|  | const Message& message) { | 
|  | std::string serialized_input; | 
|  | message.SerializeToString(&serialized_input); | 
|  | MessageType prototype; | 
|  | ConformanceRequestSetting setting1( | 
|  | RECOMMENDED, conformance::PROTOBUF, conformance::TEXT_FORMAT, | 
|  | conformance::TEXT_FORMAT_TEST, prototype, | 
|  | absl::StrCat(test_name, "_Drop"), serialized_input); | 
|  | setting1.SetPrototypeMessageForCompare(message); | 
|  | suite_.RunValidBinaryInputTest(setting1, ""); | 
|  |  | 
|  | ConformanceRequestSetting setting2( | 
|  | RECOMMENDED, conformance::PROTOBUF, conformance::TEXT_FORMAT, | 
|  | conformance::TEXT_FORMAT_TEST, prototype, | 
|  | absl::StrCat(test_name, "_Print"), serialized_input); | 
|  | setting2.SetPrototypeMessageForCompare(message); | 
|  | setting2.SetPrintUnknownFields(true); | 
|  | suite_.RunValidBinaryInputTest(setting2, serialized_input); | 
|  | } | 
|  |  | 
|  | template <typename MessageType> | 
|  | void TextFormatConformanceTestSuiteImpl<MessageType>::RunDelimitedTests() { | 
|  | RunValidTextFormatTest("GroupFieldNoColon", REQUIRED, | 
|  | "GroupLikeType { group_int32: 1 }"); | 
|  | RunValidTextFormatTest("GroupFieldWithColon", REQUIRED, | 
|  | "GroupLikeType: { group_int32: 1 }"); | 
|  | RunValidTextFormatTest("GroupFieldEmpty", REQUIRED, "GroupLikeType {}"); | 
|  | RunValidTextFormatTest( | 
|  | "GroupFieldExtension", REQUIRED, | 
|  | "[protobuf_test_messages.editions.groupliketype] { c: 1 }"); | 
|  | RunValidTextFormatTest( | 
|  | "DelimitedFieldExtension", REQUIRED, | 
|  | "[protobuf_test_messages.editions.delimited_ext] { c: 1 }"); | 
|  |  | 
|  |  | 
|  | // Test that lower-cased group name (i.e. implicit field name) are accepted. | 
|  | RunValidTextFormatTest("DelimitedFieldLowercased", REQUIRED, | 
|  | "groupliketype { group_int32: 1 }"); | 
|  | RunValidTextFormatTest("DelimitedFieldLowercasedDifferent", REQUIRED, | 
|  | "delimited_field { group_int32: 1 }"); | 
|  |  | 
|  | // Extensions always used the field name, and should never accept the message | 
|  | // name. | 
|  | ExpectParseFailure( | 
|  | "DelimitedFieldExtensionMessageName", REQUIRED, | 
|  | "[protobuf_test_messages.editions.GroupLikeType] { group_int32: 1 }"); | 
|  | } | 
|  |  | 
|  | template <typename MessageType> | 
|  | void TextFormatConformanceTestSuiteImpl<MessageType>::RunGroupTests() { | 
|  | RunValidTextFormatTest("GroupFieldNoColon", REQUIRED, | 
|  | "Data { group_int32: 1 }"); | 
|  | RunValidTextFormatTest("GroupFieldWithColon", REQUIRED, | 
|  | "Data: { group_int32: 1 }"); | 
|  | RunValidTextFormatTest("GroupFieldEmpty", REQUIRED, "Data {}"); | 
|  | RunValidTextFormatTest("GroupFieldMultiWord", REQUIRED, | 
|  | "MultiWordGroupField { group_int32: 1 }"); | 
|  |  | 
|  | // Test that lower-cased group name (i.e. implicit field name) is accepted | 
|  | RunValidTextFormatTest("GroupFieldLowercased", REQUIRED, | 
|  | "data { group_int32: 1 }"); | 
|  | RunValidTextFormatTest("GroupFieldLowercasedMultiWord", REQUIRED, | 
|  | "multiwordgroupfield { group_int32: 1 }"); | 
|  |  | 
|  | // Test extensions of group type | 
|  | RunValidTextFormatTest("GroupFieldExtension", REQUIRED, | 
|  | absl::StrFormat("[%s] { group_int32: 1 }", | 
|  | MessageType::GetDescriptor() | 
|  | ->file() | 
|  | ->FindExtensionByName("groupfield") | 
|  | ->PrintableNameForExtension())); | 
|  | ExpectParseFailure("GroupFieldExtensionGroupName", REQUIRED, | 
|  | absl::StrFormat("[%s] { group_int32: 1 }", | 
|  | MessageType::GetDescriptor() | 
|  | ->file() | 
|  | ->FindMessageTypeByName("GroupField") | 
|  | ->full_name())); | 
|  | } | 
|  |  | 
|  | template <typename MessageType> | 
|  | void TextFormatConformanceTestSuiteImpl<MessageType>::RunAllTests() { | 
|  | RunValidTextFormatTest("HelloWorld", REQUIRED, | 
|  | "optional_string: 'Hello, World!'"); | 
|  | // Integer fields. | 
|  | RunValidTextFormatTest("Int32FieldMaxValue", REQUIRED, | 
|  | "optional_int32: 2147483647"); | 
|  | RunValidTextFormatTest("Int32FieldMinValue", REQUIRED, | 
|  | "optional_int32: -2147483648"); | 
|  | RunValidTextFormatTest("Uint32FieldMaxValue", REQUIRED, | 
|  | "optional_uint32: 4294967295"); | 
|  | RunValidTextFormatTest("Int64FieldMaxValue", REQUIRED, | 
|  | "optional_int64: 9223372036854775807"); | 
|  | RunValidTextFormatTest("Int64FieldMinValue", REQUIRED, | 
|  | "optional_int64: -9223372036854775808"); | 
|  | RunValidTextFormatTest("Uint64FieldMaxValue", REQUIRED, | 
|  | "optional_uint64: 18446744073709551615"); | 
|  | // Integer fields - Hex | 
|  | RunValidTextFormatTestWithExpected("Int32FieldMaxValueHex", REQUIRED, | 
|  | "optional_int32: 0x7FFFFFFF", | 
|  | "optional_int32: 2147483647"); | 
|  | RunValidTextFormatTestWithExpected("Int32FieldMinValueHex", REQUIRED, | 
|  | "optional_int32: -0x80000000", | 
|  | "optional_int32: -2147483648"); | 
|  | RunValidTextFormatTestWithExpected("Uint32FieldMaxValueHex", REQUIRED, | 
|  | "optional_uint32: 0xFFFFFFFF", | 
|  | "optional_uint32: 4294967295"); | 
|  | RunValidTextFormatTestWithExpected("Int64FieldMaxValueHex", REQUIRED, | 
|  | "optional_int64: 0x7FFFFFFFFFFFFFFF", | 
|  | "optional_int64: 9223372036854775807"); | 
|  | RunValidTextFormatTestWithExpected("Int64FieldMinValueHex", REQUIRED, | 
|  | "optional_int64: -0x8000000000000000", | 
|  | "optional_int64: -9223372036854775808"); | 
|  | RunValidTextFormatTestWithExpected("Uint64FieldMaxValueHex", REQUIRED, | 
|  | "optional_uint64: 0xFFFFFFFFFFFFFFFF", | 
|  | "optional_uint64: 18446744073709551615"); | 
|  | // Integer fields - Octal | 
|  | RunValidTextFormatTestWithExpected("Int32FieldMaxValueOctal", REQUIRED, | 
|  | "optional_int32: 017777777777", | 
|  | "optional_int32: 2147483647"); | 
|  | RunValidTextFormatTestWithExpected("Int32FieldMinValueOctal", REQUIRED, | 
|  | "optional_int32: -020000000000", | 
|  | "optional_int32: -2147483648"); | 
|  | RunValidTextFormatTestWithExpected("Uint32FieldMaxValueOctal", REQUIRED, | 
|  | "optional_uint32: 037777777777", | 
|  | "optional_uint32: 4294967295"); | 
|  | RunValidTextFormatTestWithExpected("Int64FieldMaxValueOctal", REQUIRED, | 
|  | "optional_int64: 0777777777777777777777", | 
|  | "optional_int64: 9223372036854775807"); | 
|  | RunValidTextFormatTestWithExpected("Int64FieldMinValueOctal", REQUIRED, | 
|  | "optional_int64: -01000000000000000000000", | 
|  | "optional_int64: -9223372036854775808"); | 
|  | RunValidTextFormatTestWithExpected("Uint64FieldMaxValueOctal", REQUIRED, | 
|  | "optional_uint64: 01777777777777777777777", | 
|  | "optional_uint64: 18446744073709551615"); | 
|  |  | 
|  | // Parsers reject out-of-bound integer values. | 
|  | ExpectParseFailure("Int32FieldTooLarge", REQUIRED, | 
|  | "optional_int32: 2147483648"); | 
|  | ExpectParseFailure("Int32FieldTooSmall", REQUIRED, | 
|  | "optional_int32: -2147483649"); | 
|  | ExpectParseFailure("Uint32FieldTooLarge", REQUIRED, | 
|  | "optional_uint32: 4294967296"); | 
|  | ExpectParseFailure("Int64FieldTooLarge", REQUIRED, | 
|  | "optional_int64: 9223372036854775808"); | 
|  | ExpectParseFailure("Int64FieldTooSmall", REQUIRED, | 
|  | "optional_int64: -9223372036854775809"); | 
|  | ExpectParseFailure("Uint64FieldTooLarge", REQUIRED, | 
|  | "optional_uint64: 18446744073709551616"); | 
|  | // Parsers reject out-of-bound integer values - Hex | 
|  | ExpectParseFailure("Int32FieldTooLargeHex", REQUIRED, | 
|  | "optional_int32: 0x80000000"); | 
|  | ExpectParseFailure("Int32FieldTooSmallHex", REQUIRED, | 
|  | "optional_int32: -0x80000001"); | 
|  | ExpectParseFailure("Uint32FieldTooLargeHex", REQUIRED, | 
|  | "optional_uint32: 0x100000000"); | 
|  | ExpectParseFailure("Int64FieldTooLargeHex", REQUIRED, | 
|  | "optional_int64: 0x8000000000000000"); | 
|  | ExpectParseFailure("Int64FieldTooSmallHex", REQUIRED, | 
|  | "optional_int64: -0x8000000000000001"); | 
|  | ExpectParseFailure("Uint64FieldTooLargeHex", REQUIRED, | 
|  | "optional_uint64: 0x10000000000000000"); | 
|  | // Parsers reject out-of-bound integer values - Octal | 
|  | ExpectParseFailure("Int32FieldTooLargeOctal", REQUIRED, | 
|  | "optional_int32: 020000000000"); | 
|  | ExpectParseFailure("Int32FieldTooSmallOctal", REQUIRED, | 
|  | "optional_int32: -020000000001"); | 
|  | ExpectParseFailure("Uint32FieldTooLargeOctal", REQUIRED, | 
|  | "optional_uint32: 040000000000"); | 
|  | ExpectParseFailure("Int64FieldTooLargeOctal", REQUIRED, | 
|  | "optional_int64: 01000000000000000000000"); | 
|  | ExpectParseFailure("Int64FieldTooSmallOctal", REQUIRED, | 
|  | "optional_int64: -01000000000000000000001"); | 
|  | ExpectParseFailure("Uint64FieldTooLargeOctal", REQUIRED, | 
|  | "optional_uint64: 02000000000000000000000"); | 
|  |  | 
|  | // Floating point fields | 
|  | for (const auto& suffix : std::vector<std::string>{"", "f", "F"}) { | 
|  | const std::string name_suffix = | 
|  | suffix.empty() ? "" : absl::StrCat("_", suffix); | 
|  |  | 
|  | RunValidTextFormatTest(absl::StrCat("FloatField", name_suffix), REQUIRED, | 
|  | absl::StrCat("optional_float: 3.192837", suffix)); | 
|  | RunValidTextFormatTestWithExpected( | 
|  | absl::StrCat("FloatFieldZero", name_suffix), REQUIRED, | 
|  | absl::StrCat("optional_float: 0", suffix), | 
|  | "" /* implicit presence, so zero means unset*/); | 
|  | RunValidTextFormatTest(absl::StrCat("FloatFieldNegative", name_suffix), | 
|  | REQUIRED, | 
|  | absl::StrCat("optional_float: -3.192837", suffix)); | 
|  | RunValidTextFormatTest( | 
|  | absl::StrCat("FloatFieldWithVeryPreciseNumber", name_suffix), REQUIRED, | 
|  | absl::StrCat("optional_float: 3.123456789123456789", suffix)); | 
|  | RunValidTextFormatTest( | 
|  | absl::StrCat("FloatFieldMaxValue", name_suffix), REQUIRED, | 
|  | absl::StrCat("optional_float: 3.4028235e+38", suffix)); | 
|  | RunValidTextFormatTest(absl::StrCat("FloatFieldMinValue", name_suffix), | 
|  | REQUIRED, | 
|  | absl::StrCat("optional_float: 1.17549e-38", suffix)); | 
|  | RunValidTextFormatTest(absl::StrCat("FloatFieldWithInt32Max", name_suffix), | 
|  | REQUIRED, | 
|  | absl::StrCat("optional_float: 4294967296", suffix)); | 
|  | RunValidTextFormatTest( | 
|  | absl::StrCat("FloatFieldLargerThanInt64", name_suffix), REQUIRED, | 
|  | absl::StrCat("optional_float: 9223372036854775808", suffix)); | 
|  | RunValidTextFormatTest( | 
|  | absl::StrCat("FloatFieldTooLarge", name_suffix), REQUIRED, | 
|  | absl::StrCat("optional_float: 3.4028235e+39", suffix)); | 
|  | RunValidTextFormatTest(absl::StrCat("FloatFieldTooSmall", name_suffix), | 
|  | REQUIRED, | 
|  | absl::StrCat("optional_float: 1.17549e-39", suffix)); | 
|  | RunValidTextFormatTest( | 
|  | absl::StrCat("FloatFieldLargerThanUint64", name_suffix), REQUIRED, | 
|  | absl::StrCat("optional_float: 18446744073709551616", suffix)); | 
|  | // https://protobuf.dev/reference/protobuf/textformat-spec/#literals says | 
|  | // "-0" is a valid float literal. -0 should be considered not the same as 0 | 
|  | // when considering implicit presence, and so should round trip. | 
|  | RunValidTextFormatTest(absl::StrCat("FloatFieldNegativeZero", name_suffix), | 
|  | REQUIRED, | 
|  | absl::StrCat("optional_float: -0", suffix)); | 
|  | // https://protobuf.dev/reference/protobuf/textformat-spec/#literals says | 
|  | // ".123", "-.123", ".123e2" are a valid float literal. | 
|  | RunValidTextFormatTest(absl::StrCat("FloatFieldNoLeadingZero", name_suffix), | 
|  | REQUIRED, | 
|  | absl::StrCat("optional_float: .123", suffix)); | 
|  | RunValidTextFormatTest( | 
|  | absl::StrCat("FloatFieldNegativeNoLeadingZero", name_suffix), REQUIRED, | 
|  | absl::StrCat("optional_float: -.123", suffix)); | 
|  | RunValidTextFormatTest( | 
|  | absl::StrCat("FloatFieldNoLeadingZeroWithExponent", name_suffix), | 
|  | REQUIRED, absl::StrCat("optional_float: .123e2", suffix)); | 
|  | } | 
|  | // https://protobuf.dev/reference/protobuf/textformat-spec/#value say case | 
|  | // doesn't matter for special values, test a few | 
|  | for (const auto& value : std::vector<std::string>{"nan", "NaN", "nAn"}) { | 
|  | RunValidTextFormatTest(absl::StrCat("FloatFieldValue_", value), REQUIRED, | 
|  | absl::StrCat("optional_float: ", value)); | 
|  | } | 
|  | for (const auto& value : std::vector<std::string>{ | 
|  | "inf", "infinity", "INF", "INFINITY", "iNF", "inFINITY"}) { | 
|  | RunValidTextFormatTest(absl::StrCat("FloatFieldValue_Pos", value), REQUIRED, | 
|  | absl::StrCat("optional_float: ", value)); | 
|  | RunValidTextFormatTest(absl::StrCat("FloatFieldValue_Neg", value), REQUIRED, | 
|  | absl::StrCat("optional_float: -", value)); | 
|  | } | 
|  | // https://protobuf.dev/reference/protobuf/textformat-spec/#numeric and | 
|  | // https://protobuf.dev/reference/protobuf/textformat-spec/#value says | 
|  | // hex or octal float literals are invalid. | 
|  | ExpectParseFailure("FloatFieldNoHex", REQUIRED, "optional_float: 0x1"); | 
|  | ExpectParseFailure("FloatFieldNoNegativeHex", REQUIRED, | 
|  | "optional_float: -0x1"); | 
|  | ExpectParseFailure("FloatFieldNoOctal", REQUIRED, "optional_float: 012"); | 
|  | ExpectParseFailure("FloatFieldNoNegativeOctal", REQUIRED, | 
|  | "optional_float: -012"); | 
|  | // https://protobuf.dev/reference/protobuf/textformat-spec/#value says | 
|  | // overflows are mapped to infinity/-infinity. | 
|  | RunValidTextFormatTestWithExpected("FloatFieldOverflowInfinity", REQUIRED, | 
|  | "optional_float: 1e50", | 
|  | "optional_float: inf"); | 
|  | RunValidTextFormatTestWithExpected("FloatFieldOverflowNegativeInfinity", | 
|  | REQUIRED, "optional_float: -1e50", | 
|  | "optional_float: -inf"); | 
|  | RunValidTextFormatTestWithExpected("DoubleFieldOverflowInfinity", REQUIRED, | 
|  | "optional_double: 1e9999", | 
|  | "optional_double: inf"); | 
|  | RunValidTextFormatTestWithExpected("DoubleFieldOverflowNegativeInfinity", | 
|  | REQUIRED, "optional_double: -1e9999", | 
|  | "optional_double: -inf"); | 
|  | // Exponent is one more than uint64 max. | 
|  | RunValidTextFormatTestWithExpected( | 
|  | "FloatFieldOverflowInfinityHugeExponent", REQUIRED, | 
|  | "optional_float: 1e18446744073709551616", "optional_float: inf"); | 
|  | RunValidTextFormatTestWithExpected( | 
|  | "DoubleFieldOverflowInfinityHugeExponent", REQUIRED, | 
|  | "optional_double: 1e18446744073709551616", "optional_double: inf"); | 
|  | RunValidTextFormatTestWithExpected( | 
|  | "DoubleFieldLargeNegativeExponentParsesAsZero", REQUIRED, | 
|  | "optional_double: 1e-18446744073709551616", ""); | 
|  | RunValidTextFormatTestWithExpected( | 
|  | "NegDoubleFieldLargeNegativeExponentParsesAsNegZero", REQUIRED, | 
|  | "optional_double: -1e-18446744073709551616", "optional_double: -0"); | 
|  |  | 
|  | RunValidTextFormatTestWithExpected( | 
|  | "FloatFieldLargeNegativeExponentParsesAsZero", REQUIRED, | 
|  | "optional_float: 1e-50", ""); | 
|  | RunValidTextFormatTestWithExpected( | 
|  | "NegFloatFieldLargeNegativeExponentParsesAsNegZero", REQUIRED, | 
|  | "optional_float: -1e-50", "optional_float: -0"); | 
|  |  | 
|  | // String literals x {Strings, Bytes} | 
|  | for (const auto& field_type : std::vector<std::string>{"String", "Bytes"}) { | 
|  | const std::string field_name = | 
|  | field_type == "String" ? "optional_string" : "optional_bytes"; | 
|  | RunValidTextFormatTest( | 
|  | absl::StrCat("StringLiteralConcat", field_type), REQUIRED, | 
|  | absl::StrCat(field_name, ": 'first' \"second\"\n'third'")); | 
|  | RunValidTextFormatTest( | 
|  | absl::StrCat("StringLiteralBasicEscapes", field_type), REQUIRED, | 
|  | absl::StrCat(field_name, ": '\\a\\b\\f\\n\\r\\t\\v\\?\\\\\\'\\\"'")); | 
|  | RunValidTextFormatTest( | 
|  | absl::StrCat("StringLiteralOctalEscapes", field_type), REQUIRED, | 
|  | absl::StrCat(field_name, ": '\\341\\210\\264'")); | 
|  | RunValidTextFormatTest(absl::StrCat("StringLiteralHexEscapes", field_type), | 
|  | REQUIRED, | 
|  | absl::StrCat(field_name, ": '\\xe1\\x88\\xb4'")); | 
|  | RunValidTextFormatTest( | 
|  | absl::StrCat("StringLiteralShortUnicodeEscape", field_type), | 
|  | RECOMMENDED, absl::StrCat(field_name, ": '\\u1234'")); | 
|  | RunValidTextFormatTest( | 
|  | absl::StrCat("StringLiteralLongUnicodeEscapes", field_type), | 
|  | RECOMMENDED, absl::StrCat(field_name, ": '\\U00001234\\U00010437'")); | 
|  | // String literals don't include line feeds. | 
|  | ExpectParseFailure(absl::StrCat("StringLiteralIncludesLF", field_type), | 
|  | REQUIRED, | 
|  | absl::StrCat(field_name, ": 'first line\nsecond line'")); | 
|  | // Unicode escapes don't include code points that lie beyond the planes | 
|  | // (> 0x10ffff). | 
|  | ExpectParseFailure( | 
|  | absl::StrCat("StringLiteralLongUnicodeEscapeTooLarge", field_type), | 
|  | REQUIRED, absl::StrCat(field_name, ": '\\U00110000'")); | 
|  | // Unicode escapes don't include surrogates. | 
|  | ExpectParseFailure( | 
|  | absl::StrCat("StringLiteralShortUnicodeEscapeSurrogatePair", | 
|  | field_type), | 
|  | RECOMMENDED, absl::StrCat(field_name, ": '\\ud801\\udc37'")); | 
|  | ExpectParseFailure( | 
|  | absl::StrCat("StringLiteralShortUnicodeEscapeSurrogateFirstOnly", | 
|  | field_type), | 
|  | RECOMMENDED, absl::StrCat(field_name, ": '\\ud800'")); | 
|  | ExpectParseFailure( | 
|  | absl::StrCat("StringLiteralShortUnicodeEscapeSurrogateSecondOnly", | 
|  | field_type), | 
|  | RECOMMENDED, absl::StrCat(field_name, ": '\\udc00'")); | 
|  | ExpectParseFailure( | 
|  | absl::StrCat("StringLiteralLongUnicodeEscapeSurrogateFirstOnly", | 
|  | field_type), | 
|  | RECOMMENDED, absl::StrCat(field_name, ": '\\U0000d800'")); | 
|  | ExpectParseFailure( | 
|  | absl::StrCat("StringLiteralLongUnicodeEscapeSurrogateSecondOnly", | 
|  | field_type), | 
|  | RECOMMENDED, absl::StrCat(field_name, ": '\\U0000dc00'")); | 
|  | ExpectParseFailure( | 
|  | absl::StrCat("StringLiteralLongUnicodeEscapeSurrogatePair", field_type), | 
|  | RECOMMENDED, absl::StrCat(field_name, ": '\\U0000d801\\U00000dc37'")); | 
|  | ExpectParseFailure( | 
|  | absl::StrCat("StringLiteralUnicodeEscapeSurrogatePairLongShort", | 
|  | field_type), | 
|  | RECOMMENDED, absl::StrCat(field_name, ": '\\U0000d801\\udc37'")); | 
|  | ExpectParseFailure( | 
|  | absl::StrCat("StringLiteralUnicodeEscapeSurrogatePairShortLong", | 
|  | field_type), | 
|  | RECOMMENDED, absl::StrCat(field_name, ": '\\ud801\\U0000dc37'")); | 
|  |  | 
|  | // The following method depend on the type of field, as strings have extra | 
|  | // validation. | 
|  | const auto test_method = | 
|  | field_type == "String" | 
|  | ? &TextFormatConformanceTestSuiteImpl::ExpectParseFailure | 
|  | : &TextFormatConformanceTestSuiteImpl::RunValidTextFormatTest; | 
|  |  | 
|  | // String fields reject invalid UTF-8 byte sequences; bytes fields don't. | 
|  | (this->*test_method)(absl::StrCat(field_type, "FieldBadUTF8Octal"), | 
|  | REQUIRED, absl::StrCat(field_name, ": '\\300'")); | 
|  | (this->*test_method)(absl::StrCat(field_type, "FieldBadUTF8Hex"), REQUIRED, | 
|  | absl::StrCat(field_name, ": '\\xc0'")); | 
|  | } | 
|  |  | 
|  | // Separators | 
|  | for (const auto& test_case : std::vector<std::pair<std::string, std::string>>{ | 
|  | {"string", "\"abc\""}, | 
|  | {"bytes", "\"abc\""}, | 
|  | {"int32", "123"}, | 
|  | {"bool", "true"}, | 
|  | {"double", "1.23"}, | 
|  | {"fixed32", "0x123"}, | 
|  | }) { | 
|  | // Optional Field Separators | 
|  | for (const auto& field_type : | 
|  | std::vector<std::string>{"Single", "Repeated"}) { | 
|  | std::string field_name, field_value; | 
|  | if (field_type == "Single") { | 
|  | field_name = absl::StrCat("optional_", test_case.first); | 
|  | field_value = test_case.second; | 
|  | } else { | 
|  | field_name = absl::StrCat("repeated_", test_case.first); | 
|  | field_value = absl::StrCat("[", test_case.second, "]"); | 
|  | } | 
|  |  | 
|  | RunValidTextFormatTest(absl::StrCat("FieldSeparatorCommaTopLevel", | 
|  | field_type, "_", test_case.first), | 
|  | REQUIRED, | 
|  | absl::StrCat(field_name, ": ", field_value, ",")); | 
|  | RunValidTextFormatTest(absl::StrCat("FieldSeparatorSemiTopLevelSingle", | 
|  | field_type, "_", test_case.first), | 
|  | REQUIRED, | 
|  | absl::StrCat(field_name, ": ", field_value, ";")); | 
|  |  | 
|  | ExpectParseFailure( | 
|  | absl::StrCat("FieldSeparatorCommaTopLevelDuplicatesFails", field_type, | 
|  | "_", test_case.first), | 
|  | REQUIRED, absl::StrCat(field_name, ": ", field_value, ",,")); | 
|  | ExpectParseFailure( | 
|  | absl::StrCat("FieldSeparatorSemiTopLevelDuplicateFails", field_type, | 
|  | "_", test_case.first), | 
|  | REQUIRED, absl::StrCat(field_name, ": ", field_value, ";;")); | 
|  | } | 
|  |  | 
|  | // Required List Separators | 
|  | RunValidTextFormatTest( | 
|  | absl::StrCat("ListSeparator_", test_case.first), REQUIRED, | 
|  | absl::StrCat("repeated_", test_case.first, ": [", test_case.second, ",", | 
|  | test_case.second, "]")); | 
|  | ExpectParseFailure( | 
|  | absl::StrCat("ListSeparatorSemiFails_", test_case.first), REQUIRED, | 
|  | absl::StrCat("repeated_", test_case.first, ": [", test_case.second, ";", | 
|  | test_case.second, "]")); | 
|  | // For string and bytes, if we skip the separator, the parser will treat | 
|  | // the two values as a single value. | 
|  | if (test_case.first == "string" || test_case.first == "bytes") { | 
|  | RunValidTextFormatTest( | 
|  | absl::StrCat("ListSeparatorMissingIsOneValue_", test_case.first), | 
|  | REQUIRED, | 
|  | absl::StrCat("repeated_", test_case.first, ": [", test_case.second, | 
|  | " ", test_case.second, "]")); | 
|  | } else { | 
|  | ExpectParseFailure( | 
|  | absl::StrCat("ListSeparatorMissingFails_", test_case.first), REQUIRED, | 
|  | absl::StrCat("repeated_", test_case.first, ": [", test_case.second, | 
|  | " ", test_case.second, "]")); | 
|  | } | 
|  | ExpectParseFailure( | 
|  | absl::StrCat("ListSeparatorDuplicateFails_", test_case.first), REQUIRED, | 
|  | absl::StrCat("repeated_", test_case.first, ": [", test_case.second, | 
|  | ",,", test_case.second, "]")); | 
|  | ExpectParseFailure( | 
|  | absl::StrCat("ListSeparatorSingleTrailingFails_", test_case.first), | 
|  | REQUIRED, | 
|  | absl::StrCat("repeated_", test_case.first, ": [", test_case.second, | 
|  | ",]")); | 
|  | ExpectParseFailure( | 
|  | absl::StrCat("ListSeparatorTwoValuesTrailingFails_", test_case.first), | 
|  | REQUIRED, | 
|  | absl::StrCat("repeated_", test_case.first, ": [", test_case.second, ",", | 
|  | test_case.second, ",]")); | 
|  | } | 
|  | // The test message don't really have all types nested, so just check one | 
|  | // data type for the nested field separator support | 
|  | RunValidTextFormatTest("FieldSeparatorCommaNested", REQUIRED, | 
|  | "optional_nested_message: { a: 123, }"); | 
|  | RunValidTextFormatTest("FieldSeparatorSemiNested", REQUIRED, | 
|  | "optional_nested_message: { a: 123; }"); | 
|  | ExpectParseFailure("FieldSeparatorCommaNestedDuplicates", REQUIRED, | 
|  | "optional_nested_message: { a: 123,, }"); | 
|  | ExpectParseFailure("FieldSeparatorSemiNestedDuplicates", REQUIRED, | 
|  | "optional_nested_message: { a: 123;; }"); | 
|  |  | 
|  | // Unknown Fields | 
|  | UnknownToTestAllTypes message; | 
|  | // Unable to print unknown Fixed32/Fixed64 fields as if they are known. | 
|  | // Fixed32/Fixed64 fields are not added in the tests. | 
|  | message.set_optional_int32(123); | 
|  | message.set_optional_string("hello"); | 
|  | message.set_optional_bool(true); | 
|  | RunValidUnknownTextFormatTest("ScalarUnknownFields", message); | 
|  |  | 
|  | message.Clear(); | 
|  | message.mutable_nested_message()->set_c(111); | 
|  | RunValidUnknownTextFormatTest("MessageUnknownFields", message); | 
|  |  | 
|  | message.Clear(); | 
|  | message.mutable_optionalgroup()->set_a(321); | 
|  | RunValidUnknownTextFormatTest("GroupUnknownFields", message); | 
|  |  | 
|  | message.add_repeated_int32(1); | 
|  | message.add_repeated_int32(2); | 
|  | message.add_repeated_int32(3); | 
|  | RunValidUnknownTextFormatTest("RepeatedUnknownFields", message); | 
|  |  | 
|  | // Reserved field names | 
|  | for (const auto& test_case : std::vector<std::pair<std::string, std::string>>{ | 
|  | {"Boolean", "true"}, | 
|  | {"Integer", "-123"}, | 
|  | {"Float", "0.123"}, | 
|  | {"Enum", "ENUM_VALUE"}, | 
|  | {"String", "\"hello\""}, | 
|  | {"Message", "{ a: 123 }"}, | 
|  | {"MessageAngleBrackets", "< a: 123 >"}, | 
|  | {"RepeatedInteger", "[-123, 456]"}, | 
|  | {"RepeatedFloat", "[0.123, 1e-10] "}, | 
|  | {"RepeatedString", R"pb(["hello", "world"])pb"}, | 
|  | }) { | 
|  | RunValidTextFormatTest(absl::StrCat("ReservedFieldName.", test_case.first), | 
|  | REQUIRED, | 
|  | absl::StrCat("reserved_field: ", test_case.second)); | 
|  | // TODO: Add a test for reserved field numbers on 999999. | 
|  | } | 
|  |  | 
|  | // Map fields | 
|  | MessageType prototype; | 
|  | (*prototype.mutable_map_string_string())["c"] = "value"; | 
|  | (*prototype.mutable_map_string_string())["b"] = "value"; | 
|  | (*prototype.mutable_map_string_string())["a"] = "value"; | 
|  | RunValidTextFormatTestWithMessage("AlphabeticallySortedMapStringKeys", | 
|  | REQUIRED, | 
|  | R"( | 
|  | map_string_string { | 
|  | key: "a" | 
|  | value: "value" | 
|  | } | 
|  | map_string_string { | 
|  | key: "b" | 
|  | value: "value" | 
|  | } | 
|  | map_string_string { | 
|  | key: "c" | 
|  | value: "value" | 
|  | } | 
|  | )", | 
|  | prototype); | 
|  |  | 
|  | prototype.Clear(); | 
|  | (*prototype.mutable_map_int32_int32())[3] = 0; | 
|  | (*prototype.mutable_map_int32_int32())[2] = 0; | 
|  | (*prototype.mutable_map_int32_int32())[1] = 0; | 
|  | RunValidTextFormatTestWithMessage("AlphabeticallySortedMapIntKeys", REQUIRED, | 
|  | R"( | 
|  | map_int32_int32 { | 
|  | key: 1 | 
|  | value: 0 | 
|  | } | 
|  | map_int32_int32 { | 
|  | key: 2 | 
|  | value: 0 | 
|  | } | 
|  | map_int32_int32 { | 
|  | key: 3 | 
|  | value: 0 | 
|  | } | 
|  | )", | 
|  | prototype); | 
|  |  | 
|  | prototype.Clear(); | 
|  | (*prototype.mutable_map_bool_bool())[true] = false; | 
|  | (*prototype.mutable_map_bool_bool())[false] = false; | 
|  | RunValidTextFormatTestWithMessage("AlphabeticallySortedMapBoolKeys", REQUIRED, | 
|  | R"( | 
|  | map_bool_bool { | 
|  | key: false | 
|  | value: false | 
|  | } | 
|  | map_bool_bool { | 
|  | key: true | 
|  | value: false | 
|  | } | 
|  | )", | 
|  | prototype); | 
|  |  | 
|  | prototype.Clear(); | 
|  | ConformanceRequestSetting setting_map( | 
|  | REQUIRED, conformance::TEXT_FORMAT, conformance::PROTOBUF, | 
|  | conformance::TEXT_FORMAT_TEST, prototype, "DuplicateMapKey", R"( | 
|  | map_string_nested_message { | 
|  | key: "duplicate" | 
|  | value: { a: 123 } | 
|  | } | 
|  | map_string_nested_message { | 
|  | key: "duplicate" | 
|  | value: { corecursive: {} } | 
|  | } | 
|  | )"); | 
|  | // The last-specified value will be retained in a parsed map | 
|  | suite_.RunValidInputTest(setting_map, R"( | 
|  | map_string_nested_message { | 
|  | key: "duplicate" | 
|  | value: { corecursive: {} } | 
|  | } | 
|  | )"); | 
|  | } | 
|  |  | 
|  | template <typename MessageType> | 
|  | void TextFormatConformanceTestSuiteImpl<MessageType>::RunAnyTests() { | 
|  | // Any fields | 
|  | RunValidTextFormatTest("AnyField", REQUIRED, | 
|  | R"( | 
|  | optional_any: { | 
|  | [type.googleapis.com/protobuf_test_messages.proto3.TestAllTypesProto3] | 
|  | { optional_int32: 12345 | 
|  | } | 
|  | } | 
|  | )"); | 
|  | RunValidTextFormatTest("AnyFieldWithRawBytes", REQUIRED, | 
|  | R"( | 
|  | optional_any: { | 
|  | type_url: | 
|  | "type.googleapis.com/protobuf_test_messages.proto3.TestAllTypesProto3" value: | 
|  | "\b\271`" | 
|  | } | 
|  | )"); | 
|  | ExpectParseFailure("AnyFieldWithInvalidType", REQUIRED, | 
|  | R"( | 
|  | optional_any: { | 
|  | [type.googleapis.com/unknown] { | 
|  | optional_int32: 12345 | 
|  | } | 
|  | } | 
|  | )"); | 
|  | } | 
|  |  | 
|  | template <typename MessageType> | 
|  | void TextFormatConformanceTestSuiteImpl< | 
|  | MessageType>::RunTextFormatPerformanceTests() { | 
|  | TestTextFormatPerformanceMergeMessageWithRepeatedField("Bool", | 
|  | "repeated_bool: true"); | 
|  | TestTextFormatPerformanceMergeMessageWithRepeatedField( | 
|  | "Double", "repeated_double: 123"); | 
|  | TestTextFormatPerformanceMergeMessageWithRepeatedField( | 
|  | "Int32", "repeated_uint32: 123"); | 
|  | TestTextFormatPerformanceMergeMessageWithRepeatedField( | 
|  | "Int64", "repeated_uint64: 123"); | 
|  | TestTextFormatPerformanceMergeMessageWithRepeatedField( | 
|  | "String", R"(repeated_string: "foo")"); | 
|  | TestTextFormatPerformanceMergeMessageWithRepeatedField( | 
|  | "Bytes", R"(repeated_bytes: "foo")"); | 
|  | } | 
|  |  | 
|  | // This is currently considered valid input by some languages but not others | 
|  | template <typename MessageType> | 
|  | void TextFormatConformanceTestSuiteImpl<MessageType>:: | 
|  | TestTextFormatPerformanceMergeMessageWithRepeatedField( | 
|  | const std::string& test_type_name, const std::string& message_field) { | 
|  | std::string recursive_message = | 
|  | absl::StrCat("recursive_message { ", message_field, " }"); | 
|  |  | 
|  | std::string input; | 
|  | for (size_t i = 0; i < kPerformanceRepeatCount; i++) { | 
|  | absl::StrAppend(&input, recursive_message); | 
|  | } | 
|  |  | 
|  | std::string expected = "recursive_message { "; | 
|  | for (size_t i = 0; i < kPerformanceRepeatCount; i++) { | 
|  | absl::StrAppend(&expected, message_field, " "); | 
|  | } | 
|  | absl::StrAppend(&expected, "}"); | 
|  |  | 
|  | RunValidTextFormatTestWithExpected( | 
|  | absl::StrCat("TestTextFormatPerformanceMergeMessageWithRepeatedField", | 
|  | test_type_name), | 
|  | RECOMMENDED, input, expected); | 
|  | } | 
|  |  | 
|  | template <typename MessageType> | 
|  | void TextFormatConformanceTestSuiteImpl<MessageType>::RunOpenEnumTests() { | 
|  | RunValidTextFormatTest("ClosedEnumFieldByNumber", REQUIRED, | 
|  | R"( | 
|  | optional_nested_enum: 1 | 
|  | )"); | 
|  | RunValidTextFormatTest("ClosedEnumFieldWithUnknownNumber", REQUIRED, | 
|  | R"( | 
|  | optional_nested_enum: 42 | 
|  | )"); | 
|  | } | 
|  |  | 
|  | template <typename MessageType> | 
|  | void TextFormatConformanceTestSuiteImpl<MessageType>::RunClosedEnumTests() { | 
|  | RunValidTextFormatTest("ClosedEnumFieldByNumber", REQUIRED, | 
|  | R"( | 
|  | optional_nested_enum: 1 | 
|  | )"); | 
|  | ExpectParseFailure("ClosedEnumFieldWithUnknownNumber", REQUIRED, | 
|  | R"( | 
|  | optional_nested_enum: 42 | 
|  | )"); | 
|  | } | 
|  |  | 
|  | }  // namespace protobuf | 
|  | }  // namespace google |