argparse/test/test_actions.cpp
Sean Robinson 2b05334a3c Run Argumnet::action functor for zero-parameter arguments
Previously, only arguments with one or more parameters would run actions.
But, at times it can be useful to run an action when an argument does not
expect any parameters.

Closes #104

Signed-off-by: Sean Robinson <sean.robinson@scottsdalecc.edu>
2021-10-27 09:02:33 -07:00

160 lines
4.1 KiB
C++

#include <doctest.hpp>
#include <argparse/argparse.hpp>
using doctest::test_suite;
TEST_CASE("Users can use default value inside actions" *
test_suite("actions")) {
argparse::ArgumentParser program("test");
program.add_argument("input")
.default_value("bar")
.action([=](const std::string& value) {
static const std::vector<std::string> choices = { "foo", "bar", "baz" };
if (std::find(choices.begin(), choices.end(), value) != choices.end()) {
return value;
}
return std::string{ "bar" };
});
program.parse_args({ "test", "fez" });
REQUIRE(program.get("input") == "bar");
}
TEST_CASE("Users can add actions that return nothing" * test_suite("actions")) {
argparse::ArgumentParser program("test");
bool pressed = false;
auto &arg = program.add_argument("button").action(
[&](const std::string &) mutable { pressed = true; });
REQUIRE_FALSE(pressed);
SUBCASE("action performed") {
program.parse_args({"test", "ignored"});
REQUIRE(pressed);
}
SUBCASE("action performed and nothing overrides the default value") {
arg.default_value(42);
program.parse_args({"test", "ignored"});
REQUIRE(pressed);
REQUIRE(program.get<int>("button") == 42);
}
}
class Image {
public:
int w = 0, h = 0;
void resize(std::string_view geometry) {
std::stringstream s;
s << geometry;
s >> w;
s.ignore();
s >> h;
}
static auto create(int w, int h, std::string_view format) -> Image {
auto factor = [=] {
if (format == "720p")
return std::min(1280. / w, 720. / h);
else if (format == "1080p")
return std::min(1920. / w, 1080. / h);
else
return 1.;
}();
return {static_cast<int>(w * factor), static_cast<int>(h * factor)};
}
};
TEST_CASE("Users can bind arguments to actions" * test_suite("actions")) {
argparse::ArgumentParser program("test");
GIVEN("an default initialized object bounded by reference") {
Image img;
program.add_argument("--size").action(&Image::resize, std::ref(img));
WHEN("provided no command-line arguments") {
program.parse_args({"test"});
THEN("the object is not updated") {
REQUIRE(img.w == 0);
REQUIRE(img.h == 0);
}
}
WHEN("provided command-line arguments") {
program.parse_args({"test", "--size", "320x98"});
THEN("the object is updated accordingly") {
REQUIRE(img.w == 320);
REQUIRE(img.h == 98);
}
}
}
GIVEN("a command-line option waiting for the last argument in its action") {
program.add_argument("format").action(Image::create, 400, 300);
WHEN("provided such an argument") {
program.parse_args({"test", "720p"});
THEN("the option object is created as if providing all arguments") {
auto img = program.get<Image>("format");
REQUIRE(img.w == 960);
REQUIRE(img.h == 720);
}
}
WHEN("provided a different argument") {
program.parse_args({"test", "1080p"});
THEN("a different option object is created") {
auto img = program.get<Image>("format");
REQUIRE(img.w == 1440);
REQUIRE(img.h == 1080);
}
}
}
}
TEST_CASE("Users can use actions on remaining arguments" *
test_suite("actions")) {
argparse::ArgumentParser program("sum");
int result = 0;
program.add_argument("all").remaining().action(
[](int &sum, std::string const &value) { sum += std::stoi(value); },
std::ref(result));
program.parse_args({"sum", "42", "100", "-3", "-20"});
REQUIRE(result == 119);
}
TEST_CASE("Users can run actions on parameterless optional arguments" *
test_suite("actions")) {
argparse::ArgumentParser program("test");
GIVEN("a flag argument with a counting action") {
int count = 0;
program.add_argument("-V", "--verbose")
.action([&](const auto &) { ++count; })
.append()
.default_value(false)
.implicit_value(true)
.nargs(0);
WHEN("the flag is repeated") {
program.parse_args({"test", "-VVVV"});
THEN("the count increments once per use") {
REQUIRE(program.get<bool>("-V"));
REQUIRE(count == 4);
}
}
}
}