2020-05-26 15:49:31 +00:00
|
|
|
#include "config.hh"
|
|
|
|
#include "args.hh"
|
2024-08-26 16:28:14 +00:00
|
|
|
#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"};
|
|
|
|
|
2024-09-02 18:09:35 +00:00
|
|
|
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", {}) {}
|
2024-08-25 18:58:10 +00:00
|
|
|
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 {}; }
|
2023-04-10 02:39:04 +00:00
|
|
|
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"));
|
2023-04-10 02:39:04 +00:00
|
|
|
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;
|
|
|
|
|
2024-09-02 18:09:35 +00:00
|
|
|
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) {
|
2023-04-10 16:02:35 +00:00
|
|
|
using nlohmann::literals::operator "" _json;
|
2020-08-24 08:37:10 +00:00
|
|
|
Config config;
|
2023-04-10 16:02:35 +00:00
|
|
|
Setting<std::string> setting{
|
|
|
|
&config,
|
|
|
|
"",
|
|
|
|
"name-of-the-setting",
|
|
|
|
"description",
|
|
|
|
};
|
2024-09-02 18:09:35 +00:00
|
|
|
setting.override("value");
|
2023-04-10 16:02:35 +00:00
|
|
|
|
|
|
|
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,
|
|
|
|
};
|
2024-09-02 18:09:35 +00:00
|
|
|
setting.override("value");
|
2020-05-26 15:49:31 +00:00
|
|
|
|
2023-04-10 16:02:35 +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");
|
|
|
|
}
|
2020-05-27 12:41:01 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2024-08-26 16:28:14 +00:00
|
|
|
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");
|
|
|
|
}
|
|
|
|
|
2020-05-27 12:41:01 +00:00
|
|
|
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
|
|
|
}
|