BasicJsonDocument.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  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. class SpyingAllocator {
  10. public:
  11. SpyingAllocator(const SpyingAllocator& src) : log_(src.log_) {}
  12. SpyingAllocator(std::ostream& log) : log_(log) {}
  13. SpyingAllocator& operator=(const SpyingAllocator& src) = delete;
  14. void* allocate(size_t n) {
  15. log_ << "A" << n;
  16. return malloc(n);
  17. }
  18. void deallocate(void* p) {
  19. log_ << "F";
  20. free(p);
  21. }
  22. private:
  23. std::ostream& log_;
  24. };
  25. class ControllableAllocator {
  26. public:
  27. ControllableAllocator() : enabled_(true) {}
  28. void* allocate(size_t n) {
  29. return enabled_ ? malloc(n) : 0;
  30. }
  31. void deallocate(void* p) {
  32. free(p);
  33. }
  34. void disable() {
  35. enabled_ = false;
  36. }
  37. private:
  38. bool enabled_;
  39. };
  40. TEST_CASE("BasicJsonDocument") {
  41. std::stringstream log;
  42. SECTION("Construct/Destruct") {
  43. { BasicJsonDocument<SpyingAllocator> doc(4096, log); }
  44. REQUIRE(log.str() == "A4096F");
  45. }
  46. SECTION("Copy construct") {
  47. {
  48. BasicJsonDocument<SpyingAllocator> doc1(4096, log);
  49. doc1.set(std::string("The size of this string is 32!!"));
  50. BasicJsonDocument<SpyingAllocator> doc2(doc1);
  51. REQUIRE(doc1.as<std::string>() == "The size of this string is 32!!");
  52. REQUIRE(doc2.as<std::string>() == "The size of this string is 32!!");
  53. REQUIRE(doc2.capacity() == 4096);
  54. }
  55. REQUIRE(log.str() == "A4096A4096FF");
  56. }
  57. SECTION("Move construct") {
  58. {
  59. BasicJsonDocument<SpyingAllocator> doc1(4096, log);
  60. doc1.set(std::string("The size of this string is 32!!"));
  61. BasicJsonDocument<SpyingAllocator> doc2(std::move(doc1));
  62. REQUIRE(doc2.as<std::string>() == "The size of this string is 32!!");
  63. REQUIRE(doc1.as<std::string>() == "null");
  64. REQUIRE(doc1.capacity() == 0);
  65. REQUIRE(doc2.capacity() == 4096);
  66. }
  67. REQUIRE(log.str() == "A4096F");
  68. }
  69. SECTION("Copy assign larger") {
  70. {
  71. BasicJsonDocument<SpyingAllocator> doc1(4096, log);
  72. doc1.set(std::string("The size of this string is 32!!"));
  73. BasicJsonDocument<SpyingAllocator> doc2(8, log);
  74. doc2 = doc1;
  75. REQUIRE(doc1.as<std::string>() == "The size of this string is 32!!");
  76. REQUIRE(doc2.as<std::string>() == "The size of this string is 32!!");
  77. REQUIRE(doc2.capacity() == 4096);
  78. }
  79. REQUIRE(log.str() == "A4096A8FA4096FF");
  80. }
  81. SECTION("Copy assign smaller") {
  82. {
  83. BasicJsonDocument<SpyingAllocator> doc1(1024, log);
  84. doc1.set(std::string("The size of this string is 32!!"));
  85. BasicJsonDocument<SpyingAllocator> doc2(4096, log);
  86. doc2 = doc1;
  87. REQUIRE(doc1.as<std::string>() == "The size of this string is 32!!");
  88. REQUIRE(doc2.as<std::string>() == "The size of this string is 32!!");
  89. REQUIRE(doc2.capacity() == 1024);
  90. }
  91. REQUIRE(log.str() == "A1024A4096FA1024FF");
  92. }
  93. SECTION("Copy assign same size") {
  94. {
  95. BasicJsonDocument<SpyingAllocator> doc1(1024, log);
  96. doc1.set(std::string("The size of this string is 32!!"));
  97. BasicJsonDocument<SpyingAllocator> doc2(1024, log);
  98. doc2 = doc1;
  99. REQUIRE(doc1.as<std::string>() == "The size of this string is 32!!");
  100. REQUIRE(doc2.as<std::string>() == "The size of this string is 32!!");
  101. REQUIRE(doc2.capacity() == 1024);
  102. }
  103. REQUIRE(log.str() == "A1024A1024FF");
  104. }
  105. SECTION("Move assign") {
  106. {
  107. BasicJsonDocument<SpyingAllocator> doc1(4096, log);
  108. doc1.set(std::string("The size of this string is 32!!"));
  109. BasicJsonDocument<SpyingAllocator> doc2(8, log);
  110. doc2 = std::move(doc1);
  111. REQUIRE(doc2.as<std::string>() == "The size of this string is 32!!");
  112. REQUIRE(doc1.as<std::string>() == "null");
  113. REQUIRE(doc1.capacity() == 0);
  114. REQUIRE(doc2.capacity() == 4096);
  115. }
  116. REQUIRE(log.str() == "A4096A8FF");
  117. }
  118. SECTION("garbageCollect()") {
  119. BasicJsonDocument<ControllableAllocator> doc(4096);
  120. SECTION("when allocation succeeds") {
  121. deserializeJson(doc, "{\"blanket\":1,\"dancing\":2}");
  122. REQUIRE(doc.capacity() == 4096);
  123. REQUIRE(doc.memoryUsage() == JSON_OBJECT_SIZE(2) + 16);
  124. doc.remove("blanket");
  125. bool result = doc.garbageCollect();
  126. REQUIRE(result == true);
  127. REQUIRE(doc.memoryUsage() == JSON_OBJECT_SIZE(1) + 8);
  128. REQUIRE(doc.capacity() == 4096);
  129. REQUIRE(doc.as<std::string>() == "{\"dancing\":2}");
  130. }
  131. SECTION("when allocation fails") {
  132. deserializeJson(doc, "{\"blanket\":1,\"dancing\":2}");
  133. REQUIRE(doc.capacity() == 4096);
  134. REQUIRE(doc.memoryUsage() == JSON_OBJECT_SIZE(2) + 16);
  135. doc.remove("blanket");
  136. doc.allocator().disable();
  137. bool result = doc.garbageCollect();
  138. REQUIRE(result == false);
  139. REQUIRE(doc.memoryUsage() == JSON_OBJECT_SIZE(2) + 16);
  140. REQUIRE(doc.capacity() == 4096);
  141. REQUIRE(doc.as<std::string>() == "{\"dancing\":2}");
  142. }
  143. }
  144. }