Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vars::unset: API method for removing variable #1362

Merged
merged 2 commits into from
Apr 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions include/libdnf5/conf/vars.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,14 @@ struct Vars {
/// @throw ReadOnlyVariableError if the variable is read-only
void set(const std::string & name, const std::string & value, Priority prio = Priority::RUNTIME);

/// @brief Unset particular variable
///
/// @param name Name of the variable
/// @param prio Source/Priority of the request
/// @throw ReadOnlyVariableError if the variable is read-only
/// @return false if the variable exists after the function returns (insufficient request priority)
bool unset(const std::string & name, Priority prio = Priority::RUNTIME);

/// @brief Checks whether a variable is read-only
///
/// @param name Name of the variable
Expand Down
16 changes: 16 additions & 0 deletions libdnf5/conf/vars.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,22 @@ void Vars::set(const std::string & name, const std::string & value, Priority pri
set_unsafe(name, value, prio);
}

bool Vars::unset(const std::string & name, Priority prio) {
auto it = variables.find(name);
if (it == variables.end()) {
return true;
}
if (is_read_only(name)) {
throw ReadOnlyVariableError(M_("Variable \"{}\" is read-only"), name);
}
// Do nothing if the var is already set with a higher priority
if (prio < it->second.priority) {
return false;
}
variables.erase(it);
return true;
}

void Vars::set_lazy(
const std::string & name,
const std::function<const std::unique_ptr<const std::string>()> & get_value,
Expand Down
187 changes: 180 additions & 7 deletions test/libdnf5/conf/test_vars.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,28 +23,31 @@ along with libdnf. If not, see <https://www.gnu.org/licenses/>.

CPPUNIT_TEST_SUITE_REGISTRATION(VarsTest);

using namespace std::literals::string_literals;

// TODO possibly test the automatically detected vars (they depend on the host)

void VarsTest::setUp() {
TestCaseFixture::setUp();
base = get_preconfigured_base();
}


void VarsTest::test_vars() {
base->get_config().get_varsdir_option().set(
std::vector<std::string>{PROJECT_SOURCE_DIR "/test/libdnf5/conf/data/vars"});
// Load all variables.
base->setup();

CPPUNIT_ASSERT_EQUAL(std::string("foovalue123-bar"), base->get_vars()->substitute("foo$var1-bar"));
CPPUNIT_ASSERT_EQUAL("foovalue123-bar"s, base->get_vars()->substitute("foo$var1-bar"));
CPPUNIT_ASSERT_EQUAL("$$$value123456-$nn-${nnn}"s, base->get_vars()->substitute("$$$${var1}$var2-$nn-${nnn}"));
CPPUNIT_ASSERT_EQUAL(
std::string("$$$value123456-$nn-${nnn}"), base->get_vars()->substitute("$$$${var1}$var2-$nn-${nnn}"));
CPPUNIT_ASSERT_EQUAL(
std::string("alternate-default-${nn:+n${nn:-${nnn:}"),
"alternate-default-${nn:+n${nn:-${nnn:}"s,
base->get_vars()->substitute("${var1:+alternate}-${unset:-default}-${nn:+n${nn:-${nnn:}"));
CPPUNIT_ASSERT_EQUAL(std::string("456"), base->get_vars()->substitute("${unset:-${var1:+${var2:+$var2}}}"));
CPPUNIT_ASSERT_EQUAL("456"s, base->get_vars()->substitute("${unset:-${var1:+${var2:+$var2}}}"));
}


void VarsTest::test_vars_multiple_dirs() {
base->get_config().get_varsdir_option().set(std::vector<std::string>{
PROJECT_SOURCE_DIR "/test/libdnf5/conf/data/vars",
Expand All @@ -53,9 +56,10 @@ void VarsTest::test_vars_multiple_dirs() {
// Load all variables.
base->setup();

CPPUNIT_ASSERT_EQUAL(std::string("av333bthe answer is here"), base->get_vars()->substitute("a${var1}b${var42}"));
CPPUNIT_ASSERT_EQUAL("av333bthe answer is here"s, base->get_vars()->substitute("a${var1}b${var42}"));
}


void VarsTest::test_vars_env() {
base->get_config().get_varsdir_option().set(
std::vector<std::string>{PROJECT_SOURCE_DIR "/test/libdnf5/conf/data/vars"});
Expand All @@ -73,6 +77,175 @@ void VarsTest::test_vars_env() {
// The variables var1 and var2 are defined in the files.
// However, var1 was also an environment variable. The environment has a higher priority.
CPPUNIT_ASSERT_EQUAL(
std::string("foo0-foo1-foo9-testvar1-testvar2-456"),
"foo0-foo1-foo9-testvar1-testvar2-456"s,
base->get_vars()->substitute("${DNF0}-${DNF1}-${DNF9}-${var1}-${var41}-${var2}"));
}


void VarsTest::test_vars_api() {
base->setup();
auto vars = base->get_vars();

CPPUNIT_ASSERT(!vars->contains("test_var1"));

vars->set("test_var1", "123", libdnf5::Vars::Priority::PLUGIN);
CPPUNIT_ASSERT(vars->contains("test_var1"));

{
auto & [value, prioriry] = vars->get("test_var1");
CPPUNIT_ASSERT_EQUAL_MESSAGE("value returned by vars->get()", "123"s, value);
CPPUNIT_ASSERT_EQUAL_MESSAGE("priority returned by vars->get()", libdnf5::Vars::Priority::PLUGIN, prioriry);
}

CPPUNIT_ASSERT_EQUAL_MESSAGE("value returned by vars->get_value()", "123"s, vars->get_value("test_var1"));

CPPUNIT_ASSERT(vars->unset("test_var1"));
CPPUNIT_ASSERT_MESSAGE("after vars->unset(\"test_var1\")", !vars->contains("test_var1"));
}


void VarsTest::test_vars_api_set_prio() {
base->setup();
auto vars = base->get_vars();

CPPUNIT_ASSERT(!vars->contains("test_var1"));

// set a new variable
vars->set("test_var1", "123", libdnf5::Vars::Priority::PLUGIN);
{
auto & [value, prioriry] = vars->get("test_var1");
CPPUNIT_ASSERT_EQUAL_MESSAGE("value returned by vars->get()", "123"s, value);
CPPUNIT_ASSERT_EQUAL_MESSAGE("priority returned by vars->get()", libdnf5::Vars::Priority::PLUGIN, prioriry);
}

// change the value using the same priority
vars->set("test_var1", "345", libdnf5::Vars::Priority::PLUGIN);
{
auto & [value, prioriry] = vars->get("test_var1");
CPPUNIT_ASSERT_EQUAL_MESSAGE("value returned by vars->get()", "345"s, value);
CPPUNIT_ASSERT_EQUAL_MESSAGE("priority returned by vars->get()", libdnf5::Vars::Priority::PLUGIN, prioriry);
}

// change the value using a higher priority
vars->set("test_var1", "678", libdnf5::Vars::Priority::COMMANDLINE);
{
auto & [value, prioriry] = vars->get("test_var1");
CPPUNIT_ASSERT_EQUAL_MESSAGE("value returned by vars->get()", "678"s, value);
CPPUNIT_ASSERT_EQUAL_MESSAGE(
"priority returned by vars->get()", libdnf5::Vars::Priority::COMMANDLINE, prioriry);
}

// changing the value using a lower priority is ignored
vars->set("test_var1", "ignored_value", libdnf5::Vars::Priority::PLUGIN);
{
auto & [value, prioriry] = vars->get("test_var1");
CPPUNIT_ASSERT_EQUAL_MESSAGE("value returned by vars->get()", "678"s, value);
CPPUNIT_ASSERT_EQUAL_MESSAGE(
"priority returned by vars->get()", libdnf5::Vars::Priority::COMMANDLINE, prioriry);
}

// change the value using default priority - default is RUNTIME, the highest priority
vars->set("test_var1", "999");
{
auto & [value, prioriry] = vars->get("test_var1");
CPPUNIT_ASSERT_EQUAL_MESSAGE("value returned by vars->get()", "999"s, value);
CPPUNIT_ASSERT_EQUAL_MESSAGE("priority returned by vars->get()", libdnf5::Vars::Priority::RUNTIME, prioriry);
}
}


void VarsTest::test_vars_api_unset_prio() {
base->setup();
auto vars = base->get_vars();

// set a new variable
vars->set("test_var1", "123", libdnf5::Vars::Priority::COMMANDLINE);
{
auto & [value, prioriry] = vars->get("test_var1");
CPPUNIT_ASSERT_EQUAL_MESSAGE("value returned by vars->get()", "123"s, value);
CPPUNIT_ASSERT_EQUAL_MESSAGE(
"priority returned by vars->get()", libdnf5::Vars::Priority::COMMANDLINE, prioriry);
}

// removing a variable using a lower priority is ignored
CPPUNIT_ASSERT(!vars->unset("test_var1", libdnf5::Vars::Priority::PLUGIN));
CPPUNIT_ASSERT_MESSAGE(
"after vars->unset(\"test_var1\", libdnf5::Vars::Priority::PLUGIN)", vars->contains("test_var1"));
{
auto & [value, prioriry] = vars->get("test_var1");
CPPUNIT_ASSERT_EQUAL_MESSAGE("value returned by vars->get()", "123"s, value);
CPPUNIT_ASSERT_EQUAL_MESSAGE(
"priority returned by vars->get()", libdnf5::Vars::Priority::COMMANDLINE, prioriry);
}

// removing a variable using the same priority
CPPUNIT_ASSERT(vars->unset("test_var1", libdnf5::Vars::Priority::COMMANDLINE));
CPPUNIT_ASSERT_MESSAGE(
"after vars->unset(\"test_var1\", libdnf5::Vars::Priority::COMMANDLINE)", !vars->contains("test_var1"));


// set a new variable
vars->set("test_var2", "345", libdnf5::Vars::Priority::PLUGIN);
CPPUNIT_ASSERT(vars->contains("test_var2"));

// removing a variable using a higher priority
CPPUNIT_ASSERT(vars->unset("test_var2", libdnf5::Vars::Priority::COMMANDLINE));
CPPUNIT_ASSERT_MESSAGE(
"after vars->unset(\"test_var2\", libdnf5::Vars::Priority::COMMANDLINE)", !vars->contains("test_var2"));


// set a new variable
vars->set("test_var3", "678", libdnf5::Vars::Priority::PLUGIN);
CPPUNIT_ASSERT(vars->contains("test_var3"));

// removing a variable using default priority - default is RUNTIME, the highest priority
CPPUNIT_ASSERT(vars->unset("test_var3"));
CPPUNIT_ASSERT_MESSAGE("after vars->unset(\"test_var3\")", !vars->contains("test_var3"));
}


void VarsTest::test_vars_api_releasever() {
base->setup();
auto vars = base->get_vars();

// set the "releasever" variable
vars->set("releasever", "40.12", libdnf5::Vars::Priority::PLUGIN);

// check the value the of "releasever" variable
{
auto & [value, prioriry] = vars->get("releasever");
CPPUNIT_ASSERT_EQUAL_MESSAGE("value returned by vars->get()", "40.12"s, value);
CPPUNIT_ASSERT_EQUAL_MESSAGE("priority returned by vars->get()", libdnf5::Vars::Priority::PLUGIN, prioriry);
}

// check the value the of auto-created read-only variables
{
auto & [value, prioriry] = vars->get("releasever_major");
CPPUNIT_ASSERT_EQUAL_MESSAGE("value returned by vars->get()", "40"s, value);
CPPUNIT_ASSERT_EQUAL_MESSAGE("priority returned by vars->get()", libdnf5::Vars::Priority::PLUGIN, prioriry);
}
{
auto & [value, prioriry] = vars->get("releasever_minor");
CPPUNIT_ASSERT_EQUAL_MESSAGE("value returned by vars->get()", "12"s, value);
CPPUNIT_ASSERT_EQUAL_MESSAGE("priority returned by vars->get()", libdnf5::Vars::Priority::PLUGIN, prioriry);
}

// the "releasever" variable is read-write
CPPUNIT_ASSERT(!vars->is_read_only("releasever"));

// auto-created variables "releasever_major" and "releasever_minor" are read-only
CPPUNIT_ASSERT(vars->is_read_only("releasever_major"));
CPPUNIT_ASSERT(vars->is_read_only("releasever_minor"));

// setting the value of a read-only variable throws exception
CPPUNIT_ASSERT_THROW(
vars->set("releasever_major", "40", libdnf5::Vars::Priority::PLUGIN), libdnf5::ReadOnlyVariableError);

// removing read-only variable throws exception
CPPUNIT_ASSERT_THROW(
vars->unset("releasever_major", libdnf5::Vars::Priority::PLUGIN), libdnf5::ReadOnlyVariableError);

// because the variable "releaver" is read-write, it can be removed
CPPUNIT_ASSERT(vars->unset("releasever", libdnf5::Vars::Priority::PLUGIN));
CPPUNIT_ASSERT_MESSAGE("after vars->unset(\"test_var3\")", !vars->contains("releasever"));
}
8 changes: 8 additions & 0 deletions test/libdnf5/conf/test_vars.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ class VarsTest : public TestCaseFixture {
CPPUNIT_TEST(test_vars);
CPPUNIT_TEST(test_vars_multiple_dirs);
CPPUNIT_TEST(test_vars_env);
CPPUNIT_TEST(test_vars_api);
CPPUNIT_TEST(test_vars_api_set_prio);
CPPUNIT_TEST(test_vars_api_unset_prio);
CPPUNIT_TEST(test_vars_api_releasever);
CPPUNIT_TEST_SUITE_END();

public:
Expand All @@ -40,6 +44,10 @@ class VarsTest : public TestCaseFixture {
void test_vars();
void test_vars_multiple_dirs();
void test_vars_env();
void test_vars_api();
void test_vars_api_set_prio();
void test_vars_api_unset_prio();
void test_vars_api_releasever();

std::unique_ptr<libdnf5::Base> base;
};
Expand Down
Loading