blob: 4dfc45eba50fd7dfdc5f8d36f561d4ad9c7372f1 [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"
Bob King3a787542020-04-14 13:45:01 +080017#include "and_action.hpp"
Shawn McCarney0e8c68a2020-03-27 01:44:48 -050018#include "chassis.hpp"
19#include "config_file_parser.hpp"
20#include "config_file_parser_error.hpp"
Bob King9c36c5f2020-04-06 11:34:09 +080021#include "configuration.hpp"
Bob King0e701132020-04-03 21:50:31 +080022#include "device.hpp"
Bob Kingf09bfe02020-04-13 17:21:15 +080023#include "i2c_compare_bit_action.hpp"
24#include "i2c_compare_byte_action.hpp"
25#include "i2c_compare_bytes_action.hpp"
Bob Kingf617f892020-03-30 19:03:35 +080026#include "i2c_interface.hpp"
27#include "i2c_write_bit_action.hpp"
Bob King87ff9d72020-03-31 14:02:55 +080028#include "i2c_write_byte_action.hpp"
Bob Kingbafcb862020-03-31 16:39:00 +080029#include "i2c_write_bytes_action.hpp"
Bob Kingf1b58dc2020-04-14 14:53:10 +080030#include "not_action.hpp"
Shawn McCarney0e8c68a2020-03-27 01:44:48 -050031#include "pmbus_utils.hpp"
32#include "pmbus_write_vout_command_action.hpp"
Bob King9c36c5f2020-04-06 11:34:09 +080033#include "presence_detection.hpp"
34#include "rail.hpp"
Shawn McCarney0e8c68a2020-03-27 01:44:48 -050035#include "rule.hpp"
Bob King315b0b62020-04-03 21:47:58 +080036#include "run_rule_action.hpp"
Bob Kinga2f2a0d2020-04-09 13:32:14 +080037#include "sensor_monitoring.hpp"
Shawn McCarney80c0b042020-03-27 12:08:53 -050038#include "tmp_file.hpp"
Shawn McCarney0e8c68a2020-03-27 01:44:48 -050039
Shawn McCarney80c0b042020-03-27 12:08:53 -050040#include <sys/stat.h> // for chmod()
Shawn McCarney0e8c68a2020-03-27 01:44:48 -050041
42#include <nlohmann/json.hpp>
43
44#include <cstdint>
45#include <cstring>
46#include <exception>
47#include <filesystem>
48#include <fstream>
49#include <memory>
50#include <optional>
51#include <stdexcept>
52#include <string>
53#include <tuple>
54#include <vector>
55
56#include <gtest/gtest.h>
57
58using namespace phosphor::power::regulators;
59using namespace phosphor::power::regulators::config_file_parser;
60using namespace phosphor::power::regulators::config_file_parser::internal;
61using json = nlohmann::json;
62
Shawn McCarney0e8c68a2020-03-27 01:44:48 -050063void writeConfigFile(const std::filesystem::path& pathName,
64 const std::string& contents)
65{
66 std::ofstream file{pathName};
67 file << contents;
68}
69
70void writeConfigFile(const std::filesystem::path& pathName,
71 const json& contents)
72{
73 std::ofstream file{pathName};
74 file << contents;
75}
76
77TEST(ConfigFileParserTests, Parse)
78{
79 // Test where works
80 {
81 const json configFileContents = R"(
82 {
83 "rules": [
84 {
85 "id": "set_voltage_rule1",
86 "actions": [
87 { "pmbus_write_vout_command": { "volts": 1.03, "format": "linear" } }
88 ]
89 },
90 {
91 "id": "set_voltage_rule2",
92 "actions": [
93 { "pmbus_write_vout_command": { "volts": 1.33, "format": "linear" } }
94 ]
95 }
96 ],
97 "chassis": [
98 { "number": 1 },
99 { "number": 2 },
100 { "number": 3 }
101 ]
102 }
103 )"_json;
104
105 TmpFile configFile;
106 std::filesystem::path pathName{configFile.getName()};
107 writeConfigFile(pathName, configFileContents);
108
109 std::vector<std::unique_ptr<Rule>> rules{};
110 std::vector<std::unique_ptr<Chassis>> chassis{};
111 std::tie(rules, chassis) = parse(pathName);
112
113 EXPECT_EQ(rules.size(), 2);
114 EXPECT_EQ(rules[0]->getID(), "set_voltage_rule1");
115 EXPECT_EQ(rules[1]->getID(), "set_voltage_rule2");
116
Bob King0e701132020-04-03 21:50:31 +0800117 EXPECT_EQ(chassis.size(), 3);
118 EXPECT_EQ(chassis[0]->getNumber(), 1);
119 EXPECT_EQ(chassis[1]->getNumber(), 2);
120 EXPECT_EQ(chassis[2]->getNumber(), 3);
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500121 }
122
123 // Test where fails: File does not exist
124 try
125 {
126 std::filesystem::path pathName{"/tmp/non_existent_file"};
127 parse(pathName);
128 ADD_FAILURE() << "Should not have reached this line.";
129 }
130 catch (const ConfigFileParserError& e)
131 {
132 // Expected exception; what() message will vary
133 }
134
135 // Test where fails: File is not readable
136 try
137 {
138 const json configFileContents = R"(
139 {
140 "chassis": [ { "number": 1 } ]
141 }
142 )"_json;
143
144 TmpFile configFile;
145 std::filesystem::path pathName{configFile.getName()};
146 writeConfigFile(pathName, configFileContents);
147
148 chmod(pathName.c_str(), 0222);
149
150 parse(pathName);
151 ADD_FAILURE() << "Should not have reached this line.";
152 }
153 catch (const ConfigFileParserError& e)
154 {
155 // Expected exception; what() message will vary
156 }
157
158 // Test where fails: File is not valid JSON
159 try
160 {
161 const std::string configFileContents = "] foo [";
162
163 TmpFile configFile;
164 std::filesystem::path pathName{configFile.getName()};
165 writeConfigFile(pathName, configFileContents);
166
167 parse(pathName);
168 ADD_FAILURE() << "Should not have reached this line.";
169 }
170 catch (const ConfigFileParserError& e)
171 {
172 // Expected exception; what() message will vary
173 }
174
175 // Test where fails: Error when parsing JSON elements
176 try
177 {
178 const json configFileContents = R"( { "foo": "bar" } )"_json;
179
180 TmpFile configFile;
181 std::filesystem::path pathName{configFile.getName()};
182 writeConfigFile(pathName, configFileContents);
183
184 parse(pathName);
185 ADD_FAILURE() << "Should not have reached this line.";
186 }
187 catch (const ConfigFileParserError& e)
188 {
189 // Expected exception; what() message will vary
190 }
191}
192
193TEST(ConfigFileParserTests, GetRequiredProperty)
194{
195 // Test where property exists
196 {
197 const json element = R"( { "format": "linear" } )"_json;
198 const json& propertyElement = getRequiredProperty(element, "format");
199 EXPECT_EQ(propertyElement.get<std::string>(), "linear");
200 }
201
202 // Test where property does not exist
203 try
204 {
205 const json element = R"( { "volts": 1.03 } )"_json;
206 getRequiredProperty(element, "format");
207 ADD_FAILURE() << "Should not have reached this line.";
208 }
209 catch (const std::invalid_argument& e)
210 {
211 EXPECT_STREQ(e.what(), "Required property missing: format");
212 }
213}
214
215TEST(ConfigFileParserTests, ParseAction)
216{
217 // Test where works: comments property specified
218 {
219 const json element = R"(
220 {
221 "comments": [ "Set output voltage." ],
222 "pmbus_write_vout_command": {
223 "format": "linear"
224 }
225 }
226 )"_json;
227 std::unique_ptr<Action> action = parseAction(element);
228 EXPECT_NE(action.get(), nullptr);
229 }
230
231 // Test where works: comments property not specified
232 {
233 const json element = R"(
234 {
235 "pmbus_write_vout_command": {
236 "format": "linear"
237 }
238 }
239 )"_json;
240 std::unique_ptr<Action> action = parseAction(element);
241 EXPECT_NE(action.get(), nullptr);
242 }
243
244 // Test where works: and action type specified
Bob King3a787542020-04-14 13:45:01 +0800245 {
246 const json element = R"(
247 {
248 "and": [
249 { "i2c_compare_byte": { "register": "0xA0", "value": "0x00" } },
250 { "i2c_compare_byte": { "register": "0xA1", "value": "0x00" } }
251 ]
252 }
253 )"_json;
254 std::unique_ptr<Action> action = parseAction(element);
255 EXPECT_NE(action.get(), nullptr);
256 }
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500257
258 // Test where works: compare_presence action type specified
259 // TODO: Not implemented yet
260
261 // Test where works: compare_vpd action type specified
262 // TODO: Not implemented yet
263
264 // Test where works: i2c_compare_bit action type specified
Bob Kingf09bfe02020-04-13 17:21:15 +0800265 {
266 const json element = R"(
267 {
268 "i2c_compare_bit": {
269 "register": "0xA0",
270 "position": 3,
271 "value": 0
272 }
273 }
274 )"_json;
275 std::unique_ptr<Action> action = parseAction(element);
276 EXPECT_NE(action.get(), nullptr);
277 }
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500278
279 // Test where works: i2c_compare_byte action type specified
Bob Kingf09bfe02020-04-13 17:21:15 +0800280 {
281 const json element = R"(
282 {
283 "i2c_compare_byte": {
284 "register": "0x0A",
285 "value": "0xCC"
286 }
287 }
288 )"_json;
289 std::unique_ptr<Action> action = parseAction(element);
290 EXPECT_NE(action.get(), nullptr);
291 }
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500292
293 // Test where works: i2c_compare_bytes action type specified
Bob Kingf09bfe02020-04-13 17:21:15 +0800294 {
295 const json element = R"(
296 {
297 "i2c_compare_bytes": {
298 "register": "0x0A",
299 "values": [ "0xCC", "0xFF" ]
300 }
301 }
302 )"_json;
303 std::unique_ptr<Action> action = parseAction(element);
304 EXPECT_NE(action.get(), nullptr);
305 }
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500306
307 // Test where works: i2c_write_bit action type specified
Bob Kingf617f892020-03-30 19:03:35 +0800308 {
309 const json element = R"(
310 {
311 "i2c_write_bit": {
312 "register": "0xA0",
313 "position": 3,
314 "value": 0
315 }
316 }
317 )"_json;
318 std::unique_ptr<Action> action = parseAction(element);
319 EXPECT_NE(action.get(), nullptr);
320 }
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500321
322 // Test where works: i2c_write_byte action type specified
Bob King87ff9d72020-03-31 14:02:55 +0800323 {
324 const json element = R"(
325 {
326 "i2c_write_byte": {
327 "register": "0x0A",
328 "value": "0xCC"
329 }
330 }
331 )"_json;
332 std::unique_ptr<Action> action = parseAction(element);
333 EXPECT_NE(action.get(), nullptr);
334 }
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500335
336 // Test where works: i2c_write_bytes action type specified
Bob Kingbafcb862020-03-31 16:39:00 +0800337 {
338 const json element = R"(
339 {
340 "i2c_write_bytes": {
341 "register": "0x0A",
342 "values": [ "0xCC", "0xFF" ]
343 }
344 }
345 )"_json;
346 std::unique_ptr<Action> action = parseAction(element);
347 EXPECT_NE(action.get(), nullptr);
348 }
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500349
350 // Test where works: if action type specified
351 // TODO: Not implemented yet
352
353 // Test where works: not action type specified
Bob Kingf1b58dc2020-04-14 14:53:10 +0800354 {
355 const json element = R"(
356 {
357 "not":
358 { "i2c_compare_byte": { "register": "0xA0", "value": "0xFF" } }
359 }
360 )"_json;
361 std::unique_ptr<Action> action = parseAction(element);
362 EXPECT_NE(action.get(), nullptr);
363 }
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500364
365 // Test where works: or action type specified
366 // TODO: Not implemented yet
367
368 // Test where works: pmbus_read_sensor action type specified
369 // TODO: Not implemented yet
370
371 // Test where works: pmbus_write_vout_command action type specified
372 {
373 const json element = R"(
374 {
375 "pmbus_write_vout_command": {
376 "format": "linear"
377 }
378 }
379 )"_json;
380 std::unique_ptr<Action> action = parseAction(element);
381 EXPECT_NE(action.get(), nullptr);
382 }
383
384 // Test where works: run_rule action type specified
Bob King315b0b62020-04-03 21:47:58 +0800385 {
386 const json element = R"(
387 {
388 "run_rule": "set_voltage_rule"
389 }
390 )"_json;
391 std::unique_ptr<Action> action = parseAction(element);
392 EXPECT_NE(action.get(), nullptr);
393 }
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500394
395 // Test where works: set_device action type specified
396 // TODO: Not implemented yet
397
398 // Test where fails: Element is not an object
399 try
400 {
401 const json element = R"( [ "0xFF", "0x01" ] )"_json;
402 parseAction(element);
403 ADD_FAILURE() << "Should not have reached this line.";
404 }
405 catch (const std::invalid_argument& e)
406 {
407 EXPECT_STREQ(e.what(), "Element is not an object");
408 }
409
410 // Test where fails: No action type specified
411 try
412 {
413 const json element = R"(
414 {
415 "comments": [ "Set output voltage." ]
416 }
417 )"_json;
418 parseAction(element);
419 ADD_FAILURE() << "Should not have reached this line.";
420 }
421 catch (const std::invalid_argument& e)
422 {
423 EXPECT_STREQ(e.what(), "Required action type property missing");
424 }
425
426 // Test where fails: Multiple action types specified
Bob King0e701132020-04-03 21:50:31 +0800427 try
428 {
429 const json element = R"(
430 {
431 "pmbus_write_vout_command": { "format": "linear" },
432 "run_rule": "set_voltage_rule"
433 }
434 )"_json;
435 parseAction(element);
436 ADD_FAILURE() << "Should not have reached this line.";
437 }
438 catch (const std::invalid_argument& e)
439 {
440 EXPECT_STREQ(e.what(), "Element contains an invalid property");
441 }
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500442
443 // Test where fails: Invalid property specified
444 try
445 {
446 const json element = R"(
447 {
448 "remarks": [ "Set output voltage." ],
449 "pmbus_write_vout_command": {
450 "format": "linear"
451 }
452 }
453 )"_json;
454 parseAction(element);
455 ADD_FAILURE() << "Should not have reached this line.";
456 }
457 catch (const std::invalid_argument& e)
458 {
459 EXPECT_STREQ(e.what(), "Element contains an invalid property");
460 }
461}
462
463TEST(ConfigFileParserTests, ParseActionArray)
464{
465 // Test where works
466 {
467 const json element = R"(
468 [
469 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } },
470 { "pmbus_write_vout_command": { "volts": 1.03, "format": "linear" } }
471 ]
472 )"_json;
473 std::vector<std::unique_ptr<Action>> actions =
474 parseActionArray(element);
475 EXPECT_EQ(actions.size(), 2);
476 }
477
478 // Test where fails: Element is not an array
479 try
480 {
481 const json element = R"(
482 {
483 "foo": "bar"
484 }
485 )"_json;
486 parseActionArray(element);
487 ADD_FAILURE() << "Should not have reached this line.";
488 }
489 catch (const std::invalid_argument& e)
490 {
491 EXPECT_STREQ(e.what(), "Element is not an array");
492 }
493}
494
Bob King3a787542020-04-14 13:45:01 +0800495TEST(ConfigFileParserTests, ParseAnd)
496{
497 // Test where works: Element is an array with 2 actions
498 {
499 const json element = R"(
500 [
501 { "i2c_compare_byte": { "register": "0xA0", "value": "0x00" } },
502 { "i2c_compare_byte": { "register": "0xA1", "value": "0x00" } }
503 ]
504 )"_json;
505 std::unique_ptr<AndAction> action = parseAnd(element);
506 EXPECT_EQ(action->getActions().size(), 2);
507 }
508
509 // Test where fails: Element is an array with 1 action
510 try
511 {
512 const json element = R"(
513 [
514 { "i2c_compare_byte": { "register": "0xA0", "value": "0x00" } }
515 ]
516 )"_json;
517 parseAnd(element);
518 ADD_FAILURE() << "Should not have reached this line.";
519 }
520 catch (const std::invalid_argument& e)
521 {
522 EXPECT_STREQ(e.what(), "Array must contain two or more actions");
523 }
524
525 // Test where fails: Element is not an array
526 try
527 {
528 const json element = R"(
529 {
530 "foo": "bar"
531 }
532 )"_json;
533 parseAnd(element);
534 ADD_FAILURE() << "Should not have reached this line.";
535 }
536 catch (const std::invalid_argument& e)
537 {
538 EXPECT_STREQ(e.what(), "Element is not an array");
539 }
540}
541
Bob Kingf617f892020-03-30 19:03:35 +0800542TEST(ConfigFileParserTests, ParseBitPosition)
543{
544 // Test where works: 0
545 {
546 const json element = R"( 0 )"_json;
547 uint8_t value = parseBitPosition(element);
548 EXPECT_EQ(value, 0);
549 }
550
551 // Test where works: 7
552 {
553 const json element = R"( 7 )"_json;
554 uint8_t value = parseBitPosition(element);
555 EXPECT_EQ(value, 7);
556 }
557
558 // Test where fails: Element is not an integer
559 try
560 {
561 const json element = R"( 1.03 )"_json;
562 parseBitPosition(element);
563 ADD_FAILURE() << "Should not have reached this line.";
564 }
565 catch (const std::invalid_argument& e)
566 {
567 EXPECT_STREQ(e.what(), "Element is not an integer");
568 }
569
570 // Test where fails: Value < 0
571 try
572 {
573 const json element = R"( -1 )"_json;
574 parseBitPosition(element);
575 ADD_FAILURE() << "Should not have reached this line.";
576 }
577 catch (const std::invalid_argument& e)
578 {
579 EXPECT_STREQ(e.what(), "Element is not a bit position");
580 }
581
582 // Test where fails: Value > 7
583 try
584 {
585 const json element = R"( 8 )"_json;
586 parseBitPosition(element);
587 ADD_FAILURE() << "Should not have reached this line.";
588 }
589 catch (const std::invalid_argument& e)
590 {
591 EXPECT_STREQ(e.what(), "Element is not a bit position");
592 }
593}
594
595TEST(ConfigFileParserTests, ParseBitValue)
596{
597 // Test where works: 0
598 {
599 const json element = R"( 0 )"_json;
600 uint8_t value = parseBitValue(element);
601 EXPECT_EQ(value, 0);
602 }
603
604 // Test where works: 1
605 {
606 const json element = R"( 1 )"_json;
607 uint8_t value = parseBitValue(element);
608 EXPECT_EQ(value, 1);
609 }
610
611 // Test where fails: Element is not an integer
612 try
613 {
614 const json element = R"( 0.5 )"_json;
615 parseBitValue(element);
616 ADD_FAILURE() << "Should not have reached this line.";
617 }
618 catch (const std::invalid_argument& e)
619 {
620 EXPECT_STREQ(e.what(), "Element is not an integer");
621 }
622
623 // Test where fails: Value < 0
624 try
625 {
626 const json element = R"( -1 )"_json;
627 parseBitValue(element);
628 ADD_FAILURE() << "Should not have reached this line.";
629 }
630 catch (const std::invalid_argument& e)
631 {
632 EXPECT_STREQ(e.what(), "Element is not a bit value");
633 }
634
635 // Test where fails: Value > 1
636 try
637 {
638 const json element = R"( 2 )"_json;
639 parseBitValue(element);
640 ADD_FAILURE() << "Should not have reached this line.";
641 }
642 catch (const std::invalid_argument& e)
643 {
644 EXPECT_STREQ(e.what(), "Element is not a bit value");
645 }
646}
647
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500648TEST(ConfigFileParserTests, ParseBoolean)
649{
650 // Test where works: true
651 {
652 const json element = R"( true )"_json;
653 bool value = parseBoolean(element);
654 EXPECT_EQ(value, true);
655 }
656
657 // Test where works: false
658 {
659 const json element = R"( false )"_json;
660 bool value = parseBoolean(element);
661 EXPECT_EQ(value, false);
662 }
663
664 // Test where fails: Element is not a boolean
665 try
666 {
667 const json element = R"( 1 )"_json;
668 parseBoolean(element);
669 ADD_FAILURE() << "Should not have reached this line.";
670 }
671 catch (const std::invalid_argument& e)
672 {
673 EXPECT_STREQ(e.what(), "Element is not a boolean");
674 }
675}
676
Bob King0e701132020-04-03 21:50:31 +0800677TEST(ConfigFileParserTests, ParseChassis)
678{
679 // Test where works: Only required properties specified
680 {
681 const json element = R"(
682 {
683 "number": 1
684 }
685 )"_json;
686 std::unique_ptr<Chassis> chassis = parseChassis(element);
687 EXPECT_EQ(chassis->getNumber(), 1);
Bob King9c36c5f2020-04-06 11:34:09 +0800688 EXPECT_EQ(chassis->getDevices().size(), 0);
Bob King0e701132020-04-03 21:50:31 +0800689 }
690
691 // Test where works: All properties specified
692 {
693 const json element = R"(
694 {
695 "comments": [ "comments property" ],
696 "number": 2,
697 "devices": [
698 {
699 "id": "vdd_regulator",
700 "is_regulator": true,
701 "fru": "/system/chassis/motherboard/regulator2",
702 "i2c_interface":
703 {
704 "bus": 1,
705 "address": "0x70"
706 }
707 }
708 ]
709 }
710 )"_json;
711 std::unique_ptr<Chassis> chassis = parseChassis(element);
712 EXPECT_EQ(chassis->getNumber(), 2);
Bob King9c36c5f2020-04-06 11:34:09 +0800713 EXPECT_EQ(chassis->getDevices().size(), 1);
714 EXPECT_EQ(chassis->getDevices()[0]->getID(), "vdd_regulator");
Bob King0e701132020-04-03 21:50:31 +0800715 }
716
717 // Test where fails: number value is invalid
718 try
719 {
720 const json element = R"(
721 {
722 "number": 0.5
723 }
724 )"_json;
725 parseChassis(element);
726 ADD_FAILURE() << "Should not have reached this line.";
727 }
728 catch (const std::invalid_argument& e)
729 {
730 EXPECT_STREQ(e.what(), "Element is not an unsigned integer");
731 }
732
733 // Test where fails: Invalid property specified
734 try
735 {
736 const json element = R"(
737 {
738 "number": 1,
739 "foo": 2
740 }
741 )"_json;
742 parseChassis(element);
743 ADD_FAILURE() << "Should not have reached this line.";
744 }
745 catch (const std::invalid_argument& e)
746 {
747 EXPECT_STREQ(e.what(), "Element contains an invalid property");
748 }
749
750 // Test where fails: Required number property not specified
751 try
752 {
753 const json element = R"(
754 {
755 "devices": [
756 {
757 "id": "vdd_regulator",
758 "is_regulator": true,
759 "fru": "/system/chassis/motherboard/regulator2",
760 "i2c_interface":
761 {
762 "bus": 1,
763 "address": "0x70"
764 }
765 }
766 ]
767 }
768 )"_json;
769 parseChassis(element);
770 ADD_FAILURE() << "Should not have reached this line.";
771 }
772 catch (const std::invalid_argument& e)
773 {
774 EXPECT_STREQ(e.what(), "Required property missing: number");
775 }
776
777 // Test where fails: Element is not an object
778 try
779 {
780 const json element = R"( [ "0xFF", "0x01" ] )"_json;
781 parseChassis(element);
782 ADD_FAILURE() << "Should not have reached this line.";
783 }
784 catch (const std::invalid_argument& e)
785 {
786 EXPECT_STREQ(e.what(), "Element is not an object");
787 }
788
789 // Test where fails: number value is < 1
790 try
791 {
792 const json element = R"(
793 {
794 "number": 0
795 }
796 )"_json;
797 parseChassis(element);
798 ADD_FAILURE() << "Should not have reached this line.";
799 }
800 catch (const std::invalid_argument& e)
801 {
802 EXPECT_STREQ(e.what(), "Invalid chassis number: Must be > 0");
803 }
804
805 // Test where fails: devices value is invalid
806 try
807 {
808 const json element = R"(
809 {
810 "number": 1,
811 "devices": 2
812 }
813 )"_json;
814 parseChassis(element);
815 ADD_FAILURE() << "Should not have reached this line.";
816 }
817 catch (const std::invalid_argument& e)
818 {
819 EXPECT_STREQ(e.what(), "Element is not an array");
820 }
821}
822
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500823TEST(ConfigFileParserTests, ParseChassisArray)
824{
Bob King0e701132020-04-03 21:50:31 +0800825 // Test where works
826 {
827 const json element = R"(
828 [
829 { "number": 1 },
830 { "number": 2 }
831 ]
832 )"_json;
833 std::vector<std::unique_ptr<Chassis>> chassis =
834 parseChassisArray(element);
835 EXPECT_EQ(chassis.size(), 2);
836 EXPECT_EQ(chassis[0]->getNumber(), 1);
837 EXPECT_EQ(chassis[1]->getNumber(), 2);
838 }
839
840 // Test where fails: Element is not an array
841 try
842 {
843 const json element = R"(
844 {
845 "foo": "bar"
846 }
847 )"_json;
848 parseChassisArray(element);
849 ADD_FAILURE() << "Should not have reached this line.";
850 }
851 catch (const std::invalid_argument& e)
852 {
853 EXPECT_STREQ(e.what(), "Element is not an array");
854 }
Shawn McCarney0e8c68a2020-03-27 01:44:48 -0500855}
856
Bob King33e7eaa2020-04-01 18:09:34 +0800857TEST(ConfigFileParserTests, ParseConfiguration)
858{
859 // Test where works: actions required property specified
860 {
861 const json element = R"(
862 {
863 "actions": [
864 {
865 "pmbus_write_vout_command": {
866 "format": "linear"
867 }
868 }
869 ]
870 }
871 )"_json;
872 std::unique_ptr<Configuration> configuration =
873 parseConfiguration(element);
874 EXPECT_EQ(configuration->getActions().size(), 1);
875 EXPECT_EQ(configuration->getVolts().has_value(), false);
876 }
877
878 // Test where works: volts and actions properties specified
879 {
880 const json element = R"(
881 {
882 "comments": [ "comments property" ],
883 "volts": 1.03,
884 "actions": [
885 { "pmbus_write_vout_command": { "format": "linear" } },
886 { "run_rule": "set_voltage_rule" }
887 ]
888 }
889 )"_json;
890 std::unique_ptr<Configuration> configuration =
891 parseConfiguration(element);
892 EXPECT_EQ(configuration->getVolts().has_value(), true);
893 EXPECT_EQ(configuration->getVolts().value(), 1.03);
894 EXPECT_EQ(configuration->getActions().size(), 2);
895 }
896
897 // Test where works: volts and rule_id properties specified
898 {
899 const json element = R"(
900 {
901 "volts": 1.05,
902 "rule_id": "set_voltage_rule"
903 }
904 )"_json;
905 std::unique_ptr<Configuration> configuration =
906 parseConfiguration(element);
907 EXPECT_EQ(configuration->getVolts().has_value(), true);
908 EXPECT_EQ(configuration->getVolts().value(), 1.05);
909 EXPECT_EQ(configuration->getActions().size(), 1);
910 }
911
912 // Test where fails: volts value is invalid
913 try
914 {
915 const json element = R"(
916 {
917 "volts": "foo",
918 "actions": [
919 {
920 "pmbus_write_vout_command": {
921 "format": "linear"
922 }
923 }
924 ]
925 }
926 )"_json;
927 parseConfiguration(element);
928 ADD_FAILURE() << "Should not have reached this line.";
929 }
930 catch (const std::invalid_argument& e)
931 {
932 EXPECT_STREQ(e.what(), "Element is not a number");
933 }
934
935 // Test where fails: actions object is invalid
936 try
937 {
938 const json element = R"(
939 {
940 "volts": 1.03,
941 "actions": 1
942 }
943 )"_json;
944 parseConfiguration(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 an array");
950 }
951
952 // Test where fails: rule_id value is invalid
953 try
954 {
955 const json element = R"(
956 {
957 "volts": 1.05,
958 "rule_id": 1
959 }
960 )"_json;
961 parseConfiguration(element);
962 ADD_FAILURE() << "Should not have reached this line.";
963 }
964 catch (const std::invalid_argument& e)
965 {
966 EXPECT_STREQ(e.what(), "Element is not a string");
967 }
968
969 // Test where fails: Required actions or rule_id property not specified
970 try
971 {
972 const json element = R"(
973 {
974 "volts": 1.03
975 }
976 )"_json;
977 parseConfiguration(element);
978 ADD_FAILURE() << "Should not have reached this line.";
979 }
980 catch (const std::invalid_argument& e)
981 {
982 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain "
983 "either rule_id or actions");
984 }
985
986 // Test where fails: Required actions or rule_id property both specified
987 try
988 {
989 const json element = R"(
990 {
991 "volts": 1.03,
992 "rule_id": "set_voltage_rule",
993 "actions": [
994 {
995 "pmbus_write_vout_command": {
996 "format": "linear"
997 }
998 }
999 ]
1000 }
1001 )"_json;
1002 parseConfiguration(element);
1003 ADD_FAILURE() << "Should not have reached this line.";
1004 }
1005 catch (const std::invalid_argument& e)
1006 {
1007 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain "
1008 "either rule_id or actions");
1009 }
1010
1011 // Test where fails: Element is not an object
1012 try
1013 {
1014 const json element = R"( [ "0xFF", "0x01" ] )"_json;
1015 parseConfiguration(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 object");
1021 }
1022
1023 // Test where fails: Invalid property specified
1024 try
1025 {
1026 const json element = R"(
1027 {
1028 "volts": 1.03,
1029 "rule_id": "set_voltage_rule",
1030 "foo": 1
1031 }
1032 )"_json;
1033 parseConfiguration(element);
1034 ADD_FAILURE() << "Should not have reached this line.";
1035 }
1036 catch (const std::invalid_argument& e)
1037 {
1038 EXPECT_STREQ(e.what(), "Element contains an invalid property");
1039 }
1040}
1041
Bob King9c36c5f2020-04-06 11:34:09 +08001042TEST(ConfigFileParserTests, ParseDevice)
1043{
1044 // Test where works: Only required properties specified
1045 {
1046 const json element = R"(
1047 {
1048 "id": "vdd_regulator",
1049 "is_regulator": true,
1050 "fru": "/system/chassis/motherboard/regulator2",
1051 "i2c_interface": { "bus": 1, "address": "0x70" }
1052 }
1053 )"_json;
1054 std::unique_ptr<Device> device = parseDevice(element);
1055 EXPECT_EQ(device->getID(), "vdd_regulator");
1056 EXPECT_EQ(device->isRegulator(), true);
1057 EXPECT_EQ(device->getFRU(), "/system/chassis/motherboard/regulator2");
1058 EXPECT_NE(&(device->getI2CInterface()), nullptr);
1059 EXPECT_EQ(device->getPresenceDetection(), nullptr);
1060 EXPECT_EQ(device->getConfiguration(), nullptr);
1061 EXPECT_EQ(device->getRails().size(), 0);
1062 }
1063
1064 // Test where works: All properties specified
Bob King33e7eaa2020-04-01 18:09:34 +08001065 {
Bob Kinga2f2a0d2020-04-09 13:32:14 +08001066 // TODO : add presence_detection property
Bob King33e7eaa2020-04-01 18:09:34 +08001067 const json element = R"(
1068 {
1069 "id": "vdd_regulator",
1070 "is_regulator": true,
1071 "fru": "/system/chassis/motherboard/regulator2",
1072 "i2c_interface":
1073 {
1074 "bus": 1,
1075 "address": "0x70"
1076 },
1077 "configuration":
1078 {
1079 "rule_id": "configure_ir35221_rule"
Bob Kinga2f2a0d2020-04-09 13:32:14 +08001080 },
1081 "rails":
1082 [
1083 {
1084 "id": "vdd"
1085 }
1086 ]
Bob King33e7eaa2020-04-01 18:09:34 +08001087 }
1088 )"_json;
1089 std::unique_ptr<Device> device = parseDevice(element);
1090 EXPECT_EQ(device->getID(), "vdd_regulator");
1091 EXPECT_EQ(device->isRegulator(), true);
1092 EXPECT_EQ(device->getFRU(), "/system/chassis/motherboard/regulator2");
1093 EXPECT_NE(&(device->getI2CInterface()), nullptr);
1094 // EXPECT_NE(device->getPresenceDetection(), nullptr);
1095 EXPECT_NE(device->getConfiguration(), nullptr);
Bob Kinga2f2a0d2020-04-09 13:32:14 +08001096 EXPECT_EQ(device->getRails().size(), 1);
1097 }
1098
1099 // Test where fails: rails property exists and is_regulator is false
1100 try
1101 {
1102 const json element = R"(
1103 {
1104 "id": "vdd_regulator",
1105 "is_regulator": false,
1106 "fru": "/system/chassis/motherboard/regulator2",
1107 "i2c_interface":
1108 {
1109 "bus": 1,
1110 "address": "0x70"
1111 },
1112 "configuration":
1113 {
1114 "rule_id": "configure_ir35221_rule"
1115 },
1116 "rails":
1117 [
1118 {
1119 "id": "vdd"
1120 }
1121 ]
1122 }
1123 )"_json;
1124 parseDevice(element);
1125 ADD_FAILURE() << "Should not have reached this line.";
1126 }
1127 catch (const std::invalid_argument& e)
1128 {
1129 EXPECT_STREQ(e.what(),
1130 "Invalid rails property when is_regulator is false");
Bob King33e7eaa2020-04-01 18:09:34 +08001131 }
Bob King9c36c5f2020-04-06 11:34:09 +08001132
1133 // Test where fails: id value is invalid
1134 try
1135 {
1136 const json element = R"(
1137 {
1138 "id": 3,
1139 "is_regulator": true,
1140 "fru": "/system/chassis/motherboard/regulator2",
1141 "i2c_interface":
1142 {
1143 "bus": 1,
1144 "address": "0x70"
1145 }
1146 }
1147 )"_json;
1148 parseDevice(element);
1149 ADD_FAILURE() << "Should not have reached this line.";
1150 }
1151 catch (const std::invalid_argument& e)
1152 {
1153 EXPECT_STREQ(e.what(), "Element is not a string");
1154 }
1155
1156 // Test where fails: is_regulator value is invalid
1157 try
1158 {
1159 const json element = R"(
1160 {
1161 "id": "vdd_regulator",
1162 "is_regulator": 3,
1163 "fru": "/system/chassis/motherboard/regulator2",
1164 "i2c_interface":
1165 {
1166 "bus": 1,
1167 "address": "0x70"
1168 }
1169 }
1170 )"_json;
1171 parseDevice(element);
1172 ADD_FAILURE() << "Should not have reached this line.";
1173 }
1174 catch (const std::invalid_argument& e)
1175 {
1176 EXPECT_STREQ(e.what(), "Element is not a boolean");
1177 }
1178
1179 // Test where fails: fru value is invalid
1180 try
1181 {
1182 const json element = R"(
1183 {
1184 "id": "vdd_regulator",
1185 "is_regulator": true,
1186 "fru": 2,
1187 "i2c_interface":
1188 {
1189 "bus": 1,
1190 "address": "0x70"
1191 }
1192 }
1193 )"_json;
1194 parseDevice(element);
1195 ADD_FAILURE() << "Should not have reached this line.";
1196 }
1197 catch (const std::invalid_argument& e)
1198 {
1199 EXPECT_STREQ(e.what(), "Element is not a string");
1200 }
1201
1202 // Test where fails: i2c_interface value is invalid
1203 try
1204 {
1205 const json element = R"(
1206 {
1207 "id": "vdd_regulator",
1208 "is_regulator": true,
1209 "fru": "/system/chassis/motherboard/regulator2",
1210 "i2c_interface": 3
1211 }
1212 )"_json;
1213 parseDevice(element);
1214 ADD_FAILURE() << "Should not have reached this line.";
1215 }
1216 catch (const std::invalid_argument& e)
1217 {
1218 EXPECT_STREQ(e.what(), "Element is not an object");
1219 }
1220
1221 // Test where fails: Required id property not specified
1222 try
1223 {
1224 const json element = R"(
1225 {
1226 "is_regulator": true,
1227 "fru": "/system/chassis/motherboard/regulator2",
1228 "i2c_interface":
1229 {
1230 "bus": 1,
1231 "address": "0x70"
1232 }
1233 }
1234 )"_json;
1235 parseDevice(element);
1236 ADD_FAILURE() << "Should not have reached this line.";
1237 }
1238 catch (const std::invalid_argument& e)
1239 {
1240 EXPECT_STREQ(e.what(), "Required property missing: id");
1241 }
1242
1243 // Test where fails: Required is_regulator property not specified
1244 try
1245 {
1246 const json element = R"(
1247 {
1248 "id": "vdd_regulator",
1249 "fru": "/system/chassis/motherboard/regulator2",
1250 "i2c_interface":
1251 {
1252 "bus": 1,
1253 "address": "0x70"
1254 }
1255 }
1256 )"_json;
1257 parseDevice(element);
1258 ADD_FAILURE() << "Should not have reached this line.";
1259 }
1260 catch (const std::invalid_argument& e)
1261 {
1262 EXPECT_STREQ(e.what(), "Required property missing: is_regulator");
1263 }
1264
1265 // Test where fails: Required fru property not specified
1266 try
1267 {
1268 const json element = R"(
1269 {
1270 "id": "vdd_regulator",
1271 "is_regulator": true,
1272 "i2c_interface":
1273 {
1274 "bus": 1,
1275 "address": "0x70"
1276 }
1277 }
1278 )"_json;
1279 parseDevice(element);
1280 ADD_FAILURE() << "Should not have reached this line.";
1281 }
1282 catch (const std::invalid_argument& e)
1283 {
1284 EXPECT_STREQ(e.what(), "Required property missing: fru");
1285 }
1286
1287 // Test where fails: Required i2c_interface property not specified
1288 try
1289 {
1290 const json element = R"(
1291 {
1292 "id": "vdd_regulator",
1293 "is_regulator": true,
1294 "fru": "/system/chassis/motherboard/regulator2"
1295 }
1296 )"_json;
1297 parseDevice(element);
1298 ADD_FAILURE() << "Should not have reached this line.";
1299 }
1300 catch (const std::invalid_argument& e)
1301 {
1302 EXPECT_STREQ(e.what(), "Required property missing: i2c_interface");
1303 }
1304
1305 // Test where fails: Element is not an object
1306 try
1307 {
1308 const json element = R"( [ "0xFF", "0x01" ] )"_json;
1309 parseDevice(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 an object");
1315 }
1316
1317 // Test where fails: Invalid property specified
1318 try
1319 {
1320 const json element = R"(
1321 {
1322 "id": "vdd_regulator",
1323 "is_regulator": true,
1324 "fru": "/system/chassis/motherboard/regulator2",
1325 "i2c_interface": { "bus": 1, "address": "0x70" },
1326 "foo" : true
1327 }
1328 )"_json;
1329 parseDevice(element);
1330 ADD_FAILURE() << "Should not have reached this line.";
1331 }
1332 catch (const std::invalid_argument& e)
1333 {
1334 EXPECT_STREQ(e.what(), "Element contains an invalid property");
1335 }
1336}
1337
1338TEST(ConfigFileParserTests, ParseDeviceArray)
1339{
1340 // Test where works
1341 {
1342 const json element = R"(
1343 [
1344 {
1345 "id": "vdd_regulator",
1346 "is_regulator": true,
1347 "fru": "/system/chassis/motherboard/regulator2",
1348 "i2c_interface": { "bus": 1, "address": "0x70" }
1349 },
1350 {
1351 "id": "vio_regulator",
1352 "is_regulator": true,
1353 "fru": "/system/chassis/motherboard/regulator2",
1354 "i2c_interface": { "bus": 1, "address": "0x71" }
1355 }
1356 ]
1357 )"_json;
1358 std::vector<std::unique_ptr<Device>> devices =
1359 parseDeviceArray(element);
1360 EXPECT_EQ(devices.size(), 2);
1361 EXPECT_EQ(devices[0]->getID(), "vdd_regulator");
1362 EXPECT_EQ(devices[1]->getID(), "vio_regulator");
1363 }
1364
1365 // Test where fails: Element is not an array
1366 try
1367 {
1368 const json element = R"(
1369 {
1370 "foo": "bar"
1371 }
1372 )"_json;
1373 parseDeviceArray(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 array");
1379 }
1380}
1381
Shawn McCarney0e8c68a2020-03-27 01:44:48 -05001382TEST(ConfigFileParserTests, ParseDouble)
1383{
1384 // Test where works: floating point value
1385 {
1386 const json element = R"( 1.03 )"_json;
1387 double value = parseDouble(element);
1388 EXPECT_EQ(value, 1.03);
1389 }
1390
1391 // Test where works: integer value
1392 {
1393 const json element = R"( 24 )"_json;
1394 double value = parseDouble(element);
1395 EXPECT_EQ(value, 24.0);
1396 }
1397
1398 // Test where fails: Element is not a number
1399 try
1400 {
1401 const json element = R"( true )"_json;
1402 parseDouble(element);
1403 ADD_FAILURE() << "Should not have reached this line.";
1404 }
1405 catch (const std::invalid_argument& e)
1406 {
1407 EXPECT_STREQ(e.what(), "Element is not a number");
1408 }
1409}
1410
Bob Kingbafcb862020-03-31 16:39:00 +08001411TEST(ConfigFileParserTests, ParseHexByte)
1412{
1413 // Test where works: "0xFF"
1414 {
1415 const json element = R"( "0xFF" )"_json;
1416 uint8_t value = parseHexByte(element);
1417 EXPECT_EQ(value, 0xFF);
1418 }
1419
1420 // Test where works: "0xff"
1421 {
1422 const json element = R"( "0xff" )"_json;
1423 uint8_t value = parseHexByte(element);
1424 EXPECT_EQ(value, 0xff);
1425 }
1426
1427 // Test where works: "0xf"
1428 {
1429 const json element = R"( "0xf" )"_json;
1430 uint8_t value = parseHexByte(element);
1431 EXPECT_EQ(value, 0xf);
1432 }
1433
1434 // Test where fails: "0xfff"
1435 try
1436 {
1437 const json element = R"( "0xfff" )"_json;
1438 parseHexByte(element);
1439 ADD_FAILURE() << "Should not have reached this line.";
1440 }
1441 catch (const std::invalid_argument& e)
1442 {
1443 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
1444 }
1445
1446 // Test where fails: "0xAG"
1447 try
1448 {
1449 const json element = R"( "0xAG" )"_json;
1450 parseHexByte(element);
1451 ADD_FAILURE() << "Should not have reached this line.";
1452 }
1453 catch (const std::invalid_argument& e)
1454 {
1455 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
1456 }
1457
1458 // Test where fails: "ff"
1459 try
1460 {
1461 const json element = R"( "ff" )"_json;
1462 parseHexByte(element);
1463 ADD_FAILURE() << "Should not have reached this line.";
1464 }
1465 catch (const std::invalid_argument& e)
1466 {
1467 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
1468 }
1469
1470 // Test where fails: ""
1471 try
1472 {
1473 const json element = "";
1474 parseHexByte(element);
1475 ADD_FAILURE() << "Should not have reached this line.";
1476 }
1477 catch (const std::invalid_argument& e)
1478 {
1479 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
1480 }
1481
1482 // Test where fails: "f"
1483 try
1484 {
1485 const json element = R"( "f" )"_json;
1486 parseHexByte(element);
1487 ADD_FAILURE() << "Should not have reached this line.";
1488 }
1489 catch (const std::invalid_argument& e)
1490 {
1491 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
1492 }
1493
1494 // Test where fails: "0x"
1495 try
1496 {
1497 const json element = R"( "0x" )"_json;
1498 parseHexByte(element);
1499 ADD_FAILURE() << "Should not have reached this line.";
1500 }
1501 catch (const std::invalid_argument& e)
1502 {
1503 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
1504 }
1505
1506 // Test where fails: "0Xff"
1507 try
1508 {
1509 const json element = R"( "0XFF" )"_json;
1510 parseHexByte(element);
1511 ADD_FAILURE() << "Should not have reached this line.";
1512 }
1513 catch (const std::invalid_argument& e)
1514 {
1515 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
1516 }
1517}
1518
1519TEST(ConfigFileParserTests, ParseHexByteArray)
1520{
1521 // Test where works
1522 {
1523 const json element = R"( [ "0xCC", "0xFF" ] )"_json;
1524 std::vector<uint8_t> hexBytes = parseHexByteArray(element);
1525 std::vector<uint8_t> expected = {0xcc, 0xff};
1526 EXPECT_EQ(hexBytes, expected);
1527 }
1528
1529 // Test where fails: Element is not an array
1530 try
1531 {
1532 const json element = 0;
1533 parseHexByteArray(element);
1534 ADD_FAILURE() << "Should not have reached this line.";
1535 }
1536 catch (const std::invalid_argument& e)
1537 {
1538 EXPECT_STREQ(e.what(), "Element is not an array");
1539 }
1540}
1541
Bob Kingf09bfe02020-04-13 17:21:15 +08001542TEST(ConfigFileParserTests, ParseI2CCompareBit)
1543{
1544 // Test where works
1545 {
1546 const json element = R"(
1547 {
1548 "register": "0xA0",
1549 "position": 3,
1550 "value": 0
1551 }
1552 )"_json;
1553 std::unique_ptr<I2CCompareBitAction> action =
1554 parseI2CCompareBit(element);
1555 EXPECT_EQ(action->getRegister(), 0xA0);
1556 EXPECT_EQ(action->getPosition(), 3);
1557 EXPECT_EQ(action->getValue(), 0);
1558 }
1559
1560 // Test where fails: Invalid property specified
1561 try
1562 {
1563 const json element = R"(
1564 {
1565 "register": "0xA0",
1566 "position": 3,
1567 "value": 0,
1568 "foo": 3
1569 }
1570 )"_json;
1571 parseI2CCompareBit(element);
1572 ADD_FAILURE() << "Should not have reached this line.";
1573 }
1574 catch (const std::invalid_argument& e)
1575 {
1576 EXPECT_STREQ(e.what(), "Element contains an invalid property");
1577 }
1578
1579 // Test where fails: Element is not an object
1580 try
1581 {
1582 const json element = R"( [ "0xFF", "0x01" ] )"_json;
1583 parseI2CCompareBit(element);
1584 ADD_FAILURE() << "Should not have reached this line.";
1585 }
1586 catch (const std::invalid_argument& e)
1587 {
1588 EXPECT_STREQ(e.what(), "Element is not an object");
1589 }
1590
1591 // Test where fails: register value is invalid
1592 try
1593 {
1594 const json element = R"(
1595 {
1596 "register": "0xAG",
1597 "position": 3,
1598 "value": 0
1599 }
1600 )"_json;
1601 parseI2CCompareBit(element);
1602 ADD_FAILURE() << "Should not have reached this line.";
1603 }
1604 catch (const std::invalid_argument& e)
1605 {
1606 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
1607 }
1608
1609 // Test where fails: position value is invalid
1610 try
1611 {
1612 const json element = R"(
1613 {
1614 "register": "0xA0",
1615 "position": 8,
1616 "value": 0
1617 }
1618 )"_json;
1619 parseI2CCompareBit(element);
1620 ADD_FAILURE() << "Should not have reached this line.";
1621 }
1622 catch (const std::invalid_argument& e)
1623 {
1624 EXPECT_STREQ(e.what(), "Element is not a bit position");
1625 }
1626
1627 // Test where fails: value value is invalid
1628 try
1629 {
1630 const json element = R"(
1631 {
1632 "register": "0xA0",
1633 "position": 3,
1634 "value": 2
1635 }
1636 )"_json;
1637 parseI2CCompareBit(element);
1638 ADD_FAILURE() << "Should not have reached this line.";
1639 }
1640 catch (const std::invalid_argument& e)
1641 {
1642 EXPECT_STREQ(e.what(), "Element is not a bit value");
1643 }
1644
1645 // Test where fails: Required register property not specified
1646 try
1647 {
1648 const json element = R"(
1649 {
1650 "position": 3,
1651 "value": 0
1652 }
1653 )"_json;
1654 parseI2CCompareBit(element);
1655 ADD_FAILURE() << "Should not have reached this line.";
1656 }
1657 catch (const std::invalid_argument& e)
1658 {
1659 EXPECT_STREQ(e.what(), "Required property missing: register");
1660 }
1661
1662 // Test where fails: Required position property not specified
1663 try
1664 {
1665 const json element = R"(
1666 {
1667 "register": "0xA0",
1668 "value": 0
1669 }
1670 )"_json;
1671 parseI2CCompareBit(element);
1672 ADD_FAILURE() << "Should not have reached this line.";
1673 }
1674 catch (const std::invalid_argument& e)
1675 {
1676 EXPECT_STREQ(e.what(), "Required property missing: position");
1677 }
1678
1679 // Test where fails: Required value property not specified
1680 try
1681 {
1682 const json element = R"(
1683 {
1684 "register": "0xA0",
1685 "position": 3
1686 }
1687 )"_json;
1688 parseI2CCompareBit(element);
1689 ADD_FAILURE() << "Should not have reached this line.";
1690 }
1691 catch (const std::invalid_argument& e)
1692 {
1693 EXPECT_STREQ(e.what(), "Required property missing: value");
1694 }
1695}
1696
1697TEST(ConfigFileParserTests, ParseI2CCompareByte)
1698{
1699 // Test where works: Only required properties specified
1700 {
1701 const json element = R"(
1702 {
1703 "register": "0x0A",
1704 "value": "0xCC"
1705 }
1706 )"_json;
1707 std::unique_ptr<I2CCompareByteAction> action =
1708 parseI2CCompareByte(element);
1709 EXPECT_EQ(action->getRegister(), 0x0A);
1710 EXPECT_EQ(action->getValue(), 0xCC);
1711 EXPECT_EQ(action->getMask(), 0xFF);
1712 }
1713
1714 // Test where works: All properties specified
1715 {
1716 const json element = R"(
1717 {
1718 "register": "0x0A",
1719 "value": "0xCC",
1720 "mask": "0xF7"
1721 }
1722 )"_json;
1723 std::unique_ptr<I2CCompareByteAction> action =
1724 parseI2CCompareByte(element);
1725 EXPECT_EQ(action->getRegister(), 0x0A);
1726 EXPECT_EQ(action->getValue(), 0xCC);
1727 EXPECT_EQ(action->getMask(), 0xF7);
1728 }
1729
1730 // Test where fails: Element is not an object
1731 try
1732 {
1733 const json element = R"( [ "0xFF", "0x01" ] )"_json;
1734 parseI2CCompareByte(element);
1735 ADD_FAILURE() << "Should not have reached this line.";
1736 }
1737 catch (const std::invalid_argument& e)
1738 {
1739 EXPECT_STREQ(e.what(), "Element is not an object");
1740 }
1741
1742 // Test where fails: Invalid property specified
1743 try
1744 {
1745 const json element = R"(
1746 {
1747 "register": "0x0A",
1748 "value": "0xCC",
1749 "mask": "0xF7",
1750 "foo": 1
1751 }
1752 )"_json;
1753 parseI2CCompareByte(element);
1754 ADD_FAILURE() << "Should not have reached this line.";
1755 }
1756 catch (const std::invalid_argument& e)
1757 {
1758 EXPECT_STREQ(e.what(), "Element contains an invalid property");
1759 }
1760
1761 // Test where fails: register value is invalid
1762 try
1763 {
1764 const json element = R"(
1765 {
1766 "register": "0x0Z",
1767 "value": "0xCC",
1768 "mask": "0xF7"
1769 }
1770 )"_json;
1771 parseI2CCompareByte(element);
1772 ADD_FAILURE() << "Should not have reached this line.";
1773 }
1774 catch (const std::invalid_argument& e)
1775 {
1776 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
1777 }
1778
1779 // Test where fails: value value is invalid
1780 try
1781 {
1782 const json element = R"(
1783 {
1784 "register": "0x0A",
1785 "value": "0xCCC",
1786 "mask": "0xF7"
1787 }
1788 )"_json;
1789 parseI2CCompareByte(element);
1790 ADD_FAILURE() << "Should not have reached this line.";
1791 }
1792 catch (const std::invalid_argument& e)
1793 {
1794 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
1795 }
1796
1797 // Test where fails: mask value is invalid
1798 try
1799 {
1800 const json element = R"(
1801 {
1802 "register": "0x0A",
1803 "value": "0xCC",
1804 "mask": "F7"
1805 }
1806 )"_json;
1807 parseI2CCompareByte(element);
1808 ADD_FAILURE() << "Should not have reached this line.";
1809 }
1810 catch (const std::invalid_argument& e)
1811 {
1812 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
1813 }
1814
1815 // Test where fails: Required register property not specified
1816 try
1817 {
1818 const json element = R"(
1819 {
1820 "value": "0xCC",
1821 "mask": "0xF7"
1822 }
1823 )"_json;
1824 parseI2CCompareByte(element);
1825 ADD_FAILURE() << "Should not have reached this line.";
1826 }
1827 catch (const std::invalid_argument& e)
1828 {
1829 EXPECT_STREQ(e.what(), "Required property missing: register");
1830 }
1831
1832 // Test where fails: Required value property not specified
1833 try
1834 {
1835 const json element = R"(
1836 {
1837 "register": "0x0A",
1838 "mask": "0xF7"
1839 }
1840 )"_json;
1841 parseI2CCompareByte(element);
1842 ADD_FAILURE() << "Should not have reached this line.";
1843 }
1844 catch (const std::invalid_argument& e)
1845 {
1846 EXPECT_STREQ(e.what(), "Required property missing: value");
1847 }
1848}
1849
1850TEST(ConfigFileParserTests, ParseI2CCompareBytes)
1851{
1852 // Test where works: Only required properties specified
1853 {
1854 const json element = R"(
1855 {
1856 "register": "0x0A",
1857 "values": [ "0xCC", "0xFF" ]
1858 }
1859 )"_json;
1860 std::unique_ptr<I2CCompareBytesAction> action =
1861 parseI2CCompareBytes(element);
1862 EXPECT_EQ(action->getRegister(), 0x0A);
1863 EXPECT_EQ(action->getValues().size(), 2);
1864 EXPECT_EQ(action->getValues()[0], 0xCC);
1865 EXPECT_EQ(action->getValues()[1], 0xFF);
1866 EXPECT_EQ(action->getMasks().size(), 2);
1867 EXPECT_EQ(action->getMasks()[0], 0xFF);
1868 EXPECT_EQ(action->getMasks()[1], 0xFF);
1869 }
1870
1871 // Test where works: All properties specified
1872 {
1873 const json element = R"(
1874 {
1875 "register": "0x0A",
1876 "values": [ "0xCC", "0xFF" ],
1877 "masks": [ "0x7F", "0x77" ]
1878 }
1879 )"_json;
1880 std::unique_ptr<I2CCompareBytesAction> action =
1881 parseI2CCompareBytes(element);
1882 EXPECT_EQ(action->getRegister(), 0x0A);
1883 EXPECT_EQ(action->getValues().size(), 2);
1884 EXPECT_EQ(action->getValues()[0], 0xCC);
1885 EXPECT_EQ(action->getValues()[1], 0xFF);
1886 EXPECT_EQ(action->getMasks().size(), 2);
1887 EXPECT_EQ(action->getMasks()[0], 0x7F);
1888 EXPECT_EQ(action->getMasks()[1], 0x77);
1889 }
1890
1891 // Test where fails: Element is not an object
1892 try
1893 {
1894 const json element = R"( [ "0xFF", "0x01" ] )"_json;
1895 parseI2CCompareBytes(element);
1896 ADD_FAILURE() << "Should not have reached this line.";
1897 }
1898 catch (const std::invalid_argument& e)
1899 {
1900 EXPECT_STREQ(e.what(), "Element is not an object");
1901 }
1902
1903 // Test where fails: Invalid property specified
1904 try
1905 {
1906 const json element = R"(
1907 {
1908 "register": "0x0A",
1909 "values": [ "0xCC", "0xFF" ],
1910 "masks": [ "0x7F", "0x7F" ],
1911 "foo": 1
1912 }
1913 )"_json;
1914 parseI2CCompareBytes(element);
1915 ADD_FAILURE() << "Should not have reached this line.";
1916 }
1917 catch (const std::invalid_argument& e)
1918 {
1919 EXPECT_STREQ(e.what(), "Element contains an invalid property");
1920 }
1921
1922 // Test where fails: register value is invalid
1923 try
1924 {
1925 const json element = R"(
1926 {
1927 "register": "0x0Z",
1928 "values": [ "0xCC", "0xFF" ],
1929 "masks": [ "0x7F", "0x7F" ]
1930 }
1931 )"_json;
1932 parseI2CCompareBytes(element);
1933 ADD_FAILURE() << "Should not have reached this line.";
1934 }
1935 catch (const std::invalid_argument& e)
1936 {
1937 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
1938 }
1939
1940 // Test where fails: values value is invalid
1941 try
1942 {
1943 const json element = R"(
1944 {
1945 "register": "0x0A",
1946 "values": [ "0xCCC", "0xFF" ],
1947 "masks": [ "0x7F", "0x7F" ]
1948 }
1949 )"_json;
1950 parseI2CCompareBytes(element);
1951 ADD_FAILURE() << "Should not have reached this line.";
1952 }
1953 catch (const std::invalid_argument& e)
1954 {
1955 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
1956 }
1957
1958 // Test where fails: masks value is invalid
1959 try
1960 {
1961 const json element = R"(
1962 {
1963 "register": "0x0A",
1964 "values": [ "0xCC", "0xFF" ],
1965 "masks": [ "F", "0x7F" ]
1966 }
1967 )"_json;
1968 parseI2CCompareBytes(element);
1969 ADD_FAILURE() << "Should not have reached this line.";
1970 }
1971 catch (const std::invalid_argument& e)
1972 {
1973 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
1974 }
1975
1976 // Test where fails: number of elements in masks is invalid
1977 try
1978 {
1979 const json element = R"(
1980 {
1981 "register": "0x0A",
1982 "values": [ "0xCC", "0xFF" ],
1983 "masks": [ "0x7F" ]
1984 }
1985 )"_json;
1986 parseI2CCompareBytes(element);
1987 ADD_FAILURE() << "Should not have reached this line.";
1988 }
1989 catch (const std::invalid_argument& e)
1990 {
1991 EXPECT_STREQ(e.what(), "Invalid number of elements in masks");
1992 }
1993
1994 // Test where fails: Required register property not specified
1995 try
1996 {
1997 const json element = R"(
1998 {
1999 "values": [ "0xCC", "0xFF" ]
2000 }
2001 )"_json;
2002 parseI2CCompareBytes(element);
2003 ADD_FAILURE() << "Should not have reached this line.";
2004 }
2005 catch (const std::invalid_argument& e)
2006 {
2007 EXPECT_STREQ(e.what(), "Required property missing: register");
2008 }
2009
2010 // Test where fails: Required values property not specified
2011 try
2012 {
2013 const json element = R"(
2014 {
2015 "register": "0x0A"
2016 }
2017 )"_json;
2018 parseI2CCompareBytes(element);
2019 ADD_FAILURE() << "Should not have reached this line.";
2020 }
2021 catch (const std::invalid_argument& e)
2022 {
2023 EXPECT_STREQ(e.what(), "Required property missing: values");
2024 }
2025}
2026
Bob Kingf617f892020-03-30 19:03:35 +08002027TEST(ConfigFileParserTests, ParseI2CWriteBit)
2028{
2029 // Test where works
2030 {
2031 const json element = R"(
2032 {
2033 "register": "0xA0",
2034 "position": 3,
2035 "value": 0
2036 }
2037 )"_json;
2038 std::unique_ptr<I2CWriteBitAction> action = parseI2CWriteBit(element);
2039 EXPECT_EQ(action->getRegister(), 0xA0);
2040 EXPECT_EQ(action->getPosition(), 3);
2041 EXPECT_EQ(action->getValue(), 0);
2042 }
2043
2044 // Test where fails: Invalid property specified
2045 try
2046 {
2047 const json element = R"(
2048 {
2049 "register": "0xA0",
2050 "position": 3,
2051 "value": 0,
2052 "foo": 3
2053 }
2054 )"_json;
2055 parseI2CWriteBit(element);
2056 ADD_FAILURE() << "Should not have reached this line.";
2057 }
2058 catch (const std::invalid_argument& e)
2059 {
2060 EXPECT_STREQ(e.what(), "Element contains an invalid property");
2061 }
2062
2063 // Test where fails: Element is not an object
2064 try
2065 {
2066 const json element = R"( [ "0xFF", "0x01" ] )"_json;
2067 parseI2CWriteBit(element);
2068 ADD_FAILURE() << "Should not have reached this line.";
2069 }
2070 catch (const std::invalid_argument& e)
2071 {
2072 EXPECT_STREQ(e.what(), "Element is not an object");
2073 }
2074
2075 // Test where fails: register value is invalid
2076 try
2077 {
2078 const json element = R"(
2079 {
2080 "register": "0xAG",
2081 "position": 3,
2082 "value": 0
2083 }
2084 )"_json;
2085 parseI2CWriteBit(element);
2086 ADD_FAILURE() << "Should not have reached this line.";
2087 }
2088 catch (const std::invalid_argument& e)
2089 {
2090 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
2091 }
2092
2093 // Test where fails: position value is invalid
2094 try
2095 {
2096 const json element = R"(
2097 {
2098 "register": "0xA0",
2099 "position": 8,
2100 "value": 0
2101 }
2102 )"_json;
2103 parseI2CWriteBit(element);
2104 ADD_FAILURE() << "Should not have reached this line.";
2105 }
2106 catch (const std::invalid_argument& e)
2107 {
2108 EXPECT_STREQ(e.what(), "Element is not a bit position");
2109 }
2110
2111 // Test where fails: value value is invalid
2112 try
2113 {
2114 const json element = R"(
2115 {
2116 "register": "0xA0",
2117 "position": 3,
2118 "value": 2
2119 }
2120 )"_json;
2121 parseI2CWriteBit(element);
2122 ADD_FAILURE() << "Should not have reached this line.";
2123 }
2124 catch (const std::invalid_argument& e)
2125 {
2126 EXPECT_STREQ(e.what(), "Element is not a bit value");
2127 }
2128
2129 // Test where fails: Required register property not specified
2130 try
2131 {
2132 const json element = R"(
2133 {
2134 "position": 3,
2135 "value": 0
2136 }
2137 )"_json;
2138 parseI2CWriteBit(element);
2139 ADD_FAILURE() << "Should not have reached this line.";
2140 }
2141 catch (const std::invalid_argument& e)
2142 {
2143 EXPECT_STREQ(e.what(), "Required property missing: register");
2144 }
2145
2146 // Test where fails: Required position property not specified
2147 try
2148 {
2149 const json element = R"(
2150 {
2151 "register": "0xA0",
2152 "value": 0
2153 }
2154 )"_json;
2155 parseI2CWriteBit(element);
2156 ADD_FAILURE() << "Should not have reached this line.";
2157 }
2158 catch (const std::invalid_argument& e)
2159 {
2160 EXPECT_STREQ(e.what(), "Required property missing: position");
2161 }
2162
2163 // Test where fails: Required value property not specified
2164 try
2165 {
2166 const json element = R"(
2167 {
2168 "register": "0xA0",
2169 "position": 3
2170 }
2171 )"_json;
2172 parseI2CWriteBit(element);
2173 ADD_FAILURE() << "Should not have reached this line.";
2174 }
2175 catch (const std::invalid_argument& e)
2176 {
2177 EXPECT_STREQ(e.what(), "Required property missing: value");
2178 }
2179}
2180
Bob King87ff9d72020-03-31 14:02:55 +08002181TEST(ConfigFileParserTests, ParseI2CWriteByte)
2182{
2183 // Test where works: Only required properties specified
2184 {
2185 const json element = R"(
2186 {
2187 "register": "0x0A",
2188 "value": "0xCC"
2189 }
2190 )"_json;
2191 std::unique_ptr<I2CWriteByteAction> action = parseI2CWriteByte(element);
2192 EXPECT_EQ(action->getRegister(), 0x0A);
2193 EXPECT_EQ(action->getValue(), 0xCC);
2194 EXPECT_EQ(action->getMask(), 0xFF);
2195 }
2196
2197 // Test where works: All properties specified
2198 {
2199 const json element = R"(
2200 {
2201 "register": "0x0A",
2202 "value": "0xCC",
2203 "mask": "0xF7"
2204 }
2205 )"_json;
2206 std::unique_ptr<I2CWriteByteAction> action = parseI2CWriteByte(element);
2207 EXPECT_EQ(action->getRegister(), 0x0A);
2208 EXPECT_EQ(action->getValue(), 0xCC);
2209 EXPECT_EQ(action->getMask(), 0xF7);
2210 }
2211
2212 // Test where fails: Element is not an object
2213 try
2214 {
2215 const json element = R"( [ "0xFF", "0x01" ] )"_json;
2216 parseI2CWriteByte(element);
2217 ADD_FAILURE() << "Should not have reached this line.";
2218 }
2219 catch (const std::invalid_argument& e)
2220 {
2221 EXPECT_STREQ(e.what(), "Element is not an object");
2222 }
2223
2224 // Test where fails: Invalid property specified
2225 try
2226 {
2227 const json element = R"(
2228 {
2229 "register": "0x0A",
2230 "value": "0xCC",
2231 "mask": "0xF7",
2232 "foo": 1
2233 }
2234 )"_json;
2235 parseI2CWriteByte(element);
2236 ADD_FAILURE() << "Should not have reached this line.";
2237 }
2238 catch (const std::invalid_argument& e)
2239 {
2240 EXPECT_STREQ(e.what(), "Element contains an invalid property");
2241 }
2242
2243 // Test where fails: register value is invalid
2244 try
2245 {
2246 const json element = R"(
2247 {
2248 "register": "0x0Z",
2249 "value": "0xCC",
2250 "mask": "0xF7"
2251 }
2252 )"_json;
2253 parseI2CWriteByte(element);
2254 ADD_FAILURE() << "Should not have reached this line.";
2255 }
2256 catch (const std::invalid_argument& e)
2257 {
2258 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
2259 }
2260
2261 // Test where fails: value value is invalid
2262 try
2263 {
2264 const json element = R"(
2265 {
2266 "register": "0x0A",
2267 "value": "0xCCC",
2268 "mask": "0xF7"
2269 }
2270 )"_json;
2271 parseI2CWriteByte(element);
2272 ADD_FAILURE() << "Should not have reached this line.";
2273 }
2274 catch (const std::invalid_argument& e)
2275 {
2276 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
2277 }
2278
2279 // Test where fails: mask value is invalid
2280 try
2281 {
2282 const json element = R"(
2283 {
2284 "register": "0x0A",
2285 "value": "0xCC",
2286 "mask": "F7"
2287 }
2288 )"_json;
2289 parseI2CWriteByte(element);
2290 ADD_FAILURE() << "Should not have reached this line.";
2291 }
2292 catch (const std::invalid_argument& e)
2293 {
2294 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
2295 }
2296
2297 // Test where fails: Required register property not specified
2298 try
2299 {
2300 const json element = R"(
2301 {
2302 "value": "0xCC",
2303 "mask": "0xF7"
2304 }
2305 )"_json;
2306 parseI2CWriteByte(element);
2307 ADD_FAILURE() << "Should not have reached this line.";
2308 }
2309 catch (const std::invalid_argument& e)
2310 {
2311 EXPECT_STREQ(e.what(), "Required property missing: register");
2312 }
2313
2314 // Test where fails: Required value property not specified
2315 try
2316 {
2317 const json element = R"(
2318 {
2319 "register": "0x0A",
2320 "mask": "0xF7"
2321 }
2322 )"_json;
2323 parseI2CWriteByte(element);
2324 ADD_FAILURE() << "Should not have reached this line.";
2325 }
2326 catch (const std::invalid_argument& e)
2327 {
2328 EXPECT_STREQ(e.what(), "Required property missing: value");
2329 }
2330}
2331
Bob Kingbafcb862020-03-31 16:39:00 +08002332TEST(ConfigFileParserTests, ParseI2CWriteBytes)
2333{
2334 // Test where works: Only required properties specified
2335 {
2336 const json element = R"(
2337 {
2338 "register": "0x0A",
2339 "values": [ "0xCC", "0xFF" ]
2340 }
2341 )"_json;
2342 std::unique_ptr<I2CWriteBytesAction> action =
2343 parseI2CWriteBytes(element);
2344 EXPECT_EQ(action->getRegister(), 0x0A);
2345 EXPECT_EQ(action->getValues().size(), 2);
2346 EXPECT_EQ(action->getValues()[0], 0xCC);
2347 EXPECT_EQ(action->getValues()[1], 0xFF);
2348 EXPECT_EQ(action->getMasks().size(), 0);
2349 }
2350
2351 // Test where works: All properties specified
2352 {
2353 const json element = R"(
2354 {
2355 "register": "0x0A",
2356 "values": [ "0xCC", "0xFF" ],
2357 "masks": [ "0x7F", "0x77" ]
2358 }
2359 )"_json;
2360 std::unique_ptr<I2CWriteBytesAction> action =
2361 parseI2CWriteBytes(element);
2362 EXPECT_EQ(action->getRegister(), 0x0A);
2363 EXPECT_EQ(action->getValues().size(), 2);
2364 EXPECT_EQ(action->getValues()[0], 0xCC);
2365 EXPECT_EQ(action->getValues()[1], 0xFF);
2366 EXPECT_EQ(action->getMasks().size(), 2);
2367 EXPECT_EQ(action->getMasks()[0], 0x7F);
2368 EXPECT_EQ(action->getMasks()[1], 0x77);
2369 }
2370
2371 // Test where fails: Element is not an object
2372 try
2373 {
2374 const json element = R"( [ "0xFF", "0x01" ] )"_json;
2375 parseI2CWriteBytes(element);
2376 ADD_FAILURE() << "Should not have reached this line.";
2377 }
2378 catch (const std::invalid_argument& e)
2379 {
2380 EXPECT_STREQ(e.what(), "Element is not an object");
2381 }
2382
2383 // Test where fails: Invalid property specified
2384 try
2385 {
2386 const json element = R"(
2387 {
2388 "register": "0x0A",
2389 "values": [ "0xCC", "0xFF" ],
2390 "masks": [ "0x7F", "0x7F" ],
2391 "foo": 1
2392 }
2393 )"_json;
2394 parseI2CWriteBytes(element);
2395 ADD_FAILURE() << "Should not have reached this line.";
2396 }
2397 catch (const std::invalid_argument& e)
2398 {
2399 EXPECT_STREQ(e.what(), "Element contains an invalid property");
2400 }
2401
2402 // Test where fails: register value is invalid
2403 try
2404 {
2405 const json element = R"(
2406 {
2407 "register": "0x0Z",
2408 "values": [ "0xCC", "0xFF" ],
2409 "masks": [ "0x7F", "0x7F" ]
2410 }
2411 )"_json;
2412 parseI2CWriteBytes(element);
2413 ADD_FAILURE() << "Should not have reached this line.";
2414 }
2415 catch (const std::invalid_argument& e)
2416 {
2417 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
2418 }
2419
2420 // Test where fails: values value is invalid
2421 try
2422 {
2423 const json element = R"(
2424 {
2425 "register": "0x0A",
2426 "values": [ "0xCCC", "0xFF" ],
2427 "masks": [ "0x7F", "0x7F" ]
2428 }
2429 )"_json;
2430 parseI2CWriteBytes(element);
2431 ADD_FAILURE() << "Should not have reached this line.";
2432 }
2433 catch (const std::invalid_argument& e)
2434 {
2435 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
2436 }
2437
2438 // Test where fails: masks value is invalid
2439 try
2440 {
2441 const json element = R"(
2442 {
2443 "register": "0x0A",
2444 "values": [ "0xCC", "0xFF" ],
2445 "masks": [ "F", "0x7F" ]
2446 }
2447 )"_json;
2448 parseI2CWriteBytes(element);
2449 ADD_FAILURE() << "Should not have reached this line.";
2450 }
2451 catch (const std::invalid_argument& e)
2452 {
2453 EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
2454 }
2455
2456 // Test where fails: number of elements in masks is invalid
2457 try
2458 {
2459 const json element = R"(
2460 {
2461 "register": "0x0A",
2462 "values": [ "0xCC", "0xFF" ],
2463 "masks": [ "0x7F" ]
2464 }
2465 )"_json;
2466 parseI2CWriteBytes(element);
2467 ADD_FAILURE() << "Should not have reached this line.";
2468 }
2469 catch (const std::invalid_argument& e)
2470 {
2471 EXPECT_STREQ(e.what(), "Invalid number of elements in masks");
2472 }
2473
2474 // Test where fails: Required register property not specified
2475 try
2476 {
2477 const json element = R"(
2478 {
2479 "values": [ "0xCC", "0xFF" ]
2480 }
2481 )"_json;
2482 parseI2CWriteBytes(element);
2483 ADD_FAILURE() << "Should not have reached this line.";
2484 }
2485 catch (const std::invalid_argument& e)
2486 {
2487 EXPECT_STREQ(e.what(), "Required property missing: register");
2488 }
2489
2490 // Test where fails: Required values property not specified
2491 try
2492 {
2493 const json element = R"(
2494 {
2495 "register": "0x0A"
2496 }
2497 )"_json;
2498 parseI2CWriteBytes(element);
2499 ADD_FAILURE() << "Should not have reached this line.";
2500 }
2501 catch (const std::invalid_argument& e)
2502 {
2503 EXPECT_STREQ(e.what(), "Required property missing: values");
2504 }
2505}
2506
Bob King87ff9d72020-03-31 14:02:55 +08002507TEST(ConfigFileParserTests, ParseInt8)
2508{
2509 // Test where works: INT8_MIN
2510 {
2511 const json element = R"( -128 )"_json;
2512 int8_t value = parseInt8(element);
2513 EXPECT_EQ(value, -128);
2514 }
2515
2516 // Test where works: INT8_MAX
2517 {
2518 const json element = R"( 127 )"_json;
2519 int8_t value = parseInt8(element);
2520 EXPECT_EQ(value, 127);
2521 }
2522
2523 // Test where fails: Element is not an integer
2524 try
2525 {
2526 const json element = R"( 1.03 )"_json;
2527 parseInt8(element);
2528 ADD_FAILURE() << "Should not have reached this line.";
2529 }
2530 catch (const std::invalid_argument& e)
2531 {
2532 EXPECT_STREQ(e.what(), "Element is not an integer");
2533 }
2534
2535 // Test where fails: Value < INT8_MIN
2536 try
2537 {
2538 const json element = R"( -129 )"_json;
2539 parseInt8(element);
2540 ADD_FAILURE() << "Should not have reached this line.";
2541 }
2542 catch (const std::invalid_argument& e)
2543 {
2544 EXPECT_STREQ(e.what(), "Element is not an 8-bit signed integer");
2545 }
2546
2547 // Test where fails: Value > INT8_MAX
2548 try
2549 {
2550 const json element = R"( 128 )"_json;
2551 parseInt8(element);
2552 ADD_FAILURE() << "Should not have reached this line.";
2553 }
2554 catch (const std::invalid_argument& e)
2555 {
2556 EXPECT_STREQ(e.what(), "Element is not an 8-bit signed integer");
2557 }
2558}
2559
Bob Kingf1b58dc2020-04-14 14:53:10 +08002560TEST(ConfigFileParserTests, ParseNot)
2561{
2562 // Test where works
2563 {
2564 const json element = R"(
2565 { "i2c_compare_byte": { "register": "0xA0", "value": "0x00" } }
2566 )"_json;
2567 std::unique_ptr<NotAction> action = parseNot(element);
2568 EXPECT_NE(action->getAction().get(), nullptr);
2569 }
2570
2571 // Test where fails: Element is not an object
2572 try
2573 {
2574 const json element = R"( [ "0xFF", "0x01" ] )"_json;
2575 parseNot(element);
2576 ADD_FAILURE() << "Should not have reached this line.";
2577 }
2578 catch (const std::invalid_argument& e)
2579 {
2580 EXPECT_STREQ(e.what(), "Element is not an object");
2581 }
2582}
2583
Shawn McCarney0e8c68a2020-03-27 01:44:48 -05002584TEST(ConfigFileParserTests, ParsePMBusWriteVoutCommand)
2585{
2586 // Test where works: Only required properties specified
2587 {
2588 const json element = R"(
2589 {
2590 "format": "linear"
2591 }
2592 )"_json;
2593 std::unique_ptr<PMBusWriteVoutCommandAction> action =
2594 parsePMBusWriteVoutCommand(element);
2595 EXPECT_EQ(action->getVolts().has_value(), false);
2596 EXPECT_EQ(action->getFormat(), pmbus_utils::VoutDataFormat::linear);
2597 EXPECT_EQ(action->getExponent().has_value(), false);
2598 EXPECT_EQ(action->isVerified(), false);
2599 }
2600
2601 // Test where works: All properties specified
2602 {
2603 const json element = R"(
2604 {
2605 "volts": 1.03,
2606 "format": "linear",
2607 "exponent": -8,
2608 "is_verified": true
2609 }
2610 )"_json;
2611 std::unique_ptr<PMBusWriteVoutCommandAction> action =
2612 parsePMBusWriteVoutCommand(element);
2613 EXPECT_EQ(action->getVolts().has_value(), true);
2614 EXPECT_EQ(action->getVolts().value(), 1.03);
2615 EXPECT_EQ(action->getFormat(), pmbus_utils::VoutDataFormat::linear);
2616 EXPECT_EQ(action->getExponent().has_value(), true);
2617 EXPECT_EQ(action->getExponent().value(), -8);
2618 EXPECT_EQ(action->isVerified(), true);
2619 }
2620
2621 // Test where fails: Element is not an object
2622 try
2623 {
2624 const json element = R"( [ "0xFF", "0x01" ] )"_json;
2625 parsePMBusWriteVoutCommand(element);
2626 ADD_FAILURE() << "Should not have reached this line.";
2627 }
2628 catch (const std::invalid_argument& e)
2629 {
2630 EXPECT_STREQ(e.what(), "Element is not an object");
2631 }
2632
2633 // Test where fails: volts value is invalid
2634 try
2635 {
2636 const json element = R"(
2637 {
2638 "volts": "foo",
2639 "format": "linear"
2640 }
2641 )"_json;
2642 parsePMBusWriteVoutCommand(element);
2643 ADD_FAILURE() << "Should not have reached this line.";
2644 }
2645 catch (const std::invalid_argument& e)
2646 {
2647 EXPECT_STREQ(e.what(), "Element is not a number");
2648 }
2649
2650 // Test where fails: Required format property not specified
2651 try
2652 {
2653 const json element = R"(
2654 {
2655 "volts": 1.03,
2656 "is_verified": true
2657 }
2658 )"_json;
2659 parsePMBusWriteVoutCommand(element);
2660 ADD_FAILURE() << "Should not have reached this line.";
2661 }
2662 catch (const std::invalid_argument& e)
2663 {
2664 EXPECT_STREQ(e.what(), "Required property missing: format");
2665 }
2666
2667 // Test where fails: format value is invalid
2668 try
2669 {
2670 const json element = R"(
2671 {
2672 "format": "linear_11"
2673 }
2674 )"_json;
2675 parsePMBusWriteVoutCommand(element);
2676 ADD_FAILURE() << "Should not have reached this line.";
2677 }
2678 catch (const std::invalid_argument& e)
2679 {
2680 EXPECT_STREQ(e.what(), "Invalid format value: linear_11");
2681 }
2682
2683 // Test where fails: exponent value is invalid
2684 try
2685 {
2686 const json element = R"(
2687 {
2688 "format": "linear",
2689 "exponent": 1.3
2690 }
2691 )"_json;
2692 parsePMBusWriteVoutCommand(element);
2693 ADD_FAILURE() << "Should not have reached this line.";
2694 }
2695 catch (const std::invalid_argument& e)
2696 {
2697 EXPECT_STREQ(e.what(), "Element is not an integer");
2698 }
2699
2700 // Test where fails: is_verified value is invalid
2701 try
2702 {
2703 const json element = R"(
2704 {
2705 "format": "linear",
2706 "is_verified": "true"
2707 }
2708 )"_json;
2709 parsePMBusWriteVoutCommand(element);
2710 ADD_FAILURE() << "Should not have reached this line.";
2711 }
2712 catch (const std::invalid_argument& e)
2713 {
2714 EXPECT_STREQ(e.what(), "Element is not a boolean");
2715 }
2716
2717 // Test where fails: Invalid property specified
2718 try
2719 {
2720 const json element = R"(
2721 {
2722 "format": "linear",
2723 "foo": "bar"
2724 }
2725 )"_json;
2726 parsePMBusWriteVoutCommand(element);
2727 ADD_FAILURE() << "Should not have reached this line.";
2728 }
2729 catch (const std::invalid_argument& e)
2730 {
2731 EXPECT_STREQ(e.what(), "Element contains an invalid property");
2732 }
2733}
2734
Bob Kinga2f2a0d2020-04-09 13:32:14 +08002735TEST(ConfigFileParserTests, ParseRail)
2736{
2737 // Test where works: Only required properties specified
2738 {
2739 const json element = R"(
2740 {
2741 "id": "vdd"
2742 }
2743 )"_json;
2744 std::unique_ptr<Rail> rail = parseRail(element);
2745 EXPECT_EQ(rail->getID(), "vdd");
2746 EXPECT_EQ(rail->getConfiguration(), nullptr);
2747 EXPECT_EQ(rail->getSensorMonitoring(), nullptr);
2748 }
2749
2750 // Test where works: All properties specified
2751 {
2752 const json element = R"(
2753 {
2754 "comments": [ "comments property" ],
2755 "id": "vdd",
2756 "configuration": {
2757 "volts": 1.1,
2758 "actions": [
2759 {
2760 "pmbus_write_vout_command": {
2761 "format": "linear"
2762 }
2763 }
2764 ]
2765 },
2766 "sensor_monitoring": {
2767 "actions": [
2768 { "run_rule": "read_sensors_rule" }
2769 ]
2770 }
2771 }
2772 )"_json;
2773 std::unique_ptr<Rail> rail = parseRail(element);
2774 EXPECT_EQ(rail->getID(), "vdd");
2775 EXPECT_NE(rail->getConfiguration(), nullptr);
2776 EXPECT_NE(rail->getSensorMonitoring(), nullptr);
2777 }
2778
2779 // Test where fails: id property not specified
2780 try
2781 {
2782 const json element = R"(
2783 {
2784 "configuration": {
2785 "volts": 1.1,
2786 "actions": [
2787 {
2788 "pmbus_write_vout_command": {
2789 "format": "linear"
2790 }
2791 }
2792 ]
2793 }
2794 }
2795 )"_json;
2796 parseRail(element);
2797 ADD_FAILURE() << "Should not have reached this line.";
2798 }
2799 catch (const std::invalid_argument& e)
2800 {
2801 EXPECT_STREQ(e.what(), "Required property missing: id");
2802 }
2803
2804 // Test where fails: id property is invalid
2805 try
2806 {
2807 const json element = R"(
2808 {
2809 "id": "",
2810 "configuration": {
2811 "volts": 1.1,
2812 "actions": [
2813 {
2814 "pmbus_write_vout_command": {
2815 "format": "linear"
2816 }
2817 }
2818 ]
2819 }
2820 }
2821 )"_json;
2822 parseRail(element);
2823 ADD_FAILURE() << "Should not have reached this line.";
2824 }
2825 catch (const std::invalid_argument& e)
2826 {
2827 EXPECT_STREQ(e.what(), "Element contains an empty string");
2828 }
2829
2830 // Test where fails: Element is not an object
2831 try
2832 {
2833 const json element = R"( [ "0xFF", "0x01" ] )"_json;
2834 parseRail(element);
2835 ADD_FAILURE() << "Should not have reached this line.";
2836 }
2837 catch (const std::invalid_argument& e)
2838 {
2839 EXPECT_STREQ(e.what(), "Element is not an object");
2840 }
2841
2842 // Test where fails: configuration value is invalid
2843 try
2844 {
2845 const json element = R"(
2846 {
2847 "id": "vdd",
2848 "configuration": "config"
2849 }
2850 )"_json;
2851 parseRail(element);
2852 ADD_FAILURE() << "Should not have reached this line.";
2853 }
2854 catch (const std::invalid_argument& e)
2855 {
2856 EXPECT_STREQ(e.what(), "Element is not an object");
2857 }
2858
2859 // Test where fails: sensor_monitoring value is invalid
2860 try
2861 {
2862 const json element = R"(
2863 {
2864 "comments": [ "comments property" ],
2865 "id": "vdd",
2866 "configuration": {
2867 "volts": 1.1,
2868 "actions": [
2869 {
2870 "pmbus_write_vout_command": {
2871 "format": "linear"
2872 }
2873 }
2874 ]
2875 },
2876 "sensor_monitoring": 1
2877 }
2878 )"_json;
2879 parseRail(element);
2880 ADD_FAILURE() << "Should not have reached this line.";
2881 }
2882 catch (const std::invalid_argument& e)
2883 {
2884 EXPECT_STREQ(e.what(), "Element is not an object");
2885 }
2886
2887 // Test where fails: Invalid property specified
2888 try
2889 {
2890 const json element = R"(
2891 {
2892 "id": "vdd",
2893 "foo" : true
2894 }
2895 )"_json;
2896 parseRail(element);
2897 ADD_FAILURE() << "Should not have reached this line.";
2898 }
2899 catch (const std::invalid_argument& e)
2900 {
2901 EXPECT_STREQ(e.what(), "Element contains an invalid property");
2902 }
2903}
2904
2905TEST(ConfigFileParserTests, ParseRailArray)
2906{
2907 // Test where works
2908 {
2909 const json element = R"(
2910 [
2911 { "id": "vdd" },
2912 { "id": "vio" }
2913 ]
2914 )"_json;
2915 std::vector<std::unique_ptr<Rail>> rails = parseRailArray(element);
2916 EXPECT_EQ(rails.size(), 2);
2917 EXPECT_EQ(rails[0]->getID(), "vdd");
2918 EXPECT_EQ(rails[1]->getID(), "vio");
2919 }
2920
2921 // Test where fails: Element is not an array
2922 try
2923 {
2924 const json element = R"(
2925 {
2926 "foo": "bar"
2927 }
2928 )"_json;
2929 parseRailArray(element);
2930 ADD_FAILURE() << "Should not have reached this line.";
2931 }
2932 catch (const std::invalid_argument& e)
2933 {
2934 EXPECT_STREQ(e.what(), "Element is not an array");
2935 }
2936}
2937
Shawn McCarney0e8c68a2020-03-27 01:44:48 -05002938TEST(ConfigFileParserTests, ParseRoot)
2939{
2940 // Test where works: Only required properties specified
2941 {
2942 const json element = R"(
2943 {
2944 "chassis": [
2945 { "number": 1 }
2946 ]
2947 }
2948 )"_json;
2949 std::vector<std::unique_ptr<Rule>> rules{};
2950 std::vector<std::unique_ptr<Chassis>> chassis{};
2951 std::tie(rules, chassis) = parseRoot(element);
2952 EXPECT_EQ(rules.size(), 0);
Bob King0e701132020-04-03 21:50:31 +08002953 EXPECT_EQ(chassis.size(), 1);
Shawn McCarney0e8c68a2020-03-27 01:44:48 -05002954 }
2955
2956 // Test where works: All properties specified
2957 {
2958 const json element = R"(
2959 {
2960 "comments": [ "Config file for a FooBar one-chassis system" ],
2961 "rules": [
2962 {
2963 "id": "set_voltage_rule",
2964 "actions": [
2965 { "pmbus_write_vout_command": { "format": "linear" } }
2966 ]
2967 }
2968 ],
2969 "chassis": [
2970 { "number": 1 },
2971 { "number": 3 }
2972 ]
2973 }
2974 )"_json;
2975 std::vector<std::unique_ptr<Rule>> rules{};
2976 std::vector<std::unique_ptr<Chassis>> chassis{};
2977 std::tie(rules, chassis) = parseRoot(element);
2978 EXPECT_EQ(rules.size(), 1);
Bob King0e701132020-04-03 21:50:31 +08002979 EXPECT_EQ(chassis.size(), 2);
Shawn McCarney0e8c68a2020-03-27 01:44:48 -05002980 }
2981
2982 // Test where fails: Element is not an object
2983 try
2984 {
2985 const json element = R"( [ "0xFF", "0x01" ] )"_json;
2986 parseRoot(element);
2987 ADD_FAILURE() << "Should not have reached this line.";
2988 }
2989 catch (const std::invalid_argument& e)
2990 {
2991 EXPECT_STREQ(e.what(), "Element is not an object");
2992 }
2993
2994 // Test where fails: chassis property not specified
2995 try
2996 {
2997 const json element = R"(
2998 {
2999 "rules": [
3000 {
3001 "id": "set_voltage_rule",
3002 "actions": [
3003 { "pmbus_write_vout_command": { "format": "linear" } }
3004 ]
3005 }
3006 ]
3007 }
3008 )"_json;
3009 parseRoot(element);
3010 ADD_FAILURE() << "Should not have reached this line.";
3011 }
3012 catch (const std::invalid_argument& e)
3013 {
3014 EXPECT_STREQ(e.what(), "Required property missing: chassis");
3015 }
3016
3017 // Test where fails: Invalid property specified
3018 try
3019 {
3020 const json element = R"(
3021 {
3022 "remarks": [ "Config file for a FooBar one-chassis system" ],
3023 "chassis": [
3024 { "number": 1 }
3025 ]
3026 }
3027 )"_json;
3028 parseRoot(element);
3029 ADD_FAILURE() << "Should not have reached this line.";
3030 }
3031 catch (const std::invalid_argument& e)
3032 {
3033 EXPECT_STREQ(e.what(), "Element contains an invalid property");
3034 }
3035}
3036
3037TEST(ConfigFileParserTests, ParseRule)
3038{
3039 // Test where works: comments property specified
3040 {
3041 const json element = R"(
3042 {
3043 "comments": [ "Set voltage rule" ],
3044 "id": "set_voltage_rule",
3045 "actions": [
3046 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } },
3047 { "pmbus_write_vout_command": { "volts": 1.03, "format": "linear" } }
3048 ]
3049 }
3050 )"_json;
3051 std::unique_ptr<Rule> rule = parseRule(element);
3052 EXPECT_EQ(rule->getID(), "set_voltage_rule");
3053 EXPECT_EQ(rule->getActions().size(), 2);
3054 }
3055
3056 // Test where works: comments property not specified
3057 {
3058 const json element = R"(
3059 {
3060 "id": "set_voltage_rule",
3061 "actions": [
3062 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } },
3063 { "pmbus_write_vout_command": { "volts": 1.03, "format": "linear" } },
3064 { "pmbus_write_vout_command": { "volts": 1.05, "format": "linear" } }
3065 ]
3066 }
3067 )"_json;
3068 std::unique_ptr<Rule> rule = parseRule(element);
3069 EXPECT_EQ(rule->getID(), "set_voltage_rule");
3070 EXPECT_EQ(rule->getActions().size(), 3);
3071 }
3072
3073 // Test where fails: Element is not an object
3074 try
3075 {
3076 const json element = R"( [ "0xFF", "0x01" ] )"_json;
3077 parseRule(element);
3078 ADD_FAILURE() << "Should not have reached this line.";
3079 }
3080 catch (const std::invalid_argument& e)
3081 {
3082 EXPECT_STREQ(e.what(), "Element is not an object");
3083 }
3084
3085 // Test where fails: id property not specified
3086 try
3087 {
3088 const json element = R"(
3089 {
3090 "actions": [
3091 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } }
3092 ]
3093 }
3094 )"_json;
3095 parseRule(element);
3096 ADD_FAILURE() << "Should not have reached this line.";
3097 }
3098 catch (const std::invalid_argument& e)
3099 {
3100 EXPECT_STREQ(e.what(), "Required property missing: id");
3101 }
3102
3103 // Test where fails: id property is invalid
3104 try
3105 {
3106 const json element = R"(
3107 {
3108 "id": "",
3109 "actions": [
3110 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } }
3111 ]
3112 }
3113 )"_json;
3114 parseRule(element);
3115 ADD_FAILURE() << "Should not have reached this line.";
3116 }
3117 catch (const std::invalid_argument& e)
3118 {
3119 EXPECT_STREQ(e.what(), "Element contains an empty string");
3120 }
3121
3122 // Test where fails: actions property not specified
3123 try
3124 {
3125 const json element = R"(
3126 {
3127 "comments": [ "Set voltage rule" ],
3128 "id": "set_voltage_rule"
3129 }
3130 )"_json;
3131 parseRule(element);
3132 ADD_FAILURE() << "Should not have reached this line.";
3133 }
3134 catch (const std::invalid_argument& e)
3135 {
3136 EXPECT_STREQ(e.what(), "Required property missing: actions");
3137 }
3138
3139 // Test where fails: actions property is invalid
3140 try
3141 {
3142 const json element = R"(
3143 {
3144 "id": "set_voltage_rule",
3145 "actions": true
3146 }
3147 )"_json;
3148 parseRule(element);
3149 ADD_FAILURE() << "Should not have reached this line.";
3150 }
3151 catch (const std::invalid_argument& e)
3152 {
3153 EXPECT_STREQ(e.what(), "Element is not an array");
3154 }
3155
3156 // Test where fails: Invalid property specified
3157 try
3158 {
3159 const json element = R"(
3160 {
3161 "remarks": [ "Set voltage rule" ],
3162 "id": "set_voltage_rule",
3163 "actions": [
3164 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } }
3165 ]
3166 }
3167 )"_json;
3168 parseRule(element);
3169 ADD_FAILURE() << "Should not have reached this line.";
3170 }
3171 catch (const std::invalid_argument& e)
3172 {
3173 EXPECT_STREQ(e.what(), "Element contains an invalid property");
3174 }
3175}
3176
3177TEST(ConfigFileParserTests, ParseRuleArray)
3178{
3179 // Test where works
3180 {
3181 const json element = R"(
3182 [
3183 {
3184 "id": "set_voltage_rule1",
3185 "actions": [
3186 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } }
3187 ]
3188 },
3189 {
3190 "id": "set_voltage_rule2",
3191 "actions": [
3192 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } },
3193 { "pmbus_write_vout_command": { "volts": 1.11, "format": "linear" } }
3194 ]
3195 }
3196 ]
3197 )"_json;
3198 std::vector<std::unique_ptr<Rule>> rules = parseRuleArray(element);
3199 EXPECT_EQ(rules.size(), 2);
3200 EXPECT_EQ(rules[0]->getID(), "set_voltage_rule1");
3201 EXPECT_EQ(rules[0]->getActions().size(), 1);
3202 EXPECT_EQ(rules[1]->getID(), "set_voltage_rule2");
3203 EXPECT_EQ(rules[1]->getActions().size(), 2);
3204 }
3205
3206 // Test where fails: Element is not an array
3207 try
3208 {
3209 const json element = R"( { "id": "set_voltage_rule" } )"_json;
3210 parseRuleArray(element);
3211 ADD_FAILURE() << "Should not have reached this line.";
3212 }
3213 catch (const std::invalid_argument& e)
3214 {
3215 EXPECT_STREQ(e.what(), "Element is not an array");
3216 }
3217}
3218
Bob King33e7eaa2020-04-01 18:09:34 +08003219TEST(ConfigFileParserTests, ParseRuleIDOrActionsProperty)
3220{
3221 // Test where works: actions specified
3222 {
3223 const json element = R"(
3224 {
3225 "actions": [
3226 { "pmbus_write_vout_command": { "format": "linear" } },
3227 { "run_rule": "set_voltage_rule" }
3228 ]
3229 }
3230 )"_json;
3231 std::vector<std::unique_ptr<Action>> actions =
3232 parseRuleIDOrActionsProperty(element);
3233 EXPECT_EQ(actions.size(), 2);
3234 }
3235
3236 // Test where works: rule_id specified
3237 {
3238 const json element = R"(
3239 {
3240 "rule_id": "set_voltage_rule"
3241 }
3242 )"_json;
3243 std::vector<std::unique_ptr<Action>> actions =
3244 parseRuleIDOrActionsProperty(element);
3245 EXPECT_EQ(actions.size(), 1);
3246 }
3247
3248 // Test where fails: Element is not an object
3249 try
3250 {
3251 const json element = R"( [ "foo", "bar" ] )"_json;
3252 parseRuleIDOrActionsProperty(element);
3253 ADD_FAILURE() << "Should not have reached this line.";
3254 }
3255 catch (const std::invalid_argument& e)
3256 {
3257 EXPECT_STREQ(e.what(), "Element is not an object");
3258 }
3259
3260 // Test where fails: rule_id is invalid
3261 try
3262 {
3263 const json element = R"(
3264 { "rule_id": 1 }
3265 )"_json;
3266 parseRuleIDOrActionsProperty(element);
3267 ADD_FAILURE() << "Should not have reached this line.";
3268 }
3269 catch (const std::invalid_argument& e)
3270 {
3271 EXPECT_STREQ(e.what(), "Element is not a string");
3272 }
3273
3274 // Test where fails: actions is invalid
3275 try
3276 {
3277 const json element = R"(
3278 { "actions": 1 }
3279 )"_json;
3280 parseRuleIDOrActionsProperty(element);
3281 ADD_FAILURE() << "Should not have reached this line.";
3282 }
3283 catch (const std::invalid_argument& e)
3284 {
3285 EXPECT_STREQ(e.what(), "Element is not an array");
3286 }
3287
3288 // Test where fails: Neither rule_id nor actions specified
3289 try
3290 {
3291 const json element = R"(
3292 {
3293 "volts": 1.03
3294 }
3295 )"_json;
3296 parseRuleIDOrActionsProperty(element);
3297 ADD_FAILURE() << "Should not have reached this line.";
3298 }
3299 catch (const std::invalid_argument& e)
3300 {
3301 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain "
3302 "either rule_id or actions");
3303 }
3304
3305 // Test where fails: Both rule_id and actions specified
3306 try
3307 {
3308 const json element = R"(
3309 {
3310 "volts": 1.03,
3311 "rule_id": "set_voltage_rule",
3312 "actions": [
3313 {
3314 "pmbus_write_vout_command": {
3315 "format": "linear"
3316 }
3317 }
3318 ]
3319 }
3320 )"_json;
3321 parseRuleIDOrActionsProperty(element);
3322 ADD_FAILURE() << "Should not have reached this line.";
3323 }
3324 catch (const std::invalid_argument& e)
3325 {
3326 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain "
3327 "either rule_id or actions");
3328 }
3329}
3330
Bob King315b0b62020-04-03 21:47:58 +08003331TEST(ConfigFileParserTests, ParseRunRule)
3332{
3333 // Test where works
3334 {
3335 const json element = "vdd_regulator";
3336 std::unique_ptr<RunRuleAction> action = parseRunRule(element);
3337 EXPECT_EQ(action->getRuleID(), "vdd_regulator");
3338 }
3339
3340 // Test where fails: Element is not a string
3341 try
3342 {
3343 const json element = 1;
3344 parseRunRule(element);
3345 ADD_FAILURE() << "Should not have reached this line.";
3346 }
3347 catch (const std::invalid_argument& e)
3348 {
3349 EXPECT_STREQ(e.what(), "Element is not a string");
3350 }
3351
3352 // Test where fails: Empty string
3353 try
3354 {
3355 const json element = "";
3356 parseRunRule(element);
3357 ADD_FAILURE() << "Should not have reached this line.";
3358 }
3359 catch (const std::invalid_argument& e)
3360 {
3361 EXPECT_STREQ(e.what(), "Element contains an empty string");
3362 }
3363}
3364
Bob Kinga2f2a0d2020-04-09 13:32:14 +08003365TEST(ConfigFileParserTests, ParseSensorMonitoring)
3366{
3367 // Test where works: actions property specified
3368 {
3369 const json element = R"(
3370 {
3371 "actions": [
3372 { "run_rule": "read_sensors_rule" }
3373 ]
3374 }
3375 )"_json;
3376 std::unique_ptr<SensorMonitoring> sensorMonitoring =
3377 parseSensorMonitoring(element);
3378 EXPECT_EQ(sensorMonitoring->getActions().size(), 1);
3379 }
3380
3381 // Test where works: rule_id property specified
3382 {
3383 const json element = R"(
3384 {
3385 "comments": [ "comments property" ],
3386 "rule_id": "set_voltage_rule"
3387 }
3388 )"_json;
3389 std::unique_ptr<SensorMonitoring> sensorMonitoring =
3390 parseSensorMonitoring(element);
3391 EXPECT_EQ(sensorMonitoring->getActions().size(), 1);
3392 }
3393
3394 // Test where fails: actions object is invalid
3395 try
3396 {
3397 const json element = R"(
3398 {
3399 "actions": 1
3400 }
3401 )"_json;
3402 parseSensorMonitoring(element);
3403 ADD_FAILURE() << "Should not have reached this line.";
3404 }
3405 catch (const std::invalid_argument& e)
3406 {
3407 EXPECT_STREQ(e.what(), "Element is not an array");
3408 }
3409
3410 // Test where fails: rule_id value is invalid
3411 try
3412 {
3413 const json element = R"(
3414 {
3415 "rule_id": 1
3416 }
3417 )"_json;
3418 parseSensorMonitoring(element);
3419 ADD_FAILURE() << "Should not have reached this line.";
3420 }
3421 catch (const std::invalid_argument& e)
3422 {
3423 EXPECT_STREQ(e.what(), "Element is not a string");
3424 }
3425
3426 // Test where fails: Required actions or rule_id property not specified
3427 try
3428 {
3429 const json element = R"(
3430 {
3431 "comments": [ "comments property" ]
3432 }
3433 )"_json;
3434 parseSensorMonitoring(element);
3435 ADD_FAILURE() << "Should not have reached this line.";
3436 }
3437 catch (const std::invalid_argument& e)
3438 {
3439 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain "
3440 "either rule_id or actions");
3441 }
3442
3443 // Test where fails: Required actions or rule_id property both specified
3444 try
3445 {
3446 const json element = R"(
3447 {
3448 "rule_id": "set_voltage_rule",
3449 "actions": [
3450 { "run_rule": "read_sensors_rule" }
3451 ]
3452 }
3453 )"_json;
3454 parseSensorMonitoring(element);
3455 ADD_FAILURE() << "Should not have reached this line.";
3456 }
3457 catch (const std::invalid_argument& e)
3458 {
3459 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain "
3460 "either rule_id or actions");
3461 }
3462
3463 // Test where fails: Element is not an object
3464 try
3465 {
3466 const json element = R"( [ "foo", "bar" ] )"_json;
3467 parseSensorMonitoring(element);
3468 ADD_FAILURE() << "Should not have reached this line.";
3469 }
3470 catch (const std::invalid_argument& e)
3471 {
3472 EXPECT_STREQ(e.what(), "Element is not an object");
3473 }
3474
3475 // Test where fails: Invalid property specified
3476 try
3477 {
3478 const json element = R"(
3479 {
3480 "foo": "bar",
3481 "actions": [
3482 { "run_rule": "read_sensors_rule" }
3483 ]
3484 }
3485 )"_json;
3486 parseSensorMonitoring(element);
3487 ADD_FAILURE() << "Should not have reached this line.";
3488 }
3489 catch (const std::invalid_argument& e)
3490 {
3491 EXPECT_STREQ(e.what(), "Element contains an invalid property");
3492 }
3493}
3494
Shawn McCarney0e8c68a2020-03-27 01:44:48 -05003495TEST(ConfigFileParserTests, ParseString)
3496{
3497 // Test where works: Empty string
3498 {
3499 const json element = "";
3500 std::string value = parseString(element, true);
3501 EXPECT_EQ(value, "");
3502 }
3503
3504 // Test where works: Non-empty string
3505 {
3506 const json element = "vdd_regulator";
3507 std::string value = parseString(element, false);
3508 EXPECT_EQ(value, "vdd_regulator");
3509 }
3510
3511 // Test where fails: Element is not a string
3512 try
3513 {
3514 const json element = R"( { "foo": "bar" } )"_json;
3515 parseString(element);
3516 ADD_FAILURE() << "Should not have reached this line.";
3517 }
3518 catch (const std::invalid_argument& e)
3519 {
3520 EXPECT_STREQ(e.what(), "Element is not a string");
3521 }
3522
3523 // Test where fails: Empty string
3524 try
3525 {
3526 const json element = "";
3527 parseString(element);
3528 ADD_FAILURE() << "Should not have reached this line.";
3529 }
3530 catch (const std::invalid_argument& e)
3531 {
3532 EXPECT_STREQ(e.what(), "Element contains an empty string");
3533 }
3534}
3535
Bob Kingf617f892020-03-30 19:03:35 +08003536TEST(ConfigFileParserTests, ParseUint8)
3537{
3538 // Test where works: 0
3539 {
3540 const json element = R"( 0 )"_json;
3541 uint8_t value = parseUint8(element);
3542 EXPECT_EQ(value, 0);
3543 }
3544
3545 // Test where works: UINT8_MAX
3546 {
3547 const json element = R"( 255 )"_json;
3548 uint8_t value = parseUint8(element);
3549 EXPECT_EQ(value, 255);
3550 }
3551
3552 // Test where fails: Element is not an integer
3553 try
3554 {
3555 const json element = R"( 1.03 )"_json;
3556 parseUint8(element);
3557 ADD_FAILURE() << "Should not have reached this line.";
3558 }
3559 catch (const std::invalid_argument& e)
3560 {
3561 EXPECT_STREQ(e.what(), "Element is not an integer");
3562 }
3563
3564 // Test where fails: Value < 0
3565 try
3566 {
3567 const json element = R"( -1 )"_json;
3568 parseUint8(element);
3569 ADD_FAILURE() << "Should not have reached this line.";
3570 }
3571 catch (const std::invalid_argument& e)
3572 {
3573 EXPECT_STREQ(e.what(), "Element is not an 8-bit unsigned integer");
3574 }
3575
3576 // Test where fails: Value > UINT8_MAX
3577 try
3578 {
3579 const json element = R"( 256 )"_json;
3580 parseUint8(element);
3581 ADD_FAILURE() << "Should not have reached this line.";
3582 }
3583 catch (const std::invalid_argument& e)
3584 {
3585 EXPECT_STREQ(e.what(), "Element is not an 8-bit unsigned integer");
3586 }
3587}
3588
Bob King0e701132020-04-03 21:50:31 +08003589TEST(ConfigFileParserTests, ParseUnsignedInteger)
3590{
3591 // Test where works: 1
3592 {
3593 const json element = R"( 1 )"_json;
3594 unsigned int value = parseUnsignedInteger(element);
3595 EXPECT_EQ(value, 1);
3596 }
3597
3598 // Test where fails: Element is not an integer
3599 try
3600 {
3601 const json element = R"( 1.5 )"_json;
3602 parseUnsignedInteger(element);
3603 ADD_FAILURE() << "Should not have reached this line.";
3604 }
3605 catch (const std::invalid_argument& e)
3606 {
3607 EXPECT_STREQ(e.what(), "Element is not an unsigned integer");
3608 }
3609
3610 // Test where fails: Value < 0
3611 try
3612 {
3613 const json element = R"( -1 )"_json;
3614 parseUnsignedInteger(element);
3615 ADD_FAILURE() << "Should not have reached this line.";
3616 }
3617 catch (const std::invalid_argument& e)
3618 {
3619 EXPECT_STREQ(e.what(), "Element is not an unsigned integer");
3620 }
3621}
3622
Shawn McCarney0e8c68a2020-03-27 01:44:48 -05003623TEST(ConfigFileParserTests, VerifyIsArray)
3624{
3625 // Test where element is an array
3626 try
3627 {
3628 const json element = R"( [ "foo", "bar" ] )"_json;
3629 verifyIsArray(element);
3630 }
3631 catch (const std::exception& e)
3632 {
3633 ADD_FAILURE() << "Should not have caught exception.";
3634 }
3635
3636 // Test where element is not an array
3637 try
3638 {
3639 const json element = R"( { "foo": "bar" } )"_json;
3640 verifyIsArray(element);
3641 ADD_FAILURE() << "Should not have reached this line.";
3642 }
3643 catch (const std::invalid_argument& e)
3644 {
3645 EXPECT_STREQ(e.what(), "Element is not an array");
3646 }
3647}
3648
3649TEST(ConfigFileParserTests, VerifyIsObject)
3650{
3651 // Test where element is an object
3652 try
3653 {
3654 const json element = R"( { "foo": "bar" } )"_json;
3655 verifyIsObject(element);
3656 }
3657 catch (const std::exception& e)
3658 {
3659 ADD_FAILURE() << "Should not have caught exception.";
3660 }
3661
3662 // Test where element is not an object
3663 try
3664 {
3665 const json element = R"( [ "foo", "bar" ] )"_json;
3666 verifyIsObject(element);
3667 ADD_FAILURE() << "Should not have reached this line.";
3668 }
3669 catch (const std::invalid_argument& e)
3670 {
3671 EXPECT_STREQ(e.what(), "Element is not an object");
3672 }
3673}
3674
3675TEST(ConfigFileParserTests, VerifyPropertyCount)
3676{
3677 // Test where element has expected number of properties
3678 try
3679 {
3680 const json element = R"(
3681 {
3682 "comments": [ "Set voltage rule" ],
3683 "id": "set_voltage_rule"
3684 }
3685 )"_json;
3686 verifyPropertyCount(element, 2);
3687 }
3688 catch (const std::exception& e)
3689 {
3690 ADD_FAILURE() << "Should not have caught exception.";
3691 }
3692
3693 // Test where element has unexpected number of properties
3694 try
3695 {
3696 const json element = R"(
3697 {
3698 "comments": [ "Set voltage rule" ],
3699 "id": "set_voltage_rule",
3700 "foo": 1.3
3701 }
3702 )"_json;
3703 verifyPropertyCount(element, 2);
3704 ADD_FAILURE() << "Should not have reached this line.";
3705 }
3706 catch (const std::invalid_argument& e)
3707 {
3708 EXPECT_STREQ(e.what(), "Element contains an invalid property");
3709 }
3710}