Store the strings in the heap

This commit is contained in:
Benoit Blanchon
2023-04-11 10:03:47 +02:00
parent 7c0fa7c276
commit d8f3058efa
27 changed files with 434 additions and 377 deletions

View File

@ -5,11 +5,30 @@
#include <ArduinoJson/StringStorage/StringCopier.hpp>
#include <catch.hpp>
#include "Allocators.hpp"
using namespace ArduinoJson::detail;
TEST_CASE("StringCopier") {
SECTION("Works when buffer is big enough") {
MemoryPool pool(addPadding(sizeofString(5)));
ControllableAllocator controllableAllocator;
SpyingAllocator spyingAllocator(&controllableAllocator);
MemoryPool pool(0, &spyingAllocator);
SECTION("Empty string") {
StringCopier str(&pool);
str.startString();
str.save();
REQUIRE(pool.size() == sizeofString(0));
REQUIRE(pool.overflowed() == false);
REQUIRE(spyingAllocator.log() ==
AllocatorLog() << AllocatorLog::Allocate(sizeofString(31))
<< AllocatorLog::Reallocate(sizeofString(31),
sizeofString(0)));
}
SECTION("Short string fits in first allocation") {
StringCopier str(&pool);
str.startString();
@ -18,38 +37,60 @@ TEST_CASE("StringCopier") {
REQUIRE(str.isValid() == true);
REQUIRE(str.str() == "hello");
REQUIRE(pool.overflowed() == false);
REQUIRE(spyingAllocator.log() ==
AllocatorLog() << AllocatorLog::Allocate(sizeofString(31)));
}
SECTION("Returns null when too small") {
MemoryPool pool(sizeof(void*));
SECTION("Long string needs reallocation") {
StringCopier str(&pool);
str.startString();
str.append("hello world!");
str.append(
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do "
"eiusmod tempor incididunt ut labore et dolore magna aliqua.");
REQUIRE(str.isValid() == false);
REQUIRE(pool.overflowed() == true);
}
SECTION("Increases size of memory pool") {
MemoryPool pool(addPadding(sizeofString(6)));
StringCopier str(&pool);
str.startString();
str.save();
REQUIRE(1 == pool.size());
REQUIRE(str.isValid() == true);
REQUIRE(str.str() ==
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do "
"eiusmod tempor incididunt ut labore et dolore magna aliqua.");
REQUIRE(pool.overflowed() == false);
REQUIRE(spyingAllocator.log() ==
AllocatorLog() << AllocatorLog::Allocate(sizeofString(31))
<< AllocatorLog::Reallocate(sizeofString(31),
sizeofString(63))
<< AllocatorLog::Reallocate(sizeofString(63),
sizeofString(127)));
}
SECTION("Works when memory pool is 0 bytes") {
MemoryPool pool(0);
SECTION("Realloc fails") {
StringCopier str(&pool);
str.startString();
controllableAllocator.disable();
str.append(
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do "
"eiusmod tempor incididunt ut labore et dolore magna aliqua.");
REQUIRE(spyingAllocator.log() ==
AllocatorLog() << AllocatorLog::Allocate(sizeofString(31))
<< AllocatorLog::ReallocateFail(sizeofString(31),
sizeofString(63))
<< AllocatorLog::Deallocate(sizeofString(31)));
REQUIRE(str.isValid() == false);
REQUIRE(pool.overflowed() == true);
}
SECTION("Initial allocation fails") {
StringCopier str(&pool);
controllableAllocator.disable();
str.startString();
REQUIRE(str.isValid() == false);
REQUIRE(pool.overflowed() == true);
REQUIRE(spyingAllocator.log() ==
AllocatorLog() << AllocatorLog::AllocateFail(sizeofString(31)));
}
}
static const char* addStringToPool(MemoryPool& pool, const char* s) {

View File

@ -39,13 +39,6 @@ TEST_CASE("MemoryPool::saveString()") {
const char* a = saveString(pool, "hello\0world", 11);
const char* b = saveString(pool, "hello\0world", 11);
REQUIRE(a == b);
}
SECTION("Reuse part of a string if it ends with NUL") {
const char* a = saveString(pool, "hello\0world", 11);
const char* b = saveString(pool, "hello");
REQUIRE(a == b);
REQUIRE(pool.size() == 12);
REQUIRE(pool.size() == sizeofString(11));
}
@ -56,52 +49,8 @@ TEST_CASE("MemoryPool::saveString()") {
REQUIRE(pool.size() == sizeofString(5) + sizeofString(11));
}
SECTION("Returns NULL when full") {
REQUIRE(pool.capacity() == 32);
const void* p1 = saveString(pool, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
REQUIRE(p1 != 0);
REQUIRE(pool.size() == 32);
const void* p2 = saveString(pool, "b");
REQUIRE(p2 == 0);
}
SECTION("Returns NULL when pool is too small") {
const void* p = saveString(pool, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
REQUIRE(0 == p);
}
SECTION("Returns NULL when buffer is NULL") {
SECTION("Returns NULL when allocation fails") {
MemoryPool pool2(32, FailingAllocator::instance());
REQUIRE(0 == saveString(pool2, "a"));
}
SECTION("Returns NULL when capacity is 0") {
MemoryPool pool2(0);
REQUIRE(0 == saveString(pool2, "a"));
}
SECTION("Returns same address after clear()") {
const void* a = saveString(pool, "hello");
pool.clear();
const void* b = saveString(pool, "world");
REQUIRE(a == b);
}
SECTION("Can use full capacity when fresh") {
const void* a = saveString(pool, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
REQUIRE(a != 0);
}
SECTION("Can use full capacity after clear") {
saveString(pool, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
pool.clear();
const void* a = saveString(pool, "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");
REQUIRE(a != 0);
}
}