fix(config): preserve explicit null when merging objects

This commit is contained in:
Aleksei Bavshin 2021-09-15 22:14:12 +07:00
parent ccc60b4245
commit 0c1d3e30b6
No known key found for this signature in database
GPG Key ID: 4F071603387A382A
4 changed files with 13 additions and 4 deletions

View File

@ -1,5 +1,6 @@
#include "config.hpp" #include "config.hpp"
#include <fmt/ostream.h>
#include <spdlog/spdlog.h> #include <spdlog/spdlog.h>
#include <unistd.h> #include <unistd.h>
#include <wordexp.h> #include <wordexp.h>
@ -86,11 +87,15 @@ void Config::mergeConfig(Json::Value &a_config_, Json::Value &b_config_) {
a_config_ = b_config_; a_config_ = b_config_;
} else if (a_config_.isObject() && b_config_.isObject()) { } else if (a_config_.isObject() && b_config_.isObject()) {
for (const auto &key : b_config_.getMemberNames()) { for (const auto &key : b_config_.getMemberNames()) {
if (a_config_[key].isObject() && b_config_[key].isObject()) { // [] creates key with default value. Use `get` to avoid that.
if (a_config_.get(key, Json::Value::nullSingleton()).isObject() &&
b_config_[key].isObject()) {
mergeConfig(a_config_[key], b_config_[key]); mergeConfig(a_config_[key], b_config_[key]);
} else if (a_config_[key].isNull()) { } else if (!a_config_.isMember(key)) {
// do not allow overriding value set by top or previously included config // do not allow overriding value set by top or previously included config
a_config_[key] = b_config_[key]; a_config_[key] = b_config_[key];
} else {
spdlog::trace("Option {} is already set; ignoring value {}", key, b_config_[key]);
} }
} }
} else { } else {

View File

@ -67,6 +67,8 @@ TEST_CASE("Load simple config with include", "[config]") {
REQUIRE(data["height"].asInt() == 30); REQUIRE(data["height"].asInt() == 30);
// config override behavior: preserve value from the top config // config override behavior: preserve value from the top config
REQUIRE(data["position"].asString() == "top"); REQUIRE(data["position"].asString() == "top");
// config override behavior: explicit null is still a value and should be preserved
REQUIRE((data.isMember("nullOption") && data["nullOption"].isNull()));
} }
SECTION("select configs for configured output") { SECTION("select configs for configured output") {
auto configs = conf.getOutputConfigs("HDMI-0", "Fake HDMI output #0"); auto configs = conf.getOutputConfigs("HDMI-0", "Fake HDMI output #0");

View File

@ -2,5 +2,6 @@
"layer": "top", "layer": "top",
"position": "bottom", "position": "bottom",
"height": 30, "height": 30,
"output": ["HDMI-0", "DP-0"] "output": ["HDMI-0", "DP-0"],
"nullOption": "not null"
} }

View File

@ -1,4 +1,5 @@
{ {
"include": ["test/config/include-1.json", "test/config/include-2.json"], "include": ["test/config/include-1.json", "test/config/include-2.json"],
"position": "top" "position": "top",
"nullOption": null
} }