add.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. // ArduinoJson - https://arduinojson.org
  2. // Copyright © 2014-2025, Benoit BLANCHON
  3. // MIT License
  4. #include <ArduinoJson.h>
  5. #include <catch.hpp>
  6. #include "Allocators.hpp"
  7. #include "Literals.hpp"
  8. using namespace ArduinoJson::detail;
  9. TEST_CASE("JsonArray::add(T)") {
  10. SpyingAllocator spy;
  11. JsonDocument doc(&spy);
  12. JsonArray array = doc.to<JsonArray>();
  13. SECTION("int") {
  14. array.add(123);
  15. REQUIRE(123 == array[0].as<int>());
  16. REQUIRE(array[0].is<int>());
  17. REQUIRE(array[0].is<double>());
  18. REQUIRE(spy.log() == AllocatorLog{
  19. Allocate(sizeofPool()),
  20. });
  21. }
  22. SECTION("double") {
  23. array.add(123.45);
  24. REQUIRE(123.45 == array[0].as<double>());
  25. REQUIRE(array[0].is<double>());
  26. REQUIRE_FALSE(array[0].is<bool>());
  27. REQUIRE(spy.log() == AllocatorLog{
  28. Allocate(sizeofPool<VariantData>()),
  29. Allocate(sizeofPool<EightByteValue>()),
  30. });
  31. }
  32. SECTION("bool") {
  33. array.add(true);
  34. REQUIRE(array[0].as<bool>() == true);
  35. REQUIRE(array[0].is<bool>());
  36. REQUIRE_FALSE(array[0].is<int>());
  37. REQUIRE(spy.log() == AllocatorLog{
  38. Allocate(sizeofPool()),
  39. });
  40. }
  41. SECTION("string literal") {
  42. array.add("hello");
  43. REQUIRE(array[0].as<std::string>() == "hello");
  44. REQUIRE(array[0].is<const char*>());
  45. REQUIRE(array[0].is<int>() == false);
  46. REQUIRE(spy.log() == AllocatorLog{
  47. Allocate(sizeofPool()),
  48. Allocate(sizeofStaticStringPool()),
  49. });
  50. }
  51. SECTION("std::string") {
  52. array.add("hello"_s);
  53. REQUIRE(array[0].as<std::string>() == "hello");
  54. REQUIRE(array[0].is<const char*>() == true);
  55. REQUIRE(array[0].is<int>() == false);
  56. REQUIRE(spy.log() == AllocatorLog{
  57. Allocate(sizeofPool()),
  58. Allocate(sizeofString("hello")),
  59. });
  60. }
  61. SECTION("const char*") {
  62. const char* str = "hello";
  63. array.add(str);
  64. REQUIRE(array[0].as<std::string>() == "hello");
  65. REQUIRE(array[0].as<const char*>() != str);
  66. REQUIRE(array[0].is<const char*>() == true);
  67. REQUIRE(array[0].is<int>() == false);
  68. REQUIRE(spy.log() == AllocatorLog{
  69. Allocate(sizeofPool()),
  70. Allocate(sizeofString("hello")),
  71. });
  72. }
  73. SECTION("serialized(const char*)") {
  74. array.add(serialized("{}"));
  75. REQUIRE(doc.as<std::string>() == "[{}]");
  76. REQUIRE(spy.log() == AllocatorLog{
  77. Allocate(sizeofPool()),
  78. Allocate(sizeofString("{}")),
  79. });
  80. }
  81. SECTION("serialized(char*)") {
  82. array.add(serialized(const_cast<char*>("{}")));
  83. REQUIRE(doc.as<std::string>() == "[{}]");
  84. REQUIRE(spy.log() == AllocatorLog{
  85. Allocate(sizeofPool()),
  86. Allocate(sizeofString("{}")),
  87. });
  88. }
  89. SECTION("serialized(std::string)") {
  90. array.add(serialized("{}"_s));
  91. REQUIRE(doc.as<std::string>() == "[{}]");
  92. REQUIRE(spy.log() == AllocatorLog{
  93. Allocate(sizeofPool()),
  94. Allocate(sizeofString("{}")),
  95. });
  96. }
  97. SECTION("serialized(std::string)") {
  98. array.add(serialized("\0XX"_s));
  99. REQUIRE(doc.as<std::string>() == "[\0XX]"_s);
  100. REQUIRE(spy.log() == AllocatorLog{
  101. Allocate(sizeofPool()),
  102. Allocate(sizeofString(" XX")),
  103. });
  104. }
  105. #ifdef HAS_VARIABLE_LENGTH_ARRAY
  106. SECTION("vla") {
  107. size_t i = 16;
  108. char vla[i];
  109. strcpy(vla, "world");
  110. array.add(vla);
  111. strcpy(vla, "hello");
  112. REQUIRE(array[0] == "world"_s);
  113. REQUIRE(spy.log() == AllocatorLog{
  114. Allocate(sizeofPool()),
  115. Allocate(sizeofString("hello")),
  116. });
  117. }
  118. #endif
  119. SECTION("nested array") {
  120. JsonDocument doc2;
  121. JsonArray arr = doc2.to<JsonArray>();
  122. array.add(arr);
  123. REQUIRE(arr == array[0].as<JsonArray>());
  124. REQUIRE(array[0].is<JsonArray>());
  125. REQUIRE_FALSE(array[0].is<int>());
  126. }
  127. SECTION("nested object") {
  128. JsonDocument doc2;
  129. JsonObject obj = doc2.to<JsonObject>();
  130. array.add(obj);
  131. REQUIRE(obj == array[0].as<JsonObject>());
  132. REQUIRE(array[0].is<JsonObject>());
  133. REQUIRE_FALSE(array[0].is<int>());
  134. }
  135. SECTION("array subscript") {
  136. const char* str = "hello";
  137. JsonDocument doc2;
  138. JsonArray arr = doc2.to<JsonArray>();
  139. arr.add(str);
  140. array.add(arr[0]);
  141. REQUIRE(str == array[0]);
  142. }
  143. SECTION("object subscript") {
  144. const char* str = "hello";
  145. JsonDocument doc2;
  146. JsonObject obj = doc2.to<JsonObject>();
  147. obj["x"] = str;
  148. array.add(obj["x"]);
  149. REQUIRE(str == array[0]);
  150. }
  151. }
  152. TEST_CASE("JsonArray::add<T>()") {
  153. JsonDocument doc;
  154. JsonArray array = doc.to<JsonArray>();
  155. SECTION("add<JsonArray>()") {
  156. JsonArray nestedArray = array.add<JsonArray>();
  157. nestedArray.add(1);
  158. nestedArray.add(2);
  159. REQUIRE(doc.as<std::string>() == "[[1,2]]");
  160. }
  161. SECTION("add<JsonObject>()") {
  162. JsonObject nestedObject = array.add<JsonObject>();
  163. nestedObject["a"] = 1;
  164. nestedObject["b"] = 2;
  165. REQUIRE(doc.as<std::string>() == "[{\"a\":1,\"b\":2}]");
  166. }
  167. SECTION("add<JsonVariant>()") {
  168. JsonVariant nestedVariant = array.add<JsonVariant>();
  169. nestedVariant.set(42);
  170. REQUIRE(doc.as<std::string>() == "[42]");
  171. }
  172. }
  173. TEST_CASE("JsonObject::add(JsonObject) ") {
  174. JsonDocument doc1;
  175. doc1["key1"_s] = "value1"_s;
  176. TimebombAllocator allocator(10);
  177. SpyingAllocator spy(&allocator);
  178. JsonDocument doc2(&spy);
  179. JsonArray array = doc2.to<JsonArray>();
  180. SECTION("success") {
  181. bool result = array.add(doc1.as<JsonObject>());
  182. REQUIRE(result == true);
  183. REQUIRE(doc2.as<std::string>() == "[{\"key1\":\"value1\"}]");
  184. REQUIRE(spy.log() == AllocatorLog{
  185. Allocate(sizeofPool()),
  186. Allocate(sizeofString("key1")),
  187. Allocate(sizeofString("value1")),
  188. });
  189. }
  190. SECTION("partial failure") { // issue #2081
  191. allocator.setCountdown(2);
  192. bool result = array.add(doc1.as<JsonObject>());
  193. REQUIRE(result == false);
  194. REQUIRE(doc2.as<std::string>() == "[]");
  195. REQUIRE(spy.log() == AllocatorLog{
  196. Allocate(sizeofPool()),
  197. Allocate(sizeofString("key1")),
  198. AllocateFail(sizeofString("value1")),
  199. Deallocate(sizeofString("key1")),
  200. });
  201. }
  202. SECTION("complete failure") {
  203. allocator.setCountdown(0);
  204. bool result = array.add(doc1.as<JsonObject>());
  205. REQUIRE(result == false);
  206. REQUIRE(doc2.as<std::string>() == "[]");
  207. REQUIRE(spy.log() == AllocatorLog{
  208. AllocateFail(sizeofPool()),
  209. });
  210. }
  211. }