1/* JSON trees
2 Copyright (C) 2017-2026 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
292std::unique_ptr<value>
293object::clone () const
294{
295 return clone_as_object ();
296}
297
298std::unique_ptr<object>
299object::clone_as_object () const
300{
301 auto result = std::make_unique<object> ();
302
303 /* Iterate in the order that the keys were inserted. */
304 unsigned i;
305 const char *key;
306 FOR_EACH_VEC_ELT (m_keys, i, key)
307 {
308 map_t &mut_map = const_cast<map_t &> (m_map);
309 value *value = *mut_map.get (k: key);
310 result->set (key, v: value->clone ());
311 }
312
313 return result;
314}
315
316/* Set the json::value * for KEY, taking ownership of V
317 (and taking a copy of KEY if necessary). */
318
319void
320object::set (const char *key, value *v)
321{
322 gcc_assert (key);
323 gcc_assert (v);
324
325 value **ptr = m_map.get (k: key);
326 if (ptr)
327 {
328 /* If the key is already present, delete the existing value
329 and overwrite it. */
330 delete *ptr;
331 *ptr = v;
332 }
333 else
334 {
335 /* If the key wasn't already present, take a copy of the key,
336 and store the value. */
337 char *owned_key = xstrdup (key);
338 m_map.put (k: owned_key, v);
339 m_keys.safe_push (obj: owned_key);
340 }
341
342 v->m_pointer_token = pointer::token (*this, key);
343}
344
345/* Get the json::value * for KEY.
346
347 The object retains ownership of the value. */
348
349value *
350object::get (const char *key) const
351{
352 gcc_assert (key);
353
354 value **ptr = const_cast <map_t &> (m_map).get (k: key);
355 if (ptr)
356 return *ptr;
357 else
358 return NULL;
359}
360
361/* Set value of KEY within this object to a JSON
362 string value based on UTF8_VALUE. */
363
364void
365object::set_string (const char *key, const char *utf8_value)
366{
367 set (key, v: new json::string (utf8_value));
368}
369
370/* Set value of KEY within this object to a JSON
371 integer value based on V. */
372
373void
374object::set_integer (const char *key, long v)
375{
376 set (key, v: new json::integer_number (v));
377}
378
379/* Set value of KEY within this object to a JSON
380 floating point value based on V. */
381
382void
383object::set_float (const char *key, double v)
384{
385 set (key, v: new json::float_number (v));
386}
387
388/* Set value of KEY within this object to the JSON
389 literal true or false, based on V. */
390
391void
392object::set_bool (const char *key, bool v)
393{
394 set (key, v: new json::literal (v));
395}
396
397void
398object::set_string (const string_property &property, const char *utf8_value)
399{
400 set_string (key: property.m_key.get (), utf8_value);
401}
402
403void
404object::set_integer (const integer_property &property, long value)
405{
406 set_integer (key: property.m_key.get (), v: value);
407}
408
409void
410object::set_bool (const bool_property &property, bool value)
411{
412 set_bool (key: property.m_key.get (), v: value);
413}
414
415void
416object::set_array_of_string (const array_of_string_property &property,
417 std::unique_ptr<json::array> value)
418{
419 set<array> (key: property.m_key.get (), v: std::move (value));
420}
421
422/* Subroutine of json::compare for comparing a pairs of objects. */
423
424int
425object::compare (const json::object &obj_a, const json::object &obj_b)
426{
427 if (int cmp_size = (int)obj_a.m_keys.length () - (int)obj_b.m_keys.length ())
428 return cmp_size;
429
430 for (auto iter_a : obj_a.m_map)
431 {
432 const char *key = iter_a.first;
433 const value *value_a = iter_a.second;
434 gcc_assert (value_a);
435
436 const value *value_b = obj_b.get (key);
437 if (!value_b)
438 /* Key is in OBJ_A but not in OBJ_B. */
439 return 1;
440 /* If key is OBJ_B but not in OBJ_A, then the
441 count of keys will have been different, or
442 OBJ_A would have had a key not in OBJ_B. */
443 if (int cmp_value = value::compare (val_a: *value_a, val_b: *value_b))
444 /* Values for key are non-equal. */
445 return cmp_value;
446 }
447
448 /* Objects are equal. */
449 return 0;
450}
451
452/* class json::array, a subclass of json::value, representing
453 an ordered collection of values. */
454
455/* json::array's dtor. */
456
457array::~array ()
458{
459 unsigned i;
460 value *v;
461 FOR_EACH_VEC_ELT (m_elements, i, v)
462 delete v;
463}
464
465/* Implementation of json::value::print for json::array. */
466
467void
468array::print (pretty_printer *pp, bool formatted) const
469{
470 pp_character (pp, '[');
471 if (formatted)
472 pp_indentation (pp) += 1;
473 unsigned i;
474 value *v;
475 FOR_EACH_VEC_ELT (m_elements, i, v)
476 {
477 if (i)
478 {
479 pp_string (pp, ",");
480 if (formatted)
481 {
482 pp_newline (pp);
483 pp_indent (pp);
484 }
485 else
486 pp_space (pp);
487 }
488 v->print (pp, formatted);
489 }
490 if (formatted)
491 pp_indentation (pp) -= 1;
492 pp_character (pp, ']');
493}
494
495std::unique_ptr<value>
496array::clone () const
497{
498 auto result = std::make_unique<array> ();
499 unsigned i;
500 value *v;
501 FOR_EACH_VEC_ELT (m_elements, i, v)
502 result->append (v: v->clone ());
503 return result;
504}
505
506/* Append non-NULL value V to a json::array, taking ownership of V. */
507
508void
509array::append (value *v)
510{
511 gcc_assert (v);
512 v->m_pointer_token = pointer::token (*this, m_elements.length ());
513 m_elements.safe_push (obj: v);
514}
515
516void
517array::append_string (const char *utf8_value)
518{
519 gcc_assert (utf8_value);
520 append (v: new json::string (utf8_value));
521}
522
523/* class json::float_number, a subclass of json::value, wrapping a double. */
524
525/* Implementation of json::value::print for json::float_number. */
526
527void
528float_number::print (pretty_printer *pp,
529 bool formatted ATTRIBUTE_UNUSED) const
530{
531 char tmp[1024];
532 snprintf (s: tmp, maxlen: sizeof (tmp), format: "%g", m_value);
533 pp_string (pp, tmp);
534}
535
536std::unique_ptr<value>
537float_number::clone () const
538{
539 return std::make_unique<float_number> (args: m_value);
540}
541
542/* class json::integer_number, a subclass of json::value, wrapping a long. */
543
544/* Implementation of json::value::print for json::integer_number. */
545
546void
547integer_number::print (pretty_printer *pp,
548 bool formatted ATTRIBUTE_UNUSED) const
549{
550 char tmp[1024];
551 snprintf (s: tmp, maxlen: sizeof (tmp), format: "%ld", m_value);
552 pp_string (pp, tmp);
553}
554
555std::unique_ptr<value>
556integer_number::clone () const
557{
558 return std::make_unique<integer_number> (args: m_value);
559}
560
561/* class json::string, a subclass of json::value. */
562
563/* json::string's ctor. */
564
565string::string (const char *utf8)
566{
567 gcc_assert (utf8);
568 m_utf8 = xstrdup (utf8);
569 m_len = strlen (s: utf8);
570}
571
572string::string (const char *utf8, size_t len)
573{
574 gcc_assert (utf8);
575 m_utf8 = XNEWVEC (char, len + 1);
576 m_len = len;
577 memcpy (dest: m_utf8, src: utf8, n: len);
578 m_utf8[len] = '\0';
579}
580
581/* Implementation of json::value::print for json::string. */
582
583void
584string::print (pretty_printer *pp,
585 bool formatted ATTRIBUTE_UNUSED) const
586{
587 print_escaped_json_string (pp, utf8_str: m_utf8, len: m_len);
588}
589
590std::unique_ptr<value>
591string::clone () const
592{
593 return std::make_unique<string> (args: m_utf8, args: m_len);
594}
595
596/* class json::literal, a subclass of json::value. */
597
598/* Implementation of json::value::print for json::literal. */
599
600void
601literal::print (pretty_printer *pp,
602 bool formatted ATTRIBUTE_UNUSED) const
603{
604 switch (m_kind)
605 {
606 case JSON_TRUE:
607 pp_string (pp, "true");
608 break;
609 case JSON_FALSE:
610 pp_string (pp, "false");
611 break;
612 case JSON_NULL:
613 pp_string (pp, "null");
614 break;
615 default:
616 gcc_unreachable ();
617 }
618}
619
620std::unique_ptr<value>
621literal::clone () const
622{
623 return std::make_unique<literal> (args: m_kind);
624}
625
626
627#if CHECKING_P
628
629namespace selftest {
630
631/* Selftests. */
632
633/* Verify that JV->print () prints EXPECTED_JSON. */
634
635void
636assert_print_eq (const location &loc,
637 const json::value &jv,
638 bool formatted,
639 const char *expected_json)
640{
641 pretty_printer pp;
642 jv.print (pp: &pp, formatted);
643 ASSERT_STREQ_AT (loc, expected_json, pp_formatted_text (&pp));
644}
645
646#define ASSERT_PRINT_EQ(JV, FORMATTED, EXPECTED_JSON) \
647 assert_print_eq (SELFTEST_LOCATION, JV, FORMATTED, EXPECTED_JSON)
648
649/* Verify that object::get works as expected. */
650
651static void
652test_object_get ()
653{
654 object obj;
655 value *val = new json::string ("value");
656 obj.set (key: "foo", v: val);
657 ASSERT_EQ (obj.get ("foo"), val);
658 ASSERT_EQ (obj.get ("not-present"), NULL);
659}
660
661/* Verify that JSON objects are written correctly. */
662
663static void
664test_writing_objects ()
665{
666 object obj;
667 obj.set_string (key: "foo", utf8_value: "bar");
668 obj.set_string (key: "baz", utf8_value: "quux");
669 obj.set_string (key: "\"\\\b\f\n\r\t", utf8_value: "value for awkward key");
670
671 /* This test relies on json::object writing out key/value pairs
672 in key-insertion order. */
673 ASSERT_PRINT_EQ (obj, true,
674 "{\"foo\": \"bar\",\n"
675 " \"baz\": \"quux\",\n"
676 " \"\\\"\\\\\\b\\f\\n\\r\\t\": \"value for awkward key\"}");
677 ASSERT_PRINT_EQ (obj, false,
678 "{\"foo\": \"bar\", \"baz\": \"quux\""
679 ", \"\\\"\\\\\\b\\f\\n\\r\\t\": \"value for awkward key\"}");
680}
681
682/* Verify that JSON arrays are written correctly. */
683
684static void
685test_writing_arrays ()
686{
687 array arr;
688 ASSERT_PRINT_EQ (arr, true, "[]");
689
690 arr.append (v: new json::string ("foo"));
691 ASSERT_PRINT_EQ (arr, true, "[\"foo\"]");
692
693 arr.append_string (utf8_value: "bar");
694 ASSERT_PRINT_EQ (arr, true,
695 "[\"foo\",\n"
696 " \"bar\"]");
697 ASSERT_PRINT_EQ (arr, false,
698 "[\"foo\", \"bar\"]");
699}
700
701/* Verify that JSON numbers are written correctly. */
702
703static void
704test_writing_float_numbers ()
705{
706 ASSERT_PRINT_EQ (float_number (0), true, "0");
707 ASSERT_PRINT_EQ (float_number (42), true, "42");
708 ASSERT_PRINT_EQ (float_number (-100), true, "-100");
709 ASSERT_PRINT_EQ (float_number (123456789), true, "1.23457e+08");
710}
711
712static void
713test_writing_integer_numbers ()
714{
715 ASSERT_PRINT_EQ (integer_number (0), true, "0");
716 ASSERT_PRINT_EQ (integer_number (42), true, "42");
717 ASSERT_PRINT_EQ (integer_number (-100), true, "-100");
718 ASSERT_PRINT_EQ (integer_number (123456789), true, "123456789");
719 ASSERT_PRINT_EQ (integer_number (-123456789), true, "-123456789");
720}
721
722/* Verify that JSON strings are written correctly. */
723
724static void
725test_writing_strings ()
726{
727 string foo ("foo");
728 ASSERT_PRINT_EQ (foo, true, "\"foo\"");
729
730 string contains_quotes ("before \"quoted\" after");
731 ASSERT_PRINT_EQ (contains_quotes, true, "\"before \\\"quoted\\\" after\"");
732
733 const char data[] = {'a', 'b', 'c', 'd', '\0', 'e', 'f'};
734 string not_terminated (data, 3);
735 ASSERT_PRINT_EQ (not_terminated, true, "\"abc\"");
736 string embedded_null (data, sizeof data);
737 ASSERT_PRINT_EQ (embedded_null, true, "\"abcd\\0ef\"");
738}
739
740/* Verify that JSON literals are written correctly. */
741
742static void
743test_writing_literals ()
744{
745 ASSERT_PRINT_EQ (literal (JSON_TRUE), true, "true");
746 ASSERT_PRINT_EQ (literal (JSON_FALSE), true, "false");
747 ASSERT_PRINT_EQ (literal (JSON_NULL), true, "null");
748
749 ASSERT_PRINT_EQ (literal (true), true, "true");
750 ASSERT_PRINT_EQ (literal (false), true, "false");
751}
752
753/* Verify that nested values are formatted correctly when written.
754
755 Also, make use of array::append(std::unique_ptr<value>) and
756 object::set (const char *key, std::unique_ptr<value> v).*/
757
758static void
759test_formatting ()
760{
761 object obj;
762 object *child = new object;
763 std::unique_ptr<object> grandchild = std::make_unique<object> ();
764
765 obj.set_string (key: "str", utf8_value: "bar");
766 obj.set (key: "child", v: child);
767 obj.set_integer (key: "int", v: 42);
768
769 array *arr = new array;
770 for (int i = 0; i < 3; i++)
771 arr->append (v: std::make_unique<integer_number> (args&: i));
772 grandchild->set (key: "arr", v: arr);
773 grandchild->set_integer (key: "int", v: 1066);
774
775 child->set (key: "grandchild", v: std::move (grandchild));
776 child->set_integer (key: "int", v: 1776);
777
778 /* This test relies on json::object writing out key/value pairs
779 in key-insertion order. */
780 ASSERT_PRINT_EQ (obj, true,
781 ("{\"str\": \"bar\",\n"
782 " \"child\": {\"grandchild\": {\"arr\": [0,\n"
783 " 1,\n"
784 " 2],\n"
785 " \"int\": 1066},\n"
786 " \"int\": 1776},\n"
787 " \"int\": 42}"));
788 ASSERT_PRINT_EQ (obj, false,
789 ("{\"str\": \"bar\", \"child\": {\"grandchild\":"
790 " {\"arr\": [0, 1, 2], \"int\": 1066},"
791 " \"int\": 1776}, \"int\": 42}"));
792}
793
794/* Helper function for reporting failure of JSON comparisons. */
795
796static void
797fail_comparison (const location &loc,
798 const char *desc,
799 const value &val_a, const value &val_b,
800 const char *desc_expected_value,
801 int actual_value)
802{
803 fprintf (stderr, format: "val_a: ");
804 val_a.dump ();
805
806 fprintf (stderr, format: "val_b: ");
807 val_b.dump ();
808
809 selftest::fail_formatted (loc,
810 fmt: "%s: failed JSON comparison:"
811 " expected: %s got: %i\n",
812 desc,
813 desc_expected_value, actual_value);
814}
815
816/* Implementation of ASSERT_JSON_EQ. */
817
818static void
819assert_json_equal (const location &loc,
820 const char *desc,
821 const value &val_a, const value &val_b)
822{
823 /* Comparison should return zero, both ways, indicating no differences. */
824 const int a_vs_b = value::compare (val_a, val_b);
825 if (a_vs_b != 0)
826 fail_comparison (loc, desc, val_a, val_b, desc_expected_value: "zero", actual_value: a_vs_b);
827
828 const int b_vs_a = value::compare (val_a: val_b, val_b: val_a);
829 if (b_vs_a != 0)
830 fail_comparison (loc, desc, val_a: val_b, val_b: val_a, desc_expected_value: "zero", actual_value: b_vs_a);
831}
832
833/* Verify that json::value::compare returns 0 ("no differences") on
834 VAL1 and VAL2, in both orders. */
835
836#define ASSERT_JSON_EQ(VAL1, VAL2) \
837 SELFTEST_BEGIN_STMT \
838 assert_json_equal ((SELFTEST_LOCATION), \
839 "ASSERT_JSON_EQ", \
840 (VAL1), (VAL2)); \
841 SELFTEST_END_STMT
842
843/* Implementation of ASSERT_JSON_NE. */
844
845static void
846assert_json_non_equal (const location &loc,
847 const char *desc,
848 const value &val_a, const value &val_b)
849{
850 /* Comparison should be non-zero, indicating differences. */
851 const int a_vs_b = value::compare (val_a, val_b);
852 if (a_vs_b == 0)
853 fail_comparison (loc, desc, val_a, val_b, desc_expected_value: "non-zero", actual_value: a_vs_b);
854
855 const int b_vs_a = value::compare (val_a: val_b, val_b: val_a);
856 ASSERT_NE_AT (loc, b_vs_a, 0);
857 if (b_vs_a == 0)
858 fail_comparison (loc, desc, val_a: val_b, val_b: val_a, desc_expected_value: "non-zero", actual_value: b_vs_a);
859
860 /* Swapping the args should swap the sign of the result
861 (but isn't necessarily the negation). */
862 if ( (a_vs_b > 0) == (b_vs_a > 0) )
863 fail_comparison (loc, desc, val_a: val_b, val_b: val_a, desc_expected_value: "opposite signs", actual_value: 1);
864}
865
866/* Verify that json::value::compare returns non-zero ("different") on
867 VAL1 and VAL2, in both orders, and that they have opposite
868 sign. */
869
870#define ASSERT_JSON_NE(VAL1, VAL2) \
871 SELFTEST_BEGIN_STMT \
872 assert_json_non_equal ((SELFTEST_LOCATION), \
873 "ASSERT_JSON_NE", \
874 (VAL1), (VAL2)); \
875 SELFTEST_END_STMT
876
877/* Verify that json::value::compare works as expected. */
878
879static void
880test_comparisons ()
881{
882 /* Literals. */
883
884 literal null_lit (JSON_NULL);
885 ASSERT_JSON_EQ (null_lit, null_lit);
886
887 literal other_null_lit (JSON_NULL);
888 ASSERT_JSON_EQ (null_lit, other_null_lit);
889
890 literal true_lit (JSON_TRUE);
891 ASSERT_JSON_EQ (true_lit, true_lit);
892 ASSERT_JSON_NE (true_lit, null_lit);
893
894 literal false_lit (JSON_FALSE);
895 ASSERT_JSON_EQ (false_lit, false_lit);
896 ASSERT_JSON_NE (false_lit, true_lit);
897 ASSERT_JSON_NE (false_lit, null_lit);
898
899 /* Strings. */
900 string str_foo_1 ("foo");
901 ASSERT_JSON_EQ (str_foo_1, str_foo_1);
902
903 string str_foo_2 ("foo");
904 ASSERT_JSON_EQ (str_foo_1, str_foo_2);
905
906 string str_bar ("bar");
907 ASSERT_JSON_NE (str_bar, str_foo_1);
908
909 /* Numbers. */
910 integer_number i_42 (42);
911 ASSERT_JSON_EQ (i_42, i_42);
912 integer_number i_42_2 (42);
913 ASSERT_JSON_EQ (i_42, i_42_2);
914 integer_number i_43 (43);
915 ASSERT_JSON_NE (i_42, i_43);
916
917 float_number f_zero (0.0);
918 ASSERT_JSON_EQ (f_zero, f_zero);
919 float_number f_zero_2 (0.0);
920 ASSERT_JSON_EQ (f_zero, f_zero_2);
921 float_number f_one (1.0);
922 ASSERT_JSON_NE (f_zero, f_one);
923 /* We don't yet test the more awkward cases e.g. NaN. */
924
925 /* Objects. */
926
927 // Empty object
928 // Self comparison should be 0
929 object empty_obj_a;
930 ASSERT_JSON_EQ (empty_obj_a, empty_obj_a);
931
932 // Instances of empty objects should compare equal to each other
933 object empty_obj_b;
934 ASSERT_JSON_EQ (empty_obj_a, empty_obj_b);
935
936 // Object with one field:
937 object obj_1;
938 obj_1.set_string (key: "foo", utf8_value: "bar");
939 // Self comparison should be 0
940 ASSERT_JSON_EQ (obj_1, obj_1);
941
942 // but should be different to an empty object:
943 ASSERT_JSON_NE (obj_1, empty_obj_a);
944
945 // Another with one field, with same key/value:
946 object obj_2;
947 obj_2.set_string (key: "foo", utf8_value: "bar");
948 ASSERT_JSON_EQ (obj_1, obj_2);
949
950 // Same key, different value:
951 object obj_3;
952 obj_3.set_string (key: "foo", utf8_value: "baz");
953 ASSERT_JSON_NE (obj_1, obj_3);
954
955 // Adding an extra property:
956 obj_2.set_integer (key: "year", v: 1066);
957 ASSERT_JSON_NE (obj_1, obj_2);
958
959 /* Different insertion order, but same k-v pairs should be equal,
960 despite having different serialization. */
961 object obj_4;
962 obj_4.set_integer (key: "year", v: 1066);
963 obj_4.set_string (key: "foo", utf8_value: "bar");
964 ASSERT_JSON_EQ (obj_2, obj_4);
965 ASSERT_PRINT_EQ (obj_2, false, "{\"foo\": \"bar\", \"year\": 1066}");
966 ASSERT_PRINT_EQ (obj_4, false, "{\"year\": 1066, \"foo\": \"bar\"}");
967
968 /* Arrays. */
969
970 // Empty array
971 array empty_arr_a;
972 // Self comparison should be 0
973 ASSERT_JSON_EQ (empty_arr_a, empty_arr_a);
974
975 // Objects and arrays are different
976 ASSERT_JSON_NE (empty_obj_a, empty_arr_a);
977
978 // Instances of empty arrays should compare equal to each other
979 array empty_arr_b;
980 ASSERT_JSON_EQ (empty_arr_a, empty_arr_b);
981
982 // Array with one element:
983 array arr_1;
984 arr_1.append (v: std::make_unique<string> (args: "foo"));
985 // Self comparison should be 0
986 ASSERT_JSON_EQ (arr_1, arr_1);
987
988 // but should be different to an empty array:
989 ASSERT_JSON_NE (arr_1, empty_arr_a);
990
991 // Another with one element:
992 array arr_2;
993 arr_2.append (v: std::make_unique<string> (args: "foo"));
994 ASSERT_JSON_EQ (arr_1, arr_2);
995
996 // Adding an extra element:
997 arr_2.append (v: std::make_unique<string> (args: "bar"));
998 ASSERT_JSON_NE (arr_1, arr_2);
999}
1000
1001/* Ensure that json::string's get_string is usable as a C-style string. */
1002
1003static void
1004test_strcmp ()
1005{
1006 string str ("foobar", 3);
1007 ASSERT_EQ (strcmp (str.get_string (), "foo"), 0);
1008}
1009
1010static void
1011test_cloning ()
1012{
1013 // Objects
1014 {
1015 object obj;
1016 obj.set_string (key: "foo", utf8_value: "bar");
1017
1018 auto obj_clone = obj.clone ();
1019 ASSERT_JSON_EQ (obj, *obj_clone);
1020 }
1021
1022 // Arrays
1023 {
1024 array arr;
1025 arr.append (v: std::make_unique<string> (args: "foo"));
1026
1027 auto arr_clone = arr.clone ();
1028 ASSERT_JSON_EQ (arr, *arr_clone);
1029 }
1030
1031 // float_number
1032 {
1033 float_number f_one (1.0);
1034 auto f_clone = f_one.clone ();
1035 ASSERT_JSON_EQ (f_one, *f_clone);
1036 }
1037
1038 // integer_number
1039 {
1040 integer_number num (42);
1041 auto num_clone = num.clone ();
1042 ASSERT_JSON_EQ (num, *num_clone);
1043 }
1044
1045 // string
1046 {
1047 string str ("foo");
1048 auto str_clone = str.clone ();
1049 ASSERT_JSON_EQ (str, *str_clone);
1050 }
1051
1052 // literal
1053 {
1054 literal lit (JSON_TRUE);
1055 auto lit_clone = lit.clone ();
1056 ASSERT_JSON_EQ (lit, *lit_clone);
1057 }
1058}
1059
1060/* Run all of the selftests within this file. */
1061
1062void
1063json_cc_tests ()
1064{
1065 test_object_get ();
1066 test_writing_objects ();
1067 test_writing_arrays ();
1068 test_writing_float_numbers ();
1069 test_writing_integer_numbers ();
1070 test_writing_strings ();
1071 test_writing_literals ();
1072 test_formatting ();
1073 test_comparisons ();
1074 test_strcmp ();
1075 test_cloning ();
1076}
1077
1078} // namespace selftest
1079
1080#endif /* #if CHECKING_P */
1081

source code of gcc/json.cc