1 /**
2 * Copyright © 2020 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 "action.hpp"
17 #include "and_action.hpp"
18 #include "chassis.hpp"
19 #include "compare_presence_action.hpp"
20 #include "compare_vpd_action.hpp"
21 #include "config_file_parser.hpp"
22 #include "config_file_parser_error.hpp"
23 #include "configuration.hpp"
24 #include "device.hpp"
25 #include "i2c_capture_bytes_action.hpp"
26 #include "i2c_compare_bit_action.hpp"
27 #include "i2c_compare_byte_action.hpp"
28 #include "i2c_compare_bytes_action.hpp"
29 #include "i2c_interface.hpp"
30 #include "i2c_write_bit_action.hpp"
31 #include "i2c_write_byte_action.hpp"
32 #include "i2c_write_bytes_action.hpp"
33 #include "log_phase_fault_action.hpp"
34 #include "not_action.hpp"
35 #include "or_action.hpp"
36 #include "phase_fault.hpp"
37 #include "phase_fault_detection.hpp"
38 #include "pmbus_read_sensor_action.hpp"
39 #include "pmbus_utils.hpp"
40 #include "pmbus_write_vout_command_action.hpp"
41 #include "presence_detection.hpp"
42 #include "rail.hpp"
43 #include "rule.hpp"
44 #include "run_rule_action.hpp"
45 #include "sensor_monitoring.hpp"
46 #include "sensors.hpp"
47 #include "set_device_action.hpp"
48 #include "temporary_file.hpp"
49
50 #include <sys/stat.h> // for chmod()
51
52 #include <nlohmann/json.hpp>
53
54 #include <cstdint>
55 #include <cstring>
56 #include <exception>
57 #include <filesystem>
58 #include <fstream>
59 #include <memory>
60 #include <optional>
61 #include <stdexcept>
62 #include <string>
63 #include <tuple>
64 #include <vector>
65
66 #include <gtest/gtest.h>
67
68 using namespace phosphor::power::regulators;
69 using namespace phosphor::power::regulators::config_file_parser;
70 using namespace phosphor::power::regulators::config_file_parser::internal;
71 using ConfigFileParserError = phosphor::power::util::ConfigFileParserError;
72 using json = nlohmann::json;
73 using TemporaryFile = phosphor::power::util::TemporaryFile;
74
writeConfigFile(const std::filesystem::path & pathName,const std::string & contents)75 void writeConfigFile(const std::filesystem::path& pathName,
76 const std::string& contents)
77 {
78 std::ofstream file{pathName};
79 file << contents;
80 }
81
writeConfigFile(const std::filesystem::path & pathName,const json & contents)82 void writeConfigFile(const std::filesystem::path& pathName,
83 const json& contents)
84 {
85 std::ofstream file{pathName};
86 file << contents;
87 }
88
TEST(ConfigFileParserTests,Parse)89 TEST(ConfigFileParserTests, Parse)
90 {
91 // Test where works
92 {
93 const json configFileContents = R"(
94 {
95 "rules": [
96 {
97 "id": "set_voltage_rule1",
98 "actions": [
99 { "pmbus_write_vout_command": { "volts": 1.03, "format": "linear" } }
100 ]
101 },
102 {
103 "id": "set_voltage_rule2",
104 "actions": [
105 { "pmbus_write_vout_command": { "volts": 1.33, "format": "linear" } }
106 ]
107 }
108 ],
109 "chassis": [
110 { "number": 1, "inventory_path": "system/chassis1" },
111 { "number": 2, "inventory_path": "system/chassis2" },
112 { "number": 3, "inventory_path": "system/chassis3" }
113 ]
114 }
115 )"_json;
116
117 TemporaryFile configFile;
118 std::filesystem::path pathName{configFile.getPath()};
119 writeConfigFile(pathName, configFileContents);
120
121 std::vector<std::unique_ptr<Rule>> rules{};
122 std::vector<std::unique_ptr<Chassis>> chassis{};
123 std::tie(rules, chassis) = parse(pathName);
124
125 EXPECT_EQ(rules.size(), 2);
126 EXPECT_EQ(rules[0]->getID(), "set_voltage_rule1");
127 EXPECT_EQ(rules[1]->getID(), "set_voltage_rule2");
128
129 EXPECT_EQ(chassis.size(), 3);
130 EXPECT_EQ(chassis[0]->getNumber(), 1);
131 EXPECT_EQ(chassis[0]->getInventoryPath(),
132 "/xyz/openbmc_project/inventory/system/chassis1");
133 EXPECT_EQ(chassis[1]->getNumber(), 2);
134 EXPECT_EQ(chassis[1]->getInventoryPath(),
135 "/xyz/openbmc_project/inventory/system/chassis2");
136 EXPECT_EQ(chassis[2]->getNumber(), 3);
137 EXPECT_EQ(chassis[2]->getInventoryPath(),
138 "/xyz/openbmc_project/inventory/system/chassis3");
139 }
140
141 // Test where fails: File does not exist
142 try
143 {
144 std::filesystem::path pathName{"/tmp/non_existent_file"};
145 parse(pathName);
146 ADD_FAILURE() << "Should not have reached this line.";
147 }
148 catch (const ConfigFileParserError& e)
149 {
150 // Expected exception; what() message will vary
151 }
152
153 // Test where fails: File is not readable
154 try
155 {
156 const json configFileContents = R"(
157 {
158 "chassis": [
159 { "number": 1, "inventory_path": "system/chassis1" }
160 ]
161 }
162 )"_json;
163
164 TemporaryFile configFile;
165 std::filesystem::path pathName{configFile.getPath()};
166 writeConfigFile(pathName, configFileContents);
167
168 chmod(pathName.c_str(), 0222);
169
170 parse(pathName);
171 ADD_FAILURE() << "Should not have reached this line.";
172 }
173 catch (const ConfigFileParserError& e)
174 {
175 // Expected exception; what() message will vary
176 }
177
178 // Test where fails: File is not valid JSON
179 try
180 {
181 const std::string configFileContents = "] foo [";
182
183 TemporaryFile configFile;
184 std::filesystem::path pathName{configFile.getPath()};
185 writeConfigFile(pathName, configFileContents);
186
187 parse(pathName);
188 ADD_FAILURE() << "Should not have reached this line.";
189 }
190 catch (const ConfigFileParserError& e)
191 {
192 // Expected exception; what() message will vary
193 }
194
195 // Test where fails: Error when parsing JSON elements
196 try
197 {
198 const json configFileContents = R"( { "foo": "bar" } )"_json;
199
200 TemporaryFile configFile;
201 std::filesystem::path pathName{configFile.getPath()};
202 writeConfigFile(pathName, configFileContents);
203
204 parse(pathName);
205 ADD_FAILURE() << "Should not have reached this line.";
206 }
207 catch (const ConfigFileParserError& e)
208 {
209 // Expected exception; what() message will vary
210 }
211 }
212
TEST(ConfigFileParserTests,ParseAction)213 TEST(ConfigFileParserTests, ParseAction)
214 {
215 // Test where works: comments property specified
216 {
217 const json element = R"(
218 {
219 "comments": [ "Set output voltage." ],
220 "pmbus_write_vout_command": {
221 "format": "linear"
222 }
223 }
224 )"_json;
225 std::unique_ptr<Action> action = parseAction(element);
226 EXPECT_NE(action.get(), nullptr);
227 }
228
229 // Test where works: comments property not specified
230 {
231 const json element = R"(
232 {
233 "pmbus_write_vout_command": {
234 "format": "linear"
235 }
236 }
237 )"_json;
238 std::unique_ptr<Action> action = parseAction(element);
239 EXPECT_NE(action.get(), nullptr);
240 }
241
242 // Test where works: and action type specified
243 {
244 const json element = R"(
245 {
246 "and": [
247 { "i2c_compare_byte": { "register": "0xA0", "value": "0x00" } },
248 { "i2c_compare_byte": { "register": "0xA1", "value": "0x00" } }
249 ]
250 }
251 )"_json;
252 std::unique_ptr<Action> action = parseAction(element);
253 EXPECT_NE(action.get(), nullptr);
254 }
255
256 // Test where works: compare_presence action type specified
257 {
258 const json element = R"(
259 {
260 "compare_presence":
261 {
262 "fru": "system/chassis/motherboard/cpu3",
263 "value": true
264 }
265 }
266 )"_json;
267 std::unique_ptr<Action> action = parseAction(element);
268 EXPECT_NE(action.get(), nullptr);
269 }
270
271 // Test where works: compare_vpd action type specified
272 {
273 const json element = R"(
274 {
275 "compare_vpd":
276 {
277 "fru": "system/chassis/disk_backplane",
278 "keyword": "CCIN",
279 "value": "2D35"
280 }
281 }
282 )"_json;
283 std::unique_ptr<Action> action = parseAction(element);
284 EXPECT_NE(action.get(), nullptr);
285 }
286
287 // Test where works: i2c_capture_bytes action type specified
288 {
289 const json element = R"(
290 {
291 "i2c_capture_bytes": {
292 "register": "0xA0",
293 "count": 2
294 }
295 }
296 )"_json;
297 std::unique_ptr<Action> action = parseAction(element);
298 EXPECT_NE(action.get(), nullptr);
299 }
300
301 // Test where works: i2c_compare_bit action type specified
302 {
303 const json element = R"(
304 {
305 "i2c_compare_bit": {
306 "register": "0xA0",
307 "position": 3,
308 "value": 0
309 }
310 }
311 )"_json;
312 std::unique_ptr<Action> action = parseAction(element);
313 EXPECT_NE(action.get(), nullptr);
314 }
315
316 // Test where works: i2c_compare_byte action type specified
317 {
318 const json element = R"(
319 {
320 "i2c_compare_byte": {
321 "register": "0x0A",
322 "value": "0xCC"
323 }
324 }
325 )"_json;
326 std::unique_ptr<Action> action = parseAction(element);
327 EXPECT_NE(action.get(), nullptr);
328 }
329
330 // Test where works: i2c_compare_bytes action type specified
331 {
332 const json element = R"(
333 {
334 "i2c_compare_bytes": {
335 "register": "0x0A",
336 "values": [ "0xCC", "0xFF" ]
337 }
338 }
339 )"_json;
340 std::unique_ptr<Action> action = parseAction(element);
341 EXPECT_NE(action.get(), nullptr);
342 }
343
344 // Test where works: i2c_write_bit action type specified
345 {
346 const json element = R"(
347 {
348 "i2c_write_bit": {
349 "register": "0xA0",
350 "position": 3,
351 "value": 0
352 }
353 }
354 )"_json;
355 std::unique_ptr<Action> action = parseAction(element);
356 EXPECT_NE(action.get(), nullptr);
357 }
358
359 // Test where works: i2c_write_byte action type specified
360 {
361 const json element = R"(
362 {
363 "i2c_write_byte": {
364 "register": "0x0A",
365 "value": "0xCC"
366 }
367 }
368 )"_json;
369 std::unique_ptr<Action> action = parseAction(element);
370 EXPECT_NE(action.get(), nullptr);
371 }
372
373 // Test where works: i2c_write_bytes action type specified
374 {
375 const json element = R"(
376 {
377 "i2c_write_bytes": {
378 "register": "0x0A",
379 "values": [ "0xCC", "0xFF" ]
380 }
381 }
382 )"_json;
383 std::unique_ptr<Action> action = parseAction(element);
384 EXPECT_NE(action.get(), nullptr);
385 }
386
387 // Test where works: if action type specified
388 {
389 const json element = R"(
390 {
391 "if":
392 {
393 "condition": { "run_rule": "is_downlevel_regulator" },
394 "then": [ { "run_rule": "configure_downlevel_regulator" } ],
395 "else": [ { "run_rule": "configure_standard_regulator" } ]
396 }
397 }
398 )"_json;
399 std::unique_ptr<Action> action = parseAction(element);
400 EXPECT_NE(action.get(), nullptr);
401 }
402
403 // Test where works: log_phase_fault action type specified
404 {
405 const json element = R"(
406 {
407 "log_phase_fault": {
408 "type": "n+1"
409 }
410 }
411 )"_json;
412 std::unique_ptr<Action> action = parseAction(element);
413 EXPECT_NE(action.get(), nullptr);
414 }
415
416 // Test where works: not action type specified
417 {
418 const json element = R"(
419 {
420 "not":
421 { "i2c_compare_byte": { "register": "0xA0", "value": "0xFF" } }
422 }
423 )"_json;
424 std::unique_ptr<Action> action = parseAction(element);
425 EXPECT_NE(action.get(), nullptr);
426 }
427
428 // Test where works: or action type specified
429 {
430 const json element = R"(
431 {
432 "or": [
433 { "i2c_compare_byte": { "register": "0xA0", "value": "0x00" } },
434 { "i2c_compare_byte": { "register": "0xA1", "value": "0x00" } }
435 ]
436 }
437 )"_json;
438 std::unique_ptr<Action> action = parseAction(element);
439 EXPECT_NE(action.get(), nullptr);
440 }
441
442 // Test where works: pmbus_read_sensor action type specified
443 {
444 const json element = R"(
445 {
446 "pmbus_read_sensor": {
447 "type": "iout",
448 "command": "0x8C",
449 "format": "linear_11"
450 }
451 }
452 )"_json;
453 std::unique_ptr<Action> action = parseAction(element);
454 EXPECT_NE(action.get(), nullptr);
455 }
456
457 // Test where works: pmbus_write_vout_command action type specified
458 {
459 const json element = R"(
460 {
461 "pmbus_write_vout_command": {
462 "format": "linear"
463 }
464 }
465 )"_json;
466 std::unique_ptr<Action> action = parseAction(element);
467 EXPECT_NE(action.get(), nullptr);
468 }
469
470 // Test where works: run_rule action type specified
471 {
472 const json element = R"(
473 {
474 "run_rule": "set_voltage_rule"
475 }
476 )"_json;
477 std::unique_ptr<Action> action = parseAction(element);
478 EXPECT_NE(action.get(), nullptr);
479 }
480
481 // Test where works: set_device action type specified
482 {
483 const json element = R"(
484 {
485 "set_device": "io_expander2"
486 }
487 )"_json;
488 std::unique_ptr<Action> action = parseAction(element);
489 EXPECT_NE(action.get(), nullptr);
490 }
491
492 // Test where fails: Element is not an object
493 try
494 {
495 const json element = R"( [ "0xFF", "0x01" ] )"_json;
496 parseAction(element);
497 ADD_FAILURE() << "Should not have reached this line.";
498 }
499 catch (const std::invalid_argument& e)
500 {
501 EXPECT_STREQ(e.what(), "Element is not an object");
502 }
503
504 // Test where fails: No action type specified
505 try
506 {
507 const json element = R"(
508 {
509 "comments": [ "Set output voltage." ]
510 }
511 )"_json;
512 parseAction(element);
513 ADD_FAILURE() << "Should not have reached this line.";
514 }
515 catch (const std::invalid_argument& e)
516 {
517 EXPECT_STREQ(e.what(), "Required action type property missing");
518 }
519
520 // Test where fails: Multiple action types specified
521 try
522 {
523 const json element = R"(
524 {
525 "pmbus_write_vout_command": { "format": "linear" },
526 "run_rule": "set_voltage_rule"
527 }
528 )"_json;
529 parseAction(element);
530 ADD_FAILURE() << "Should not have reached this line.";
531 }
532 catch (const std::invalid_argument& e)
533 {
534 EXPECT_STREQ(e.what(), "Element contains an invalid property");
535 }
536
537 // Test where fails: Invalid property specified
538 try
539 {
540 const json element = R"(
541 {
542 "remarks": [ "Set output voltage." ],
543 "pmbus_write_vout_command": {
544 "format": "linear"
545 }
546 }
547 )"_json;
548 parseAction(element);
549 ADD_FAILURE() << "Should not have reached this line.";
550 }
551 catch (const std::invalid_argument& e)
552 {
553 EXPECT_STREQ(e.what(), "Element contains an invalid property");
554 }
555 }
556
TEST(ConfigFileParserTests,ParseActionArray)557 TEST(ConfigFileParserTests, ParseActionArray)
558 {
559 // Test where works
560 {
561 const json element = R"(
562 [
563 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } },
564 { "pmbus_write_vout_command": { "volts": 1.03, "format": "linear" } }
565 ]
566 )"_json;
567 std::vector<std::unique_ptr<Action>> actions =
568 parseActionArray(element);
569 EXPECT_EQ(actions.size(), 2);
570 }
571
572 // Test where fails: Element is not an array
573 try
574 {
575 const json element = R"(
576 {
577 "foo": "bar"
578 }
579 )"_json;
580 parseActionArray(element);
581 ADD_FAILURE() << "Should not have reached this line.";
582 }
583 catch (const std::invalid_argument& e)
584 {
585 EXPECT_STREQ(e.what(), "Element is not an array");
586 }
587 }
588
TEST(ConfigFileParserTests,ParseAnd)589 TEST(ConfigFileParserTests, ParseAnd)
590 {
591 // Test where works: Element is an array with 2 actions
592 {
593 const json element = R"(
594 [
595 { "i2c_compare_byte": { "register": "0xA0", "value": "0x00" } },
596 { "i2c_compare_byte": { "register": "0xA1", "value": "0x00" } }
597 ]
598 )"_json;
599 std::unique_ptr<AndAction> action = parseAnd(element);
600 EXPECT_EQ(action->getActions().size(), 2);
601 }
602
603 // Test where fails: Element is an array with 1 action
604 try
605 {
606 const json element = R"(
607 [
608 { "i2c_compare_byte": { "register": "0xA0", "value": "0x00" } }
609 ]
610 )"_json;
611 parseAnd(element);
612 ADD_FAILURE() << "Should not have reached this line.";
613 }
614 catch (const std::invalid_argument& e)
615 {
616 EXPECT_STREQ(e.what(), "Array must contain two or more actions");
617 }
618
619 // Test where fails: Element is not an array
620 try
621 {
622 const json element = R"(
623 {
624 "foo": "bar"
625 }
626 )"_json;
627 parseAnd(element);
628 ADD_FAILURE() << "Should not have reached this line.";
629 }
630 catch (const std::invalid_argument& e)
631 {
632 EXPECT_STREQ(e.what(), "Element is not an array");
633 }
634 }
635
TEST(ConfigFileParserTests,ParseChassis)636 TEST(ConfigFileParserTests, ParseChassis)
637 {
638 // Test where works: Only required properties specified
639 {
640 const json element = R"(
641 {
642 "number": 1,
643 "inventory_path": "system/chassis1"
644 }
645 )"_json;
646 std::unique_ptr<Chassis> chassis = parseChassis(element);
647 EXPECT_EQ(chassis->getNumber(), 1);
648 EXPECT_EQ(chassis->getInventoryPath(),
649 "/xyz/openbmc_project/inventory/system/chassis1");
650 EXPECT_EQ(chassis->getDevices().size(), 0);
651 }
652
653 // Test where works: All properties specified
654 {
655 const json element = R"(
656 {
657 "comments": [ "comments property" ],
658 "number": 2,
659 "inventory_path": "system/chassis2",
660 "devices": [
661 {
662 "id": "vdd_regulator",
663 "is_regulator": true,
664 "fru": "system/chassis/motherboard/regulator2",
665 "i2c_interface":
666 {
667 "bus": 1,
668 "address": "0x70"
669 }
670 }
671 ]
672 }
673 )"_json;
674 std::unique_ptr<Chassis> chassis = parseChassis(element);
675 EXPECT_EQ(chassis->getNumber(), 2);
676 EXPECT_EQ(chassis->getInventoryPath(),
677 "/xyz/openbmc_project/inventory/system/chassis2");
678 EXPECT_EQ(chassis->getDevices().size(), 1);
679 EXPECT_EQ(chassis->getDevices()[0]->getID(), "vdd_regulator");
680 }
681
682 // Test where fails: number value is invalid
683 try
684 {
685 const json element = R"(
686 {
687 "number": 0.5,
688 "inventory_path": "system/chassis"
689 }
690 )"_json;
691 parseChassis(element);
692 ADD_FAILURE() << "Should not have reached this line.";
693 }
694 catch (const std::invalid_argument& e)
695 {
696 EXPECT_STREQ(e.what(), "Element is not an integer");
697 }
698
699 // Test where fails: inventory_path is invalid: Not a string
700 try
701 {
702 const json element = R"(
703 {
704 "number": 2,
705 "inventory_path": true
706 }
707 )"_json;
708 parseChassis(element);
709 ADD_FAILURE() << "Should not have reached this line.";
710 }
711 catch (const std::invalid_argument& e)
712 {
713 EXPECT_STREQ(e.what(), "Element is not a string");
714 }
715
716 // Test where fails: inventory_path is invalid: Empty string
717 try
718 {
719 const json element = R"(
720 {
721 "number": 2,
722 "inventory_path": ""
723 }
724 )"_json;
725 parseChassis(element);
726 ADD_FAILURE() << "Should not have reached this line.";
727 }
728 catch (const std::invalid_argument& e)
729 {
730 EXPECT_STREQ(e.what(), "Element contains an empty string");
731 }
732
733 // Test where fails: Invalid property specified
734 try
735 {
736 const json element = R"(
737 {
738 "number": 1,
739 "inventory_path": "system/chassis",
740 "foo": 2
741 }
742 )"_json;
743 parseChassis(element);
744 ADD_FAILURE() << "Should not have reached this line.";
745 }
746 catch (const std::invalid_argument& e)
747 {
748 EXPECT_STREQ(e.what(), "Element contains an invalid property");
749 }
750
751 // Test where fails: Required number property not specified
752 try
753 {
754 const json element = R"(
755 {
756 "inventory_path": "system/chassis"
757 }
758 )"_json;
759 parseChassis(element);
760 ADD_FAILURE() << "Should not have reached this line.";
761 }
762 catch (const std::invalid_argument& e)
763 {
764 EXPECT_STREQ(e.what(), "Required property missing: number");
765 }
766
767 // Test where fails: Required inventory_path property not specified
768 try
769 {
770 const json element = R"(
771 {
772 "number": 1
773 }
774 )"_json;
775 parseChassis(element);
776 ADD_FAILURE() << "Should not have reached this line.";
777 }
778 catch (const std::invalid_argument& e)
779 {
780 EXPECT_STREQ(e.what(), "Required property missing: inventory_path");
781 }
782
783 // Test where fails: Element is not an object
784 try
785 {
786 const json element = R"( [ "0xFF", "0x01" ] )"_json;
787 parseChassis(element);
788 ADD_FAILURE() << "Should not have reached this line.";
789 }
790 catch (const std::invalid_argument& e)
791 {
792 EXPECT_STREQ(e.what(), "Element is not an object");
793 }
794
795 // Test where fails: number value is < 1
796 try
797 {
798 const json element = R"(
799 {
800 "number": 0,
801 "inventory_path": "system/chassis"
802 }
803 )"_json;
804 parseChassis(element);
805 ADD_FAILURE() << "Should not have reached this line.";
806 }
807 catch (const std::invalid_argument& e)
808 {
809 EXPECT_STREQ(e.what(), "Invalid chassis number: Must be > 0");
810 }
811
812 // Test where fails: devices value is invalid
813 try
814 {
815 const json element = R"(
816 {
817 "number": 1,
818 "inventory_path": "system/chassis",
819 "devices": 2
820 }
821 )"_json;
822 parseChassis(element);
823 ADD_FAILURE() << "Should not have reached this line.";
824 }
825 catch (const std::invalid_argument& e)
826 {
827 EXPECT_STREQ(e.what(), "Element is not an array");
828 }
829 }
830
TEST(ConfigFileParserTests,ParseChassisArray)831 TEST(ConfigFileParserTests, ParseChassisArray)
832 {
833 // Test where works
834 {
835 const json element = R"(
836 [
837 { "number": 1, "inventory_path": "system/chassis1" },
838 { "number": 2, "inventory_path": "system/chassis2" }
839 ]
840 )"_json;
841 std::vector<std::unique_ptr<Chassis>> chassis =
842 parseChassisArray(element);
843 EXPECT_EQ(chassis.size(), 2);
844 EXPECT_EQ(chassis[0]->getNumber(), 1);
845 EXPECT_EQ(chassis[0]->getInventoryPath(),
846 "/xyz/openbmc_project/inventory/system/chassis1");
847 EXPECT_EQ(chassis[1]->getNumber(), 2);
848 EXPECT_EQ(chassis[1]->getInventoryPath(),
849 "/xyz/openbmc_project/inventory/system/chassis2");
850 }
851
852 // Test where fails: Element is not an array
853 try
854 {
855 const json element = R"(
856 {
857 "foo": "bar"
858 }
859 )"_json;
860 parseChassisArray(element);
861 ADD_FAILURE() << "Should not have reached this line.";
862 }
863 catch (const std::invalid_argument& e)
864 {
865 EXPECT_STREQ(e.what(), "Element is not an array");
866 }
867 }
868
TEST(ConfigFileParserTests,ParseComparePresence)869 TEST(ConfigFileParserTests, ParseComparePresence)
870 {
871 // Test where works
872 {
873 const json element = R"(
874 {
875 "fru": "system/chassis/motherboard/cpu3",
876 "value": true
877 }
878 )"_json;
879 std::unique_ptr<ComparePresenceAction> action =
880 parseComparePresence(element);
881 EXPECT_EQ(
882 action->getFRU(),
883 "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu3");
884 EXPECT_EQ(action->getValue(), true);
885 }
886
887 // Test where fails: Element is not an object
888 try
889 {
890 const json element = R"( [ "0xFF", "0x01" ] )"_json;
891 parseComparePresence(element);
892 ADD_FAILURE() << "Should not have reached this line.";
893 }
894 catch (const std::invalid_argument& e)
895 {
896 EXPECT_STREQ(e.what(), "Element is not an object");
897 }
898
899 // Test where fails: Invalid property specified
900 try
901 {
902 const json element = R"(
903 {
904 "fru": "system/chassis/motherboard/cpu3",
905 "value": true,
906 "foo" : true
907 }
908 )"_json;
909 parseComparePresence(element);
910 ADD_FAILURE() << "Should not have reached this line.";
911 }
912 catch (const std::invalid_argument& e)
913 {
914 EXPECT_STREQ(e.what(), "Element contains an invalid property");
915 }
916
917 // Test where fails: Required fru property not specified
918 try
919 {
920 const json element = R"(
921 {
922 "value": true
923 }
924 )"_json;
925 parseComparePresence(element);
926 ADD_FAILURE() << "Should not have reached this line.";
927 }
928 catch (const std::invalid_argument& e)
929 {
930 EXPECT_STREQ(e.what(), "Required property missing: fru");
931 }
932
933 // Test where fails: Required value property not specified
934 try
935 {
936 const json element = R"(
937 {
938 "fru": "system/chassis/motherboard/cpu3"
939 }
940 )"_json;
941 parseComparePresence(element);
942 ADD_FAILURE() << "Should not have reached this line.";
943 }
944 catch (const std::invalid_argument& e)
945 {
946 EXPECT_STREQ(e.what(), "Required property missing: value");
947 }
948
949 // Test where fails: fru value is invalid
950 try
951 {
952 const json element = R"(
953 {
954 "fru": 1,
955 "value": true
956 }
957 )"_json;
958 parseComparePresence(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 a string");
964 }
965
966 // Test where fails: value value is invalid
967 try
968 {
969 const json element = R"(
970 {
971 "fru": "system/chassis/motherboard/cpu3",
972 "value": 1
973 }
974 )"_json;
975 parseComparePresence(element);
976 ADD_FAILURE() << "Should not have reached this line.";
977 }
978 catch (const std::invalid_argument& e)
979 {
980 EXPECT_STREQ(e.what(), "Element is not a boolean");
981 }
982 }
983
TEST(ConfigFileParserTests,ParseCompareVPD)984 TEST(ConfigFileParserTests, ParseCompareVPD)
985 {
986 // Test where works: value property: Not empty
987 {
988 const json element = R"(
989 {
990 "fru": "system/chassis/disk_backplane",
991 "keyword": "CCIN",
992 "value": "2D35"
993 }
994 )"_json;
995 std::unique_ptr<CompareVPDAction> action = parseCompareVPD(element);
996 EXPECT_EQ(
997 action->getFRU(),
998 "/xyz/openbmc_project/inventory/system/chassis/disk_backplane");
999 EXPECT_EQ(action->getKeyword(), "CCIN");
1000 EXPECT_EQ(action->getValue(),
1001 (std::vector<uint8_t>{0x32, 0x44, 0x33, 0x35}));
1002 }
1003
1004 // Test where works: value property: Empty
1005 {
1006 const json element = R"(
1007 {
1008 "fru": "system/chassis/disk_backplane",
1009 "keyword": "CCIN",
1010 "value": ""
1011 }
1012 )"_json;
1013 std::unique_ptr<CompareVPDAction> action = parseCompareVPD(element);
1014 EXPECT_EQ(
1015 action->getFRU(),
1016 "/xyz/openbmc_project/inventory/system/chassis/disk_backplane");
1017 EXPECT_EQ(action->getKeyword(), "CCIN");
1018 EXPECT_EQ(action->getValue(), (std::vector<uint8_t>{}));
1019 }
1020
1021 // Test where works: byte_values property: Not empty
1022 {
1023 const json element = R"(
1024 {
1025 "fru": "system/chassis/disk_backplane",
1026 "keyword": "CCIN",
1027 "byte_values": ["0x11", "0x22", "0x33"]
1028 }
1029 )"_json;
1030 std::unique_ptr<CompareVPDAction> action = parseCompareVPD(element);
1031 EXPECT_EQ(
1032 action->getFRU(),
1033 "/xyz/openbmc_project/inventory/system/chassis/disk_backplane");
1034 EXPECT_EQ(action->getKeyword(), "CCIN");
1035 EXPECT_EQ(action->getValue(), (std::vector<uint8_t>{0x11, 0x22, 0x33}));
1036 }
1037
1038 // Test where works: byte_values property: Empty
1039 {
1040 const json element = R"(
1041 {
1042 "fru": "system/chassis/disk_backplane",
1043 "keyword": "CCIN",
1044 "byte_values": []
1045 }
1046 )"_json;
1047 std::unique_ptr<CompareVPDAction> action = parseCompareVPD(element);
1048 EXPECT_EQ(
1049 action->getFRU(),
1050 "/xyz/openbmc_project/inventory/system/chassis/disk_backplane");
1051 EXPECT_EQ(action->getKeyword(), "CCIN");
1052 EXPECT_EQ(action->getValue(), (std::vector<uint8_t>{}));
1053 }
1054
1055 // Test where fails: Element is not an object
1056 try
1057 {
1058 const json element = R"( [ "0xFF", "0x01" ] )"_json;
1059 parseCompareVPD(element);
1060 ADD_FAILURE() << "Should not have reached this line.";
1061 }
1062 catch (const std::invalid_argument& e)
1063 {
1064 EXPECT_STREQ(e.what(), "Element is not an object");
1065 }
1066
1067 // Test where fails: Invalid property specified
1068 try
1069 {
1070 const json element = R"(
1071 {
1072 "fru": "system/chassis/disk_backplane",
1073 "keyword": "CCIN",
1074 "value": "2D35",
1075 "foo" : true
1076 }
1077 )"_json;
1078 parseCompareVPD(element);
1079 ADD_FAILURE() << "Should not have reached this line.";
1080 }
1081 catch (const std::invalid_argument& e)
1082 {
1083 EXPECT_STREQ(e.what(), "Element contains an invalid property");
1084 }
1085
1086 // Test where fails: Required fru property not specified
1087 try
1088 {
1089 const json element = R"(
1090 {
1091 "keyword": "CCIN",
1092 "value": "2D35"
1093 }
1094 )"_json;
1095 parseCompareVPD(element);
1096 ADD_FAILURE() << "Should not have reached this line.";
1097 }
1098 catch (const std::invalid_argument& e)
1099 {
1100 EXPECT_STREQ(e.what(), "Required property missing: fru");
1101 }
1102
1103 // Test where fails: Required keyword property not specified
1104 try
1105 {
1106 const json element = R"(
1107 {
1108 "fru": "system/chassis/disk_backplane",
1109 "value": "2D35"
1110 }
1111 )"_json;
1112 parseCompareVPD(element);
1113 ADD_FAILURE() << "Should not have reached this line.";
1114 }
1115 catch (const std::invalid_argument& e)
1116 {
1117 EXPECT_STREQ(e.what(), "Required property missing: keyword");
1118 }
1119
1120 // Test where fails: Required value property not specified
1121 try
1122 {
1123 const json element = R"(
1124 {
1125 "fru": "system/chassis/disk_backplane",
1126 "keyword": "CCIN"
1127 }
1128 )"_json;
1129 parseCompareVPD(element);
1130 ADD_FAILURE() << "Should not have reached this line.";
1131 }
1132 catch (const std::invalid_argument& e)
1133 {
1134 EXPECT_STREQ(e.what(), "Invalid property: Must contain "
1135 "either value or byte_values");
1136 }
1137
1138 // Test where fails: both value and byte_values specified
1139 try
1140 {
1141 const json element = R"(
1142 {
1143 "fru": "system/chassis/disk_backplane",
1144 "keyword": "CCIN",
1145 "value": "2D35",
1146 "byte_values": [ "0x01", "0x02" ]
1147 }
1148 )"_json;
1149 parseCompareVPD(element);
1150 ADD_FAILURE() << "Should not have reached this line.";
1151 }
1152 catch (const std::invalid_argument& e)
1153 {
1154 EXPECT_STREQ(e.what(), "Invalid property: Must contain "
1155 "either value or byte_values");
1156 }
1157
1158 // Test where fails: fru value is invalid
1159 try
1160 {
1161 const json element = R"(
1162 {
1163 "fru": 1,
1164 "keyword": "CCIN",
1165 "value": "2D35"
1166 }
1167 )"_json;
1168 parseCompareVPD(element);
1169 ADD_FAILURE() << "Should not have reached this line.";
1170 }
1171 catch (const std::invalid_argument& e)
1172 {
1173 EXPECT_STREQ(e.what(), "Element is not a string");
1174 }
1175
1176 // Test where fails: keyword value is invalid
1177 try
1178 {
1179 const json element = R"(
1180 {
1181 "fru": "system/chassis/disk_backplane",
1182 "keyword": 1,
1183 "value": "2D35"
1184 }
1185 )"_json;
1186 parseCompareVPD(element);
1187 ADD_FAILURE() << "Should not have reached this line.";
1188 }
1189 catch (const std::invalid_argument& e)
1190 {
1191 EXPECT_STREQ(e.what(), "Element is not a string");
1192 }
1193
1194 // Test where fails: value value is invalid
1195 try
1196 {
1197 const json element = R"(
1198 {
1199 "fru": "system/chassis/disk_backplane",
1200 "keyword": "CCIN",
1201 "value": 1
1202 }
1203 )"_json;
1204 parseCompareVPD(element);
1205 ADD_FAILURE() << "Should not have reached this line.";
1206 }
1207 catch (const std::invalid_argument& e)
1208 {
1209 EXPECT_STREQ(e.what(), "Element is not a string");
1210 }
1211
1212 // Test where fails: byte_values is wrong format
1213 try
1214 {
1215 const json element = R"(
1216 {
1217 "fru": "system/chassis/disk_backplane",
1218 "keyword": "CCIN",
1219 "byte_values": [1, 2, 3]
1220 }
1221 )"_json;
1222 parseCompareVPD(element);
1223 ADD_FAILURE() << "Should not have reached this line.";
1224 }
1225 catch (const std::invalid_argument& e)
1226 {
1227 EXPECT_STREQ(e.what(), "Element is not a string");
1228 }
1229 }
1230
TEST(ConfigFileParserTests,ParseConfiguration)1231 TEST(ConfigFileParserTests, ParseConfiguration)
1232 {
1233 // Test where works: actions required property specified
1234 {
1235 const json element = R"(
1236 {
1237 "actions": [
1238 {
1239 "pmbus_write_vout_command": {
1240 "format": "linear"
1241 }
1242 }
1243 ]
1244 }
1245 )"_json;
1246 std::unique_ptr<Configuration> configuration =
1247 parseConfiguration(element);
1248 EXPECT_EQ(configuration->getActions().size(), 1);
1249 EXPECT_EQ(configuration->getVolts().has_value(), false);
1250 }
1251
1252 // Test where works: volts and actions properties specified
1253 {
1254 const json element = R"(
1255 {
1256 "comments": [ "comments property" ],
1257 "volts": 1.03,
1258 "actions": [
1259 { "pmbus_write_vout_command": { "format": "linear" } },
1260 { "run_rule": "set_voltage_rule" }
1261 ]
1262 }
1263 )"_json;
1264 std::unique_ptr<Configuration> configuration =
1265 parseConfiguration(element);
1266 EXPECT_EQ(configuration->getVolts().has_value(), true);
1267 EXPECT_EQ(configuration->getVolts().value(), 1.03);
1268 EXPECT_EQ(configuration->getActions().size(), 2);
1269 }
1270
1271 // Test where works: volts and rule_id properties specified
1272 {
1273 const json element = R"(
1274 {
1275 "volts": 1.05,
1276 "rule_id": "set_voltage_rule"
1277 }
1278 )"_json;
1279 std::unique_ptr<Configuration> configuration =
1280 parseConfiguration(element);
1281 EXPECT_EQ(configuration->getVolts().has_value(), true);
1282 EXPECT_EQ(configuration->getVolts().value(), 1.05);
1283 EXPECT_EQ(configuration->getActions().size(), 1);
1284 }
1285
1286 // Test where fails: volts value is invalid
1287 try
1288 {
1289 const json element = R"(
1290 {
1291 "volts": "foo",
1292 "actions": [
1293 {
1294 "pmbus_write_vout_command": {
1295 "format": "linear"
1296 }
1297 }
1298 ]
1299 }
1300 )"_json;
1301 parseConfiguration(element);
1302 ADD_FAILURE() << "Should not have reached this line.";
1303 }
1304 catch (const std::invalid_argument& e)
1305 {
1306 EXPECT_STREQ(e.what(), "Element is not a double");
1307 }
1308
1309 // Test where fails: actions object is invalid
1310 try
1311 {
1312 const json element = R"(
1313 {
1314 "volts": 1.03,
1315 "actions": 1
1316 }
1317 )"_json;
1318 parseConfiguration(element);
1319 ADD_FAILURE() << "Should not have reached this line.";
1320 }
1321 catch (const std::invalid_argument& e)
1322 {
1323 EXPECT_STREQ(e.what(), "Element is not an array");
1324 }
1325
1326 // Test where fails: rule_id value is invalid
1327 try
1328 {
1329 const json element = R"(
1330 {
1331 "volts": 1.05,
1332 "rule_id": 1
1333 }
1334 )"_json;
1335 parseConfiguration(element);
1336 ADD_FAILURE() << "Should not have reached this line.";
1337 }
1338 catch (const std::invalid_argument& e)
1339 {
1340 EXPECT_STREQ(e.what(), "Element is not a string");
1341 }
1342
1343 // Test where fails: Required actions or rule_id property not specified
1344 try
1345 {
1346 const json element = R"(
1347 {
1348 "volts": 1.03
1349 }
1350 )"_json;
1351 parseConfiguration(element);
1352 ADD_FAILURE() << "Should not have reached this line.";
1353 }
1354 catch (const std::invalid_argument& e)
1355 {
1356 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain "
1357 "either rule_id or actions");
1358 }
1359
1360 // Test where fails: Required actions or rule_id property both specified
1361 try
1362 {
1363 const json element = R"(
1364 {
1365 "volts": 1.03,
1366 "rule_id": "set_voltage_rule",
1367 "actions": [
1368 {
1369 "pmbus_write_vout_command": {
1370 "format": "linear"
1371 }
1372 }
1373 ]
1374 }
1375 )"_json;
1376 parseConfiguration(element);
1377 ADD_FAILURE() << "Should not have reached this line.";
1378 }
1379 catch (const std::invalid_argument& e)
1380 {
1381 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain "
1382 "either rule_id or actions");
1383 }
1384
1385 // Test where fails: Element is not an object
1386 try
1387 {
1388 const json element = R"( [ "0xFF", "0x01" ] )"_json;
1389 parseConfiguration(element);
1390 ADD_FAILURE() << "Should not have reached this line.";
1391 }
1392 catch (const std::invalid_argument& e)
1393 {
1394 EXPECT_STREQ(e.what(), "Element is not an object");
1395 }
1396
1397 // Test where fails: Invalid property specified
1398 try
1399 {
1400 const json element = R"(
1401 {
1402 "volts": 1.03,
1403 "rule_id": "set_voltage_rule",
1404 "foo": 1
1405 }
1406 )"_json;
1407 parseConfiguration(element);
1408 ADD_FAILURE() << "Should not have reached this line.";
1409 }
1410 catch (const std::invalid_argument& e)
1411 {
1412 EXPECT_STREQ(e.what(), "Element contains an invalid property");
1413 }
1414 }
1415
TEST(ConfigFileParserTests,ParseDevice)1416 TEST(ConfigFileParserTests, ParseDevice)
1417 {
1418 // Test where works: Only required properties specified
1419 {
1420 const json element = R"(
1421 {
1422 "id": "vdd_regulator",
1423 "is_regulator": true,
1424 "fru": "system/chassis/motherboard/regulator2",
1425 "i2c_interface": { "bus": 1, "address": "0x70" }
1426 }
1427 )"_json;
1428 std::unique_ptr<Device> device = parseDevice(element);
1429 EXPECT_EQ(device->getID(), "vdd_regulator");
1430 EXPECT_EQ(device->isRegulator(), true);
1431 EXPECT_EQ(device->getFRU(), "/xyz/openbmc_project/inventory/system/"
1432 "chassis/motherboard/regulator2");
1433 EXPECT_NE(&(device->getI2CInterface()), nullptr);
1434 EXPECT_EQ(device->getPresenceDetection(), nullptr);
1435 EXPECT_EQ(device->getConfiguration(), nullptr);
1436 EXPECT_EQ(device->getPhaseFaultDetection(), nullptr);
1437 EXPECT_EQ(device->getRails().size(), 0);
1438 }
1439
1440 // Test where works: All properties specified
1441 {
1442 const json element = R"(
1443 {
1444 "comments": [ "VDD Regulator" ],
1445 "id": "vdd_regulator",
1446 "is_regulator": true,
1447 "fru": "system/chassis/motherboard/regulator2",
1448 "i2c_interface":
1449 {
1450 "bus": 1,
1451 "address": "0x70"
1452 },
1453 "presence_detection":
1454 {
1455 "rule_id": "is_foobar_backplane_installed_rule"
1456 },
1457 "configuration":
1458 {
1459 "rule_id": "configure_ir35221_rule"
1460 },
1461 "phase_fault_detection":
1462 {
1463 "rule_id": "detect_phase_fault_rule"
1464 },
1465 "rails":
1466 [
1467 {
1468 "id": "vdd"
1469 }
1470 ]
1471 }
1472 )"_json;
1473 std::unique_ptr<Device> device = parseDevice(element);
1474 EXPECT_EQ(device->getID(), "vdd_regulator");
1475 EXPECT_EQ(device->isRegulator(), true);
1476 EXPECT_EQ(device->getFRU(), "/xyz/openbmc_project/inventory/system/"
1477 "chassis/motherboard/regulator2");
1478 EXPECT_NE(&(device->getI2CInterface()), nullptr);
1479 EXPECT_NE(device->getPresenceDetection(), nullptr);
1480 EXPECT_NE(device->getConfiguration(), nullptr);
1481 EXPECT_NE(device->getPhaseFaultDetection(), nullptr);
1482 EXPECT_EQ(device->getRails().size(), 1);
1483 }
1484
1485 // Test where fails: phase_fault_detection property exists and is_regulator
1486 // is false
1487 try
1488 {
1489 const json element = R"(
1490 {
1491 "id": "vdd_regulator",
1492 "is_regulator": false,
1493 "fru": "system/chassis/motherboard/regulator2",
1494 "i2c_interface":
1495 {
1496 "bus": 1,
1497 "address": "0x70"
1498 },
1499 "phase_fault_detection":
1500 {
1501 "rule_id": "detect_phase_fault_rule"
1502 }
1503 }
1504 )"_json;
1505 parseDevice(element);
1506 ADD_FAILURE() << "Should not have reached this line.";
1507 }
1508 catch (const std::invalid_argument& e)
1509 {
1510 EXPECT_STREQ(e.what(), "Invalid phase_fault_detection property when "
1511 "is_regulator is false");
1512 }
1513
1514 // Test where fails: rails property exists and is_regulator is false
1515 try
1516 {
1517 const json element = R"(
1518 {
1519 "id": "vdd_regulator",
1520 "is_regulator": false,
1521 "fru": "system/chassis/motherboard/regulator2",
1522 "i2c_interface":
1523 {
1524 "bus": 1,
1525 "address": "0x70"
1526 },
1527 "configuration":
1528 {
1529 "rule_id": "configure_ir35221_rule"
1530 },
1531 "rails":
1532 [
1533 {
1534 "id": "vdd"
1535 }
1536 ]
1537 }
1538 )"_json;
1539 parseDevice(element);
1540 ADD_FAILURE() << "Should not have reached this line.";
1541 }
1542 catch (const std::invalid_argument& e)
1543 {
1544 EXPECT_STREQ(e.what(),
1545 "Invalid rails property when is_regulator is false");
1546 }
1547
1548 // Test where fails: id value is invalid
1549 try
1550 {
1551 const json element = R"(
1552 {
1553 "id": 3,
1554 "is_regulator": true,
1555 "fru": "system/chassis/motherboard/regulator2",
1556 "i2c_interface":
1557 {
1558 "bus": 1,
1559 "address": "0x70"
1560 }
1561 }
1562 )"_json;
1563 parseDevice(element);
1564 ADD_FAILURE() << "Should not have reached this line.";
1565 }
1566 catch (const std::invalid_argument& e)
1567 {
1568 EXPECT_STREQ(e.what(), "Element is not a string");
1569 }
1570
1571 // Test where fails: is_regulator value is invalid
1572 try
1573 {
1574 const json element = R"(
1575 {
1576 "id": "vdd_regulator",
1577 "is_regulator": 3,
1578 "fru": "system/chassis/motherboard/regulator2",
1579 "i2c_interface":
1580 {
1581 "bus": 1,
1582 "address": "0x70"
1583 }
1584 }
1585 )"_json;
1586 parseDevice(element);
1587 ADD_FAILURE() << "Should not have reached this line.";
1588 }
1589 catch (const std::invalid_argument& e)
1590 {
1591 EXPECT_STREQ(e.what(), "Element is not a boolean");
1592 }
1593
1594 // Test where fails: fru value is invalid
1595 try
1596 {
1597 const json element = R"(
1598 {
1599 "id": "vdd_regulator",
1600 "is_regulator": true,
1601 "fru": 2,
1602 "i2c_interface":
1603 {
1604 "bus": 1,
1605 "address": "0x70"
1606 }
1607 }
1608 )"_json;
1609 parseDevice(element);
1610 ADD_FAILURE() << "Should not have reached this line.";
1611 }
1612 catch (const std::invalid_argument& e)
1613 {
1614 EXPECT_STREQ(e.what(), "Element is not a string");
1615 }
1616
1617 // Test where fails: i2c_interface value is invalid
1618 try
1619 {
1620 const json element = R"(
1621 {
1622 "id": "vdd_regulator",
1623 "is_regulator": true,
1624 "fru": "system/chassis/motherboard/regulator2",
1625 "i2c_interface": 3
1626 }
1627 )"_json;
1628 parseDevice(element);
1629 ADD_FAILURE() << "Should not have reached this line.";
1630 }
1631 catch (const std::invalid_argument& e)
1632 {
1633 EXPECT_STREQ(e.what(), "Element is not an object");
1634 }
1635
1636 // Test where fails: Required id property not specified
1637 try
1638 {
1639 const json element = R"(
1640 {
1641 "is_regulator": true,
1642 "fru": "system/chassis/motherboard/regulator2",
1643 "i2c_interface":
1644 {
1645 "bus": 1,
1646 "address": "0x70"
1647 }
1648 }
1649 )"_json;
1650 parseDevice(element);
1651 ADD_FAILURE() << "Should not have reached this line.";
1652 }
1653 catch (const std::invalid_argument& e)
1654 {
1655 EXPECT_STREQ(e.what(), "Required property missing: id");
1656 }
1657
1658 // Test where fails: Required is_regulator property not specified
1659 try
1660 {
1661 const json element = R"(
1662 {
1663 "id": "vdd_regulator",
1664 "fru": "system/chassis/motherboard/regulator2",
1665 "i2c_interface":
1666 {
1667 "bus": 1,
1668 "address": "0x70"
1669 }
1670 }
1671 )"_json;
1672 parseDevice(element);
1673 ADD_FAILURE() << "Should not have reached this line.";
1674 }
1675 catch (const std::invalid_argument& e)
1676 {
1677 EXPECT_STREQ(e.what(), "Required property missing: is_regulator");
1678 }
1679
1680 // Test where fails: Required fru property not specified
1681 try
1682 {
1683 const json element = R"(
1684 {
1685 "id": "vdd_regulator",
1686 "is_regulator": true,
1687 "i2c_interface":
1688 {
1689 "bus": 1,
1690 "address": "0x70"
1691 }
1692 }
1693 )"_json;
1694 parseDevice(element);
1695 ADD_FAILURE() << "Should not have reached this line.";
1696 }
1697 catch (const std::invalid_argument& e)
1698 {
1699 EXPECT_STREQ(e.what(), "Required property missing: fru");
1700 }
1701
1702 // Test where fails: Required i2c_interface property not specified
1703 try
1704 {
1705 const json element = R"(
1706 {
1707 "id": "vdd_regulator",
1708 "is_regulator": true,
1709 "fru": "system/chassis/motherboard/regulator2"
1710 }
1711 )"_json;
1712 parseDevice(element);
1713 ADD_FAILURE() << "Should not have reached this line.";
1714 }
1715 catch (const std::invalid_argument& e)
1716 {
1717 EXPECT_STREQ(e.what(), "Required property missing: i2c_interface");
1718 }
1719
1720 // Test where fails: Element is not an object
1721 try
1722 {
1723 const json element = R"( [ "0xFF", "0x01" ] )"_json;
1724 parseDevice(element);
1725 ADD_FAILURE() << "Should not have reached this line.";
1726 }
1727 catch (const std::invalid_argument& e)
1728 {
1729 EXPECT_STREQ(e.what(), "Element is not an object");
1730 }
1731
1732 // Test where fails: Invalid property specified
1733 try
1734 {
1735 const json element = R"(
1736 {
1737 "id": "vdd_regulator",
1738 "is_regulator": true,
1739 "fru": "system/chassis/motherboard/regulator2",
1740 "i2c_interface": { "bus": 1, "address": "0x70" },
1741 "foo" : true
1742 }
1743 )"_json;
1744 parseDevice(element);
1745 ADD_FAILURE() << "Should not have reached this line.";
1746 }
1747 catch (const std::invalid_argument& e)
1748 {
1749 EXPECT_STREQ(e.what(), "Element contains an invalid property");
1750 }
1751 }
1752
TEST(ConfigFileParserTests,ParseDeviceArray)1753 TEST(ConfigFileParserTests, ParseDeviceArray)
1754 {
1755 // Test where works
1756 {
1757 const json element = R"(
1758 [
1759 {
1760 "id": "vdd_regulator",
1761 "is_regulator": true,
1762 "fru": "system/chassis/motherboard/regulator2",
1763 "i2c_interface": { "bus": 1, "address": "0x70" }
1764 },
1765 {
1766 "id": "vio_regulator",
1767 "is_regulator": true,
1768 "fru": "system/chassis/motherboard/regulator2",
1769 "i2c_interface": { "bus": 1, "address": "0x71" }
1770 }
1771 ]
1772 )"_json;
1773 std::vector<std::unique_ptr<Device>> devices =
1774 parseDeviceArray(element);
1775 EXPECT_EQ(devices.size(), 2);
1776 EXPECT_EQ(devices[0]->getID(), "vdd_regulator");
1777 EXPECT_EQ(devices[1]->getID(), "vio_regulator");
1778 }
1779
1780 // Test where fails: Element is not an array
1781 try
1782 {
1783 const json element = R"(
1784 {
1785 "foo": "bar"
1786 }
1787 )"_json;
1788 parseDeviceArray(element);
1789 ADD_FAILURE() << "Should not have reached this line.";
1790 }
1791 catch (const std::invalid_argument& e)
1792 {
1793 EXPECT_STREQ(e.what(), "Element is not an array");
1794 }
1795 }
1796
TEST(ConfigFileParserTests,ParseI2CCaptureBytes)1797 TEST(ConfigFileParserTests, ParseI2CCaptureBytes)
1798 {
1799 // Test where works
1800 {
1801 const json element = R"(
1802 {
1803 "register": "0xA0",
1804 "count": 2
1805 }
1806 )"_json;
1807 std::unique_ptr<I2CCaptureBytesAction> action =
1808 parseI2CCaptureBytes(element);
1809 EXPECT_EQ(action->getRegister(), 0xA0);
1810 EXPECT_EQ(action->getCount(), 2);
1811 }
1812
1813 // Test where fails: Element is not an object
1814 try
1815 {
1816 const json element = R"( [ "0xFF", "0x01" ] )"_json;
1817 parseI2CCaptureBytes(element);
1818 ADD_FAILURE() << "Should not have reached this line.";
1819 }
1820 catch (const std::invalid_argument& e)
1821 {
1822 EXPECT_STREQ(e.what(), "Element is not an object");
1823 }
1824
1825 // Test where fails: register value is invalid
1826 try
1827 {
1828 const json element = R"(
1829 {
1830 "register": "0x0Z",
1831 "count": 2
1832 }
1833 )"_json;
1834 parseI2CCaptureBytes(element);
1835 ADD_FAILURE() << "Should not have reached this line.";
1836 }
1837 catch (const std::invalid_argument& e)
1838 {
1839 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
1840 }
1841
1842 // Test where fails: count value is invalid
1843 try
1844 {
1845 const json element = R"(
1846 {
1847 "register": "0xA0",
1848 "count": 0
1849 }
1850 )"_json;
1851 parseI2CCaptureBytes(element);
1852 ADD_FAILURE() << "Should not have reached this line.";
1853 }
1854 catch (const std::invalid_argument& e)
1855 {
1856 EXPECT_STREQ(e.what(), "Invalid byte count: Must be > 0");
1857 }
1858
1859 // Test where fails: Required register property not specified
1860 try
1861 {
1862 const json element = R"(
1863 {
1864 "count": 2
1865 }
1866 )"_json;
1867 parseI2CCaptureBytes(element);
1868 ADD_FAILURE() << "Should not have reached this line.";
1869 }
1870 catch (const std::invalid_argument& e)
1871 {
1872 EXPECT_STREQ(e.what(), "Required property missing: register");
1873 }
1874
1875 // Test where fails: Required count property not specified
1876 try
1877 {
1878 const json element = R"(
1879 {
1880 "register": "0xA0"
1881 }
1882 )"_json;
1883 parseI2CCaptureBytes(element);
1884 ADD_FAILURE() << "Should not have reached this line.";
1885 }
1886 catch (const std::invalid_argument& e)
1887 {
1888 EXPECT_STREQ(e.what(), "Required property missing: count");
1889 }
1890
1891 // Test where fails: Invalid property specified
1892 try
1893 {
1894 const json element = R"(
1895 {
1896 "register": "0xA0",
1897 "count": 2,
1898 "foo": 3
1899 }
1900 )"_json;
1901 parseI2CCaptureBytes(element);
1902 ADD_FAILURE() << "Should not have reached this line.";
1903 }
1904 catch (const std::invalid_argument& e)
1905 {
1906 EXPECT_STREQ(e.what(), "Element contains an invalid property");
1907 }
1908 }
1909
TEST(ConfigFileParserTests,ParseI2CCompareBit)1910 TEST(ConfigFileParserTests, ParseI2CCompareBit)
1911 {
1912 // Test where works
1913 {
1914 const json element = R"(
1915 {
1916 "register": "0xA0",
1917 "position": 3,
1918 "value": 0
1919 }
1920 )"_json;
1921 std::unique_ptr<I2CCompareBitAction> action =
1922 parseI2CCompareBit(element);
1923 EXPECT_EQ(action->getRegister(), 0xA0);
1924 EXPECT_EQ(action->getPosition(), 3);
1925 EXPECT_EQ(action->getValue(), 0);
1926 }
1927
1928 // Test where fails: Invalid property specified
1929 try
1930 {
1931 const json element = R"(
1932 {
1933 "register": "0xA0",
1934 "position": 3,
1935 "value": 0,
1936 "foo": 3
1937 }
1938 )"_json;
1939 parseI2CCompareBit(element);
1940 ADD_FAILURE() << "Should not have reached this line.";
1941 }
1942 catch (const std::invalid_argument& e)
1943 {
1944 EXPECT_STREQ(e.what(), "Element contains an invalid property");
1945 }
1946
1947 // Test where fails: Element is not an object
1948 try
1949 {
1950 const json element = R"( [ "0xFF", "0x01" ] )"_json;
1951 parseI2CCompareBit(element);
1952 ADD_FAILURE() << "Should not have reached this line.";
1953 }
1954 catch (const std::invalid_argument& e)
1955 {
1956 EXPECT_STREQ(e.what(), "Element is not an object");
1957 }
1958
1959 // Test where fails: register value is invalid
1960 try
1961 {
1962 const json element = R"(
1963 {
1964 "register": "0xAG",
1965 "position": 3,
1966 "value": 0
1967 }
1968 )"_json;
1969 parseI2CCompareBit(element);
1970 ADD_FAILURE() << "Should not have reached this line.";
1971 }
1972 catch (const std::invalid_argument& e)
1973 {
1974 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
1975 }
1976
1977 // Test where fails: position value is invalid
1978 try
1979 {
1980 const json element = R"(
1981 {
1982 "register": "0xA0",
1983 "position": 8,
1984 "value": 0
1985 }
1986 )"_json;
1987 parseI2CCompareBit(element);
1988 ADD_FAILURE() << "Should not have reached this line.";
1989 }
1990 catch (const std::invalid_argument& e)
1991 {
1992 EXPECT_STREQ(e.what(), "Element is not a bit position");
1993 }
1994
1995 // Test where fails: value value is invalid
1996 try
1997 {
1998 const json element = R"(
1999 {
2000 "register": "0xA0",
2001 "position": 3,
2002 "value": 2
2003 }
2004 )"_json;
2005 parseI2CCompareBit(element);
2006 ADD_FAILURE() << "Should not have reached this line.";
2007 }
2008 catch (const std::invalid_argument& e)
2009 {
2010 EXPECT_STREQ(e.what(), "Element is not a bit value");
2011 }
2012
2013 // Test where fails: Required register property not specified
2014 try
2015 {
2016 const json element = R"(
2017 {
2018 "position": 3,
2019 "value": 0
2020 }
2021 )"_json;
2022 parseI2CCompareBit(element);
2023 ADD_FAILURE() << "Should not have reached this line.";
2024 }
2025 catch (const std::invalid_argument& e)
2026 {
2027 EXPECT_STREQ(e.what(), "Required property missing: register");
2028 }
2029
2030 // Test where fails: Required position property not specified
2031 try
2032 {
2033 const json element = R"(
2034 {
2035 "register": "0xA0",
2036 "value": 0
2037 }
2038 )"_json;
2039 parseI2CCompareBit(element);
2040 ADD_FAILURE() << "Should not have reached this line.";
2041 }
2042 catch (const std::invalid_argument& e)
2043 {
2044 EXPECT_STREQ(e.what(), "Required property missing: position");
2045 }
2046
2047 // Test where fails: Required value property not specified
2048 try
2049 {
2050 const json element = R"(
2051 {
2052 "register": "0xA0",
2053 "position": 3
2054 }
2055 )"_json;
2056 parseI2CCompareBit(element);
2057 ADD_FAILURE() << "Should not have reached this line.";
2058 }
2059 catch (const std::invalid_argument& e)
2060 {
2061 EXPECT_STREQ(e.what(), "Required property missing: value");
2062 }
2063 }
2064
TEST(ConfigFileParserTests,ParseI2CCompareByte)2065 TEST(ConfigFileParserTests, ParseI2CCompareByte)
2066 {
2067 // Test where works: Only required properties specified
2068 {
2069 const json element = R"(
2070 {
2071 "register": "0x0A",
2072 "value": "0xCC"
2073 }
2074 )"_json;
2075 std::unique_ptr<I2CCompareByteAction> action =
2076 parseI2CCompareByte(element);
2077 EXPECT_EQ(action->getRegister(), 0x0A);
2078 EXPECT_EQ(action->getValue(), 0xCC);
2079 EXPECT_EQ(action->getMask(), 0xFF);
2080 }
2081
2082 // Test where works: All properties specified
2083 {
2084 const json element = R"(
2085 {
2086 "register": "0x0A",
2087 "value": "0xCC",
2088 "mask": "0xF7"
2089 }
2090 )"_json;
2091 std::unique_ptr<I2CCompareByteAction> action =
2092 parseI2CCompareByte(element);
2093 EXPECT_EQ(action->getRegister(), 0x0A);
2094 EXPECT_EQ(action->getValue(), 0xCC);
2095 EXPECT_EQ(action->getMask(), 0xF7);
2096 }
2097
2098 // Test where fails: Element is not an object
2099 try
2100 {
2101 const json element = R"( [ "0xFF", "0x01" ] )"_json;
2102 parseI2CCompareByte(element);
2103 ADD_FAILURE() << "Should not have reached this line.";
2104 }
2105 catch (const std::invalid_argument& e)
2106 {
2107 EXPECT_STREQ(e.what(), "Element is not an object");
2108 }
2109
2110 // Test where fails: Invalid property specified
2111 try
2112 {
2113 const json element = R"(
2114 {
2115 "register": "0x0A",
2116 "value": "0xCC",
2117 "mask": "0xF7",
2118 "foo": 1
2119 }
2120 )"_json;
2121 parseI2CCompareByte(element);
2122 ADD_FAILURE() << "Should not have reached this line.";
2123 }
2124 catch (const std::invalid_argument& e)
2125 {
2126 EXPECT_STREQ(e.what(), "Element contains an invalid property");
2127 }
2128
2129 // Test where fails: register value is invalid
2130 try
2131 {
2132 const json element = R"(
2133 {
2134 "register": "0x0Z",
2135 "value": "0xCC",
2136 "mask": "0xF7"
2137 }
2138 )"_json;
2139 parseI2CCompareByte(element);
2140 ADD_FAILURE() << "Should not have reached this line.";
2141 }
2142 catch (const std::invalid_argument& e)
2143 {
2144 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
2145 }
2146
2147 // Test where fails: value value is invalid
2148 try
2149 {
2150 const json element = R"(
2151 {
2152 "register": "0x0A",
2153 "value": "0xCCC",
2154 "mask": "0xF7"
2155 }
2156 )"_json;
2157 parseI2CCompareByte(element);
2158 ADD_FAILURE() << "Should not have reached this line.";
2159 }
2160 catch (const std::invalid_argument& e)
2161 {
2162 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
2163 }
2164
2165 // Test where fails: mask value is invalid
2166 try
2167 {
2168 const json element = R"(
2169 {
2170 "register": "0x0A",
2171 "value": "0xCC",
2172 "mask": "F7"
2173 }
2174 )"_json;
2175 parseI2CCompareByte(element);
2176 ADD_FAILURE() << "Should not have reached this line.";
2177 }
2178 catch (const std::invalid_argument& e)
2179 {
2180 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
2181 }
2182
2183 // Test where fails: Required register property not specified
2184 try
2185 {
2186 const json element = R"(
2187 {
2188 "value": "0xCC",
2189 "mask": "0xF7"
2190 }
2191 )"_json;
2192 parseI2CCompareByte(element);
2193 ADD_FAILURE() << "Should not have reached this line.";
2194 }
2195 catch (const std::invalid_argument& e)
2196 {
2197 EXPECT_STREQ(e.what(), "Required property missing: register");
2198 }
2199
2200 // Test where fails: Required value property not specified
2201 try
2202 {
2203 const json element = R"(
2204 {
2205 "register": "0x0A",
2206 "mask": "0xF7"
2207 }
2208 )"_json;
2209 parseI2CCompareByte(element);
2210 ADD_FAILURE() << "Should not have reached this line.";
2211 }
2212 catch (const std::invalid_argument& e)
2213 {
2214 EXPECT_STREQ(e.what(), "Required property missing: value");
2215 }
2216 }
2217
TEST(ConfigFileParserTests,ParseI2CCompareBytes)2218 TEST(ConfigFileParserTests, ParseI2CCompareBytes)
2219 {
2220 // Test where works: Only required properties specified
2221 {
2222 const json element = R"(
2223 {
2224 "register": "0x0A",
2225 "values": [ "0xCC", "0xFF" ]
2226 }
2227 )"_json;
2228 std::unique_ptr<I2CCompareBytesAction> action =
2229 parseI2CCompareBytes(element);
2230 EXPECT_EQ(action->getRegister(), 0x0A);
2231 EXPECT_EQ(action->getValues().size(), 2);
2232 EXPECT_EQ(action->getValues()[0], 0xCC);
2233 EXPECT_EQ(action->getValues()[1], 0xFF);
2234 EXPECT_EQ(action->getMasks().size(), 2);
2235 EXPECT_EQ(action->getMasks()[0], 0xFF);
2236 EXPECT_EQ(action->getMasks()[1], 0xFF);
2237 }
2238
2239 // Test where works: All properties specified
2240 {
2241 const json element = R"(
2242 {
2243 "register": "0x0A",
2244 "values": [ "0xCC", "0xFF" ],
2245 "masks": [ "0x7F", "0x77" ]
2246 }
2247 )"_json;
2248 std::unique_ptr<I2CCompareBytesAction> action =
2249 parseI2CCompareBytes(element);
2250 EXPECT_EQ(action->getRegister(), 0x0A);
2251 EXPECT_EQ(action->getValues().size(), 2);
2252 EXPECT_EQ(action->getValues()[0], 0xCC);
2253 EXPECT_EQ(action->getValues()[1], 0xFF);
2254 EXPECT_EQ(action->getMasks().size(), 2);
2255 EXPECT_EQ(action->getMasks()[0], 0x7F);
2256 EXPECT_EQ(action->getMasks()[1], 0x77);
2257 }
2258
2259 // Test where fails: Element is not an object
2260 try
2261 {
2262 const json element = R"( [ "0xFF", "0x01" ] )"_json;
2263 parseI2CCompareBytes(element);
2264 ADD_FAILURE() << "Should not have reached this line.";
2265 }
2266 catch (const std::invalid_argument& e)
2267 {
2268 EXPECT_STREQ(e.what(), "Element is not an object");
2269 }
2270
2271 // Test where fails: Invalid property specified
2272 try
2273 {
2274 const json element = R"(
2275 {
2276 "register": "0x0A",
2277 "values": [ "0xCC", "0xFF" ],
2278 "masks": [ "0x7F", "0x7F" ],
2279 "foo": 1
2280 }
2281 )"_json;
2282 parseI2CCompareBytes(element);
2283 ADD_FAILURE() << "Should not have reached this line.";
2284 }
2285 catch (const std::invalid_argument& e)
2286 {
2287 EXPECT_STREQ(e.what(), "Element contains an invalid property");
2288 }
2289
2290 // Test where fails: register value is invalid
2291 try
2292 {
2293 const json element = R"(
2294 {
2295 "register": "0x0Z",
2296 "values": [ "0xCC", "0xFF" ],
2297 "masks": [ "0x7F", "0x7F" ]
2298 }
2299 )"_json;
2300 parseI2CCompareBytes(element);
2301 ADD_FAILURE() << "Should not have reached this line.";
2302 }
2303 catch (const std::invalid_argument& e)
2304 {
2305 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
2306 }
2307
2308 // Test where fails: values value is invalid
2309 try
2310 {
2311 const json element = R"(
2312 {
2313 "register": "0x0A",
2314 "values": [ "0xCCC", "0xFF" ],
2315 "masks": [ "0x7F", "0x7F" ]
2316 }
2317 )"_json;
2318 parseI2CCompareBytes(element);
2319 ADD_FAILURE() << "Should not have reached this line.";
2320 }
2321 catch (const std::invalid_argument& e)
2322 {
2323 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
2324 }
2325
2326 // Test where fails: masks value is invalid
2327 try
2328 {
2329 const json element = R"(
2330 {
2331 "register": "0x0A",
2332 "values": [ "0xCC", "0xFF" ],
2333 "masks": [ "F", "0x7F" ]
2334 }
2335 )"_json;
2336 parseI2CCompareBytes(element);
2337 ADD_FAILURE() << "Should not have reached this line.";
2338 }
2339 catch (const std::invalid_argument& e)
2340 {
2341 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
2342 }
2343
2344 // Test where fails: number of elements in masks is invalid
2345 try
2346 {
2347 const json element = R"(
2348 {
2349 "register": "0x0A",
2350 "values": [ "0xCC", "0xFF" ],
2351 "masks": [ "0x7F" ]
2352 }
2353 )"_json;
2354 parseI2CCompareBytes(element);
2355 ADD_FAILURE() << "Should not have reached this line.";
2356 }
2357 catch (const std::invalid_argument& e)
2358 {
2359 EXPECT_STREQ(e.what(), "Invalid number of elements in masks");
2360 }
2361
2362 // Test where fails: Required register property not specified
2363 try
2364 {
2365 const json element = R"(
2366 {
2367 "values": [ "0xCC", "0xFF" ]
2368 }
2369 )"_json;
2370 parseI2CCompareBytes(element);
2371 ADD_FAILURE() << "Should not have reached this line.";
2372 }
2373 catch (const std::invalid_argument& e)
2374 {
2375 EXPECT_STREQ(e.what(), "Required property missing: register");
2376 }
2377
2378 // Test where fails: Required values property not specified
2379 try
2380 {
2381 const json element = R"(
2382 {
2383 "register": "0x0A"
2384 }
2385 )"_json;
2386 parseI2CCompareBytes(element);
2387 ADD_FAILURE() << "Should not have reached this line.";
2388 }
2389 catch (const std::invalid_argument& e)
2390 {
2391 EXPECT_STREQ(e.what(), "Required property missing: values");
2392 }
2393 }
2394
TEST(ConfigFileParserTests,ParseI2CWriteBit)2395 TEST(ConfigFileParserTests, ParseI2CWriteBit)
2396 {
2397 // Test where works
2398 {
2399 const json element = R"(
2400 {
2401 "register": "0xA0",
2402 "position": 3,
2403 "value": 0
2404 }
2405 )"_json;
2406 std::unique_ptr<I2CWriteBitAction> action = parseI2CWriteBit(element);
2407 EXPECT_EQ(action->getRegister(), 0xA0);
2408 EXPECT_EQ(action->getPosition(), 3);
2409 EXPECT_EQ(action->getValue(), 0);
2410 }
2411
2412 // Test where fails: Invalid property specified
2413 try
2414 {
2415 const json element = R"(
2416 {
2417 "register": "0xA0",
2418 "position": 3,
2419 "value": 0,
2420 "foo": 3
2421 }
2422 )"_json;
2423 parseI2CWriteBit(element);
2424 ADD_FAILURE() << "Should not have reached this line.";
2425 }
2426 catch (const std::invalid_argument& e)
2427 {
2428 EXPECT_STREQ(e.what(), "Element contains an invalid property");
2429 }
2430
2431 // Test where fails: Element is not an object
2432 try
2433 {
2434 const json element = R"( [ "0xFF", "0x01" ] )"_json;
2435 parseI2CWriteBit(element);
2436 ADD_FAILURE() << "Should not have reached this line.";
2437 }
2438 catch (const std::invalid_argument& e)
2439 {
2440 EXPECT_STREQ(e.what(), "Element is not an object");
2441 }
2442
2443 // Test where fails: register value is invalid
2444 try
2445 {
2446 const json element = R"(
2447 {
2448 "register": "0xAG",
2449 "position": 3,
2450 "value": 0
2451 }
2452 )"_json;
2453 parseI2CWriteBit(element);
2454 ADD_FAILURE() << "Should not have reached this line.";
2455 }
2456 catch (const std::invalid_argument& e)
2457 {
2458 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
2459 }
2460
2461 // Test where fails: position value is invalid
2462 try
2463 {
2464 const json element = R"(
2465 {
2466 "register": "0xA0",
2467 "position": 8,
2468 "value": 0
2469 }
2470 )"_json;
2471 parseI2CWriteBit(element);
2472 ADD_FAILURE() << "Should not have reached this line.";
2473 }
2474 catch (const std::invalid_argument& e)
2475 {
2476 EXPECT_STREQ(e.what(), "Element is not a bit position");
2477 }
2478
2479 // Test where fails: value value is invalid
2480 try
2481 {
2482 const json element = R"(
2483 {
2484 "register": "0xA0",
2485 "position": 3,
2486 "value": 2
2487 }
2488 )"_json;
2489 parseI2CWriteBit(element);
2490 ADD_FAILURE() << "Should not have reached this line.";
2491 }
2492 catch (const std::invalid_argument& e)
2493 {
2494 EXPECT_STREQ(e.what(), "Element is not a bit value");
2495 }
2496
2497 // Test where fails: Required register property not specified
2498 try
2499 {
2500 const json element = R"(
2501 {
2502 "position": 3,
2503 "value": 0
2504 }
2505 )"_json;
2506 parseI2CWriteBit(element);
2507 ADD_FAILURE() << "Should not have reached this line.";
2508 }
2509 catch (const std::invalid_argument& e)
2510 {
2511 EXPECT_STREQ(e.what(), "Required property missing: register");
2512 }
2513
2514 // Test where fails: Required position property not specified
2515 try
2516 {
2517 const json element = R"(
2518 {
2519 "register": "0xA0",
2520 "value": 0
2521 }
2522 )"_json;
2523 parseI2CWriteBit(element);
2524 ADD_FAILURE() << "Should not have reached this line.";
2525 }
2526 catch (const std::invalid_argument& e)
2527 {
2528 EXPECT_STREQ(e.what(), "Required property missing: position");
2529 }
2530
2531 // Test where fails: Required value property not specified
2532 try
2533 {
2534 const json element = R"(
2535 {
2536 "register": "0xA0",
2537 "position": 3
2538 }
2539 )"_json;
2540 parseI2CWriteBit(element);
2541 ADD_FAILURE() << "Should not have reached this line.";
2542 }
2543 catch (const std::invalid_argument& e)
2544 {
2545 EXPECT_STREQ(e.what(), "Required property missing: value");
2546 }
2547 }
2548
TEST(ConfigFileParserTests,ParseI2CWriteByte)2549 TEST(ConfigFileParserTests, ParseI2CWriteByte)
2550 {
2551 // Test where works: Only required properties specified
2552 {
2553 const json element = R"(
2554 {
2555 "register": "0x0A",
2556 "value": "0xCC"
2557 }
2558 )"_json;
2559 std::unique_ptr<I2CWriteByteAction> action = parseI2CWriteByte(element);
2560 EXPECT_EQ(action->getRegister(), 0x0A);
2561 EXPECT_EQ(action->getValue(), 0xCC);
2562 EXPECT_EQ(action->getMask(), 0xFF);
2563 }
2564
2565 // Test where works: All properties specified
2566 {
2567 const json element = R"(
2568 {
2569 "register": "0x0A",
2570 "value": "0xCC",
2571 "mask": "0xF7"
2572 }
2573 )"_json;
2574 std::unique_ptr<I2CWriteByteAction> action = parseI2CWriteByte(element);
2575 EXPECT_EQ(action->getRegister(), 0x0A);
2576 EXPECT_EQ(action->getValue(), 0xCC);
2577 EXPECT_EQ(action->getMask(), 0xF7);
2578 }
2579
2580 // Test where fails: Element is not an object
2581 try
2582 {
2583 const json element = R"( [ "0xFF", "0x01" ] )"_json;
2584 parseI2CWriteByte(element);
2585 ADD_FAILURE() << "Should not have reached this line.";
2586 }
2587 catch (const std::invalid_argument& e)
2588 {
2589 EXPECT_STREQ(e.what(), "Element is not an object");
2590 }
2591
2592 // Test where fails: Invalid property specified
2593 try
2594 {
2595 const json element = R"(
2596 {
2597 "register": "0x0A",
2598 "value": "0xCC",
2599 "mask": "0xF7",
2600 "foo": 1
2601 }
2602 )"_json;
2603 parseI2CWriteByte(element);
2604 ADD_FAILURE() << "Should not have reached this line.";
2605 }
2606 catch (const std::invalid_argument& e)
2607 {
2608 EXPECT_STREQ(e.what(), "Element contains an invalid property");
2609 }
2610
2611 // Test where fails: register value is invalid
2612 try
2613 {
2614 const json element = R"(
2615 {
2616 "register": "0x0Z",
2617 "value": "0xCC",
2618 "mask": "0xF7"
2619 }
2620 )"_json;
2621 parseI2CWriteByte(element);
2622 ADD_FAILURE() << "Should not have reached this line.";
2623 }
2624 catch (const std::invalid_argument& e)
2625 {
2626 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
2627 }
2628
2629 // Test where fails: value value is invalid
2630 try
2631 {
2632 const json element = R"(
2633 {
2634 "register": "0x0A",
2635 "value": "0xCCC",
2636 "mask": "0xF7"
2637 }
2638 )"_json;
2639 parseI2CWriteByte(element);
2640 ADD_FAILURE() << "Should not have reached this line.";
2641 }
2642 catch (const std::invalid_argument& e)
2643 {
2644 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
2645 }
2646
2647 // Test where fails: mask value is invalid
2648 try
2649 {
2650 const json element = R"(
2651 {
2652 "register": "0x0A",
2653 "value": "0xCC",
2654 "mask": "F7"
2655 }
2656 )"_json;
2657 parseI2CWriteByte(element);
2658 ADD_FAILURE() << "Should not have reached this line.";
2659 }
2660 catch (const std::invalid_argument& e)
2661 {
2662 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
2663 }
2664
2665 // Test where fails: Required register property not specified
2666 try
2667 {
2668 const json element = R"(
2669 {
2670 "value": "0xCC",
2671 "mask": "0xF7"
2672 }
2673 )"_json;
2674 parseI2CWriteByte(element);
2675 ADD_FAILURE() << "Should not have reached this line.";
2676 }
2677 catch (const std::invalid_argument& e)
2678 {
2679 EXPECT_STREQ(e.what(), "Required property missing: register");
2680 }
2681
2682 // Test where fails: Required value property not specified
2683 try
2684 {
2685 const json element = R"(
2686 {
2687 "register": "0x0A",
2688 "mask": "0xF7"
2689 }
2690 )"_json;
2691 parseI2CWriteByte(element);
2692 ADD_FAILURE() << "Should not have reached this line.";
2693 }
2694 catch (const std::invalid_argument& e)
2695 {
2696 EXPECT_STREQ(e.what(), "Required property missing: value");
2697 }
2698 }
2699
TEST(ConfigFileParserTests,ParseI2CWriteBytes)2700 TEST(ConfigFileParserTests, ParseI2CWriteBytes)
2701 {
2702 // Test where works: Only required properties specified
2703 {
2704 const json element = R"(
2705 {
2706 "register": "0x0A",
2707 "values": [ "0xCC", "0xFF" ]
2708 }
2709 )"_json;
2710 std::unique_ptr<I2CWriteBytesAction> action =
2711 parseI2CWriteBytes(element);
2712 EXPECT_EQ(action->getRegister(), 0x0A);
2713 EXPECT_EQ(action->getValues().size(), 2);
2714 EXPECT_EQ(action->getValues()[0], 0xCC);
2715 EXPECT_EQ(action->getValues()[1], 0xFF);
2716 EXPECT_EQ(action->getMasks().size(), 0);
2717 }
2718
2719 // Test where works: All properties specified
2720 {
2721 const json element = R"(
2722 {
2723 "register": "0x0A",
2724 "values": [ "0xCC", "0xFF" ],
2725 "masks": [ "0x7F", "0x77" ]
2726 }
2727 )"_json;
2728 std::unique_ptr<I2CWriteBytesAction> action =
2729 parseI2CWriteBytes(element);
2730 EXPECT_EQ(action->getRegister(), 0x0A);
2731 EXPECT_EQ(action->getValues().size(), 2);
2732 EXPECT_EQ(action->getValues()[0], 0xCC);
2733 EXPECT_EQ(action->getValues()[1], 0xFF);
2734 EXPECT_EQ(action->getMasks().size(), 2);
2735 EXPECT_EQ(action->getMasks()[0], 0x7F);
2736 EXPECT_EQ(action->getMasks()[1], 0x77);
2737 }
2738
2739 // Test where fails: Element is not an object
2740 try
2741 {
2742 const json element = R"( [ "0xFF", "0x01" ] )"_json;
2743 parseI2CWriteBytes(element);
2744 ADD_FAILURE() << "Should not have reached this line.";
2745 }
2746 catch (const std::invalid_argument& e)
2747 {
2748 EXPECT_STREQ(e.what(), "Element is not an object");
2749 }
2750
2751 // Test where fails: Invalid property specified
2752 try
2753 {
2754 const json element = R"(
2755 {
2756 "register": "0x0A",
2757 "values": [ "0xCC", "0xFF" ],
2758 "masks": [ "0x7F", "0x7F" ],
2759 "foo": 1
2760 }
2761 )"_json;
2762 parseI2CWriteBytes(element);
2763 ADD_FAILURE() << "Should not have reached this line.";
2764 }
2765 catch (const std::invalid_argument& e)
2766 {
2767 EXPECT_STREQ(e.what(), "Element contains an invalid property");
2768 }
2769
2770 // Test where fails: register value is invalid
2771 try
2772 {
2773 const json element = R"(
2774 {
2775 "register": "0x0Z",
2776 "values": [ "0xCC", "0xFF" ],
2777 "masks": [ "0x7F", "0x7F" ]
2778 }
2779 )"_json;
2780 parseI2CWriteBytes(element);
2781 ADD_FAILURE() << "Should not have reached this line.";
2782 }
2783 catch (const std::invalid_argument& e)
2784 {
2785 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
2786 }
2787
2788 // Test where fails: values value is invalid
2789 try
2790 {
2791 const json element = R"(
2792 {
2793 "register": "0x0A",
2794 "values": [ "0xCCC", "0xFF" ],
2795 "masks": [ "0x7F", "0x7F" ]
2796 }
2797 )"_json;
2798 parseI2CWriteBytes(element);
2799 ADD_FAILURE() << "Should not have reached this line.";
2800 }
2801 catch (const std::invalid_argument& e)
2802 {
2803 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
2804 }
2805
2806 // Test where fails: masks value is invalid
2807 try
2808 {
2809 const json element = R"(
2810 {
2811 "register": "0x0A",
2812 "values": [ "0xCC", "0xFF" ],
2813 "masks": [ "F", "0x7F" ]
2814 }
2815 )"_json;
2816 parseI2CWriteBytes(element);
2817 ADD_FAILURE() << "Should not have reached this line.";
2818 }
2819 catch (const std::invalid_argument& e)
2820 {
2821 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
2822 }
2823
2824 // Test where fails: number of elements in masks is invalid
2825 try
2826 {
2827 const json element = R"(
2828 {
2829 "register": "0x0A",
2830 "values": [ "0xCC", "0xFF" ],
2831 "masks": [ "0x7F" ]
2832 }
2833 )"_json;
2834 parseI2CWriteBytes(element);
2835 ADD_FAILURE() << "Should not have reached this line.";
2836 }
2837 catch (const std::invalid_argument& e)
2838 {
2839 EXPECT_STREQ(e.what(), "Invalid number of elements in masks");
2840 }
2841
2842 // Test where fails: Required register property not specified
2843 try
2844 {
2845 const json element = R"(
2846 {
2847 "values": [ "0xCC", "0xFF" ]
2848 }
2849 )"_json;
2850 parseI2CWriteBytes(element);
2851 ADD_FAILURE() << "Should not have reached this line.";
2852 }
2853 catch (const std::invalid_argument& e)
2854 {
2855 EXPECT_STREQ(e.what(), "Required property missing: register");
2856 }
2857
2858 // Test where fails: Required values property not specified
2859 try
2860 {
2861 const json element = R"(
2862 {
2863 "register": "0x0A"
2864 }
2865 )"_json;
2866 parseI2CWriteBytes(element);
2867 ADD_FAILURE() << "Should not have reached this line.";
2868 }
2869 catch (const std::invalid_argument& e)
2870 {
2871 EXPECT_STREQ(e.what(), "Required property missing: values");
2872 }
2873 }
2874
TEST(ConfigFileParserTests,ParseIf)2875 TEST(ConfigFileParserTests, ParseIf)
2876 {
2877 // Test where works: Only required properties specified
2878 {
2879 const json element = R"(
2880 {
2881 "condition": { "run_rule": "is_downlevel_regulator" },
2882 "then": [ { "run_rule": "configure_downlevel_regulator" },
2883 { "run_rule": "configure_standard_regulator" } ]
2884 }
2885 )"_json;
2886 std::unique_ptr<IfAction> action = parseIf(element);
2887 EXPECT_NE(action->getConditionAction().get(), nullptr);
2888 EXPECT_EQ(action->getThenActions().size(), 2);
2889 EXPECT_EQ(action->getElseActions().size(), 0);
2890 }
2891
2892 // Test where works: All properties specified
2893 {
2894 const json element = R"(
2895 {
2896 "condition": { "run_rule": "is_downlevel_regulator" },
2897 "then": [ { "run_rule": "configure_downlevel_regulator" } ],
2898 "else": [ { "run_rule": "configure_standard_regulator" } ]
2899 }
2900 )"_json;
2901 std::unique_ptr<IfAction> action = parseIf(element);
2902 EXPECT_NE(action->getConditionAction().get(), nullptr);
2903 EXPECT_EQ(action->getThenActions().size(), 1);
2904 EXPECT_EQ(action->getElseActions().size(), 1);
2905 }
2906
2907 // Test where fails: Required condition property not specified
2908 try
2909 {
2910 const json element = R"(
2911 {
2912 "then": [ { "run_rule": "configure_downlevel_regulator" } ],
2913 "else": [ { "run_rule": "configure_standard_regulator" } ]
2914 }
2915 )"_json;
2916 parseIf(element);
2917 ADD_FAILURE() << "Should not have reached this line.";
2918 }
2919 catch (const std::invalid_argument& e)
2920 {
2921 EXPECT_STREQ(e.what(), "Required property missing: condition");
2922 }
2923
2924 // Test where fails: Required then property not specified
2925 try
2926 {
2927 const json element = R"(
2928 {
2929 "condition": { "run_rule": "is_downlevel_regulator" },
2930 "else": [ { "run_rule": "configure_standard_regulator" } ]
2931 }
2932 )"_json;
2933 parseIf(element);
2934 ADD_FAILURE() << "Should not have reached this line.";
2935 }
2936 catch (const std::invalid_argument& e)
2937 {
2938 EXPECT_STREQ(e.what(), "Required property missing: then");
2939 }
2940
2941 // Test where fails: condition value is invalid
2942 try
2943 {
2944 const json element = R"(
2945 {
2946 "condition": 1,
2947 "then": [ { "run_rule": "configure_downlevel_regulator" } ],
2948 "else": [ { "run_rule": "configure_standard_regulator" } ]
2949 }
2950 )"_json;
2951 parseIf(element);
2952 ADD_FAILURE() << "Should not have reached this line.";
2953 }
2954 catch (const std::invalid_argument& e)
2955 {
2956 EXPECT_STREQ(e.what(), "Element is not an object");
2957 }
2958
2959 // Test where fails: then value is invalid
2960 try
2961 {
2962 const json element = R"(
2963 {
2964 "condition": { "run_rule": "is_downlevel_regulator" },
2965 "then": "foo",
2966 "else": [ { "run_rule": "configure_standard_regulator" } ]
2967 }
2968 )"_json;
2969 parseIf(element);
2970 ADD_FAILURE() << "Should not have reached this line.";
2971 }
2972 catch (const std::invalid_argument& e)
2973 {
2974 EXPECT_STREQ(e.what(), "Element is not an array");
2975 }
2976
2977 // Test where fails: else value is invalid
2978 try
2979 {
2980 const json element = R"(
2981 {
2982 "condition": { "run_rule": "is_downlevel_regulator" },
2983 "then": [ { "run_rule": "configure_downlevel_regulator" } ],
2984 "else": 1
2985 }
2986 )"_json;
2987 parseIf(element);
2988 ADD_FAILURE() << "Should not have reached this line.";
2989 }
2990 catch (const std::invalid_argument& e)
2991 {
2992 EXPECT_STREQ(e.what(), "Element is not an array");
2993 }
2994
2995 // Test where fails: Invalid property specified
2996 try
2997 {
2998 const json element = R"(
2999 {
3000 "condition": { "run_rule": "is_downlevel_regulator" },
3001 "then": [ { "run_rule": "configure_downlevel_regulator" } ],
3002 "foo": "bar"
3003 }
3004 )"_json;
3005 parseIf(element);
3006 ADD_FAILURE() << "Should not have reached this line.";
3007 }
3008 catch (const std::invalid_argument& e)
3009 {
3010 EXPECT_STREQ(e.what(), "Element contains an invalid property");
3011 }
3012
3013 // Test where fails: Element is not an object
3014 try
3015 {
3016 const json element = R"( [ "0xFF", "0x01" ] )"_json;
3017 parseIf(element);
3018 ADD_FAILURE() << "Should not have reached this line.";
3019 }
3020 catch (const std::invalid_argument& e)
3021 {
3022 EXPECT_STREQ(e.what(), "Element is not an object");
3023 }
3024 }
3025
TEST(ConfigFileParserTests,ParseInventoryPath)3026 TEST(ConfigFileParserTests, ParseInventoryPath)
3027 {
3028 // Test where works: Inventory path has a leading '/'
3029 {
3030 const json element = "/system/chassis/motherboard/cpu3";
3031 std::string value = parseInventoryPath(element);
3032 EXPECT_EQ(
3033 value,
3034 "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu3");
3035 }
3036
3037 // Test where works: Inventory path does not have a leading '/'
3038 {
3039 const json element = "system/chassis/motherboard/cpu1";
3040 std::string value = parseInventoryPath(element);
3041 EXPECT_EQ(
3042 value,
3043 "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu1");
3044 }
3045
3046 // Test where fails: JSON element is not a string
3047 try
3048 {
3049 const json element = R"( { "foo": "bar" } )"_json;
3050 parseInventoryPath(element);
3051 ADD_FAILURE() << "Should not have reached this line.";
3052 }
3053 catch (const std::invalid_argument& e)
3054 {
3055 EXPECT_STREQ(e.what(), "Element is not a string");
3056 }
3057
3058 // Test where fails: JSON element contains an empty string
3059 try
3060 {
3061 const json element = "";
3062 parseInventoryPath(element);
3063 ADD_FAILURE() << "Should not have reached this line.";
3064 }
3065 catch (const std::invalid_argument& e)
3066 {
3067 EXPECT_STREQ(e.what(), "Element contains an empty string");
3068 }
3069 }
3070
TEST(ConfigFileParserTests,ParseLogPhaseFault)3071 TEST(ConfigFileParserTests, ParseLogPhaseFault)
3072 {
3073 // Test where works
3074 {
3075 const json element = R"(
3076 {
3077 "type": "n+1"
3078 }
3079 )"_json;
3080 std::unique_ptr<LogPhaseFaultAction> action =
3081 parseLogPhaseFault(element);
3082 EXPECT_EQ(action->getType(), PhaseFaultType::n_plus_1);
3083 }
3084
3085 // Test where fails: Element is not an object
3086 try
3087 {
3088 const json element = R"( [ "0xFF", "0x01" ] )"_json;
3089 parseLogPhaseFault(element);
3090 ADD_FAILURE() << "Should not have reached this line.";
3091 }
3092 catch (const std::invalid_argument& e)
3093 {
3094 EXPECT_STREQ(e.what(), "Element is not an object");
3095 }
3096
3097 // Test where fails: Required type property not specified
3098 try
3099 {
3100 const json element = R"(
3101 {
3102 }
3103 )"_json;
3104 parseLogPhaseFault(element);
3105 ADD_FAILURE() << "Should not have reached this line.";
3106 }
3107 catch (const std::invalid_argument& e)
3108 {
3109 EXPECT_STREQ(e.what(), "Required property missing: type");
3110 }
3111
3112 // Test where fails: type value is invalid
3113 try
3114 {
3115 const json element = R"(
3116 {
3117 "type": "n+2"
3118 }
3119 )"_json;
3120 parseLogPhaseFault(element);
3121 ADD_FAILURE() << "Should not have reached this line.";
3122 }
3123 catch (const std::invalid_argument& e)
3124 {
3125 EXPECT_STREQ(e.what(), "Element is not a phase fault type");
3126 }
3127
3128 // Test where fails: Invalid property specified
3129 try
3130 {
3131 const json element = R"(
3132 {
3133 "type": "n+1",
3134 "foo": 1
3135 }
3136 )"_json;
3137 parseLogPhaseFault(element);
3138 ADD_FAILURE() << "Should not have reached this line.";
3139 }
3140 catch (const std::invalid_argument& e)
3141 {
3142 EXPECT_STREQ(e.what(), "Element contains an invalid property");
3143 }
3144 }
3145
TEST(ConfigFileParserTests,ParseNot)3146 TEST(ConfigFileParserTests, ParseNot)
3147 {
3148 // Test where works
3149 {
3150 const json element = R"(
3151 { "i2c_compare_byte": { "register": "0xA0", "value": "0x00" } }
3152 )"_json;
3153 std::unique_ptr<NotAction> action = parseNot(element);
3154 EXPECT_NE(action->getAction().get(), nullptr);
3155 }
3156
3157 // Test where fails: Element is not an object
3158 try
3159 {
3160 const json element = R"( [ "0xFF", "0x01" ] )"_json;
3161 parseNot(element);
3162 ADD_FAILURE() << "Should not have reached this line.";
3163 }
3164 catch (const std::invalid_argument& e)
3165 {
3166 EXPECT_STREQ(e.what(), "Element is not an object");
3167 }
3168 }
3169
TEST(ConfigFileParserTests,ParseOr)3170 TEST(ConfigFileParserTests, ParseOr)
3171 {
3172 // Test where works: Element is an array with 2 actions
3173 {
3174 const json element = R"(
3175 [
3176 { "i2c_compare_byte": { "register": "0xA0", "value": "0x00" } },
3177 { "i2c_compare_byte": { "register": "0xA1", "value": "0x00" } }
3178 ]
3179 )"_json;
3180 std::unique_ptr<OrAction> action = parseOr(element);
3181 EXPECT_EQ(action->getActions().size(), 2);
3182 }
3183
3184 // Test where fails: Element is an array with 1 action
3185 try
3186 {
3187 const json element = R"(
3188 [
3189 { "i2c_compare_byte": { "register": "0xA0", "value": "0x00" } }
3190 ]
3191 )"_json;
3192 parseOr(element);
3193 ADD_FAILURE() << "Should not have reached this line.";
3194 }
3195 catch (const std::invalid_argument& e)
3196 {
3197 EXPECT_STREQ(e.what(), "Array must contain two or more actions");
3198 }
3199
3200 // Test where fails: Element is not an array
3201 try
3202 {
3203 const json element = R"(
3204 {
3205 "foo": "bar"
3206 }
3207 )"_json;
3208 parseOr(element);
3209 ADD_FAILURE() << "Should not have reached this line.";
3210 }
3211 catch (const std::invalid_argument& e)
3212 {
3213 EXPECT_STREQ(e.what(), "Element is not an array");
3214 }
3215 }
3216
TEST(ConfigFileParserTests,ParsePhaseFaultDetection)3217 TEST(ConfigFileParserTests, ParsePhaseFaultDetection)
3218 {
3219 // Test where works: actions specified: optional properties not specified
3220 {
3221 const json element = R"(
3222 {
3223 "actions": [
3224 { "run_rule": "detect_phase_fault_rule" }
3225 ]
3226 }
3227 )"_json;
3228 std::unique_ptr<PhaseFaultDetection> phaseFaultDetection =
3229 parsePhaseFaultDetection(element);
3230 EXPECT_EQ(phaseFaultDetection->getActions().size(), 1);
3231 EXPECT_EQ(phaseFaultDetection->getDeviceID(), "");
3232 }
3233
3234 // Test where works: rule_id specified: optional properties specified
3235 {
3236 const json element = R"(
3237 {
3238 "comments": [ "Detect phase fault using I/O expander" ],
3239 "device_id": "io_expander",
3240 "rule_id": "detect_phase_fault_rule"
3241 }
3242 )"_json;
3243 std::unique_ptr<PhaseFaultDetection> phaseFaultDetection =
3244 parsePhaseFaultDetection(element);
3245 EXPECT_EQ(phaseFaultDetection->getActions().size(), 1);
3246 EXPECT_EQ(phaseFaultDetection->getDeviceID(), "io_expander");
3247 }
3248
3249 // Test where fails: Element is not an object
3250 try
3251 {
3252 const json element = R"( [ "foo", "bar" ] )"_json;
3253 parsePhaseFaultDetection(element);
3254 ADD_FAILURE() << "Should not have reached this line.";
3255 }
3256 catch (const std::invalid_argument& e)
3257 {
3258 EXPECT_STREQ(e.what(), "Element is not an object");
3259 }
3260
3261 // Test where fails: device_id value is invalid
3262 try
3263 {
3264 const json element = R"(
3265 {
3266 "device_id": 1,
3267 "rule_id": "detect_phase_fault_rule"
3268 }
3269 )"_json;
3270 parsePhaseFaultDetection(element);
3271 ADD_FAILURE() << "Should not have reached this line.";
3272 }
3273 catch (const std::invalid_argument& e)
3274 {
3275 EXPECT_STREQ(e.what(), "Element is not a string");
3276 }
3277
3278 // Test where fails: rule_id value is invalid
3279 try
3280 {
3281 const json element = R"(
3282 {
3283 "rule_id": 1
3284 }
3285 )"_json;
3286 parsePhaseFaultDetection(element);
3287 ADD_FAILURE() << "Should not have reached this line.";
3288 }
3289 catch (const std::invalid_argument& e)
3290 {
3291 EXPECT_STREQ(e.what(), "Element is not a string");
3292 }
3293
3294 // Test where fails: actions object is invalid
3295 try
3296 {
3297 const json element = R"(
3298 {
3299 "actions": 1
3300 }
3301 )"_json;
3302 parsePhaseFaultDetection(element);
3303 ADD_FAILURE() << "Should not have reached this line.";
3304 }
3305 catch (const std::invalid_argument& e)
3306 {
3307 EXPECT_STREQ(e.what(), "Element is not an array");
3308 }
3309
3310 // Test where fails: Required actions or rule_id property not specified
3311 try
3312 {
3313 const json element = R"(
3314 {
3315 "device_id": "io_expander"
3316 }
3317 )"_json;
3318 parsePhaseFaultDetection(element);
3319 ADD_FAILURE() << "Should not have reached this line.";
3320 }
3321 catch (const std::invalid_argument& e)
3322 {
3323 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain "
3324 "either rule_id or actions");
3325 }
3326
3327 // Test where fails: Required actions or rule_id property both specified
3328 try
3329 {
3330 const json element = R"(
3331 {
3332 "rule_id": "detect_phase_fault_rule",
3333 "actions": [
3334 { "run_rule": "detect_phase_fault_rule" }
3335 ]
3336 }
3337 )"_json;
3338 parsePhaseFaultDetection(element);
3339 ADD_FAILURE() << "Should not have reached this line.";
3340 }
3341 catch (const std::invalid_argument& e)
3342 {
3343 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain "
3344 "either rule_id or actions");
3345 }
3346
3347 // Test where fails: Invalid property specified
3348 try
3349 {
3350 const json element = R"(
3351 {
3352 "foo": "bar",
3353 "actions": [
3354 { "run_rule": "detect_phase_fault_rule" }
3355 ]
3356 }
3357 )"_json;
3358 parsePhaseFaultDetection(element);
3359 ADD_FAILURE() << "Should not have reached this line.";
3360 }
3361 catch (const std::invalid_argument& e)
3362 {
3363 EXPECT_STREQ(e.what(), "Element contains an invalid property");
3364 }
3365 }
3366
TEST(ConfigFileParserTests,ParsePhaseFaultType)3367 TEST(ConfigFileParserTests, ParsePhaseFaultType)
3368 {
3369 // Test where works: n
3370 {
3371 const json element = "n";
3372 PhaseFaultType type = parsePhaseFaultType(element);
3373 EXPECT_EQ(type, PhaseFaultType::n);
3374 }
3375
3376 // Test where works: n+1
3377 {
3378 const json element = "n+1";
3379 PhaseFaultType type = parsePhaseFaultType(element);
3380 EXPECT_EQ(type, PhaseFaultType::n_plus_1);
3381 }
3382
3383 // Test where fails: Element is not a phase fault type
3384 try
3385 {
3386 const json element = "n+2";
3387 parsePhaseFaultType(element);
3388 ADD_FAILURE() << "Should not have reached this line.";
3389 }
3390 catch (const std::invalid_argument& e)
3391 {
3392 EXPECT_STREQ(e.what(), "Element is not a phase fault type");
3393 }
3394
3395 // Test where fails: Element is not a string
3396 try
3397 {
3398 const json element = R"( { "foo": "bar" } )"_json;
3399 parsePhaseFaultType(element);
3400 ADD_FAILURE() << "Should not have reached this line.";
3401 }
3402 catch (const std::invalid_argument& e)
3403 {
3404 EXPECT_STREQ(e.what(), "Element is not a string");
3405 }
3406 }
3407
TEST(ConfigFileParserTests,ParsePMBusReadSensor)3408 TEST(ConfigFileParserTests, ParsePMBusReadSensor)
3409 {
3410 // Test where works: Only required properties specified
3411 {
3412 const json element = R"(
3413 {
3414 "type": "iout",
3415 "command": "0x8C",
3416 "format": "linear_11"
3417 }
3418 )"_json;
3419 std::unique_ptr<PMBusReadSensorAction> action =
3420 parsePMBusReadSensor(element);
3421 EXPECT_EQ(action->getType(), SensorType::iout);
3422 EXPECT_EQ(action->getCommand(), 0x8C);
3423 EXPECT_EQ(action->getFormat(),
3424 pmbus_utils::SensorDataFormat::linear_11);
3425 EXPECT_EQ(action->getExponent().has_value(), false);
3426 }
3427
3428 // Test where works: All properties specified
3429 {
3430 const json element = R"(
3431 {
3432 "type": "temperature",
3433 "command": "0x7A",
3434 "format": "linear_16",
3435 "exponent": -8
3436 }
3437 )"_json;
3438 std::unique_ptr<PMBusReadSensorAction> action =
3439 parsePMBusReadSensor(element);
3440 EXPECT_EQ(action->getType(), SensorType::temperature);
3441 EXPECT_EQ(action->getCommand(), 0x7A);
3442 EXPECT_EQ(action->getFormat(),
3443 pmbus_utils::SensorDataFormat::linear_16);
3444 EXPECT_EQ(action->getExponent().has_value(), true);
3445 EXPECT_EQ(action->getExponent().value(), -8);
3446 }
3447
3448 // Test where fails: Element is not an object
3449 try
3450 {
3451 const json element = R"( [ "0xFF", "0x01" ] )"_json;
3452 parsePMBusReadSensor(element);
3453 ADD_FAILURE() << "Should not have reached this line.";
3454 }
3455 catch (const std::invalid_argument& e)
3456 {
3457 EXPECT_STREQ(e.what(), "Element is not an object");
3458 }
3459
3460 // Test where fails: Invalid property specified
3461 try
3462 {
3463 const json element = R"(
3464 {
3465 "type": "iout",
3466 "command": "0x8C",
3467 "format": "linear_11",
3468 "foo": 1
3469 }
3470 )"_json;
3471 parsePMBusReadSensor(element);
3472 ADD_FAILURE() << "Should not have reached this line.";
3473 }
3474 catch (const std::invalid_argument& e)
3475 {
3476 EXPECT_STREQ(e.what(), "Element contains an invalid property");
3477 }
3478
3479 // Test where fails: Required type property not specified
3480 try
3481 {
3482 const json element = R"(
3483 {
3484 "command": "0x8C",
3485 "format": "linear_11"
3486 }
3487 )"_json;
3488 parsePMBusReadSensor(element);
3489 ADD_FAILURE() << "Should not have reached this line.";
3490 }
3491 catch (const std::invalid_argument& e)
3492 {
3493 EXPECT_STREQ(e.what(), "Required property missing: type");
3494 }
3495
3496 // Test where fails: Required command property not specified
3497 try
3498 {
3499 const json element = R"(
3500 {
3501 "type": "iout",
3502 "format": "linear_11"
3503 }
3504 )"_json;
3505 parsePMBusReadSensor(element);
3506 ADD_FAILURE() << "Should not have reached this line.";
3507 }
3508 catch (const std::invalid_argument& e)
3509 {
3510 EXPECT_STREQ(e.what(), "Required property missing: command");
3511 }
3512
3513 // Test where fails: Required format property not specified
3514 try
3515 {
3516 const json element = R"(
3517 {
3518 "type": "iout",
3519 "command": "0x8C"
3520 }
3521 )"_json;
3522 parsePMBusReadSensor(element);
3523 ADD_FAILURE() << "Should not have reached this line.";
3524 }
3525 catch (const std::invalid_argument& e)
3526 {
3527 EXPECT_STREQ(e.what(), "Required property missing: format");
3528 }
3529
3530 // Test where fails: type value is invalid
3531 try
3532 {
3533 const json element = R"(
3534 {
3535 "type": 1,
3536 "command": "0x7A",
3537 "format": "linear_16"
3538 }
3539 )"_json;
3540 parsePMBusReadSensor(element);
3541 ADD_FAILURE() << "Should not have reached this line.";
3542 }
3543 catch (const std::invalid_argument& e)
3544 {
3545 EXPECT_STREQ(e.what(), "Element is not a string");
3546 }
3547
3548 // Test where fails: command value is invalid
3549 try
3550 {
3551 const json element = R"(
3552 {
3553 "type": "temperature",
3554 "command": 0,
3555 "format": "linear_16"
3556 }
3557 )"_json;
3558 parsePMBusReadSensor(element);
3559 ADD_FAILURE() << "Should not have reached this line.";
3560 }
3561 catch (const std::invalid_argument& e)
3562 {
3563 EXPECT_STREQ(e.what(), "Element is not a string");
3564 }
3565
3566 // Test where fails: format value is invalid
3567 try
3568 {
3569 const json element = R"(
3570 {
3571 "type": "temperature",
3572 "command": "0x7A",
3573 "format": 1
3574 }
3575 )"_json;
3576 parsePMBusReadSensor(element);
3577 ADD_FAILURE() << "Should not have reached this line.";
3578 }
3579 catch (const std::invalid_argument& e)
3580 {
3581 EXPECT_STREQ(e.what(), "Element is not a string");
3582 }
3583
3584 // Test where fails: exponent value is invalid
3585 try
3586 {
3587 const json element = R"(
3588 {
3589 "type": "temperature",
3590 "command": "0x7A",
3591 "format": "linear_16",
3592 "exponent": 1.3
3593 }
3594 )"_json;
3595 parsePMBusReadSensor(element);
3596 ADD_FAILURE() << "Should not have reached this line.";
3597 }
3598 catch (const std::invalid_argument& e)
3599 {
3600 EXPECT_STREQ(e.what(), "Element is not an integer");
3601 }
3602 }
3603
TEST(ConfigFileParserTests,ParsePMBusWriteVoutCommand)3604 TEST(ConfigFileParserTests, ParsePMBusWriteVoutCommand)
3605 {
3606 // Test where works: Only required properties specified
3607 {
3608 const json element = R"(
3609 {
3610 "format": "linear"
3611 }
3612 )"_json;
3613 std::unique_ptr<PMBusWriteVoutCommandAction> action =
3614 parsePMBusWriteVoutCommand(element);
3615 EXPECT_EQ(action->getVolts().has_value(), false);
3616 EXPECT_EQ(action->getFormat(), pmbus_utils::VoutDataFormat::linear);
3617 EXPECT_EQ(action->getExponent().has_value(), false);
3618 EXPECT_EQ(action->isVerified(), false);
3619 }
3620
3621 // Test where works: All properties specified
3622 {
3623 const json element = R"(
3624 {
3625 "volts": 1.03,
3626 "format": "linear",
3627 "exponent": -8,
3628 "is_verified": true
3629 }
3630 )"_json;
3631 std::unique_ptr<PMBusWriteVoutCommandAction> action =
3632 parsePMBusWriteVoutCommand(element);
3633 EXPECT_EQ(action->getVolts().has_value(), true);
3634 EXPECT_EQ(action->getVolts().value(), 1.03);
3635 EXPECT_EQ(action->getFormat(), pmbus_utils::VoutDataFormat::linear);
3636 EXPECT_EQ(action->getExponent().has_value(), true);
3637 EXPECT_EQ(action->getExponent().value(), -8);
3638 EXPECT_EQ(action->isVerified(), true);
3639 }
3640
3641 // Test where fails: Element is not an object
3642 try
3643 {
3644 const json element = R"( [ "0xFF", "0x01" ] )"_json;
3645 parsePMBusWriteVoutCommand(element);
3646 ADD_FAILURE() << "Should not have reached this line.";
3647 }
3648 catch (const std::invalid_argument& e)
3649 {
3650 EXPECT_STREQ(e.what(), "Element is not an object");
3651 }
3652
3653 // Test where fails: volts value is invalid
3654 try
3655 {
3656 const json element = R"(
3657 {
3658 "volts": "foo",
3659 "format": "linear"
3660 }
3661 )"_json;
3662 parsePMBusWriteVoutCommand(element);
3663 ADD_FAILURE() << "Should not have reached this line.";
3664 }
3665 catch (const std::invalid_argument& e)
3666 {
3667 EXPECT_STREQ(e.what(), "Element is not a double");
3668 }
3669
3670 // Test where fails: Required format property not specified
3671 try
3672 {
3673 const json element = R"(
3674 {
3675 "volts": 1.03,
3676 "is_verified": true
3677 }
3678 )"_json;
3679 parsePMBusWriteVoutCommand(element);
3680 ADD_FAILURE() << "Should not have reached this line.";
3681 }
3682 catch (const std::invalid_argument& e)
3683 {
3684 EXPECT_STREQ(e.what(), "Required property missing: format");
3685 }
3686
3687 // Test where fails: format value is invalid
3688 try
3689 {
3690 const json element = R"(
3691 {
3692 "format": "linear_11"
3693 }
3694 )"_json;
3695 parsePMBusWriteVoutCommand(element);
3696 ADD_FAILURE() << "Should not have reached this line.";
3697 }
3698 catch (const std::invalid_argument& e)
3699 {
3700 EXPECT_STREQ(e.what(), "Invalid format value: linear_11");
3701 }
3702
3703 // Test where fails: exponent value is invalid
3704 try
3705 {
3706 const json element = R"(
3707 {
3708 "format": "linear",
3709 "exponent": 1.3
3710 }
3711 )"_json;
3712 parsePMBusWriteVoutCommand(element);
3713 ADD_FAILURE() << "Should not have reached this line.";
3714 }
3715 catch (const std::invalid_argument& e)
3716 {
3717 EXPECT_STREQ(e.what(), "Element is not an integer");
3718 }
3719
3720 // Test where fails: is_verified value is invalid
3721 try
3722 {
3723 const json element = R"(
3724 {
3725 "format": "linear",
3726 "is_verified": "true"
3727 }
3728 )"_json;
3729 parsePMBusWriteVoutCommand(element);
3730 ADD_FAILURE() << "Should not have reached this line.";
3731 }
3732 catch (const std::invalid_argument& e)
3733 {
3734 EXPECT_STREQ(e.what(), "Element is not a boolean");
3735 }
3736
3737 // Test where fails: Invalid property specified
3738 try
3739 {
3740 const json element = R"(
3741 {
3742 "format": "linear",
3743 "foo": "bar"
3744 }
3745 )"_json;
3746 parsePMBusWriteVoutCommand(element);
3747 ADD_FAILURE() << "Should not have reached this line.";
3748 }
3749 catch (const std::invalid_argument& e)
3750 {
3751 EXPECT_STREQ(e.what(), "Element contains an invalid property");
3752 }
3753 }
3754
TEST(ConfigFileParserTests,ParsePresenceDetection)3755 TEST(ConfigFileParserTests, ParsePresenceDetection)
3756 {
3757 // Test where works: actions property specified
3758 {
3759 const json element = R"(
3760 {
3761 "actions": [
3762 { "run_rule": "read_sensors_rule" }
3763 ]
3764 }
3765 )"_json;
3766 std::unique_ptr<PresenceDetection> presenceDetection =
3767 parsePresenceDetection(element);
3768 EXPECT_EQ(presenceDetection->getActions().size(), 1);
3769 }
3770
3771 // Test where works: rule_id property specified
3772 {
3773 const json element = R"(
3774 {
3775 "comments": [ "comments property" ],
3776 "rule_id": "set_voltage_rule"
3777 }
3778 )"_json;
3779 std::unique_ptr<PresenceDetection> presenceDetection =
3780 parsePresenceDetection(element);
3781 EXPECT_EQ(presenceDetection->getActions().size(), 1);
3782 }
3783
3784 // Test where fails: actions object is invalid
3785 try
3786 {
3787 const json element = R"(
3788 {
3789 "actions": 1
3790 }
3791 )"_json;
3792 parsePresenceDetection(element);
3793 ADD_FAILURE() << "Should not have reached this line.";
3794 }
3795 catch (const std::invalid_argument& e)
3796 {
3797 EXPECT_STREQ(e.what(), "Element is not an array");
3798 }
3799
3800 // Test where fails: rule_id value is invalid
3801 try
3802 {
3803 const json element = R"(
3804 {
3805 "rule_id": 1
3806 }
3807 )"_json;
3808 parsePresenceDetection(element);
3809 ADD_FAILURE() << "Should not have reached this line.";
3810 }
3811 catch (const std::invalid_argument& e)
3812 {
3813 EXPECT_STREQ(e.what(), "Element is not a string");
3814 }
3815
3816 // Test where fails: Required actions or rule_id property not specified
3817 try
3818 {
3819 const json element = R"(
3820 {
3821 "comments": [ "comments property" ]
3822 }
3823 )"_json;
3824 parsePresenceDetection(element);
3825 ADD_FAILURE() << "Should not have reached this line.";
3826 }
3827 catch (const std::invalid_argument& e)
3828 {
3829 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain "
3830 "either rule_id or actions");
3831 }
3832
3833 // Test where fails: Required actions or rule_id property both specified
3834 try
3835 {
3836 const json element = R"(
3837 {
3838 "rule_id": "set_voltage_rule",
3839 "actions": [
3840 { "run_rule": "read_sensors_rule" }
3841 ]
3842 }
3843 )"_json;
3844 parsePresenceDetection(element);
3845 ADD_FAILURE() << "Should not have reached this line.";
3846 }
3847 catch (const std::invalid_argument& e)
3848 {
3849 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain "
3850 "either rule_id or actions");
3851 }
3852
3853 // Test where fails: Element is not an object
3854 try
3855 {
3856 const json element = R"( [ "foo", "bar" ] )"_json;
3857 parsePresenceDetection(element);
3858 ADD_FAILURE() << "Should not have reached this line.";
3859 }
3860 catch (const std::invalid_argument& e)
3861 {
3862 EXPECT_STREQ(e.what(), "Element is not an object");
3863 }
3864
3865 // Test where fails: Invalid property specified
3866 try
3867 {
3868 const json element = R"(
3869 {
3870 "foo": "bar",
3871 "actions": [
3872 { "run_rule": "read_sensors_rule" }
3873 ]
3874 }
3875 )"_json;
3876 parsePresenceDetection(element);
3877 ADD_FAILURE() << "Should not have reached this line.";
3878 }
3879 catch (const std::invalid_argument& e)
3880 {
3881 EXPECT_STREQ(e.what(), "Element contains an invalid property");
3882 }
3883 }
3884
TEST(ConfigFileParserTests,ParseRail)3885 TEST(ConfigFileParserTests, ParseRail)
3886 {
3887 // Test where works: Only required properties specified
3888 {
3889 const json element = R"(
3890 {
3891 "id": "vdd"
3892 }
3893 )"_json;
3894 std::unique_ptr<Rail> rail = parseRail(element);
3895 EXPECT_EQ(rail->getID(), "vdd");
3896 EXPECT_EQ(rail->getConfiguration(), nullptr);
3897 EXPECT_EQ(rail->getSensorMonitoring(), nullptr);
3898 }
3899
3900 // Test where works: All properties specified
3901 {
3902 const json element = R"(
3903 {
3904 "comments": [ "comments property" ],
3905 "id": "vdd",
3906 "configuration": {
3907 "volts": 1.1,
3908 "actions": [
3909 {
3910 "pmbus_write_vout_command": {
3911 "format": "linear"
3912 }
3913 }
3914 ]
3915 },
3916 "sensor_monitoring": {
3917 "actions": [
3918 { "run_rule": "read_sensors_rule" }
3919 ]
3920 }
3921 }
3922 )"_json;
3923 std::unique_ptr<Rail> rail = parseRail(element);
3924 EXPECT_EQ(rail->getID(), "vdd");
3925 EXPECT_NE(rail->getConfiguration(), nullptr);
3926 EXPECT_NE(rail->getSensorMonitoring(), nullptr);
3927 }
3928
3929 // Test where fails: id property not specified
3930 try
3931 {
3932 const json element = R"(
3933 {
3934 "configuration": {
3935 "volts": 1.1,
3936 "actions": [
3937 {
3938 "pmbus_write_vout_command": {
3939 "format": "linear"
3940 }
3941 }
3942 ]
3943 }
3944 }
3945 )"_json;
3946 parseRail(element);
3947 ADD_FAILURE() << "Should not have reached this line.";
3948 }
3949 catch (const std::invalid_argument& e)
3950 {
3951 EXPECT_STREQ(e.what(), "Required property missing: id");
3952 }
3953
3954 // Test where fails: id property is invalid
3955 try
3956 {
3957 const json element = R"(
3958 {
3959 "id": "",
3960 "configuration": {
3961 "volts": 1.1,
3962 "actions": [
3963 {
3964 "pmbus_write_vout_command": {
3965 "format": "linear"
3966 }
3967 }
3968 ]
3969 }
3970 }
3971 )"_json;
3972 parseRail(element);
3973 ADD_FAILURE() << "Should not have reached this line.";
3974 }
3975 catch (const std::invalid_argument& e)
3976 {
3977 EXPECT_STREQ(e.what(), "Element contains an empty string");
3978 }
3979
3980 // Test where fails: Element is not an object
3981 try
3982 {
3983 const json element = R"( [ "0xFF", "0x01" ] )"_json;
3984 parseRail(element);
3985 ADD_FAILURE() << "Should not have reached this line.";
3986 }
3987 catch (const std::invalid_argument& e)
3988 {
3989 EXPECT_STREQ(e.what(), "Element is not an object");
3990 }
3991
3992 // Test where fails: configuration value is invalid
3993 try
3994 {
3995 const json element = R"(
3996 {
3997 "id": "vdd",
3998 "configuration": "config"
3999 }
4000 )"_json;
4001 parseRail(element);
4002 ADD_FAILURE() << "Should not have reached this line.";
4003 }
4004 catch (const std::invalid_argument& e)
4005 {
4006 EXPECT_STREQ(e.what(), "Element is not an object");
4007 }
4008
4009 // Test where fails: sensor_monitoring value is invalid
4010 try
4011 {
4012 const json element = R"(
4013 {
4014 "comments": [ "comments property" ],
4015 "id": "vdd",
4016 "configuration": {
4017 "volts": 1.1,
4018 "actions": [
4019 {
4020 "pmbus_write_vout_command": {
4021 "format": "linear"
4022 }
4023 }
4024 ]
4025 },
4026 "sensor_monitoring": 1
4027 }
4028 )"_json;
4029 parseRail(element);
4030 ADD_FAILURE() << "Should not have reached this line.";
4031 }
4032 catch (const std::invalid_argument& e)
4033 {
4034 EXPECT_STREQ(e.what(), "Element is not an object");
4035 }
4036
4037 // Test where fails: Invalid property specified
4038 try
4039 {
4040 const json element = R"(
4041 {
4042 "id": "vdd",
4043 "foo" : true
4044 }
4045 )"_json;
4046 parseRail(element);
4047 ADD_FAILURE() << "Should not have reached this line.";
4048 }
4049 catch (const std::invalid_argument& e)
4050 {
4051 EXPECT_STREQ(e.what(), "Element contains an invalid property");
4052 }
4053 }
4054
TEST(ConfigFileParserTests,ParseRailArray)4055 TEST(ConfigFileParserTests, ParseRailArray)
4056 {
4057 // Test where works
4058 {
4059 const json element = R"(
4060 [
4061 { "id": "vdd" },
4062 { "id": "vio" }
4063 ]
4064 )"_json;
4065 std::vector<std::unique_ptr<Rail>> rails = parseRailArray(element);
4066 EXPECT_EQ(rails.size(), 2);
4067 EXPECT_EQ(rails[0]->getID(), "vdd");
4068 EXPECT_EQ(rails[1]->getID(), "vio");
4069 }
4070
4071 // Test where fails: Element is not an array
4072 try
4073 {
4074 const json element = R"(
4075 {
4076 "foo": "bar"
4077 }
4078 )"_json;
4079 parseRailArray(element);
4080 ADD_FAILURE() << "Should not have reached this line.";
4081 }
4082 catch (const std::invalid_argument& e)
4083 {
4084 EXPECT_STREQ(e.what(), "Element is not an array");
4085 }
4086 }
4087
TEST(ConfigFileParserTests,ParseRoot)4088 TEST(ConfigFileParserTests, ParseRoot)
4089 {
4090 // Test where works: Only required properties specified
4091 {
4092 const json element = R"(
4093 {
4094 "chassis": [
4095 { "number": 1, "inventory_path": "system/chassis" }
4096 ]
4097 }
4098 )"_json;
4099 std::vector<std::unique_ptr<Rule>> rules{};
4100 std::vector<std::unique_ptr<Chassis>> chassis{};
4101 std::tie(rules, chassis) = parseRoot(element);
4102 EXPECT_EQ(rules.size(), 0);
4103 EXPECT_EQ(chassis.size(), 1);
4104 }
4105
4106 // Test where works: All properties specified
4107 {
4108 const json element = R"(
4109 {
4110 "comments": [ "Config file for a FooBar one-chassis system" ],
4111 "rules": [
4112 {
4113 "id": "set_voltage_rule",
4114 "actions": [
4115 { "pmbus_write_vout_command": { "format": "linear" } }
4116 ]
4117 }
4118 ],
4119 "chassis": [
4120 { "number": 1, "inventory_path": "system/chassis1" },
4121 { "number": 3, "inventory_path": "system/chassis3" }
4122 ]
4123 }
4124 )"_json;
4125 std::vector<std::unique_ptr<Rule>> rules{};
4126 std::vector<std::unique_ptr<Chassis>> chassis{};
4127 std::tie(rules, chassis) = parseRoot(element);
4128 EXPECT_EQ(rules.size(), 1);
4129 EXPECT_EQ(chassis.size(), 2);
4130 }
4131
4132 // Test where fails: Element is not an object
4133 try
4134 {
4135 const json element = R"( [ "0xFF", "0x01" ] )"_json;
4136 parseRoot(element);
4137 ADD_FAILURE() << "Should not have reached this line.";
4138 }
4139 catch (const std::invalid_argument& e)
4140 {
4141 EXPECT_STREQ(e.what(), "Element is not an object");
4142 }
4143
4144 // Test where fails: chassis property not specified
4145 try
4146 {
4147 const json element = R"(
4148 {
4149 "rules": [
4150 {
4151 "id": "set_voltage_rule",
4152 "actions": [
4153 { "pmbus_write_vout_command": { "format": "linear" } }
4154 ]
4155 }
4156 ]
4157 }
4158 )"_json;
4159 parseRoot(element);
4160 ADD_FAILURE() << "Should not have reached this line.";
4161 }
4162 catch (const std::invalid_argument& e)
4163 {
4164 EXPECT_STREQ(e.what(), "Required property missing: chassis");
4165 }
4166
4167 // Test where fails: Invalid property specified
4168 try
4169 {
4170 const json element = R"(
4171 {
4172 "remarks": [ "Config file for a FooBar one-chassis system" ],
4173 "chassis": [
4174 { "number": 1, "inventory_path": "system/chassis" }
4175 ]
4176 }
4177 )"_json;
4178 parseRoot(element);
4179 ADD_FAILURE() << "Should not have reached this line.";
4180 }
4181 catch (const std::invalid_argument& e)
4182 {
4183 EXPECT_STREQ(e.what(), "Element contains an invalid property");
4184 }
4185 }
4186
TEST(ConfigFileParserTests,ParseRule)4187 TEST(ConfigFileParserTests, ParseRule)
4188 {
4189 // Test where works: comments property specified
4190 {
4191 const json element = R"(
4192 {
4193 "comments": [ "Set voltage rule" ],
4194 "id": "set_voltage_rule",
4195 "actions": [
4196 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } },
4197 { "pmbus_write_vout_command": { "volts": 1.03, "format": "linear" } }
4198 ]
4199 }
4200 )"_json;
4201 std::unique_ptr<Rule> rule = parseRule(element);
4202 EXPECT_EQ(rule->getID(), "set_voltage_rule");
4203 EXPECT_EQ(rule->getActions().size(), 2);
4204 }
4205
4206 // Test where works: comments property not specified
4207 {
4208 const json element = R"(
4209 {
4210 "id": "set_voltage_rule",
4211 "actions": [
4212 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } },
4213 { "pmbus_write_vout_command": { "volts": 1.03, "format": "linear" } },
4214 { "pmbus_write_vout_command": { "volts": 1.05, "format": "linear" } }
4215 ]
4216 }
4217 )"_json;
4218 std::unique_ptr<Rule> rule = parseRule(element);
4219 EXPECT_EQ(rule->getID(), "set_voltage_rule");
4220 EXPECT_EQ(rule->getActions().size(), 3);
4221 }
4222
4223 // Test where fails: Element is not an object
4224 try
4225 {
4226 const json element = R"( [ "0xFF", "0x01" ] )"_json;
4227 parseRule(element);
4228 ADD_FAILURE() << "Should not have reached this line.";
4229 }
4230 catch (const std::invalid_argument& e)
4231 {
4232 EXPECT_STREQ(e.what(), "Element is not an object");
4233 }
4234
4235 // Test where fails: id property not specified
4236 try
4237 {
4238 const json element = R"(
4239 {
4240 "actions": [
4241 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } }
4242 ]
4243 }
4244 )"_json;
4245 parseRule(element);
4246 ADD_FAILURE() << "Should not have reached this line.";
4247 }
4248 catch (const std::invalid_argument& e)
4249 {
4250 EXPECT_STREQ(e.what(), "Required property missing: id");
4251 }
4252
4253 // Test where fails: id property is invalid
4254 try
4255 {
4256 const json element = R"(
4257 {
4258 "id": "",
4259 "actions": [
4260 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } }
4261 ]
4262 }
4263 )"_json;
4264 parseRule(element);
4265 ADD_FAILURE() << "Should not have reached this line.";
4266 }
4267 catch (const std::invalid_argument& e)
4268 {
4269 EXPECT_STREQ(e.what(), "Element contains an empty string");
4270 }
4271
4272 // Test where fails: actions property not specified
4273 try
4274 {
4275 const json element = R"(
4276 {
4277 "comments": [ "Set voltage rule" ],
4278 "id": "set_voltage_rule"
4279 }
4280 )"_json;
4281 parseRule(element);
4282 ADD_FAILURE() << "Should not have reached this line.";
4283 }
4284 catch (const std::invalid_argument& e)
4285 {
4286 EXPECT_STREQ(e.what(), "Required property missing: actions");
4287 }
4288
4289 // Test where fails: actions property is invalid
4290 try
4291 {
4292 const json element = R"(
4293 {
4294 "id": "set_voltage_rule",
4295 "actions": true
4296 }
4297 )"_json;
4298 parseRule(element);
4299 ADD_FAILURE() << "Should not have reached this line.";
4300 }
4301 catch (const std::invalid_argument& e)
4302 {
4303 EXPECT_STREQ(e.what(), "Element is not an array");
4304 }
4305
4306 // Test where fails: Invalid property specified
4307 try
4308 {
4309 const json element = R"(
4310 {
4311 "remarks": [ "Set voltage rule" ],
4312 "id": "set_voltage_rule",
4313 "actions": [
4314 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } }
4315 ]
4316 }
4317 )"_json;
4318 parseRule(element);
4319 ADD_FAILURE() << "Should not have reached this line.";
4320 }
4321 catch (const std::invalid_argument& e)
4322 {
4323 EXPECT_STREQ(e.what(), "Element contains an invalid property");
4324 }
4325 }
4326
TEST(ConfigFileParserTests,ParseRuleArray)4327 TEST(ConfigFileParserTests, ParseRuleArray)
4328 {
4329 // Test where works
4330 {
4331 const json element = R"(
4332 [
4333 {
4334 "id": "set_voltage_rule1",
4335 "actions": [
4336 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } }
4337 ]
4338 },
4339 {
4340 "id": "set_voltage_rule2",
4341 "actions": [
4342 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } },
4343 { "pmbus_write_vout_command": { "volts": 1.11, "format": "linear" } }
4344 ]
4345 }
4346 ]
4347 )"_json;
4348 std::vector<std::unique_ptr<Rule>> rules = parseRuleArray(element);
4349 EXPECT_EQ(rules.size(), 2);
4350 EXPECT_EQ(rules[0]->getID(), "set_voltage_rule1");
4351 EXPECT_EQ(rules[0]->getActions().size(), 1);
4352 EXPECT_EQ(rules[1]->getID(), "set_voltage_rule2");
4353 EXPECT_EQ(rules[1]->getActions().size(), 2);
4354 }
4355
4356 // Test where fails: Element is not an array
4357 try
4358 {
4359 const json element = R"( { "id": "set_voltage_rule" } )"_json;
4360 parseRuleArray(element);
4361 ADD_FAILURE() << "Should not have reached this line.";
4362 }
4363 catch (const std::invalid_argument& e)
4364 {
4365 EXPECT_STREQ(e.what(), "Element is not an array");
4366 }
4367 }
4368
TEST(ConfigFileParserTests,ParseRuleIDOrActionsProperty)4369 TEST(ConfigFileParserTests, ParseRuleIDOrActionsProperty)
4370 {
4371 // Test where works: actions specified
4372 {
4373 const json element = R"(
4374 {
4375 "actions": [
4376 { "pmbus_write_vout_command": { "format": "linear" } },
4377 { "run_rule": "set_voltage_rule" }
4378 ]
4379 }
4380 )"_json;
4381 std::vector<std::unique_ptr<Action>> actions =
4382 parseRuleIDOrActionsProperty(element);
4383 EXPECT_EQ(actions.size(), 2);
4384 }
4385
4386 // Test where works: rule_id specified
4387 {
4388 const json element = R"(
4389 {
4390 "rule_id": "set_voltage_rule"
4391 }
4392 )"_json;
4393 std::vector<std::unique_ptr<Action>> actions =
4394 parseRuleIDOrActionsProperty(element);
4395 EXPECT_EQ(actions.size(), 1);
4396 }
4397
4398 // Test where fails: Element is not an object
4399 try
4400 {
4401 const json element = R"( [ "foo", "bar" ] )"_json;
4402 parseRuleIDOrActionsProperty(element);
4403 ADD_FAILURE() << "Should not have reached this line.";
4404 }
4405 catch (const std::invalid_argument& e)
4406 {
4407 EXPECT_STREQ(e.what(), "Element is not an object");
4408 }
4409
4410 // Test where fails: rule_id is invalid
4411 try
4412 {
4413 const json element = R"(
4414 { "rule_id": 1 }
4415 )"_json;
4416 parseRuleIDOrActionsProperty(element);
4417 ADD_FAILURE() << "Should not have reached this line.";
4418 }
4419 catch (const std::invalid_argument& e)
4420 {
4421 EXPECT_STREQ(e.what(), "Element is not a string");
4422 }
4423
4424 // Test where fails: actions is invalid
4425 try
4426 {
4427 const json element = R"(
4428 { "actions": 1 }
4429 )"_json;
4430 parseRuleIDOrActionsProperty(element);
4431 ADD_FAILURE() << "Should not have reached this line.";
4432 }
4433 catch (const std::invalid_argument& e)
4434 {
4435 EXPECT_STREQ(e.what(), "Element is not an array");
4436 }
4437
4438 // Test where fails: Neither rule_id nor actions specified
4439 try
4440 {
4441 const json element = R"(
4442 {
4443 "volts": 1.03
4444 }
4445 )"_json;
4446 parseRuleIDOrActionsProperty(element);
4447 ADD_FAILURE() << "Should not have reached this line.";
4448 }
4449 catch (const std::invalid_argument& e)
4450 {
4451 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain "
4452 "either rule_id or actions");
4453 }
4454
4455 // Test where fails: Both rule_id and actions specified
4456 try
4457 {
4458 const json element = R"(
4459 {
4460 "volts": 1.03,
4461 "rule_id": "set_voltage_rule",
4462 "actions": [
4463 {
4464 "pmbus_write_vout_command": {
4465 "format": "linear"
4466 }
4467 }
4468 ]
4469 }
4470 )"_json;
4471 parseRuleIDOrActionsProperty(element);
4472 ADD_FAILURE() << "Should not have reached this line.";
4473 }
4474 catch (const std::invalid_argument& e)
4475 {
4476 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain "
4477 "either rule_id or actions");
4478 }
4479 }
4480
TEST(ConfigFileParserTests,ParseRunRule)4481 TEST(ConfigFileParserTests, ParseRunRule)
4482 {
4483 // Test where works
4484 {
4485 const json element = "vdd_regulator";
4486 std::unique_ptr<RunRuleAction> action = parseRunRule(element);
4487 EXPECT_EQ(action->getRuleID(), "vdd_regulator");
4488 }
4489
4490 // Test where fails: Element is not a string
4491 try
4492 {
4493 const json element = 1;
4494 parseRunRule(element);
4495 ADD_FAILURE() << "Should not have reached this line.";
4496 }
4497 catch (const std::invalid_argument& e)
4498 {
4499 EXPECT_STREQ(e.what(), "Element is not a string");
4500 }
4501
4502 // Test where fails: Empty string
4503 try
4504 {
4505 const json element = "";
4506 parseRunRule(element);
4507 ADD_FAILURE() << "Should not have reached this line.";
4508 }
4509 catch (const std::invalid_argument& e)
4510 {
4511 EXPECT_STREQ(e.what(), "Element contains an empty string");
4512 }
4513 }
4514
TEST(ConfigFileParserTests,ParseSensorDataFormat)4515 TEST(ConfigFileParserTests, ParseSensorDataFormat)
4516 {
4517 // Test where works: linear_11
4518 {
4519 const json element = "linear_11";
4520 pmbus_utils::SensorDataFormat value = parseSensorDataFormat(element);
4521 pmbus_utils::SensorDataFormat format =
4522 pmbus_utils::SensorDataFormat::linear_11;
4523 EXPECT_EQ(value, format);
4524 }
4525
4526 // Test where works: linear_16
4527 {
4528 const json element = "linear_16";
4529 pmbus_utils::SensorDataFormat value = parseSensorDataFormat(element);
4530 pmbus_utils::SensorDataFormat format =
4531 pmbus_utils::SensorDataFormat::linear_16;
4532 EXPECT_EQ(value, format);
4533 }
4534
4535 // Test where fails: Element is not a sensor data format
4536 try
4537 {
4538 const json element = "foo";
4539 parseSensorDataFormat(element);
4540 ADD_FAILURE() << "Should not have reached this line.";
4541 }
4542 catch (const std::invalid_argument& e)
4543 {
4544 EXPECT_STREQ(e.what(), "Element is not a sensor data format");
4545 }
4546
4547 // Test where fails: Element is not a string
4548 try
4549 {
4550 const json element = R"( { "foo": "bar" } )"_json;
4551 parseSensorDataFormat(element);
4552 ADD_FAILURE() << "Should not have reached this line.";
4553 }
4554 catch (const std::invalid_argument& e)
4555 {
4556 EXPECT_STREQ(e.what(), "Element is not a string");
4557 }
4558 }
4559
TEST(ConfigFileParserTests,ParseSensorMonitoring)4560 TEST(ConfigFileParserTests, ParseSensorMonitoring)
4561 {
4562 // Test where works: actions property specified
4563 {
4564 const json element = R"(
4565 {
4566 "actions": [
4567 { "run_rule": "read_sensors_rule" }
4568 ]
4569 }
4570 )"_json;
4571 std::unique_ptr<SensorMonitoring> sensorMonitoring =
4572 parseSensorMonitoring(element);
4573 EXPECT_EQ(sensorMonitoring->getActions().size(), 1);
4574 }
4575
4576 // Test where works: rule_id property specified
4577 {
4578 const json element = R"(
4579 {
4580 "comments": [ "comments property" ],
4581 "rule_id": "set_voltage_rule"
4582 }
4583 )"_json;
4584 std::unique_ptr<SensorMonitoring> sensorMonitoring =
4585 parseSensorMonitoring(element);
4586 EXPECT_EQ(sensorMonitoring->getActions().size(), 1);
4587 }
4588
4589 // Test where fails: actions object is invalid
4590 try
4591 {
4592 const json element = R"(
4593 {
4594 "actions": 1
4595 }
4596 )"_json;
4597 parseSensorMonitoring(element);
4598 ADD_FAILURE() << "Should not have reached this line.";
4599 }
4600 catch (const std::invalid_argument& e)
4601 {
4602 EXPECT_STREQ(e.what(), "Element is not an array");
4603 }
4604
4605 // Test where fails: rule_id value is invalid
4606 try
4607 {
4608 const json element = R"(
4609 {
4610 "rule_id": 1
4611 }
4612 )"_json;
4613 parseSensorMonitoring(element);
4614 ADD_FAILURE() << "Should not have reached this line.";
4615 }
4616 catch (const std::invalid_argument& e)
4617 {
4618 EXPECT_STREQ(e.what(), "Element is not a string");
4619 }
4620
4621 // Test where fails: Required actions or rule_id property not specified
4622 try
4623 {
4624 const json element = R"(
4625 {
4626 "comments": [ "comments property" ]
4627 }
4628 )"_json;
4629 parseSensorMonitoring(element);
4630 ADD_FAILURE() << "Should not have reached this line.";
4631 }
4632 catch (const std::invalid_argument& e)
4633 {
4634 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain "
4635 "either rule_id or actions");
4636 }
4637
4638 // Test where fails: Required actions or rule_id property both specified
4639 try
4640 {
4641 const json element = R"(
4642 {
4643 "rule_id": "set_voltage_rule",
4644 "actions": [
4645 { "run_rule": "read_sensors_rule" }
4646 ]
4647 }
4648 )"_json;
4649 parseSensorMonitoring(element);
4650 ADD_FAILURE() << "Should not have reached this line.";
4651 }
4652 catch (const std::invalid_argument& e)
4653 {
4654 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain "
4655 "either rule_id or actions");
4656 }
4657
4658 // Test where fails: Element is not an object
4659 try
4660 {
4661 const json element = R"( [ "foo", "bar" ] )"_json;
4662 parseSensorMonitoring(element);
4663 ADD_FAILURE() << "Should not have reached this line.";
4664 }
4665 catch (const std::invalid_argument& e)
4666 {
4667 EXPECT_STREQ(e.what(), "Element is not an object");
4668 }
4669
4670 // Test where fails: Invalid property specified
4671 try
4672 {
4673 const json element = R"(
4674 {
4675 "foo": "bar",
4676 "actions": [
4677 { "run_rule": "read_sensors_rule" }
4678 ]
4679 }
4680 )"_json;
4681 parseSensorMonitoring(element);
4682 ADD_FAILURE() << "Should not have reached this line.";
4683 }
4684 catch (const std::invalid_argument& e)
4685 {
4686 EXPECT_STREQ(e.what(), "Element contains an invalid property");
4687 }
4688 }
4689
TEST(ConfigFileParserTests,ParseSensorType)4690 TEST(ConfigFileParserTests, ParseSensorType)
4691 {
4692 // Test where works: iout
4693 {
4694 const json element = "iout";
4695 SensorType type = parseSensorType(element);
4696 EXPECT_EQ(type, SensorType::iout);
4697 }
4698
4699 // Test where works: iout_peak
4700 {
4701 const json element = "iout_peak";
4702 SensorType type = parseSensorType(element);
4703 EXPECT_EQ(type, SensorType::iout_peak);
4704 }
4705
4706 // Test where works: iout_valley
4707 {
4708 const json element = "iout_valley";
4709 SensorType type = parseSensorType(element);
4710 EXPECT_EQ(type, SensorType::iout_valley);
4711 }
4712
4713 // Test where works: pout
4714 {
4715 const json element = "pout";
4716 SensorType type = parseSensorType(element);
4717 EXPECT_EQ(type, SensorType::pout);
4718 }
4719
4720 // Test where works: temperature
4721 {
4722 const json element = "temperature";
4723 SensorType type = parseSensorType(element);
4724 EXPECT_EQ(type, SensorType::temperature);
4725 }
4726
4727 // Test where works: temperature_peak
4728 {
4729 const json element = "temperature_peak";
4730 SensorType type = parseSensorType(element);
4731 EXPECT_EQ(type, SensorType::temperature_peak);
4732 }
4733
4734 // Test where works: vout
4735 {
4736 const json element = "vout";
4737 SensorType type = parseSensorType(element);
4738 EXPECT_EQ(type, SensorType::vout);
4739 }
4740
4741 // Test where works: vout_peak
4742 {
4743 const json element = "vout_peak";
4744 SensorType type = parseSensorType(element);
4745 EXPECT_EQ(type, SensorType::vout_peak);
4746 }
4747
4748 // Test where works: vout_valley
4749 {
4750 const json element = "vout_valley";
4751 SensorType type = parseSensorType(element);
4752 EXPECT_EQ(type, SensorType::vout_valley);
4753 }
4754
4755 // Test where fails: Element is not a sensor type
4756 try
4757 {
4758 const json element = "foo";
4759 parseSensorType(element);
4760 ADD_FAILURE() << "Should not have reached this line.";
4761 }
4762 catch (const std::invalid_argument& e)
4763 {
4764 EXPECT_STREQ(e.what(), "Element is not a sensor type");
4765 }
4766
4767 // Test where fails: Element is not a string
4768 try
4769 {
4770 const json element = R"( { "foo": "bar" } )"_json;
4771 parseSensorType(element);
4772 ADD_FAILURE() << "Should not have reached this line.";
4773 }
4774 catch (const std::invalid_argument& e)
4775 {
4776 EXPECT_STREQ(e.what(), "Element is not a string");
4777 }
4778 }
4779
TEST(ConfigFileParserTests,ParseSetDevice)4780 TEST(ConfigFileParserTests, ParseSetDevice)
4781 {
4782 // Test where works
4783 {
4784 const json element = "regulator1";
4785 std::unique_ptr<SetDeviceAction> action = parseSetDevice(element);
4786 EXPECT_EQ(action->getDeviceID(), "regulator1");
4787 }
4788
4789 // Test where fails: Element is not a string
4790 try
4791 {
4792 const json element = 1;
4793 parseSetDevice(element);
4794 ADD_FAILURE() << "Should not have reached this line.";
4795 }
4796 catch (const std::invalid_argument& e)
4797 {
4798 EXPECT_STREQ(e.what(), "Element is not a string");
4799 }
4800
4801 // Test where fails: Empty string
4802 try
4803 {
4804 const json element = "";
4805 parseSetDevice(element);
4806 ADD_FAILURE() << "Should not have reached this line.";
4807 }
4808 catch (const std::invalid_argument& e)
4809 {
4810 EXPECT_STREQ(e.what(), "Element contains an empty string");
4811 }
4812 }
4813
TEST(ConfigFileParserTests,ParseVoutDataFormat)4814 TEST(ConfigFileParserTests, ParseVoutDataFormat)
4815 {
4816 // Test where works: linear
4817 {
4818 const json element = "linear";
4819 pmbus_utils::VoutDataFormat value = parseVoutDataFormat(element);
4820 pmbus_utils::VoutDataFormat format =
4821 pmbus_utils::VoutDataFormat::linear;
4822 EXPECT_EQ(value, format);
4823 }
4824
4825 // Test where works: vid
4826 {
4827 const json element = "vid";
4828 pmbus_utils::VoutDataFormat value = parseVoutDataFormat(element);
4829 pmbus_utils::VoutDataFormat format = pmbus_utils::VoutDataFormat::vid;
4830 EXPECT_EQ(value, format);
4831 }
4832
4833 // Test where works: direct
4834 {
4835 const json element = "direct";
4836 pmbus_utils::VoutDataFormat value = parseVoutDataFormat(element);
4837 pmbus_utils::VoutDataFormat format =
4838 pmbus_utils::VoutDataFormat::direct;
4839 EXPECT_EQ(value, format);
4840 }
4841
4842 // Test where works: ieee
4843 {
4844 const json element = "ieee";
4845 pmbus_utils::VoutDataFormat value = parseVoutDataFormat(element);
4846 pmbus_utils::VoutDataFormat format = pmbus_utils::VoutDataFormat::ieee;
4847 EXPECT_EQ(value, format);
4848 }
4849
4850 // Test where fails: Element is not a vout data format
4851 try
4852 {
4853 const json element = "foo";
4854 parseVoutDataFormat(element);
4855 ADD_FAILURE() << "Should not have reached this line.";
4856 }
4857 catch (const std::invalid_argument& e)
4858 {
4859 EXPECT_STREQ(e.what(), "Element is not a vout data format");
4860 }
4861
4862 // Test where fails: Element is not a string
4863 try
4864 {
4865 const json element = R"( { "foo": "bar" } )"_json;
4866 parseVoutDataFormat(element);
4867 ADD_FAILURE() << "Should not have reached this line.";
4868 }
4869 catch (const std::invalid_argument& e)
4870 {
4871 EXPECT_STREQ(e.what(), "Element is not a string");
4872 }
4873 }
4874