allocator.cpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  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 <utility>
  8. #include "Allocators.hpp"
  9. using ArduinoJson::detail::sizeofObject;
  10. TEST_CASE("JsonDocument's allocator") {
  11. SpyingAllocator spyingAllocator;
  12. ControllableAllocator controllableAllocator;
  13. SECTION("Construct/Destruct") {
  14. { JsonDocument doc(4096, &spyingAllocator); }
  15. REQUIRE(spyingAllocator.log() == AllocatorLog()
  16. << AllocatorLog::Allocate(4096)
  17. << AllocatorLog::Deallocate(4096));
  18. }
  19. SECTION("Copy construct") {
  20. {
  21. JsonDocument doc1(4096, &spyingAllocator);
  22. doc1.set(std::string("The size of this string is 32!!"));
  23. JsonDocument doc2(doc1);
  24. REQUIRE(doc1.as<std::string>() == "The size of this string is 32!!");
  25. REQUIRE(doc2.as<std::string>() == "The size of this string is 32!!");
  26. REQUIRE(doc2.capacity() == 4096);
  27. }
  28. REQUIRE(spyingAllocator.log() == AllocatorLog()
  29. << AllocatorLog::Allocate(4096)
  30. << AllocatorLog::Allocate(4096)
  31. << AllocatorLog::Deallocate(4096)
  32. << AllocatorLog::Deallocate(4096));
  33. }
  34. SECTION("Move construct") {
  35. {
  36. JsonDocument doc1(4096, &spyingAllocator);
  37. doc1.set(std::string("The size of this string is 32!!"));
  38. JsonDocument doc2(std::move(doc1));
  39. REQUIRE(doc2.as<std::string>() == "The size of this string is 32!!");
  40. REQUIRE(doc1.as<std::string>() == "null");
  41. REQUIRE(doc1.capacity() == 0);
  42. REQUIRE(doc2.capacity() == 4096);
  43. }
  44. REQUIRE(spyingAllocator.log() == AllocatorLog()
  45. << AllocatorLog::Allocate(4096)
  46. << AllocatorLog::Deallocate(4096));
  47. }
  48. SECTION("Copy assign larger") {
  49. {
  50. JsonDocument doc1(4096, &spyingAllocator);
  51. doc1.set(std::string("The size of this string is 32!!"));
  52. JsonDocument doc2(8, &spyingAllocator);
  53. doc2 = doc1;
  54. REQUIRE(doc1.as<std::string>() == "The size of this string is 32!!");
  55. REQUIRE(doc2.as<std::string>() == "The size of this string is 32!!");
  56. REQUIRE(doc2.capacity() == 4096);
  57. }
  58. REQUIRE(spyingAllocator.log() == AllocatorLog()
  59. << AllocatorLog::Allocate(4096)
  60. << AllocatorLog::Allocate(8)
  61. << AllocatorLog::Deallocate(8)
  62. << AllocatorLog::Allocate(4096)
  63. << AllocatorLog::Deallocate(4096)
  64. << AllocatorLog::Deallocate(4096));
  65. }
  66. SECTION("Copy assign smaller") {
  67. {
  68. JsonDocument doc1(1024, &spyingAllocator);
  69. doc1.set(std::string("The size of this string is 32!!"));
  70. JsonDocument doc2(4096, &spyingAllocator);
  71. doc2 = doc1;
  72. REQUIRE(doc1.as<std::string>() == "The size of this string is 32!!");
  73. REQUIRE(doc2.as<std::string>() == "The size of this string is 32!!");
  74. REQUIRE(doc2.capacity() == 1024);
  75. }
  76. REQUIRE(spyingAllocator.log() == AllocatorLog()
  77. << AllocatorLog::Allocate(1024)
  78. << AllocatorLog::Allocate(4096)
  79. << AllocatorLog::Deallocate(4096)
  80. << AllocatorLog::Allocate(1024)
  81. << AllocatorLog::Deallocate(1024)
  82. << AllocatorLog::Deallocate(1024));
  83. }
  84. SECTION("Copy assign same size") {
  85. {
  86. JsonDocument doc1(1024, &spyingAllocator);
  87. doc1.set(std::string("The size of this string is 32!!"));
  88. JsonDocument doc2(1024, &spyingAllocator);
  89. doc2 = doc1;
  90. REQUIRE(doc1.as<std::string>() == "The size of this string is 32!!");
  91. REQUIRE(doc2.as<std::string>() == "The size of this string is 32!!");
  92. REQUIRE(doc2.capacity() == 1024);
  93. }
  94. REQUIRE(spyingAllocator.log() == AllocatorLog()
  95. << AllocatorLog::Allocate(1024)
  96. << AllocatorLog::Allocate(1024)
  97. << AllocatorLog::Deallocate(1024)
  98. << AllocatorLog::Deallocate(1024));
  99. }
  100. SECTION("Move assign") {
  101. {
  102. JsonDocument doc1(4096, &spyingAllocator);
  103. doc1.set(std::string("The size of this string is 32!!"));
  104. JsonDocument doc2(8, &spyingAllocator);
  105. doc2 = std::move(doc1);
  106. REQUIRE(doc2.as<std::string>() == "The size of this string is 32!!");
  107. REQUIRE(doc1.as<std::string>() == "null");
  108. REQUIRE(doc1.capacity() == 0);
  109. REQUIRE(doc2.capacity() == 4096);
  110. }
  111. REQUIRE(spyingAllocator.log() == AllocatorLog()
  112. << AllocatorLog::Allocate(4096)
  113. << AllocatorLog::Allocate(8)
  114. << AllocatorLog::Deallocate(8)
  115. << AllocatorLog::Deallocate(4096));
  116. }
  117. SECTION("garbageCollect()") {
  118. JsonDocument doc(4096, &controllableAllocator);
  119. SECTION("when allocation succeeds") {
  120. deserializeJson(doc, "{\"blanket\":1,\"dancing\":2}");
  121. REQUIRE(doc.capacity() == 4096);
  122. REQUIRE(doc.memoryUsage() == sizeofObject(2) + 16);
  123. doc.remove("blanket");
  124. bool result = doc.garbageCollect();
  125. REQUIRE(result == true);
  126. REQUIRE(doc.memoryUsage() == sizeofObject(1) + 8);
  127. REQUIRE(doc.capacity() == 4096);
  128. REQUIRE(doc.as<std::string>() == "{\"dancing\":2}");
  129. }
  130. SECTION("when allocation fails") {
  131. deserializeJson(doc, "{\"blanket\":1,\"dancing\":2}");
  132. REQUIRE(doc.capacity() == 4096);
  133. REQUIRE(doc.memoryUsage() == sizeofObject(2) + 16);
  134. doc.remove("blanket");
  135. controllableAllocator.disable();
  136. bool result = doc.garbageCollect();
  137. REQUIRE(result == false);
  138. REQUIRE(doc.memoryUsage() == sizeofObject(2) + 16);
  139. REQUIRE(doc.capacity() == 4096);
  140. REQUIRE(doc.as<std::string>() == "{\"dancing\":2}");
  141. }
  142. }
  143. }