forked from lix-project/lix
![John Ericson](/assets/img/avatar_default.png)
Today, with the tests inside a `tests` intermingled with the corresponding library's source code, we have a few problems: - We have to be careful that wildcards don't end up with tests being built as part of Nix proper, or test headers being installed as part of Nix proper. - Tests in libraries but not executables is not right: - It means each executable runs the previous unit tests again, because it needs the libraries. - It doesn't work right on Windows, which doesn't want you to load a DLL just for the side global variable . It could be made to work with the dlopen equivalent, but that's gross! This reorg solves these problems. There is a remaining problem which is that sibbling headers (like `hash.hh` the test header vs `hash.hh` the main `libnixutil` header) end up shadowing each other. This PR doesn't solve that. That is left as future work for a future PR. Co-authored-by: Valentin Gagarin <valentin.gagarin@tweag.io> (cherry picked from commit 91b6833686a6a6d9eac7f3f66393ec89ef1d3b57) (cherry picked from commit a61e42adb528b3d40ce43e07c79368d779a8b624)
296 lines
9.9 KiB
C++
296 lines
9.9 KiB
C++
#include "config.hh"
|
|
#include "args.hh"
|
|
|
|
#include <sstream>
|
|
#include <gtest/gtest.h>
|
|
#include <nlohmann/json.hpp>
|
|
|
|
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"};
|
|
|
|
config.getSettings(settings, /* overriddenOnly = */ false);
|
|
const auto iter = settings.find("name-of-the-setting");
|
|
ASSERT_NE(iter, settings.end());
|
|
ASSERT_EQ(iter->second.value, "");
|
|
ASSERT_EQ(iter->second.description, "description\n");
|
|
}
|
|
|
|
TEST(Config, getDefinedOverriddenSettingNotSet) {
|
|
Config config;
|
|
std::string value;
|
|
std::map<std::string, Config::SettingInfo> settings;
|
|
Setting<std::string> foo{&config, value, "name-of-the-setting", "description"};
|
|
|
|
config.getSettings(settings, /* overriddenOnly = */ true);
|
|
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.assign("value");
|
|
|
|
config.getSettings(settings, /* overriddenOnly = */ false);
|
|
const auto iter = settings.find("name-of-the-setting");
|
|
ASSERT_NE(iter, settings.end());
|
|
ASSERT_EQ(iter->second.value, "value");
|
|
ASSERT_EQ(iter->second.description, "description\n");
|
|
}
|
|
|
|
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"));
|
|
|
|
config.getSettings(settings, /* overriddenOnly = */ false);
|
|
const auto e = settings.find("name-of-the-setting");
|
|
ASSERT_NE(e, settings.end());
|
|
ASSERT_EQ(e->second.value, "value");
|
|
ASSERT_EQ(e->second.description, "description\n");
|
|
}
|
|
|
|
TEST(Config, addSetting) {
|
|
class TestSetting : public AbstractSetting {
|
|
public:
|
|
TestSetting() : AbstractSetting("test", "test", {}) {}
|
|
void set(const std::string & value, bool append) override {}
|
|
std::string to_string() const override { return {}; }
|
|
bool isAppendable() override { return false; }
|
|
};
|
|
|
|
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"));
|
|
}
|
|
|
|
TEST(Config, withInitialValue) {
|
|
const StringMap initials = {
|
|
{ "key", "value" },
|
|
};
|
|
Config config(initials);
|
|
|
|
{
|
|
std::map<std::string, Config::SettingInfo> settings;
|
|
config.getSettings(settings, /* overriddenOnly = */ false);
|
|
ASSERT_EQ(settings.find("key"), settings.end());
|
|
}
|
|
|
|
Setting<std::string> setting{&config, "default-value", "key", "description"};
|
|
|
|
{
|
|
std::map<std::string, Config::SettingInfo> settings;
|
|
config.getSettings(settings, /* overriddenOnly = */ false);
|
|
ASSERT_EQ(settings["key"].value, "value");
|
|
}
|
|
}
|
|
|
|
TEST(Config, resetOverridden) {
|
|
Config config;
|
|
config.resetOverridden();
|
|
}
|
|
|
|
TEST(Config, resetOverriddenWithSetting) {
|
|
Config config;
|
|
Setting<std::string> setting{&config, "", "name-of-the-setting", "description"};
|
|
|
|
{
|
|
std::map<std::string, Config::SettingInfo> settings;
|
|
|
|
setting.set("foo");
|
|
ASSERT_EQ(setting.get(), "foo");
|
|
config.getSettings(settings, /* overriddenOnly = */ true);
|
|
ASSERT_TRUE(settings.empty());
|
|
}
|
|
|
|
{
|
|
std::map<std::string, Config::SettingInfo> settings;
|
|
|
|
setting.override("bar");
|
|
ASSERT_TRUE(setting.overridden);
|
|
ASSERT_EQ(setting.get(), "bar");
|
|
config.getSettings(settings, /* overriddenOnly = */ true);
|
|
ASSERT_FALSE(settings.empty());
|
|
}
|
|
|
|
{
|
|
std::map<std::string, Config::SettingInfo> settings;
|
|
|
|
config.resetOverridden();
|
|
ASSERT_FALSE(setting.overridden);
|
|
config.getSettings(settings, /* overriddenOnly = */ true);
|
|
ASSERT_TRUE(settings.empty());
|
|
}
|
|
}
|
|
|
|
TEST(Config, toJSONOnEmptyConfig) {
|
|
ASSERT_EQ(Config().toJSON().dump(), "{}");
|
|
}
|
|
|
|
TEST(Config, toJSONOnNonEmptyConfig) {
|
|
using nlohmann::literals::operator "" _json;
|
|
Config config;
|
|
Setting<std::string> setting{
|
|
&config,
|
|
"",
|
|
"name-of-the-setting",
|
|
"description",
|
|
};
|
|
setting.assign("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.assign("value");
|
|
|
|
ASSERT_EQ(config.toJSON(),
|
|
R"#({
|
|
"name-of-the-setting": {
|
|
"aliases": [],
|
|
"defaultValue": "",
|
|
"description": "description\n",
|
|
"documentDefault": true,
|
|
"value": "value",
|
|
"experimentalFeature": "flakes"
|
|
}
|
|
})#"_json);
|
|
}
|
|
|
|
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, applyConfigInvalidThrows) {
|
|
Config config;
|
|
ASSERT_THROW(config.applyConfig("value == key"), UsageError);
|
|
ASSERT_THROW(config.applyConfig("value "), UsageError);
|
|
}
|
|
}
|