1*6777b538SAndroid Build Coastguard Worker // Copyright 2013 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker
5*6777b538SAndroid Build Coastguard Worker #include "base/json/string_escape.h"
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker #include <stddef.h>
8*6777b538SAndroid Build Coastguard Worker
9*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_util.h"
10*6777b538SAndroid Build Coastguard Worker #include "base/strings/utf_string_conversions.h"
11*6777b538SAndroid Build Coastguard Worker #include "testing/gtest/include/gtest/gtest.h"
12*6777b538SAndroid Build Coastguard Worker
13*6777b538SAndroid Build Coastguard Worker namespace base {
14*6777b538SAndroid Build Coastguard Worker
TEST(JSONStringEscapeTest,EscapeUTF8)15*6777b538SAndroid Build Coastguard Worker TEST(JSONStringEscapeTest, EscapeUTF8) {
16*6777b538SAndroid Build Coastguard Worker const struct {
17*6777b538SAndroid Build Coastguard Worker const char* to_escape;
18*6777b538SAndroid Build Coastguard Worker const char* escaped;
19*6777b538SAndroid Build Coastguard Worker } cases[] = {
20*6777b538SAndroid Build Coastguard Worker {"\b\001aZ\"\\wee", "\\b\\u0001aZ\\\"\\\\wee"},
21*6777b538SAndroid Build Coastguard Worker {"a\b\f\n\r\t\v\1\\.\"z", "a\\b\\f\\n\\r\\t\\u000B\\u0001\\\\.\\\"z"},
22*6777b538SAndroid Build Coastguard Worker {"b\x0f\x7f\xf0\xff!", // \xf0\xff is not a valid UTF-8 unit.
23*6777b538SAndroid Build Coastguard Worker "b\\u000F\x7F\xEF\xBF\xBD\xEF\xBF\xBD!"},
24*6777b538SAndroid Build Coastguard Worker {"c<>d", "c\\u003C>d"},
25*6777b538SAndroid Build Coastguard Worker {"Hello\xE2\x80\xA8world", "Hello\\u2028world"}, // U+2028
26*6777b538SAndroid Build Coastguard Worker {"\xE2\x80\xA9purple", "\\u2029purple"}, // U+2029
27*6777b538SAndroid Build Coastguard Worker // Unicode non-characters.
28*6777b538SAndroid Build Coastguard Worker {"\xEF\xB7\x90", "\xEF\xB7\x90"}, // U+FDD0
29*6777b538SAndroid Build Coastguard Worker {"\xEF\xB7\x9F", "\xEF\xB7\x9F"}, // U+FDDF
30*6777b538SAndroid Build Coastguard Worker {"\xEF\xB7\xAF", "\xEF\xB7\xAF"}, // U+FDEF
31*6777b538SAndroid Build Coastguard Worker {"\xEF\xBF\xBE", "\xEF\xBF\xBE"}, // U+FFFE
32*6777b538SAndroid Build Coastguard Worker {"\xEF\xBF\xBF", "\xEF\xBF\xBF"}, // U+FFFF
33*6777b538SAndroid Build Coastguard Worker {"\xF0\x9F\xBF\xBE", "\xF0\x9F\xBF\xBE"}, // U+01FFFE
34*6777b538SAndroid Build Coastguard Worker {"\xF0\x9F\xBF\xBF", "\xF0\x9F\xBF\xBF"}, // U+01FFFF
35*6777b538SAndroid Build Coastguard Worker {"\xF0\xAF\xBF\xBE", "\xF0\xAF\xBF\xBE"}, // U+02FFFE
36*6777b538SAndroid Build Coastguard Worker {"\xF0\xAF\xBF\xBF", "\xF0\xAF\xBF\xBF"}, // U+02FFFF
37*6777b538SAndroid Build Coastguard Worker {"\xF0\xBF\xBF\xBE", "\xF0\xBF\xBF\xBE"}, // U+03FFFE
38*6777b538SAndroid Build Coastguard Worker {"\xF0\xBF\xBF\xBF", "\xF0\xBF\xBF\xBF"}, // U+03FFFF
39*6777b538SAndroid Build Coastguard Worker {"\xF1\x8F\xBF\xBE", "\xF1\x8F\xBF\xBE"}, // U+04FFFE
40*6777b538SAndroid Build Coastguard Worker {"\xF1\x8F\xBF\xBF", "\xF1\x8F\xBF\xBF"}, // U+04FFFF
41*6777b538SAndroid Build Coastguard Worker {"\xF1\x9F\xBF\xBE", "\xF1\x9F\xBF\xBE"}, // U+05FFFE
42*6777b538SAndroid Build Coastguard Worker {"\xF1\x9F\xBF\xBF", "\xF1\x9F\xBF\xBF"}, // U+05FFFF
43*6777b538SAndroid Build Coastguard Worker {"\xF1\xAF\xBF\xBE", "\xF1\xAF\xBF\xBE"}, // U+06FFFE
44*6777b538SAndroid Build Coastguard Worker {"\xF1\xAF\xBF\xBF", "\xF1\xAF\xBF\xBF"}, // U+06FFFF
45*6777b538SAndroid Build Coastguard Worker {"\xF1\xBF\xBF\xBE", "\xF1\xBF\xBF\xBE"}, // U+07FFFE
46*6777b538SAndroid Build Coastguard Worker {"\xF1\xBF\xBF\xBF", "\xF1\xBF\xBF\xBF"}, // U+07FFFF
47*6777b538SAndroid Build Coastguard Worker {"\xF2\x8F\xBF\xBE", "\xF2\x8F\xBF\xBE"}, // U+08FFFE
48*6777b538SAndroid Build Coastguard Worker {"\xF2\x8F\xBF\xBF", "\xF2\x8F\xBF\xBF"}, // U+08FFFF
49*6777b538SAndroid Build Coastguard Worker {"\xF2\x9F\xBF\xBE", "\xF2\x9F\xBF\xBE"}, // U+09FFFE
50*6777b538SAndroid Build Coastguard Worker {"\xF2\x9F\xBF\xBF", "\xF2\x9F\xBF\xBF"}, // U+09FFFF
51*6777b538SAndroid Build Coastguard Worker {"\xF2\xAF\xBF\xBE", "\xF2\xAF\xBF\xBE"}, // U+0AFFFE
52*6777b538SAndroid Build Coastguard Worker {"\xF2\xAF\xBF\xBF", "\xF2\xAF\xBF\xBF"}, // U+0AFFFF
53*6777b538SAndroid Build Coastguard Worker {"\xF2\xBF\xBF\xBE", "\xF2\xBF\xBF\xBE"}, // U+0BFFFE
54*6777b538SAndroid Build Coastguard Worker {"\xF2\xBF\xBF\xBF", "\xF2\xBF\xBF\xBF"}, // U+0BFFFF
55*6777b538SAndroid Build Coastguard Worker {"\xF3\x8F\xBF\xBE", "\xF3\x8F\xBF\xBE"}, // U+0CFFFE
56*6777b538SAndroid Build Coastguard Worker {"\xF3\x8F\xBF\xBF", "\xF3\x8F\xBF\xBF"}, // U+0CFFFF
57*6777b538SAndroid Build Coastguard Worker {"\xF3\x9F\xBF\xBE", "\xF3\x9F\xBF\xBE"}, // U+0DFFFE
58*6777b538SAndroid Build Coastguard Worker {"\xF3\x9F\xBF\xBF", "\xF3\x9F\xBF\xBF"}, // U+0DFFFF
59*6777b538SAndroid Build Coastguard Worker {"\xF3\xAF\xBF\xBE", "\xF3\xAF\xBF\xBE"}, // U+0EFFFE
60*6777b538SAndroid Build Coastguard Worker {"\xF3\xAF\xBF\xBF", "\xF3\xAF\xBF\xBF"}, // U+0EFFFF
61*6777b538SAndroid Build Coastguard Worker {"\xF3\xBF\xBF\xBE", "\xF3\xBF\xBF\xBE"}, // U+0FFFFE
62*6777b538SAndroid Build Coastguard Worker {"\xF3\xBF\xBF\xBF", "\xF3\xBF\xBF\xBF"}, // U+0FFFFF
63*6777b538SAndroid Build Coastguard Worker {"\xF4\x8F\xBF\xBE", "\xF4\x8F\xBF\xBE"}, // U+10FFFE
64*6777b538SAndroid Build Coastguard Worker {"\xF4\x8F\xBF\xBF", "\xF4\x8F\xBF\xBF"}, // U+10FFFF
65*6777b538SAndroid Build Coastguard Worker };
66*6777b538SAndroid Build Coastguard Worker
67*6777b538SAndroid Build Coastguard Worker for (const auto& i : cases) {
68*6777b538SAndroid Build Coastguard Worker const char* in_ptr = i.to_escape;
69*6777b538SAndroid Build Coastguard Worker std::string in_str = in_ptr;
70*6777b538SAndroid Build Coastguard Worker
71*6777b538SAndroid Build Coastguard Worker std::string out;
72*6777b538SAndroid Build Coastguard Worker EscapeJSONString(in_ptr, false, &out);
73*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(std::string(i.escaped), out);
74*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(IsStringUTF8AllowingNoncharacters(out));
75*6777b538SAndroid Build Coastguard Worker
76*6777b538SAndroid Build Coastguard Worker out.erase();
77*6777b538SAndroid Build Coastguard Worker EscapeJSONString(in_str, false, &out);
78*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(std::string(i.escaped), out);
79*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(IsStringUTF8AllowingNoncharacters(out));
80*6777b538SAndroid Build Coastguard Worker
81*6777b538SAndroid Build Coastguard Worker std::string fooout = GetQuotedJSONString(in_str);
82*6777b538SAndroid Build Coastguard Worker EXPECT_EQ("\"" + std::string(i.escaped) + "\"", fooout);
83*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(IsStringUTF8AllowingNoncharacters(out));
84*6777b538SAndroid Build Coastguard Worker }
85*6777b538SAndroid Build Coastguard Worker
86*6777b538SAndroid Build Coastguard Worker std::string in = cases[0].to_escape;
87*6777b538SAndroid Build Coastguard Worker std::string out;
88*6777b538SAndroid Build Coastguard Worker EscapeJSONString(in, false, &out);
89*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(IsStringUTF8AllowingNoncharacters(out));
90*6777b538SAndroid Build Coastguard Worker
91*6777b538SAndroid Build Coastguard Worker // test quoting
92*6777b538SAndroid Build Coastguard Worker std::string out_quoted;
93*6777b538SAndroid Build Coastguard Worker EscapeJSONString(in, true, &out_quoted);
94*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(out.length() + 2, out_quoted.length());
95*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(out_quoted.find(out), 1U);
96*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(IsStringUTF8AllowingNoncharacters(out_quoted));
97*6777b538SAndroid Build Coastguard Worker
98*6777b538SAndroid Build Coastguard Worker // now try with a NULL in the string
99*6777b538SAndroid Build Coastguard Worker std::string null_prepend = "test";
100*6777b538SAndroid Build Coastguard Worker null_prepend.push_back(0);
101*6777b538SAndroid Build Coastguard Worker in = null_prepend + in;
102*6777b538SAndroid Build Coastguard Worker std::string expected = "test\\u0000";
103*6777b538SAndroid Build Coastguard Worker expected += cases[0].escaped;
104*6777b538SAndroid Build Coastguard Worker out.clear();
105*6777b538SAndroid Build Coastguard Worker EscapeJSONString(in, false, &out);
106*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(expected, out);
107*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(IsStringUTF8AllowingNoncharacters(out));
108*6777b538SAndroid Build Coastguard Worker }
109*6777b538SAndroid Build Coastguard Worker
TEST(JSONStringEscapeTest,EscapeUTF16)110*6777b538SAndroid Build Coastguard Worker TEST(JSONStringEscapeTest, EscapeUTF16) {
111*6777b538SAndroid Build Coastguard Worker const struct {
112*6777b538SAndroid Build Coastguard Worker const wchar_t* to_escape;
113*6777b538SAndroid Build Coastguard Worker const char* escaped;
114*6777b538SAndroid Build Coastguard Worker } cases[] = {
115*6777b538SAndroid Build Coastguard Worker {L"b\uffb1\u00ff", "b\xEF\xBE\xB1\xC3\xBF"},
116*6777b538SAndroid Build Coastguard Worker {L"\b\001aZ\"\\wee", "\\b\\u0001aZ\\\"\\\\wee"},
117*6777b538SAndroid Build Coastguard Worker {L"a\b\f\n\r\t\v\1\\.\"z", "a\\b\\f\\n\\r\\t\\u000B\\u0001\\\\.\\\"z"},
118*6777b538SAndroid Build Coastguard Worker {L"b\x0F\x7F\xF0\xFF!", "b\\u000F\x7F\xC3\xB0\xC3\xBF!"},
119*6777b538SAndroid Build Coastguard Worker {L"c<>d", "c\\u003C>d"},
120*6777b538SAndroid Build Coastguard Worker {L"Hello\u2028world", "Hello\\u2028world"},
121*6777b538SAndroid Build Coastguard Worker {L"\u2029purple", "\\u2029purple"},
122*6777b538SAndroid Build Coastguard Worker // Unicode non-characters.
123*6777b538SAndroid Build Coastguard Worker {L"\uFDD0", "\xEF\xB7\x90"}, // U+FDD0
124*6777b538SAndroid Build Coastguard Worker {L"\uFDDF", "\xEF\xB7\x9F"}, // U+FDDF
125*6777b538SAndroid Build Coastguard Worker {L"\uFDEF", "\xEF\xB7\xAF"}, // U+FDEF
126*6777b538SAndroid Build Coastguard Worker {L"\uFFFE", "\xEF\xBF\xBE"}, // U+FFFE
127*6777b538SAndroid Build Coastguard Worker {L"\uFFFF", "\xEF\xBF\xBF"}, // U+FFFF
128*6777b538SAndroid Build Coastguard Worker {L"\U0001FFFE", "\xF0\x9F\xBF\xBE"}, // U+01FFFE
129*6777b538SAndroid Build Coastguard Worker {L"\U0001FFFF", "\xF0\x9F\xBF\xBF"}, // U+01FFFF
130*6777b538SAndroid Build Coastguard Worker {L"\U0002FFFE", "\xF0\xAF\xBF\xBE"}, // U+02FFFE
131*6777b538SAndroid Build Coastguard Worker {L"\U0002FFFF", "\xF0\xAF\xBF\xBF"}, // U+02FFFF
132*6777b538SAndroid Build Coastguard Worker {L"\U0003FFFE", "\xF0\xBF\xBF\xBE"}, // U+03FFFE
133*6777b538SAndroid Build Coastguard Worker {L"\U0003FFFF", "\xF0\xBF\xBF\xBF"}, // U+03FFFF
134*6777b538SAndroid Build Coastguard Worker {L"\U0004FFFE", "\xF1\x8F\xBF\xBE"}, // U+04FFFE
135*6777b538SAndroid Build Coastguard Worker {L"\U0004FFFF", "\xF1\x8F\xBF\xBF"}, // U+04FFFF
136*6777b538SAndroid Build Coastguard Worker {L"\U0005FFFE", "\xF1\x9F\xBF\xBE"}, // U+05FFFE
137*6777b538SAndroid Build Coastguard Worker {L"\U0005FFFF", "\xF1\x9F\xBF\xBF"}, // U+05FFFF
138*6777b538SAndroid Build Coastguard Worker {L"\U0006FFFE", "\xF1\xAF\xBF\xBE"}, // U+06FFFE
139*6777b538SAndroid Build Coastguard Worker {L"\U0006FFFF", "\xF1\xAF\xBF\xBF"}, // U+06FFFF
140*6777b538SAndroid Build Coastguard Worker {L"\U0007FFFE", "\xF1\xBF\xBF\xBE"}, // U+07FFFE
141*6777b538SAndroid Build Coastguard Worker {L"\U0007FFFF", "\xF1\xBF\xBF\xBF"}, // U+07FFFF
142*6777b538SAndroid Build Coastguard Worker {L"\U0008FFFE", "\xF2\x8F\xBF\xBE"}, // U+08FFFE
143*6777b538SAndroid Build Coastguard Worker {L"\U0008FFFF", "\xF2\x8F\xBF\xBF"}, // U+08FFFF
144*6777b538SAndroid Build Coastguard Worker {L"\U0009FFFE", "\xF2\x9F\xBF\xBE"}, // U+09FFFE
145*6777b538SAndroid Build Coastguard Worker {L"\U0009FFFF", "\xF2\x9F\xBF\xBF"}, // U+09FFFF
146*6777b538SAndroid Build Coastguard Worker {L"\U000AFFFE", "\xF2\xAF\xBF\xBE"}, // U+0AFFFE
147*6777b538SAndroid Build Coastguard Worker {L"\U000AFFFF", "\xF2\xAF\xBF\xBF"}, // U+0AFFFF
148*6777b538SAndroid Build Coastguard Worker {L"\U000BFFFE", "\xF2\xBF\xBF\xBE"}, // U+0BFFFE
149*6777b538SAndroid Build Coastguard Worker {L"\U000BFFFF", "\xF2\xBF\xBF\xBF"}, // U+0BFFFF
150*6777b538SAndroid Build Coastguard Worker {L"\U000CFFFE", "\xF3\x8F\xBF\xBE"}, // U+0CFFFE
151*6777b538SAndroid Build Coastguard Worker {L"\U000CFFFF", "\xF3\x8F\xBF\xBF"}, // U+0CFFFF
152*6777b538SAndroid Build Coastguard Worker {L"\U000DFFFE", "\xF3\x9F\xBF\xBE"}, // U+0DFFFE
153*6777b538SAndroid Build Coastguard Worker {L"\U000DFFFF", "\xF3\x9F\xBF\xBF"}, // U+0DFFFF
154*6777b538SAndroid Build Coastguard Worker {L"\U000EFFFE", "\xF3\xAF\xBF\xBE"}, // U+0EFFFE
155*6777b538SAndroid Build Coastguard Worker {L"\U000EFFFF", "\xF3\xAF\xBF\xBF"}, // U+0EFFFF
156*6777b538SAndroid Build Coastguard Worker {L"\U000FFFFE", "\xF3\xBF\xBF\xBE"}, // U+0FFFFE
157*6777b538SAndroid Build Coastguard Worker {L"\U000FFFFF", "\xF3\xBF\xBF\xBF"}, // U+0FFFFF
158*6777b538SAndroid Build Coastguard Worker {L"\U0010FFFE", "\xF4\x8F\xBF\xBE"}, // U+10FFFE
159*6777b538SAndroid Build Coastguard Worker {L"\U0010FFFF", "\xF4\x8F\xBF\xBF"}, // U+10FFFF
160*6777b538SAndroid Build Coastguard Worker };
161*6777b538SAndroid Build Coastguard Worker
162*6777b538SAndroid Build Coastguard Worker for (const auto& i : cases) {
163*6777b538SAndroid Build Coastguard Worker std::u16string in = WideToUTF16(i.to_escape);
164*6777b538SAndroid Build Coastguard Worker
165*6777b538SAndroid Build Coastguard Worker std::string out;
166*6777b538SAndroid Build Coastguard Worker EscapeJSONString(in, false, &out);
167*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(std::string(i.escaped), out);
168*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(IsStringUTF8AllowingNoncharacters(out));
169*6777b538SAndroid Build Coastguard Worker
170*6777b538SAndroid Build Coastguard Worker out = GetQuotedJSONString(in);
171*6777b538SAndroid Build Coastguard Worker EXPECT_EQ("\"" + std::string(i.escaped) + "\"", out);
172*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(IsStringUTF8AllowingNoncharacters(out));
173*6777b538SAndroid Build Coastguard Worker }
174*6777b538SAndroid Build Coastguard Worker
175*6777b538SAndroid Build Coastguard Worker std::u16string in = WideToUTF16(cases[0].to_escape);
176*6777b538SAndroid Build Coastguard Worker std::string out;
177*6777b538SAndroid Build Coastguard Worker EscapeJSONString(in, false, &out);
178*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(IsStringUTF8AllowingNoncharacters(out));
179*6777b538SAndroid Build Coastguard Worker
180*6777b538SAndroid Build Coastguard Worker // test quoting
181*6777b538SAndroid Build Coastguard Worker std::string out_quoted;
182*6777b538SAndroid Build Coastguard Worker EscapeJSONString(in, true, &out_quoted);
183*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(out.length() + 2, out_quoted.length());
184*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(out_quoted.find(out), 1U);
185*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(IsStringUTF8AllowingNoncharacters(out));
186*6777b538SAndroid Build Coastguard Worker
187*6777b538SAndroid Build Coastguard Worker // now try with a NULL in the string
188*6777b538SAndroid Build Coastguard Worker std::u16string null_prepend = u"test";
189*6777b538SAndroid Build Coastguard Worker null_prepend.push_back(0);
190*6777b538SAndroid Build Coastguard Worker in = null_prepend + in;
191*6777b538SAndroid Build Coastguard Worker std::string expected = "test\\u0000";
192*6777b538SAndroid Build Coastguard Worker expected += cases[0].escaped;
193*6777b538SAndroid Build Coastguard Worker out.clear();
194*6777b538SAndroid Build Coastguard Worker EscapeJSONString(in, false, &out);
195*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(expected, out);
196*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(IsStringUTF8AllowingNoncharacters(out));
197*6777b538SAndroid Build Coastguard Worker }
198*6777b538SAndroid Build Coastguard Worker
TEST(JSONStringEscapeTest,EscapeUTF16OutsideBMP)199*6777b538SAndroid Build Coastguard Worker TEST(JSONStringEscapeTest, EscapeUTF16OutsideBMP) {
200*6777b538SAndroid Build Coastguard Worker {
201*6777b538SAndroid Build Coastguard Worker // {a, U+10300, !}, SMP.
202*6777b538SAndroid Build Coastguard Worker std::u16string test;
203*6777b538SAndroid Build Coastguard Worker test.push_back('a');
204*6777b538SAndroid Build Coastguard Worker test.push_back(0xD800);
205*6777b538SAndroid Build Coastguard Worker test.push_back(0xDF00);
206*6777b538SAndroid Build Coastguard Worker test.push_back('!');
207*6777b538SAndroid Build Coastguard Worker std::string actual;
208*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(EscapeJSONString(test, false, &actual));
209*6777b538SAndroid Build Coastguard Worker EXPECT_EQ("a\xF0\x90\x8C\x80!", actual);
210*6777b538SAndroid Build Coastguard Worker }
211*6777b538SAndroid Build Coastguard Worker {
212*6777b538SAndroid Build Coastguard Worker // {U+20021, U+2002B}, SIP.
213*6777b538SAndroid Build Coastguard Worker std::u16string test;
214*6777b538SAndroid Build Coastguard Worker test.push_back(0xD840);
215*6777b538SAndroid Build Coastguard Worker test.push_back(0xDC21);
216*6777b538SAndroid Build Coastguard Worker test.push_back(0xD840);
217*6777b538SAndroid Build Coastguard Worker test.push_back(0xDC2B);
218*6777b538SAndroid Build Coastguard Worker std::string actual;
219*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(EscapeJSONString(test, false, &actual));
220*6777b538SAndroid Build Coastguard Worker EXPECT_EQ("\xF0\xA0\x80\xA1\xF0\xA0\x80\xAB", actual);
221*6777b538SAndroid Build Coastguard Worker }
222*6777b538SAndroid Build Coastguard Worker {
223*6777b538SAndroid Build Coastguard Worker // {?, U+D800, @}, lone surrogate.
224*6777b538SAndroid Build Coastguard Worker std::u16string test;
225*6777b538SAndroid Build Coastguard Worker test.push_back('?');
226*6777b538SAndroid Build Coastguard Worker test.push_back(0xD800);
227*6777b538SAndroid Build Coastguard Worker test.push_back('@');
228*6777b538SAndroid Build Coastguard Worker std::string actual;
229*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(EscapeJSONString(test, false, &actual));
230*6777b538SAndroid Build Coastguard Worker EXPECT_EQ("?\xEF\xBF\xBD@", actual);
231*6777b538SAndroid Build Coastguard Worker }
232*6777b538SAndroid Build Coastguard Worker }
233*6777b538SAndroid Build Coastguard Worker
TEST(JSONStringEscapeTest,EscapeBytes)234*6777b538SAndroid Build Coastguard Worker TEST(JSONStringEscapeTest, EscapeBytes) {
235*6777b538SAndroid Build Coastguard Worker const struct {
236*6777b538SAndroid Build Coastguard Worker const char* to_escape;
237*6777b538SAndroid Build Coastguard Worker const char* escaped;
238*6777b538SAndroid Build Coastguard Worker } cases[] = {
239*6777b538SAndroid Build Coastguard Worker {"b\x0f\x7f\xf0\xff!", "b\\u000F\\u007F\\u00F0\\u00FF!"},
240*6777b538SAndroid Build Coastguard Worker {"\xe5\xc4\x4f\x05\xb6\xfd", "\\u00E5\\u00C4O\\u0005\\u00B6\\u00FD"},
241*6777b538SAndroid Build Coastguard Worker };
242*6777b538SAndroid Build Coastguard Worker
243*6777b538SAndroid Build Coastguard Worker for (const auto& i : cases) {
244*6777b538SAndroid Build Coastguard Worker std::string in = std::string(i.to_escape);
245*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(IsStringUTF8AllowingNoncharacters(in));
246*6777b538SAndroid Build Coastguard Worker
247*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(std::string(i.escaped),
248*6777b538SAndroid Build Coastguard Worker EscapeBytesAsInvalidJSONString(in, false));
249*6777b538SAndroid Build Coastguard Worker EXPECT_EQ("\"" + std::string(i.escaped) + "\"",
250*6777b538SAndroid Build Coastguard Worker EscapeBytesAsInvalidJSONString(in, true));
251*6777b538SAndroid Build Coastguard Worker }
252*6777b538SAndroid Build Coastguard Worker
253*6777b538SAndroid Build Coastguard Worker const char kEmbedNull[] = { '\xab', '\x39', '\0', '\x9f', '\xab' };
254*6777b538SAndroid Build Coastguard Worker std::string in(kEmbedNull, std::size(kEmbedNull));
255*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(IsStringUTF8AllowingNoncharacters(in));
256*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(std::string("\\u00AB9\\u0000\\u009F\\u00AB"),
257*6777b538SAndroid Build Coastguard Worker EscapeBytesAsInvalidJSONString(in, false));
258*6777b538SAndroid Build Coastguard Worker }
259*6777b538SAndroid Build Coastguard Worker
260*6777b538SAndroid Build Coastguard Worker } // namespace base
261