xref: /aosp_15_r20/external/pigweed/pw_json/builder_test.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2024 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 #include "pw_json/builder.h"
16 
17 #include <array>
18 #include <cstring>
19 #include <string_view>
20 
21 #include "pw_assert/check.h"
22 #include "pw_compilation_testing/negative_compilation.h"
23 #include "pw_unit_test/framework.h"
24 
25 namespace {
26 
27 using namespace std::string_view_literals;
28 
29 // First example for the docs.
__anon1fb128a40202null30 static_assert([] {
31   bool is_simple = true;
32   int safety_percentage = 100;
33 
34   std::string_view features[] = {"values", "arrays", "objects", "nesting!"};
35 
36   // DOCTSAG: [pw-json-builder-example-1]
37   pw::JsonBuffer<256> json_buffer;
38   pw::JsonObject& object = json_buffer.StartObject();
39   object.Add("tagline", "Easy, efficient JSON serialization!")
40       .Add("simple", is_simple)
41       .Add("safe", safety_percentage)
42       .Add("dynamic allocation", false);
43 
44   pw::NestedJsonArray nested_array = object.AddNestedArray("features");
45   for (const std::string_view feature : features) {
46     nested_array.Append(feature);
47   }
48   // DOCTSAG: [pw-json-builder-example-1]
49   return json_buffer;
50 }() == R"({"tagline": "Easy, efficient JSON serialization!", "simple": true,)"
51        R"( "safe": 100, "dynamic allocation": false, "features":)"
52        R"( ["values", "arrays", "objects", "nesting!"]})"sv);
53 
54 // Second example for the docs.
__anon1fb128a40302null55 static_assert([] {
56   constexpr char empty[128] = {};
57   std::string_view huge_string_that_wont_fit(empty, sizeof(empty));
58 
59   // DOCTSAG: [pw-json-builder-example-2]
60   // Declare a JsonBuffer (JsonBuilder with included buffer) and start a JSON
61   // object in it.
62   pw::JsonBuffer<128> json_buffer;
63   pw::JsonObject& json = json_buffer.StartObject();
64 
65   const char* name = "Crag";
66   constexpr const char* kOccupationKey = "job";
67 
68   // Add key-value pairs to a JSON object.
69   json.Add("name", name).Add(kOccupationKey, "hacker");
70 
71   // Add an array as the value in a key-value pair.
72   pw::NestedJsonArray nested_array = json.AddNestedArray("skills");
73 
74   // Append items to an array.
75   nested_array.Append(20).Append(1).Append(1).Append(1);
76 
77   // Check that everything fit in the JSON buffer.
78   PW_ASSERT(json.ok());
79 
80   // Compare the contents of the JSON to a std::string_view.
81   PW_ASSERT(std::string_view(json) ==
82             R"({"name": "Crag", "job": "hacker", "skills": [20, 1, 1, 1]})");
83 
84   // Add an object as the value in a key-value pair.
85   pw::NestedJsonObject nested_object = json.AddNestedObject("items");
86 
87   // Declare another JsonArray, and add it as nested value.
88   pw::JsonBuffer<10> inner_buffer;
89   inner_buffer.StartArray().Append(nullptr);
90   nested_object.Add("misc", inner_buffer);
91 
92   // Add a value that is too large for the JsonBuffer.
93   json.Add("way too big!", huge_string_that_wont_fit);
94 
95   // Adding the last entry failed, but the JSON is still valid.
96   PW_ASSERT(json.status().IsResourceExhausted());
97 
98   PW_ASSERT(std::string_view(json) ==
99             R"({"name": "Crag", "job": "hacker", "skills": [20, 1, 1, 1],)"
100             R"( "items": {"misc": [null]}})");
101   // DOCTSAG: [pw-json-builder-example-2]
102   return json_buffer;
103 }() == R"({"name": "Crag", "job": "hacker", "skills": [20, 1, 1, 1],)"
104        R"( "items": {"misc": [null]}})"sv);
105 
106 }  // namespace
107 
108 namespace pw {
109 namespace {
110 
111 class JsonOverflowTest : public ::testing::Test {
112  public:
~JsonOverflowTest()113   ~JsonOverflowTest() override {
114     EXPECT_STREQ(&buffer_[end_], kTag) << "Overflow occurred!";
115   }
116 
117  protected:
MarkBufferEnd(const JsonBuilder & json)118   void MarkBufferEnd(const JsonBuilder& json) {
119     end_ = json.max_size() + 1;
120     ASSERT_LT(end_, sizeof(buffer_) - sizeof(kTag));
121     std::memcpy(&buffer_[end_], kTag, sizeof(kTag));
122   }
123 
124   char buffer_[512];
125 
126  private:
127   static constexpr const char kTag[] = "Hi! Your buffer is safe.";
128 
129   size_t end_ = 0;
130 };
131 
TEST(JsonObject,BasicJson)132 TEST(JsonObject, BasicJson) {
133   char buffer[128];
134   std::memset(buffer, '?', sizeof(buffer));
135   JsonBuilder json_buffer(buffer);
136   JsonObject& json = json_buffer.StartObject();
137 
138   EXPECT_EQ(buffer, json.data());
139   EXPECT_STREQ("{}", json.data());
140   EXPECT_EQ(2u, json.size());
141 
142   EXPECT_EQ(OkStatus(), json.Add("foo", "bar").status());
143   EXPECT_STREQ(R"({"foo": "bar"})", json.data());
144   EXPECT_EQ(std::strlen(json.data()), json.size());
145 
146   EXPECT_EQ(OkStatus(), json.Add("bar", 0).status());
147   EXPECT_STREQ(R"({"foo": "bar", "bar": 0})", json.data());
148   EXPECT_EQ(std::strlen(json.data()), json.size());
149 
150   EXPECT_EQ(OkStatus(), json.Add("baz", nullptr).status());
151   EXPECT_STREQ(R"({"foo": "bar", "bar": 0, "baz": null})", json.data());
152   EXPECT_EQ(std::strlen(json.data()), json.size());
153 
154   EXPECT_EQ(OkStatus(), json.Add("EMPTY STR!", "").status());
155   EXPECT_STREQ(R"({"foo": "bar", "bar": 0, "baz": null, "EMPTY STR!": ""})",
156                json.data());
157   EXPECT_EQ(std::strlen(json.data()), json.size());
158 }
159 
TEST(JsonObject,OverflowAtKey)160 TEST(JsonObject, OverflowAtKey) {
161   JsonBuffer<19> json_buffer;
162   JsonObject& json = json_buffer.StartObject();
163 
164   EXPECT_EQ(OkStatus(), json.Add("a", 5l).Add("b", "!").status());
165   EXPECT_STREQ(R"({"a": 5, "b": "!"})", json.data());  // 18 chars + \0
166 
167   EXPECT_EQ(Status::ResourceExhausted(), json.Add("b", "!").status());
168   EXPECT_STREQ(R"({"a": 5, "b": "!"})", json.data());
169   EXPECT_EQ(Status::ResourceExhausted(), json.Add("b", "").status());
170   EXPECT_STREQ(R"({"a": 5, "b": "!"})", json.data());
171   EXPECT_EQ(Status::ResourceExhausted(), json.status());
172   EXPECT_EQ(Status::ResourceExhausted(), json.last_status());
173   json.clear_status();
174   EXPECT_STREQ(R"({"a": 5, "b": "!"})", json.data());
175   EXPECT_EQ(OkStatus(), json.status());
176   EXPECT_EQ(OkStatus(), json.last_status());
177 }
178 
TEST_F(JsonOverflowTest,ObjectOverflowAtFirstEntry)179 TEST_F(JsonOverflowTest, ObjectOverflowAtFirstEntry) {
180   JsonBuilder json_builder(buffer_, 5);
181   MarkBufferEnd(json_builder);
182 
183   JsonObject& json = json_builder.StartObject();
184   ASSERT_STREQ("{}", json.data());
185   EXPECT_EQ(Status::ResourceExhausted(), json.Add("some_key", "").status());
186   EXPECT_STREQ("{}", json.data());
187 }
188 
TEST_F(JsonOverflowTest,ObjectOverflowAtStringValue)189 TEST_F(JsonOverflowTest, ObjectOverflowAtStringValue) {
190   JsonBuilder json_builder(buffer_, 32);
191   MarkBufferEnd(json_builder);
192 
193   JsonObject& json = json_builder.StartObject();
194   EXPECT_EQ(OkStatus(), json.Add("a", 5l).status());
195   EXPECT_STREQ(R"({"a": 5})", json.data());
196 
197   EXPECT_EQ(
198       Status::ResourceExhausted(),
199       json.Add("b", "This string is so long that it won't fit!!!!").status());
200   EXPECT_STREQ(R"({"a": 5})", json.data());
201   EXPECT_EQ(Status::ResourceExhausted(), json.status());
202 
203   EXPECT_EQ(OkStatus(), json.Add("b", "This will!").last_status());
204   EXPECT_STREQ(R"({"a": 5, "b": "This will!"})", json.data());
205   EXPECT_EQ(Status::ResourceExhausted(), json.status());
206   EXPECT_EQ(OkStatus(), json.last_status());
207 }
208 
TEST_F(JsonOverflowTest,OverflowAtUnicodeCharacter)209 TEST_F(JsonOverflowTest, OverflowAtUnicodeCharacter) {
210   JsonBuilder json_builder(buffer_, 10);
211   MarkBufferEnd(json_builder);
212 
213   JsonValue& overflow_at_unicode = json_builder.StartValue();
214   EXPECT_EQ(Status::ResourceExhausted(), overflow_at_unicode.Set("234\x01"));
215   EXPECT_STREQ("null", overflow_at_unicode.data());
216   EXPECT_EQ(Status::ResourceExhausted(), overflow_at_unicode.Set("2345\x01"));
217   EXPECT_STREQ("null", overflow_at_unicode.data());
218   EXPECT_EQ(Status::ResourceExhausted(),
219             overflow_at_unicode.Set("23456789\x01"));
220   EXPECT_STREQ("null", overflow_at_unicode.data());
221 }
222 
TEST_F(JsonOverflowTest,ObjectOverflowAtNumber)223 TEST_F(JsonOverflowTest, ObjectOverflowAtNumber) {
224   JsonBuilder json_builder(buffer_, 14);
225   MarkBufferEnd(json_builder);
226 
227   JsonObject& json = json_builder.StartObject();
228   EXPECT_EQ(OkStatus(), json.Add("a", 123456).status());
229   EXPECT_STREQ(R"({"a": 123456})", json.data());
230   EXPECT_EQ(json.max_size(), json.size());
231   json.clear();
232 
233   EXPECT_EQ(Status::ResourceExhausted(), json.Add("a", 1234567).status());
234   EXPECT_STREQ(R"({})", json.data());
235   EXPECT_EQ(2u, json.size());
236   json.clear();
237 
238   EXPECT_EQ(Status::ResourceExhausted(), json.Add("a", 12345678).status());
239   EXPECT_STREQ(R"({})", json.data());
240   EXPECT_EQ(2u, json.size());
241 }
242 
TEST(JsonObject,StringValueFillsAllSpace)243 TEST(JsonObject, StringValueFillsAllSpace) {
244   JsonBuffer<15> json_buffer;
245 
246   JsonObject& json = json_buffer.StartObject();
247   EXPECT_EQ(OkStatus(), json.Add("key", "12\\").status());
248   EXPECT_STREQ(R"({"key": "12\\"})", json.data());
249   EXPECT_EQ(15u, json.size());
250 
251   json.clear();
252   EXPECT_EQ(Status::ResourceExhausted(), json.Add("key", "123\\").status());
253   EXPECT_STREQ(R"({})", json.data());
254 }
255 
TEST(JsonObject,NestedJson)256 TEST(JsonObject, NestedJson) {
257   JsonBuffer<64> outside_builder;
258   JsonBuffer<32> inside_builder;
259 
260   JsonObject& outside = outside_builder.StartObject();
261   JsonObject& inside = inside_builder.StartObject();
262 
263   ASSERT_EQ(OkStatus(), inside.Add("inside", 123).status());
264   ASSERT_STREQ(R"({"inside": 123})", inside.data());
265 
266   EXPECT_EQ(OkStatus(), outside.Add("some_value", inside).status());
267   EXPECT_STREQ(R"({"some_value": {"inside": 123}})", outside.data());
268 
269   inside.clear();
270   EXPECT_EQ(OkStatus(), outside.Add("MT", inside).status());
271   EXPECT_STREQ(R"({"some_value": {"inside": 123}, "MT": {}})", outside.data());
272 
273   outside.AddNestedArray("key").Append(99).Append(1);
274   EXPECT_EQ(outside,
275             R"({"some_value": {"inside": 123}, "MT": {}, "key": [99, 1]})"sv);
276 }
277 
TEST(JsonObject,NestedArrayOverflowWhenNesting)278 TEST(JsonObject, NestedArrayOverflowWhenNesting) {
279   JsonBuffer<5> buffer;
280   JsonArray& array = buffer.StartArray();
281   array.Append(123);
282   ASSERT_EQ(array, "[123]"sv);
283 
284   NestedJsonArray nested_array = array.AppendNestedArray();
285   EXPECT_EQ(Status::ResourceExhausted(), array.status());
286   nested_array.Append(1);
287   EXPECT_EQ(array, "[123]"sv);
288 }
289 
TEST(JsonObject,NestedArrayOverflowAppend)290 TEST(JsonObject, NestedArrayOverflowAppend) {
291   JsonBuffer<5> buffer;
292   JsonArray& array = buffer.StartArray();
293   NestedJsonArray nested_array = array.AppendNestedArray();
294 
295   EXPECT_EQ(OkStatus(), array.status());
296   nested_array.Append(10);
297   EXPECT_EQ(Status::ResourceExhausted(), array.status());
298   EXPECT_EQ(array, "[[]]"sv);
299 }
300 
TEST(JsonObject,NestedArrayOverflowSecondAppend)301 TEST(JsonObject, NestedArrayOverflowSecondAppend) {
302   JsonBuffer<7> buffer;
303   JsonArray& array = buffer.StartArray();
304   NestedJsonArray nested_array = array.AppendNestedArray();
305 
306   EXPECT_EQ(OkStatus(), array.status());
307   nested_array.Append(1);
308   EXPECT_EQ(array, "[[1]]"sv);
309   EXPECT_EQ(OkStatus(), array.status());
310 
311   nested_array.Append(2);
312   EXPECT_EQ(array, "[[1]]"sv);
313   EXPECT_EQ(Status::ResourceExhausted(), array.status());
314 }
315 
TEST(JsonObject,NestedObjectOverflowWhenNesting)316 TEST(JsonObject, NestedObjectOverflowWhenNesting) {
317   JsonBuffer<5> buffer;
318   JsonArray& array = buffer.StartArray();
319   array.Append(123);
320   ASSERT_EQ(array, "[123]"sv);
321 
322   std::ignore = array.AppendNestedObject();
323   EXPECT_EQ(Status::ResourceExhausted(), array.status());
324   EXPECT_EQ(array, "[123]"sv);
325 }
326 
TEST(JsonObject,NestedObjectOverflowAppend)327 TEST(JsonObject, NestedObjectOverflowAppend) {
328   JsonBuffer<5> buffer;
329   JsonArray& array = buffer.StartArray();
330   NestedJsonObject nested_object = array.AppendNestedObject();
331 
332   EXPECT_EQ(OkStatus(), array.status());
333   nested_object.Add("k", 10);
334   EXPECT_EQ(Status::ResourceExhausted(), array.status());
335   EXPECT_EQ(array, "[{}]"sv);
336 }
337 
TEST(JsonObject,NestedObjectOverflowSecondAppend)338 TEST(JsonObject, NestedObjectOverflowSecondAppend) {
339   JsonBuffer<14> buffer;
340   JsonArray& array = buffer.StartArray();
341   NestedJsonObject nested_object = array.AppendNestedObject();
342 
343   EXPECT_EQ(OkStatus(), array.status());
344   nested_object.Add("k", 1);
345   EXPECT_EQ(array, R"([{"k": 1}])"sv);
346   EXPECT_EQ(OkStatus(), array.status());
347 
348   nested_object.Add("K", 2);
349   EXPECT_EQ(array, R"([{"k": 1}])"sv);
350   EXPECT_EQ(Status::ResourceExhausted(), array.status());
351 }
352 
TEST_F(JsonOverflowTest,ObjectNestedJsonOverflow)353 TEST_F(JsonOverflowTest, ObjectNestedJsonOverflow) {
354   JsonBuffer<32> inside_buffer;
355   JsonObject& inside = inside_buffer.StartObject();
356 
357   JsonBuilder outside_builder(buffer_, 20);
358   MarkBufferEnd(outside_builder);
359   JsonObject& outside = outside_builder.StartObject();
360 
361   ASSERT_EQ(OkStatus(), inside.Add("k", 78).status());
362   ASSERT_EQ(9u, inside.size());  // 9 bytes, will fit
363 
364   EXPECT_EQ(OkStatus(), outside.Add("data", inside).status());
365   EXPECT_STREQ(R"({"data": {"k": 78}})", outside.data());  // 20 bytes total
366 
367   inside.clear();
368   ASSERT_EQ(OkStatus(), inside.Add("k", 789).status());
369   ASSERT_EQ(10u, inside.size());  // 10 bytes, won't fit
370 
371   outside.clear();
372   EXPECT_EQ(Status::ResourceExhausted(), outside.Add("data", inside).status());
373   EXPECT_EQ(Status::ResourceExhausted(), outside.last_status());
374   EXPECT_EQ(Status::ResourceExhausted(), outside.status());
375   EXPECT_STREQ(R"({})", outside.data());
376 
377   inside.clear();
378   EXPECT_EQ(OkStatus(), outside.Add("data", inside).last_status());
379   EXPECT_EQ(OkStatus(), outside.last_status());
380   EXPECT_EQ(Status::ResourceExhausted(), outside.status());
381 }
382 
TEST(JsonValue,BasicValues)383 TEST(JsonValue, BasicValues) {
384   JsonBuffer<13> json;
385   EXPECT_EQ(OkStatus(), json.SetValue(-15));
386   EXPECT_STREQ("-15", json.data());
387   EXPECT_EQ(3u, json.size());
388 
389   EXPECT_EQ(OkStatus(), json.SetValue(0));
390   EXPECT_STREQ("0", json.data());
391   EXPECT_EQ(1u, json.size());
392 
393   EXPECT_EQ(OkStatus(), json.SetValue(static_cast<char>(35)));
394   EXPECT_STREQ("35", json.data());
395   EXPECT_EQ(2u, json.size());
396 
397   EXPECT_EQ(OkStatus(), json.SetValue(nullptr));
398   EXPECT_STREQ("null", json.data());
399   EXPECT_EQ(4u, json.size());
400 
401   EXPECT_EQ(OkStatus(), json.SetValue(static_cast<const char*>(nullptr)));
402   EXPECT_STREQ("null", json.data());
403   EXPECT_EQ(4u, json.size());
404 
405   EXPECT_EQ(OkStatus(), json.SetValue(""));
406   EXPECT_STREQ(R"("")", json.data());
407   EXPECT_EQ(2u, json.size());
408 
409   EXPECT_EQ(OkStatus(), json.SetValue("Hey\n!"));
410   EXPECT_STREQ(R"("Hey\n!")", json.data());
411   EXPECT_EQ(8u, json.size());
412 
413   JsonValue& json_value = json.StartValue();
414   EXPECT_STREQ("null", json_value.data());
415 
416   char str[] = R"(Qu"o"tes)";
417   EXPECT_EQ(OkStatus(), json_value.Set(str));
418   EXPECT_STREQ(R"("Qu\"o\"tes")", json_value.data());
419   EXPECT_EQ(12u, json_value.size());
420 
421   EXPECT_EQ(OkStatus(), json_value.Set(true));
422   EXPECT_STREQ("true", json_value.data());
423   EXPECT_EQ(4u, json_value.size());
424 
425   bool false_value = false;
426   EXPECT_EQ(OkStatus(), json.SetValue(false_value));
427   EXPECT_STREQ("false", json.data());
428   EXPECT_EQ(5u, json.size());
429 
430   EXPECT_EQ(OkStatus(), json_value.Set(static_cast<double>(1)));
431   EXPECT_EQ(json_value, "1"sv);
432   EXPECT_EQ(OkStatus(), json_value.Set(-1.0f));
433   EXPECT_EQ(json_value, "-1"sv);
434 }
435 
436 TEST_F(JsonOverflowTest, ValueOverflowUnquoted) {
437   JsonBuilder json(buffer_, 5);
438   MarkBufferEnd(json);
439   ASSERT_EQ(4u, json.max_size());
440 
441   EXPECT_EQ(Status::ResourceExhausted(), json.SetValue(12345));
442   EXPECT_STREQ("null", json.data());
443   EXPECT_EQ(4u, json.size());
444 
445   EXPECT_EQ(OkStatus(), json.SetValue(1234));
446   EXPECT_STREQ("1234", json.data());
447   EXPECT_EQ(4u, json.size());
448 
449   EXPECT_EQ(Status::ResourceExhausted(), json.SetValue(false));
450   EXPECT_STREQ("null", json.data());
451   EXPECT_EQ(4u, json.size());
452 
453   EXPECT_EQ(OkStatus(), json.SetValue(true));
454   EXPECT_STREQ("true", json.data());
455   EXPECT_EQ(4u, json.size());
456 }
457 
458 TEST_F(JsonOverflowTest, ValueOverflowQuoted) {
459   JsonBuilder json(buffer_, 8);
460   MarkBufferEnd(json);
461   ASSERT_EQ(7u, json.max_size());
462 
463   EXPECT_EQ(OkStatus(), json.SetValue("34567"));
464   EXPECT_STREQ(R"("34567")", json.data());
465   EXPECT_EQ(7u, json.size());
466 
467   EXPECT_EQ(Status::ResourceExhausted(), json.SetValue("345678"));
468   EXPECT_STREQ("null", json.data());
469   EXPECT_EQ(4u, json.size());
470 
471   EXPECT_EQ(OkStatus(), json.SetValue("567\n"));
472   EXPECT_STREQ(R"("567\n")", json.data());
473   EXPECT_EQ(7u, json.size());
474 
475   EXPECT_EQ(Status::ResourceExhausted(), json.SetValue("5678\n"));
476   EXPECT_STREQ("null", json.data());
477   EXPECT_EQ(4u, json.size());
478 
479   EXPECT_EQ(Status::ResourceExhausted(), json.SetValue("\x05"));
480   EXPECT_STREQ("null", json.data());
481   EXPECT_EQ(4u, json.size());
482 
483   JsonBuffer<9> bigger_json;
484   EXPECT_EQ(OkStatus(), bigger_json.SetValue("\x05"));
485   EXPECT_STREQ(R"("\u0005")", bigger_json.data());
486   EXPECT_EQ(8u, bigger_json.size());
487 }
488 
489 TEST(JsonValue, NestedJson) {
490   JsonBuffer<11> json;
491   JsonBuffer<12> object_buffer;
492   JsonObject& object = object_buffer.StartObject();
493 
494   ASSERT_EQ(OkStatus(), object.Add("3", 7890).status());
495   ASSERT_STREQ(R"({"3": 7890})", object.data());
496   ASSERT_EQ(json.max_size(), object.size());
497 
498   EXPECT_EQ(OkStatus(), json.SetValue(object));
499   EXPECT_STREQ(R"({"3": 7890})", json.data());
500   EXPECT_EQ(11u, json.size());
501 
502   object.clear();
503   ASSERT_EQ(OkStatus(), object.Add("3", 78901).status());
504   ASSERT_STREQ(R"({"3": 78901})", object.data());
505   ASSERT_EQ(object.max_size(), object.size());
506   ASSERT_GT(object.size(), json.size());
507 
508   EXPECT_EQ(Status::ResourceExhausted(), json.SetValue(object));
509   EXPECT_STREQ("null", json.data());
510   EXPECT_EQ(4u, json.size());
511 
512   JsonBuffer<12> value;
513   const char* something = nullptr;
514   EXPECT_EQ(OkStatus(), value.SetValue(something));
515 
516   EXPECT_EQ(OkStatus(), json.SetValue(value));
517   EXPECT_STREQ("null", json.data());
518   EXPECT_EQ(4u, json.size());
519 }
520 
521 TEST(JsonValue, SetFromOtherJsonValue) {
522   JsonBuffer<32> first = JsonBuffer<32>::Value("$$02$ok$$C");
523   constexpr const char kExpected[] = R"("$$02$ok$$C")";
524   ASSERT_STREQ(kExpected, first.data());
525   ASSERT_EQ(sizeof(kExpected) - 1, first.size());
526 
527   JsonBuffer<24> second;
528   EXPECT_EQ(OkStatus(), second.SetValue(first));
529   EXPECT_STREQ(kExpected, second.data());
530   EXPECT_EQ(sizeof(kExpected) - 1, second.size());
531 }
532 
533 TEST(JsonValue, ToJsonValue) {
534   static constexpr auto value = JsonBuffer<4>::Value(1234);
535 
536   EXPECT_STREQ("1234", value.data());
537   EXPECT_STREQ("\"1234\"", JsonBuffer<6>::Value("1234").data());
538   EXPECT_STREQ("null", JsonBuffer<4>::Value(nullptr).data());
539   EXPECT_STREQ("false", JsonBuffer<5>::Value(false).data());
540 
541 #if PW_NC_TEST(ValueDoesNotFit)
542   PW_NC_EXPECT("PW_ASSERT\(json.SetValue\(initial_value\).ok\(\)\)");
543   [[maybe_unused]] static constexpr auto fail = JsonBuffer<4>::Value(12345);
544 #endif  // PW_NC_TEST
545 }
546 
__anon1fb128a40502null547 static_assert([] {
548   JsonBuffer<32> buffer;
549   buffer.StartObject().Add("hello", "world").Add("ptr", nullptr);
550   return buffer;
551 }() == std::string_view(R"({"hello": "world", "ptr": null})"));
552 
TEST(JsonArray,BasicUse)553 TEST(JsonArray, BasicUse) {
554   JsonBuffer<48> list_buffer;
555   JsonArray& list = list_buffer.StartArray();
556   ASSERT_EQ(OkStatus(), list.Append(nullptr).last_status());
557   ASSERT_EQ(OkStatus(), list.Append("what").status());
558 
559   JsonBuffer<96> big_list_buffer;
560   JsonArray& big_list = big_list_buffer.StartArray();
561   EXPECT_EQ(OkStatus(), big_list.Append(list).status());
562   EXPECT_EQ(OkStatus(), big_list.Append(123).status());
563 
564   JsonBuffer<48> object_buffer;
565   JsonObject& object = object_buffer.StartObject();
566   ASSERT_EQ(OkStatus(), object.Add("foo", "bar").status());
567   ASSERT_EQ(OkStatus(), object.Add("bar", list).status());
568   EXPECT_EQ(OkStatus(), big_list.Append(object).status());
569 
570   EXPECT_EQ(OkStatus(), big_list.Append('\0').status());
571 
572   std::array<bool, 2> bools{true, false};
573   EXPECT_EQ(OkStatus(), big_list.Extend(bools).status());
574 
575   const char kExpected[] =
576       R"([[null, "what"], 123, {"foo": "bar", "bar": [null, "what"]}, )"
577       R"(0, true, false])";
578   EXPECT_STREQ(kExpected, big_list.data());
579   EXPECT_EQ(sizeof(kExpected) - 1, big_list.size());
580 }
581 
TEST(JsonArray,FromArray)582 TEST(JsonArray, FromArray) {
583   JsonBuffer<31> array_buffer;
584   JsonArray& array = array_buffer.StartArray();
585   EXPECT_EQ(OkStatus(), array.Extend({1, 2, 3, 4, 5}).status());
586   EXPECT_STREQ("[1, 2, 3, 4, 5]", array.data());
587   EXPECT_EQ(15u, array.size());
588 
589   EXPECT_EQ(OkStatus(), array.Extend({6, 7, 8, 9, 0}).status());
590   EXPECT_STREQ("[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]", array.data());
591   EXPECT_EQ(30u, array.size());
592 }
593 
TEST_F(JsonOverflowTest,FromArrayOverflow)594 TEST_F(JsonOverflowTest, FromArrayOverflow) {
595   JsonBuilder array_buffer(buffer_, 31);
596   MarkBufferEnd(array_buffer);
597   JsonArray& array = array_buffer.StartArray();
598 
599   EXPECT_EQ(OkStatus(), array.Extend({1, 2, 3, 4, 5}).status());
600   EXPECT_STREQ("[1, 2, 3, 4, 5]", array.data());
601   EXPECT_EQ(15u, array.size());
602 
603   EXPECT_EQ(Status::ResourceExhausted(),
604             array.Extend({6, 7, 8, 9, 0, 1, 2, 3}).status());
605   EXPECT_STREQ("[1, 2, 3, 4, 5]", array.data());
606   EXPECT_EQ(15u, array.size());
607 
608   EXPECT_EQ(Status::ResourceExhausted(),
609             array.Extend({6, 7, 8}).Extend({9, 0}).status());
610   EXPECT_STREQ("[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]", array.data());
611   EXPECT_EQ(30u, array.size());
612 
613   EXPECT_EQ(Status::ResourceExhausted(), array.Extend({5}).status());
614   EXPECT_STREQ("[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]", array.data());
615   EXPECT_EQ(30u, array.size());
616 }
617 
TEST(JsonArray,AppendIndividualExtendContainer)618 TEST(JsonArray, AppendIndividualExtendContainer) {
619   JsonBuffer<64> array_buffer;
620   JsonArray& array = array_buffer.StartArray();
621   constexpr int kInts[] = {1, 2, 3};
622 #if PW_NC_TEST(CannotAppendArrays)
623   PW_NC_EXPECT("JSON values may only be numbers, strings, JSON");
624   array.Append(kInts);
625 #endif  // PW_NC_TEST
626 
627   ASSERT_EQ(OkStatus(), array.Extend(kInts).status());
628   EXPECT_STREQ("[1, 2, 3]", array.data());
629 }
630 
TEST(JsonArray,NestingArray)631 TEST(JsonArray, NestingArray) {
632   JsonBuffer<64> array_buffer;
633   JsonArray& array = array_buffer.StartArray();
634   std::ignore = array.AppendNestedArray();
635 
636   EXPECT_STREQ(array.data(), "[[]]");
637 
638   NestedJsonArray nested = array.AppendNestedArray();
639   EXPECT_EQ(OkStatus(), array.last_status());
640   EXPECT_STREQ(array.data(), "[[], []]");
641 
642   nested.Append(123);
643   EXPECT_EQ(array.size(), sizeof("[[], [123]]") - 1);
644   EXPECT_STREQ(array.data(), "[[], [123]]");
645 
646   nested.Append("");
647   EXPECT_STREQ(array.data(), "[[], [123, \"\"]]");
648 }
649 
TEST(JsonArray,NestingObject)650 TEST(JsonArray, NestingObject) {
651   JsonBuffer<64> array_buffer;
652   JsonArray& array = array_buffer.StartArray();
653   NestedJsonObject object = array.AppendNestedObject();
654 
655   EXPECT_STREQ(array.data(), "[{}]");
656 
657   object.Add("key", 123);
658   EXPECT_EQ(array, R"([{"key": 123}])"sv);
659 
660   object.Add("k", true);
661   EXPECT_EQ(array, R"([{"key": 123, "k": true}])"sv);
662 
663   array.AppendNestedArray().Append("done").Append("!");
664   EXPECT_EQ(array, R"([{"key": 123, "k": true}, ["done", "!"]])"sv);
665 }
666 
TEST(JsonBuilder,DeepNesting)667 TEST(JsonBuilder, DeepNesting) {
668   JsonBuffer<64> buffer;
669   JsonArray& arr1 = buffer.StartArray();
670   std::ignore = arr1.AppendNestedObject();
671 
672   EXPECT_EQ(buffer, "[{}]"sv);
673 
674   auto arr2 = arr1.AppendNestedObject().Add("a", 1).AddNestedArray("b");
675   arr2.Append(0).Append(1).AppendNestedObject().Add("yes", "no");
676   arr2.Append(2);
677 
678   EXPECT_EQ(buffer, R"([{}, {"a": 1, "b": [0, 1, {"yes": "no"}, 2]}])"sv);
679 
680   arr1.Append(true);
681   EXPECT_EQ(buffer, R"([{}, {"a": 1, "b": [0, 1, {"yes": "no"}, 2]}, true])"sv);
682 }
683 
TEST(JsonBuilder,ConvertBetween)684 TEST(JsonBuilder, ConvertBetween) {
685   JsonBuffer<64> buffer;
686   EXPECT_STREQ("null", buffer.data());
687   EXPECT_TRUE(buffer.IsValue());
688   EXPECT_FALSE(buffer.IsObject());
689   EXPECT_FALSE(buffer.IsArray());
690 
691   JsonObject& object = buffer.StartObject();
692   EXPECT_STREQ("{}", buffer.data());
693   EXPECT_FALSE(object.IsValue());
694   EXPECT_FALSE(object.IsArray());
695   EXPECT_TRUE(object.IsObject());
696   object.Add("123", true);
697   EXPECT_STREQ(R"({"123": true})", buffer.data());
698 
699   JsonArray& array = buffer.StartArray();
700 
701   EXPECT_FALSE(object.IsObject()) << "No longer an object";
702   EXPECT_TRUE(object.ok()) << "Still OK, just not an object";
703   EXPECT_FALSE(array.IsValue());
704   EXPECT_TRUE(array.IsArray());
705   EXPECT_FALSE(array.IsObject());
706 
707   EXPECT_STREQ("[]", buffer.data());
708   EXPECT_EQ(OkStatus(), array.Extend({1, 2, 3}).status());
709   EXPECT_STREQ("[1, 2, 3]", buffer.data());
710 
711   EXPECT_EQ(OkStatus(), array.Append(false).Append(-1).status());
712   EXPECT_STREQ("[1, 2, 3, false, -1]", buffer.data());
713 
714   object.clear();
715   EXPECT_EQ(OkStatus(), object.Add("yes", nullptr).status());
716   EXPECT_STREQ(R"({"yes": null})", buffer.data());
717   EXPECT_EQ(OkStatus(), buffer.status());
718 }
719 
__anon1fb128a40602null720 static_assert([] {
721   JsonBuffer<64> buffer;
722   auto& object = buffer.StartObject();
723   auto nested_array = object.AddNestedArray("array");
724   nested_array.Append(1);
725   object.Add("key", "value");
726   if (buffer != R"({"array": [1], "key": "value"})"sv) {
727     return false;
728   }
729 
730 #if PW_NC_TEST(NestedJsonAttemptsToDetectWrongType)
731   PW_NC_EXPECT("PW_ASSERT\(.*// Nested structure must match the expected type");
732   nested_array.Append(2);
733 #elif PW_NC_TEST(NestedJsonDetectsClearedJson)
734   PW_NC_EXPECT("PW_ASSERT\(.*// JSON must not have been cleared since nesting");
735   object.clear();
736   nested_array.Append(2);
737 #endif  // PW_NC_TEST
738   return true;
739 }());
740 
__anon1fb128a40702null741 static_assert([] {
742   JsonBuffer<64> buffer;
743   auto& array = buffer.StartArray();
744 
745   NestedJsonArray nested = array.AppendNestedArray();
746   for (int i = 1; i < 16; ++i) {
747     nested = nested.AppendNestedArray();
748   }
749   // 17 arrays total (1 outer array, 16 levels of nesting inside it).
750   //              1234567890123456712345678901234567
751   if (array != R"([[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]])"sv) {
752     return JsonBuffer<64>{};
753   }
754   nested.Append("-_-");
755 
756 #if PW_NC_TEST(NestingLimit)
757   PW_NC_EXPECT(
758       "PW_ASSERT\(.*// Arrays or objects may be nested at most 17 times");
759   std::ignore = nested.AppendNestedArray();
760 #endif  // PW_NC_TEST
761   return buffer;
762 }() == R"([[[[[[[[[[[[[[[[["-_-"]]]]]]]]]]]]]]]]])"sv);
763 
TEST(JsonBuffer,SetClear)764 TEST(JsonBuffer, SetClear) {
765   JsonBuffer<4> buffer;
766   EXPECT_EQ(buffer, "null"sv);
767   ASSERT_EQ(OkStatus(), buffer.SetValue(""));
768   EXPECT_TRUE(buffer.ok());
769   EXPECT_EQ(buffer, "\"\""sv);
770 
771   ASSERT_EQ(Status::ResourceExhausted(), buffer.SetValue("234"));
772   EXPECT_FALSE(buffer.ok());
773   EXPECT_EQ(buffer, "null"sv);
774 
775   buffer.clear();
776   EXPECT_TRUE(buffer.ok());
777   EXPECT_EQ(buffer, "null"sv);
778 }
779 
TEST(JsonBuffer,Copy)780 TEST(JsonBuffer, Copy) {
781   JsonBuffer<64> foo;
782   ASSERT_EQ(OkStatus(), foo.SetValue("yes"));
783 
784   JsonBuffer<48> bar;
785   auto& object = bar.StartObject().Add("no", true);
786   EXPECT_EQ(object, R"({"no": true})"sv);
787   EXPECT_EQ(OkStatus(), bar.StartArray().Append(1).Append(2).status());
788 
789   foo = bar;
790   EXPECT_STREQ("[1, 2]", foo.data());
791   EXPECT_EQ(6u, foo.size());
792 
793   JsonBuffer<128> baz(foo);
794   EXPECT_STREQ(foo.data(), baz.data());
795 }
796 
797 // Tests character escaping using a table generated with the following Python:
798 //
799 // import json
800 // print(', '.join('R"_({})_"'.format(json.dumps(chr(i))) for i in range(128)))
TEST(JsonBuilder,TestEscape)801 TEST(JsonBuilder, TestEscape) {
802   static constexpr std::array<const char*, 128> kEscapedCharacters = {
803       R"_("\u0000")_", R"_("\u0001")_", R"_("\u0002")_", R"_("\u0003")_",
804       R"_("\u0004")_", R"_("\u0005")_", R"_("\u0006")_", R"_("\u0007")_",
805       R"_("\b")_",     R"_("\t")_",     R"_("\n")_",     R"_("\u000b")_",
806       R"_("\f")_",     R"_("\r")_",     R"_("\u000e")_", R"_("\u000f")_",
807       R"_("\u0010")_", R"_("\u0011")_", R"_("\u0012")_", R"_("\u0013")_",
808       R"_("\u0014")_", R"_("\u0015")_", R"_("\u0016")_", R"_("\u0017")_",
809       R"_("\u0018")_", R"_("\u0019")_", R"_("\u001a")_", R"_("\u001b")_",
810       R"_("\u001c")_", R"_("\u001d")_", R"_("\u001e")_", R"_("\u001f")_",
811       R"_(" ")_",      R"_("!")_",      R"_("\"")_",     R"_("#")_",
812       R"_("$")_",      R"_("%")_",      R"_("&")_",      R"_("'")_",
813       R"_("(")_",      R"_(")")_",      R"_("*")_",      R"_("+")_",
814       R"_(",")_",      R"_("-")_",      R"_(".")_",      R"_("/")_",
815       R"_("0")_",      R"_("1")_",      R"_("2")_",      R"_("3")_",
816       R"_("4")_",      R"_("5")_",      R"_("6")_",      R"_("7")_",
817       R"_("8")_",      R"_("9")_",      R"_(":")_",      R"_(";")_",
818       R"_("<")_",      R"_("=")_",      R"_(">")_",      R"_("?")_",
819       R"_("@")_",      R"_("A")_",      R"_("B")_",      R"_("C")_",
820       R"_("D")_",      R"_("E")_",      R"_("F")_",      R"_("G")_",
821       R"_("H")_",      R"_("I")_",      R"_("J")_",      R"_("K")_",
822       R"_("L")_",      R"_("M")_",      R"_("N")_",      R"_("O")_",
823       R"_("P")_",      R"_("Q")_",      R"_("R")_",      R"_("S")_",
824       R"_("T")_",      R"_("U")_",      R"_("V")_",      R"_("W")_",
825       R"_("X")_",      R"_("Y")_",      R"_("Z")_",      R"_("[")_",
826       R"_("\\")_",     R"_("]")_",      R"_("^")_",      R"_("_")_",
827       R"_("`")_",      R"_("a")_",      R"_("b")_",      R"_("c")_",
828       R"_("d")_",      R"_("e")_",      R"_("f")_",      R"_("g")_",
829       R"_("h")_",      R"_("i")_",      R"_("j")_",      R"_("k")_",
830       R"_("l")_",      R"_("m")_",      R"_("n")_",      R"_("o")_",
831       R"_("p")_",      R"_("q")_",      R"_("r")_",      R"_("s")_",
832       R"_("t")_",      R"_("u")_",      R"_("v")_",      R"_("w")_",
833       R"_("x")_",      R"_("y")_",      R"_("z")_",      R"_("{")_",
834       R"_("|")_",      R"_("}")_",      R"_("~")_",      R"_("\u007f")_"};
835 
836   JsonBuffer<9> buffer;
837 
838   for (size_t i = 0; i < kEscapedCharacters.size(); ++i) {
839     const char character = static_cast<char>(i);
840     ASSERT_EQ(OkStatus(), buffer.SetValue(std::string_view(&character, 1)));
841     ASSERT_STREQ(kEscapedCharacters[i], buffer.data());
842   }
843 }
844 
845 class JsonObjectTest : public ::testing::Test {
846  protected:
847   static constexpr size_t kMaxSize = 127;
848   static constexpr size_t kBufferSize = kMaxSize + 1;
849 
850   JsonObjectTest() : object_(json_buffer_.StartObject()) {}
851 
852   JsonBuffer<kMaxSize> json_buffer_;
853   JsonObject& object_;
854 };
855 
856 TEST_F(JsonObjectTest, TestSingleStringValue) {
857   EXPECT_EQ(OkStatus(), object_.Add("key", "value").status());
858   EXPECT_STREQ("{\"key\": \"value\"}", object_.data());
859 }
860 
861 TEST_F(JsonObjectTest, TestEscapedQuoteString) {
862   const char* buf = "{\"key\": \"\\\"value\\\"\"}";
863   EXPECT_STREQ(buf, object_.Add("key", "\"value\"").data());
864 }
865 
866 TEST_F(JsonObjectTest, TestEscapedSlashString) {
867   const char* buf = "{\"key\": \"\\\\\"}";
868   EXPECT_STREQ(buf, object_.Add("key", "\\").data());
869 }
870 
871 TEST_F(JsonObjectTest, TestEscapedCharactersString) {
872   const char* buf = "{\"key\": \"\\r\\n\\t\"}";
873   EXPECT_STREQ(buf, object_.Add("key", "\r\n\t").data());
874 }
875 
876 TEST_F(JsonObjectTest, TestEscapedControlCharacterString) {
877   EXPECT_STREQ("{\"key\": \"\\u001f\"}", object_.Add("key", "\x1F").data());
878   object_.clear();
879   EXPECT_STREQ("{\"key\": \"\\u0080\"}", object_.Add("key", "\x80").data());
880 }
881 
882 TEST_F(JsonObjectTest, TestNullptrString) {
883   EXPECT_STREQ("{\"key\": null}",
884                object_.Add("key", static_cast<const char*>(nullptr)).data());
885 }
886 
887 TEST_F(JsonObjectTest, TestCharValue) {
888   EXPECT_STREQ("{\"key\": 88}",
889                object_.Add("key", static_cast<unsigned char>('X')).data());
890   object_.clear();
891   EXPECT_STREQ("{\"key\": 88}", object_.Add("key", 'X').data());
892 }
893 
894 TEST_F(JsonObjectTest, TestShortValue) {
895   EXPECT_STREQ("{\"key\": 88}",
896                object_.Add("key", static_cast<unsigned short>(88)).data());
897   object_.clear();
898   EXPECT_STREQ("{\"key\": -88}",
899                object_.Add("key", static_cast<short>(-88)).data());
900 }
901 
902 TEST_F(JsonObjectTest, TestIntValue) {
903   EXPECT_STREQ("{\"key\": 88}",
904                object_.Add("key", static_cast<unsigned int>(88)).data());
905   object_.clear();
906   EXPECT_STREQ("{\"key\": -88}", object_.Add("key", -88).data());
907 }
908 
909 TEST_F(JsonObjectTest, TestLongValue) {
910   EXPECT_STREQ("{\"key\": 88}", object_.Add("key", 88UL).data());
911   object_.clear();
912   EXPECT_STREQ("{\"key\": -88}", object_.Add("key", -88L).data());
913 }
914 
915 TEST_F(JsonObjectTest, TestMultipleValues) {
916   char buf[16] = "nonconst";
917   EXPECT_STREQ("{\"one\": \"nonconst\", \"two\": null, \"three\": -3}",
918                object_.Add("one", buf)
919                    .Add("two", static_cast<char*>(nullptr))
920                    .Add("three", -3)
921                    .data());
922 }
923 
924 TEST_F(JsonObjectTest, TestOverflow) {
925   // Create a buffer that is just large enough to overflow with "key".
926   std::array<char, kBufferSize + 1 /* NUL */ - (sizeof("{\"key\": \"\"}") - 1)>
927       buf;
928   std::memset(buf.data(), 'z', sizeof(buf));
929   buf[sizeof(buf) - 1] = '\0';
930 
931   // Make sure the overflow happens at exactly the right character.
932   EXPECT_EQ(Status::ResourceExhausted(),
933             object_.Add("key", buf.data()).status());
934   EXPECT_EQ(Status::ResourceExhausted(), object_.status());
935 
936   object_.clear();
937   EXPECT_EQ(OkStatus(), object_.Add("ke", buf.data()).status());
938   EXPECT_EQ(OkStatus(), object_.status());
939 
940   // Ensure the internal buffer is NUL-terminated still, even on overflow.
941   EXPECT_EQ(object_.data()[object_.size()], '\0');
942 }
943 
944 }  // namespace
945 }  // namespace pw
946