allocator.cpp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. // ArduinoJson - https://arduinojson.org
  2. // Copyright © 2014-2023, Benoit BLANCHON
  3. // MIT License
  4. #include <ArduinoJson.h>
  5. #include <stdlib.h> // malloc, free
  6. #include <catch.hpp>
  7. #include <sstream>
  8. #include <utility>
  9. using ArduinoJson::detail::sizeofObject;
  10. class SpyingAllocator : public Allocator {
  11. public:
  12. virtual ~SpyingAllocator() {}
  13. void* allocate(size_t n) override {
  14. _log << "A" << n;
  15. return malloc(n);
  16. }
  17. void deallocate(void* p) override {
  18. _log << "F";
  19. free(p);
  20. }
  21. void* reallocate(void* ptr, size_t n) override {
  22. _log << "R" << n;
  23. return realloc(ptr, n);
  24. }
  25. std::string log() const {
  26. return _log.str();
  27. }
  28. private:
  29. std::ostringstream _log;
  30. };
  31. class ControllableAllocator : public Allocator {
  32. public:
  33. ControllableAllocator() : _enabled(true) {}
  34. virtual ~ControllableAllocator() {}
  35. void* allocate(size_t n) override {
  36. return _enabled ? malloc(n) : 0;
  37. }
  38. void deallocate(void* p) override {
  39. free(p);
  40. }
  41. void* reallocate(void* ptr, size_t n) override {
  42. return realloc(ptr, n);
  43. }
  44. void disable() {
  45. _enabled = false;
  46. }
  47. private:
  48. bool _enabled;
  49. };
  50. TEST_CASE("JsonDocument's allocator") {
  51. SpyingAllocator spyingAllocator;
  52. ControllableAllocator controllableAllocator;
  53. SECTION("Construct/Destruct") {
  54. { JsonDocument doc(4096, &spyingAllocator); }
  55. REQUIRE(spyingAllocator.log() == "A4096F");
  56. }
  57. SECTION("Copy construct") {
  58. {
  59. JsonDocument doc1(4096, &spyingAllocator);
  60. doc1.set(std::string("The size of this string is 32!!"));
  61. JsonDocument doc2(doc1);
  62. REQUIRE(doc1.as<std::string>() == "The size of this string is 32!!");
  63. REQUIRE(doc2.as<std::string>() == "The size of this string is 32!!");
  64. REQUIRE(doc2.capacity() == 4096);
  65. }
  66. REQUIRE(spyingAllocator.log() == "A4096A4096FF");
  67. }
  68. SECTION("Move construct") {
  69. {
  70. JsonDocument doc1(4096, &spyingAllocator);
  71. doc1.set(std::string("The size of this string is 32!!"));
  72. JsonDocument doc2(std::move(doc1));
  73. REQUIRE(doc2.as<std::string>() == "The size of this string is 32!!");
  74. REQUIRE(doc1.as<std::string>() == "null");
  75. REQUIRE(doc1.capacity() == 0);
  76. REQUIRE(doc2.capacity() == 4096);
  77. }
  78. REQUIRE(spyingAllocator.log() == "A4096F");
  79. }
  80. SECTION("Copy assign larger") {
  81. {
  82. JsonDocument doc1(4096, &spyingAllocator);
  83. doc1.set(std::string("The size of this string is 32!!"));
  84. JsonDocument doc2(8, &spyingAllocator);
  85. doc2 = doc1;
  86. REQUIRE(doc1.as<std::string>() == "The size of this string is 32!!");
  87. REQUIRE(doc2.as<std::string>() == "The size of this string is 32!!");
  88. REQUIRE(doc2.capacity() == 4096);
  89. }
  90. REQUIRE(spyingAllocator.log() == "A4096A8FA4096FF");
  91. }
  92. SECTION("Copy assign smaller") {
  93. {
  94. JsonDocument doc1(1024, &spyingAllocator);
  95. doc1.set(std::string("The size of this string is 32!!"));
  96. JsonDocument doc2(4096, &spyingAllocator);
  97. doc2 = doc1;
  98. REQUIRE(doc1.as<std::string>() == "The size of this string is 32!!");
  99. REQUIRE(doc2.as<std::string>() == "The size of this string is 32!!");
  100. REQUIRE(doc2.capacity() == 1024);
  101. }
  102. REQUIRE(spyingAllocator.log() == "A1024A4096FA1024FF");
  103. }
  104. SECTION("Copy assign same size") {
  105. {
  106. JsonDocument doc1(1024, &spyingAllocator);
  107. doc1.set(std::string("The size of this string is 32!!"));
  108. JsonDocument doc2(1024, &spyingAllocator);
  109. doc2 = doc1;
  110. REQUIRE(doc1.as<std::string>() == "The size of this string is 32!!");
  111. REQUIRE(doc2.as<std::string>() == "The size of this string is 32!!");
  112. REQUIRE(doc2.capacity() == 1024);
  113. }
  114. REQUIRE(spyingAllocator.log() == "A1024A1024FF");
  115. }
  116. SECTION("Move assign") {
  117. {
  118. JsonDocument doc1(4096, &spyingAllocator);
  119. doc1.set(std::string("The size of this string is 32!!"));
  120. JsonDocument doc2(8, &spyingAllocator);
  121. doc2 = std::move(doc1);
  122. REQUIRE(doc2.as<std::string>() == "The size of this string is 32!!");
  123. REQUIRE(doc1.as<std::string>() == "null");
  124. REQUIRE(doc1.capacity() == 0);
  125. REQUIRE(doc2.capacity() == 4096);
  126. }
  127. REQUIRE(spyingAllocator.log() == "A4096A8FF");
  128. }
  129. SECTION("garbageCollect()") {
  130. JsonDocument doc(4096, &controllableAllocator);
  131. SECTION("when allocation succeeds") {
  132. deserializeJson(doc, "{\"blanket\":1,\"dancing\":2}");
  133. REQUIRE(doc.capacity() == 4096);
  134. REQUIRE(doc.memoryUsage() == sizeofObject(2) + 16);
  135. doc.remove("blanket");
  136. bool result = doc.garbageCollect();
  137. REQUIRE(result == true);
  138. REQUIRE(doc.memoryUsage() == sizeofObject(1) + 8);
  139. REQUIRE(doc.capacity() == 4096);
  140. REQUIRE(doc.as<std::string>() == "{\"dancing\":2}");
  141. }
  142. SECTION("when allocation fails") {
  143. deserializeJson(doc, "{\"blanket\":1,\"dancing\":2}");
  144. REQUIRE(doc.capacity() == 4096);
  145. REQUIRE(doc.memoryUsage() == sizeofObject(2) + 16);
  146. doc.remove("blanket");
  147. controllableAllocator.disable();
  148. bool result = doc.garbageCollect();
  149. REQUIRE(result == false);
  150. REQUIRE(doc.memoryUsage() == sizeofObject(2) + 16);
  151. REQUIRE(doc.capacity() == 4096);
  152. REQUIRE(doc.as<std::string>() == "{\"dancing\":2}");
  153. }
  154. }
  155. }