blob: be8a4c8e789ee78312874ec21f4c2b40e9cc8ff8 [file] [log] [blame]
Shawn McCarney0e8c68a2020-03-27 01:44:48 -05001/**
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 "chassis.hpp"
18#include "config_file_parser.hpp"
19#include "config_file_parser_error.hpp"
Bob King9c36c5f2020-04-06 11:34:09 +080020#include "configuration.hpp"
Bob King0e701132020-04-03 21:50:31 +080021#include "device.hpp"
Bob Kingf617f892020-03-30 19:03:35 +080022#include "i2c_interface.hpp"
23#include "i2c_write_bit_action.hpp"
Bob King87ff9d72020-03-31 14:02:55 +080024#include "i2c_write_byte_action.hpp"
Bob Kingbafcb862020-03-31 16:39:00 +080025#include "i2c_write_bytes_action.hpp"
Shawn McCarney0e8c68a2020-03-27 01:44:48 -050026#include "pmbus_utils.hpp"
27#include "pmbus_write_vout_command_action.hpp"
Bob King9c36c5f2020-04-06 11:34:09 +080028#include "presence_detection.hpp"
29#include "rail.hpp"
Shawn McCarney0e8c68a2020-03-27 01:44:48 -050030#include "rule.hpp"
Bob King315b0b62020-04-03 21:47:58 +080031#include "run_rule_action.hpp"
Bob Kinga2f2a0d2020-04-09 13:32:14 +080032#include "sensor_monitoring.hpp"
Shawn McCarney80c0b042020-03-27 12:08:53 -050033#include "tmp_file.hpp"
Shawn McCarney0e8c68a2020-03-27 01:44:48 -050034
Shawn McCarney80c0b042020-03-27 12:08:53 -050035#include <sys/stat.h> // for chmod()
Shawn McCarney0e8c68a2020-03-27 01:44:48 -050036
37#include <nlohmann/json.hpp>
38
39#include <cstdint>
40#include <cstring>
41#include <exception>
42#include <filesystem>
43#include <fstream>
44#include <memory>
45#include <optional>
46#include <stdexcept>
47#include <string>
48#include <tuple>
49#include <vector>
50
51#include <gtest/gtest.h>
52
53using namespace phosphor::power::regulators;
54using namespace phosphor::power::regulators::config_file_parser;
55using namespace phosphor::power::regulators::config_file_parser::internal;
56using json = nlohmann::json;
57
Shawn McCarney0e8c68a2020-03-27 01:44:48 -050058void writeConfigFile(const std::filesystem::path& pathName,
59 const std::string& contents)
60{
61 std::ofstream file{pathName};
62 file << contents;
63}
64
65void writeConfigFile(const std::filesystem::path& pathName,
66 const json& contents)
67{
68 std::ofstream file{pathName};
69 file << contents;
70}
71
72TEST(ConfigFileParserTests, Parse)
73{
74 // Test where works
75 {
76 const json configFileContents = R"(
77 {
78 "rules": [
79 {
80 "id": "set_voltage_rule1",
81 "actions": [
82 { "pmbus_write_vout_command": { "volts": 1.03, "format": "linear" } }
83 ]
84 },
85 {
86 "id": "set_voltage_rule2",
87 "actions": [
88 { "pmbus_write_vout_command": { "volts": 1.33, "format": "linear" } }
89 ]
90 }
91 ],
92 "chassis": [
93 { "number": 1 },
94 { "number": 2 },
95 { "number": 3 }
96 ]
97 }
98 )"_json;
99
100 TmpFile configFile;
101 std::filesystem::path pathName{configFile.getName()};
102 writeConfigFile(pathName, configFileContents);
103
104 std::vector<std::unique_ptr<Rule>> rules{};
105 std::vector<std::unique_ptr<Chassis>> chassis{};
106 std::tie(rules, chassis) = parse(pathName);
107
108 EXPECT_EQ(rules.size(), 2);
109 EXPECT_EQ(rules[0]->getID(), "set_voltage_rule1");
110 EXPECT_EQ(rules[1]->getID(), "set_voltage_rule2");
111
Bob King0e701132020-04-03 21:50:31 +0800112 EXPECT_EQ(chassis.size(), 3);
113 EXPECT_EQ(chassis[0]->getNumber(), 1);
114 EXPECT_EQ(chassis[1]->getNumber(), 2);
115 EXPECT_EQ(chassis[2]->getNumber(), 3);
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500116 }
117
118 // Test where fails: File does not exist
119 try
120 {
121 std::filesystem::path pathName{"/tmp/non_existent_file"};
122 parse(pathName);
123 ADD_FAILURE() << "Should not have reached this line.";
124 }
125 catch (const ConfigFileParserError& e)
126 {
127 // Expected exception; what() message will vary
128 }
129
130 // Test where fails: File is not readable
131 try
132 {
133 const json configFileContents = R"(
134 {
135 "chassis": [ { "number": 1 } ]
136 }
137 )"_json;
138
139 TmpFile configFile;
140 std::filesystem::path pathName{configFile.getName()};
141 writeConfigFile(pathName, configFileContents);
142
143 chmod(pathName.c_str(), 0222);
144
145 parse(pathName);
146 ADD_FAILURE() << "Should not have reached this line.";
147 }
148 catch (const ConfigFileParserError& e)
149 {
150 // Expected exception; what() message will vary
151 }
152
153 // Test where fails: File is not valid JSON
154 try
155 {
156 const std::string configFileContents = "] foo [";
157
158 TmpFile configFile;
159 std::filesystem::path pathName{configFile.getName()};
160 writeConfigFile(pathName, configFileContents);
161
162 parse(pathName);
163 ADD_FAILURE() << "Should not have reached this line.";
164 }
165 catch (const ConfigFileParserError& e)
166 {
167 // Expected exception; what() message will vary
168 }
169
170 // Test where fails: Error when parsing JSON elements
171 try
172 {
173 const json configFileContents = R"( { "foo": "bar" } )"_json;
174
175 TmpFile configFile;
176 std::filesystem::path pathName{configFile.getName()};
177 writeConfigFile(pathName, configFileContents);
178
179 parse(pathName);
180 ADD_FAILURE() << "Should not have reached this line.";
181 }
182 catch (const ConfigFileParserError& e)
183 {
184 // Expected exception; what() message will vary
185 }
186}
187
188TEST(ConfigFileParserTests, GetRequiredProperty)
189{
190 // Test where property exists
191 {
192 const json element = R"( { "format": "linear" } )"_json;
193 const json& propertyElement = getRequiredProperty(element, "format");
194 EXPECT_EQ(propertyElement.get<std::string>(), "linear");
195 }
196
197 // Test where property does not exist
198 try
199 {
200 const json element = R"( { "volts": 1.03 } )"_json;
201 getRequiredProperty(element, "format");
202 ADD_FAILURE() << "Should not have reached this line.";
203 }
204 catch (const std::invalid_argument& e)
205 {
206 EXPECT_STREQ(e.what(), "Required property missing: format");
207 }
208}
209
210TEST(ConfigFileParserTests, ParseAction)
211{
212 // Test where works: comments property specified
213 {
214 const json element = R"(
215 {
216 "comments": [ "Set output voltage." ],
217 "pmbus_write_vout_command": {
218 "format": "linear"
219 }
220 }
221 )"_json;
222 std::unique_ptr<Action> action = parseAction(element);
223 EXPECT_NE(action.get(), nullptr);
224 }
225
226 // Test where works: comments property not specified
227 {
228 const json element = R"(
229 {
230 "pmbus_write_vout_command": {
231 "format": "linear"
232 }
233 }
234 )"_json;
235 std::unique_ptr<Action> action = parseAction(element);
236 EXPECT_NE(action.get(), nullptr);
237 }
238
239 // Test where works: and action type specified
240 // TODO: Not implemented yet
241
242 // Test where works: compare_presence action type specified
243 // TODO: Not implemented yet
244
245 // Test where works: compare_vpd action type specified
246 // TODO: Not implemented yet
247
248 // Test where works: i2c_compare_bit action type specified
249 // TODO: Not implemented yet
250
251 // Test where works: i2c_compare_byte action type specified
252 // TODO: Not implemented yet
253
254 // Test where works: i2c_compare_bytes action type specified
255 // TODO: Not implemented yet
256
257 // Test where works: i2c_write_bit action type specified
Bob Kingf617f892020-03-30 19:03:35 +0800258 {
259 const json element = R"(
260 {
261 "i2c_write_bit": {
262 "register": "0xA0",
263 "position": 3,
264 "value": 0
265 }
266 }
267 )"_json;
268 std::unique_ptr<Action> action = parseAction(element);
269 EXPECT_NE(action.get(), nullptr);
270 }
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500271
272 // Test where works: i2c_write_byte action type specified
Bob King87ff9d72020-03-31 14:02:55 +0800273 {
274 const json element = R"(
275 {
276 "i2c_write_byte": {
277 "register": "0x0A",
278 "value": "0xCC"
279 }
280 }
281 )"_json;
282 std::unique_ptr<Action> action = parseAction(element);
283 EXPECT_NE(action.get(), nullptr);
284 }
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500285
286 // Test where works: i2c_write_bytes action type specified
Bob Kingbafcb862020-03-31 16:39:00 +0800287 {
288 const json element = R"(
289 {
290 "i2c_write_bytes": {
291 "register": "0x0A",
292 "values": [ "0xCC", "0xFF" ]
293 }
294 }
295 )"_json;
296 std::unique_ptr<Action> action = parseAction(element);
297 EXPECT_NE(action.get(), nullptr);
298 }
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500299
300 // Test where works: if action type specified
301 // TODO: Not implemented yet
302
303 // Test where works: not action type specified
304 // TODO: Not implemented yet
305
306 // Test where works: or action type specified
307 // TODO: Not implemented yet
308
309 // Test where works: pmbus_read_sensor action type specified
310 // TODO: Not implemented yet
311
312 // Test where works: pmbus_write_vout_command action type specified
313 {
314 const json element = R"(
315 {
316 "pmbus_write_vout_command": {
317 "format": "linear"
318 }
319 }
320 )"_json;
321 std::unique_ptr<Action> action = parseAction(element);
322 EXPECT_NE(action.get(), nullptr);
323 }
324
325 // Test where works: run_rule action type specified
Bob King315b0b62020-04-03 21:47:58 +0800326 {
327 const json element = R"(
328 {
329 "run_rule": "set_voltage_rule"
330 }
331 )"_json;
332 std::unique_ptr<Action> action = parseAction(element);
333 EXPECT_NE(action.get(), nullptr);
334 }
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500335
336 // Test where works: set_device action type specified
337 // TODO: Not implemented yet
338
339 // Test where fails: Element is not an object
340 try
341 {
342 const json element = R"( [ "0xFF", "0x01" ] )"_json;
343 parseAction(element);
344 ADD_FAILURE() << "Should not have reached this line.";
345 }
346 catch (const std::invalid_argument& e)
347 {
348 EXPECT_STREQ(e.what(), "Element is not an object");
349 }
350
351 // Test where fails: No action type specified
352 try
353 {
354 const json element = R"(
355 {
356 "comments": [ "Set output voltage." ]
357 }
358 )"_json;
359 parseAction(element);
360 ADD_FAILURE() << "Should not have reached this line.";
361 }
362 catch (const std::invalid_argument& e)
363 {
364 EXPECT_STREQ(e.what(), "Required action type property missing");
365 }
366
367 // Test where fails: Multiple action types specified
Bob King0e701132020-04-03 21:50:31 +0800368 try
369 {
370 const json element = R"(
371 {
372 "pmbus_write_vout_command": { "format": "linear" },
373 "run_rule": "set_voltage_rule"
374 }
375 )"_json;
376 parseAction(element);
377 ADD_FAILURE() << "Should not have reached this line.";
378 }
379 catch (const std::invalid_argument& e)
380 {
381 EXPECT_STREQ(e.what(), "Element contains an invalid property");
382 }
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500383
384 // Test where fails: Invalid property specified
385 try
386 {
387 const json element = R"(
388 {
389 "remarks": [ "Set output voltage." ],
390 "pmbus_write_vout_command": {
391 "format": "linear"
392 }
393 }
394 )"_json;
395 parseAction(element);
396 ADD_FAILURE() << "Should not have reached this line.";
397 }
398 catch (const std::invalid_argument& e)
399 {
400 EXPECT_STREQ(e.what(), "Element contains an invalid property");
401 }
402}
403
404TEST(ConfigFileParserTests, ParseActionArray)
405{
406 // Test where works
407 {
408 const json element = R"(
409 [
410 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } },
411 { "pmbus_write_vout_command": { "volts": 1.03, "format": "linear" } }
412 ]
413 )"_json;
414 std::vector<std::unique_ptr<Action>> actions =
415 parseActionArray(element);
416 EXPECT_EQ(actions.size(), 2);
417 }
418
419 // Test where fails: Element is not an array
420 try
421 {
422 const json element = R"(
423 {
424 "foo": "bar"
425 }
426 )"_json;
427 parseActionArray(element);
428 ADD_FAILURE() << "Should not have reached this line.";
429 }
430 catch (const std::invalid_argument& e)
431 {
432 EXPECT_STREQ(e.what(), "Element is not an array");
433 }
434}
435
Bob Kingf617f892020-03-30 19:03:35 +0800436TEST(ConfigFileParserTests, ParseBitPosition)
437{
438 // Test where works: 0
439 {
440 const json element = R"( 0 )"_json;
441 uint8_t value = parseBitPosition(element);
442 EXPECT_EQ(value, 0);
443 }
444
445 // Test where works: 7
446 {
447 const json element = R"( 7 )"_json;
448 uint8_t value = parseBitPosition(element);
449 EXPECT_EQ(value, 7);
450 }
451
452 // Test where fails: Element is not an integer
453 try
454 {
455 const json element = R"( 1.03 )"_json;
456 parseBitPosition(element);
457 ADD_FAILURE() << "Should not have reached this line.";
458 }
459 catch (const std::invalid_argument& e)
460 {
461 EXPECT_STREQ(e.what(), "Element is not an integer");
462 }
463
464 // Test where fails: Value < 0
465 try
466 {
467 const json element = R"( -1 )"_json;
468 parseBitPosition(element);
469 ADD_FAILURE() << "Should not have reached this line.";
470 }
471 catch (const std::invalid_argument& e)
472 {
473 EXPECT_STREQ(e.what(), "Element is not a bit position");
474 }
475
476 // Test where fails: Value > 7
477 try
478 {
479 const json element = R"( 8 )"_json;
480 parseBitPosition(element);
481 ADD_FAILURE() << "Should not have reached this line.";
482 }
483 catch (const std::invalid_argument& e)
484 {
485 EXPECT_STREQ(e.what(), "Element is not a bit position");
486 }
487}
488
489TEST(ConfigFileParserTests, ParseBitValue)
490{
491 // Test where works: 0
492 {
493 const json element = R"( 0 )"_json;
494 uint8_t value = parseBitValue(element);
495 EXPECT_EQ(value, 0);
496 }
497
498 // Test where works: 1
499 {
500 const json element = R"( 1 )"_json;
501 uint8_t value = parseBitValue(element);
502 EXPECT_EQ(value, 1);
503 }
504
505 // Test where fails: Element is not an integer
506 try
507 {
508 const json element = R"( 0.5 )"_json;
509 parseBitValue(element);
510 ADD_FAILURE() << "Should not have reached this line.";
511 }
512 catch (const std::invalid_argument& e)
513 {
514 EXPECT_STREQ(e.what(), "Element is not an integer");
515 }
516
517 // Test where fails: Value < 0
518 try
519 {
520 const json element = R"( -1 )"_json;
521 parseBitValue(element);
522 ADD_FAILURE() << "Should not have reached this line.";
523 }
524 catch (const std::invalid_argument& e)
525 {
526 EXPECT_STREQ(e.what(), "Element is not a bit value");
527 }
528
529 // Test where fails: Value > 1
530 try
531 {
532 const json element = R"( 2 )"_json;
533 parseBitValue(element);
534 ADD_FAILURE() << "Should not have reached this line.";
535 }
536 catch (const std::invalid_argument& e)
537 {
538 EXPECT_STREQ(e.what(), "Element is not a bit value");
539 }
540}
541
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500542TEST(ConfigFileParserTests, ParseBoolean)
543{
544 // Test where works: true
545 {
546 const json element = R"( true )"_json;
547 bool value = parseBoolean(element);
548 EXPECT_EQ(value, true);
549 }
550
551 // Test where works: false
552 {
553 const json element = R"( false )"_json;
554 bool value = parseBoolean(element);
555 EXPECT_EQ(value, false);
556 }
557
558 // Test where fails: Element is not a boolean
559 try
560 {
561 const json element = R"( 1 )"_json;
562 parseBoolean(element);
563 ADD_FAILURE() << "Should not have reached this line.";
564 }
565 catch (const std::invalid_argument& e)
566 {
567 EXPECT_STREQ(e.what(), "Element is not a boolean");
568 }
569}
570
Bob King0e701132020-04-03 21:50:31 +0800571TEST(ConfigFileParserTests, ParseChassis)
572{
573 // Test where works: Only required properties specified
574 {
575 const json element = R"(
576 {
577 "number": 1
578 }
579 )"_json;
580 std::unique_ptr<Chassis> chassis = parseChassis(element);
581 EXPECT_EQ(chassis->getNumber(), 1);
Bob King9c36c5f2020-04-06 11:34:09 +0800582 EXPECT_EQ(chassis->getDevices().size(), 0);
Bob King0e701132020-04-03 21:50:31 +0800583 }
584
585 // Test where works: All properties specified
586 {
587 const json element = R"(
588 {
589 "comments": [ "comments property" ],
590 "number": 2,
591 "devices": [
592 {
593 "id": "vdd_regulator",
594 "is_regulator": true,
595 "fru": "/system/chassis/motherboard/regulator2",
596 "i2c_interface":
597 {
598 "bus": 1,
599 "address": "0x70"
600 }
601 }
602 ]
603 }
604 )"_json;
605 std::unique_ptr<Chassis> chassis = parseChassis(element);
606 EXPECT_EQ(chassis->getNumber(), 2);
Bob King9c36c5f2020-04-06 11:34:09 +0800607 EXPECT_EQ(chassis->getDevices().size(), 1);
608 EXPECT_EQ(chassis->getDevices()[0]->getID(), "vdd_regulator");
Bob King0e701132020-04-03 21:50:31 +0800609 }
610
611 // Test where fails: number value is invalid
612 try
613 {
614 const json element = R"(
615 {
616 "number": 0.5
617 }
618 )"_json;
619 parseChassis(element);
620 ADD_FAILURE() << "Should not have reached this line.";
621 }
622 catch (const std::invalid_argument& e)
623 {
624 EXPECT_STREQ(e.what(), "Element is not an unsigned integer");
625 }
626
627 // Test where fails: Invalid property specified
628 try
629 {
630 const json element = R"(
631 {
632 "number": 1,
633 "foo": 2
634 }
635 )"_json;
636 parseChassis(element);
637 ADD_FAILURE() << "Should not have reached this line.";
638 }
639 catch (const std::invalid_argument& e)
640 {
641 EXPECT_STREQ(e.what(), "Element contains an invalid property");
642 }
643
644 // Test where fails: Required number property not specified
645 try
646 {
647 const json element = R"(
648 {
649 "devices": [
650 {
651 "id": "vdd_regulator",
652 "is_regulator": true,
653 "fru": "/system/chassis/motherboard/regulator2",
654 "i2c_interface":
655 {
656 "bus": 1,
657 "address": "0x70"
658 }
659 }
660 ]
661 }
662 )"_json;
663 parseChassis(element);
664 ADD_FAILURE() << "Should not have reached this line.";
665 }
666 catch (const std::invalid_argument& e)
667 {
668 EXPECT_STREQ(e.what(), "Required property missing: number");
669 }
670
671 // Test where fails: Element is not an object
672 try
673 {
674 const json element = R"( [ "0xFF", "0x01" ] )"_json;
675 parseChassis(element);
676 ADD_FAILURE() << "Should not have reached this line.";
677 }
678 catch (const std::invalid_argument& e)
679 {
680 EXPECT_STREQ(e.what(), "Element is not an object");
681 }
682
683 // Test where fails: number value is < 1
684 try
685 {
686 const json element = R"(
687 {
688 "number": 0
689 }
690 )"_json;
691 parseChassis(element);
692 ADD_FAILURE() << "Should not have reached this line.";
693 }
694 catch (const std::invalid_argument& e)
695 {
696 EXPECT_STREQ(e.what(), "Invalid chassis number: Must be > 0");
697 }
698
699 // Test where fails: devices value is invalid
700 try
701 {
702 const json element = R"(
703 {
704 "number": 1,
705 "devices": 2
706 }
707 )"_json;
708 parseChassis(element);
709 ADD_FAILURE() << "Should not have reached this line.";
710 }
711 catch (const std::invalid_argument& e)
712 {
713 EXPECT_STREQ(e.what(), "Element is not an array");
714 }
715}
716
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500717TEST(ConfigFileParserTests, ParseChassisArray)
718{
Bob King0e701132020-04-03 21:50:31 +0800719 // Test where works
720 {
721 const json element = R"(
722 [
723 { "number": 1 },
724 { "number": 2 }
725 ]
726 )"_json;
727 std::vector<std::unique_ptr<Chassis>> chassis =
728 parseChassisArray(element);
729 EXPECT_EQ(chassis.size(), 2);
730 EXPECT_EQ(chassis[0]->getNumber(), 1);
731 EXPECT_EQ(chassis[1]->getNumber(), 2);
732 }
733
734 // Test where fails: Element is not an array
735 try
736 {
737 const json element = R"(
738 {
739 "foo": "bar"
740 }
741 )"_json;
742 parseChassisArray(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 an array");
748 }
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500749}
750
Bob King33e7eaa2020-04-01 18:09:34 +0800751TEST(ConfigFileParserTests, ParseConfiguration)
752{
753 // Test where works: actions required property specified
754 {
755 const json element = R"(
756 {
757 "actions": [
758 {
759 "pmbus_write_vout_command": {
760 "format": "linear"
761 }
762 }
763 ]
764 }
765 )"_json;
766 std::unique_ptr<Configuration> configuration =
767 parseConfiguration(element);
768 EXPECT_EQ(configuration->getActions().size(), 1);
769 EXPECT_EQ(configuration->getVolts().has_value(), false);
770 }
771
772 // Test where works: volts and actions properties specified
773 {
774 const json element = R"(
775 {
776 "comments": [ "comments property" ],
777 "volts": 1.03,
778 "actions": [
779 { "pmbus_write_vout_command": { "format": "linear" } },
780 { "run_rule": "set_voltage_rule" }
781 ]
782 }
783 )"_json;
784 std::unique_ptr<Configuration> configuration =
785 parseConfiguration(element);
786 EXPECT_EQ(configuration->getVolts().has_value(), true);
787 EXPECT_EQ(configuration->getVolts().value(), 1.03);
788 EXPECT_EQ(configuration->getActions().size(), 2);
789 }
790
791 // Test where works: volts and rule_id properties specified
792 {
793 const json element = R"(
794 {
795 "volts": 1.05,
796 "rule_id": "set_voltage_rule"
797 }
798 )"_json;
799 std::unique_ptr<Configuration> configuration =
800 parseConfiguration(element);
801 EXPECT_EQ(configuration->getVolts().has_value(), true);
802 EXPECT_EQ(configuration->getVolts().value(), 1.05);
803 EXPECT_EQ(configuration->getActions().size(), 1);
804 }
805
806 // Test where fails: volts value is invalid
807 try
808 {
809 const json element = R"(
810 {
811 "volts": "foo",
812 "actions": [
813 {
814 "pmbus_write_vout_command": {
815 "format": "linear"
816 }
817 }
818 ]
819 }
820 )"_json;
821 parseConfiguration(element);
822 ADD_FAILURE() << "Should not have reached this line.";
823 }
824 catch (const std::invalid_argument& e)
825 {
826 EXPECT_STREQ(e.what(), "Element is not a number");
827 }
828
829 // Test where fails: actions object is invalid
830 try
831 {
832 const json element = R"(
833 {
834 "volts": 1.03,
835 "actions": 1
836 }
837 )"_json;
838 parseConfiguration(element);
839 ADD_FAILURE() << "Should not have reached this line.";
840 }
841 catch (const std::invalid_argument& e)
842 {
843 EXPECT_STREQ(e.what(), "Element is not an array");
844 }
845
846 // Test where fails: rule_id value is invalid
847 try
848 {
849 const json element = R"(
850 {
851 "volts": 1.05,
852 "rule_id": 1
853 }
854 )"_json;
855 parseConfiguration(element);
856 ADD_FAILURE() << "Should not have reached this line.";
857 }
858 catch (const std::invalid_argument& e)
859 {
860 EXPECT_STREQ(e.what(), "Element is not a string");
861 }
862
863 // Test where fails: Required actions or rule_id property not specified
864 try
865 {
866 const json element = R"(
867 {
868 "volts": 1.03
869 }
870 )"_json;
871 parseConfiguration(element);
872 ADD_FAILURE() << "Should not have reached this line.";
873 }
874 catch (const std::invalid_argument& e)
875 {
876 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain "
877 "either rule_id or actions");
878 }
879
880 // Test where fails: Required actions or rule_id property both specified
881 try
882 {
883 const json element = R"(
884 {
885 "volts": 1.03,
886 "rule_id": "set_voltage_rule",
887 "actions": [
888 {
889 "pmbus_write_vout_command": {
890 "format": "linear"
891 }
892 }
893 ]
894 }
895 )"_json;
896 parseConfiguration(element);
897 ADD_FAILURE() << "Should not have reached this line.";
898 }
899 catch (const std::invalid_argument& e)
900 {
901 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain "
902 "either rule_id or actions");
903 }
904
905 // Test where fails: Element is not an object
906 try
907 {
908 const json element = R"( [ "0xFF", "0x01" ] )"_json;
909 parseConfiguration(element);
910 ADD_FAILURE() << "Should not have reached this line.";
911 }
912 catch (const std::invalid_argument& e)
913 {
914 EXPECT_STREQ(e.what(), "Element is not an object");
915 }
916
917 // Test where fails: Invalid property specified
918 try
919 {
920 const json element = R"(
921 {
922 "volts": 1.03,
923 "rule_id": "set_voltage_rule",
924 "foo": 1
925 }
926 )"_json;
927 parseConfiguration(element);
928 ADD_FAILURE() << "Should not have reached this line.";
929 }
930 catch (const std::invalid_argument& e)
931 {
932 EXPECT_STREQ(e.what(), "Element contains an invalid property");
933 }
934}
935
Bob King9c36c5f2020-04-06 11:34:09 +0800936TEST(ConfigFileParserTests, ParseDevice)
937{
938 // Test where works: Only required properties specified
939 {
940 const json element = R"(
941 {
942 "id": "vdd_regulator",
943 "is_regulator": true,
944 "fru": "/system/chassis/motherboard/regulator2",
945 "i2c_interface": { "bus": 1, "address": "0x70" }
946 }
947 )"_json;
948 std::unique_ptr<Device> device = parseDevice(element);
949 EXPECT_EQ(device->getID(), "vdd_regulator");
950 EXPECT_EQ(device->isRegulator(), true);
951 EXPECT_EQ(device->getFRU(), "/system/chassis/motherboard/regulator2");
952 EXPECT_NE(&(device->getI2CInterface()), nullptr);
953 EXPECT_EQ(device->getPresenceDetection(), nullptr);
954 EXPECT_EQ(device->getConfiguration(), nullptr);
955 EXPECT_EQ(device->getRails().size(), 0);
956 }
957
958 // Test where works: All properties specified
Bob King33e7eaa2020-04-01 18:09:34 +0800959 {
Bob Kinga2f2a0d2020-04-09 13:32:14 +0800960 // TODO : add presence_detection property
Bob King33e7eaa2020-04-01 18:09:34 +0800961 const json element = R"(
962 {
963 "id": "vdd_regulator",
964 "is_regulator": true,
965 "fru": "/system/chassis/motherboard/regulator2",
966 "i2c_interface":
967 {
968 "bus": 1,
969 "address": "0x70"
970 },
971 "configuration":
972 {
973 "rule_id": "configure_ir35221_rule"
Bob Kinga2f2a0d2020-04-09 13:32:14 +0800974 },
975 "rails":
976 [
977 {
978 "id": "vdd"
979 }
980 ]
Bob King33e7eaa2020-04-01 18:09:34 +0800981 }
982 )"_json;
983 std::unique_ptr<Device> device = parseDevice(element);
984 EXPECT_EQ(device->getID(), "vdd_regulator");
985 EXPECT_EQ(device->isRegulator(), true);
986 EXPECT_EQ(device->getFRU(), "/system/chassis/motherboard/regulator2");
987 EXPECT_NE(&(device->getI2CInterface()), nullptr);
988 // EXPECT_NE(device->getPresenceDetection(), nullptr);
989 EXPECT_NE(device->getConfiguration(), nullptr);
Bob Kinga2f2a0d2020-04-09 13:32:14 +0800990 EXPECT_EQ(device->getRails().size(), 1);
991 }
992
993 // Test where fails: rails property exists and is_regulator is false
994 try
995 {
996 const json element = R"(
997 {
998 "id": "vdd_regulator",
999 "is_regulator": false,
1000 "fru": "/system/chassis/motherboard/regulator2",
1001 "i2c_interface":
1002 {
1003 "bus": 1,
1004 "address": "0x70"
1005 },
1006 "configuration":
1007 {
1008 "rule_id": "configure_ir35221_rule"
1009 },
1010 "rails":
1011 [
1012 {
1013 "id": "vdd"
1014 }
1015 ]
1016 }
1017 )"_json;
1018 parseDevice(element);
1019 ADD_FAILURE() << "Should not have reached this line.";
1020 }
1021 catch (const std::invalid_argument& e)
1022 {
1023 EXPECT_STREQ(e.what(),
1024 "Invalid rails property when is_regulator is false");
Bob King33e7eaa2020-04-01 18:09:34 +08001025 }
Bob King9c36c5f2020-04-06 11:34:09 +08001026
1027 // Test where fails: id value is invalid
1028 try
1029 {
1030 const json element = R"(
1031 {
1032 "id": 3,
1033 "is_regulator": true,
1034 "fru": "/system/chassis/motherboard/regulator2",
1035 "i2c_interface":
1036 {
1037 "bus": 1,
1038 "address": "0x70"
1039 }
1040 }
1041 )"_json;
1042 parseDevice(element);
1043 ADD_FAILURE() << "Should not have reached this line.";
1044 }
1045 catch (const std::invalid_argument& e)
1046 {
1047 EXPECT_STREQ(e.what(), "Element is not a string");
1048 }
1049
1050 // Test where fails: is_regulator value is invalid
1051 try
1052 {
1053 const json element = R"(
1054 {
1055 "id": "vdd_regulator",
1056 "is_regulator": 3,
1057 "fru": "/system/chassis/motherboard/regulator2",
1058 "i2c_interface":
1059 {
1060 "bus": 1,
1061 "address": "0x70"
1062 }
1063 }
1064 )"_json;
1065 parseDevice(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 is not a boolean");
1071 }
1072
1073 // Test where fails: fru value is invalid
1074 try
1075 {
1076 const json element = R"(
1077 {
1078 "id": "vdd_regulator",
1079 "is_regulator": true,
1080 "fru": 2,
1081 "i2c_interface":
1082 {
1083 "bus": 1,
1084 "address": "0x70"
1085 }
1086 }
1087 )"_json;
1088 parseDevice(element);
1089 ADD_FAILURE() << "Should not have reached this line.";
1090 }
1091 catch (const std::invalid_argument& e)
1092 {
1093 EXPECT_STREQ(e.what(), "Element is not a string");
1094 }
1095
1096 // Test where fails: i2c_interface value is invalid
1097 try
1098 {
1099 const json element = R"(
1100 {
1101 "id": "vdd_regulator",
1102 "is_regulator": true,
1103 "fru": "/system/chassis/motherboard/regulator2",
1104 "i2c_interface": 3
1105 }
1106 )"_json;
1107 parseDevice(element);
1108 ADD_FAILURE() << "Should not have reached this line.";
1109 }
1110 catch (const std::invalid_argument& e)
1111 {
1112 EXPECT_STREQ(e.what(), "Element is not an object");
1113 }
1114
1115 // Test where fails: Required id property not specified
1116 try
1117 {
1118 const json element = R"(
1119 {
1120 "is_regulator": true,
1121 "fru": "/system/chassis/motherboard/regulator2",
1122 "i2c_interface":
1123 {
1124 "bus": 1,
1125 "address": "0x70"
1126 }
1127 }
1128 )"_json;
1129 parseDevice(element);
1130 ADD_FAILURE() << "Should not have reached this line.";
1131 }
1132 catch (const std::invalid_argument& e)
1133 {
1134 EXPECT_STREQ(e.what(), "Required property missing: id");
1135 }
1136
1137 // Test where fails: Required is_regulator property not specified
1138 try
1139 {
1140 const json element = R"(
1141 {
1142 "id": "vdd_regulator",
1143 "fru": "/system/chassis/motherboard/regulator2",
1144 "i2c_interface":
1145 {
1146 "bus": 1,
1147 "address": "0x70"
1148 }
1149 }
1150 )"_json;
1151 parseDevice(element);
1152 ADD_FAILURE() << "Should not have reached this line.";
1153 }
1154 catch (const std::invalid_argument& e)
1155 {
1156 EXPECT_STREQ(e.what(), "Required property missing: is_regulator");
1157 }
1158
1159 // Test where fails: Required fru property not specified
1160 try
1161 {
1162 const json element = R"(
1163 {
1164 "id": "vdd_regulator",
1165 "is_regulator": true,
1166 "i2c_interface":
1167 {
1168 "bus": 1,
1169 "address": "0x70"
1170 }
1171 }
1172 )"_json;
1173 parseDevice(element);
1174 ADD_FAILURE() << "Should not have reached this line.";
1175 }
1176 catch (const std::invalid_argument& e)
1177 {
1178 EXPECT_STREQ(e.what(), "Required property missing: fru");
1179 }
1180
1181 // Test where fails: Required i2c_interface property not specified
1182 try
1183 {
1184 const json element = R"(
1185 {
1186 "id": "vdd_regulator",
1187 "is_regulator": true,
1188 "fru": "/system/chassis/motherboard/regulator2"
1189 }
1190 )"_json;
1191 parseDevice(element);
1192 ADD_FAILURE() << "Should not have reached this line.";
1193 }
1194 catch (const std::invalid_argument& e)
1195 {
1196 EXPECT_STREQ(e.what(), "Required property missing: i2c_interface");
1197 }
1198
1199 // Test where fails: Element is not an object
1200 try
1201 {
1202 const json element = R"( [ "0xFF", "0x01" ] )"_json;
1203 parseDevice(element);
1204 ADD_FAILURE() << "Should not have reached this line.";
1205 }
1206 catch (const std::invalid_argument& e)
1207 {
1208 EXPECT_STREQ(e.what(), "Element is not an object");
1209 }
1210
1211 // Test where fails: Invalid property specified
1212 try
1213 {
1214 const json element = R"(
1215 {
1216 "id": "vdd_regulator",
1217 "is_regulator": true,
1218 "fru": "/system/chassis/motherboard/regulator2",
1219 "i2c_interface": { "bus": 1, "address": "0x70" },
1220 "foo" : true
1221 }
1222 )"_json;
1223 parseDevice(element);
1224 ADD_FAILURE() << "Should not have reached this line.";
1225 }
1226 catch (const std::invalid_argument& e)
1227 {
1228 EXPECT_STREQ(e.what(), "Element contains an invalid property");
1229 }
1230}
1231
1232TEST(ConfigFileParserTests, ParseDeviceArray)
1233{
1234 // Test where works
1235 {
1236 const json element = R"(
1237 [
1238 {
1239 "id": "vdd_regulator",
1240 "is_regulator": true,
1241 "fru": "/system/chassis/motherboard/regulator2",
1242 "i2c_interface": { "bus": 1, "address": "0x70" }
1243 },
1244 {
1245 "id": "vio_regulator",
1246 "is_regulator": true,
1247 "fru": "/system/chassis/motherboard/regulator2",
1248 "i2c_interface": { "bus": 1, "address": "0x71" }
1249 }
1250 ]
1251 )"_json;
1252 std::vector<std::unique_ptr<Device>> devices =
1253 parseDeviceArray(element);
1254 EXPECT_EQ(devices.size(), 2);
1255 EXPECT_EQ(devices[0]->getID(), "vdd_regulator");
1256 EXPECT_EQ(devices[1]->getID(), "vio_regulator");
1257 }
1258
1259 // Test where fails: Element is not an array
1260 try
1261 {
1262 const json element = R"(
1263 {
1264 "foo": "bar"
1265 }
1266 )"_json;
1267 parseDeviceArray(element);
1268 ADD_FAILURE() << "Should not have reached this line.";
1269 }
1270 catch (const std::invalid_argument& e)
1271 {
1272 EXPECT_STREQ(e.what(), "Element is not an array");
1273 }
1274}
1275
Shawn McCarney0e8c68a2020-03-27 01:44:48 -05001276TEST(ConfigFileParserTests, ParseDouble)
1277{
1278 // Test where works: floating point value
1279 {
1280 const json element = R"( 1.03 )"_json;
1281 double value = parseDouble(element);
1282 EXPECT_EQ(value, 1.03);
1283 }
1284
1285 // Test where works: integer value
1286 {
1287 const json element = R"( 24 )"_json;
1288 double value = parseDouble(element);
1289 EXPECT_EQ(value, 24.0);
1290 }
1291
1292 // Test where fails: Element is not a number
1293 try
1294 {
1295 const json element = R"( true )"_json;
1296 parseDouble(element);
1297 ADD_FAILURE() << "Should not have reached this line.";
1298 }
1299 catch (const std::invalid_argument& e)
1300 {
1301 EXPECT_STREQ(e.what(), "Element is not a number");
1302 }
1303}
1304
Bob Kingbafcb862020-03-31 16:39:00 +08001305TEST(ConfigFileParserTests, ParseHexByte)
1306{
1307 // Test where works: "0xFF"
1308 {
1309 const json element = R"( "0xFF" )"_json;
1310 uint8_t value = parseHexByte(element);
1311 EXPECT_EQ(value, 0xFF);
1312 }
1313
1314 // Test where works: "0xff"
1315 {
1316 const json element = R"( "0xff" )"_json;
1317 uint8_t value = parseHexByte(element);
1318 EXPECT_EQ(value, 0xff);
1319 }
1320
1321 // Test where works: "0xf"
1322 {
1323 const json element = R"( "0xf" )"_json;
1324 uint8_t value = parseHexByte(element);
1325 EXPECT_EQ(value, 0xf);
1326 }
1327
1328 // Test where fails: "0xfff"
1329 try
1330 {
1331 const json element = R"( "0xfff" )"_json;
1332 parseHexByte(element);
1333 ADD_FAILURE() << "Should not have reached this line.";
1334 }
1335 catch (const std::invalid_argument& e)
1336 {
1337 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
1338 }
1339
1340 // Test where fails: "0xAG"
1341 try
1342 {
1343 const json element = R"( "0xAG" )"_json;
1344 parseHexByte(element);
1345 ADD_FAILURE() << "Should not have reached this line.";
1346 }
1347 catch (const std::invalid_argument& e)
1348 {
1349 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
1350 }
1351
1352 // Test where fails: "ff"
1353 try
1354 {
1355 const json element = R"( "ff" )"_json;
1356 parseHexByte(element);
1357 ADD_FAILURE() << "Should not have reached this line.";
1358 }
1359 catch (const std::invalid_argument& e)
1360 {
1361 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
1362 }
1363
1364 // Test where fails: ""
1365 try
1366 {
1367 const json element = "";
1368 parseHexByte(element);
1369 ADD_FAILURE() << "Should not have reached this line.";
1370 }
1371 catch (const std::invalid_argument& e)
1372 {
1373 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
1374 }
1375
1376 // Test where fails: "f"
1377 try
1378 {
1379 const json element = R"( "f" )"_json;
1380 parseHexByte(element);
1381 ADD_FAILURE() << "Should not have reached this line.";
1382 }
1383 catch (const std::invalid_argument& e)
1384 {
1385 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
1386 }
1387
1388 // Test where fails: "0x"
1389 try
1390 {
1391 const json element = R"( "0x" )"_json;
1392 parseHexByte(element);
1393 ADD_FAILURE() << "Should not have reached this line.";
1394 }
1395 catch (const std::invalid_argument& e)
1396 {
1397 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
1398 }
1399
1400 // Test where fails: "0Xff"
1401 try
1402 {
1403 const json element = R"( "0XFF" )"_json;
1404 parseHexByte(element);
1405 ADD_FAILURE() << "Should not have reached this line.";
1406 }
1407 catch (const std::invalid_argument& e)
1408 {
1409 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
1410 }
1411}
1412
1413TEST(ConfigFileParserTests, ParseHexByteArray)
1414{
1415 // Test where works
1416 {
1417 const json element = R"( [ "0xCC", "0xFF" ] )"_json;
1418 std::vector<uint8_t> hexBytes = parseHexByteArray(element);
1419 std::vector<uint8_t> expected = {0xcc, 0xff};
1420 EXPECT_EQ(hexBytes, expected);
1421 }
1422
1423 // Test where fails: Element is not an array
1424 try
1425 {
1426 const json element = 0;
1427 parseHexByteArray(element);
1428 ADD_FAILURE() << "Should not have reached this line.";
1429 }
1430 catch (const std::invalid_argument& e)
1431 {
1432 EXPECT_STREQ(e.what(), "Element is not an array");
1433 }
1434}
1435
Bob Kingf617f892020-03-30 19:03:35 +08001436TEST(ConfigFileParserTests, ParseI2CWriteBit)
1437{
1438 // Test where works
1439 {
1440 const json element = R"(
1441 {
1442 "register": "0xA0",
1443 "position": 3,
1444 "value": 0
1445 }
1446 )"_json;
1447 std::unique_ptr<I2CWriteBitAction> action = parseI2CWriteBit(element);
1448 EXPECT_EQ(action->getRegister(), 0xA0);
1449 EXPECT_EQ(action->getPosition(), 3);
1450 EXPECT_EQ(action->getValue(), 0);
1451 }
1452
1453 // Test where fails: Invalid property specified
1454 try
1455 {
1456 const json element = R"(
1457 {
1458 "register": "0xA0",
1459 "position": 3,
1460 "value": 0,
1461 "foo": 3
1462 }
1463 )"_json;
1464 parseI2CWriteBit(element);
1465 ADD_FAILURE() << "Should not have reached this line.";
1466 }
1467 catch (const std::invalid_argument& e)
1468 {
1469 EXPECT_STREQ(e.what(), "Element contains an invalid property");
1470 }
1471
1472 // Test where fails: Element is not an object
1473 try
1474 {
1475 const json element = R"( [ "0xFF", "0x01" ] )"_json;
1476 parseI2CWriteBit(element);
1477 ADD_FAILURE() << "Should not have reached this line.";
1478 }
1479 catch (const std::invalid_argument& e)
1480 {
1481 EXPECT_STREQ(e.what(), "Element is not an object");
1482 }
1483
1484 // Test where fails: register value is invalid
1485 try
1486 {
1487 const json element = R"(
1488 {
1489 "register": "0xAG",
1490 "position": 3,
1491 "value": 0
1492 }
1493 )"_json;
1494 parseI2CWriteBit(element);
1495 ADD_FAILURE() << "Should not have reached this line.";
1496 }
1497 catch (const std::invalid_argument& e)
1498 {
1499 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
1500 }
1501
1502 // Test where fails: position value is invalid
1503 try
1504 {
1505 const json element = R"(
1506 {
1507 "register": "0xA0",
1508 "position": 8,
1509 "value": 0
1510 }
1511 )"_json;
1512 parseI2CWriteBit(element);
1513 ADD_FAILURE() << "Should not have reached this line.";
1514 }
1515 catch (const std::invalid_argument& e)
1516 {
1517 EXPECT_STREQ(e.what(), "Element is not a bit position");
1518 }
1519
1520 // Test where fails: value value is invalid
1521 try
1522 {
1523 const json element = R"(
1524 {
1525 "register": "0xA0",
1526 "position": 3,
1527 "value": 2
1528 }
1529 )"_json;
1530 parseI2CWriteBit(element);
1531 ADD_FAILURE() << "Should not have reached this line.";
1532 }
1533 catch (const std::invalid_argument& e)
1534 {
1535 EXPECT_STREQ(e.what(), "Element is not a bit value");
1536 }
1537
1538 // Test where fails: Required register property not specified
1539 try
1540 {
1541 const json element = R"(
1542 {
1543 "position": 3,
1544 "value": 0
1545 }
1546 )"_json;
1547 parseI2CWriteBit(element);
1548 ADD_FAILURE() << "Should not have reached this line.";
1549 }
1550 catch (const std::invalid_argument& e)
1551 {
1552 EXPECT_STREQ(e.what(), "Required property missing: register");
1553 }
1554
1555 // Test where fails: Required position property not specified
1556 try
1557 {
1558 const json element = R"(
1559 {
1560 "register": "0xA0",
1561 "value": 0
1562 }
1563 )"_json;
1564 parseI2CWriteBit(element);
1565 ADD_FAILURE() << "Should not have reached this line.";
1566 }
1567 catch (const std::invalid_argument& e)
1568 {
1569 EXPECT_STREQ(e.what(), "Required property missing: position");
1570 }
1571
1572 // Test where fails: Required value property not specified
1573 try
1574 {
1575 const json element = R"(
1576 {
1577 "register": "0xA0",
1578 "position": 3
1579 }
1580 )"_json;
1581 parseI2CWriteBit(element);
1582 ADD_FAILURE() << "Should not have reached this line.";
1583 }
1584 catch (const std::invalid_argument& e)
1585 {
1586 EXPECT_STREQ(e.what(), "Required property missing: value");
1587 }
1588}
1589
Bob King87ff9d72020-03-31 14:02:55 +08001590TEST(ConfigFileParserTests, ParseI2CWriteByte)
1591{
1592 // Test where works: Only required properties specified
1593 {
1594 const json element = R"(
1595 {
1596 "register": "0x0A",
1597 "value": "0xCC"
1598 }
1599 )"_json;
1600 std::unique_ptr<I2CWriteByteAction> action = parseI2CWriteByte(element);
1601 EXPECT_EQ(action->getRegister(), 0x0A);
1602 EXPECT_EQ(action->getValue(), 0xCC);
1603 EXPECT_EQ(action->getMask(), 0xFF);
1604 }
1605
1606 // Test where works: All properties specified
1607 {
1608 const json element = R"(
1609 {
1610 "register": "0x0A",
1611 "value": "0xCC",
1612 "mask": "0xF7"
1613 }
1614 )"_json;
1615 std::unique_ptr<I2CWriteByteAction> action = parseI2CWriteByte(element);
1616 EXPECT_EQ(action->getRegister(), 0x0A);
1617 EXPECT_EQ(action->getValue(), 0xCC);
1618 EXPECT_EQ(action->getMask(), 0xF7);
1619 }
1620
1621 // Test where fails: Element is not an object
1622 try
1623 {
1624 const json element = R"( [ "0xFF", "0x01" ] )"_json;
1625 parseI2CWriteByte(element);
1626 ADD_FAILURE() << "Should not have reached this line.";
1627 }
1628 catch (const std::invalid_argument& e)
1629 {
1630 EXPECT_STREQ(e.what(), "Element is not an object");
1631 }
1632
1633 // Test where fails: Invalid property specified
1634 try
1635 {
1636 const json element = R"(
1637 {
1638 "register": "0x0A",
1639 "value": "0xCC",
1640 "mask": "0xF7",
1641 "foo": 1
1642 }
1643 )"_json;
1644 parseI2CWriteByte(element);
1645 ADD_FAILURE() << "Should not have reached this line.";
1646 }
1647 catch (const std::invalid_argument& e)
1648 {
1649 EXPECT_STREQ(e.what(), "Element contains an invalid property");
1650 }
1651
1652 // Test where fails: register value is invalid
1653 try
1654 {
1655 const json element = R"(
1656 {
1657 "register": "0x0Z",
1658 "value": "0xCC",
1659 "mask": "0xF7"
1660 }
1661 )"_json;
1662 parseI2CWriteByte(element);
1663 ADD_FAILURE() << "Should not have reached this line.";
1664 }
1665 catch (const std::invalid_argument& e)
1666 {
1667 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
1668 }
1669
1670 // Test where fails: value value is invalid
1671 try
1672 {
1673 const json element = R"(
1674 {
1675 "register": "0x0A",
1676 "value": "0xCCC",
1677 "mask": "0xF7"
1678 }
1679 )"_json;
1680 parseI2CWriteByte(element);
1681 ADD_FAILURE() << "Should not have reached this line.";
1682 }
1683 catch (const std::invalid_argument& e)
1684 {
1685 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
1686 }
1687
1688 // Test where fails: mask value is invalid
1689 try
1690 {
1691 const json element = R"(
1692 {
1693 "register": "0x0A",
1694 "value": "0xCC",
1695 "mask": "F7"
1696 }
1697 )"_json;
1698 parseI2CWriteByte(element);
1699 ADD_FAILURE() << "Should not have reached this line.";
1700 }
1701 catch (const std::invalid_argument& e)
1702 {
1703 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
1704 }
1705
1706 // Test where fails: Required register property not specified
1707 try
1708 {
1709 const json element = R"(
1710 {
1711 "value": "0xCC",
1712 "mask": "0xF7"
1713 }
1714 )"_json;
1715 parseI2CWriteByte(element);
1716 ADD_FAILURE() << "Should not have reached this line.";
1717 }
1718 catch (const std::invalid_argument& e)
1719 {
1720 EXPECT_STREQ(e.what(), "Required property missing: register");
1721 }
1722
1723 // Test where fails: Required value property not specified
1724 try
1725 {
1726 const json element = R"(
1727 {
1728 "register": "0x0A",
1729 "mask": "0xF7"
1730 }
1731 )"_json;
1732 parseI2CWriteByte(element);
1733 ADD_FAILURE() << "Should not have reached this line.";
1734 }
1735 catch (const std::invalid_argument& e)
1736 {
1737 EXPECT_STREQ(e.what(), "Required property missing: value");
1738 }
1739}
1740
Bob Kingbafcb862020-03-31 16:39:00 +08001741TEST(ConfigFileParserTests, ParseI2CWriteBytes)
1742{
1743 // Test where works: Only required properties specified
1744 {
1745 const json element = R"(
1746 {
1747 "register": "0x0A",
1748 "values": [ "0xCC", "0xFF" ]
1749 }
1750 )"_json;
1751 std::unique_ptr<I2CWriteBytesAction> action =
1752 parseI2CWriteBytes(element);
1753 EXPECT_EQ(action->getRegister(), 0x0A);
1754 EXPECT_EQ(action->getValues().size(), 2);
1755 EXPECT_EQ(action->getValues()[0], 0xCC);
1756 EXPECT_EQ(action->getValues()[1], 0xFF);
1757 EXPECT_EQ(action->getMasks().size(), 0);
1758 }
1759
1760 // Test where works: All properties specified
1761 {
1762 const json element = R"(
1763 {
1764 "register": "0x0A",
1765 "values": [ "0xCC", "0xFF" ],
1766 "masks": [ "0x7F", "0x77" ]
1767 }
1768 )"_json;
1769 std::unique_ptr<I2CWriteBytesAction> action =
1770 parseI2CWriteBytes(element);
1771 EXPECT_EQ(action->getRegister(), 0x0A);
1772 EXPECT_EQ(action->getValues().size(), 2);
1773 EXPECT_EQ(action->getValues()[0], 0xCC);
1774 EXPECT_EQ(action->getValues()[1], 0xFF);
1775 EXPECT_EQ(action->getMasks().size(), 2);
1776 EXPECT_EQ(action->getMasks()[0], 0x7F);
1777 EXPECT_EQ(action->getMasks()[1], 0x77);
1778 }
1779
1780 // Test where fails: Element is not an object
1781 try
1782 {
1783 const json element = R"( [ "0xFF", "0x01" ] )"_json;
1784 parseI2CWriteBytes(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: Invalid property specified
1793 try
1794 {
1795 const json element = R"(
1796 {
1797 "register": "0x0A",
1798 "values": [ "0xCC", "0xFF" ],
1799 "masks": [ "0x7F", "0x7F" ],
1800 "foo": 1
1801 }
1802 )"_json;
1803 parseI2CWriteBytes(element);
1804 ADD_FAILURE() << "Should not have reached this line.";
1805 }
1806 catch (const std::invalid_argument& e)
1807 {
1808 EXPECT_STREQ(e.what(), "Element contains an invalid property");
1809 }
1810
1811 // Test where fails: register value is invalid
1812 try
1813 {
1814 const json element = R"(
1815 {
1816 "register": "0x0Z",
1817 "values": [ "0xCC", "0xFF" ],
1818 "masks": [ "0x7F", "0x7F" ]
1819 }
1820 )"_json;
1821 parseI2CWriteBytes(element);
1822 ADD_FAILURE() << "Should not have reached this line.";
1823 }
1824 catch (const std::invalid_argument& e)
1825 {
1826 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
1827 }
1828
1829 // Test where fails: values value is invalid
1830 try
1831 {
1832 const json element = R"(
1833 {
1834 "register": "0x0A",
1835 "values": [ "0xCCC", "0xFF" ],
1836 "masks": [ "0x7F", "0x7F" ]
1837 }
1838 )"_json;
1839 parseI2CWriteBytes(element);
1840 ADD_FAILURE() << "Should not have reached this line.";
1841 }
1842 catch (const std::invalid_argument& e)
1843 {
1844 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
1845 }
1846
1847 // Test where fails: masks value is invalid
1848 try
1849 {
1850 const json element = R"(
1851 {
1852 "register": "0x0A",
1853 "values": [ "0xCC", "0xFF" ],
1854 "masks": [ "F", "0x7F" ]
1855 }
1856 )"_json;
1857 parseI2CWriteBytes(element);
1858 ADD_FAILURE() << "Should not have reached this line.";
1859 }
1860 catch (const std::invalid_argument& e)
1861 {
1862 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
1863 }
1864
1865 // Test where fails: number of elements in masks is invalid
1866 try
1867 {
1868 const json element = R"(
1869 {
1870 "register": "0x0A",
1871 "values": [ "0xCC", "0xFF" ],
1872 "masks": [ "0x7F" ]
1873 }
1874 )"_json;
1875 parseI2CWriteBytes(element);
1876 ADD_FAILURE() << "Should not have reached this line.";
1877 }
1878 catch (const std::invalid_argument& e)
1879 {
1880 EXPECT_STREQ(e.what(), "Invalid number of elements in masks");
1881 }
1882
1883 // Test where fails: Required register property not specified
1884 try
1885 {
1886 const json element = R"(
1887 {
1888 "values": [ "0xCC", "0xFF" ]
1889 }
1890 )"_json;
1891 parseI2CWriteBytes(element);
1892 ADD_FAILURE() << "Should not have reached this line.";
1893 }
1894 catch (const std::invalid_argument& e)
1895 {
1896 EXPECT_STREQ(e.what(), "Required property missing: register");
1897 }
1898
1899 // Test where fails: Required values property not specified
1900 try
1901 {
1902 const json element = R"(
1903 {
1904 "register": "0x0A"
1905 }
1906 )"_json;
1907 parseI2CWriteBytes(element);
1908 ADD_FAILURE() << "Should not have reached this line.";
1909 }
1910 catch (const std::invalid_argument& e)
1911 {
1912 EXPECT_STREQ(e.what(), "Required property missing: values");
1913 }
1914}
1915
Bob King87ff9d72020-03-31 14:02:55 +08001916TEST(ConfigFileParserTests, ParseInt8)
1917{
1918 // Test where works: INT8_MIN
1919 {
1920 const json element = R"( -128 )"_json;
1921 int8_t value = parseInt8(element);
1922 EXPECT_EQ(value, -128);
1923 }
1924
1925 // Test where works: INT8_MAX
1926 {
1927 const json element = R"( 127 )"_json;
1928 int8_t value = parseInt8(element);
1929 EXPECT_EQ(value, 127);
1930 }
1931
1932 // Test where fails: Element is not an integer
1933 try
1934 {
1935 const json element = R"( 1.03 )"_json;
1936 parseInt8(element);
1937 ADD_FAILURE() << "Should not have reached this line.";
1938 }
1939 catch (const std::invalid_argument& e)
1940 {
1941 EXPECT_STREQ(e.what(), "Element is not an integer");
1942 }
1943
1944 // Test where fails: Value < INT8_MIN
1945 try
1946 {
1947 const json element = R"( -129 )"_json;
1948 parseInt8(element);
1949 ADD_FAILURE() << "Should not have reached this line.";
1950 }
1951 catch (const std::invalid_argument& e)
1952 {
1953 EXPECT_STREQ(e.what(), "Element is not an 8-bit signed integer");
1954 }
1955
1956 // Test where fails: Value > INT8_MAX
1957 try
1958 {
1959 const json element = R"( 128 )"_json;
1960 parseInt8(element);
1961 ADD_FAILURE() << "Should not have reached this line.";
1962 }
1963 catch (const std::invalid_argument& e)
1964 {
1965 EXPECT_STREQ(e.what(), "Element is not an 8-bit signed integer");
1966 }
1967}
1968
Shawn McCarney0e8c68a2020-03-27 01:44:48 -05001969TEST(ConfigFileParserTests, ParsePMBusWriteVoutCommand)
1970{
1971 // Test where works: Only required properties specified
1972 {
1973 const json element = R"(
1974 {
1975 "format": "linear"
1976 }
1977 )"_json;
1978 std::unique_ptr<PMBusWriteVoutCommandAction> action =
1979 parsePMBusWriteVoutCommand(element);
1980 EXPECT_EQ(action->getVolts().has_value(), false);
1981 EXPECT_EQ(action->getFormat(), pmbus_utils::VoutDataFormat::linear);
1982 EXPECT_EQ(action->getExponent().has_value(), false);
1983 EXPECT_EQ(action->isVerified(), false);
1984 }
1985
1986 // Test where works: All properties specified
1987 {
1988 const json element = R"(
1989 {
1990 "volts": 1.03,
1991 "format": "linear",
1992 "exponent": -8,
1993 "is_verified": true
1994 }
1995 )"_json;
1996 std::unique_ptr<PMBusWriteVoutCommandAction> action =
1997 parsePMBusWriteVoutCommand(element);
1998 EXPECT_EQ(action->getVolts().has_value(), true);
1999 EXPECT_EQ(action->getVolts().value(), 1.03);
2000 EXPECT_EQ(action->getFormat(), pmbus_utils::VoutDataFormat::linear);
2001 EXPECT_EQ(action->getExponent().has_value(), true);
2002 EXPECT_EQ(action->getExponent().value(), -8);
2003 EXPECT_EQ(action->isVerified(), true);
2004 }
2005
2006 // Test where fails: Element is not an object
2007 try
2008 {
2009 const json element = R"( [ "0xFF", "0x01" ] )"_json;
2010 parsePMBusWriteVoutCommand(element);
2011 ADD_FAILURE() << "Should not have reached this line.";
2012 }
2013 catch (const std::invalid_argument& e)
2014 {
2015 EXPECT_STREQ(e.what(), "Element is not an object");
2016 }
2017
2018 // Test where fails: volts value is invalid
2019 try
2020 {
2021 const json element = R"(
2022 {
2023 "volts": "foo",
2024 "format": "linear"
2025 }
2026 )"_json;
2027 parsePMBusWriteVoutCommand(element);
2028 ADD_FAILURE() << "Should not have reached this line.";
2029 }
2030 catch (const std::invalid_argument& e)
2031 {
2032 EXPECT_STREQ(e.what(), "Element is not a number");
2033 }
2034
2035 // Test where fails: Required format property not specified
2036 try
2037 {
2038 const json element = R"(
2039 {
2040 "volts": 1.03,
2041 "is_verified": true
2042 }
2043 )"_json;
2044 parsePMBusWriteVoutCommand(element);
2045 ADD_FAILURE() << "Should not have reached this line.";
2046 }
2047 catch (const std::invalid_argument& e)
2048 {
2049 EXPECT_STREQ(e.what(), "Required property missing: format");
2050 }
2051
2052 // Test where fails: format value is invalid
2053 try
2054 {
2055 const json element = R"(
2056 {
2057 "format": "linear_11"
2058 }
2059 )"_json;
2060 parsePMBusWriteVoutCommand(element);
2061 ADD_FAILURE() << "Should not have reached this line.";
2062 }
2063 catch (const std::invalid_argument& e)
2064 {
2065 EXPECT_STREQ(e.what(), "Invalid format value: linear_11");
2066 }
2067
2068 // Test where fails: exponent value is invalid
2069 try
2070 {
2071 const json element = R"(
2072 {
2073 "format": "linear",
2074 "exponent": 1.3
2075 }
2076 )"_json;
2077 parsePMBusWriteVoutCommand(element);
2078 ADD_FAILURE() << "Should not have reached this line.";
2079 }
2080 catch (const std::invalid_argument& e)
2081 {
2082 EXPECT_STREQ(e.what(), "Element is not an integer");
2083 }
2084
2085 // Test where fails: is_verified value is invalid
2086 try
2087 {
2088 const json element = R"(
2089 {
2090 "format": "linear",
2091 "is_verified": "true"
2092 }
2093 )"_json;
2094 parsePMBusWriteVoutCommand(element);
2095 ADD_FAILURE() << "Should not have reached this line.";
2096 }
2097 catch (const std::invalid_argument& e)
2098 {
2099 EXPECT_STREQ(e.what(), "Element is not a boolean");
2100 }
2101
2102 // Test where fails: Invalid property specified
2103 try
2104 {
2105 const json element = R"(
2106 {
2107 "format": "linear",
2108 "foo": "bar"
2109 }
2110 )"_json;
2111 parsePMBusWriteVoutCommand(element);
2112 ADD_FAILURE() << "Should not have reached this line.";
2113 }
2114 catch (const std::invalid_argument& e)
2115 {
2116 EXPECT_STREQ(e.what(), "Element contains an invalid property");
2117 }
2118}
2119
Bob Kinga2f2a0d2020-04-09 13:32:14 +08002120TEST(ConfigFileParserTests, ParseRail)
2121{
2122 // Test where works: Only required properties specified
2123 {
2124 const json element = R"(
2125 {
2126 "id": "vdd"
2127 }
2128 )"_json;
2129 std::unique_ptr<Rail> rail = parseRail(element);
2130 EXPECT_EQ(rail->getID(), "vdd");
2131 EXPECT_EQ(rail->getConfiguration(), nullptr);
2132 EXPECT_EQ(rail->getSensorMonitoring(), nullptr);
2133 }
2134
2135 // Test where works: All properties specified
2136 {
2137 const json element = R"(
2138 {
2139 "comments": [ "comments property" ],
2140 "id": "vdd",
2141 "configuration": {
2142 "volts": 1.1,
2143 "actions": [
2144 {
2145 "pmbus_write_vout_command": {
2146 "format": "linear"
2147 }
2148 }
2149 ]
2150 },
2151 "sensor_monitoring": {
2152 "actions": [
2153 { "run_rule": "read_sensors_rule" }
2154 ]
2155 }
2156 }
2157 )"_json;
2158 std::unique_ptr<Rail> rail = parseRail(element);
2159 EXPECT_EQ(rail->getID(), "vdd");
2160 EXPECT_NE(rail->getConfiguration(), nullptr);
2161 EXPECT_NE(rail->getSensorMonitoring(), nullptr);
2162 }
2163
2164 // Test where fails: id property not specified
2165 try
2166 {
2167 const json element = R"(
2168 {
2169 "configuration": {
2170 "volts": 1.1,
2171 "actions": [
2172 {
2173 "pmbus_write_vout_command": {
2174 "format": "linear"
2175 }
2176 }
2177 ]
2178 }
2179 }
2180 )"_json;
2181 parseRail(element);
2182 ADD_FAILURE() << "Should not have reached this line.";
2183 }
2184 catch (const std::invalid_argument& e)
2185 {
2186 EXPECT_STREQ(e.what(), "Required property missing: id");
2187 }
2188
2189 // Test where fails: id property is invalid
2190 try
2191 {
2192 const json element = R"(
2193 {
2194 "id": "",
2195 "configuration": {
2196 "volts": 1.1,
2197 "actions": [
2198 {
2199 "pmbus_write_vout_command": {
2200 "format": "linear"
2201 }
2202 }
2203 ]
2204 }
2205 }
2206 )"_json;
2207 parseRail(element);
2208 ADD_FAILURE() << "Should not have reached this line.";
2209 }
2210 catch (const std::invalid_argument& e)
2211 {
2212 EXPECT_STREQ(e.what(), "Element contains an empty string");
2213 }
2214
2215 // Test where fails: Element is not an object
2216 try
2217 {
2218 const json element = R"( [ "0xFF", "0x01" ] )"_json;
2219 parseRail(element);
2220 ADD_FAILURE() << "Should not have reached this line.";
2221 }
2222 catch (const std::invalid_argument& e)
2223 {
2224 EXPECT_STREQ(e.what(), "Element is not an object");
2225 }
2226
2227 // Test where fails: configuration value is invalid
2228 try
2229 {
2230 const json element = R"(
2231 {
2232 "id": "vdd",
2233 "configuration": "config"
2234 }
2235 )"_json;
2236 parseRail(element);
2237 ADD_FAILURE() << "Should not have reached this line.";
2238 }
2239 catch (const std::invalid_argument& e)
2240 {
2241 EXPECT_STREQ(e.what(), "Element is not an object");
2242 }
2243
2244 // Test where fails: sensor_monitoring value is invalid
2245 try
2246 {
2247 const json element = R"(
2248 {
2249 "comments": [ "comments property" ],
2250 "id": "vdd",
2251 "configuration": {
2252 "volts": 1.1,
2253 "actions": [
2254 {
2255 "pmbus_write_vout_command": {
2256 "format": "linear"
2257 }
2258 }
2259 ]
2260 },
2261 "sensor_monitoring": 1
2262 }
2263 )"_json;
2264 parseRail(element);
2265 ADD_FAILURE() << "Should not have reached this line.";
2266 }
2267 catch (const std::invalid_argument& e)
2268 {
2269 EXPECT_STREQ(e.what(), "Element is not an object");
2270 }
2271
2272 // Test where fails: Invalid property specified
2273 try
2274 {
2275 const json element = R"(
2276 {
2277 "id": "vdd",
2278 "foo" : true
2279 }
2280 )"_json;
2281 parseRail(element);
2282 ADD_FAILURE() << "Should not have reached this line.";
2283 }
2284 catch (const std::invalid_argument& e)
2285 {
2286 EXPECT_STREQ(e.what(), "Element contains an invalid property");
2287 }
2288}
2289
2290TEST(ConfigFileParserTests, ParseRailArray)
2291{
2292 // Test where works
2293 {
2294 const json element = R"(
2295 [
2296 { "id": "vdd" },
2297 { "id": "vio" }
2298 ]
2299 )"_json;
2300 std::vector<std::unique_ptr<Rail>> rails = parseRailArray(element);
2301 EXPECT_EQ(rails.size(), 2);
2302 EXPECT_EQ(rails[0]->getID(), "vdd");
2303 EXPECT_EQ(rails[1]->getID(), "vio");
2304 }
2305
2306 // Test where fails: Element is not an array
2307 try
2308 {
2309 const json element = R"(
2310 {
2311 "foo": "bar"
2312 }
2313 )"_json;
2314 parseRailArray(element);
2315 ADD_FAILURE() << "Should not have reached this line.";
2316 }
2317 catch (const std::invalid_argument& e)
2318 {
2319 EXPECT_STREQ(e.what(), "Element is not an array");
2320 }
2321}
2322
Shawn McCarney0e8c68a2020-03-27 01:44:48 -05002323TEST(ConfigFileParserTests, ParseRoot)
2324{
2325 // Test where works: Only required properties specified
2326 {
2327 const json element = R"(
2328 {
2329 "chassis": [
2330 { "number": 1 }
2331 ]
2332 }
2333 )"_json;
2334 std::vector<std::unique_ptr<Rule>> rules{};
2335 std::vector<std::unique_ptr<Chassis>> chassis{};
2336 std::tie(rules, chassis) = parseRoot(element);
2337 EXPECT_EQ(rules.size(), 0);
Bob King0e701132020-04-03 21:50:31 +08002338 EXPECT_EQ(chassis.size(), 1);
Shawn McCarney0e8c68a2020-03-27 01:44:48 -05002339 }
2340
2341 // Test where works: All properties specified
2342 {
2343 const json element = R"(
2344 {
2345 "comments": [ "Config file for a FooBar one-chassis system" ],
2346 "rules": [
2347 {
2348 "id": "set_voltage_rule",
2349 "actions": [
2350 { "pmbus_write_vout_command": { "format": "linear" } }
2351 ]
2352 }
2353 ],
2354 "chassis": [
2355 { "number": 1 },
2356 { "number": 3 }
2357 ]
2358 }
2359 )"_json;
2360 std::vector<std::unique_ptr<Rule>> rules{};
2361 std::vector<std::unique_ptr<Chassis>> chassis{};
2362 std::tie(rules, chassis) = parseRoot(element);
2363 EXPECT_EQ(rules.size(), 1);
Bob King0e701132020-04-03 21:50:31 +08002364 EXPECT_EQ(chassis.size(), 2);
Shawn McCarney0e8c68a2020-03-27 01:44:48 -05002365 }
2366
2367 // Test where fails: Element is not an object
2368 try
2369 {
2370 const json element = R"( [ "0xFF", "0x01" ] )"_json;
2371 parseRoot(element);
2372 ADD_FAILURE() << "Should not have reached this line.";
2373 }
2374 catch (const std::invalid_argument& e)
2375 {
2376 EXPECT_STREQ(e.what(), "Element is not an object");
2377 }
2378
2379 // Test where fails: chassis property not specified
2380 try
2381 {
2382 const json element = R"(
2383 {
2384 "rules": [
2385 {
2386 "id": "set_voltage_rule",
2387 "actions": [
2388 { "pmbus_write_vout_command": { "format": "linear" } }
2389 ]
2390 }
2391 ]
2392 }
2393 )"_json;
2394 parseRoot(element);
2395 ADD_FAILURE() << "Should not have reached this line.";
2396 }
2397 catch (const std::invalid_argument& e)
2398 {
2399 EXPECT_STREQ(e.what(), "Required property missing: chassis");
2400 }
2401
2402 // Test where fails: Invalid property specified
2403 try
2404 {
2405 const json element = R"(
2406 {
2407 "remarks": [ "Config file for a FooBar one-chassis system" ],
2408 "chassis": [
2409 { "number": 1 }
2410 ]
2411 }
2412 )"_json;
2413 parseRoot(element);
2414 ADD_FAILURE() << "Should not have reached this line.";
2415 }
2416 catch (const std::invalid_argument& e)
2417 {
2418 EXPECT_STREQ(e.what(), "Element contains an invalid property");
2419 }
2420}
2421
2422TEST(ConfigFileParserTests, ParseRule)
2423{
2424 // Test where works: comments property specified
2425 {
2426 const json element = R"(
2427 {
2428 "comments": [ "Set voltage rule" ],
2429 "id": "set_voltage_rule",
2430 "actions": [
2431 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } },
2432 { "pmbus_write_vout_command": { "volts": 1.03, "format": "linear" } }
2433 ]
2434 }
2435 )"_json;
2436 std::unique_ptr<Rule> rule = parseRule(element);
2437 EXPECT_EQ(rule->getID(), "set_voltage_rule");
2438 EXPECT_EQ(rule->getActions().size(), 2);
2439 }
2440
2441 // Test where works: comments property not specified
2442 {
2443 const json element = R"(
2444 {
2445 "id": "set_voltage_rule",
2446 "actions": [
2447 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } },
2448 { "pmbus_write_vout_command": { "volts": 1.03, "format": "linear" } },
2449 { "pmbus_write_vout_command": { "volts": 1.05, "format": "linear" } }
2450 ]
2451 }
2452 )"_json;
2453 std::unique_ptr<Rule> rule = parseRule(element);
2454 EXPECT_EQ(rule->getID(), "set_voltage_rule");
2455 EXPECT_EQ(rule->getActions().size(), 3);
2456 }
2457
2458 // Test where fails: Element is not an object
2459 try
2460 {
2461 const json element = R"( [ "0xFF", "0x01" ] )"_json;
2462 parseRule(element);
2463 ADD_FAILURE() << "Should not have reached this line.";
2464 }
2465 catch (const std::invalid_argument& e)
2466 {
2467 EXPECT_STREQ(e.what(), "Element is not an object");
2468 }
2469
2470 // Test where fails: id property not specified
2471 try
2472 {
2473 const json element = R"(
2474 {
2475 "actions": [
2476 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } }
2477 ]
2478 }
2479 )"_json;
2480 parseRule(element);
2481 ADD_FAILURE() << "Should not have reached this line.";
2482 }
2483 catch (const std::invalid_argument& e)
2484 {
2485 EXPECT_STREQ(e.what(), "Required property missing: id");
2486 }
2487
2488 // Test where fails: id property is invalid
2489 try
2490 {
2491 const json element = R"(
2492 {
2493 "id": "",
2494 "actions": [
2495 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } }
2496 ]
2497 }
2498 )"_json;
2499 parseRule(element);
2500 ADD_FAILURE() << "Should not have reached this line.";
2501 }
2502 catch (const std::invalid_argument& e)
2503 {
2504 EXPECT_STREQ(e.what(), "Element contains an empty string");
2505 }
2506
2507 // Test where fails: actions property not specified
2508 try
2509 {
2510 const json element = R"(
2511 {
2512 "comments": [ "Set voltage rule" ],
2513 "id": "set_voltage_rule"
2514 }
2515 )"_json;
2516 parseRule(element);
2517 ADD_FAILURE() << "Should not have reached this line.";
2518 }
2519 catch (const std::invalid_argument& e)
2520 {
2521 EXPECT_STREQ(e.what(), "Required property missing: actions");
2522 }
2523
2524 // Test where fails: actions property is invalid
2525 try
2526 {
2527 const json element = R"(
2528 {
2529 "id": "set_voltage_rule",
2530 "actions": true
2531 }
2532 )"_json;
2533 parseRule(element);
2534 ADD_FAILURE() << "Should not have reached this line.";
2535 }
2536 catch (const std::invalid_argument& e)
2537 {
2538 EXPECT_STREQ(e.what(), "Element is not an array");
2539 }
2540
2541 // Test where fails: Invalid property specified
2542 try
2543 {
2544 const json element = R"(
2545 {
2546 "remarks": [ "Set voltage rule" ],
2547 "id": "set_voltage_rule",
2548 "actions": [
2549 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } }
2550 ]
2551 }
2552 )"_json;
2553 parseRule(element);
2554 ADD_FAILURE() << "Should not have reached this line.";
2555 }
2556 catch (const std::invalid_argument& e)
2557 {
2558 EXPECT_STREQ(e.what(), "Element contains an invalid property");
2559 }
2560}
2561
2562TEST(ConfigFileParserTests, ParseRuleArray)
2563{
2564 // Test where works
2565 {
2566 const json element = R"(
2567 [
2568 {
2569 "id": "set_voltage_rule1",
2570 "actions": [
2571 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } }
2572 ]
2573 },
2574 {
2575 "id": "set_voltage_rule2",
2576 "actions": [
2577 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } },
2578 { "pmbus_write_vout_command": { "volts": 1.11, "format": "linear" } }
2579 ]
2580 }
2581 ]
2582 )"_json;
2583 std::vector<std::unique_ptr<Rule>> rules = parseRuleArray(element);
2584 EXPECT_EQ(rules.size(), 2);
2585 EXPECT_EQ(rules[0]->getID(), "set_voltage_rule1");
2586 EXPECT_EQ(rules[0]->getActions().size(), 1);
2587 EXPECT_EQ(rules[1]->getID(), "set_voltage_rule2");
2588 EXPECT_EQ(rules[1]->getActions().size(), 2);
2589 }
2590
2591 // Test where fails: Element is not an array
2592 try
2593 {
2594 const json element = R"( { "id": "set_voltage_rule" } )"_json;
2595 parseRuleArray(element);
2596 ADD_FAILURE() << "Should not have reached this line.";
2597 }
2598 catch (const std::invalid_argument& e)
2599 {
2600 EXPECT_STREQ(e.what(), "Element is not an array");
2601 }
2602}
2603
Bob King33e7eaa2020-04-01 18:09:34 +08002604TEST(ConfigFileParserTests, ParseRuleIDOrActionsProperty)
2605{
2606 // Test where works: actions specified
2607 {
2608 const json element = R"(
2609 {
2610 "actions": [
2611 { "pmbus_write_vout_command": { "format": "linear" } },
2612 { "run_rule": "set_voltage_rule" }
2613 ]
2614 }
2615 )"_json;
2616 std::vector<std::unique_ptr<Action>> actions =
2617 parseRuleIDOrActionsProperty(element);
2618 EXPECT_EQ(actions.size(), 2);
2619 }
2620
2621 // Test where works: rule_id specified
2622 {
2623 const json element = R"(
2624 {
2625 "rule_id": "set_voltage_rule"
2626 }
2627 )"_json;
2628 std::vector<std::unique_ptr<Action>> actions =
2629 parseRuleIDOrActionsProperty(element);
2630 EXPECT_EQ(actions.size(), 1);
2631 }
2632
2633 // Test where fails: Element is not an object
2634 try
2635 {
2636 const json element = R"( [ "foo", "bar" ] )"_json;
2637 parseRuleIDOrActionsProperty(element);
2638 ADD_FAILURE() << "Should not have reached this line.";
2639 }
2640 catch (const std::invalid_argument& e)
2641 {
2642 EXPECT_STREQ(e.what(), "Element is not an object");
2643 }
2644
2645 // Test where fails: rule_id is invalid
2646 try
2647 {
2648 const json element = R"(
2649 { "rule_id": 1 }
2650 )"_json;
2651 parseRuleIDOrActionsProperty(element);
2652 ADD_FAILURE() << "Should not have reached this line.";
2653 }
2654 catch (const std::invalid_argument& e)
2655 {
2656 EXPECT_STREQ(e.what(), "Element is not a string");
2657 }
2658
2659 // Test where fails: actions is invalid
2660 try
2661 {
2662 const json element = R"(
2663 { "actions": 1 }
2664 )"_json;
2665 parseRuleIDOrActionsProperty(element);
2666 ADD_FAILURE() << "Should not have reached this line.";
2667 }
2668 catch (const std::invalid_argument& e)
2669 {
2670 EXPECT_STREQ(e.what(), "Element is not an array");
2671 }
2672
2673 // Test where fails: Neither rule_id nor actions specified
2674 try
2675 {
2676 const json element = R"(
2677 {
2678 "volts": 1.03
2679 }
2680 )"_json;
2681 parseRuleIDOrActionsProperty(element);
2682 ADD_FAILURE() << "Should not have reached this line.";
2683 }
2684 catch (const std::invalid_argument& e)
2685 {
2686 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain "
2687 "either rule_id or actions");
2688 }
2689
2690 // Test where fails: Both rule_id and actions specified
2691 try
2692 {
2693 const json element = R"(
2694 {
2695 "volts": 1.03,
2696 "rule_id": "set_voltage_rule",
2697 "actions": [
2698 {
2699 "pmbus_write_vout_command": {
2700 "format": "linear"
2701 }
2702 }
2703 ]
2704 }
2705 )"_json;
2706 parseRuleIDOrActionsProperty(element);
2707 ADD_FAILURE() << "Should not have reached this line.";
2708 }
2709 catch (const std::invalid_argument& e)
2710 {
2711 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain "
2712 "either rule_id or actions");
2713 }
2714}
2715
Bob King315b0b62020-04-03 21:47:58 +08002716TEST(ConfigFileParserTests, ParseRunRule)
2717{
2718 // Test where works
2719 {
2720 const json element = "vdd_regulator";
2721 std::unique_ptr<RunRuleAction> action = parseRunRule(element);
2722 EXPECT_EQ(action->getRuleID(), "vdd_regulator");
2723 }
2724
2725 // Test where fails: Element is not a string
2726 try
2727 {
2728 const json element = 1;
2729 parseRunRule(element);
2730 ADD_FAILURE() << "Should not have reached this line.";
2731 }
2732 catch (const std::invalid_argument& e)
2733 {
2734 EXPECT_STREQ(e.what(), "Element is not a string");
2735 }
2736
2737 // Test where fails: Empty string
2738 try
2739 {
2740 const json element = "";
2741 parseRunRule(element);
2742 ADD_FAILURE() << "Should not have reached this line.";
2743 }
2744 catch (const std::invalid_argument& e)
2745 {
2746 EXPECT_STREQ(e.what(), "Element contains an empty string");
2747 }
2748}
2749
Bob Kinga2f2a0d2020-04-09 13:32:14 +08002750TEST(ConfigFileParserTests, ParseSensorMonitoring)
2751{
2752 // Test where works: actions property specified
2753 {
2754 const json element = R"(
2755 {
2756 "actions": [
2757 { "run_rule": "read_sensors_rule" }
2758 ]
2759 }
2760 )"_json;
2761 std::unique_ptr<SensorMonitoring> sensorMonitoring =
2762 parseSensorMonitoring(element);
2763 EXPECT_EQ(sensorMonitoring->getActions().size(), 1);
2764 }
2765
2766 // Test where works: rule_id property specified
2767 {
2768 const json element = R"(
2769 {
2770 "comments": [ "comments property" ],
2771 "rule_id": "set_voltage_rule"
2772 }
2773 )"_json;
2774 std::unique_ptr<SensorMonitoring> sensorMonitoring =
2775 parseSensorMonitoring(element);
2776 EXPECT_EQ(sensorMonitoring->getActions().size(), 1);
2777 }
2778
2779 // Test where fails: actions object is invalid
2780 try
2781 {
2782 const json element = R"(
2783 {
2784 "actions": 1
2785 }
2786 )"_json;
2787 parseSensorMonitoring(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 an array");
2793 }
2794
2795 // Test where fails: rule_id value is invalid
2796 try
2797 {
2798 const json element = R"(
2799 {
2800 "rule_id": 1
2801 }
2802 )"_json;
2803 parseSensorMonitoring(element);
2804 ADD_FAILURE() << "Should not have reached this line.";
2805 }
2806 catch (const std::invalid_argument& e)
2807 {
2808 EXPECT_STREQ(e.what(), "Element is not a string");
2809 }
2810
2811 // Test where fails: Required actions or rule_id property not specified
2812 try
2813 {
2814 const json element = R"(
2815 {
2816 "comments": [ "comments property" ]
2817 }
2818 )"_json;
2819 parseSensorMonitoring(element);
2820 ADD_FAILURE() << "Should not have reached this line.";
2821 }
2822 catch (const std::invalid_argument& e)
2823 {
2824 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain "
2825 "either rule_id or actions");
2826 }
2827
2828 // Test where fails: Required actions or rule_id property both specified
2829 try
2830 {
2831 const json element = R"(
2832 {
2833 "rule_id": "set_voltage_rule",
2834 "actions": [
2835 { "run_rule": "read_sensors_rule" }
2836 ]
2837 }
2838 )"_json;
2839 parseSensorMonitoring(element);
2840 ADD_FAILURE() << "Should not have reached this line.";
2841 }
2842 catch (const std::invalid_argument& e)
2843 {
2844 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain "
2845 "either rule_id or actions");
2846 }
2847
2848 // Test where fails: Element is not an object
2849 try
2850 {
2851 const json element = R"( [ "foo", "bar" ] )"_json;
2852 parseSensorMonitoring(element);
2853 ADD_FAILURE() << "Should not have reached this line.";
2854 }
2855 catch (const std::invalid_argument& e)
2856 {
2857 EXPECT_STREQ(e.what(), "Element is not an object");
2858 }
2859
2860 // Test where fails: Invalid property specified
2861 try
2862 {
2863 const json element = R"(
2864 {
2865 "foo": "bar",
2866 "actions": [
2867 { "run_rule": "read_sensors_rule" }
2868 ]
2869 }
2870 )"_json;
2871 parseSensorMonitoring(element);
2872 ADD_FAILURE() << "Should not have reached this line.";
2873 }
2874 catch (const std::invalid_argument& e)
2875 {
2876 EXPECT_STREQ(e.what(), "Element contains an invalid property");
2877 }
2878}
2879
Shawn McCarney0e8c68a2020-03-27 01:44:48 -05002880TEST(ConfigFileParserTests, ParseString)
2881{
2882 // Test where works: Empty string
2883 {
2884 const json element = "";
2885 std::string value = parseString(element, true);
2886 EXPECT_EQ(value, "");
2887 }
2888
2889 // Test where works: Non-empty string
2890 {
2891 const json element = "vdd_regulator";
2892 std::string value = parseString(element, false);
2893 EXPECT_EQ(value, "vdd_regulator");
2894 }
2895
2896 // Test where fails: Element is not a string
2897 try
2898 {
2899 const json element = R"( { "foo": "bar" } )"_json;
2900 parseString(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 a string");
2906 }
2907
2908 // Test where fails: Empty string
2909 try
2910 {
2911 const json element = "";
2912 parseString(element);
2913 ADD_FAILURE() << "Should not have reached this line.";
2914 }
2915 catch (const std::invalid_argument& e)
2916 {
2917 EXPECT_STREQ(e.what(), "Element contains an empty string");
2918 }
2919}
2920
Bob Kingf617f892020-03-30 19:03:35 +08002921TEST(ConfigFileParserTests, ParseUint8)
2922{
2923 // Test where works: 0
2924 {
2925 const json element = R"( 0 )"_json;
2926 uint8_t value = parseUint8(element);
2927 EXPECT_EQ(value, 0);
2928 }
2929
2930 // Test where works: UINT8_MAX
2931 {
2932 const json element = R"( 255 )"_json;
2933 uint8_t value = parseUint8(element);
2934 EXPECT_EQ(value, 255);
2935 }
2936
2937 // Test where fails: Element is not an integer
2938 try
2939 {
2940 const json element = R"( 1.03 )"_json;
2941 parseUint8(element);
2942 ADD_FAILURE() << "Should not have reached this line.";
2943 }
2944 catch (const std::invalid_argument& e)
2945 {
2946 EXPECT_STREQ(e.what(), "Element is not an integer");
2947 }
2948
2949 // Test where fails: Value < 0
2950 try
2951 {
2952 const json element = R"( -1 )"_json;
2953 parseUint8(element);
2954 ADD_FAILURE() << "Should not have reached this line.";
2955 }
2956 catch (const std::invalid_argument& e)
2957 {
2958 EXPECT_STREQ(e.what(), "Element is not an 8-bit unsigned integer");
2959 }
2960
2961 // Test where fails: Value > UINT8_MAX
2962 try
2963 {
2964 const json element = R"( 256 )"_json;
2965 parseUint8(element);
2966 ADD_FAILURE() << "Should not have reached this line.";
2967 }
2968 catch (const std::invalid_argument& e)
2969 {
2970 EXPECT_STREQ(e.what(), "Element is not an 8-bit unsigned integer");
2971 }
2972}
2973
Bob King0e701132020-04-03 21:50:31 +08002974TEST(ConfigFileParserTests, ParseUnsignedInteger)
2975{
2976 // Test where works: 1
2977 {
2978 const json element = R"( 1 )"_json;
2979 unsigned int value = parseUnsignedInteger(element);
2980 EXPECT_EQ(value, 1);
2981 }
2982
2983 // Test where fails: Element is not an integer
2984 try
2985 {
2986 const json element = R"( 1.5 )"_json;
2987 parseUnsignedInteger(element);
2988 ADD_FAILURE() << "Should not have reached this line.";
2989 }
2990 catch (const std::invalid_argument& e)
2991 {
2992 EXPECT_STREQ(e.what(), "Element is not an unsigned integer");
2993 }
2994
2995 // Test where fails: Value < 0
2996 try
2997 {
2998 const json element = R"( -1 )"_json;
2999 parseUnsignedInteger(element);
3000 ADD_FAILURE() << "Should not have reached this line.";
3001 }
3002 catch (const std::invalid_argument& e)
3003 {
3004 EXPECT_STREQ(e.what(), "Element is not an unsigned integer");
3005 }
3006}
3007
Shawn McCarney0e8c68a2020-03-27 01:44:48 -05003008TEST(ConfigFileParserTests, VerifyIsArray)
3009{
3010 // Test where element is an array
3011 try
3012 {
3013 const json element = R"( [ "foo", "bar" ] )"_json;
3014 verifyIsArray(element);
3015 }
3016 catch (const std::exception& e)
3017 {
3018 ADD_FAILURE() << "Should not have caught exception.";
3019 }
3020
3021 // Test where element is not an array
3022 try
3023 {
3024 const json element = R"( { "foo": "bar" } )"_json;
3025 verifyIsArray(element);
3026 ADD_FAILURE() << "Should not have reached this line.";
3027 }
3028 catch (const std::invalid_argument& e)
3029 {
3030 EXPECT_STREQ(e.what(), "Element is not an array");
3031 }
3032}
3033
3034TEST(ConfigFileParserTests, VerifyIsObject)
3035{
3036 // Test where element is an object
3037 try
3038 {
3039 const json element = R"( { "foo": "bar" } )"_json;
3040 verifyIsObject(element);
3041 }
3042 catch (const std::exception& e)
3043 {
3044 ADD_FAILURE() << "Should not have caught exception.";
3045 }
3046
3047 // Test where element is not an object
3048 try
3049 {
3050 const json element = R"( [ "foo", "bar" ] )"_json;
3051 verifyIsObject(element);
3052 ADD_FAILURE() << "Should not have reached this line.";
3053 }
3054 catch (const std::invalid_argument& e)
3055 {
3056 EXPECT_STREQ(e.what(), "Element is not an object");
3057 }
3058}
3059
3060TEST(ConfigFileParserTests, VerifyPropertyCount)
3061{
3062 // Test where element has expected number of properties
3063 try
3064 {
3065 const json element = R"(
3066 {
3067 "comments": [ "Set voltage rule" ],
3068 "id": "set_voltage_rule"
3069 }
3070 )"_json;
3071 verifyPropertyCount(element, 2);
3072 }
3073 catch (const std::exception& e)
3074 {
3075 ADD_FAILURE() << "Should not have caught exception.";
3076 }
3077
3078 // Test where element has unexpected number of properties
3079 try
3080 {
3081 const json element = R"(
3082 {
3083 "comments": [ "Set voltage rule" ],
3084 "id": "set_voltage_rule",
3085 "foo": 1.3
3086 }
3087 )"_json;
3088 verifyPropertyCount(element, 2);
3089 ADD_FAILURE() << "Should not have reached this line.";
3090 }
3091 catch (const std::invalid_argument& e)
3092 {
3093 EXPECT_STREQ(e.what(), "Element contains an invalid property");
3094 }
3095}