1 /*
2 *
3 * A set of tests for JSON parsing and serialization.
4 */
5
6 #include <string>
7
8 #include "tests/json/test.upb.h" // Test that it compiles for C++.
9 #include "tests/json/test.upbdefs.h"
10 #include "tests/test_util.h"
11 #include "tests/upb_test.h"
12 #include "upb/def.hpp"
13 #include "upb/handlers.h"
14 #include "upb/json/parser.h"
15 #include "upb/json/printer.h"
16 #include "upb/port_def.inc"
17 #include "upb/upb.h"
18
19 // Macros for readability in test case list: allows us to give TEST("...") /
20 // EXPECT("...") pairs.
21 #define TEST(x) x
22 #define EXPECT_SAME NULL
23 #define EXPECT(x) x
24 #define TEST_SENTINEL { NULL, NULL }
25
26 struct TestCase {
27 const char* input;
28 const char* expected;
29 };
30
31 bool verbose = false;
32
33 static TestCase kTestRoundtripMessages[] = {
34 // Test most fields here.
35 {
36 TEST("{\"optionalInt32\":-42,\"optionalString\":\"Test\\u0001Message\","
37 "\"optionalMsg\":{\"foo\":42},"
38 "\"optionalBool\":true,\"repeatedMsg\":[{\"foo\":1},"
39 "{\"foo\":2}]}"),
40 EXPECT_SAME
41 },
42 // We must also recognize raw proto names.
43 {
44 TEST("{\"optional_int32\":-42,\"optional_string\":\"Test\\u0001Message\","
45 "\"optional_msg\":{\"foo\":42},"
46 "\"optional_bool\":true,\"repeated_msg\":[{\"foo\":1},"
47 "{\"foo\":2}]}"),
48 EXPECT("{\"optionalInt32\":-42,\"optionalString\":\"Test\\u0001Message\","
49 "\"optionalMsg\":{\"foo\":42},"
50 "\"optionalBool\":true,\"repeatedMsg\":[{\"foo\":1},"
51 "{\"foo\":2}]}")
52 },
53 // Test special escapes in strings.
54 {
55 TEST("{\"repeatedString\":[\"\\b\",\"\\r\",\"\\n\",\"\\f\",\"\\t\","
56 "\"\uFFFF\"]}"),
57 EXPECT_SAME
58 },
59 // Test enum symbolic names.
60 {
61 // The common case: parse and print the symbolic name.
62 TEST("{\"optionalEnum\":\"A\"}"),
63 EXPECT_SAME
64 },
65 {
66 // Unknown enum value: will be printed as an integer.
67 TEST("{\"optionalEnum\":42}"),
68 EXPECT_SAME
69 },
70 {
71 // Known enum value: we're happy to parse an integer but we will re-emit the
72 // symbolic name.
73 TEST("{\"optionalEnum\":1}"),
74 EXPECT("{\"optionalEnum\":\"B\"}")
75 },
76 // UTF-8 tests: escapes -> literal UTF8 in output.
77 {
78 // Note double escape on \uXXXX: we want the escape to be processed by the
79 // JSON parser, not by the C++ compiler!
80 TEST("{\"optionalString\":\"\\u007F\"}"),
81 EXPECT("{\"optionalString\":\"\x7F\"}")
82 },
83 {
84 TEST("{\"optionalString\":\"\\u0080\"}"),
85 EXPECT("{\"optionalString\":\"\xC2\x80\"}")
86 },
87 {
88 TEST("{\"optionalString\":\"\\u07FF\"}"),
89 EXPECT("{\"optionalString\":\"\xDF\xBF\"}")
90 },
91 {
92 TEST("{\"optionalString\":\"\\u0800\"}"),
93 EXPECT("{\"optionalString\":\"\xE0\xA0\x80\"}")
94 },
95 {
96 TEST("{\"optionalString\":\"\\uFFFF\"}"),
97 EXPECT("{\"optionalString\":\"\xEF\xBF\xBF\"}")
98 },
99 // map-field tests
100 {
101 TEST("{\"mapStringString\":{\"a\":\"value1\",\"b\":\"value2\","
102 "\"c\":\"value3\"}}"),
103 EXPECT_SAME
104 },
105 {
106 TEST("{\"mapInt32String\":{\"1\":\"value1\",\"-1\":\"value2\","
107 "\"1234\":\"value3\"}}"),
108 EXPECT_SAME
109 },
110 {
111 TEST("{\"mapBoolString\":{\"false\":\"value1\",\"true\":\"value2\"}}"),
112 EXPECT_SAME
113 },
114 {
115 TEST("{\"mapStringInt32\":{\"asdf\":1234,\"jkl;\":-1}}"),
116 EXPECT_SAME
117 },
118 {
119 TEST("{\"mapStringBool\":{\"asdf\":true,\"jkl;\":false}}"),
120 EXPECT_SAME
121 },
122 {
123 TEST("{\"mapStringMsg\":{\"asdf\":{\"foo\":42},\"jkl;\":{\"foo\":84}}}"),
124 EXPECT_SAME
125 },
126 TEST_SENTINEL
127 };
128
129 static TestCase kTestRoundtripMessagesPreserve[] = {
130 // Test most fields here.
131 {
132 TEST("{\"optional_int32\":-42,\"optional_string\":\"Test\\u0001Message\","
133 "\"optional_msg\":{\"foo\":42},"
134 "\"optional_bool\":true,\"repeated_msg\":[{\"foo\":1},"
135 "{\"foo\":2}]}"),
136 EXPECT_SAME
137 },
138 TEST_SENTINEL
139 };
140
141 static TestCase kTestSkipUnknown[] = {
142 {
143 TEST("{\"optionalEnum\":\"UNKNOWN_ENUM_VALUE\"}"),
144 EXPECT("{}"),
145 },
146 TEST_SENTINEL
147 };
148
149 static TestCase kTestFailure[] = {
150 {
151 TEST("{\"optionalEnum\":\"UNKNOWN_ENUM_VALUE\"}"),
152 EXPECT("{}"), /* Actually we expect error, this is checked later. */
153 },
154 TEST_SENTINEL
155 };
156
157 class StringSink {
158 public:
StringSink()159 StringSink() {
160 upb_byteshandler_init(&byteshandler_);
161 upb_byteshandler_setstring(&byteshandler_, &str_handler, NULL);
162 upb_bytessink_reset(&bytessink_, &byteshandler_, &s_);
163 }
~StringSink()164 ~StringSink() { }
165
Sink()166 upb_bytessink Sink() { return bytessink_; }
167
Data()168 const std::string& Data() { return s_; }
169
170 private:
171
str_handler(void * _closure,const void * hd,const char * data,size_t len,const upb_bufhandle * handle)172 static size_t str_handler(void* _closure, const void* hd,
173 const char* data, size_t len,
174 const upb_bufhandle* handle) {
175 UPB_UNUSED(hd);
176 UPB_UNUSED(handle);
177 std::string* s = static_cast<std::string*>(_closure);
178 std::string appended(data, len);
179 s->append(data, len);
180 return len;
181 }
182
183 upb_byteshandler byteshandler_;
184 upb_bytessink bytessink_;
185 std::string s_;
186 };
187
test_json_roundtrip_message(const char * json_src,const char * json_expected,const upb::Handlers * serialize_handlers,const upb::json::ParserMethodPtr parser_method,int seam,bool ignore_unknown)188 void test_json_roundtrip_message(const char* json_src,
189 const char* json_expected,
190 const upb::Handlers* serialize_handlers,
191 const upb::json::ParserMethodPtr parser_method,
192 int seam,
193 bool ignore_unknown) {
194 VerboseParserEnvironment env(verbose);
195 StringSink data_sink;
196 upb::json::PrinterPtr printer = upb::json::PrinterPtr::Create(
197 env.arena(), serialize_handlers, data_sink.Sink());
198 upb::json::ParserPtr parser = upb::json::ParserPtr::Create(
199 env.arena(), parser_method, NULL, printer.input(),
200 env.status(), ignore_unknown);
201 env.ResetBytesSink(parser.input());
202 env.Reset(json_src, strlen(json_src), false, false);
203
204 bool ok = env.Start() &&
205 env.ParseBuffer(seam) &&
206 env.ParseBuffer(-1) &&
207 env.End();
208
209 ASSERT(ok);
210 ASSERT(env.CheckConsistency());
211
212 if (memcmp(json_expected,
213 data_sink.Data().data(),
214 data_sink.Data().size())) {
215 fprintf(stderr,
216 "JSON parse/serialize roundtrip result differs:\n"
217 "Expected:\n%s\nParsed/Serialized:\n%s\n",
218 json_expected, data_sink.Data().c_str());
219 abort();
220 }
221 }
222
223 // Starts with a message in JSON format, parses and directly serializes again,
224 // and compares the result.
test_json_roundtrip()225 void test_json_roundtrip() {
226 upb::SymbolTable symtab;
227 upb::HandlerCache serialize_handlercache(
228 upb::json::PrinterPtr::NewCache(false));
229 upb::json::CodeCache parse_codecache;
230
231 upb::MessageDefPtr md(upb_test_json_TestMessage_getmsgdef(symtab.ptr()));
232 ASSERT(md);
233 const upb::Handlers* serialize_handlers = serialize_handlercache.Get(md);
234 const upb::json::ParserMethodPtr parser_method = parse_codecache.Get(md);
235 ASSERT(serialize_handlers);
236
237 for (const TestCase* test_case = kTestRoundtripMessages;
238 test_case->input != NULL; test_case++) {
239 const char *expected =
240 (test_case->expected == EXPECT_SAME) ?
241 test_case->input :
242 test_case->expected;
243
244 for (size_t i = 0; i < strlen(test_case->input); i++) {
245 test_json_roundtrip_message(test_case->input, expected,
246 serialize_handlers, parser_method, (int)i,
247 false);
248 }
249 }
250
251 // Tests ignore unknown.
252 for (const TestCase* test_case = kTestSkipUnknown;
253 test_case->input != NULL; test_case++) {
254 const char *expected =
255 (test_case->expected == EXPECT_SAME) ?
256 test_case->input :
257 test_case->expected;
258
259 for (size_t i = 0; i < strlen(test_case->input); i++) {
260 test_json_roundtrip_message(test_case->input, expected,
261 serialize_handlers, parser_method, (int)i,
262 true);
263 }
264 }
265
266 serialize_handlercache = upb::json::PrinterPtr::NewCache(true);
267 serialize_handlers = serialize_handlercache.Get(md);
268
269 for (const TestCase* test_case = kTestRoundtripMessagesPreserve;
270 test_case->input != NULL; test_case++) {
271 const char *expected =
272 (test_case->expected == EXPECT_SAME) ?
273 test_case->input :
274 test_case->expected;
275
276 for (size_t i = 0; i < strlen(test_case->input); i++) {
277 test_json_roundtrip_message(test_case->input, expected,
278 serialize_handlers, parser_method, (int)i,
279 false);
280 }
281 }
282 }
283
test_json_parse_failure(const char * json_src,const upb::Handlers * serialize_handlers,const upb::json::ParserMethodPtr parser_method,int seam)284 void test_json_parse_failure(const char* json_src,
285 const upb::Handlers* serialize_handlers,
286 const upb::json::ParserMethodPtr parser_method,
287 int seam) {
288 VerboseParserEnvironment env(verbose);
289 StringSink data_sink;
290 upb::json::PrinterPtr printer = upb::json::PrinterPtr::Create(
291 env.arena(), serialize_handlers, data_sink.Sink());
292 upb::json::ParserPtr parser = upb::json::ParserPtr::Create(
293 env.arena(), parser_method, NULL, printer.input(), env.status(), false);
294 env.ResetBytesSink(parser.input());
295 env.Reset(json_src, strlen(json_src), false, true);
296
297 bool ok = env.Start() &&
298 env.ParseBuffer(seam) &&
299 env.ParseBuffer(-1) &&
300 env.End();
301
302 ASSERT(!ok);
303 ASSERT(env.CheckConsistency());
304 }
305
306 // Starts with a proto message in JSON format, parses and expects failre.
test_json_failure()307 void test_json_failure() {
308 upb::SymbolTable symtab;
309 upb::HandlerCache serialize_handlercache(
310 upb::json::PrinterPtr::NewCache(false));
311 upb::json::CodeCache parse_codecache;
312
313 upb::MessageDefPtr md(upb_test_json_TestMessage_getmsgdef(symtab.ptr()));
314 ASSERT(md);
315 const upb::Handlers* serialize_handlers = serialize_handlercache.Get(md);
316 const upb::json::ParserMethodPtr parser_method = parse_codecache.Get(md);
317 ASSERT(serialize_handlers);
318
319 for (const TestCase* test_case = kTestFailure;
320 test_case->input != NULL; test_case++) {
321 for (size_t i = 0; i < strlen(test_case->input); i++) {
322 test_json_parse_failure(test_case->input, serialize_handlers,
323 parser_method, (int)i);
324 }
325 }
326 }
327
328 extern "C" {
run_tests(int argc,char * argv[])329 int run_tests(int argc, char *argv[]) {
330 UPB_UNUSED(argc);
331 UPB_UNUSED(argv);
332 test_json_roundtrip();
333 test_json_failure();
334 return 0;
335 }
336 }
337