LCOV - code coverage report
Current view: top level - gcc - json.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 95.4 % 432 412
Test Date: 2025-06-21 16:26:05 Functions: 95.5 % 44 42
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : /* JSON trees
       2                 :             :    Copyright (C) 2017-2025 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                 :     1379842 : print_escaped_json_string (pretty_printer *pp,
      37                 :             :                            const char *utf8_str,
      38                 :             :                            size_t len)
      39                 :             : {
      40                 :     1379842 :   pp_character (pp, '"');
      41                 :    18726896 :   for (size_t i = 0; i != len; ++i)
      42                 :             :     {
      43                 :    17347054 :       char ch = utf8_str[i];
      44                 :    17347054 :       switch (ch)
      45                 :             :         {
      46                 :        2552 :         case '"':
      47                 :        2552 :           pp_string (pp, "\\\"");
      48                 :        2552 :           break;
      49                 :        1483 :         case '\\':
      50                 :        1483 :           pp_string (pp, "\\\\");
      51                 :        1483 :           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                 :       55142 :         case '\n':
      59                 :       55142 :           pp_string (pp, "\\n");
      60                 :       55142 :           break;
      61                 :           8 :         case '\r':
      62                 :           8 :           pp_string (pp, "\\r");
      63                 :           8 :           break;
      64                 :        3694 :         case '\t':
      65                 :        3694 :           pp_string (pp, "\\t");
      66                 :        3694 :           break;
      67                 :           4 :         case '\0':
      68                 :           4 :           pp_string (pp, "\\0");
      69                 :           4 :           break;
      70                 :    17284155 :         default:
      71                 :    17284155 :           pp_character (pp, ch);
      72                 :             :         }
      73                 :             :     }
      74                 :     1379842 :   pp_character (pp, '"');
      75                 :     1379842 : }
      76                 :             : 
      77                 :             : /* class pointer::token.  */
      78                 :             : 
      79                 :     4172350 : pointer::token::token ()
      80                 :             : {
      81                 :     4172350 :   m_parent = nullptr;
      82                 :     4172350 :   m_data.u_member = nullptr;
      83                 :     4172350 :   m_kind = kind::root_value;
      84                 :     4172350 : }
      85                 :             : 
      86                 :     3362290 : pointer::token::token (json::object &parent, const char *member)
      87                 :             : {
      88                 :     3362290 :   m_parent = &parent;
      89                 :     3362290 :   m_data.u_member = xstrdup (member); // ideally we'd share
      90                 :     3362290 :   m_kind = kind::object_member;
      91                 :     3362290 : }
      92                 :             : 
      93                 :      806567 : pointer::token::token (json::array &parent, size_t index)
      94                 :             : {
      95                 :      806567 :   m_parent = &parent;
      96                 :      806567 :   m_data.u_index = index;
      97                 :      806567 :   m_kind = kind::array_index;
      98                 :      806567 : }
      99                 :             : 
     100                 :     8339855 : pointer::token::~token ()
     101                 :             : {
     102                 :     8339855 :   if (m_kind == kind::object_member)
     103                 :             :     {
     104                 :     3361156 :       gcc_assert (m_data.u_member);
     105                 :     3361156 :       free (m_data.u_member);
     106                 :             :     }
     107                 :     8339855 : }
     108                 :             : 
     109                 :             : pointer::token &
     110                 :     4168857 : pointer::token::operator= (pointer::token &&other)
     111                 :             : {
     112                 :     4168857 :   m_parent = other.m_parent;
     113                 :     4168857 :   m_data = other.m_data;
     114                 :     4168857 :   m_kind = other.m_kind;
     115                 :             : 
     116                 :     4168857 :   other.m_parent = nullptr;
     117                 :     4168857 :   other.m_data.u_member = nullptr;
     118                 :     4168857 :   other.m_kind = kind::root_value;
     119                 :             : 
     120                 :     4168857 :   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                 :             : 
     130                 :             : void
     131                 :         139 : value::dump (FILE *outf, bool formatted) const
     132                 :             : {
     133                 :         139 :   pretty_printer pp;
     134                 :         139 :   pp_buffer (&pp)->m_stream = outf;
     135                 :         139 :   print (&pp, formatted);
     136                 :         139 :   pp_flush (&pp);
     137                 :         139 : }
     138                 :             : 
     139                 :             : /* A convenience function for debugging.
     140                 :             :    Dump to stderr with formatting, and a trailing newline. */
     141                 :             : 
     142                 :             : void
     143                 :           0 : value::dump () const
     144                 :             : {
     145                 :           0 :   dump (stderr, true);
     146                 :           0 :   fprintf (stderr, "\n");
     147                 :           0 : }
     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                 :             : 
     162                 :             : int
     163                 :       14624 : value::compare (const value &val_a, const value &val_b)
     164                 :             : {
     165                 :       14624 :   enum kind kind_a = val_a.get_kind ();
     166                 :       14624 :   enum kind kind_b = val_b.get_kind ();
     167                 :       14624 :   if (kind_a != kind_b)
     168                 :          32 :     return (int)kind_a - (int)kind_b;
     169                 :             : 
     170                 :       14592 :   switch (kind_a)
     171                 :             :     {
     172                 :           0 :     default:
     173                 :           0 :       gcc_unreachable ();
     174                 :             : 
     175                 :        4843 :     case JSON_OBJECT:
     176                 :        4843 :       {
     177                 :        4843 :         const object &obj_a = (const object &)val_a;
     178                 :        4843 :         const object &obj_b = (const object &)val_b;
     179                 :        4843 :         return object::compare (obj_a, obj_b);
     180                 :             :       }
     181                 :          48 :       break;
     182                 :             : 
     183                 :          48 :     case JSON_ARRAY:
     184                 :          48 :       {
     185                 :          48 :         const array &arr_a = (const array &)val_a;
     186                 :          48 :         const array &arr_b = (const array &)val_b;
     187                 :         104 :         if (int cmp_size = (int)arr_a.size () - (int)arr_b.size ())
     188                 :             :           return cmp_size;
     189                 :          48 :         for (size_t idx = 0; idx < arr_a.size (); ++idx)
     190                 :          16 :           if (int cmp_element = compare (*arr_a[idx], *arr_b[idx]))
     191                 :             :             return cmp_element;
     192                 :             :         return 0;
     193                 :             :       }
     194                 :          61 :       break;
     195                 :             : 
     196                 :          61 :     case JSON_INTEGER:
     197                 :          61 :       {
     198                 :          61 :         const integer_number &int_a = (const integer_number &)val_a;
     199                 :          61 :         const integer_number &int_b = (const integer_number &)val_b;
     200                 :          61 :         return int_a.get () - int_b.get ();
     201                 :             :       }
     202                 :          24 :       break;
     203                 :             : 
     204                 :          24 :     case JSON_FLOAT:
     205                 :          24 :       {
     206                 :          24 :         const float_number &float_a = (const float_number &)val_a;
     207                 :          24 :         const float_number &float_b = (const float_number &)val_b;
     208                 :          24 :         union u
     209                 :             :         {
     210                 :             :           double u_double;
     211                 :             :           char u_buf[sizeof(double)];
     212                 :             :         };
     213                 :          24 :         union u u_a, u_b;
     214                 :          24 :         u_a.u_double = float_a.get ();
     215                 :          24 :         u_b.u_double = float_b.get ();
     216                 :          24 :         return memcmp (&u_a, &u_b, sizeof(double));
     217                 :             :       }
     218                 :        9584 :       break;
     219                 :             : 
     220                 :        9584 :     case JSON_STRING:
     221                 :        9584 :       {
     222                 :        9584 :         const string &str_a = (const string &)val_a;
     223                 :        9584 :         const string &str_b = (const string &)val_b;
     224                 :        9584 :         return strcmp (str_a.get_string (), 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                 :             : 
     242                 :     1519342 : object::~object ()
     243                 :             : {
     244                 :     7486900 :   for (map_t::iterator it = m_map.begin (); it != m_map.end (); ++it)
     245                 :             :     {
     246                 :     3361156 :       free (const_cast <char *>((*it).first));
     247                 :     3361156 :       delete ((*it).second);
     248                 :             :     }
     249                 :     1519342 : }
     250                 :             : 
     251                 :             : /* Implementation of json::value::print for json::object.  */
     252                 :             : 
     253                 :             : void
     254                 :      259811 : object::print (pretty_printer *pp, bool formatted) const
     255                 :             : {
     256                 :      259811 :   pp_character (pp, '{');
     257                 :      259811 :   if (formatted)
     258                 :        4328 :     pp_indentation (pp) += 1;
     259                 :             : 
     260                 :             :   /* Iterate in the order that the keys were inserted.  */
     261                 :             :   unsigned i;
     262                 :             :   const char *key;
     263                 :     1107946 :   FOR_EACH_VEC_ELT (m_keys, i, key)
     264                 :             :     {
     265                 :      848135 :       if (i > 0)
     266                 :             :         {
     267                 :      588332 :           pp_string (pp, ",");
     268                 :      588332 :           if (formatted)
     269                 :             :             {
     270                 :        6668 :               pp_newline (pp);
     271                 :        6668 :               pp_indent (pp);
     272                 :             :             }
     273                 :             :           else
     274                 :      581664 :             pp_space (pp);
     275                 :             :         }
     276                 :      848135 :       map_t &mut_map = const_cast<map_t &> (m_map);
     277                 :      848135 :       value *value = *mut_map.get (key);
     278                 :      848135 :       print_escaped_json_string (pp, key, strlen (key));
     279                 :      848135 :       pp_string (pp, ": ");
     280                 :      848135 :       const int indent = strlen (key) + 4;
     281                 :      848135 :       if (formatted)
     282                 :       10988 :         pp_indentation (pp) += indent;
     283                 :      848135 :       value->print (pp, formatted);
     284                 :      848135 :       if (formatted)
     285                 :       10988 :         pp_indentation (pp) -= indent;
     286                 :             :     }
     287                 :      259811 :   if (formatted)
     288                 :        4328 :     pp_indentation (pp) -= 1;
     289                 :      259811 :   pp_character (pp, '}');
     290                 :      259811 : }
     291                 :             : 
     292                 :             : /* Set the json::value * for KEY, taking ownership of V
     293                 :             :    (and taking a copy of KEY if necessary).  */
     294                 :             : 
     295                 :             : void
     296                 :     3362290 : object::set (const char *key, value *v)
     297                 :             : {
     298                 :     3362290 :   gcc_assert (key);
     299                 :     3362290 :   gcc_assert (v);
     300                 :             : 
     301                 :     3362290 :   value **ptr = m_map.get (key);
     302                 :     3362290 :   if (ptr)
     303                 :             :     {
     304                 :             :       /* If the key is already present, delete the existing value
     305                 :             :          and overwrite it.  */
     306                 :           0 :       delete *ptr;
     307                 :           0 :       *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                 :     3362290 :       char *owned_key = xstrdup (key);
     314                 :     3362290 :       m_map.put (owned_key, v);
     315                 :     3362290 :       m_keys.safe_push (owned_key);
     316                 :             :     }
     317                 :             : 
     318                 :     3362290 :   v->m_pointer_token = pointer::token (*this, key);
     319                 :     3362290 : }
     320                 :             : 
     321                 :             : /* Get the json::value * for KEY.
     322                 :             : 
     323                 :             :    The object retains ownership of the value.  */
     324                 :             : 
     325                 :             : value *
     326                 :       15819 : object::get (const char *key) const
     327                 :             : {
     328                 :       15819 :   gcc_assert (key);
     329                 :             : 
     330                 :       15819 :   value **ptr = const_cast <map_t &> (m_map).get (key);
     331                 :       15819 :   if (ptr)
     332                 :       15441 :     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                 :             : 
     340                 :             : void
     341                 :     1368221 : object::set_string (const char *key, const char *utf8_value)
     342                 :             : {
     343                 :     1368221 :   set (key, new json::string (utf8_value));
     344                 :     1368221 : }
     345                 :             : 
     346                 :             : /* Set value of KEY within this object to a JSON
     347                 :             :    integer value based on V.  */
     348                 :             : 
     349                 :             : void
     350                 :      679766 : object::set_integer (const char *key, long v)
     351                 :             : {
     352                 :      679766 :   set (key, new json::integer_number (v));
     353                 :      679766 : }
     354                 :             : 
     355                 :             : /* Set value of KEY within this object to a JSON
     356                 :             :    floating point value based on V.  */
     357                 :             : 
     358                 :             : void
     359                 :          16 : object::set_float (const char *key, double v)
     360                 :             : {
     361                 :          16 :   set (key, new json::float_number (v));
     362                 :          16 : }
     363                 :             : 
     364                 :             : /* Set value of KEY within this object to the JSON
     365                 :             :    literal true or false, based on V.  */
     366                 :             : 
     367                 :             : void
     368                 :         534 : object::set_bool (const char *key, bool v)
     369                 :             : {
     370                 :        1068 :   set (key, new json::literal (v));
     371                 :         534 : }
     372                 :             : 
     373                 :             : /* Subroutine of json::compare for comparing a pairs of objects.  */
     374                 :             : 
     375                 :             : int
     376                 :        4843 : object::compare (const json::object &obj_a, const json::object &obj_b)
     377                 :             : {
     378                 :       14453 :   if (int cmp_size = (int)obj_a.m_keys.length () - (int)obj_b.m_keys.length ())
     379                 :             :     return cmp_size;
     380                 :             : 
     381                 :       14800 :   for (auto iter_a : obj_a.m_map)
     382                 :             :     {
     383                 :        9541 :       const char *key = iter_a.first;
     384                 :        9541 :       const value *value_a = iter_a.second;
     385                 :        9541 :       gcc_assert (value_a);
     386                 :             : 
     387                 :        9541 :       const value *value_b = obj_b.get (key);
     388                 :        9541 :       if (!value_b)
     389                 :             :         /* Key is in OBJ_A but not in OBJ_B.  */
     390                 :        4492 :         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                 :        9541 :       if (int cmp_value = value::compare (*value_a, *value_b))
     395                 :             :         /* Values for key are non-equal.  */
     396                 :             :         return cmp_value;
     397                 :             :     }
     398                 :             : 
     399                 :             :   /* Objects are equal.  */
     400                 :         210 :   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                 :             : 
     408                 :     1241916 : array::~array ()
     409                 :             : {
     410                 :      621179 :   unsigned i;
     411                 :      621179 :   value *v;
     412                 :     1427667 :   FOR_EACH_VEC_ELT (m_elements, i, v)
     413                 :      806488 :     delete v;
     414                 :     1241916 : }
     415                 :             : 
     416                 :             : /* Implementation of json::value::print for json::array.  */
     417                 :             : 
     418                 :             : void
     419                 :       96866 : array::print (pretty_printer *pp, bool formatted) const
     420                 :             : {
     421                 :       96866 :   pp_character (pp, '[');
     422                 :       96866 :   if (formatted)
     423                 :        1481 :     pp_indentation (pp) += 1;
     424                 :             :   unsigned i;
     425                 :             :   value *v;
     426                 :      317930 :   FOR_EACH_VEC_ELT (m_elements, i, v)
     427                 :             :     {
     428                 :      221064 :       if (i)
     429                 :             :         {
     430                 :      138857 :           pp_string (pp, ",");
     431                 :      138857 :           if (formatted)
     432                 :             :             {
     433                 :        3550 :               pp_newline (pp);
     434                 :        3550 :               pp_indent (pp);
     435                 :             :             }
     436                 :             :           else
     437                 :      135307 :             pp_space (pp);
     438                 :             :         }
     439                 :      221064 :       v->print (pp, formatted);
     440                 :             :     }
     441                 :       96866 :   if (formatted)
     442                 :        1481 :     pp_indentation (pp) -= 1;
     443                 :       96866 :   pp_character (pp, ']');
     444                 :       96866 : }
     445                 :             : 
     446                 :             : /* Append non-NULL value V to a json::array, taking ownership of V.  */
     447                 :             : 
     448                 :             : void
     449                 :      806567 : array::append (value *v)
     450                 :             : {
     451                 :      806567 :   gcc_assert (v);
     452                 :     1414012 :   v->m_pointer_token = pointer::token (*this, m_elements.length ());
     453                 :      806567 :   m_elements.safe_push (v);
     454                 :      806567 : }
     455                 :             : 
     456                 :             : void
     457                 :      185138 : array::append_string (const char *utf8_value)
     458                 :             : {
     459                 :      185138 :   gcc_assert (utf8_value);
     460                 :      185138 :   append (new json::string (utf8_value));
     461                 :      185138 : }
     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                 :             : 
     467                 :             : void
     468                 :          32 : float_number::print (pretty_printer *pp,
     469                 :             :                      bool formatted ATTRIBUTE_UNUSED) const
     470                 :             : {
     471                 :          32 :   char tmp[1024];
     472                 :          32 :   snprintf (tmp, sizeof (tmp), "%g", m_value);
     473                 :          32 :   pp_string (pp, tmp);
     474                 :          32 : }
     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                 :             : 
     480                 :             : void
     481                 :      180864 : integer_number::print (pretty_printer *pp,
     482                 :             :                        bool formatted ATTRIBUTE_UNUSED) const
     483                 :             : {
     484                 :      180864 :   char tmp[1024];
     485                 :      180864 :   snprintf (tmp, sizeof (tmp), "%ld", m_value);
     486                 :      180864 :   pp_string (pp, tmp);
     487                 :      180864 : }
     488                 :             : 
     489                 :             : 
     490                 :             : /* class json::string, a subclass of json::value.  */
     491                 :             : 
     492                 :             : /* json::string's ctor.  */
     493                 :             : 
     494                 :     2105338 : string::string (const char *utf8)
     495                 :             : {
     496                 :     2105338 :   gcc_assert (utf8);
     497                 :     2105338 :   m_utf8 = xstrdup (utf8);
     498                 :     2105338 :   m_len = strlen (utf8);
     499                 :     2105338 : }
     500                 :             : 
     501                 :         215 : string::string (const char *utf8, size_t len)
     502                 :             : {
     503                 :         215 :   gcc_assert (utf8);
     504                 :         215 :   m_utf8 = XNEWVEC (char, len);
     505                 :         215 :   m_len = len;
     506                 :         215 :   memcpy (m_utf8, utf8, len);
     507                 :         215 : }
     508                 :             : 
     509                 :             : /* Implementation of json::value::print for json::string.  */
     510                 :             : 
     511                 :             : void
     512                 :      531707 : string::print (pretty_printer *pp,
     513                 :             :                bool formatted ATTRIBUTE_UNUSED) const
     514                 :             : {
     515                 :      531707 :   print_escaped_json_string (pp, m_utf8, m_len);
     516                 :      531707 : }
     517                 :             : 
     518                 :             : /* class json::literal, a subclass of json::value.  */
     519                 :             : 
     520                 :             : /* Implementation of json::value::print for json::literal.  */
     521                 :             : 
     522                 :             : void
     523                 :         265 : literal::print (pretty_printer *pp,
     524                 :             :                 bool formatted ATTRIBUTE_UNUSED) const
     525                 :             : {
     526                 :         265 :   switch (m_kind)
     527                 :             :     {
     528                 :         110 :     case JSON_TRUE:
     529                 :         110 :       pp_string (pp, "true");
     530                 :         110 :       break;
     531                 :         147 :     case JSON_FALSE:
     532                 :         147 :       pp_string (pp, "false");
     533                 :         147 :       break;
     534                 :           8 :     case JSON_NULL:
     535                 :           8 :       pp_string (pp, "null");
     536                 :           8 :       break;
     537                 :           0 :     default:
     538                 :           0 :       gcc_unreachable ();
     539                 :             :     }
     540                 :         265 : }
     541                 :             : 
     542                 :             : 
     543                 :             : #if CHECKING_P
     544                 :             : 
     545                 :             : namespace selftest {
     546                 :             : 
     547                 :             : /* Selftests.  */
     548                 :             : 
     549                 :             : /* Verify that JV->print () prints EXPECTED_JSON.  */
     550                 :             : 
     551                 :             : void
     552                 :         160 : assert_print_eq (const location &loc,
     553                 :             :                  const json::value &jv,
     554                 :             :                  bool formatted,
     555                 :             :                  const char *expected_json)
     556                 :             : {
     557                 :         160 :   pretty_printer pp;
     558                 :         160 :   jv.print (&pp, formatted);
     559                 :         160 :   ASSERT_STREQ_AT (loc, expected_json, pp_formatted_text (&pp));
     560                 :         160 : }
     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                 :             : 
     567                 :             : static void
     568                 :           4 : test_object_get ()
     569                 :             : {
     570                 :           4 :   object obj;
     571                 :           4 :   value *val = new json::string ("value");
     572                 :           4 :   obj.set ("foo", val);
     573                 :           4 :   ASSERT_EQ (obj.get ("foo"), val);
     574                 :           4 :   ASSERT_EQ (obj.get ("not-present"), NULL);
     575                 :           4 : }
     576                 :             : 
     577                 :             : /* Verify that JSON objects are written correctly.  */
     578                 :             : 
     579                 :             : static void
     580                 :           4 : test_writing_objects ()
     581                 :             : {
     582                 :           4 :   object obj;
     583                 :           4 :   obj.set_string ("foo", "bar");
     584                 :           4 :   obj.set_string ("baz", "quux");
     585                 :           4 :   obj.set_string ("\"\\\b\f\n\r\t", "value for awkward key");
     586                 :             : 
     587                 :             :   /* This test relies on json::object writing out key/value pairs
     588                 :             :      in key-insertion order.  */
     589                 :           4 :   ASSERT_PRINT_EQ (obj, true,
     590                 :             :                    "{\"foo\": \"bar\",\n"
     591                 :             :                    " \"baz\": \"quux\",\n"
     592                 :             :                    " \"\\\"\\\\\\b\\f\\n\\r\\t\": \"value for awkward key\"}");
     593                 :           4 :   ASSERT_PRINT_EQ (obj, false,
     594                 :             :                    "{\"foo\": \"bar\", \"baz\": \"quux\""
     595                 :             :                    ", \"\\\"\\\\\\b\\f\\n\\r\\t\": \"value for awkward key\"}");
     596                 :           4 : }
     597                 :             : 
     598                 :             : /* Verify that JSON arrays are written correctly.  */
     599                 :             : 
     600                 :             : static void
     601                 :           4 : test_writing_arrays ()
     602                 :             : {
     603                 :           4 :   array arr;
     604                 :           4 :   ASSERT_PRINT_EQ (arr, true, "[]");
     605                 :             : 
     606                 :           4 :   arr.append (new json::string ("foo"));
     607                 :           4 :   ASSERT_PRINT_EQ (arr, true, "[\"foo\"]");
     608                 :             : 
     609                 :           4 :   arr.append_string ("bar");
     610                 :           4 :   ASSERT_PRINT_EQ (arr, true,
     611                 :             :                    "[\"foo\",\n"
     612                 :             :                    " \"bar\"]");
     613                 :           4 :   ASSERT_PRINT_EQ (arr, false,
     614                 :             :                    "[\"foo\", \"bar\"]");
     615                 :           4 : }
     616                 :             : 
     617                 :             : /* Verify that JSON numbers are written correctly.  */
     618                 :             : 
     619                 :             : static void
     620                 :           4 : test_writing_float_numbers ()
     621                 :             : {
     622                 :           4 :   ASSERT_PRINT_EQ (float_number (0), true, "0");
     623                 :           4 :   ASSERT_PRINT_EQ (float_number (42), true, "42");
     624                 :           4 :   ASSERT_PRINT_EQ (float_number (-100), true, "-100");
     625                 :           4 :   ASSERT_PRINT_EQ (float_number (123456789), true, "1.23457e+08");
     626                 :           4 : }
     627                 :             : 
     628                 :             : static void
     629                 :           4 : test_writing_integer_numbers ()
     630                 :             : {
     631                 :           4 :   ASSERT_PRINT_EQ (integer_number (0), true, "0");
     632                 :           4 :   ASSERT_PRINT_EQ (integer_number (42), true, "42");
     633                 :           4 :   ASSERT_PRINT_EQ (integer_number (-100), true, "-100");
     634                 :           4 :   ASSERT_PRINT_EQ (integer_number (123456789), true, "123456789");
     635                 :           4 :   ASSERT_PRINT_EQ (integer_number (-123456789), true, "-123456789");
     636                 :           4 : }
     637                 :             : 
     638                 :             : /* Verify that JSON strings are written correctly.  */
     639                 :             : 
     640                 :             : static void
     641                 :           4 : test_writing_strings ()
     642                 :             : {
     643                 :           4 :   string foo ("foo");
     644                 :           4 :   ASSERT_PRINT_EQ (foo, true, "\"foo\"");
     645                 :             : 
     646                 :           4 :   string contains_quotes ("before \"quoted\" after");
     647                 :           4 :   ASSERT_PRINT_EQ (contains_quotes, true, "\"before \\\"quoted\\\" after\"");
     648                 :             : 
     649                 :           4 :   const char data[] = {'a', 'b', 'c', 'd', '\0', 'e', 'f'};
     650                 :           4 :   string not_terminated (data, 3);
     651                 :           4 :   ASSERT_PRINT_EQ (not_terminated, true, "\"abc\"");
     652                 :           4 :   string embedded_null (data, sizeof data);
     653                 :           4 :   ASSERT_PRINT_EQ (embedded_null, true, "\"abcd\\0ef\"");
     654                 :           4 : }
     655                 :             : 
     656                 :             : /* Verify that JSON literals are written correctly.  */
     657                 :             : 
     658                 :             : static void
     659                 :           4 : test_writing_literals ()
     660                 :             : {
     661                 :           4 :   ASSERT_PRINT_EQ (literal (JSON_TRUE), true, "true");
     662                 :           4 :   ASSERT_PRINT_EQ (literal (JSON_FALSE), true, "false");
     663                 :           4 :   ASSERT_PRINT_EQ (literal (JSON_NULL), true, "null");
     664                 :             : 
     665                 :           4 :   ASSERT_PRINT_EQ (literal (true), true, "true");
     666                 :           4 :   ASSERT_PRINT_EQ (literal (false), true, "false");
     667                 :           4 : }
     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                 :             : 
     674                 :             : static void
     675                 :           4 : test_formatting ()
     676                 :             : {
     677                 :           4 :   object obj;
     678                 :           4 :   object *child = new object;
     679                 :           4 :   std::unique_ptr<object> grandchild = std::make_unique<object> ();
     680                 :             : 
     681                 :           4 :   obj.set_string ("str", "bar");
     682                 :           4 :   obj.set ("child", child);
     683                 :           4 :   obj.set_integer ("int", 42);
     684                 :             : 
     685                 :           4 :   array *arr = new array;
     686                 :          16 :   for (int i = 0; i < 3; i++)
     687                 :          12 :     arr->append (std::make_unique<integer_number> (i));
     688                 :           4 :   grandchild->set ("arr", arr);
     689                 :           4 :   grandchild->set_integer ("int", 1066);
     690                 :             : 
     691                 :           4 :   child->set ("grandchild", std::move (grandchild));
     692                 :           4 :   child->set_integer ("int", 1776);
     693                 :             : 
     694                 :             :   /* This test relies on json::object writing out key/value pairs
     695                 :             :      in key-insertion order.  */
     696                 :           4 :   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                 :           4 :   ASSERT_PRINT_EQ (obj, false,
     705                 :             :                    ("{\"str\": \"bar\", \"child\": {\"grandchild\":"
     706                 :             :                     " {\"arr\": [0, 1, 2], \"int\": 1066},"
     707                 :             :                     " \"int\": 1776}, \"int\": 42}"));
     708                 :           4 : }
     709                 :             : 
     710                 :             : /* Helper function for reporting failure of JSON comparisons.  */
     711                 :             : 
     712                 :             : static void
     713                 :           0 : fail_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                 :           0 :   fprintf (stderr, "val_a: ");
     720                 :           0 :   val_a.dump ();
     721                 :             : 
     722                 :           0 :   fprintf (stderr, "val_b: ");
     723                 :           0 :   val_b.dump ();
     724                 :             : 
     725                 :           0 :   selftest::fail_formatted (loc,
     726                 :             :                             "%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                 :             : 
     734                 :             : static void
     735                 :          76 : assert_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                 :          76 :   const int a_vs_b = value::compare (val_a, val_b);
     741                 :          76 :   if (a_vs_b != 0)
     742                 :           0 :     fail_comparison (loc, desc, val_a, val_b, "zero", a_vs_b);
     743                 :             : 
     744                 :          76 :   const int b_vs_a = value::compare (val_b, val_a);
     745                 :          76 :   if (b_vs_a != 0)
     746                 :           0 :     fail_comparison (loc, desc, val_b, val_a, "zero", b_vs_a);
     747                 :          76 : }
     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                 :             : 
     761                 :             : static void
     762                 :          48 : assert_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                 :          48 :   const int a_vs_b = value::compare (val_a, val_b);
     768                 :          48 :   if (a_vs_b == 0)
     769                 :           0 :     fail_comparison (loc, desc, val_a, val_b, "non-zero", a_vs_b);
     770                 :             : 
     771                 :          48 :   const int b_vs_a = value::compare (val_b, val_a);
     772                 :          48 :   ASSERT_NE_AT (loc, b_vs_a, 0);
     773                 :          48 :   if (b_vs_a == 0)
     774                 :             :     fail_comparison (loc, desc, val_b, val_a, "non-zero", b_vs_a);
     775                 :             : 
     776                 :             :   /* Swapping the args should swap the sign of the result
     777                 :             :      (but isn't necessarily the negation).  */
     778                 :          48 :   if ( (a_vs_b > 0) == (b_vs_a > 0) )
     779                 :           0 :     fail_comparison (loc, desc, val_b, val_a, "opposite signs", 1);
     780                 :          48 : }
     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                 :             : 
     795                 :             : static void
     796                 :           4 : test_comparisons ()
     797                 :             : {
     798                 :             :   /* Literals.  */
     799                 :             : 
     800                 :           4 :   literal null_lit (JSON_NULL);
     801                 :           4 :   ASSERT_JSON_EQ (null_lit, null_lit);
     802                 :             : 
     803                 :           4 :   literal other_null_lit (JSON_NULL);
     804                 :           4 :   ASSERT_JSON_EQ (null_lit, other_null_lit);
     805                 :             : 
     806                 :           4 :   literal true_lit (JSON_TRUE);
     807                 :           4 :   ASSERT_JSON_EQ (true_lit, true_lit);
     808                 :           4 :   ASSERT_JSON_NE (true_lit, null_lit);
     809                 :             : 
     810                 :           4 :   literal false_lit (JSON_FALSE);
     811                 :           4 :   ASSERT_JSON_EQ (false_lit, false_lit);
     812                 :           4 :   ASSERT_JSON_NE (false_lit, true_lit);
     813                 :           4 :   ASSERT_JSON_NE (false_lit, null_lit);
     814                 :             : 
     815                 :             :   /* Strings.  */
     816                 :           4 :   string str_foo_1 ("foo");
     817                 :           4 :   ASSERT_JSON_EQ (str_foo_1, str_foo_1);
     818                 :             : 
     819                 :           4 :   string str_foo_2 ("foo");
     820                 :           4 :   ASSERT_JSON_EQ (str_foo_1, str_foo_2);
     821                 :             : 
     822                 :           4 :   string str_bar ("bar");
     823                 :           4 :   ASSERT_JSON_NE (str_bar, str_foo_1);
     824                 :             : 
     825                 :             :   /* Numbers.  */
     826                 :           4 :   integer_number i_42 (42);
     827                 :           4 :   ASSERT_JSON_EQ (i_42, i_42);
     828                 :           4 :   integer_number i_42_2 (42);
     829                 :           4 :   ASSERT_JSON_EQ (i_42, i_42_2);
     830                 :           4 :   integer_number i_43 (43);
     831                 :           4 :   ASSERT_JSON_NE (i_42, i_43);
     832                 :             : 
     833                 :           4 :   float_number f_zero (0.0);
     834                 :           4 :   ASSERT_JSON_EQ (f_zero, f_zero);
     835                 :           4 :   float_number f_zero_2 (0.0);
     836                 :           4 :   ASSERT_JSON_EQ (f_zero, f_zero_2);
     837                 :           4 :   float_number f_one (1.0);
     838                 :           4 :   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                 :           4 :   object empty_obj_a;
     846                 :           4 :   ASSERT_JSON_EQ (empty_obj_a, empty_obj_a);
     847                 :             : 
     848                 :             :   // Instances of empty objects should compare equal to each other
     849                 :           4 :   object empty_obj_b;
     850                 :           4 :   ASSERT_JSON_EQ (empty_obj_a, empty_obj_b);
     851                 :             : 
     852                 :             :   // Object with one field:
     853                 :           4 :   object obj_1;
     854                 :           4 :   obj_1.set_string ("foo", "bar");
     855                 :             :   // Self comparison should be 0
     856                 :           4 :   ASSERT_JSON_EQ (obj_1, obj_1);
     857                 :             : 
     858                 :             :   // but should be different to an empty object:
     859                 :           4 :   ASSERT_JSON_NE (obj_1, empty_obj_a);
     860                 :             : 
     861                 :             :   // Another with one field, with same key/value:
     862                 :           4 :   object obj_2;
     863                 :           4 :   obj_2.set_string ("foo", "bar");
     864                 :           4 :   ASSERT_JSON_EQ (obj_1, obj_2);
     865                 :             : 
     866                 :             :   // Same key, different value:
     867                 :           4 :   object obj_3;
     868                 :           4 :   obj_3.set_string ("foo", "baz");
     869                 :           4 :   ASSERT_JSON_NE (obj_1, obj_3);
     870                 :             : 
     871                 :             :   // Adding an extra property:
     872                 :           4 :   obj_2.set_integer ("year", 1066);
     873                 :           4 :   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                 :           4 :   object obj_4;
     878                 :           4 :   obj_4.set_integer ("year", 1066);
     879                 :           4 :   obj_4.set_string ("foo", "bar");
     880                 :           4 :   ASSERT_JSON_EQ (obj_2, obj_4);
     881                 :           4 :   ASSERT_PRINT_EQ (obj_2, false, "{\"foo\": \"bar\", \"year\": 1066}");
     882                 :           4 :   ASSERT_PRINT_EQ (obj_4, false, "{\"year\": 1066, \"foo\": \"bar\"}");
     883                 :             : 
     884                 :             :   /* Arrays.  */
     885                 :             : 
     886                 :             :   // Empty array
     887                 :           4 :   array empty_arr_a;
     888                 :             :   // Self comparison should be 0
     889                 :           4 :   ASSERT_JSON_EQ (empty_arr_a, empty_arr_a);
     890                 :             : 
     891                 :             :   // Objects and arrays are different
     892                 :           4 :   ASSERT_JSON_NE (empty_obj_a, empty_arr_a);
     893                 :             : 
     894                 :             :   // Instances of empty arrays should compare equal to each other
     895                 :           4 :   array empty_arr_b;
     896                 :           4 :   ASSERT_JSON_EQ (empty_arr_a, empty_arr_b);
     897                 :             : 
     898                 :             :   // Array with one element:
     899                 :           4 :   array arr_1;
     900                 :           4 :   arr_1.append (std::make_unique<string> ("foo"));
     901                 :             :   // Self comparison should be 0
     902                 :           4 :   ASSERT_JSON_EQ (arr_1, arr_1);
     903                 :             : 
     904                 :             :   // but should be different to an empty array:
     905                 :           4 :   ASSERT_JSON_NE (arr_1, empty_arr_a);
     906                 :             : 
     907                 :             :   // Another with one element:
     908                 :           4 :   array arr_2;
     909                 :           4 :   arr_2.append (std::make_unique<string> ("foo"));
     910                 :           4 :   ASSERT_JSON_EQ (arr_1, arr_2);
     911                 :             : 
     912                 :             :   // Adding an extra element:
     913                 :           4 :   arr_2.append (std::make_unique<string> ("bar"));
     914                 :           4 :   ASSERT_JSON_NE (arr_1, arr_2);
     915                 :           4 : }
     916                 :             : 
     917                 :             : /* Run all of the selftests within this file.  */
     918                 :             : 
     919                 :             : void
     920                 :           4 : json_cc_tests ()
     921                 :             : {
     922                 :           4 :   test_object_get ();
     923                 :           4 :   test_writing_objects ();
     924                 :           4 :   test_writing_arrays ();
     925                 :           4 :   test_writing_float_numbers ();
     926                 :           4 :   test_writing_integer_numbers ();
     927                 :           4 :   test_writing_strings ();
     928                 :           4 :   test_writing_literals ();
     929                 :           4 :   test_formatting ();
     930                 :           4 :   test_comparisons ();
     931                 :           4 : }
     932                 :             : 
     933                 :             : } // namespace selftest
     934                 :             : 
     935                 :             : #endif /* #if CHECKING_P */
        

Generated by: LCOV version 2.1-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.