add.cpp 6.9 KB

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