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