blob: f28d827da158edba6a40409aa66399b8cc3c4c31 [file] [log] [blame]
Shawn McCarney6a957f62024-01-10 16:15:19 -06001/**
2 * Copyright © 2024 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 "config_file_parser.hpp"
17#include "config_file_parser_error.hpp"
18#include "rail.hpp"
19#include "temporary_file.hpp"
20
21#include <sys/stat.h> // for chmod()
22
23#include <nlohmann/json.hpp>
24
25#include <cstdint>
26#include <exception>
27#include <filesystem>
28#include <fstream>
29#include <memory>
30#include <optional>
31#include <stdexcept>
32#include <string>
33#include <vector>
34
35#include <gtest/gtest.h>
36
37using namespace phosphor::power::sequencer;
38using namespace phosphor::power::sequencer::config_file_parser;
39using namespace phosphor::power::sequencer::config_file_parser::internal;
40using json = nlohmann::json;
41using TemporaryFile = phosphor::power::util::TemporaryFile;
42
43void writeConfigFile(const std::filesystem::path& pathName,
44 const std::string& contents)
45{
46 std::ofstream file{pathName};
47 file << contents;
48}
49
50void writeConfigFile(const std::filesystem::path& pathName,
51 const json& contents)
52{
53 std::ofstream file{pathName};
54 file << contents;
55}
56
57TEST(ConfigFileParserTests, Parse)
58{
59 // Test where works
60 {
61 const json configFileContents = R"(
62 {
63 "rails": [
64 {
65 "name": "VDD_CPU0",
66 "page": 11,
67 "check_status_vout": true
68 },
69 {
70 "name": "VCS_CPU1",
71 "presence": "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu1",
72 "gpio": { "line": 60 }
73 }
74 ]
75 }
76 )"_json;
77
78 TemporaryFile configFile;
79 std::filesystem::path pathName{configFile.getPath()};
80 writeConfigFile(pathName, configFileContents);
81
82 std::vector<std::unique_ptr<Rail>> rails = parse(pathName);
83
84 EXPECT_EQ(rails.size(), 2);
85 EXPECT_EQ(rails[0]->getName(), "VDD_CPU0");
86 EXPECT_EQ(rails[1]->getName(), "VCS_CPU1");
87 }
88
89 // Test where fails: File does not exist
90 {
91 std::filesystem::path pathName{"/tmp/non_existent_file"};
92 EXPECT_THROW(parse(pathName), ConfigFileParserError);
93 }
94
95 // Test where fails: File is not readable
96 {
97 const json configFileContents = R"(
98 {
99 "rails": [
100 {
101 "name": "VDD_CPU0"
102 }
103 ]
104 }
105 )"_json;
106
107 TemporaryFile configFile;
108 std::filesystem::path pathName{configFile.getPath()};
109 writeConfigFile(pathName, configFileContents);
110
111 chmod(pathName.c_str(), 0222);
112 EXPECT_THROW(parse(pathName), ConfigFileParserError);
113 }
114
115 // Test where fails: File is not valid JSON
116 {
117 const std::string configFileContents = "] foo [";
118
119 TemporaryFile configFile;
120 std::filesystem::path pathName{configFile.getPath()};
121 writeConfigFile(pathName, configFileContents);
122
123 EXPECT_THROW(parse(pathName), ConfigFileParserError);
124 }
125
126 // Test where fails: JSON does not conform to config file format
127 {
128 const json configFileContents = R"( [ "foo", "bar" ] )"_json;
129
130 TemporaryFile configFile;
131 std::filesystem::path pathName{configFile.getPath()};
132 writeConfigFile(pathName, configFileContents);
133
134 EXPECT_THROW(parse(pathName), ConfigFileParserError);
135 }
136}
137
138TEST(ConfigFileParserTests, GetRequiredProperty)
139{
140 // Test where property exists
141 {
142 const json element = R"( { "name": "VDD_CPU0" } )"_json;
143 const json& propertyElement = getRequiredProperty(element, "name");
144 EXPECT_EQ(propertyElement.get<std::string>(), "VDD_CPU0");
145 }
146
147 // Test where property does not exist
148 try
149 {
150 const json element = R"( { "foo": 23 } )"_json;
151 getRequiredProperty(element, "name");
152 ADD_FAILURE() << "Should not have reached this line.";
153 }
154 catch (const std::invalid_argument& e)
155 {
156 EXPECT_STREQ(e.what(), "Required property missing: name");
157 }
158}
159
160TEST(ConfigFileParserTests, ParseBoolean)
161{
162 // Test where works: true
163 {
164 const json element = R"( true )"_json;
165 bool value = parseBoolean(element);
166 EXPECT_EQ(value, true);
167 }
168
169 // Test where works: false
170 {
171 const json element = R"( false )"_json;
172 bool value = parseBoolean(element);
173 EXPECT_EQ(value, false);
174 }
175
176 // Test where fails: Element is not a boolean
177 try
178 {
179 const json element = R"( 1 )"_json;
180 parseBoolean(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 boolean");
186 }
187}
188
189TEST(ConfigFileParserTests, ParseGPIO)
190{
191 // Test where works: Only required properties specified
192 {
193 const json element = R"(
194 {
195 "line": 60
196 }
197 )"_json;
198 GPIO gpio = parseGPIO(element);
199 EXPECT_EQ(gpio.line, 60);
200 EXPECT_FALSE(gpio.activeLow);
201 }
202
203 // Test where works: All properties specified
204 {
205 const json element = R"(
206 {
207 "line": 131,
208 "active_low": true
209 }
210 )"_json;
211 GPIO gpio = parseGPIO(element);
212 EXPECT_EQ(gpio.line, 131);
213 EXPECT_TRUE(gpio.activeLow);
214 }
215
216 // Test where fails: Element is not an object
217 try
218 {
219 const json element = R"( [ "vdda", "vddb" ] )"_json;
220 parseGPIO(element);
221 ADD_FAILURE() << "Should not have reached this line.";
222 }
223 catch (const std::invalid_argument& e)
224 {
225 EXPECT_STREQ(e.what(), "Element is not an object");
226 }
227
228 // Test where fails: Required line property not specified
229 try
230 {
231 const json element = R"(
232 {
233 "active_low": true
234 }
235 )"_json;
236 parseGPIO(element);
237 ADD_FAILURE() << "Should not have reached this line.";
238 }
239 catch (const std::invalid_argument& e)
240 {
241 EXPECT_STREQ(e.what(), "Required property missing: line");
242 }
243
244 // Test where fails: line value is invalid
245 try
246 {
247 const json element = R"(
248 {
249 "line": -131,
250 "active_low": true
251 }
252 )"_json;
253 parseGPIO(element);
254 ADD_FAILURE() << "Should not have reached this line.";
255 }
256 catch (const std::invalid_argument& e)
257 {
258 EXPECT_STREQ(e.what(), "Element is not an unsigned integer");
259 }
260
261 // Test where fails: active_low value is invalid
262 try
263 {
264 const json element = R"(
265 {
266 "line": 131,
267 "active_low": "true"
268 }
269 )"_json;
270 parseGPIO(element);
271 ADD_FAILURE() << "Should not have reached this line.";
272 }
273 catch (const std::invalid_argument& e)
274 {
275 EXPECT_STREQ(e.what(), "Element is not a boolean");
276 }
277
278 // Test where fails: Invalid property specified
279 try
280 {
281 const json element = R"(
282 {
283 "line": 131,
284 "foo": "bar"
285 }
286 )"_json;
287 parseGPIO(element);
288 ADD_FAILURE() << "Should not have reached this line.";
289 }
290 catch (const std::invalid_argument& e)
291 {
292 EXPECT_STREQ(e.what(), "Element contains an invalid property");
293 }
294}
295
296TEST(ConfigFileParserTests, ParseRail)
297{
298 // Test where works: Only required properties specified
299 {
300 const json element = R"(
301 {
302 "name": "VDD_CPU0"
303 }
304 )"_json;
305 std::unique_ptr<Rail> rail = parseRail(element);
306 EXPECT_EQ(rail->getName(), "VDD_CPU0");
307 EXPECT_FALSE(rail->getPresence().has_value());
308 EXPECT_FALSE(rail->getPage().has_value());
Shawn McCarney16e493a2024-01-29 14:20:32 -0600309 EXPECT_FALSE(rail->isPowerSupplyRail());
Shawn McCarney6a957f62024-01-10 16:15:19 -0600310 EXPECT_FALSE(rail->getCheckStatusVout());
Shawn McCarney9ec0d432024-02-09 18:26:00 -0600311 EXPECT_FALSE(rail->getCompareVoltageToLimit());
Shawn McCarney6a957f62024-01-10 16:15:19 -0600312 EXPECT_FALSE(rail->getGPIO().has_value());
313 }
314
315 // Test where works: All properties specified
316 {
317 const json element = R"(
318 {
Shawn McCarney16e493a2024-01-29 14:20:32 -0600319 "name": "12.0VB",
320 "presence": "/xyz/openbmc_project/inventory/system/chassis/powersupply1",
Shawn McCarney6a957f62024-01-10 16:15:19 -0600321 "page": 11,
Shawn McCarney16e493a2024-01-29 14:20:32 -0600322 "is_power_supply_rail": true,
Shawn McCarney6a957f62024-01-10 16:15:19 -0600323 "check_status_vout": true,
Shawn McCarney9ec0d432024-02-09 18:26:00 -0600324 "compare_voltage_to_limit": true,
Shawn McCarney6a957f62024-01-10 16:15:19 -0600325 "gpio": { "line": 60, "active_low": true }
326 }
327 )"_json;
328 std::unique_ptr<Rail> rail = parseRail(element);
Shawn McCarney16e493a2024-01-29 14:20:32 -0600329 EXPECT_EQ(rail->getName(), "12.0VB");
Shawn McCarney6a957f62024-01-10 16:15:19 -0600330 EXPECT_TRUE(rail->getPresence().has_value());
Shawn McCarney16e493a2024-01-29 14:20:32 -0600331 EXPECT_EQ(rail->getPresence().value(),
332 "/xyz/openbmc_project/inventory/system/chassis/powersupply1");
Shawn McCarney6a957f62024-01-10 16:15:19 -0600333 EXPECT_TRUE(rail->getPage().has_value());
334 EXPECT_EQ(rail->getPage().value(), 11);
Shawn McCarney16e493a2024-01-29 14:20:32 -0600335 EXPECT_TRUE(rail->isPowerSupplyRail());
Shawn McCarney6a957f62024-01-10 16:15:19 -0600336 EXPECT_TRUE(rail->getCheckStatusVout());
Shawn McCarney9ec0d432024-02-09 18:26:00 -0600337 EXPECT_TRUE(rail->getCompareVoltageToLimit());
Shawn McCarney6a957f62024-01-10 16:15:19 -0600338 EXPECT_TRUE(rail->getGPIO().has_value());
339 EXPECT_EQ(rail->getGPIO().value().line, 60);
340 EXPECT_TRUE(rail->getGPIO().value().activeLow);
341 }
342
343 // Test where fails: Element is not an object
344 try
345 {
346 const json element = R"( [ "vdda", "vddb" ] )"_json;
347 parseRail(element);
348 ADD_FAILURE() << "Should not have reached this line.";
349 }
350 catch (const std::invalid_argument& e)
351 {
352 EXPECT_STREQ(e.what(), "Element is not an object");
353 }
354
355 // Test where fails: Required name property not specified
356 try
357 {
358 const json element = R"(
359 {
360 "page": 11
361 }
362 )"_json;
363 parseRail(element);
364 ADD_FAILURE() << "Should not have reached this line.";
365 }
366 catch (const std::invalid_argument& e)
367 {
368 EXPECT_STREQ(e.what(), "Required property missing: name");
369 }
370
371 // Test where fails: name value is invalid
372 try
373 {
374 const json element = R"(
375 {
376 "name": 31,
377 "page": 11
378 }
379 )"_json;
380 parseRail(element);
381 ADD_FAILURE() << "Should not have reached this line.";
382 }
383 catch (const std::invalid_argument& e)
384 {
385 EXPECT_STREQ(e.what(), "Element is not a string");
386 }
387
388 // Test where fails: presence value is invalid
389 try
390 {
391 const json element = R"(
392 {
393 "name": "VCS_CPU1",
394 "presence": false
395 }
396 )"_json;
397 parseRail(element);
398 ADD_FAILURE() << "Should not have reached this line.";
399 }
400 catch (const std::invalid_argument& e)
401 {
402 EXPECT_STREQ(e.what(), "Element is not a string");
403 }
404
405 // Test where fails: page value is invalid
406 try
407 {
408 const json element = R"(
409 {
410 "name": "VCS_CPU1",
411 "page": 256
412 }
413 )"_json;
414 parseRail(element);
415 ADD_FAILURE() << "Should not have reached this line.";
416 }
417 catch (const std::invalid_argument& e)
418 {
419 EXPECT_STREQ(e.what(), "Element is not an 8-bit unsigned integer");
420 }
421
Shawn McCarney16e493a2024-01-29 14:20:32 -0600422 // Test where fails: is_power_supply_rail value is invalid
423 try
424 {
425 const json element = R"(
426 {
427 "name": "12.0VA",
428 "is_power_supply_rail": "true"
429 }
430 )"_json;
431 parseRail(element);
432 ADD_FAILURE() << "Should not have reached this line.";
433 }
434 catch (const std::invalid_argument& e)
435 {
436 EXPECT_STREQ(e.what(), "Element is not a boolean");
437 }
438
Shawn McCarney6a957f62024-01-10 16:15:19 -0600439 // Test where fails: check_status_vout value is invalid
440 try
441 {
442 const json element = R"(
443 {
444 "name": "VCS_CPU1",
445 "check_status_vout": "false"
446 }
447 )"_json;
448 parseRail(element);
449 ADD_FAILURE() << "Should not have reached this line.";
450 }
451 catch (const std::invalid_argument& e)
452 {
453 EXPECT_STREQ(e.what(), "Element is not a boolean");
454 }
455
Shawn McCarney9ec0d432024-02-09 18:26:00 -0600456 // Test where fails: compare_voltage_to_limit value is invalid
Shawn McCarney6a957f62024-01-10 16:15:19 -0600457 try
458 {
459 const json element = R"(
460 {
461 "name": "VCS_CPU1",
Shawn McCarney9ec0d432024-02-09 18:26:00 -0600462 "compare_voltage_to_limit": 23
Shawn McCarney6a957f62024-01-10 16:15:19 -0600463 }
464 )"_json;
465 parseRail(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 a boolean");
471 }
472
473 // Test where fails: gpio value is invalid
474 try
475 {
476 const json element = R"(
477 {
478 "name": "VCS_CPU1",
479 "gpio": 131
480 }
481 )"_json;
482 parseRail(element);
483 ADD_FAILURE() << "Should not have reached this line.";
484 }
485 catch (const std::invalid_argument& e)
486 {
487 EXPECT_STREQ(e.what(), "Element is not an object");
488 }
489
490 // Test where fails: check_status_vout is true and page not specified
491 try
492 {
493 const json element = R"(
494 {
495 "name": "VCS_CPU1",
496 "check_status_vout": true
497 }
498 )"_json;
499 parseRail(element);
500 ADD_FAILURE() << "Should not have reached this line.";
501 }
502 catch (const std::invalid_argument& e)
503 {
504 EXPECT_STREQ(e.what(), "Required property missing: page");
505 }
506
Shawn McCarney9ec0d432024-02-09 18:26:00 -0600507 // Test where fails: compare_voltage_to_limit is true and page not
Shawn McCarney6a957f62024-01-10 16:15:19 -0600508 // specified
509 try
510 {
511 const json element = R"(
512 {
513 "name": "VCS_CPU1",
Shawn McCarney9ec0d432024-02-09 18:26:00 -0600514 "compare_voltage_to_limit": true
Shawn McCarney6a957f62024-01-10 16:15:19 -0600515 }
516 )"_json;
517 parseRail(element);
518 ADD_FAILURE() << "Should not have reached this line.";
519 }
520 catch (const std::invalid_argument& e)
521 {
522 EXPECT_STREQ(e.what(), "Required property missing: page");
523 }
524
525 // Test where fails: Invalid property specified
526 try
527 {
528 const json element = R"(
529 {
530 "name": "VCS_CPU1",
531 "foo": "bar"
532 }
533 )"_json;
534 parseRail(element);
535 ADD_FAILURE() << "Should not have reached this line.";
536 }
537 catch (const std::invalid_argument& e)
538 {
539 EXPECT_STREQ(e.what(), "Element contains an invalid property");
540 }
541}
542
543TEST(ConfigFileParserTests, ParseRailArray)
544{
545 // Test where works: Array is empty
546 {
547 const json element = R"(
548 [
549 ]
550 )"_json;
551 std::vector<std::unique_ptr<Rail>> rails = parseRailArray(element);
552 EXPECT_EQ(rails.size(), 0);
553 }
554
555 // Test where works: Array is not empty
556 {
557 const json element = R"(
558 [
559 { "name": "VDD_CPU0" },
560 { "name": "VCS_CPU1" }
561 ]
562 )"_json;
563 std::vector<std::unique_ptr<Rail>> rails = parseRailArray(element);
564 EXPECT_EQ(rails.size(), 2);
565 EXPECT_EQ(rails[0]->getName(), "VDD_CPU0");
566 EXPECT_EQ(rails[1]->getName(), "VCS_CPU1");
567 }
568
569 // Test where fails: Element is not an array
570 try
571 {
572 const json element = R"(
573 {
574 "foo": "bar"
575 }
576 )"_json;
577 parseRailArray(element);
578 ADD_FAILURE() << "Should not have reached this line.";
579 }
580 catch (const std::invalid_argument& e)
581 {
582 EXPECT_STREQ(e.what(), "Element is not an array");
583 }
584
585 // Test where fails: Element within array is invalid
586 try
587 {
588 const json element = R"(
589 [
590 { "name": "VDD_CPU0" },
591 23
592 ]
593 )"_json;
594 parseRailArray(element);
595 ADD_FAILURE() << "Should not have reached this line.";
596 }
597 catch (const std::invalid_argument& e)
598 {
599 EXPECT_STREQ(e.what(), "Element is not an object");
600 }
601}
602
603TEST(ConfigFileParserTests, ParseRoot)
604{
605 // Test where works
606 {
607 const json element = R"(
608 {
609 "rails": [
610 {
611 "name": "VDD_CPU0",
612 "page": 11,
613 "check_status_vout": true
614 },
615 {
616 "name": "VCS_CPU1",
617 "presence": "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu1",
618 "gpio": { "line": 60 }
619 }
620 ]
621 }
622 )"_json;
623 std::vector<std::unique_ptr<Rail>> rails = parseRoot(element);
624 EXPECT_EQ(rails.size(), 2);
625 EXPECT_EQ(rails[0]->getName(), "VDD_CPU0");
626 EXPECT_EQ(rails[1]->getName(), "VCS_CPU1");
627 }
628
629 // Test where fails: Element is not an object
630 try
631 {
632 const json element = R"( [ "VDD_CPU0", "VCS_CPU1" ] )"_json;
633 parseRoot(element);
634 ADD_FAILURE() << "Should not have reached this line.";
635 }
636 catch (const std::invalid_argument& e)
637 {
638 EXPECT_STREQ(e.what(), "Element is not an object");
639 }
640
641 // Test where fails: Required rails property not specified
642 try
643 {
644 const json element = R"(
645 {
646 }
647 )"_json;
648 parseRoot(element);
649 ADD_FAILURE() << "Should not have reached this line.";
650 }
651 catch (const std::invalid_argument& e)
652 {
653 EXPECT_STREQ(e.what(), "Required property missing: rails");
654 }
655
656 // Test where fails: rails value is invalid
657 try
658 {
659 const json element = R"(
660 {
661 "rails": 31
662 }
663 )"_json;
664 parseRoot(element);
665 ADD_FAILURE() << "Should not have reached this line.";
666 }
667 catch (const std::invalid_argument& e)
668 {
669 EXPECT_STREQ(e.what(), "Element is not an array");
670 }
671
672 // Test where fails: Invalid property specified
673 try
674 {
675 const json element = R"(
676 {
677 "rails": [
678 {
679 "name": "VDD_CPU0",
680 "page": 11,
681 "check_status_vout": true
682 }
683 ],
684 "foo": true
685 }
686 )"_json;
687 parseRoot(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 contains an invalid property");
693 }
694}
695
696TEST(ConfigFileParserTests, ParseString)
697{
698 // Test where works: Empty string
699 {
700 const json element = "";
701 std::string value = parseString(element, true);
702 EXPECT_EQ(value, "");
703 }
704
705 // Test where works: Non-empty string
706 {
707 const json element = "vdd_cpu1";
708 std::string value = parseString(element, false);
709 EXPECT_EQ(value, "vdd_cpu1");
710 }
711
712 // Test where fails: Element is not a string
713 try
714 {
715 const json element = R"( { "foo": "bar" } )"_json;
716 parseString(element);
717 ADD_FAILURE() << "Should not have reached this line.";
718 }
719 catch (const std::invalid_argument& e)
720 {
721 EXPECT_STREQ(e.what(), "Element is not a string");
722 }
723
724 // Test where fails: Empty string
725 try
726 {
727 const json element = "";
728 parseString(element);
729 ADD_FAILURE() << "Should not have reached this line.";
730 }
731 catch (const std::invalid_argument& e)
732 {
733 EXPECT_STREQ(e.what(), "Element contains an empty string");
734 }
735}
736
737TEST(ConfigFileParserTests, ParseUint8)
738{
739 // Test where works: 0
740 {
741 const json element = R"( 0 )"_json;
742 uint8_t value = parseUint8(element);
743 EXPECT_EQ(value, 0);
744 }
745
746 // Test where works: UINT8_MAX
747 {
748 const json element = R"( 255 )"_json;
749 uint8_t value = parseUint8(element);
750 EXPECT_EQ(value, 255);
751 }
752
753 // Test where fails: Element is not an integer
754 try
755 {
756 const json element = R"( 1.03 )"_json;
757 parseUint8(element);
758 ADD_FAILURE() << "Should not have reached this line.";
759 }
760 catch (const std::invalid_argument& e)
761 {
762 EXPECT_STREQ(e.what(), "Element is not an integer");
763 }
764
765 // Test where fails: Value < 0
766 try
767 {
768 const json element = R"( -1 )"_json;
769 parseUint8(element);
770 ADD_FAILURE() << "Should not have reached this line.";
771 }
772 catch (const std::invalid_argument& e)
773 {
774 EXPECT_STREQ(e.what(), "Element is not an 8-bit unsigned integer");
775 }
776
777 // Test where fails: Value > UINT8_MAX
778 try
779 {
780 const json element = R"( 256 )"_json;
781 parseUint8(element);
782 ADD_FAILURE() << "Should not have reached this line.";
783 }
784 catch (const std::invalid_argument& e)
785 {
786 EXPECT_STREQ(e.what(), "Element is not an 8-bit unsigned integer");
787 }
788}
789
790TEST(ConfigFileParserTests, ParseUnsignedInteger)
791{
792 // Test where works: 1
793 {
794 const json element = R"( 1 )"_json;
795 unsigned int value = parseUnsignedInteger(element);
796 EXPECT_EQ(value, 1);
797 }
798
799 // Test where fails: Element is not an integer
800 try
801 {
802 const json element = R"( 1.5 )"_json;
803 parseUnsignedInteger(element);
804 ADD_FAILURE() << "Should not have reached this line.";
805 }
806 catch (const std::invalid_argument& e)
807 {
808 EXPECT_STREQ(e.what(), "Element is not an unsigned integer");
809 }
810
811 // Test where fails: Value < 0
812 try
813 {
814 const json element = R"( -1 )"_json;
815 parseUnsignedInteger(element);
816 ADD_FAILURE() << "Should not have reached this line.";
817 }
818 catch (const std::invalid_argument& e)
819 {
820 EXPECT_STREQ(e.what(), "Element is not an unsigned integer");
821 }
822}
823
824TEST(ConfigFileParserTests, VerifyIsArray)
825{
826 // Test where element is an array
827 {
828 const json element = R"( [ "foo", "bar" ] )"_json;
829 verifyIsArray(element);
830 }
831
832 // Test where element is not an array
833 try
834 {
835 const json element = R"( { "foo": "bar" } )"_json;
836 verifyIsArray(element);
837 ADD_FAILURE() << "Should not have reached this line.";
838 }
839 catch (const std::invalid_argument& e)
840 {
841 EXPECT_STREQ(e.what(), "Element is not an array");
842 }
843}
844
845TEST(ConfigFileParserTests, VerifyIsObject)
846{
847 // Test where element is an object
848 {
849 const json element = R"( { "foo": "bar" } )"_json;
850 verifyIsObject(element);
851 }
852
853 // Test where element is not an object
854 try
855 {
856 const json element = R"( [ "foo", "bar" ] )"_json;
857 verifyIsObject(element);
858 ADD_FAILURE() << "Should not have reached this line.";
859 }
860 catch (const std::invalid_argument& e)
861 {
862 EXPECT_STREQ(e.what(), "Element is not an object");
863 }
864}
865
866TEST(ConfigFileParserTests, VerifyPropertyCount)
867{
868 // Test where element has expected number of properties
869 {
870 const json element = R"(
871 {
872 "line": 131,
873 "active_low": true
874 }
875 )"_json;
876 verifyPropertyCount(element, 2);
877 }
878
879 // Test where element has unexpected number of properties
880 try
881 {
882 const json element = R"(
883 {
884 "line": 131,
885 "active_low": true,
886 "foo": 1.3
887 }
888 )"_json;
889 verifyPropertyCount(element, 2);
890 ADD_FAILURE() << "Should not have reached this line.";
891 }
892 catch (const std::invalid_argument& e)
893 {
894 EXPECT_STREQ(e.what(), "Element contains an invalid property");
895 }
896}