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