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