regulators: Add log_phase_fault to parser

Enhance the JSON configuration file parser to support the new
log_phase_fault action.

Add gtest test cases to exercise new code.

Signed-off-by: Shawn McCarney <shawnmm@us.ibm.com>
Change-Id: I8ef9974df8ca8be07dd284552bd978802f502338
diff --git a/phosphor-regulators/src/config_file_parser.cpp b/phosphor-regulators/src/config_file_parser.cpp
index 5330f59..6527b5f 100644
--- a/phosphor-regulators/src/config_file_parser.cpp
+++ b/phosphor-regulators/src/config_file_parser.cpp
@@ -120,6 +120,11 @@
         action = parseIf(element["if"]);
         ++propertyCount;
     }
+    else if (element.contains("log_phase_fault"))
+    {
+        action = parseLogPhaseFault(element["log_phase_fault"]);
+        ++propertyCount;
+    }
     else if (element.contains("not"))
     {
         action = parseNot(element["not"]);
@@ -715,6 +720,22 @@
     return absPath;
 }
 
+std::unique_ptr<LogPhaseFaultAction> parseLogPhaseFault(const json& element)
+{
+    verifyIsObject(element);
+    unsigned int propertyCount{0};
+
+    // Required type property
+    const json& typeElement = getRequiredProperty(element, "type");
+    PhaseFaultType type = parsePhaseFaultType(typeElement);
+    ++propertyCount;
+
+    // Verify no invalid properties exist
+    verifyPropertyCount(element, propertyCount);
+
+    return std::make_unique<LogPhaseFaultAction>(type);
+}
+
 std::unique_ptr<NotAction> parseNot(const json& element)
 {
     // Required action to execute
diff --git a/phosphor-regulators/src/config_file_parser.hpp b/phosphor-regulators/src/config_file_parser.hpp
index a1bdd6e..63c8bf8 100644
--- a/phosphor-regulators/src/config_file_parser.hpp
+++ b/phosphor-regulators/src/config_file_parser.hpp
@@ -31,6 +31,7 @@
 #include "i2c_write_byte_action.hpp"
 #include "i2c_write_bytes_action.hpp"
 #include "if_action.hpp"
+#include "log_phase_fault_action.hpp"
 #include "not_action.hpp"
 #include "or_action.hpp"
 #include "phase_fault.hpp"
@@ -516,6 +517,19 @@
 std::string parseInventoryPath(const nlohmann::json& element);
 
 /**
+ * Parses a JSON element containing a log_phase_fault action.
+ *
+ * Returns the corresponding C++ LogPhaseFaultAction object.
+ *
+ * Throws an exception if parsing fails.
+ *
+ * @param element JSON element
+ * @return LogPhaseFaultAction object
+ */
+std::unique_ptr<LogPhaseFaultAction>
+    parseLogPhaseFault(const nlohmann::json& element);
+
+/**
  * Parses a JSON element containing a not action.
  *
  * Returns the corresponding C++ NotAction object.
diff --git a/phosphor-regulators/test/config_file_parser_tests.cpp b/phosphor-regulators/test/config_file_parser_tests.cpp
index cf261fa..b48f8b8 100644
--- a/phosphor-regulators/test/config_file_parser_tests.cpp
+++ b/phosphor-regulators/test/config_file_parser_tests.cpp
@@ -30,6 +30,7 @@
 #include "i2c_write_bit_action.hpp"
 #include "i2c_write_byte_action.hpp"
 #include "i2c_write_bytes_action.hpp"
+#include "log_phase_fault_action.hpp"
 #include "not_action.hpp"
 #include "or_action.hpp"
 #include "phase_fault.hpp"
@@ -410,6 +411,19 @@
         EXPECT_NE(action.get(), nullptr);
     }
 
+    // Test where works: log_phase_fault action type specified
+    {
+        const json element = R"(
+            {
+              "log_phase_fault": {
+                "type": "n+1"
+              }
+            }
+        )"_json;
+        std::unique_ptr<Action> action = parseAction(element);
+        EXPECT_NE(action.get(), nullptr);
+    }
+
     // Test where works: not action type specified
     {
         const json element = R"(
@@ -3329,6 +3343,81 @@
     }
 }
 
+TEST(ConfigFileParserTests, ParseLogPhaseFault)
+{
+    // Test where works
+    {
+        const json element = R"(
+            {
+              "type": "n+1"
+            }
+        )"_json;
+        std::unique_ptr<LogPhaseFaultAction> action =
+            parseLogPhaseFault(element);
+        EXPECT_EQ(action->getType(), PhaseFaultType::n_plus_1);
+    }
+
+    // Test where fails: Element is not an object
+    try
+    {
+        const json element = R"( [ "0xFF", "0x01" ] )"_json;
+        parseLogPhaseFault(element);
+        ADD_FAILURE() << "Should not have reached this line.";
+    }
+    catch (const std::invalid_argument& e)
+    {
+        EXPECT_STREQ(e.what(), "Element is not an object");
+    }
+
+    // Test where fails: Required type property not specified
+    try
+    {
+        const json element = R"(
+            {
+            }
+        )"_json;
+        parseLogPhaseFault(element);
+        ADD_FAILURE() << "Should not have reached this line.";
+    }
+    catch (const std::invalid_argument& e)
+    {
+        EXPECT_STREQ(e.what(), "Required property missing: type");
+    }
+
+    // Test where fails: type value is invalid
+    try
+    {
+        const json element = R"(
+            {
+              "type": "n+2"
+            }
+        )"_json;
+        parseLogPhaseFault(element);
+        ADD_FAILURE() << "Should not have reached this line.";
+    }
+    catch (const std::invalid_argument& e)
+    {
+        EXPECT_STREQ(e.what(), "Element is not a phase fault type");
+    }
+
+    // Test where fails: Invalid property specified
+    try
+    {
+        const json element = R"(
+            {
+              "type": "n+1",
+              "foo": 1
+            }
+        )"_json;
+        parseLogPhaseFault(element);
+        ADD_FAILURE() << "Should not have reached this line.";
+    }
+    catch (const std::invalid_argument& e)
+    {
+        EXPECT_STREQ(e.what(), "Element contains an invalid property");
+    }
+}
+
 TEST(ConfigFileParserTests, ParseNot)
 {
     // Test where works