Home | History | Annotate | Download | only in json
      1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "base/json/string_escape.h"
      6 
      7 #include "base/strings/string_util.h"
      8 #include "base/strings/utf_string_conversions.h"
      9 #include "testing/gtest/include/gtest/gtest.h"
     10 
     11 namespace base {
     12 
     13 TEST(JSONStringEscapeTest, EscapeUTF8) {
     14   const struct {
     15     const char* to_escape;
     16     const char* escaped;
     17   } cases[] = {
     18     {"\b\001aZ\"\\wee", "\\b\\u0001aZ\\\"\\\\wee"},
     19     {"a\b\f\n\r\t\v\1\\.\"z",
     20         "a\\b\\f\\n\\r\\t\\u000B\\u0001\\\\.\\\"z"},
     21     {"b\x0f\x7f\xf0\xff!",  // \xf0\xff is not a valid UTF-8 unit.
     22         "b\\u000F\x7F\xEF\xBF\xBD\xEF\xBF\xBD!"},
     23     {"c<>d", "c\\u003C>d"},
     24   };
     25 
     26   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
     27     const char* in_ptr = cases[i].to_escape;
     28     std::string in_str = in_ptr;
     29 
     30     std::string out;
     31     EscapeJSONString(in_ptr, false, &out);
     32     EXPECT_EQ(std::string(cases[i].escaped), out);
     33     EXPECT_TRUE(IsStringUTF8(out));
     34 
     35     out.erase();
     36     bool convert_ok = EscapeJSONString(in_str, false, &out);
     37     EXPECT_EQ(std::string(cases[i].escaped), out);
     38     EXPECT_TRUE(IsStringUTF8(out));
     39 
     40     if (convert_ok) {
     41       std::string fooout = GetQuotedJSONString(in_str);
     42       EXPECT_EQ("\"" + std::string(cases[i].escaped) + "\"", fooout);
     43       EXPECT_TRUE(IsStringUTF8(out));
     44     }
     45   }
     46 
     47   std::string in = cases[0].to_escape;
     48   std::string out;
     49   EscapeJSONString(in, false, &out);
     50   EXPECT_TRUE(IsStringUTF8(out));
     51 
     52   // test quoting
     53   std::string out_quoted;
     54   EscapeJSONString(in, true, &out_quoted);
     55   EXPECT_EQ(out.length() + 2, out_quoted.length());
     56   EXPECT_EQ(out_quoted.find(out), 1U);
     57   EXPECT_TRUE(IsStringUTF8(out_quoted));
     58 
     59   // now try with a NULL in the string
     60   std::string null_prepend = "test";
     61   null_prepend.push_back(0);
     62   in = null_prepend + in;
     63   std::string expected = "test\\u0000";
     64   expected += cases[0].escaped;
     65   out.clear();
     66   EscapeJSONString(in, false, &out);
     67   EXPECT_EQ(expected, out);
     68   EXPECT_TRUE(IsStringUTF8(out));
     69 }
     70 
     71 TEST(JSONStringEscapeTest, EscapeUTF16) {
     72   const struct {
     73     const wchar_t* to_escape;
     74     const char* escaped;
     75   } cases[] = {
     76     {L"b\uffb1\u00ff", "b\xEF\xBE\xB1\xC3\xBF"},
     77     {L"\b\001aZ\"\\wee", "\\b\\u0001aZ\\\"\\\\wee"},
     78     {L"a\b\f\n\r\t\v\1\\.\"z",
     79         "a\\b\\f\\n\\r\\t\\u000B\\u0001\\\\.\\\"z"},
     80     {L"b\x0f\x7f\xf0\xff!", "b\\u000F\x7F\xC3\xB0\xC3\xBF!"},
     81     {L"c<>d", "c\\u003C>d"},
     82   };
     83 
     84   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
     85     string16 in = WideToUTF16(cases[i].to_escape);
     86 
     87     std::string out;
     88     EscapeJSONString(in, false, &out);
     89     EXPECT_EQ(std::string(cases[i].escaped), out);
     90     EXPECT_TRUE(IsStringUTF8(out));
     91 
     92     out = GetQuotedJSONString(in);
     93     EXPECT_EQ("\"" + std::string(cases[i].escaped) + "\"", out);
     94     EXPECT_TRUE(IsStringUTF8(out));
     95   }
     96 
     97   string16 in = WideToUTF16(cases[0].to_escape);
     98   std::string out;
     99   EscapeJSONString(in, false, &out);
    100   EXPECT_TRUE(IsStringUTF8(out));
    101 
    102   // test quoting
    103   std::string out_quoted;
    104   EscapeJSONString(in, true, &out_quoted);
    105   EXPECT_EQ(out.length() + 2, out_quoted.length());
    106   EXPECT_EQ(out_quoted.find(out), 1U);
    107   EXPECT_TRUE(IsStringUTF8(out));
    108 
    109   // now try with a NULL in the string
    110   string16 null_prepend = WideToUTF16(L"test");
    111   null_prepend.push_back(0);
    112   in = null_prepend + in;
    113   std::string expected = "test\\u0000";
    114   expected += cases[0].escaped;
    115   out.clear();
    116   EscapeJSONString(in, false, &out);
    117   EXPECT_EQ(expected, out);
    118   EXPECT_TRUE(IsStringUTF8(out));
    119 }
    120 
    121 TEST(JSONStringEscapeTest, EscapeUTF16OutsideBMP) {
    122   {
    123     // {a, U+10300, !}, SMP.
    124     string16 test;
    125     test.push_back('a');
    126     test.push_back(0xD800);
    127     test.push_back(0xDF00);
    128     test.push_back('!');
    129     std::string actual;
    130     EXPECT_TRUE(EscapeJSONString(test, false, &actual));
    131     EXPECT_EQ("a\xF0\x90\x8C\x80!", actual);
    132   }
    133   {
    134     // {U+20021, U+2002B}, SIP.
    135     string16 test;
    136     test.push_back(0xD840);
    137     test.push_back(0xDC21);
    138     test.push_back(0xD840);
    139     test.push_back(0xDC2B);
    140     std::string actual;
    141     EXPECT_TRUE(EscapeJSONString(test, false, &actual));
    142     EXPECT_EQ("\xF0\xA0\x80\xA1\xF0\xA0\x80\xAB", actual);
    143   }
    144   {
    145     // {?, U+D800, @}, lone surrogate.
    146     string16 test;
    147     test.push_back('?');
    148     test.push_back(0xD800);
    149     test.push_back('@');
    150     std::string actual;
    151     EXPECT_FALSE(EscapeJSONString(test, false, &actual));
    152     EXPECT_EQ("?\xEF\xBF\xBD@", actual);
    153   }
    154 }
    155 
    156 TEST(JSONStringEscapeTest, EscapeBytes) {
    157   const struct {
    158     const char* to_escape;
    159     const char* escaped;
    160   } cases[] = {
    161     {"b\x0f\x7f\xf0\xff!", "b\\u000F\\u007F\\u00F0\\u00FF!"},
    162     {"\xe5\xc4\x4f\x05\xb6\xfd\0", "\\u00E5\\u00C4O\\u0005\\u00B6\\u00FD"},
    163   };
    164 
    165   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
    166     std::string in = std::string(cases[i].to_escape);
    167     EXPECT_FALSE(IsStringUTF8(in));
    168 
    169     EXPECT_EQ(std::string(cases[i].escaped),
    170         EscapeBytesAsInvalidJSONString(in, false));
    171     EXPECT_EQ("\"" + std::string(cases[i].escaped) + "\"",
    172         EscapeBytesAsInvalidJSONString(in, true));
    173   }
    174 
    175   const char kEmbedNull[] = { '\xab', '\x39', '\0', '\x9f', '\xab' };
    176   std::string in(kEmbedNull, ARRAYSIZE_UNSAFE(kEmbedNull));
    177   EXPECT_FALSE(IsStringUTF8(in));
    178   EXPECT_EQ(std::string("\\u00AB9\\u0000\\u009F\\u00AB"),
    179             EscapeBytesAsInvalidJSONString(in, false));
    180 }
    181 
    182 }  // namespace base
    183