shrinkToFit.cpp 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. // ArduinoJson - https://arduinojson.org
  2. // Copyright © 2014-2023, Benoit BLANCHON
  3. // MIT License
  4. #include <ArduinoJson.h>
  5. #include <catch.hpp>
  6. #include <stdlib.h> // malloc, free
  7. #include <string>
  8. class ArmoredAllocator {
  9. public:
  10. ArmoredAllocator() : ptr_(0), size_(0) {}
  11. void* allocate(size_t size) {
  12. ptr_ = malloc(size);
  13. size_ = size;
  14. return ptr_;
  15. }
  16. void deallocate(void* ptr) {
  17. REQUIRE(ptr == ptr_);
  18. free(ptr);
  19. ptr_ = 0;
  20. size_ = 0;
  21. }
  22. void* reallocate(void* ptr, size_t new_size) {
  23. REQUIRE(ptr == ptr_);
  24. // don't call realloc, instead alloc a new buffer and erase the old one
  25. // this way we make sure we support relocation
  26. void* new_ptr = malloc(new_size);
  27. memcpy(new_ptr, ptr_, std::min(new_size, size_));
  28. memset(ptr_, '#', size_); // erase
  29. free(ptr_);
  30. ptr_ = new_ptr;
  31. return new_ptr;
  32. }
  33. private:
  34. void* ptr_;
  35. size_t size_;
  36. };
  37. typedef BasicJsonDocument<ArmoredAllocator> ShrinkToFitTestDocument;
  38. void testShrinkToFit(ShrinkToFitTestDocument& doc, std::string expected_json,
  39. size_t expected_size) {
  40. // test twice: shrinkToFit() should be idempotent
  41. for (int i = 0; i < 2; i++) {
  42. doc.shrinkToFit();
  43. REQUIRE(doc.capacity() == expected_size);
  44. REQUIRE(doc.memoryUsage() == expected_size);
  45. std::string json;
  46. serializeJson(doc, json);
  47. REQUIRE(json == expected_json);
  48. }
  49. }
  50. TEST_CASE("BasicJsonDocument::shrinkToFit()") {
  51. ShrinkToFitTestDocument doc(4096);
  52. SECTION("null") {
  53. testShrinkToFit(doc, "null", 0);
  54. }
  55. SECTION("empty object") {
  56. deserializeJson(doc, "{}");
  57. testShrinkToFit(doc, "{}", JSON_OBJECT_SIZE(0));
  58. }
  59. SECTION("empty array") {
  60. deserializeJson(doc, "[]");
  61. testShrinkToFit(doc, "[]", JSON_ARRAY_SIZE(0));
  62. }
  63. SECTION("linked string") {
  64. doc.set("hello");
  65. testShrinkToFit(doc, "\"hello\"", 0);
  66. }
  67. SECTION("owned string") {
  68. doc.set(std::string("abcdefg"));
  69. testShrinkToFit(doc, "\"abcdefg\"", 8);
  70. }
  71. SECTION("linked raw") {
  72. doc.set(serialized("[{},123]"));
  73. testShrinkToFit(doc, "[{},123]", 0);
  74. }
  75. SECTION("owned raw") {
  76. doc.set(serialized(std::string("[{},12]")));
  77. testShrinkToFit(doc, "[{},12]", 8);
  78. }
  79. SECTION("linked key") {
  80. doc["key"] = 42;
  81. testShrinkToFit(doc, "{\"key\":42}", JSON_OBJECT_SIZE(1));
  82. }
  83. SECTION("owned key") {
  84. doc[std::string("abcdefg")] = 42;
  85. testShrinkToFit(doc, "{\"abcdefg\":42}", JSON_OBJECT_SIZE(1) + 8);
  86. }
  87. SECTION("linked string in array") {
  88. doc.add("hello");
  89. testShrinkToFit(doc, "[\"hello\"]", JSON_ARRAY_SIZE(1));
  90. }
  91. SECTION("owned string in array") {
  92. doc.add(std::string("abcdefg"));
  93. testShrinkToFit(doc, "[\"abcdefg\"]", JSON_ARRAY_SIZE(1) + 8);
  94. }
  95. SECTION("linked string in object") {
  96. doc["key"] = "hello";
  97. testShrinkToFit(doc, "{\"key\":\"hello\"}", JSON_OBJECT_SIZE(1));
  98. }
  99. SECTION("owned string in object") {
  100. doc["key"] = std::string("abcdefg");
  101. testShrinkToFit(doc, "{\"key\":\"abcdefg\"}", JSON_ARRAY_SIZE(1) + 8);
  102. }
  103. SECTION("unaligned") {
  104. doc.add(std::string("?")); // two bytes in the string pool
  105. REQUIRE(doc.memoryUsage() == JSON_OBJECT_SIZE(1) + 2);
  106. doc.shrinkToFit();
  107. // the new capacity should be padded to align the pointers
  108. REQUIRE(doc.capacity() == JSON_OBJECT_SIZE(1) + sizeof(void*));
  109. REQUIRE(doc.memoryUsage() == JSON_OBJECT_SIZE(1) + 2);
  110. REQUIRE(doc[0] == "?");
  111. }
  112. }
  113. TEST_CASE("DynamicJsonDocument::shrinkToFit()") {
  114. DynamicJsonDocument doc(4096);
  115. deserializeJson(doc, "{\"hello\":[\"world\"]");
  116. doc.shrinkToFit();
  117. std::string json;
  118. serializeJson(doc, json);
  119. REQUIRE(json == "{\"hello\":[\"world\"]}");
  120. }