BasicJsonDocument.cpp 5.1 KB

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