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