1 /*
2 * Copyright 2017-2023, Andrew Lindesay <apl@lindesay.co.nz>
3 * Distributed under the terms of the MIT License.
4 */
5 #include "JsonEndToEndTest.h"
6
7 #include <AutoDeleter.h>
8
9 #include <Json.h>
10 #include <JsonTextWriter.h>
11
12 #include <cppunit/TestCaller.h>
13 #include <cppunit/TestSuite.h>
14
15 #include "ChecksumJsonEventListener.h"
16 #include "FakeJsonDataGenerator.h"
17 #include "JsonSamples.h"
18
19
20 using namespace BPrivate;
21
22
23 static const size_t kHighVolumeItemCount = 10000;
24 static const uint32 kChecksumLimit = 100000;
25
26
JsonEndToEndTest()27 JsonEndToEndTest::JsonEndToEndTest()
28 {
29 }
30
31
~JsonEndToEndTest()32 JsonEndToEndTest::~JsonEndToEndTest()
33 {
34 }
35
36
37 /*! Just here so it is possible to extract timings for the data generation cost.
38 */
39
40 void
TestHighVolumeStringSampleGenerationOnly()41 JsonEndToEndTest::TestHighVolumeStringSampleGenerationOnly()
42 {
43 FakeJsonStreamDataIO* inputData = new FakeJsonStringStreamDataIO(kHighVolumeItemCount,
44 kChecksumLimit);
45 char c;
46
47 while (inputData->Read(&c, 1) == 1) {
48 // do nothing
49 }
50 }
51
52
53 /*! Just here so it is possible to extract timings for the data generation cost.
54 */
55
56 void
TestHighVolumeNumberSampleGenerationOnly()57 JsonEndToEndTest::TestHighVolumeNumberSampleGenerationOnly()
58 {
59 FakeJsonStreamDataIO* inputData = new FakeJsonNumberStreamDataIO(kHighVolumeItemCount,
60 kChecksumLimit);
61 char c;
62
63 while (inputData->Read(&c, 1) == 1) {
64 // do nothing
65 }
66 }
67
68
69 void
TestHighVolumeStringParsing()70 JsonEndToEndTest::TestHighVolumeStringParsing()
71 {
72 FakeJsonStreamDataIO* inputData = new FakeJsonStringStreamDataIO(kHighVolumeItemCount,
73 kChecksumLimit);
74 ChecksumJsonEventListener* listener = new ChecksumJsonEventListener(kChecksumLimit);
75
76 // ----------------------
77 BPrivate::BJson::Parse(inputData, listener);
78 // ----------------------
79
80 CPPUNIT_ASSERT_EQUAL(B_OK, listener->Error());
81 CPPUNIT_ASSERT_EQUAL(inputData->Checksum(), listener->Checksum());
82 }
83
84
85 void
TestHighVolumeNumberParsing()86 JsonEndToEndTest::TestHighVolumeNumberParsing()
87 {
88 FakeJsonStreamDataIO* inputData = new FakeJsonNumberStreamDataIO(kHighVolumeItemCount,
89 kChecksumLimit);
90 ChecksumJsonEventListener* listener = new ChecksumJsonEventListener(kChecksumLimit);
91
92 // ----------------------
93 BPrivate::BJson::Parse(inputData, listener);
94 // ----------------------
95
96 CPPUNIT_ASSERT_EQUAL(B_OK, listener->Error());
97 CPPUNIT_ASSERT_EQUAL(inputData->Checksum(), listener->Checksum());
98 }
99
100
101 void
TestParseAndWrite(const char * input,const char * expectedOutput)102 JsonEndToEndTest::TestParseAndWrite(const char* input, const char* expectedOutput)
103 {
104 BDataIO* inputData = new BMemoryIO(input, strlen(input));
105 ObjectDeleter<BDataIO> inputDataDeleter(inputData);
106 BMallocIO* outputData = new BMallocIO();
107 ObjectDeleter<BMallocIO> outputDataDeleter(outputData);
108 BPrivate::BJsonTextWriter* listener
109 = new BJsonTextWriter(outputData);
110 ObjectDeleter<BPrivate::BJsonTextWriter> listenerDeleter(listener);
111
112 // ----------------------
113 BPrivate::BJson::Parse(inputData, listener);
114 // ----------------------
115
116 CPPUNIT_ASSERT_EQUAL(B_OK, listener->ErrorStatus());
117 fprintf(stderr, "in >%s<\n", input);
118 fprintf(stderr, "expected out >%s<\n", expectedOutput);
119 fprintf(stderr, "actual out >%s<\n", (char*)outputData->Buffer());
120 CPPUNIT_ASSERT_MESSAGE("expected did no equal actual output",
121 0 == strncmp(expectedOutput, (char*)outputData->Buffer(),
122 strlen(expectedOutput)));
123 }
124
125
126 void
TestNullA()127 JsonEndToEndTest::TestNullA()
128 {
129 TestParseAndWrite(JSON_SAMPLE_NULL_A_IN,
130 JSON_SAMPLE_NULL_A_EXPECTED_OUT);
131 }
132
133
134 void
TestTrueA()135 JsonEndToEndTest::TestTrueA()
136 {
137 TestParseAndWrite(JSON_SAMPLE_TRUE_A_IN,
138 JSON_SAMPLE_TRUE_A_EXPECTED_OUT);
139 }
140
141
142 void
TestFalseA()143 JsonEndToEndTest::TestFalseA()
144 {
145 TestParseAndWrite(JSON_SAMPLE_FALSE_A_IN,
146 JSON_SAMPLE_FALSE_A_EXPECTED_OUT);
147 }
148
149
150 void
TestNumberA()151 JsonEndToEndTest::TestNumberA()
152 {
153 TestParseAndWrite(JSON_SAMPLE_NUMBER_A_IN,
154 JSON_SAMPLE_NUMBER_A_EXPECTED_OUT);
155 }
156
157
158 void
TestStringA()159 JsonEndToEndTest::TestStringA()
160 {
161 TestParseAndWrite(JSON_SAMPLE_STRING_A_IN,
162 JSON_SAMPLE_STRING_A_EXPECTED_OUT);
163 }
164
165
166 void
TestStringB()167 JsonEndToEndTest::TestStringB()
168 {
169 TestParseAndWrite(JSON_SAMPLE_STRING_B_IN,
170 JSON_SAMPLE_STRING_B_EXPECTED_OUT);
171 }
172
173
174 /* In this test, there are some UTF-8 characters. */
175
176 void
TestStringA2()177 JsonEndToEndTest::TestStringA2()
178 {
179 TestParseAndWrite(JSON_SAMPLE_STRING_A2_IN,
180 JSON_SAMPLE_STRING_A_EXPECTED_OUT);
181 }
182
183
184 void
TestArrayA()185 JsonEndToEndTest::TestArrayA()
186 {
187 TestParseAndWrite(JSON_SAMPLE_ARRAY_A_IN, JSON_SAMPLE_ARRAY_A_EXPECTED_OUT);
188 }
189
190
191 void
TestArrayB()192 JsonEndToEndTest::TestArrayB()
193 {
194 TestParseAndWrite(JSON_SAMPLE_ARRAY_B_IN, JSON_SAMPLE_ARRAY_B_EXPECTED_OUT);
195 }
196
197
198 void
TestObjectA()199 JsonEndToEndTest::TestObjectA()
200 {
201 TestParseAndWrite(JSON_SAMPLE_OBJECT_A_IN,
202 JSON_SAMPLE_OBJECT_A_EXPECTED_OUT);
203 }
204
205
206 /*! This method will test an element being unterminated; such an object that
207 is missing the terminating "}" symbol or a string that has no closing
208 quote. This is tested here because the writer
209 */
210
211 void
TestUnterminated(const char * input)212 JsonEndToEndTest::TestUnterminated(const char *input)
213 {
214 BDataIO* inputData = new BMemoryIO(input, strlen(input));
215 ObjectDeleter<BDataIO> inputDataDeleter(inputData);
216 BMallocIO* outputData = new BMallocIO();
217 ObjectDeleter<BMallocIO> outputDataDeleter(outputData);
218 BPrivate::BJsonTextWriter* listener
219 = new BJsonTextWriter(outputData);
220 ObjectDeleter<BPrivate::BJsonTextWriter> listenerDeleter(listener);
221
222 // ----------------------
223 BPrivate::BJson::Parse(inputData, listener);
224 // ----------------------
225
226 CPPUNIT_ASSERT_EQUAL(B_BAD_DATA, listener->ErrorStatus());
227 }
228
229
230 void
TestStringUnterminated()231 JsonEndToEndTest::TestStringUnterminated()
232 {
233 TestUnterminated(JSON_SAMPLE_BROKEN_UNTERMINATED_STRING);
234 }
235
236 void
TestArrayUnterminated()237 JsonEndToEndTest::TestArrayUnterminated()
238 {
239 TestUnterminated(JSON_SAMPLE_BROKEN_UNTERMINATED_ARRAY);
240 }
241
242 void
TestObjectUnterminated()243 JsonEndToEndTest::TestObjectUnterminated()
244 {
245 TestUnterminated(JSON_SAMPLE_BROKEN_UNTERMINATED_OBJECT);
246 }
247
248
249 /*static*/ void
AddTests(BTestSuite & parent)250 JsonEndToEndTest::AddTests(BTestSuite& parent)
251 {
252 CppUnit::TestSuite& suite = *new CppUnit::TestSuite("JsonEndToEndTest");
253
254 suite.addTest(new CppUnit::TestCaller<JsonEndToEndTest>(
255 "JsonEndToEndTest::TestNullA", &JsonEndToEndTest::TestNullA));
256 suite.addTest(new CppUnit::TestCaller<JsonEndToEndTest>(
257 "JsonEndToEndTest::TestTrueA", &JsonEndToEndTest::TestTrueA));
258 suite.addTest(new CppUnit::TestCaller<JsonEndToEndTest>(
259 "JsonEndToEndTest::TestFalseA", &JsonEndToEndTest::TestFalseA));
260 suite.addTest(new CppUnit::TestCaller<JsonEndToEndTest>(
261 "JsonEndToEndTest::TestNumberA", &JsonEndToEndTest::TestNumberA));
262 suite.addTest(new CppUnit::TestCaller<JsonEndToEndTest>(
263 "JsonEndToEndTest::TestStringA", &JsonEndToEndTest::TestStringA));
264 suite.addTest(new CppUnit::TestCaller<JsonEndToEndTest>(
265 "JsonEndToEndTest::TestStringA2", &JsonEndToEndTest::TestStringA2));
266 suite.addTest(new CppUnit::TestCaller<JsonEndToEndTest>(
267 "JsonEndToEndTest::TestStringB", &JsonEndToEndTest::TestStringB));
268 suite.addTest(new CppUnit::TestCaller<JsonEndToEndTest>(
269 "JsonEndToEndTest::TestArrayA", &JsonEndToEndTest::TestArrayA));
270 suite.addTest(new CppUnit::TestCaller<JsonEndToEndTest>(
271 "JsonEndToEndTest::TestArrayB", &JsonEndToEndTest::TestArrayB));
272 suite.addTest(new CppUnit::TestCaller<JsonEndToEndTest>(
273 "JsonEndToEndTest::TestObjectA", &JsonEndToEndTest::TestObjectA));
274 suite.addTest(new CppUnit::TestCaller<JsonEndToEndTest>(
275 "JsonEndToEndTest::TestStringUnterminated",
276 &JsonEndToEndTest::TestStringUnterminated));
277 suite.addTest(new CppUnit::TestCaller<JsonEndToEndTest>(
278 "JsonEndToEndTest::TestArrayUnterminated",
279 &JsonEndToEndTest::TestArrayUnterminated));
280 suite.addTest(new CppUnit::TestCaller<JsonEndToEndTest>(
281 "JsonEndToEndTest::TestHighVolumeStringParsing",
282 &JsonEndToEndTest::TestHighVolumeStringParsing));
283 suite.addTest(new CppUnit::TestCaller<JsonEndToEndTest>(
284 "JsonEndToEndTest::TestHighVolumeNumberParsing",
285 &JsonEndToEndTest::TestHighVolumeNumberParsing));
286 suite.addTest(new CppUnit::TestCaller<JsonEndToEndTest>(
287 "JsonEndToEndTest::TestHighVolumeStringSampleGenerationOnly",
288 &JsonEndToEndTest::TestHighVolumeStringSampleGenerationOnly));
289 suite.addTest(new CppUnit::TestCaller<JsonEndToEndTest>(
290 "JsonEndToEndTest::TestHighVolumeNumberSampleGenerationOnly",
291 &JsonEndToEndTest::TestHighVolumeNumberSampleGenerationOnly));
292
293 parent.addTest("JsonEndToEndTest", &suite);
294 }
295