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