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