• 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   // Group fields
262   RunValidTextFormatTestProto2("GroupFieldNoColon", REQUIRED,
263                                "Data { group_int32: 1 }");
264   RunValidTextFormatTestProto2("GroupFieldWithColon", REQUIRED,
265                                "Data: { group_int32: 1 }");
266   RunValidTextFormatTestProto2("GroupFieldEmpty", REQUIRED,
267                                "Data {}");
268 
269 
270   // Unknown Fields
271   UnknownToTestAllTypes message;
272   // Unable to print unknown Fixed32/Fixed64 fields as if they are known.
273   // Fixed32/Fixed64 fields are not added in the tests.
274   message.set_optional_int32(123);
275   message.set_optional_string("hello");
276   message.set_optional_bool(true);
277   RunValidUnknownTextFormatTest("ScalarUnknownFields", message);
278 
279   message.Clear();
280   message.mutable_nested_message()->set_c(111);
281   RunValidUnknownTextFormatTest("MessageUnknownFields", message);
282 
283   message.Clear();
284   message.mutable_optionalgroup()->set_a(321);
285   RunValidUnknownTextFormatTest("GroupUnknownFields", message);
286 
287   message.add_repeated_int32(1);
288   message.add_repeated_int32(2);
289   message.add_repeated_int32(3);
290   RunValidUnknownTextFormatTest("RepeatedUnknownFields", message);
291 
292   // Any fields
293   RunValidTextFormatTest("AnyField", REQUIRED,
294                          R"(
295       optional_any: {
296         [type.googleapis.com/protobuf_test_messages.proto3.TestAllTypesProto3] {
297           optional_int32: 12345
298         }
299       }
300       )");
301   RunValidTextFormatTest("AnyFieldWithRawBytes", REQUIRED,
302                          R"(
303       optional_any: {
304         type_url: "type.googleapis.com/protobuf_test_messages.proto3.TestAllTypesProto3"
305         value: "\b\271`"
306       }
307       )");
308   ExpectParseFailure("AnyFieldWithInvalidType", REQUIRED,
309                      R"(
310       optional_any: {
311         [type.googleapis.com/unknown] {
312           optional_int32: 12345
313         }
314       }
315       )");
316 
317   // Map fields
318   TestAllTypesProto3 prototype;
319   (*prototype.mutable_map_string_string())["c"] = "value";
320   (*prototype.mutable_map_string_string())["b"] = "value";
321   (*prototype.mutable_map_string_string())["a"] = "value";
322   RunValidTextFormatTestWithMessage("AlphabeticallySortedMapStringKeys",
323                                     REQUIRED,
324                                     R"(
325       map_string_string {
326         key: "a"
327         value: "value"
328       }
329       map_string_string {
330         key: "b"
331         value: "value"
332       }
333       map_string_string {
334         key: "c"
335         value: "value"
336       }
337       )",
338                                     prototype);
339 
340   prototype.Clear();
341   (*prototype.mutable_map_int32_int32())[3] = 0;
342   (*prototype.mutable_map_int32_int32())[2] = 0;
343   (*prototype.mutable_map_int32_int32())[1] = 0;
344   RunValidTextFormatTestWithMessage("AlphabeticallySortedMapIntKeys", REQUIRED,
345                                     R"(
346       map_int32_int32 {
347         key: 1
348         value: 0
349       }
350       map_int32_int32 {
351         key: 2
352         value: 0
353       }
354       map_int32_int32 {
355         key: 3
356         value: 0
357       }
358       )",
359                                     prototype);
360 
361   prototype.Clear();
362   (*prototype.mutable_map_bool_bool())[true] = false;
363   (*prototype.mutable_map_bool_bool())[false] = false;
364   RunValidTextFormatTestWithMessage("AlphabeticallySortedMapBoolKeys", REQUIRED,
365                                     R"(
366       map_bool_bool {
367         key: false
368         value: false
369       }
370       map_bool_bool {
371         key: true
372         value: false
373       }
374       )",
375                                     prototype);
376 }
377 
378 }  // namespace protobuf
379 }  // namespace google
380