1/* JSON trees
2 Copyright (C) 2017-2025 Free Software Foundation, Inc.
3 Contributed by David Malcolm <dmalcolm@redhat.com>.
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free
9Software Foundation; either version 3, or (at your option) any later
10version.
11
12GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15for more details.
16
17You should have received a copy of the GNU General Public License
18along with GCC; see the file COPYING3. If not see
19<http://www.gnu.org/licenses/>. */
20
21#include "config.h"
22#include "system.h"
23#include "coretypes.h"
24#include "json.h"
25#include "pretty-print.h"
26#include "math.h"
27#include "selftest.h"
28
29using namespace json;
30
31/* Print a JSON string to PP, escaping '"', control characters,
32 and embedded null bytes.
33 The string is required to be UTF-8 encoded. */
34
35static void
36print_escaped_json_string (pretty_printer *pp,
37 const char *utf8_str,
38 size_t len)
39{
40 pp_character (pp, '"');
41 for (size_t i = 0; i != len; ++i)
42 {
43 char ch = utf8_str[i];
44 switch (ch)
45 {
46 case '"':
47 pp_string (pp, "\\\"");
48 break;
49 case '\\':
50 pp_string (pp, "\\\\");
51 break;
52 case '\b':
53 pp_string (pp, "\\b");
54 break;
55 case '\f':
56 pp_string (pp, "\\f");
57 break;
58 case '\n':
59 pp_string (pp, "\\n");
60 break;
61 case '\r':
62 pp_string (pp, "\\r");
63 break;
64 case '\t':
65 pp_string (pp, "\\t");
66 break;
67 case '\0':
68 pp_string (pp, "\\0");
69 break;
70 default:
71 pp_character (pp, ch);
72 }
73 }
74 pp_character (pp, '"');
75}
76
77/* class pointer::token. */
78
79pointer::token::token ()
80{
81 m_parent = nullptr;
82 m_data.u_member = nullptr;
83 m_kind = kind::root_value;
84}
85
86pointer::token::token (json::object &parent, const char *member)
87{
88 m_parent = &parent;
89 m_data.u_member = xstrdup (member); // ideally we'd share
90 m_kind = kind::object_member;
91}
92
93pointer::token::token (json::array &parent, size_t index)
94{
95 m_parent = &parent;
96 m_data.u_index = index;
97 m_kind = kind::array_index;
98}
99
100pointer::token::~token ()
101{
102 if (m_kind == kind::object_member)
103 {
104 gcc_assert (m_data.u_member);
105 free (ptr: m_data.u_member);
106 }
107}
108
109pointer::token &
110pointer::token::operator= (pointer::token &&other)
111{
112 m_parent = other.m_parent;
113 m_data = other.m_data;
114 m_kind = other.m_kind;
115
116 other.m_parent = nullptr;
117 other.m_data.u_member = nullptr;
118 other.m_kind = kind::root_value;
119
120 return *this;
121}
122
123/* class json::value. */
124
125/* Dump this json::value tree to OUTF.
126
127 The key/value pairs of json::objects are printed in the order
128 in which the keys were originally inserted. */
129
130void
131value::dump (FILE *outf, bool formatted) const
132{
133 pretty_printer pp;
134 pp_buffer (pp: &pp)->m_stream = outf;
135 print (pp: &pp, formatted);
136 pp_flush (&pp);
137}
138
139/* A convenience function for debugging.
140 Dump to stderr with formatting, and a trailing newline. */
141
142void
143value::dump () const
144{
145 dump (stderr, formatted: true);
146 fprintf (stderr, format: "\n");
147}
148
149/* A deterministic total ordering for comparing json values, so that we
150 can e.g. put them in std::map.
151
152 This is intended to follow the condition for equality described in
153 the JSON Schema standard (§4.3, “Instance equality”), as referenced
154 by SARIF v2.1.0 (§3.7.3 "Array properties with unique values"), but has
155 the following limitations:
156 - numbers are supposed to be checked for "the same mathematical value",
157 but in this implementation int vs float numbers won't compare as equal,
158 and float number comparison is bitwise
159 - strings are supposed to be "the same codepoint-for-codepoint", but
160 this implementation doesn't take into account canonicalization issues. */
161
162int
163value::compare (const value &val_a, const value &val_b)
164{
165 enum kind kind_a = val_a.get_kind ();
166 enum kind kind_b = val_b.get_kind ();
167 if (kind_a != kind_b)
168 return (int)kind_a - (int)kind_b;
169
170 switch (kind_a)
171 {
172 default:
173 gcc_unreachable ();
174
175 case JSON_OBJECT:
176 {
177 const object &obj_a = (const object &)val_a;
178 const object &obj_b = (const object &)val_b;
179 return object::compare (obj_a, obj_b);
180 }
181 break;
182
183 case JSON_ARRAY:
184 {
185 const array &arr_a = (const array &)val_a;
186 const array &arr_b = (const array &)val_b;
187 if (int cmp_size = (int)arr_a.size () - (int)arr_b.size ())
188 return cmp_size;
189 for (size_t idx = 0; idx < arr_a.size (); ++idx)
190 if (int cmp_element = compare (val_a: *arr_a[idx], val_b: *arr_b[idx]))
191 return cmp_element;
192 return 0;
193 }
194 break;
195
196 case JSON_INTEGER:
197 {
198 const integer_number &int_a = (const integer_number &)val_a;
199 const integer_number &int_b = (const integer_number &)val_b;
200 return int_a.get () - int_b.get ();
201 }
202 break;
203
204 case JSON_FLOAT:
205 {
206 const float_number &float_a = (const float_number &)val_a;
207 const float_number &float_b = (const float_number &)val_b;
208 union u
209 {
210 double u_double;
211 char u_buf[sizeof(double)];
212 };
213 union u u_a, u_b;
214 u_a.u_double = float_a.get ();
215 u_b.u_double = float_b.get ();
216 return memcmp (s1: &u_a, s2: &u_b, n: sizeof(double));
217 }
218 break;
219
220 case JSON_STRING:
221 {
222 const string &str_a = (const string &)val_a;
223 const string &str_b = (const string &)val_b;
224 return strcmp (s1: str_a.get_string (), s2: str_b.get_string ());
225 }
226 break;
227
228 case JSON_TRUE:
229 case JSON_FALSE:
230 case JSON_NULL:
231 /* All instances of literals compare equal to instances
232 of the same literal. */
233 return 0;
234 }
235}
236
237/* class json::object, a subclass of json::value, representing
238 an ordered collection of key/value pairs. */
239
240/* json:object's dtor. */
241
242object::~object ()
243{
244 for (map_t::iterator it = m_map.begin (); it != m_map.end (); ++it)
245 {
246 free (ptr: const_cast <char *>((*it).first));
247 delete ((*it).second);
248 }
249}
250
251/* Implementation of json::value::print for json::object. */
252
253void
254object::print (pretty_printer *pp, bool formatted) const
255{
256 pp_character (pp, '{');
257 if (formatted)
258 pp_indentation (pp) += 1;
259
260 /* Iterate in the order that the keys were inserted. */
261 unsigned i;
262 const char *key;
263 FOR_EACH_VEC_ELT (m_keys, i, key)
264 {
265 if (i > 0)
266 {
267 pp_string (pp, ",");
268 if (formatted)
269 {
270 pp_newline (pp);
271 pp_indent (pp);
272 }
273 else
274 pp_space (pp);
275 }
276 map_t &mut_map = const_cast<map_t &> (m_map);
277 value *value = *mut_map.get (k: key);
278 print_escaped_json_string (pp, utf8_str: key, len: strlen (s: key));
279 pp_string (pp, ": ");
280 const int indent = strlen (s: key) + 4;
281 if (formatted)
282 pp_indentation (pp) += indent;
283 value->print (pp, formatted);
284 if (formatted)
285 pp_indentation (pp) -= indent;
286 }
287 if (formatted)
288 pp_indentation (pp) -= 1;
289 pp_character (pp, '}');
290}
291
292/* Set the json::value * for KEY, taking ownership of V
293 (and taking a copy of KEY if necessary). */
294
295void
296object::set (const char *key, value *v)
297{
298 gcc_assert (key);
299 gcc_assert (v);
300
301 value **ptr = m_map.get (k: key);
302 if (ptr)
303 {
304 /* If the key is already present, delete the existing value
305 and overwrite it. */
306 delete *ptr;
307 *ptr = v;
308 }
309 else
310 {
311 /* If the key wasn't already present, take a copy of the key,
312 and store the value. */
313 char *owned_key = xstrdup (key);
314 m_map.put (k: owned_key, v);
315 m_keys.safe_push (obj: owned_key);
316 }
317
318 v->m_pointer_token = pointer::token (*this, key);
319}
320
321/* Get the json::value * for KEY.
322
323 The object retains ownership of the value. */
324
325value *
326object::get (const char *key) const
327{
328 gcc_assert (key);
329
330 value **ptr = const_cast <map_t &> (m_map).get (k: key);
331 if (ptr)
332 return *ptr;
333 else
334 return NULL;
335}
336
337/* Set value of KEY within this object to a JSON
338 string value based on UTF8_VALUE. */
339
340void
341object::set_string (const char *key, const char *utf8_value)
342{
343 set (key, v: new json::string (utf8_value));
344}
345
346/* Set value of KEY within this object to a JSON
347 integer value based on V. */
348
349void
350object::set_integer (const char *key, long v)
351{
352 set (key, v: new json::integer_number (v));
353}
354
355/* Set value of KEY within this object to a JSON
356 floating point value based on V. */
357
358void
359object::set_float (const char *key, double v)
360{
361 set (key, v: new json::float_number (v));
362}
363
364/* Set value of KEY within this object to the JSON
365 literal true or false, based on V. */
366
367void
368object::set_bool (const char *key, bool v)
369{
370 set (key, v: new json::literal (v));
371}
372
373/* Subroutine of json::compare for comparing a pairs of objects. */
374
375int
376object::compare (const json::object &obj_a, const json::object &obj_b)
377{
378 if (int cmp_size = (int)obj_a.m_keys.length () - (int)obj_b.m_keys.length ())
379 return cmp_size;
380
381 for (auto iter_a : obj_a.m_map)
382 {
383 const char *key = iter_a.first;
384 const value *value_a = iter_a.second;
385 gcc_assert (value_a);
386
387 const value *value_b = obj_b.get (key);
388 if (!value_b)
389 /* Key is in OBJ_A but not in OBJ_B. */
390 return 1;
391 /* If key is OBJ_B but not in OBJ_A, then the
392 count of keys will have been different, or
393 OBJ_A would have had a key not in OBJ_B. */
394 if (int cmp_value = value::compare (val_a: *value_a, val_b: *value_b))
395 /* Values for key are non-equal. */
396 return cmp_value;
397 }
398
399 /* Objects are equal. */
400 return 0;
401}
402
403/* class json::array, a subclass of json::value, representing
404 an ordered collection of values. */
405
406/* json::array's dtor. */
407
408array::~array ()
409{
410 unsigned i;
411 value *v;
412 FOR_EACH_VEC_ELT (m_elements, i, v)
413 delete v;
414}
415
416/* Implementation of json::value::print for json::array. */
417
418void
419array::print (pretty_printer *pp, bool formatted) const
420{
421 pp_character (pp, '[');
422 if (formatted)
423 pp_indentation (pp) += 1;
424 unsigned i;
425 value *v;
426 FOR_EACH_VEC_ELT (m_elements, i, v)
427 {
428 if (i)
429 {
430 pp_string (pp, ",");
431 if (formatted)
432 {
433 pp_newline (pp);
434 pp_indent (pp);
435 }
436 else
437 pp_space (pp);
438 }
439 v->print (pp, formatted);
440 }
441 if (formatted)
442 pp_indentation (pp) -= 1;
443 pp_character (pp, ']');
444}
445
446/* Append non-NULL value V to a json::array, taking ownership of V. */
447
448void
449array::append (value *v)
450{
451 gcc_assert (v);
452 v->m_pointer_token = pointer::token (*this, m_elements.length ());
453 m_elements.safe_push (obj: v);
454}
455
456void
457array::append_string (const char *utf8_value)
458{
459 gcc_assert (utf8_value);
460 append (v: new json::string (utf8_value));
461}
462
463/* class json::float_number, a subclass of json::value, wrapping a double. */
464
465/* Implementation of json::value::print for json::float_number. */
466
467void
468float_number::print (pretty_printer *pp,
469 bool formatted ATTRIBUTE_UNUSED) const
470{
471 char tmp[1024];
472 snprintf (s: tmp, maxlen: sizeof (tmp), format: "%g", m_value);
473 pp_string (pp, tmp);
474}
475
476/* class json::integer_number, a subclass of json::value, wrapping a long. */
477
478/* Implementation of json::value::print for json::integer_number. */
479
480void
481integer_number::print (pretty_printer *pp,
482 bool formatted ATTRIBUTE_UNUSED) const
483{
484 char tmp[1024];
485 snprintf (s: tmp, maxlen: sizeof (tmp), format: "%ld", m_value);
486 pp_string (pp, tmp);
487}
488
489
490/* class json::string, a subclass of json::value. */
491
492/* json::string's ctor. */
493
494string::string (const char *utf8)
495{
496 gcc_assert (utf8);
497 m_utf8 = xstrdup (utf8);
498 m_len = strlen (s: utf8);
499}
500
501string::string (const char *utf8, size_t len)
502{
503 gcc_assert (utf8);
504 m_utf8 = XNEWVEC (char, len);
505 m_len = len;
506 memcpy (dest: m_utf8, src: utf8, n: len);
507}
508
509/* Implementation of json::value::print for json::string. */
510
511void
512string::print (pretty_printer *pp,
513 bool formatted ATTRIBUTE_UNUSED) const
514{
515 print_escaped_json_string (pp, utf8_str: m_utf8, len: m_len);
516}
517
518/* class json::literal, a subclass of json::value. */
519
520/* Implementation of json::value::print for json::literal. */
521
522void
523literal::print (pretty_printer *pp,
524 bool formatted ATTRIBUTE_UNUSED) const
525{
526 switch (m_kind)
527 {
528 case JSON_TRUE:
529 pp_string (pp, "true");
530 break;
531 case JSON_FALSE:
532 pp_string (pp, "false");
533 break;
534 case JSON_NULL:
535 pp_string (pp, "null");
536 break;
537 default:
538 gcc_unreachable ();
539 }
540}
541
542
543#if CHECKING_P
544
545namespace selftest {
546
547/* Selftests. */
548
549/* Verify that JV->print () prints EXPECTED_JSON. */
550
551void
552assert_print_eq (const location &loc,
553 const json::value &jv,
554 bool formatted,
555 const char *expected_json)
556{
557 pretty_printer pp;
558 jv.print (pp: &pp, formatted);
559 ASSERT_STREQ_AT (loc, expected_json, pp_formatted_text (&pp));
560}
561
562#define ASSERT_PRINT_EQ(JV, FORMATTED, EXPECTED_JSON) \
563 assert_print_eq (SELFTEST_LOCATION, JV, FORMATTED, EXPECTED_JSON)
564
565/* Verify that object::get works as expected. */
566
567static void
568test_object_get ()
569{
570 object obj;
571 value *val = new json::string ("value");
572 obj.set (key: "foo", v: val);
573 ASSERT_EQ (obj.get ("foo"), val);
574 ASSERT_EQ (obj.get ("not-present"), NULL);
575}
576
577/* Verify that JSON objects are written correctly. */
578
579static void
580test_writing_objects ()
581{
582 object obj;
583 obj.set_string (key: "foo", utf8_value: "bar");
584 obj.set_string (key: "baz", utf8_value: "quux");
585 obj.set_string (key: "\"\\\b\f\n\r\t", utf8_value: "value for awkward key");
586
587 /* This test relies on json::object writing out key/value pairs
588 in key-insertion order. */
589 ASSERT_PRINT_EQ (obj, true,
590 "{\"foo\": \"bar\",\n"
591 " \"baz\": \"quux\",\n"
592 " \"\\\"\\\\\\b\\f\\n\\r\\t\": \"value for awkward key\"}");
593 ASSERT_PRINT_EQ (obj, false,
594 "{\"foo\": \"bar\", \"baz\": \"quux\""
595 ", \"\\\"\\\\\\b\\f\\n\\r\\t\": \"value for awkward key\"}");
596}
597
598/* Verify that JSON arrays are written correctly. */
599
600static void
601test_writing_arrays ()
602{
603 array arr;
604 ASSERT_PRINT_EQ (arr, true, "[]");
605
606 arr.append (v: new json::string ("foo"));
607 ASSERT_PRINT_EQ (arr, true, "[\"foo\"]");
608
609 arr.append_string (utf8_value: "bar");
610 ASSERT_PRINT_EQ (arr, true,
611 "[\"foo\",\n"
612 " \"bar\"]");
613 ASSERT_PRINT_EQ (arr, false,
614 "[\"foo\", \"bar\"]");
615}
616
617/* Verify that JSON numbers are written correctly. */
618
619static void
620test_writing_float_numbers ()
621{
622 ASSERT_PRINT_EQ (float_number (0), true, "0");
623 ASSERT_PRINT_EQ (float_number (42), true, "42");
624 ASSERT_PRINT_EQ (float_number (-100), true, "-100");
625 ASSERT_PRINT_EQ (float_number (123456789), true, "1.23457e+08");
626}
627
628static void
629test_writing_integer_numbers ()
630{
631 ASSERT_PRINT_EQ (integer_number (0), true, "0");
632 ASSERT_PRINT_EQ (integer_number (42), true, "42");
633 ASSERT_PRINT_EQ (integer_number (-100), true, "-100");
634 ASSERT_PRINT_EQ (integer_number (123456789), true, "123456789");
635 ASSERT_PRINT_EQ (integer_number (-123456789), true, "-123456789");
636}
637
638/* Verify that JSON strings are written correctly. */
639
640static void
641test_writing_strings ()
642{
643 string foo ("foo");
644 ASSERT_PRINT_EQ (foo, true, "\"foo\"");
645
646 string contains_quotes ("before \"quoted\" after");
647 ASSERT_PRINT_EQ (contains_quotes, true, "\"before \\\"quoted\\\" after\"");
648
649 const char data[] = {'a', 'b', 'c', 'd', '\0', 'e', 'f'};
650 string not_terminated (data, 3);
651 ASSERT_PRINT_EQ (not_terminated, true, "\"abc\"");
652 string embedded_null (data, sizeof data);
653 ASSERT_PRINT_EQ (embedded_null, true, "\"abcd\\0ef\"");
654}
655
656/* Verify that JSON literals are written correctly. */
657
658static void
659test_writing_literals ()
660{
661 ASSERT_PRINT_EQ (literal (JSON_TRUE), true, "true");
662 ASSERT_PRINT_EQ (literal (JSON_FALSE), true, "false");
663 ASSERT_PRINT_EQ (literal (JSON_NULL), true, "null");
664
665 ASSERT_PRINT_EQ (literal (true), true, "true");
666 ASSERT_PRINT_EQ (literal (false), true, "false");
667}
668
669/* Verify that nested values are formatted correctly when written.
670
671 Also, make use of array::append(std::unique_ptr<value>) and
672 object::set (const char *key, std::unique_ptr<value> v).*/
673
674static void
675test_formatting ()
676{
677 object obj;
678 object *child = new object;
679 std::unique_ptr<object> grandchild = std::make_unique<object> ();
680
681 obj.set_string (key: "str", utf8_value: "bar");
682 obj.set (key: "child", v: child);
683 obj.set_integer (key: "int", v: 42);
684
685 array *arr = new array;
686 for (int i = 0; i < 3; i++)
687 arr->append (v: std::make_unique<integer_number> (args&: i));
688 grandchild->set (key: "arr", v: arr);
689 grandchild->set_integer (key: "int", v: 1066);
690
691 child->set (key: "grandchild", v: std::move (grandchild));
692 child->set_integer (key: "int", v: 1776);
693
694 /* This test relies on json::object writing out key/value pairs
695 in key-insertion order. */
696 ASSERT_PRINT_EQ (obj, true,
697 ("{\"str\": \"bar\",\n"
698 " \"child\": {\"grandchild\": {\"arr\": [0,\n"
699 " 1,\n"
700 " 2],\n"
701 " \"int\": 1066},\n"
702 " \"int\": 1776},\n"
703 " \"int\": 42}"));
704 ASSERT_PRINT_EQ (obj, false,
705 ("{\"str\": \"bar\", \"child\": {\"grandchild\":"
706 " {\"arr\": [0, 1, 2], \"int\": 1066},"
707 " \"int\": 1776}, \"int\": 42}"));
708}
709
710/* Helper function for reporting failure of JSON comparisons. */
711
712static void
713fail_comparison (const location &loc,
714 const char *desc,
715 const value &val_a, const value &val_b,
716 const char *desc_expected_value,
717 int actual_value)
718{
719 fprintf (stderr, format: "val_a: ");
720 val_a.dump ();
721
722 fprintf (stderr, format: "val_b: ");
723 val_b.dump ();
724
725 selftest::fail_formatted (loc,
726 fmt: "%s: failed JSON comparison:"
727 " expected: %s got: %i\n",
728 desc,
729 desc_expected_value, actual_value);
730}
731
732/* Implementation of ASSERT_JSON_EQ. */
733
734static void
735assert_json_equal (const location &loc,
736 const char *desc,
737 const value &val_a, const value &val_b)
738{
739 /* Comparison should return zero, both ways, indicating no differences. */
740 const int a_vs_b = value::compare (val_a, val_b);
741 if (a_vs_b != 0)
742 fail_comparison (loc, desc, val_a, val_b, desc_expected_value: "zero", actual_value: a_vs_b);
743
744 const int b_vs_a = value::compare (val_a: val_b, val_b: val_a);
745 if (b_vs_a != 0)
746 fail_comparison (loc, desc, val_a: val_b, val_b: val_a, desc_expected_value: "zero", actual_value: b_vs_a);
747}
748
749/* Verify that json::value::compare returns 0 ("no differences") on
750 VAL1 and VAL2, in both orders. */
751
752#define ASSERT_JSON_EQ(VAL1, VAL2) \
753 SELFTEST_BEGIN_STMT \
754 assert_json_equal ((SELFTEST_LOCATION), \
755 "ASSERT_JSON_EQ", \
756 (VAL1), (VAL2)); \
757 SELFTEST_END_STMT
758
759/* Implementation of ASSERT_JSON_NE. */
760
761static void
762assert_json_non_equal (const location &loc,
763 const char *desc,
764 const value &val_a, const value &val_b)
765{
766 /* Comparison should be non-zero, indicating differences. */
767 const int a_vs_b = value::compare (val_a, val_b);
768 if (a_vs_b == 0)
769 fail_comparison (loc, desc, val_a, val_b, desc_expected_value: "non-zero", actual_value: a_vs_b);
770
771 const int b_vs_a = value::compare (val_a: val_b, val_b: val_a);
772 ASSERT_NE_AT (loc, b_vs_a, 0);
773 if (b_vs_a == 0)
774 fail_comparison (loc, desc, val_a: val_b, val_b: val_a, desc_expected_value: "non-zero", actual_value: b_vs_a);
775
776 /* Swapping the args should swap the sign of the result
777 (but isn't necessarily the negation). */
778 if ( (a_vs_b > 0) == (b_vs_a > 0) )
779 fail_comparison (loc, desc, val_a: val_b, val_b: val_a, desc_expected_value: "opposite signs", actual_value: 1);
780}
781
782/* Verify that json::value::compare returns non-zero ("different") on
783 VAL1 and VAL2, in both orders, and that they have opposite
784 sign. */
785
786#define ASSERT_JSON_NE(VAL1, VAL2) \
787 SELFTEST_BEGIN_STMT \
788 assert_json_non_equal ((SELFTEST_LOCATION), \
789 "ASSERT_JSON_NE", \
790 (VAL1), (VAL2)); \
791 SELFTEST_END_STMT
792
793/* Verify that json::value::compare works as expected. */
794
795static void
796test_comparisons ()
797{
798 /* Literals. */
799
800 literal null_lit (JSON_NULL);
801 ASSERT_JSON_EQ (null_lit, null_lit);
802
803 literal other_null_lit (JSON_NULL);
804 ASSERT_JSON_EQ (null_lit, other_null_lit);
805
806 literal true_lit (JSON_TRUE);
807 ASSERT_JSON_EQ (true_lit, true_lit);
808 ASSERT_JSON_NE (true_lit, null_lit);
809
810 literal false_lit (JSON_FALSE);
811 ASSERT_JSON_EQ (false_lit, false_lit);
812 ASSERT_JSON_NE (false_lit, true_lit);
813 ASSERT_JSON_NE (false_lit, null_lit);
814
815 /* Strings. */
816 string str_foo_1 ("foo");
817 ASSERT_JSON_EQ (str_foo_1, str_foo_1);
818
819 string str_foo_2 ("foo");
820 ASSERT_JSON_EQ (str_foo_1, str_foo_2);
821
822 string str_bar ("bar");
823 ASSERT_JSON_NE (str_bar, str_foo_1);
824
825 /* Numbers. */
826 integer_number i_42 (42);
827 ASSERT_JSON_EQ (i_42, i_42);
828 integer_number i_42_2 (42);
829 ASSERT_JSON_EQ (i_42, i_42_2);
830 integer_number i_43 (43);
831 ASSERT_JSON_NE (i_42, i_43);
832
833 float_number f_zero (0.0);
834 ASSERT_JSON_EQ (f_zero, f_zero);
835 float_number f_zero_2 (0.0);
836 ASSERT_JSON_EQ (f_zero, f_zero_2);
837 float_number f_one (1.0);
838 ASSERT_JSON_NE (f_zero, f_one);
839 /* We don't yet test the more awkward cases e.g. NaN. */
840
841 /* Objects. */
842
843 // Empty object
844 // Self comparison should be 0
845 object empty_obj_a;
846 ASSERT_JSON_EQ (empty_obj_a, empty_obj_a);
847
848 // Instances of empty objects should compare equal to each other
849 object empty_obj_b;
850 ASSERT_JSON_EQ (empty_obj_a, empty_obj_b);
851
852 // Object with one field:
853 object obj_1;
854 obj_1.set_string (key: "foo", utf8_value: "bar");
855 // Self comparison should be 0
856 ASSERT_JSON_EQ (obj_1, obj_1);
857
858 // but should be different to an empty object:
859 ASSERT_JSON_NE (obj_1, empty_obj_a);
860
861 // Another with one field, with same key/value:
862 object obj_2;
863 obj_2.set_string (key: "foo", utf8_value: "bar");
864 ASSERT_JSON_EQ (obj_1, obj_2);
865
866 // Same key, different value:
867 object obj_3;
868 obj_3.set_string (key: "foo", utf8_value: "baz");
869 ASSERT_JSON_NE (obj_1, obj_3);
870
871 // Adding an extra property:
872 obj_2.set_integer (key: "year", v: 1066);
873 ASSERT_JSON_NE (obj_1, obj_2);
874
875 /* Different insertion order, but same k-v pairs should be equal,
876 despite having different serialization. */
877 object obj_4;
878 obj_4.set_integer (key: "year", v: 1066);
879 obj_4.set_string (key: "foo", utf8_value: "bar");
880 ASSERT_JSON_EQ (obj_2, obj_4);
881 ASSERT_PRINT_EQ (obj_2, false, "{\"foo\": \"bar\", \"year\": 1066}");
882 ASSERT_PRINT_EQ (obj_4, false, "{\"year\": 1066, \"foo\": \"bar\"}");
883
884 /* Arrays. */
885
886 // Empty array
887 array empty_arr_a;
888 // Self comparison should be 0
889 ASSERT_JSON_EQ (empty_arr_a, empty_arr_a);
890
891 // Objects and arrays are different
892 ASSERT_JSON_NE (empty_obj_a, empty_arr_a);
893
894 // Instances of empty arrays should compare equal to each other
895 array empty_arr_b;
896 ASSERT_JSON_EQ (empty_arr_a, empty_arr_b);
897
898 // Array with one element:
899 array arr_1;
900 arr_1.append (v: std::make_unique<string> (args: "foo"));
901 // Self comparison should be 0
902 ASSERT_JSON_EQ (arr_1, arr_1);
903
904 // but should be different to an empty array:
905 ASSERT_JSON_NE (arr_1, empty_arr_a);
906
907 // Another with one element:
908 array arr_2;
909 arr_2.append (v: std::make_unique<string> (args: "foo"));
910 ASSERT_JSON_EQ (arr_1, arr_2);
911
912 // Adding an extra element:
913 arr_2.append (v: std::make_unique<string> (args: "bar"));
914 ASSERT_JSON_NE (arr_1, arr_2);
915}
916
917/* Run all of the selftests within this file. */
918
919void
920json_cc_tests ()
921{
922 test_object_get ();
923 test_writing_objects ();
924 test_writing_arrays ();
925 test_writing_float_numbers ();
926 test_writing_integer_numbers ();
927 test_writing_strings ();
928 test_writing_literals ();
929 test_formatting ();
930 test_comparisons ();
931}
932
933} // namespace selftest
934
935#endif /* #if CHECKING_P */
936

source code of gcc/json.cc