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