1228512Sjilles/* 2228512Sjilles * Copyright 2017, Andrew Lindesay <apl@lindesay.co.nz> 3228512Sjilles * Distributed under the terms of the MIT License. 4228512Sjilles */ 5228512Sjilles#include "JsonErrorHandlingTest.h" 6228512Sjilles 7228512Sjilles#include <AutoDeleter.h> 8228512Sjilles 9228512Sjilles#include <Json.h> 10228512Sjilles#include <JsonEventListener.h> 11228512Sjilles 12228512Sjilles#include <cppunit/TestCaller.h> 13228512Sjilles#include <cppunit/TestSuite.h> 14228512Sjilles 15228512Sjilles#include "JsonSamples.h" 16228512Sjilles 17228512Sjilles 18228512Sjillesusing namespace BPrivate; 19228512Sjilles 20228512Sjillesclass ErrorCapturingListener : public BJsonEventListener { 21228512Sjillespublic: 22228512Sjilles ErrorCapturingListener(); 23228512Sjilles virtual ~ErrorCapturingListener(); 24228512Sjilles 25228512Sjilles bool Handle(const BJsonEvent& event); 26228512Sjilles void HandleError(status_t status, int32 line, 27228512Sjilles const char* message); 28228512Sjilles void Complete() {}; 29290914Sngie 30228512Sjilles status_t ErrorStatus(); 31290914Sngie int32 GetErrorLine(); 32290914Sngie BString GetErrorMessage(); 33290914Sngie bool HasEventsAfterError(); 34228512Sjilles json_event_type FirstEventTypeAfterError(); 35228512Sjillesprivate: 36228512Sjilles status_t fErrorStatus; 37228512Sjilles int32 fErrorLine; 38228512Sjilles BString fErrorMessage; 39290914Sngie json_event_type fFirstEventTypeAfterError; 40228512Sjilles int32 fEventCountAfterError; 41228512Sjilles 42228512Sjilles}; 43228512Sjilles 44228512Sjilles 45228512Sjilles/*! This DataIO concrete implementation is designed to open and then to fail 46228512Sjilles in order to simulate what might happen if there were an IO problem when 47228512Sjilles parsing some JSON. 48228512Sjilles*/ 49228512Sjilles 50228512Sjillesclass FailingDataIO : public BDataIO { 51228512Sjillespublic: 52228512Sjilles FailingDataIO(); 53228512Sjilles virtual ~FailingDataIO(); 54228512Sjilles 55228512Sjilles ssize_t Read(void* buffer, size_t size); 56228512Sjilles ssize_t Write(const void* buffer, size_t size); 57228512Sjilles 58228512Sjilles status_t Flush(); 59228512Sjilles}; 60228512Sjilles 61228512Sjilles 62228512Sjilles// #pragma mark - FailingDataIO 63228512Sjilles 64228512Sjilles 65228512SjillesFailingDataIO::FailingDataIO() 66228512Sjilles{ 67228512Sjilles} 68 69 70FailingDataIO::~FailingDataIO() 71{ 72} 73 74 75ssize_t 76FailingDataIO::Read(void* buffer, size_t size) 77{ 78 return B_IO_ERROR; 79} 80 81 82ssize_t 83FailingDataIO::Write(const void* buffer, size_t size) 84{ 85 fprintf(stdout, "attempt to write"); 86 return B_IO_ERROR; 87} 88 89 90status_t 91FailingDataIO::Flush() 92{ 93 return B_IO_ERROR; 94} 95 96 97// #pragma mark - ErrorCapturingListener 98 99 100ErrorCapturingListener::ErrorCapturingListener() 101{ 102 fErrorStatus = B_OK; 103 fFirstEventTypeAfterError = B_JSON_NULL; // least likely 104 fEventCountAfterError = 0; 105} 106 107 108ErrorCapturingListener::~ErrorCapturingListener() 109{ 110} 111 112 113bool 114ErrorCapturingListener::Handle(const BJsonEvent& event) 115{ 116 if (fErrorStatus != B_OK) { 117 if (fEventCountAfterError == 0) 118 fFirstEventTypeAfterError = event.EventType(); 119 120 fEventCountAfterError++; 121 } 122 return true; // keep going. 123} 124 125 126void 127ErrorCapturingListener::HandleError(status_t status, int32 line, 128 const char *message) 129{ 130 fErrorStatus = status; 131 fErrorLine = line; 132 133 if (message != NULL) 134 fErrorMessage = BString(message); 135 else 136 fErrorMessage = BString(); 137} 138 139 140status_t 141ErrorCapturingListener::ErrorStatus() 142{ 143 return fErrorStatus; 144} 145 146 147int32 148ErrorCapturingListener::GetErrorLine() 149{ 150 return fErrorLine; 151} 152 153 154BString 155ErrorCapturingListener::GetErrorMessage() 156{ 157 return fErrorMessage; 158} 159 160 161json_event_type 162ErrorCapturingListener::FirstEventTypeAfterError() 163{ 164 return fFirstEventTypeAfterError; 165} 166 167 168bool 169ErrorCapturingListener::HasEventsAfterError() 170{ 171 return fEventCountAfterError > 0; 172} 173 174 175JsonErrorHandlingTest::JsonErrorHandlingTest() 176{ 177} 178 179 180JsonErrorHandlingTest::~JsonErrorHandlingTest() 181{ 182} 183 184 185void 186JsonErrorHandlingTest::TestParseWithBadStringEscape(const char* input, 187 int32 line, status_t expectedStatus, char expectedBadEscapeChar) 188{ 189 BString expectedMessage; 190 expectedMessage.SetToFormat("unexpected escaped character [%c] " 191 "in string parsing", expectedBadEscapeChar); 192 193 TestParseWithErrorMessage(input, line, expectedStatus, 194 expectedMessage.String()); 195} 196 197 198void 199JsonErrorHandlingTest::TestParseWithUnterminatedElement(const char* input, 200 int32 line, status_t expectedStatus) 201{ 202 BString expectedMessage; 203 expectedMessage.SetToFormat("unterminated element"); 204 205 TestParseWithErrorMessage(input, line, expectedStatus, 206 expectedMessage.String()); 207} 208 209 210void 211JsonErrorHandlingTest::TestParseWithUnexpectedCharacter(const char* input, 212 int32 line, status_t expectedStatus, char expectedChar) 213{ 214 BString expectedMessage; 215 expectedMessage.SetToFormat("unexpected character [%" B_PRIu8 216 "] (%c) when parsing element", static_cast<uint8>(expectedChar), 217 expectedChar); 218 219 TestParseWithErrorMessage(input, line, expectedStatus, 220 expectedMessage.String()); 221} 222 223 224void 225JsonErrorHandlingTest::TestParseWithErrorMessage(const char* input, int32 line, 226 status_t expectedStatus, const char* expectedMessage) 227{ 228 fprintf(stderr, "in >%s<\n", input); 229 BDataIO *inputData = new BMemoryIO(input, strlen(input)); 230 ObjectDeleter<BDataIO> inputDataDeleter(inputData); 231 TestParseWithErrorMessage(inputData, line, expectedStatus, expectedMessage); 232} 233 234 235void 236JsonErrorHandlingTest::TestParseWithErrorMessage(BDataIO* inputData, int32 line, 237 status_t expectedStatus, const char* expectedMessage) 238{ 239 ErrorCapturingListener* listener = new ErrorCapturingListener(); 240 ObjectDeleter<ErrorCapturingListener> listenerDeleter(listener); 241 242// ---------------------- 243 BPrivate::BJson::Parse(inputData, listener); 244// ---------------------- 245 246 fprintf(stderr, "expected error at line %" B_PRIi32 " - %s : %s\n", 247 line, 248 strerror(expectedStatus), 249 expectedMessage); 250 251 fprintf(stderr, "actual error at line %" B_PRIi32 " - %s : %s\n", 252 listener->GetErrorLine(), 253 strerror(listener->ErrorStatus()), 254 listener->GetErrorMessage().String()); 255 256 if (listener->HasEventsAfterError()) { 257 fprintf(stderr, "first event after error [%d]\n", 258 listener->FirstEventTypeAfterError()); 259 } 260 261 CPPUNIT_ASSERT(!listener->HasEventsAfterError()); 262 CPPUNIT_ASSERT_EQUAL(expectedStatus, listener->ErrorStatus()); 263 CPPUNIT_ASSERT_EQUAL(line, listener->GetErrorLine()); 264 CPPUNIT_ASSERT(0 == strcmp(expectedMessage, 265 listener->GetErrorMessage().String())); 266} 267 268 269void 270JsonErrorHandlingTest::TestCompletelyUnknown() 271{ 272 TestParseWithUnexpectedCharacter( 273 JSON_SAMPLE_BROKEN_COMPLETELY_UNKNOWN, 1, B_BAD_DATA, 'z'); 274} 275 276 277void 278JsonErrorHandlingTest::TestObjectWithPrematureSeparator() 279{ 280 TestParseWithErrorMessage(JSON_SAMPLE_BROKEN_OBJECT_PREMATURE_SEPARATOR, 1, 281 B_BAD_DATA, "unexpected item separator when parsing start of object"); 282} 283 284 285void 286JsonErrorHandlingTest::TestStringUnterminated() 287{ 288 TestParseWithErrorMessage(JSON_SAMPLE_BROKEN_UNTERMINATED_STRING, 1, 289 B_BAD_DATA, "unexpected end of input"); 290} 291 292 293void 294JsonErrorHandlingTest::TestBadStringEscape() 295{ 296 TestParseWithBadStringEscape( 297 JSON_SAMPLE_BROKEN_BAD_STRING_ESCAPE, 1, B_BAD_DATA, 'v'); 298} 299 300 301void 302JsonErrorHandlingTest::TestBadNumber() 303{ 304 TestParseWithErrorMessage(JSON_SAMPLE_BROKEN_NUMBER, 1, B_BAD_DATA, 305 "malformed number"); 306} 307 308 309void 310JsonErrorHandlingTest::TestIOIssue() 311{ 312 BDataIO *inputData = new FailingDataIO(); 313 ObjectDeleter<BDataIO> inputDataDeleter(inputData); 314 TestParseWithErrorMessage(inputData, -1, B_IO_ERROR, 315 "io related read error"); 316} 317 318 319/*static*/ void 320JsonErrorHandlingTest::AddTests(BTestSuite& parent) 321{ 322 CppUnit::TestSuite& suite = *new CppUnit::TestSuite( 323 "JsonErrorHandlingTest"); 324 325 suite.addTest(new CppUnit::TestCaller<JsonErrorHandlingTest>( 326 "JsonErrorHandlingTest::TestCompletelyUnknown", 327 &JsonErrorHandlingTest::TestCompletelyUnknown)); 328 329 suite.addTest(new CppUnit::TestCaller<JsonErrorHandlingTest>( 330 "JsonErrorHandlingTest::TestObjectWithPrematureSeparator", 331 &JsonErrorHandlingTest::TestObjectWithPrematureSeparator)); 332 333 suite.addTest(new CppUnit::TestCaller<JsonErrorHandlingTest>( 334 "JsonErrorHandlingTest::TestStringUnterminated", 335 &JsonErrorHandlingTest::TestStringUnterminated)); 336 337 suite.addTest(new CppUnit::TestCaller<JsonErrorHandlingTest>( 338 "JsonErrorHandlingTest::TestBadStringEscape", 339 &JsonErrorHandlingTest::TestBadStringEscape)); 340 341 suite.addTest(new CppUnit::TestCaller<JsonErrorHandlingTest>( 342 "JsonErrorHandlingTest::TestBadNumber", 343 &JsonErrorHandlingTest::TestBadNumber)); 344 345 suite.addTest(new CppUnit::TestCaller<JsonErrorHandlingTest>( 346 "JsonErrorHandlingTest::TestIOIssue", 347 &JsonErrorHandlingTest::TestIOIssue)); 348 349 parent.addTest("JsonErrorHandlingTest", &suite); 350}