blob: 92706a3a4eed299e643b2bbf417c230ea1b6d77a [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 King0e701132020-04-03 21:50:31 +080020#include "device.hpp"
Bob Kingf617f892020-03-30 19:03:35 +080021#include "i2c_interface.hpp"
22#include "i2c_write_bit_action.hpp"
Bob King87ff9d72020-03-31 14:02:55 +080023#include "i2c_write_byte_action.hpp"
Bob Kingbafcb862020-03-31 16:39:00 +080024#include "i2c_write_bytes_action.hpp"
Shawn McCarney0e8c68a2020-03-27 01:44:48 -050025#include "pmbus_utils.hpp"
26#include "pmbus_write_vout_command_action.hpp"
27#include "rule.hpp"
Bob King315b0b62020-04-03 21:47:58 +080028#include "run_rule_action.hpp"
Shawn McCarney80c0b042020-03-27 12:08:53 -050029#include "tmp_file.hpp"
Shawn McCarney0e8c68a2020-03-27 01:44:48 -050030
Shawn McCarney80c0b042020-03-27 12:08:53 -050031#include <sys/stat.h> // for chmod()
Shawn McCarney0e8c68a2020-03-27 01:44:48 -050032
33#include <nlohmann/json.hpp>
34
35#include <cstdint>
36#include <cstring>
37#include <exception>
38#include <filesystem>
39#include <fstream>
40#include <memory>
41#include <optional>
42#include <stdexcept>
43#include <string>
44#include <tuple>
45#include <vector>
46
47#include <gtest/gtest.h>
48
49using namespace phosphor::power::regulators;
50using namespace phosphor::power::regulators::config_file_parser;
51using namespace phosphor::power::regulators::config_file_parser::internal;
52using json = nlohmann::json;
53
Shawn McCarney0e8c68a2020-03-27 01:44:48 -050054void writeConfigFile(const std::filesystem::path& pathName,
55 const std::string& contents)
56{
57 std::ofstream file{pathName};
58 file << contents;
59}
60
61void writeConfigFile(const std::filesystem::path& pathName,
62 const json& contents)
63{
64 std::ofstream file{pathName};
65 file << contents;
66}
67
68TEST(ConfigFileParserTests, Parse)
69{
70 // Test where works
71 {
72 const json configFileContents = R"(
73 {
74 "rules": [
75 {
76 "id": "set_voltage_rule1",
77 "actions": [
78 { "pmbus_write_vout_command": { "volts": 1.03, "format": "linear" } }
79 ]
80 },
81 {
82 "id": "set_voltage_rule2",
83 "actions": [
84 { "pmbus_write_vout_command": { "volts": 1.33, "format": "linear" } }
85 ]
86 }
87 ],
88 "chassis": [
89 { "number": 1 },
90 { "number": 2 },
91 { "number": 3 }
92 ]
93 }
94 )"_json;
95
96 TmpFile configFile;
97 std::filesystem::path pathName{configFile.getName()};
98 writeConfigFile(pathName, configFileContents);
99
100 std::vector<std::unique_ptr<Rule>> rules{};
101 std::vector<std::unique_ptr<Chassis>> chassis{};
102 std::tie(rules, chassis) = parse(pathName);
103
104 EXPECT_EQ(rules.size(), 2);
105 EXPECT_EQ(rules[0]->getID(), "set_voltage_rule1");
106 EXPECT_EQ(rules[1]->getID(), "set_voltage_rule2");
107
Bob King0e701132020-04-03 21:50:31 +0800108 EXPECT_EQ(chassis.size(), 3);
109 EXPECT_EQ(chassis[0]->getNumber(), 1);
110 EXPECT_EQ(chassis[1]->getNumber(), 2);
111 EXPECT_EQ(chassis[2]->getNumber(), 3);
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500112 }
113
114 // Test where fails: File does not exist
115 try
116 {
117 std::filesystem::path pathName{"/tmp/non_existent_file"};
118 parse(pathName);
119 ADD_FAILURE() << "Should not have reached this line.";
120 }
121 catch (const ConfigFileParserError& e)
122 {
123 // Expected exception; what() message will vary
124 }
125
126 // Test where fails: File is not readable
127 try
128 {
129 const json configFileContents = R"(
130 {
131 "chassis": [ { "number": 1 } ]
132 }
133 )"_json;
134
135 TmpFile configFile;
136 std::filesystem::path pathName{configFile.getName()};
137 writeConfigFile(pathName, configFileContents);
138
139 chmod(pathName.c_str(), 0222);
140
141 parse(pathName);
142 ADD_FAILURE() << "Should not have reached this line.";
143 }
144 catch (const ConfigFileParserError& e)
145 {
146 // Expected exception; what() message will vary
147 }
148
149 // Test where fails: File is not valid JSON
150 try
151 {
152 const std::string configFileContents = "] foo [";
153
154 TmpFile configFile;
155 std::filesystem::path pathName{configFile.getName()};
156 writeConfigFile(pathName, configFileContents);
157
158 parse(pathName);
159 ADD_FAILURE() << "Should not have reached this line.";
160 }
161 catch (const ConfigFileParserError& e)
162 {
163 // Expected exception; what() message will vary
164 }
165
166 // Test where fails: Error when parsing JSON elements
167 try
168 {
169 const json configFileContents = R"( { "foo": "bar" } )"_json;
170
171 TmpFile configFile;
172 std::filesystem::path pathName{configFile.getName()};
173 writeConfigFile(pathName, configFileContents);
174
175 parse(pathName);
176 ADD_FAILURE() << "Should not have reached this line.";
177 }
178 catch (const ConfigFileParserError& e)
179 {
180 // Expected exception; what() message will vary
181 }
182}
183
184TEST(ConfigFileParserTests, GetRequiredProperty)
185{
186 // Test where property exists
187 {
188 const json element = R"( { "format": "linear" } )"_json;
189 const json& propertyElement = getRequiredProperty(element, "format");
190 EXPECT_EQ(propertyElement.get<std::string>(), "linear");
191 }
192
193 // Test where property does not exist
194 try
195 {
196 const json element = R"( { "volts": 1.03 } )"_json;
197 getRequiredProperty(element, "format");
198 ADD_FAILURE() << "Should not have reached this line.";
199 }
200 catch (const std::invalid_argument& e)
201 {
202 EXPECT_STREQ(e.what(), "Required property missing: format");
203 }
204}
205
206TEST(ConfigFileParserTests, ParseAction)
207{
208 // Test where works: comments property specified
209 {
210 const json element = R"(
211 {
212 "comments": [ "Set output voltage." ],
213 "pmbus_write_vout_command": {
214 "format": "linear"
215 }
216 }
217 )"_json;
218 std::unique_ptr<Action> action = parseAction(element);
219 EXPECT_NE(action.get(), nullptr);
220 }
221
222 // Test where works: comments property not specified
223 {
224 const json element = R"(
225 {
226 "pmbus_write_vout_command": {
227 "format": "linear"
228 }
229 }
230 )"_json;
231 std::unique_ptr<Action> action = parseAction(element);
232 EXPECT_NE(action.get(), nullptr);
233 }
234
235 // Test where works: and action type specified
236 // TODO: Not implemented yet
237
238 // Test where works: compare_presence action type specified
239 // TODO: Not implemented yet
240
241 // Test where works: compare_vpd action type specified
242 // TODO: Not implemented yet
243
244 // Test where works: i2c_compare_bit action type specified
245 // TODO: Not implemented yet
246
247 // Test where works: i2c_compare_byte action type specified
248 // TODO: Not implemented yet
249
250 // Test where works: i2c_compare_bytes action type specified
251 // TODO: Not implemented yet
252
253 // Test where works: i2c_write_bit action type specified
Bob Kingf617f892020-03-30 19:03:35 +0800254 {
255 const json element = R"(
256 {
257 "i2c_write_bit": {
258 "register": "0xA0",
259 "position": 3,
260 "value": 0
261 }
262 }
263 )"_json;
264 std::unique_ptr<Action> action = parseAction(element);
265 EXPECT_NE(action.get(), nullptr);
266 }
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500267
268 // Test where works: i2c_write_byte action type specified
Bob King87ff9d72020-03-31 14:02:55 +0800269 {
270 const json element = R"(
271 {
272 "i2c_write_byte": {
273 "register": "0x0A",
274 "value": "0xCC"
275 }
276 }
277 )"_json;
278 std::unique_ptr<Action> action = parseAction(element);
279 EXPECT_NE(action.get(), nullptr);
280 }
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500281
282 // Test where works: i2c_write_bytes action type specified
Bob Kingbafcb862020-03-31 16:39:00 +0800283 {
284 const json element = R"(
285 {
286 "i2c_write_bytes": {
287 "register": "0x0A",
288 "values": [ "0xCC", "0xFF" ]
289 }
290 }
291 )"_json;
292 std::unique_ptr<Action> action = parseAction(element);
293 EXPECT_NE(action.get(), nullptr);
294 }
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500295
296 // Test where works: if action type specified
297 // TODO: Not implemented yet
298
299 // Test where works: not action type specified
300 // TODO: Not implemented yet
301
302 // Test where works: or action type specified
303 // TODO: Not implemented yet
304
305 // Test where works: pmbus_read_sensor action type specified
306 // TODO: Not implemented yet
307
308 // Test where works: pmbus_write_vout_command action type specified
309 {
310 const json element = R"(
311 {
312 "pmbus_write_vout_command": {
313 "format": "linear"
314 }
315 }
316 )"_json;
317 std::unique_ptr<Action> action = parseAction(element);
318 EXPECT_NE(action.get(), nullptr);
319 }
320
321 // Test where works: run_rule action type specified
Bob King315b0b62020-04-03 21:47:58 +0800322 {
323 const json element = R"(
324 {
325 "run_rule": "set_voltage_rule"
326 }
327 )"_json;
328 std::unique_ptr<Action> action = parseAction(element);
329 EXPECT_NE(action.get(), nullptr);
330 }
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500331
332 // Test where works: set_device action type specified
333 // TODO: Not implemented yet
334
335 // Test where fails: Element is not an object
336 try
337 {
338 const json element = R"( [ "0xFF", "0x01" ] )"_json;
339 parseAction(element);
340 ADD_FAILURE() << "Should not have reached this line.";
341 }
342 catch (const std::invalid_argument& e)
343 {
344 EXPECT_STREQ(e.what(), "Element is not an object");
345 }
346
347 // Test where fails: No action type specified
348 try
349 {
350 const json element = R"(
351 {
352 "comments": [ "Set output voltage." ]
353 }
354 )"_json;
355 parseAction(element);
356 ADD_FAILURE() << "Should not have reached this line.";
357 }
358 catch (const std::invalid_argument& e)
359 {
360 EXPECT_STREQ(e.what(), "Required action type property missing");
361 }
362
363 // Test where fails: Multiple action types specified
Bob King0e701132020-04-03 21:50:31 +0800364 try
365 {
366 const json element = R"(
367 {
368 "pmbus_write_vout_command": { "format": "linear" },
369 "run_rule": "set_voltage_rule"
370 }
371 )"_json;
372 parseAction(element);
373 ADD_FAILURE() << "Should not have reached this line.";
374 }
375 catch (const std::invalid_argument& e)
376 {
377 EXPECT_STREQ(e.what(), "Element contains an invalid property");
378 }
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500379
380 // Test where fails: Invalid property specified
381 try
382 {
383 const json element = R"(
384 {
385 "remarks": [ "Set output voltage." ],
386 "pmbus_write_vout_command": {
387 "format": "linear"
388 }
389 }
390 )"_json;
391 parseAction(element);
392 ADD_FAILURE() << "Should not have reached this line.";
393 }
394 catch (const std::invalid_argument& e)
395 {
396 EXPECT_STREQ(e.what(), "Element contains an invalid property");
397 }
398}
399
400TEST(ConfigFileParserTests, ParseActionArray)
401{
402 // Test where works
403 {
404 const json element = R"(
405 [
406 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } },
407 { "pmbus_write_vout_command": { "volts": 1.03, "format": "linear" } }
408 ]
409 )"_json;
410 std::vector<std::unique_ptr<Action>> actions =
411 parseActionArray(element);
412 EXPECT_EQ(actions.size(), 2);
413 }
414
415 // Test where fails: Element is not an array
416 try
417 {
418 const json element = R"(
419 {
420 "foo": "bar"
421 }
422 )"_json;
423 parseActionArray(element);
424 ADD_FAILURE() << "Should not have reached this line.";
425 }
426 catch (const std::invalid_argument& e)
427 {
428 EXPECT_STREQ(e.what(), "Element is not an array");
429 }
430}
431
Bob Kingf617f892020-03-30 19:03:35 +0800432TEST(ConfigFileParserTests, ParseBitPosition)
433{
434 // Test where works: 0
435 {
436 const json element = R"( 0 )"_json;
437 uint8_t value = parseBitPosition(element);
438 EXPECT_EQ(value, 0);
439 }
440
441 // Test where works: 7
442 {
443 const json element = R"( 7 )"_json;
444 uint8_t value = parseBitPosition(element);
445 EXPECT_EQ(value, 7);
446 }
447
448 // Test where fails: Element is not an integer
449 try
450 {
451 const json element = R"( 1.03 )"_json;
452 parseBitPosition(element);
453 ADD_FAILURE() << "Should not have reached this line.";
454 }
455 catch (const std::invalid_argument& e)
456 {
457 EXPECT_STREQ(e.what(), "Element is not an integer");
458 }
459
460 // Test where fails: Value < 0
461 try
462 {
463 const json element = R"( -1 )"_json;
464 parseBitPosition(element);
465 ADD_FAILURE() << "Should not have reached this line.";
466 }
467 catch (const std::invalid_argument& e)
468 {
469 EXPECT_STREQ(e.what(), "Element is not a bit position");
470 }
471
472 // Test where fails: Value > 7
473 try
474 {
475 const json element = R"( 8 )"_json;
476 parseBitPosition(element);
477 ADD_FAILURE() << "Should not have reached this line.";
478 }
479 catch (const std::invalid_argument& e)
480 {
481 EXPECT_STREQ(e.what(), "Element is not a bit position");
482 }
483}
484
485TEST(ConfigFileParserTests, ParseBitValue)
486{
487 // Test where works: 0
488 {
489 const json element = R"( 0 )"_json;
490 uint8_t value = parseBitValue(element);
491 EXPECT_EQ(value, 0);
492 }
493
494 // Test where works: 1
495 {
496 const json element = R"( 1 )"_json;
497 uint8_t value = parseBitValue(element);
498 EXPECT_EQ(value, 1);
499 }
500
501 // Test where fails: Element is not an integer
502 try
503 {
504 const json element = R"( 0.5 )"_json;
505 parseBitValue(element);
506 ADD_FAILURE() << "Should not have reached this line.";
507 }
508 catch (const std::invalid_argument& e)
509 {
510 EXPECT_STREQ(e.what(), "Element is not an integer");
511 }
512
513 // Test where fails: Value < 0
514 try
515 {
516 const json element = R"( -1 )"_json;
517 parseBitValue(element);
518 ADD_FAILURE() << "Should not have reached this line.";
519 }
520 catch (const std::invalid_argument& e)
521 {
522 EXPECT_STREQ(e.what(), "Element is not a bit value");
523 }
524
525 // Test where fails: Value > 1
526 try
527 {
528 const json element = R"( 2 )"_json;
529 parseBitValue(element);
530 ADD_FAILURE() << "Should not have reached this line.";
531 }
532 catch (const std::invalid_argument& e)
533 {
534 EXPECT_STREQ(e.what(), "Element is not a bit value");
535 }
536}
537
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500538TEST(ConfigFileParserTests, ParseBoolean)
539{
540 // Test where works: true
541 {
542 const json element = R"( true )"_json;
543 bool value = parseBoolean(element);
544 EXPECT_EQ(value, true);
545 }
546
547 // Test where works: false
548 {
549 const json element = R"( false )"_json;
550 bool value = parseBoolean(element);
551 EXPECT_EQ(value, false);
552 }
553
554 // Test where fails: Element is not a boolean
555 try
556 {
557 const json element = R"( 1 )"_json;
558 parseBoolean(element);
559 ADD_FAILURE() << "Should not have reached this line.";
560 }
561 catch (const std::invalid_argument& e)
562 {
563 EXPECT_STREQ(e.what(), "Element is not a boolean");
564 }
565}
566
Bob King0e701132020-04-03 21:50:31 +0800567TEST(ConfigFileParserTests, ParseChassis)
568{
569 // Test where works: Only required properties specified
570 {
571 const json element = R"(
572 {
573 "number": 1
574 }
575 )"_json;
576 std::unique_ptr<Chassis> chassis = parseChassis(element);
577 EXPECT_EQ(chassis->getNumber(), 1);
578 // TODO: Not implemented yet
579 // EXPECT_EQ(chassis->getDevices().size(), 0);
580 }
581
582 // Test where works: All properties specified
583 {
584 const json element = R"(
585 {
586 "comments": [ "comments property" ],
587 "number": 2,
588 "devices": [
589 {
590 "id": "vdd_regulator",
591 "is_regulator": true,
592 "fru": "/system/chassis/motherboard/regulator2",
593 "i2c_interface":
594 {
595 "bus": 1,
596 "address": "0x70"
597 }
598 }
599 ]
600 }
601 )"_json;
602 std::unique_ptr<Chassis> chassis = parseChassis(element);
603 EXPECT_EQ(chassis->getNumber(), 2);
604 // TODO: Not implemented yet
605 // EXPECT_EQ(chassis->getDevices().size(), 1);
606 // EXPECT_EQ(chassis->getDevices()[0]->getID(), "vdd_regulator")
607 }
608
609 // Test where fails: number value is invalid
610 try
611 {
612 const json element = R"(
613 {
614 "number": 0.5
615 }
616 )"_json;
617 parseChassis(element);
618 ADD_FAILURE() << "Should not have reached this line.";
619 }
620 catch (const std::invalid_argument& e)
621 {
622 EXPECT_STREQ(e.what(), "Element is not an unsigned integer");
623 }
624
625 // Test where fails: Invalid property specified
626 try
627 {
628 const json element = R"(
629 {
630 "number": 1,
631 "foo": 2
632 }
633 )"_json;
634 parseChassis(element);
635 ADD_FAILURE() << "Should not have reached this line.";
636 }
637 catch (const std::invalid_argument& e)
638 {
639 EXPECT_STREQ(e.what(), "Element contains an invalid property");
640 }
641
642 // Test where fails: Required number property not specified
643 try
644 {
645 const json element = R"(
646 {
647 "devices": [
648 {
649 "id": "vdd_regulator",
650 "is_regulator": true,
651 "fru": "/system/chassis/motherboard/regulator2",
652 "i2c_interface":
653 {
654 "bus": 1,
655 "address": "0x70"
656 }
657 }
658 ]
659 }
660 )"_json;
661 parseChassis(element);
662 ADD_FAILURE() << "Should not have reached this line.";
663 }
664 catch (const std::invalid_argument& e)
665 {
666 EXPECT_STREQ(e.what(), "Required property missing: number");
667 }
668
669 // Test where fails: Element is not an object
670 try
671 {
672 const json element = R"( [ "0xFF", "0x01" ] )"_json;
673 parseChassis(element);
674 ADD_FAILURE() << "Should not have reached this line.";
675 }
676 catch (const std::invalid_argument& e)
677 {
678 EXPECT_STREQ(e.what(), "Element is not an object");
679 }
680
681 // Test where fails: number value is < 1
682 try
683 {
684 const json element = R"(
685 {
686 "number": 0
687 }
688 )"_json;
689 parseChassis(element);
690 ADD_FAILURE() << "Should not have reached this line.";
691 }
692 catch (const std::invalid_argument& e)
693 {
694 EXPECT_STREQ(e.what(), "Invalid chassis number: Must be > 0");
695 }
696
697 // Test where fails: devices value is invalid
698 try
699 {
700 const json element = R"(
701 {
702 "number": 1,
703 "devices": 2
704 }
705 )"_json;
706 parseChassis(element);
707 ADD_FAILURE() << "Should not have reached this line.";
708 }
709 catch (const std::invalid_argument& e)
710 {
711 EXPECT_STREQ(e.what(), "Element is not an array");
712 }
713}
714
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500715TEST(ConfigFileParserTests, ParseChassisArray)
716{
Bob King0e701132020-04-03 21:50:31 +0800717 // Test where works
718 {
719 const json element = R"(
720 [
721 { "number": 1 },
722 { "number": 2 }
723 ]
724 )"_json;
725 std::vector<std::unique_ptr<Chassis>> chassis =
726 parseChassisArray(element);
727 EXPECT_EQ(chassis.size(), 2);
728 EXPECT_EQ(chassis[0]->getNumber(), 1);
729 EXPECT_EQ(chassis[1]->getNumber(), 2);
730 }
731
732 // Test where fails: Element is not an array
733 try
734 {
735 const json element = R"(
736 {
737 "foo": "bar"
738 }
739 )"_json;
740 parseChassisArray(element);
741 ADD_FAILURE() << "Should not have reached this line.";
742 }
743 catch (const std::invalid_argument& e)
744 {
745 EXPECT_STREQ(e.what(), "Element is not an array");
746 }
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500747}
748
749TEST(ConfigFileParserTests, ParseDouble)
750{
751 // Test where works: floating point value
752 {
753 const json element = R"( 1.03 )"_json;
754 double value = parseDouble(element);
755 EXPECT_EQ(value, 1.03);
756 }
757
758 // Test where works: integer value
759 {
760 const json element = R"( 24 )"_json;
761 double value = parseDouble(element);
762 EXPECT_EQ(value, 24.0);
763 }
764
765 // Test where fails: Element is not a number
766 try
767 {
768 const json element = R"( true )"_json;
769 parseDouble(element);
770 ADD_FAILURE() << "Should not have reached this line.";
771 }
772 catch (const std::invalid_argument& e)
773 {
774 EXPECT_STREQ(e.what(), "Element is not a number");
775 }
776}
777
Bob Kingbafcb862020-03-31 16:39:00 +0800778TEST(ConfigFileParserTests, ParseHexByte)
779{
780 // Test where works: "0xFF"
781 {
782 const json element = R"( "0xFF" )"_json;
783 uint8_t value = parseHexByte(element);
784 EXPECT_EQ(value, 0xFF);
785 }
786
787 // Test where works: "0xff"
788 {
789 const json element = R"( "0xff" )"_json;
790 uint8_t value = parseHexByte(element);
791 EXPECT_EQ(value, 0xff);
792 }
793
794 // Test where works: "0xf"
795 {
796 const json element = R"( "0xf" )"_json;
797 uint8_t value = parseHexByte(element);
798 EXPECT_EQ(value, 0xf);
799 }
800
801 // Test where fails: "0xfff"
802 try
803 {
804 const json element = R"( "0xfff" )"_json;
805 parseHexByte(element);
806 ADD_FAILURE() << "Should not have reached this line.";
807 }
808 catch (const std::invalid_argument& e)
809 {
810 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
811 }
812
813 // Test where fails: "0xAG"
814 try
815 {
816 const json element = R"( "0xAG" )"_json;
817 parseHexByte(element);
818 ADD_FAILURE() << "Should not have reached this line.";
819 }
820 catch (const std::invalid_argument& e)
821 {
822 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
823 }
824
825 // Test where fails: "ff"
826 try
827 {
828 const json element = R"( "ff" )"_json;
829 parseHexByte(element);
830 ADD_FAILURE() << "Should not have reached this line.";
831 }
832 catch (const std::invalid_argument& e)
833 {
834 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
835 }
836
837 // Test where fails: ""
838 try
839 {
840 const json element = "";
841 parseHexByte(element);
842 ADD_FAILURE() << "Should not have reached this line.";
843 }
844 catch (const std::invalid_argument& e)
845 {
846 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
847 }
848
849 // Test where fails: "f"
850 try
851 {
852 const json element = R"( "f" )"_json;
853 parseHexByte(element);
854 ADD_FAILURE() << "Should not have reached this line.";
855 }
856 catch (const std::invalid_argument& e)
857 {
858 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
859 }
860
861 // Test where fails: "0x"
862 try
863 {
864 const json element = R"( "0x" )"_json;
865 parseHexByte(element);
866 ADD_FAILURE() << "Should not have reached this line.";
867 }
868 catch (const std::invalid_argument& e)
869 {
870 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
871 }
872
873 // Test where fails: "0Xff"
874 try
875 {
876 const json element = R"( "0XFF" )"_json;
877 parseHexByte(element);
878 ADD_FAILURE() << "Should not have reached this line.";
879 }
880 catch (const std::invalid_argument& e)
881 {
882 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
883 }
884}
885
886TEST(ConfigFileParserTests, ParseHexByteArray)
887{
888 // Test where works
889 {
890 const json element = R"( [ "0xCC", "0xFF" ] )"_json;
891 std::vector<uint8_t> hexBytes = parseHexByteArray(element);
892 std::vector<uint8_t> expected = {0xcc, 0xff};
893 EXPECT_EQ(hexBytes, expected);
894 }
895
896 // Test where fails: Element is not an array
897 try
898 {
899 const json element = 0;
900 parseHexByteArray(element);
901 ADD_FAILURE() << "Should not have reached this line.";
902 }
903 catch (const std::invalid_argument& e)
904 {
905 EXPECT_STREQ(e.what(), "Element is not an array");
906 }
907}
908
Bob Kingf617f892020-03-30 19:03:35 +0800909TEST(ConfigFileParserTests, ParseI2CWriteBit)
910{
911 // Test where works
912 {
913 const json element = R"(
914 {
915 "register": "0xA0",
916 "position": 3,
917 "value": 0
918 }
919 )"_json;
920 std::unique_ptr<I2CWriteBitAction> action = parseI2CWriteBit(element);
921 EXPECT_EQ(action->getRegister(), 0xA0);
922 EXPECT_EQ(action->getPosition(), 3);
923 EXPECT_EQ(action->getValue(), 0);
924 }
925
926 // Test where fails: Invalid property specified
927 try
928 {
929 const json element = R"(
930 {
931 "register": "0xA0",
932 "position": 3,
933 "value": 0,
934 "foo": 3
935 }
936 )"_json;
937 parseI2CWriteBit(element);
938 ADD_FAILURE() << "Should not have reached this line.";
939 }
940 catch (const std::invalid_argument& e)
941 {
942 EXPECT_STREQ(e.what(), "Element contains an invalid property");
943 }
944
945 // Test where fails: Element is not an object
946 try
947 {
948 const json element = R"( [ "0xFF", "0x01" ] )"_json;
949 parseI2CWriteBit(element);
950 ADD_FAILURE() << "Should not have reached this line.";
951 }
952 catch (const std::invalid_argument& e)
953 {
954 EXPECT_STREQ(e.what(), "Element is not an object");
955 }
956
957 // Test where fails: register value is invalid
958 try
959 {
960 const json element = R"(
961 {
962 "register": "0xAG",
963 "position": 3,
964 "value": 0
965 }
966 )"_json;
967 parseI2CWriteBit(element);
968 ADD_FAILURE() << "Should not have reached this line.";
969 }
970 catch (const std::invalid_argument& e)
971 {
972 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
973 }
974
975 // Test where fails: position value is invalid
976 try
977 {
978 const json element = R"(
979 {
980 "register": "0xA0",
981 "position": 8,
982 "value": 0
983 }
984 )"_json;
985 parseI2CWriteBit(element);
986 ADD_FAILURE() << "Should not have reached this line.";
987 }
988 catch (const std::invalid_argument& e)
989 {
990 EXPECT_STREQ(e.what(), "Element is not a bit position");
991 }
992
993 // Test where fails: value value is invalid
994 try
995 {
996 const json element = R"(
997 {
998 "register": "0xA0",
999 "position": 3,
1000 "value": 2
1001 }
1002 )"_json;
1003 parseI2CWriteBit(element);
1004 ADD_FAILURE() << "Should not have reached this line.";
1005 }
1006 catch (const std::invalid_argument& e)
1007 {
1008 EXPECT_STREQ(e.what(), "Element is not a bit value");
1009 }
1010
1011 // Test where fails: Required register property not specified
1012 try
1013 {
1014 const json element = R"(
1015 {
1016 "position": 3,
1017 "value": 0
1018 }
1019 )"_json;
1020 parseI2CWriteBit(element);
1021 ADD_FAILURE() << "Should not have reached this line.";
1022 }
1023 catch (const std::invalid_argument& e)
1024 {
1025 EXPECT_STREQ(e.what(), "Required property missing: register");
1026 }
1027
1028 // Test where fails: Required position property not specified
1029 try
1030 {
1031 const json element = R"(
1032 {
1033 "register": "0xA0",
1034 "value": 0
1035 }
1036 )"_json;
1037 parseI2CWriteBit(element);
1038 ADD_FAILURE() << "Should not have reached this line.";
1039 }
1040 catch (const std::invalid_argument& e)
1041 {
1042 EXPECT_STREQ(e.what(), "Required property missing: position");
1043 }
1044
1045 // Test where fails: Required value property not specified
1046 try
1047 {
1048 const json element = R"(
1049 {
1050 "register": "0xA0",
1051 "position": 3
1052 }
1053 )"_json;
1054 parseI2CWriteBit(element);
1055 ADD_FAILURE() << "Should not have reached this line.";
1056 }
1057 catch (const std::invalid_argument& e)
1058 {
1059 EXPECT_STREQ(e.what(), "Required property missing: value");
1060 }
1061}
1062
Bob King87ff9d72020-03-31 14:02:55 +08001063TEST(ConfigFileParserTests, ParseI2CWriteByte)
1064{
1065 // Test where works: Only required properties specified
1066 {
1067 const json element = R"(
1068 {
1069 "register": "0x0A",
1070 "value": "0xCC"
1071 }
1072 )"_json;
1073 std::unique_ptr<I2CWriteByteAction> action = parseI2CWriteByte(element);
1074 EXPECT_EQ(action->getRegister(), 0x0A);
1075 EXPECT_EQ(action->getValue(), 0xCC);
1076 EXPECT_EQ(action->getMask(), 0xFF);
1077 }
1078
1079 // Test where works: All properties specified
1080 {
1081 const json element = R"(
1082 {
1083 "register": "0x0A",
1084 "value": "0xCC",
1085 "mask": "0xF7"
1086 }
1087 )"_json;
1088 std::unique_ptr<I2CWriteByteAction> action = parseI2CWriteByte(element);
1089 EXPECT_EQ(action->getRegister(), 0x0A);
1090 EXPECT_EQ(action->getValue(), 0xCC);
1091 EXPECT_EQ(action->getMask(), 0xF7);
1092 }
1093
1094 // Test where fails: Element is not an object
1095 try
1096 {
1097 const json element = R"( [ "0xFF", "0x01" ] )"_json;
1098 parseI2CWriteByte(element);
1099 ADD_FAILURE() << "Should not have reached this line.";
1100 }
1101 catch (const std::invalid_argument& e)
1102 {
1103 EXPECT_STREQ(e.what(), "Element is not an object");
1104 }
1105
1106 // Test where fails: Invalid property specified
1107 try
1108 {
1109 const json element = R"(
1110 {
1111 "register": "0x0A",
1112 "value": "0xCC",
1113 "mask": "0xF7",
1114 "foo": 1
1115 }
1116 )"_json;
1117 parseI2CWriteByte(element);
1118 ADD_FAILURE() << "Should not have reached this line.";
1119 }
1120 catch (const std::invalid_argument& e)
1121 {
1122 EXPECT_STREQ(e.what(), "Element contains an invalid property");
1123 }
1124
1125 // Test where fails: register value is invalid
1126 try
1127 {
1128 const json element = R"(
1129 {
1130 "register": "0x0Z",
1131 "value": "0xCC",
1132 "mask": "0xF7"
1133 }
1134 )"_json;
1135 parseI2CWriteByte(element);
1136 ADD_FAILURE() << "Should not have reached this line.";
1137 }
1138 catch (const std::invalid_argument& e)
1139 {
1140 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
1141 }
1142
1143 // Test where fails: value value is invalid
1144 try
1145 {
1146 const json element = R"(
1147 {
1148 "register": "0x0A",
1149 "value": "0xCCC",
1150 "mask": "0xF7"
1151 }
1152 )"_json;
1153 parseI2CWriteByte(element);
1154 ADD_FAILURE() << "Should not have reached this line.";
1155 }
1156 catch (const std::invalid_argument& e)
1157 {
1158 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
1159 }
1160
1161 // Test where fails: mask value is invalid
1162 try
1163 {
1164 const json element = R"(
1165 {
1166 "register": "0x0A",
1167 "value": "0xCC",
1168 "mask": "F7"
1169 }
1170 )"_json;
1171 parseI2CWriteByte(element);
1172 ADD_FAILURE() << "Should not have reached this line.";
1173 }
1174 catch (const std::invalid_argument& e)
1175 {
1176 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
1177 }
1178
1179 // Test where fails: Required register property not specified
1180 try
1181 {
1182 const json element = R"(
1183 {
1184 "value": "0xCC",
1185 "mask": "0xF7"
1186 }
1187 )"_json;
1188 parseI2CWriteByte(element);
1189 ADD_FAILURE() << "Should not have reached this line.";
1190 }
1191 catch (const std::invalid_argument& e)
1192 {
1193 EXPECT_STREQ(e.what(), "Required property missing: register");
1194 }
1195
1196 // Test where fails: Required value property not specified
1197 try
1198 {
1199 const json element = R"(
1200 {
1201 "register": "0x0A",
1202 "mask": "0xF7"
1203 }
1204 )"_json;
1205 parseI2CWriteByte(element);
1206 ADD_FAILURE() << "Should not have reached this line.";
1207 }
1208 catch (const std::invalid_argument& e)
1209 {
1210 EXPECT_STREQ(e.what(), "Required property missing: value");
1211 }
1212}
1213
Bob Kingbafcb862020-03-31 16:39:00 +08001214TEST(ConfigFileParserTests, ParseI2CWriteBytes)
1215{
1216 // Test where works: Only required properties specified
1217 {
1218 const json element = R"(
1219 {
1220 "register": "0x0A",
1221 "values": [ "0xCC", "0xFF" ]
1222 }
1223 )"_json;
1224 std::unique_ptr<I2CWriteBytesAction> action =
1225 parseI2CWriteBytes(element);
1226 EXPECT_EQ(action->getRegister(), 0x0A);
1227 EXPECT_EQ(action->getValues().size(), 2);
1228 EXPECT_EQ(action->getValues()[0], 0xCC);
1229 EXPECT_EQ(action->getValues()[1], 0xFF);
1230 EXPECT_EQ(action->getMasks().size(), 0);
1231 }
1232
1233 // Test where works: All properties specified
1234 {
1235 const json element = R"(
1236 {
1237 "register": "0x0A",
1238 "values": [ "0xCC", "0xFF" ],
1239 "masks": [ "0x7F", "0x77" ]
1240 }
1241 )"_json;
1242 std::unique_ptr<I2CWriteBytesAction> action =
1243 parseI2CWriteBytes(element);
1244 EXPECT_EQ(action->getRegister(), 0x0A);
1245 EXPECT_EQ(action->getValues().size(), 2);
1246 EXPECT_EQ(action->getValues()[0], 0xCC);
1247 EXPECT_EQ(action->getValues()[1], 0xFF);
1248 EXPECT_EQ(action->getMasks().size(), 2);
1249 EXPECT_EQ(action->getMasks()[0], 0x7F);
1250 EXPECT_EQ(action->getMasks()[1], 0x77);
1251 }
1252
1253 // Test where fails: Element is not an object
1254 try
1255 {
1256 const json element = R"( [ "0xFF", "0x01" ] )"_json;
1257 parseI2CWriteBytes(element);
1258 ADD_FAILURE() << "Should not have reached this line.";
1259 }
1260 catch (const std::invalid_argument& e)
1261 {
1262 EXPECT_STREQ(e.what(), "Element is not an object");
1263 }
1264
1265 // Test where fails: Invalid property specified
1266 try
1267 {
1268 const json element = R"(
1269 {
1270 "register": "0x0A",
1271 "values": [ "0xCC", "0xFF" ],
1272 "masks": [ "0x7F", "0x7F" ],
1273 "foo": 1
1274 }
1275 )"_json;
1276 parseI2CWriteBytes(element);
1277 ADD_FAILURE() << "Should not have reached this line.";
1278 }
1279 catch (const std::invalid_argument& e)
1280 {
1281 EXPECT_STREQ(e.what(), "Element contains an invalid property");
1282 }
1283
1284 // Test where fails: register value is invalid
1285 try
1286 {
1287 const json element = R"(
1288 {
1289 "register": "0x0Z",
1290 "values": [ "0xCC", "0xFF" ],
1291 "masks": [ "0x7F", "0x7F" ]
1292 }
1293 )"_json;
1294 parseI2CWriteBytes(element);
1295 ADD_FAILURE() << "Should not have reached this line.";
1296 }
1297 catch (const std::invalid_argument& e)
1298 {
1299 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
1300 }
1301
1302 // Test where fails: values value is invalid
1303 try
1304 {
1305 const json element = R"(
1306 {
1307 "register": "0x0A",
1308 "values": [ "0xCCC", "0xFF" ],
1309 "masks": [ "0x7F", "0x7F" ]
1310 }
1311 )"_json;
1312 parseI2CWriteBytes(element);
1313 ADD_FAILURE() << "Should not have reached this line.";
1314 }
1315 catch (const std::invalid_argument& e)
1316 {
1317 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
1318 }
1319
1320 // Test where fails: masks value is invalid
1321 try
1322 {
1323 const json element = R"(
1324 {
1325 "register": "0x0A",
1326 "values": [ "0xCC", "0xFF" ],
1327 "masks": [ "F", "0x7F" ]
1328 }
1329 )"_json;
1330 parseI2CWriteBytes(element);
1331 ADD_FAILURE() << "Should not have reached this line.";
1332 }
1333 catch (const std::invalid_argument& e)
1334 {
1335 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
1336 }
1337
1338 // Test where fails: number of elements in masks is invalid
1339 try
1340 {
1341 const json element = R"(
1342 {
1343 "register": "0x0A",
1344 "values": [ "0xCC", "0xFF" ],
1345 "masks": [ "0x7F" ]
1346 }
1347 )"_json;
1348 parseI2CWriteBytes(element);
1349 ADD_FAILURE() << "Should not have reached this line.";
1350 }
1351 catch (const std::invalid_argument& e)
1352 {
1353 EXPECT_STREQ(e.what(), "Invalid number of elements in masks");
1354 }
1355
1356 // Test where fails: Required register property not specified
1357 try
1358 {
1359 const json element = R"(
1360 {
1361 "values": [ "0xCC", "0xFF" ]
1362 }
1363 )"_json;
1364 parseI2CWriteBytes(element);
1365 ADD_FAILURE() << "Should not have reached this line.";
1366 }
1367 catch (const std::invalid_argument& e)
1368 {
1369 EXPECT_STREQ(e.what(), "Required property missing: register");
1370 }
1371
1372 // Test where fails: Required values property not specified
1373 try
1374 {
1375 const json element = R"(
1376 {
1377 "register": "0x0A"
1378 }
1379 )"_json;
1380 parseI2CWriteBytes(element);
1381 ADD_FAILURE() << "Should not have reached this line.";
1382 }
1383 catch (const std::invalid_argument& e)
1384 {
1385 EXPECT_STREQ(e.what(), "Required property missing: values");
1386 }
1387}
1388
Bob King87ff9d72020-03-31 14:02:55 +08001389TEST(ConfigFileParserTests, ParseInt8)
1390{
1391 // Test where works: INT8_MIN
1392 {
1393 const json element = R"( -128 )"_json;
1394 int8_t value = parseInt8(element);
1395 EXPECT_EQ(value, -128);
1396 }
1397
1398 // Test where works: INT8_MAX
1399 {
1400 const json element = R"( 127 )"_json;
1401 int8_t value = parseInt8(element);
1402 EXPECT_EQ(value, 127);
1403 }
1404
1405 // Test where fails: Element is not an integer
1406 try
1407 {
1408 const json element = R"( 1.03 )"_json;
1409 parseInt8(element);
1410 ADD_FAILURE() << "Should not have reached this line.";
1411 }
1412 catch (const std::invalid_argument& e)
1413 {
1414 EXPECT_STREQ(e.what(), "Element is not an integer");
1415 }
1416
1417 // Test where fails: Value < INT8_MIN
1418 try
1419 {
1420 const json element = R"( -129 )"_json;
1421 parseInt8(element);
1422 ADD_FAILURE() << "Should not have reached this line.";
1423 }
1424 catch (const std::invalid_argument& e)
1425 {
1426 EXPECT_STREQ(e.what(), "Element is not an 8-bit signed integer");
1427 }
1428
1429 // Test where fails: Value > INT8_MAX
1430 try
1431 {
1432 const json element = R"( 128 )"_json;
1433 parseInt8(element);
1434 ADD_FAILURE() << "Should not have reached this line.";
1435 }
1436 catch (const std::invalid_argument& e)
1437 {
1438 EXPECT_STREQ(e.what(), "Element is not an 8-bit signed integer");
1439 }
1440}
1441
Shawn McCarney0e8c68a2020-03-27 01:44:48 -05001442TEST(ConfigFileParserTests, ParsePMBusWriteVoutCommand)
1443{
1444 // Test where works: Only required properties specified
1445 {
1446 const json element = R"(
1447 {
1448 "format": "linear"
1449 }
1450 )"_json;
1451 std::unique_ptr<PMBusWriteVoutCommandAction> action =
1452 parsePMBusWriteVoutCommand(element);
1453 EXPECT_EQ(action->getVolts().has_value(), false);
1454 EXPECT_EQ(action->getFormat(), pmbus_utils::VoutDataFormat::linear);
1455 EXPECT_EQ(action->getExponent().has_value(), false);
1456 EXPECT_EQ(action->isVerified(), false);
1457 }
1458
1459 // Test where works: All properties specified
1460 {
1461 const json element = R"(
1462 {
1463 "volts": 1.03,
1464 "format": "linear",
1465 "exponent": -8,
1466 "is_verified": true
1467 }
1468 )"_json;
1469 std::unique_ptr<PMBusWriteVoutCommandAction> action =
1470 parsePMBusWriteVoutCommand(element);
1471 EXPECT_EQ(action->getVolts().has_value(), true);
1472 EXPECT_EQ(action->getVolts().value(), 1.03);
1473 EXPECT_EQ(action->getFormat(), pmbus_utils::VoutDataFormat::linear);
1474 EXPECT_EQ(action->getExponent().has_value(), true);
1475 EXPECT_EQ(action->getExponent().value(), -8);
1476 EXPECT_EQ(action->isVerified(), true);
1477 }
1478
1479 // Test where fails: Element is not an object
1480 try
1481 {
1482 const json element = R"( [ "0xFF", "0x01" ] )"_json;
1483 parsePMBusWriteVoutCommand(element);
1484 ADD_FAILURE() << "Should not have reached this line.";
1485 }
1486 catch (const std::invalid_argument& e)
1487 {
1488 EXPECT_STREQ(e.what(), "Element is not an object");
1489 }
1490
1491 // Test where fails: volts value is invalid
1492 try
1493 {
1494 const json element = R"(
1495 {
1496 "volts": "foo",
1497 "format": "linear"
1498 }
1499 )"_json;
1500 parsePMBusWriteVoutCommand(element);
1501 ADD_FAILURE() << "Should not have reached this line.";
1502 }
1503 catch (const std::invalid_argument& e)
1504 {
1505 EXPECT_STREQ(e.what(), "Element is not a number");
1506 }
1507
1508 // Test where fails: Required format property not specified
1509 try
1510 {
1511 const json element = R"(
1512 {
1513 "volts": 1.03,
1514 "is_verified": true
1515 }
1516 )"_json;
1517 parsePMBusWriteVoutCommand(element);
1518 ADD_FAILURE() << "Should not have reached this line.";
1519 }
1520 catch (const std::invalid_argument& e)
1521 {
1522 EXPECT_STREQ(e.what(), "Required property missing: format");
1523 }
1524
1525 // Test where fails: format value is invalid
1526 try
1527 {
1528 const json element = R"(
1529 {
1530 "format": "linear_11"
1531 }
1532 )"_json;
1533 parsePMBusWriteVoutCommand(element);
1534 ADD_FAILURE() << "Should not have reached this line.";
1535 }
1536 catch (const std::invalid_argument& e)
1537 {
1538 EXPECT_STREQ(e.what(), "Invalid format value: linear_11");
1539 }
1540
1541 // Test where fails: exponent value is invalid
1542 try
1543 {
1544 const json element = R"(
1545 {
1546 "format": "linear",
1547 "exponent": 1.3
1548 }
1549 )"_json;
1550 parsePMBusWriteVoutCommand(element);
1551 ADD_FAILURE() << "Should not have reached this line.";
1552 }
1553 catch (const std::invalid_argument& e)
1554 {
1555 EXPECT_STREQ(e.what(), "Element is not an integer");
1556 }
1557
1558 // Test where fails: is_verified value is invalid
1559 try
1560 {
1561 const json element = R"(
1562 {
1563 "format": "linear",
1564 "is_verified": "true"
1565 }
1566 )"_json;
1567 parsePMBusWriteVoutCommand(element);
1568 ADD_FAILURE() << "Should not have reached this line.";
1569 }
1570 catch (const std::invalid_argument& e)
1571 {
1572 EXPECT_STREQ(e.what(), "Element is not a boolean");
1573 }
1574
1575 // Test where fails: Invalid property specified
1576 try
1577 {
1578 const json element = R"(
1579 {
1580 "format": "linear",
1581 "foo": "bar"
1582 }
1583 )"_json;
1584 parsePMBusWriteVoutCommand(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 contains an invalid property");
1590 }
1591}
1592
1593TEST(ConfigFileParserTests, ParseRoot)
1594{
1595 // Test where works: Only required properties specified
1596 {
1597 const json element = R"(
1598 {
1599 "chassis": [
1600 { "number": 1 }
1601 ]
1602 }
1603 )"_json;
1604 std::vector<std::unique_ptr<Rule>> rules{};
1605 std::vector<std::unique_ptr<Chassis>> chassis{};
1606 std::tie(rules, chassis) = parseRoot(element);
1607 EXPECT_EQ(rules.size(), 0);
Bob King0e701132020-04-03 21:50:31 +08001608 EXPECT_EQ(chassis.size(), 1);
Shawn McCarney0e8c68a2020-03-27 01:44:48 -05001609 }
1610
1611 // Test where works: All properties specified
1612 {
1613 const json element = R"(
1614 {
1615 "comments": [ "Config file for a FooBar one-chassis system" ],
1616 "rules": [
1617 {
1618 "id": "set_voltage_rule",
1619 "actions": [
1620 { "pmbus_write_vout_command": { "format": "linear" } }
1621 ]
1622 }
1623 ],
1624 "chassis": [
1625 { "number": 1 },
1626 { "number": 3 }
1627 ]
1628 }
1629 )"_json;
1630 std::vector<std::unique_ptr<Rule>> rules{};
1631 std::vector<std::unique_ptr<Chassis>> chassis{};
1632 std::tie(rules, chassis) = parseRoot(element);
1633 EXPECT_EQ(rules.size(), 1);
Bob King0e701132020-04-03 21:50:31 +08001634 EXPECT_EQ(chassis.size(), 2);
Shawn McCarney0e8c68a2020-03-27 01:44:48 -05001635 }
1636
1637 // Test where fails: Element is not an object
1638 try
1639 {
1640 const json element = R"( [ "0xFF", "0x01" ] )"_json;
1641 parseRoot(element);
1642 ADD_FAILURE() << "Should not have reached this line.";
1643 }
1644 catch (const std::invalid_argument& e)
1645 {
1646 EXPECT_STREQ(e.what(), "Element is not an object");
1647 }
1648
1649 // Test where fails: chassis property not specified
1650 try
1651 {
1652 const json element = R"(
1653 {
1654 "rules": [
1655 {
1656 "id": "set_voltage_rule",
1657 "actions": [
1658 { "pmbus_write_vout_command": { "format": "linear" } }
1659 ]
1660 }
1661 ]
1662 }
1663 )"_json;
1664 parseRoot(element);
1665 ADD_FAILURE() << "Should not have reached this line.";
1666 }
1667 catch (const std::invalid_argument& e)
1668 {
1669 EXPECT_STREQ(e.what(), "Required property missing: chassis");
1670 }
1671
1672 // Test where fails: Invalid property specified
1673 try
1674 {
1675 const json element = R"(
1676 {
1677 "remarks": [ "Config file for a FooBar one-chassis system" ],
1678 "chassis": [
1679 { "number": 1 }
1680 ]
1681 }
1682 )"_json;
1683 parseRoot(element);
1684 ADD_FAILURE() << "Should not have reached this line.";
1685 }
1686 catch (const std::invalid_argument& e)
1687 {
1688 EXPECT_STREQ(e.what(), "Element contains an invalid property");
1689 }
1690}
1691
1692TEST(ConfigFileParserTests, ParseRule)
1693{
1694 // Test where works: comments property specified
1695 {
1696 const json element = R"(
1697 {
1698 "comments": [ "Set voltage rule" ],
1699 "id": "set_voltage_rule",
1700 "actions": [
1701 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } },
1702 { "pmbus_write_vout_command": { "volts": 1.03, "format": "linear" } }
1703 ]
1704 }
1705 )"_json;
1706 std::unique_ptr<Rule> rule = parseRule(element);
1707 EXPECT_EQ(rule->getID(), "set_voltage_rule");
1708 EXPECT_EQ(rule->getActions().size(), 2);
1709 }
1710
1711 // Test where works: comments property not specified
1712 {
1713 const json element = R"(
1714 {
1715 "id": "set_voltage_rule",
1716 "actions": [
1717 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } },
1718 { "pmbus_write_vout_command": { "volts": 1.03, "format": "linear" } },
1719 { "pmbus_write_vout_command": { "volts": 1.05, "format": "linear" } }
1720 ]
1721 }
1722 )"_json;
1723 std::unique_ptr<Rule> rule = parseRule(element);
1724 EXPECT_EQ(rule->getID(), "set_voltage_rule");
1725 EXPECT_EQ(rule->getActions().size(), 3);
1726 }
1727
1728 // Test where fails: Element is not an object
1729 try
1730 {
1731 const json element = R"( [ "0xFF", "0x01" ] )"_json;
1732 parseRule(element);
1733 ADD_FAILURE() << "Should not have reached this line.";
1734 }
1735 catch (const std::invalid_argument& e)
1736 {
1737 EXPECT_STREQ(e.what(), "Element is not an object");
1738 }
1739
1740 // Test where fails: id property not specified
1741 try
1742 {
1743 const json element = R"(
1744 {
1745 "actions": [
1746 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } }
1747 ]
1748 }
1749 )"_json;
1750 parseRule(element);
1751 ADD_FAILURE() << "Should not have reached this line.";
1752 }
1753 catch (const std::invalid_argument& e)
1754 {
1755 EXPECT_STREQ(e.what(), "Required property missing: id");
1756 }
1757
1758 // Test where fails: id property is invalid
1759 try
1760 {
1761 const json element = R"(
1762 {
1763 "id": "",
1764 "actions": [
1765 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } }
1766 ]
1767 }
1768 )"_json;
1769 parseRule(element);
1770 ADD_FAILURE() << "Should not have reached this line.";
1771 }
1772 catch (const std::invalid_argument& e)
1773 {
1774 EXPECT_STREQ(e.what(), "Element contains an empty string");
1775 }
1776
1777 // Test where fails: actions property not specified
1778 try
1779 {
1780 const json element = R"(
1781 {
1782 "comments": [ "Set voltage rule" ],
1783 "id": "set_voltage_rule"
1784 }
1785 )"_json;
1786 parseRule(element);
1787 ADD_FAILURE() << "Should not have reached this line.";
1788 }
1789 catch (const std::invalid_argument& e)
1790 {
1791 EXPECT_STREQ(e.what(), "Required property missing: actions");
1792 }
1793
1794 // Test where fails: actions property is invalid
1795 try
1796 {
1797 const json element = R"(
1798 {
1799 "id": "set_voltage_rule",
1800 "actions": true
1801 }
1802 )"_json;
1803 parseRule(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 is not an array");
1809 }
1810
1811 // Test where fails: Invalid property specified
1812 try
1813 {
1814 const json element = R"(
1815 {
1816 "remarks": [ "Set voltage rule" ],
1817 "id": "set_voltage_rule",
1818 "actions": [
1819 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } }
1820 ]
1821 }
1822 )"_json;
1823 parseRule(element);
1824 ADD_FAILURE() << "Should not have reached this line.";
1825 }
1826 catch (const std::invalid_argument& e)
1827 {
1828 EXPECT_STREQ(e.what(), "Element contains an invalid property");
1829 }
1830}
1831
1832TEST(ConfigFileParserTests, ParseRuleArray)
1833{
1834 // Test where works
1835 {
1836 const json element = R"(
1837 [
1838 {
1839 "id": "set_voltage_rule1",
1840 "actions": [
1841 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } }
1842 ]
1843 },
1844 {
1845 "id": "set_voltage_rule2",
1846 "actions": [
1847 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } },
1848 { "pmbus_write_vout_command": { "volts": 1.11, "format": "linear" } }
1849 ]
1850 }
1851 ]
1852 )"_json;
1853 std::vector<std::unique_ptr<Rule>> rules = parseRuleArray(element);
1854 EXPECT_EQ(rules.size(), 2);
1855 EXPECT_EQ(rules[0]->getID(), "set_voltage_rule1");
1856 EXPECT_EQ(rules[0]->getActions().size(), 1);
1857 EXPECT_EQ(rules[1]->getID(), "set_voltage_rule2");
1858 EXPECT_EQ(rules[1]->getActions().size(), 2);
1859 }
1860
1861 // Test where fails: Element is not an array
1862 try
1863 {
1864 const json element = R"( { "id": "set_voltage_rule" } )"_json;
1865 parseRuleArray(element);
1866 ADD_FAILURE() << "Should not have reached this line.";
1867 }
1868 catch (const std::invalid_argument& e)
1869 {
1870 EXPECT_STREQ(e.what(), "Element is not an array");
1871 }
1872}
1873
Bob King315b0b62020-04-03 21:47:58 +08001874TEST(ConfigFileParserTests, ParseRunRule)
1875{
1876 // Test where works
1877 {
1878 const json element = "vdd_regulator";
1879 std::unique_ptr<RunRuleAction> action = parseRunRule(element);
1880 EXPECT_EQ(action->getRuleID(), "vdd_regulator");
1881 }
1882
1883 // Test where fails: Element is not a string
1884 try
1885 {
1886 const json element = 1;
1887 parseRunRule(element);
1888 ADD_FAILURE() << "Should not have reached this line.";
1889 }
1890 catch (const std::invalid_argument& e)
1891 {
1892 EXPECT_STREQ(e.what(), "Element is not a string");
1893 }
1894
1895 // Test where fails: Empty string
1896 try
1897 {
1898 const json element = "";
1899 parseRunRule(element);
1900 ADD_FAILURE() << "Should not have reached this line.";
1901 }
1902 catch (const std::invalid_argument& e)
1903 {
1904 EXPECT_STREQ(e.what(), "Element contains an empty string");
1905 }
1906}
1907
Shawn McCarney0e8c68a2020-03-27 01:44:48 -05001908TEST(ConfigFileParserTests, ParseString)
1909{
1910 // Test where works: Empty string
1911 {
1912 const json element = "";
1913 std::string value = parseString(element, true);
1914 EXPECT_EQ(value, "");
1915 }
1916
1917 // Test where works: Non-empty string
1918 {
1919 const json element = "vdd_regulator";
1920 std::string value = parseString(element, false);
1921 EXPECT_EQ(value, "vdd_regulator");
1922 }
1923
1924 // Test where fails: Element is not a string
1925 try
1926 {
1927 const json element = R"( { "foo": "bar" } )"_json;
1928 parseString(element);
1929 ADD_FAILURE() << "Should not have reached this line.";
1930 }
1931 catch (const std::invalid_argument& e)
1932 {
1933 EXPECT_STREQ(e.what(), "Element is not a string");
1934 }
1935
1936 // Test where fails: Empty string
1937 try
1938 {
1939 const json element = "";
1940 parseString(element);
1941 ADD_FAILURE() << "Should not have reached this line.";
1942 }
1943 catch (const std::invalid_argument& e)
1944 {
1945 EXPECT_STREQ(e.what(), "Element contains an empty string");
1946 }
1947}
1948
Bob Kingf617f892020-03-30 19:03:35 +08001949TEST(ConfigFileParserTests, ParseUint8)
1950{
1951 // Test where works: 0
1952 {
1953 const json element = R"( 0 )"_json;
1954 uint8_t value = parseUint8(element);
1955 EXPECT_EQ(value, 0);
1956 }
1957
1958 // Test where works: UINT8_MAX
1959 {
1960 const json element = R"( 255 )"_json;
1961 uint8_t value = parseUint8(element);
1962 EXPECT_EQ(value, 255);
1963 }
1964
1965 // Test where fails: Element is not an integer
1966 try
1967 {
1968 const json element = R"( 1.03 )"_json;
1969 parseUint8(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 integer");
1975 }
1976
1977 // Test where fails: Value < 0
1978 try
1979 {
1980 const json element = R"( -1 )"_json;
1981 parseUint8(element);
1982 ADD_FAILURE() << "Should not have reached this line.";
1983 }
1984 catch (const std::invalid_argument& e)
1985 {
1986 EXPECT_STREQ(e.what(), "Element is not an 8-bit unsigned integer");
1987 }
1988
1989 // Test where fails: Value > UINT8_MAX
1990 try
1991 {
1992 const json element = R"( 256 )"_json;
1993 parseUint8(element);
1994 ADD_FAILURE() << "Should not have reached this line.";
1995 }
1996 catch (const std::invalid_argument& e)
1997 {
1998 EXPECT_STREQ(e.what(), "Element is not an 8-bit unsigned integer");
1999 }
2000}
2001
Bob King0e701132020-04-03 21:50:31 +08002002TEST(ConfigFileParserTests, ParseUnsignedInteger)
2003{
2004 // Test where works: 1
2005 {
2006 const json element = R"( 1 )"_json;
2007 unsigned int value = parseUnsignedInteger(element);
2008 EXPECT_EQ(value, 1);
2009 }
2010
2011 // Test where fails: Element is not an integer
2012 try
2013 {
2014 const json element = R"( 1.5 )"_json;
2015 parseUnsignedInteger(element);
2016 ADD_FAILURE() << "Should not have reached this line.";
2017 }
2018 catch (const std::invalid_argument& e)
2019 {
2020 EXPECT_STREQ(e.what(), "Element is not an unsigned integer");
2021 }
2022
2023 // Test where fails: Value < 0
2024 try
2025 {
2026 const json element = R"( -1 )"_json;
2027 parseUnsignedInteger(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 an unsigned integer");
2033 }
2034}
2035
Shawn McCarney0e8c68a2020-03-27 01:44:48 -05002036TEST(ConfigFileParserTests, VerifyIsArray)
2037{
2038 // Test where element is an array
2039 try
2040 {
2041 const json element = R"( [ "foo", "bar" ] )"_json;
2042 verifyIsArray(element);
2043 }
2044 catch (const std::exception& e)
2045 {
2046 ADD_FAILURE() << "Should not have caught exception.";
2047 }
2048
2049 // Test where element is not an array
2050 try
2051 {
2052 const json element = R"( { "foo": "bar" } )"_json;
2053 verifyIsArray(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 an array");
2059 }
2060}
2061
2062TEST(ConfigFileParserTests, VerifyIsObject)
2063{
2064 // Test where element is an object
2065 try
2066 {
2067 const json element = R"( { "foo": "bar" } )"_json;
2068 verifyIsObject(element);
2069 }
2070 catch (const std::exception& e)
2071 {
2072 ADD_FAILURE() << "Should not have caught exception.";
2073 }
2074
2075 // Test where element is not an object
2076 try
2077 {
2078 const json element = R"( [ "foo", "bar" ] )"_json;
2079 verifyIsObject(element);
2080 ADD_FAILURE() << "Should not have reached this line.";
2081 }
2082 catch (const std::invalid_argument& e)
2083 {
2084 EXPECT_STREQ(e.what(), "Element is not an object");
2085 }
2086}
2087
2088TEST(ConfigFileParserTests, VerifyPropertyCount)
2089{
2090 // Test where element has expected number of properties
2091 try
2092 {
2093 const json element = R"(
2094 {
2095 "comments": [ "Set voltage rule" ],
2096 "id": "set_voltage_rule"
2097 }
2098 )"_json;
2099 verifyPropertyCount(element, 2);
2100 }
2101 catch (const std::exception& e)
2102 {
2103 ADD_FAILURE() << "Should not have caught exception.";
2104 }
2105
2106 // Test where element has unexpected number of properties
2107 try
2108 {
2109 const json element = R"(
2110 {
2111 "comments": [ "Set voltage rule" ],
2112 "id": "set_voltage_rule",
2113 "foo": 1.3
2114 }
2115 )"_json;
2116 verifyPropertyCount(element, 2);
2117 ADD_FAILURE() << "Should not have reached this line.";
2118 }
2119 catch (const std::invalid_argument& e)
2120 {
2121 EXPECT_STREQ(e.what(), "Element contains an invalid property");
2122 }
2123}