shrinkToFit.cpp 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. // ArduinoJson - https://arduinojson.org
  2. // Copyright © 2014-2024, 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() == AllocatorLog{});
  59. }
  60. SECTION("owned string") {
  61. doc.set("abcdefg"_s);
  62. REQUIRE(doc.as<std::string>() == "abcdefg");
  63. doc.shrinkToFit();
  64. REQUIRE(doc.as<std::string>() == "abcdefg");
  65. REQUIRE(spyingAllocator.log() == AllocatorLog{
  66. Allocate(sizeofString("abcdefg")),
  67. });
  68. }
  69. SECTION("raw string") {
  70. doc.set(serialized("[{},12]"));
  71. doc.shrinkToFit();
  72. REQUIRE(doc.as<std::string>() == "[{},12]");
  73. REQUIRE(spyingAllocator.log() == AllocatorLog{
  74. Allocate(sizeofString("[{},12]")),
  75. });
  76. }
  77. SECTION("linked key") {
  78. doc["key"] = 42;
  79. doc.shrinkToFit();
  80. REQUIRE(doc.as<std::string>() == "{\"key\":42}");
  81. REQUIRE(spyingAllocator.log() ==
  82. AllocatorLog{
  83. Allocate(sizeofPool()),
  84. Reallocate(sizeofPool(), sizeofObject(1)),
  85. });
  86. }
  87. SECTION("owned key") {
  88. doc["abcdefg"_s] = 42;
  89. doc.shrinkToFit();
  90. REQUIRE(doc.as<std::string>() == "{\"abcdefg\":42}");
  91. REQUIRE(spyingAllocator.log() ==
  92. AllocatorLog{
  93. Allocate(sizeofPool()),
  94. Allocate(sizeofString("abcdefg")),
  95. Reallocate(sizeofPool(), sizeofObject(1)),
  96. });
  97. }
  98. SECTION("linked string in array") {
  99. doc.add("hello");
  100. doc.shrinkToFit();
  101. REQUIRE(doc.as<std::string>() == "[\"hello\"]");
  102. REQUIRE(spyingAllocator.log() ==
  103. AllocatorLog{
  104. Allocate(sizeofPool()),
  105. Reallocate(sizeofPool(), sizeofArray(1)),
  106. });
  107. }
  108. SECTION("owned string in array") {
  109. doc.add("abcdefg"_s);
  110. doc.shrinkToFit();
  111. REQUIRE(doc.as<std::string>() == "[\"abcdefg\"]");
  112. REQUIRE(spyingAllocator.log() ==
  113. AllocatorLog{
  114. Allocate(sizeofPool()),
  115. Allocate(sizeofString("abcdefg")),
  116. Reallocate(sizeofPool(), sizeofArray(1)),
  117. });
  118. }
  119. SECTION("linked string in object") {
  120. doc["key"] = "hello";
  121. doc.shrinkToFit();
  122. REQUIRE(doc.as<std::string>() == "{\"key\":\"hello\"}");
  123. REQUIRE(spyingAllocator.log() ==
  124. AllocatorLog{
  125. Allocate(sizeofPool()),
  126. Reallocate(sizeofPool(), sizeofObject(1)),
  127. });
  128. }
  129. SECTION("owned string in object") {
  130. doc["key"] = "abcdefg"_s;
  131. doc.shrinkToFit();
  132. REQUIRE(doc.as<std::string>() == "{\"key\":\"abcdefg\"}");
  133. REQUIRE(spyingAllocator.log() ==
  134. AllocatorLog{
  135. Allocate(sizeofPool()),
  136. Allocate(sizeofString("abcdefg")),
  137. Reallocate(sizeofPool(), sizeofPool(2)),
  138. });
  139. }
  140. }