15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/json/string_escape.h" 65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/strings/string_util.h" 8868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace base { 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST(JSONStringEscapeTest, EscapeUTF8) { 145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const struct { 155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const char* to_escape; 165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const char* escaped; 175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } cases[] = { 185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) {"\b\001aZ\"\\wee", "\\b\\u0001aZ\\\"\\\\wee"}, 195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) {"a\b\f\n\r\t\v\1\\.\"z", 205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "a\\b\\f\\n\\r\\t\\u000B\\u0001\\\\.\\\"z"}, 215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) {"b\x0f\x7f\xf0\xff!", // \xf0\xff is not a valid UTF-8 unit. 225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "b\\u000F\x7F\xEF\xBF\xBD\xEF\xBF\xBD!"}, 235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) {"c<>d", "c\\u003C>d"}, 245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) }; 255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { 275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const char* in_ptr = cases[i].to_escape; 2858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) std::string in_str = in_ptr; 295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string out; 315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EscapeJSONString(in_ptr, false, &out); 325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ(std::string(cases[i].escaped), out); 335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_TRUE(IsStringUTF8(out)); 345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) out.erase(); 365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) bool convert_ok = EscapeJSONString(in_str, false, &out); 375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ(std::string(cases[i].escaped), out); 385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_TRUE(IsStringUTF8(out)); 395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (convert_ok) { 415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::string fooout = GetQuotedJSONString(in_str); 425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ("\"" + std::string(cases[i].escaped) + "\"", fooout); 435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_TRUE(IsStringUTF8(out)); 445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::string in = cases[0].to_escape; 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string out; 495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EscapeJSONString(in, false, &out); 505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_TRUE(IsStringUTF8(out)); 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // test quoting 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string out_quoted; 545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EscapeJSONString(in, true, &out_quoted); 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(out.length() + 2, out_quoted.length()); 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(out_quoted.find(out), 1U); 575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_TRUE(IsStringUTF8(out_quoted)); 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // now try with a NULL in the string 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string null_prepend = "test"; 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) null_prepend.push_back(0); 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) in = null_prepend + in; 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string expected = "test\\u0000"; 645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) expected += cases[0].escaped; 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) out.clear(); 665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EscapeJSONString(in, false, &out); 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(expected, out); 685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_TRUE(IsStringUTF8(out)); 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST(JSONStringEscapeTest, EscapeUTF16) { 725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const struct { 735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const wchar_t* to_escape; 745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const char* escaped; 755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } cases[] = { 765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) {L"b\uffb1\u00ff", "b\xEF\xBE\xB1\xC3\xBF"}, 775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) {L"\b\001aZ\"\\wee", "\\b\\u0001aZ\\\"\\\\wee"}, 785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) {L"a\b\f\n\r\t\v\1\\.\"z", 795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "a\\b\\f\\n\\r\\t\\u000B\\u0001\\\\.\\\"z"}, 805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) {L"b\x0f\x7f\xf0\xff!", "b\\u000F\x7F\xC3\xB0\xC3\xBF!"}, 815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) {L"c<>d", "c\\u003C>d"}, 825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) }; 835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { 855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) string16 in = WideToUTF16(cases[i].to_escape); 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string out; 885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EscapeJSONString(in, false, &out); 895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ(std::string(cases[i].escaped), out); 905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_TRUE(IsStringUTF8(out)); 915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) out = GetQuotedJSONString(in); 935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ("\"" + std::string(cases[i].escaped) + "\"", out); 945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_TRUE(IsStringUTF8(out)); 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) string16 in = WideToUTF16(cases[0].to_escape); 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string out; 995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EscapeJSONString(in, false, &out); 1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_TRUE(IsStringUTF8(out)); 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // test quoting 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string out_quoted; 1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EscapeJSONString(in, true, &out_quoted); 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(out.length() + 2, out_quoted.length()); 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(out_quoted.find(out), 1U); 1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_TRUE(IsStringUTF8(out)); 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // now try with a NULL in the string 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string16 null_prepend = WideToUTF16(L"test"); 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) null_prepend.push_back(0); 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) in = null_prepend + in; 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string expected = "test\\u0000"; 1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) expected += cases[0].escaped; 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) out.clear(); 1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EscapeJSONString(in, false, &out); 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(expected, out); 1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_TRUE(IsStringUTF8(out)); 1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST(JSONStringEscapeTest, EscapeUTF16OutsideBMP) { 1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) { 1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // {a, U+10300, !}, SMP. 1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) string16 test; 1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) test.push_back('a'); 1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) test.push_back(0xD800); 1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) test.push_back(0xDF00); 1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) test.push_back('!'); 1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::string actual; 1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_TRUE(EscapeJSONString(test, false, &actual)); 1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ("a\xF0\x90\x8C\x80!", actual); 1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) { 1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // {U+20021, U+2002B}, SIP. 1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) string16 test; 1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) test.push_back(0xD840); 1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) test.push_back(0xDC21); 1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) test.push_back(0xD840); 1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) test.push_back(0xDC2B); 1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::string actual; 1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_TRUE(EscapeJSONString(test, false, &actual)); 1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ("\xF0\xA0\x80\xA1\xF0\xA0\x80\xAB", actual); 1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) { 1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // {?, U+D800, @}, lone surrogate. 1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) string16 test; 1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) test.push_back('?'); 1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) test.push_back(0xD800); 1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) test.push_back('@'); 1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::string actual; 1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_FALSE(EscapeJSONString(test, false, &actual)); 1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ("?\xEF\xBF\xBD@", actual); 1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST(JSONStringEscapeTest, EscapeBytes) { 1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const struct { 1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const char* to_escape; 1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const char* escaped; 1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } cases[] = { 1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) {"b\x0f\x7f\xf0\xff!", "b\\u000F\\u007F\\u00F0\\u00FF!"}, 1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) {"\xe5\xc4\x4f\x05\xb6\xfd\0", "\\u00E5\\u00C4O\\u0005\\u00B6\\u00FD"}, 1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) }; 1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { 1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::string in = std::string(cases[i].to_escape); 1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_FALSE(IsStringUTF8(in)); 1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ(std::string(cases[i].escaped), 1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EscapeBytesAsInvalidJSONString(in, false)); 1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ("\"" + std::string(cases[i].escaped) + "\"", 1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EscapeBytesAsInvalidJSONString(in, true)); 1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const char kEmbedNull[] = { '\xab', '\x39', '\0', '\x9f', '\xab' }; 1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::string in(kEmbedNull, ARRAYSIZE_UNSAFE(kEmbedNull)); 1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_FALSE(IsStringUTF8(in)); 1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ(std::string("\\u00AB9\\u0000\\u009F\\u00AB"), 1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EscapeBytesAsInvalidJSONString(in, false)); 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace base 183