blob: 460bc24900e58be7f1f8153be64d4f4e1146a4ab [file] [log] [blame]
Yilun Chongd8c25012019-02-22 18:13:33 +08001// 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
Yilun Chongd8c25012019-02-22 18:13:33 +080033#include <google/protobuf/any.pb.h>
Rafi Kamal58d44202019-11-11 17:06:56 -080034#include <google/protobuf/text_format.h>
35#include "conformance_test.h"
Yilun Chongd8c25012019-02-22 18:13:33 +080036#include <google/protobuf/test_messages_proto2.pb.h>
37#include <google/protobuf/test_messages_proto3.pb.h>
Rafi Kamal58d44202019-11-11 17:06:56 -080038
39namespace proto2_messages = protobuf_test_messages::proto2;
Yilun Chongd8c25012019-02-22 18:13:33 +080040
41using conformance::ConformanceRequest;
42using conformance::ConformanceResponse;
43using conformance::WireFormat;
44using google::protobuf::Message;
45using google::protobuf::TextFormat;
Rafi Kamal58d44202019-11-11 17:06:56 -080046using proto2_messages::TestAllTypesProto2;
47using proto2_messages::UnknownToTestAllTypes;
Yilun Chongd8c25012019-02-22 18:13:33 +080048using protobuf_test_messages::proto3::TestAllTypesProto3;
49using std::string;
50
51namespace google {
52namespace protobuf {
53
54TextFormatConformanceTestSuite::TextFormatConformanceTestSuite() {
55 SetFailureListFlagName("--text_format_failure_list");
56}
57
58bool TextFormatConformanceTestSuite::ParseTextFormatResponse(
Hao Nguyen2f864fd2019-03-20 11:45:01 -070059 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)) {
Yilun Chongd8c25012019-02-22 18:13:33 +080067 GOOGLE_LOG(ERROR) << "INTERNAL ERROR: internal text->protobuf transcode "
Rafi Kamal58d44202019-11-11 17:06:56 -080068 << "yielded unparseable proto. Text payload: "
69 << response.text_payload();
Yilun Chongd8c25012019-02-22 18:13:33 +080070 return false;
71 }
72
73 return true;
74}
75
76bool 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) {
Rafi Kamal58d44202019-11-11 17:06:56 -080087 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());
Yilun Chongd8c25012019-02-22 18:13:33 +080092 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) {
Rafi Kamal58d44202019-11-11 17:06:56 -0800106 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());
Yilun Chongd8c25012019-02-22 18:13:33 +0800111 return false;
112 }
113
Hao Nguyen2f864fd2019-03-20 11:45:01 -0700114 if (!ParseTextFormatResponse(response, setting, test_message)) {
Yilun Chongd8c25012019-02-22 18:13:33 +0800115 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
Rafi Kamal58d44202019-11-11 17:06:56 -0800126 << ": unknown payload type: " << response.result_case();
Yilun Chongd8c25012019-02-22 18:13:33 +0800127 }
128
129 return true;
130}
131
132void 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;
Rafi Kamal58d44202019-11-11 17:06:56 -0800143 string effective_test_name =
144 StrCat(setting.ConformanceLevelToString(level),
145 ".Proto3.TextFormatInput.", test_name);
Yilun Chongd8c25012019-02-22 18:13:33 +0800146
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
158void 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
164void 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
170void 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
Hao Nguyen2f864fd2019-03-20 11:45:01 -0700183void 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
Yilun Chongd8c25012019-02-22 18:13:33 +0800204void 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,
Hao Nguyen176f7db2019-04-09 06:23:32 -0700241 "optional_float: 3.4028235e+38");
Yilun Chongd8c25012019-02-22 18:13:33 +0800242 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");
Hao Nguyend0f91c82019-03-06 12:39:12 -0800254 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");
Yilun Chongd8c25012019-02-22 18:13:33 +0800260
Joshua Haberman38d6de12020-09-28 11:54:54 -0700261 // String literals x {Strings, Bytes}
Joshua Habermand90f3b82020-09-28 14:40:09 -0700262 for (const auto& field_type : std::vector<std::string>{"String", "Bytes"}) {
Joshua Haberman38d6de12020-09-28 11:54:54 -0700263 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
Yilun Chongd8c25012019-02-22 18:13:33 +0800339 // 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 {}");
Hao Nguyen2f864fd2019-03-20 11:45:01 -0700346
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);
Hao Nguyen176f7db2019-04-09 06:23:32 -0700369
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 )");
Joshua Habermanb99994d2020-03-31 16:25:37 -0700394
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);
Joshua Haberman96307d22021-03-22 13:05:55 -0700454
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 )");
Yilun Chongd8c25012019-02-22 18:13:33 +0800475}
476
477} // namespace protobuf
478} // namespace google