LCOV - code coverage report
Current view: top level - tests - catch_json_tokens.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 100.0 % 615 615
Test Date: 2025-06-22 07:49:47 Functions: 100.0 % 2 2
Legend: Lines: hit not hit

            Line data    Source code
       1              : // Copyright (c) 2021-2023  Made to Order Software Corp.  All Rights Reserved
       2              : //
       3              : // https://snapwebsites.org/project/libutf8
       4              : // contact@m2osw.com
       5              : //
       6              : // This program is free software; you can redistribute it and/or modify
       7              : // it under the terms of the GNU General Public License as published by
       8              : // the Free Software Foundation; either version 2 of the License, or
       9              : // (at your option) any later version.
      10              : //
      11              : // This program is distributed in the hope that it will be useful,
      12              : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      13              : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14              : // GNU General Public License for more details.
      15              : //
      16              : // You should have received a copy of the GNU General Public License along
      17              : // with this program; if not, write to the Free Software Foundation, Inc.,
      18              : // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      19              : 
      20              : // libutf8
      21              : //
      22              : #include    <libutf8/json_tokens.h>
      23              : 
      24              : #include    <libutf8/libutf8.h>
      25              : 
      26              : 
      27              : // unit test
      28              : //
      29              : #include    "catch_main.h"
      30              : 
      31              : 
      32              : // snapdev
      33              : //
      34              : #include    <snapdev/file_contents.h>
      35              : 
      36              : 
      37              : // C++
      38              : //
      39              : #include    <cctype>
      40              : #include    <iomanip>
      41              : #include    <iostream>
      42              : 
      43              : 
      44              : // last include
      45              : //
      46              : #include    <snapdev/poison.h>
      47              : 
      48              : 
      49              : 
      50              : #pragma GCC diagnostic push
      51              : #pragma GCC diagnostic ignored "-Wfloat-equal"
      52            4 : CATCH_TEST_CASE("json_tokens", "[json][iterator]")
      53              : {
      54            4 :     CATCH_START_SECTION("json_tokens: valid JSON tokens")
      55              :     {
      56            1 :         std::string valid_json(
      57              :             "{\n"
      58              :                 "\"array-of-numbers\": [\n"
      59              :                     "\t1,\r\n"
      60              :                     "\t1.0,\r"
      61              :                     "\t-0.1\r\n"
      62              :                 "]   ,  \n"
      63              :                 "\"color\"      :true  ,\n"
      64              :                 "\"temporary\"  :false,   \r"
      65              :                 "\"flowers\":null\r\n"
      66              :             "}"
      67            3 :         );
      68              : 
      69              : #if 0
      70              :         snap::file_contents f("test.json");
      71              :         f.contents(valid_json);
      72              :         f.write_all();
      73              : #endif
      74              : 
      75            1 :         libutf8::json_tokens jt(valid_json);
      76            1 :         CATCH_REQUIRE(jt.line() == 0);
      77            1 :         CATCH_REQUIRE(jt.column() == 0);
      78            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_OPEN_OBJECT);
      79            1 :         CATCH_REQUIRE(jt.line() == 1);
      80            1 :         CATCH_REQUIRE(jt.column() == 1);
      81            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
      82            1 :         CATCH_REQUIRE(jt.string() == "array-of-numbers");
      83            1 :         CATCH_REQUIRE(jt.line() == 2);
      84            1 :         CATCH_REQUIRE(jt.column() == 1);
      85            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
      86            1 :         CATCH_REQUIRE(jt.line() == 2);
      87            1 :         CATCH_REQUIRE(jt.column() == 19);
      88            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_OPEN_ARRAY);
      89            1 :         CATCH_REQUIRE(jt.line() == 2);
      90            1 :         CATCH_REQUIRE(jt.column() == 21);
      91            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_NUMBER);
      92            1 :         CATCH_REQUIRE(jt.number() == 1.0_a);
      93            1 :         CATCH_REQUIRE(jt.line() == 3);
      94            1 :         CATCH_REQUIRE(jt.column() == 2);
      95            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COMMA);
      96            1 :         CATCH_REQUIRE(jt.line() == 3);
      97            1 :         CATCH_REQUIRE(jt.column() == 3 + 1);    // error due to the unget
      98            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_NUMBER);
      99            1 :         CATCH_REQUIRE(jt.number() == 1.0_a);
     100            1 :         CATCH_REQUIRE(jt.line() == 4);
     101            1 :         CATCH_REQUIRE(jt.column() == 2);
     102            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COMMA);
     103            1 :         CATCH_REQUIRE(jt.line() == 4);
     104            1 :         CATCH_REQUIRE(jt.column() == 5 + 1);    // error due to the unget
     105            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_NUMBER);
     106            1 :         CATCH_REQUIRE(jt.number() == -0.1_a);
     107            1 :         CATCH_REQUIRE(jt.line() == 5);
     108            1 :         CATCH_REQUIRE(jt.column() == 2);
     109            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_CLOSE_ARRAY);
     110            1 :         CATCH_REQUIRE(jt.line() == 6);
     111            1 :         CATCH_REQUIRE(jt.column() == 1);
     112            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COMMA);
     113            1 :         CATCH_REQUIRE(jt.line() == 6);
     114            1 :         CATCH_REQUIRE(jt.column() == 5);
     115            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
     116            1 :         CATCH_REQUIRE(jt.string() == "color");
     117            1 :         CATCH_REQUIRE(jt.line() == 7);
     118            1 :         CATCH_REQUIRE(jt.column() == 1);
     119            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
     120            1 :         CATCH_REQUIRE(jt.line() == 7);
     121            1 :         CATCH_REQUIRE(jt.column() == 14);
     122            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_TRUE);
     123            1 :         CATCH_REQUIRE(jt.line() == 7);
     124            1 :         CATCH_REQUIRE(jt.column() == 15);
     125            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COMMA);
     126            1 :         CATCH_REQUIRE(jt.line() == 7);
     127            1 :         CATCH_REQUIRE(jt.column() == 21);
     128            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
     129            1 :         CATCH_REQUIRE(jt.string() == "temporary");
     130            1 :         CATCH_REQUIRE(jt.line() == 8);
     131            1 :         CATCH_REQUIRE(jt.column() == 1);
     132            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
     133            1 :         CATCH_REQUIRE(jt.line() == 8);
     134            1 :         CATCH_REQUIRE(jt.column() == 14);
     135            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_FALSE);
     136            1 :         CATCH_REQUIRE(jt.line() == 8);
     137            1 :         CATCH_REQUIRE(jt.column() == 15);
     138            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COMMA);
     139            1 :         CATCH_REQUIRE(jt.line() == 8);
     140            1 :         CATCH_REQUIRE(jt.column() == 20);
     141            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
     142            1 :         CATCH_REQUIRE(jt.string() == "flowers");
     143            1 :         CATCH_REQUIRE(jt.line() == 9);
     144            1 :         CATCH_REQUIRE(jt.column() == 1);
     145            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
     146            1 :         CATCH_REQUIRE(jt.line() == 9);
     147            1 :         CATCH_REQUIRE(jt.column() == 10);
     148            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_NULL);
     149            1 :         CATCH_REQUIRE(jt.line() == 9);
     150            1 :         CATCH_REQUIRE(jt.column() == 11);
     151            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_CLOSE_OBJECT);
     152            1 :         CATCH_REQUIRE(jt.line() == 10);
     153            1 :         CATCH_REQUIRE(jt.column() == 1);
     154            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_END);
     155            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_END);
     156            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_END);
     157            1 :     }
     158            4 :     CATCH_END_SECTION()
     159              : 
     160            4 :     CATCH_START_SECTION("json_tokens: valid JSON numbers")
     161              :     {
     162            1 :         std::string valid_json(
     163              :             "["
     164              :                 "733,"
     165              :                 "-1892,"
     166              :                 "-1.892,"
     167              :                 "-9.892e33,"
     168              :                 "101.302e+3,"
     169              :                 "5031.70232e-13"
     170              :             "]"
     171            3 :         );
     172              : 
     173            1 :         libutf8::json_tokens jt(valid_json);
     174            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_OPEN_ARRAY);
     175            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_NUMBER);
     176            1 :         CATCH_REQUIRE_FLOATING_POINT(jt.number(), 733.0);
     177            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COMMA);
     178            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_NUMBER);
     179            1 :         CATCH_REQUIRE_FLOATING_POINT(jt.number(), -1892.0);
     180            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COMMA);
     181            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_NUMBER);
     182            1 :         CATCH_REQUIRE_FLOATING_POINT(jt.number(), -1.892);
     183            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COMMA);
     184            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_NUMBER);
     185            1 :         CATCH_REQUIRE_FLOATING_POINT(jt.number(), -9.892e33);
     186            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COMMA);
     187            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_NUMBER);
     188            1 :         CATCH_REQUIRE_FLOATING_POINT(jt.number(), 101.302e3);
     189            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COMMA);
     190            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_NUMBER);
     191            1 :         CATCH_REQUIRE_FLOATING_POINT(jt.number(), 5031.70232e-13);
     192            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_CLOSE_ARRAY);
     193            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_END);
     194            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_END);
     195            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_END);
     196            1 :     }
     197            4 :     CATCH_END_SECTION()
     198              : 
     199            4 :     CATCH_START_SECTION("json_tokens: valid JSON special escaped characters")
     200              :     {
     201            1 :         std::string valid_json(
     202              :             "{"
     203              :                 "\"backslash\":\"\\\\\","
     204              :                 "\"quote\":\"\\\"\","
     205              :                 "\"slash\":\"\\/\","
     206              :                 "\"backspace\":\"\\b\","
     207              :                 "\"formfeed\":\"\\f\","
     208              :                 "\"newline\":\"\\n\","
     209              :                 "\"carriage-return\":\"\\r\","
     210              :                 "\"tab\":\"\\t\""
     211              :             "}"
     212            3 :         );
     213              : 
     214            1 :         libutf8::json_tokens jt(valid_json);
     215            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_OPEN_OBJECT);
     216            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
     217            1 :         CATCH_REQUIRE(jt.string() == "backslash");
     218            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
     219            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
     220            1 :         CATCH_REQUIRE(jt.string() == "\\");
     221            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COMMA);
     222            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
     223            1 :         CATCH_REQUIRE(jt.string() == "quote");
     224            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
     225            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
     226            1 :         CATCH_REQUIRE(jt.string() == "\"");
     227            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COMMA);
     228            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
     229            1 :         CATCH_REQUIRE(jt.string() == "slash");
     230            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
     231            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
     232            1 :         CATCH_REQUIRE(jt.string() == "/");
     233            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COMMA);
     234            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
     235            1 :         CATCH_REQUIRE(jt.string() == "backspace");
     236            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
     237            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
     238            1 :         CATCH_REQUIRE(jt.string() == "\b");
     239            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COMMA);
     240            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
     241            1 :         CATCH_REQUIRE(jt.string() == "formfeed");
     242            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
     243            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
     244            1 :         CATCH_REQUIRE(jt.string() == "\f");
     245            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COMMA);
     246            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
     247            1 :         CATCH_REQUIRE(jt.string() == "newline");
     248            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
     249            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
     250            1 :         CATCH_REQUIRE(jt.string() == "\n");
     251            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COMMA);
     252            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
     253            1 :         CATCH_REQUIRE(jt.string() == "carriage-return");
     254            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
     255            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
     256            1 :         CATCH_REQUIRE(jt.string() == "\r");
     257            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COMMA);
     258            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
     259            1 :         CATCH_REQUIRE(jt.string() == "tab");
     260            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
     261            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
     262            1 :         CATCH_REQUIRE(jt.string() == "\t");
     263            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_CLOSE_OBJECT);
     264            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_END);
     265            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_END);
     266            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_END);
     267            1 :     }
     268            4 :     CATCH_END_SECTION()
     269              : 
     270            4 :     CATCH_START_SECTION("json_tokens: valid JSON unicode escaped characters")
     271              :     {
     272      1114112 :         for(char32_t c(1); c < 0x110000; ++c)
     273              :         {
     274      1114111 :             if(c >= 0xD800 && c <= 0xDFFF)
     275              :             {
     276         2048 :                 continue;
     277              :             }
     278              : 
     279      1112063 :             std::stringstream ss;
     280      1112063 :             std::string valid_json;
     281      1112063 :             valid_json += "{\"unicode\":\"\\u";
     282      1112063 :             if(c > 0xFFFF)
     283              :             {
     284      1048576 :                 int s(c - 0x10000);
     285      1048576 :                 ss << std::hex << std::setw(4) << std::setfill('0') << ((s >> 10) | 0xD800)
     286      1048576 :                    << "\\u" << std::setw(4) << std::setfill('0') << ((s & 0x3FF) | 0xDC00);
     287              :             }
     288              :             else
     289              :             {
     290        63487 :                 ss << std::hex << std::setw(4) << std::setfill('0') << static_cast<int>(c);
     291              :             }
     292      1112063 :             valid_json += ss.str();
     293      1112063 :             valid_json += "\"}";
     294              : 
     295      1112063 :             libutf8::json_tokens jt(valid_json);
     296      1112063 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_OPEN_OBJECT);
     297      1112063 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
     298      1112063 :             CATCH_REQUIRE(jt.string() == "unicode");
     299      1112063 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
     300      1112063 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
     301      1112063 :             std::string expected(libutf8::to_u8string(c));
     302      1112063 :             CATCH_REQUIRE_LONG_STRING(jt.string(), expected);
     303      1112063 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_CLOSE_OBJECT);
     304      1112063 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_END);
     305      1112063 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_END);
     306      1112063 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_END);
     307      1112063 :         }
     308              :     }
     309            4 :     CATCH_END_SECTION()
     310            4 : }
     311              : #pragma GCC diagnostic pop
     312              : 
     313              : 
     314           20 : CATCH_TEST_CASE("json_tokens_invalid", "[json][iterator][invalid]")
     315              : {
     316           20 :     CATCH_START_SECTION("json_tokens_invalid: invalid JSON negative number")
     317              :     {
     318            1 :         std::string valid_json(
     319              :             "-a"
     320            3 :         );
     321              : 
     322            1 :         libutf8::json_tokens jt(valid_json);
     323            1 :         CATCH_REQUIRE(jt.line() == 0);
     324            1 :         CATCH_REQUIRE(jt.column() == 0);
     325            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
     326            1 :         CATCH_REQUIRE(jt.line() == 1);
     327            1 :         CATCH_REQUIRE(jt.column() == 1);
     328            1 :         CATCH_REQUIRE(jt.error() == "found unexpected character: '-'");
     329            1 :     }
     330           20 :     CATCH_END_SECTION()
     331              : 
     332           20 :     CATCH_START_SECTION("json_tokens_invalid: invalid JSON number with fraction")
     333              :     {
     334            1 :         std::string valid_json(
     335              :             "-3., 2."
     336            3 :         );
     337              : 
     338            1 :         libutf8::json_tokens jt(valid_json);
     339            1 :         CATCH_REQUIRE(jt.line() == 0);
     340            1 :         CATCH_REQUIRE(jt.column() == 0);
     341            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
     342            1 :         CATCH_REQUIRE(jt.line() == 1);
     343            1 :         CATCH_REQUIRE(jt.column() == 1);
     344            1 :         CATCH_REQUIRE(jt.error() == "number cannot end with a period (\"1.\" is not valid JSON)");
     345            1 :     }
     346           20 :     CATCH_END_SECTION()
     347              : 
     348           20 :     CATCH_START_SECTION("json_tokens_invalid: invalid JSON number exponent")
     349              :     {
     350            1 :         std::string valid_json(
     351              :             "-3.0e+a, 2.1"
     352            3 :         );
     353              : 
     354            1 :         libutf8::json_tokens jt(valid_json);
     355            1 :         CATCH_REQUIRE(jt.line() == 0);
     356            1 :         CATCH_REQUIRE(jt.column() == 0);
     357            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
     358            1 :         CATCH_REQUIRE(jt.line() == 1);
     359            1 :         CATCH_REQUIRE(jt.column() == 1);
     360            1 :         CATCH_REQUIRE(jt.error() == "number exponent must include at least one digit");
     361            1 :     }
     362           20 :     CATCH_END_SECTION()
     363              : 
     364           20 :     CATCH_START_SECTION("json_tokens_invalid: invalid JSON number with fraction")
     365              :     {
     366            1 :         std::string valid_json(
     367              :             "\"back\\slash\""
     368            3 :         );
     369              : 
     370            1 :         libutf8::json_tokens jt(valid_json);
     371            1 :         CATCH_REQUIRE(jt.line() == 0);
     372            1 :         CATCH_REQUIRE(jt.column() == 0);
     373            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
     374            1 :         CATCH_REQUIRE(jt.line() == 1);
     375            1 :         CATCH_REQUIRE(jt.column() == 1);
     376            1 :         CATCH_REQUIRE(jt.error() == "unexpected escape character: 's'");
     377            1 :     }
     378           20 :     CATCH_END_SECTION()
     379              : 
     380           20 :     CATCH_START_SECTION("json_tokens_invalid: unsupported JSON backslash character")
     381              :     {
     382              :         {
     383            1 :             std::string valid_json(
     384              :                 "\"back\\slash\""
     385            3 :             );
     386              : 
     387            1 :             libutf8::json_tokens jt(valid_json);
     388            1 :             CATCH_REQUIRE(jt.line() == 0);
     389            1 :             CATCH_REQUIRE(jt.column() == 0);
     390            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
     391            1 :             CATCH_REQUIRE(jt.line() == 1);
     392            1 :             CATCH_REQUIRE(jt.column() == 1);
     393            1 :             CATCH_REQUIRE(jt.error() == "unexpected escape character: 's'");
     394            1 :         }
     395              : 
     396              :     }
     397           20 :     CATCH_END_SECTION()
     398              : 
     399           20 :     CATCH_START_SECTION("json_tokens_invalid: invalid JSON unicode: too short")
     400              :     {
     401              :         {
     402            1 :             std::string valid_json(
     403              :                 "\"\\u0"
     404            3 :             );
     405              : 
     406            1 :             libutf8::json_tokens jt(valid_json);
     407            1 :             CATCH_REQUIRE(jt.line() == 0);
     408            1 :             CATCH_REQUIRE(jt.column() == 0);
     409            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
     410            1 :             CATCH_REQUIRE(jt.line() == 1);
     411            1 :             CATCH_REQUIRE(jt.column() == 1);
     412            1 :             CATCH_REQUIRE(jt.error() == "invalid unicode character: 'EOS'");
     413            1 :         }
     414              : 
     415              :         {
     416            1 :             std::string valid_json(
     417              :                 "\"\\u20"
     418            3 :             );
     419              : 
     420            1 :             libutf8::json_tokens jt(valid_json);
     421            1 :             CATCH_REQUIRE(jt.line() == 0);
     422            1 :             CATCH_REQUIRE(jt.column() == 0);
     423            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
     424            1 :             CATCH_REQUIRE(jt.line() == 1);
     425            1 :             CATCH_REQUIRE(jt.column() == 1);
     426            1 :             CATCH_REQUIRE(jt.error() == "invalid unicode character: 'EOS'");
     427            1 :         }
     428              : 
     429              :         {
     430            1 :             std::string valid_json(
     431              :                 "\"\\u301"
     432            3 :             );
     433              : 
     434            1 :             libutf8::json_tokens jt(valid_json);
     435            1 :             CATCH_REQUIRE(jt.line() == 0);
     436            1 :             CATCH_REQUIRE(jt.column() == 0);
     437            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
     438            1 :             CATCH_REQUIRE(jt.line() == 1);
     439            1 :             CATCH_REQUIRE(jt.column() == 1);
     440            1 :             CATCH_REQUIRE(jt.error() == "invalid unicode character: 'EOS'");
     441            1 :         }
     442              : 
     443              :     }
     444           20 :     CATCH_END_SECTION()
     445              : 
     446           20 :     CATCH_START_SECTION("json_tokens_invalid: invalid JSON unicode: low surrogate missing backslash")
     447              :     {
     448            1 :         std::string valid_json(
     449              :             "\"\\uD91Fmissing\""
     450            3 :         );
     451              : 
     452            1 :         libutf8::json_tokens jt(valid_json);
     453            1 :         CATCH_REQUIRE(jt.line() == 0);
     454            1 :         CATCH_REQUIRE(jt.column() == 0);
     455            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
     456            1 :         CATCH_REQUIRE(jt.line() == 1);
     457            1 :         CATCH_REQUIRE(jt.column() == 1);
     458            1 :         CATCH_REQUIRE(jt.error() == "expected a low surrogate right after a high surrogate, backslash (\\) mising");
     459            1 :     }
     460           20 :     CATCH_END_SECTION()
     461              : 
     462           20 :     CATCH_START_SECTION("json_tokens_invalid: invalid JSON unicode: low surrogate missing 'u'")
     463              :     {
     464            1 :         std::string valid_json(
     465              :             "\"\\uD91F\\missing\""
     466            3 :         );
     467              : 
     468            1 :         libutf8::json_tokens jt(valid_json);
     469            1 :         CATCH_REQUIRE(jt.line() == 0);
     470            1 :         CATCH_REQUIRE(jt.column() == 0);
     471            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
     472            1 :         CATCH_REQUIRE(jt.line() == 1);
     473            1 :         CATCH_REQUIRE(jt.column() == 1);
     474            1 :         CATCH_REQUIRE(jt.error() == "expected a low surrogate right after a high surrogate, 'u' missing");
     475            1 :     }
     476           20 :     CATCH_END_SECTION()
     477              : 
     478           20 :     CATCH_START_SECTION("json_tokens_invalid: invalid JSON unicode: low surrogate expected")
     479              :     {
     480              :         {
     481            1 :             std::string valid_json(
     482              :                 "\"\\uD91F\\u0010\""
     483            3 :             );
     484              : 
     485            1 :             libutf8::json_tokens jt(valid_json);
     486            1 :             CATCH_REQUIRE(jt.line() == 0);
     487            1 :             CATCH_REQUIRE(jt.column() == 0);
     488            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
     489            1 :             CATCH_REQUIRE(jt.line() == 1);
     490            1 :             CATCH_REQUIRE(jt.column() == 1);
     491            1 :             CATCH_REQUIRE(jt.error() == "expected a low surrogate right after a high surrogate");
     492            1 :         }
     493              : 
     494              :         {
     495            1 :             std::string valid_json(
     496              :                 "\"\\uD91F\\uDBFF\""
     497            3 :             );
     498              : 
     499            1 :             libutf8::json_tokens jt(valid_json);
     500            1 :             CATCH_REQUIRE(jt.line() == 0);
     501            1 :             CATCH_REQUIRE(jt.column() == 0);
     502            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
     503            1 :             CATCH_REQUIRE(jt.line() == 1);
     504            1 :             CATCH_REQUIRE(jt.column() == 1);
     505            1 :             CATCH_REQUIRE(jt.error() == "expected a low surrogate right after a high surrogate");
     506            1 :         }
     507              : 
     508              :         {
     509            1 :             std::string valid_json(
     510              :                 "\"\\uD91F\\uE030"
     511            3 :             );
     512              : 
     513            1 :             libutf8::json_tokens jt(valid_json);
     514            1 :             CATCH_REQUIRE(jt.line() == 0);
     515            1 :             CATCH_REQUIRE(jt.column() == 0);
     516            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
     517            1 :             CATCH_REQUIRE(jt.line() == 1);
     518            1 :             CATCH_REQUIRE(jt.column() == 1);
     519            1 :             CATCH_REQUIRE(jt.error() == "expected a low surrogate right after a high surrogate");
     520            1 :         }
     521              :     }
     522           20 :     CATCH_END_SECTION()
     523              : 
     524           20 :     CATCH_START_SECTION("json_tokens_invalid: invalid JSON unicode: low surrogate too short")
     525              :     {
     526              :         {
     527            1 :             std::string valid_json(
     528              :                 "\"\\uD91F\\u0"
     529            3 :             );
     530              : 
     531            1 :             libutf8::json_tokens jt(valid_json);
     532            1 :             CATCH_REQUIRE(jt.line() == 0);
     533            1 :             CATCH_REQUIRE(jt.column() == 0);
     534            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
     535            1 :             CATCH_REQUIRE(jt.line() == 1);
     536            1 :             CATCH_REQUIRE(jt.column() == 1);
     537            1 :             CATCH_REQUIRE(jt.error() == "invalid unicode character: 'EOS'");
     538            1 :         }
     539              : 
     540              :         {
     541            1 :             std::string valid_json(
     542              :                 "\"\\uD91F\\u0f"
     543            3 :             );
     544              : 
     545            1 :             libutf8::json_tokens jt(valid_json);
     546            1 :             CATCH_REQUIRE(jt.line() == 0);
     547            1 :             CATCH_REQUIRE(jt.column() == 0);
     548            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
     549            1 :             CATCH_REQUIRE(jt.line() == 1);
     550            1 :             CATCH_REQUIRE(jt.column() == 1);
     551            1 :             CATCH_REQUIRE(jt.error() == "invalid unicode character: 'EOS'");
     552            1 :         }
     553              : 
     554              :         {
     555            1 :             std::string valid_json(
     556              :                 "\"\\uD91F\\u0fa"
     557            3 :             );
     558              : 
     559            1 :             libutf8::json_tokens jt(valid_json);
     560            1 :             CATCH_REQUIRE(jt.line() == 0);
     561            1 :             CATCH_REQUIRE(jt.column() == 0);
     562            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
     563            1 :             CATCH_REQUIRE(jt.line() == 1);
     564            1 :             CATCH_REQUIRE(jt.column() == 1);
     565            1 :             CATCH_REQUIRE(jt.error() == "invalid unicode character: 'EOS'");
     566            1 :         }
     567              :     }
     568           20 :     CATCH_END_SECTION()
     569              : 
     570           20 :     CATCH_START_SECTION("json_tokens_invalid: invalid JSON unicode: invalid hexadecimal digit (low surrogate)")
     571              :     {
     572              :         {
     573            1 :             std::string valid_json(
     574              :                 "\"\\udb31\\u0t\""
     575            3 :             );
     576              : 
     577            1 :             libutf8::json_tokens jt(valid_json);
     578            1 :             CATCH_REQUIRE(jt.line() == 0);
     579            1 :             CATCH_REQUIRE(jt.column() == 0);
     580            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
     581            1 :             CATCH_REQUIRE(jt.line() == 1);
     582            1 :             CATCH_REQUIRE(jt.column() == 1);
     583            1 :             CATCH_REQUIRE(jt.error() == "invalid unicode character: 't'");
     584            1 :         }
     585              : 
     586              :         {
     587            1 :             std::string valid_json(
     588              :                 "\"\\udb31\\u3eg\""
     589            3 :             );
     590              : 
     591            1 :             libutf8::json_tokens jt(valid_json);
     592            1 :             CATCH_REQUIRE(jt.line() == 0);
     593            1 :             CATCH_REQUIRE(jt.column() == 0);
     594            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
     595            1 :             CATCH_REQUIRE(jt.line() == 1);
     596            1 :             CATCH_REQUIRE(jt.column() == 1);
     597            1 :             CATCH_REQUIRE(jt.error() == "invalid unicode character: 'g'");
     598            1 :         }
     599              : 
     600              :         {
     601            1 :             std::string valid_json(
     602              :                 "\"\\udb31\\ua3e!\""
     603            3 :             );
     604              : 
     605            1 :             libutf8::json_tokens jt(valid_json);
     606            1 :             CATCH_REQUIRE(jt.line() == 0);
     607            1 :             CATCH_REQUIRE(jt.column() == 0);
     608            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
     609            1 :             CATCH_REQUIRE(jt.line() == 1);
     610            1 :             CATCH_REQUIRE(jt.column() == 1);
     611            1 :             CATCH_REQUIRE(jt.error() == "invalid unicode character: '!'");
     612            1 :         }
     613              :     }
     614           20 :     CATCH_END_SECTION()
     615              : 
     616           20 :     CATCH_START_SECTION("json_tokens_invalid: invalid JSON unicode: low surrogate first")
     617              :     {
     618         1025 :         for(char32_t c(0xDC00); c <= 0xDFFF; ++c)
     619              :         {
     620         1024 :             std::stringstream ss;
     621         1024 :             ss << "\\u" << std::hex << std::setw(4)
     622         1024 :                 << std::setfill('0') << static_cast<int>(c);
     623              : 
     624              :             // breaking up line so it compiles on lunar
     625              :             //
     626              :             //libutf8::json_tokens jt("\"" + ss.str() + "\"");
     627         3072 :             std::string str("\"");
     628         1024 :             str += ss.str();
     629         1024 :             str += "\"";
     630         1024 :             libutf8::json_tokens jt(str);
     631              : 
     632         1024 :             CATCH_REQUIRE(jt.line() == 0);
     633         1024 :             CATCH_REQUIRE(jt.column() == 0);
     634         1024 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
     635         1024 :             CATCH_REQUIRE(jt.line() == 1);
     636         1024 :             CATCH_REQUIRE(jt.column() == 1);
     637         3072 :             std::string const msg("low surrogate " + ss.str()
     638         2048 :                                     + " found before a high surrogate");
     639         1024 :             CATCH_REQUIRE(jt.error() == msg);
     640         1024 :         }
     641              : 
     642              :     }
     643           20 :     CATCH_END_SECTION()
     644              : 
     645           20 :     CATCH_START_SECTION("json_tokens_invalid: invalid JSON unicode: invalid hexadecimal digit")
     646              :     {
     647              :         {
     648            1 :             std::string valid_json(
     649              :                 "\"\\u5z"
     650            3 :             );
     651              : 
     652            1 :             libutf8::json_tokens jt(valid_json);
     653            1 :             CATCH_REQUIRE(jt.line() == 0);
     654            1 :             CATCH_REQUIRE(jt.column() == 0);
     655            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
     656            1 :             CATCH_REQUIRE(jt.line() == 1);
     657            1 :             CATCH_REQUIRE(jt.column() == 1);
     658            1 :             CATCH_REQUIRE(jt.error() == "invalid unicode character: 'z'");
     659            1 :         }
     660              : 
     661              :         {
     662            1 :             std::string valid_json(
     663              :                 "\"\\uaa$"
     664            3 :             );
     665              : 
     666            1 :             libutf8::json_tokens jt(valid_json);
     667            1 :             CATCH_REQUIRE(jt.line() == 0);
     668            1 :             CATCH_REQUIRE(jt.column() == 0);
     669            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
     670            1 :             CATCH_REQUIRE(jt.line() == 1);
     671            1 :             CATCH_REQUIRE(jt.column() == 1);
     672            1 :             CATCH_REQUIRE(jt.error() == "invalid unicode character: '$'");
     673            1 :         }
     674              : 
     675              :         {
     676            1 :             std::string valid_json(
     677              :                 "\"\\ua9a\001"
     678            3 :             );
     679              : 
     680            1 :             libutf8::json_tokens jt(valid_json);
     681            1 :             CATCH_REQUIRE(jt.line() == 0);
     682            1 :             CATCH_REQUIRE(jt.column() == 0);
     683            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
     684            1 :             CATCH_REQUIRE(jt.line() == 1);
     685            1 :             CATCH_REQUIRE(jt.column() == 1);
     686            1 :             CATCH_REQUIRE(jt.error() == "invalid unicode character: '^A'");
     687            1 :         }
     688              :     }
     689           20 :     CATCH_END_SECTION()
     690              : 
     691           20 :     CATCH_START_SECTION("json_tokens_invalid: unterminated JSON string")
     692              :     {
     693            3 :         libutf8::json_tokens jt("\"unterminated");
     694            1 :         CATCH_REQUIRE(jt.line() == 0);
     695            1 :         CATCH_REQUIRE(jt.column() == 0);
     696            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
     697            1 :         CATCH_REQUIRE(jt.line() == 1);
     698            1 :         CATCH_REQUIRE(jt.column() == 1);
     699            1 :         CATCH_REQUIRE(jt.error() == "unclosed string");
     700              : 
     701            1 :     }
     702           20 :     CATCH_END_SECTION()
     703              : 
     704           20 :     CATCH_START_SECTION("json_tokens_invalid: JSON true with missing characters")
     705              :     {
     706              :         {
     707            3 :             libutf8::json_tokens jt("{\"bad-true\":tru}");
     708            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_OPEN_OBJECT);
     709            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
     710            1 :             CATCH_REQUIRE(jt.string() == "bad-true");
     711            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
     712            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
     713            1 :             CATCH_REQUIRE(jt.error() == "found unexpected character: 't'");
     714            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
     715            1 :             CATCH_REQUIRE(jt.error() == "found unexpected character: 'r'");
     716            1 :         }
     717              : 
     718              :         {
     719            3 :             libutf8::json_tokens jt("{\"bad-true\":tr}");
     720            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_OPEN_OBJECT);
     721            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
     722            1 :             CATCH_REQUIRE(jt.string() == "bad-true");
     723            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
     724            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
     725            1 :             CATCH_REQUIRE(jt.error() == "found unexpected character: 't'");
     726            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
     727            1 :             CATCH_REQUIRE(jt.error() == "found unexpected character: 'r'");
     728            1 :         }
     729              : 
     730              :         {
     731            3 :             libutf8::json_tokens jt("{\"bad-true\":t}");
     732            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_OPEN_OBJECT);
     733            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
     734            1 :             CATCH_REQUIRE(jt.string() == "bad-true");
     735            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
     736            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
     737            1 :             CATCH_REQUIRE(jt.error() == "found unexpected character: 't'");
     738            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_CLOSE_OBJECT);
     739            1 :         }
     740              :     }
     741           20 :     CATCH_END_SECTION()
     742              : 
     743           20 :     CATCH_START_SECTION("json_tokens_invalid: JSON false with missing characters")
     744              :     {
     745              :         {
     746            3 :             libutf8::json_tokens jt("{\"bad-false\":fals}");
     747            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_OPEN_OBJECT);
     748            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
     749            1 :             CATCH_REQUIRE(jt.string() == "bad-false");
     750            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
     751            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
     752            1 :             CATCH_REQUIRE(jt.error() == "found unexpected character: 'f'");
     753            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
     754            1 :             CATCH_REQUIRE(jt.error() == "found unexpected character: 'a'");
     755            1 :         }
     756              : 
     757              :         {
     758            3 :             libutf8::json_tokens jt("{\"bad-false\":fal}");
     759            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_OPEN_OBJECT);
     760            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
     761            1 :             CATCH_REQUIRE(jt.string() == "bad-false");
     762            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
     763            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
     764            1 :             CATCH_REQUIRE(jt.error() == "found unexpected character: 'f'");
     765            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
     766            1 :             CATCH_REQUIRE(jt.error() == "found unexpected character: 'a'");
     767            1 :         }
     768              : 
     769              :         {
     770            3 :             libutf8::json_tokens jt("{\"bad-false\":fa}");
     771            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_OPEN_OBJECT);
     772            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
     773            1 :             CATCH_REQUIRE(jt.string() == "bad-false");
     774            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
     775            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
     776            1 :             CATCH_REQUIRE(jt.error() == "found unexpected character: 'f'");
     777            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
     778            1 :             CATCH_REQUIRE(jt.error() == "found unexpected character: 'a'");
     779            1 :         }
     780              : 
     781              :         {
     782            3 :             libutf8::json_tokens jt("{\"bad-false\":f}");
     783            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_OPEN_OBJECT);
     784            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
     785            1 :             CATCH_REQUIRE(jt.string() == "bad-false");
     786            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
     787            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
     788            1 :             CATCH_REQUIRE(jt.error() == "found unexpected character: 'f'");
     789            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_CLOSE_OBJECT);
     790            1 :         }
     791              :     }
     792           20 :     CATCH_END_SECTION()
     793              : 
     794           20 :     CATCH_START_SECTION("json_tokens_invalid: JSON null with missing characters")
     795              :     {
     796              :         {
     797            3 :             libutf8::json_tokens jt("{\"bad-null\":nul}");
     798            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_OPEN_OBJECT);
     799            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
     800            1 :             CATCH_REQUIRE(jt.string() == "bad-null");
     801            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
     802            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
     803            1 :             CATCH_REQUIRE(jt.error() == "found unexpected character: 'n'");
     804            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
     805            1 :             CATCH_REQUIRE(jt.error() == "found unexpected character: 'u'");
     806            1 :         }
     807              : 
     808              :         {
     809            3 :             libutf8::json_tokens jt("{\"bad-null\":nu}");
     810            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_OPEN_OBJECT);
     811            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
     812            1 :             CATCH_REQUIRE(jt.string() == "bad-null");
     813            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
     814            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
     815            1 :             CATCH_REQUIRE(jt.error() == "found unexpected character: 'n'");
     816            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
     817            1 :             CATCH_REQUIRE(jt.error() == "found unexpected character: 'u'");
     818            1 :         }
     819              : 
     820              :         {
     821            3 :             libutf8::json_tokens jt("{\"bad-null\":n}");
     822            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_OPEN_OBJECT);
     823            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_STRING);
     824            1 :             CATCH_REQUIRE(jt.string() == "bad-null");
     825            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_COLON);
     826            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
     827            1 :             CATCH_REQUIRE(jt.error() == "found unexpected character: 'n'");
     828            1 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_CLOSE_OBJECT);
     829            1 :         }
     830              :     }
     831           20 :     CATCH_END_SECTION()
     832              : 
     833           20 :     CATCH_START_SECTION("json_tokens_invalid: unexpected JSON characters")
     834              :     {
     835      1114112 :         for(char32_t c(1); c < 0x110000; ++c)
     836              :         {
     837      1114111 :             if(c >= 0xD800 && c <= 0xDFFF)
     838              :             {
     839         2048 :                 continue;
     840              :             }
     841      1112063 :             switch(c)
     842              :             {
     843           24 :             case '"':
     844              :             case '{':
     845              :             case '}':
     846              :             case '[':
     847              :             case ']':
     848              :             case '0':
     849              :             case '1':
     850              :             case '2':
     851              :             case '3':
     852              :             case '4':
     853              :             case '5':
     854              :             case '6':
     855              :             case '7':
     856              :             case '8':
     857              :             case '9':
     858              :             case ' ':
     859              :             case '\t':
     860              :             case '\r':
     861              :             case '\n':
     862              :             case 'n':
     863              :             case 't':
     864              :             case 'f':
     865              :             case ',':
     866              :             case ':':
     867           24 :                 continue;
     868              : 
     869              :             }
     870              : 
     871      2224078 :             std::string invalid_json(libutf8::to_u8string(c));
     872      2224078 :             libutf8::json_tokens jt(invalid_json);
     873              : 
     874      1112039 :             CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
     875      1112039 :             if(c < 0x20)
     876              :             {
     877           28 :                 CATCH_REQUIRE(jt.error() == "found unexpected character: '^" + libutf8::to_u8string(static_cast<char32_t>(c + 0x40)) + "'");
     878              :             }
     879      1112011 :             else if(c >= 0x80 && c < 0xA0)
     880              :             {
     881           32 :                 CATCH_REQUIRE(jt.error() == "found unexpected character: '@" + libutf8::to_u8string(static_cast<char32_t>(c - 0x40)) + "'");
     882           32 :             }
     883              :             else
     884              :             {
     885      1111979 :                 CATCH_REQUIRE(jt.error() == "found unexpected character: '" + libutf8::to_u8string(c) + "'");
     886              :             }
     887              :         }
     888              :     }
     889           20 :     CATCH_END_SECTION()
     890              : 
     891           20 :     CATCH_START_SECTION("json_tokens_invalid: unexpected '\\0' in JSON")
     892              :     {
     893            1 :         std::string invalid_json;
     894            1 :         invalid_json += '\0';
     895            1 :         libutf8::json_tokens jt(invalid_json);
     896              : 
     897            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
     898            1 :         CATCH_REQUIRE(jt.error() == "found unexpected NULL character");
     899            1 :     }
     900           20 :     CATCH_END_SECTION()
     901              : 
     902           20 :     CATCH_START_SECTION("json_tokens_invalid: unexpected '\\0' in JSON string")
     903              :     {
     904            3 :         std::string invalid_json("\"string");
     905            1 :         invalid_json += '\0';
     906            1 :         invalid_json += "with null\"";
     907            1 :         libutf8::json_tokens jt(invalid_json);
     908              : 
     909            1 :         CATCH_REQUIRE(jt.next_token() == libutf8::token_t::TOKEN_ERROR);
     910            1 :         CATCH_REQUIRE(jt.error() == "unexpected NULL character in string");
     911            1 :     }
     912           20 :     CATCH_END_SECTION()
     913           20 : }
     914              : 
     915              : 
     916              : 
     917              : // vim: ts=4 sw=4 et
        

Generated by: LCOV version 2.0-1

Snap C++ | List of projects | List of versions