Added table of contents to README and clang formatted code

This commit is contained in:
Pranav Srinivas Kumar 2022-09-20 20:27:24 -07:00
parent 6987a83ad5
commit 6c7da857b6
21 changed files with 405 additions and 426 deletions

View File

@ -16,6 +16,35 @@
* Requires C++17
* MIT License
## Table of Contents
* [Quick Start](#quick-start)
* [Positional Arguments](#positional-arguments)
* [Optional Arguments](#optional-arguments)
* [Requiring optional arguments](#requiring-optional-arguments)
* [Accessing optional arguments without default values](#accessing-optional-arguments-without-default-values)
* [Deciding if the value was given by the user](#deciding-if-the-value-was-given-by-the-user)
* [Joining values of repeated optional arguments](#joining-values-of-repeated-optional-arguments)
* [Repeating an argument to increase a value](#repeating-an-argument-to-increase-a-value)
* [Negative Numbers](#negative-numbers)
* [Combining Positional and Optional Arguments](#combining-positional-and-optional-arguments)
* [Printing Help](#printing-help)
* [Adding a description and an epilog to help](#adding-a-description-and-an-epilog-to-help)
* [List of Arguments](#list-of-arguments)
* [Compound Arguments](#compound-arguments)
* [Converting to Numeric Types](#converting-to-numeric-types)
* [Default Arguments](#default-arguments)
* [Gathering Remaining Arguments](#gathering-remaining-arguments)
* [Parent Parsers](#parent-parsers)
* [Further Examples](#further-examples)
* [Construct a JSON object from a filename argument](#construct-a-json-object-from-a-filename-argument)
* [Positional Arguments with Compound Toggle Arguments](#positional-arguments-with-compound-toggle-arguments)
* [Restricting the set of values for an argument](#restricting-the-set-of-values-for-an-argument)
* [CMake Integration](#cmake-integration)
* [Supported Toolchains](#supported-toolchains)
* [Contributing](#contributing)
* [License](#license)
## Quick Start
Simply include argparse.hpp and you're good to go.

1
clang_format.bash Executable file
View File

@ -0,0 +1 @@
clang-format -i include/argparse/*.hpp test/*.cpp

View File

@ -149,8 +149,9 @@ constexpr bool standard_integer =
standard_signed_integer<T> || standard_unsigned_integer<T>;
template <class F, class Tuple, class Extra, std::size_t... I>
constexpr decltype(auto) apply_plus_one_impl(F &&f, Tuple &&t, Extra &&x,
std::index_sequence<I...> /*unused*/) {
constexpr decltype(auto)
apply_plus_one_impl(F &&f, Tuple &&t, Extra &&x,
std::index_sequence<I...> /*unused*/) {
return std::invoke(std::forward<F>(f), std::get<I>(std::forward<Tuple>(t))...,
std::forward<Extra>(x));
}
@ -328,11 +329,7 @@ template <class T> struct parse_number<T, chars_format::fixed> {
} // namespace details
enum class nargs_pattern {
optional,
any,
at_least_one
};
enum class nargs_pattern { optional, any, at_least_one };
enum class default_arguments : unsigned int {
none = 0,
@ -395,7 +392,7 @@ public:
}
template <class F, class... Args>
auto action(F &&callable, Args &&...bound_args)
auto action(F &&callable, Args &&... bound_args)
-> std::enable_if_t<std::is_invocable_v<F, Args..., std::string const>,
Argument &> {
using action_type = std::conditional_t<
@ -429,7 +426,8 @@ public:
if constexpr (is_one_of(Shape, 'd') && details::standard_integer<T>) {
action(details::parse_number<T, details::radix_10>());
} else if constexpr (is_one_of(Shape, 'i') && details::standard_integer<T>) {
} else if constexpr (is_one_of(Shape, 'i') &&
details::standard_integer<T>) {
action(details::parse_number<T>());
} else if constexpr (is_one_of(Shape, 'u') &&
details::standard_unsigned_integer<T>) {
@ -506,7 +504,8 @@ public:
std::visit([](const auto &f) { f({}); }, m_action);
return start;
}
if ((dist = static_cast<std::size_t>(std::distance(start, end))) >= num_args_min) {
if ((dist = static_cast<std::size_t>(std::distance(start, end))) >=
num_args_min) {
if (num_args_max < dist) {
end = std::next(start, num_args_max);
}
@ -558,7 +557,8 @@ public:
throw_required_arg_no_value_provided_error();
}
} else {
if (!m_num_args_range.contains(m_values.size()) && !m_default_value.has_value()) {
if (!m_num_args_range.contains(m_values.size()) &&
!m_default_value.has_value()) {
throw_nargs_range_validation_error();
}
}
@ -606,15 +606,13 @@ public:
return get<T>() == rhs;
} else {
auto lhs = get<T>();
return std::equal(std::begin(lhs), std::end(lhs), std::begin(rhs),
std::end(rhs), [](const auto &lhs, const auto &rhs) {
return lhs == rhs;
});
return std::equal(
std::begin(lhs), std::end(lhs), std::begin(rhs), std::end(rhs),
[](const auto &lhs, const auto &rhs) { return lhs == rhs; });
}
}
private:
class NArgsRange {
std::size_t m_min;
std::size_t m_max;
@ -631,21 +629,15 @@ private:
return value >= m_min && value <= m_max;
}
bool is_exact() const {
return m_min == m_max;
}
bool is_exact() const { return m_min == m_max; }
bool is_right_bounded() const {
return m_max < std::numeric_limits<std::size_t>::max();
}
std::size_t get_min() const {
return m_min;
}
std::size_t get_min() const { return m_min; }
std::size_t get_max() const {
return m_max;
}
std::size_t get_max() const { return m_max; }
};
void throw_nargs_range_validation_error() const {
@ -656,7 +648,8 @@ private:
if (m_num_args_range.is_exact()) {
stream << m_num_args_range.get_min();
} else if (m_num_args_range.is_right_bounded()) {
stream << m_num_args_range.get_min() << " to " << m_num_args_range.get_max();
stream << m_num_args_range.get_min() << " to "
<< m_num_args_range.get_max();
} else {
stream << m_num_args_range.get_min() << " or more";
}
@ -855,7 +848,9 @@ private:
* Get argument value given a type
* @throws std::logic_error in case of incompatible types
*/
template <typename T> auto get() const -> std::conditional_t<details::IsContainer<T>, T, const T&> {
template <typename T>
auto get() const
-> std::conditional_t<details::IsContainer<T>, T, const T &> {
if (!m_values.empty()) {
if constexpr (details::IsContainer<T>) {
return any_cast_container<T>(m_values);
@ -916,7 +911,7 @@ private:
std::in_place_type<valued_action>,
[](const std::string &value) { return value; }};
std::vector<std::any> m_values;
NArgsRange m_num_args_range {1, 1};
NArgsRange m_num_args_range{1, 1};
bool m_accepts_optional_like_value = false;
bool m_is_optional : true;
bool m_is_required : true;
@ -932,7 +927,7 @@ public:
: m_program_name(std::move(program_name)), m_version(std::move(version)) {
if ((add_args & default_arguments::help) == default_arguments::help) {
add_argument("-h", "--help")
.action([&](const auto &/*unused*/) {
.action([&](const auto & /*unused*/) {
std::cout << help().str();
std::exit(0);
})
@ -943,7 +938,7 @@ public:
}
if ((add_args & default_arguments::version) == default_arguments::version) {
add_argument("-v", "--version")
.action([&](const auto &/*unused*/) {
.action([&](const auto & /*unused*/) {
std::cout << m_version << std::endl;
std::exit(0);
})
@ -958,10 +953,8 @@ public:
ArgumentParser &operator=(ArgumentParser &&) = default;
ArgumentParser(const ArgumentParser &other)
: m_program_name(other.m_program_name),
m_version(other.m_version),
m_description(other.m_description),
m_epilog(other.m_epilog),
: m_program_name(other.m_program_name), m_version(other.m_version),
m_description(other.m_description), m_epilog(other.m_epilog),
m_is_parsed(other.m_is_parsed),
m_positional_arguments(other.m_positional_arguments),
m_optional_arguments(other.m_optional_arguments) {
@ -1002,7 +995,7 @@ public:
// Parameter packed add_parents method
// Accepts a variadic number of ArgumentParser objects
template <typename... Targs>
ArgumentParser &add_parents(const Targs &...f_args) {
ArgumentParser &add_parents(const Targs &... f_args) {
for (const ArgumentParser &parent_parser : {std::ref(f_args)...}) {
for (const auto &argument : parent_parser.m_positional_arguments) {
auto it = m_positional_arguments.insert(
@ -1036,7 +1029,7 @@ public:
void parse_args(const std::vector<std::string> &arguments) {
parse_args_internal(arguments);
// Check if all arguments are parsed
for ([[maybe_unused]] const auto& [unused, argument] : m_argument_map) {
for ([[maybe_unused]] const auto &[unused, argument] : m_argument_map) {
argument->validate();
}
}
@ -1056,8 +1049,9 @@ public:
* @throws std::logic_error if the option has no value
* @throws std::bad_any_cast if the option is not of type T
*/
template <typename T = std::string> auto get(std::string_view arg_name) const
-> std::conditional_t<details::IsContainer<T>, T, const T&> {
template <typename T = std::string>
auto get(std::string_view arg_name) const
-> std::conditional_t<details::IsContainer<T>, T, const T &> {
if (!m_is_parsed) {
throw std::logic_error("Nothing parsed, no arguments are available.");
}
@ -1148,17 +1142,16 @@ public:
}
if (!parser.m_subparser_map.empty()) {
stream << (parser.m_positional_arguments.empty() ?
(parser.m_optional_arguments.empty() ? "" : "\n") :
"\n")
stream << (parser.m_positional_arguments.empty()
? (parser.m_optional_arguments.empty() ? "" : "\n")
: "\n")
<< "Subcommands:\n";
stream << "{";
std::size_t i = 0;
std::size_t i = 0;
for (const auto &[argument, unused] : parser.m_subparser_map) {
if (i == 0) {
stream << argument;
}
else {
} else {
stream << ", " << argument;
}
++i;
@ -1190,7 +1183,8 @@ public:
return out.str();
}
void add_subparser(ArgumentParser& parser) {
void add_subparser(ArgumentParser &parser) {
auto it = m_subparsers.emplace(std::cend(m_subparsers), parser);
m_subparser_map.insert_or_assign(parser.m_program_name, it);
}
@ -1217,11 +1211,13 @@ private:
if (subparser_it != m_subparser_map.end()) {
// build list of remaining args
const auto unprocessed_arguments = std::vector<std::string>(it, end);
const auto unprocessed_arguments =
std::vector<std::string>(it, end);
// invoke subparser
m_is_parsed = true;
return subparser_it->second->get().parse_args(unprocessed_arguments);
return subparser_it->second->get().parse_args(
unprocessed_arguments);
}
throw std::runtime_error(
@ -1263,17 +1259,18 @@ private:
return 0;
}
std::size_t max_size = 0;
for ([[maybe_unused]] const auto& [unused, argument] : m_argument_map) {
for ([[maybe_unused]] const auto &[unused, argument] : m_argument_map) {
max_size = std::max(max_size, argument->get_arguments_length());
}
for ([[maybe_unused]] const auto& [command, unused] : m_subparser_map) {
for ([[maybe_unused]] const auto &[command, unused] : m_subparser_map) {
max_size = std::max(max_size, command.size());
}
return max_size;
}
using argument_it = std::list<Argument>::iterator;
using argument_parser_it = std::list<std::reference_wrapper<ArgumentParser>>::iterator;
using argument_parser_it =
std::list<std::reference_wrapper<ArgumentParser>>::iterator;
void index_argument(argument_it it) {
for (const auto &name : std::as_const(it->m_names)) {

View File

@ -1,22 +1,21 @@
#include <doctest.hpp>
#include <argparse/argparse.hpp>
#include <doctest.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.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" });
program.parse_args({"test", "fez"});
REQUIRE(program.get("input") == "bar");
}
@ -126,9 +125,11 @@ TEST_CASE("Users can use actions on nargs=ANY arguments" *
argparse::ArgumentParser program("sum");
int result = 0;
program.add_argument("all").nargs(argparse::nargs_pattern::any).action(
[](int &sum, std::string const &value) { sum += std::stoi(value); },
std::ref(result));
program.add_argument("all")
.nargs(argparse::nargs_pattern::any)
.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);
@ -154,11 +155,11 @@ TEST_CASE("Users can run actions on parameterless optional arguments" *
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);
.action([&](const auto &) { ++count; })
.append()
.default_value(false)
.implicit_value(true)
.nargs(0);
WHEN("the flag is repeated") {
program.parse_args({"test", "-VVVV"});

View File

@ -1,46 +1,40 @@
#include <doctest.hpp>
#include <argparse/argparse.hpp>
#include <doctest.hpp>
using doctest::test_suite;
TEST_CASE("Simplest .append" * test_suite("append")) {
argparse::ArgumentParser program("test");
program.add_argument("--dir")
.append();
program.parse_args({ "test", "--dir", "./Docs" });
std::string result { program.get("--dir") };
program.add_argument("--dir").append();
program.parse_args({"test", "--dir", "./Docs"});
std::string result{program.get("--dir")};
REQUIRE(result == "./Docs");
}
TEST_CASE("Two parameter .append" * test_suite("append")) {
argparse::ArgumentParser program("test");
program.add_argument("--dir")
.append();
program.parse_args({ "test", "--dir", "./Docs", "--dir", "./Src" });
auto result { program.get<std::vector<std::string>>("--dir") };
program.add_argument("--dir").append();
program.parse_args({"test", "--dir", "./Docs", "--dir", "./Src"});
auto result{program.get<std::vector<std::string>>("--dir")};
REQUIRE(result.at(0) == "./Docs");
REQUIRE(result.at(1) == "./Src");
}
TEST_CASE("Two int .append" * test_suite("append")) {
argparse::ArgumentParser program("test");
program.add_argument("--factor")
.append()
.scan<'i', int>();
program.parse_args({ "test", "--factor", "2", "--factor", "5" });
auto result { program.get<std::vector<int>>("--factor") };
program.add_argument("--factor").append().scan<'i', int>();
program.parse_args({"test", "--factor", "2", "--factor", "5"});
auto result{program.get<std::vector<int>>("--factor")};
REQUIRE(result.at(0) == 2);
REQUIRE(result.at(1) == 5);
}
TEST_CASE("Default value with .append" * test_suite("append")) {
std::vector<std::string> expected { "./Src", "./Imgs" };
std::vector<std::string> expected{"./Src", "./Imgs"};
argparse::ArgumentParser program("test");
program.add_argument("--dir")
.default_value(expected)
.append();
program.parse_args({ "test" });
auto result { program.get<std::vector<std::string>>("--dir") };
program.add_argument("--dir").default_value(expected).append();
program.parse_args({"test"});
auto result{program.get<std::vector<std::string>>("--dir")};
REQUIRE(result == expected);
}

View File

@ -1,5 +1,5 @@
#include <doctest.hpp>
#include <argparse/argparse.hpp>
#include <doctest.hpp>
#include <test_utility.hpp>
using doctest::test_suite;
@ -7,19 +7,13 @@ using doctest::test_suite;
TEST_CASE("Parse compound toggle arguments with implicit values" *
test_suite("compound_arguments")) {
argparse::ArgumentParser program("test");
program.add_argument("-a")
.default_value(false)
.implicit_value(true);
program.add_argument("-a").default_value(false).implicit_value(true);
program.add_argument("-u")
.default_value(false)
.implicit_value(true);
program.add_argument("-u").default_value(false).implicit_value(true);
program.add_argument("-x")
.default_value(false)
.implicit_value(true);
program.add_argument("-x").default_value(false).implicit_value(true);
program.parse_args({ "./test.exe", "-aux" });
program.parse_args({"./test.exe", "-aux"});
REQUIRE(program.get<bool>("-a") == true);
REQUIRE(program.get<bool>("-u") == true);
REQUIRE(program.get<bool>("-x") == true);
@ -28,23 +22,16 @@ TEST_CASE("Parse compound toggle arguments with implicit values" *
TEST_CASE("Parse compound toggle arguments with implicit values and nargs" *
test_suite("compound_arguments")) {
argparse::ArgumentParser program("test");
program.add_argument("-a")
.default_value(false)
.implicit_value(true);
program.add_argument("-a").default_value(false).implicit_value(true);
program.add_argument("-b")
.default_value(false)
.implicit_value(true);
program.add_argument("-b").default_value(false).implicit_value(true);
program.add_argument("-c")
.nargs(2)
.scan<'g', float>();
program.add_argument("-c").nargs(2).scan<'g', float>();
program.add_argument("--input_files")
.nargs(3);
program.add_argument("--input_files").nargs(3);
program.parse_args({ "./test.exe", "-abc", "3.14", "2.718", "--input_files",
"a.txt", "b.txt", "c.txt" });
program.parse_args({"./test.exe", "-abc", "3.14", "2.718", "--input_files",
"a.txt", "b.txt", "c.txt"});
REQUIRE(program.get<bool>("-a") == true);
REQUIRE(program.get<bool>("-b") == true);
auto c = program.get<std::vector<float>>("-c");
@ -63,49 +50,36 @@ TEST_CASE("Parse compound toggle arguments with implicit values and nargs and "
test_suite("compound_arguments")) {
argparse::ArgumentParser program("test");
program.add_argument("numbers")
.nargs(3)
.scan<'i', int>();
program.add_argument("numbers").nargs(3).scan<'i', int>();
program.add_argument("-a")
.default_value(false)
.implicit_value(true);
program.add_argument("-a").default_value(false).implicit_value(true);
program.add_argument("-b")
.default_value(false)
.implicit_value(true);
program.add_argument("-b").default_value(false).implicit_value(true);
program.add_argument("-c")
.nargs(2)
.scan<'g', float>();
program.add_argument("-c").nargs(2).scan<'g', float>();
program.add_argument("--input_files")
.nargs(3);
program.add_argument("--input_files").nargs(3);
REQUIRE_THROWS(program.parse_args({ "./test.exe", "1", "-abc", "3.14", "2.718", "2", "--input_files", "a.txt", "b.txt", "c.txt", "3" }));
REQUIRE_THROWS(
program.parse_args({"./test.exe", "1", "-abc", "3.14", "2.718", "2",
"--input_files", "a.txt", "b.txt", "c.txt", "3"}));
}
TEST_CASE("Parse out-of-order compound arguments" *
test_suite("compound_arguments")) {
argparse::ArgumentParser program("test");
program.add_argument("-a")
.default_value(false)
.implicit_value(true);
program.add_argument("-a").default_value(false).implicit_value(true);
program.add_argument("-b")
.default_value(false)
.implicit_value(true);
program.add_argument("-b").default_value(false).implicit_value(true);
program.add_argument("-c")
.nargs(2)
.scan<'g', float>();
program.add_argument("-c").nargs(2).scan<'g', float>();
program.parse_args({ "./main", "-cab", "3.14", "2.718" });
program.parse_args({"./main", "-cab", "3.14", "2.718"});
auto a = program.get<bool>("-a"); // true
auto b = program.get<bool>("-b"); // true
auto c = program.get<std::vector<float>>("-c"); // {3.14f, 2.718f}
auto a = program.get<bool>("-a"); // true
auto b = program.get<bool>("-b"); // true
auto c = program.get<std::vector<float>>("-c"); // {3.14f, 2.718f}
REQUIRE(a == true);
REQUIRE(b == true);
REQUIRE(program["-c"] == std::vector<float>{3.14f, 2.718f});
@ -115,20 +89,16 @@ TEST_CASE("Parse out-of-order compound arguments. Second variation" *
test_suite("compound_arguments")) {
argparse::ArgumentParser program("test");
program.add_argument("-a")
.default_value(false)
.implicit_value(true);
program.add_argument("-a").default_value(false).implicit_value(true);
program.add_argument("-b")
.default_value(false)
.implicit_value(true);
program.add_argument("-b").default_value(false).implicit_value(true);
program.add_argument("-c")
.nargs(2)
.default_value(std::vector<float>{0.0f, 0.0f})
.scan<'g', float>();
.nargs(2)
.default_value(std::vector<float>{0.0f, 0.0f})
.scan<'g', float>();
program.parse_args({"./main", "-cb"});
program.parse_args({"./main", "-cb"});
auto a = program.get<bool>("-a");
auto b = program.get<bool>("-b");

View File

@ -1,15 +1,14 @@
#include <doctest.hpp>
#include <argparse/argparse.hpp>
#include <doctest.hpp>
#include <test_utility.hpp>
using doctest::test_suite;
TEST_CASE("Parse vector of arguments" * test_suite("vector")) {
argparse::ArgumentParser program("test");
program.add_argument("input")
.nargs(2);
program.add_argument("input").nargs(2);
program.parse_args({ "test", "rocket.mesh", "thrust_profile.csv" });
program.parse_args({"test", "rocket.mesh", "thrust_profile.csv"});
auto inputs = program.get<std::vector<std::string>>("input");
REQUIRE(inputs.size() == 2);
@ -19,10 +18,9 @@ TEST_CASE("Parse vector of arguments" * test_suite("vector")) {
TEST_CASE("Parse list of arguments" * test_suite("vector")) {
argparse::ArgumentParser program("test");
program.add_argument("input")
.nargs(2);
program.add_argument("input").nargs(2);
program.parse_args({ "test", "rocket.mesh", "thrust_profile.csv" });
program.parse_args({"test", "rocket.mesh", "thrust_profile.csv"});
auto inputs = program.get<std::list<std::string>>("input");
REQUIRE(inputs.size() == 2);
@ -34,10 +32,10 @@ TEST_CASE("Parse list of arguments with default values" *
test_suite("vector")) {
argparse::ArgumentParser program("test");
program.add_argument("--input")
.default_value(std::list<int>{1, 2, 3, 4, 5})
.nargs(5);
.default_value(std::list<int>{1, 2, 3, 4, 5})
.nargs(5);
program.parse_args({ "test" });
program.parse_args({"test"});
auto inputs = program.get<std::list<int>>("--input");
REQUIRE(inputs.size() == 5);
@ -54,19 +52,20 @@ TEST_CASE("Parse list of arguments and save in an object" *
struct ConfigManager {
std::vector<std::string> files;
void add_file(const std::string& file) {
files.push_back(file);
}
void add_file(const std::string &file) { files.push_back(file); }
};
ConfigManager config_manager;
argparse::ArgumentParser program("test");
program.add_argument("--input_files")
.nargs(2)
.action([&](const std::string& value) { config_manager.add_file(value); return value; });
.nargs(2)
.action([&](const std::string &value) {
config_manager.add_file(value);
return value;
});
program.parse_args({ "test", "--input_files", "config.xml", "system.json" });
program.parse_args({"test", "--input_files", "config.xml", "system.json"});
auto file_args = program.get<std::vector<std::string>>("--input_files");
REQUIRE(file_args.size() == 2);
@ -76,5 +75,6 @@ TEST_CASE("Parse list of arguments and save in an object" *
REQUIRE(config_manager.files.size() == 2);
REQUIRE(config_manager.files[0] == "config.xml");
REQUIRE(config_manager.files[1] == "system.json");
REQUIRE(program["--input_files"] == std::vector<std::string>{"config.xml", "system.json"});
REQUIRE(program["--input_files"] ==
std::vector<std::string>{"config.xml", "system.json"});
}

View File

@ -5,7 +5,7 @@ using doctest::test_suite;
TEST_CASE("Include all default arguments" * test_suite("default_args")) {
argparse::ArgumentParser parser("test");
auto help_msg { parser.help().str() };
auto help_msg{parser.help().str()};
REQUIRE(help_msg.find("shows help message") != std::string::npos);
REQUIRE(help_msg.find("prints version information") != std::string::npos);
}

View File

@ -1,12 +1,12 @@
#include <doctest.hpp>
#include <argparse/argparse.hpp>
#include <doctest.hpp>
using doctest::test_suite;
TEST_CASE("Getting a simple argument" * test_suite("ArgumentParser::get")) {
argparse::ArgumentParser program("test");
program.add_argument("-s", "--stuff");
REQUIRE_NOTHROW(program.parse_args({ "test", "-s", "./src" }));
REQUIRE_NOTHROW(program.parse_args({"test", "-s", "./src"}));
REQUIRE(program.get("--stuff") == "./src");
}
@ -21,17 +21,15 @@ TEST_CASE("Skipped call to parse_args" * test_suite("ArgumentParser::get")) {
TEST_CASE("Missing argument" * test_suite("ArgumentParser::get")) {
argparse::ArgumentParser program("test");
program.add_argument("-s", "--stuff");
REQUIRE_NOTHROW(program.parse_args({ "test" }));
REQUIRE_NOTHROW(program.parse_args({"test"}));
REQUIRE_THROWS_WITH_AS(program.get("--stuff"),
"No value provided for '--stuff'.",
std::logic_error);
"No value provided for '--stuff'.", std::logic_error);
}
TEST_CASE("Implicit argument" * test_suite("ArgumentParser::get")) {
argparse::ArgumentParser program("test");
program.add_argument("-s", "--stuff").nargs(1);
REQUIRE_NOTHROW(program.parse_args({ "test" }));
REQUIRE_NOTHROW(program.parse_args({"test"}));
REQUIRE_THROWS_WITH_AS(program.get("--stuff"),
"No value provided for '--stuff'.",
std::logic_error);
"No value provided for '--stuff'.", std::logic_error);
}

View File

@ -64,12 +64,10 @@ TEST_CASE("Users can replace default -h/--help" * test_suite("help")) {
argparse::default_arguments::version);
std::stringstream buffer;
program.add_argument("-h", "--help")
.action([&](const auto &) {
buffer << program;
})
.default_value(false)
.implicit_value(true)
.nargs(0);
.action([&](const auto &) { buffer << program; })
.default_value(false)
.implicit_value(true)
.nargs(0);
REQUIRE(buffer.str().empty());
program.parse_args({"test", "--help"});

View File

@ -1,5 +1,5 @@
#include <doctest.hpp>
#include <argparse/argparse.hpp>
#include <doctest.hpp>
using doctest::test_suite;
@ -8,33 +8,32 @@ TEST_CASE("Parse unknown optional argument" *
argparse::ArgumentParser bfm("bfm");
bfm.add_argument("-l","--load")
.help("load a VMM into the kernel");
bfm.add_argument("-l", "--load").help("load a VMM into the kernel");
bfm.add_argument("-x", "--start")
.default_value(false)
.implicit_value(true)
.help("start a previously loaded VMM");
.default_value(false)
.implicit_value(true)
.help("start a previously loaded VMM");
bfm.add_argument("-d", "--dump")
.default_value(false)
.implicit_value(true)
.help("output the contents of the VMM's debug buffer");
.default_value(false)
.implicit_value(true)
.help("output the contents of the VMM's debug buffer");
bfm.add_argument("-s", "--stop")
.default_value(false)
.implicit_value(true)
.help("stop a previously started VMM");
.default_value(false)
.implicit_value(true)
.help("stop a previously started VMM");
bfm.add_argument("-u", "--unload")
.default_value(false)
.implicit_value(true)
.help("unload a previously loaded VMM");
.default_value(false)
.implicit_value(true)
.help("unload a previously loaded VMM");
bfm.add_argument("-m", "--mem")
.default_value(64ULL)
.scan<'u', unsigned long long>()
.help("memory in MB to give the VMM when loading");
.default_value(64ULL)
.scan<'u', unsigned long long>()
.help("memory in MB to give the VMM when loading");
REQUIRE_THROWS_WITH_AS(bfm.parse_args({"./test.exe", "-om"}),
"Unknown argument: -om", std::runtime_error);

View File

@ -1,22 +1,20 @@
#include <doctest.hpp>
#include <argparse/argparse.hpp>
#include <doctest.hpp>
using doctest::test_suite;
TEST_CASE("User-supplied argument" * test_suite("is_used")) {
argparse::ArgumentParser program("test");
program.add_argument("--dir")
.default_value(std::string("/"));
program.parse_args({ "test", "--dir", "/home/user" });
program.add_argument("--dir").default_value(std::string("/"));
program.parse_args({"test", "--dir", "/home/user"});
REQUIRE(program.get("--dir") == "/home/user");
REQUIRE(program.is_used("--dir") == true);
}
TEST_CASE("Not user-supplied argument" * test_suite("is_used")) {
argparse::ArgumentParser program("test");
program.add_argument("--dir")
.default_value(std::string("/"));
program.parse_args({ "test" });
program.add_argument("--dir").default_value(std::string("/"));
program.parse_args({"test"});
REQUIRE(program.get("--dir") == "/");
REQUIRE(program.is_used("--dir") == false);
}

View File

@ -1,39 +1,38 @@
#include <doctest.hpp>
#include <argparse/argparse.hpp>
#include <doctest.hpp>
using doctest::test_suite;
TEST_CASE("Issues with implicit values #37" * test_suite("implicit_values")) {
argparse::ArgumentParser m_bfm("test");
m_bfm.add_argument("-l", "--load")
.help("load a VMM into the kernel");
m_bfm.add_argument("-l", "--load").help("load a VMM into the kernel");
m_bfm.add_argument("-u", "--unload")
.default_value(false)
.implicit_value(true)
.help("unload a previously loaded VMM");
.default_value(false)
.implicit_value(true)
.help("unload a previously loaded VMM");
m_bfm.add_argument("-x", "--start")
.default_value(false)
.implicit_value(true)
.help("start a previously loaded VMM");
.default_value(false)
.implicit_value(true)
.help("start a previously loaded VMM");
m_bfm.add_argument("-s", "--stop")
.default_value(false)
.implicit_value(true)
.help("stop a previously started VMM");
.default_value(false)
.implicit_value(true)
.help("stop a previously started VMM");
m_bfm.add_argument("-d", "--dump")
.default_value(false)
.implicit_value(true)
.help("output the contents of the VMM's debug buffer");
.default_value(false)
.implicit_value(true)
.help("output the contents of the VMM's debug buffer");
m_bfm.add_argument("-m", "--mem")
.default_value(100)
.required()
.scan<'u', unsigned long long>()
.help("memory in MB to give the VMM when loading");
m_bfm.parse_args({ "test", "-l", "blah", "-d", "-u" });
.default_value(100)
.required()
.scan<'u', unsigned long long>()
.help("memory in MB to give the VMM when loading");
m_bfm.parse_args({"test", "-l", "blah", "-d", "-u"});
REQUIRE(m_bfm.get("--load") == "blah");
REQUIRE(m_bfm.get("-l") == "blah");

View File

@ -1,18 +1,16 @@
#include <doctest.hpp>
#include <argparse/argparse.hpp>
#include <doctest.hpp>
using doctest::test_suite;
TEST_CASE("Parse negative integer" * test_suite("positional_arguments")) {
argparse::ArgumentParser program;
program.add_argument("--verbose", "-v")
.help("enable verbose logging")
.default_value(false)
.implicit_value(true);
.help("enable verbose logging")
.default_value(false)
.implicit_value(true);
program.add_argument("number")
.help("Input number")
.scan<'i', int>();
program.add_argument("number").help("Input number").scan<'i', int>();
program.parse_args({"./main", "-1"});
REQUIRE(program.get<int>("number") == -1);
@ -22,14 +20,11 @@ TEST_CASE("Parse negative integers into a vector" *
test_suite("positional_arguments")) {
argparse::ArgumentParser program;
program.add_argument("--verbose", "-v")
.help("enable verbose logging")
.default_value(false)
.implicit_value(true);
.help("enable verbose logging")
.default_value(false)
.implicit_value(true);
program.add_argument("number")
.help("Input number")
.nargs(3)
.scan<'i', int>();
program.add_argument("number").help("Input number").nargs(3).scan<'i', int>();
program.parse_args({"./main", "-1", "-2", "3"});
REQUIRE(program["number"] == std::vector<int>{-1, -2, 3});
@ -38,13 +33,11 @@ TEST_CASE("Parse negative integers into a vector" *
TEST_CASE("Parse negative float" * test_suite("positional_arguments")) {
argparse::ArgumentParser program;
program.add_argument("--verbose", "-v")
.help("enable verbose logging")
.default_value(false)
.implicit_value(true);
.help("enable verbose logging")
.default_value(false)
.implicit_value(true);
program.add_argument("number")
.help("Input number")
.scan<'g', float>();
program.add_argument("number").help("Input number").scan<'g', float>();
program.parse_args({"./main", "-1.0"});
REQUIRE(program.get<float>("number") == -1.0);
@ -54,14 +47,14 @@ TEST_CASE("Parse negative floats into a vector" *
test_suite("positional_arguments")) {
argparse::ArgumentParser program;
program.add_argument("--verbose", "-v")
.help("enable verbose logging")
.default_value(false)
.implicit_value(true);
.help("enable verbose logging")
.default_value(false)
.implicit_value(true);
program.add_argument("number")
.help("Input number")
.nargs(3)
.scan<'g', double>();
.help("Input number")
.nargs(3)
.scan<'g', double>();
program.parse_args({"./main", "-1.001", "-2.002", "3.003"});
REQUIRE(program["number"] == std::vector<double>{-1.001, -2.002, 3.003});
@ -70,13 +63,11 @@ TEST_CASE("Parse negative floats into a vector" *
TEST_CASE("Parse numbers in E notation" * test_suite("positional_arguments")) {
argparse::ArgumentParser program;
program.add_argument("--verbose", "-v")
.help("enable verbose logging")
.default_value(false)
.implicit_value(true);
.help("enable verbose logging")
.default_value(false)
.implicit_value(true);
program.add_argument("number")
.help("Input number")
.scan<'g', double>();
program.add_argument("number").help("Input number").scan<'g', double>();
program.parse_args({"./main", "-1.2e3"});
REQUIRE(program.get<double>("number") == -1200.0);
@ -86,13 +77,11 @@ TEST_CASE("Parse numbers in E notation (capital E)" *
test_suite("positional_arguments")) {
argparse::ArgumentParser program;
program.add_argument("--verbose", "-v")
.help("enable verbose logging")
.default_value(false)
.implicit_value(true);
.help("enable verbose logging")
.default_value(false)
.implicit_value(true);
program.add_argument("number")
.help("Input number")
.scan<'g', double>();
program.add_argument("number").help("Input number").scan<'g', double>();
program.parse_args({"./main", "-1.32E4"});
REQUIRE(program.get<double>("number") == -13200.0);

View File

@ -1,5 +1,5 @@
#include <doctest.hpp>
#include <argparse/argparse.hpp>
#include <doctest.hpp>
using doctest::test_suite;
@ -7,10 +7,10 @@ TEST_CASE("Parse toggle arguments with default value" *
test_suite("optional_arguments")) {
argparse::ArgumentParser program("test");
program.add_argument("--verbose", "-v")
.default_value(false)
.implicit_value(true);
.default_value(false)
.implicit_value(true);
program.parse_args({ "./test.exe" });
program.parse_args({"./test.exe"});
REQUIRE(program.get<bool>("--verbose") == false);
REQUIRE(program["--verbose"] == false);
}
@ -19,18 +19,16 @@ TEST_CASE("Argument '-' is not an optional argument" *
test_suite("optional_arguments")) {
argparse::ArgumentParser program("test");
program.add_argument("input");
program.parse_args({ "./test.exe", "-"});
program.parse_args({"./test.exe", "-"});
REQUIRE(program.get<std::string>("input") == "-");
}
TEST_CASE("Argument '-' is not an optional argument but '-l' is" *
test_suite("optional_arguments")) {
argparse::ArgumentParser program("test");
program.add_argument("-l")
.default_value(false)
.implicit_value(true);
program.add_argument("-l").default_value(false).implicit_value(true);
program.add_argument("input");
program.parse_args({ "./test.exe", "-l", "-"});
program.parse_args({"./test.exe", "-l", "-"});
REQUIRE(program.get<bool>("-l") == true);
REQUIRE(program.get<std::string>("input") == "-");
}
@ -38,11 +36,9 @@ TEST_CASE("Argument '-' is not an optional argument but '-l' is" *
TEST_CASE("Argument '-l' is an optional argument but '-' is not" *
test_suite("optional_arguments")) {
argparse::ArgumentParser program("test");
program.add_argument("-l")
.default_value(false)
.implicit_value(true);
program.add_argument("-l").default_value(false).implicit_value(true);
program.add_argument("input");
program.parse_args({ "./test.exe", "-", "-l"});
program.parse_args({"./test.exe", "-", "-l"});
REQUIRE(program.get<bool>("-l") == true);
REQUIRE(program.get<std::string>("input") == "-");
}
@ -50,11 +46,9 @@ TEST_CASE("Argument '-l' is an optional argument but '-' is not" *
TEST_CASE("Parse toggle arguments with implicit value" *
test_suite("optional_arguments")) {
argparse::ArgumentParser program("test");
program.add_argument("--verbose")
.default_value(false)
.implicit_value(true);
program.add_argument("--verbose").default_value(false).implicit_value(true);
program.parse_args({ "./test.exe", "--verbose" });
program.parse_args({"./test.exe", "--verbose"});
REQUIRE(program.get<bool>("--verbose") == true);
REQUIRE(program["--verbose"] == true);
REQUIRE(program["--verbose"] != false);
@ -63,19 +57,13 @@ TEST_CASE("Parse toggle arguments with implicit value" *
TEST_CASE("Parse multiple toggle arguments with implicit values" *
test_suite("optional_arguments")) {
argparse::ArgumentParser program("test");
program.add_argument("-a")
.default_value(false)
.implicit_value(true);
program.add_argument("-a").default_value(false).implicit_value(true);
program.add_argument("-u")
.default_value(false)
.implicit_value(true);
program.add_argument("-u").default_value(false).implicit_value(true);
program.add_argument("-x")
.default_value(false)
.implicit_value(true);
program.add_argument("-x").default_value(false).implicit_value(true);
program.parse_args({ "./test.exe", "-a", "-x" });
program.parse_args({"./test.exe", "-a", "-x"});
REQUIRE(program.get<bool>("-a") == true);
REQUIRE(program.get<bool>("-u") == false);
REQUIRE(program.get<bool>("-x") == true);
@ -114,7 +102,9 @@ TEST_CASE("Parse 2 optional arguments of many values" *
test_suite("optional_arguments")) {
GIVEN("a program that accepts 2 optional arguments of many values") {
argparse::ArgumentParser program("test");
program.add_argument("-i").nargs(argparse::nargs_pattern::any).scan<'i', int>();
program.add_argument("-i")
.nargs(argparse::nargs_pattern::any)
.scan<'i', int>();
program.add_argument("-s").nargs(argparse::nargs_pattern::any);
WHEN("provided no argument") {
@ -129,8 +119,8 @@ TEST_CASE("Parse 2 optional arguments of many values" *
}
WHEN("provided 2 options with many arguments") {
program.parse_args(
{"test", "-i", "-42", "8", "100", "300", "-s", "ok", "this", "works"});
program.parse_args({"test", "-i", "-42", "8", "100", "300", "-s", "ok",
"this", "works"});
THEN("the optional parameter consumes each arguments") {
auto i = program.get<std::vector<int>>("-i");
@ -171,8 +161,7 @@ TEST_CASE("Parse an optional argument of many values"
}
WHEN("provided many arguments followed by an option with many arguments") {
program.parse_args(
{"test", "foo", "bar", "-s", "ok", "this", "works"});
program.parse_args({"test", "foo", "bar", "-s", "ok", "this", "works"});
THEN("the parameters consume each arguments") {
auto s = program.get<std::vector<std::string>>("-s");

View File

@ -1,17 +1,17 @@
#include <doctest.hpp>
#include <argparse/argparse.hpp>
#include <doctest.hpp>
using doctest::test_suite;
TEST_CASE("Add parent parsers" * test_suite("parent_parsers")) {
argparse::ArgumentParser parent_parser("main");
parent_parser.add_argument("--verbose")
.default_value(false)
.implicit_value(true);
.default_value(false)
.implicit_value(true);
argparse::ArgumentParser child_parser("foo");
child_parser.add_parents(parent_parser);
child_parser.parse_args({ "./main", "--verbose"});
child_parser.parse_args({"./main", "--verbose"});
REQUIRE(child_parser["--verbose"] == true);
REQUIRE(parent_parser["--verbose"] == false);
}
@ -19,20 +19,18 @@ TEST_CASE("Add parent parsers" * test_suite("parent_parsers")) {
TEST_CASE("Add parent to multiple parent parsers" *
test_suite("parent_parsers")) {
argparse::ArgumentParser parent_parser("main");
parent_parser.add_argument("--parent")
.default_value(0)
.scan<'i', int>();
parent_parser.add_argument("--parent").default_value(0).scan<'i', int>();
argparse::ArgumentParser foo_parser("foo");
foo_parser.add_argument("foo");
foo_parser.add_parents(parent_parser);
foo_parser.parse_args({ "./main", "--parent", "2", "XXX" });
foo_parser.parse_args({"./main", "--parent", "2", "XXX"});
REQUIRE(foo_parser["--parent"] == 2);
REQUIRE(foo_parser["foo"] == std::string("XXX"));
REQUIRE(parent_parser["--parent"] == 0);
argparse::ArgumentParser bar_parser("bar");
bar_parser.add_argument("--bar");
bar_parser.parse_args({ "./main", "--bar", "YYY" });
bar_parser.parse_args({"./main", "--bar", "YYY"});
REQUIRE(bar_parser["--bar"] == std::string("YYY"));
}

View File

@ -1,12 +1,12 @@
#include <doctest.hpp>
#include <argparse/argparse.hpp>
#include <doctest.hpp>
using doctest::test_suite;
TEST_CASE("Missing argument" * test_suite("parse_args")) {
argparse::ArgumentParser program("test");
program.add_argument("--config").nargs(1);
REQUIRE_THROWS_WITH_AS(program.parse_args({ "test", "--config" }),
REQUIRE_THROWS_WITH_AS(program.parse_args({"test", "--config"}),
"Too few arguments for '--config'.",
std::runtime_error);
}
@ -14,16 +14,15 @@ TEST_CASE("Missing argument" * test_suite("parse_args")) {
TEST_CASE("Parse a string argument with value" * test_suite("parse_args")) {
argparse::ArgumentParser program("test");
program.add_argument("--config");
program.parse_args({ "test", "--config", "config.yml"});
program.parse_args({"test", "--config", "config.yml"});
REQUIRE(program.get("--config") == "config.yml");
}
TEST_CASE("Parse a string argument with default value" *
test_suite("parse_args")) {
argparse::ArgumentParser program("test");
program.add_argument("--config")
.default_value(std::string("foo.yml"));
program.parse_args({ "test", "--config" });
program.add_argument("--config").default_value(std::string("foo.yml"));
program.parse_args({"test", "--config"});
REQUIRE(program.get("--config") == "foo.yml");
}
@ -55,64 +54,53 @@ TEST_CASE("Parse a string argument without default value" *
TEST_CASE("Parse an int argument with value" * test_suite("parse_args")) {
argparse::ArgumentParser program("test");
program.add_argument("--count")
.scan<'i', int>();
program.parse_args({ "test", "--count", "5" });
program.add_argument("--count").scan<'i', int>();
program.parse_args({"test", "--count", "5"});
REQUIRE(program.get<int>("--count") == 5);
}
TEST_CASE("Parse an int argument with default value" *
test_suite("parse_args")) {
argparse::ArgumentParser program("test");
program.add_argument("--count")
.default_value(2)
.scan<'i', int>();
program.parse_args({ "test", "--count" });
program.add_argument("--count").default_value(2).scan<'i', int>();
program.parse_args({"test", "--count"});
REQUIRE(program.get<int>("--count") == 2);
}
TEST_CASE("Parse a float argument with value" * test_suite("parse_args")) {
argparse::ArgumentParser program("test");
program.add_argument("--ratio")
.scan<'g', float>();
program.parse_args({ "test", "--ratio", "5.6645" });
program.add_argument("--ratio").scan<'g', float>();
program.parse_args({"test", "--ratio", "5.6645"});
REQUIRE(program.get<float>("--ratio") == 5.6645f);
}
TEST_CASE("Parse a float argument with default value" *
test_suite("parse_args")) {
argparse::ArgumentParser program("test");
program.add_argument("--ratio")
.default_value(3.14f)
.scan<'g', float>();
program.parse_args({ "test", "--ratio" });
program.add_argument("--ratio").default_value(3.14f).scan<'g', float>();
program.parse_args({"test", "--ratio"});
REQUIRE(program.get<float>("--ratio") == 3.14f);
}
TEST_CASE("Parse a double argument with value" * test_suite("parse_args")) {
argparse::ArgumentParser program("test");
program.add_argument("--ratio")
.scan<'g', double>();
program.parse_args({ "test", "--ratio", "5.6645" });
program.add_argument("--ratio").scan<'g', double>();
program.parse_args({"test", "--ratio", "5.6645"});
REQUIRE(program.get<double>("--ratio") == 5.6645);
}
TEST_CASE("Parse a double argument with default value" *
test_suite("parse_args")) {
argparse::ArgumentParser program("test");
program.add_argument("--ratio")
.default_value(3.14)
.scan<'g', double>();
program.parse_args({ "test", "--ratio" });
program.add_argument("--ratio").default_value(3.14).scan<'g', double>();
program.parse_args({"test", "--ratio"});
REQUIRE(program.get<double>("--ratio") == 3.14);
}
TEST_CASE("Parse a vector of integer arguments" * test_suite("parse_args")) {
argparse::ArgumentParser program("test");
program.add_argument("--vector")
.nargs(5)
.scan<'i', int>();
program.parse_args({ "test", "--vector", "1", "2", "3", "4", "5" });
program.add_argument("--vector").nargs(5).scan<'i', int>();
program.parse_args({"test", "--vector", "1", "2", "3", "4", "5"});
auto vector = program.get<std::vector<int>>("--vector");
REQUIRE(vector.size() == 5);
REQUIRE(vector[0] == 1);
@ -124,10 +112,8 @@ TEST_CASE("Parse a vector of integer arguments" * test_suite("parse_args")) {
TEST_CASE("Parse a vector of float arguments" * test_suite("parse_args")) {
argparse::ArgumentParser program("test");
program.add_argument("--vector")
.nargs(5)
.scan<'g', float>();
program.parse_args({ "test", "--vector", "1.1", "2.2", "3.3", "4.4", "5.5" });
program.add_argument("--vector").nargs(5).scan<'g', float>();
program.parse_args({"test", "--vector", "1.1", "2.2", "3.3", "4.4", "5.5"});
auto vector = program.get<std::vector<float>>("--vector");
REQUIRE(vector.size() == 5);
REQUIRE(vector[0] == 1.1f);
@ -170,10 +156,8 @@ TEST_CASE("Parse a vector of float without default value" *
TEST_CASE("Parse a vector of double arguments" * test_suite("parse_args")) {
argparse::ArgumentParser program("test");
program.add_argument("--vector")
.nargs(5)
.scan<'g', double>();
program.parse_args({ "test", "--vector", "1.1", "2.2", "3.3", "4.4", "5.5" });
program.add_argument("--vector").nargs(5).scan<'g', double>();
program.parse_args({"test", "--vector", "1.1", "2.2", "3.3", "4.4", "5.5"});
auto vector = program.get<std::vector<double>>("--vector");
REQUIRE(vector.size() == 5);
REQUIRE(vector[0] == 1.1);
@ -185,9 +169,8 @@ TEST_CASE("Parse a vector of double arguments" * test_suite("parse_args")) {
TEST_CASE("Parse a vector of string arguments" * test_suite("parse_args")) {
argparse::ArgumentParser program("test");
program.add_argument("--vector")
.nargs(5);
program.parse_args({ "test", "--vector", "abc", "def", "ghi", "jkl", "mno" });
program.add_argument("--vector").nargs(5);
program.parse_args({"test", "--vector", "abc", "def", "ghi", "jkl", "mno"});
auto vector = program.get<std::vector<std::string>>("--vector");
REQUIRE(vector.size() == 5);
REQUIRE(vector[0] == "abc");
@ -200,9 +183,9 @@ TEST_CASE("Parse a vector of string arguments" * test_suite("parse_args")) {
TEST_CASE("Parse a vector of character arguments" * test_suite("parse_args")) {
argparse::ArgumentParser program("test");
program.add_argument("--vector")
.nargs(5)
.action([](const std::string& value) { return value[0]; });
program.parse_args({ "test", "--vector", "a", "b", "c", "d", "e" });
.nargs(5)
.action([](const std::string &value) { return value[0]; });
program.parse_args({"test", "--vector", "a", "b", "c", "d", "e"});
auto vector = program.get<std::vector<char>>("--vector");
REQUIRE(vector.size() == 5);
REQUIRE(vector[0] == 'a');
@ -217,15 +200,15 @@ TEST_CASE("Parse a vector of string arguments and construct objects" *
class Foo {
public:
Foo(const std::string& value) : value(value) {}
Foo(const std::string &value) : value(value) {}
std::string value;
};
argparse::ArgumentParser program("test");
program.add_argument("--vector")
.nargs(5)
.action([](const std::string& value) { return Foo(value); });
program.parse_args({ "test", "--vector", "abc", "def", "ghi", "jkl", "mno" });
.nargs(5)
.action([](const std::string &value) { return Foo(value); });
program.parse_args({"test", "--vector", "abc", "def", "ghi", "jkl", "mno"});
auto vector = program.get<std::vector<Foo>>("--vector");
REQUIRE(vector.size() == 5);
REQUIRE(vector[0].value == Foo("abc").value);

View File

@ -1,6 +1,6 @@
#include <doctest.hpp>
#include <argparse/argparse.hpp>
#include <cmath>
#include <doctest.hpp>
using doctest::test_suite;
@ -8,7 +8,7 @@ TEST_CASE("Parse positional arguments" * test_suite("positional_arguments")) {
argparse::ArgumentParser program("test");
program.add_argument("input");
program.add_argument("output");
program.parse_args({ "test", "rocket.mesh", "thrust_profile.csv" });
program.parse_args({"test", "rocket.mesh", "thrust_profile.csv"});
REQUIRE(program.get("input") == "rocket.mesh");
REQUIRE(program.get("output") == "thrust_profile.csv");
}
@ -17,7 +17,7 @@ TEST_CASE("Missing expected positional argument" *
test_suite("positional_arguments")) {
argparse::ArgumentParser program("test");
program.add_argument("input");
REQUIRE_THROWS_WITH_AS(program.parse_args({ "test" }),
REQUIRE_THROWS_WITH_AS(program.parse_args({"test"}),
"1 argument(s) expected. 0 provided.",
std::runtime_error);
}
@ -27,7 +27,8 @@ TEST_CASE("Parse positional arguments with fixed nargs" *
argparse::ArgumentParser program("test");
program.add_argument("input");
program.add_argument("output").nargs(2);
program.parse_args({ "test", "rocket.mesh", "thrust_profile.csv", "output.mesh" });
program.parse_args(
{"test", "rocket.mesh", "thrust_profile.csv", "output.mesh"});
REQUIRE(program.get("input") == "rocket.mesh");
auto outputs = program.get<std::vector<std::string>>("output");
REQUIRE(outputs.size() == 2);
@ -40,9 +41,9 @@ TEST_CASE("Parse positional arguments with optional arguments" *
argparse::ArgumentParser program("test");
program.add_argument("input");
program.add_argument("output").nargs(2);
program.add_argument("--num_iterations")
.scan<'i', int>();
program.parse_args({ "test", "rocket.mesh", "--num_iterations", "15", "thrust_profile.csv", "output.mesh" });
program.add_argument("--num_iterations").scan<'i', int>();
program.parse_args({"test", "rocket.mesh", "--num_iterations", "15",
"thrust_profile.csv", "output.mesh"});
REQUIRE(program.get<int>("--num_iterations") == 15);
REQUIRE(program.get("input") == "rocket.mesh");
auto outputs = program.get<std::vector<std::string>>("output");
@ -56,14 +57,16 @@ TEST_CASE("Parse positional arguments with optional arguments in the middle" *
argparse::ArgumentParser program("test");
program.add_argument("input");
program.add_argument("output").nargs(2);
program.add_argument("--num_iterations")
.scan<'i', int>();
REQUIRE_THROWS(program.parse_args({ "test", "rocket.mesh", "thrust_profile.csv", "--num_iterations", "15", "output.mesh" }));
program.add_argument("--num_iterations").scan<'i', int>();
REQUIRE_THROWS(
program.parse_args({"test", "rocket.mesh", "thrust_profile.csv",
"--num_iterations", "15", "output.mesh"}));
}
TEST_CASE("Parse positional nargs=1..2 arguments" *
test_suite("positional_arguments")) {
GIVEN("a program that accepts an optional argument and nargs=1..2 positional arguments") {
GIVEN("a program that accepts an optional argument and nargs=1..2 positional "
"arguments") {
argparse::ArgumentParser program("test");
program.add_argument("-o");
program.add_argument("input").nargs(1, 2);
@ -131,7 +134,8 @@ TEST_CASE("Parse positional nargs=1..2 arguments" *
WHEN("provided an optional in between positional arguments") {
THEN("the program does not accept it") {
REQUIRE_THROWS(program.parse_args({"test", "a.c", "-o", "a.out", "b.c"}));
REQUIRE_THROWS(
program.parse_args({"test", "a.c", "-o", "a.out", "b.c"}));
}
}
}
@ -139,7 +143,8 @@ TEST_CASE("Parse positional nargs=1..2 arguments" *
TEST_CASE("Parse positional nargs=ANY arguments" *
test_suite("positional_arguments")) {
GIVEN("a program that accepts an optional argument and nargs=ANY positional arguments") {
GIVEN("a program that accepts an optional argument and nargs=ANY positional "
"arguments") {
argparse::ArgumentParser program("test");
program.add_argument("-o");
program.add_argument("input").nargs(argparse::nargs_pattern::any);
@ -236,19 +241,21 @@ TEST_CASE("Parse remaining arguments deemed positional" *
TEST_CASE("Reversed order nargs is not allowed" *
test_suite("positional_arguments")) {
argparse::ArgumentParser program("test");
REQUIRE_THROWS_AS(program.add_argument("output").nargs(2, 1), std::logic_error);
REQUIRE_THROWS_AS(program.add_argument("output").nargs(2, 1),
std::logic_error);
}
TEST_CASE("Square a number" * test_suite("positional_arguments")) {
argparse::ArgumentParser program;
program.add_argument("--verbose", "-v")
.help("enable verbose logging")
.default_value(false)
.implicit_value(true);
.help("enable verbose logging")
.default_value(false)
.implicit_value(true);
program.add_argument("square")
.help("display a square of a given number")
.action([](const std::string& value) { return pow(std::stoi(value), 2); });
.help("display a square of a given number")
.action(
[](const std::string &value) { return pow(std::stoi(value), 2); });
program.parse_args({"./main", "15"});
REQUIRE(program.get<double>("square") == 225);

View File

@ -1,5 +1,5 @@
#include <doctest.hpp>
#include <argparse/argparse.hpp>
#include <doctest.hpp>
using doctest::test_suite;

View File

@ -1,6 +1,6 @@
#include <doctest.hpp>
#include <argparse/argparse.hpp>
#include <cmath>
#include <doctest.hpp>
using doctest::test_suite;
@ -16,7 +16,7 @@ TEST_CASE("Add subparsers" * test_suite("subparsers")) {
program.add_subparser(command_1);
program.add_subparser(command_2);
program.parse_args({ "test", "--output", "thrust_profile.csv" });
program.parse_args({"test", "--output", "thrust_profile.csv"});
REQUIRE(program.get("--output") == "thrust_profile.csv");
}
@ -29,49 +29,82 @@ TEST_CASE("Parse subparser command" * test_suite("subparsers")) {
argparse::ArgumentParser command_2("clean");
command_2.add_argument("--fullclean")
.default_value(false)
.implicit_value(true);
.default_value(false)
.implicit_value(true);
program.add_subparser(command_1);
program.add_subparser(command_2);
SUBCASE("command 1") {
program.parse_args({ "test", "add", "file1.txt", "file2.txt" });
program.parse_args({"test", "add", "file1.txt", "file2.txt"});
REQUIRE(command_1.is_used("file"));
REQUIRE((command_1.get<std::vector<std::string>>("file") == std::vector<std::string>{"file1.txt", "file2.txt"}));
REQUIRE((command_1.get<std::vector<std::string>>("file") ==
std::vector<std::string>{"file1.txt", "file2.txt"}));
}
SUBCASE("command 2") {
program.parse_args({ "test", "clean", "--fullclean" });
program.parse_args({"test", "clean", "--fullclean"});
REQUIRE(command_2.get<bool>("--fullclean") == true);
}
}
TEST_CASE("Parse subparser command with optional argument" * test_suite("subparsers")) {
TEST_CASE("Parse subparser command with optional argument" *
test_suite("subparsers")) {
argparse::ArgumentParser program("test");
program.add_argument("--verbose")
.default_value(false)
.implicit_value(true);
program.add_argument("--verbose").default_value(false).implicit_value(true);
argparse::ArgumentParser command_1("add");
command_1.add_argument("file");
argparse::ArgumentParser command_2("clean");
command_2.add_argument("--fullclean")
.default_value(false)
.implicit_value(true);
.default_value(false)
.implicit_value(true);
program.add_subparser(command_1);
program.add_subparser(command_2);
SUBCASE("Optional argument BEFORE subcommand") {
program.parse_args({ "test", "--verbose", "clean", "--fullclean" });
program.parse_args({"test", "--verbose", "clean", "--fullclean"});
REQUIRE(program.get<bool>("--verbose") == true);
REQUIRE(command_2.get<bool>("--fullclean") == true);
}
SUBCASE("Optional argument AFTER subcommand") {
REQUIRE_THROWS_WITH_AS(program.parse_args({ "test", "clean", "--fullclean", "--verbose" }),
REQUIRE_THROWS_WITH_AS(
program.parse_args({"test", "clean", "--fullclean", "--verbose"}),
"Unknown argument: --verbose", std::runtime_error);
}
}
TEST_CASE("Parse subparser command with parent parser" *
test_suite("subparsers")) {
argparse::ArgumentParser program("test");
argparse::ArgumentParser parent("parent");
parent.add_argument("--verbose").default_value(false).implicit_value(true);
program.add_parents(parent);
argparse::ArgumentParser command_1("add");
command_1.add_argument("file");
argparse::ArgumentParser command_2("clean");
command_2.add_argument("--fullclean")
.default_value(false)
.implicit_value(true);
program.add_subparser(command_1);
program.add_subparser(command_2);
SUBCASE("Optional argument BEFORE subcommand") {
program.parse_args({"test", "--verbose", "clean", "--fullclean"});
REQUIRE(program.get<bool>("--verbose") == true);
REQUIRE(command_2.get<bool>("--fullclean") == true);
}
SUBCASE("Optional argument AFTER subcommand") {
REQUIRE_THROWS_WITH_AS(
program.parse_args({"test", "clean", "--fullclean", "--verbose"}),
"Unknown argument: --verbose", std::runtime_error);
}
}
@ -80,13 +113,10 @@ TEST_CASE("Parse git commands" * test_suite("subparsers")) {
argparse::ArgumentParser program("git");
argparse::ArgumentParser add_command("add");
add_command.add_argument("files")
.remaining();
add_command.add_argument("files").remaining();
argparse::ArgumentParser commit_command("commit");
commit_command.add_argument("-a")
.default_value(false)
.implicit_value(true);
commit_command.add_argument("-a").default_value(false).implicit_value(true);
commit_command.add_argument("-m");
@ -97,11 +127,11 @@ TEST_CASE("Parse git commands" * test_suite("subparsers")) {
argparse::ArgumentParser submodule_command("submodule");
argparse::ArgumentParser submodule_update_command("update");
submodule_update_command.add_argument("--init")
.default_value(false)
.implicit_value(true);
.default_value(false)
.implicit_value(true);
submodule_update_command.add_argument("--recursive")
.default_value(false)
.implicit_value(true);
.default_value(false)
.implicit_value(true);
submodule_command.add_subparser(submodule_update_command);
program.add_subparser(add_command);
@ -110,43 +140,45 @@ TEST_CASE("Parse git commands" * test_suite("subparsers")) {
program.add_subparser(submodule_command);
SUBCASE("git add") {
program.parse_args({ "git", "add", "main.cpp", "foo.hpp", "foo.cpp" });
REQUIRE((add_command.get<std::vector<std::string>>("files") == std::vector<std::string>{"main.cpp", "foo.hpp", "foo.cpp"}));
program.parse_args({"git", "add", "main.cpp", "foo.hpp", "foo.cpp"});
REQUIRE((add_command.get<std::vector<std::string>>("files") ==
std::vector<std::string>{"main.cpp", "foo.hpp", "foo.cpp"}));
}
SUBCASE("git commit") {
program.parse_args({ "git", "commit", "-am", "Initial commit" });
program.parse_args({"git", "commit", "-am", "Initial commit"});
REQUIRE(commit_command.get<bool>("-a") == true);
REQUIRE(commit_command.get<std::string>("-m") == std::string{"Initial commit"});
REQUIRE(commit_command.get<std::string>("-m") ==
std::string{"Initial commit"});
}
SUBCASE("git cat-file -t") {
program.parse_args({ "git", "cat-file", "-t", "3739f5" });
program.parse_args({"git", "cat-file", "-t", "3739f5"});
REQUIRE(catfile_command.get<std::string>("-t") == std::string{"3739f5"});
}
SUBCASE("git cat-file -p") {
program.parse_args({ "git", "cat-file", "-p", "3739f5" });
program.parse_args({"git", "cat-file", "-p", "3739f5"});
REQUIRE(catfile_command.get<std::string>("-p") == std::string{"3739f5"});
}
SUBCASE("git submodule update") {
program.parse_args({ "git", "submodule", "update" });
program.parse_args({"git", "submodule", "update"});
}
SUBCASE("git submodule update --init") {
program.parse_args({ "git", "submodule", "update", "--init" });
program.parse_args({"git", "submodule", "update", "--init"});
REQUIRE(submodule_update_command.get<bool>("--init") == true);
REQUIRE(submodule_update_command.get<bool>("--recursive") == false);
}
SUBCASE("git submodule update --recursive") {
program.parse_args({ "git", "submodule", "update", "--recursive" });
program.parse_args({"git", "submodule", "update", "--recursive"});
REQUIRE(submodule_update_command.get<bool>("--recursive") == true);
}
SUBCASE("git submodule update --init --recursive") {
program.parse_args({ "git", "submodule", "update", "--init", "--recursive" });
program.parse_args({"git", "submodule", "update", "--init", "--recursive"});
REQUIRE(submodule_update_command.get<bool>("--init") == true);
REQUIRE(submodule_update_command.get<bool>("--recursive") == true);
}

View File

@ -1,15 +1,14 @@
#include <doctest.hpp>
#include <argparse/argparse.hpp>
#include <doctest.hpp>
#include <sstream>
using doctest::test_suite;
TEST_CASE("Users can print version and exit" * test_suite("version")
* doctest::skip()) {
TEST_CASE("Users can print version and exit" * test_suite("version") *
doctest::skip()) {
argparse::ArgumentParser program("cli-test", "1.9.0");
program.add_argument("-d", "--dir")
.required();
program.parse_args( { "test", "--version" });
program.add_argument("-d", "--dir").required();
program.parse_args({"test", "--version"});
REQUIRE(program.get("--version") == "1.9.0");
}
@ -21,17 +20,15 @@ TEST_CASE("Users can disable default -v/--version" * test_suite("version")) {
}
TEST_CASE("Users can replace default -v/--version" * test_suite("version")) {
std::string version { "3.1415" };
std::string version{"3.1415"};
argparse::ArgumentParser program("test", version,
argparse::default_arguments::help);
std::stringstream buffer;
program.add_argument("-v", "--version")
.action([&](const auto &) {
buffer << version;
})
.default_value(true)
.implicit_value(false)
.nargs(0);
.action([&](const auto &) { buffer << version; })
.default_value(true)
.implicit_value(false)
.nargs(0);
REQUIRE(buffer.str().empty());
program.parse_args({"test", "--version"});