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 27 JsonEndToEndTest::JsonEndToEndTest() 28 { 29 } 30 31 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 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 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 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 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 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 127 JsonEndToEndTest::TestNullA() 128 { 129 TestParseAndWrite(JSON_SAMPLE_NULL_A_IN, 130 JSON_SAMPLE_NULL_A_EXPECTED_OUT); 131 } 132 133 134 void 135 JsonEndToEndTest::TestTrueA() 136 { 137 TestParseAndWrite(JSON_SAMPLE_TRUE_A_IN, 138 JSON_SAMPLE_TRUE_A_EXPECTED_OUT); 139 } 140 141 142 void 143 JsonEndToEndTest::TestFalseA() 144 { 145 TestParseAndWrite(JSON_SAMPLE_FALSE_A_IN, 146 JSON_SAMPLE_FALSE_A_EXPECTED_OUT); 147 } 148 149 150 void 151 JsonEndToEndTest::TestNumberA() 152 { 153 TestParseAndWrite(JSON_SAMPLE_NUMBER_A_IN, 154 JSON_SAMPLE_NUMBER_A_EXPECTED_OUT); 155 } 156 157 158 void 159 JsonEndToEndTest::TestStringA() 160 { 161 TestParseAndWrite(JSON_SAMPLE_STRING_A_IN, 162 JSON_SAMPLE_STRING_A_EXPECTED_OUT); 163 } 164 165 166 void 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 177 JsonEndToEndTest::TestStringA2() 178 { 179 TestParseAndWrite(JSON_SAMPLE_STRING_A2_IN, 180 JSON_SAMPLE_STRING_A_EXPECTED_OUT); 181 } 182 183 184 void 185 JsonEndToEndTest::TestArrayA() 186 { 187 TestParseAndWrite(JSON_SAMPLE_ARRAY_A_IN, JSON_SAMPLE_ARRAY_A_EXPECTED_OUT); 188 } 189 190 191 void 192 JsonEndToEndTest::TestArrayB() 193 { 194 TestParseAndWrite(JSON_SAMPLE_ARRAY_B_IN, JSON_SAMPLE_ARRAY_B_EXPECTED_OUT); 195 } 196 197 198 void 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 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 231 JsonEndToEndTest::TestStringUnterminated() 232 { 233 TestUnterminated(JSON_SAMPLE_BROKEN_UNTERMINATED_STRING); 234 } 235 236 void 237 JsonEndToEndTest::TestArrayUnterminated() 238 { 239 TestUnterminated(JSON_SAMPLE_BROKEN_UNTERMINATED_ARRAY); 240 } 241 242 void 243 JsonEndToEndTest::TestObjectUnterminated() 244 { 245 TestUnterminated(JSON_SAMPLE_BROKEN_UNTERMINATED_OBJECT); 246 } 247 248 249 /*static*/ void 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