xref: /openbmc/phosphor-power/test/json_parser_utils_tests.cpp (revision 8873f428276818761348b4091574334870ae51a7)
1 /**
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 
28 using namespace phosphor::power::json_parser_utils;
29 using namespace phosphor::power::json_parser_utils::internal;
30 using json = nlohmann::json;
31 
TEST(JSONParserUtilsTests,GetRequiredProperty)32 TEST(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 
TEST(JSONParserUtilsTests,ParseBitPosition)54 TEST(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 
70     // 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 
78     // 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     }
113 
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     }
126 }
127 
TEST(JSONParserUtilsTests,ParseBitValue)128 TEST(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 
144     // 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 
152     // 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     }
187 
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     }
200 }
201 
TEST(JSONParserUtilsTests,ParseBoolean)202 TEST(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 
218     // 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 
234     // 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     }
245 
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     }
270 }
271 
TEST(JSONParserUtilsTests,ParseDouble)272 TEST(JSONParserUtilsTests, ParseDouble)
273 {
274     // Test where works: Floating point value
275     {
276         const json element = R"( 1.03 )"_json;
277         double value = parseDouble(element);
278         EXPECT_EQ(value, 1.03);
279     }
280 
281     // Test where works: Integer value
282     {
283         const json element = R"( -24 )"_json;
284         double value = parseDouble(element);
285         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);
301         EXPECT_EQ(value, 24.0);
302     }
303 
304     // Test where fails: Element is not a double
305     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     {
313         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");
391     }
392 }
393 
TEST(JSONParserUtilsTests,ParseHexByte)394 TEST(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 
417     // 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 
425     // 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     }
508 
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     }
521 }
522 
TEST(JSONParserUtilsTests,ParseHexByteArray)523 TEST(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 
533     // 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 
543     // 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     }
554 
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     }
568 }
569 
TEST(JSONParserUtilsTests,ParseInt8)570 TEST(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 
586     // 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 
594     // 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     }
629 
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 
TEST(JSONParserUtilsTests,ParseInteger)644 TEST(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     }
771 }
772 
TEST(JSONParserUtilsTests,ParseString)773 TEST(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 
789     // 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 
805     // 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     }
828 
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     }
854 }
855 
TEST(JSONParserUtilsTests,ParseUint8)856 TEST(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 
872     // 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 
880     // 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     }
915 
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     }
928 }
929 
TEST(JSONParserUtilsTests,ParseUint16)930 TEST(JSONParserUtilsTests, ParseUint16)
931 {
932     // Test where works: 0
933     {
934         const json element = R"( 0 )"_json;
935         uint16_t value = parseUint16(element);
936         EXPECT_EQ(value, 0);
937     }
938 
939     // Test where works: UINT16_MAX
940     {
941         const json element = R"( 65535 )"_json;
942         uint16_t value = parseUint16(element);
943         EXPECT_EQ(value, 65535);
944     }
945 
946     // Test where works: Variable specified
947     {
948         std::map<std::string, std::string> variables{{"var", "24699"}};
949         const json element = R"( "${var}" )"_json;
950         uint16_t value = parseUint16(element, variables);
951         EXPECT_EQ(value, 24699);
952     }
953 
954     // Test where fails: Element is not an integer
955     try
956     {
957         const json element = R"( 1.03 )"_json;
958         parseUint16(element);
959         ADD_FAILURE() << "Should not have reached this line.";
960     }
961     catch (const std::invalid_argument& e)
962     {
963         EXPECT_STREQ(e.what(), "Element is not an integer");
964     }
965 
966     // Test where fails: Value < 0
967     try
968     {
969         const json element = R"( -1 )"_json;
970         parseUint16(element);
971         ADD_FAILURE() << "Should not have reached this line.";
972     }
973     catch (const std::invalid_argument& e)
974     {
975         EXPECT_STREQ(e.what(), "Element is not a 16-bit unsigned integer");
976     }
977 
978     // Test where fails: Value > UINT16_MAX
979     try
980     {
981         const json element = R"( 65536 )"_json;
982         parseUint16(element);
983         ADD_FAILURE() << "Should not have reached this line.";
984     }
985     catch (const std::invalid_argument& e)
986     {
987         EXPECT_STREQ(e.what(), "Element is not a 16-bit unsigned integer");
988     }
989 
990     // Test where fails: Variable specified: Value > UINT16_MAX
991     try
992     {
993         std::map<std::string, std::string> variables{{"var", "65536"}};
994         const json element = R"( "${var}" )"_json;
995         parseUint16(element, variables);
996         ADD_FAILURE() << "Should not have reached this line.";
997     }
998     catch (const std::invalid_argument& e)
999     {
1000         EXPECT_STREQ(e.what(), "Element is not a 16-bit unsigned integer");
1001     }
1002 }
1003 
TEST(JSONParserUtilsTests,ParseUnsignedInteger)1004 TEST(JSONParserUtilsTests, ParseUnsignedInteger)
1005 {
1006     // Test where works: 1
1007     {
1008         const json element = R"( 1 )"_json;
1009         unsigned int value = parseUnsignedInteger(element);
1010         EXPECT_EQ(value, 1);
1011     }
1012 
1013     // Test where works: Variable specified
1014     {
1015         std::map<std::string, std::string> variables{{"var", "25678"}};
1016         const json element = R"( "${var}" )"_json;
1017         unsigned int value = parseUnsignedInteger(element, variables);
1018         EXPECT_EQ(value, 25678);
1019     }
1020 
1021     // Test where fails: Element is not an integer
1022     try
1023     {
1024         const json element = R"( 1.5 )"_json;
1025         parseUnsignedInteger(element);
1026         ADD_FAILURE() << "Should not have reached this line.";
1027     }
1028     catch (const std::invalid_argument& e)
1029     {
1030         EXPECT_STREQ(e.what(), "Element is not an integer");
1031     }
1032 
1033     // Test where fails: Value < 0
1034     try
1035     {
1036         const json element = R"( -1 )"_json;
1037         parseUnsignedInteger(element);
1038         ADD_FAILURE() << "Should not have reached this line.";
1039     }
1040     catch (const std::invalid_argument& e)
1041     {
1042         EXPECT_STREQ(e.what(), "Element is not an unsigned integer");
1043     }
1044 
1045     // Test where fails: Variable specified: Value < 0
1046     try
1047     {
1048         std::map<std::string, std::string> variables{{"var", "-23"}};
1049         const json element = R"( "${var}" )"_json;
1050         parseUnsignedInteger(element, variables);
1051         ADD_FAILURE() << "Should not have reached this line.";
1052     }
1053     catch (const std::invalid_argument& e)
1054     {
1055         EXPECT_STREQ(e.what(), "Element is not an unsigned integer");
1056     }
1057 }
1058 
TEST(JSONParserUtilsTests,VerifyIsArray)1059 TEST(JSONParserUtilsTests, VerifyIsArray)
1060 {
1061     // Test where element is an array
1062     {
1063         const json element = R"( [ "foo", "bar" ] )"_json;
1064         verifyIsArray(element);
1065     }
1066 
1067     // Test where element is not an array
1068     try
1069     {
1070         const json element = R"( { "foo": "bar" } )"_json;
1071         verifyIsArray(element);
1072         ADD_FAILURE() << "Should not have reached this line.";
1073     }
1074     catch (const std::invalid_argument& e)
1075     {
1076         EXPECT_STREQ(e.what(), "Element is not an array");
1077     }
1078 }
1079 
TEST(JSONParserUtilsTests,VerifyIsObject)1080 TEST(JSONParserUtilsTests, VerifyIsObject)
1081 {
1082     // Test where element is an object
1083     {
1084         const json element = R"( { "foo": "bar" } )"_json;
1085         verifyIsObject(element);
1086     }
1087 
1088     // Test where element is not an object
1089     try
1090     {
1091         const json element = R"( [ "foo", "bar" ] )"_json;
1092         verifyIsObject(element);
1093         ADD_FAILURE() << "Should not have reached this line.";
1094     }
1095     catch (const std::invalid_argument& e)
1096     {
1097         EXPECT_STREQ(e.what(), "Element is not an object");
1098     }
1099 }
1100 
TEST(JSONParserUtilsTests,VerifyPropertyCount)1101 TEST(JSONParserUtilsTests, VerifyPropertyCount)
1102 {
1103     // Test where element has expected number of properties
1104     {
1105         const json element = R"(
1106             {
1107               "comments": [ "Set voltage rule" ],
1108               "id": "set_voltage_rule"
1109             }
1110         )"_json;
1111         verifyPropertyCount(element, 2);
1112     }
1113 
1114     // Test where element has unexpected number of properties
1115     try
1116     {
1117         const json element = R"(
1118             {
1119               "comments": [ "Set voltage rule" ],
1120               "id": "set_voltage_rule",
1121               "foo": 1.3
1122             }
1123         )"_json;
1124         verifyPropertyCount(element, 2);
1125         ADD_FAILURE() << "Should not have reached this line.";
1126     }
1127     catch (const std::invalid_argument& e)
1128     {
1129         EXPECT_STREQ(e.what(), "Element contains an invalid property");
1130     }
1131 }
1132 
TEST(JSONParserUtilsTests,ExpandVariables)1133 TEST(JSONParserUtilsTests, ExpandVariables)
1134 {
1135     // Test where works: Single variable: Variable is entire value: Lower case
1136     // in variable name
1137     {
1138         std::map<std::string, std::string> variables{{"var", "vio_regulator"}};
1139         std::string value{"${var}"};
1140         expandVariables(value, variables);
1141         EXPECT_EQ(value, "vio_regulator");
1142     }
1143 
1144     // Test where works: Multiple variables: Variables are part of value: Upper
1145     // case and underscore in variable name
1146     {
1147         std::map<std::string, std::string> variables{
1148             {"CHASSIS_NUMBER", "1"}, {"REGULATOR", "vcs_vio"}, {"RAIL", "vio"}};
1149         std::string value{
1150             "chassis${CHASSIS_NUMBER}_${REGULATOR}_regulator_${RAIL}_rail"};
1151         expandVariables(value, variables);
1152         EXPECT_EQ(value, "chassis1_vcs_vio_regulator_vio_rail");
1153     }
1154 
1155     // Test where works: Variable at start of value: Number in variable name
1156     {
1157         std::map<std::string, std::string> variables{{"var1", "vio_regulator"}};
1158         std::string value{"${var1}_rail"};
1159         expandVariables(value, variables);
1160         EXPECT_EQ(value, "vio_regulator_rail");
1161     }
1162 
1163     // Test where works: Variable at end of value
1164     {
1165         std::map<std::string, std::string> variables{{"chassis_number", "3"}};
1166         std::string value{
1167             "/xyz/openbmc_project/inventory/system/chassis${chassis_number}"};
1168         expandVariables(value, variables);
1169         EXPECT_EQ(value, "/xyz/openbmc_project/inventory/system/chassis3");
1170     }
1171 
1172     // Test where works: Variable has empty value: Start of value
1173     {
1174         std::map<std::string, std::string> variables{{"chassis_prefix", ""}};
1175         std::string value{"${chassis_prefix}vio_regulator"};
1176         expandVariables(value, variables);
1177         EXPECT_EQ(value, "vio_regulator");
1178     }
1179 
1180     // Test where works: Variable has empty value: Middle of value
1181     {
1182         std::map<std::string, std::string> variables{{"chassis_number", ""}};
1183         std::string value{"c${chassis_number}_vio_regulator"};
1184         expandVariables(value, variables);
1185         EXPECT_EQ(value, "c_vio_regulator");
1186     }
1187 
1188     // Test where works: Variable has empty value: End of value
1189     {
1190         std::map<std::string, std::string> variables{{"chassis_number", ""}};
1191         std::string value{
1192             "/xyz/openbmc_project/inventory/system/chassis${chassis_number}"};
1193         expandVariables(value, variables);
1194         EXPECT_EQ(value, "/xyz/openbmc_project/inventory/system/chassis");
1195     }
1196 
1197     // Test where works: No variables specified
1198     {
1199         std::map<std::string, std::string> variables{{"var", "vio_regulator"}};
1200         std::string value{"vcs_rail"};
1201         expandVariables(value, variables);
1202         EXPECT_EQ(value, "vcs_rail");
1203     }
1204 
1205     // Test where works: Nested variable expansion
1206     {
1207         std::map<std::string, std::string> variables{{"var1", "${var2}"},
1208                                                      {"var2", "vio_reg"}};
1209         std::string value{"${var1}_rail"};
1210         expandVariables(value, variables);
1211         EXPECT_EQ(value, "vio_reg_rail");
1212     }
1213 
1214     // Test where fails: Variables map is empty
1215     {
1216         std::map<std::string, std::string> variables{};
1217         std::string value{"${var}_rail"};
1218         expandVariables(value, variables);
1219         EXPECT_EQ(value, "${var}_rail");
1220     }
1221 
1222     // Test where fails: Variable missing $
1223     {
1224         std::map<std::string, std::string> variables{{"var", "vio_reg"}};
1225         std::string value{"{var}_rail"};
1226         expandVariables(value, variables);
1227         EXPECT_EQ(value, "{var}_rail");
1228     }
1229 
1230     // Test where fails: Variable missing {
1231     {
1232         std::map<std::string, std::string> variables{{"var", "vio_reg"}};
1233         std::string value{"$var}_rail"};
1234         expandVariables(value, variables);
1235         EXPECT_EQ(value, "$var}_rail");
1236     }
1237 
1238     // Test where fails: Variable missing }
1239     {
1240         std::map<std::string, std::string> variables{{"var", "vio_reg"}};
1241         std::string value{"${var_rail"};
1242         expandVariables(value, variables);
1243         EXPECT_EQ(value, "${var_rail");
1244     }
1245 
1246     // Test where fails: Variable missing name
1247     {
1248         std::map<std::string, std::string> variables{{"var", "vio_reg"}};
1249         std::string value{"${}_rail"};
1250         expandVariables(value, variables);
1251         EXPECT_EQ(value, "${}_rail");
1252     }
1253 
1254     // Test where fails: Variable name has invalid characters
1255     {
1256         std::map<std::string, std::string> variables{{"var-2", "vio_reg"}};
1257         std::string value{"${var-2}_rail"};
1258         expandVariables(value, variables);
1259         EXPECT_EQ(value, "${var-2}_rail");
1260     }
1261 
1262     // Test where fails: Variable has unexpected whitespace
1263     {
1264         std::map<std::string, std::string> variables{{"var", "vio_reg"}};
1265         std::string value{"${ var }_rail"};
1266         expandVariables(value, variables);
1267         EXPECT_EQ(value, "${ var }_rail");
1268     }
1269 
1270     // Test where fails: Undefined variable
1271     try
1272     {
1273         std::map<std::string, std::string> variables{{"var", "vio_reg"}};
1274         std::string value{"${foo}_rail"};
1275         expandVariables(value, variables);
1276         ADD_FAILURE() << "Should not have reached this line.";
1277     }
1278     catch (const std::invalid_argument& e)
1279     {
1280         EXPECT_STREQ(e.what(), "Undefined variable: foo");
1281     }
1282 }
1283