json builder: fix error with buildHandlerConfigs

Problem: mistakenly defined the implementation of buildHandlerConfigs in
a separate cpp file. This breaks calling buildHandlerConfigs from a
derived class.

Solution: move implementation of buildHandlerConfigs into the header.

unit tests added:
firmware_json_unittest.cpp * add a test to parse json from file
                           * add a test to parse an invalid json file

Signed-off-by: Jason Ling <jasonling@google.com>
Change-Id: I5cd93ad01a329850a8ee516fae8a35339c991ae0
diff --git a/bmc/buildjson.cpp b/bmc/buildjson.cpp
index c4bc4b5..9c0bb9c 100644
--- a/bmc/buildjson.cpp
+++ b/bmc/buildjson.cpp
@@ -16,7 +16,6 @@
 #include "buildjson.hpp"
 
 #include "file_handler.hpp"
-#include "fs.hpp"
 
 #include <nlohmann/json.hpp>
 #include <sdbusplus/bus.hpp>
@@ -68,34 +67,4 @@
                                               unit, systemdMode);
 }
 
-template <typename T>
-std::vector<HandlerConfig<T>>
-    HandlersBuilderIfc<T>::buildHandlerConfigs(const std::string& directory)
-{
-    std::vector<HandlerConfig<T>> output;
-
-    std::vector<std::string> jsonPaths = GetJsonList(directory);
-
-    for (const auto& path : jsonPaths)
-    {
-        std::ifstream jsonFile(path);
-        if (!jsonFile.is_open())
-        {
-            std::fprintf(stderr, "Unable to open json file: %s\n",
-                         path.c_str());
-            continue;
-        }
-
-        auto data = nlohmann::json::parse(jsonFile, nullptr, false);
-        if (data.is_discarded())
-        {
-            std::fprintf(stderr, "Parsing json failed: %s\n", path.c_str());
-        }
-
-        std::vector<HandlerConfig<T>> configs = buildHandlerFromJson(data);
-        std::move(configs.begin(), configs.end(), std::back_inserter(output));
-    }
-    return output;
-}
-
 } // namespace ipmi_flash
diff --git a/bmc/buildjson.hpp b/bmc/buildjson.hpp
index 4aae00d..53773c2 100644
--- a/bmc/buildjson.hpp
+++ b/bmc/buildjson.hpp
@@ -1,5 +1,6 @@
 #pragma once
 
+#include "fs.hpp"
 #include "general_systemd.hpp"
 #include "image_handler.hpp"
 
@@ -11,9 +12,15 @@
 
 namespace ipmi_flash
 {
+/**
+ * build a systemd file triggerable action from json data
+ */
 std::unique_ptr<TriggerableActionInterface>
     buildFileSystemd(const nlohmann::json& data);
 
+/**
+ * build a systemd triggerable action from json data
+ */
 std::unique_ptr<TriggerableActionInterface>
     buildSystemd(const nlohmann::json& data);
 
@@ -73,7 +80,35 @@
      * @return list of HandlerConfig objects.
      */
     std::vector<HandlerConfig<T>>
-        buildHandlerConfigs(const std::string& directory);
+        buildHandlerConfigs(const std::string& directory)
+    {
+
+        std::vector<HandlerConfig<T>> output;
+
+        std::vector<std::string> jsonPaths = GetJsonList(directory);
+        for (const auto& path : jsonPaths)
+        {
+            std::ifstream jsonFile(path);
+            if (!jsonFile.is_open())
+            {
+                std::fprintf(stderr, "Unable to open json file: %s\n",
+                             path.c_str());
+                continue;
+            }
+
+            auto data = nlohmann::json::parse(jsonFile, nullptr, false);
+            if (data.is_discarded())
+            {
+                std::fprintf(stderr, "Parsing json failed: %s\n", path.c_str());
+                continue;
+            }
+
+            std::vector<HandlerConfig<T>> configs = buildHandlerFromJson(data);
+            std::move(configs.begin(), configs.end(),
+                      std::back_inserter(output));
+        }
+        return output;
+    };
     /**
      * Given a list of handlers as json data, construct the appropriate
      * HandlerConfig objects.  This method is meant to be called per json
diff --git a/bmc/firmware-handler/test/firmware_json_unittest.cpp b/bmc/firmware-handler/test/firmware_json_unittest.cpp
index 235b33c..89d4741 100644
--- a/bmc/firmware-handler/test/firmware_json_unittest.cpp
+++ b/bmc/firmware-handler/test/firmware_json_unittest.cpp
@@ -13,8 +13,8 @@
 {
 using ::testing::IsEmpty;
 
+static constexpr auto TESTFNAME = "test.json";
 using json = nlohmann::json;
-
 TEST(FirmwareJsonTest, InvalidHandlerType)
 {
     auto j2 = R"(
@@ -615,5 +615,61 @@
     EXPECT_FALSE(h[0].actions->update == nullptr);
 }
 
+TEST(FirmwareJsonTest, BuildFromFile)
+{
+    std::ofstream testfile;
+    testfile.open(TESTFNAME, std::ios::out);
+    auto good = R"(
+        [{
+            "blob" : "/flash/image",
+            "handler" : {
+                "type" : "file",
+                "path" : "/run/initramfs/bmc-image"
+            },
+            "actions" : {
+                "preparation" : {
+                    "type" : "skip"
+                },
+                "verification" : {
+                    "type" : "skip"
+                },
+                "update" : {
+                    "type" : "skip"
+                }
+            }
+         }]
+    )"_json;
+    testfile << good.dump(4);
+    testfile.flush();
+    FirmwareHandlersBuilder b;
+    auto h = b.buildHandlerConfigs("./");
+    EXPECT_EQ(h.size(), 1);
+    EXPECT_EQ(h[0].blobId, "/flash/image");
+    EXPECT_FALSE(h[0].handler == nullptr);
+    EXPECT_FALSE(h[0].actions == nullptr);
+    EXPECT_FALSE(h[0].actions->preparation == nullptr);
+    EXPECT_FALSE(h[0].actions->verification == nullptr);
+    EXPECT_FALSE(h[0].actions->update == nullptr);
+    if (std::remove(TESTFNAME) != 0)
+    {
+        fprintf(stderr, "warning: filecleanup of %s failed\n", TESTFNAME);
+    }
+}
+
+TEST(FirmwareJsonTest, BuildFromBadFile)
+{
+    std::ofstream testfile;
+    testfile.open(TESTFNAME, std::ios::out);
+    testfile << "{] a malformed json {{";
+    testfile.flush();
+    FirmwareHandlersBuilder b;
+    auto h = b.buildHandlerConfigs("./");
+    EXPECT_THAT(h, IsEmpty());
+    if (std::remove(TESTFNAME) != 0)
+    {
+        fprintf(stderr, "warning: filecleanup of %s failed\n", TESTFNAME);
+    }
+}
+
 } // namespace
 } // namespace ipmi_flash