mirror of
https://github.com/bblanchon/ArduinoJson.git
synced 2025-07-29 18:27:37 +02:00
Store the strings in the heap
This commit is contained in:
@ -9,63 +9,59 @@
|
||||
|
||||
using ArduinoJson::detail::sizeofArray;
|
||||
using ArduinoJson::detail::sizeofObject;
|
||||
using ArduinoJson::detail::sizeofString;
|
||||
|
||||
TEST_CASE("JsonDocument assignment") {
|
||||
SpyingAllocator spyingAllocator;
|
||||
|
||||
SECTION("Copy assignment same capacity") {
|
||||
{
|
||||
JsonDocument doc1(1024, &spyingAllocator);
|
||||
deserializeJson(doc1, "{\"hello\":\"world\"}");
|
||||
JsonDocument doc2(1024, &spyingAllocator);
|
||||
JsonDocument doc1(1024, &spyingAllocator);
|
||||
deserializeJson(doc1, "{\"hello\":\"world\"}");
|
||||
JsonDocument doc2(1024, &spyingAllocator);
|
||||
spyingAllocator.clearLog();
|
||||
|
||||
doc2 = doc1;
|
||||
doc2 = doc1;
|
||||
|
||||
REQUIRE(doc2.as<std::string>() == "{\"hello\":\"world\"}");
|
||||
}
|
||||
REQUIRE(spyingAllocator.log() == AllocatorLog()
|
||||
<< AllocatorLog::Allocate(1024)
|
||||
<< AllocatorLog::Allocate(1024)
|
||||
<< AllocatorLog::Deallocate(1024)
|
||||
<< AllocatorLog::Deallocate(1024));
|
||||
REQUIRE(doc2.as<std::string>() == "{\"hello\":\"world\"}");
|
||||
|
||||
REQUIRE(spyingAllocator.log() ==
|
||||
AllocatorLog() << AllocatorLog::Allocate(sizeofString(5)) // hello
|
||||
<< AllocatorLog::Allocate(sizeofString(5)) // world
|
||||
);
|
||||
}
|
||||
|
||||
SECTION("Copy assignment reallocates when capacity is smaller") {
|
||||
{
|
||||
JsonDocument doc1(4096, &spyingAllocator);
|
||||
deserializeJson(doc1, "{\"hello\":\"world\"}");
|
||||
JsonDocument doc2(8, &spyingAllocator);
|
||||
JsonDocument doc1(4096, &spyingAllocator);
|
||||
deserializeJson(doc1, "{\"hello\":\"world\"}");
|
||||
JsonDocument doc2(8, &spyingAllocator);
|
||||
spyingAllocator.clearLog();
|
||||
|
||||
doc2 = doc1;
|
||||
doc2 = doc1;
|
||||
|
||||
REQUIRE(doc2.as<std::string>() == "{\"hello\":\"world\"}");
|
||||
}
|
||||
REQUIRE(spyingAllocator.log() == AllocatorLog()
|
||||
<< AllocatorLog::Allocate(4096)
|
||||
<< AllocatorLog::Allocate(8)
|
||||
<< AllocatorLog::Deallocate(8)
|
||||
<< AllocatorLog::Allocate(4096)
|
||||
<< AllocatorLog::Deallocate(4096)
|
||||
<< AllocatorLog::Deallocate(4096));
|
||||
REQUIRE(doc2.as<std::string>() == "{\"hello\":\"world\"}");
|
||||
REQUIRE(spyingAllocator.log() ==
|
||||
AllocatorLog() << AllocatorLog::Deallocate(8)
|
||||
<< AllocatorLog::Allocate(4096)
|
||||
<< AllocatorLog::Allocate(sizeofString(5)) // hello
|
||||
<< AllocatorLog::Allocate(sizeofString(5)) // world
|
||||
);
|
||||
}
|
||||
|
||||
SECTION("Copy assignment reallocates when capacity is larger") {
|
||||
{
|
||||
JsonDocument doc1(1024, &spyingAllocator);
|
||||
deserializeJson(doc1, "{\"hello\":\"world\"}");
|
||||
JsonDocument doc2(4096, &spyingAllocator);
|
||||
JsonDocument doc1(1024, &spyingAllocator);
|
||||
deserializeJson(doc1, "{\"hello\":\"world\"}");
|
||||
JsonDocument doc2(4096, &spyingAllocator);
|
||||
spyingAllocator.clearLog();
|
||||
|
||||
doc2 = doc1;
|
||||
doc2 = doc1;
|
||||
|
||||
REQUIRE(doc2.as<std::string>() == "{\"hello\":\"world\"}");
|
||||
}
|
||||
REQUIRE(spyingAllocator.log() == AllocatorLog()
|
||||
<< AllocatorLog::Allocate(1024)
|
||||
<< AllocatorLog::Allocate(4096)
|
||||
<< AllocatorLog::Deallocate(4096)
|
||||
<< AllocatorLog::Allocate(1024)
|
||||
<< AllocatorLog::Deallocate(1024)
|
||||
<< AllocatorLog::Deallocate(1024));
|
||||
REQUIRE(doc2.as<std::string>() == "{\"hello\":\"world\"}");
|
||||
REQUIRE(spyingAllocator.log() ==
|
||||
AllocatorLog() << AllocatorLog::Deallocate(4096)
|
||||
<< AllocatorLog::Allocate(1024)
|
||||
<< AllocatorLog::Allocate(sizeofString(5)) // hello
|
||||
<< AllocatorLog::Allocate(sizeofString(5)) // world
|
||||
);
|
||||
}
|
||||
|
||||
SECTION("Move assign") {
|
||||
@ -79,11 +75,13 @@ TEST_CASE("JsonDocument assignment") {
|
||||
REQUIRE(doc2.as<std::string>() == "The size of this string is 32!!");
|
||||
REQUIRE(doc1.as<std::string>() == "null");
|
||||
}
|
||||
REQUIRE(spyingAllocator.log() == AllocatorLog()
|
||||
<< AllocatorLog::Allocate(4096)
|
||||
<< AllocatorLog::Allocate(8)
|
||||
<< AllocatorLog::Deallocate(8)
|
||||
<< AllocatorLog::Deallocate(4096));
|
||||
REQUIRE(spyingAllocator.log() ==
|
||||
AllocatorLog() << AllocatorLog::Allocate(4096)
|
||||
<< AllocatorLog::Allocate(sizeofString(31))
|
||||
<< AllocatorLog::Allocate(8)
|
||||
<< AllocatorLog::Deallocate(8)
|
||||
<< AllocatorLog::Deallocate(sizeofString(31))
|
||||
<< AllocatorLog::Deallocate(4096));
|
||||
}
|
||||
|
||||
SECTION("Assign from JsonObject") {
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "Allocators.hpp"
|
||||
|
||||
using ArduinoJson::detail::addPadding;
|
||||
using ArduinoJson::detail::sizeofString;
|
||||
|
||||
TEST_CASE("JsonDocument constructor") {
|
||||
SpyingAllocator spyingAllocator;
|
||||
@ -29,11 +30,15 @@ TEST_CASE("JsonDocument constructor") {
|
||||
REQUIRE(doc1.as<std::string>() == "The size of this string is 32!!");
|
||||
REQUIRE(doc2.as<std::string>() == "The size of this string is 32!!");
|
||||
}
|
||||
REQUIRE(spyingAllocator.log() == AllocatorLog()
|
||||
<< AllocatorLog::Allocate(4096)
|
||||
<< AllocatorLog::Allocate(4096)
|
||||
<< AllocatorLog::Deallocate(4096)
|
||||
<< AllocatorLog::Deallocate(4096));
|
||||
REQUIRE(spyingAllocator.log() ==
|
||||
AllocatorLog() << AllocatorLog::Allocate(4096)
|
||||
<< AllocatorLog::Allocate(sizeofString(31))
|
||||
<< AllocatorLog::Allocate(4096)
|
||||
<< AllocatorLog::Allocate(sizeofString(31))
|
||||
<< AllocatorLog::Deallocate(sizeofString(31))
|
||||
<< AllocatorLog::Deallocate(4096)
|
||||
<< AllocatorLog::Deallocate(sizeofString(31))
|
||||
<< AllocatorLog::Deallocate(4096));
|
||||
}
|
||||
|
||||
SECTION("JsonDocument(JsonDocument&&)") {
|
||||
@ -46,9 +51,11 @@ TEST_CASE("JsonDocument constructor") {
|
||||
REQUIRE(doc2.as<std::string>() == "The size of this string is 32!!");
|
||||
REQUIRE(doc1.as<std::string>() == "null");
|
||||
}
|
||||
REQUIRE(spyingAllocator.log() == AllocatorLog()
|
||||
<< AllocatorLog::Allocate(4096)
|
||||
<< AllocatorLog::Deallocate(4096));
|
||||
REQUIRE(spyingAllocator.log() ==
|
||||
AllocatorLog() << AllocatorLog::Allocate(4096)
|
||||
<< AllocatorLog::Allocate(sizeofString(31))
|
||||
<< AllocatorLog::Deallocate(sizeofString(31))
|
||||
<< AllocatorLog::Deallocate(4096));
|
||||
}
|
||||
|
||||
SECTION("JsonDocument(JsonObject)") {
|
||||
@ -82,7 +89,9 @@ TEST_CASE("JsonDocument constructor") {
|
||||
JsonDocument doc2(doc1.as<JsonVariant>(), &spyingAllocator);
|
||||
|
||||
REQUIRE(doc2.as<std::string>() == "hello");
|
||||
REQUIRE(spyingAllocator.log() == AllocatorLog() << AllocatorLog::Allocate(
|
||||
addPadding(doc1.memoryUsage())));
|
||||
REQUIRE(
|
||||
spyingAllocator.log() ==
|
||||
AllocatorLog() << AllocatorLog::Allocate(addPadding(doc1.memoryUsage()))
|
||||
<< AllocatorLog::Allocate(sizeofString(5)));
|
||||
}
|
||||
}
|
||||
|
@ -21,16 +21,19 @@ TEST_CASE("JsonDocument::garbageCollect()") {
|
||||
deserializeJson(doc, "{\"blanket\":1,\"dancing\":2}");
|
||||
REQUIRE(doc.memoryUsage() == sizeofObject(2) + 2 * sizeofString(7));
|
||||
doc.remove("blanket");
|
||||
spyingAllocator.clearLog();
|
||||
|
||||
bool result = doc.garbageCollect();
|
||||
|
||||
REQUIRE(result == true);
|
||||
REQUIRE(doc.memoryUsage() == sizeofObject(1) + sizeofString(7));
|
||||
REQUIRE(doc.as<std::string>() == "{\"dancing\":2}");
|
||||
REQUIRE(spyingAllocator.log() == AllocatorLog()
|
||||
<< AllocatorLog::Allocate(4096)
|
||||
<< AllocatorLog::Allocate(4096)
|
||||
<< AllocatorLog::Deallocate(4096));
|
||||
REQUIRE(spyingAllocator.log() ==
|
||||
AllocatorLog() << AllocatorLog::Allocate(4096)
|
||||
<< AllocatorLog::Allocate(sizeofString(7))
|
||||
<< AllocatorLog::Deallocate(sizeofString(7))
|
||||
<< AllocatorLog::Deallocate(sizeofString(7))
|
||||
<< AllocatorLog::Deallocate(4096));
|
||||
}
|
||||
|
||||
SECTION("when allocation fails") {
|
||||
@ -38,6 +41,7 @@ TEST_CASE("JsonDocument::garbageCollect()") {
|
||||
REQUIRE(doc.memoryUsage() == sizeofObject(2) + 2 * sizeofString(7));
|
||||
doc.remove("blanket");
|
||||
controllableAllocator.disable();
|
||||
spyingAllocator.clearLog();
|
||||
|
||||
bool result = doc.garbageCollect();
|
||||
|
||||
@ -46,7 +50,6 @@ TEST_CASE("JsonDocument::garbageCollect()") {
|
||||
REQUIRE(doc.as<std::string>() == "{\"dancing\":2}");
|
||||
|
||||
REQUIRE(spyingAllocator.log() == AllocatorLog()
|
||||
<< AllocatorLog::Allocate(4096)
|
||||
<< AllocatorLog::AllocateFail(4096));
|
||||
}
|
||||
}
|
||||
|
@ -5,8 +5,9 @@
|
||||
#include <ArduinoJson.h>
|
||||
#include <catch.hpp>
|
||||
|
||||
#include "Allocators.hpp"
|
||||
|
||||
using ArduinoJson::detail::sizeofArray;
|
||||
using ArduinoJson::detail::sizeofString;
|
||||
|
||||
TEST_CASE("JsonDocument::overflowed()") {
|
||||
SECTION("returns false on a fresh object") {
|
||||
@ -27,13 +28,15 @@ TEST_CASE("JsonDocument::overflowed()") {
|
||||
}
|
||||
|
||||
SECTION("returns true after a failed string copy") {
|
||||
JsonDocument doc(sizeofArray(1));
|
||||
ControllableAllocator allocator;
|
||||
JsonDocument doc(sizeofArray(1), &allocator);
|
||||
allocator.disable();
|
||||
doc.add(std::string("example"));
|
||||
CHECK(doc.overflowed() == true);
|
||||
}
|
||||
|
||||
SECTION("returns false after a successful string copy") {
|
||||
JsonDocument doc(sizeofArray(1) + sizeofString(7));
|
||||
JsonDocument doc(sizeofArray(1));
|
||||
doc.add(std::string("example"));
|
||||
CHECK(doc.overflowed() == false);
|
||||
}
|
||||
@ -46,12 +49,12 @@ TEST_CASE("JsonDocument::overflowed()") {
|
||||
|
||||
SECTION("returns true after a failed deserialization") {
|
||||
JsonDocument doc(sizeofArray(1));
|
||||
deserializeJson(doc, "[\"example\"]");
|
||||
deserializeJson(doc, "[1, 2]");
|
||||
CHECK(doc.overflowed() == true);
|
||||
}
|
||||
|
||||
SECTION("returns false after a successful deserialization") {
|
||||
JsonDocument doc(sizeofArray(1) + sizeofString(7));
|
||||
JsonDocument doc(sizeofArray(1));
|
||||
deserializeJson(doc, "[\"example\"]");
|
||||
CHECK(doc.overflowed() == false);
|
||||
}
|
||||
|
@ -86,13 +86,15 @@ TEST_CASE("JsonDocument::shrinkToFit()") {
|
||||
|
||||
SECTION("owned string") {
|
||||
doc.set(std::string("abcdefg"));
|
||||
REQUIRE(doc.as<std::string>() == "abcdefg");
|
||||
|
||||
doc.shrinkToFit();
|
||||
|
||||
REQUIRE(doc.as<std::string>() == "abcdefg");
|
||||
REQUIRE(spyingAllocator.log() ==
|
||||
AllocatorLog() << AllocatorLog::Allocate(4096)
|
||||
<< AllocatorLog::Reallocate(4096, sizeofString(7)));
|
||||
<< AllocatorLog::Allocate(sizeofString(7))
|
||||
<< AllocatorLog::Reallocate(4096, 0));
|
||||
}
|
||||
|
||||
SECTION("linked raw") {
|
||||
@ -114,7 +116,8 @@ TEST_CASE("JsonDocument::shrinkToFit()") {
|
||||
REQUIRE(doc.as<std::string>() == "[{},12]");
|
||||
REQUIRE(spyingAllocator.log() ==
|
||||
AllocatorLog() << AllocatorLog::Allocate(4096)
|
||||
<< AllocatorLog::Reallocate(4096, sizeofString(7)));
|
||||
<< AllocatorLog::Allocate(sizeofString(7))
|
||||
<< AllocatorLog::Reallocate(4096, 0));
|
||||
}
|
||||
|
||||
SECTION("linked key") {
|
||||
@ -136,8 +139,8 @@ TEST_CASE("JsonDocument::shrinkToFit()") {
|
||||
REQUIRE(doc.as<std::string>() == "{\"abcdefg\":42}");
|
||||
REQUIRE(spyingAllocator.log() ==
|
||||
AllocatorLog() << AllocatorLog::Allocate(4096)
|
||||
<< AllocatorLog::Reallocate(
|
||||
4096, sizeofObject(1) + sizeofString(7)));
|
||||
<< AllocatorLog::Allocate(sizeofString(7))
|
||||
<< AllocatorLog::Reallocate(4096, sizeofObject(1)));
|
||||
}
|
||||
|
||||
SECTION("linked string in array") {
|
||||
@ -159,8 +162,8 @@ TEST_CASE("JsonDocument::shrinkToFit()") {
|
||||
REQUIRE(doc.as<std::string>() == "[\"abcdefg\"]");
|
||||
REQUIRE(spyingAllocator.log() ==
|
||||
AllocatorLog() << AllocatorLog::Allocate(4096)
|
||||
<< AllocatorLog::Reallocate(
|
||||
4096, sizeofArray(1) + sizeofString(7)));
|
||||
<< AllocatorLog::Allocate(sizeofString(7))
|
||||
<< AllocatorLog::Reallocate(4096, sizeofArray(1)));
|
||||
}
|
||||
|
||||
SECTION("linked string in object") {
|
||||
@ -182,21 +185,7 @@ TEST_CASE("JsonDocument::shrinkToFit()") {
|
||||
REQUIRE(doc.as<std::string>() == "{\"key\":\"abcdefg\"}");
|
||||
REQUIRE(spyingAllocator.log() ==
|
||||
AllocatorLog() << AllocatorLog::Allocate(4096)
|
||||
<< AllocatorLog::Reallocate(
|
||||
4096, sizeofObject(1) + sizeofString(7)));
|
||||
}
|
||||
|
||||
SECTION("unaligned") {
|
||||
doc.add(std::string("?")); // two bytes in the string pool
|
||||
REQUIRE(doc.memoryUsage() == sizeofObject(1) + sizeofString(1));
|
||||
|
||||
doc.shrinkToFit();
|
||||
|
||||
// the new capacity should be padded to align the pointers
|
||||
REQUIRE(doc[0] == "?");
|
||||
REQUIRE(spyingAllocator.log() ==
|
||||
AllocatorLog() << AllocatorLog::Allocate(4096)
|
||||
<< AllocatorLog::Reallocate(
|
||||
4096, sizeofArray(1) + sizeof(void*)));
|
||||
<< AllocatorLog::Allocate(sizeofString(7))
|
||||
<< AllocatorLog::Reallocate(4096, sizeofObject(1)));
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user