LCOV - code coverage report
Current view: top level - gcc - json.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 96.1 % 542 521
Test Date: 2026-02-28 14:20:25 Functions: 94.9 % 59 56
Legend: Lines:     hit not hit

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

Generated by: LCOV version 2.4-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.