add.cpp 7.0 KB

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