shrinkToFit.cpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. // ArduinoJson - https://arduinojson.org
  2. // Copyright © 2014-2025, Benoit BLANCHON
  3. // MIT License
  4. #include <ArduinoJson.h>
  5. #include <catch.hpp>
  6. #include <stdlib.h> // malloc, free
  7. #include <string>
  8. #include "Allocators.hpp"
  9. #include "Literals.hpp"
  10. using ArduinoJson::detail::sizeofArray;
  11. using ArduinoJson::detail::sizeofObject;
  12. class ArmoredAllocator : public Allocator {
  13. public:
  14. virtual ~ArmoredAllocator() {}
  15. void* allocate(size_t size) override {
  16. return malloc(size);
  17. }
  18. void deallocate(void* ptr) override {
  19. free(ptr);
  20. }
  21. void* reallocate(void* ptr, size_t new_size) override {
  22. // don't call realloc, instead alloc a new buffer and erase the old one
  23. // this way we make sure we support relocation
  24. void* new_ptr = malloc(new_size);
  25. memset(new_ptr, '#', new_size); // erase
  26. if (ptr) {
  27. memcpy(new_ptr, ptr, std::min(new_size, new_size));
  28. free(ptr);
  29. }
  30. return new_ptr;
  31. }
  32. };
  33. TEST_CASE("JsonDocument::shrinkToFit()") {
  34. ArmoredAllocator armoredAllocator;
  35. SpyingAllocator spyingAllocator(&armoredAllocator);
  36. JsonDocument doc(&spyingAllocator);
  37. SECTION("null") {
  38. doc.shrinkToFit();
  39. REQUIRE(doc.as<std::string>() == "null");
  40. REQUIRE(spyingAllocator.log() == AllocatorLog{});
  41. }
  42. SECTION("empty object") {
  43. deserializeJson(doc, "{}");
  44. doc.shrinkToFit();
  45. REQUIRE(doc.as<std::string>() == "{}");
  46. REQUIRE(spyingAllocator.log() == AllocatorLog{});
  47. }
  48. SECTION("empty array") {
  49. deserializeJson(doc, "[]");
  50. doc.shrinkToFit();
  51. REQUIRE(doc.as<std::string>() == "[]");
  52. REQUIRE(spyingAllocator.log() == AllocatorLog{});
  53. }
  54. SECTION("linked string") {
  55. doc.set("hello");
  56. doc.shrinkToFit();
  57. REQUIRE(doc.as<std::string>() == "hello");
  58. REQUIRE(spyingAllocator.log() ==
  59. AllocatorLog{
  60. Allocate(sizeofStaticStringPool()),
  61. Reallocate(sizeofStaticStringPool(), sizeofStaticStringPool(1)),
  62. });
  63. }
  64. SECTION("owned string") {
  65. doc.set("abcdefg"_s);
  66. REQUIRE(doc.as<std::string>() == "abcdefg");
  67. doc.shrinkToFit();
  68. REQUIRE(doc.as<std::string>() == "abcdefg");
  69. REQUIRE(spyingAllocator.log() == AllocatorLog{
  70. Allocate(sizeofString("abcdefg")),
  71. });
  72. }
  73. SECTION("raw string") {
  74. doc.set(serialized("[{},12]"));
  75. doc.shrinkToFit();
  76. REQUIRE(doc.as<std::string>() == "[{},12]");
  77. REQUIRE(spyingAllocator.log() == AllocatorLog{
  78. Allocate(sizeofString("[{},12]")),
  79. });
  80. }
  81. SECTION("linked key") {
  82. doc["key"] = 42;
  83. doc.shrinkToFit();
  84. REQUIRE(doc.as<std::string>() == "{\"key\":42}");
  85. REQUIRE(spyingAllocator.log() ==
  86. AllocatorLog{
  87. Allocate(sizeofPool()),
  88. Allocate(sizeofStaticStringPool()),
  89. Reallocate(sizeofPool(), sizeofObject(1)),
  90. Reallocate(sizeofStaticStringPool(), sizeofStaticStringPool(1)),
  91. });
  92. }
  93. SECTION("owned key") {
  94. doc["abcdefg"_s] = 42;
  95. doc.shrinkToFit();
  96. REQUIRE(doc.as<std::string>() == "{\"abcdefg\":42}");
  97. REQUIRE(spyingAllocator.log() ==
  98. AllocatorLog{
  99. Allocate(sizeofPool()),
  100. Allocate(sizeofString("abcdefg")),
  101. Reallocate(sizeofPool(), sizeofObject(1)),
  102. });
  103. }
  104. SECTION("linked string in array") {
  105. doc.add("hello");
  106. doc.shrinkToFit();
  107. REQUIRE(doc.as<std::string>() == "[\"hello\"]");
  108. REQUIRE(spyingAllocator.log() ==
  109. AllocatorLog{
  110. Allocate(sizeofPool()),
  111. Allocate(sizeofStaticStringPool()),
  112. Reallocate(sizeofPool(), sizeofArray(1)),
  113. Reallocate(sizeofStaticStringPool(), sizeofStaticStringPool(1)),
  114. });
  115. }
  116. SECTION("owned string in array") {
  117. doc.add("abcdefg"_s);
  118. doc.shrinkToFit();
  119. REQUIRE(doc.as<std::string>() == "[\"abcdefg\"]");
  120. REQUIRE(spyingAllocator.log() ==
  121. AllocatorLog{
  122. Allocate(sizeofPool()),
  123. Allocate(sizeofString("abcdefg")),
  124. Reallocate(sizeofPool(), sizeofArray(1)),
  125. });
  126. }
  127. SECTION("linked string in object") {
  128. doc["key"] = "hello";
  129. doc.shrinkToFit();
  130. REQUIRE(doc.as<std::string>() == "{\"key\":\"hello\"}");
  131. REQUIRE(spyingAllocator.log() ==
  132. AllocatorLog{
  133. Allocate(sizeofPool()),
  134. Allocate(sizeofStaticStringPool()),
  135. Reallocate(sizeofPool(), sizeofObject(1)),
  136. Reallocate(sizeofStaticStringPool(), sizeofStaticStringPool(2)),
  137. });
  138. }
  139. SECTION("owned string in object") {
  140. doc["key1"_s] = "value"_s;
  141. doc.shrinkToFit();
  142. REQUIRE(doc.as<std::string>() == "{\"key1\":\"value\"}");
  143. REQUIRE(spyingAllocator.log() ==
  144. AllocatorLog{
  145. Allocate(sizeofPool()),
  146. Allocate(sizeofString("key1")),
  147. Allocate(sizeofString("value")),
  148. Reallocate(sizeofPool(), sizeofPool(2)),
  149. });
  150. }
  151. }