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