json_serializer: add tests

Signed-off-by: Patrick Williams <patrick@stwcx.xyz>
Change-Id: I717b01ac4f69b9b086a4853cb28bb4c27d1f784b
diff --git a/test/json_serializer_test.cpp b/test/json_serializer_test.cpp
new file mode 100644
index 0000000..50ac53f
--- /dev/null
+++ b/test/json_serializer_test.cpp
@@ -0,0 +1,125 @@
+#include <unistd.h>
+
+#include <json_serializer.hpp>
+
+#include <filesystem>
+#include <fstream>
+#include <string>
+
+#include <gtest/gtest.h>
+
+namespace s = std::string_literals;
+
+class JsonSerializerTest : public testing::Test
+{
+  protected:
+    std::string test_file;
+
+    void SetUp() override
+    {
+        char tmpTemplate[] = "/tmp/test_file_XXXXXX";
+        int fd = mkstemp(tmpTemplate);
+        if (fd == -1)
+        {
+            throw std::runtime_error("Failed to create temporary file.");
+        }
+        close(fd);
+        test_file = tmpTemplate;
+    }
+
+    void TearDown() override
+    {
+        if (std::filesystem::exists(test_file))
+        {
+            std::filesystem::remove(test_file);
+        }
+    }
+};
+
+TEST_F(JsonSerializerTest, MakeJson)
+{
+    JsonSerializer s(test_file);
+    nlohmann::json j = s.makeJson("foo/bar/baz", "value");
+    EXPECT_EQ(j["foo"]["bar"]["baz"], "value");
+}
+
+TEST_F(JsonSerializerTest, SerializeDeserialize)
+{
+    JsonSerializer s(test_file);
+    s.serialize("foo/bar/baz", "value");
+    std::string value;
+    s.deserialize("foo/bar/baz", value);
+    EXPECT_EQ(value, "value");
+}
+
+TEST_F(JsonSerializerTest, StoreLoad)
+{
+    JsonSerializer s(test_file);
+    s.serialize("foo/bar/baz", "value");
+    s.store();
+
+    // Create a new JsonSerializer instance to load from the same file
+    // This simulates a fresh process loading the configuration
+    JsonSerializer s2(test_file);
+    s2.load();
+    std::string value;
+    s2.deserialize("foo/bar/baz", value);
+    EXPECT_EQ(value, "value");
+}
+
+TEST_F(JsonSerializerTest, Erase)
+{
+    JsonSerializer s(test_file);
+    s.serialize("foo/bar/baz", "value");
+    // The current erase method only handles top-level keys.
+    // Calling erase with a nested path like "foo/bar/baz" will not remove
+    // "baz".
+    s.erase("foo/bar/baz");
+    s.store();
+
+    // Verify that the value is still present because erase did not remove the
+    // nested key.
+    JsonSerializer s2(test_file);
+    s2.load();
+    std::string value;
+    s2.deserialize("foo/bar/baz", value);
+    EXPECT_EQ(value, "value"); // Expect original value to remain
+}
+
+TEST_F(JsonSerializerTest, GetLeafNode)
+{
+    JsonSerializer s(test_file);
+    s.serialize("foo/bar/baz", "value");
+    auto leaf = s.getLeafNode("foo/bar/baz");
+    EXPECT_TRUE(leaf.has_value());
+    if (leaf.has_value())
+    {
+        EXPECT_EQ(*leaf, "value");
+    }
+
+    leaf = s.getLeafNode("foo/bar/nonexistent");
+    EXPECT_FALSE(leaf.has_value());
+}
+
+TEST_F(JsonSerializerTest, LoadInvalidJsonFile)
+{
+    // Ensure the file is empty or contains invalid JSON
+    std::ofstream ofs(test_file, std::ios::trunc);
+    ofs.close();
+
+    JsonSerializer s(test_file);
+    // nlohmann::json will throw a parse error for empty files or invalid JSON
+    EXPECT_THROW(s.load(), nlohmann::json::parse_error);
+}
+
+TEST_F(JsonSerializerTest, LoadGarbledJsonFile)
+{
+    // Write a garbled JSON string to the file
+    std::ofstream ofs(test_file);
+    ofs << "{"; // Incomplete JSON object
+    ofs.close();
+
+    JsonSerializer s(test_file);
+    // nlohmann::json will throw a parse error for incomplete JSON
+    EXPECT_THROW(s.load(), nlohmann::json::parse_error);
+}
diff --git a/test/meson.build b/test/meson.build
index adb9651..e544958 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -48,6 +48,17 @@
 )
 
 test(
+    'json_serializer_test',
+    executable(
+        'json_serializer_test',
+        'json_serializer_test.cpp',
+        include_directories: '..',
+        dependencies: [gtest_dep, gmock_dep, user_manager_dep],
+    ),
+)
+
+
+test(
     'execute_cmd_test',
     executable(
         'execute_cmd_test',