lix/tests/unit/libutil/config.cc

329 lines
11 KiB
C++
Raw Normal View History

2020-05-26 15:49:31 +00:00
#include "config.hh"
#include "args.hh"
#include "file-system.hh"
#include "environment-variables.hh"
#include "logging.hh"
#include "tests/test-data.hh"
2020-05-26 15:49:31 +00:00
#include <sstream>
#include <gtest/gtest.h>
2020-08-25 08:51:14 +00:00
#include <nlohmann/json.hpp>
2020-05-26 15:49:31 +00:00
namespace nix {
/* ----------------------------------------------------------------------------
* Config
* --------------------------------------------------------------------------*/
TEST(Config, setUndefinedSetting) {
Config config;
ASSERT_EQ(config.set("undefined-key", "value"), false);
}
TEST(Config, setDefinedSetting) {
Config config;
std::string value;
Setting<std::string> foo{&config, value, "name-of-the-setting", "description"};
ASSERT_EQ(config.set("name-of-the-setting", "value"), true);
}
TEST(Config, getDefinedSetting) {
Config config;
std::string value;
std::map<std::string, Config::SettingInfo> settings;
Setting<std::string> foo{&config, value, "name-of-the-setting", "description"};
2021-03-26 15:14:38 +00:00
config.getSettings(settings, /* overriddenOnly = */ false);
2020-05-26 15:49:31 +00:00
const auto iter = settings.find("name-of-the-setting");
ASSERT_NE(iter, settings.end());
ASSERT_EQ(iter->second.value, "");
2020-08-24 08:37:10 +00:00
ASSERT_EQ(iter->second.description, "description\n");
2020-05-26 15:49:31 +00:00
}
2021-03-26 15:14:38 +00:00
TEST(Config, getDefinedOverriddenSettingNotSet) {
2020-05-26 15:49:31 +00:00
Config config;
std::string value;
std::map<std::string, Config::SettingInfo> settings;
Setting<std::string> foo{&config, value, "name-of-the-setting", "description"};
2021-03-26 15:14:38 +00:00
config.getSettings(settings, /* overriddenOnly = */ true);
2020-05-26 15:49:31 +00:00
const auto e = settings.find("name-of-the-setting");
ASSERT_EQ(e, settings.end());
}
TEST(Config, getDefinedSettingSet1) {
Config config;
std::string value;
std::map<std::string, Config::SettingInfo> settings;
Setting<std::string> setting{&config, value, "name-of-the-setting", "description"};
setting.override("value");
2020-05-26 15:49:31 +00:00
2021-03-26 15:14:38 +00:00
config.getSettings(settings, /* overriddenOnly = */ false);
2020-05-26 15:49:31 +00:00
const auto iter = settings.find("name-of-the-setting");
ASSERT_NE(iter, settings.end());
ASSERT_EQ(iter->second.value, "value");
2020-08-24 08:37:10 +00:00
ASSERT_EQ(iter->second.description, "description\n");
2020-05-26 15:49:31 +00:00
}
TEST(Config, getDefinedSettingSet2) {
Config config;
std::map<std::string, Config::SettingInfo> settings;
Setting<std::string> setting{&config, "", "name-of-the-setting", "description"};
ASSERT_TRUE(config.set("name-of-the-setting", "value"));
2021-03-26 15:14:38 +00:00
config.getSettings(settings, /* overriddenOnly = */ false);
2020-05-26 15:49:31 +00:00
const auto e = settings.find("name-of-the-setting");
ASSERT_NE(e, settings.end());
ASSERT_EQ(e->second.value, "value");
2020-08-24 08:37:10 +00:00
ASSERT_EQ(e->second.description, "description\n");
2020-05-26 15:49:31 +00:00
}
TEST(Config, addSetting) {
class TestSetting : public AbstractSetting {
public:
TestSetting() : AbstractSetting("test", "test", {}) {}
void set(const std::string & value, bool append, const ApplyConfigOptions & options) override {}
2020-10-30 11:00:43 +00:00
std::string to_string() const override { return {}; }
bool isAppendable() override { return false; }
2020-05-26 15:49:31 +00:00
};
Config config;
TestSetting setting;
ASSERT_FALSE(config.set("test", "value"));
config.addSetting(&setting);
ASSERT_TRUE(config.set("test", "value"));
ASSERT_FALSE(config.set("extra-test", "value"));
2020-05-26 15:49:31 +00:00
}
TEST(Config, withInitialValue) {
const StringMap initials = {
{ "key", "value" },
};
Config config(initials);
{
std::map<std::string, Config::SettingInfo> settings;
2021-03-26 15:14:38 +00:00
config.getSettings(settings, /* overriddenOnly = */ false);
2020-05-26 15:49:31 +00:00
ASSERT_EQ(settings.find("key"), settings.end());
}
Setting<std::string> setting{&config, "default-value", "key", "description"};
{
std::map<std::string, Config::SettingInfo> settings;
2021-03-26 15:14:38 +00:00
config.getSettings(settings, /* overriddenOnly = */ false);
2020-05-26 15:49:31 +00:00
ASSERT_EQ(settings["key"].value, "value");
}
}
2021-03-26 15:14:38 +00:00
TEST(Config, resetOverridden) {
2020-05-26 15:49:31 +00:00
Config config;
2021-03-26 15:14:38 +00:00
config.resetOverridden();
2020-05-26 15:49:31 +00:00
}
2021-03-26 15:14:38 +00:00
TEST(Config, resetOverriddenWithSetting) {
2020-05-26 15:49:31 +00:00
Config config;
Setting<std::string> setting{&config, "", "name-of-the-setting", "description"};
{
std::map<std::string, Config::SettingInfo> settings;
setting.setDefault("foo");
2020-05-26 15:49:31 +00:00
ASSERT_EQ(setting.get(), "foo");
2021-03-26 15:14:38 +00:00
config.getSettings(settings, /* overriddenOnly = */ true);
2020-05-26 15:49:31 +00:00
ASSERT_TRUE(settings.empty());
}
{
std::map<std::string, Config::SettingInfo> settings;
setting.override("bar");
2021-03-26 15:14:38 +00:00
ASSERT_TRUE(setting.overridden);
2020-05-26 15:49:31 +00:00
ASSERT_EQ(setting.get(), "bar");
2021-03-26 15:14:38 +00:00
config.getSettings(settings, /* overriddenOnly = */ true);
2020-05-26 15:49:31 +00:00
ASSERT_FALSE(settings.empty());
}
{
std::map<std::string, Config::SettingInfo> settings;
2021-03-26 15:14:38 +00:00
config.resetOverridden();
ASSERT_FALSE(setting.overridden);
config.getSettings(settings, /* overriddenOnly = */ true);
2020-05-26 15:49:31 +00:00
ASSERT_TRUE(settings.empty());
}
}
TEST(Config, toJSONOnEmptyConfig) {
2020-08-24 08:37:10 +00:00
ASSERT_EQ(Config().toJSON().dump(), "{}");
2020-05-26 15:49:31 +00:00
}
TEST(Config, toJSONOnNonEmptyConfig) {
using nlohmann::literals::operator "" _json;
2020-08-24 08:37:10 +00:00
Config config;
Setting<std::string> setting{
&config,
"",
"name-of-the-setting",
"description",
};
setting.override("value");
ASSERT_EQ(config.toJSON(),
R"#({
"name-of-the-setting": {
"aliases": [],
"defaultValue": "",
"description": "description\n",
"documentDefault": true,
"value": "value",
"experimentalFeature": null
}
})#"_json);
}
TEST(Config, toJSONOnNonEmptyConfigWithExperimentalSetting) {
using nlohmann::literals::operator "" _json;
Config config;
Setting<std::string> setting{
&config,
"",
"name-of-the-setting",
"description",
{},
true,
Xp::Flakes,
};
setting.override("value");
2020-05-26 15:49:31 +00:00
ASSERT_EQ(config.toJSON(),
R"#({
"name-of-the-setting": {
"aliases": [],
"defaultValue": "",
"description": "description\n",
"documentDefault": true,
"value": "value",
"experimentalFeature": "flakes"
}
})#"_json);
2020-05-26 15:49:31 +00:00
}
TEST(Config, setSettingAlias) {
Config config;
Setting<std::string> setting{&config, "", "some-int", "best number", { "another-int" }};
ASSERT_TRUE(config.set("some-int", "1"));
ASSERT_EQ(setting.get(), "1");
ASSERT_TRUE(config.set("another-int", "2"));
ASSERT_EQ(setting.get(), "2");
ASSERT_TRUE(config.set("some-int", "3"));
ASSERT_EQ(setting.get(), "3");
}
/* FIXME: The reapplyUnknownSettings method doesn't seem to do anything
* useful (these days). Whenever we add a new setting to Config the
* unknown settings are always considered. In which case is this function
* actually useful? Is there some way to register a Setting without calling
* addSetting? */
TEST(Config, DISABLED_reapplyUnknownSettings) {
Config config;
ASSERT_FALSE(config.set("name-of-the-setting", "unknownvalue"));
Setting<std::string> setting{&config, "default", "name-of-the-setting", "description"};
ASSERT_EQ(setting.get(), "default");
config.reapplyUnknownSettings();
ASSERT_EQ(setting.get(), "unknownvalue");
}
TEST(Config, applyConfigEmpty) {
Config config;
std::map<std::string, Config::SettingInfo> settings;
config.applyConfig("");
config.getSettings(settings);
ASSERT_TRUE(settings.empty());
}
TEST(Config, applyConfigEmptyWithComment) {
Config config;
std::map<std::string, Config::SettingInfo> settings;
config.applyConfig("# just a comment");
config.getSettings(settings);
ASSERT_TRUE(settings.empty());
}
TEST(Config, applyConfigAssignment) {
Config config;
std::map<std::string, Config::SettingInfo> settings;
Setting<std::string> setting{&config, "", "name-of-the-setting", "description"};
config.applyConfig(
"name-of-the-setting = value-from-file #useful comment\n"
"# name-of-the-setting = foo\n"
);
config.getSettings(settings);
ASSERT_FALSE(settings.empty());
ASSERT_EQ(settings["name-of-the-setting"].value, "value-from-file");
}
TEST(Config, applyConfigWithReassignedSetting) {
Config config;
std::map<std::string, Config::SettingInfo> settings;
Setting<std::string> setting{&config, "", "name-of-the-setting", "description"};
config.applyConfig(
"name-of-the-setting = first-value\n"
"name-of-the-setting = second-value\n"
);
config.getSettings(settings);
ASSERT_FALSE(settings.empty());
ASSERT_EQ(settings["name-of-the-setting"].value, "second-value");
}
TEST(Config, applyConfigFailsOnMissingIncludes) {
Config config;
std::map<std::string, Config::SettingInfo> settings;
Setting<std::string> setting{&config, "", "name-of-the-setting", "description"};
ASSERT_THROW(config.applyConfig(
"name-of-the-setting = value-from-file\n"
"# name-of-the-setting = foo\n"
"include /nix/store/does/not/exist.nix"
), Error);
}
TEST(Config, includeRelativePath) {
Config config;
Setting<std::string> setting{&config, "", "puppy", "description"};
config.applyConfig("include puppy.conf", {
.path = getUnitTestDataPath("nix.conf")
});
std::map<std::string, Config::SettingInfo> settings;
config.getSettings(settings);
ASSERT_FALSE(settings.empty());
ASSERT_EQ(settings["puppy"].value, "doggy");
}
TEST(Config, includeTildePath) {
Config config;
Setting<std::string> setting{&config, "", "puppy", "description"};
config.applyConfig("include ~/puppy.conf", {
.path = "/doesnt-exist",
.home = getUnitTestData()
});
std::map<std::string, Config::SettingInfo> settings;
config.getSettings(settings);
ASSERT_FALSE(settings.empty());
ASSERT_EQ(settings["puppy"].value, "doggy");
}
TEST(Config, applyConfigInvalidThrows) {
Config config;
ASSERT_THROW(config.applyConfig("value == key"), UsageError);
ASSERT_THROW(config.applyConfig("value "), UsageError);
}
2020-05-26 15:49:31 +00:00
}