• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 // https://developers.google.com/protocol-buffers/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 //     * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 //     * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 //     * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 
31 #include "text_format_conformance_suite.h"
32 
33 #include <google/protobuf/any.pb.h>
34 #include <google/protobuf/text_format.h>
35 #include "conformance_test.h"
36 #include <google/protobuf/test_messages_proto2.pb.h>
37 #include <google/protobuf/test_messages_proto3.pb.h>
38 
39 namespace proto2_messages = protobuf_test_messages::proto2;
40 
41 using conformance::ConformanceRequest;
42 using conformance::ConformanceResponse;
43 using conformance::WireFormat;
44 using google::protobuf::Message;
45 using google::protobuf::TextFormat;
46 using proto2_messages::TestAllTypesProto2;
47 using proto2_messages::UnknownToTestAllTypes;
48 using protobuf_test_messages::proto3::TestAllTypesProto3;
49 using std::string;
50 
51 namespace google {
52 namespace protobuf {
53 
TextFormatConformanceTestSuite()54 TextFormatConformanceTestSuite::TextFormatConformanceTestSuite() {
55   SetFailureListFlagName("--text_format_failure_list");
56 }
57 
ParseTextFormatResponse(const ConformanceResponse & response,const ConformanceRequestSetting & setting,Message * test_message)58 bool TextFormatConformanceTestSuite::ParseTextFormatResponse(
59     const ConformanceResponse& response,
60     const ConformanceRequestSetting& setting, Message* test_message) {
61   TextFormat::Parser parser;
62   const ConformanceRequest& request = setting.GetRequest();
63   if (request.print_unknown_fields()) {
64     parser.AllowFieldNumber(true);
65   }
66   if (!parser.ParseFromString(response.text_payload(), test_message)) {
67     GOOGLE_LOG(ERROR) << "INTERNAL ERROR: internal text->protobuf transcode "
68                << "yielded unparseable proto. Text payload: "
69                << response.text_payload();
70     return false;
71   }
72 
73   return true;
74 }
75 
ParseResponse(const ConformanceResponse & response,const ConformanceRequestSetting & setting,Message * test_message)76 bool TextFormatConformanceTestSuite::ParseResponse(
77     const ConformanceResponse& response,
78     const ConformanceRequestSetting& setting, Message* test_message) {
79   const ConformanceRequest& request = setting.GetRequest();
80   WireFormat requested_output = request.requested_output_format();
81   const string& test_name = setting.GetTestName();
82   ConformanceLevel level = setting.GetLevel();
83 
84   switch (response.result_case()) {
85     case ConformanceResponse::kProtobufPayload: {
86       if (requested_output != conformance::PROTOBUF) {
87         ReportFailure(test_name, level, request, response,
88                       StrCat("Test was asked for ",
89                                    WireFormatToString(requested_output),
90                                    " output but provided PROTOBUF instead.")
91                           .c_str());
92         return false;
93       }
94 
95       if (!test_message->ParseFromString(response.protobuf_payload())) {
96         ReportFailure(test_name, level, request, response,
97                       "Protobuf output we received from test was unparseable.");
98         return false;
99       }
100 
101       break;
102     }
103 
104     case ConformanceResponse::kTextPayload: {
105       if (requested_output != conformance::TEXT_FORMAT) {
106         ReportFailure(test_name, level, request, response,
107                       StrCat("Test was asked for ",
108                                    WireFormatToString(requested_output),
109                                    " output but provided TEXT_FORMAT instead.")
110                           .c_str());
111         return false;
112       }
113 
114       if (!ParseTextFormatResponse(response, setting, test_message)) {
115         ReportFailure(
116             test_name, level, request, response,
117             "TEXT_FORMAT output we received from test was unparseable.");
118         return false;
119       }
120 
121       break;
122     }
123 
124     default:
125       GOOGLE_LOG(FATAL) << test_name
126                  << ": unknown payload type: " << response.result_case();
127   }
128 
129   return true;
130 }
131 
ExpectParseFailure(const string & test_name,ConformanceLevel level,const string & input)132 void TextFormatConformanceTestSuite::ExpectParseFailure(const string& test_name,
133                                                         ConformanceLevel level,
134                                                         const string& input) {
135   TestAllTypesProto3 prototype;
136   // We don't expect output, but if the program erroneously accepts the protobuf
137   // we let it send its response as this.  We must not leave it unspecified.
138   ConformanceRequestSetting setting(
139       level, conformance::TEXT_FORMAT, conformance::TEXT_FORMAT,
140       conformance::TEXT_FORMAT_TEST, prototype, test_name, input);
141   const ConformanceRequest& request = setting.GetRequest();
142   ConformanceResponse response;
143   string effective_test_name =
144       StrCat(setting.ConformanceLevelToString(level),
145                    ".Proto3.TextFormatInput.", test_name);
146 
147   RunTest(effective_test_name, request, &response);
148   if (response.result_case() == ConformanceResponse::kParseError) {
149     ReportSuccess(effective_test_name);
150   } else if (response.result_case() == ConformanceResponse::kSkipped) {
151     ReportSkip(effective_test_name, request, response);
152   } else {
153     ReportFailure(effective_test_name, level, request, response,
154                   "Should have failed to parse, but didn't.");
155   }
156 }
157 
RunValidTextFormatTest(const string & test_name,ConformanceLevel level,const string & input_text)158 void TextFormatConformanceTestSuite::RunValidTextFormatTest(
159     const string& test_name, ConformanceLevel level, const string& input_text) {
160   TestAllTypesProto3 prototype;
161   RunValidTextFormatTestWithMessage(test_name, level, input_text, prototype);
162 }
163 
RunValidTextFormatTestProto2(const string & test_name,ConformanceLevel level,const string & input_text)164 void TextFormatConformanceTestSuite::RunValidTextFormatTestProto2(
165     const string& test_name, ConformanceLevel level, const string& input_text) {
166   TestAllTypesProto2 prototype;
167   RunValidTextFormatTestWithMessage(test_name, level, input_text, prototype);
168 }
169 
RunValidTextFormatTestWithMessage(const string & test_name,ConformanceLevel level,const string & input_text,const Message & prototype)170 void TextFormatConformanceTestSuite::RunValidTextFormatTestWithMessage(
171     const string& test_name, ConformanceLevel level, const string& input_text,
172     const Message& prototype) {
173   ConformanceRequestSetting setting1(
174       level, conformance::TEXT_FORMAT, conformance::PROTOBUF,
175       conformance::TEXT_FORMAT_TEST, prototype, test_name, input_text);
176   RunValidInputTest(setting1, input_text);
177   ConformanceRequestSetting setting2(
178       level, conformance::TEXT_FORMAT, conformance::TEXT_FORMAT,
179       conformance::TEXT_FORMAT_TEST, prototype, test_name, input_text);
180   RunValidInputTest(setting2, input_text);
181 }
182 
RunValidUnknownTextFormatTest(const string & test_name,const Message & message)183 void TextFormatConformanceTestSuite::RunValidUnknownTextFormatTest(
184     const string& test_name, const Message& message) {
185   string serialized_input;
186   message.SerializeToString(&serialized_input);
187   TestAllTypesProto3 prototype;
188   ConformanceRequestSetting setting1(
189       RECOMMENDED, conformance::PROTOBUF, conformance::TEXT_FORMAT,
190       conformance::TEXT_FORMAT_TEST, prototype, test_name + "_Drop",
191       serialized_input);
192   setting1.SetPrototypeMessageForCompare(message);
193   RunValidBinaryInputTest(setting1, "");
194 
195   ConformanceRequestSetting setting2(
196       RECOMMENDED, conformance::PROTOBUF, conformance::TEXT_FORMAT,
197       conformance::TEXT_FORMAT_TEST, prototype, test_name + "_Print",
198       serialized_input);
199   setting2.SetPrototypeMessageForCompare(message);
200   setting2.SetPrintUnknownFields(true);
201   RunValidBinaryInputTest(setting2, serialized_input);
202 }
203 
RunSuiteImpl()204 void TextFormatConformanceTestSuite::RunSuiteImpl() {
205   RunValidTextFormatTest("HelloWorld", REQUIRED,
206                          "optional_string: 'Hello, World!'");
207   // Integer fields.
208   RunValidTextFormatTest("Int32FieldMaxValue", REQUIRED,
209                          "optional_int32: 2147483647");
210   RunValidTextFormatTest("Int32FieldMinValue", REQUIRED,
211                          "optional_int32: -2147483648");
212   RunValidTextFormatTest("Uint32FieldMaxValue", REQUIRED,
213                          "optional_uint32: 4294967295");
214   RunValidTextFormatTest("Int64FieldMaxValue", REQUIRED,
215                          "optional_int64: 9223372036854775807");
216   RunValidTextFormatTest("Int64FieldMinValue", REQUIRED,
217                          "optional_int64: -9223372036854775808");
218   RunValidTextFormatTest("Uint64FieldMaxValue", REQUIRED,
219                          "optional_uint64: 18446744073709551615");
220 
221   // Parsers reject out-of-bound integer values.
222   ExpectParseFailure("Int32FieldTooLarge", REQUIRED,
223                      "optional_int32: 2147483648");
224   ExpectParseFailure("Int32FieldTooSmall", REQUIRED,
225                      "optional_int32: -2147483649");
226   ExpectParseFailure("Uint32FieldTooLarge", REQUIRED,
227                      "optional_uint32: 4294967296");
228   ExpectParseFailure("Int64FieldTooLarge", REQUIRED,
229                      "optional_int64: 9223372036854775808");
230   ExpectParseFailure("Int64FieldTooSmall", REQUIRED,
231                      "optional_int64: -9223372036854775809");
232   ExpectParseFailure("Uint64FieldTooLarge", REQUIRED,
233                      "optional_uint64: 18446744073709551616");
234 
235   // Floating point fields
236   RunValidTextFormatTest("FloatField", REQUIRED,
237                          "optional_float: 3.192837");
238   RunValidTextFormatTest("FloatFieldWithVeryPreciseNumber", REQUIRED,
239                          "optional_float: 3.123456789123456789");
240   RunValidTextFormatTest("FloatFieldMaxValue", REQUIRED,
241                          "optional_float: 3.4028235e+38");
242   RunValidTextFormatTest("FloatFieldMinValue", REQUIRED,
243                          "optional_float: 1.17549e-38");
244   RunValidTextFormatTest("FloatFieldNaNValue", REQUIRED,
245                          "optional_float: NaN");
246   RunValidTextFormatTest("FloatFieldPosInfValue", REQUIRED,
247                          "optional_float: inf");
248   RunValidTextFormatTest("FloatFieldNegInfValue", REQUIRED,
249                          "optional_float: -inf");
250   RunValidTextFormatTest("FloatFieldWithInt32Max", REQUIRED,
251                          "optional_float: 4294967296");
252   RunValidTextFormatTest("FloatFieldLargerThanInt64", REQUIRED,
253                          "optional_float: 9223372036854775808");
254   RunValidTextFormatTest("FloatFieldTooLarge", REQUIRED,
255                          "optional_float: 3.4028235e+39");
256   RunValidTextFormatTest("FloatFieldTooSmall", REQUIRED,
257                          "optional_float: 1.17549e-39");
258   RunValidTextFormatTest("FloatFieldLargerThanUint64", REQUIRED,
259                          "optional_float: 18446744073709551616");
260 
261   // String literals x {Strings, Bytes}
262   for (const auto& field_type : std::vector<std::string>{"String", "Bytes"}) {
263     const std::string field_name =
264         field_type == "String" ? "optional_string" : "optional_bytes";
265     RunValidTextFormatTest(
266         StrCat("StringLiteralConcat", field_type), REQUIRED,
267         StrCat(field_name, ": 'first' \"second\"\n'third'"));
268     RunValidTextFormatTest(
269         StrCat("StringLiteralBasicEscapes", field_type), REQUIRED,
270         StrCat(field_name, ": '\\a\\b\\f\\n\\r\\t\\v\\?\\\\\\'\\\"'"));
271     RunValidTextFormatTest(
272         StrCat("StringLiteralOctalEscapes", field_type), REQUIRED,
273         StrCat(field_name, ": '\\341\\210\\264'"));
274     RunValidTextFormatTest(StrCat("StringLiteralHexEscapes", field_type),
275                            REQUIRED,
276                            StrCat(field_name, ": '\\xe1\\x88\\xb4'"));
277     RunValidTextFormatTest(
278         StrCat("StringLiteralShortUnicodeEscape", field_type),
279         RECOMMENDED, StrCat(field_name, ": '\\u1234'"));
280     RunValidTextFormatTest(
281         StrCat("StringLiteralLongUnicodeEscapes", field_type),
282         RECOMMENDED, StrCat(field_name, ": '\\U00001234\\U00010437'"));
283     // String literals don't include line feeds.
284     ExpectParseFailure(StrCat("StringLiteralIncludesLF", field_type),
285                        REQUIRED,
286                        StrCat(field_name, ": 'first line\nsecond line'"));
287     // Unicode escapes don't include code points that lie beyond the planes
288     // (> 0x10ffff).
289     ExpectParseFailure(
290         StrCat("StringLiteralLongUnicodeEscapeTooLarge", field_type),
291         REQUIRED, StrCat(field_name, ": '\\U00110000'"));
292     // Unicode escapes don't include surrogates.
293     ExpectParseFailure(
294         StrCat("StringLiteralShortUnicodeEscapeSurrogatePair",
295                      field_type),
296         RECOMMENDED, StrCat(field_name, ": '\\ud801\\udc37'"));
297     ExpectParseFailure(
298         StrCat("StringLiteralShortUnicodeEscapeSurrogateFirstOnly",
299                      field_type),
300         RECOMMENDED, StrCat(field_name, ": '\\ud800'"));
301     ExpectParseFailure(
302         StrCat("StringLiteralShortUnicodeEscapeSurrogateSecondOnly",
303                      field_type),
304         RECOMMENDED, StrCat(field_name, ": '\\udc00'"));
305     ExpectParseFailure(
306         StrCat("StringLiteralLongUnicodeEscapeSurrogateFirstOnly",
307                      field_type),
308         RECOMMENDED, StrCat(field_name, ": '\\U0000d800'"));
309     ExpectParseFailure(
310         StrCat("StringLiteralLongUnicodeEscapeSurrogateSecondOnly",
311                      field_type),
312         RECOMMENDED, StrCat(field_name, ": '\\U0000dc00'"));
313     ExpectParseFailure(
314         StrCat("StringLiteralLongUnicodeEscapeSurrogatePair", field_type),
315         RECOMMENDED, StrCat(field_name, ": '\\U0000d801\\U00000dc37'"));
316     ExpectParseFailure(
317         StrCat("StringLiteralUnicodeEscapeSurrogatePairLongShort",
318                      field_type),
319         RECOMMENDED, StrCat(field_name, ": '\\U0000d801\\udc37'"));
320     ExpectParseFailure(
321         StrCat("StringLiteralUnicodeEscapeSurrogatePairShortLong",
322                      field_type),
323         RECOMMENDED, StrCat(field_name, ": '\\ud801\\U0000dc37'"));
324 
325     // The following method depend on the type of field, as strings have extra
326     // validation.
327     const auto test_method =
328         field_type == "String"
329             ? &TextFormatConformanceTestSuite::ExpectParseFailure
330             : &TextFormatConformanceTestSuite::RunValidTextFormatTest;
331 
332     // String fields reject invalid UTF-8 byte sequences; bytes fields don't.
333     (this->*test_method)(StrCat(field_type, "FieldBadUTF8Octal"),
334                          REQUIRED, StrCat(field_name, ": '\\300'"));
335     (this->*test_method)(StrCat(field_type, "FieldBadUTF8Hex"), REQUIRED,
336                          StrCat(field_name, ": '\\xc0'"));
337   }
338 
339   // Group fields
340   RunValidTextFormatTestProto2("GroupFieldNoColon", REQUIRED,
341                                "Data { group_int32: 1 }");
342   RunValidTextFormatTestProto2("GroupFieldWithColon", REQUIRED,
343                                "Data: { group_int32: 1 }");
344   RunValidTextFormatTestProto2("GroupFieldEmpty", REQUIRED,
345                                "Data {}");
346 
347 
348   // Unknown Fields
349   UnknownToTestAllTypes message;
350   // Unable to print unknown Fixed32/Fixed64 fields as if they are known.
351   // Fixed32/Fixed64 fields are not added in the tests.
352   message.set_optional_int32(123);
353   message.set_optional_string("hello");
354   message.set_optional_bool(true);
355   RunValidUnknownTextFormatTest("ScalarUnknownFields", message);
356 
357   message.Clear();
358   message.mutable_nested_message()->set_c(111);
359   RunValidUnknownTextFormatTest("MessageUnknownFields", message);
360 
361   message.Clear();
362   message.mutable_optionalgroup()->set_a(321);
363   RunValidUnknownTextFormatTest("GroupUnknownFields", message);
364 
365   message.add_repeated_int32(1);
366   message.add_repeated_int32(2);
367   message.add_repeated_int32(3);
368   RunValidUnknownTextFormatTest("RepeatedUnknownFields", message);
369 
370   // Any fields
371   RunValidTextFormatTest("AnyField", REQUIRED,
372                          R"(
373       optional_any: {
374         [type.googleapis.com/protobuf_test_messages.proto3.TestAllTypesProto3] {
375           optional_int32: 12345
376         }
377       }
378       )");
379   RunValidTextFormatTest("AnyFieldWithRawBytes", REQUIRED,
380                          R"(
381       optional_any: {
382         type_url: "type.googleapis.com/protobuf_test_messages.proto3.TestAllTypesProto3"
383         value: "\b\271`"
384       }
385       )");
386   ExpectParseFailure("AnyFieldWithInvalidType", REQUIRED,
387                      R"(
388       optional_any: {
389         [type.googleapis.com/unknown] {
390           optional_int32: 12345
391         }
392       }
393       )");
394 
395   // Map fields
396   TestAllTypesProto3 prototype;
397   (*prototype.mutable_map_string_string())["c"] = "value";
398   (*prototype.mutable_map_string_string())["b"] = "value";
399   (*prototype.mutable_map_string_string())["a"] = "value";
400   RunValidTextFormatTestWithMessage("AlphabeticallySortedMapStringKeys",
401                                     REQUIRED,
402                                     R"(
403       map_string_string {
404         key: "a"
405         value: "value"
406       }
407       map_string_string {
408         key: "b"
409         value: "value"
410       }
411       map_string_string {
412         key: "c"
413         value: "value"
414       }
415       )",
416                                     prototype);
417 
418   prototype.Clear();
419   (*prototype.mutable_map_int32_int32())[3] = 0;
420   (*prototype.mutable_map_int32_int32())[2] = 0;
421   (*prototype.mutable_map_int32_int32())[1] = 0;
422   RunValidTextFormatTestWithMessage("AlphabeticallySortedMapIntKeys", REQUIRED,
423                                     R"(
424       map_int32_int32 {
425         key: 1
426         value: 0
427       }
428       map_int32_int32 {
429         key: 2
430         value: 0
431       }
432       map_int32_int32 {
433         key: 3
434         value: 0
435       }
436       )",
437                                     prototype);
438 
439   prototype.Clear();
440   (*prototype.mutable_map_bool_bool())[true] = false;
441   (*prototype.mutable_map_bool_bool())[false] = false;
442   RunValidTextFormatTestWithMessage("AlphabeticallySortedMapBoolKeys", REQUIRED,
443                                     R"(
444       map_bool_bool {
445         key: false
446         value: false
447       }
448       map_bool_bool {
449         key: true
450         value: false
451       }
452       )",
453                                     prototype);
454 
455   prototype.Clear();
456   ConformanceRequestSetting setting_map(
457       REQUIRED, conformance::TEXT_FORMAT, conformance::PROTOBUF,
458       conformance::TEXT_FORMAT_TEST, prototype, "DuplicateMapKey", R"(
459       map_string_nested_message {
460         key: "duplicate"
461         value: { a: 123 }
462       }
463       map_string_nested_message {
464         key: "duplicate"
465         value: { corecursive: {} }
466       }
467       )");
468   // The last-specified value will be retained in a parsed map
469   RunValidInputTest(setting_map, R"(
470       map_string_nested_message {
471         key: "duplicate"
472         value: { corecursive: {} }
473       }
474       )");
475 }
476 
477 }  // namespace protobuf
478 }  // namespace google
479