1 /**
2  * Copyright c 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 "temporary_file.hpp"
17 
18 #include <stdio.h>    // for popen(), pclose(), fgets()
19 #include <sys/stat.h> // for chmod()
20 #include <sys/wait.h> // for WEXITSTATUS
21 
22 #include <nlohmann/json.hpp>
23 
24 #include <cstdio>
25 #include <fstream>
26 
27 #include <gtest/gtest.h>
28 
29 #define EXPECT_FILE_VALID(configFile) expectFileValid(configFile)
30 #define EXPECT_FILE_INVALID(configFile, expectedErrorMessage,                  \
31                             expectedOutputMessage)                             \
32     expectFileInvalid(configFile, expectedErrorMessage, expectedOutputMessage)
33 #define EXPECT_JSON_VALID(configFileJson) expectJsonValid(configFileJson)
34 #define EXPECT_JSON_INVALID(configFileJson, expectedErrorMessage,              \
35                             expectedOutputMessage)                             \
36     expectJsonInvalid(configFileJson, expectedErrorMessage,                    \
37                       expectedOutputMessage)
38 
39 using namespace phosphor::power::regulators;
40 using json = nlohmann::json;
41 
42 const json validConfigFile = R"(
43     {
44       "comments": [ "Config file for a FooBar one-chassis system" ],
45 
46       "rules": [
47         {
48           "comments": [ "Sets output voltage for a PMBus regulator rail" ],
49           "id": "set_voltage_rule",
50           "actions": [
51             {
52               "pmbus_write_vout_command": {
53                 "format": "linear"
54               }
55             }
56           ]
57         },
58         {
59           "comments": [ "Reads sensors from a PMBus regulator rail" ],
60           "id": "read_sensors_rule",
61           "actions": [
62             {
63               "comments": [ "Read output voltage from READ_VOUT." ],
64               "pmbus_read_sensor": {
65                 "type": "vout",
66                 "command": "0x8B",
67                 "format": "linear_16"
68               }
69             }
70           ]
71         }
72       ],
73 
74       "chassis": [
75         {
76           "comments": [ "Chassis number 1 containing CPUs and memory" ],
77           "number": 1,
78           "inventory_path": "system/chassis",
79           "devices": [
80             {
81               "comments": [ "IR35221 regulator producing the Vdd rail" ],
82               "id": "vdd_regulator",
83               "is_regulator": true,
84               "fru": "system/chassis/motherboard/regulator1",
85               "i2c_interface": {
86                 "bus": 1,
87                 "address": "0x70"
88               },
89               "rails": [
90                 {
91                   "comments": [ "Vdd rail" ],
92                   "id": "vdd",
93                   "configuration": {
94                     "volts": 1.03,
95                     "rule_id": "set_voltage_rule"
96                   },
97                   "sensor_monitoring": {
98                     "rule_id": "read_sensors_rule"
99                   }
100                 }
101               ]
102             }
103           ]
104         }
105       ]
106     }
107 )"_json;
108 
109 std::string getValidationToolCommand(const std::string& configFileName)
110 {
111     std::string command =
112         "../phosphor-regulators/tools/validate-regulators-config.py -s \
113          ../phosphor-regulators/schema/config_schema.json -c ";
114     command += configFileName;
115     return command;
116 }
117 
118 int runToolForOutputWithCommand(std::string command,
119                                 std::string& standardOutput,
120                                 std::string& standardError)
121 {
122     // run the validation tool with the temporary file and return the output
123     // of the validation tool.
124     TemporaryFile tmpFile;
125     command += " 2> " + tmpFile.getPath().string();
126     // get the jsonschema print from validation tool.
127     char buffer[256];
128     std::string result;
129     // to get the stdout from the validation tool.
130     FILE* pipe = popen(command.c_str(), "r");
131     if (!pipe)
132     {
133         throw std::runtime_error("popen() failed!");
134     }
135     while (!std::feof(pipe))
136     {
137         if (fgets(buffer, sizeof buffer, pipe) != NULL)
138         {
139             result += buffer;
140         }
141     }
142     int returnValue = pclose(pipe);
143     // Check if pclose() failed
144     if (returnValue == -1)
145     {
146         // unable to close pipe.  Print error and exit function.
147         throw std::runtime_error("pclose() failed!");
148     }
149     std::string firstLine = result.substr(0, result.find('\n'));
150     standardOutput = firstLine;
151     // Get command exit status from return value
152     int exitStatus = WEXITSTATUS(returnValue);
153 
154     // Read the standardError from tmpFile.
155     std::ifstream input(tmpFile.getPath());
156     std::string line;
157 
158     if (std::getline(input, line))
159     {
160         standardError = line;
161     }
162 
163     return exitStatus;
164 }
165 
166 int runToolForOutput(const std::string& configFileName, std::string& output,
167                      std::string& error)
168 {
169     std::string command = getValidationToolCommand(configFileName);
170     return runToolForOutputWithCommand(command, output, error);
171 }
172 
173 void expectFileValid(const std::string& configFileName)
174 {
175     std::string errorMessage;
176     std::string outputMessage;
177     EXPECT_EQ(runToolForOutput(configFileName, outputMessage, errorMessage), 0);
178     EXPECT_EQ(errorMessage, "");
179     EXPECT_EQ(outputMessage, "");
180 }
181 
182 void expectFileInvalid(const std::string& configFileName,
183                        const std::string& expectedErrorMessage,
184                        const std::string& expectedOutputMessage)
185 {
186     std::string errorMessage;
187     std::string outputMessage;
188     EXPECT_EQ(runToolForOutput(configFileName, outputMessage, errorMessage), 1);
189     EXPECT_EQ(errorMessage, expectedErrorMessage);
190     EXPECT_EQ(outputMessage, expectedOutputMessage);
191 }
192 
193 void writeDataToFile(const json configFileJson, std::string fileName)
194 {
195     std::string jsonData = configFileJson.dump();
196     std::ofstream out(fileName);
197     out << jsonData;
198     out.close();
199 }
200 
201 void expectJsonValid(const json configFileJson)
202 {
203     TemporaryFile tmpFile;
204     std::string fileName = tmpFile.getPath().string();
205     writeDataToFile(configFileJson, fileName);
206 
207     EXPECT_FILE_VALID(fileName);
208 }
209 
210 void expectJsonInvalid(const json configFileJson,
211                        const std::string& expectedErrorMessage,
212                        const std::string& expectedOutputMessage)
213 {
214     TemporaryFile tmpFile;
215     std::string fileName = tmpFile.getPath().string();
216     writeDataToFile(configFileJson, fileName);
217 
218     EXPECT_FILE_INVALID(fileName, expectedErrorMessage, expectedOutputMessage);
219 }
220 
221 void expectCommandLineSyntax(const std::string& expectedErrorMessage,
222                              const std::string& expectedOutputMessage,
223                              const std::string& command, int status)
224 {
225     std::string errorMessage;
226     std::string outputMessage;
227     EXPECT_EQ(runToolForOutputWithCommand(command, outputMessage, errorMessage),
228               status);
229     EXPECT_EQ(errorMessage, expectedErrorMessage);
230     EXPECT_EQ(outputMessage, expectedOutputMessage);
231 }
232 
233 TEST(ValidateRegulatorsConfigTest, Action)
234 {
235     // Valid: Comments property not specified
236     {
237         json configFile = validConfigFile;
238         EXPECT_JSON_VALID(configFile);
239     }
240     // Valid: Comments property specified
241     {
242         json configFile = validConfigFile;
243         configFile["rules"][0]["actions"][0]["comments"][0] =
244             "Set VOUT_COMMAND";
245         EXPECT_JSON_VALID(configFile);
246     }
247     // Valid: and action type specified
248     {
249         json configFile = validConfigFile;
250         json andAction =
251             R"(
252                 {
253                  "and": [
254                     { "i2c_compare_byte": { "register": "0xA0", "value": "0x00" } },
255                     { "i2c_compare_byte": { "register": "0xA1", "value": "0x00" } }
256                   ]
257                 }
258             )"_json;
259         configFile["rules"][0]["actions"].push_back(andAction);
260         EXPECT_JSON_VALID(configFile);
261     }
262     // Valid: compare_presence action type specified
263     {
264         json configFile = validConfigFile;
265         configFile["rules"][0]["actions"][1]["compare_presence"]["fru"] =
266             "system/chassis/motherboard/regulator2";
267         configFile["rules"][0]["actions"][1]["compare_presence"]["value"] =
268             true;
269         EXPECT_JSON_VALID(configFile);
270     }
271     // Valid: compare_vpd action type specified
272     {
273         json configFile = validConfigFile;
274         configFile["rules"][0]["actions"][1]["compare_vpd"]["fru"] =
275             "system/chassis/motherboard/regulator2";
276         configFile["rules"][0]["actions"][1]["compare_vpd"]["keyword"] = "CCIN";
277         configFile["rules"][0]["actions"][1]["compare_vpd"]["value"] = "2D35";
278         EXPECT_JSON_VALID(configFile);
279     }
280     // Valid: i2c_compare_bit action type specified
281     {
282         json configFile = validConfigFile;
283         configFile["rules"][0]["actions"][1]["i2c_compare_bit"]["register"] =
284             "0xA0";
285         configFile["rules"][0]["actions"][1]["i2c_compare_bit"]["position"] = 3;
286         configFile["rules"][0]["actions"][1]["i2c_compare_bit"]["value"] = 1;
287         EXPECT_JSON_VALID(configFile);
288     }
289     // Valid: i2c_compare_byte action type specified
290     {
291         json configFile = validConfigFile;
292         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["register"] =
293             "0x82";
294         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["value"] =
295             "0x40";
296         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["mask"] =
297             "0x7F";
298         EXPECT_JSON_VALID(configFile);
299     }
300     // Valid: i2c_compare_bytes action type specified
301     {
302         json configFile = validConfigFile;
303         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["register"] =
304             "0x82";
305         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["values"] = {
306             "0x02", "0x73"};
307         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["masks"] = {
308             "0x7F", "0x7F"};
309         EXPECT_JSON_VALID(configFile);
310     }
311     // Valid: i2c_write_bit action type specified
312     {
313         json configFile = validConfigFile;
314         configFile["rules"][0]["actions"][1]["i2c_write_bit"]["register"] =
315             "0xA0";
316         configFile["rules"][0]["actions"][1]["i2c_write_bit"]["position"] = 3;
317         configFile["rules"][0]["actions"][1]["i2c_write_bit"]["value"] = 1;
318         EXPECT_JSON_VALID(configFile);
319     }
320     // Valid: i2c_write_byte action type specified
321     {
322         json configFile = validConfigFile;
323         configFile["rules"][0]["actions"][1]["i2c_write_byte"]["register"] =
324             "0x82";
325         configFile["rules"][0]["actions"][1]["i2c_write_byte"]["value"] =
326             "0x40";
327         configFile["rules"][0]["actions"][1]["i2c_write_byte"]["mask"] = "0x7F";
328         EXPECT_JSON_VALID(configFile);
329     }
330     // Valid: i2c_write_bytes action type specified
331     {
332         json configFile = validConfigFile;
333         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["register"] =
334             "0x82";
335         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["values"] = {
336             "0x02", "0x73"};
337         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["masks"] = {
338             "0x7F", "0x7F"};
339         EXPECT_JSON_VALID(configFile);
340     }
341     // Valid: if action type specified
342     {
343         json configFile = validConfigFile;
344         configFile["rules"][2]["actions"][0]["if"]["condition"]["run_rule"] =
345             "set_voltage_rule";
346         configFile["rules"][2]["actions"][0]["if"]["then"][0]["run_rule"] =
347             "read_sensors_rule";
348         configFile["rules"][2]["actions"][0]["if"]["else"][0]["run_rule"] =
349             "read_sensors_rule";
350         configFile["rules"][2]["id"] = "rule_if";
351         EXPECT_JSON_VALID(configFile);
352     }
353     // Valid: not action type specified
354     {
355         json configFile = validConfigFile;
356         configFile["rules"][0]["actions"][1]["not"]["i2c_compare_byte"]
357                   ["register"] = "0xA0";
358         configFile["rules"][0]["actions"][1]["not"]["i2c_compare_byte"]
359                   ["value"] = "0xFF";
360         EXPECT_JSON_VALID(configFile);
361     }
362     // Valid: or action type specified
363     {
364         json configFile = validConfigFile;
365         configFile["rules"][0]["actions"][1]["or"][0]["i2c_compare_byte"]
366                   ["register"] = "0xA0";
367         configFile["rules"][0]["actions"][1]["or"][0]["i2c_compare_byte"]
368                   ["value"] = "0x00";
369         configFile["rules"][0]["actions"][1]["or"][1]["i2c_compare_byte"]
370                   ["register"] = "0xA1";
371         configFile["rules"][0]["actions"][1]["or"][1]["i2c_compare_byte"]
372                   ["value"] = "0x00";
373         EXPECT_JSON_VALID(configFile);
374     }
375     // Valid: pmbus_read_sensor and pmbus_write_vout_command action type
376     // specified
377     {
378         EXPECT_JSON_VALID(validConfigFile);
379     }
380     // Valid: run_rule action type specified
381     {
382         json configFile = validConfigFile;
383         configFile["rules"][0]["actions"][1]["run_rule"] = "read_sensors_rule";
384         EXPECT_JSON_VALID(configFile);
385     }
386     // Valid: set_device action type specified
387     {
388         json configFile = validConfigFile;
389         configFile["rules"][0]["actions"][1]["set_device"] = "vdd_regulator";
390         EXPECT_JSON_VALID(configFile);
391     }
392     // Invalid: Wrong data type for comments (should be array of string)
393     {
394         json configFile = validConfigFile;
395         configFile["rules"][0]["actions"][0]["comments"] = true;
396         EXPECT_JSON_INVALID(configFile, "Validation failed.",
397                             "True is not of type 'array'");
398     }
399     // Invalid: Wrong data type for action type (such as "i2c_write_byte": true)
400     {
401         json configFile = validConfigFile;
402         configFile["rules"][0]["actions"][1]["i2c_write_byte"] = true;
403         EXPECT_JSON_INVALID(configFile, "Validation failed.",
404                             "True is not of type 'object'");
405     }
406     // Invalid: Empty comments array
407     {
408         json configFile = validConfigFile;
409         configFile["rules"][0]["actions"][0]["comments"] = json::array();
410         EXPECT_JSON_INVALID(configFile, "Validation failed.",
411                             "[] is too short");
412     }
413     // Invalid: Comments array has wrong element type (should be string)
414     {
415         json configFile = validConfigFile;
416         configFile["rules"][0]["actions"][0]["comments"][0] = true;
417         EXPECT_JSON_INVALID(configFile, "Validation failed.",
418                             "True is not of type 'string'");
419     }
420     // Invalid: No action type specified
421     {
422         json configFile = validConfigFile;
423         configFile["rules"][0]["actions"][1]["comments"][0] =
424             "Check if bit 3 is on";
425         EXPECT_JSON_INVALID(configFile, "Validation failed.",
426                             "'and' is a required property");
427     }
428     // Invalid: Multiple action types specified (such as both 'compare_presence'
429     // and 'pmbus_write_vout_command')
430     {
431         json configFile = validConfigFile;
432         configFile["rules"][0]["actions"][0]["compare_presence"]["value"] =
433             true;
434         EXPECT_JSON_INVALID(
435             configFile, "Validation failed.",
436             "{'compare_presence': {'value': True}, 'pmbus_write_vout_command': "
437             "{'format': 'linear'}} is valid under each of {'required': "
438             "['pmbus_write_vout_command']}, {'required': "
439             "['compare_presence']}");
440     }
441     // Invalid: Unexpected property specified (like 'foo')
442     {
443         json configFile = validConfigFile;
444         configFile["rules"][0]["actions"][1]["foo"] = "foo";
445         EXPECT_JSON_INVALID(
446             configFile, "Validation failed.",
447             "Additional properties are not allowed ('foo' was unexpected)");
448     }
449 }
450 TEST(ValidateRegulatorsConfigTest, And)
451 {
452     // Valid.
453     {
454         json configFile = validConfigFile;
455         json andAction =
456             R"(
457                 {
458                  "and": [
459                     { "i2c_compare_byte": { "register": "0xA0", "value": "0x00" } },
460                     { "i2c_compare_byte": { "register": "0xA1", "value": "0x00" } }
461                   ]
462                 }
463             )"_json;
464         configFile["rules"][0]["actions"].push_back(andAction);
465         EXPECT_JSON_VALID(configFile);
466     }
467 
468     // Invalid: actions property value is an empty array.
469     {
470         json configFile = validConfigFile;
471         json andAction =
472             R"(
473                 {
474                  "and": []
475                 }
476             )"_json;
477         configFile["rules"][0]["actions"].push_back(andAction);
478         EXPECT_JSON_INVALID(configFile, "Validation failed.",
479                             "[] is too short");
480     }
481 
482     // Invalid: actions property has incorrect value data type.
483     {
484         json configFile = validConfigFile;
485         json andAction =
486             R"(
487                 {
488                  "and": true
489                 }
490             )"_json;
491         configFile["rules"][0]["actions"].push_back(andAction);
492         EXPECT_JSON_INVALID(configFile, "Validation failed.",
493                             "True is not of type 'array'");
494     }
495 
496     // Invalid: actions property value contains wrong element type
497     {
498         json configFile = validConfigFile;
499         json andAction =
500             R"(
501                 {
502                  "and": ["foo"]
503                 }
504             )"_json;
505         configFile["rules"][0]["actions"].push_back(andAction);
506         EXPECT_JSON_INVALID(configFile, "Validation failed.",
507                             "'foo' is not of type 'object'");
508     }
509 }
510 TEST(ValidateRegulatorsConfigTest, Chassis)
511 {
512     // Valid: test chassis.
513     {
514         json configFile = validConfigFile;
515         EXPECT_JSON_VALID(configFile);
516     }
517     // Valid: test chassis with only required properties.
518     {
519         json configFile = validConfigFile;
520         configFile["chassis"][0].erase("comments");
521         configFile["chassis"][0].erase("inventory_path");
522         configFile["chassis"][0].erase("devices");
523         EXPECT_JSON_VALID(configFile);
524     }
525     // Invalid: test chassis with no number.
526     {
527         json configFile = validConfigFile;
528         configFile["chassis"][0].erase("number");
529         EXPECT_JSON_INVALID(configFile, "Validation failed.",
530                             "'number' is a required property");
531     }
532     // Invalid: test chassis with property comments wrong type.
533     {
534         json configFile = validConfigFile;
535         configFile["chassis"][0]["comments"] = true;
536         EXPECT_JSON_INVALID(configFile, "Validation failed.",
537                             "True is not of type 'array'");
538     }
539     // Invalid: test chassis with property number wrong type.
540     {
541         json configFile = validConfigFile;
542         configFile["chassis"][0]["number"] = 1.3;
543         EXPECT_JSON_INVALID(configFile, "Validation failed.",
544                             "1.3 is not of type 'integer'");
545     }
546     // Invalid: test chassis with property inventory_path wrong type.
547     {
548         json configFile = validConfigFile;
549         configFile["chassis"][0]["inventory_path"] = 2;
550         EXPECT_JSON_INVALID(configFile, "Validation failed.",
551                             "2 is not of type 'string'");
552     }
553     // Invalid: test chassis with property devices wrong type.
554     {
555         json configFile = validConfigFile;
556         configFile["chassis"][0]["devices"] = true;
557         EXPECT_JSON_INVALID(configFile, "Validation failed.",
558                             "True is not of type 'array'");
559     }
560     // Invalid: test chassis with property comments empty array.
561     {
562         json configFile = validConfigFile;
563         configFile["chassis"][0]["comments"] = json::array();
564         EXPECT_JSON_INVALID(configFile, "Validation failed.",
565                             "[] is too short");
566     }
567     // Invalid: test chassis with property devices empty array.
568     {
569         json configFile = validConfigFile;
570         configFile["chassis"][0]["devices"] = json::array();
571         EXPECT_JSON_INVALID(configFile, "Validation failed.",
572                             "[] is too short");
573     }
574     // Invalid: test chassis with property number less than 1.
575     {
576         json configFile = validConfigFile;
577         configFile["chassis"][0]["number"] = 0;
578         EXPECT_JSON_INVALID(configFile, "Validation failed.",
579                             "0 is less than the minimum of 1");
580     }
581     // Invalid: test chassis with property inventory_path empty string.
582     {
583         json configFile = validConfigFile;
584         configFile["chassis"][0]["inventory_path"] = "";
585         EXPECT_JSON_INVALID(configFile, "Validation failed.",
586                             "'' is too short");
587     }
588 }
589 TEST(ValidateRegulatorsConfigTest, ComparePresence)
590 {
591     json comparePresenceFile = validConfigFile;
592     comparePresenceFile["rules"][0]["actions"][1]["compare_presence"]["fru"] =
593         "system/chassis/motherboard/regulator2";
594     comparePresenceFile["rules"][0]["actions"][1]["compare_presence"]["value"] =
595         true;
596     // Valid.
597     {
598         json configFile = comparePresenceFile;
599         EXPECT_JSON_VALID(configFile);
600     }
601 
602     // Invalid: no FRU property.
603     {
604         json configFile = comparePresenceFile;
605         configFile["rules"][0]["actions"][1]["compare_presence"].erase("fru");
606         EXPECT_JSON_INVALID(configFile, "Validation failed.",
607                             "'fru' is a required property");
608     }
609 
610     // Invalid: FRU property length is string less than 1.
611     {
612         json configFile = comparePresenceFile;
613         configFile["rules"][0]["actions"][1]["compare_presence"]["fru"] = "";
614         EXPECT_JSON_INVALID(configFile, "Validation failed.",
615                             "'' is too short");
616     }
617 
618     // Invalid: no value property.
619     {
620         json configFile = comparePresenceFile;
621         configFile["rules"][0]["actions"][1]["compare_presence"].erase("value");
622         EXPECT_JSON_INVALID(configFile, "Validation failed.",
623                             "'value' is a required property");
624     }
625 
626     // Invalid: value property type is not boolean.
627     {
628         json configFile = comparePresenceFile;
629         configFile["rules"][0]["actions"][1]["compare_presence"]["value"] = "1";
630         EXPECT_JSON_INVALID(configFile, "Validation failed.",
631                             "'1' is not of type 'boolean'");
632     }
633 
634     // Invalid: FRU property type is not string.
635     {
636         json configFile = comparePresenceFile;
637         configFile["rules"][0]["actions"][1]["compare_presence"]["fru"] = 1;
638         EXPECT_JSON_INVALID(configFile, "Validation failed.",
639                             "1 is not of type 'string'");
640     }
641 }
642 TEST(ValidateRegulatorsConfigTest, CompareVpd)
643 {
644     json compareVpdFile = validConfigFile;
645     compareVpdFile["rules"][0]["actions"][1]["compare_vpd"]["fru"] =
646         "system/chassis/motherboard/regulator2";
647     compareVpdFile["rules"][0]["actions"][1]["compare_vpd"]["keyword"] = "CCIN";
648     compareVpdFile["rules"][0]["actions"][1]["compare_vpd"]["value"] = "2D35";
649 
650     // Valid.
651     {
652         json configFile = compareVpdFile;
653         EXPECT_JSON_VALID(configFile);
654     }
655 
656     // Invalid: no FRU property.
657     {
658         json configFile = compareVpdFile;
659         configFile["rules"][0]["actions"][1]["compare_vpd"].erase("fru");
660         EXPECT_JSON_INVALID(configFile, "Validation failed.",
661                             "'fru' is a required property");
662     }
663 
664     // Invalid: no keyword property.
665     {
666         json configFile = compareVpdFile;
667         configFile["rules"][0]["actions"][1]["compare_vpd"].erase("keyword");
668         EXPECT_JSON_INVALID(configFile, "Validation failed.",
669                             "'keyword' is a required property");
670     }
671 
672     // Invalid: no value property.
673     {
674         json configFile = compareVpdFile;
675         configFile["rules"][0]["actions"][1]["compare_vpd"].erase("value");
676         EXPECT_JSON_INVALID(configFile, "Validation failed.",
677                             "'value' is a required property");
678     }
679 
680     // Invalid: property FRU wrong type.
681     {
682         json configFile = compareVpdFile;
683         configFile["rules"][0]["actions"][1]["compare_vpd"]["fru"] = 1;
684         EXPECT_JSON_INVALID(configFile, "Validation failed.",
685                             "1 is not of type 'string'");
686     }
687 
688     // Invalid: property FRU is string less than 1.
689     {
690         json configFile = compareVpdFile;
691         configFile["rules"][0]["actions"][1]["compare_vpd"]["fru"] = "";
692         EXPECT_JSON_INVALID(configFile, "Validation failed.",
693                             "'' is too short");
694     }
695 
696     // Invalid: property keyword is not "CCIN", "Manufacturer", "Model",
697     // "PartNumber"
698     {
699         json configFile = compareVpdFile;
700         configFile["rules"][0]["actions"][1]["compare_vpd"]["keyword"] =
701             "Number";
702         EXPECT_JSON_INVALID(configFile, "Validation failed.",
703                             "'Number' is not one of ['CCIN', "
704                             "'Manufacturer', 'Model', 'PartNumber']");
705     }
706 
707     // Invalid: property value wrong type.
708     {
709         json configFile = compareVpdFile;
710         configFile["rules"][0]["actions"][1]["compare_vpd"]["value"] = 1;
711         EXPECT_JSON_INVALID(configFile, "Validation failed.",
712                             "1 is not of type 'string'");
713     }
714 }
715 TEST(ValidateRegulatorsConfigTest, ConfigFile)
716 {
717     // Valid: Only required properties specified
718     {
719         json configFile;
720         configFile["chassis"][0]["number"] = 1;
721         EXPECT_JSON_VALID(configFile);
722     }
723     // Valid: All properties specified
724     {
725         json configFile = validConfigFile;
726         EXPECT_JSON_VALID(configFile);
727     }
728     // Invalid: Required chassis property not specified
729     {
730         json configFile = validConfigFile;
731         configFile.erase("chassis");
732         EXPECT_JSON_INVALID(configFile, "Validation failed.",
733                             "'chassis' is a required property");
734     }
735     // Invalid: Wrong data type for comments
736     {
737         json configFile = validConfigFile;
738         configFile["comments"] = true;
739         EXPECT_JSON_INVALID(configFile, "Validation failed.",
740                             "True is not of type 'array'");
741     }
742     // Invalid: Wrong data type for rules
743     {
744         json configFile = validConfigFile;
745         configFile["rules"] = true;
746         EXPECT_JSON_INVALID(configFile, "Validation failed.",
747                             "True is not of type 'array'");
748     }
749     // Invalid: Wrong data type for chassis
750     {
751         json configFile = validConfigFile;
752         configFile["chassis"] = true;
753         EXPECT_JSON_INVALID(configFile, "Validation failed.",
754                             "True is not of type 'array'");
755     }
756     // Invalid: Empty comments array;
757     {
758         json configFile = validConfigFile;
759         configFile["comments"] = json::array();
760         EXPECT_JSON_INVALID(configFile, "Validation failed.",
761                             "[] is too short");
762     }
763     // Invalid: Empty rules array
764     {
765         json configFile = validConfigFile;
766         configFile["rules"] = json::array();
767         EXPECT_JSON_INVALID(configFile, "Validation failed.",
768                             "[] is too short");
769     }
770     // Invalid: Empty chassis array
771     {
772         json configFile = validConfigFile;
773         configFile["chassis"] = json::array();
774         EXPECT_JSON_INVALID(configFile, "Validation failed.",
775                             "[] is too short");
776     }
777     // Invalid: Comments array has wrong element type (should be string)
778     {
779         json configFile = validConfigFile;
780         configFile["comments"][0] = true;
781         EXPECT_JSON_INVALID(configFile, "Validation failed.",
782                             "True is not of type 'string'");
783     }
784     // Invalid: Rules array has wrong element type (should be rule)
785     {
786         json configFile = validConfigFile;
787         configFile["rules"][0] = true;
788         EXPECT_JSON_INVALID(configFile, "Validation failed.",
789                             "True is not of type 'object'");
790     }
791     // Invalid: Chassis array has wrong element type (should be chassis)
792     {
793         json configFile = validConfigFile;
794         configFile["chassis"][0] = true;
795         EXPECT_JSON_INVALID(configFile, "Validation failed.",
796                             "True is not of type 'object'");
797     }
798     // Invalid: Unexpected property specified
799     {
800         json configFile = validConfigFile;
801         configFile["foo"] = json::array();
802         EXPECT_JSON_INVALID(
803             configFile, "Validation failed.",
804             "Additional properties are not allowed ('foo' was unexpected)");
805     }
806 }
807 TEST(ValidateRegulatorsConfigTest, Configuration)
808 {
809     json configurationFile = validConfigFile;
810     configurationFile["chassis"][0]["devices"][0]["configuration"]["comments"]
811                      [0] = "Set rail to 1.25V using standard rule";
812     configurationFile["chassis"][0]["devices"][0]["configuration"]["volts"] =
813         1.25;
814     configurationFile["chassis"][0]["devices"][0]["configuration"]["rule_id"] =
815         "set_voltage_rule";
816     // Valid: test configuration with property rule_id and with no actions.
817     {
818         json configFile = configurationFile;
819         configFile["chassis"][0]["devices"][0]["configuration"]["comments"][1] =
820             "test multiple array elements in comments.";
821         EXPECT_JSON_VALID(configFile);
822     }
823     // Valid: test configuration with property actions and with no rule_id.
824     {
825         json configFile = configurationFile;
826         configFile["chassis"][0]["devices"][0]["configuration"].erase(
827             "rule_id");
828         configFile["chassis"][0]["devices"][0]["configuration"]["actions"][0]
829                   ["compare_presence"]["fru"] =
830                       "system/chassis/motherboard/cpu3";
831         configFile["chassis"][0]["devices"][0]["configuration"]["actions"][0]
832                   ["compare_presence"]["value"] = true;
833         EXPECT_JSON_VALID(configFile);
834     }
835     // Valid: comments not specified (optional property).
836     {
837         json configFile = configurationFile;
838         configFile["chassis"][0]["devices"][0]["configuration"].erase(
839             "comments");
840         EXPECT_JSON_VALID(configFile);
841     }
842     // Valid: volts not specified (optional property).
843     {
844         json configFile = configurationFile;
845         configFile["chassis"][0]["devices"][0]["configuration"].erase("volts");
846         EXPECT_JSON_VALID(configFile);
847     }
848     // Valid: configuration is property of a rail (vs. a device).
849     {
850         json configFile = validConfigFile;
851         configFile["chassis"][0]["devices"][0]["rails"][0]["configuration"]
852                   ["comments"][0] = "Set rail to 1.25V using standard rule";
853         configFile["chassis"][0]["devices"][0]["rails"][0]["configuration"]
854                   ["volts"] = 1.25;
855         configFile["chassis"][0]["devices"][0]["rails"][0]["configuration"]
856                   ["rule_id"] = "set_voltage_rule";
857         EXPECT_JSON_VALID(configFile);
858     }
859     // Invalid: comments property has wrong data type (not an array).
860     {
861         json configFile = configurationFile;
862         configFile["chassis"][0]["devices"][0]["configuration"]["comments"] = 1;
863         EXPECT_JSON_INVALID(configFile, "Validation failed.",
864                             "1 is not of type 'array'");
865     }
866     // Invalid: test configuration with both actions and rule_id properties.
867     {
868         json configFile = configurationFile;
869         configFile["chassis"][0]["devices"][0]["configuration"]["actions"][0]
870                   ["compare_presence"]["fru"] =
871                       "system/chassis/motherboard/cpu3";
872         configFile["chassis"][0]["devices"][0]["configuration"]["actions"][0]
873                   ["compare_presence"]["value"] = true;
874         EXPECT_JSON_INVALID(
875             configFile, "Validation failed.",
876             "{'actions': [{'compare_presence': {'fru': "
877             "'system/chassis/motherboard/cpu3', 'value': True}}], 'comments': "
878             "['Set rail to 1.25V using standard rule'], 'rule_id': "
879             "'set_voltage_rule', 'volts': 1.25} is valid under each of "
880             "{'required': ['actions']}, {'required': ['rule_id']}");
881     }
882     // Invalid: test configuration with no rule_id and actions.
883     {
884         json configFile = configurationFile;
885         configFile["chassis"][0]["devices"][0]["configuration"].erase(
886             "rule_id");
887         EXPECT_JSON_INVALID(configFile, "Validation failed.",
888                             "'rule_id' is a required property");
889     }
890     // Invalid: test configuration with property volts wrong type.
891     {
892         json configFile = configurationFile;
893         configFile["chassis"][0]["devices"][0]["configuration"]["volts"] = true;
894         EXPECT_JSON_INVALID(configFile, "Validation failed.",
895                             "True is not of type 'number'");
896     }
897     // Invalid: test configuration with property rule_id wrong type.
898     {
899         json configFile = configurationFile;
900         configFile["chassis"][0]["devices"][0]["configuration"]["rule_id"] =
901             true;
902         EXPECT_JSON_INVALID(configFile, "Validation failed.",
903                             "True is not of type 'string'");
904     }
905     // Invalid: test configuration with property actions wrong type.
906     {
907         json configFile = configurationFile;
908         configFile["chassis"][0]["devices"][0]["configuration"].erase(
909             "rule_id");
910         configFile["chassis"][0]["devices"][0]["configuration"]["actions"] =
911             true;
912         EXPECT_JSON_INVALID(configFile, "Validation failed.",
913                             "True is not of type 'array'");
914     }
915     // Invalid: test configuration with property comments empty array.
916     {
917         json configFile = configurationFile;
918         configFile["chassis"][0]["devices"][0]["configuration"]["comments"] =
919             json::array();
920         EXPECT_JSON_INVALID(configFile, "Validation failed.",
921                             "[] is too short");
922     }
923     // Invalid: test configuration with property rule_id wrong format.
924     {
925         json configFile = configurationFile;
926         configFile["chassis"][0]["devices"][0]["configuration"]["rule_id"] =
927             "id!";
928         EXPECT_JSON_INVALID(configFile, "Validation failed.",
929                             "'id!' does not match '^[A-Za-z0-9_]+$'");
930     }
931     // Invalid: test configuration with property actions empty array.
932     {
933         json configFile = configurationFile;
934         configFile["chassis"][0]["devices"][0]["configuration"].erase(
935             "rule_id");
936         configFile["chassis"][0]["devices"][0]["configuration"]["actions"] =
937             json::array();
938         EXPECT_JSON_INVALID(configFile, "Validation failed.",
939                             "[] is too short");
940     }
941 }
942 TEST(ValidateRegulatorsConfigTest, Device)
943 {
944 
945     // Valid: test devices.
946     {
947         json configFile = validConfigFile;
948         EXPECT_JSON_VALID(configFile);
949     }
950     // Valid: test devices with required properties.
951     {
952         json configFile = validConfigFile;
953         configFile["chassis"][0]["devices"][0].erase("comments");
954         configFile["chassis"][0]["devices"][0].erase("presence_detection");
955         configFile["chassis"][0]["devices"][0].erase("configuration");
956         configFile["chassis"][0]["devices"][0].erase("rails");
957         EXPECT_JSON_VALID(configFile);
958     }
959     // Invalid: test devices with no id.
960     {
961         json configFile = validConfigFile;
962         configFile["chassis"][0]["devices"][0].erase("id");
963         EXPECT_JSON_INVALID(configFile, "Validation failed.",
964                             "'id' is a required property");
965     }
966     // Invalid: test devices with no is_regulator.
967     {
968         json configFile = validConfigFile;
969         configFile["chassis"][0]["devices"][0].erase("is_regulator");
970         EXPECT_JSON_INVALID(configFile, "Validation failed.",
971                             "'is_regulator' is a required property");
972     }
973     // Invalid: test devices with no fru.
974     {
975         json configFile = validConfigFile;
976         configFile["chassis"][0]["devices"][0].erase("fru");
977         EXPECT_JSON_INVALID(configFile, "Validation failed.",
978                             "'fru' is a required property");
979     }
980     // Invalid: test devices with no i2c_interface.
981     {
982         json configFile = validConfigFile;
983         configFile["chassis"][0]["devices"][0].erase("i2c_interface");
984         EXPECT_JSON_INVALID(configFile, "Validation failed.",
985                             "'i2c_interface' is a required property");
986     }
987     // Invalid: test devices with property comments wrong type.
988     {
989         json configFile = validConfigFile;
990         configFile["chassis"][0]["devices"][0]["comments"] = true;
991         EXPECT_JSON_INVALID(configFile, "Validation failed.",
992                             "True is not of type 'array'");
993     }
994     // Invalid: test devices with property id wrong type.
995     {
996         json configFile = validConfigFile;
997         configFile["chassis"][0]["devices"][0]["id"] = true;
998         EXPECT_JSON_INVALID(configFile, "Validation failed.",
999                             "True is not of type 'string'");
1000     }
1001     // Invalid: test devices with property is_regulator wrong type.
1002     {
1003         json configFile = validConfigFile;
1004         configFile["chassis"][0]["devices"][0]["is_regulator"] = 1;
1005         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1006                             "1 is not of type 'boolean'");
1007     }
1008     // Invalid: test devices with property fru wrong type.
1009     {
1010         json configFile = validConfigFile;
1011         configFile["chassis"][0]["devices"][0]["fru"] = true;
1012         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1013                             "True is not of type 'string'");
1014     }
1015     // Invalid: test devices with property i2c_interface wrong type.
1016     {
1017         json configFile = validConfigFile;
1018         configFile["chassis"][0]["devices"][0]["i2c_interface"] = true;
1019         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1020                             "True is not of type 'object'");
1021     }
1022     // Invalid: test devices with property presence_detection wrong
1023     // type.
1024     {
1025         json configFile = validConfigFile;
1026         configFile["chassis"][0]["devices"][0]["presence_detection"] = true;
1027         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1028                             "True is not of type 'object'");
1029     }
1030     // Invalid: test devices with property configuration wrong type.
1031     {
1032         json configFile = validConfigFile;
1033         configFile["chassis"][0]["devices"][0]["configuration"] = true;
1034         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1035                             "True is not of type 'object'");
1036     }
1037     // Invalid: test devices with property rails wrong type.
1038     {
1039         json configFile = validConfigFile;
1040         configFile["chassis"][0]["devices"][0]["rails"] = true;
1041         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1042                             "True is not of type 'array'");
1043     }
1044     // Invalid: test devices with property comments empty array.
1045     {
1046         json configFile = validConfigFile;
1047         configFile["chassis"][0]["devices"][0]["comments"] = json::array();
1048         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1049                             "[] is too short");
1050     }
1051     // Invalid: test devices with property fru length less than 1.
1052     {
1053         json configFile = validConfigFile;
1054         configFile["chassis"][0]["devices"][0]["fru"] = "";
1055         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1056                             "'' is too short");
1057     }
1058     // Invalid: test devices with property id wrong format.
1059     {
1060         json configFile = validConfigFile;
1061         configFile["chassis"][0]["devices"][0]["id"] = "id#";
1062         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1063                             "'id#' does not match '^[A-Za-z0-9_]+$'");
1064     }
1065     // Invalid: test devices with property rails empty array.
1066     {
1067         json configFile = validConfigFile;
1068         configFile["chassis"][0]["devices"][0]["rails"] = json::array();
1069         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1070                             "[] is too short");
1071     }
1072 }
1073 TEST(ValidateRegulatorsConfigTest, I2CCompareBit)
1074 {
1075     json i2cCompareBitFile = validConfigFile;
1076     i2cCompareBitFile["rules"][0]["actions"][1]["i2c_compare_bit"]["register"] =
1077         "0xA0";
1078     i2cCompareBitFile["rules"][0]["actions"][1]["i2c_compare_bit"]["position"] =
1079         3;
1080     i2cCompareBitFile["rules"][0]["actions"][1]["i2c_compare_bit"]["value"] = 1;
1081     // Valid: test rule actions i2c_compare_bit.
1082     {
1083         json configFile = i2cCompareBitFile;
1084         EXPECT_JSON_VALID(configFile);
1085     }
1086     // Invalid: test i2c_compare_bit with no register.
1087     {
1088         json configFile = i2cCompareBitFile;
1089         configFile["rules"][0]["actions"][1]["i2c_compare_bit"].erase(
1090             "register");
1091         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1092                             "'register' is a required property");
1093     }
1094     // Invalid: test i2c_compare_bit with no position.
1095     {
1096         json configFile = i2cCompareBitFile;
1097         configFile["rules"][0]["actions"][1]["i2c_compare_bit"].erase(
1098             "position");
1099         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1100                             "'position' is a required property");
1101     }
1102     // Invalid: test i2c_compare_bit with no value.
1103     {
1104         json configFile = i2cCompareBitFile;
1105         configFile["rules"][0]["actions"][1]["i2c_compare_bit"].erase("value");
1106         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1107                             "'value' is a required property");
1108     }
1109     // Invalid: test i2c_compare_bit with register wrong type.
1110     {
1111         json configFile = i2cCompareBitFile;
1112         configFile["rules"][0]["actions"][1]["i2c_compare_bit"]["register"] = 1;
1113         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1114                             "1 is not of type 'string'");
1115     }
1116     // Invalid: test i2c_compare_bit with register wrong format.
1117     {
1118         json configFile = i2cCompareBitFile;
1119         configFile["rules"][0]["actions"][1]["i2c_compare_bit"]["register"] =
1120             "0xA00";
1121         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1122                             "'0xA00' does not match '^0x[0-9A-Fa-f]{2}$'");
1123     }
1124     // Invalid: test i2c_compare_bit with position wrong type.
1125     {
1126         json configFile = i2cCompareBitFile;
1127         configFile["rules"][0]["actions"][1]["i2c_compare_bit"]["position"] =
1128             3.1;
1129         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1130                             "3.1 is not of type 'integer'");
1131     }
1132     // Invalid: test i2c_compare_bit with position greater than 7.
1133     {
1134         json configFile = i2cCompareBitFile;
1135         configFile["rules"][0]["actions"][1]["i2c_compare_bit"]["position"] = 8;
1136         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1137                             "8 is greater than the maximum of 7");
1138     }
1139     // Invalid: test i2c_compare_bit with position less than 0.
1140     {
1141         json configFile = i2cCompareBitFile;
1142         configFile["rules"][0]["actions"][1]["i2c_compare_bit"]["position"] =
1143             -1;
1144         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1145                             "-1 is less than the minimum of 0");
1146     }
1147     // Invalid: test i2c_compare_bit with value wrong type.
1148     {
1149         json configFile = i2cCompareBitFile;
1150         configFile["rules"][0]["actions"][1]["i2c_compare_bit"]["value"] = "1";
1151         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1152                             "'1' is not of type 'integer'");
1153     }
1154     // Invalid: test i2c_compare_bit with value greater than 1.
1155     {
1156         json configFile = i2cCompareBitFile;
1157         configFile["rules"][0]["actions"][1]["i2c_compare_bit"]["value"] = 2;
1158         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1159                             "2 is greater than the maximum of 1");
1160     }
1161     // Invalid: test i2c_compare_bit with value less than 0.
1162     {
1163         json configFile = i2cCompareBitFile;
1164         configFile["rules"][0]["actions"][1]["i2c_compare_bit"]["value"] = -1;
1165         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1166                             "-1 is less than the minimum of 0");
1167     }
1168 }
1169 TEST(ValidateRegulatorsConfigTest, I2CCompareByte)
1170 {
1171     json i2cCompareByteFile = validConfigFile;
1172     i2cCompareByteFile["rules"][0]["actions"][1]["i2c_compare_byte"]
1173                       ["register"] = "0x82";
1174     i2cCompareByteFile["rules"][0]["actions"][1]["i2c_compare_byte"]["value"] =
1175         "0x40";
1176     i2cCompareByteFile["rules"][0]["actions"][1]["i2c_compare_byte"]["mask"] =
1177         "0x7F";
1178     // Valid: test i2c_compare_byte with all properties.
1179     {
1180         json configFile = i2cCompareByteFile;
1181         EXPECT_JSON_VALID(configFile);
1182     }
1183     // Valid: test i2c_compare_byte with all required properties.
1184     {
1185         json configFile = i2cCompareByteFile;
1186         configFile["rules"][0]["actions"][1]["i2c_compare_byte"].erase("mask");
1187         EXPECT_JSON_VALID(configFile);
1188     }
1189     // Invalid: test i2c_compare_byte with no register.
1190     {
1191         json configFile = i2cCompareByteFile;
1192         configFile["rules"][0]["actions"][1]["i2c_compare_byte"].erase(
1193             "register");
1194         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1195                             "'register' is a required property");
1196     }
1197     // Invalid: test i2c_compare_byte with no value.
1198     {
1199         json configFile = i2cCompareByteFile;
1200         configFile["rules"][0]["actions"][1]["i2c_compare_byte"].erase("value");
1201         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1202                             "'value' is a required property");
1203     }
1204     // Invalid: test i2c_compare_byte with property register wrong type.
1205     {
1206         json configFile = i2cCompareByteFile;
1207         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["register"] =
1208             1;
1209         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1210                             "1 is not of type 'string'");
1211     }
1212     // Invalid: test i2c_compare_byte with property value wrong type.
1213     {
1214         json configFile = i2cCompareByteFile;
1215         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["value"] = 1;
1216         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1217                             "1 is not of type 'string'");
1218     }
1219     // Invalid: test i2c_compare_byte with property mask wrong type.
1220     {
1221         json configFile = i2cCompareByteFile;
1222         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["mask"] = 1;
1223         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1224                             "1 is not of type 'string'");
1225     }
1226     // Invalid: test i2c_compare_byte with property register more than 2 hex
1227     // digits.
1228     {
1229         json configFile = i2cCompareByteFile;
1230         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["register"] =
1231             "0x820";
1232         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1233                             "'0x820' does not match '^0x[0-9A-Fa-f]{2}$'");
1234     }
1235     // Invalid: test i2c_compare_byte with property value more than 2 hex
1236     // digits.
1237     {
1238         json configFile = i2cCompareByteFile;
1239         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["value"] =
1240             "0x820";
1241         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1242                             "'0x820' does not match '^0x[0-9A-Fa-f]{2}$'");
1243     }
1244     // Invalid: test i2c_compare_byte with property mask more than 2 hex digits.
1245     {
1246         json configFile = i2cCompareByteFile;
1247         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["mask"] =
1248             "0x820";
1249         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1250                             "'0x820' does not match '^0x[0-9A-Fa-f]{2}$'");
1251     }
1252     // Invalid: test i2c_compare_byte with property register less than 2 hex
1253     // digits.
1254     {
1255         json configFile = i2cCompareByteFile;
1256         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["register"] =
1257             "0x8";
1258         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1259                             "'0x8' does not match '^0x[0-9A-Fa-f]{2}$'");
1260     }
1261     // Invalid: test i2c_compare_byte with property value less than 2 hex
1262     // digits.
1263     {
1264         json configFile = i2cCompareByteFile;
1265         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["value"] =
1266             "0x8";
1267         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1268                             "'0x8' does not match '^0x[0-9A-Fa-f]{2}$'");
1269     }
1270     // Invalid: test i2c_compare_byte with property mask less than 2 hex digits.
1271     {
1272         json configFile = i2cCompareByteFile;
1273         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["mask"] =
1274             "0x8";
1275         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1276                             "'0x8' does not match '^0x[0-9A-Fa-f]{2}$'");
1277     }
1278     // Invalid: test i2c_compare_byte with property register no leading prefix.
1279     {
1280         json configFile = i2cCompareByteFile;
1281         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["register"] =
1282             "82";
1283         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1284                             "'82' does not match '^0x[0-9A-Fa-f]{2}$'");
1285     }
1286     // Invalid: test i2c_compare_byte with property value no leading prefix.
1287     {
1288         json configFile = i2cCompareByteFile;
1289         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["value"] =
1290             "82";
1291         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1292                             "'82' does not match '^0x[0-9A-Fa-f]{2}$'");
1293     }
1294     // Invalid: test i2c_compare_byte with property mask no leading prefix.
1295     {
1296         json configFile = i2cCompareByteFile;
1297         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["mask"] = "82";
1298         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1299                             "'82' does not match '^0x[0-9A-Fa-f]{2}$'");
1300     }
1301     // Invalid: test i2c_compare_byte with property register invalid hex digit.
1302     {
1303         json configFile = i2cCompareByteFile;
1304         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["register"] =
1305             "0xG1";
1306         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1307                             "'0xG1' does not match '^0x[0-9A-Fa-f]{2}$'");
1308     }
1309     // Invalid: test i2c_compare_byte with property value invalid hex digit.
1310     {
1311         json configFile = i2cCompareByteFile;
1312         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["value"] =
1313             "0xG1";
1314         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1315                             "'0xG1' does not match '^0x[0-9A-Fa-f]{2}$'");
1316     }
1317     // Invalid: test i2c_compare_byte with property mask invalid hex digit.
1318     {
1319         json configFile = i2cCompareByteFile;
1320         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["mask"] =
1321             "0xG1";
1322         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1323                             "'0xG1' does not match '^0x[0-9A-Fa-f]{2}$'");
1324     }
1325 }
1326 TEST(ValidateRegulatorsConfigTest, I2CCompareBytes)
1327 {
1328     json i2cCompareBytesFile = validConfigFile;
1329     i2cCompareBytesFile["rules"][0]["actions"][1]["i2c_compare_bytes"]
1330                        ["register"] = "0x82";
1331     i2cCompareBytesFile["rules"][0]["actions"][1]["i2c_compare_bytes"]
1332                        ["values"] = {"0x02", "0x73"};
1333     i2cCompareBytesFile["rules"][0]["actions"][1]["i2c_compare_bytes"]
1334                        ["masks"] = {"0x7F", "0x7F"};
1335     // Valid: test i2c_compare_bytes.
1336     {
1337         json configFile = i2cCompareBytesFile;
1338         EXPECT_JSON_VALID(configFile);
1339     }
1340     // Valid: test i2c_compare_bytes with all required properties.
1341     {
1342         json configFile = i2cCompareBytesFile;
1343         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"].erase(
1344             "masks");
1345         EXPECT_JSON_VALID(configFile);
1346     }
1347     // Invalid: test i2c_compare_bytes with no register.
1348     {
1349         json configFile = i2cCompareBytesFile;
1350         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"].erase(
1351             "register");
1352         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1353                             "'register' is a required property");
1354     }
1355     // Invalid: test i2c_compare_bytes with no values.
1356     {
1357         json configFile = i2cCompareBytesFile;
1358         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"].erase(
1359             "values");
1360         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1361                             "'values' is a required property");
1362     }
1363     // Invalid: test i2c_compare_bytes with property values as empty array.
1364     {
1365         json configFile = i2cCompareBytesFile;
1366         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["values"] =
1367             json::array();
1368         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1369                             "[] is too short");
1370     }
1371     // Invalid: test i2c_compare_bytes with property masks as empty array.
1372     {
1373         json configFile = i2cCompareBytesFile;
1374         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["masks"] =
1375             json::array();
1376         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1377                             "[] is too short");
1378     }
1379     // Invalid: test i2c_compare_bytes with property register wrong type.
1380     {
1381         json configFile = i2cCompareBytesFile;
1382         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["register"] =
1383             1;
1384         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1385                             "1 is not of type 'string'");
1386     }
1387     // Invalid: test i2c_compare_bytes with property values wrong type.
1388     {
1389         json configFile = i2cCompareBytesFile;
1390         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["values"] = 1;
1391         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1392                             "1 is not of type 'array'");
1393     }
1394     // Invalid: test i2c_compare_bytes with property masks wrong type.
1395     {
1396         json configFile = i2cCompareBytesFile;
1397         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["masks"] = 1;
1398         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1399                             "1 is not of type 'array'");
1400     }
1401     // Invalid: test i2c_compare_bytes with property register more than 2 hex
1402     // digits.
1403     {
1404         json configFile = i2cCompareBytesFile;
1405         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["register"] =
1406             "0x820";
1407         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1408                             "'0x820' does not match '^0x[0-9A-Fa-f]{2}$'");
1409     }
1410     // Invalid: test i2c_compare_bytes with property values more than 2 hex
1411     // digits.
1412     {
1413         json configFile = i2cCompareBytesFile;
1414         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["values"][0] =
1415             "0x820";
1416         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1417                             "'0x820' does not match '^0x[0-9A-Fa-f]{2}$'");
1418     }
1419     // Invalid: test i2c_compare_bytes with property masks more than 2 hex
1420     // digits.
1421     {
1422         json configFile = i2cCompareBytesFile;
1423         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["masks"][0] =
1424             "0x820";
1425         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1426                             "'0x820' does not match '^0x[0-9A-Fa-f]{2}$'");
1427     }
1428     // Invalid: test i2c_compare_bytes with property register less than 2 hex
1429     // digits.
1430     {
1431         json configFile = i2cCompareBytesFile;
1432         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["register"] =
1433             "0x8";
1434         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1435                             "'0x8' does not match '^0x[0-9A-Fa-f]{2}$'");
1436     }
1437     // Invalid: test i2c_compare_bytes with property values less than 2 hex
1438     // digits.
1439     {
1440         json configFile = i2cCompareBytesFile;
1441         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["values"][0] =
1442             "0x8";
1443         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1444                             "'0x8' does not match '^0x[0-9A-Fa-f]{2}$'");
1445     }
1446     // Invalid: test i2c_compare_bytes with property masks less than 2 hex
1447     // digits.
1448     {
1449         json configFile = i2cCompareBytesFile;
1450         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["masks"][0] =
1451             "0x8";
1452         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1453                             "'0x8' does not match '^0x[0-9A-Fa-f]{2}$'");
1454     }
1455     // Invalid: test i2c_compare_bytes with property register no leading prefix.
1456     {
1457         json configFile = i2cCompareBytesFile;
1458         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["register"] =
1459             "82";
1460         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1461                             "'82' does not match '^0x[0-9A-Fa-f]{2}$'");
1462     }
1463     // Invalid: test i2c_compare_bytes with property values no leading prefix.
1464     {
1465         json configFile = i2cCompareBytesFile;
1466         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["values"][0] =
1467             "82";
1468         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1469                             "'82' does not match '^0x[0-9A-Fa-f]{2}$'");
1470     }
1471     // Invalid: test i2c_compare_bytes with property masks no leading prefix.
1472     {
1473         json configFile = i2cCompareBytesFile;
1474         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["masks"][0] =
1475             "82";
1476         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1477                             "'82' does not match '^0x[0-9A-Fa-f]{2}$'");
1478     }
1479     // Invalid: test i2c_compare_bytes with property register invalid hex digit.
1480     {
1481         json configFile = i2cCompareBytesFile;
1482         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["register"] =
1483             "0xG1";
1484         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1485                             "'0xG1' does not match '^0x[0-9A-Fa-f]{2}$'");
1486     }
1487     // Invalid: test i2c_compare_bytes with property values invalid hex digit.
1488     {
1489         json configFile = i2cCompareBytesFile;
1490         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["values"][0] =
1491             "0xG1";
1492         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1493                             "'0xG1' does not match '^0x[0-9A-Fa-f]{2}$'");
1494     }
1495     // Invalid: test i2c_compare_bytes with property masks invalid hex digit.
1496     {
1497         json configFile = i2cCompareBytesFile;
1498         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["masks"][0] =
1499             "0xG1";
1500         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1501                             "'0xG1' does not match '^0x[0-9A-Fa-f]{2}$'");
1502     }
1503 }
1504 TEST(ValidateRegulatorsConfigTest, I2CInterface)
1505 {
1506     // Valid: test i2c_interface.
1507     {
1508         json configFile = validConfigFile;
1509         EXPECT_JSON_VALID(configFile);
1510     }
1511     // Invalid: testi2c_interface with no bus.
1512     {
1513         json configFile = validConfigFile;
1514         configFile["chassis"][0]["devices"][0]["i2c_interface"].erase("bus");
1515         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1516                             "'bus' is a required property");
1517     }
1518     // Invalid: test i2c_interface with no address.
1519     {
1520         json configFile = validConfigFile;
1521         configFile["chassis"][0]["devices"][0]["i2c_interface"].erase(
1522             "address");
1523         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1524                             "'address' is a required property");
1525     }
1526     // Invalid: test i2c_interface with property bus wrong type.
1527     {
1528         json configFile = validConfigFile;
1529         configFile["chassis"][0]["devices"][0]["i2c_interface"]["bus"] = true;
1530         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1531                             "True is not of type 'integer'");
1532     }
1533     // Invalid: test i2c_interface with property address wrong
1534     // type.
1535     {
1536         json configFile = validConfigFile;
1537         configFile["chassis"][0]["devices"][0]["i2c_interface"]["address"] =
1538             true;
1539         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1540                             "True is not of type 'string'");
1541     }
1542     // Invalid: test i2c_interface with property bus less than
1543     // 0.
1544     {
1545         json configFile = validConfigFile;
1546         configFile["chassis"][0]["devices"][0]["i2c_interface"]["bus"] = -1;
1547         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1548                             "-1 is less than the minimum of 0");
1549     }
1550     // Invalid: test i2c_interface with property address wrong
1551     // format.
1552     {
1553         json configFile = validConfigFile;
1554         configFile["chassis"][0]["devices"][0]["i2c_interface"]["address"] =
1555             "0x700";
1556         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1557                             "'0x700' does not match '^0x[0-9A-Fa-f]{2}$'");
1558     }
1559 }
1560 TEST(ValidateRegulatorsConfigTest, I2CWriteBit)
1561 {
1562     json i2cWriteBitFile = validConfigFile;
1563     i2cWriteBitFile["rules"][0]["actions"][1]["i2c_write_bit"]["register"] =
1564         "0xA0";
1565     i2cWriteBitFile["rules"][0]["actions"][1]["i2c_write_bit"]["position"] = 3;
1566     i2cWriteBitFile["rules"][0]["actions"][1]["i2c_write_bit"]["value"] = 1;
1567     // Valid: test rule actions i2c_write_bit.
1568     {
1569         json configFile = i2cWriteBitFile;
1570         EXPECT_JSON_VALID(configFile);
1571     }
1572     // Invalid: test i2c_write_bit with no register.
1573     {
1574         json configFile = i2cWriteBitFile;
1575         configFile["rules"][0]["actions"][1]["i2c_write_bit"].erase("register");
1576         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1577                             "'register' is a required property");
1578     }
1579     // Invalid: test i2c_write_bit with no position.
1580     {
1581         json configFile = i2cWriteBitFile;
1582         configFile["rules"][0]["actions"][1]["i2c_write_bit"].erase("position");
1583         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1584                             "'position' is a required property");
1585     }
1586     // Invalid: test i2c_write_bit with no value.
1587     {
1588         json configFile = i2cWriteBitFile;
1589         configFile["rules"][0]["actions"][1]["i2c_write_bit"].erase("value");
1590         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1591                             "'value' is a required property");
1592     }
1593     // Invalid: test i2c_write_bit with register wrong type.
1594     {
1595         json configFile = i2cWriteBitFile;
1596         configFile["rules"][0]["actions"][1]["i2c_write_bit"]["register"] = 1;
1597         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1598                             "1 is not of type 'string'");
1599     }
1600     // Invalid: test i2c_write_bit with register wrong format.
1601     {
1602         json configFile = i2cWriteBitFile;
1603         configFile["rules"][0]["actions"][1]["i2c_write_bit"]["register"] =
1604             "0xA00";
1605         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1606                             "'0xA00' does not match '^0x[0-9A-Fa-f]{2}$'");
1607     }
1608     // Invalid: test i2c_write_bit with position wrong type.
1609     {
1610         json configFile = i2cWriteBitFile;
1611         configFile["rules"][0]["actions"][1]["i2c_write_bit"]["position"] = 3.1;
1612         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1613                             "3.1 is not of type 'integer'");
1614     }
1615     // Invalid: test i2c_write_bit with position greater than 7.
1616     {
1617         json configFile = i2cWriteBitFile;
1618         configFile["rules"][0]["actions"][1]["i2c_write_bit"]["position"] = 8;
1619         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1620                             "8 is greater than the maximum of 7");
1621     }
1622     // Invalid: test i2c_write_bit with position less than 0.
1623     {
1624         json configFile = i2cWriteBitFile;
1625         configFile["rules"][0]["actions"][1]["i2c_write_bit"]["position"] = -1;
1626         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1627                             "-1 is less than the minimum of 0");
1628     }
1629     // Invalid: test i2c_write_bit with value wrong type.
1630     {
1631         json configFile = i2cWriteBitFile;
1632         configFile["rules"][0]["actions"][1]["i2c_write_bit"]["value"] = "1";
1633         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1634                             "'1' is not of type 'integer'");
1635     }
1636     // Invalid: test i2c_write_bit with value greater than 1.
1637     {
1638         json configFile = i2cWriteBitFile;
1639         configFile["rules"][0]["actions"][1]["i2c_write_bit"]["value"] = 2;
1640         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1641                             "2 is greater than the maximum of 1");
1642     }
1643     // Invalid: test i2c_write_bit with value less than 0.
1644     {
1645         json configFile = i2cWriteBitFile;
1646         configFile["rules"][0]["actions"][1]["i2c_write_bit"]["value"] = -1;
1647         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1648                             "-1 is less than the minimum of 0");
1649     }
1650 }
1651 TEST(ValidateRegulatorsConfigTest, I2CWriteByte)
1652 {
1653     json i2cWriteByteFile = validConfigFile;
1654     i2cWriteByteFile["rules"][0]["actions"][1]["i2c_write_byte"]["register"] =
1655         "0x82";
1656     i2cWriteByteFile["rules"][0]["actions"][1]["i2c_write_byte"]["value"] =
1657         "0x40";
1658     i2cWriteByteFile["rules"][0]["actions"][1]["i2c_write_byte"]["mask"] =
1659         "0x7F";
1660     // Valid: test i2c_write_byte with all properties.
1661     {
1662         json configFile = i2cWriteByteFile;
1663         EXPECT_JSON_VALID(configFile);
1664     }
1665     // Valid: test i2c_write_byte with all required properties.
1666     {
1667         json configFile = i2cWriteByteFile;
1668         configFile["rules"][0]["actions"][1]["i2c_write_byte"].erase("mask");
1669         EXPECT_JSON_VALID(configFile);
1670     }
1671     // Invalid: test i2c_write_byte with no register.
1672     {
1673         json configFile = i2cWriteByteFile;
1674         configFile["rules"][0]["actions"][1]["i2c_write_byte"].erase(
1675             "register");
1676         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1677                             "'register' is a required property");
1678     }
1679     // Invalid: test i2c_write_byte with no value.
1680     {
1681         json configFile = i2cWriteByteFile;
1682         configFile["rules"][0]["actions"][1]["i2c_write_byte"].erase("value");
1683         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1684                             "'value' is a required property");
1685     }
1686     // Invalid: test i2c_write_byte with property register wrong type.
1687     {
1688         json configFile = i2cWriteByteFile;
1689         configFile["rules"][0]["actions"][1]["i2c_write_byte"]["register"] = 1;
1690         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1691                             "1 is not of type 'string'");
1692     }
1693     // Invalid: test i2c_write_byte with property value wrong type.
1694     {
1695         json configFile = i2cWriteByteFile;
1696         configFile["rules"][0]["actions"][1]["i2c_write_byte"]["value"] = 1;
1697         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1698                             "1 is not of type 'string'");
1699     }
1700     // Invalid: test i2c_write_byte with property mask wrong type.
1701     {
1702         json configFile = i2cWriteByteFile;
1703         configFile["rules"][0]["actions"][1]["i2c_write_byte"]["mask"] = 1;
1704         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1705                             "1 is not of type 'string'");
1706     }
1707     // Invalid: test i2c_write_byte with property register more than 2 hex
1708     // digits.
1709     {
1710         json configFile = i2cWriteByteFile;
1711         configFile["rules"][0]["actions"][1]["i2c_write_byte"]["register"] =
1712             "0x820";
1713         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1714                             "'0x820' does not match '^0x[0-9A-Fa-f]{2}$'");
1715     }
1716     // Invalid: test i2c_write_byte with property value more than 2 hex
1717     // digits.
1718     {
1719         json configFile = i2cWriteByteFile;
1720         configFile["rules"][0]["actions"][1]["i2c_write_byte"]["value"] =
1721             "0x820";
1722         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1723                             "'0x820' does not match '^0x[0-9A-Fa-f]{2}$'");
1724     }
1725     // Invalid: test i2c_write_byte with property mask more than 2 hex digits.
1726     {
1727         json configFile = i2cWriteByteFile;
1728         configFile["rules"][0]["actions"][1]["i2c_write_byte"]["mask"] =
1729             "0x820";
1730         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1731                             "'0x820' does not match '^0x[0-9A-Fa-f]{2}$'");
1732     }
1733     // Invalid: test i2c_write_byte with property register less than 2 hex
1734     // digits.
1735     {
1736         json configFile = i2cWriteByteFile;
1737         configFile["rules"][0]["actions"][1]["i2c_write_byte"]["register"] =
1738             "0x8";
1739         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1740                             "'0x8' does not match '^0x[0-9A-Fa-f]{2}$'");
1741     }
1742     // Invalid: test i2c_write_byte with property value less than 2 hex
1743     // digits.
1744     {
1745         json configFile = i2cWriteByteFile;
1746         configFile["rules"][0]["actions"][1]["i2c_write_byte"]["value"] = "0x8";
1747         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1748                             "'0x8' does not match '^0x[0-9A-Fa-f]{2}$'");
1749     }
1750     // Invalid: test i2c_write_byte with property mask less than 2 hex digits.
1751     {
1752         json configFile = i2cWriteByteFile;
1753         configFile["rules"][0]["actions"][1]["i2c_write_byte"]["mask"] = "0x8";
1754         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1755                             "'0x8' does not match '^0x[0-9A-Fa-f]{2}$'");
1756     }
1757     // Invalid: test i2c_write_byte with property register no leading prefix.
1758     {
1759         json configFile = i2cWriteByteFile;
1760         configFile["rules"][0]["actions"][1]["i2c_write_byte"]["register"] =
1761             "82";
1762         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1763                             "'82' does not match '^0x[0-9A-Fa-f]{2}$'");
1764     }
1765     // Invalid: test i2c_write_byte with property value no leading prefix.
1766     {
1767         json configFile = i2cWriteByteFile;
1768         configFile["rules"][0]["actions"][1]["i2c_write_byte"]["value"] = "82";
1769         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1770                             "'82' does not match '^0x[0-9A-Fa-f]{2}$'");
1771     }
1772     // Invalid: test i2c_write_byte with property mask no leading prefix.
1773     {
1774         json configFile = i2cWriteByteFile;
1775         configFile["rules"][0]["actions"][1]["i2c_write_byte"]["mask"] = "82";
1776         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1777                             "'82' does not match '^0x[0-9A-Fa-f]{2}$'");
1778     }
1779     // Invalid: test i2c_write_byte with property register invalid hex digit.
1780     {
1781         json configFile = i2cWriteByteFile;
1782         configFile["rules"][0]["actions"][1]["i2c_write_byte"]["register"] =
1783             "0xG1";
1784         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1785                             "'0xG1' does not match '^0x[0-9A-Fa-f]{2}$'");
1786     }
1787     // Invalid: test i2c_write_byte with property value invalid hex digit.
1788     {
1789         json configFile = i2cWriteByteFile;
1790         configFile["rules"][0]["actions"][1]["i2c_write_byte"]["value"] =
1791             "0xG1";
1792         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1793                             "'0xG1' does not match '^0x[0-9A-Fa-f]{2}$'");
1794     }
1795     // Invalid: test i2c_write_byte with property mask invalid hex digit.
1796     {
1797         json configFile = i2cWriteByteFile;
1798         configFile["rules"][0]["actions"][1]["i2c_write_byte"]["mask"] = "0xG1";
1799         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1800                             "'0xG1' does not match '^0x[0-9A-Fa-f]{2}$'");
1801     }
1802 }
1803 TEST(ValidateRegulatorsConfigTest, I2CWriteBytes)
1804 {
1805     json i2cWriteBytesFile = validConfigFile;
1806     i2cWriteBytesFile["rules"][0]["actions"][1]["i2c_write_bytes"]["register"] =
1807         "0x82";
1808     i2cWriteBytesFile["rules"][0]["actions"][1]["i2c_write_bytes"]["values"] = {
1809         "0x02", "0x73"};
1810     i2cWriteBytesFile["rules"][0]["actions"][1]["i2c_write_bytes"]["masks"] = {
1811         "0x7F", "0x7F"};
1812     // Valid: test i2c_write_bytes.
1813     {
1814         json configFile = i2cWriteBytesFile;
1815         EXPECT_JSON_VALID(configFile);
1816     }
1817     // Valid: test i2c_write_bytes with all required properties.
1818     {
1819         json configFile = i2cWriteBytesFile;
1820         configFile["rules"][0]["actions"][1]["i2c_write_bytes"].erase("masks");
1821         EXPECT_JSON_VALID(configFile);
1822     }
1823     // Invalid: test i2c_write_bytes with no register.
1824     {
1825         json configFile = i2cWriteBytesFile;
1826         configFile["rules"][0]["actions"][1]["i2c_write_bytes"].erase(
1827             "register");
1828         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1829                             "'register' is a required property");
1830     }
1831     // Invalid: test i2c_write_bytes with no values.
1832     {
1833         json configFile = i2cWriteBytesFile;
1834         configFile["rules"][0]["actions"][1]["i2c_write_bytes"].erase("values");
1835         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1836                             "'values' is a required property");
1837     }
1838     // Invalid: test i2c_write_bytes with property values as empty array.
1839     {
1840         json configFile = i2cWriteBytesFile;
1841         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["values"] =
1842             json::array();
1843         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1844                             "[] is too short");
1845     }
1846     // Invalid: test i2c_write_bytes with property masks as empty array.
1847     {
1848         json configFile = i2cWriteBytesFile;
1849         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["masks"] =
1850             json::array();
1851         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1852                             "[] is too short");
1853     }
1854     // Invalid: test i2c_write_bytes with property register wrong type.
1855     {
1856         json configFile = i2cWriteBytesFile;
1857         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["register"] = 1;
1858         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1859                             "1 is not of type 'string'");
1860     }
1861     // Invalid: test i2c_write_bytes with property values wrong type.
1862     {
1863         json configFile = i2cWriteBytesFile;
1864         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["values"] = 1;
1865         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1866                             "1 is not of type 'array'");
1867     }
1868     // Invalid: test i2c_write_bytes with property masks wrong type.
1869     {
1870         json configFile = i2cWriteBytesFile;
1871         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["masks"] = 1;
1872         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1873                             "1 is not of type 'array'");
1874     }
1875     // Invalid: test i2c_write_bytes with property register more than 2 hex
1876     // digits.
1877     {
1878         json configFile = i2cWriteBytesFile;
1879         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["register"] =
1880             "0x820";
1881         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1882                             "'0x820' does not match '^0x[0-9A-Fa-f]{2}$'");
1883     }
1884     // Invalid: test i2c_write_bytes with property values more than 2 hex
1885     // digits.
1886     {
1887         json configFile = i2cWriteBytesFile;
1888         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["values"][0] =
1889             "0x820";
1890         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1891                             "'0x820' does not match '^0x[0-9A-Fa-f]{2}$'");
1892     }
1893     // Invalid: test i2c_write_bytes with property masks more than 2 hex
1894     // digits.
1895     {
1896         json configFile = i2cWriteBytesFile;
1897         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["masks"][0] =
1898             "0x820";
1899         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1900                             "'0x820' does not match '^0x[0-9A-Fa-f]{2}$'");
1901     }
1902     // Invalid: test i2c_write_bytes with property register less than 2 hex
1903     // digits.
1904     {
1905         json configFile = i2cWriteBytesFile;
1906         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["register"] =
1907             "0x8";
1908         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1909                             "'0x8' does not match '^0x[0-9A-Fa-f]{2}$'");
1910     }
1911     // Invalid: test i2c_write_bytes with property values less than 2 hex
1912     // digits.
1913     {
1914         json configFile = i2cWriteBytesFile;
1915         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["values"][0] =
1916             "0x8";
1917         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1918                             "'0x8' does not match '^0x[0-9A-Fa-f]{2}$'");
1919     }
1920     // Invalid: test i2c_write_bytes with property masks less than 2 hex
1921     // digits.
1922     {
1923         json configFile = i2cWriteBytesFile;
1924         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["masks"][0] =
1925             "0x8";
1926         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1927                             "'0x8' does not match '^0x[0-9A-Fa-f]{2}$'");
1928     }
1929     // Invalid: test i2c_write_bytes with property register no leading prefix.
1930     {
1931         json configFile = i2cWriteBytesFile;
1932         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["register"] =
1933             "82";
1934         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1935                             "'82' does not match '^0x[0-9A-Fa-f]{2}$'");
1936     }
1937     // Invalid: test i2c_write_bytes with property values no leading prefix.
1938     {
1939         json configFile = i2cWriteBytesFile;
1940         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["values"][0] =
1941             "82";
1942         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1943                             "'82' does not match '^0x[0-9A-Fa-f]{2}$'");
1944     }
1945     // Invalid: test i2c_write_bytes with property masks no leading prefix.
1946     {
1947         json configFile = i2cWriteBytesFile;
1948         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["masks"][0] =
1949             "82";
1950         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1951                             "'82' does not match '^0x[0-9A-Fa-f]{2}$'");
1952     }
1953     // Invalid: test i2c_write_bytes with property register invalid hex digit.
1954     {
1955         json configFile = i2cWriteBytesFile;
1956         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["register"] =
1957             "0xG1";
1958         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1959                             "'0xG1' does not match '^0x[0-9A-Fa-f]{2}$'");
1960     }
1961     // Invalid: test i2c_write_bytes with property values invalid hex digit.
1962     {
1963         json configFile = i2cWriteBytesFile;
1964         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["values"][0] =
1965             "0xG1";
1966         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1967                             "'0xG1' does not match '^0x[0-9A-Fa-f]{2}$'");
1968     }
1969     // Invalid: test i2c_write_bytes with property masks invalid hex digit.
1970     {
1971         json configFile = i2cWriteBytesFile;
1972         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["masks"][0] =
1973             "0xG1";
1974         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1975                             "'0xG1' does not match '^0x[0-9A-Fa-f]{2}$'");
1976     }
1977 }
1978 TEST(ValidateRegulatorsConfigTest, If)
1979 {
1980     json ifFile = validConfigFile;
1981     ifFile["rules"][2]["actions"][0]["if"]["condition"]["run_rule"] =
1982         "set_voltage_rule";
1983     ifFile["rules"][2]["actions"][0]["if"]["then"][0]["run_rule"] =
1984         "read_sensors_rule";
1985     ifFile["rules"][2]["actions"][0]["if"]["else"][0]["run_rule"] =
1986         "read_sensors_rule";
1987     ifFile["rules"][2]["id"] = "rule_if";
1988     // Valid: test if.
1989     {
1990         json configFile = ifFile;
1991         EXPECT_JSON_VALID(configFile);
1992     }
1993     // Valid: test if with required properties.
1994     {
1995         json configFile = ifFile;
1996         configFile["rules"][2]["actions"][0]["if"].erase("else");
1997         EXPECT_JSON_VALID(configFile);
1998     }
1999     // Invalid: test if with no property condition.
2000     {
2001         json configFile = ifFile;
2002         configFile["rules"][2]["actions"][0]["if"].erase("condition");
2003         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2004                             "'condition' is a required property");
2005     }
2006     // Invalid: test if with no property then.
2007     {
2008         json configFile = ifFile;
2009         configFile["rules"][2]["actions"][0]["if"].erase("then");
2010         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2011                             "'then' is a required property");
2012     }
2013     // Invalid: test if with property then empty array.
2014     {
2015         json configFile = ifFile;
2016         configFile["rules"][2]["actions"][0]["if"]["then"] = json::array();
2017         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2018                             "[] is too short");
2019     }
2020     // Invalid: test if with property else empty array.
2021     {
2022         json configFile = ifFile;
2023         configFile["rules"][2]["actions"][0]["if"]["else"] = json::array();
2024         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2025                             "[] is too short");
2026     }
2027     // Invalid: test if with property condition wrong type.
2028     {
2029         json configFile = ifFile;
2030         configFile["rules"][2]["actions"][0]["if"]["condition"] = 1;
2031         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2032                             "1 is not of type 'object'");
2033     }
2034     // Invalid: test if with property then wrong type.
2035     {
2036         json configFile = ifFile;
2037         configFile["rules"][2]["actions"][0]["if"]["then"] = 1;
2038         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2039                             "1 is not of type 'array'");
2040     }
2041     // Invalid: test if with property else wrong type.
2042     {
2043         json configFile = ifFile;
2044         configFile["rules"][2]["actions"][0]["if"]["else"] = 1;
2045         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2046                             "1 is not of type 'array'");
2047     }
2048 }
2049 TEST(ValidateRegulatorsConfigTest, Not)
2050 {
2051     json notFile = validConfigFile;
2052     notFile["rules"][0]["actions"][1]["not"]["i2c_compare_byte"]["register"] =
2053         "0xA0";
2054     notFile["rules"][0]["actions"][1]["not"]["i2c_compare_byte"]["value"] =
2055         "0xFF";
2056     // Valid: test not.
2057     {
2058         json configFile = notFile;
2059         EXPECT_JSON_VALID(configFile);
2060     }
2061     // Invalid: test not with wrong type.
2062     {
2063         json configFile = notFile;
2064         configFile["rules"][0]["actions"][1]["not"] = 1;
2065         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2066                             "1 is not of type 'object'");
2067     }
2068 }
2069 TEST(ValidateRegulatorsConfigTest, Or)
2070 {
2071     json orFile = validConfigFile;
2072     orFile["rules"][0]["actions"][1]["or"][0]["i2c_compare_byte"]["register"] =
2073         "0xA0";
2074     orFile["rules"][0]["actions"][1]["or"][0]["i2c_compare_byte"]["value"] =
2075         "0x00";
2076     orFile["rules"][0]["actions"][1]["or"][1]["i2c_compare_byte"]["register"] =
2077         "0xA1";
2078     orFile["rules"][0]["actions"][1]["or"][1]["i2c_compare_byte"]["value"] =
2079         "0x00";
2080     // Valid: test or.
2081     {
2082         json configFile = orFile;
2083         EXPECT_JSON_VALID(configFile);
2084     }
2085     // Invalid: test or with empty array.
2086     {
2087         json configFile = orFile;
2088         configFile["rules"][0]["actions"][1]["or"] = json::array();
2089         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2090                             "[] is too short");
2091     }
2092     // Invalid: test or with wrong type.
2093     {
2094         json configFile = orFile;
2095         configFile["rules"][0]["actions"][1]["or"] = 1;
2096         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2097                             "1 is not of type 'array'");
2098     }
2099 }
2100 TEST(ValidateRegulatorsConfigTest, PmbusReadSensor)
2101 {
2102     json pmbusReadSensorFile = validConfigFile;
2103     pmbusReadSensorFile["rules"][0]["actions"][1]["pmbus_read_sensor"]["type"] =
2104         "vout";
2105     pmbusReadSensorFile["rules"][0]["actions"][1]["pmbus_read_sensor"]
2106                        ["command"] = "0x8B";
2107     pmbusReadSensorFile["rules"][0]["actions"][1]["pmbus_read_sensor"]
2108                        ["format"] = "linear_16";
2109     pmbusReadSensorFile["rules"][0]["actions"][1]["pmbus_read_sensor"]
2110                        ["exponent"] = -8;
2111     // Valid: test pmbus_read_sensor.
2112     {
2113         json configFile = pmbusReadSensorFile;
2114         EXPECT_JSON_VALID(configFile);
2115     }
2116     // Valid: test pmbus_read_sensor with required properties.
2117     {
2118         json configFile = pmbusReadSensorFile;
2119         configFile["rules"][0]["actions"][1]["pmbus_read_sensor"].erase(
2120             "exponent");
2121         EXPECT_JSON_VALID(configFile);
2122     }
2123     // Invalid: test pmbus_read_sensor with no type.
2124     {
2125         json configFile = pmbusReadSensorFile;
2126         configFile["rules"][0]["actions"][1]["pmbus_read_sensor"].erase("type");
2127         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2128                             "'type' is a required property");
2129     }
2130     // Invalid: test pmbus_read_sensor with no command.
2131     {
2132         json configFile = pmbusReadSensorFile;
2133         configFile["rules"][0]["actions"][1]["pmbus_read_sensor"].erase(
2134             "command");
2135         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2136                             "'command' is a required property");
2137     }
2138     // Invalid: test pmbus_read_sensor with no format.
2139     {
2140         json configFile = pmbusReadSensorFile;
2141         configFile["rules"][0]["actions"][1]["pmbus_read_sensor"].erase(
2142             "format");
2143         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2144                             "'format' is a required property");
2145     }
2146     // Invalid: test pmbus_read_sensor with property type wrong type.
2147     {
2148         json configFile = pmbusReadSensorFile;
2149         configFile["rules"][0]["actions"][1]["pmbus_read_sensor"]["type"] =
2150             true;
2151         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2152                             "True is not of type 'string'");
2153     }
2154     // Invalid: test pmbus_read_sensor with property command wrong type.
2155     {
2156         json configFile = pmbusReadSensorFile;
2157         configFile["rules"][0]["actions"][1]["pmbus_read_sensor"]["command"] =
2158             true;
2159         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2160                             "True is not of type 'string'");
2161     }
2162     // Invalid: test pmbus_read_sensor with property format wrong type.
2163     {
2164         json configFile = pmbusReadSensorFile;
2165         configFile["rules"][0]["actions"][1]["pmbus_read_sensor"]["format"] =
2166             true;
2167         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2168                             "True is not of type 'string'");
2169     }
2170     // Invalid: test pmbus_read_sensor with property exponent wrong type.
2171     {
2172         json configFile = pmbusReadSensorFile;
2173         configFile["rules"][0]["actions"][1]["pmbus_read_sensor"]["exponent"] =
2174             true;
2175         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2176                             "True is not of type 'integer'");
2177     }
2178     // Invalid: test pmbus_read_sensor with property type wrong format.
2179     {
2180         json configFile = pmbusReadSensorFile;
2181         configFile["rules"][0]["actions"][1]["pmbus_read_sensor"]["type"] =
2182             "foo";
2183         EXPECT_JSON_INVALID(
2184             configFile, "Validation failed.",
2185             "'foo' is not one of ['iout', 'iout_peak', 'iout_valley', "
2186             "'pout', 'temperature', 'temperature_peak', 'vout', "
2187             "'vout_peak', 'vout_valley']");
2188     }
2189     // Invalid: test pmbus_read_sensor with property command wrong format.
2190     {
2191         json configFile = pmbusReadSensorFile;
2192         configFile["rules"][0]["actions"][1]["pmbus_read_sensor"]["command"] =
2193             "0x8B0";
2194         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2195                             "'0x8B0' does not match '^0x[0-9a-fA-F]{2}$'");
2196     }
2197     // Invalid: test pmbus_read_sensor with property format wrong format.
2198     {
2199         json configFile = pmbusReadSensorFile;
2200         configFile["rules"][0]["actions"][1]["pmbus_read_sensor"]["format"] =
2201             "foo";
2202         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2203                             "'foo' is not one of ['linear_11', 'linear_16']");
2204     }
2205 }
2206 TEST(ValidateRegulatorsConfigTest, PmbusWriteVoutCommand)
2207 {
2208     json pmbusWriteVoutCommandFile = validConfigFile;
2209     pmbusWriteVoutCommandFile["rules"][0]["actions"][1]
2210                              ["pmbus_write_vout_command"]["volts"] = 1.03;
2211     pmbusWriteVoutCommandFile["rules"][0]["actions"][1]
2212                              ["pmbus_write_vout_command"]["format"] = "linear";
2213     pmbusWriteVoutCommandFile["rules"][0]["actions"][1]
2214                              ["pmbus_write_vout_command"]["exponent"] = -8;
2215     pmbusWriteVoutCommandFile["rules"][0]["actions"][1]
2216                              ["pmbus_write_vout_command"]["is_verified"] = true;
2217     // Valid: test pmbus_write_vout_command.
2218     {
2219         json configFile = pmbusWriteVoutCommandFile;
2220         EXPECT_JSON_VALID(configFile);
2221     }
2222     // Valid: test pmbus_write_vout_command with required properties.
2223     {
2224         json configFile = pmbusWriteVoutCommandFile;
2225         configFile["rules"][0]["actions"][1]["pmbus_write_vout_command"].erase(
2226             "volts");
2227         configFile["rules"][0]["actions"][1]["pmbus_write_vout_command"].erase(
2228             "exponent");
2229         configFile["rules"][0]["actions"][1]["pmbus_write_vout_command"].erase(
2230             "is_verified");
2231         EXPECT_JSON_VALID(configFile);
2232     }
2233     // Invalid: test pmbus_write_vout_command with no format.
2234     {
2235         json configFile = pmbusWriteVoutCommandFile;
2236         configFile["rules"][0]["actions"][1]["pmbus_write_vout_command"].erase(
2237             "format");
2238         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2239                             "'format' is a required property");
2240     }
2241     // Invalid: test pmbus_write_vout_command with property volts wrong type.
2242     {
2243         json configFile = pmbusWriteVoutCommandFile;
2244         configFile["rules"][0]["actions"][1]["pmbus_write_vout_command"]
2245                   ["volts"] = true;
2246         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2247                             "True is not of type 'number'");
2248     }
2249     // Invalid: test pmbus_write_vout_command with property format wrong type.
2250     {
2251         json configFile = pmbusWriteVoutCommandFile;
2252         configFile["rules"][0]["actions"][1]["pmbus_write_vout_command"]
2253                   ["format"] = true;
2254         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2255                             "True is not of type 'string'");
2256     }
2257     // Invalid: test pmbus_write_vout_command with property exponent wrong type.
2258     {
2259         json configFile = pmbusWriteVoutCommandFile;
2260         configFile["rules"][0]["actions"][1]["pmbus_write_vout_command"]
2261                   ["exponent"] = 1.3;
2262         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2263                             "1.3 is not of type 'integer'");
2264     }
2265     // Invalid: test pmbus_write_vout_command with property is_verified wrong
2266     // type.
2267     {
2268         json configFile = pmbusWriteVoutCommandFile;
2269         configFile["rules"][0]["actions"][1]["pmbus_write_vout_command"]
2270                   ["is_verified"] = 1;
2271         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2272                             "1 is not of type 'boolean'");
2273     }
2274     // Invalid: test pmbus_write_vout_command with property format wrong format.
2275     {
2276         json configFile = pmbusWriteVoutCommandFile;
2277         configFile["rules"][0]["actions"][1]["pmbus_write_vout_command"]
2278                   ["format"] = "foo";
2279         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2280                             "'foo' is not one of ['linear']");
2281     }
2282 }
2283 TEST(ValidateRegulatorsConfigTest, PresenceDetection)
2284 {
2285     json presenceDetectionFile = validConfigFile;
2286     presenceDetectionFile
2287         ["chassis"][0]["devices"][0]["presence_detection"]["comments"][0] =
2288             "Regulator is only present on the FooBar backplane";
2289     presenceDetectionFile["chassis"][0]["devices"][0]["presence_detection"]
2290                          ["rule_id"] = "set_voltage_rule";
2291     // Valid: test presence_detection with only property rule_id.
2292     {
2293         json configFile = presenceDetectionFile;
2294         EXPECT_JSON_VALID(configFile);
2295     }
2296     // Valid: test presence_detection with only property actions.
2297     {
2298         json configFile = presenceDetectionFile;
2299         configFile["chassis"][0]["devices"][0]["presence_detection"].erase(
2300             "rule_id");
2301         configFile["chassis"][0]["devices"][0]["presence_detection"]["actions"]
2302                   [0]["compare_presence"]["fru"] =
2303                       "system/chassis/motherboard/cpu3";
2304         configFile["chassis"][0]["devices"][0]["presence_detection"]["actions"]
2305                   [0]["compare_presence"]["value"] = true;
2306         configFile["chassis"][0]["devices"][0]["presence_detection"].erase(
2307             "comments");
2308         EXPECT_JSON_VALID(configFile);
2309     }
2310     // Invalid: test presence_detection with both property rule_id and actions.
2311     {
2312         json configFile = presenceDetectionFile;
2313         configFile["chassis"][0]["devices"][0]["presence_detection"]["actions"]
2314                   [0]["compare_presence"]["fru"] =
2315                       "system/chassis/motherboard/cpu3";
2316         configFile["chassis"][0]["devices"][0]["presence_detection"]["actions"]
2317                   [0]["compare_presence"]["value"] = true;
2318         EXPECT_JSON_INVALID(
2319             configFile, "Validation failed.",
2320             "{'actions': [{'compare_presence': {'fru': "
2321             "'system/chassis/motherboard/cpu3', 'value': True}}], 'comments': "
2322             "['Regulator is only present on the FooBar backplane'], 'rule_id': "
2323             "'set_voltage_rule'} is valid under each of {'required': "
2324             "['actions']}, {'required': ['rule_id']}");
2325     }
2326     // Invalid: test presence_detection with no rule_id and actions.
2327     {
2328         json configFile = presenceDetectionFile;
2329         configFile["chassis"][0]["devices"][0]["presence_detection"].erase(
2330             "rule_id");
2331         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2332                             "'rule_id' is a required property");
2333     }
2334     // Invalid: test presence_detection with property comments wrong type.
2335     {
2336         json configFile = presenceDetectionFile;
2337         configFile["chassis"][0]["devices"][0]["presence_detection"]
2338                   ["comments"] = true;
2339         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2340                             "True is not of type 'array'");
2341     }
2342     // Invalid: test presence_detection with property rule_id wrong type.
2343     {
2344         json configFile = presenceDetectionFile;
2345         configFile["chassis"][0]["devices"][0]["presence_detection"]
2346                   ["rule_id"] = true;
2347         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2348                             "True is not of type 'string'");
2349     }
2350     // Invalid: test presence_detection with property actions wrong type.
2351     {
2352         json configFile = presenceDetectionFile;
2353         configFile["chassis"][0]["devices"][0]["presence_detection"].erase(
2354             "rule_id");
2355         configFile["chassis"][0]["devices"][0]["presence_detection"]
2356                   ["actions"] = true;
2357         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2358                             "True is not of type 'array'");
2359     }
2360     // Invalid: test presence_detection with property rule_id wrong format.
2361     {
2362         json configFile = presenceDetectionFile;
2363         configFile["chassis"][0]["devices"][0]["presence_detection"]
2364                   ["rule_id"] = "id@";
2365         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2366                             "'id@' does not match '^[A-Za-z0-9_]+$'");
2367     }
2368     // Invalid: test presence_detection with property comments empty array.
2369     {
2370         json configFile = presenceDetectionFile;
2371         configFile["chassis"][0]["devices"][0]["presence_detection"]
2372                   ["comments"] = json::array();
2373         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2374                             "[] is too short");
2375     }
2376     // Invalid: test presence_detection with property actions empty array.
2377     {
2378         json configFile = presenceDetectionFile;
2379         configFile["chassis"][0]["devices"][0]["presence_detection"].erase(
2380             "rule_id");
2381         configFile["chassis"][0]["devices"][0]["presence_detection"]
2382                   ["actions"] = json::array();
2383         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2384                             "[] is too short");
2385     }
2386 }
2387 TEST(ValidateRegulatorsConfigTest, Rail)
2388 {
2389     // Valid: test rail.
2390     {
2391         json configFile = validConfigFile;
2392         EXPECT_JSON_VALID(configFile);
2393     }
2394     // Valid: test rail with required properties.
2395     {
2396         json configFile = validConfigFile;
2397         configFile["chassis"][0]["devices"][0]["rails"][0].erase("comments");
2398         configFile["chassis"][0]["devices"][0]["rails"][0].erase(
2399             "configuration");
2400         configFile["chassis"][0]["devices"][0]["rails"][0].erase(
2401             "sensor_monitoring");
2402         EXPECT_JSON_VALID(configFile);
2403     }
2404     // Invalid: test rail with no id.
2405     {
2406         json configFile = validConfigFile;
2407         configFile["chassis"][0]["devices"][0]["rails"][0].erase("id");
2408         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2409                             "'id' is a required property");
2410     }
2411     // Invalid: test rail with comments wrong type.
2412     {
2413         json configFile = validConfigFile;
2414         configFile["chassis"][0]["devices"][0]["rails"][0]["comments"] = true;
2415         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2416                             "True is not of type 'array'");
2417     }
2418     // Invalid: test rail with id wrong type.
2419     {
2420         json configFile = validConfigFile;
2421         configFile["chassis"][0]["devices"][0]["rails"][0]["id"] = true;
2422         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2423                             "True is not of type 'string'");
2424     }
2425     // Invalid: test rail with configuration wrong type.
2426     {
2427         json configFile = validConfigFile;
2428         configFile["chassis"][0]["devices"][0]["rails"][0]["configuration"] =
2429             true;
2430         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2431                             "True is not of type 'object'");
2432     }
2433     // Invalid: test rail with sensor_monitoring wrong type.
2434     {
2435         json configFile = validConfigFile;
2436         configFile["chassis"][0]["devices"][0]["rails"][0]
2437                   ["sensor_monitoring"] = true;
2438         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2439                             "True is not of type 'object'");
2440     }
2441     // Invalid: test rail with comments empty array.
2442     {
2443         json configFile = validConfigFile;
2444         configFile["chassis"][0]["devices"][0]["rails"][0]["comments"] =
2445             json::array();
2446         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2447                             "[] is too short");
2448     }
2449     // Invalid: test rail with id wrong format.
2450     {
2451         json configFile = validConfigFile;
2452         configFile["chassis"][0]["devices"][0]["rails"][0]["id"] = "id~";
2453         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2454                             "'id~' does not match '^[A-Za-z0-9_]+$'");
2455     }
2456 }
2457 TEST(ValidateRegulatorsConfigTest, Rule)
2458 {
2459     // valid test comments property, id property,
2460     // action property specified.
2461     {
2462         json configFile = validConfigFile;
2463         EXPECT_JSON_VALID(configFile);
2464     }
2465 
2466     // valid test rule with no comments
2467     {
2468         json configFile = validConfigFile;
2469         configFile["rules"][0].erase("comments");
2470         EXPECT_JSON_VALID(configFile);
2471     }
2472 
2473     // invalid test comments property has invalid value type
2474     {
2475         json configFile = validConfigFile;
2476         configFile["rules"][0]["comments"] = {1};
2477         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2478                             "1 is not of type 'string'");
2479     }
2480 
2481     // invalid test rule with no ID
2482     {
2483         json configFile = validConfigFile;
2484         configFile["rules"][0].erase("id");
2485         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2486                             "'id' is a required property");
2487     }
2488 
2489     // invalid test id property has invalid value type (not string)
2490     {
2491         json configFile = validConfigFile;
2492         configFile["rules"][0]["id"] = true;
2493         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2494                             "True is not of type 'string'");
2495     }
2496 
2497     // invalid test id property has invalid value
2498     {
2499         json configFile = validConfigFile;
2500         configFile["rules"][0]["id"] = "foo%";
2501         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2502                             "'foo%' does not match '^[A-Za-z0-9_]+$'");
2503     }
2504 
2505     // invalid test rule with no actions property
2506     {
2507         json configFile = validConfigFile;
2508         configFile["rules"][0].erase("actions");
2509         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2510                             "'actions' is a required property");
2511     }
2512 
2513     // valid test rule with multiple actions
2514     {
2515         json configFile = validConfigFile;
2516         configFile["rules"][0]["actions"][1]["run_rule"] = "read_sensors_rule";
2517         EXPECT_JSON_VALID(configFile);
2518     }
2519 
2520     // invalid test actions property has invalid value type (not an array)
2521     {
2522         json configFile = validConfigFile;
2523         configFile["rules"][0]["actions"] = 1;
2524         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2525                             "1 is not of type 'array'");
2526     }
2527 
2528     // invalid test actions property has invalid value of action
2529     {
2530         json configFile = validConfigFile;
2531         configFile["rules"][0]["actions"][0] = "foo";
2532         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2533                             "'foo' is not of type 'object'");
2534     }
2535 
2536     // invalid test actions property has empty array
2537     {
2538         json configFile = validConfigFile;
2539         configFile["rules"][0]["actions"] = json::array();
2540         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2541                             "[] is too short");
2542     }
2543 }
2544 TEST(ValidateRegulatorsConfigTest, RunRule)
2545 {
2546     json runRuleFile = validConfigFile;
2547     runRuleFile["rules"][0]["actions"][1]["run_rule"] = "read_sensors_rule";
2548     // Valid: test run_rule.
2549     {
2550         json configFile = runRuleFile;
2551         EXPECT_JSON_VALID(configFile);
2552     }
2553     // Invalid: test run_rule wrong type.
2554     {
2555         json configFile = runRuleFile;
2556         configFile["rules"][0]["actions"][1]["run_rule"] = true;
2557         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2558                             "True is not of type 'string'");
2559     }
2560     // Invalid: test run_rule wrong format.
2561     {
2562         json configFile = runRuleFile;
2563         configFile["rules"][0]["actions"][1]["run_rule"] = "set_voltage_rule%";
2564         EXPECT_JSON_INVALID(
2565             configFile, "Validation failed.",
2566             "'set_voltage_rule%' does not match '^[A-Za-z0-9_]+$'");
2567     }
2568 }
2569 TEST(ValidateRegulatorsConfigTest, SensorMonitoring)
2570 {
2571     // Valid: test rails sensor_monitoring with only property rule id.
2572     {
2573         json configFile = validConfigFile;
2574         EXPECT_JSON_VALID(configFile);
2575     }
2576     // Valid: test rails sensor_monitoring with only property actions.
2577     {
2578         json configFile = validConfigFile;
2579         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2580             .erase("rule_id");
2581         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2582                   ["actions"][0]["compare_presence"]["fru"] =
2583                       "system/chassis/motherboard/cpu3";
2584         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2585                   ["actions"][0]["compare_presence"]["value"] = true;
2586         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2587                   ["comments"][0] = "comments";
2588         EXPECT_JSON_VALID(configFile);
2589     }
2590     // Invalid: test rails sensor_monitoring with both property rule_id and
2591     // actions.
2592     {
2593         json configFile = validConfigFile;
2594         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2595                   ["actions"][0]["compare_presence"]["fru"] =
2596                       "system/chassis/motherboard/cpu3";
2597         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2598                   ["actions"][0]["compare_presence"]["value"] = true;
2599         EXPECT_JSON_INVALID(
2600             configFile, "Validation failed.",
2601             "{'actions': [{'compare_presence': {'fru': "
2602             "'system/chassis/motherboard/cpu3', 'value': True}}], 'rule_id': "
2603             "'read_sensors_rule'} is valid under each of {'required': "
2604             "['actions']}, {'required': ['rule_id']}");
2605     }
2606     // Invalid: test rails sensor_monitoring with no rule_id and actions.
2607     {
2608         json configFile = validConfigFile;
2609         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2610             .erase("rule_id");
2611         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2612                             "'rule_id' is a required property");
2613     }
2614     // Invalid: test rails sensor_monitoring with property comments wrong type.
2615     {
2616         json configFile = validConfigFile;
2617         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2618                   ["comments"] = true;
2619         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2620                             "True is not of type 'array'");
2621     }
2622     // Invalid: test rails sensor_monitoring with property rule_id wrong type.
2623     {
2624         json configFile = validConfigFile;
2625         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2626                   ["rule_id"] = true;
2627         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2628                             "True is not of type 'string'");
2629     }
2630     // Invalid: test rails sensor_monitoring with property actions wrong type.
2631     {
2632         json configFile = validConfigFile;
2633         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2634             .erase("rule_id");
2635         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2636                   ["actions"] = true;
2637         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2638                             "True is not of type 'array'");
2639     }
2640     // Invalid: test rails sensor_monitoring with property rule_id wrong format.
2641     {
2642         json configFile = validConfigFile;
2643         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2644                   ["rule_id"] = "id@";
2645         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2646                             "'id@' does not match '^[A-Za-z0-9_]+$'");
2647     }
2648     // Invalid: test rails sensor_monitoring with property comments empty array.
2649     {
2650         json configFile = validConfigFile;
2651         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2652                   ["comments"] = json::array();
2653         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2654                             "[] is too short");
2655     }
2656     // Invalid: test rails sensor_monitoring with property actions empty array.
2657     {
2658         json configFile = validConfigFile;
2659         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2660             .erase("rule_id");
2661         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2662                   ["actions"] = json::array();
2663         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2664                             "[] is too short");
2665     }
2666 }
2667 TEST(ValidateRegulatorsConfigTest, SetDevice)
2668 {
2669     json setDeviceFile = validConfigFile;
2670     setDeviceFile["rules"][0]["actions"][1]["set_device"] = "vdd_regulator";
2671     // Valid: test set_device.
2672     {
2673         json configFile = setDeviceFile;
2674         EXPECT_JSON_VALID(configFile);
2675     }
2676     // Invalid: test set_device wrong type.
2677     {
2678         json configFile = setDeviceFile;
2679         configFile["rules"][0]["actions"][1]["set_device"] = true;
2680         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2681                             "True is not of type 'string'");
2682     }
2683     // Invalid: test set_device wrong format.
2684     {
2685         json configFile = setDeviceFile;
2686         configFile["rules"][0]["actions"][1]["set_device"] = "io_expander2%";
2687         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2688                             "'io_expander2%' does not match '^[A-Za-z0-9_]+$'");
2689     }
2690 }
2691 TEST(ValidateRegulatorsConfigTest, DuplicateRuleID)
2692 {
2693     // Invalid: test duplicate ID in rule.
2694     {
2695         json configFile = validConfigFile;
2696         configFile["rules"][2]["id"] = "set_voltage_rule";
2697         configFile["rules"][2]["actions"][0]["pmbus_write_vout_command"]
2698                   ["format"] = "linear";
2699         EXPECT_JSON_INVALID(configFile, "Error: Duplicate rule ID.", "");
2700     }
2701 }
2702 TEST(ValidateRegulatorsConfigTest, DuplicateChassisNumber)
2703 {
2704     // Invalid: test duplicate number in chassis.
2705     {
2706         json configFile = validConfigFile;
2707         configFile["chassis"][1]["number"] = 1;
2708         EXPECT_JSON_INVALID(configFile, "Error: Duplicate chassis number.", "");
2709     }
2710 }
2711 TEST(ValidateRegulatorsConfigTest, DuplicateDeviceID)
2712 {
2713     // Invalid: test duplicate ID in device.
2714     {
2715         json configFile = validConfigFile;
2716         configFile["chassis"][0]["devices"][1]["id"] = "vdd_regulator";
2717         configFile["chassis"][0]["devices"][1]["is_regulator"] = true;
2718         configFile["chassis"][0]["devices"][1]["fru"] =
2719             "system/chassis/motherboard/regulator1";
2720         configFile["chassis"][0]["devices"][1]["i2c_interface"]["bus"] = 2;
2721         configFile["chassis"][0]["devices"][1]["i2c_interface"]["address"] =
2722             "0x71";
2723         EXPECT_JSON_INVALID(configFile, "Error: Duplicate device ID.", "");
2724     }
2725 }
2726 TEST(ValidateRegulatorsConfigTest, DuplicateRailID)
2727 {
2728     // Invalid: test duplicate ID in rail.
2729     {
2730         json configFile = validConfigFile;
2731         configFile["chassis"][0]["devices"][0]["rails"][1]["id"] = "vdd";
2732         EXPECT_JSON_INVALID(configFile, "Error: Duplicate rail ID.", "");
2733     }
2734 }
2735 TEST(ValidateRegulatorsConfigTest, DuplicateObjectID)
2736 {
2737     // Invalid: test duplicate object ID in device and rail.
2738     {
2739         json configFile = validConfigFile;
2740         configFile["chassis"][0]["devices"][0]["rails"][1]["id"] =
2741             "vdd_regulator";
2742         EXPECT_JSON_INVALID(configFile, "Error: Duplicate ID.", "");
2743     }
2744     // Invalid: test duplicate object ID in device and rule.
2745     {
2746         json configFile = validConfigFile;
2747         configFile["rules"][2]["id"] = "vdd_regulator";
2748         configFile["rules"][2]["actions"][0]["pmbus_write_vout_command"]
2749                   ["format"] = "linear";
2750         EXPECT_JSON_INVALID(configFile, "Error: Duplicate ID.", "");
2751     }
2752     // Invalid: test duplicate object ID in rule and rail.
2753     {
2754         json configFile = validConfigFile;
2755         configFile["chassis"][0]["devices"][0]["rails"][1]["id"] =
2756             "set_voltage_rule";
2757         EXPECT_JSON_INVALID(configFile, "Error: Duplicate ID.", "");
2758     }
2759 }
2760 TEST(ValidateRegulatorsConfigTest, InfiniteLoops)
2761 {
2762     // Invalid: test run_rule with infinite loop (rules run each other).
2763     {
2764         json configFile = validConfigFile;
2765         configFile["rules"][2]["actions"][0]["run_rule"] = "set_voltage_rule2";
2766         configFile["rules"][2]["id"] = "set_voltage_rule1";
2767         configFile["rules"][3]["actions"][0]["run_rule"] = "set_voltage_rule1";
2768         configFile["rules"][3]["id"] = "set_voltage_rule2";
2769         EXPECT_JSON_INVALID(configFile,
2770                             "Infinite loop caused by run_rule actions.", "");
2771     }
2772     // Invalid: test run_rule with infinite loop (rule runs itself).
2773     {
2774         json configFile = validConfigFile;
2775         configFile["rules"][2]["actions"][0]["run_rule"] = "set_voltage_rule1";
2776         configFile["rules"][2]["id"] = "set_voltage_rule1";
2777         EXPECT_JSON_INVALID(configFile,
2778                             "Infinite loop caused by run_rule actions.", "");
2779     }
2780     // Invalid: test run_rule with infinite loop (indirect loop).
2781     {
2782         json configFile = validConfigFile;
2783         configFile["rules"][2]["actions"][0]["run_rule"] = "set_voltage_rule2";
2784         configFile["rules"][2]["id"] = "set_voltage_rule1";
2785         configFile["rules"][3]["actions"][0]["run_rule"] = "set_voltage_rule3";
2786         configFile["rules"][3]["id"] = "set_voltage_rule2";
2787         configFile["rules"][4]["actions"][0]["run_rule"] = "set_voltage_rule1";
2788         configFile["rules"][4]["id"] = "set_voltage_rule3";
2789         EXPECT_JSON_INVALID(configFile,
2790                             "Infinite loop caused by run_rule actions.", "");
2791     }
2792 }
2793 TEST(ValidateRegulatorsConfigTest, RunRuleValueExists)
2794 {
2795     // Invalid: test run_rule actions specify a rule ID that does not exist.
2796     {
2797         json configFile = validConfigFile;
2798         configFile["rules"][2]["actions"][0]["run_rule"] = "set_voltage_rule2";
2799         configFile["rules"][2]["id"] = "set_voltage_rule1";
2800         EXPECT_JSON_INVALID(configFile, "Error: Rule ID does not exist.", "");
2801     }
2802 }
2803 TEST(ValidateRegulatorsConfigTest, SetDeviceValueExists)
2804 {
2805     // Invalid: test set_device actions specify a device ID that does not exist.
2806     {
2807         json configFile = validConfigFile;
2808         configFile["rules"][2]["actions"][0]["set_device"] = "vdd_regulator2";
2809         configFile["rules"][2]["id"] = "set_voltage_rule1";
2810         EXPECT_JSON_INVALID(configFile, "Error: Device ID does not exist.", "");
2811     }
2812 }
2813 TEST(ValidateRegulatorsConfigTest, RuleIDExists)
2814 {
2815     // Invalid: test rule_id property in configuration specifies a rule ID that
2816     // does not exist.
2817     {
2818         json configFile = validConfigFile;
2819         configFile["chassis"][0]["devices"][0]["configuration"]["rule_id"] =
2820             "set_voltage_rule2";
2821         EXPECT_JSON_INVALID(configFile, "Error: Rule ID does not exist.", "");
2822     }
2823     // Invalid: test rule_id property in presence_detection specifies a rule ID
2824     // that does not exist.
2825     {
2826         json configFile = validConfigFile;
2827         configFile["chassis"][0]["devices"][0]["presence_detection"]
2828                   ["rule_id"] = "set_voltage_rule2";
2829         EXPECT_JSON_INVALID(configFile, "Error: Rule ID does not exist.", "");
2830     }
2831     // Invalid: test rule_id property in sensor_monitoring specifies a rule ID
2832     // that does not exist.
2833     {
2834         json configFile = validConfigFile;
2835         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2836                   ["rule_id"] = "set_voltage_rule2";
2837         EXPECT_JSON_INVALID(configFile, "Error: Rule ID does not exist.", "");
2838     }
2839 }
2840 TEST(ValidateRegulatorsConfigTest, NumberOfElementsInMasks)
2841 {
2842     // Invalid: test number of elements in masks not equal to number in values
2843     // in i2c_compare_bytes.
2844     {
2845         json configFile = validConfigFile;
2846         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["register"] =
2847             "0x82";
2848         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["values"] = {
2849             "0x02", "0x73"};
2850         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["masks"] = {
2851             "0x7F"};
2852         EXPECT_JSON_INVALID(configFile,
2853                             "Error: Invalid i2c_compare_bytes action.", "");
2854     }
2855     // Invalid: test number of elements in masks not equal to number in values
2856     // in i2c_write_bytes.
2857     {
2858         json configFile = validConfigFile;
2859         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["register"] =
2860             "0x82";
2861         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["values"] = {
2862             "0x02", "0x73"};
2863         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["masks"] = {
2864             "0x7F"};
2865         EXPECT_JSON_INVALID(configFile,
2866                             "Error: Invalid i2c_write_bytes action.", "");
2867     }
2868 }
2869 TEST(ValidateRegulatorsConfigTest, CommandLineSyntax)
2870 {
2871     std::string validateTool =
2872         " ../phosphor-regulators/tools/validate-regulators-config.py ";
2873     std::string schema = " -s ";
2874     std::string schemaFile =
2875         " ../phosphor-regulators/schema/config_schema.json ";
2876     std::string configuration = " -c ";
2877     std::string command;
2878     std::string errorMessage;
2879     std::string outputMessage;
2880     std::string outputMessageHelp =
2881         "usage: validate-regulators-config.py [-h] [-s SCHEMA_FILE]";
2882     int valid = 0;
2883 
2884     TemporaryFile tmpFile;
2885     std::string fileName = tmpFile.getPath().string();
2886     writeDataToFile(validConfigFile, fileName);
2887     // Valid: -s specified
2888     {
2889         command = validateTool + "-s " + schemaFile + configuration + fileName;
2890         expectCommandLineSyntax(errorMessage, outputMessage, command, valid);
2891     }
2892     // Valid: --schema-file specified
2893     {
2894         command = validateTool + "--schema-file " + schemaFile + configuration +
2895                   fileName;
2896         expectCommandLineSyntax(errorMessage, outputMessage, command, valid);
2897     }
2898     // Valid: -c specified
2899     {
2900         command = validateTool + schema + schemaFile + "-c " + fileName;
2901         expectCommandLineSyntax(errorMessage, outputMessage, command, valid);
2902     }
2903     // Valid: --configuration-file specified
2904     {
2905         command = validateTool + schema + schemaFile + "--configuration-file " +
2906                   fileName;
2907         expectCommandLineSyntax(errorMessage, outputMessage, command, valid);
2908     }
2909     // Valid: -h specified
2910     {
2911         command = validateTool + "-h ";
2912         expectCommandLineSyntax(errorMessage, outputMessageHelp, command,
2913                                 valid);
2914     }
2915     // Valid: --help specified
2916     {
2917         command = validateTool + "--help ";
2918         expectCommandLineSyntax(errorMessage, outputMessageHelp, command,
2919                                 valid);
2920     }
2921     // Invalid: -c/--configuration-file not specified
2922     {
2923         command = validateTool + schema + schemaFile;
2924         expectCommandLineSyntax("Error: Configuration file is required.",
2925                                 outputMessageHelp, command, 1);
2926     }
2927     // Invalid: -s/--schema-file not specified
2928     {
2929         command = validateTool + configuration + fileName;
2930         expectCommandLineSyntax("Error: Schema file is required.",
2931                                 outputMessageHelp, command, 1);
2932     }
2933     // Invalid: -c specified more than once
2934     {
2935         command = validateTool + schema + schemaFile + "-c -c " + fileName;
2936         expectCommandLineSyntax(outputMessageHelp, outputMessage, command, 2);
2937     }
2938     // Invalid: -s specified more than once
2939     {
2940         command =
2941             validateTool + "-s -s " + schemaFile + configuration + fileName;
2942         expectCommandLineSyntax(outputMessageHelp, outputMessage, command, 2);
2943     }
2944     // Invalid: No file name specified after -c
2945     {
2946         command = validateTool + schema + schemaFile + configuration;
2947         expectCommandLineSyntax(outputMessageHelp, outputMessage, command, 2);
2948     }
2949     // Invalid: No file name specified after -s
2950     {
2951         command = validateTool + schema + configuration + fileName;
2952         expectCommandLineSyntax(outputMessageHelp, outputMessage, command, 2);
2953     }
2954     // Invalid: File specified after -c does not exist
2955     {
2956         command = validateTool + schema + schemaFile + configuration +
2957                   "../notExistFile";
2958         expectCommandLineSyntax("Error: Configuration file does not exist.",
2959                                 outputMessageHelp, command, 1);
2960     }
2961     // Invalid: File specified after -s does not exist
2962     {
2963         command = validateTool + schema + "../notExistFile " + configuration +
2964                   fileName;
2965         expectCommandLineSyntax("Error: Schema file does not exist.",
2966                                 outputMessageHelp, command, 1);
2967     }
2968     // Invalid: File specified after -c is not right data format
2969     {
2970         TemporaryFile wrongFormatFile;
2971         std::string wrongFormatFileName = wrongFormatFile.getPath().string();
2972         std::ofstream out(wrongFormatFileName);
2973         out << "foo";
2974         out.close();
2975         command = validateTool + schema + schemaFile + configuration +
2976                   wrongFormatFileName;
2977         expectCommandLineSyntax(
2978             "Error: Configuration file is not in the JSON format.",
2979             outputMessageHelp, command, 1);
2980     }
2981     // Invalid: File specified after -s is not right data format
2982     {
2983         TemporaryFile wrongFormatFile;
2984         std::string wrongFormatFileName = wrongFormatFile.getPath().string();
2985         std::ofstream out(wrongFormatFileName);
2986         out << "foo";
2987         out.close();
2988         command = validateTool + schema + wrongFormatFileName + configuration +
2989                   fileName;
2990         expectCommandLineSyntax("Error: Schema file is not in the JSON format.",
2991                                 outputMessageHelp, command, 1);
2992     }
2993     // Invalid: File specified after -c is not readable
2994     {
2995         TemporaryFile notReadableFile;
2996         std::string notReadableFileName = notReadableFile.getPath().string();
2997         writeDataToFile(validConfigFile, notReadableFileName);
2998         command = validateTool + schema + schemaFile + configuration +
2999                   notReadableFileName;
3000         chmod(notReadableFileName.c_str(), 0222);
3001         expectCommandLineSyntax("Error: Configuration file is not readable.",
3002                                 outputMessageHelp, command, 1);
3003     }
3004     // Invalid: File specified after -s is not readable
3005     {
3006         TemporaryFile notReadableFile;
3007         std::string notReadableFileName = notReadableFile.getPath().string();
3008         writeDataToFile(validConfigFile, notReadableFileName);
3009         command = validateTool + schema + notReadableFileName + configuration +
3010                   fileName;
3011         chmod(notReadableFileName.c_str(), 0222);
3012         expectCommandLineSyntax("Error: Schema file is not readable.",
3013                                 outputMessageHelp, command, 1);
3014     }
3015     // Invalid: Unexpected parameter specified (like -g)
3016     {
3017         command = validateTool + schema + schemaFile + configuration +
3018                   fileName + " -g";
3019         expectCommandLineSyntax(outputMessageHelp, outputMessage, command, 2);
3020     }
3021 }
3022