Remove memoryUsage()

This commit is contained in:
Benoit Blanchon
2023-07-24 17:21:25 +02:00
parent 2fdacb1ca0
commit 00c9d8680a
43 changed files with 1173 additions and 567 deletions

View File

@ -22,3 +22,4 @@ HEAD
* `JsonDocument`'s capacity grows as needed, no need to pass it to the constructor anymore
* `JsonDocument`'s allocator is not monotonic anymore, removed values get recycled
* Show a link to the documentation when user passes an unsupported input type
* Remove `JsonDocument::memoryUsage()`

View File

@ -3,6 +3,8 @@
#include <string_view>
#include "Allocators.hpp"
#if !ARDUINOJSON_ENABLE_STRING_VIEW
# error ARDUINOJSON_ENABLE_STRING_VIEW must be set to 1
#endif
@ -11,7 +13,8 @@ using ArduinoJson::detail::sizeofArray;
using ArduinoJson::detail::sizeofString;
TEST_CASE("string_view") {
JsonDocument doc;
SpyingAllocator allocator;
JsonDocument doc(&allocator);
JsonVariant variant = doc.to<JsonVariant>();
SECTION("deserializeJson()") {
@ -56,18 +59,14 @@ TEST_CASE("string_view") {
SECTION("String deduplication") {
doc.add(std::string_view("example one", 7));
REQUIRE(doc.memoryUsage() == sizeofArray(1) + sizeofString(7));
doc.add(std::string_view("example two", 7));
REQUIRE(doc.memoryUsage() == sizeofArray(2) + sizeofString(7));
doc.add(std::string_view("example\0tree", 12));
REQUIRE(doc.memoryUsage() ==
sizeofArray(3) + sizeofString(7) + sizeofString(12));
doc.add(std::string_view("example\0tree and a half", 12));
REQUIRE(doc.memoryUsage() ==
sizeofArray(4) + sizeofString(7) + sizeofString(12));
REQUIRE(allocator.log() == AllocatorLog()
<< AllocatorLog::Allocate(sizeofPool())
<< AllocatorLog::Allocate(sizeofString(7))
<< AllocatorLog::Allocate(sizeofString(12)));
}
SECTION("as<std::string_view>()") {

View File

@ -117,11 +117,16 @@ class SpyingAllocator : public ArduinoJson::Allocator {
: upstream_(upstream) {}
virtual ~SpyingAllocator() {}
size_t allocatedBytes() const {
return allocatedBytes_;
}
void* allocate(size_t n) override {
auto block = reinterpret_cast<AllocatedBlock*>(
upstream_->allocate(sizeof(AllocatedBlock) + n - 1));
if (block) {
log_ << AllocatorLog::Allocate(n);
allocatedBytes_ += n;
block->size = n;
return block->payload;
} else {
@ -132,6 +137,7 @@ class SpyingAllocator : public ArduinoJson::Allocator {
void deallocate(void* p) override {
auto block = AllocatedBlock::fromPayload(p);
allocatedBytes_ -= block->size;
log_ << AllocatorLog::Deallocate(block ? block->size : 0);
upstream_->deallocate(block);
}
@ -144,6 +150,7 @@ class SpyingAllocator : public ArduinoJson::Allocator {
if (block) {
log_ << AllocatorLog::Reallocate(oldSize, n);
block->size = n;
allocatedBytes_ += n - oldSize;
return block->payload;
} else {
log_ << AllocatorLog::ReallocateFail(oldSize, n);
@ -177,6 +184,7 @@ class SpyingAllocator : public ArduinoJson::Allocator {
AllocatorLog log_;
Allocator* upstream_;
size_t allocatedBytes_ = 0;
};
class ControllableAllocator : public ArduinoJson::Allocator {

View File

@ -11,7 +11,6 @@ add_executable(JsonArrayTests
equals.cpp
isNull.cpp
iterator.cpp
memoryUsage.cpp
nesting.cpp
remove.cpp
size.cpp

View File

@ -5,11 +5,14 @@
#include <ArduinoJson.h>
#include <catch.hpp>
#include "Allocators.hpp"
using ArduinoJson::detail::sizeofArray;
using ArduinoJson::detail::sizeofString;
TEST_CASE("JsonArray::add()") {
JsonDocument doc;
SpyingAllocator allocator;
JsonDocument doc(&allocator);
JsonArray array = doc.to<JsonArray>();
SECTION("int") {
@ -99,43 +102,49 @@ TEST_CASE("JsonArray::add()") {
SECTION("should not duplicate const char*") {
array.add("world");
const size_t expectedSize = sizeofArray(1);
REQUIRE(expectedSize == doc.memoryUsage());
REQUIRE(allocator.log() == AllocatorLog()
<< AllocatorLog::Allocate(sizeofPool()));
}
SECTION("should duplicate char*") {
array.add(const_cast<char*>("world"));
const size_t expectedSize = sizeofArray(1) + sizeofString(5);
REQUIRE(expectedSize == doc.memoryUsage());
REQUIRE(allocator.log() == AllocatorLog()
<< AllocatorLog::Allocate(sizeofPool())
<< AllocatorLog::Allocate(sizeofString(5)));
}
SECTION("should duplicate std::string") {
array.add(std::string("world"));
const size_t expectedSize = sizeofArray(1) + sizeofString(5);
REQUIRE(expectedSize == doc.memoryUsage());
REQUIRE(allocator.log() == AllocatorLog()
<< AllocatorLog::Allocate(sizeofPool())
<< AllocatorLog::Allocate(sizeofString(5)));
}
SECTION("should duplicate serialized(const char*)") {
array.add(serialized("{}"));
const size_t expectedSize = sizeofArray(1) + sizeofString(2);
REQUIRE(expectedSize == doc.memoryUsage());
REQUIRE(allocator.log() == AllocatorLog()
<< AllocatorLog::Allocate(sizeofPool())
<< AllocatorLog::Allocate(sizeofString(2)));
}
SECTION("should duplicate serialized(char*)") {
array.add(serialized(const_cast<char*>("{}")));
const size_t expectedSize = sizeofArray(1) + sizeofString(2);
REQUIRE(expectedSize == doc.memoryUsage());
REQUIRE(allocator.log() == AllocatorLog()
<< AllocatorLog::Allocate(sizeofPool())
<< AllocatorLog::Allocate(sizeofString(2)));
}
SECTION("should duplicate serialized(std::string)") {
array.add(serialized(std::string("{}")));
const size_t expectedSize = sizeofArray(1) + sizeofString(2);
REQUIRE(expectedSize == doc.memoryUsage());
REQUIRE(allocator.log() == AllocatorLog()
<< AllocatorLog::Allocate(sizeofPool())
<< AllocatorLog::Allocate(sizeofString(2)));
}
SECTION("should duplicate serialized(std::string)") {
array.add(serialized(std::string("\0XX", 3)));
const size_t expectedSize = sizeofArray(1) + sizeofString(3);
REQUIRE(expectedSize == doc.memoryUsage());
REQUIRE(allocator.log() == AllocatorLog()
<< AllocatorLog::Allocate(sizeofPool())
<< AllocatorLog::Allocate(sizeofString(3)));
}
}

View File

@ -1,46 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
using ArduinoJson::detail::sizeofArray;
using ArduinoJson::detail::sizeofObject;
using ArduinoJson::detail::sizeofString;
TEST_CASE("JsonArray::memoryUsage()") {
JsonDocument doc;
JsonArray arr = doc.to<JsonArray>();
SECTION("return 0 if uninitialized") {
JsonArray unitialized;
REQUIRE(unitialized.memoryUsage() == 0);
}
SECTION("sizeofArray(0) if empty") {
REQUIRE(arr.memoryUsage() == sizeofArray(0));
}
SECTION("sizeofArray(1) after add") {
arr.add("hello");
REQUIRE(arr.memoryUsage() == sizeofArray(1));
}
SECTION("includes the size of the string") {
arr.add(std::string("hello"));
REQUIRE(arr.memoryUsage() == sizeofArray(1) + sizeofString(5));
}
SECTION("includes the size of the nested array") {
JsonArray nested = arr.createNestedArray();
nested.add(42);
REQUIRE(arr.memoryUsage() == 2 * sizeofArray(1));
}
SECTION("includes the size of the nested arrect") {
JsonObject nested = arr.createNestedObject();
nested["hello"] = "world";
REQUIRE(arr.memoryUsage() == sizeofObject(1) + sizeofArray(1));
}
}

View File

@ -6,11 +6,14 @@
#include <stdint.h>
#include <catch.hpp>
#include "Allocators.hpp"
using ArduinoJson::detail::sizeofArray;
using ArduinoJson::detail::sizeofString;
TEST_CASE("JsonArray::operator[]") {
JsonDocument doc;
SpyingAllocator allocator;
JsonDocument doc(&allocator);
JsonArray array = doc.to<JsonArray>();
SECTION("Pad with null") {
@ -115,20 +118,22 @@ TEST_CASE("JsonArray::operator[]") {
SECTION("should not duplicate const char*") {
array[0] = "world";
const size_t expectedSize = sizeofArray(1);
REQUIRE(expectedSize == doc.memoryUsage());
REQUIRE(allocator.log() == AllocatorLog()
<< AllocatorLog::Allocate(sizeofPool()));
}
SECTION("should duplicate char*") {
array[0] = const_cast<char*>("world");
const size_t expectedSize = sizeofArray(1) + sizeofString(5);
REQUIRE(expectedSize == doc.memoryUsage());
REQUIRE(allocator.log() == AllocatorLog()
<< AllocatorLog::Allocate(sizeofPool())
<< AllocatorLog::Allocate(sizeofString(5)));
}
SECTION("should duplicate std::string") {
array[0] = std::string("world");
const size_t expectedSize = sizeofArray(1) + sizeofString(5);
REQUIRE(expectedSize == doc.memoryUsage());
REQUIRE(allocator.log() == AllocatorLog()
<< AllocatorLog::Allocate(sizeofPool())
<< AllocatorLog::Allocate(sizeofString(5)));
}
SECTION("array[0].to<JsonObject>()") {

View File

@ -11,7 +11,8 @@ using ArduinoJson::detail::sizeofArray;
using ArduinoJson::detail::sizeofString;
TEST_CASE("deserialize JSON array") {
JsonDocument doc;
SpyingAllocator allocator;
JsonDocument doc(&allocator);
SECTION("An empty array") {
DeserializationError err = deserializeJson(doc, "[]");
@ -253,16 +254,19 @@ TEST_CASE("deserialize JSON array") {
JsonArray arr = doc.as<JsonArray>();
REQUIRE(arr.size() == 0);
REQUIRE(doc.memoryUsage() == sizeofArray(0));
REQUIRE(allocator.log() == AllocatorLog()
<< AllocatorLog::Allocate(sizeofPool())
<< AllocatorLog::Deallocate(sizeofPool()));
}
}
TEST_CASE("deserialize JSON array under memory constraints") {
TimebombAllocator allocator(100);
TimebombAllocator timebomb(100);
SpyingAllocator allocator(&timebomb);
JsonDocument doc(&allocator);
SECTION("empty array requires no allocation") {
allocator.setCountdown(0);
timebomb.setCountdown(0);
char input[] = "[]";
DeserializationError err = deserializeJson(doc, input);
@ -271,7 +275,7 @@ TEST_CASE("deserialize JSON array under memory constraints") {
}
SECTION("allocation of pool list fails") {
allocator.setCountdown(0);
timebomb.setCountdown(0);
char input[] = "[1]";
DeserializationError err = deserializeJson(doc, input);
@ -281,7 +285,7 @@ TEST_CASE("deserialize JSON array under memory constraints") {
}
SECTION("allocation of pool fails") {
allocator.setCountdown(0);
timebomb.setCountdown(0);
char input[] = "[1]";
DeserializationError err = deserializeJson(doc, input);
@ -291,7 +295,7 @@ TEST_CASE("deserialize JSON array under memory constraints") {
}
SECTION("allocation of string fails in array") {
allocator.setCountdown(1);
timebomb.setCountdown(1);
char input[] = "[0,\"hi!\"]";
DeserializationError err = deserializeJson(doc, input);
@ -303,6 +307,10 @@ TEST_CASE("deserialize JSON array under memory constraints") {
SECTION("don't store space characters") {
deserializeJson(doc, " [ \"1234567\" ] ");
REQUIRE(sizeofArray(1) + sizeofString(7) == doc.memoryUsage());
REQUIRE(allocator.log() == AllocatorLog()
<< AllocatorLog::Allocate(sizeofPool())
<< AllocatorLog::Allocate(sizeofString(31))
<< AllocatorLog::Reallocate(
sizeofString(31), sizeofString(7)));
}
}

View File

@ -9,6 +9,8 @@
#include <sstream>
#include <string>
#include "Allocators.hpp"
using ArduinoJson::detail::sizeofArray;
using ArduinoJson::detail::sizeofObject;
using ArduinoJson::detail::sizeofString;
@ -689,8 +691,9 @@ TEST_CASE("Filtering") {
for (size_t i = 0; i < sizeof(testCases) / sizeof(testCases[0]); i++) {
CAPTURE(i);
SpyingAllocator allocator;
JsonDocument filter;
JsonDocument doc;
JsonDocument doc(&allocator);
TestCase& tc = testCases[i];
CAPTURE(tc.filter);
@ -703,7 +706,9 @@ TEST_CASE("Filtering") {
tc.nestingLimit)) == tc.error);
CHECK(doc.as<std::string>() == tc.output);
CHECK(doc.memoryUsage() == tc.memoryUsage);
doc.shrinkToFit();
CHECK(allocator.allocatedBytes() == tc.memoryUsage);
}
}

View File

@ -7,20 +7,30 @@
#include <catch.hpp>
#include <sstream>
#include "Allocators.hpp"
#include "CustomReader.hpp"
using ArduinoJson::detail::sizeofObject;
using ArduinoJson::detail::sizeofString;
TEST_CASE("deserializeJson(char*)") {
JsonDocument doc;
SpyingAllocator allocator;
JsonDocument doc(&allocator);
char input[] = "{\"hello\":\"world\"}";
DeserializationError err = deserializeJson(doc, input);
REQUIRE(err == DeserializationError::Ok);
CHECK(doc.memoryUsage() == sizeofObject(1) + 2 * sizeofString(5));
REQUIRE(allocator.log() == AllocatorLog()
<< AllocatorLog::Allocate(sizeofString(31))
<< AllocatorLog::Reallocate(sizeofString(31),
sizeofString(5))
<< AllocatorLog::Allocate(sizeofPool())
<< AllocatorLog::Allocate(sizeofString(31))
<< AllocatorLog::Reallocate(sizeofString(31),
sizeofString(5)));
}
TEST_CASE("deserializeJson(unsigned char*, unsigned int)") { // issue #1897

View File

@ -5,12 +5,15 @@
#include <ArduinoJson.h>
#include <catch.hpp>
#include "Allocators.hpp"
using namespace Catch::Matchers;
using ArduinoJson::detail::sizeofObject;
TEST_CASE("deserializeJson(JsonDocument&)") {
JsonDocument doc;
SpyingAllocator allocator;
JsonDocument doc(&allocator);
SECTION("Edge cases") {
SECTION("null char*") {
@ -114,6 +117,8 @@ TEST_CASE("deserializeJson(JsonDocument&)") {
deserializeJson(doc, "{}");
REQUIRE(doc.is<JsonObject>());
REQUIRE(doc.memoryUsage() == sizeofObject(0));
REQUIRE(allocator.log() == AllocatorLog()
<< AllocatorLog::Allocate(sizeofPool())
<< AllocatorLog::Deallocate(sizeofPool()));
}
}

View File

@ -11,7 +11,8 @@ using ArduinoJson::detail::sizeofObject;
using ArduinoJson::detail::sizeofString;
TEST_CASE("deserialize JSON object") {
JsonDocument doc;
SpyingAllocator allocator;
JsonDocument doc(&allocator);
SECTION("An empty object") {
DeserializationError err = deserializeJson(doc, "{}");
@ -282,8 +283,28 @@ TEST_CASE("deserialize JSON object") {
DeserializationError err = deserializeJson(doc, "{a:{b:{c:1}},a:2}");
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc["a"] == 2);
REQUIRE(doc.memoryUsage() == 3 * sizeofObject(1) + sizeofString(1));
REQUIRE(doc.as<std::string>() == "{\"a\":2}");
REQUIRE(allocator.log() ==
AllocatorLog()
// a
<< AllocatorLog::Allocate(sizeofString(31))
<< AllocatorLog::Reallocate(sizeofString(31), sizeofString(1))
// pool
<< AllocatorLog::Allocate(sizeofPool())
// b
<< AllocatorLog::Allocate(sizeofString(31))
<< AllocatorLog::Reallocate(sizeofString(31), sizeofString(1))
// c
<< AllocatorLog::Allocate(sizeofString(31))
<< AllocatorLog::Reallocate(sizeofString(31), sizeofString(1))
// string builder
<< AllocatorLog::Allocate(sizeofString(31))
// remove b & c
<< AllocatorLog::Deallocate(sizeofString(1)) * 2
// string builder
<< AllocatorLog::Deallocate(sizeofString(31))
);
}
SECTION("Repeated key with zero copy mode") { // issue #1697
@ -310,7 +331,21 @@ TEST_CASE("deserialize JSON object") {
REQUIRE(doc.is<JsonObject>());
REQUIRE(obj.size() == 0);
REQUIRE(doc.memoryUsage() == sizeofObject(0));
REQUIRE(allocator.log() ==
AllocatorLog()
// string "hello"
<< AllocatorLog::Allocate(sizeofString(31))
<< AllocatorLog::Reallocate(sizeofString(31), sizeofString(5))
// pool
<< AllocatorLog::Allocate(sizeofPool())
// string "world"
<< AllocatorLog::Allocate(sizeofString(31))
<< AllocatorLog::Reallocate(sizeofString(31), sizeofString(5))
// free pool
<< AllocatorLog::Deallocate(sizeofPool())
// free "hello" and "world"
<< AllocatorLog::Deallocate(sizeofString(5))
<< AllocatorLog::Deallocate(sizeofString(5)));
}
SECTION("Issue #1335") {

View File

@ -155,21 +155,42 @@ TEST_CASE("String allocation fails") {
}
TEST_CASE("Deduplicate values") {
JsonDocument doc;
SpyingAllocator allocator;
JsonDocument doc(&allocator);
deserializeJson(doc, "[\"example\",\"example\"]");
CHECK(doc.memoryUsage() == sizeofArray(2) + sizeofString(7));
CHECK(doc[0].as<const char*>() == doc[1].as<const char*>());
REQUIRE(allocator.log() == AllocatorLog()
// pool
<< AllocatorLog::Allocate(sizeofPool())
// string builder
<< AllocatorLog::Allocate(sizeofString(31))
// string "example"
<< AllocatorLog::Reallocate(sizeofString(31),
sizeofString(7))
// string builder
<< AllocatorLog::Allocate(sizeofString(31))
<< AllocatorLog::Deallocate(sizeofString(31)));
}
TEST_CASE("Deduplicate keys") {
JsonDocument doc;
SpyingAllocator allocator;
JsonDocument doc(&allocator);
deserializeJson(doc, "[{\"example\":1},{\"example\":2}]");
CHECK(doc.memoryUsage() ==
2 * sizeofObject(1) + sizeofArray(2) + sizeofString(7));
const char* key1 = doc[0].as<JsonObject>().begin()->key().c_str();
const char* key2 = doc[1].as<JsonObject>().begin()->key().c_str();
CHECK(key1 == key2);
REQUIRE(allocator.log() == AllocatorLog()
// pool
<< AllocatorLog::Allocate(sizeofPool())
// string builder
<< AllocatorLog::Allocate(sizeofString(31))
// string "example"
<< AllocatorLog::Reallocate(sizeofString(31),
sizeofString(7))
// string builder
<< AllocatorLog::Allocate(sizeofString(31))
<< AllocatorLog::Deallocate(sizeofString(31)));
}

View File

@ -15,7 +15,6 @@ add_executable(JsonDocumentTests
isNull.cpp
issue1120.cpp
MemberProxy.cpp
memoryUsage.cpp
nesting.cpp
overflowed.cpp
remove.cpp

View File

@ -189,21 +189,6 @@ TEST_CASE("ElementProxy::size()") {
}
}
TEST_CASE("ElementProxy::memoryUsage()") {
JsonDocument doc;
doc.add();
ElementProxy ep = doc[0];
SECTION("returns 0 for null") {
REQUIRE(ep.memoryUsage() == 0);
}
SECTION("returns size for string") {
ep.set(std::string("hello"));
REQUIRE(ep.memoryUsage() == sizeofString(5));
}
}
TEST_CASE("ElementProxy::operator[]") {
JsonDocument doc;
ElementProxy ep = doc[1];

View File

@ -239,20 +239,6 @@ TEST_CASE("MemberProxy::size()") {
}
}
TEST_CASE("MemberProxy::memoryUsage()") {
JsonDocument doc;
MemberProxy mp = doc["hello"];
SECTION("returns 0 when null") {
REQUIRE(mp.memoryUsage() == 0);
}
SECTION("return the size for a string") {
mp.set(std::string("hello"));
REQUIRE(mp.memoryUsage() == sizeofString(5));
}
}
TEST_CASE("MemberProxy::operator[]") {
JsonDocument doc;
MemberProxy mp = doc["hello"];
@ -329,18 +315,20 @@ TEST_CASE("MemberProxy::createNestedObject(key)") {
}
TEST_CASE("Deduplicate keys") {
JsonDocument doc;
SpyingAllocator allocator;
JsonDocument doc(&allocator);
SECTION("std::string") {
doc[0][std::string("example")] = 1;
doc[1][std::string("example")] = 2;
CHECK(doc.memoryUsage() ==
sizeofArray(2) + 2 * sizeofObject(1) + sizeofString(7));
const char* key1 = doc[0].as<JsonObject>().begin()->key().c_str();
const char* key2 = doc[1].as<JsonObject>().begin()->key().c_str();
CHECK(key1 == key2);
REQUIRE(allocator.log() == AllocatorLog()
<< AllocatorLog::Allocate(sizeofPool())
<< AllocatorLog::Allocate(sizeofString(7)));
}
SECTION("char*") {
@ -348,42 +336,46 @@ TEST_CASE("Deduplicate keys") {
doc[0][key] = 1;
doc[1][key] = 2;
CHECK(doc.memoryUsage() ==
sizeofArray(2) + 2 * sizeofObject(1) + sizeofString(7));
const char* key1 = doc[0].as<JsonObject>().begin()->key().c_str();
const char* key2 = doc[1].as<JsonObject>().begin()->key().c_str();
CHECK(key1 == key2);
REQUIRE(allocator.log() == AllocatorLog()
<< AllocatorLog::Allocate(sizeofPool())
<< AllocatorLog::Allocate(sizeofString(7)));
}
SECTION("Arduino String") {
doc[0][String("example")] = 1;
doc[1][String("example")] = 2;
CHECK(doc.memoryUsage() ==
sizeofArray(2) + 2 * sizeofObject(1) + sizeofString(7));
const char* key1 = doc[0].as<JsonObject>().begin()->key().c_str();
const char* key2 = doc[1].as<JsonObject>().begin()->key().c_str();
CHECK(key1 == key2);
REQUIRE(allocator.log() == AllocatorLog()
<< AllocatorLog::Allocate(sizeofPool())
<< AllocatorLog::Allocate(sizeofString(7)));
}
SECTION("Flash string") {
doc[0][F("example")] = 1;
doc[1][F("example")] = 2;
CHECK(doc.memoryUsage() ==
sizeofArray(2) + 2 * sizeofObject(1) + sizeofString(7));
const char* key1 = doc[0].as<JsonObject>().begin()->key().c_str();
const char* key2 = doc[1].as<JsonObject>().begin()->key().c_str();
CHECK(key1 == key2);
REQUIRE(allocator.log() == AllocatorLog()
<< AllocatorLog::Allocate(sizeofPool())
<< AllocatorLog::Allocate(sizeofString(7)));
}
}
TEST_CASE("MemberProxy under memory constraints") {
ControllableAllocator allocator;
JsonDocument doc(&allocator);
SpyingAllocator spy(&allocator);
JsonDocument doc(&spy);
SECTION("key allocation fails") {
allocator.disable();
@ -392,7 +384,8 @@ TEST_CASE("MemberProxy under memory constraints") {
REQUIRE(doc.is<JsonObject>());
REQUIRE(doc.size() == 0);
REQUIRE(doc.memoryUsage() == 0);
REQUIRE(doc.overflowed() == true);
REQUIRE(spy.log() == AllocatorLog()
<< AllocatorLog::AllocateFail(sizeofString(5)));
}
}

View File

@ -8,30 +8,39 @@
#include <catch.hpp>
#include "Allocators.hpp"
using ArduinoJson::detail::sizeofArray;
using ArduinoJson::detail::sizeofString;
TEST_CASE("JsonDocument::add()") {
JsonDocument doc;
SpyingAllocator allocator;
JsonDocument doc(&allocator);
SECTION("integer") {
doc.add(42);
REQUIRE(doc.as<std::string>() == "[42]");
REQUIRE(allocator.log() == AllocatorLog()
<< AllocatorLog::Allocate(sizeofPool()));
}
SECTION("const char*") {
doc.add("hello");
REQUIRE(doc.as<std::string>() == "[\"hello\"]");
REQUIRE(allocator.log() == AllocatorLog()
<< AllocatorLog::Allocate(sizeofPool()));
}
SECTION("std::string") {
doc.add(std::string("example"));
doc.add(std::string("example"));
CHECK(doc.memoryUsage() == sizeofArray(2) + sizeofString(7));
CHECK(doc[0].as<const char*>() == doc[1].as<const char*>());
REQUIRE(allocator.log() == AllocatorLog()
<< AllocatorLog::Allocate(sizeofPool())
<< AllocatorLog::Allocate(sizeofString(7)));
}
SECTION("char*") {
@ -39,23 +48,29 @@ TEST_CASE("JsonDocument::add()") {
doc.add(value);
doc.add(value);
CHECK(doc.memoryUsage() == sizeofArray(2) + sizeofString(7));
CHECK(doc[0].as<const char*>() == doc[1].as<const char*>());
REQUIRE(allocator.log() == AllocatorLog()
<< AllocatorLog::Allocate(sizeofPool())
<< AllocatorLog::Allocate(sizeofString(7)));
}
SECTION("Arduino String") {
doc.add(String("example"));
doc.add(String("example"));
CHECK(doc.memoryUsage() == sizeofArray(2) + sizeofString(7));
CHECK(doc[0].as<const char*>() == doc[1].as<const char*>());
REQUIRE(allocator.log() == AllocatorLog()
<< AllocatorLog::Allocate(sizeofPool())
<< AllocatorLog::Allocate(sizeofString(7)));
}
SECTION("Flash string") {
doc.add(F("example"));
doc.add(F("example"));
CHECK(doc.memoryUsage() == sizeofArray(2) + sizeofString(7));
CHECK(doc[0].as<const char*>() == doc[1].as<const char*>());
REQUIRE(allocator.log() == AllocatorLog()
<< AllocatorLog::Allocate(sizeofPool())
<< AllocatorLog::Allocate(sizeofString(7)));
}
}

View File

@ -19,14 +19,12 @@ TEST_CASE("JsonDocument::garbageCollect()") {
SECTION("when allocation succeeds") {
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(sizeofString(7))
@ -37,7 +35,6 @@ TEST_CASE("JsonDocument::garbageCollect()") {
SECTION("when allocation fails") {
deserializeJson(doc, "{\"blanket\":1,\"dancing\":2}");
REQUIRE(doc.memoryUsage() == sizeofObject(2) + 2 * sizeofString(7));
doc.remove("blanket");
controllableAllocator.disable();
spyingAllocator.clearLog();
@ -45,7 +42,6 @@ TEST_CASE("JsonDocument::garbageCollect()") {
bool result = doc.garbageCollect();
REQUIRE(result == false);
REQUIRE(doc.memoryUsage() == sizeofObject(2) + sizeofString(7));
REQUIRE(doc.as<std::string>() == "{\"dancing\":2}");
REQUIRE(spyingAllocator.log() ==

View File

@ -1,52 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
using ArduinoJson::detail::sizeofArray;
using ArduinoJson::detail::sizeofObject;
TEST_CASE("JsonDocument::memoryUsage()") {
JsonDocument doc;
SECTION("starts at zero") {
REQUIRE(doc.memoryUsage() == 0);
}
SECTION("sizeofArray(0)") {
doc.to<JsonArray>();
REQUIRE(doc.memoryUsage() == sizeofArray(0));
}
SECTION("sizeofArray(1)") {
doc.to<JsonArray>().add(42);
REQUIRE(doc.memoryUsage() == sizeofArray(1));
}
SECTION("sizeofArray(1) + sizeofArray(0)") {
doc.to<JsonArray>().createNestedArray();
REQUIRE(doc.memoryUsage() == sizeofArray(1) + sizeofArray(0));
}
SECTION("Increases after adding value to array") {
JsonArray arr = doc.to<JsonArray>();
REQUIRE(doc.memoryUsage() == sizeofArray(0));
arr.add(42);
REQUIRE(doc.memoryUsage() == sizeofArray(1));
arr.add(43);
REQUIRE(doc.memoryUsage() == sizeofArray(2));
}
SECTION("Increases after adding value to object") {
JsonObject obj = doc.to<JsonObject>();
REQUIRE(doc.memoryUsage() == sizeofObject(0));
obj["a"] = 1;
REQUIRE(doc.memoryUsage() == sizeofObject(1));
obj["b"] = 2;
REQUIRE(doc.memoryUsage() == sizeofObject(2));
}
}

View File

@ -13,7 +13,6 @@ add_executable(JsonObjectTests
invalid.cpp
isNull.cpp
iterator.cpp
memoryUsage.cpp
nesting.cpp
remove.cpp
size.cpp

View File

@ -7,61 +7,80 @@
#include "Allocators.hpp"
using ArduinoJson::detail::sizeofString;
TEST_CASE("JsonObject::set()") {
JsonDocument doc1;
JsonDocument doc2;
SpyingAllocator allocator;
JsonDocument doc1(&allocator);
JsonDocument doc2(&allocator);
JsonObject obj1 = doc1.to<JsonObject>();
JsonObject obj2 = doc2.to<JsonObject>();
SECTION("doesn't copy static string in key or value") {
obj1["hello"] = "world";
allocator.clearLog();
bool success = obj2.set(obj1);
REQUIRE(success == true);
REQUIRE(doc1.memoryUsage() == doc2.memoryUsage());
REQUIRE(obj2["hello"] == std::string("world"));
REQUIRE(allocator.log() == AllocatorLog()
<< AllocatorLog::Allocate(sizeofPool()));
}
SECTION("copy local string value") {
obj1["hello"] = std::string("world");
allocator.clearLog();
bool success = obj2.set(obj1);
REQUIRE(success == true);
REQUIRE(doc1.memoryUsage() == doc2.memoryUsage());
REQUIRE(obj2["hello"] == std::string("world"));
REQUIRE(allocator.log() == AllocatorLog()
<< AllocatorLog::Allocate(sizeofPool())
<< AllocatorLog::Allocate(sizeofString(5)));
}
SECTION("copy local key") {
obj1[std::string("hello")] = "world";
allocator.clearLog();
bool success = obj2.set(obj1);
REQUIRE(success == true);
REQUIRE(doc1.memoryUsage() == doc2.memoryUsage());
REQUIRE(obj2["hello"] == std::string("world"));
REQUIRE(allocator.log() == AllocatorLog()
<< AllocatorLog::Allocate(sizeofString(5))
<< AllocatorLog::Allocate(sizeofPool()));
}
SECTION("copy string from deserializeJson()") {
deserializeJson(doc1, "{'hello':'world'}");
allocator.clearLog();
bool success = obj2.set(obj1);
REQUIRE(success == true);
REQUIRE(doc1.memoryUsage() == doc2.memoryUsage());
REQUIRE(obj2["hello"] == std::string("world"));
REQUIRE(allocator.log() == AllocatorLog()
<< AllocatorLog::Allocate(sizeofString(5))
<< AllocatorLog::Allocate(sizeofPool())
<< AllocatorLog::Allocate(sizeofString(5)));
}
SECTION("copy string from deserializeMsgPack()") {
deserializeMsgPack(doc1, "\x81\xA5hello\xA5world");
allocator.clearLog();
bool success = obj2.set(obj1);
REQUIRE(success == true);
REQUIRE(doc1.memoryUsage() == doc2.memoryUsage());
REQUIRE(obj2["hello"] == std::string("world"));
REQUIRE(allocator.log() == AllocatorLog()
<< AllocatorLog::Allocate(sizeofString(5))
<< AllocatorLog::Allocate(sizeofPool())
<< AllocatorLog::Allocate(sizeofString(5)));
}
SECTION("should work with JsonObjectConst") {
@ -69,13 +88,12 @@ TEST_CASE("JsonObject::set()") {
obj2.set(static_cast<JsonObjectConst>(obj1));
REQUIRE(doc1.memoryUsage() == doc2.memoryUsage());
REQUIRE(obj2["hello"] == std::string("world"));
}
SECTION("copy fails in the middle of an object") {
TimebombAllocator allocator(2);
JsonDocument doc3(&allocator);
TimebombAllocator timebomb(2);
JsonDocument doc3(&timebomb);
JsonObject obj3 = doc3.to<JsonObject>();
obj1[std::string("a")] = 1;
@ -88,8 +106,8 @@ TEST_CASE("JsonObject::set()") {
}
SECTION("copy fails in the middle of an array") {
TimebombAllocator allocator(1);
JsonDocument doc3(&allocator);
TimebombAllocator timebomb(1);
JsonDocument doc3(&timebomb);
JsonObject obj3 = doc3.to<JsonObject>();
obj1["hello"][0] = std::string("world");

View File

@ -1,47 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
#include <string>
using ArduinoJson::detail::sizeofArray;
using ArduinoJson::detail::sizeofObject;
using ArduinoJson::detail::sizeofString;
TEST_CASE("JsonObject::memoryUsage()") {
JsonDocument doc;
JsonObject obj = doc.to<JsonObject>();
SECTION("return 0 if uninitialized") {
JsonObject unitialized;
REQUIRE(unitialized.memoryUsage() == 0);
}
SECTION("sizeofObject(0) for empty object") {
REQUIRE(obj.memoryUsage() == sizeofObject(0));
}
SECTION("sizeofObject(1) after add") {
obj["hello"] = 42;
REQUIRE(obj.memoryUsage() == sizeofObject(1));
}
SECTION("includes the size of the key") {
obj[std::string("hello")] = 42;
REQUIRE(obj.memoryUsage() == sizeofObject(1) + sizeofString(5));
}
SECTION("includes the size of the nested array") {
JsonArray nested = obj.createNestedArray("nested");
nested.add(42);
REQUIRE(obj.memoryUsage() == sizeofObject(1) + sizeofArray(1));
}
SECTION("includes the size of the nested object") {
JsonObject nested = obj.createNestedObject("nested");
nested["hello"] = "world";
REQUIRE(obj.memoryUsage() == 2 * sizeofObject(1));
}
}

View File

@ -83,28 +83,4 @@ TEST_CASE("std::string") {
eraseString(value);
REQUIRE(std::string("world") == obj["hello"]);
}
SECTION("memoryUsage() increases when adding a new key") {
std::string key1("hello"), key2("world");
JsonObject obj = doc.to<JsonObject>();
obj[key1] = 1;
size_t sizeBefore = doc.memoryUsage();
obj[key2] = 2;
size_t sizeAfter = doc.memoryUsage();
REQUIRE(sizeAfter - sizeBefore >= key2.size());
}
SECTION("memoryUsage() remains when adding the same key") {
std::string key("hello");
JsonObject obj = doc.to<JsonObject>();
obj[key] = 1;
size_t sizeBefore = doc.memoryUsage();
obj[key] = 2;
size_t sizeAfter = doc.memoryUsage();
REQUIRE(sizeBefore == sizeAfter);
}
}

View File

@ -5,11 +5,14 @@
#include <ArduinoJson.h>
#include <catch.hpp>
#include "Allocators.hpp"
using ArduinoJson::detail::sizeofObject;
using ArduinoJson::detail::sizeofString;
TEST_CASE("JsonObject::operator[]") {
JsonDocument doc;
SpyingAllocator allocator;
JsonDocument doc(&allocator);
JsonObject obj = doc.to<JsonObject>();
SECTION("int") {
@ -103,56 +106,65 @@ TEST_CASE("JsonObject::operator[]") {
SECTION("should not duplicate const char*") {
obj["hello"] = "world";
const size_t expectedSize = sizeofObject(1);
REQUIRE(expectedSize == doc.memoryUsage());
REQUIRE(allocator.log() == AllocatorLog()
<< AllocatorLog::Allocate(sizeofPool()));
}
SECTION("should duplicate char* value") {
obj["hello"] = const_cast<char*>("world");
const size_t expectedSize = sizeofObject(1) + sizeofString(5);
REQUIRE(expectedSize == doc.memoryUsage());
REQUIRE(allocator.log() == AllocatorLog()
<< AllocatorLog::Allocate(sizeofPool())
<< AllocatorLog::Allocate(sizeofString(5)));
}
SECTION("should duplicate char* key") {
obj[const_cast<char*>("hello")] = "world";
const size_t expectedSize = sizeofObject(1) + sizeofString(5);
REQUIRE(expectedSize == doc.memoryUsage());
REQUIRE(allocator.log() == AllocatorLog()
<< AllocatorLog::Allocate(sizeofString(5))
<< AllocatorLog::Allocate(sizeofPool()));
}
SECTION("should duplicate char* key&value") {
obj[const_cast<char*>("hello")] = const_cast<char*>("world");
const size_t expectedSize = sizeofObject(1) + 2 * sizeofString(5);
REQUIRE(expectedSize <= doc.memoryUsage());
REQUIRE(allocator.log() == AllocatorLog()
<< AllocatorLog::Allocate(sizeofString(5))
<< AllocatorLog::Allocate(sizeofPool())
<< AllocatorLog::Allocate(sizeofString(5)));
}
SECTION("should duplicate std::string value") {
obj["hello"] = std::string("world");
const size_t expectedSize = sizeofObject(1) + sizeofString(5);
REQUIRE(expectedSize == doc.memoryUsage());
REQUIRE(allocator.log() == AllocatorLog()
<< AllocatorLog::Allocate(sizeofPool())
<< AllocatorLog::Allocate(sizeofString(5)));
}
SECTION("should duplicate std::string key") {
obj[std::string("hello")] = "world";
const size_t expectedSize = sizeofObject(1) + sizeofString(5);
REQUIRE(expectedSize == doc.memoryUsage());
REQUIRE(allocator.log() == AllocatorLog()
<< AllocatorLog::Allocate(sizeofString(5))
<< AllocatorLog::Allocate(sizeofPool()));
}
SECTION("should duplicate std::string key&value") {
obj[std::string("hello")] = std::string("world");
const size_t expectedSize = sizeofObject(1) + 2 * sizeofString(5);
REQUIRE(expectedSize <= doc.memoryUsage());
REQUIRE(allocator.log() == AllocatorLog()
<< AllocatorLog::Allocate(sizeofString(5))
<< AllocatorLog::Allocate(sizeofPool())
<< AllocatorLog::Allocate(sizeofString(5)));
}
SECTION("should duplicate a non-static JsonString key") {
obj[JsonString("hello", JsonString::Copied)] = "world";
const size_t expectedSize = sizeofObject(1) + sizeofString(5);
REQUIRE(expectedSize == doc.memoryUsage());
REQUIRE(allocator.log() == AllocatorLog()
<< AllocatorLog::Allocate(sizeofString(5))
<< AllocatorLog::Allocate(sizeofPool()));
}
SECTION("should not duplicate a static JsonString key") {
obj[JsonString("hello", JsonString::Linked)] = "world";
const size_t expectedSize = sizeofObject(1);
REQUIRE(expectedSize == doc.memoryUsage());
REQUIRE(allocator.log() == AllocatorLog()
<< AllocatorLog::Allocate(sizeofPool()));
}
SECTION("should ignore null key") {

View File

@ -51,7 +51,6 @@ TEST_CASE("serialize JsonObject to std::string") {
TEST_CASE("serialize an std::string containing a NUL") {
JsonDocument doc;
doc.set(std::string("hello\0world", 11));
CHECK(doc.memoryUsage() == sizeofString(11));
std::string json;
serializeJson(doc, json);

View File

@ -13,7 +13,6 @@ add_executable(JsonVariantTests
createNested.cpp
is.cpp
isnull.cpp
memoryUsage.cpp
misc.cpp
nesting.cpp
nullptr.cpp

View File

@ -6,10 +6,13 @@
#include <stdint.h>
#include <catch.hpp>
#include "Allocators.hpp"
using ArduinoJson::detail::sizeofString;
TEST_CASE("JsonVariant::clear()") {
JsonDocument doc;
SpyingAllocator allocator;
JsonDocument doc(&allocator);
JsonVariant var = doc.to<JsonVariant>();
SECTION("size goes back to zero") {
@ -28,9 +31,10 @@ TEST_CASE("JsonVariant::clear()") {
SECTION("releases owned string") {
var.set(std::string("hello"));
REQUIRE(doc.memoryUsage() == sizeofString(5));
var.clear();
REQUIRE(doc.memoryUsage() == 0);
REQUIRE(allocator.log() ==
AllocatorLog() << AllocatorLog::Allocate(sizeofString(5))
<< AllocatorLog::Deallocate(sizeofString(5)));
}
}

View File

@ -44,8 +44,6 @@ TEST_CASE("JsonVariant::set(JsonVariant)") {
var2.set(var1);
REQUIRE(doc1.memoryUsage() == 0);
REQUIRE(doc2.memoryUsage() == 0);
REQUIRE(spyingAllocator.log() == AllocatorLog());
}
@ -56,8 +54,6 @@ TEST_CASE("JsonVariant::set(JsonVariant)") {
var2.set(var1);
REQUIRE(doc1.memoryUsage() == sizeofString(7));
REQUIRE(doc2.memoryUsage() == sizeofString(7));
REQUIRE(spyingAllocator.log() ==
AllocatorLog() << AllocatorLog::Allocate(sizeofString((7))));
}
@ -70,8 +66,6 @@ TEST_CASE("JsonVariant::set(JsonVariant)") {
var2.set(var1);
REQUIRE(doc1.memoryUsage() == sizeofString(7));
REQUIRE(doc2.memoryUsage() == 0);
REQUIRE(doc2.overflowed() == true);
REQUIRE(spyingAllocator.log() ==
AllocatorLog() << AllocatorLog::AllocateFail(sizeofString((7))));
@ -83,8 +77,6 @@ TEST_CASE("JsonVariant::set(JsonVariant)") {
var2.set(var1);
REQUIRE(doc1.memoryUsage() == sizeofString(7));
REQUIRE(doc2.memoryUsage() == sizeofString(7));
REQUIRE(spyingAllocator.log() ==
AllocatorLog() << AllocatorLog::Allocate(sizeofString((7))));
}
@ -95,8 +87,6 @@ TEST_CASE("JsonVariant::set(JsonVariant)") {
var2.set(var1);
REQUIRE(doc1.memoryUsage() == sizeofString(7));
REQUIRE(doc2.memoryUsage() == sizeofString(7));
REQUIRE(spyingAllocator.log() ==
AllocatorLog() << AllocatorLog::Allocate(sizeofString((7))));
}
@ -108,8 +98,6 @@ TEST_CASE("JsonVariant::set(JsonVariant)") {
var2.set(var1);
REQUIRE(doc1.memoryUsage() == sizeofString(7));
REQUIRE(doc2.memoryUsage() == sizeofString(7));
REQUIRE(spyingAllocator.log() ==
AllocatorLog() << AllocatorLog::Allocate(sizeofString((7))));
}
@ -120,8 +108,6 @@ TEST_CASE("JsonVariant::set(JsonVariant)") {
var2.set(var1);
REQUIRE(doc1.memoryUsage() == sizeofString(7));
REQUIRE(doc2.memoryUsage() == sizeofString(7));
REQUIRE(spyingAllocator.log() ==
AllocatorLog() << AllocatorLog::Allocate(sizeofString((7))));
}
@ -133,8 +119,6 @@ TEST_CASE("JsonVariant::set(JsonVariant)") {
var2.set(var1);
REQUIRE(doc1.memoryUsage() == sizeofString(7));
REQUIRE(doc2.memoryUsage() == 0);
REQUIRE(doc2.overflowed() == true);
REQUIRE(spyingAllocator.log() ==
AllocatorLog() << AllocatorLog::AllocateFail(sizeofString((7))));

View File

@ -1,45 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
#include <string>
using ArduinoJson::detail::sizeofArray;
using ArduinoJson::detail::sizeofObject;
using ArduinoJson::detail::sizeofString;
TEST_CASE("JsonVariant::memoryUsage()") {
JsonDocument doc;
JsonVariant var = doc.to<JsonVariant>();
SECTION("returns 0 if uninitialized") {
JsonVariant unitialized;
REQUIRE(unitialized.memoryUsage() == 0);
}
SECTION("returns size of object") {
JsonObject obj = var.to<JsonObject>();
obj["hello"] = 42;
REQUIRE(var.memoryUsage() == sizeofObject(1));
}
SECTION("returns size of array") {
JsonArray arr = var.to<JsonArray>();
arr.add(42);
REQUIRE(var.memoryUsage() == sizeofArray(1));
}
SECTION("returns size of owned string") {
var.set(std::string("hello"));
REQUIRE(var.memoryUsage() == sizeofString(5));
REQUIRE(var.memoryUsage() == doc.memoryUsage());
}
SECTION("returns size of raw string") {
var.set(serialized("hello"));
REQUIRE(var.memoryUsage() == sizeofString(5));
REQUIRE(var.memoryUsage() == doc.memoryUsage());
}
}

View File

@ -6,11 +6,14 @@
#include <stdint.h>
#include <catch.hpp>
#include "Allocators.hpp"
using ArduinoJson::detail::sizeofArray;
using ArduinoJson::detail::sizeofString;
TEST_CASE("JsonVariant::remove(int)") {
JsonDocument doc;
SpyingAllocator allocator;
JsonDocument doc(&allocator);
SECTION("release top level strings") {
doc.add(std::string("hello"));
@ -19,19 +22,23 @@ TEST_CASE("JsonVariant::remove(int)") {
JsonVariant var = doc.as<JsonVariant>();
REQUIRE(var.as<std::string>() == "[\"hello\",\"hello\",\"world\"]");
REQUIRE(doc.memoryUsage() == sizeofArray(3) + 2 * sizeofString(5));
allocator.clearLog();
var.remove(1);
REQUIRE(var.as<std::string>() == "[\"hello\",\"world\"]");
REQUIRE(doc.memoryUsage() == sizeofArray(3) + 2 * sizeofString(5));
REQUIRE(allocator.log() == AllocatorLog());
allocator.clearLog();
var.remove(1);
REQUIRE(var.as<std::string>() == "[\"hello\"]");
REQUIRE(doc.memoryUsage() == sizeofArray(3) + 1 * sizeofString(5));
REQUIRE(allocator.log() ==
AllocatorLog() << AllocatorLog::Deallocate(sizeofString(5)));
allocator.clearLog();
var.remove(0);
REQUIRE(var.as<std::string>() == "[]");
REQUIRE(doc.memoryUsage() == sizeofArray(3));
REQUIRE(allocator.log() ==
AllocatorLog() << AllocatorLog::Deallocate(sizeofString(5)));
}
SECTION("release strings in nested array") {
@ -39,11 +46,13 @@ TEST_CASE("JsonVariant::remove(int)") {
JsonVariant var = doc.as<JsonVariant>();
REQUIRE(var.as<std::string>() == "[[\"hello\"]]");
REQUIRE(doc.memoryUsage() == 2 * sizeofArray(1) + sizeofString(5));
allocator.clearLog();
var.remove(0);
REQUIRE(var.as<std::string>() == "[]");
REQUIRE(doc.memoryUsage() == 2 * sizeofArray(1));
REQUIRE(allocator.log() ==
AllocatorLog() << AllocatorLog::Deallocate(sizeofString(5)));
}
}

View File

@ -177,34 +177,41 @@ TEST_CASE("JsonVariant::set(JsonDocument)") {
}
TEST_CASE("JsonVariant::set() releases the previous value") {
JsonDocument doc;
SpyingAllocator allocator;
JsonDocument doc(&allocator);
doc["hello"] = std::string("world");
REQUIRE(doc.memoryUsage() == sizeofObject(1) + sizeofString(5));
allocator.clearLog();
JsonVariant v = doc["hello"];
SECTION("int") {
v.set(42);
REQUIRE(doc.memoryUsage() == sizeofObject(1));
REQUIRE(allocator.log() ==
AllocatorLog() << AllocatorLog::Deallocate(sizeofString(5)));
}
SECTION("bool") {
v.set(false);
REQUIRE(doc.memoryUsage() == sizeofObject(1));
REQUIRE(allocator.log() ==
AllocatorLog() << AllocatorLog::Deallocate(sizeofString(5)));
}
SECTION("const char*") {
v.set("hello");
REQUIRE(doc.memoryUsage() == sizeofObject(1));
REQUIRE(allocator.log() ==
AllocatorLog() << AllocatorLog::Deallocate(sizeofString(5)));
}
SECTION("float") {
v.set(1.2);
REQUIRE(doc.memoryUsage() == sizeofObject(1));
REQUIRE(allocator.log() ==
AllocatorLog() << AllocatorLog::Deallocate(sizeofString(5)));
}
SECTION("Serialized<const char*>") {
v.set(serialized("[]"));
REQUIRE(doc.memoryUsage() == sizeofObject(1) + sizeofString(2));
REQUIRE(allocator.log() == AllocatorLog()
<< AllocatorLog::Deallocate(sizeofString(5))
<< AllocatorLog::Allocate(sizeofString(2)));
}
}

View File

@ -53,7 +53,8 @@ struct PrintableString : public Printable {
TEST_CASE("Printable") {
SECTION("Doesn't overflow") {
JsonDocument doc;
SpyingAllocator allocator;
JsonDocument doc(&allocator);
const char* value = "example";
doc.set(666); // to make sure we override the value
@ -64,8 +65,10 @@ TEST_CASE("Printable") {
CHECK(doc.as<std::string>() == value);
CHECK(printable.totalBytesWritten() == 7);
CHECK(doc.overflowed() == false);
CHECK(doc.memoryUsage() == sizeofString(7));
CHECK(doc.as<JsonVariant>().memoryUsage() == sizeofString(7));
CHECK(allocator.log() == AllocatorLog()
<< AllocatorLog::Allocate(sizeofString(31))
<< AllocatorLog::Reallocate(
sizeofString(31), sizeofString(7)));
}
SECTION("Via Print::write(const char* size_t)") {
@ -74,8 +77,10 @@ TEST_CASE("Printable") {
CHECK(doc.as<std::string>() == value);
CHECK(printable.totalBytesWritten() == 7);
CHECK(doc.overflowed() == false);
CHECK(doc.memoryUsage() == sizeofString(7));
CHECK(doc.as<JsonVariant>().memoryUsage() == sizeofString(7));
CHECK(allocator.log() == AllocatorLog()
<< AllocatorLog::Allocate(sizeofString(31))
<< AllocatorLog::Reallocate(
sizeofString(31), sizeofString(7)));
}
}
@ -95,7 +100,6 @@ TEST_CASE("Printable") {
CHECK(doc.isNull());
CHECK(printable.totalBytesWritten() == 0);
CHECK(doc.overflowed() == true);
CHECK(doc.memoryUsage() == 0);
CHECK(spyingAllocator.log() ==
AllocatorLog() << AllocatorLog::AllocateFail(sizeofString(31)));
}
@ -109,7 +113,6 @@ TEST_CASE("Printable") {
CHECK(doc.isNull());
CHECK(printable.totalBytesWritten() == 0);
CHECK(doc.overflowed() == true);
CHECK(doc.memoryUsage() == 0);
CHECK(spyingAllocator.log() ==
AllocatorLog() << AllocatorLog::AllocateFail(sizeofString(31)));
}
@ -132,7 +135,6 @@ TEST_CASE("Printable") {
CHECK(doc.isNull());
CHECK(printable.totalBytesWritten() == 31);
CHECK(doc.overflowed() == true);
CHECK(doc.memoryUsage() == 0);
CHECK(spyingAllocator.log() ==
AllocatorLog() << AllocatorLog::Allocate(sizeofString(31))
<< AllocatorLog::ReallocateFail(sizeofString(31),
@ -149,7 +151,6 @@ TEST_CASE("Printable") {
CHECK(doc.isNull());
CHECK(printable.totalBytesWritten() == 31);
CHECK(doc.overflowed() == true);
CHECK(doc.memoryUsage() == 0);
CHECK(spyingAllocator.log() ==
AllocatorLog() << AllocatorLog::Allocate(sizeofString(31))
<< AllocatorLog::ReallocateFail(sizeofString(31),
@ -167,12 +168,19 @@ TEST_CASE("Printable") {
}
SECTION("String deduplication") {
JsonDocument doc;
SpyingAllocator allocator;
JsonDocument doc(&allocator);
doc.add(PrintableString<PrintOneCharacterAtATime>("Hello World!"));
doc.add(PrintableString<PrintAllAtOnce>("Hello World!"));
REQUIRE(doc.size() == 2);
CHECK(doc[0] == "Hello World!");
CHECK(doc[1] == "Hello World!");
CHECK(doc.memoryUsage() == sizeofArray(2) + sizeofString(12));
CHECK(allocator.log() == AllocatorLog()
<< AllocatorLog::Allocate(sizeofPool())
<< AllocatorLog::Allocate(sizeofString(31))
<< AllocatorLog::Reallocate(sizeofString(31),
sizeofString(12))
<< AllocatorLog::Allocate(sizeofString(31))
<< AllocatorLog::Deallocate(sizeofString(31)));
}
}

File diff suppressed because it is too large Load Diff

View File

@ -145,12 +145,6 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
return data_ != 0;
}
// Returns the number of bytes occupied by the array.
// https://arduinojson.org/v6/api/jsonarray/memoryusage/
FORCE_INLINE size_t memoryUsage() const {
return data_ ? data_->memoryUsage(resources_) : 0;
}
// Returns the depth (nesting level) of the array.
// https://arduinojson.org/v6/api/jsonarray/nesting/
FORCE_INLINE size_t nesting() const {

View File

@ -66,12 +66,6 @@ class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> {
return data_ != 0;
}
// Returns the number of bytes occupied by the array.
// https://arduinojson.org/v6/api/jsonarrayconst/memoryusage/
FORCE_INLINE size_t memoryUsage() const {
return data_ ? data_->memoryUsage(resources_) : 0;
}
// Returns the depth (nesting level) of the array.
// https://arduinojson.org/v6/api/jsonarrayconst/nesting/
FORCE_INLINE size_t nesting() const {

View File

@ -88,7 +88,6 @@ class CollectionData {
return iterator(resources->getSlot(head_), head_);
}
size_t memoryUsage(const ResourceManager*) const;
size_t size(const ResourceManager*) const;
size_t nesting(const ResourceManager*) const;

View File

@ -105,17 +105,6 @@ inline void CollectionData::remove(iterator it, ResourceManager* resources) {
releaseSlot({it.slot_, it.currentId_}, resources);
}
inline size_t CollectionData::memoryUsage(
const ResourceManager* resources) const {
size_t total = 0;
for (auto it = createIterator(resources); !it.done(); it.next(resources)) {
total += sizeof(VariantSlot) + it->memoryUsage(resources);
if (it.ownsKey())
total += sizeofString(strlen(it.key()));
}
return total;
}
inline size_t CollectionData::nesting(const ResourceManager* resources) const {
size_t maxChildNesting = 0;
for (auto it = createIterator(resources); !it.done(); it.next(resources)) {

View File

@ -128,12 +128,6 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
return getSlot().isNull();
}
// Returns the number of used bytes in the memory pool.
// https://arduinojson.org/v6/api/jsondocument/memoryusage/
size_t memoryUsage() const {
return resources_.size();
}
// Returns trues if the memory pool was too small.
// https://arduinojson.org/v6/api/jsondocument/overflowed/
bool overflowed() const {

View File

@ -53,12 +53,6 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
return data_ != 0;
}
// Returns the number of bytes occupied by the object.
// https://arduinojson.org/v6/api/jsonobject/memoryusage/
FORCE_INLINE size_t memoryUsage() const {
return data_ ? data_->memoryUsage(resources_) : 0;
}
// Returns the depth (nesting level) of the object.
// https://arduinojson.org/v6/api/jsonobject/nesting/
FORCE_INLINE size_t nesting() const {

View File

@ -42,12 +42,6 @@ class JsonObjectConst : public detail::VariantOperators<JsonObjectConst> {
return data_ != 0;
}
// Returns the number of bytes occupied by the object.
// https://arduinojson.org/v6/api/jsonobjectconst/memoryusage/
FORCE_INLINE size_t memoryUsage() const {
return data_ ? data_->memoryUsage(resources_) : 0;
}
// Returns the depth (nesting level) of the object.
// https://arduinojson.org/v6/api/jsonobjectconst/nesting/
FORCE_INLINE size_t nesting() const {

View File

@ -47,12 +47,6 @@ class JsonVariantConst : public detail::VariantTag,
return !data_;
}
// Returns the number of bytes occupied by the value.
// https://arduinojson.org/v6/api/jsonvariantconst/memoryusage/
FORCE_INLINE size_t memoryUsage() const {
return data_ ? data_->memoryUsage(resources_) : 0;
}
// Returns the depth (nesting level) of the value.
// https://arduinojson.org/v6/api/jsonvariantconst/nesting/
FORCE_INLINE size_t nesting() const {

View File

@ -274,19 +274,6 @@ class VariantData {
return type() == VALUE_IS_LINKED_STRING || type() == VALUE_IS_OWNED_STRING;
}
size_t memoryUsage(const ResourceManager* resources) const {
switch (type()) {
case VALUE_IS_OWNED_STRING:
case VALUE_IS_RAW_STRING:
return sizeofString(content_.asOwnedString->length);
case VALUE_IS_OBJECT:
case VALUE_IS_ARRAY:
return content_.asCollection.memoryUsage(resources);
default:
return 0;
}
}
size_t nesting(const ResourceManager* resources) const {
auto collection = asCollection();
if (collection)

View File

@ -130,13 +130,6 @@ class VariantRefBase : public VariantTag {
return VariantData::size(getData(), getResourceManager());
}
// Returns the number of bytes occupied by the value.
// https://arduinojson.org/v6/api/jsonvariant/memoryusage/
FORCE_INLINE size_t memoryUsage() const {
VariantData* data = getData();
return data ? data->memoryUsage(getResourceManager()) : 0;
}
// Returns the depth (nesting level) of the value.
// https://arduinojson.org/v6/api/jsonvariant/nesting/
FORCE_INLINE size_t nesting() const {