]>
Commit | Line | Data |
---|---|---|
31f18b77 FG |
1 | // Tencent is pleased to support the open source community by making RapidJSON available. |
2 | // | |
3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. | |
4 | // | |
5 | // Licensed under the MIT License (the "License"); you may not use this file except | |
6 | // in compliance with the License. You may obtain a copy of the License at | |
7 | // | |
8 | // http://opensource.org/licenses/MIT | |
9 | // | |
10 | // Unless required by applicable law or agreed to in writing, software distributed | |
11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR | |
12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the | |
13 | // specific language governing permissions and limitations under the License. | |
14 | ||
15 | #include "unittest.h" | |
16 | ||
17 | #include "rapidjson/reader.h" | |
18 | #include "rapidjson/internal/dtoa.h" | |
19 | #include "rapidjson/internal/itoa.h" | |
20 | #include "rapidjson/memorystream.h" | |
21 | ||
22 | #include <limits> | |
23 | ||
24 | using namespace rapidjson; | |
25 | ||
26 | RAPIDJSON_DIAG_PUSH | |
27 | #ifdef __GNUC__ | |
28 | RAPIDJSON_DIAG_OFF(effc++) | |
29 | RAPIDJSON_DIAG_OFF(float-equal) | |
30 | RAPIDJSON_DIAG_OFF(missing-noreturn) | |
31 | #if __GNUC__ >= 7 | |
32 | RAPIDJSON_DIAG_OFF(dangling-else) | |
33 | #endif | |
34 | #endif // __GNUC__ | |
35 | ||
36 | #ifdef __clang__ | |
37 | RAPIDJSON_DIAG_OFF(variadic-macros) | |
38 | RAPIDJSON_DIAG_OFF(c++98-compat-pedantic) | |
39 | #endif | |
40 | ||
41 | template<bool expect> | |
42 | struct ParseBoolHandler : BaseReaderHandler<UTF8<>, ParseBoolHandler<expect> > { | |
43 | ParseBoolHandler() : step_(0) {} | |
44 | bool Default() { ADD_FAILURE(); return false; } | |
45 | // gcc 4.8.x generates warning in EXPECT_EQ(bool, bool) on this gtest version. | |
46 | // Workaround with EXPECT_TRUE(). | |
47 | bool Bool(bool b) { /*EXPECT_EQ(expect, b); */EXPECT_TRUE(expect == b); ++step_; return true; } | |
48 | ||
49 | unsigned step_; | |
50 | }; | |
51 | ||
52 | TEST(Reader, ParseTrue) { | |
53 | StringStream s("true"); | |
54 | ParseBoolHandler<true> h; | |
55 | Reader reader; | |
56 | reader.Parse(s, h); | |
57 | EXPECT_EQ(1u, h.step_); | |
58 | } | |
59 | ||
60 | TEST(Reader, ParseFalse) { | |
61 | StringStream s("false"); | |
62 | ParseBoolHandler<false> h; | |
63 | Reader reader; | |
64 | reader.Parse(s, h); | |
65 | EXPECT_EQ(1u, h.step_); | |
66 | } | |
67 | ||
68 | struct ParseIntHandler : BaseReaderHandler<UTF8<>, ParseIntHandler> { | |
69 | ParseIntHandler() : step_(0), actual_() {} | |
70 | bool Default() { ADD_FAILURE(); return false; } | |
71 | bool Int(int i) { actual_ = i; step_++; return true; } | |
72 | ||
73 | unsigned step_; | |
74 | int actual_; | |
75 | }; | |
76 | ||
77 | struct ParseUintHandler : BaseReaderHandler<UTF8<>, ParseUintHandler> { | |
78 | ParseUintHandler() : step_(0), actual_() {} | |
79 | bool Default() { ADD_FAILURE(); return false; } | |
80 | bool Uint(unsigned i) { actual_ = i; step_++; return true; } | |
81 | ||
82 | unsigned step_; | |
83 | unsigned actual_; | |
84 | }; | |
85 | ||
86 | struct ParseInt64Handler : BaseReaderHandler<UTF8<>, ParseInt64Handler> { | |
87 | ParseInt64Handler() : step_(0), actual_() {} | |
88 | bool Default() { ADD_FAILURE(); return false; } | |
89 | bool Int64(int64_t i) { actual_ = i; step_++; return true; } | |
90 | ||
91 | unsigned step_; | |
92 | int64_t actual_; | |
93 | }; | |
94 | ||
95 | struct ParseUint64Handler : BaseReaderHandler<UTF8<>, ParseUint64Handler> { | |
96 | ParseUint64Handler() : step_(0), actual_() {} | |
97 | bool Default() { ADD_FAILURE(); return false; } | |
98 | bool Uint64(uint64_t i) { actual_ = i; step_++; return true; } | |
99 | ||
100 | unsigned step_; | |
101 | uint64_t actual_; | |
102 | }; | |
103 | ||
104 | struct ParseDoubleHandler : BaseReaderHandler<UTF8<>, ParseDoubleHandler> { | |
105 | ParseDoubleHandler() : step_(0), actual_() {} | |
106 | bool Default() { ADD_FAILURE(); return false; } | |
107 | bool Double(double d) { actual_ = d; step_++; return true; } | |
108 | ||
109 | unsigned step_; | |
110 | double actual_; | |
111 | }; | |
112 | ||
113 | TEST(Reader, ParseNumber_Integer) { | |
114 | #define TEST_INTEGER(Handler, str, x) \ | |
115 | { \ | |
116 | StringStream s(str); \ | |
117 | Handler h; \ | |
118 | Reader reader; \ | |
119 | reader.Parse(s, h); \ | |
120 | EXPECT_EQ(1u, h.step_); \ | |
121 | EXPECT_EQ(x, h.actual_); \ | |
122 | } | |
123 | ||
124 | TEST_INTEGER(ParseUintHandler, "0", 0u); | |
125 | TEST_INTEGER(ParseUintHandler, "123", 123u); | |
126 | TEST_INTEGER(ParseUintHandler, "2147483648", 2147483648u); // 2^31 - 1 (cannot be stored in int) | |
127 | TEST_INTEGER(ParseUintHandler, "4294967295", 4294967295u); | |
128 | ||
129 | TEST_INTEGER(ParseIntHandler, "-123", -123); | |
130 | TEST_INTEGER(ParseIntHandler, "-2147483648", static_cast<int32_t>(0x80000000)); // -2^31 (min of int) | |
131 | ||
132 | TEST_INTEGER(ParseUint64Handler, "4294967296", RAPIDJSON_UINT64_C2(1, 0)); // 2^32 (max of unsigned + 1, force to use uint64_t) | |
133 | TEST_INTEGER(ParseUint64Handler, "18446744073709551615", RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0xFFFFFFFF)); // 2^64 - 1 (max of uint64_t) | |
134 | ||
135 | TEST_INTEGER(ParseInt64Handler, "-2147483649", static_cast<int64_t>(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x7FFFFFFF))); // -2^31 -1 (min of int - 1, force to use int64_t) | |
136 | TEST_INTEGER(ParseInt64Handler, "-9223372036854775808", static_cast<int64_t>(RAPIDJSON_UINT64_C2(0x80000000, 0x00000000))); // -2^63 (min of int64_t) | |
137 | ||
138 | // Random test for uint32_t/int32_t | |
139 | { | |
140 | union { | |
141 | uint32_t u; | |
142 | int32_t i; | |
143 | }u; | |
144 | Random r; | |
145 | ||
146 | for (unsigned i = 0; i < 100000; i++) { | |
147 | u.u = r(); | |
148 | ||
149 | char buffer[32]; | |
150 | *internal::u32toa(u.u, buffer) = '\0'; | |
151 | TEST_INTEGER(ParseUintHandler, buffer, u.u); | |
152 | ||
153 | if (u.i < 0) { | |
154 | *internal::i32toa(u.i, buffer) = '\0'; | |
155 | TEST_INTEGER(ParseIntHandler, buffer, u.i); | |
156 | } | |
157 | } | |
158 | } | |
159 | ||
160 | // Random test for uint64_t/int64_t | |
161 | { | |
162 | union { | |
163 | uint64_t u; | |
164 | int64_t i; | |
165 | }u; | |
166 | Random r; | |
167 | ||
168 | for (unsigned i = 0; i < 100000; i++) { | |
169 | u.u = uint64_t(r()) << 32; | |
170 | u.u |= r(); | |
171 | ||
172 | char buffer[32]; | |
173 | if (u.u > uint64_t(4294967295u)) { | |
174 | *internal::u64toa(u.u, buffer) = '\0'; | |
175 | TEST_INTEGER(ParseUint64Handler, buffer, u.u); | |
176 | } | |
177 | ||
178 | if (u.i < -int64_t(2147483648u)) { | |
179 | *internal::i64toa(u.i, buffer) = '\0'; | |
180 | TEST_INTEGER(ParseInt64Handler, buffer, u.i); | |
181 | } | |
182 | } | |
183 | } | |
184 | #undef TEST_INTEGER | |
185 | } | |
186 | ||
187 | template<bool fullPrecision> | |
188 | static void TestParseDouble() { | |
189 | #define TEST_DOUBLE(fullPrecision, str, x) \ | |
190 | { \ | |
191 | StringStream s(str); \ | |
192 | ParseDoubleHandler h; \ | |
193 | Reader reader; \ | |
194 | ASSERT_EQ(kParseErrorNone, reader.Parse<fullPrecision ? kParseFullPrecisionFlag : 0>(s, h).Code()); \ | |
195 | EXPECT_EQ(1u, h.step_); \ | |
196 | internal::Double e(x), a(h.actual_); \ | |
197 | if (fullPrecision) { \ | |
198 | EXPECT_EQ(e.Uint64Value(), a.Uint64Value()); \ | |
199 | if (e.Uint64Value() != a.Uint64Value()) \ | |
200 | printf(" String: %s\n Actual: %.17g\nExpected: %.17g\n", str, h.actual_, x); \ | |
201 | } \ | |
202 | else { \ | |
203 | EXPECT_EQ(e.Sign(), a.Sign()); /* for 0.0 != -0.0 */ \ | |
204 | EXPECT_DOUBLE_EQ(x, h.actual_); \ | |
205 | } \ | |
206 | } | |
207 | ||
208 | TEST_DOUBLE(fullPrecision, "0.0", 0.0); | |
209 | TEST_DOUBLE(fullPrecision, "-0.0", -0.0); // For checking issue #289 | |
210 | TEST_DOUBLE(fullPrecision, "1.0", 1.0); | |
211 | TEST_DOUBLE(fullPrecision, "-1.0", -1.0); | |
212 | TEST_DOUBLE(fullPrecision, "1.5", 1.5); | |
213 | TEST_DOUBLE(fullPrecision, "-1.5", -1.5); | |
214 | TEST_DOUBLE(fullPrecision, "3.1416", 3.1416); | |
215 | TEST_DOUBLE(fullPrecision, "1E10", 1E10); | |
216 | TEST_DOUBLE(fullPrecision, "1e10", 1e10); | |
217 | TEST_DOUBLE(fullPrecision, "1E+10", 1E+10); | |
218 | TEST_DOUBLE(fullPrecision, "1E-10", 1E-10); | |
219 | TEST_DOUBLE(fullPrecision, "-1E10", -1E10); | |
220 | TEST_DOUBLE(fullPrecision, "-1e10", -1e10); | |
221 | TEST_DOUBLE(fullPrecision, "-1E+10", -1E+10); | |
222 | TEST_DOUBLE(fullPrecision, "-1E-10", -1E-10); | |
223 | TEST_DOUBLE(fullPrecision, "1.234E+10", 1.234E+10); | |
224 | TEST_DOUBLE(fullPrecision, "1.234E-10", 1.234E-10); | |
225 | TEST_DOUBLE(fullPrecision, "1.79769e+308", 1.79769e+308); | |
226 | TEST_DOUBLE(fullPrecision, "2.22507e-308", 2.22507e-308); | |
227 | TEST_DOUBLE(fullPrecision, "-1.79769e+308", -1.79769e+308); | |
228 | TEST_DOUBLE(fullPrecision, "-2.22507e-308", -2.22507e-308); | |
229 | TEST_DOUBLE(fullPrecision, "4.9406564584124654e-324", 4.9406564584124654e-324); // minimum denormal | |
230 | TEST_DOUBLE(fullPrecision, "2.2250738585072009e-308", 2.2250738585072009e-308); // Max subnormal double | |
231 | TEST_DOUBLE(fullPrecision, "2.2250738585072014e-308", 2.2250738585072014e-308); // Min normal positive double | |
232 | TEST_DOUBLE(fullPrecision, "1.7976931348623157e+308", 1.7976931348623157e+308); // Max double | |
233 | TEST_DOUBLE(fullPrecision, "1e-10000", 0.0); // must underflow | |
234 | TEST_DOUBLE(fullPrecision, "18446744073709551616", 18446744073709551616.0); // 2^64 (max of uint64_t + 1, force to use double) | |
235 | TEST_DOUBLE(fullPrecision, "-9223372036854775809", -9223372036854775809.0); // -2^63 - 1(min of int64_t + 1, force to use double) | |
236 | TEST_DOUBLE(fullPrecision, "0.9868011474609375", 0.9868011474609375); // https://github.com/miloyip/rapidjson/issues/120 | |
237 | TEST_DOUBLE(fullPrecision, "123e34", 123e34); // Fast Path Cases In Disguise | |
238 | TEST_DOUBLE(fullPrecision, "45913141877270640000.0", 45913141877270640000.0); | |
239 | TEST_DOUBLE(fullPrecision, "2.2250738585072011e-308", 2.2250738585072011e-308); // http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/ | |
240 | TEST_DOUBLE(fullPrecision, "1e-00011111111111", 0.0); // Issue #313 | |
241 | TEST_DOUBLE(fullPrecision, "-1e-00011111111111", -0.0); | |
242 | TEST_DOUBLE(fullPrecision, "1e-214748363", 0.0); // Maximum supported negative exponent | |
243 | TEST_DOUBLE(fullPrecision, "1e-214748364", 0.0); | |
244 | TEST_DOUBLE(fullPrecision, "1e-21474836311", 0.0); | |
245 | TEST_DOUBLE(fullPrecision, "0.017976931348623157e+310", 1.7976931348623157e+308); // Max double in another form | |
246 | ||
247 | // Since | |
248 | // abs((2^-1022 - 2^-1074) - 2.2250738585072012e-308) = 3.109754131239141401123495768877590405345064751974375599... �� 10^-324 | |
249 | // abs((2^-1022) - 2.2250738585072012e-308) = 1.830902327173324040642192159804623318305533274168872044... �� 10 ^ -324 | |
250 | // So 2.2250738585072012e-308 should round to 2^-1022 = 2.2250738585072014e-308 | |
251 | TEST_DOUBLE(fullPrecision, "2.2250738585072012e-308", 2.2250738585072014e-308); // http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/ | |
252 | ||
253 | // More closer to normal/subnormal boundary | |
254 | // boundary = 2^-1022 - 2^-1075 = 2.225073858507201136057409796709131975934819546351645648... �� 10^-308 | |
255 | TEST_DOUBLE(fullPrecision, "2.22507385850720113605740979670913197593481954635164564e-308", 2.2250738585072009e-308); | |
256 | TEST_DOUBLE(fullPrecision, "2.22507385850720113605740979670913197593481954635164565e-308", 2.2250738585072014e-308); | |
257 | ||
258 | // 1.0 is in (1.0 - 2^-54, 1.0 + 2^-53) | |
259 | // 1.0 - 2^-54 = 0.999999999999999944488848768742172978818416595458984375 | |
260 | TEST_DOUBLE(fullPrecision, "0.999999999999999944488848768742172978818416595458984375", 1.0); // round to even | |
261 | TEST_DOUBLE(fullPrecision, "0.999999999999999944488848768742172978818416595458984374", 0.99999999999999989); // previous double | |
262 | TEST_DOUBLE(fullPrecision, "0.999999999999999944488848768742172978818416595458984376", 1.0); // next double | |
263 | // 1.0 + 2^-53 = 1.00000000000000011102230246251565404236316680908203125 | |
264 | TEST_DOUBLE(fullPrecision, "1.00000000000000011102230246251565404236316680908203125", 1.0); // round to even | |
265 | TEST_DOUBLE(fullPrecision, "1.00000000000000011102230246251565404236316680908203124", 1.0); // previous double | |
266 | TEST_DOUBLE(fullPrecision, "1.00000000000000011102230246251565404236316680908203126", 1.00000000000000022); // next double | |
267 | ||
268 | // Numbers from https://github.com/floitsch/double-conversion/blob/master/test/cctest/test-strtod.cc | |
269 | ||
270 | TEST_DOUBLE(fullPrecision, "72057594037927928.0", 72057594037927928.0); | |
271 | TEST_DOUBLE(fullPrecision, "72057594037927936.0", 72057594037927936.0); | |
272 | TEST_DOUBLE(fullPrecision, "72057594037927932.0", 72057594037927936.0); | |
273 | TEST_DOUBLE(fullPrecision, "7205759403792793199999e-5", 72057594037927928.0); | |
274 | TEST_DOUBLE(fullPrecision, "7205759403792793200001e-5", 72057594037927936.0); | |
275 | ||
276 | TEST_DOUBLE(fullPrecision, "9223372036854774784.0", 9223372036854774784.0); | |
277 | TEST_DOUBLE(fullPrecision, "9223372036854775808.0", 9223372036854775808.0); | |
278 | TEST_DOUBLE(fullPrecision, "9223372036854775296.0", 9223372036854775808.0); | |
279 | TEST_DOUBLE(fullPrecision, "922337203685477529599999e-5", 9223372036854774784.0); | |
280 | TEST_DOUBLE(fullPrecision, "922337203685477529600001e-5", 9223372036854775808.0); | |
281 | ||
282 | TEST_DOUBLE(fullPrecision, "10141204801825834086073718800384", 10141204801825834086073718800384.0); | |
283 | TEST_DOUBLE(fullPrecision, "10141204801825835211973625643008", 10141204801825835211973625643008.0); | |
284 | TEST_DOUBLE(fullPrecision, "10141204801825834649023672221696", 10141204801825835211973625643008.0); | |
285 | TEST_DOUBLE(fullPrecision, "1014120480182583464902367222169599999e-5", 10141204801825834086073718800384.0); | |
286 | TEST_DOUBLE(fullPrecision, "1014120480182583464902367222169600001e-5", 10141204801825835211973625643008.0); | |
287 | ||
288 | TEST_DOUBLE(fullPrecision, "5708990770823838890407843763683279797179383808", 5708990770823838890407843763683279797179383808.0); | |
289 | TEST_DOUBLE(fullPrecision, "5708990770823839524233143877797980545530986496", 5708990770823839524233143877797980545530986496.0); | |
290 | TEST_DOUBLE(fullPrecision, "5708990770823839207320493820740630171355185152", 5708990770823839524233143877797980545530986496.0); | |
291 | TEST_DOUBLE(fullPrecision, "5708990770823839207320493820740630171355185151999e-3", 5708990770823838890407843763683279797179383808.0); | |
292 | TEST_DOUBLE(fullPrecision, "5708990770823839207320493820740630171355185152001e-3", 5708990770823839524233143877797980545530986496.0); | |
293 | ||
294 | { | |
295 | char n1e308[310]; // '1' followed by 308 '0' | |
296 | n1e308[0] = '1'; | |
297 | for (int i = 1; i < 309; i++) | |
298 | n1e308[i] = '0'; | |
299 | n1e308[309] = '\0'; | |
300 | TEST_DOUBLE(fullPrecision, n1e308, 1E308); | |
301 | } | |
302 | ||
303 | // Cover trimming | |
304 | TEST_DOUBLE(fullPrecision, | |
305 | "2.22507385850720113605740979670913197593481954635164564802342610972482222202107694551652952390813508" | |
306 | "7914149158913039621106870086438694594645527657207407820621743379988141063267329253552286881372149012" | |
307 | "9811224514518898490572223072852551331557550159143974763979834118019993239625482890171070818506906306" | |
308 | "6665599493827577257201576306269066333264756530000924588831643303777979186961204949739037782970490505" | |
309 | "1080609940730262937128958950003583799967207254304360284078895771796150945516748243471030702609144621" | |
310 | "5722898802581825451803257070188608721131280795122334262883686223215037756666225039825343359745688844" | |
311 | "2390026549819838548794829220689472168983109969836584681402285424333066033985088644580400103493397042" | |
312 | "7567186443383770486037861622771738545623065874679014086723327636718751234567890123456789012345678901" | |
313 | "e-308", | |
314 | 2.2250738585072014e-308); | |
315 | ||
316 | { | |
317 | static const unsigned count = 100; // Tested with 1000000 locally | |
318 | Random r; | |
319 | Reader reader; // Reusing reader to prevent heap allocation | |
320 | ||
321 | // Exhaustively test different exponents with random significant | |
322 | for (uint64_t exp = 0; exp < 2047; exp++) { | |
323 | ; | |
324 | for (unsigned i = 0; i < count; i++) { | |
325 | // Need to call r() in two statements for cross-platform coherent sequence. | |
326 | uint64_t u = (exp << 52) | uint64_t(r() & 0x000FFFFF) << 32; | |
327 | u |= uint64_t(r()); | |
328 | internal::Double d = internal::Double(u); | |
329 | ||
330 | char buffer[32]; | |
331 | *internal::dtoa(d.Value(), buffer) = '\0'; | |
332 | ||
333 | StringStream s(buffer); | |
334 | ParseDoubleHandler h; | |
335 | ASSERT_EQ(kParseErrorNone, reader.Parse<fullPrecision ? kParseFullPrecisionFlag : 0>(s, h).Code()); | |
336 | EXPECT_EQ(1u, h.step_); | |
337 | internal::Double a(h.actual_); | |
338 | if (fullPrecision) { | |
339 | EXPECT_EQ(d.Uint64Value(), a.Uint64Value()); | |
340 | if (d.Uint64Value() != a.Uint64Value()) | |
341 | printf(" String: %s\n Actual: %.17g\nExpected: %.17g\n", buffer, h.actual_, d.Value()); | |
342 | } | |
343 | else { | |
344 | EXPECT_EQ(d.Sign(), a.Sign()); // for 0.0 != -0.0 | |
345 | EXPECT_DOUBLE_EQ(d.Value(), h.actual_); | |
346 | } | |
347 | } | |
348 | } | |
349 | } | |
350 | ||
351 | // Issue #340 | |
352 | TEST_DOUBLE(fullPrecision, "7.450580596923828e-9", 7.450580596923828e-9); | |
353 | { | |
354 | internal::Double d(1.0); | |
355 | for (int i = 0; i < 324; i++) { | |
356 | char buffer[32]; | |
357 | *internal::dtoa(d.Value(), buffer) = '\0'; | |
358 | ||
359 | StringStream s(buffer); | |
360 | ParseDoubleHandler h; | |
361 | Reader reader; | |
362 | ASSERT_EQ(kParseErrorNone, reader.Parse<fullPrecision ? kParseFullPrecisionFlag : 0>(s, h).Code()); | |
363 | EXPECT_EQ(1u, h.step_); | |
364 | internal::Double a(h.actual_); | |
365 | if (fullPrecision) { | |
366 | EXPECT_EQ(d.Uint64Value(), a.Uint64Value()); | |
367 | if (d.Uint64Value() != a.Uint64Value()) | |
368 | printf(" String: %s\n Actual: %.17g\nExpected: %.17g\n", buffer, h.actual_, d.Value()); | |
369 | } | |
370 | else { | |
371 | EXPECT_EQ(d.Sign(), a.Sign()); // for 0.0 != -0.0 | |
372 | EXPECT_DOUBLE_EQ(d.Value(), h.actual_); | |
373 | } | |
374 | ||
375 | ||
376 | d = d.Value() * 0.5; | |
377 | } | |
378 | } | |
379 | #undef TEST_DOUBLE | |
380 | } | |
381 | ||
382 | TEST(Reader, ParseNumber_NormalPrecisionDouble) { | |
383 | TestParseDouble<false>(); | |
384 | } | |
385 | ||
386 | TEST(Reader, ParseNumber_FullPrecisionDouble) { | |
387 | TestParseDouble<true>(); | |
388 | } | |
389 | ||
390 | TEST(Reader, ParseNumber_NormalPrecisionError) { | |
391 | static unsigned count = 1000000; | |
392 | Random r; | |
393 | ||
394 | double ulpSum = 0.0; | |
395 | double ulpMax = 0.0; | |
396 | for (unsigned i = 0; i < count; i++) { | |
397 | internal::Double e, a; | |
398 | do { | |
399 | // Need to call r() in two statements for cross-platform coherent sequence. | |
400 | uint64_t u = uint64_t(r()) << 32; | |
401 | u |= uint64_t(r()); | |
402 | e = u; | |
403 | } while (e.IsNan() || e.IsInf() || !e.IsNormal()); | |
404 | ||
405 | char buffer[32]; | |
406 | *internal::dtoa(e.Value(), buffer) = '\0'; | |
407 | ||
408 | StringStream s(buffer); | |
409 | ParseDoubleHandler h; | |
410 | Reader reader; | |
411 | ASSERT_EQ(kParseErrorNone, reader.Parse(s, h).Code()); | |
412 | EXPECT_EQ(1u, h.step_); | |
413 | ||
414 | a = h.actual_; | |
415 | uint64_t bias1 = e.ToBias(); | |
416 | uint64_t bias2 = a.ToBias(); | |
417 | double ulp = static_cast<double>(bias1 >= bias2 ? bias1 - bias2 : bias2 - bias1); | |
418 | ulpMax = std::max(ulpMax, ulp); | |
419 | ulpSum += ulp; | |
420 | } | |
421 | printf("ULP Average = %g, Max = %g \n", ulpSum / count, ulpMax); | |
422 | } | |
423 | ||
424 | TEST(Reader, ParseNumber_Error) { | |
425 | #define TEST_NUMBER_ERROR(errorCode, str, errorOffset, streamPos) \ | |
426 | { \ | |
427 | char buffer[1001]; \ | |
428 | sprintf(buffer, "%s", str); \ | |
429 | InsituStringStream s(buffer); \ | |
430 | BaseReaderHandler<> h; \ | |
431 | Reader reader; \ | |
432 | EXPECT_FALSE(reader.Parse(s, h)); \ | |
433 | EXPECT_EQ(errorCode, reader.GetParseErrorCode());\ | |
434 | EXPECT_EQ(errorOffset, reader.GetErrorOffset());\ | |
435 | EXPECT_EQ(streamPos, s.Tell());\ | |
436 | } | |
437 | ||
438 | // Number too big to be stored in double. | |
439 | { | |
440 | char n1e309[311]; // '1' followed by 309 '0' | |
441 | n1e309[0] = '1'; | |
442 | for (int i = 1; i < 310; i++) | |
443 | n1e309[i] = '0'; | |
444 | n1e309[310] = '\0'; | |
445 | TEST_NUMBER_ERROR(kParseErrorNumberTooBig, n1e309, 0, 309); | |
446 | } | |
447 | TEST_NUMBER_ERROR(kParseErrorNumberTooBig, "1e309", 0, 5); | |
448 | ||
449 | // Miss fraction part in number. | |
450 | TEST_NUMBER_ERROR(kParseErrorNumberMissFraction, "1.", 2, 2); | |
451 | TEST_NUMBER_ERROR(kParseErrorNumberMissFraction, "1.a", 2, 2); | |
452 | ||
453 | // Miss exponent in number. | |
454 | TEST_NUMBER_ERROR(kParseErrorNumberMissExponent, "1e", 2, 2); | |
455 | TEST_NUMBER_ERROR(kParseErrorNumberMissExponent, "1e_", 2, 2); | |
456 | ||
457 | #undef TEST_NUMBER_ERROR | |
458 | } | |
459 | ||
460 | template <typename Encoding> | |
461 | struct ParseStringHandler : BaseReaderHandler<Encoding, ParseStringHandler<Encoding> > { | |
462 | ParseStringHandler() : str_(0), length_(0), copy_() {} | |
463 | ~ParseStringHandler() { EXPECT_TRUE(str_ != 0); if (copy_) free(const_cast<typename Encoding::Ch*>(str_)); } | |
464 | ||
465 | ParseStringHandler(const ParseStringHandler&); | |
466 | ParseStringHandler& operator=(const ParseStringHandler&); | |
467 | ||
468 | bool Default() { ADD_FAILURE(); return false; } | |
469 | bool String(const typename Encoding::Ch* str, size_t length, bool copy) { | |
470 | EXPECT_EQ(0, str_); | |
471 | if (copy) { | |
472 | str_ = static_cast<typename Encoding::Ch*>(malloc((length + 1) * sizeof(typename Encoding::Ch))); | |
473 | memcpy(const_cast<typename Encoding::Ch*>(str_), str, (length + 1) * sizeof(typename Encoding::Ch)); | |
474 | } | |
475 | else | |
476 | str_ = str; | |
477 | length_ = length; | |
478 | copy_ = copy; | |
479 | return true; | |
480 | } | |
481 | ||
482 | const typename Encoding::Ch* str_; | |
483 | size_t length_; | |
484 | bool copy_; | |
485 | }; | |
486 | ||
487 | TEST(Reader, ParseString) { | |
488 | #define TEST_STRING(Encoding, e, x) \ | |
489 | { \ | |
490 | Encoding::Ch* buffer = StrDup(x); \ | |
491 | GenericInsituStringStream<Encoding> is(buffer); \ | |
492 | ParseStringHandler<Encoding> h; \ | |
493 | GenericReader<Encoding, Encoding> reader; \ | |
494 | reader.Parse<kParseInsituFlag | kParseValidateEncodingFlag>(is, h); \ | |
495 | EXPECT_EQ(0, StrCmp<Encoding::Ch>(e, h.str_)); \ | |
496 | EXPECT_EQ(StrLen(e), h.length_); \ | |
497 | free(buffer); \ | |
498 | GenericStringStream<Encoding> s(x); \ | |
499 | ParseStringHandler<Encoding> h2; \ | |
500 | GenericReader<Encoding, Encoding> reader2; \ | |
501 | reader2.Parse(s, h2); \ | |
502 | EXPECT_EQ(0, StrCmp<Encoding::Ch>(e, h2.str_)); \ | |
503 | EXPECT_EQ(StrLen(e), h2.length_); \ | |
504 | } | |
505 | ||
506 | // String constant L"\xXX" can only specify character code in bytes, which is not endianness-neutral. | |
507 | // And old compiler does not support u"" and U"" string literal. So here specify string literal by array of Ch. | |
508 | // In addition, GCC 4.8 generates -Wnarrowing warnings when character code >= 128 are assigned to signed integer types. | |
509 | // Therefore, utype is added for declaring unsigned array, and then cast it to Encoding::Ch. | |
510 | #define ARRAY(...) { __VA_ARGS__ } | |
511 | #define TEST_STRINGARRAY(Encoding, utype, array, x) \ | |
512 | { \ | |
513 | static const utype ue[] = array; \ | |
514 | static const Encoding::Ch* e = reinterpret_cast<const Encoding::Ch *>(&ue[0]); \ | |
515 | TEST_STRING(Encoding, e, x); \ | |
516 | } | |
517 | ||
518 | #define TEST_STRINGARRAY2(Encoding, utype, earray, xarray) \ | |
519 | { \ | |
520 | static const utype ue[] = earray; \ | |
521 | static const utype xe[] = xarray; \ | |
522 | static const Encoding::Ch* e = reinterpret_cast<const Encoding::Ch *>(&ue[0]); \ | |
523 | static const Encoding::Ch* x = reinterpret_cast<const Encoding::Ch *>(&xe[0]); \ | |
524 | TEST_STRING(Encoding, e, x); \ | |
525 | } | |
526 | ||
527 | TEST_STRING(UTF8<>, "", "\"\""); | |
528 | TEST_STRING(UTF8<>, "Hello", "\"Hello\""); | |
529 | TEST_STRING(UTF8<>, "Hello\nWorld", "\"Hello\\nWorld\""); | |
530 | TEST_STRING(UTF8<>, "\"\\/\b\f\n\r\t", "\"\\\"\\\\/\\b\\f\\n\\r\\t\""); | |
531 | TEST_STRING(UTF8<>, "\x24", "\"\\u0024\""); // Dollar sign U+0024 | |
532 | TEST_STRING(UTF8<>, "\xC2\xA2", "\"\\u00A2\""); // Cents sign U+00A2 | |
533 | TEST_STRING(UTF8<>, "\xE2\x82\xAC", "\"\\u20AC\""); // Euro sign U+20AC | |
534 | TEST_STRING(UTF8<>, "\xF0\x9D\x84\x9E", "\"\\uD834\\uDD1E\""); // G clef sign U+1D11E | |
535 | ||
536 | // UTF16 | |
537 | TEST_STRING(UTF16<>, L"", L"\"\""); | |
538 | TEST_STRING(UTF16<>, L"Hello", L"\"Hello\""); | |
539 | TEST_STRING(UTF16<>, L"Hello\nWorld", L"\"Hello\\nWorld\""); | |
540 | TEST_STRING(UTF16<>, L"\"\\/\b\f\n\r\t", L"\"\\\"\\\\/\\b\\f\\n\\r\\t\""); | |
541 | TEST_STRINGARRAY(UTF16<>, wchar_t, ARRAY(0x0024, 0x0000), L"\"\\u0024\""); | |
542 | TEST_STRINGARRAY(UTF16<>, wchar_t, ARRAY(0x00A2, 0x0000), L"\"\\u00A2\""); // Cents sign U+00A2 | |
543 | TEST_STRINGARRAY(UTF16<>, wchar_t, ARRAY(0x20AC, 0x0000), L"\"\\u20AC\""); // Euro sign U+20AC | |
544 | TEST_STRINGARRAY(UTF16<>, wchar_t, ARRAY(0xD834, 0xDD1E, 0x0000), L"\"\\uD834\\uDD1E\""); // G clef sign U+1D11E | |
545 | ||
546 | // UTF32 | |
547 | TEST_STRINGARRAY2(UTF32<>, unsigned, ARRAY('\0'), ARRAY('\"', '\"', '\0')); | |
548 | TEST_STRINGARRAY2(UTF32<>, unsigned, ARRAY('H', 'e', 'l', 'l', 'o', '\0'), ARRAY('\"', 'H', 'e', 'l', 'l', 'o', '\"', '\0')); | |
549 | TEST_STRINGARRAY2(UTF32<>, unsigned, ARRAY('H', 'e', 'l', 'l', 'o', '\n', 'W', 'o', 'r', 'l', 'd', '\0'), ARRAY('\"', 'H', 'e', 'l', 'l', 'o', '\\', 'n', 'W', 'o', 'r', 'l', 'd', '\"', '\0')); | |
550 | TEST_STRINGARRAY2(UTF32<>, unsigned, ARRAY('\"', '\\', '/', '\b', '\f', '\n', '\r', '\t', '\0'), ARRAY('\"', '\\', '\"', '\\', '\\', '/', '\\', 'b', '\\', 'f', '\\', 'n', '\\', 'r', '\\', 't', '\"', '\0')); | |
551 | TEST_STRINGARRAY2(UTF32<>, unsigned, ARRAY(0x00024, 0x0000), ARRAY('\"', '\\', 'u', '0', '0', '2', '4', '\"', '\0')); | |
552 | TEST_STRINGARRAY2(UTF32<>, unsigned, ARRAY(0x000A2, 0x0000), ARRAY('\"', '\\', 'u', '0', '0', 'A', '2', '\"', '\0')); // Cents sign U+00A2 | |
553 | TEST_STRINGARRAY2(UTF32<>, unsigned, ARRAY(0x020AC, 0x0000), ARRAY('\"', '\\', 'u', '2', '0', 'A', 'C', '\"', '\0')); // Euro sign U+20AC | |
554 | TEST_STRINGARRAY2(UTF32<>, unsigned, ARRAY(0x1D11E, 0x0000), ARRAY('\"', '\\', 'u', 'D', '8', '3', '4', '\\', 'u', 'D', 'D', '1', 'E', '\"', '\0')); // G clef sign U+1D11E | |
555 | ||
556 | #undef TEST_STRINGARRAY | |
557 | #undef ARRAY | |
558 | #undef TEST_STRING | |
559 | ||
560 | // Support of null character in string | |
561 | { | |
562 | StringStream s("\"Hello\\u0000World\""); | |
563 | const char e[] = "Hello\0World"; | |
564 | ParseStringHandler<UTF8<> > h; | |
565 | Reader reader; | |
566 | reader.Parse(s, h); | |
567 | EXPECT_EQ(0, memcmp(e, h.str_, h.length_ + 1)); | |
568 | EXPECT_EQ(11u, h.length_); | |
569 | } | |
570 | } | |
571 | ||
572 | TEST(Reader, ParseString_Transcoding) { | |
573 | const char* x = "\"Hello\""; | |
574 | const wchar_t* e = L"Hello"; | |
575 | GenericStringStream<UTF8<> > is(x); | |
576 | GenericReader<UTF8<>, UTF16<> > reader; | |
577 | ParseStringHandler<UTF16<> > h; | |
578 | reader.Parse(is, h); | |
579 | EXPECT_EQ(0, StrCmp<UTF16<>::Ch>(e, h.str_)); | |
580 | EXPECT_EQ(StrLen(e), h.length_); | |
581 | } | |
582 | ||
583 | TEST(Reader, ParseString_TranscodingWithValidation) { | |
584 | const char* x = "\"Hello\""; | |
585 | const wchar_t* e = L"Hello"; | |
586 | GenericStringStream<UTF8<> > is(x); | |
587 | GenericReader<UTF8<>, UTF16<> > reader; | |
588 | ParseStringHandler<UTF16<> > h; | |
589 | reader.Parse<kParseValidateEncodingFlag>(is, h); | |
590 | EXPECT_EQ(0, StrCmp<UTF16<>::Ch>(e, h.str_)); | |
591 | EXPECT_EQ(StrLen(e), h.length_); | |
592 | } | |
593 | ||
594 | TEST(Reader, ParseString_NonDestructive) { | |
595 | StringStream s("\"Hello\\nWorld\""); | |
596 | ParseStringHandler<UTF8<> > h; | |
597 | Reader reader; | |
598 | reader.Parse(s, h); | |
599 | EXPECT_EQ(0, StrCmp("Hello\nWorld", h.str_)); | |
600 | EXPECT_EQ(11u, h.length_); | |
601 | } | |
602 | ||
603 | template <typename Encoding> | |
604 | ParseErrorCode TestString(const typename Encoding::Ch* str) { | |
605 | GenericStringStream<Encoding> s(str); | |
606 | BaseReaderHandler<Encoding> h; | |
607 | GenericReader<Encoding, Encoding> reader; | |
608 | reader.template Parse<kParseValidateEncodingFlag>(s, h); | |
609 | return reader.GetParseErrorCode(); | |
610 | } | |
611 | ||
612 | TEST(Reader, ParseString_Error) { | |
613 | #define TEST_STRING_ERROR(errorCode, str, errorOffset, streamPos)\ | |
614 | {\ | |
615 | GenericStringStream<UTF8<> > s(str);\ | |
616 | BaseReaderHandler<UTF8<> > h;\ | |
617 | GenericReader<UTF8<> , UTF8<> > reader;\ | |
618 | reader.Parse<kParseValidateEncodingFlag>(s, h);\ | |
619 | EXPECT_EQ(errorCode, reader.GetParseErrorCode());\ | |
620 | EXPECT_EQ(errorOffset, reader.GetErrorOffset());\ | |
621 | EXPECT_EQ(streamPos, s.Tell());\ | |
622 | } | |
623 | ||
624 | #define ARRAY(...) { __VA_ARGS__ } | |
625 | #define TEST_STRINGENCODING_ERROR(Encoding, TargetEncoding, utype, array) \ | |
626 | { \ | |
627 | static const utype ue[] = array; \ | |
628 | static const Encoding::Ch* e = reinterpret_cast<const Encoding::Ch *>(&ue[0]); \ | |
629 | EXPECT_EQ(kParseErrorStringInvalidEncoding, TestString<Encoding>(e));\ | |
630 | /* decode error */\ | |
631 | GenericStringStream<Encoding> s(e);\ | |
632 | BaseReaderHandler<TargetEncoding> h;\ | |
633 | GenericReader<Encoding, TargetEncoding> reader;\ | |
634 | reader.Parse(s, h);\ | |
635 | EXPECT_EQ(kParseErrorStringInvalidEncoding, reader.GetParseErrorCode());\ | |
636 | } | |
637 | ||
638 | // Invalid escape character in string. | |
639 | TEST_STRING_ERROR(kParseErrorStringEscapeInvalid, "[\"\\a\"]", 2, 3); | |
640 | ||
641 | // Incorrect hex digit after \\u escape in string. | |
642 | TEST_STRING_ERROR(kParseErrorStringUnicodeEscapeInvalidHex, "[\"\\uABCG\"]", 2, 7); | |
643 | ||
644 | // Quotation in \\u escape in string (Issue #288) | |
645 | TEST_STRING_ERROR(kParseErrorStringUnicodeEscapeInvalidHex, "[\"\\uaaa\"]", 2, 7); | |
646 | TEST_STRING_ERROR(kParseErrorStringUnicodeEscapeInvalidHex, "[\"\\uD800\\uFFF\"]", 2, 13); | |
647 | ||
648 | // The surrogate pair in string is invalid. | |
649 | TEST_STRING_ERROR(kParseErrorStringUnicodeSurrogateInvalid, "[\"\\uD800X\"]", 2, 8); | |
650 | TEST_STRING_ERROR(kParseErrorStringUnicodeSurrogateInvalid, "[\"\\uD800\\uFFFF\"]", 2, 14); | |
651 | ||
652 | // Missing a closing quotation mark in string. | |
653 | TEST_STRING_ERROR(kParseErrorStringMissQuotationMark, "[\"Test]", 7, 7); | |
654 | ||
655 | // http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt | |
656 | ||
657 | // 3 Malformed sequences | |
658 | ||
659 | // 3.1 Unexpected continuation bytes | |
660 | { | |
661 | char e[] = { '[', '\"', 0, '\"', ']', '\0' }; | |
662 | for (unsigned char c = 0x80u; c <= 0xBFu; c++) { | |
663 | e[2] = static_cast<char>(c); | |
664 | ParseErrorCode error = TestString<UTF8<> >(e); | |
665 | EXPECT_EQ(kParseErrorStringInvalidEncoding, error); | |
666 | if (error != kParseErrorStringInvalidEncoding) | |
667 | std::cout << static_cast<unsigned>(c) << std::endl; | |
668 | } | |
669 | } | |
670 | ||
671 | // 3.2 Lonely start characters, 3.5 Impossible bytes | |
672 | { | |
673 | char e[] = { '[', '\"', 0, ' ', '\"', ']', '\0' }; | |
674 | for (unsigned c = 0xC0u; c <= 0xFFu; c++) { | |
675 | e[2] = static_cast<char>(c); | |
676 | int streamPos; | |
677 | if (c <= 0xC1u) | |
678 | streamPos = 3; // 0xC0 - 0xC1 | |
679 | else if (c <= 0xDFu) | |
680 | streamPos = 4; // 0xC2 - 0xDF | |
681 | else if (c <= 0xEFu) | |
682 | streamPos = 5; // 0xE0 - 0xEF | |
683 | else if (c <= 0xF4u) | |
684 | streamPos = 6; // 0xF0 - 0xF4 | |
685 | else | |
686 | streamPos = 3; // 0xF5 - 0xFF | |
687 | TEST_STRING_ERROR(kParseErrorStringInvalidEncoding, e, 2, streamPos); | |
688 | } | |
689 | } | |
690 | ||
691 | // 4 Overlong sequences | |
692 | ||
693 | // 4.1 Examples of an overlong ASCII character | |
694 | TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xC0u, 0xAFu, '\"', ']', '\0')); | |
695 | TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xE0u, 0x80u, 0xAFu, '\"', ']', '\0')); | |
696 | TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xF0u, 0x80u, 0x80u, 0xAFu, '\"', ']', '\0')); | |
697 | ||
698 | // 4.2 Maximum overlong sequences | |
699 | TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xC1u, 0xBFu, '\"', ']', '\0')); | |
700 | TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xE0u, 0x9Fu, 0xBFu, '\"', ']', '\0')); | |
701 | TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xF0u, 0x8Fu, 0xBFu, 0xBFu, '\"', ']', '\0')); | |
702 | ||
703 | // 4.3 Overlong representation of the NUL character | |
704 | TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xC0u, 0x80u, '\"', ']', '\0')); | |
705 | TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xE0u, 0x80u, 0x80u, '\"', ']', '\0')); | |
706 | TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xF0u, 0x80u, 0x80u, 0x80u, '\"', ']', '\0')); | |
707 | ||
708 | // 5 Illegal code positions | |
709 | ||
710 | // 5.1 Single UTF-16 surrogates | |
711 | TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xA0u, 0x80u, '\"', ']', '\0')); | |
712 | TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xADu, 0xBFu, '\"', ']', '\0')); | |
713 | TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xAEu, 0x80u, '\"', ']', '\0')); | |
714 | TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xAFu, 0xBFu, '\"', ']', '\0')); | |
715 | TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xB0u, 0x80u, '\"', ']', '\0')); | |
716 | TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xBEu, 0x80u, '\"', ']', '\0')); | |
717 | TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xBFu, 0xBFu, '\"', ']', '\0')); | |
718 | ||
719 | // Malform UTF-16 sequences | |
720 | TEST_STRINGENCODING_ERROR(UTF16<>, UTF8<>, wchar_t, ARRAY('[', '\"', 0xDC00, 0xDC00, '\"', ']', '\0')); | |
721 | TEST_STRINGENCODING_ERROR(UTF16<>, UTF8<>, wchar_t, ARRAY('[', '\"', 0xD800, 0xD800, '\"', ']', '\0')); | |
722 | ||
723 | // Malform UTF-32 sequence | |
724 | TEST_STRINGENCODING_ERROR(UTF32<>, UTF8<>, unsigned, ARRAY('[', '\"', 0x110000, '\"', ']', '\0')); | |
725 | ||
726 | // Malform ASCII sequence | |
727 | TEST_STRINGENCODING_ERROR(ASCII<>, UTF8<>, char, ARRAY('[', '\"', char(0x80u), '\"', ']', '\0')); | |
728 | ||
729 | #undef ARRAY | |
730 | #undef TEST_STRINGARRAY_ERROR | |
731 | } | |
732 | ||
733 | template <unsigned count> | |
734 | struct ParseArrayHandler : BaseReaderHandler<UTF8<>, ParseArrayHandler<count> > { | |
735 | ParseArrayHandler() : step_(0) {} | |
736 | ||
737 | bool Default() { ADD_FAILURE(); return false; } | |
738 | bool Uint(unsigned i) { EXPECT_EQ(step_, i); step_++; return true; } | |
739 | bool StartArray() { EXPECT_EQ(0u, step_); step_++; return true; } | |
740 | bool EndArray(SizeType) { step_++; return true; } | |
741 | ||
742 | unsigned step_; | |
743 | }; | |
744 | ||
745 | TEST(Reader, ParseEmptyArray) { | |
746 | char *json = StrDup("[ ] "); | |
747 | InsituStringStream s(json); | |
748 | ParseArrayHandler<0> h; | |
749 | Reader reader; | |
750 | reader.Parse(s, h); | |
751 | EXPECT_EQ(2u, h.step_); | |
752 | free(json); | |
753 | } | |
754 | ||
755 | TEST(Reader, ParseArray) { | |
756 | char *json = StrDup("[1, 2, 3, 4]"); | |
757 | InsituStringStream s(json); | |
758 | ParseArrayHandler<4> h; | |
759 | Reader reader; | |
760 | reader.Parse(s, h); | |
761 | EXPECT_EQ(6u, h.step_); | |
762 | free(json); | |
763 | } | |
764 | ||
765 | TEST(Reader, ParseArray_Error) { | |
766 | #define TEST_ARRAY_ERROR(errorCode, str, errorOffset) \ | |
767 | { \ | |
768 | int streamPos = errorOffset; \ | |
769 | char buffer[1001]; \ | |
770 | strncpy(buffer, str, 1000); \ | |
771 | InsituStringStream s(buffer); \ | |
772 | BaseReaderHandler<> h; \ | |
773 | GenericReader<UTF8<>, UTF8<>, CrtAllocator> reader; \ | |
774 | EXPECT_FALSE(reader.Parse(s, h)); \ | |
775 | EXPECT_EQ(errorCode, reader.GetParseErrorCode());\ | |
776 | EXPECT_EQ(errorOffset, reader.GetErrorOffset());\ | |
777 | EXPECT_EQ(streamPos, s.Tell());\ | |
778 | } | |
779 | ||
780 | // Missing a comma or ']' after an array element. | |
781 | TEST_ARRAY_ERROR(kParseErrorArrayMissCommaOrSquareBracket, "[1", 2); | |
782 | TEST_ARRAY_ERROR(kParseErrorArrayMissCommaOrSquareBracket, "[1}", 2); | |
783 | TEST_ARRAY_ERROR(kParseErrorArrayMissCommaOrSquareBracket, "[1 2]", 3); | |
784 | ||
785 | // Array cannot have a trailing comma (without kParseTrailingCommasFlag); | |
786 | // a value must follow a comma | |
787 | TEST_ARRAY_ERROR(kParseErrorValueInvalid, "[1,]", 3); | |
788 | ||
789 | #undef TEST_ARRAY_ERROR | |
790 | } | |
791 | ||
792 | struct ParseObjectHandler : BaseReaderHandler<UTF8<>, ParseObjectHandler> { | |
793 | ParseObjectHandler() : step_(0) {} | |
794 | ||
795 | bool Default() { ADD_FAILURE(); return false; } | |
796 | bool Null() { EXPECT_EQ(8u, step_); step_++; return true; } | |
797 | bool Bool(bool b) { | |
798 | switch(step_) { | |
799 | case 4: EXPECT_TRUE(b); step_++; return true; | |
800 | case 6: EXPECT_FALSE(b); step_++; return true; | |
801 | default: ADD_FAILURE(); return false; | |
802 | } | |
803 | } | |
804 | bool Int(int i) { | |
805 | switch(step_) { | |
806 | case 10: EXPECT_EQ(123, i); step_++; return true; | |
807 | case 15: EXPECT_EQ(1, i); step_++; return true; | |
808 | case 16: EXPECT_EQ(2, i); step_++; return true; | |
809 | case 17: EXPECT_EQ(3, i); step_++; return true; | |
810 | default: ADD_FAILURE(); return false; | |
811 | } | |
812 | } | |
813 | bool Uint(unsigned i) { return Int(static_cast<int>(i)); } | |
814 | bool Double(double d) { EXPECT_EQ(12u, step_); EXPECT_DOUBLE_EQ(3.1416, d); step_++; return true; } | |
815 | bool String(const char* str, size_t, bool) { | |
816 | switch(step_) { | |
817 | case 1: EXPECT_STREQ("hello", str); step_++; return true; | |
818 | case 2: EXPECT_STREQ("world", str); step_++; return true; | |
819 | case 3: EXPECT_STREQ("t", str); step_++; return true; | |
820 | case 5: EXPECT_STREQ("f", str); step_++; return true; | |
821 | case 7: EXPECT_STREQ("n", str); step_++; return true; | |
822 | case 9: EXPECT_STREQ("i", str); step_++; return true; | |
823 | case 11: EXPECT_STREQ("pi", str); step_++; return true; | |
824 | case 13: EXPECT_STREQ("a", str); step_++; return true; | |
825 | default: ADD_FAILURE(); return false; | |
826 | } | |
827 | } | |
828 | bool StartObject() { EXPECT_EQ(0u, step_); step_++; return true; } | |
829 | bool EndObject(SizeType memberCount) { EXPECT_EQ(19u, step_); EXPECT_EQ(7u, memberCount); step_++; return true; } | |
830 | bool StartArray() { EXPECT_EQ(14u, step_); step_++; return true; } | |
831 | bool EndArray(SizeType elementCount) { EXPECT_EQ(18u, step_); EXPECT_EQ(3u, elementCount); step_++; return true; } | |
832 | ||
833 | unsigned step_; | |
834 | }; | |
835 | ||
836 | TEST(Reader, ParseObject) { | |
837 | const char* json = "{ \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] } "; | |
838 | ||
839 | // Insitu | |
840 | { | |
841 | char* json2 = StrDup(json); | |
842 | InsituStringStream s(json2); | |
843 | ParseObjectHandler h; | |
844 | Reader reader; | |
845 | reader.Parse<kParseInsituFlag>(s, h); | |
846 | EXPECT_EQ(20u, h.step_); | |
847 | free(json2); | |
848 | } | |
849 | ||
850 | // Normal | |
851 | { | |
852 | StringStream s(json); | |
853 | ParseObjectHandler h; | |
854 | Reader reader; | |
855 | reader.Parse(s, h); | |
856 | EXPECT_EQ(20u, h.step_); | |
857 | } | |
858 | } | |
859 | ||
860 | struct ParseEmptyObjectHandler : BaseReaderHandler<UTF8<>, ParseEmptyObjectHandler> { | |
861 | ParseEmptyObjectHandler() : step_(0) {} | |
862 | ||
863 | bool Default() { ADD_FAILURE(); return false; } | |
864 | bool StartObject() { EXPECT_EQ(0u, step_); step_++; return true; } | |
865 | bool EndObject(SizeType) { EXPECT_EQ(1u, step_); step_++; return true; } | |
866 | ||
867 | unsigned step_; | |
868 | }; | |
869 | ||
870 | TEST(Reader, Parse_EmptyObject) { | |
871 | StringStream s("{ } "); | |
872 | ParseEmptyObjectHandler h; | |
873 | Reader reader; | |
874 | reader.Parse(s, h); | |
875 | EXPECT_EQ(2u, h.step_); | |
876 | } | |
877 | ||
878 | struct ParseMultipleRootHandler : BaseReaderHandler<UTF8<>, ParseMultipleRootHandler> { | |
879 | ParseMultipleRootHandler() : step_(0) {} | |
880 | ||
881 | bool Default() { ADD_FAILURE(); return false; } | |
882 | bool StartObject() { EXPECT_EQ(0u, step_); step_++; return true; } | |
883 | bool EndObject(SizeType) { EXPECT_EQ(1u, step_); step_++; return true; } | |
884 | bool StartArray() { EXPECT_EQ(2u, step_); step_++; return true; } | |
885 | bool EndArray(SizeType) { EXPECT_EQ(3u, step_); step_++; return true; } | |
886 | ||
887 | unsigned step_; | |
888 | }; | |
889 | ||
890 | template <unsigned parseFlags> | |
891 | void TestMultipleRoot() { | |
892 | StringStream s("{}[] a"); | |
893 | ParseMultipleRootHandler h; | |
894 | Reader reader; | |
895 | EXPECT_TRUE(reader.Parse<parseFlags>(s, h)); | |
896 | EXPECT_EQ(2u, h.step_); | |
897 | EXPECT_TRUE(reader.Parse<parseFlags>(s, h)); | |
898 | EXPECT_EQ(4u, h.step_); | |
899 | EXPECT_EQ(' ', s.Take()); | |
900 | EXPECT_EQ('a', s.Take()); | |
901 | } | |
902 | ||
903 | TEST(Reader, Parse_MultipleRoot) { | |
904 | TestMultipleRoot<kParseStopWhenDoneFlag>(); | |
905 | } | |
906 | ||
907 | TEST(Reader, ParseIterative_MultipleRoot) { | |
908 | TestMultipleRoot<kParseIterativeFlag | kParseStopWhenDoneFlag>(); | |
909 | } | |
910 | ||
911 | template <unsigned parseFlags> | |
912 | void TestInsituMultipleRoot() { | |
913 | char* buffer = strdup("{}[] a"); | |
914 | InsituStringStream s(buffer); | |
915 | ParseMultipleRootHandler h; | |
916 | Reader reader; | |
917 | EXPECT_TRUE(reader.Parse<kParseInsituFlag | parseFlags>(s, h)); | |
918 | EXPECT_EQ(2u, h.step_); | |
919 | EXPECT_TRUE(reader.Parse<kParseInsituFlag | parseFlags>(s, h)); | |
920 | EXPECT_EQ(4u, h.step_); | |
921 | EXPECT_EQ(' ', s.Take()); | |
922 | EXPECT_EQ('a', s.Take()); | |
923 | free(buffer); | |
924 | } | |
925 | ||
926 | TEST(Reader, ParseInsitu_MultipleRoot) { | |
927 | TestInsituMultipleRoot<kParseStopWhenDoneFlag>(); | |
928 | } | |
929 | ||
930 | TEST(Reader, ParseInsituIterative_MultipleRoot) { | |
931 | TestInsituMultipleRoot<kParseIterativeFlag | kParseStopWhenDoneFlag>(); | |
932 | } | |
933 | ||
934 | #define TEST_ERROR(errorCode, str, errorOffset) \ | |
935 | { \ | |
936 | int streamPos = errorOffset; \ | |
937 | char buffer[1001]; \ | |
938 | strncpy(buffer, str, 1000); \ | |
939 | InsituStringStream s(buffer); \ | |
940 | BaseReaderHandler<> h; \ | |
941 | Reader reader; \ | |
942 | EXPECT_FALSE(reader.Parse(s, h)); \ | |
943 | EXPECT_EQ(errorCode, reader.GetParseErrorCode());\ | |
944 | EXPECT_EQ(errorOffset, reader.GetErrorOffset());\ | |
945 | EXPECT_EQ(streamPos, s.Tell());\ | |
946 | } | |
947 | ||
948 | TEST(Reader, ParseDocument_Error) { | |
949 | // The document is empty. | |
950 | TEST_ERROR(kParseErrorDocumentEmpty, "", 0); | |
951 | TEST_ERROR(kParseErrorDocumentEmpty, " ", 1); | |
952 | TEST_ERROR(kParseErrorDocumentEmpty, " \n", 2); | |
953 | ||
954 | // The document root must not follow by other values. | |
955 | TEST_ERROR(kParseErrorDocumentRootNotSingular, "[] 0", 3); | |
956 | TEST_ERROR(kParseErrorDocumentRootNotSingular, "{} 0", 3); | |
957 | TEST_ERROR(kParseErrorDocumentRootNotSingular, "null []", 5); | |
958 | TEST_ERROR(kParseErrorDocumentRootNotSingular, "0 {}", 2); | |
959 | } | |
960 | ||
961 | TEST(Reader, ParseValue_Error) { | |
962 | // Invalid value. | |
963 | TEST_ERROR(kParseErrorValueInvalid, "nulL", 3); | |
964 | TEST_ERROR(kParseErrorValueInvalid, "truE", 3); | |
965 | TEST_ERROR(kParseErrorValueInvalid, "falsE", 4); | |
966 | TEST_ERROR(kParseErrorValueInvalid, "a]", 0); | |
967 | TEST_ERROR(kParseErrorValueInvalid, ".1", 0); | |
968 | } | |
969 | ||
970 | TEST(Reader, ParseObject_Error) { | |
971 | // Missing a name for object member. | |
972 | TEST_ERROR(kParseErrorObjectMissName, "{1}", 1); | |
973 | TEST_ERROR(kParseErrorObjectMissName, "{:1}", 1); | |
974 | TEST_ERROR(kParseErrorObjectMissName, "{null:1}", 1); | |
975 | TEST_ERROR(kParseErrorObjectMissName, "{true:1}", 1); | |
976 | TEST_ERROR(kParseErrorObjectMissName, "{false:1}", 1); | |
977 | TEST_ERROR(kParseErrorObjectMissName, "{1:1}", 1); | |
978 | TEST_ERROR(kParseErrorObjectMissName, "{[]:1}", 1); | |
979 | TEST_ERROR(kParseErrorObjectMissName, "{{}:1}", 1); | |
980 | TEST_ERROR(kParseErrorObjectMissName, "{xyz:1}", 1); | |
981 | ||
982 | // Missing a colon after a name of object member. | |
983 | TEST_ERROR(kParseErrorObjectMissColon, "{\"a\" 1}", 5); | |
984 | TEST_ERROR(kParseErrorObjectMissColon, "{\"a\",1}", 4); | |
985 | ||
986 | // Must be a comma or '}' after an object member | |
987 | TEST_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, "{\"a\":1]", 6); | |
988 | ||
989 | // Object cannot have a trailing comma (without kParseTrailingCommasFlag); | |
990 | // an object member name must follow a comma | |
991 | TEST_ERROR(kParseErrorObjectMissName, "{\"a\":1,}", 7); | |
992 | ||
993 | // This tests that MemoryStream is checking the length in Peek(). | |
994 | { | |
995 | MemoryStream ms("{\"a\"", 1); | |
996 | BaseReaderHandler<> h; | |
997 | Reader reader; | |
998 | EXPECT_FALSE(reader.Parse<kParseStopWhenDoneFlag>(ms, h)); | |
999 | EXPECT_EQ(kParseErrorObjectMissName, reader.GetParseErrorCode()); | |
1000 | } | |
1001 | } | |
1002 | ||
1003 | #undef TEST_ERROR | |
1004 | ||
1005 | TEST(Reader, SkipWhitespace) { | |
1006 | StringStream ss(" A \t\tB\n \n\nC\r\r \rD \t\n\r E"); | |
1007 | const char* expected = "ABCDE"; | |
1008 | for (size_t i = 0; i < 5; i++) { | |
1009 | SkipWhitespace(ss); | |
1010 | EXPECT_EQ(expected[i], ss.Take()); | |
1011 | } | |
1012 | } | |
1013 | ||
1014 | // Test implementing a stream without copy stream optimization. | |
1015 | // Clone from GenericStringStream except that copy constructor is disabled. | |
1016 | template <typename Encoding> | |
1017 | class CustomStringStream { | |
1018 | public: | |
1019 | typedef typename Encoding::Ch Ch; | |
1020 | ||
1021 | CustomStringStream(const Ch *src) : src_(src), head_(src) {} | |
1022 | ||
1023 | Ch Peek() const { return *src_; } | |
1024 | Ch Take() { return *src_++; } | |
1025 | size_t Tell() const { return static_cast<size_t>(src_ - head_); } | |
1026 | ||
1027 | Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } | |
1028 | void Put(Ch) { RAPIDJSON_ASSERT(false); } | |
1029 | void Flush() { RAPIDJSON_ASSERT(false); } | |
1030 | size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } | |
1031 | ||
1032 | private: | |
1033 | // Prohibit copy constructor & assignment operator. | |
1034 | CustomStringStream(const CustomStringStream&); | |
1035 | CustomStringStream& operator=(const CustomStringStream&); | |
1036 | ||
1037 | const Ch* src_; //!< Current read position. | |
1038 | const Ch* head_; //!< Original head of the string. | |
1039 | }; | |
1040 | ||
1041 | // If the following code is compiled, it should generate compilation error as predicted. | |
1042 | // Because CustomStringStream<> is not copyable via making copy constructor private. | |
1043 | #if 0 | |
1044 | namespace rapidjson { | |
1045 | ||
1046 | template <typename Encoding> | |
1047 | struct StreamTraits<CustomStringStream<Encoding> > { | |
1048 | enum { copyOptimization = 1 }; | |
1049 | }; | |
1050 | ||
1051 | } // namespace rapidjson | |
1052 | #endif | |
1053 | ||
1054 | TEST(Reader, CustomStringStream) { | |
1055 | const char* json = "{ \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] } "; | |
1056 | CustomStringStream<UTF8<char> > s(json); | |
1057 | ParseObjectHandler h; | |
1058 | Reader reader; | |
1059 | reader.Parse(s, h); | |
1060 | EXPECT_EQ(20u, h.step_); | |
1061 | } | |
1062 | ||
1063 | #include <sstream> | |
1064 | ||
1065 | class IStreamWrapper { | |
1066 | public: | |
1067 | typedef char Ch; | |
1068 | ||
1069 | IStreamWrapper(std::istream& is) : is_(is) {} | |
1070 | ||
1071 | Ch Peek() const { | |
1072 | int c = is_.peek(); | |
1073 | return c == std::char_traits<char>::eof() ? '\0' : static_cast<Ch>(c); | |
1074 | } | |
1075 | ||
1076 | Ch Take() { | |
1077 | int c = is_.get(); | |
1078 | return c == std::char_traits<char>::eof() ? '\0' : static_cast<Ch>(c); | |
1079 | } | |
1080 | ||
1081 | size_t Tell() const { return static_cast<size_t>(is_.tellg()); } | |
1082 | ||
1083 | Ch* PutBegin() { assert(false); return 0; } | |
1084 | void Put(Ch) { assert(false); } | |
1085 | void Flush() { assert(false); } | |
1086 | size_t PutEnd(Ch*) { assert(false); return 0; } | |
1087 | ||
1088 | private: | |
1089 | IStreamWrapper(const IStreamWrapper&); | |
1090 | IStreamWrapper& operator=(const IStreamWrapper&); | |
1091 | ||
1092 | std::istream& is_; | |
1093 | }; | |
1094 | ||
1095 | TEST(Reader, Parse_IStreamWrapper_StringStream) { | |
1096 | const char* json = "[1,2,3,4]"; | |
1097 | ||
1098 | std::stringstream ss(json); | |
1099 | IStreamWrapper is(ss); | |
1100 | ||
1101 | Reader reader; | |
1102 | ParseArrayHandler<4> h; | |
1103 | reader.Parse(is, h); | |
1104 | EXPECT_FALSE(reader.HasParseError()); | |
1105 | } | |
1106 | ||
1107 | // Test iterative parsing. | |
1108 | ||
1109 | #define TESTERRORHANDLING(text, errorCode, offset)\ | |
1110 | {\ | |
1111 | int streamPos = offset; \ | |
1112 | StringStream json(text); \ | |
1113 | BaseReaderHandler<> handler; \ | |
1114 | Reader reader; \ | |
1115 | reader.Parse<kParseIterativeFlag>(json, handler); \ | |
1116 | EXPECT_TRUE(reader.HasParseError()); \ | |
1117 | EXPECT_EQ(errorCode, reader.GetParseErrorCode()); \ | |
1118 | EXPECT_EQ(offset, reader.GetErrorOffset()); \ | |
1119 | EXPECT_EQ(streamPos, json.Tell()); \ | |
1120 | } | |
1121 | ||
1122 | TEST(Reader, IterativeParsing_ErrorHandling) { | |
1123 | TESTERRORHANDLING("{\"a\": a}", kParseErrorValueInvalid, 6u); | |
1124 | ||
1125 | TESTERRORHANDLING("", kParseErrorDocumentEmpty, 0u); | |
1126 | TESTERRORHANDLING("{}{}", kParseErrorDocumentRootNotSingular, 2u); | |
1127 | ||
1128 | TESTERRORHANDLING("{1}", kParseErrorObjectMissName, 1u); | |
1129 | TESTERRORHANDLING("{\"a\", 1}", kParseErrorObjectMissColon, 4u); | |
1130 | TESTERRORHANDLING("{\"a\"}", kParseErrorObjectMissColon, 4u); | |
1131 | TESTERRORHANDLING("{\"a\": 1", kParseErrorObjectMissCommaOrCurlyBracket, 7u); | |
1132 | TESTERRORHANDLING("[1 2 3]", kParseErrorArrayMissCommaOrSquareBracket, 3u); | |
1133 | TESTERRORHANDLING("{\"a: 1", kParseErrorStringMissQuotationMark, 6u); | |
1134 | TESTERRORHANDLING("{\"a\":}", kParseErrorValueInvalid, 5u); | |
1135 | TESTERRORHANDLING("{\"a\":]", kParseErrorValueInvalid, 5u); | |
1136 | TESTERRORHANDLING("[1,2,}", kParseErrorValueInvalid, 5u); | |
1137 | TESTERRORHANDLING("[}]", kParseErrorValueInvalid, 1u); | |
1138 | TESTERRORHANDLING("[,]", kParseErrorValueInvalid, 1u); | |
1139 | TESTERRORHANDLING("[1,,]", kParseErrorValueInvalid, 3u); | |
1140 | ||
1141 | // Trailing commas are not allowed without kParseTrailingCommasFlag | |
1142 | TESTERRORHANDLING("{\"a\": 1,}", kParseErrorObjectMissName, 8u); | |
1143 | TESTERRORHANDLING("[1,2,3,]", kParseErrorValueInvalid, 7u); | |
1144 | ||
1145 | // Any JSON value can be a valid root element in RFC7159. | |
1146 | TESTERRORHANDLING("\"ab", kParseErrorStringMissQuotationMark, 3u); | |
1147 | TESTERRORHANDLING("truE", kParseErrorValueInvalid, 3u); | |
1148 | TESTERRORHANDLING("False", kParseErrorValueInvalid, 0u); | |
1149 | TESTERRORHANDLING("true, false", kParseErrorDocumentRootNotSingular, 4u); | |
1150 | TESTERRORHANDLING("false, false", kParseErrorDocumentRootNotSingular, 5u); | |
1151 | TESTERRORHANDLING("nulL", kParseErrorValueInvalid, 3u); | |
1152 | TESTERRORHANDLING("null , null", kParseErrorDocumentRootNotSingular, 5u); | |
1153 | TESTERRORHANDLING("1a", kParseErrorDocumentRootNotSingular, 1u); | |
1154 | } | |
1155 | ||
1156 | template<typename Encoding = UTF8<> > | |
1157 | struct IterativeParsingReaderHandler { | |
1158 | typedef typename Encoding::Ch Ch; | |
1159 | ||
1160 | const static int LOG_NULL = -1; | |
1161 | const static int LOG_BOOL = -2; | |
1162 | const static int LOG_INT = -3; | |
1163 | const static int LOG_UINT = -4; | |
1164 | const static int LOG_INT64 = -5; | |
1165 | const static int LOG_UINT64 = -6; | |
1166 | const static int LOG_DOUBLE = -7; | |
1167 | const static int LOG_STRING = -8; | |
1168 | const static int LOG_STARTOBJECT = -9; | |
1169 | const static int LOG_KEY = -10; | |
1170 | const static int LOG_ENDOBJECT = -11; | |
1171 | const static int LOG_STARTARRAY = -12; | |
1172 | const static int LOG_ENDARRAY = -13; | |
1173 | ||
1174 | const static size_t LogCapacity = 256; | |
1175 | int Logs[LogCapacity]; | |
1176 | size_t LogCount; | |
1177 | ||
1178 | IterativeParsingReaderHandler() : LogCount(0) { | |
1179 | } | |
1180 | ||
1181 | bool Null() { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_NULL; return true; } | |
1182 | ||
1183 | bool Bool(bool) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_BOOL; return true; } | |
1184 | ||
1185 | bool Int(int) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_INT; return true; } | |
1186 | ||
1187 | bool Uint(unsigned) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_INT; return true; } | |
1188 | ||
1189 | bool Int64(int64_t) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_INT64; return true; } | |
1190 | ||
1191 | bool Uint64(uint64_t) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_UINT64; return true; } | |
1192 | ||
1193 | bool Double(double) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_DOUBLE; return true; } | |
1194 | ||
1195 | bool RawNumber(const Ch*, SizeType, bool) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_STRING; return true; } | |
1196 | ||
1197 | bool String(const Ch*, SizeType, bool) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_STRING; return true; } | |
1198 | ||
1199 | bool StartObject() { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_STARTOBJECT; return true; } | |
1200 | ||
1201 | bool Key (const Ch*, SizeType, bool) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_KEY; return true; } | |
1202 | ||
1203 | bool EndObject(SizeType c) { | |
1204 | RAPIDJSON_ASSERT(LogCount < LogCapacity); | |
1205 | Logs[LogCount++] = LOG_ENDOBJECT; | |
1206 | Logs[LogCount++] = static_cast<int>(c); | |
1207 | return true; | |
1208 | } | |
1209 | ||
1210 | bool StartArray() { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_STARTARRAY; return true; } | |
1211 | ||
1212 | bool EndArray(SizeType c) { | |
1213 | RAPIDJSON_ASSERT(LogCount < LogCapacity); | |
1214 | Logs[LogCount++] = LOG_ENDARRAY; | |
1215 | Logs[LogCount++] = static_cast<int>(c); | |
1216 | return true; | |
1217 | } | |
1218 | }; | |
1219 | ||
1220 | TEST(Reader, IterativeParsing_General) { | |
1221 | { | |
1222 | StringStream is("[1, {\"k\": [1, 2]}, null, false, true, \"string\", 1.2]"); | |
1223 | Reader reader; | |
1224 | IterativeParsingReaderHandler<> handler; | |
1225 | ||
1226 | ParseResult r = reader.Parse<kParseIterativeFlag>(is, handler); | |
1227 | ||
1228 | EXPECT_FALSE(r.IsError()); | |
1229 | EXPECT_FALSE(reader.HasParseError()); | |
1230 | ||
1231 | int e[] = { | |
1232 | handler.LOG_STARTARRAY, | |
1233 | handler.LOG_INT, | |
1234 | handler.LOG_STARTOBJECT, | |
1235 | handler.LOG_KEY, | |
1236 | handler.LOG_STARTARRAY, | |
1237 | handler.LOG_INT, | |
1238 | handler.LOG_INT, | |
1239 | handler.LOG_ENDARRAY, 2, | |
1240 | handler.LOG_ENDOBJECT, 1, | |
1241 | handler.LOG_NULL, | |
1242 | handler.LOG_BOOL, | |
1243 | handler.LOG_BOOL, | |
1244 | handler.LOG_STRING, | |
1245 | handler.LOG_DOUBLE, | |
1246 | handler.LOG_ENDARRAY, 7 | |
1247 | }; | |
1248 | ||
1249 | EXPECT_EQ(sizeof(e) / sizeof(int), handler.LogCount); | |
1250 | ||
1251 | for (size_t i = 0; i < handler.LogCount; ++i) { | |
1252 | EXPECT_EQ(e[i], handler.Logs[i]) << "i = " << i; | |
1253 | } | |
1254 | } | |
1255 | } | |
1256 | ||
1257 | TEST(Reader, IterativeParsing_Count) { | |
1258 | { | |
1259 | StringStream is("[{}, {\"k\": 1}, [1], []]"); | |
1260 | Reader reader; | |
1261 | IterativeParsingReaderHandler<> handler; | |
1262 | ||
1263 | ParseResult r = reader.Parse<kParseIterativeFlag>(is, handler); | |
1264 | ||
1265 | EXPECT_FALSE(r.IsError()); | |
1266 | EXPECT_FALSE(reader.HasParseError()); | |
1267 | ||
1268 | int e[] = { | |
1269 | handler.LOG_STARTARRAY, | |
1270 | handler.LOG_STARTOBJECT, | |
1271 | handler.LOG_ENDOBJECT, 0, | |
1272 | handler.LOG_STARTOBJECT, | |
1273 | handler.LOG_KEY, | |
1274 | handler.LOG_INT, | |
1275 | handler.LOG_ENDOBJECT, 1, | |
1276 | handler.LOG_STARTARRAY, | |
1277 | handler.LOG_INT, | |
1278 | handler.LOG_ENDARRAY, 1, | |
1279 | handler.LOG_STARTARRAY, | |
1280 | handler.LOG_ENDARRAY, 0, | |
1281 | handler.LOG_ENDARRAY, 4 | |
1282 | }; | |
1283 | ||
1284 | EXPECT_EQ(sizeof(e) / sizeof(int), handler.LogCount); | |
1285 | ||
1286 | for (size_t i = 0; i < handler.LogCount; ++i) { | |
1287 | EXPECT_EQ(e[i], handler.Logs[i]) << "i = " << i; | |
1288 | } | |
1289 | } | |
1290 | } | |
1291 | ||
1292 | // Test iterative parsing on kParseErrorTermination. | |
1293 | struct HandlerTerminateAtStartObject : public IterativeParsingReaderHandler<> { | |
1294 | bool StartObject() { return false; } | |
1295 | }; | |
1296 | ||
1297 | struct HandlerTerminateAtStartArray : public IterativeParsingReaderHandler<> { | |
1298 | bool StartArray() { return false; } | |
1299 | }; | |
1300 | ||
1301 | struct HandlerTerminateAtEndObject : public IterativeParsingReaderHandler<> { | |
1302 | bool EndObject(SizeType) { return false; } | |
1303 | }; | |
1304 | ||
1305 | struct HandlerTerminateAtEndArray : public IterativeParsingReaderHandler<> { | |
1306 | bool EndArray(SizeType) { return false; } | |
1307 | }; | |
1308 | ||
1309 | TEST(Reader, IterativeParsing_ShortCircuit) { | |
1310 | { | |
1311 | HandlerTerminateAtStartObject handler; | |
1312 | Reader reader; | |
1313 | StringStream is("[1, {}]"); | |
1314 | ||
1315 | ParseResult r = reader.Parse<kParseIterativeFlag>(is, handler); | |
1316 | ||
1317 | EXPECT_TRUE(reader.HasParseError()); | |
1318 | EXPECT_EQ(kParseErrorTermination, r.Code()); | |
1319 | EXPECT_EQ(4u, r.Offset()); | |
1320 | } | |
1321 | ||
1322 | { | |
1323 | HandlerTerminateAtStartArray handler; | |
1324 | Reader reader; | |
1325 | StringStream is("{\"a\": []}"); | |
1326 | ||
1327 | ParseResult r = reader.Parse<kParseIterativeFlag>(is, handler); | |
1328 | ||
1329 | EXPECT_TRUE(reader.HasParseError()); | |
1330 | EXPECT_EQ(kParseErrorTermination, r.Code()); | |
1331 | EXPECT_EQ(6u, r.Offset()); | |
1332 | } | |
1333 | ||
1334 | { | |
1335 | HandlerTerminateAtEndObject handler; | |
1336 | Reader reader; | |
1337 | StringStream is("[1, {}]"); | |
1338 | ||
1339 | ParseResult r = reader.Parse<kParseIterativeFlag>(is, handler); | |
1340 | ||
1341 | EXPECT_TRUE(reader.HasParseError()); | |
1342 | EXPECT_EQ(kParseErrorTermination, r.Code()); | |
1343 | EXPECT_EQ(5u, r.Offset()); | |
1344 | } | |
1345 | ||
1346 | { | |
1347 | HandlerTerminateAtEndArray handler; | |
1348 | Reader reader; | |
1349 | StringStream is("{\"a\": []}"); | |
1350 | ||
1351 | ParseResult r = reader.Parse<kParseIterativeFlag>(is, handler); | |
1352 | ||
1353 | EXPECT_TRUE(reader.HasParseError()); | |
1354 | EXPECT_EQ(kParseErrorTermination, r.Code()); | |
1355 | EXPECT_EQ(7u, r.Offset()); | |
1356 | } | |
1357 | } | |
1358 | ||
1359 | // For covering BaseReaderHandler default functions | |
1360 | TEST(Reader, BaseReaderHandler_Default) { | |
1361 | BaseReaderHandler<> h; | |
1362 | Reader reader; | |
1363 | StringStream is("[null, true, -1, 1, -1234567890123456789, 1234567890123456789, 3.14, \"s\", { \"a\" : 1 }]"); | |
1364 | EXPECT_TRUE(reader.Parse(is, h)); | |
1365 | } | |
1366 | ||
1367 | template <int e> | |
1368 | struct TerminateHandler { | |
1369 | bool Null() { return e != 0; } | |
1370 | bool Bool(bool) { return e != 1; } | |
1371 | bool Int(int) { return e != 2; } | |
1372 | bool Uint(unsigned) { return e != 3; } | |
1373 | bool Int64(int64_t) { return e != 4; } | |
1374 | bool Uint64(uint64_t) { return e != 5; } | |
1375 | bool Double(double) { return e != 6; } | |
1376 | bool RawNumber(const char*, SizeType, bool) { return e != 7; } | |
1377 | bool String(const char*, SizeType, bool) { return e != 8; } | |
1378 | bool StartObject() { return e != 9; } | |
1379 | bool Key(const char*, SizeType, bool) { return e != 10; } | |
1380 | bool EndObject(SizeType) { return e != 11; } | |
1381 | bool StartArray() { return e != 12; } | |
1382 | bool EndArray(SizeType) { return e != 13; } | |
1383 | }; | |
1384 | ||
1385 | #define TEST_TERMINATION(e, json)\ | |
1386 | {\ | |
1387 | Reader reader;\ | |
1388 | TerminateHandler<e> h;\ | |
1389 | StringStream is(json);\ | |
1390 | EXPECT_FALSE(reader.Parse(is, h));\ | |
1391 | EXPECT_EQ(kParseErrorTermination, reader.GetParseErrorCode());\ | |
1392 | } | |
1393 | ||
1394 | TEST(Reader, ParseTerminationByHandler) { | |
1395 | TEST_TERMINATION(0, "[null"); | |
1396 | TEST_TERMINATION(1, "[true"); | |
1397 | TEST_TERMINATION(1, "[false"); | |
1398 | TEST_TERMINATION(2, "[-1"); | |
1399 | TEST_TERMINATION(3, "[1"); | |
1400 | TEST_TERMINATION(4, "[-1234567890123456789"); | |
1401 | TEST_TERMINATION(5, "[1234567890123456789"); | |
1402 | TEST_TERMINATION(6, "[0.5]"); | |
1403 | // RawNumber() is never called | |
1404 | TEST_TERMINATION(8, "[\"a\""); | |
1405 | TEST_TERMINATION(9, "[{"); | |
1406 | TEST_TERMINATION(10, "[{\"a\""); | |
1407 | TEST_TERMINATION(11, "[{}"); | |
1408 | TEST_TERMINATION(11, "[{\"a\":1}"); // non-empty object | |
1409 | TEST_TERMINATION(12, "{\"a\":["); | |
1410 | TEST_TERMINATION(13, "{\"a\":[]"); | |
1411 | TEST_TERMINATION(13, "{\"a\":[1]"); // non-empty array | |
1412 | } | |
1413 | ||
1414 | TEST(Reader, ParseComments) { | |
1415 | const char* json = | |
1416 | "// Here is a one-line comment.\n" | |
1417 | "{// And here's another one\n" | |
1418 | " /*And here's an in-line one.*/\"hello\" : \"world\"," | |
1419 | " \"t\" :/* And one with '*' symbol*/true ," | |
1420 | "/* A multiline comment\n" | |
1421 | " goes here*/" | |
1422 | " \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3]" | |
1423 | "}/*And the last one to be sure */"; | |
1424 | ||
1425 | StringStream s(json); | |
1426 | ParseObjectHandler h; | |
1427 | Reader reader; | |
1428 | EXPECT_TRUE(reader.Parse<kParseCommentsFlag>(s, h)); | |
1429 | EXPECT_EQ(20u, h.step_); | |
1430 | } | |
1431 | ||
1432 | TEST(Reader, ParseEmptyInlineComment) { | |
1433 | const char* json = "{/**/\"hello\" : \"world\", \"t\" : true, \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] }"; | |
1434 | ||
1435 | StringStream s(json); | |
1436 | ParseObjectHandler h; | |
1437 | Reader reader; | |
1438 | EXPECT_TRUE(reader.Parse<kParseCommentsFlag>(s, h)); | |
1439 | EXPECT_EQ(20u, h.step_); | |
1440 | } | |
1441 | ||
1442 | TEST(Reader, ParseEmptyOnelineComment) { | |
1443 | const char* json = "{//\n\"hello\" : \"world\", \"t\" : true, \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] }"; | |
1444 | ||
1445 | StringStream s(json); | |
1446 | ParseObjectHandler h; | |
1447 | Reader reader; | |
1448 | EXPECT_TRUE(reader.Parse<kParseCommentsFlag>(s, h)); | |
1449 | EXPECT_EQ(20u, h.step_); | |
1450 | } | |
1451 | ||
1452 | TEST(Reader, ParseMultipleCommentsInARow) { | |
1453 | const char* json = | |
1454 | "{/* first comment *//* second */\n" | |
1455 | "/* third */ /*fourth*/// last one\n" | |
1456 | "\"hello\" : \"world\", \"t\" : true, \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] }"; | |
1457 | ||
1458 | StringStream s(json); | |
1459 | ParseObjectHandler h; | |
1460 | Reader reader; | |
1461 | EXPECT_TRUE(reader.Parse<kParseCommentsFlag>(s, h)); | |
1462 | EXPECT_EQ(20u, h.step_); | |
1463 | } | |
1464 | ||
1465 | TEST(Reader, InlineCommentsAreDisabledByDefault) { | |
1466 | { | |
1467 | const char* json = "{/* Inline comment. */\"hello\" : \"world\", \"t\" : true, \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] }"; | |
1468 | ||
1469 | StringStream s(json); | |
1470 | ParseObjectHandler h; | |
1471 | Reader reader; | |
1472 | EXPECT_FALSE(reader.Parse<kParseDefaultFlags>(s, h)); | |
1473 | } | |
1474 | ||
1475 | { | |
1476 | const char* json = | |
1477 | "{\"hello\" : /* Multiline comment starts here\n" | |
1478 | " continues here\n" | |
1479 | " and ends here */\"world\", \"t\" :true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] }"; | |
1480 | ||
1481 | StringStream s(json); | |
1482 | ParseObjectHandler h; | |
1483 | Reader reader; | |
1484 | EXPECT_FALSE(reader.Parse<kParseDefaultFlags>(s, h)); | |
1485 | } | |
1486 | } | |
1487 | ||
1488 | TEST(Reader, OnelineCommentsAreDisabledByDefault) { | |
1489 | const char* json = "{// One-line comment\n\"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] }"; | |
1490 | ||
1491 | StringStream s(json); | |
1492 | ParseObjectHandler h; | |
1493 | Reader reader; | |
1494 | EXPECT_FALSE(reader.Parse<kParseDefaultFlags>(s, h)); | |
1495 | } | |
1496 | ||
1497 | TEST(Reader, EofAfterOneLineComment) { | |
1498 | const char* json = "{\"hello\" : \"world\" // EOF is here -->\0 \n}"; | |
1499 | ||
1500 | StringStream s(json); | |
1501 | ParseObjectHandler h; | |
1502 | Reader reader; | |
1503 | EXPECT_FALSE(reader.Parse<kParseCommentsFlag>(s, h)); | |
1504 | EXPECT_EQ(kParseErrorObjectMissCommaOrCurlyBracket, reader.GetParseErrorCode()); | |
1505 | } | |
1506 | ||
1507 | TEST(Reader, IncompleteMultilineComment) { | |
1508 | const char* json = "{\"hello\" : \"world\" /* EOF is here -->\0 */}"; | |
1509 | ||
1510 | StringStream s(json); | |
1511 | ParseObjectHandler h; | |
1512 | Reader reader; | |
1513 | EXPECT_FALSE(reader.Parse<kParseCommentsFlag>(s, h)); | |
1514 | EXPECT_EQ(kParseErrorUnspecificSyntaxError, reader.GetParseErrorCode()); | |
1515 | } | |
1516 | ||
1517 | TEST(Reader, IncompleteMultilineComment2) { | |
1518 | const char* json = "{\"hello\" : \"world\" /* *\0 */}"; | |
1519 | ||
1520 | StringStream s(json); | |
1521 | ParseObjectHandler h; | |
1522 | Reader reader; | |
1523 | EXPECT_FALSE(reader.Parse<kParseCommentsFlag>(s, h)); | |
1524 | EXPECT_EQ(kParseErrorUnspecificSyntaxError, reader.GetParseErrorCode()); | |
1525 | } | |
1526 | ||
1527 | TEST(Reader, UnrecognizedComment) { | |
1528 | const char* json = "{\"hello\" : \"world\" /! }"; | |
1529 | ||
1530 | StringStream s(json); | |
1531 | ParseObjectHandler h; | |
1532 | Reader reader; | |
1533 | EXPECT_FALSE(reader.Parse<kParseCommentsFlag>(s, h)); | |
1534 | EXPECT_EQ(kParseErrorUnspecificSyntaxError, reader.GetParseErrorCode()); | |
1535 | } | |
1536 | ||
1537 | struct NumbersAsStringsHandler { | |
1538 | bool Null() { return true; } | |
1539 | bool Bool(bool) { return true; } | |
1540 | bool Int(int) { return true; } | |
1541 | bool Uint(unsigned) { return true; } | |
1542 | bool Int64(int64_t) { return true; } | |
1543 | bool Uint64(uint64_t) { return true; } | |
1544 | bool Double(double) { return true; } | |
1545 | // 'str' is not null-terminated | |
1546 | bool RawNumber(const char* str, SizeType length, bool) { | |
1547 | EXPECT_TRUE(str != 0); | |
1548 | EXPECT_TRUE(expected_len_ == length); | |
1549 | EXPECT_TRUE(strncmp(str, expected_, length) == 0); | |
1550 | return true; | |
1551 | } | |
1552 | bool String(const char*, SizeType, bool) { return true; } | |
1553 | bool StartObject() { return true; } | |
1554 | bool Key(const char*, SizeType, bool) { return true; } | |
1555 | bool EndObject(SizeType) { return true; } | |
1556 | bool StartArray() { return true; } | |
1557 | bool EndArray(SizeType) { return true; } | |
1558 | ||
1559 | NumbersAsStringsHandler(const char* expected) | |
1560 | : expected_(expected) | |
1561 | , expected_len_(strlen(expected)) {} | |
1562 | ||
1563 | const char* expected_; | |
1564 | size_t expected_len_; | |
1565 | }; | |
1566 | ||
1567 | TEST(Reader, NumbersAsStrings) { | |
1568 | { | |
1569 | const char* json = "{ \"pi\": 3.1416 } "; | |
1570 | StringStream s(json); | |
1571 | NumbersAsStringsHandler h("3.1416"); | |
1572 | Reader reader; | |
1573 | EXPECT_TRUE(reader.Parse<kParseNumbersAsStringsFlag>(s, h)); | |
1574 | } | |
1575 | { | |
1576 | char* json = StrDup("{ \"pi\": 3.1416 } "); | |
1577 | InsituStringStream s(json); | |
1578 | NumbersAsStringsHandler h("3.1416"); | |
1579 | Reader reader; | |
1580 | EXPECT_TRUE(reader.Parse<kParseInsituFlag|kParseNumbersAsStringsFlag>(s, h)); | |
1581 | free(json); | |
1582 | } | |
1583 | { | |
1584 | const char* json = "{ \"gigabyte\": 1.0e9 } "; | |
1585 | StringStream s(json); | |
1586 | NumbersAsStringsHandler h("1.0e9"); | |
1587 | Reader reader; | |
1588 | EXPECT_TRUE(reader.Parse<kParseNumbersAsStringsFlag>(s, h)); | |
1589 | } | |
1590 | { | |
1591 | char* json = StrDup("{ \"gigabyte\": 1.0e9 } "); | |
1592 | InsituStringStream s(json); | |
1593 | NumbersAsStringsHandler h("1.0e9"); | |
1594 | Reader reader; | |
1595 | EXPECT_TRUE(reader.Parse<kParseInsituFlag|kParseNumbersAsStringsFlag>(s, h)); | |
1596 | free(json); | |
1597 | } | |
1598 | { | |
1599 | const char* json = "{ \"pi\": 314.159e-2 } "; | |
1600 | StringStream s(json); | |
1601 | NumbersAsStringsHandler h("314.159e-2"); | |
1602 | Reader reader; | |
1603 | EXPECT_TRUE(reader.Parse<kParseNumbersAsStringsFlag>(s, h)); | |
1604 | } | |
1605 | { | |
1606 | char* json = StrDup("{ \"gigabyte\": 314.159e-2 } "); | |
1607 | InsituStringStream s(json); | |
1608 | NumbersAsStringsHandler h("314.159e-2"); | |
1609 | Reader reader; | |
1610 | EXPECT_TRUE(reader.Parse<kParseInsituFlag|kParseNumbersAsStringsFlag>(s, h)); | |
1611 | free(json); | |
1612 | } | |
1613 | { | |
1614 | const char* json = "{ \"negative\": -1.54321 } "; | |
1615 | StringStream s(json); | |
1616 | NumbersAsStringsHandler h("-1.54321"); | |
1617 | Reader reader; | |
1618 | EXPECT_TRUE(reader.Parse<kParseNumbersAsStringsFlag>(s, h)); | |
1619 | } | |
1620 | { | |
1621 | char* json = StrDup("{ \"negative\": -1.54321 } "); | |
1622 | InsituStringStream s(json); | |
1623 | NumbersAsStringsHandler h("-1.54321"); | |
1624 | Reader reader; | |
1625 | EXPECT_TRUE(reader.Parse<kParseInsituFlag|kParseNumbersAsStringsFlag>(s, h)); | |
1626 | free(json); | |
1627 | } | |
1628 | { | |
1629 | const char* json = "{ \"pi\": 314.159e-2 } "; | |
1630 | std::stringstream ss(json); | |
1631 | IStreamWrapper s(ss); | |
1632 | NumbersAsStringsHandler h("314.159e-2"); | |
1633 | Reader reader; | |
1634 | EXPECT_TRUE(reader.Parse<kParseNumbersAsStringsFlag>(s, h)); | |
1635 | } | |
1636 | } | |
1637 | ||
1638 | template <unsigned extraFlags> | |
1639 | void TestTrailingCommas() { | |
1640 | { | |
1641 | StringStream s("[1,2,3,]"); | |
1642 | ParseArrayHandler<3> h; | |
1643 | Reader reader; | |
1644 | EXPECT_TRUE(reader.Parse<extraFlags|kParseTrailingCommasFlag>(s, h)); | |
1645 | EXPECT_EQ(5u, h.step_); | |
1646 | } | |
1647 | { | |
1648 | const char* json = "{ \"hello\" : \"world\", \"t\" : true , \"f\" : false," | |
1649 | "\"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3],}"; | |
1650 | StringStream s(json); | |
1651 | ParseObjectHandler h; | |
1652 | Reader reader; | |
1653 | EXPECT_TRUE(reader.Parse<extraFlags|kParseTrailingCommasFlag>(s, h)); | |
1654 | EXPECT_EQ(20u, h.step_); | |
1655 | } | |
1656 | { | |
1657 | // whitespace around trailing commas | |
1658 | const char* json = "{ \"hello\" : \"world\", \"t\" : true , \"f\" : false," | |
1659 | "\"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3\n,\n]\n,\n} "; | |
1660 | StringStream s(json); | |
1661 | ParseObjectHandler h; | |
1662 | Reader reader; | |
1663 | EXPECT_TRUE(reader.Parse<extraFlags|kParseTrailingCommasFlag>(s, h)); | |
1664 | EXPECT_EQ(20u, h.step_); | |
1665 | } | |
1666 | { | |
1667 | // comments around trailing commas | |
1668 | const char* json = "{ \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null," | |
1669 | "\"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3/*test*/,/*test*/]/*test*/,/*test*/}"; | |
1670 | StringStream s(json); | |
1671 | ParseObjectHandler h; | |
1672 | Reader reader; | |
1673 | EXPECT_TRUE(reader.Parse<extraFlags|kParseTrailingCommasFlag|kParseCommentsFlag>(s, h)); | |
1674 | EXPECT_EQ(20u, h.step_); | |
1675 | } | |
1676 | } | |
1677 | ||
1678 | TEST(Reader, TrailingCommas) { | |
1679 | TestTrailingCommas<kParseNoFlags>(); | |
1680 | } | |
1681 | ||
1682 | TEST(Reader, TrailingCommasIterative) { | |
1683 | TestTrailingCommas<kParseIterativeFlag>(); | |
1684 | } | |
1685 | ||
1686 | template <unsigned extraFlags> | |
1687 | void TestMultipleTrailingCommaErrors() { | |
1688 | // only a single trailing comma is allowed. | |
1689 | { | |
1690 | StringStream s("[1,2,3,,]"); | |
1691 | ParseArrayHandler<3> h; | |
1692 | Reader reader; | |
1693 | ParseResult r = reader.Parse<extraFlags|kParseTrailingCommasFlag>(s, h); | |
1694 | EXPECT_TRUE(reader.HasParseError()); | |
1695 | EXPECT_EQ(kParseErrorValueInvalid, r.Code()); | |
1696 | EXPECT_EQ(7u, r.Offset()); | |
1697 | } | |
1698 | { | |
1699 | const char* json = "{ \"hello\" : \"world\", \"t\" : true , \"f\" : false," | |
1700 | "\"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3,],,}"; | |
1701 | StringStream s(json); | |
1702 | ParseObjectHandler h; | |
1703 | Reader reader; | |
1704 | ParseResult r = reader.Parse<extraFlags|kParseTrailingCommasFlag>(s, h); | |
1705 | EXPECT_TRUE(reader.HasParseError()); | |
1706 | EXPECT_EQ(kParseErrorObjectMissName, r.Code()); | |
1707 | EXPECT_EQ(95u, r.Offset()); | |
1708 | } | |
1709 | } | |
1710 | ||
1711 | TEST(Reader, MultipleTrailingCommaErrors) { | |
1712 | TestMultipleTrailingCommaErrors<kParseNoFlags>(); | |
1713 | } | |
1714 | ||
1715 | TEST(Reader, MultipleTrailingCommaErrorsIterative) { | |
1716 | TestMultipleTrailingCommaErrors<kParseIterativeFlag>(); | |
1717 | } | |
1718 | ||
1719 | template <unsigned extraFlags> | |
1720 | void TestEmptyExceptForCommaErrors() { | |
1721 | // not allowed even with trailing commas enabled; the | |
1722 | // trailing comma must follow a value. | |
1723 | { | |
1724 | StringStream s("[,]"); | |
1725 | ParseArrayHandler<3> h; | |
1726 | Reader reader; | |
1727 | ParseResult r = reader.Parse<extraFlags|kParseTrailingCommasFlag>(s, h); | |
1728 | EXPECT_TRUE(reader.HasParseError()); | |
1729 | EXPECT_EQ(kParseErrorValueInvalid, r.Code()); | |
1730 | EXPECT_EQ(1u, r.Offset()); | |
1731 | } | |
1732 | { | |
1733 | StringStream s("{,}"); | |
1734 | ParseObjectHandler h; | |
1735 | Reader reader; | |
1736 | ParseResult r = reader.Parse<extraFlags|kParseTrailingCommasFlag>(s, h); | |
1737 | EXPECT_TRUE(reader.HasParseError()); | |
1738 | EXPECT_EQ(kParseErrorObjectMissName, r.Code()); | |
1739 | EXPECT_EQ(1u, r.Offset()); | |
1740 | } | |
1741 | } | |
1742 | ||
1743 | TEST(Reader, EmptyExceptForCommaErrors) { | |
1744 | TestEmptyExceptForCommaErrors<kParseNoFlags>(); | |
1745 | } | |
1746 | ||
1747 | TEST(Reader, EmptyExceptForCommaErrorsIterative) { | |
1748 | TestEmptyExceptForCommaErrors<kParseIterativeFlag>(); | |
1749 | } | |
1750 | ||
1751 | template <unsigned extraFlags> | |
1752 | void TestTrailingCommaHandlerTermination() { | |
1753 | { | |
1754 | HandlerTerminateAtEndArray h; | |
1755 | Reader reader; | |
1756 | StringStream s("[1,2,3,]"); | |
1757 | ParseResult r = reader.Parse<extraFlags|kParseTrailingCommasFlag>(s, h); | |
1758 | EXPECT_TRUE(reader.HasParseError()); | |
1759 | EXPECT_EQ(kParseErrorTermination, r.Code()); | |
1760 | EXPECT_EQ(7u, r.Offset()); | |
1761 | } | |
1762 | { | |
1763 | HandlerTerminateAtEndObject h; | |
1764 | Reader reader; | |
1765 | StringStream s("{\"t\": true, \"f\": false,}"); | |
1766 | ParseResult r = reader.Parse<extraFlags|kParseTrailingCommasFlag>(s, h); | |
1767 | EXPECT_TRUE(reader.HasParseError()); | |
1768 | EXPECT_EQ(kParseErrorTermination, r.Code()); | |
1769 | EXPECT_EQ(23u, r.Offset()); | |
1770 | } | |
1771 | } | |
1772 | ||
1773 | TEST(Reader, TrailingCommaHandlerTermination) { | |
1774 | TestTrailingCommaHandlerTermination<kParseNoFlags>(); | |
1775 | } | |
1776 | ||
1777 | TEST(Reader, TrailingCommaHandlerTerminationIterative) { | |
1778 | TestTrailingCommaHandlerTermination<kParseIterativeFlag>(); | |
1779 | } | |
1780 | ||
1781 | TEST(Reader, ParseNanAndInfinity) { | |
1782 | #define TEST_NAN_INF(str, x) \ | |
1783 | { \ | |
1784 | { \ | |
1785 | StringStream s(str); \ | |
1786 | ParseDoubleHandler h; \ | |
1787 | Reader reader; \ | |
1788 | ASSERT_EQ(kParseErrorNone, reader.Parse<kParseNanAndInfFlag>(s, h).Code()); \ | |
1789 | EXPECT_EQ(1u, h.step_); \ | |
1790 | internal::Double e(x), a(h.actual_); \ | |
1791 | EXPECT_EQ(e.IsNan(), a.IsNan()); \ | |
1792 | EXPECT_EQ(e.IsInf(), a.IsInf()); \ | |
1793 | if (!e.IsNan()) \ | |
1794 | EXPECT_EQ(e.Sign(), a.Sign()); \ | |
1795 | } \ | |
1796 | { \ | |
1797 | const char* json = "{ \"naninfdouble\": " str " } "; \ | |
1798 | StringStream s(json); \ | |
1799 | NumbersAsStringsHandler h(str); \ | |
1800 | Reader reader; \ | |
1801 | EXPECT_TRUE(reader.Parse<kParseNumbersAsStringsFlag|kParseNanAndInfFlag>(s, h)); \ | |
1802 | } \ | |
1803 | { \ | |
1804 | char* json = StrDup("{ \"naninfdouble\": " str " } "); \ | |
1805 | InsituStringStream s(json); \ | |
1806 | NumbersAsStringsHandler h(str); \ | |
1807 | Reader reader; \ | |
1808 | EXPECT_TRUE(reader.Parse<kParseInsituFlag|kParseNumbersAsStringsFlag|kParseNanAndInfFlag>(s, h)); \ | |
1809 | free(json); \ | |
1810 | } \ | |
1811 | } | |
1812 | #define TEST_NAN_INF_ERROR(errorCode, str, errorOffset) \ | |
1813 | { \ | |
1814 | int streamPos = errorOffset; \ | |
1815 | char buffer[1001]; \ | |
1816 | strncpy(buffer, str, 1000); \ | |
1817 | InsituStringStream s(buffer); \ | |
1818 | BaseReaderHandler<> h; \ | |
1819 | Reader reader; \ | |
1820 | EXPECT_FALSE(reader.Parse<kParseNanAndInfFlag>(s, h)); \ | |
1821 | EXPECT_EQ(errorCode, reader.GetParseErrorCode());\ | |
1822 | EXPECT_EQ(errorOffset, reader.GetErrorOffset());\ | |
1823 | EXPECT_EQ(streamPos, s.Tell());\ | |
1824 | } | |
1825 | ||
1826 | double nan = std::numeric_limits<double>::quiet_NaN(); | |
1827 | double inf = std::numeric_limits<double>::infinity(); | |
1828 | ||
1829 | TEST_NAN_INF("NaN", nan); | |
1830 | TEST_NAN_INF("-NaN", nan); | |
1831 | TEST_NAN_INF("Inf", inf); | |
1832 | TEST_NAN_INF("Infinity", inf); | |
1833 | TEST_NAN_INF("-Inf", -inf); | |
1834 | TEST_NAN_INF("-Infinity", -inf); | |
1835 | TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "nan", 1); | |
1836 | TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "-nan", 1); | |
1837 | TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "NAN", 1); | |
1838 | TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "-Infinty", 6); | |
1839 | ||
1840 | #undef TEST_NAN_INF_ERROR | |
1841 | #undef TEST_NAN_INF | |
1842 | } | |
1843 | ||
1844 | RAPIDJSON_DIAG_POP |