From 5a02a4c7508b22abddcedc586565c5708b431bc4 Mon Sep 17 00:00:00 2001 From: tqcq <99722391+tqcq@users.noreply.github.com> Date: Thu, 15 Aug 2024 11:12:06 +0800 Subject: [PATCH] fix json configuration --- .gitignore | 1 + CMakeLists.txt | 3 + tile/base/config/json_configuration.cc | 36 ++++++---- tile/base/config/json_configuration.h | 9 +-- tile/base/config/json_configuration_test.cc | 76 +++++++++++++++++++++ 5 files changed, 108 insertions(+), 17 deletions(-) create mode 100644 tile/base/config/json_configuration_test.cc diff --git a/.gitignore b/.gitignore index 253e16b..6e95f64 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ out/ build/ .cache/ compile_commands.json +.gdb_history diff --git a/CMakeLists.txt b/CMakeLists.txt index 23a459c..405b12b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -302,6 +302,9 @@ function(add_test_group prefix group_name) # convert to relative path message(STATUS "${prefix} -> ${TEST_FILE}") file(RELATIVE_PATH TEST_NAME "${prefix}" "${SRC_FILE}") string(REPLACE "/" "_" TEST_NAME "${TEST_NAME}") + string(REPLACE ".cpp" "" TEST_NAME "${TEST_NAME}") + string(REPLACE ".cc" "" TEST_NAME "${TEST_NAME}") + string(REPLACE ".c" "" TEST_NAME "${TEST_NAME}") # if group_name is not empty, add suffix _ if (NOT group_name STREQUAL "") set(TEST_NAME "${group_name}_${TEST_NAME}") diff --git a/tile/base/config/json_configuration.cc b/tile/base/config/json_configuration.cc index 918f3ff..efdc238 100644 --- a/tile/base/config/json_configuration.cc +++ b/tile/base/config/json_configuration.cc @@ -22,33 +22,39 @@ bool JSONConfiguration::load(std::istream &istr) { } void JSONConfiguration::SetInt(const Slice &key, int value) { + Configuration::ScopedLock _(*this); SetValue(key, value); } void JSONConfiguration::SetBool(const Slice &key, bool value) { + Configuration::ScopedLock _(*this); SetValue(key, value); } void JSONConfiguration::SetDouble(const Slice &key, double value) { + Configuration::ScopedLock _(*this); SetValue(key, value); } void JSONConfiguration::SetString(const Slice &key, const std::string &value) { + Configuration::ScopedLock _(*this); SetValue(key, value); } void JSONConfiguration::RemoveRaw(const Slice &key) { - Configuration::ScopedLock _(*this); - Json::Value root; + Json::Value *root; Slice last_part; if (!FindStart(key, &last_part, &root)) { return; } - root.removeMember(last_part.ToString()); + root->removeMember(last_part.ToString()); +} +std::string JSONConfiguration::Dump() const { + Configuration::ScopedLock _(*this); + return object_.toStyledString(); } bool JSONConfiguration::GetRaw(const Slice &key, std::string *value) const { - Configuration::ScopedLock _(*this); auto keys = Split(key, '.'); auto root = object_; for (std::size_t i = 0; i < keys.size(); ++i) { @@ -57,13 +63,17 @@ bool JSONConfiguration::GetRaw(const Slice &key, std::string *value) const { TILE_LOG_ERROR("Invalid key: {}", key); return false; } - if (!object_.isMember(cur_key)) { + if (!root.isMember(cur_key)) { return false; } root = root[cur_key]; } - *value = root.asString(); + if (root.isConvertibleTo(Json::stringValue)) { + *value = root.asString(); + } else { + *value = root.toStyledString(); + } return true; } @@ -83,7 +93,7 @@ Configuration::Keys JSONConfiguration::Enumerate(const Slice &range) const { TILE_LOG_ERROR("Invalid range: {}", range); return key_set; } - if (!object_.isMember(cur_key)) { + if (!root.isMember(cur_key)) { return key_set; } root = root[cur_key]; @@ -96,13 +106,13 @@ Configuration::Keys JSONConfiguration::Enumerate(const Slice &range) const { } bool JSONConfiguration::FindStart(const Slice &key, Slice *last_part, - Json::Value *parent_obj) { + Json::Value **parent_obj) { auto keys = Split(key, '.'); if (keys.empty()) { return false; } - auto root = object_; + Json::Value *root = &object_; for (std::size_t i = 0; i < keys.size() - 1; ++i) { const auto &cur_key = keys[i]; if (cur_key.empty()) { @@ -110,14 +120,14 @@ bool JSONConfiguration::FindStart(const Slice &key, Slice *last_part, return false; } - if (!root.isMember(cur_key)) { - root[cur_key] = Json::Value(Json::objectValue); - } else if (!root[cur_key].isObject()) { + if (!root->isMember(cur_key)) { + (*root)[cur_key] = Json::Value(Json::objectValue); + } else if (!(*root)[cur_key].isObject()) { TILE_LOG_ERROR("only leaf nodes can be set: key: {}, cur_key(idx={}): {}", key, i, cur_key); return false; } - root = root[cur_key]; + root = &(*root)[cur_key]; } *last_part = keys.back(); diff --git a/tile/base/config/json_configuration.h b/tile/base/config/json_configuration.h index 2208300..be45c3a 100644 --- a/tile/base/config/json_configuration.h +++ b/tile/base/config/json_configuration.h @@ -21,13 +21,15 @@ public: void SetString(const Slice &key, const std::string &value) override; void RemoveRaw(const Slice &key) override; + std::string Dump() const; + protected: bool GetRaw(const Slice &key, std::string *value) const override; bool SetRaw(const Slice &key, const Slice &value) override; Keys Enumerate(const Slice &range) const override; private: - bool FindStart(const Slice &key, Slice *last_prt, Json::Value *parent_obj); + bool FindStart(const Slice &key, Slice *last_prt, Json::Value **parent_obj); template bool SetValue(const Slice &key, T value); Json::Value object_; }; @@ -35,12 +37,11 @@ private: template bool JSONConfiguration::SetValue(const Slice &key, T value) { Slice last_part; - Json::Value root; - Configuration::ScopedLock _(*this); + Json::Value *root; if (!FindStart(key, &last_part, &root)) { return false; } - root[last_part] = Json::Value(value); + (*root)[last_part] = Json::Value(value); return true; } } // namespace tile diff --git a/tile/base/config/json_configuration_test.cc b/tile/base/config/json_configuration_test.cc new file mode 100644 index 0000000..33be658 --- /dev/null +++ b/tile/base/config/json_configuration_test.cc @@ -0,0 +1,76 @@ +#include "tile/base/config/json_configuration.h" + +#include "gtest/gtest.h" + +namespace tile { +namespace { +const char *kJsonConfig = R"( + { + "key1": "value1", + "key2": 2, + "key3": 3.0, + "key4": true, + "key5": { + "key51": "value51", + "key52": 52 + } + } + )"; +} + +TEST(JSONConfiguration, Load) { + JSONConfiguration config; + std::istringstream istr(kJsonConfig); + ASSERT_TRUE(config.load(istr)); +} +TEST(JSONConfiguration, Has) { + JSONConfiguration config; + std::istringstream istr(kJsonConfig); + ASSERT_TRUE(config.load(istr)); + + ASSERT_TRUE(config.Has("key1")); + ASSERT_TRUE(config.Has("key2")); + ASSERT_TRUE(config.Has("key3")); + ASSERT_TRUE(config.Has("key4")); + ASSERT_TRUE(config.Has("key5")); + ASSERT_TRUE(config.Has("key5.key51")); + ASSERT_TRUE(config.Has("key5.key52")); +} + +TEST(JSONConfiguration, SampleSet) { + JSONConfiguration config; + std::istringstream istr(kJsonConfig); + ASSERT_TRUE(config.load(istr)); + ASSERT_TRUE(config.GetInt32("key2")); + ASSERT_EQ(*config.GetInt32("key2"), 2); + + config.SetInt("key2", 20); + ASSERT_TRUE(config.GetInt32("key2")); + ASSERT_EQ(20, *config.GetInt32("key2")) << config.Dump(); + + config.SetDouble("key3", 30.0); + ASSERT_TRUE(config.GetDouble("key3")); + ASSERT_NEAR(30.0, *config.GetDouble("key3"), 0.0001) << config.Dump(); + + config.SetBool("key4", false); + ASSERT_TRUE(config.GetBool("key4")); + ASSERT_FALSE(*config.GetBool("key4")) << config.Dump(); +} + +TEST(JSONConfiguration, LayeredSet) { + JSONConfiguration config; + std::istringstream istr(kJsonConfig); + ASSERT_TRUE(config.load(istr)); + + // ASSERT_TRUE(config.GetInt32("key5.key52")); + config.SetInt("key5.key52", 520); + ASSERT_TRUE(config.GetInt32("key5.key52")) << config.Dump(); + ASSERT_EQ(520, *config.GetInt32("key5.key52")) << config.Dump(); + + // override by other type + config.SetBool("key5.key52", false); + ASSERT_TRUE(config.GetBool("key5.key52")) << config.Dump(); + ASSERT_FALSE(*config.GetBool("key5.key52")) << config.Dump(); +} + +} // namespace tile