set.cpp 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. // ArduinoJson - https://arduinojson.org
  2. // Copyright © 2014-2024, 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::sizeofObject;
  9. enum ErrorCode { ERROR_01 = 1, ERROR_10 = 10 };
  10. TEST_CASE("JsonVariant::set() when there is enough memory") {
  11. SpyingAllocator spy;
  12. JsonDocument doc(&spy);
  13. JsonVariant variant = doc.to<JsonVariant>();
  14. SECTION("const char*") {
  15. char str[16];
  16. strcpy(str, "hello");
  17. bool result = variant.set(static_cast<const char*>(str));
  18. strcpy(str, "world");
  19. REQUIRE(result == true);
  20. REQUIRE(variant == "world"); // stores by pointer
  21. REQUIRE(spy.log() == AllocatorLog{});
  22. }
  23. SECTION("(const char*)0") {
  24. bool result = variant.set(static_cast<const char*>(0));
  25. REQUIRE(result == true);
  26. REQUIRE(variant.isNull());
  27. REQUIRE(spy.log() == AllocatorLog{});
  28. }
  29. SECTION("char*") {
  30. char str[16];
  31. strcpy(str, "hello");
  32. bool result = variant.set(str);
  33. strcpy(str, "world");
  34. REQUIRE(result == true);
  35. REQUIRE(variant == "hello"); // stores by copy
  36. REQUIRE(spy.log() == AllocatorLog{
  37. Allocate(sizeofString("hello")),
  38. });
  39. }
  40. SECTION("(char*)0") {
  41. bool result = variant.set(static_cast<char*>(0));
  42. REQUIRE(result == true);
  43. REQUIRE(variant.isNull());
  44. REQUIRE(spy.log() == AllocatorLog{});
  45. }
  46. SECTION("unsigned char*") {
  47. char str[16];
  48. strcpy(str, "hello");
  49. bool result = variant.set(reinterpret_cast<unsigned char*>(str));
  50. strcpy(str, "world");
  51. REQUIRE(result == true);
  52. REQUIRE(variant == "hello"); // stores by copy
  53. REQUIRE(spy.log() == AllocatorLog{
  54. Allocate(sizeofString("hello")),
  55. });
  56. }
  57. SECTION("signed char*") {
  58. char str[16];
  59. strcpy(str, "hello");
  60. bool result = variant.set(reinterpret_cast<signed char*>(str));
  61. strcpy(str, "world");
  62. REQUIRE(result == true);
  63. REQUIRE(variant == "hello"); // stores by copy
  64. REQUIRE(spy.log() == AllocatorLog{
  65. Allocate(sizeofString("hello")),
  66. });
  67. }
  68. #ifdef HAS_VARIABLE_LENGTH_ARRAY
  69. SECTION("VLA") {
  70. size_t n = 16;
  71. char str[n];
  72. strcpy(str, "hello");
  73. bool result = variant.set(str);
  74. strcpy(str, "world");
  75. REQUIRE(result == true);
  76. REQUIRE(variant == "hello"); // stores by copy
  77. REQUIRE(spy.log() == AllocatorLog{
  78. Allocate(sizeofString("hello")),
  79. });
  80. }
  81. #endif
  82. SECTION("std::string") {
  83. std::string str;
  84. str = "hello";
  85. bool result = variant.set(str);
  86. str.replace(0, 5, "world");
  87. REQUIRE(result == true);
  88. REQUIRE(variant == "hello"); // stores by copy
  89. REQUIRE(spy.log() == AllocatorLog{
  90. Allocate(sizeofString("hello")),
  91. });
  92. }
  93. SECTION("static JsonString") {
  94. char str[16];
  95. strcpy(str, "hello");
  96. bool result = variant.set(JsonString(str, JsonString::Linked));
  97. strcpy(str, "world");
  98. REQUIRE(result == true);
  99. REQUIRE(variant == "world"); // stores by pointer
  100. REQUIRE(spy.log() == AllocatorLog{});
  101. }
  102. SECTION("non-static JsonString") {
  103. char str[16];
  104. strcpy(str, "hello");
  105. bool result = variant.set(JsonString(str, JsonString::Copied));
  106. strcpy(str, "world");
  107. REQUIRE(result == true);
  108. REQUIRE(variant == "hello"); // stores by copy
  109. REQUIRE(spy.log() == AllocatorLog{
  110. Allocate(sizeofString("hello")),
  111. });
  112. }
  113. SECTION("enum") {
  114. ErrorCode code = ERROR_10;
  115. bool result = variant.set(code);
  116. REQUIRE(result == true);
  117. REQUIRE(variant.is<int>() == true);
  118. REQUIRE(variant.as<int>() == 10);
  119. REQUIRE(spy.log() == AllocatorLog{});
  120. }
  121. SECTION("float") {
  122. bool result = variant.set(1.2f);
  123. REQUIRE(result == true);
  124. REQUIRE(variant.is<float>() == true);
  125. REQUIRE(variant.as<float>() == 1.2f);
  126. REQUIRE(spy.log() == AllocatorLog{});
  127. }
  128. SECTION("double") {
  129. bool result = variant.set(1.2);
  130. doc.shrinkToFit();
  131. REQUIRE(result == true);
  132. REQUIRE(variant.is<double>() == true);
  133. REQUIRE(variant.as<double>() == 1.2);
  134. REQUIRE(spy.log() ==
  135. AllocatorLog{
  136. Allocate(sizeofPool()),
  137. Reallocate(sizeofPool(), sizeofPool(1)), // one extension slot
  138. });
  139. }
  140. SECTION("int32_t") {
  141. bool result = variant.set(int32_t(42));
  142. REQUIRE(result == true);
  143. REQUIRE(variant.is<int32_t>() == true);
  144. REQUIRE(variant.as<int32_t>() == 42);
  145. REQUIRE(spy.log() == AllocatorLog{});
  146. }
  147. SECTION("int64_t") {
  148. bool result = variant.set(int64_t(-2147483649LL));
  149. doc.shrinkToFit();
  150. REQUIRE(result == true);
  151. REQUIRE(variant.is<int64_t>() == true);
  152. REQUIRE(variant.as<int64_t>() == -2147483649LL);
  153. REQUIRE(spy.log() ==
  154. AllocatorLog{
  155. Allocate(sizeofPool()),
  156. Reallocate(sizeofPool(), sizeofPool(1)), // one extension slot
  157. });
  158. }
  159. SECTION("uint32_t") {
  160. bool result = variant.set(uint32_t(42));
  161. REQUIRE(result == true);
  162. REQUIRE(variant.is<uint32_t>() == true);
  163. REQUIRE(variant.as<uint32_t>() == 42);
  164. REQUIRE(spy.log() == AllocatorLog{});
  165. }
  166. SECTION("uint64_t") {
  167. bool result = variant.set(uint64_t(4294967296));
  168. doc.shrinkToFit();
  169. REQUIRE(result == true);
  170. REQUIRE(variant.is<uint64_t>() == true);
  171. REQUIRE(variant.as<uint64_t>() == 4294967296);
  172. REQUIRE(spy.log() ==
  173. AllocatorLog{
  174. Allocate(sizeofPool()),
  175. Reallocate(sizeofPool(), sizeofPool(1)), // one extension slot
  176. });
  177. }
  178. SECTION("JsonDocument") {
  179. JsonDocument doc1;
  180. doc1["hello"] = "world";
  181. // Should copy the doc
  182. variant.set(doc1);
  183. doc1.clear();
  184. std::string json;
  185. serializeJson(doc, json);
  186. REQUIRE(json == "{\"hello\":\"world\"}");
  187. }
  188. }
  189. TEST_CASE("JsonVariant::set() with not enough memory") {
  190. JsonDocument doc(FailingAllocator::instance());
  191. JsonVariant v = doc.to<JsonVariant>();
  192. SECTION("std::string") {
  193. bool result = v.set("hello world!!"_s);
  194. REQUIRE(result == false);
  195. REQUIRE(v.isNull());
  196. }
  197. SECTION("Serialized<std::string>") {
  198. bool result = v.set(serialized("hello world!!"_s));
  199. REQUIRE(result == false);
  200. REQUIRE(v.isNull());
  201. }
  202. SECTION("char*") {
  203. char s[] = "hello world!!";
  204. bool result = v.set(s);
  205. REQUIRE(result == false);
  206. REQUIRE(v.isNull());
  207. }
  208. SECTION("float") {
  209. bool result = v.set(1.2f);
  210. REQUIRE(result == true);
  211. REQUIRE(v.is<float>());
  212. }
  213. SECTION("double") {
  214. bool result = v.set(1.2);
  215. REQUIRE(result == false);
  216. REQUIRE(v.isNull());
  217. }
  218. SECTION("int32_t") {
  219. bool result = v.set(-42);
  220. REQUIRE(result == true);
  221. REQUIRE(v.is<int32_t>());
  222. }
  223. SECTION("int64_t") {
  224. bool result = v.set(-2147483649LL);
  225. REQUIRE(result == false);
  226. REQUIRE(v.isNull());
  227. }
  228. SECTION("uint32_t") {
  229. bool result = v.set(42);
  230. REQUIRE(result == true);
  231. REQUIRE(v.is<uint32_t>());
  232. }
  233. SECTION("uint64_t") {
  234. bool result = v.set(4294967296U);
  235. REQUIRE(result == false);
  236. REQUIRE(v.isNull());
  237. }
  238. }
  239. TEST_CASE("JsonVariant::set() releases the previous value") {
  240. SpyingAllocator spy;
  241. JsonDocument doc(&spy);
  242. doc["hello"] = "world"_s;
  243. spy.clearLog();
  244. JsonVariant v = doc["hello"];
  245. SECTION("int") {
  246. v.set(42);
  247. REQUIRE(spy.log() == AllocatorLog{
  248. Deallocate(sizeofString("world")),
  249. });
  250. }
  251. SECTION("bool") {
  252. v.set(false);
  253. REQUIRE(spy.log() == AllocatorLog{
  254. Deallocate(sizeofString("world")),
  255. });
  256. }
  257. SECTION("const char*") {
  258. v.set("hello");
  259. REQUIRE(spy.log() == AllocatorLog{
  260. Deallocate(sizeofString("world")),
  261. });
  262. }
  263. SECTION("float") {
  264. v.set(1.2);
  265. REQUIRE(spy.log() == AllocatorLog{
  266. Deallocate(sizeofString("world")),
  267. });
  268. }
  269. SECTION("Serialized<const char*>") {
  270. v.set(serialized("[]"));
  271. REQUIRE(spy.log() == AllocatorLog{
  272. Deallocate(sizeofString("world")),
  273. Allocate(sizeofString("[]")),
  274. });
  275. }
  276. }
  277. TEST_CASE("JsonVariant::set() reuses extension slot") {
  278. SpyingAllocator spy;
  279. JsonDocument doc(&spy);
  280. JsonVariant variant = doc.to<JsonVariant>();
  281. variant.set(1.2);
  282. doc.shrinkToFit();
  283. spy.clearLog();
  284. SECTION("double") {
  285. bool result = variant.set(3.4);
  286. REQUIRE(result == true);
  287. REQUIRE(spy.log() == AllocatorLog{});
  288. }
  289. SECTION("int64_t") {
  290. bool result = variant.set(-2147483649LL);
  291. REQUIRE(result == true);
  292. REQUIRE(spy.log() == AllocatorLog{});
  293. }
  294. SECTION("uint64_t") {
  295. bool result = variant.set(4294967296U);
  296. REQUIRE(result == true);
  297. REQUIRE(spy.log() == AllocatorLog{});
  298. }
  299. }