// ArduinoJson - https://arduinojson.org // Copyright © 2014-2024, Benoit BLANCHON // MIT License #include #include #include "Allocators.hpp" using ArduinoJson::detail::sizeofArray; TEST_CASE("deserialize JSON array") { SpyingAllocator spy; JsonDocument doc(&spy); SECTION("An empty array") { DeserializationError err = deserializeJson(doc, "[]"); JsonArray arr = doc.as(); REQUIRE(err == DeserializationError::Ok); REQUIRE(0 == arr.size()); } SECTION("Spaces") { SECTION("Before the opening bracket") { DeserializationError err = deserializeJson(doc, " []"); JsonArray arr = doc.as(); REQUIRE(err == DeserializationError::Ok); REQUIRE(0 == arr.size()); } SECTION("Before first value") { DeserializationError err = deserializeJson(doc, "[ \t\r\n42]"); JsonArray arr = doc.as(); REQUIRE(err == DeserializationError::Ok); REQUIRE(1 == arr.size()); REQUIRE(arr[0] == 42); } SECTION("After first value") { DeserializationError err = deserializeJson(doc, "[42 \t\r\n]"); JsonArray arr = doc.as(); REQUIRE(err == DeserializationError::Ok); REQUIRE(1 == arr.size()); REQUIRE(arr[0] == 42); } } SECTION("Values types") { SECTION("On integer") { DeserializationError err = deserializeJson(doc, "[42]"); JsonArray arr = doc.as(); REQUIRE(err == DeserializationError::Ok); REQUIRE(1 == arr.size()); REQUIRE(arr[0] == 42); } SECTION("Two integers") { DeserializationError err = deserializeJson(doc, "[42,84]"); JsonArray arr = doc.as(); REQUIRE(err == DeserializationError::Ok); REQUIRE(2 == arr.size()); REQUIRE(arr[0] == 42); REQUIRE(arr[1] == 84); } SECTION("Double") { DeserializationError err = deserializeJson(doc, "[4.2,1e2]"); JsonArray arr = doc.as(); REQUIRE(err == DeserializationError::Ok); REQUIRE(2 == arr.size()); REQUIRE(arr[0] == 4.2); REQUIRE(arr[1] == 1e2); } SECTION("Unsigned long") { DeserializationError err = deserializeJson(doc, "[4294967295]"); JsonArray arr = doc.as(); REQUIRE(err == DeserializationError::Ok); REQUIRE(1 == arr.size()); REQUIRE(arr[0] == 4294967295UL); } SECTION("Boolean") { DeserializationError err = deserializeJson(doc, "[true,false]"); JsonArray arr = doc.as(); REQUIRE(err == DeserializationError::Ok); REQUIRE(2 == arr.size()); REQUIRE(arr[0] == true); REQUIRE(arr[1] == false); } SECTION("Null") { DeserializationError err = deserializeJson(doc, "[null,null]"); JsonArray arr = doc.as(); REQUIRE(err == DeserializationError::Ok); REQUIRE(2 == arr.size()); REQUIRE(arr[0].as() == 0); REQUIRE(arr[1].as() == 0); } } SECTION("Quotes") { SECTION("Double quotes") { DeserializationError err = deserializeJson(doc, "[ \"hello\" , \"world\" ]"); JsonArray arr = doc.as(); REQUIRE(err == DeserializationError::Ok); REQUIRE(2 == arr.size()); REQUIRE(arr[0] == "hello"); REQUIRE(arr[1] == "world"); } SECTION("Single quotes") { DeserializationError err = deserializeJson(doc, "[ 'hello' , 'world' ]"); JsonArray arr = doc.as(); REQUIRE(err == DeserializationError::Ok); REQUIRE(2 == arr.size()); REQUIRE(arr[0] == "hello"); REQUIRE(arr[1] == "world"); } SECTION("No quotes") { DeserializationError err = deserializeJson(doc, "[ hello , world ]"); REQUIRE(err == DeserializationError::InvalidInput); } SECTION("Double quotes (empty strings)") { DeserializationError err = deserializeJson(doc, "[\"\",\"\"]"); JsonArray arr = doc.as(); REQUIRE(err == DeserializationError::Ok); REQUIRE(2 == arr.size()); REQUIRE(arr[0] == ""); REQUIRE(arr[1] == ""); } SECTION("Single quotes (empty strings)") { DeserializationError err = deserializeJson(doc, "[\'\',\'\']"); JsonArray arr = doc.as(); REQUIRE(err == DeserializationError::Ok); REQUIRE(2 == arr.size()); REQUIRE(arr[0] == ""); REQUIRE(arr[1] == ""); } SECTION("No quotes (empty strings)") { DeserializationError err = deserializeJson(doc, "[,]"); REQUIRE(err == DeserializationError::InvalidInput); } SECTION("Closing single quotes missing") { DeserializationError err = deserializeJson(doc, "[\"]"); REQUIRE(err == DeserializationError::IncompleteInput); } SECTION("Closing double quotes missing") { DeserializationError err = deserializeJson(doc, "[\']"); REQUIRE(err == DeserializationError::IncompleteInput); } } SECTION("Premature null-terminator") { SECTION("After opening bracket") { DeserializationError err = deserializeJson(doc, "["); REQUIRE(err == DeserializationError::IncompleteInput); } SECTION("After value") { DeserializationError err = deserializeJson(doc, "[1"); REQUIRE(err == DeserializationError::IncompleteInput); } SECTION("After comma") { DeserializationError err = deserializeJson(doc, "[1,"); REQUIRE(err == DeserializationError::IncompleteInput); } } SECTION("Premature end of input") { const char* input = "[1,2]"; SECTION("After opening bracket") { DeserializationError err = deserializeJson(doc, input, 1); REQUIRE(err == DeserializationError::IncompleteInput); } SECTION("After value") { DeserializationError err = deserializeJson(doc, input, 2); REQUIRE(err == DeserializationError::IncompleteInput); } SECTION("After comma") { DeserializationError err = deserializeJson(doc, input, 3); REQUIRE(err == DeserializationError::IncompleteInput); } } SECTION("Misc") { SECTION("Nested objects") { char jsonString[] = " [ { \"a\" : 1 , \"b\" : 2 } , { \"c\" : 3 , \"d\" : 4 } ] "; DeserializationError err = deserializeJson(doc, jsonString); JsonArray arr = doc.as(); JsonObject object1 = arr[0]; const JsonObject object2 = arr[1]; JsonObject object3 = arr[2]; REQUIRE(err == DeserializationError::Ok); REQUIRE(object1.isNull() == false); REQUIRE(object2.isNull() == false); REQUIRE(object3.isNull() == true); REQUIRE(2 == object1.size()); REQUIRE(2 == object2.size()); REQUIRE(0 == object3.size()); REQUIRE(1 == object1["a"].as()); REQUIRE(2 == object1["b"].as()); REQUIRE(3 == object2["c"].as()); REQUIRE(4 == object2["d"].as()); REQUIRE(0 == object3["e"].as()); } } SECTION("Should clear the JsonArray") { deserializeJson(doc, "[1,2,3,4]"); spy.clearLog(); deserializeJson(doc, "[]"); JsonArray arr = doc.as(); REQUIRE(arr.size() == 0); REQUIRE(spy.log() == AllocatorLog{ Deallocate(sizeofArray(4)), }); } } TEST_CASE("deserialize JSON array under memory constraints") { TimebombAllocator timebomb(100); SpyingAllocator spy(&timebomb); JsonDocument doc(&spy); SECTION("empty array requires no allocation") { timebomb.setCountdown(0); char input[] = "[]"; DeserializationError err = deserializeJson(doc, input); REQUIRE(err == DeserializationError::Ok); } SECTION("allocation of pool list fails") { timebomb.setCountdown(0); char input[] = "[1]"; DeserializationError err = deserializeJson(doc, input); REQUIRE(err == DeserializationError::NoMemory); REQUIRE(doc.as() == "[]"); } SECTION("allocation of pool fails") { timebomb.setCountdown(0); char input[] = "[1]"; DeserializationError err = deserializeJson(doc, input); REQUIRE(err == DeserializationError::NoMemory); REQUIRE(doc.as() == "[]"); } SECTION("allocation of string fails in array") { timebomb.setCountdown(1); char input[] = "[0,\"hi!\"]"; DeserializationError err = deserializeJson(doc, input); REQUIRE(err == DeserializationError::NoMemory); REQUIRE(doc.as() == "[0,null]"); } SECTION("don't store space characters") { deserializeJson(doc, " [ \"1234567\" ] "); REQUIRE(spy.log() == AllocatorLog{ Allocate(sizeofPool()), Allocate(sizeofStringBuffer()), Reallocate(sizeofStringBuffer(), sizeofString("1234567")), Reallocate(sizeofPool(), sizeofArray(1)), }); } }