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