blob: af49977382273c4d0e614aca37ffb23041cc783d [file] [log] [blame]
Shawn McCarney38f85002025-10-31 17:59:36 -05001/**
2 * Copyright © 2025 IBM Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16#include "json_parser_utils.hpp"
17
18#include <nlohmann/json.hpp>
19
20#include <cstdint>
21#include <exception>
22#include <stdexcept>
23#include <string>
24#include <vector>
25
26#include <gtest/gtest.h>
27
28using namespace phosphor::power::json_parser_utils;
Shawn McCarneyf1845c02025-11-04 17:06:19 -060029using namespace phosphor::power::json_parser_utils::internal;
Shawn McCarney38f85002025-10-31 17:59:36 -050030using json = nlohmann::json;
31
32TEST(JSONParserUtilsTests, GetRequiredProperty)
33{
34 // Test where property exists
35 {
36 const json element = R"( { "format": "linear" } )"_json;
37 const json& propertyElement = getRequiredProperty(element, "format");
38 EXPECT_EQ(propertyElement.get<std::string>(), "linear");
39 }
40
41 // Test where property does not exist
42 try
43 {
44 const json element = R"( { "volts": 1.03 } )"_json;
45 getRequiredProperty(element, "format");
46 ADD_FAILURE() << "Should not have reached this line.";
47 }
48 catch (const std::invalid_argument& e)
49 {
50 EXPECT_STREQ(e.what(), "Required property missing: format");
51 }
52}
53
54TEST(JSONParserUtilsTests, ParseBitPosition)
55{
56 // Test where works: 0
57 {
58 const json element = R"( 0 )"_json;
59 uint8_t value = parseBitPosition(element);
60 EXPECT_EQ(value, 0);
61 }
62
63 // Test where works: 7
64 {
65 const json element = R"( 7 )"_json;
66 uint8_t value = parseBitPosition(element);
67 EXPECT_EQ(value, 7);
68 }
69
Shawn McCarneyf1845c02025-11-04 17:06:19 -060070 // Test where works: Variable specified
71 {
72 std::map<std::string, std::string> variables{{"bit_pos", "3"}};
73 const json element = R"( "${bit_pos}" )"_json;
74 uint8_t value = parseBitPosition(element, variables);
75 EXPECT_EQ(value, 3);
76 }
77
Shawn McCarney38f85002025-10-31 17:59:36 -050078 // Test where fails: Element is not an integer
79 try
80 {
81 const json element = R"( 1.03 )"_json;
82 parseBitPosition(element);
83 ADD_FAILURE() << "Should not have reached this line.";
84 }
85 catch (const std::invalid_argument& e)
86 {
87 EXPECT_STREQ(e.what(), "Element is not an integer");
88 }
89
90 // Test where fails: Value < 0
91 try
92 {
93 const json element = R"( -1 )"_json;
94 parseBitPosition(element);
95 ADD_FAILURE() << "Should not have reached this line.";
96 }
97 catch (const std::invalid_argument& e)
98 {
99 EXPECT_STREQ(e.what(), "Element is not a bit position");
100 }
101
102 // Test where fails: Value > 7
103 try
104 {
105 const json element = R"( 8 )"_json;
106 parseBitPosition(element);
107 ADD_FAILURE() << "Should not have reached this line.";
108 }
109 catch (const std::invalid_argument& e)
110 {
111 EXPECT_STREQ(e.what(), "Element is not a bit position");
112 }
Shawn McCarneyf1845c02025-11-04 17:06:19 -0600113
114 // Test where fails: Variable specified: Value < 0
115 try
116 {
117 std::map<std::string, std::string> variables{{"bit_pos", "-1"}};
118 const json element = R"( "${bit_pos}" )"_json;
119 parseBitPosition(element, variables);
120 ADD_FAILURE() << "Should not have reached this line.";
121 }
122 catch (const std::invalid_argument& e)
123 {
124 EXPECT_STREQ(e.what(), "Element is not a bit position");
125 }
Shawn McCarney38f85002025-10-31 17:59:36 -0500126}
127
128TEST(JSONParserUtilsTests, ParseBitValue)
129{
130 // Test where works: 0
131 {
132 const json element = R"( 0 )"_json;
133 uint8_t value = parseBitValue(element);
134 EXPECT_EQ(value, 0);
135 }
136
137 // Test where works: 1
138 {
139 const json element = R"( 1 )"_json;
140 uint8_t value = parseBitValue(element);
141 EXPECT_EQ(value, 1);
142 }
143
Shawn McCarneyf1845c02025-11-04 17:06:19 -0600144 // Test where works: Variable specified
145 {
146 std::map<std::string, std::string> variables{{"bit_val", "1"}};
147 const json element = R"( "${bit_val}" )"_json;
148 uint8_t value = parseBitValue(element, variables);
149 EXPECT_EQ(value, 1);
150 }
151
Shawn McCarney38f85002025-10-31 17:59:36 -0500152 // Test where fails: Element is not an integer
153 try
154 {
155 const json element = R"( 0.5 )"_json;
156 parseBitValue(element);
157 ADD_FAILURE() << "Should not have reached this line.";
158 }
159 catch (const std::invalid_argument& e)
160 {
161 EXPECT_STREQ(e.what(), "Element is not an integer");
162 }
163
164 // Test where fails: Value < 0
165 try
166 {
167 const json element = R"( -1 )"_json;
168 parseBitValue(element);
169 ADD_FAILURE() << "Should not have reached this line.";
170 }
171 catch (const std::invalid_argument& e)
172 {
173 EXPECT_STREQ(e.what(), "Element is not a bit value");
174 }
175
176 // Test where fails: Value > 1
177 try
178 {
179 const json element = R"( 2 )"_json;
180 parseBitValue(element);
181 ADD_FAILURE() << "Should not have reached this line.";
182 }
183 catch (const std::invalid_argument& e)
184 {
185 EXPECT_STREQ(e.what(), "Element is not a bit value");
186 }
Shawn McCarneyf1845c02025-11-04 17:06:19 -0600187
188 // Test where fails: Variable specified: Not an integer
189 try
190 {
191 std::map<std::string, std::string> variables{{"bit_val", "one"}};
192 const json element = R"( "${bit_val}" )"_json;
193 parseBitValue(element, variables);
194 ADD_FAILURE() << "Should not have reached this line.";
195 }
196 catch (const std::invalid_argument& e)
197 {
198 EXPECT_STREQ(e.what(), "Element is not an integer");
199 }
Shawn McCarney38f85002025-10-31 17:59:36 -0500200}
201
202TEST(JSONParserUtilsTests, ParseBoolean)
203{
204 // Test where works: true
205 {
206 const json element = R"( true )"_json;
207 bool value = parseBoolean(element);
208 EXPECT_EQ(value, true);
209 }
210
211 // Test where works: false
212 {
213 const json element = R"( false )"_json;
214 bool value = parseBoolean(element);
215 EXPECT_EQ(value, false);
216 }
217
Shawn McCarneyf1845c02025-11-04 17:06:19 -0600218 // Test where works: Variable specified: true
219 {
220 std::map<std::string, std::string> variables{{"bool_val", "true"}};
221 const json element = R"( "${bool_val}" )"_json;
222 bool value = parseBoolean(element, variables);
223 EXPECT_EQ(value, true);
224 }
225
226 // Test where works: Variable specified: false
227 {
228 std::map<std::string, std::string> variables{{"bool_val", "false"}};
229 const json element = R"( "${bool_val}" )"_json;
230 bool value = parseBoolean(element, variables);
231 EXPECT_EQ(value, false);
232 }
233
Shawn McCarney38f85002025-10-31 17:59:36 -0500234 // Test where fails: Element is not a boolean
235 try
236 {
237 const json element = R"( 1 )"_json;
238 parseBoolean(element);
239 ADD_FAILURE() << "Should not have reached this line.";
240 }
241 catch (const std::invalid_argument& e)
242 {
243 EXPECT_STREQ(e.what(), "Element is not a boolean");
244 }
Shawn McCarneyf1845c02025-11-04 17:06:19 -0600245
246 // Test where fails: Variable specified: Variables map not specified
247 try
248 {
249 const json element = R"( "${bool_val}" )"_json;
250 parseBoolean(element);
251 ADD_FAILURE() << "Should not have reached this line.";
252 }
253 catch (const std::invalid_argument& e)
254 {
255 EXPECT_STREQ(e.what(), "Element is not a boolean");
256 }
257
258 // Test where fails: Variable specified: Value is not a boolean
259 try
260 {
261 std::map<std::string, std::string> variables{{"bool_val", "3.2"}};
262 const json element = R"( "${bool_val}" )"_json;
263 parseBoolean(element, variables);
264 ADD_FAILURE() << "Should not have reached this line.";
265 }
266 catch (const std::invalid_argument& e)
267 {
268 EXPECT_STREQ(e.what(), "Element is not a boolean");
269 }
Shawn McCarney38f85002025-10-31 17:59:36 -0500270}
271
272TEST(JSONParserUtilsTests, ParseDouble)
273{
Shawn McCarneyf1845c02025-11-04 17:06:19 -0600274 // Test where works: Floating point value
Shawn McCarney38f85002025-10-31 17:59:36 -0500275 {
276 const json element = R"( 1.03 )"_json;
277 double value = parseDouble(element);
278 EXPECT_EQ(value, 1.03);
279 }
280
Shawn McCarneyf1845c02025-11-04 17:06:19 -0600281 // Test where works: Integer value
Shawn McCarney38f85002025-10-31 17:59:36 -0500282 {
Shawn McCarneyf1845c02025-11-04 17:06:19 -0600283 const json element = R"( -24 )"_json;
Shawn McCarney38f85002025-10-31 17:59:36 -0500284 double value = parseDouble(element);
Shawn McCarneyf1845c02025-11-04 17:06:19 -0600285 EXPECT_EQ(value, -24.0);
286 }
287
288 // Test where works: Variable specified: Floating point value
289 {
290 std::map<std::string, std::string> variables{{"var", "-1.03"}};
291 const json element = R"( "${var}" )"_json;
292 double value = parseDouble(element, variables);
293 EXPECT_EQ(value, -1.03);
294 }
295
296 // Test where works: Variable specified: Integer value
297 {
298 std::map<std::string, std::string> variables{{"var", "24"}};
299 const json element = R"( "${var}" )"_json;
300 double value = parseDouble(element, variables);
Shawn McCarney38f85002025-10-31 17:59:36 -0500301 EXPECT_EQ(value, 24.0);
302 }
303
Shawn McCarneyf1845c02025-11-04 17:06:19 -0600304 // Test where fails: Element is not a double
Shawn McCarney38f85002025-10-31 17:59:36 -0500305 try
306 {
307 const json element = R"( true )"_json;
308 parseDouble(element);
309 ADD_FAILURE() << "Should not have reached this line.";
310 }
311 catch (const std::invalid_argument& e)
312 {
Shawn McCarneyf1845c02025-11-04 17:06:19 -0600313 EXPECT_STREQ(e.what(), "Element is not a double");
314 }
315
316 // Test where fails: Variable specified: Variables map not specified
317 try
318 {
319 const json element = R"( "${var}" )"_json;
320 parseDouble(element);
321 ADD_FAILURE() << "Should not have reached this line.";
322 }
323 catch (const std::invalid_argument& e)
324 {
325 EXPECT_STREQ(e.what(), "Element is not a double");
326 }
327
328 // Test where fails: Variable specified: Leading whitespace
329 try
330 {
331 std::map<std::string, std::string> variables{{"var", " -1.03"}};
332 const json element = R"( "${var}" )"_json;
333 parseDouble(element, variables);
334 ADD_FAILURE() << "Should not have reached this line.";
335 }
336 catch (const std::invalid_argument& e)
337 {
338 EXPECT_STREQ(e.what(), "Element is not a double");
339 }
340
341 // Test where fails: Variable specified: Trailing whitespace
342 try
343 {
344 std::map<std::string, std::string> variables{{"var", "-1.03 "}};
345 const json element = R"( "${var}" )"_json;
346 parseDouble(element, variables);
347 ADD_FAILURE() << "Should not have reached this line.";
348 }
349 catch (const std::invalid_argument& e)
350 {
351 EXPECT_STREQ(e.what(), "Element is not a double");
352 }
353
354 // Test where fails: Variable specified: Starts with non-number character
355 try
356 {
357 std::map<std::string, std::string> variables{{"var", "x-1.03"}};
358 const json element = R"( "${var}" )"_json;
359 parseDouble(element, variables);
360 ADD_FAILURE() << "Should not have reached this line.";
361 }
362 catch (const std::invalid_argument& e)
363 {
364 EXPECT_STREQ(e.what(), "Element is not a double");
365 }
366
367 // Test where fails: Variable specified: Ends with non-number character
368 try
369 {
370 std::map<std::string, std::string> variables{{"var", "-1.03x"}};
371 const json element = R"( "${var}" )"_json;
372 parseDouble(element, variables);
373 ADD_FAILURE() << "Should not have reached this line.";
374 }
375 catch (const std::invalid_argument& e)
376 {
377 EXPECT_STREQ(e.what(), "Element is not a double");
378 }
379
380 // Test where fails: Variable specified: Not a double
381 try
382 {
383 std::map<std::string, std::string> variables{{"var", "foo"}};
384 const json element = R"( "${var}" )"_json;
385 parseDouble(element, variables);
386 ADD_FAILURE() << "Should not have reached this line.";
387 }
388 catch (const std::invalid_argument& e)
389 {
390 EXPECT_STREQ(e.what(), "Element is not a double");
Shawn McCarney38f85002025-10-31 17:59:36 -0500391 }
392}
393
394TEST(JSONParserUtilsTests, ParseHexByte)
395{
396 // Test where works: "0xFF"
397 {
398 const json element = R"( "0xFF" )"_json;
399 uint8_t value = parseHexByte(element);
400 EXPECT_EQ(value, 0xFF);
401 }
402
403 // Test where works: "0xff"
404 {
405 const json element = R"( "0xff" )"_json;
406 uint8_t value = parseHexByte(element);
407 EXPECT_EQ(value, 0xff);
408 }
409
410 // Test where works: "0xf"
411 {
412 const json element = R"( "0xf" )"_json;
413 uint8_t value = parseHexByte(element);
414 EXPECT_EQ(value, 0xf);
415 }
416
Shawn McCarneyf1845c02025-11-04 17:06:19 -0600417 // Test where works: Variable specified
418 {
419 std::map<std::string, std::string> variables{{"var", "ed"}};
420 const json element = R"( "0x${var}" )"_json;
421 uint8_t value = parseHexByte(element, variables);
422 EXPECT_EQ(value, 0xed);
423 }
424
Shawn McCarney38f85002025-10-31 17:59:36 -0500425 // Test where fails: "0xfff"
426 try
427 {
428 const json element = R"( "0xfff" )"_json;
429 parseHexByte(element);
430 ADD_FAILURE() << "Should not have reached this line.";
431 }
432 catch (const std::invalid_argument& e)
433 {
434 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
435 }
436
437 // Test where fails: "0xAG"
438 try
439 {
440 const json element = R"( "0xAG" )"_json;
441 parseHexByte(element);
442 ADD_FAILURE() << "Should not have reached this line.";
443 }
444 catch (const std::invalid_argument& e)
445 {
446 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
447 }
448
449 // Test where fails: "ff"
450 try
451 {
452 const json element = R"( "ff" )"_json;
453 parseHexByte(element);
454 ADD_FAILURE() << "Should not have reached this line.";
455 }
456 catch (const std::invalid_argument& e)
457 {
458 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
459 }
460
461 // Test where fails: ""
462 try
463 {
464 const json element = "";
465 parseHexByte(element);
466 ADD_FAILURE() << "Should not have reached this line.";
467 }
468 catch (const std::invalid_argument& e)
469 {
470 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
471 }
472
473 // Test where fails: "f"
474 try
475 {
476 const json element = R"( "f" )"_json;
477 parseHexByte(element);
478 ADD_FAILURE() << "Should not have reached this line.";
479 }
480 catch (const std::invalid_argument& e)
481 {
482 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
483 }
484
485 // Test where fails: "0x"
486 try
487 {
488 const json element = R"( "0x" )"_json;
489 parseHexByte(element);
490 ADD_FAILURE() << "Should not have reached this line.";
491 }
492 catch (const std::invalid_argument& e)
493 {
494 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
495 }
496
497 // Test where fails: "0Xff"
498 try
499 {
500 const json element = R"( "0XFF" )"_json;
501 parseHexByte(element);
502 ADD_FAILURE() << "Should not have reached this line.";
503 }
504 catch (const std::invalid_argument& e)
505 {
506 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
507 }
Shawn McCarneyf1845c02025-11-04 17:06:19 -0600508
509 // Test where fails: Variable specified: Not a hex string
510 try
511 {
512 std::map<std::string, std::string> variables{{"var", "0xsz"}};
513 const json element = R"( "${var}" )"_json;
514 parseHexByte(element, variables);
515 ADD_FAILURE() << "Should not have reached this line.";
516 }
517 catch (const std::invalid_argument& e)
518 {
519 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
520 }
Shawn McCarney38f85002025-10-31 17:59:36 -0500521}
522
523TEST(JSONParserUtilsTests, ParseHexByteArray)
524{
525 // Test where works
526 {
527 const json element = R"( [ "0xCC", "0xFF" ] )"_json;
528 std::vector<uint8_t> hexBytes = parseHexByteArray(element);
529 std::vector<uint8_t> expected = {0xcc, 0xff};
530 EXPECT_EQ(hexBytes, expected);
531 }
532
Shawn McCarneyf1845c02025-11-04 17:06:19 -0600533 // Test where works: Variables specified
534 {
535 std::map<std::string, std::string> variables{{"var1", "0xCC"},
536 {"var2", "0xFF"}};
537 const json element = R"( [ "${var1}", "${var2}" ] )"_json;
538 std::vector<uint8_t> hexBytes = parseHexByteArray(element, variables);
539 std::vector<uint8_t> expected = {0xcc, 0xff};
540 EXPECT_EQ(hexBytes, expected);
541 }
542
Shawn McCarney38f85002025-10-31 17:59:36 -0500543 // Test where fails: Element is not an array
544 try
545 {
546 const json element = 0;
547 parseHexByteArray(element);
548 ADD_FAILURE() << "Should not have reached this line.";
549 }
550 catch (const std::invalid_argument& e)
551 {
552 EXPECT_STREQ(e.what(), "Element is not an array");
553 }
Shawn McCarneyf1845c02025-11-04 17:06:19 -0600554
555 // Test where fails: Variables specified: Invalid byte value
556 try
557 {
558 std::map<std::string, std::string> variables{{"var1", "0xCC"},
559 {"var2", "99"}};
560 const json element = R"( [ "${var1}", "${var2}" ] )"_json;
561 parseHexByteArray(element, variables);
562 ADD_FAILURE() << "Should not have reached this line.";
563 }
564 catch (const std::invalid_argument& e)
565 {
566 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
567 }
Shawn McCarney38f85002025-10-31 17:59:36 -0500568}
569
570TEST(JSONParserUtilsTests, ParseInt8)
571{
572 // Test where works: INT8_MIN
573 {
574 const json element = R"( -128 )"_json;
575 int8_t value = parseInt8(element);
576 EXPECT_EQ(value, -128);
577 }
578
579 // Test where works: INT8_MAX
580 {
581 const json element = R"( 127 )"_json;
582 int8_t value = parseInt8(element);
583 EXPECT_EQ(value, 127);
584 }
585
Shawn McCarneyf1845c02025-11-04 17:06:19 -0600586 // Test where works: Variable specified
587 {
588 std::map<std::string, std::string> variables{{"var", "-23"}};
589 const json element = R"( "${var}" )"_json;
590 int8_t value = parseInt8(element, variables);
591 EXPECT_EQ(value, -23);
592 }
593
Shawn McCarney38f85002025-10-31 17:59:36 -0500594 // Test where fails: Element is not an integer
595 try
596 {
597 const json element = R"( 1.03 )"_json;
598 parseInt8(element);
599 ADD_FAILURE() << "Should not have reached this line.";
600 }
601 catch (const std::invalid_argument& e)
602 {
603 EXPECT_STREQ(e.what(), "Element is not an integer");
604 }
605
606 // Test where fails: Value < INT8_MIN
607 try
608 {
609 const json element = R"( -129 )"_json;
610 parseInt8(element);
611 ADD_FAILURE() << "Should not have reached this line.";
612 }
613 catch (const std::invalid_argument& e)
614 {
615 EXPECT_STREQ(e.what(), "Element is not an 8-bit signed integer");
616 }
617
618 // Test where fails: Value > INT8_MAX
619 try
620 {
621 const json element = R"( 128 )"_json;
622 parseInt8(element);
623 ADD_FAILURE() << "Should not have reached this line.";
624 }
625 catch (const std::invalid_argument& e)
626 {
627 EXPECT_STREQ(e.what(), "Element is not an 8-bit signed integer");
628 }
Shawn McCarneyf1845c02025-11-04 17:06:19 -0600629
630 // Test where fails: Variable specified: Value > INT8_MAX
631 try
632 {
633 std::map<std::string, std::string> variables{{"var", "128"}};
634 const json element = R"( "${var}" )"_json;
635 parseInt8(element, variables);
636 ADD_FAILURE() << "Should not have reached this line.";
637 }
638 catch (const std::invalid_argument& e)
639 {
640 EXPECT_STREQ(e.what(), "Element is not an 8-bit signed integer");
641 }
642}
643
644TEST(JSONParserUtilsTests, ParseInteger)
645{
646 // Test where works: Zero
647 {
648 const json element = R"( 0 )"_json;
649 int value = parseInteger(element);
650 EXPECT_EQ(value, 0);
651 }
652
653 // Test where works: Positive value
654 {
655 const json element = R"( 103 )"_json;
656 int value = parseInteger(element);
657 EXPECT_EQ(value, 103);
658 }
659
660 // Test where works: Negative value
661 {
662 const json element = R"( -24 )"_json;
663 int value = parseInteger(element);
664 EXPECT_EQ(value, -24);
665 }
666
667 // Test where works: Variable specified: Positive value
668 {
669 std::map<std::string, std::string> variables{{"var", "1024"}};
670 const json element = R"( "${var}" )"_json;
671 int value = parseInteger(element, variables);
672 EXPECT_EQ(value, 1024);
673 }
674
675 // Test where works: Variable specified: Negative value
676 {
677 std::map<std::string, std::string> variables{{"var", "-9924"}};
678 const json element = R"( "${var}" )"_json;
679 int value = parseInteger(element, variables);
680 EXPECT_EQ(value, -9924);
681 }
682
683 // Test where fails: Element is not a integer
684 try
685 {
686 const json element = R"( true )"_json;
687 parseInteger(element);
688 ADD_FAILURE() << "Should not have reached this line.";
689 }
690 catch (const std::invalid_argument& e)
691 {
692 EXPECT_STREQ(e.what(), "Element is not an integer");
693 }
694
695 // Test where fails: Variable specified: Variables map not specified
696 try
697 {
698 const json element = R"( "${var}" )"_json;
699 parseInteger(element);
700 ADD_FAILURE() << "Should not have reached this line.";
701 }
702 catch (const std::invalid_argument& e)
703 {
704 EXPECT_STREQ(e.what(), "Element is not an integer");
705 }
706
707 // Test where fails: Variable specified: Leading whitespace
708 try
709 {
710 std::map<std::string, std::string> variables{{"var", " -13"}};
711 const json element = R"( "${var}" )"_json;
712 parseInteger(element, variables);
713 ADD_FAILURE() << "Should not have reached this line.";
714 }
715 catch (const std::invalid_argument& e)
716 {
717 EXPECT_STREQ(e.what(), "Element is not an integer");
718 }
719
720 // Test where fails: Variable specified: Trailing whitespace
721 try
722 {
723 std::map<std::string, std::string> variables{{"var", "-13 "}};
724 const json element = R"( "${var}" )"_json;
725 parseInteger(element, variables);
726 ADD_FAILURE() << "Should not have reached this line.";
727 }
728 catch (const std::invalid_argument& e)
729 {
730 EXPECT_STREQ(e.what(), "Element is not an integer");
731 }
732
733 // Test where fails: Variable specified: Starts with non-number character
734 try
735 {
736 std::map<std::string, std::string> variables{{"var", "x-13"}};
737 const json element = R"( "${var}" )"_json;
738 parseInteger(element, variables);
739 ADD_FAILURE() << "Should not have reached this line.";
740 }
741 catch (const std::invalid_argument& e)
742 {
743 EXPECT_STREQ(e.what(), "Element is not an integer");
744 }
745
746 // Test where fails: Variable specified: Ends with non-number character
747 try
748 {
749 std::map<std::string, std::string> variables{{"var", "-13x"}};
750 const json element = R"( "${var}" )"_json;
751 parseInteger(element, variables);
752 ADD_FAILURE() << "Should not have reached this line.";
753 }
754 catch (const std::invalid_argument& e)
755 {
756 EXPECT_STREQ(e.what(), "Element is not an integer");
757 }
758
759 // Test where fails: Variable specified: Not an integer
760 try
761 {
762 std::map<std::string, std::string> variables{{"var", "foo"}};
763 const json element = R"( "${var}" )"_json;
764 parseInteger(element, variables);
765 ADD_FAILURE() << "Should not have reached this line.";
766 }
767 catch (const std::invalid_argument& e)
768 {
769 EXPECT_STREQ(e.what(), "Element is not an integer");
770 }
Shawn McCarney38f85002025-10-31 17:59:36 -0500771}
772
773TEST(JSONParserUtilsTests, ParseString)
774{
775 // Test where works: Empty string
776 {
777 const json element = "";
778 std::string value = parseString(element, true);
779 EXPECT_EQ(value, "");
780 }
781
782 // Test where works: Non-empty string
783 {
784 const json element = "vdd_regulator";
785 std::string value = parseString(element, false);
786 EXPECT_EQ(value, "vdd_regulator");
787 }
788
Shawn McCarneyf1845c02025-11-04 17:06:19 -0600789 // Test where works: Variable specified: Empty string
790 {
791 std::map<std::string, std::string> variables{{"var", ""}};
792 const json element = R"( "${var}" )"_json;
793 std::string value = parseString(element, true, variables);
794 EXPECT_EQ(value, "");
795 }
796
797 // Test where works: Variable specified: Non-empty string
798 {
799 std::map<std::string, std::string> variables{{"var", "vio_regulator"}};
800 const json element = R"( "${var}" )"_json;
801 std::string value = parseString(element, false, variables);
802 EXPECT_EQ(value, "vio_regulator");
803 }
804
Shawn McCarney38f85002025-10-31 17:59:36 -0500805 // Test where fails: Element is not a string
806 try
807 {
808 const json element = R"( { "foo": "bar" } )"_json;
809 parseString(element);
810 ADD_FAILURE() << "Should not have reached this line.";
811 }
812 catch (const std::invalid_argument& e)
813 {
814 EXPECT_STREQ(e.what(), "Element is not a string");
815 }
816
817 // Test where fails: Empty string
818 try
819 {
820 const json element = "";
821 parseString(element);
822 ADD_FAILURE() << "Should not have reached this line.";
823 }
824 catch (const std::invalid_argument& e)
825 {
826 EXPECT_STREQ(e.what(), "Element contains an empty string");
827 }
Shawn McCarneyf1845c02025-11-04 17:06:19 -0600828
829 // Test where fails: Variable specified: Empty string
830 try
831 {
832 std::map<std::string, std::string> variables{{"var", ""}};
833 const json element = R"( "${var}" )"_json;
834 parseString(element, false, variables);
835 ADD_FAILURE() << "Should not have reached this line.";
836 }
837 catch (const std::invalid_argument& e)
838 {
839 EXPECT_STREQ(e.what(), "Element contains an empty string");
840 }
841
842 // Test where fails: Variable specified: Variable not defined
843 try
844 {
845 std::map<std::string, std::string> variables{{"var1", "foo"}};
846 const json element = R"( "${var2}" )"_json;
847 parseString(element, false, variables);
848 ADD_FAILURE() << "Should not have reached this line.";
849 }
850 catch (const std::invalid_argument& e)
851 {
852 EXPECT_STREQ(e.what(), "Undefined variable: var2");
853 }
Shawn McCarney38f85002025-10-31 17:59:36 -0500854}
855
856TEST(JSONParserUtilsTests, ParseUint8)
857{
858 // Test where works: 0
859 {
860 const json element = R"( 0 )"_json;
861 uint8_t value = parseUint8(element);
862 EXPECT_EQ(value, 0);
863 }
864
865 // Test where works: UINT8_MAX
866 {
867 const json element = R"( 255 )"_json;
868 uint8_t value = parseUint8(element);
869 EXPECT_EQ(value, 255);
870 }
871
Shawn McCarneyf1845c02025-11-04 17:06:19 -0600872 // Test where works: Variable specified
873 {
874 std::map<std::string, std::string> variables{{"var", "19"}};
875 const json element = R"( "${var}" )"_json;
876 uint8_t value = parseUint8(element, variables);
877 EXPECT_EQ(value, 19);
878 }
879
Shawn McCarney38f85002025-10-31 17:59:36 -0500880 // Test where fails: Element is not an integer
881 try
882 {
883 const json element = R"( 1.03 )"_json;
884 parseUint8(element);
885 ADD_FAILURE() << "Should not have reached this line.";
886 }
887 catch (const std::invalid_argument& e)
888 {
889 EXPECT_STREQ(e.what(), "Element is not an integer");
890 }
891
892 // Test where fails: Value < 0
893 try
894 {
895 const json element = R"( -1 )"_json;
896 parseUint8(element);
897 ADD_FAILURE() << "Should not have reached this line.";
898 }
899 catch (const std::invalid_argument& e)
900 {
901 EXPECT_STREQ(e.what(), "Element is not an 8-bit unsigned integer");
902 }
903
904 // Test where fails: Value > UINT8_MAX
905 try
906 {
907 const json element = R"( 256 )"_json;
908 parseUint8(element);
909 ADD_FAILURE() << "Should not have reached this line.";
910 }
911 catch (const std::invalid_argument& e)
912 {
913 EXPECT_STREQ(e.what(), "Element is not an 8-bit unsigned integer");
914 }
Shawn McCarneyf1845c02025-11-04 17:06:19 -0600915
916 // Test where fails: Variable specified: Value > UINT8_MAX
917 try
918 {
919 std::map<std::string, std::string> variables{{"var", "256"}};
920 const json element = R"( "${var}" )"_json;
921 parseUint8(element, variables);
922 ADD_FAILURE() << "Should not have reached this line.";
923 }
924 catch (const std::invalid_argument& e)
925 {
926 EXPECT_STREQ(e.what(), "Element is not an 8-bit unsigned integer");
927 }
Shawn McCarney38f85002025-10-31 17:59:36 -0500928}
929
930TEST(JSONParserUtilsTests, ParseUnsignedInteger)
931{
932 // Test where works: 1
933 {
934 const json element = R"( 1 )"_json;
935 unsigned int value = parseUnsignedInteger(element);
936 EXPECT_EQ(value, 1);
937 }
938
Shawn McCarneyf1845c02025-11-04 17:06:19 -0600939 // Test where works: Variable specified
940 {
941 std::map<std::string, std::string> variables{{"var", "25678"}};
942 const json element = R"( "${var}" )"_json;
943 unsigned int value = parseUnsignedInteger(element, variables);
944 EXPECT_EQ(value, 25678);
945 }
946
Shawn McCarney38f85002025-10-31 17:59:36 -0500947 // Test where fails: Element is not an integer
948 try
949 {
950 const json element = R"( 1.5 )"_json;
951 parseUnsignedInteger(element);
952 ADD_FAILURE() << "Should not have reached this line.";
953 }
954 catch (const std::invalid_argument& e)
955 {
Shawn McCarneyf1845c02025-11-04 17:06:19 -0600956 EXPECT_STREQ(e.what(), "Element is not an integer");
Shawn McCarney38f85002025-10-31 17:59:36 -0500957 }
958
959 // Test where fails: Value < 0
960 try
961 {
962 const json element = R"( -1 )"_json;
963 parseUnsignedInteger(element);
964 ADD_FAILURE() << "Should not have reached this line.";
965 }
966 catch (const std::invalid_argument& e)
967 {
968 EXPECT_STREQ(e.what(), "Element is not an unsigned integer");
969 }
Shawn McCarneyf1845c02025-11-04 17:06:19 -0600970
971 // Test where fails: Variable specified: Value < 0
972 try
973 {
974 std::map<std::string, std::string> variables{{"var", "-23"}};
975 const json element = R"( "${var}" )"_json;
976 parseUnsignedInteger(element, variables);
977 ADD_FAILURE() << "Should not have reached this line.";
978 }
979 catch (const std::invalid_argument& e)
980 {
981 EXPECT_STREQ(e.what(), "Element is not an unsigned integer");
982 }
Shawn McCarney38f85002025-10-31 17:59:36 -0500983}
984
985TEST(JSONParserUtilsTests, VerifyIsArray)
986{
987 // Test where element is an array
988 {
989 const json element = R"( [ "foo", "bar" ] )"_json;
990 verifyIsArray(element);
991 }
992
993 // Test where element is not an array
994 try
995 {
996 const json element = R"( { "foo": "bar" } )"_json;
997 verifyIsArray(element);
998 ADD_FAILURE() << "Should not have reached this line.";
999 }
1000 catch (const std::invalid_argument& e)
1001 {
1002 EXPECT_STREQ(e.what(), "Element is not an array");
1003 }
1004}
1005
1006TEST(JSONParserUtilsTests, VerifyIsObject)
1007{
1008 // Test where element is an object
1009 {
1010 const json element = R"( { "foo": "bar" } )"_json;
1011 verifyIsObject(element);
1012 }
1013
1014 // Test where element is not an object
1015 try
1016 {
1017 const json element = R"( [ "foo", "bar" ] )"_json;
1018 verifyIsObject(element);
1019 ADD_FAILURE() << "Should not have reached this line.";
1020 }
1021 catch (const std::invalid_argument& e)
1022 {
1023 EXPECT_STREQ(e.what(), "Element is not an object");
1024 }
1025}
1026
1027TEST(JSONParserUtilsTests, VerifyPropertyCount)
1028{
1029 // Test where element has expected number of properties
1030 {
1031 const json element = R"(
1032 {
1033 "comments": [ "Set voltage rule" ],
1034 "id": "set_voltage_rule"
1035 }
1036 )"_json;
1037 verifyPropertyCount(element, 2);
1038 }
1039
1040 // Test where element has unexpected number of properties
1041 try
1042 {
1043 const json element = R"(
1044 {
1045 "comments": [ "Set voltage rule" ],
1046 "id": "set_voltage_rule",
1047 "foo": 1.3
1048 }
1049 )"_json;
1050 verifyPropertyCount(element, 2);
1051 ADD_FAILURE() << "Should not have reached this line.";
1052 }
1053 catch (const std::invalid_argument& e)
1054 {
1055 EXPECT_STREQ(e.what(), "Element contains an invalid property");
1056 }
1057}
Shawn McCarneyf1845c02025-11-04 17:06:19 -06001058
1059TEST(JSONParserUtilsTests, ExpandVariables)
1060{
1061 // Test where works: Single variable: Variable is entire value: Lower case
1062 // in variable name
1063 {
1064 std::map<std::string, std::string> variables{{"var", "vio_regulator"}};
1065 std::string value{"${var}"};
1066 expandVariables(value, variables);
1067 EXPECT_EQ(value, "vio_regulator");
1068 }
1069
1070 // Test where works: Multiple variables: Variables are part of value: Upper
1071 // case and underscore in variable name
1072 {
1073 std::map<std::string, std::string> variables{
1074 {"CHASSIS_NUMBER", "1"}, {"REGULATOR", "vcs_vio"}, {"RAIL", "vio"}};
1075 std::string value{
1076 "chassis${CHASSIS_NUMBER}_${REGULATOR}_regulator_${RAIL}_rail"};
1077 expandVariables(value, variables);
1078 EXPECT_EQ(value, "chassis1_vcs_vio_regulator_vio_rail");
1079 }
1080
1081 // Test where works: Variable at start of value: Number in variable name
1082 {
1083 std::map<std::string, std::string> variables{{"var1", "vio_regulator"}};
1084 std::string value{"${var1}_rail"};
1085 expandVariables(value, variables);
1086 EXPECT_EQ(value, "vio_regulator_rail");
1087 }
1088
1089 // Test where works: Variable at end of value
1090 {
1091 std::map<std::string, std::string> variables{{"chassis_number", "3"}};
1092 std::string value{
1093 "/xyz/openbmc_project/inventory/system/chassis${chassis_number}"};
1094 expandVariables(value, variables);
1095 EXPECT_EQ(value, "/xyz/openbmc_project/inventory/system/chassis3");
1096 }
1097
1098 // Test where works: Variable has empty value: Start of value
1099 {
1100 std::map<std::string, std::string> variables{{"chassis_prefix", ""}};
1101 std::string value{"${chassis_prefix}vio_regulator"};
1102 expandVariables(value, variables);
1103 EXPECT_EQ(value, "vio_regulator");
1104 }
1105
1106 // Test where works: Variable has empty value: Middle of value
1107 {
1108 std::map<std::string, std::string> variables{{"chassis_number", ""}};
1109 std::string value{"c${chassis_number}_vio_regulator"};
1110 expandVariables(value, variables);
1111 EXPECT_EQ(value, "c_vio_regulator");
1112 }
1113
1114 // Test where works: Variable has empty value: End of value
1115 {
1116 std::map<std::string, std::string> variables{{"chassis_number", ""}};
1117 std::string value{
1118 "/xyz/openbmc_project/inventory/system/chassis${chassis_number}"};
1119 expandVariables(value, variables);
1120 EXPECT_EQ(value, "/xyz/openbmc_project/inventory/system/chassis");
1121 }
1122
1123 // Test where works: No variables specified
1124 {
1125 std::map<std::string, std::string> variables{{"var", "vio_regulator"}};
1126 std::string value{"vcs_rail"};
1127 expandVariables(value, variables);
1128 EXPECT_EQ(value, "vcs_rail");
1129 }
1130
1131 // Test where works: Nested variable expansion
1132 {
1133 std::map<std::string, std::string> variables{{"var1", "${var2}"},
1134 {"var2", "vio_reg"}};
1135 std::string value{"${var1}_rail"};
1136 expandVariables(value, variables);
1137 EXPECT_EQ(value, "vio_reg_rail");
1138 }
1139
1140 // Test where fails: Variables map is empty
1141 {
1142 std::map<std::string, std::string> variables{};
1143 std::string value{"${var}_rail"};
1144 expandVariables(value, variables);
1145 EXPECT_EQ(value, "${var}_rail");
1146 }
1147
1148 // Test where fails: Variable missing $
1149 {
1150 std::map<std::string, std::string> variables{{"var", "vio_reg"}};
1151 std::string value{"{var}_rail"};
1152 expandVariables(value, variables);
1153 EXPECT_EQ(value, "{var}_rail");
1154 }
1155
1156 // Test where fails: Variable missing {
1157 {
1158 std::map<std::string, std::string> variables{{"var", "vio_reg"}};
1159 std::string value{"$var}_rail"};
1160 expandVariables(value, variables);
1161 EXPECT_EQ(value, "$var}_rail");
1162 }
1163
1164 // Test where fails: Variable missing }
1165 {
1166 std::map<std::string, std::string> variables{{"var", "vio_reg"}};
1167 std::string value{"${var_rail"};
1168 expandVariables(value, variables);
1169 EXPECT_EQ(value, "${var_rail");
1170 }
1171
1172 // Test where fails: Variable missing name
1173 {
1174 std::map<std::string, std::string> variables{{"var", "vio_reg"}};
1175 std::string value{"${}_rail"};
1176 expandVariables(value, variables);
1177 EXPECT_EQ(value, "${}_rail");
1178 }
1179
1180 // Test where fails: Variable name has invalid characters
1181 {
1182 std::map<std::string, std::string> variables{{"var-2", "vio_reg"}};
1183 std::string value{"${var-2}_rail"};
1184 expandVariables(value, variables);
1185 EXPECT_EQ(value, "${var-2}_rail");
1186 }
1187
1188 // Test where fails: Variable has unexpected whitespace
1189 {
1190 std::map<std::string, std::string> variables{{"var", "vio_reg"}};
1191 std::string value{"${ var }_rail"};
1192 expandVariables(value, variables);
1193 EXPECT_EQ(value, "${ var }_rail");
1194 }
1195
1196 // Test where fails: Undefined variable
1197 try
1198 {
1199 std::map<std::string, std::string> variables{{"var", "vio_reg"}};
1200 std::string value{"${foo}_rail"};
1201 expandVariables(value, variables);
1202 ADD_FAILURE() << "Should not have reached this line.";
1203 }
1204 catch (const std::invalid_argument& e)
1205 {
1206 EXPECT_STREQ(e.what(), "Undefined variable: foo");
1207 }
1208}