blob: 9942c04d1300a6c2b11cc5c8d2157b5c00186a79 [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 Kingf617f892020-03-30 19:03:35 +080020#include "i2c_interface.hpp"
21#include "i2c_write_bit_action.hpp"
Bob King87ff9d72020-03-31 14:02:55 +080022#include "i2c_write_byte_action.hpp"
Bob Kingbafcb862020-03-31 16:39:00 +080023#include "i2c_write_bytes_action.hpp"
Shawn McCarney0e8c68a2020-03-27 01:44:48 -050024#include "pmbus_utils.hpp"
25#include "pmbus_write_vout_command_action.hpp"
26#include "rule.hpp"
Bob King315b0b62020-04-03 21:47:58 +080027#include "run_rule_action.hpp"
Shawn McCarney80c0b042020-03-27 12:08:53 -050028#include "tmp_file.hpp"
Shawn McCarney0e8c68a2020-03-27 01:44:48 -050029
Shawn McCarney80c0b042020-03-27 12:08:53 -050030#include <sys/stat.h> // for chmod()
Shawn McCarney0e8c68a2020-03-27 01:44:48 -050031
32#include <nlohmann/json.hpp>
33
34#include <cstdint>
35#include <cstring>
36#include <exception>
37#include <filesystem>
38#include <fstream>
39#include <memory>
40#include <optional>
41#include <stdexcept>
42#include <string>
43#include <tuple>
44#include <vector>
45
46#include <gtest/gtest.h>
47
48using namespace phosphor::power::regulators;
49using namespace phosphor::power::regulators::config_file_parser;
50using namespace phosphor::power::regulators::config_file_parser::internal;
51using json = nlohmann::json;
52
Shawn McCarney0e8c68a2020-03-27 01:44:48 -050053void writeConfigFile(const std::filesystem::path& pathName,
54 const std::string& contents)
55{
56 std::ofstream file{pathName};
57 file << contents;
58}
59
60void writeConfigFile(const std::filesystem::path& pathName,
61 const json& contents)
62{
63 std::ofstream file{pathName};
64 file << contents;
65}
66
67TEST(ConfigFileParserTests, Parse)
68{
69 // Test where works
70 {
71 const json configFileContents = R"(
72 {
73 "rules": [
74 {
75 "id": "set_voltage_rule1",
76 "actions": [
77 { "pmbus_write_vout_command": { "volts": 1.03, "format": "linear" } }
78 ]
79 },
80 {
81 "id": "set_voltage_rule2",
82 "actions": [
83 { "pmbus_write_vout_command": { "volts": 1.33, "format": "linear" } }
84 ]
85 }
86 ],
87 "chassis": [
88 { "number": 1 },
89 { "number": 2 },
90 { "number": 3 }
91 ]
92 }
93 )"_json;
94
95 TmpFile configFile;
96 std::filesystem::path pathName{configFile.getName()};
97 writeConfigFile(pathName, configFileContents);
98
99 std::vector<std::unique_ptr<Rule>> rules{};
100 std::vector<std::unique_ptr<Chassis>> chassis{};
101 std::tie(rules, chassis) = parse(pathName);
102
103 EXPECT_EQ(rules.size(), 2);
104 EXPECT_EQ(rules[0]->getID(), "set_voltage_rule1");
105 EXPECT_EQ(rules[1]->getID(), "set_voltage_rule2");
106
107 // TODO: Not implemented yet
108 // 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);
112 }
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
364 // TODO: Implement after another action type is supported
365
366 // Test where fails: Invalid property specified
367 try
368 {
369 const json element = R"(
370 {
371 "remarks": [ "Set output voltage." ],
372 "pmbus_write_vout_command": {
373 "format": "linear"
374 }
375 }
376 )"_json;
377 parseAction(element);
378 ADD_FAILURE() << "Should not have reached this line.";
379 }
380 catch (const std::invalid_argument& e)
381 {
382 EXPECT_STREQ(e.what(), "Element contains an invalid property");
383 }
384}
385
386TEST(ConfigFileParserTests, ParseActionArray)
387{
388 // Test where works
389 {
390 const json element = R"(
391 [
392 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } },
393 { "pmbus_write_vout_command": { "volts": 1.03, "format": "linear" } }
394 ]
395 )"_json;
396 std::vector<std::unique_ptr<Action>> actions =
397 parseActionArray(element);
398 EXPECT_EQ(actions.size(), 2);
399 }
400
401 // Test where fails: Element is not an array
402 try
403 {
404 const json element = R"(
405 {
406 "foo": "bar"
407 }
408 )"_json;
409 parseActionArray(element);
410 ADD_FAILURE() << "Should not have reached this line.";
411 }
412 catch (const std::invalid_argument& e)
413 {
414 EXPECT_STREQ(e.what(), "Element is not an array");
415 }
416}
417
Bob Kingf617f892020-03-30 19:03:35 +0800418TEST(ConfigFileParserTests, ParseBitPosition)
419{
420 // Test where works: 0
421 {
422 const json element = R"( 0 )"_json;
423 uint8_t value = parseBitPosition(element);
424 EXPECT_EQ(value, 0);
425 }
426
427 // Test where works: 7
428 {
429 const json element = R"( 7 )"_json;
430 uint8_t value = parseBitPosition(element);
431 EXPECT_EQ(value, 7);
432 }
433
434 // Test where fails: Element is not an integer
435 try
436 {
437 const json element = R"( 1.03 )"_json;
438 parseBitPosition(element);
439 ADD_FAILURE() << "Should not have reached this line.";
440 }
441 catch (const std::invalid_argument& e)
442 {
443 EXPECT_STREQ(e.what(), "Element is not an integer");
444 }
445
446 // Test where fails: Value < 0
447 try
448 {
449 const json element = R"( -1 )"_json;
450 parseBitPosition(element);
451 ADD_FAILURE() << "Should not have reached this line.";
452 }
453 catch (const std::invalid_argument& e)
454 {
455 EXPECT_STREQ(e.what(), "Element is not a bit position");
456 }
457
458 // Test where fails: Value > 7
459 try
460 {
461 const json element = R"( 8 )"_json;
462 parseBitPosition(element);
463 ADD_FAILURE() << "Should not have reached this line.";
464 }
465 catch (const std::invalid_argument& e)
466 {
467 EXPECT_STREQ(e.what(), "Element is not a bit position");
468 }
469}
470
471TEST(ConfigFileParserTests, ParseBitValue)
472{
473 // Test where works: 0
474 {
475 const json element = R"( 0 )"_json;
476 uint8_t value = parseBitValue(element);
477 EXPECT_EQ(value, 0);
478 }
479
480 // Test where works: 1
481 {
482 const json element = R"( 1 )"_json;
483 uint8_t value = parseBitValue(element);
484 EXPECT_EQ(value, 1);
485 }
486
487 // Test where fails: Element is not an integer
488 try
489 {
490 const json element = R"( 0.5 )"_json;
491 parseBitValue(element);
492 ADD_FAILURE() << "Should not have reached this line.";
493 }
494 catch (const std::invalid_argument& e)
495 {
496 EXPECT_STREQ(e.what(), "Element is not an integer");
497 }
498
499 // Test where fails: Value < 0
500 try
501 {
502 const json element = R"( -1 )"_json;
503 parseBitValue(element);
504 ADD_FAILURE() << "Should not have reached this line.";
505 }
506 catch (const std::invalid_argument& e)
507 {
508 EXPECT_STREQ(e.what(), "Element is not a bit value");
509 }
510
511 // Test where fails: Value > 1
512 try
513 {
514 const json element = R"( 2 )"_json;
515 parseBitValue(element);
516 ADD_FAILURE() << "Should not have reached this line.";
517 }
518 catch (const std::invalid_argument& e)
519 {
520 EXPECT_STREQ(e.what(), "Element is not a bit value");
521 }
522}
523
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500524TEST(ConfigFileParserTests, ParseBoolean)
525{
526 // Test where works: true
527 {
528 const json element = R"( true )"_json;
529 bool value = parseBoolean(element);
530 EXPECT_EQ(value, true);
531 }
532
533 // Test where works: false
534 {
535 const json element = R"( false )"_json;
536 bool value = parseBoolean(element);
537 EXPECT_EQ(value, false);
538 }
539
540 // Test where fails: Element is not a boolean
541 try
542 {
543 const json element = R"( 1 )"_json;
544 parseBoolean(element);
545 ADD_FAILURE() << "Should not have reached this line.";
546 }
547 catch (const std::invalid_argument& e)
548 {
549 EXPECT_STREQ(e.what(), "Element is not a boolean");
550 }
551}
552
553TEST(ConfigFileParserTests, ParseChassisArray)
554{
555 // TODO: Not implemented yet
556}
557
558TEST(ConfigFileParserTests, ParseDouble)
559{
560 // Test where works: floating point value
561 {
562 const json element = R"( 1.03 )"_json;
563 double value = parseDouble(element);
564 EXPECT_EQ(value, 1.03);
565 }
566
567 // Test where works: integer value
568 {
569 const json element = R"( 24 )"_json;
570 double value = parseDouble(element);
571 EXPECT_EQ(value, 24.0);
572 }
573
574 // Test where fails: Element is not a number
575 try
576 {
577 const json element = R"( true )"_json;
578 parseDouble(element);
579 ADD_FAILURE() << "Should not have reached this line.";
580 }
581 catch (const std::invalid_argument& e)
582 {
583 EXPECT_STREQ(e.what(), "Element is not a number");
584 }
585}
586
Bob Kingbafcb862020-03-31 16:39:00 +0800587TEST(ConfigFileParserTests, ParseHexByte)
588{
589 // Test where works: "0xFF"
590 {
591 const json element = R"( "0xFF" )"_json;
592 uint8_t value = parseHexByte(element);
593 EXPECT_EQ(value, 0xFF);
594 }
595
596 // Test where works: "0xff"
597 {
598 const json element = R"( "0xff" )"_json;
599 uint8_t value = parseHexByte(element);
600 EXPECT_EQ(value, 0xff);
601 }
602
603 // Test where works: "0xf"
604 {
605 const json element = R"( "0xf" )"_json;
606 uint8_t value = parseHexByte(element);
607 EXPECT_EQ(value, 0xf);
608 }
609
610 // Test where fails: "0xfff"
611 try
612 {
613 const json element = R"( "0xfff" )"_json;
614 parseHexByte(element);
615 ADD_FAILURE() << "Should not have reached this line.";
616 }
617 catch (const std::invalid_argument& e)
618 {
619 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
620 }
621
622 // Test where fails: "0xAG"
623 try
624 {
625 const json element = R"( "0xAG" )"_json;
626 parseHexByte(element);
627 ADD_FAILURE() << "Should not have reached this line.";
628 }
629 catch (const std::invalid_argument& e)
630 {
631 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
632 }
633
634 // Test where fails: "ff"
635 try
636 {
637 const json element = R"( "ff" )"_json;
638 parseHexByte(element);
639 ADD_FAILURE() << "Should not have reached this line.";
640 }
641 catch (const std::invalid_argument& e)
642 {
643 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
644 }
645
646 // Test where fails: ""
647 try
648 {
649 const json element = "";
650 parseHexByte(element);
651 ADD_FAILURE() << "Should not have reached this line.";
652 }
653 catch (const std::invalid_argument& e)
654 {
655 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
656 }
657
658 // Test where fails: "f"
659 try
660 {
661 const json element = R"( "f" )"_json;
662 parseHexByte(element);
663 ADD_FAILURE() << "Should not have reached this line.";
664 }
665 catch (const std::invalid_argument& e)
666 {
667 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
668 }
669
670 // Test where fails: "0x"
671 try
672 {
673 const json element = R"( "0x" )"_json;
674 parseHexByte(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 hexadecimal string");
680 }
681
682 // Test where fails: "0Xff"
683 try
684 {
685 const json element = R"( "0XFF" )"_json;
686 parseHexByte(element);
687 ADD_FAILURE() << "Should not have reached this line.";
688 }
689 catch (const std::invalid_argument& e)
690 {
691 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
692 }
693}
694
695TEST(ConfigFileParserTests, ParseHexByteArray)
696{
697 // Test where works
698 {
699 const json element = R"( [ "0xCC", "0xFF" ] )"_json;
700 std::vector<uint8_t> hexBytes = parseHexByteArray(element);
701 std::vector<uint8_t> expected = {0xcc, 0xff};
702 EXPECT_EQ(hexBytes, expected);
703 }
704
705 // Test where fails: Element is not an array
706 try
707 {
708 const json element = 0;
709 parseHexByteArray(element);
710 ADD_FAILURE() << "Should not have reached this line.";
711 }
712 catch (const std::invalid_argument& e)
713 {
714 EXPECT_STREQ(e.what(), "Element is not an array");
715 }
716}
717
Bob Kingf617f892020-03-30 19:03:35 +0800718TEST(ConfigFileParserTests, ParseI2CWriteBit)
719{
720 // Test where works
721 {
722 const json element = R"(
723 {
724 "register": "0xA0",
725 "position": 3,
726 "value": 0
727 }
728 )"_json;
729 std::unique_ptr<I2CWriteBitAction> action = parseI2CWriteBit(element);
730 EXPECT_EQ(action->getRegister(), 0xA0);
731 EXPECT_EQ(action->getPosition(), 3);
732 EXPECT_EQ(action->getValue(), 0);
733 }
734
735 // Test where fails: Invalid property specified
736 try
737 {
738 const json element = R"(
739 {
740 "register": "0xA0",
741 "position": 3,
742 "value": 0,
743 "foo": 3
744 }
745 )"_json;
746 parseI2CWriteBit(element);
747 ADD_FAILURE() << "Should not have reached this line.";
748 }
749 catch (const std::invalid_argument& e)
750 {
751 EXPECT_STREQ(e.what(), "Element contains an invalid property");
752 }
753
754 // Test where fails: Element is not an object
755 try
756 {
757 const json element = R"( [ "0xFF", "0x01" ] )"_json;
758 parseI2CWriteBit(element);
759 ADD_FAILURE() << "Should not have reached this line.";
760 }
761 catch (const std::invalid_argument& e)
762 {
763 EXPECT_STREQ(e.what(), "Element is not an object");
764 }
765
766 // Test where fails: register value is invalid
767 try
768 {
769 const json element = R"(
770 {
771 "register": "0xAG",
772 "position": 3,
773 "value": 0
774 }
775 )"_json;
776 parseI2CWriteBit(element);
777 ADD_FAILURE() << "Should not have reached this line.";
778 }
779 catch (const std::invalid_argument& e)
780 {
781 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
782 }
783
784 // Test where fails: position value is invalid
785 try
786 {
787 const json element = R"(
788 {
789 "register": "0xA0",
790 "position": 8,
791 "value": 0
792 }
793 )"_json;
794 parseI2CWriteBit(element);
795 ADD_FAILURE() << "Should not have reached this line.";
796 }
797 catch (const std::invalid_argument& e)
798 {
799 EXPECT_STREQ(e.what(), "Element is not a bit position");
800 }
801
802 // Test where fails: value value is invalid
803 try
804 {
805 const json element = R"(
806 {
807 "register": "0xA0",
808 "position": 3,
809 "value": 2
810 }
811 )"_json;
812 parseI2CWriteBit(element);
813 ADD_FAILURE() << "Should not have reached this line.";
814 }
815 catch (const std::invalid_argument& e)
816 {
817 EXPECT_STREQ(e.what(), "Element is not a bit value");
818 }
819
820 // Test where fails: Required register property not specified
821 try
822 {
823 const json element = R"(
824 {
825 "position": 3,
826 "value": 0
827 }
828 )"_json;
829 parseI2CWriteBit(element);
830 ADD_FAILURE() << "Should not have reached this line.";
831 }
832 catch (const std::invalid_argument& e)
833 {
834 EXPECT_STREQ(e.what(), "Required property missing: register");
835 }
836
837 // Test where fails: Required position property not specified
838 try
839 {
840 const json element = R"(
841 {
842 "register": "0xA0",
843 "value": 0
844 }
845 )"_json;
846 parseI2CWriteBit(element);
847 ADD_FAILURE() << "Should not have reached this line.";
848 }
849 catch (const std::invalid_argument& e)
850 {
851 EXPECT_STREQ(e.what(), "Required property missing: position");
852 }
853
854 // Test where fails: Required value property not specified
855 try
856 {
857 const json element = R"(
858 {
859 "register": "0xA0",
860 "position": 3
861 }
862 )"_json;
863 parseI2CWriteBit(element);
864 ADD_FAILURE() << "Should not have reached this line.";
865 }
866 catch (const std::invalid_argument& e)
867 {
868 EXPECT_STREQ(e.what(), "Required property missing: value");
869 }
870}
871
Bob King87ff9d72020-03-31 14:02:55 +0800872TEST(ConfigFileParserTests, ParseI2CWriteByte)
873{
874 // Test where works: Only required properties specified
875 {
876 const json element = R"(
877 {
878 "register": "0x0A",
879 "value": "0xCC"
880 }
881 )"_json;
882 std::unique_ptr<I2CWriteByteAction> action = parseI2CWriteByte(element);
883 EXPECT_EQ(action->getRegister(), 0x0A);
884 EXPECT_EQ(action->getValue(), 0xCC);
885 EXPECT_EQ(action->getMask(), 0xFF);
886 }
887
888 // Test where works: All properties specified
889 {
890 const json element = R"(
891 {
892 "register": "0x0A",
893 "value": "0xCC",
894 "mask": "0xF7"
895 }
896 )"_json;
897 std::unique_ptr<I2CWriteByteAction> action = parseI2CWriteByte(element);
898 EXPECT_EQ(action->getRegister(), 0x0A);
899 EXPECT_EQ(action->getValue(), 0xCC);
900 EXPECT_EQ(action->getMask(), 0xF7);
901 }
902
903 // Test where fails: Element is not an object
904 try
905 {
906 const json element = R"( [ "0xFF", "0x01" ] )"_json;
907 parseI2CWriteByte(element);
908 ADD_FAILURE() << "Should not have reached this line.";
909 }
910 catch (const std::invalid_argument& e)
911 {
912 EXPECT_STREQ(e.what(), "Element is not an object");
913 }
914
915 // Test where fails: Invalid property specified
916 try
917 {
918 const json element = R"(
919 {
920 "register": "0x0A",
921 "value": "0xCC",
922 "mask": "0xF7",
923 "foo": 1
924 }
925 )"_json;
926 parseI2CWriteByte(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 // Test where fails: register value is invalid
935 try
936 {
937 const json element = R"(
938 {
939 "register": "0x0Z",
940 "value": "0xCC",
941 "mask": "0xF7"
942 }
943 )"_json;
944 parseI2CWriteByte(element);
945 ADD_FAILURE() << "Should not have reached this line.";
946 }
947 catch (const std::invalid_argument& e)
948 {
949 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
950 }
951
952 // Test where fails: value value is invalid
953 try
954 {
955 const json element = R"(
956 {
957 "register": "0x0A",
958 "value": "0xCCC",
959 "mask": "0xF7"
960 }
961 )"_json;
962 parseI2CWriteByte(element);
963 ADD_FAILURE() << "Should not have reached this line.";
964 }
965 catch (const std::invalid_argument& e)
966 {
967 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
968 }
969
970 // Test where fails: mask value is invalid
971 try
972 {
973 const json element = R"(
974 {
975 "register": "0x0A",
976 "value": "0xCC",
977 "mask": "F7"
978 }
979 )"_json;
980 parseI2CWriteByte(element);
981 ADD_FAILURE() << "Should not have reached this line.";
982 }
983 catch (const std::invalid_argument& e)
984 {
985 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
986 }
987
988 // Test where fails: Required register property not specified
989 try
990 {
991 const json element = R"(
992 {
993 "value": "0xCC",
994 "mask": "0xF7"
995 }
996 )"_json;
997 parseI2CWriteByte(element);
998 ADD_FAILURE() << "Should not have reached this line.";
999 }
1000 catch (const std::invalid_argument& e)
1001 {
1002 EXPECT_STREQ(e.what(), "Required property missing: register");
1003 }
1004
1005 // Test where fails: Required value property not specified
1006 try
1007 {
1008 const json element = R"(
1009 {
1010 "register": "0x0A",
1011 "mask": "0xF7"
1012 }
1013 )"_json;
1014 parseI2CWriteByte(element);
1015 ADD_FAILURE() << "Should not have reached this line.";
1016 }
1017 catch (const std::invalid_argument& e)
1018 {
1019 EXPECT_STREQ(e.what(), "Required property missing: value");
1020 }
1021}
1022
Bob Kingbafcb862020-03-31 16:39:00 +08001023TEST(ConfigFileParserTests, ParseI2CWriteBytes)
1024{
1025 // Test where works: Only required properties specified
1026 {
1027 const json element = R"(
1028 {
1029 "register": "0x0A",
1030 "values": [ "0xCC", "0xFF" ]
1031 }
1032 )"_json;
1033 std::unique_ptr<I2CWriteBytesAction> action =
1034 parseI2CWriteBytes(element);
1035 EXPECT_EQ(action->getRegister(), 0x0A);
1036 EXPECT_EQ(action->getValues().size(), 2);
1037 EXPECT_EQ(action->getValues()[0], 0xCC);
1038 EXPECT_EQ(action->getValues()[1], 0xFF);
1039 EXPECT_EQ(action->getMasks().size(), 0);
1040 }
1041
1042 // Test where works: All properties specified
1043 {
1044 const json element = R"(
1045 {
1046 "register": "0x0A",
1047 "values": [ "0xCC", "0xFF" ],
1048 "masks": [ "0x7F", "0x77" ]
1049 }
1050 )"_json;
1051 std::unique_ptr<I2CWriteBytesAction> action =
1052 parseI2CWriteBytes(element);
1053 EXPECT_EQ(action->getRegister(), 0x0A);
1054 EXPECT_EQ(action->getValues().size(), 2);
1055 EXPECT_EQ(action->getValues()[0], 0xCC);
1056 EXPECT_EQ(action->getValues()[1], 0xFF);
1057 EXPECT_EQ(action->getMasks().size(), 2);
1058 EXPECT_EQ(action->getMasks()[0], 0x7F);
1059 EXPECT_EQ(action->getMasks()[1], 0x77);
1060 }
1061
1062 // Test where fails: Element is not an object
1063 try
1064 {
1065 const json element = R"( [ "0xFF", "0x01" ] )"_json;
1066 parseI2CWriteBytes(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: Invalid property specified
1075 try
1076 {
1077 const json element = R"(
1078 {
1079 "register": "0x0A",
1080 "values": [ "0xCC", "0xFF" ],
1081 "masks": [ "0x7F", "0x7F" ],
1082 "foo": 1
1083 }
1084 )"_json;
1085 parseI2CWriteBytes(element);
1086 ADD_FAILURE() << "Should not have reached this line.";
1087 }
1088 catch (const std::invalid_argument& e)
1089 {
1090 EXPECT_STREQ(e.what(), "Element contains an invalid property");
1091 }
1092
1093 // Test where fails: register value is invalid
1094 try
1095 {
1096 const json element = R"(
1097 {
1098 "register": "0x0Z",
1099 "values": [ "0xCC", "0xFF" ],
1100 "masks": [ "0x7F", "0x7F" ]
1101 }
1102 )"_json;
1103 parseI2CWriteBytes(element);
1104 ADD_FAILURE() << "Should not have reached this line.";
1105 }
1106 catch (const std::invalid_argument& e)
1107 {
1108 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
1109 }
1110
1111 // Test where fails: values value is invalid
1112 try
1113 {
1114 const json element = R"(
1115 {
1116 "register": "0x0A",
1117 "values": [ "0xCCC", "0xFF" ],
1118 "masks": [ "0x7F", "0x7F" ]
1119 }
1120 )"_json;
1121 parseI2CWriteBytes(element);
1122 ADD_FAILURE() << "Should not have reached this line.";
1123 }
1124 catch (const std::invalid_argument& e)
1125 {
1126 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
1127 }
1128
1129 // Test where fails: masks value is invalid
1130 try
1131 {
1132 const json element = R"(
1133 {
1134 "register": "0x0A",
1135 "values": [ "0xCC", "0xFF" ],
1136 "masks": [ "F", "0x7F" ]
1137 }
1138 )"_json;
1139 parseI2CWriteBytes(element);
1140 ADD_FAILURE() << "Should not have reached this line.";
1141 }
1142 catch (const std::invalid_argument& e)
1143 {
1144 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
1145 }
1146
1147 // Test where fails: number of elements in masks is invalid
1148 try
1149 {
1150 const json element = R"(
1151 {
1152 "register": "0x0A",
1153 "values": [ "0xCC", "0xFF" ],
1154 "masks": [ "0x7F" ]
1155 }
1156 )"_json;
1157 parseI2CWriteBytes(element);
1158 ADD_FAILURE() << "Should not have reached this line.";
1159 }
1160 catch (const std::invalid_argument& e)
1161 {
1162 EXPECT_STREQ(e.what(), "Invalid number of elements in masks");
1163 }
1164
1165 // Test where fails: Required register property not specified
1166 try
1167 {
1168 const json element = R"(
1169 {
1170 "values": [ "0xCC", "0xFF" ]
1171 }
1172 )"_json;
1173 parseI2CWriteBytes(element);
1174 ADD_FAILURE() << "Should not have reached this line.";
1175 }
1176 catch (const std::invalid_argument& e)
1177 {
1178 EXPECT_STREQ(e.what(), "Required property missing: register");
1179 }
1180
1181 // Test where fails: Required values property not specified
1182 try
1183 {
1184 const json element = R"(
1185 {
1186 "register": "0x0A"
1187 }
1188 )"_json;
1189 parseI2CWriteBytes(element);
1190 ADD_FAILURE() << "Should not have reached this line.";
1191 }
1192 catch (const std::invalid_argument& e)
1193 {
1194 EXPECT_STREQ(e.what(), "Required property missing: values");
1195 }
1196}
1197
Bob King87ff9d72020-03-31 14:02:55 +08001198TEST(ConfigFileParserTests, ParseInt8)
1199{
1200 // Test where works: INT8_MIN
1201 {
1202 const json element = R"( -128 )"_json;
1203 int8_t value = parseInt8(element);
1204 EXPECT_EQ(value, -128);
1205 }
1206
1207 // Test where works: INT8_MAX
1208 {
1209 const json element = R"( 127 )"_json;
1210 int8_t value = parseInt8(element);
1211 EXPECT_EQ(value, 127);
1212 }
1213
1214 // Test where fails: Element is not an integer
1215 try
1216 {
1217 const json element = R"( 1.03 )"_json;
1218 parseInt8(element);
1219 ADD_FAILURE() << "Should not have reached this line.";
1220 }
1221 catch (const std::invalid_argument& e)
1222 {
1223 EXPECT_STREQ(e.what(), "Element is not an integer");
1224 }
1225
1226 // Test where fails: Value < INT8_MIN
1227 try
1228 {
1229 const json element = R"( -129 )"_json;
1230 parseInt8(element);
1231 ADD_FAILURE() << "Should not have reached this line.";
1232 }
1233 catch (const std::invalid_argument& e)
1234 {
1235 EXPECT_STREQ(e.what(), "Element is not an 8-bit signed integer");
1236 }
1237
1238 // Test where fails: Value > INT8_MAX
1239 try
1240 {
1241 const json element = R"( 128 )"_json;
1242 parseInt8(element);
1243 ADD_FAILURE() << "Should not have reached this line.";
1244 }
1245 catch (const std::invalid_argument& e)
1246 {
1247 EXPECT_STREQ(e.what(), "Element is not an 8-bit signed integer");
1248 }
1249}
1250
Shawn McCarney0e8c68a2020-03-27 01:44:48 -05001251TEST(ConfigFileParserTests, ParsePMBusWriteVoutCommand)
1252{
1253 // Test where works: Only required properties specified
1254 {
1255 const json element = R"(
1256 {
1257 "format": "linear"
1258 }
1259 )"_json;
1260 std::unique_ptr<PMBusWriteVoutCommandAction> action =
1261 parsePMBusWriteVoutCommand(element);
1262 EXPECT_EQ(action->getVolts().has_value(), false);
1263 EXPECT_EQ(action->getFormat(), pmbus_utils::VoutDataFormat::linear);
1264 EXPECT_EQ(action->getExponent().has_value(), false);
1265 EXPECT_EQ(action->isVerified(), false);
1266 }
1267
1268 // Test where works: All properties specified
1269 {
1270 const json element = R"(
1271 {
1272 "volts": 1.03,
1273 "format": "linear",
1274 "exponent": -8,
1275 "is_verified": true
1276 }
1277 )"_json;
1278 std::unique_ptr<PMBusWriteVoutCommandAction> action =
1279 parsePMBusWriteVoutCommand(element);
1280 EXPECT_EQ(action->getVolts().has_value(), true);
1281 EXPECT_EQ(action->getVolts().value(), 1.03);
1282 EXPECT_EQ(action->getFormat(), pmbus_utils::VoutDataFormat::linear);
1283 EXPECT_EQ(action->getExponent().has_value(), true);
1284 EXPECT_EQ(action->getExponent().value(), -8);
1285 EXPECT_EQ(action->isVerified(), true);
1286 }
1287
1288 // Test where fails: Element is not an object
1289 try
1290 {
1291 const json element = R"( [ "0xFF", "0x01" ] )"_json;
1292 parsePMBusWriteVoutCommand(element);
1293 ADD_FAILURE() << "Should not have reached this line.";
1294 }
1295 catch (const std::invalid_argument& e)
1296 {
1297 EXPECT_STREQ(e.what(), "Element is not an object");
1298 }
1299
1300 // Test where fails: volts value is invalid
1301 try
1302 {
1303 const json element = R"(
1304 {
1305 "volts": "foo",
1306 "format": "linear"
1307 }
1308 )"_json;
1309 parsePMBusWriteVoutCommand(element);
1310 ADD_FAILURE() << "Should not have reached this line.";
1311 }
1312 catch (const std::invalid_argument& e)
1313 {
1314 EXPECT_STREQ(e.what(), "Element is not a number");
1315 }
1316
1317 // Test where fails: Required format property not specified
1318 try
1319 {
1320 const json element = R"(
1321 {
1322 "volts": 1.03,
1323 "is_verified": true
1324 }
1325 )"_json;
1326 parsePMBusWriteVoutCommand(element);
1327 ADD_FAILURE() << "Should not have reached this line.";
1328 }
1329 catch (const std::invalid_argument& e)
1330 {
1331 EXPECT_STREQ(e.what(), "Required property missing: format");
1332 }
1333
1334 // Test where fails: format value is invalid
1335 try
1336 {
1337 const json element = R"(
1338 {
1339 "format": "linear_11"
1340 }
1341 )"_json;
1342 parsePMBusWriteVoutCommand(element);
1343 ADD_FAILURE() << "Should not have reached this line.";
1344 }
1345 catch (const std::invalid_argument& e)
1346 {
1347 EXPECT_STREQ(e.what(), "Invalid format value: linear_11");
1348 }
1349
1350 // Test where fails: exponent value is invalid
1351 try
1352 {
1353 const json element = R"(
1354 {
1355 "format": "linear",
1356 "exponent": 1.3
1357 }
1358 )"_json;
1359 parsePMBusWriteVoutCommand(element);
1360 ADD_FAILURE() << "Should not have reached this line.";
1361 }
1362 catch (const std::invalid_argument& e)
1363 {
1364 EXPECT_STREQ(e.what(), "Element is not an integer");
1365 }
1366
1367 // Test where fails: is_verified value is invalid
1368 try
1369 {
1370 const json element = R"(
1371 {
1372 "format": "linear",
1373 "is_verified": "true"
1374 }
1375 )"_json;
1376 parsePMBusWriteVoutCommand(element);
1377 ADD_FAILURE() << "Should not have reached this line.";
1378 }
1379 catch (const std::invalid_argument& e)
1380 {
1381 EXPECT_STREQ(e.what(), "Element is not a boolean");
1382 }
1383
1384 // Test where fails: Invalid property specified
1385 try
1386 {
1387 const json element = R"(
1388 {
1389 "format": "linear",
1390 "foo": "bar"
1391 }
1392 )"_json;
1393 parsePMBusWriteVoutCommand(element);
1394 ADD_FAILURE() << "Should not have reached this line.";
1395 }
1396 catch (const std::invalid_argument& e)
1397 {
1398 EXPECT_STREQ(e.what(), "Element contains an invalid property");
1399 }
1400}
1401
1402TEST(ConfigFileParserTests, ParseRoot)
1403{
1404 // Test where works: Only required properties specified
1405 {
1406 const json element = R"(
1407 {
1408 "chassis": [
1409 { "number": 1 }
1410 ]
1411 }
1412 )"_json;
1413 std::vector<std::unique_ptr<Rule>> rules{};
1414 std::vector<std::unique_ptr<Chassis>> chassis{};
1415 std::tie(rules, chassis) = parseRoot(element);
1416 EXPECT_EQ(rules.size(), 0);
1417 // TODO: Not implemented yet
1418 // EXPECT_EQ(chassis.size(), 1);
1419 }
1420
1421 // Test where works: All properties specified
1422 {
1423 const json element = R"(
1424 {
1425 "comments": [ "Config file for a FooBar one-chassis system" ],
1426 "rules": [
1427 {
1428 "id": "set_voltage_rule",
1429 "actions": [
1430 { "pmbus_write_vout_command": { "format": "linear" } }
1431 ]
1432 }
1433 ],
1434 "chassis": [
1435 { "number": 1 },
1436 { "number": 3 }
1437 ]
1438 }
1439 )"_json;
1440 std::vector<std::unique_ptr<Rule>> rules{};
1441 std::vector<std::unique_ptr<Chassis>> chassis{};
1442 std::tie(rules, chassis) = parseRoot(element);
1443 EXPECT_EQ(rules.size(), 1);
1444 // TODO: Not implemented yet
1445 // EXPECT_EQ(chassis.size(), 2);
1446 }
1447
1448 // Test where fails: Element is not an object
1449 try
1450 {
1451 const json element = R"( [ "0xFF", "0x01" ] )"_json;
1452 parseRoot(element);
1453 ADD_FAILURE() << "Should not have reached this line.";
1454 }
1455 catch (const std::invalid_argument& e)
1456 {
1457 EXPECT_STREQ(e.what(), "Element is not an object");
1458 }
1459
1460 // Test where fails: chassis property not specified
1461 try
1462 {
1463 const json element = R"(
1464 {
1465 "rules": [
1466 {
1467 "id": "set_voltage_rule",
1468 "actions": [
1469 { "pmbus_write_vout_command": { "format": "linear" } }
1470 ]
1471 }
1472 ]
1473 }
1474 )"_json;
1475 parseRoot(element);
1476 ADD_FAILURE() << "Should not have reached this line.";
1477 }
1478 catch (const std::invalid_argument& e)
1479 {
1480 EXPECT_STREQ(e.what(), "Required property missing: chassis");
1481 }
1482
1483 // Test where fails: Invalid property specified
1484 try
1485 {
1486 const json element = R"(
1487 {
1488 "remarks": [ "Config file for a FooBar one-chassis system" ],
1489 "chassis": [
1490 { "number": 1 }
1491 ]
1492 }
1493 )"_json;
1494 parseRoot(element);
1495 ADD_FAILURE() << "Should not have reached this line.";
1496 }
1497 catch (const std::invalid_argument& e)
1498 {
1499 EXPECT_STREQ(e.what(), "Element contains an invalid property");
1500 }
1501}
1502
1503TEST(ConfigFileParserTests, ParseRule)
1504{
1505 // Test where works: comments property specified
1506 {
1507 const json element = R"(
1508 {
1509 "comments": [ "Set voltage rule" ],
1510 "id": "set_voltage_rule",
1511 "actions": [
1512 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } },
1513 { "pmbus_write_vout_command": { "volts": 1.03, "format": "linear" } }
1514 ]
1515 }
1516 )"_json;
1517 std::unique_ptr<Rule> rule = parseRule(element);
1518 EXPECT_EQ(rule->getID(), "set_voltage_rule");
1519 EXPECT_EQ(rule->getActions().size(), 2);
1520 }
1521
1522 // Test where works: comments property not specified
1523 {
1524 const json element = R"(
1525 {
1526 "id": "set_voltage_rule",
1527 "actions": [
1528 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } },
1529 { "pmbus_write_vout_command": { "volts": 1.03, "format": "linear" } },
1530 { "pmbus_write_vout_command": { "volts": 1.05, "format": "linear" } }
1531 ]
1532 }
1533 )"_json;
1534 std::unique_ptr<Rule> rule = parseRule(element);
1535 EXPECT_EQ(rule->getID(), "set_voltage_rule");
1536 EXPECT_EQ(rule->getActions().size(), 3);
1537 }
1538
1539 // Test where fails: Element is not an object
1540 try
1541 {
1542 const json element = R"( [ "0xFF", "0x01" ] )"_json;
1543 parseRule(element);
1544 ADD_FAILURE() << "Should not have reached this line.";
1545 }
1546 catch (const std::invalid_argument& e)
1547 {
1548 EXPECT_STREQ(e.what(), "Element is not an object");
1549 }
1550
1551 // Test where fails: id property not specified
1552 try
1553 {
1554 const json element = R"(
1555 {
1556 "actions": [
1557 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } }
1558 ]
1559 }
1560 )"_json;
1561 parseRule(element);
1562 ADD_FAILURE() << "Should not have reached this line.";
1563 }
1564 catch (const std::invalid_argument& e)
1565 {
1566 EXPECT_STREQ(e.what(), "Required property missing: id");
1567 }
1568
1569 // Test where fails: id property is invalid
1570 try
1571 {
1572 const json element = R"(
1573 {
1574 "id": "",
1575 "actions": [
1576 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } }
1577 ]
1578 }
1579 )"_json;
1580 parseRule(element);
1581 ADD_FAILURE() << "Should not have reached this line.";
1582 }
1583 catch (const std::invalid_argument& e)
1584 {
1585 EXPECT_STREQ(e.what(), "Element contains an empty string");
1586 }
1587
1588 // Test where fails: actions property not specified
1589 try
1590 {
1591 const json element = R"(
1592 {
1593 "comments": [ "Set voltage rule" ],
1594 "id": "set_voltage_rule"
1595 }
1596 )"_json;
1597 parseRule(element);
1598 ADD_FAILURE() << "Should not have reached this line.";
1599 }
1600 catch (const std::invalid_argument& e)
1601 {
1602 EXPECT_STREQ(e.what(), "Required property missing: actions");
1603 }
1604
1605 // Test where fails: actions property is invalid
1606 try
1607 {
1608 const json element = R"(
1609 {
1610 "id": "set_voltage_rule",
1611 "actions": true
1612 }
1613 )"_json;
1614 parseRule(element);
1615 ADD_FAILURE() << "Should not have reached this line.";
1616 }
1617 catch (const std::invalid_argument& e)
1618 {
1619 EXPECT_STREQ(e.what(), "Element is not an array");
1620 }
1621
1622 // Test where fails: Invalid property specified
1623 try
1624 {
1625 const json element = R"(
1626 {
1627 "remarks": [ "Set voltage rule" ],
1628 "id": "set_voltage_rule",
1629 "actions": [
1630 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } }
1631 ]
1632 }
1633 )"_json;
1634 parseRule(element);
1635 ADD_FAILURE() << "Should not have reached this line.";
1636 }
1637 catch (const std::invalid_argument& e)
1638 {
1639 EXPECT_STREQ(e.what(), "Element contains an invalid property");
1640 }
1641}
1642
1643TEST(ConfigFileParserTests, ParseRuleArray)
1644{
1645 // Test where works
1646 {
1647 const json element = R"(
1648 [
1649 {
1650 "id": "set_voltage_rule1",
1651 "actions": [
1652 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } }
1653 ]
1654 },
1655 {
1656 "id": "set_voltage_rule2",
1657 "actions": [
1658 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } },
1659 { "pmbus_write_vout_command": { "volts": 1.11, "format": "linear" } }
1660 ]
1661 }
1662 ]
1663 )"_json;
1664 std::vector<std::unique_ptr<Rule>> rules = parseRuleArray(element);
1665 EXPECT_EQ(rules.size(), 2);
1666 EXPECT_EQ(rules[0]->getID(), "set_voltage_rule1");
1667 EXPECT_EQ(rules[0]->getActions().size(), 1);
1668 EXPECT_EQ(rules[1]->getID(), "set_voltage_rule2");
1669 EXPECT_EQ(rules[1]->getActions().size(), 2);
1670 }
1671
1672 // Test where fails: Element is not an array
1673 try
1674 {
1675 const json element = R"( { "id": "set_voltage_rule" } )"_json;
1676 parseRuleArray(element);
1677 ADD_FAILURE() << "Should not have reached this line.";
1678 }
1679 catch (const std::invalid_argument& e)
1680 {
1681 EXPECT_STREQ(e.what(), "Element is not an array");
1682 }
1683}
1684
Bob King315b0b62020-04-03 21:47:58 +08001685TEST(ConfigFileParserTests, ParseRunRule)
1686{
1687 // Test where works
1688 {
1689 const json element = "vdd_regulator";
1690 std::unique_ptr<RunRuleAction> action = parseRunRule(element);
1691 EXPECT_EQ(action->getRuleID(), "vdd_regulator");
1692 }
1693
1694 // Test where fails: Element is not a string
1695 try
1696 {
1697 const json element = 1;
1698 parseRunRule(element);
1699 ADD_FAILURE() << "Should not have reached this line.";
1700 }
1701 catch (const std::invalid_argument& e)
1702 {
1703 EXPECT_STREQ(e.what(), "Element is not a string");
1704 }
1705
1706 // Test where fails: Empty string
1707 try
1708 {
1709 const json element = "";
1710 parseRunRule(element);
1711 ADD_FAILURE() << "Should not have reached this line.";
1712 }
1713 catch (const std::invalid_argument& e)
1714 {
1715 EXPECT_STREQ(e.what(), "Element contains an empty string");
1716 }
1717}
1718
Shawn McCarney0e8c68a2020-03-27 01:44:48 -05001719TEST(ConfigFileParserTests, ParseString)
1720{
1721 // Test where works: Empty string
1722 {
1723 const json element = "";
1724 std::string value = parseString(element, true);
1725 EXPECT_EQ(value, "");
1726 }
1727
1728 // Test where works: Non-empty string
1729 {
1730 const json element = "vdd_regulator";
1731 std::string value = parseString(element, false);
1732 EXPECT_EQ(value, "vdd_regulator");
1733 }
1734
1735 // Test where fails: Element is not a string
1736 try
1737 {
1738 const json element = R"( { "foo": "bar" } )"_json;
1739 parseString(element);
1740 ADD_FAILURE() << "Should not have reached this line.";
1741 }
1742 catch (const std::invalid_argument& e)
1743 {
1744 EXPECT_STREQ(e.what(), "Element is not a string");
1745 }
1746
1747 // Test where fails: Empty string
1748 try
1749 {
1750 const json element = "";
1751 parseString(element);
1752 ADD_FAILURE() << "Should not have reached this line.";
1753 }
1754 catch (const std::invalid_argument& e)
1755 {
1756 EXPECT_STREQ(e.what(), "Element contains an empty string");
1757 }
1758}
1759
Bob Kingf617f892020-03-30 19:03:35 +08001760TEST(ConfigFileParserTests, ParseUint8)
1761{
1762 // Test where works: 0
1763 {
1764 const json element = R"( 0 )"_json;
1765 uint8_t value = parseUint8(element);
1766 EXPECT_EQ(value, 0);
1767 }
1768
1769 // Test where works: UINT8_MAX
1770 {
1771 const json element = R"( 255 )"_json;
1772 uint8_t value = parseUint8(element);
1773 EXPECT_EQ(value, 255);
1774 }
1775
1776 // Test where fails: Element is not an integer
1777 try
1778 {
1779 const json element = R"( 1.03 )"_json;
1780 parseUint8(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 an integer");
1786 }
1787
1788 // Test where fails: Value < 0
1789 try
1790 {
1791 const json element = R"( -1 )"_json;
1792 parseUint8(element);
1793 ADD_FAILURE() << "Should not have reached this line.";
1794 }
1795 catch (const std::invalid_argument& e)
1796 {
1797 EXPECT_STREQ(e.what(), "Element is not an 8-bit unsigned integer");
1798 }
1799
1800 // Test where fails: Value > UINT8_MAX
1801 try
1802 {
1803 const json element = R"( 256 )"_json;
1804 parseUint8(element);
1805 ADD_FAILURE() << "Should not have reached this line.";
1806 }
1807 catch (const std::invalid_argument& e)
1808 {
1809 EXPECT_STREQ(e.what(), "Element is not an 8-bit unsigned integer");
1810 }
1811}
1812
Shawn McCarney0e8c68a2020-03-27 01:44:48 -05001813TEST(ConfigFileParserTests, VerifyIsArray)
1814{
1815 // Test where element is an array
1816 try
1817 {
1818 const json element = R"( [ "foo", "bar" ] )"_json;
1819 verifyIsArray(element);
1820 }
1821 catch (const std::exception& e)
1822 {
1823 ADD_FAILURE() << "Should not have caught exception.";
1824 }
1825
1826 // Test where element is not an array
1827 try
1828 {
1829 const json element = R"( { "foo": "bar" } )"_json;
1830 verifyIsArray(element);
1831 ADD_FAILURE() << "Should not have reached this line.";
1832 }
1833 catch (const std::invalid_argument& e)
1834 {
1835 EXPECT_STREQ(e.what(), "Element is not an array");
1836 }
1837}
1838
1839TEST(ConfigFileParserTests, VerifyIsObject)
1840{
1841 // Test where element is an object
1842 try
1843 {
1844 const json element = R"( { "foo": "bar" } )"_json;
1845 verifyIsObject(element);
1846 }
1847 catch (const std::exception& e)
1848 {
1849 ADD_FAILURE() << "Should not have caught exception.";
1850 }
1851
1852 // Test where element is not an object
1853 try
1854 {
1855 const json element = R"( [ "foo", "bar" ] )"_json;
1856 verifyIsObject(element);
1857 ADD_FAILURE() << "Should not have reached this line.";
1858 }
1859 catch (const std::invalid_argument& e)
1860 {
1861 EXPECT_STREQ(e.what(), "Element is not an object");
1862 }
1863}
1864
1865TEST(ConfigFileParserTests, VerifyPropertyCount)
1866{
1867 // Test where element has expected number of properties
1868 try
1869 {
1870 const json element = R"(
1871 {
1872 "comments": [ "Set voltage rule" ],
1873 "id": "set_voltage_rule"
1874 }
1875 )"_json;
1876 verifyPropertyCount(element, 2);
1877 }
1878 catch (const std::exception& e)
1879 {
1880 ADD_FAILURE() << "Should not have caught exception.";
1881 }
1882
1883 // Test where element has unexpected number of properties
1884 try
1885 {
1886 const json element = R"(
1887 {
1888 "comments": [ "Set voltage rule" ],
1889 "id": "set_voltage_rule",
1890 "foo": 1.3
1891 }
1892 )"_json;
1893 verifyPropertyCount(element, 2);
1894 ADD_FAILURE() << "Should not have reached this line.";
1895 }
1896 catch (const std::invalid_argument& e)
1897 {
1898 EXPECT_STREQ(e.what(), "Element contains an invalid property");
1899 }
1900}