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