1 /* Copyright (c) 2015, 2021, Oracle and/or its affiliates.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License, version 2.0, for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
22
23 // First include (the generated) my_config.h, to get correct platform defines.
24 #include "my_config.h"
25 #include "my_decimal.h"
26 #include "sql_string.h"
27 #include "sql_time.h"
28 #include "json_binary.h"
29 #include "json_dom.h"
30 #include "base64.h"
31 #include "template_utils.h" // down_cast
32
33 #include <gtest/gtest.h>
34 #include "test_utils.h"
35
36 #include <memory>
37 #include <cstring>
38
39 /**
40 Test Json_dom class hierarchy API, cf. json_dom.h
41 */
42 namespace json_dom_unittest {
43
44 class JsonDomTest : public ::testing::Test
45 {
46 protected:
SetUp()47 virtual void SetUp() { initializer.SetUp(); }
TearDown()48 virtual void TearDown() { initializer.TearDown(); }
49 my_testing::Server_initializer initializer;
50 };
51
52 /**
53 Format a Json_dom object to JSON text using Json_wrapper's
54 to_string functionality.
55
56 @param d The DOM object to be formatted
57 */
format(const Json_dom & d)58 std::string format(const Json_dom &d)
59 {
60 String buffer;
61 Json_wrapper w(d.clone());
62 EXPECT_FALSE(w.to_string(&buffer, true, "format"));
63
64 return std::string(buffer.ptr(), buffer.length());
65 }
66
format(const Json_dom * ptr)67 std::string format(const Json_dom *ptr)
68 {
69 return format(*ptr);
70 }
71
TEST_F(JsonDomTest,BasicTest)72 TEST_F(JsonDomTest, BasicTest)
73 {
74 String buffer;
75 /* string scalar */
76 const std::string std_s("abc");
77 Json_string s(std_s);
78 EXPECT_EQ(std_s, s.value());
79 EXPECT_EQ(Json_dom::J_STRING, s.json_type());
80 EXPECT_TRUE(s.is_scalar());
81 EXPECT_EQ(1U, s.depth());
82 EXPECT_FALSE(s.is_number());
83 EXPECT_EQ(std::string("\"abc\""), format(s));
84
85 /*
86 Escaping in strings, cf. ECMA-404 The JSON Data Interchange Format
87 */
88 Json_array a;
89 /* double quote and backslash */
90 Json_string js1(std::string("a\"b\\c"));
91 a.append_clone(&js1);
92 EXPECT_EQ(std::string("[\"a\\\"b\\\\c\"]"), format(a));
93
94 a.clear();
95 /* Printable control characters */
96 Json_string js2(std::string("a\b\f\n\r\tb"));
97 a.append_clone(&js2);
98 EXPECT_EQ(7U, static_cast<Json_string *>(a[0])->size());
99 EXPECT_EQ(std::string("[\"a\\b\\f\\n\\r\\tb\"]"), format(a));
100
101 a.clear();
102 /* Unprintable control characters and non-ASCII Unicode characters */
103 Json_string js3(std::string("丳\x13" "丽\x3"));
104 a.append_clone(&js3);
105 EXPECT_EQ(std::string("[\"丳\\u0013丽\\u0003\"]"), format(a));
106
107 /* boolean scalar */
108 const Json_boolean jb(true);
109 EXPECT_EQ(Json_dom::J_BOOLEAN, jb.json_type());
110 EXPECT_EQ(true, jb.value());
111 EXPECT_EQ(std::string("true"), format(jb));
112
113 /* Integer scalar */
114 const Json_int ji(-123);
115 EXPECT_EQ(Json_dom::J_INT, ji.json_type());
116 EXPECT_EQ(-123, ji.value());
117 EXPECT_EQ(std::string("-123"), format(ji));
118
119 const Json_int max_32_int(2147483647);
120 EXPECT_EQ(std::string("2147483647"), format(max_32_int));
121
122 const Json_int max_64_int(9223372036854775807LL);
123 EXPECT_EQ(std::string("9223372036854775807"), format(max_64_int));
124
125 const Json_uint max_64_uint(18446744073709551615ULL);
126 EXPECT_EQ(Json_dom::J_UINT, max_64_uint.json_type());
127 EXPECT_EQ(std::string("18446744073709551615"), format(max_64_uint));
128
129 /* Double scalar */
130 const Json_double jdb(-123.45);
131 EXPECT_EQ(Json_dom::J_DOUBLE, jdb.json_type());
132 EXPECT_EQ(-123.45, jdb.value());
133 EXPECT_EQ(std::string("-123.45"), format(jdb));
134
135 /* Simple array with strings */
136 a.clear();
137 EXPECT_EQ(Json_dom::J_ARRAY, a.json_type());
138 EXPECT_FALSE(a.is_scalar());
139 EXPECT_EQ(0U, a.size());
140 Json_string js4(std::string("val1"));
141 a.append_clone(&js4);
142 Json_string js5(std::string("val2"));
143 a.append_clone(&js5);
144 EXPECT_EQ(2U, a.size());
145 EXPECT_EQ(std::string("[\"val1\", \"val2\"]"), format(a));
146 EXPECT_EQ(2U, a.depth());
147 Json_dom *elt0= a[0];
148 Json_dom *elt1= a[a.size() - 1];
149 EXPECT_EQ(std::string("\"val1\""), format(elt0));
150 EXPECT_EQ(std::string("\"val2\""), format(elt1));
151
152 /* Simple object with string values, iterator and array cloning */
153 Json_object o;
154 EXPECT_EQ(Json_dom::J_OBJECT, o.json_type());
155 EXPECT_FALSE(a.is_scalar());
156 EXPECT_EQ(0U, o.cardinality());
157 Json_null null;
158 EXPECT_EQ(Json_dom::J_NULL, null.json_type());
159 o.add_clone(std::string("key1"), &null);
160 o.add_clone(std::string("key2"), &a);
161
162 const std::string key_expected[]=
163 {std::string("key1"), std::string("key2")};
164 const std::string value_expected[]=
165 {std::string("null"), std::string("[\"val1\", \"val2\"]")};
166
167 int idx= 0;
168
169 for (Json_object::const_iterator i= o.begin(); i != o.end(); ++i)
170 {
171 EXPECT_EQ(key_expected[idx], i->first);
172 EXPECT_EQ(value_expected[idx], format(i->second));
173 idx++;
174 }
175
176 /* Test uniqueness of keys */
177 Json_string js6(std::string("should be discarded"));
178 o.add_clone(std::string("key1"), &js6);
179 EXPECT_EQ(2U, o.cardinality());
180 EXPECT_EQ(std::string("{\"key1\": null, \"key2\": [\"val1\", \"val2\"]}"),
181 format(o));
182 EXPECT_EQ(3U, o.depth());
183
184 /* Nested array inside object and object inside array,
185 * and object cloning
186 */
187 Json_array level3;
188 level3.append_clone(&o);
189 Json_int ji2(123);
190 level3.insert_clone(0U, &ji2);
191 EXPECT_EQ(std::string("[123, {\"key1\": null, \"key2\": "
192 "[\"val1\", \"val2\"]}]"),
193 format(level3));
194 EXPECT_EQ(4U, level3.depth());
195
196 /* Array access: index */
197 Json_dom * const elt= level3[1];
198 EXPECT_EQ(std::string("{\"key1\": null, \"key2\": "
199 "[\"val1\", \"val2\"]}"),
200 format(elt));
201
202 /* Object access: key look-up */
203 EXPECT_EQ(Json_dom::J_OBJECT, elt->json_type());
204 Json_object * const object_elt= down_cast<Json_object *>(elt);
205 EXPECT_TRUE(object_elt != NULL);
206 const Json_dom * const elt2= object_elt->get(std::string("key1"));
207 EXPECT_EQ(std::string("null"), format(elt2));
208
209 /* Clear object. */
210 object_elt->clear();
211 EXPECT_EQ(0U, object_elt->cardinality());
212
213 /* Array remove element */
214 EXPECT_TRUE(level3.remove(1));
215 EXPECT_EQ(std::string("[123]"), format(level3));
216 EXPECT_FALSE(level3.remove(level3.size()));
217 EXPECT_EQ(std::string("[123]"), format(level3));
218
219 /* Decimal scalar, including cloning */
220 my_decimal m;
221 EXPECT_FALSE(double2my_decimal(0, 3.14, &m));
222
223 const Json_decimal jd(m);
224 EXPECT_EQ(Json_dom::J_DECIMAL, jd.json_type());
225 EXPECT_TRUE(jd.is_number());
226 EXPECT_TRUE(jd.is_scalar());
227 const my_decimal m_out= *jd.value();
228 double m_d;
229 double m_out_d;
230
231 decimal2double(&m, &m_d);
232 decimal2double(&m_out, &m_out_d);
233 EXPECT_EQ(m_d, m_out_d);
234
235 a.append_clone(&jd);
236 std::auto_ptr<Json_array> b(static_cast<Json_array *>(a.clone()));
237 EXPECT_EQ(std::string("[\"val1\", \"val2\", 3.14]"), format(a));
238 EXPECT_EQ(std::string("[\"val1\", \"val2\", 3.14]"), format(b.get()));
239
240 /* Array insert beyond end appends at end */
241 a.clear();
242 a.insert_alias(0, new (std::nothrow) Json_int(0));
243 a.insert_alias(2, new (std::nothrow) Json_int(2));
244 EXPECT_EQ(std::string("[0, 2]"), format(a));
245 a.clear();
246 a.insert_alias(0, new (std::nothrow) Json_int(0));
247 a.insert_alias(1, new (std::nothrow) Json_int(1));
248 EXPECT_EQ(std::string("[0, 1]"), format(a));
249
250 /* Array clear, null type, boolean literals, including cloning */
251 a.clear();
252 Json_null jn;
253 Json_boolean jbf(false);
254 Json_boolean jbt(true);
255 a.append_clone(&jn);
256 a.append_clone(&jbf);
257 a.append_clone(&jbt);
258 std::auto_ptr<const Json_dom> c(a.clone());
259 EXPECT_EQ(std::string("[null, false, true]"), format(a));
260 EXPECT_EQ(std::string("[null, false, true]"), format(c.get()));
261
262 /* DATETIME scalar */
263 MYSQL_TIME dt;
264 std::memset(&dt, 0, sizeof dt);
265 MYSQL_TIME_STATUS status;
266 EXPECT_FALSE(str_to_datetime(&my_charset_utf8mb4_bin,
267 "19990412",
268 8,
269 &dt,
270 (my_time_flags_t)0,
271 &status));
272 const Json_datetime scalar(dt, MYSQL_TYPE_DATETIME);
273 EXPECT_EQ(Json_dom::J_DATETIME, scalar.json_type());
274
275 const MYSQL_TIME *dt_out= scalar.value();
276
277 EXPECT_FALSE(std::memcmp(&dt, dt_out, sizeof(MYSQL_TIME)));
278 EXPECT_EQ(std::string("\"1999-04-12\""), format(scalar));
279
280 a.clear();
281 a.append_clone(&scalar);
282 EXPECT_EQ(std::string("[\"1999-04-12\"]"), format(a));
283
284 EXPECT_FALSE(str_to_datetime(&my_charset_utf8mb4_bin,
285 "14-11-15 12.04.55.123456",
286 24,
287 &dt,
288 (my_time_flags_t)0,
289 &status));
290
291 Json_datetime scalar2(dt, MYSQL_TYPE_DATETIME);
292 EXPECT_EQ(std::string("\"2014-11-15 12:04:55.123456\""), format(scalar2));
293
294 /* Opaque type storage scalar */
295 const uint32 i= 0xCAFEBABE;
296 char i_as_char[4];
297 int4store(i_as_char, i);
298 Json_opaque opaque(MYSQL_TYPE_TINY_BLOB, i_as_char, sizeof(i_as_char));
299 EXPECT_EQ(Json_dom::J_OPAQUE, opaque.json_type());
300 EXPECT_EQ(i, uint4korr(opaque.value()));
301 EXPECT_EQ(MYSQL_TYPE_TINY_BLOB, opaque.type());
302 EXPECT_EQ(sizeof(i_as_char), opaque.size());
303 EXPECT_EQ(std::string("\"base64:type249:vrr+yg==\""),
304 format(opaque));
305
306 const char *encoded= "vrr+yg==";
307 char *buff= new char[static_cast<size_t>
308 (base64_needed_decoded_length(static_cast<int>
309 (std::strlen(encoded))))];
310 EXPECT_EQ(4, base64_decode(encoded, std::strlen(encoded), buff, NULL, 0));
311 EXPECT_EQ(0xCAFEBABE, uint4korr(buff));
312 delete[] buff;
313
314 /* Build DOM from JSON text using rapdjson */
315 const char *msg;
316 size_t msg_offset;
317 const char *sample_doc=
318 "{\"abc\": 3, \"foo\": [1, 2, {\"foo\": 3.24}, null]}";
319 std::auto_ptr<Json_dom> dom(Json_dom::parse(sample_doc,
320 std::strlen(sample_doc),
321 &msg, &msg_offset));
322 EXPECT_TRUE(dom.get() != NULL);
323 EXPECT_EQ(4U, dom->depth());
324 EXPECT_EQ(std::string(sample_doc), format(dom.get()));
325
326 const char *sample_array=
327 "[3, {\"abc\": \"\\u0000inTheText\"}]";
328 dom.reset(Json_dom::parse(sample_array, std::strlen(sample_array),
329 &msg, &msg_offset));
330 EXPECT_TRUE(dom.get() != NULL);
331 EXPECT_EQ(3U, dom->depth());
332 EXPECT_EQ(std::string(sample_array), format(dom.get()));
333
334 const char *sample_scalar_doc= "2";
335 dom.reset(Json_dom::parse(sample_scalar_doc, std::strlen(sample_scalar_doc),
336 &msg, &msg_offset));
337 EXPECT_TRUE(dom.get() != NULL);
338 EXPECT_EQ(std::string(sample_scalar_doc), format(dom.get()));
339
340 const char *max_uint_scalar= "18446744073709551615";
341 dom.reset(Json_dom::parse(max_uint_scalar, std::strlen(max_uint_scalar),
342 &msg, &msg_offset));
343 EXPECT_EQ(std::string(max_uint_scalar), format(dom.get()));
344
345 /*
346 Test that duplicate keys are eliminated, and that the returned
347 keys are in the expected order (sorted on length before
348 contents).
349 */
350 const char *sample_object= "{\"key1\":1, \"key2\":2, \"key1\":3, "
351 "\"key1\\u0000x\":4, \"key1\\u0000y\":5, \"a\":6, \"ab\":7, \"b\":8, "
352 "\"\":9, \"\":10}";
353 const std::string expected[8][2]=
354 {
355 { "", "9" },
356 { "a", "6" },
357 { "b", "8" },
358 { "ab", "7" },
359 { "key1", "1" },
360 { "key2", "2" },
361 { std::string("key1\0x", 6), "4" },
362 { std::string("key1\0y", 6), "5" },
363 };
364 dom.reset(Json_dom::parse(sample_object, std::strlen(sample_object),
365 &msg, &msg_offset));
366 EXPECT_TRUE(dom.get() != NULL);
367 const Json_object *obj= down_cast<const Json_object *>(dom.get());
368 EXPECT_EQ(8U, obj->cardinality());
369 idx= 0;
370
371 for (Json_object::const_iterator it= obj->begin(); it != obj->end(); ++it)
372 {
373 EXPECT_EQ(expected[idx][0], it->first);
374 EXPECT_EQ(expected[idx][1], format(it->second));
375 idx++;
376 }
377
378 EXPECT_EQ(8, idx);
379
380 /* Try to build DOM for JSON text using rapidjson on invalid text
381 Included so we test error recovery
382 */
383 const char *half_object_item= "{\"label\": ";
384 dom.reset(Json_dom::parse(half_object_item, std::strlen(half_object_item),
385 &msg, &msg_offset));
386 const Json_dom *null_dom= NULL;
387 EXPECT_EQ(null_dom, dom.get());
388
389 const char *half_array_item= "[1,";
390 dom.reset(Json_dom::parse(half_array_item, std::strlen(half_array_item),
391 &msg, &msg_offset));
392 EXPECT_EQ(null_dom, dom.get());
393 }
394
395 /*
396 Test that special characters are escaped when a Json_string is
397 converted to text, so that it is possible to parse the resulting
398 string. The JSON parser requires all characters in the range [0x00,
399 0x1F] and the characters " (double-quote) and \ (backslash) to be
400 escaped.
401 */
TEST_F(JsonDomTest,EscapeSpecialChars)402 TEST_F(JsonDomTest, EscapeSpecialChars)
403 {
404 // Create a JSON string with all characters in the range [0, 127].
405 char input[128];
406 for (size_t i= 0; i < sizeof(input); ++i)
407 input[i]= static_cast<char>(i);
408 const Json_string jstr(std::string(input, sizeof(input)));
409
410 // Now convert that value from JSON to text and back to JSON.
411 std::string str= format(jstr);
412 std::auto_ptr<Json_dom> dom(Json_dom::parse(str.c_str(), str.length(),
413 NULL, NULL));
414 EXPECT_NE(static_cast<Json_dom*>(NULL), dom.get());
415 EXPECT_EQ(Json_dom::J_STRING, dom->json_type());
416
417 // Expect to get the same string back, including all the special characters.
418 const Json_string *jstr2= down_cast<const Json_string *>(dom.get());
419 EXPECT_EQ(jstr.value(), jstr2->value());
420 }
421
vet_wrapper_length(char * text,size_t expected_length)422 void vet_wrapper_length(char * text, size_t expected_length )
423 {
424 const char *msg;
425 size_t msg_offset;
426 Json_dom *dom= Json_dom::parse(text, std::strlen(text), &msg, &msg_offset);
427 Json_wrapper dom_wrapper(dom);
428
429 EXPECT_EQ(expected_length, dom_wrapper.length())
430 << "Wrapped DOM: " << text << "\n";
431
432 String serialized_form;
433 EXPECT_FALSE(json_binary::serialize(dom, &serialized_form));
434 json_binary::Value binary=
435 json_binary::parse_binary(serialized_form.ptr(),
436 serialized_form.length());
437 Json_wrapper binary_wrapper(binary);
438
439 json_binary::Value::enum_type binary_type= binary.type();
440
441 if ((binary_type == json_binary::Value::ARRAY) ||
442 (binary_type == json_binary::Value::OBJECT))
443 {
444 EXPECT_EQ(expected_length, binary.element_count())
445 << "BINARY: " << text << " and data = " << binary.get_data() << "\n";
446 }
447 EXPECT_EQ(expected_length, binary_wrapper.length())
448 << "Wrapped BINARY: " << text << "\n";
449 }
450
TEST_F(JsonDomTest,WrapperTest)451 TEST_F(JsonDomTest, WrapperTest)
452 {
453 // Constructors, assignment, copy constructors, aliasing
454 Json_dom *d= new (std::nothrow) Json_null();
455 Json_wrapper w(d);
456 EXPECT_EQ(w.to_dom(), d);
457 Json_wrapper w_2(w);
458 EXPECT_NE(w.to_dom(), w_2.to_dom()); // deep copy
459
460 Json_wrapper w_2b;
461 EXPECT_TRUE(w_2b.empty());
462 w_2b= w;
463 EXPECT_NE(w.to_dom(), w_2b.to_dom()); // deep copy
464
465 w.set_alias(); // d is now "free" again
466 Json_wrapper w_3(w);
467 EXPECT_EQ(w.to_dom(), w_3.to_dom()); // alias copy
468 w_3= w;
469 EXPECT_EQ(w.to_dom(), w_3.to_dom()); // alias copy
470
471 Json_wrapper w_4(d); // give d a new owner
472 Json_wrapper w_5;
473 w_5.steal(&w_4); // takes over d
474 EXPECT_EQ(w_4.to_dom(), w_5.to_dom());
475
476 Json_wrapper w_6;
477 EXPECT_EQ(Json_dom::J_ERROR, w_6.type());
478 EXPECT_EQ(0U, w_6.length());
479 EXPECT_EQ(0U, w_6.depth());
480
481 Json_dom *i= new (std::nothrow) Json_int(1);
482 Json_wrapper w_7(i);
483 w_5.steal(&w_7); // should deallocate w_5's original
484
485 // scalars
486 vet_wrapper_length((char *) "false", 1);
487 vet_wrapper_length((char *) "true", 1);
488 vet_wrapper_length((char *) "null", 1);
489 vet_wrapper_length((char *) "1.1", 1);
490 vet_wrapper_length((char *) "\"hello world\"", 1);
491
492 // objects
493 vet_wrapper_length((char *) "{}", 0);
494 vet_wrapper_length((char *) "{ \"a\" : 100 }", 1);
495 vet_wrapper_length((char *) "{ \"a\" : 100, \"b\" : 200 }", 2);
496
497 // arrays
498 vet_wrapper_length((char *) "[]", 0);
499 vet_wrapper_length((char *) "[ 100 ]", 1);
500 vet_wrapper_length((char *) "[ 100, 200 ]", 2);
501
502 // nested objects
503 vet_wrapper_length((char *) "{ \"a\" : 100, \"b\" : { \"c\" : 300 } }", 2);
504
505 // nested arrays
506 vet_wrapper_length((char *) "[ 100, [ 200, 300 ] ]", 2);
507 }
508
vet_merge(char * left_text,char * right_text,std::string expected)509 void vet_merge(char * left_text, char * right_text, std::string expected )
510 {
511 const char *msg;
512 size_t msg_offset;
513 Json_dom *left_dom= Json_dom::parse(left_text, std::strlen(left_text),
514 &msg, &msg_offset);
515 Json_dom *right_dom= Json_dom::parse(right_text, std::strlen(right_text),
516 &msg, &msg_offset);
517 Json_dom *result_dom= merge_doms(left_dom, right_dom);
518
519 EXPECT_EQ(expected, format(*result_dom));
520
521 delete result_dom;
522 }
523
TEST_F(JsonDomTest,MergeTest)524 TEST_F(JsonDomTest, MergeTest)
525 {
526 // merge 2 scalars
527 {
528 SCOPED_TRACE("");
529 vet_merge((char *) "1", (char *) "true", "[1, true]");
530 }
531
532 // merge a scalar with an array
533 {
534 SCOPED_TRACE("");
535 vet_merge((char *) "1", (char *) "[true, false]", "[1, true, false]");
536 }
537
538 // merge an array with a scalar
539 {
540 SCOPED_TRACE("");
541 vet_merge((char *) "[true, false]", (char *) "1", "[true, false, 1]");
542 }
543
544 // merge a scalar with an object
545 {
546 SCOPED_TRACE("");
547 vet_merge((char *) "1", (char *) "{\"a\": 2}", "[1, {\"a\": 2}]");
548 }
549
550 // merge an object with a scalar
551 {
552 SCOPED_TRACE("");
553 vet_merge((char *) "{\"a\": 2}", (char *) "1", "[{\"a\": 2}, 1]");
554 }
555
556 // merge 2 arrays
557 {
558 SCOPED_TRACE("");
559 vet_merge((char *) "[1, 2]", (char *) "[3, 4]", "[1, 2, 3, 4]");
560 }
561
562 // merge 2 objects
563 {
564 SCOPED_TRACE("");
565 vet_merge((char *) "{\"a\": 1, \"b\": 2 }",
566 (char *) "{\"c\": 3, \"d\": 4 }",
567 "{\"a\": 1, \"b\": 2, \"c\": 3, \"d\": 4}");
568 }
569
570 // merge an array with an object
571 {
572 SCOPED_TRACE("");
573 vet_merge((char *) "[1, 2]",
574 (char *) "{\"c\": 3, \"d\": 4 }",
575 "[1, 2, {\"c\": 3, \"d\": 4}]");
576 }
577
578 // merge an object with an array
579 {
580 SCOPED_TRACE("");
581 vet_merge((char *) "{\"c\": 3, \"d\": 4 }",
582 (char *) "[1, 2]",
583 "[{\"c\": 3, \"d\": 4}, 1, 2]");
584 }
585
586 // merge two objects which share a key. scalar + scalar
587 {
588 SCOPED_TRACE("");
589 vet_merge((char *) "{\"a\": 1, \"b\": 2 }",
590 (char *) "{\"b\": 3, \"d\": 4 }",
591 "{\"a\": 1, \"b\": [2, 3], \"d\": 4}");
592 }
593
594 // merge two objects which share a key. scalar + array
595 {
596 SCOPED_TRACE("");
597 vet_merge((char *) "{\"a\": 1, \"b\": 2 }",
598 (char *) "{\"b\": [3, 4], \"d\": 4 }",
599 "{\"a\": 1, \"b\": [2, 3, 4], \"d\": 4}");
600 }
601
602 // merge two objects which share a key. array + scalar
603 {
604 SCOPED_TRACE("");
605 vet_merge((char *) "{\"a\": 1, \"b\": [2, 3] }",
606 (char *) "{\"b\": 4, \"d\": 4 }",
607 "{\"a\": 1, \"b\": [2, 3, 4], \"d\": 4}");
608 }
609
610 // merge two objects which share a key. scalar + object
611 {
612 SCOPED_TRACE("");
613 vet_merge((char *) "{\"a\": 1, \"b\": 2 }",
614 (char *) "{\"b\": {\"e\": 7, \"f\": 8}, \"d\": 4 }",
615 "{\"a\": 1, \"b\": [2, {\"e\": 7, \"f\": 8}], \"d\": 4}");
616 }
617
618 // merge two objects which share a key. object + scalar
619 {
620 SCOPED_TRACE("");
621 vet_merge((char *) (char *) "{\"b\": {\"e\": 7, \"f\": 8}, \"d\": 4 }",
622 (char *) "{\"a\": 1, \"b\": 2 }",
623 "{\"a\": 1, \"b\": [{\"e\": 7, \"f\": 8}, 2], \"d\": 4}");
624 }
625
626 // merge two objects which share a key. array + array
627 {
628 SCOPED_TRACE("");
629 vet_merge((char *) "{\"a\": 1, \"b\": [2, 9] }",
630 (char *) "{\"b\": [10, 11], \"d\": 4 }",
631 "{\"a\": 1, \"b\": [2, 9, 10, 11], \"d\": 4}");
632 }
633
634 // merge two objects which share a key. array + object
635 {
636 SCOPED_TRACE("");
637 vet_merge((char *) "{\"a\": 1, \"b\": [2, 9] }",
638 (char *) "{\"b\": {\"e\": 7, \"f\": 8}, \"d\": 4 }",
639 "{\"a\": 1, \"b\": [2, 9, {\"e\": 7, \"f\": 8}], \"d\": 4}");
640 }
641
642 // merge two objects which share a key. object + array
643 {
644 SCOPED_TRACE("");
645 vet_merge((char *) (char *) "{\"b\": {\"e\": 7, \"f\": 8}, \"d\": 4 }",
646 (char *) "{\"a\": 1, \"b\": [2, 9] }",
647 "{\"a\": 1, \"b\": [{\"e\": 7, \"f\": 8}, 2, 9], \"d\": 4}");
648 }
649
650 // merge two objects which share a key. object + object
651 {
652 SCOPED_TRACE("");
653 vet_merge((char *) (char *) "{\"b\": {\"e\": 7, \"f\": 8}, \"d\": 4 }",
654 (char *) "{\"a\": 1, \"b\": {\"e\": 20, \"g\": 21 } }",
655 "{\"a\": 1, \"b\": {\"e\": [7, 20], \"f\": 8, \"g\": 21}, "
656 "\"d\": 4}");
657 }
658 }
659
660 } // namespace
661