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 "conformance_test.h"
34
35 #include <google/protobuf/any.pb.h>
36 #include <google/protobuf/test_messages_proto2.pb.h>
37 #include <google/protobuf/test_messages_proto3.pb.h>
38 #include <google/protobuf/text_format.h>
39
40 using conformance::ConformanceRequest;
41 using conformance::ConformanceResponse;
42 using conformance::WireFormat;
43 using google::protobuf::Message;
44 using google::protobuf::TextFormat;
45 using protobuf_test_messages::proto2::TestAllTypesProto2;
46 using protobuf_test_messages::proto2::UnknownToTestAllTypes;
47 using protobuf_test_messages::proto3::TestAllTypesProto3;
48 using std::string;
49
50 namespace google {
51 namespace protobuf {
52
TextFormatConformanceTestSuite()53 TextFormatConformanceTestSuite::TextFormatConformanceTestSuite() {
54 SetFailureListFlagName("--text_format_failure_list");
55 }
56
ParseTextFormatResponse(const ConformanceResponse & response,const ConformanceRequestSetting & setting,Message * test_message)57 bool TextFormatConformanceTestSuite::ParseTextFormatResponse(
58 const ConformanceResponse& response,
59 const ConformanceRequestSetting& setting, Message* test_message) {
60 TextFormat::Parser parser;
61 const ConformanceRequest& request = setting.GetRequest();
62 if (request.print_unknown_fields()) {
63 parser.AllowFieldNumber(true);
64 }
65 if (!parser.ParseFromString(response.text_payload(), test_message)) {
66 GOOGLE_LOG(ERROR) << "INTERNAL ERROR: internal text->protobuf transcode "
67 << "yielded unparseable proto. Text payload: "
68 << response.text_payload();
69 return false;
70 }
71
72 return true;
73 }
74
ParseResponse(const ConformanceResponse & response,const ConformanceRequestSetting & setting,Message * test_message)75 bool TextFormatConformanceTestSuite::ParseResponse(
76 const ConformanceResponse& response,
77 const ConformanceRequestSetting& setting, Message* test_message) {
78 const ConformanceRequest& request = setting.GetRequest();
79 WireFormat requested_output = request.requested_output_format();
80 const string& test_name = setting.GetTestName();
81 ConformanceLevel level = setting.GetLevel();
82
83 switch (response.result_case()) {
84 case ConformanceResponse::kProtobufPayload: {
85 if (requested_output != conformance::PROTOBUF) {
86 ReportFailure(
87 test_name, level, request, response,
88 StrCat("Test was asked for ", WireFormatToString(requested_output),
89 " output but provided PROTOBUF instead.")
90 .c_str());
91 return false;
92 }
93
94 if (!test_message->ParseFromString(response.protobuf_payload())) {
95 ReportFailure(test_name, level, request, response,
96 "Protobuf output we received from test was unparseable.");
97 return false;
98 }
99
100 break;
101 }
102
103 case ConformanceResponse::kTextPayload: {
104 if (requested_output != conformance::TEXT_FORMAT) {
105 ReportFailure(
106 test_name, level, request, response,
107 StrCat("Test was asked for ", WireFormatToString(requested_output),
108 " output but provided TEXT_FORMAT instead.")
109 .c_str());
110 return false;
111 }
112
113 if (!ParseTextFormatResponse(response, setting, test_message)) {
114 ReportFailure(
115 test_name, level, request, response,
116 "TEXT_FORMAT output we received from test was unparseable.");
117 return false;
118 }
119
120 break;
121 }
122
123 default:
124 GOOGLE_LOG(FATAL) << test_name
125 << ": unknown payload type: " << response.result_case();
126 }
127
128 return true;
129 }
130
ExpectParseFailure(const string & test_name,ConformanceLevel level,const string & input)131 void TextFormatConformanceTestSuite::ExpectParseFailure(const string& test_name,
132 ConformanceLevel level,
133 const string& input) {
134 TestAllTypesProto3 prototype;
135 // We don't expect output, but if the program erroneously accepts the protobuf
136 // we let it send its response as this. We must not leave it unspecified.
137 ConformanceRequestSetting setting(
138 level, conformance::TEXT_FORMAT, conformance::TEXT_FORMAT,
139 conformance::TEXT_FORMAT_TEST, prototype, test_name, input);
140 const ConformanceRequest& request = setting.GetRequest();
141 ConformanceResponse response;
142 string effective_test_name = StrCat(setting.ConformanceLevelToString(level),
143 ".Proto3.TextFormatInput.", test_name);
144
145 RunTest(effective_test_name, request, &response);
146 if (response.result_case() == ConformanceResponse::kParseError) {
147 ReportSuccess(effective_test_name);
148 } else if (response.result_case() == ConformanceResponse::kSkipped) {
149 ReportSkip(effective_test_name, request, response);
150 } else {
151 ReportFailure(effective_test_name, level, request, response,
152 "Should have failed to parse, but didn't.");
153 }
154 }
155
RunValidTextFormatTest(const string & test_name,ConformanceLevel level,const string & input_text)156 void TextFormatConformanceTestSuite::RunValidTextFormatTest(
157 const string& test_name, ConformanceLevel level, const string& input_text) {
158 TestAllTypesProto3 prototype;
159 RunValidTextFormatTestWithMessage(test_name, level, input_text, prototype);
160 }
161
RunValidTextFormatTestProto2(const string & test_name,ConformanceLevel level,const string & input_text)162 void TextFormatConformanceTestSuite::RunValidTextFormatTestProto2(
163 const string& test_name, ConformanceLevel level, const string& input_text) {
164 TestAllTypesProto2 prototype;
165 RunValidTextFormatTestWithMessage(test_name, level, input_text, prototype);
166 }
167
RunValidTextFormatTestWithMessage(const string & test_name,ConformanceLevel level,const string & input_text,const Message & prototype)168 void TextFormatConformanceTestSuite::RunValidTextFormatTestWithMessage(
169 const string& test_name, ConformanceLevel level, const string& input_text,
170 const Message& prototype) {
171 ConformanceRequestSetting setting1(
172 level, conformance::TEXT_FORMAT, conformance::PROTOBUF,
173 conformance::TEXT_FORMAT_TEST, prototype, test_name, input_text);
174 RunValidInputTest(setting1, input_text);
175 ConformanceRequestSetting setting2(
176 level, conformance::TEXT_FORMAT, conformance::TEXT_FORMAT,
177 conformance::TEXT_FORMAT_TEST, prototype, test_name, input_text);
178 RunValidInputTest(setting2, input_text);
179 }
180
RunValidUnknownTextFormatTest(const string & test_name,const Message & message)181 void TextFormatConformanceTestSuite::RunValidUnknownTextFormatTest(
182 const string& test_name, const Message& message) {
183 string serialized_input;
184 message.SerializeToString(&serialized_input);
185 TestAllTypesProto3 prototype;
186 ConformanceRequestSetting setting1(
187 RECOMMENDED, conformance::PROTOBUF, conformance::TEXT_FORMAT,
188 conformance::TEXT_FORMAT_TEST, prototype, test_name + "_Drop",
189 serialized_input);
190 setting1.SetPrototypeMessageForCompare(message);
191 RunValidBinaryInputTest(setting1, "");
192
193 ConformanceRequestSetting setting2(
194 RECOMMENDED, conformance::PROTOBUF, conformance::TEXT_FORMAT,
195 conformance::TEXT_FORMAT_TEST, prototype, test_name + "_Print",
196 serialized_input);
197 setting2.SetPrototypeMessageForCompare(message);
198 setting2.SetPrintUnknownFields(true);
199 RunValidBinaryInputTest(setting2, serialized_input);
200 }
201
RunSuiteImpl()202 void TextFormatConformanceTestSuite::RunSuiteImpl() {
203 RunValidTextFormatTest("HelloWorld", REQUIRED,
204 "optional_string: 'Hello, World!'");
205 // Integer fields.
206 RunValidTextFormatTest("Int32FieldMaxValue", REQUIRED,
207 "optional_int32: 2147483647");
208 RunValidTextFormatTest("Int32FieldMinValue", REQUIRED,
209 "optional_int32: -2147483648");
210 RunValidTextFormatTest("Uint32FieldMaxValue", REQUIRED,
211 "optional_uint32: 4294967295");
212 RunValidTextFormatTest("Int64FieldMaxValue", REQUIRED,
213 "optional_int64: 9223372036854775807");
214 RunValidTextFormatTest("Int64FieldMinValue", REQUIRED,
215 "optional_int64: -9223372036854775808");
216 RunValidTextFormatTest("Uint64FieldMaxValue", REQUIRED,
217 "optional_uint64: 18446744073709551615");
218
219 // Parsers reject out-of-bound integer values.
220 ExpectParseFailure("Int32FieldTooLarge", REQUIRED,
221 "optional_int32: 2147483648");
222 ExpectParseFailure("Int32FieldTooSmall", REQUIRED,
223 "optional_int32: -2147483649");
224 ExpectParseFailure("Uint32FieldTooLarge", REQUIRED,
225 "optional_uint32: 4294967296");
226 ExpectParseFailure("Int64FieldTooLarge", REQUIRED,
227 "optional_int64: 9223372036854775808");
228 ExpectParseFailure("Int64FieldTooSmall", REQUIRED,
229 "optional_int64: -9223372036854775809");
230 ExpectParseFailure("Uint64FieldTooLarge", REQUIRED,
231 "optional_uint64: 18446744073709551616");
232
233 // Floating point fields
234 RunValidTextFormatTest("FloatField", REQUIRED,
235 "optional_float: 3.192837");
236 RunValidTextFormatTest("FloatFieldWithVeryPreciseNumber", REQUIRED,
237 "optional_float: 3.123456789123456789");
238 RunValidTextFormatTest("FloatFieldMaxValue", REQUIRED,
239 "optional_float: 3.4028235e+38");
240 RunValidTextFormatTest("FloatFieldMinValue", REQUIRED,
241 "optional_float: 1.17549e-38");
242 RunValidTextFormatTest("FloatFieldNaNValue", REQUIRED,
243 "optional_float: NaN");
244 RunValidTextFormatTest("FloatFieldPosInfValue", REQUIRED,
245 "optional_float: inf");
246 RunValidTextFormatTest("FloatFieldNegInfValue", REQUIRED,
247 "optional_float: -inf");
248 RunValidTextFormatTest("FloatFieldWithInt32Max", REQUIRED,
249 "optional_float: 4294967296");
250 RunValidTextFormatTest("FloatFieldLargerThanInt64", REQUIRED,
251 "optional_float: 9223372036854775808");
252 RunValidTextFormatTest("FloatFieldTooLarge", REQUIRED,
253 "optional_float: 3.4028235e+39");
254 RunValidTextFormatTest("FloatFieldTooSmall", REQUIRED,
255 "optional_float: 1.17549e-39");
256 RunValidTextFormatTest("FloatFieldLargerThanUint64", REQUIRED,
257 "optional_float: 18446744073709551616");
258
259 // Group fields
260 RunValidTextFormatTestProto2("GroupFieldNoColon", REQUIRED,
261 "Data { group_int32: 1 }");
262 RunValidTextFormatTestProto2("GroupFieldWithColon", REQUIRED,
263 "Data: { group_int32: 1 }");
264 RunValidTextFormatTestProto2("GroupFieldEmpty", REQUIRED,
265 "Data {}");
266
267
268 // Unknown Fields
269 UnknownToTestAllTypes message;
270 // Unable to print unknown Fixed32/Fixed64 fields as if they are known.
271 // Fixed32/Fixed64 fields are not added in the tests.
272 message.set_optional_int32(123);
273 message.set_optional_string("hello");
274 message.set_optional_bool(true);
275 RunValidUnknownTextFormatTest("ScalarUnknownFields", message);
276
277 message.Clear();
278 message.mutable_nested_message()->set_c(111);
279 RunValidUnknownTextFormatTest("MessageUnknownFields", message);
280
281 message.Clear();
282 message.mutable_optionalgroup()->set_a(321);
283 RunValidUnknownTextFormatTest("GroupUnknownFields", message);
284
285 message.add_repeated_int32(1);
286 message.add_repeated_int32(2);
287 message.add_repeated_int32(3);
288 RunValidUnknownTextFormatTest("RepeatedUnknownFields", message);
289
290 // Any fields
291 RunValidTextFormatTest("AnyField", REQUIRED,
292 R"(
293 optional_any: {
294 [type.googleapis.com/protobuf_test_messages.proto3.TestAllTypesProto3] {
295 optional_int32: 12345
296 }
297 }
298 )");
299 RunValidTextFormatTest("AnyFieldWithRawBytes", REQUIRED,
300 R"(
301 optional_any: {
302 type_url: "type.googleapis.com/protobuf_test_messages.proto3.TestAllTypesProto3"
303 value: "\b\271`"
304 }
305 )");
306 ExpectParseFailure("AnyFieldWithInvalidType", REQUIRED,
307 R"(
308 optional_any: {
309 [type.googleapis.com/unknown] {
310 optional_int32: 12345
311 }
312 }
313 )");
314 }
315
316 } // namespace protobuf
317 } // namespace google
318