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