// ArduinoJson - https://arduinojson.org // Copyright © 2014-2022, Benoit BLANCHON // MIT License #include #include // malloc, free #include #include #include using ARDUINOJSON_NAMESPACE::addPadding; class SpyingAllocator { public: SpyingAllocator(const SpyingAllocator& src) : _log(src._log) {} SpyingAllocator(std::ostream& log) : _log(log) {} void* allocate(size_t n) { _log << "A" << n; return malloc(n); } void deallocate(void* p) { _log << "F"; free(p); } private: SpyingAllocator& operator=(const SpyingAllocator& src); std::ostream& _log; }; class ControllableAllocator { public: ControllableAllocator() : _enabled(true) {} void* allocate(size_t n) { return _enabled ? malloc(n) : 0; } void deallocate(void* p) { free(p); } void disable() { _enabled = false; } private: bool _enabled; }; TEST_CASE("BasicJsonDocument") { std::stringstream log; SECTION("Construct/Destruct") { { BasicJsonDocument doc(4096, log); } REQUIRE(log.str() == "A4096F"); } SECTION("Copy construct") { { BasicJsonDocument doc1(4096, log); doc1.set(std::string("The size of this string is 32!!")); BasicJsonDocument doc2(doc1); REQUIRE(doc1.as() == "The size of this string is 32!!"); REQUIRE(doc2.as() == "The size of this string is 32!!"); REQUIRE(doc2.capacity() == 4096); } REQUIRE(log.str() == "A4096A4096FF"); } #if ARDUINOJSON_HAS_RVALUE_REFERENCES SECTION("Move construct") { { BasicJsonDocument doc1(4096, log); doc1.set(std::string("The size of this string is 32!!")); BasicJsonDocument doc2(std::move(doc1)); REQUIRE(doc2.as() == "The size of this string is 32!!"); REQUIRE(doc1.as() == "null"); REQUIRE(doc1.capacity() == 0); REQUIRE(doc2.capacity() == 4096); } REQUIRE(log.str() == "A4096F"); } #endif SECTION("Copy assign larger") { { BasicJsonDocument doc1(4096, log); doc1.set(std::string("The size of this string is 32!!")); BasicJsonDocument doc2(8, log); doc2 = doc1; REQUIRE(doc1.as() == "The size of this string is 32!!"); REQUIRE(doc2.as() == "The size of this string is 32!!"); REQUIRE(doc2.capacity() == 4096); } REQUIRE(log.str() == "A4096A8FA4096FF"); } SECTION("Copy assign smaller") { { BasicJsonDocument doc1(1024, log); doc1.set(std::string("The size of this string is 32!!")); BasicJsonDocument doc2(4096, log); doc2 = doc1; REQUIRE(doc1.as() == "The size of this string is 32!!"); REQUIRE(doc2.as() == "The size of this string is 32!!"); REQUIRE(doc2.capacity() == 1024); } REQUIRE(log.str() == "A1024A4096FA1024FF"); } SECTION("Copy assign same size") { { BasicJsonDocument doc1(1024, log); doc1.set(std::string("The size of this string is 32!!")); BasicJsonDocument doc2(1024, log); doc2 = doc1; REQUIRE(doc1.as() == "The size of this string is 32!!"); REQUIRE(doc2.as() == "The size of this string is 32!!"); REQUIRE(doc2.capacity() == 1024); } REQUIRE(log.str() == "A1024A1024FF"); } #if ARDUINOJSON_HAS_RVALUE_REFERENCES SECTION("Move assign") { { BasicJsonDocument doc1(4096, log); doc1.set(std::string("The size of this string is 32!!")); BasicJsonDocument doc2(8, log); doc2 = std::move(doc1); REQUIRE(doc2.as() == "The size of this string is 32!!"); REQUIRE(doc1.as() == "null"); REQUIRE(doc1.capacity() == 0); REQUIRE(doc2.capacity() == 4096); } REQUIRE(log.str() == "A4096A8FF"); } #endif SECTION("garbageCollect()") { BasicJsonDocument doc(4096); SECTION("when allocation succeeds") { deserializeJson(doc, "{\"blanket\":1,\"dancing\":2}"); REQUIRE(doc.capacity() == 4096); REQUIRE(doc.memoryUsage() == JSON_OBJECT_SIZE(2) + 16); doc.remove("blanket"); bool result = doc.garbageCollect(); REQUIRE(result == true); REQUIRE(doc.memoryUsage() == JSON_OBJECT_SIZE(1) + 8); REQUIRE(doc.capacity() == 4096); REQUIRE(doc.as() == "{\"dancing\":2}"); } SECTION("when allocation fails") { deserializeJson(doc, "{\"blanket\":1,\"dancing\":2}"); REQUIRE(doc.capacity() == 4096); REQUIRE(doc.memoryUsage() == JSON_OBJECT_SIZE(2) + 16); doc.remove("blanket"); doc.allocator().disable(); bool result = doc.garbageCollect(); REQUIRE(result == false); REQUIRE(doc.memoryUsage() == JSON_OBJECT_SIZE(2) + 16); REQUIRE(doc.capacity() == 4096); REQUIRE(doc.as() == "{\"dancing\":2}"); } } }