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