tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

TestJSONWriter.cpp (15076B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "mozilla/Assertions.h"
      8 #include "mozilla/JSONWriter.h"
      9 #include "mozilla/UniquePtr.h"
     10 #include <stdio.h>
     11 #include <string>
     12 #include <string.h>
     13 
     14 using mozilla::JSONWriteFunc;
     15 using mozilla::JSONWriter;
     16 using mozilla::MakeStringSpan;
     17 using mozilla::MakeUnique;
     18 using mozilla::Span;
     19 
     20 // This writes all the output into a big buffer.
     21 struct StringWriteFunc final : public JSONWriteFunc {
     22  std::string mString;
     23 
     24  void Write(const mozilla::Span<const char>& aStr) final {
     25    mString.append(aStr.data(), aStr.size());
     26  }
     27 };
     28 
     29 void Check(JSONWriter& aWriter, const char* aExpected) {
     30  JSONWriteFunc& func = aWriter.WriteFunc();
     31  const std::string& actual = static_cast<StringWriteFunc&>(func).mString;
     32  if (strcmp(aExpected, actual.c_str()) != 0) {
     33    fprintf(stderr,
     34            "---- EXPECTED ----\n<<<%s>>>\n"
     35            "---- ACTUAL ----\n<<<%s>>>\n",
     36            aExpected, actual.c_str());
     37    MOZ_RELEASE_ASSERT(false, "expected and actual output don't match");
     38  }
     39 }
     40 
     41 // Note: to convert actual output into |expected| strings that C++ can handle,
     42 // apply the following substitutions, in order, to each line.
     43 // - s/\\/\\\\/g    # escapes backslashes
     44 // - s/"/\\"/g      # escapes quotes
     45 // - s/$/\\n\\/     # adds a newline and string continuation char to each line
     46 
     47 void TestBasicProperties() {
     48  const char* expected =
     49      "\
     50 {\n\
     51 \"null\": null,\n\
     52 \"bool1\": true,\n\
     53 \"bool2\": false,\n\
     54 \"int1\": 123,\n\
     55 \"int2\": -123,\n\
     56 \"int3\": -123456789000,\n\
     57 \"double1\": 1.2345,\n\
     58 \"double2\": -3,\n\
     59 \"double3\": 1e-7,\n\
     60 \"double4\": 1.1111111111111111e+21,\n\
     61 \"string1\": \"\",\n\
     62 \"string2\": \"1234\",\n\
     63 \"string3\": \"hello\",\n\
     64 \"string4\": \"\\\" \\\\ \\u0007 \\b \\t \\n \\u000b \\f \\r\",\n\
     65 \"string5\": \"hello\",\n\
     66 \"string6\": \"\\\" \\\\ \\u0007 \\b \\t \",\n\
     67 \"span1\": \"buf1\",\n\
     68 \"span2\": \"buf2\",\n\
     69 \"span3\": \"buf3\",\n\
     70 \"span4\": \"buf\\n4\",\n\
     71 \"span5\": \"MakeStringSpan\",\n\
     72 \"len 0 array, multi-line\": [\n\
     73 ],\n\
     74 \"len 0 array, single-line\": [],\n\
     75 \"len 1 array\": [\n\
     76  1\n\
     77 ],\n\
     78 \"len 5 array, multi-line\": [\n\
     79  1,\n\
     80  2,\n\
     81  3,\n\
     82  4,\n\
     83  5\n\
     84 ],\n\
     85 \"len 3 array, single-line\": [1, [{}, 2, []], 3],\n\
     86 \"len 0 object, multi-line\": {\n\
     87 },\n\
     88 \"len 0 object, single-line\": {},\n\
     89 \"len 1 object\": {\n\
     90  \"one\": 1\n\
     91 },\n\
     92 \"len 5 object\": {\n\
     93  \"one\": 1,\n\
     94  \"two\": 2,\n\
     95  \"three\": 3,\n\
     96  \"four\": 4,\n\
     97  \"five\": 5\n\
     98 },\n\
     99 \"len 3 object, single-line\": {\"a\": 1, \"b\": [{}, 2, []], \"c\": 3}\n\
    100 }\n\
    101 ";
    102 
    103  JSONWriter w(MakeUnique<StringWriteFunc>());
    104 
    105  w.Start();
    106  {
    107    w.NullProperty("null");
    108 
    109    w.BoolProperty("bool1", true);
    110    w.BoolProperty("bool2", false);
    111 
    112    w.IntProperty("int1", 123);
    113    w.IntProperty("int2", -0x7b);
    114    w.IntProperty("int3", -123456789000ll);
    115 
    116    w.DoubleProperty("double1", 1.2345);
    117    w.DoubleProperty("double2", -3);
    118    w.DoubleProperty("double3", 1e-7);
    119    w.DoubleProperty("double4", 1.1111111111111111e+21);
    120 
    121    w.StringProperty("string1", "");
    122    w.StringProperty("string2", "1234");
    123    w.StringProperty("string3", "hello");
    124    w.StringProperty("string4", "\" \\ \a \b \t \n \v \f \r");
    125    w.StringProperty("string5", "hello\0cut");  // '\0' marks the end.
    126    w.StringProperty("string6", "\" \\ \a \b \t \0 \n \v \f \r");
    127 
    128    const char buf1[] = {'b', 'u', 'f', '1'};
    129    w.StringProperty("span1", buf1);
    130    const char buf2[] = {'b', 'u', 'f', '2', '\0'};
    131    w.StringProperty("span2", buf2);
    132    const char buf3[] = {'b', 'u', 'f', '3', '\0', '?'};
    133    w.StringProperty("span3", buf3);
    134    const char buf4[] = {'b', 'u', 'f', '\n', '4', '\0', '?'};
    135    w.StringProperty("span4", buf4);
    136    w.StringProperty("span5", MakeStringSpan("MakeStringSpan"));
    137 
    138    w.StartArrayProperty("len 0 array, multi-line", w.MultiLineStyle);
    139    w.EndArray();
    140 
    141    w.StartArrayProperty("len 0 array, single-line", w.SingleLineStyle);
    142    w.EndArray();
    143 
    144    w.StartArrayProperty("len 1 array");
    145    {
    146      w.IntElement(1);
    147    }
    148    w.EndArray();
    149 
    150    w.StartArrayProperty("len 5 array, multi-line", w.MultiLineStyle);
    151    {
    152      w.IntElement(1);
    153      w.IntElement(2);
    154      w.IntElement(3);
    155      w.IntElement(4);
    156      w.IntElement(5);
    157    }
    158    w.EndArray();
    159 
    160    w.StartArrayProperty("len 3 array, single-line", w.SingleLineStyle);
    161    {
    162      w.IntElement(1);
    163      w.StartArrayElement();
    164      {
    165        w.StartObjectElement(w.SingleLineStyle);
    166        w.EndObject();
    167 
    168        w.IntElement(2);
    169 
    170        w.StartArrayElement(w.MultiLineStyle);  // style overridden from above
    171        w.EndArray();
    172      }
    173      w.EndArray();
    174      w.IntElement(3);
    175    }
    176    w.EndArray();
    177 
    178    w.StartObjectProperty("len 0 object, multi-line");
    179    w.EndObject();
    180 
    181    w.StartObjectProperty("len 0 object, single-line", w.SingleLineStyle);
    182    w.EndObject();
    183 
    184    w.StartObjectProperty("len 1 object");
    185    {
    186      w.IntProperty("one", 1);
    187    }
    188    w.EndObject();
    189 
    190    w.StartObjectProperty("len 5 object");
    191    {
    192      w.IntProperty("one", 1);
    193      w.IntProperty("two", 2);
    194      w.IntProperty("three", 3);
    195      w.IntProperty("four", 4);
    196      w.IntProperty("five", 5);
    197    }
    198    w.EndObject();
    199 
    200    w.StartObjectProperty("len 3 object, single-line", w.SingleLineStyle);
    201    {
    202      w.IntProperty("a", 1);
    203      w.StartArrayProperty("b");
    204      {
    205        w.StartObjectElement();
    206        w.EndObject();
    207 
    208        w.IntElement(2);
    209 
    210        w.StartArrayElement(w.SingleLineStyle);
    211        w.EndArray();
    212      }
    213      w.EndArray();
    214      w.IntProperty("c", 3);
    215    }
    216    w.EndObject();
    217  }
    218  w.End();
    219 
    220  Check(w, expected);
    221 }
    222 
    223 void TestBasicElements() {
    224  const char* expected =
    225      "\
    226 {\n\
    227 \"array\": [\n\
    228  null,\n\
    229  true,\n\
    230  false,\n\
    231  123,\n\
    232  -123,\n\
    233  -123456789000,\n\
    234  1.2345,\n\
    235  -3,\n\
    236  1e-7,\n\
    237  1.1111111111111111e+21,\n\
    238  \"\",\n\
    239  \"1234\",\n\
    240  \"hello\",\n\
    241  \"\\\" \\\\ \\u0007 \\b \\t \\n \\u000b \\f \\r\",\n\
    242  \"hello\",\n\
    243  \"\\\" \\\\ \\u0007 \\b \\t \",\n\
    244  \"buf1\",\n\
    245  \"buf2\",\n\
    246  \"buf3\",\n\
    247  \"buf\\n4\",\n\
    248  \"MakeStringSpan\",\n\
    249  [\n\
    250  ],\n\
    251  [],\n\
    252  [\n\
    253   1\n\
    254  ],\n\
    255  [\n\
    256   1,\n\
    257   2,\n\
    258   3,\n\
    259   4,\n\
    260   5\n\
    261  ],\n\
    262  [1, [{}, 2, []], 3],\n\
    263  {\n\
    264  },\n\
    265  {},\n\
    266  {\n\
    267   \"one\": 1\n\
    268  },\n\
    269  {\n\
    270   \"one\": 1,\n\
    271   \"two\": 2,\n\
    272   \"three\": 3,\n\
    273   \"four\": 4,\n\
    274   \"five\": 5\n\
    275  },\n\
    276  {\"a\": 1, \"b\": [{}, 2, []], \"c\": 3}\n\
    277 ]\n\
    278 }\n\
    279 ";
    280 
    281  JSONWriter w(MakeUnique<StringWriteFunc>());
    282 
    283  w.Start();
    284  w.StartArrayProperty("array");
    285  {
    286    w.NullElement();
    287 
    288    w.BoolElement(true);
    289    w.BoolElement(false);
    290 
    291    w.IntElement(123);
    292    w.IntElement(-0x7b);
    293    w.IntElement(-123456789000ll);
    294 
    295    w.DoubleElement(1.2345);
    296    w.DoubleElement(-3);
    297    w.DoubleElement(1e-7);
    298    w.DoubleElement(1.1111111111111111e+21);
    299 
    300    w.StringElement("");
    301    w.StringElement("1234");
    302    w.StringElement("hello");
    303    w.StringElement("\" \\ \a \b \t \n \v \f \r");
    304    w.StringElement("hello\0cut");  // '\0' marks the end.
    305    w.StringElement("\" \\ \a \b \t \0 \n \v \f \r");
    306 
    307    const char buf1[] = {'b', 'u', 'f', '1'};
    308    w.StringElement(buf1);
    309    const char buf2[] = {'b', 'u', 'f', '2', '\0'};
    310    w.StringElement(buf2);
    311    const char buf3[] = {'b', 'u', 'f', '3', '\0', '?'};
    312    w.StringElement(buf3);
    313    const char buf4[] = {'b', 'u', 'f', '\n', '4', '\0', '?'};
    314    w.StringElement(buf4);
    315    w.StringElement(MakeStringSpan("MakeStringSpan"));
    316 
    317    w.StartArrayElement();
    318    w.EndArray();
    319 
    320    w.StartArrayElement(w.SingleLineStyle);
    321    w.EndArray();
    322 
    323    w.StartArrayElement();
    324    {
    325      w.IntElement(1);
    326    }
    327    w.EndArray();
    328 
    329    w.StartArrayElement();
    330    {
    331      w.IntElement(1);
    332      w.IntElement(2);
    333      w.IntElement(3);
    334      w.IntElement(4);
    335      w.IntElement(5);
    336    }
    337    w.EndArray();
    338 
    339    w.StartArrayElement(w.SingleLineStyle);
    340    {
    341      w.IntElement(1);
    342      w.StartArrayElement();
    343      {
    344        w.StartObjectElement(w.SingleLineStyle);
    345        w.EndObject();
    346 
    347        w.IntElement(2);
    348 
    349        w.StartArrayElement(w.MultiLineStyle);  // style overridden from above
    350        w.EndArray();
    351      }
    352      w.EndArray();
    353      w.IntElement(3);
    354    }
    355    w.EndArray();
    356 
    357    w.StartObjectElement();
    358    w.EndObject();
    359 
    360    w.StartObjectElement(w.SingleLineStyle);
    361    w.EndObject();
    362 
    363    w.StartObjectElement();
    364    {
    365      w.IntProperty("one", 1);
    366    }
    367    w.EndObject();
    368 
    369    w.StartObjectElement();
    370    {
    371      w.IntProperty("one", 1);
    372      w.IntProperty("two", 2);
    373      w.IntProperty("three", 3);
    374      w.IntProperty("four", 4);
    375      w.IntProperty("five", 5);
    376    }
    377    w.EndObject();
    378 
    379    w.StartObjectElement(w.SingleLineStyle);
    380    {
    381      w.IntProperty("a", 1);
    382      w.StartArrayProperty("b");
    383      {
    384        w.StartObjectElement();
    385        w.EndObject();
    386 
    387        w.IntElement(2);
    388 
    389        w.StartArrayElement(w.SingleLineStyle);
    390        w.EndArray();
    391      }
    392      w.EndArray();
    393      w.IntProperty("c", 3);
    394    }
    395    w.EndObject();
    396  }
    397  w.EndArray();
    398  w.End();
    399 
    400  Check(w, expected);
    401 }
    402 
    403 void TestOneLineObject() {
    404  const char* expected =
    405      "\
    406 {\"i\": 1, \"array\": [null, [{}], {\"o\": {}}, \"s\"], \"d\": 3.33}\n\
    407 ";
    408 
    409  JSONWriter w(MakeUnique<StringWriteFunc>());
    410 
    411  w.Start(w.SingleLineStyle);
    412 
    413  w.IntProperty("i", 1);
    414 
    415  w.StartArrayProperty("array");
    416  {
    417    w.NullElement();
    418 
    419    w.StartArrayElement(w.MultiLineStyle);  // style overridden from above
    420    {
    421      w.StartObjectElement();
    422      w.EndObject();
    423    }
    424    w.EndArray();
    425 
    426    w.StartObjectElement();
    427    {
    428      w.StartObjectProperty("o");
    429      w.EndObject();
    430    }
    431    w.EndObject();
    432 
    433    w.StringElement("s");
    434  }
    435  w.EndArray();
    436 
    437  w.DoubleProperty("d", 3.33);
    438 
    439  w.End();
    440 
    441  Check(w, expected);
    442 }
    443 
    444 void TestOneLineJson() {
    445  const char* expected =
    446      "\
    447 {\"i\":1,\"array\":[null,[{}],{\"o\":{}},\"s\"],\"d\":3.33}\
    448 ";
    449 
    450  StringWriteFunc func;
    451  JSONWriter w(func, JSONWriter::SingleLineStyle);
    452 
    453  w.Start(w.MultiLineStyle);  // style overridden from above
    454 
    455  w.IntProperty("i", 1);
    456 
    457  w.StartArrayProperty("array");
    458  {
    459    w.NullElement();
    460 
    461    w.StartArrayElement(w.MultiLineStyle);  // style overridden from above
    462    {
    463      w.StartObjectElement();
    464      w.EndObject();
    465    }
    466    w.EndArray();
    467 
    468    w.StartObjectElement();
    469    {
    470      w.StartObjectProperty("o");
    471      w.EndObject();
    472    }
    473    w.EndObject();
    474 
    475    w.StringElement("s");
    476  }
    477  w.EndArray();
    478 
    479  w.DoubleProperty("d", 3.33);
    480 
    481  w.End();  // No newline in this case.
    482 
    483  Check(w, expected);
    484 }
    485 
    486 void TestStringEscaping() {
    487  // This test uses hexadecimal character escapes because UTF8 literals cause
    488  // problems for some compilers (see bug 1069726).
    489  const char* expected =
    490      "\
    491 {\n\
    492 \"ascii\": \"\x7F~}|{zyxwvutsrqponmlkjihgfedcba`_^]\\\\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)('&%$#\\\"! \\u001f\\u001e\\u001d\\u001c\\u001b\\u001a\\u0019\\u0018\\u0017\\u0016\\u0015\\u0014\\u0013\\u0012\\u0011\\u0010\\u000f\\u000e\\r\\f\\u000b\\n\\t\\b\\u0007\\u0006\\u0005\\u0004\\u0003\\u0002\\u0001\",\n\
    493 \"\xD9\x85\xD8\xB1\xD8\xAD\xD8\xA8\xD8\xA7 \xD9\x87\xD9\x86\xD8\xA7\xD9\x83\": true,\n\
    494 \"\xD5\xA2\xD5\xA1\xD6\x80\xD5\xA5\xD6\x82 \xD5\xB9\xD5\xAF\xD5\xA1\": -123,\n\
    495 \"\xE4\xBD\xA0\xE5\xA5\xBD\": 1.234,\n\
    496 \"\xCE\xB3\xCE\xB5\xCE\xB9\xCE\xB1 \xCE\xB5\xCE\xBA\xCE\xB5\xCE\xAF\": \"\xD8\xB3\xD9\x84\xD8\xA7\xD9\x85\",\n\
    497 \"hall\xC3\xB3 \xC3\xBE"
    498      "arna\": 4660,\n\
    499 \"\xE3\x81\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1\xE3\x81\xAF\": {\n\
    500  \"\xD0\xBF\xD1\x80\xD0\xB8\xD0\xB2\xD0\xB5\xD1\x82\": [\n\
    501  ]\n\
    502 }\n\
    503 }\n\
    504 ";
    505 
    506  JSONWriter w(MakeUnique<StringWriteFunc>());
    507 
    508  // Test the string escaping behaviour.
    509  w.Start();
    510  {
    511    // Test all 127 ascii values. Do it in reverse order so that the 0
    512    // at the end serves as the null char.
    513    char buf[128];
    514    for (int i = 0; i < 128; i++) {
    515      buf[i] = 127 - i;
    516    }
    517    w.StringProperty("ascii", buf);
    518 
    519    // Test lots of unicode stuff. Note that this file is encoded as UTF-8.
    520    w.BoolProperty(
    521        "\xD9\x85\xD8\xB1\xD8\xAD\xD8\xA8\xD8\xA7 "
    522        "\xD9\x87\xD9\x86\xD8\xA7\xD9\x83",
    523        true);
    524    w.IntProperty(
    525        "\xD5\xA2\xD5\xA1\xD6\x80\xD5\xA5\xD6\x82 \xD5\xB9\xD5\xAF\xD5\xA1",
    526        -123);
    527    w.DoubleProperty("\xE4\xBD\xA0\xE5\xA5\xBD", 1.234);
    528    w.StringProperty(
    529        "\xCE\xB3\xCE\xB5\xCE\xB9\xCE\xB1 \xCE\xB5\xCE\xBA\xCE\xB5\xCE\xAF",
    530        "\xD8\xB3\xD9\x84\xD8\xA7\xD9\x85");
    531    w.IntProperty(
    532        "hall\xC3\xB3 \xC3\xBE"
    533        "arna",
    534        0x1234);
    535    w.StartObjectProperty(
    536        "\xE3\x81\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1\xE3\x81\xAF");
    537    {
    538      w.StartArrayProperty("\xD0\xBF\xD1\x80\xD0\xB8\xD0\xB2\xD0\xB5\xD1\x82");
    539      w.EndArray();
    540    }
    541    w.EndObject();
    542  }
    543  w.End();
    544 
    545  Check(w, expected);
    546 }
    547 
    548 void TestDeepNesting() {
    549  const char* expected =
    550      "\
    551 {\n\
    552 \"a\": [\n\
    553  {\n\
    554   \"a\": [\n\
    555    {\n\
    556     \"a\": [\n\
    557      {\n\
    558       \"a\": [\n\
    559        {\n\
    560         \"a\": [\n\
    561          {\n\
    562           \"a\": [\n\
    563            {\n\
    564             \"a\": [\n\
    565              {\n\
    566               \"a\": [\n\
    567                {\n\
    568                 \"a\": [\n\
    569                  {\n\
    570                   \"a\": [\n\
    571                    {\n\
    572                    }\n\
    573                   ]\n\
    574                  }\n\
    575                 ]\n\
    576                }\n\
    577               ]\n\
    578              }\n\
    579             ]\n\
    580            }\n\
    581           ]\n\
    582          }\n\
    583         ]\n\
    584        }\n\
    585       ]\n\
    586      }\n\
    587     ]\n\
    588    }\n\
    589   ]\n\
    590  }\n\
    591 ]\n\
    592 }\n\
    593 ";
    594 
    595  JSONWriter w(MakeUnique<StringWriteFunc>());
    596 
    597  w.Start();
    598  {
    599    static const int n = 10;
    600    for (int i = 0; i < n; i++) {
    601      w.StartArrayProperty("a");
    602      w.StartObjectElement();
    603    }
    604    for (int i = 0; i < n; i++) {
    605      w.EndObject();
    606      w.EndArray();
    607    }
    608  }
    609  w.End();
    610 
    611  Check(w, expected);
    612 }
    613 
    614 void TestEscapedPropertyNames() {
    615  const char* expected =
    616      "\
    617 {\"i\\t\": 1, \"array\\t\": [null, [{}], {\"o\\t\": {}}, \"s\"], \"d\": 3.33}\n\
    618 ";
    619 
    620  JSONWriter w(MakeUnique<StringWriteFunc>());
    621 
    622  w.Start(w.SingleLineStyle);
    623 
    624  w.IntProperty("i\t\0cut", 1);  // '\0' marks the end.
    625 
    626  w.StartArrayProperty("array\t");
    627  {
    628    w.NullElement();
    629 
    630    w.StartArrayElement(w.MultiLineStyle);  // style overridden from above
    631    {
    632      w.StartObjectElement();
    633      w.EndObject();
    634    }
    635    w.EndArray();
    636 
    637    w.StartObjectElement();
    638    {
    639      w.StartObjectProperty("o\t");
    640      w.EndObject();
    641    }
    642    w.EndObject();
    643 
    644    w.StringElement("s");
    645  }
    646  w.EndArray();
    647 
    648  w.DoubleProperty("d\0\t", 3.33);
    649 
    650  w.End();
    651 
    652  Check(w, expected);
    653 }
    654 
    655 int main(void) {
    656  TestBasicProperties();
    657  TestBasicElements();
    658  TestOneLineObject();
    659  TestOneLineJson();
    660  TestStringEscaping();
    661  TestDeepNesting();
    662  TestEscapedPropertyNames();
    663 
    664  return 0;
    665 }