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