set.cpp 9.3 KB

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