xref: /openbmc/phosphor-user-manager/test/json_serializer_test.cpp (revision 5cf5ddf3f4cbc9fc5573117bb5409249f7a02ee4)
1 #include <unistd.h>
2 
3 #include <json_serializer.hpp>
4 
5 #include <filesystem>
6 #include <fstream>
7 #include <string>
8 
9 #include <gtest/gtest.h>
10 
11 namespace s = std::string_literals;
12 
13 class JsonSerializerTest : public testing::Test
14 {
15   protected:
16     std::string test_file;
17 
18     void SetUp() override
19     {
20         char tmpTemplate[] = "/tmp/test_file_XXXXXX";
21         int fd = mkstemp(tmpTemplate);
22         if (fd == -1)
23         {
24             throw std::runtime_error("Failed to create temporary file.");
25         }
26         close(fd);
27         test_file = tmpTemplate;
28     }
29 
30     void TearDown() override
31     {
32         if (std::filesystem::exists(test_file))
33         {
34             std::filesystem::remove(test_file);
35         }
36     }
37 };
38 
39 TEST_F(JsonSerializerTest, MakeJson)
40 {
41     JsonSerializer s(test_file);
42     nlohmann::json j = s.makeJson("foo/bar/baz", "value");
43     EXPECT_EQ(j["foo"]["bar"]["baz"], "value");
44 }
45 
46 TEST_F(JsonSerializerTest, SerializeDeserialize)
47 {
48     JsonSerializer s(test_file);
49     s.serialize("foo/bar/baz", "value");
50     std::string value;
51     s.deserialize("foo/bar/baz", value);
52     EXPECT_EQ(value, "value");
53 }
54 
55 TEST_F(JsonSerializerTest, StoreLoad)
56 {
57     JsonSerializer s(test_file);
58     s.serialize("foo/bar/baz", "value");
59     s.store();
60 
61     // Create a new JsonSerializer instance to load from the same file
62     // This simulates a fresh process loading the configuration
63     JsonSerializer s2(test_file);
64     s2.load();
65     std::string value;
66     s2.deserialize("foo/bar/baz", value);
67     EXPECT_EQ(value, "value");
68 }
69 
70 TEST_F(JsonSerializerTest, Erase)
71 {
72     JsonSerializer s(test_file);
73     s.serialize("foo/bar/baz", "value");
74     // The current erase method only handles top-level keys.
75     // Calling erase with a nested path like "foo/bar/baz" will not remove
76     // "baz".
77     s.erase("foo/bar/baz");
78     s.store();
79 
80     // Verify that the value is still present because erase did not remove the
81     // nested key.
82     JsonSerializer s2(test_file);
83     s2.load();
84     std::string value;
85     s2.deserialize("foo/bar/baz", value);
86     EXPECT_EQ(value, "value"); // Expect original value to remain
87 }
88 
89 TEST_F(JsonSerializerTest, GetLeafNode)
90 {
91     JsonSerializer s(test_file);
92     s.serialize("foo/bar/baz", "value");
93     auto leaf = s.getLeafNode("foo/bar/baz");
94     EXPECT_TRUE(leaf.has_value());
95     if (leaf.has_value())
96     {
97         EXPECT_EQ(*leaf, "value");
98     }
99 
100     leaf = s.getLeafNode("foo/bar/nonexistent");
101     EXPECT_FALSE(leaf.has_value());
102 }
103 
104 TEST_F(JsonSerializerTest, LoadInvalidJsonFile)
105 {
106     // Ensure the file is empty or contains invalid JSON
107     std::ofstream ofs(test_file, std::ios::trunc);
108     ofs.close();
109 
110     JsonSerializer s(test_file);
111     // nlohmann::json will throw a parse error for empty files or invalid JSON
112     EXPECT_THROW(s.load(), nlohmann::json::parse_error);
113 }
114 
115 TEST_F(JsonSerializerTest, LoadGarbledJsonFile)
116 {
117     // Write a garbled JSON string to the file
118     std::ofstream ofs(test_file);
119     ofs << "{"; // Incomplete JSON object
120     ofs.close();
121 
122     JsonSerializer s(test_file);
123     // nlohmann::json will throw a parse error for incomplete JSON
124     EXPECT_THROW(s.load(), nlohmann::json::parse_error);
125 }
126