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 * Requires C++17
* MIT License * 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 ## Quick Start
Simply include argparse.hpp and you're good to go. 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,7 +149,8 @@ constexpr bool standard_integer =
standard_signed_integer<T> || standard_unsigned_integer<T>; standard_signed_integer<T> || standard_unsigned_integer<T>;
template <class F, class Tuple, class Extra, std::size_t... I> template <class F, class Tuple, class Extra, std::size_t... I>
constexpr decltype(auto) apply_plus_one_impl(F &&f, Tuple &&t, Extra &&x, constexpr decltype(auto)
apply_plus_one_impl(F &&f, Tuple &&t, Extra &&x,
std::index_sequence<I...> /*unused*/) { std::index_sequence<I...> /*unused*/) {
return std::invoke(std::forward<F>(f), std::get<I>(std::forward<Tuple>(t))..., return std::invoke(std::forward<F>(f), std::get<I>(std::forward<Tuple>(t))...,
std::forward<Extra>(x)); std::forward<Extra>(x));
@ -328,11 +329,7 @@ template <class T> struct parse_number<T, chars_format::fixed> {
} // namespace details } // namespace details
enum class nargs_pattern { enum class nargs_pattern { optional, any, at_least_one };
optional,
any,
at_least_one
};
enum class default_arguments : unsigned int { enum class default_arguments : unsigned int {
none = 0, none = 0,
@ -429,7 +426,8 @@ public:
if constexpr (is_one_of(Shape, 'd') && details::standard_integer<T>) { if constexpr (is_one_of(Shape, 'd') && details::standard_integer<T>) {
action(details::parse_number<T, details::radix_10>()); 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>()); action(details::parse_number<T>());
} else if constexpr (is_one_of(Shape, 'u') && } else if constexpr (is_one_of(Shape, 'u') &&
details::standard_unsigned_integer<T>) { details::standard_unsigned_integer<T>) {
@ -506,7 +504,8 @@ public:
std::visit([](const auto &f) { f({}); }, m_action); std::visit([](const auto &f) { f({}); }, m_action);
return start; 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) { if (num_args_max < dist) {
end = std::next(start, num_args_max); end = std::next(start, num_args_max);
} }
@ -558,7 +557,8 @@ public:
throw_required_arg_no_value_provided_error(); throw_required_arg_no_value_provided_error();
} }
} else { } 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(); throw_nargs_range_validation_error();
} }
} }
@ -606,15 +606,13 @@ public:
return get<T>() == rhs; return get<T>() == rhs;
} else { } else {
auto lhs = get<T>(); auto lhs = get<T>();
return std::equal(std::begin(lhs), std::end(lhs), std::begin(rhs), return std::equal(
std::end(rhs), [](const auto &lhs, const auto &rhs) { std::begin(lhs), std::end(lhs), std::begin(rhs), std::end(rhs),
return lhs == rhs; [](const auto &lhs, const auto &rhs) { return lhs == rhs; });
});
} }
} }
private: private:
class NArgsRange { class NArgsRange {
std::size_t m_min; std::size_t m_min;
std::size_t m_max; std::size_t m_max;
@ -631,21 +629,15 @@ private:
return value >= m_min && value <= m_max; return value >= m_min && value <= m_max;
} }
bool is_exact() const { bool is_exact() const { return m_min == m_max; }
return m_min == m_max;
}
bool is_right_bounded() const { bool is_right_bounded() const {
return m_max < std::numeric_limits<std::size_t>::max(); return m_max < std::numeric_limits<std::size_t>::max();
} }
std::size_t get_min() const { std::size_t get_min() const { return m_min; }
return m_min;
}
std::size_t get_max() const { std::size_t get_max() const { return m_max; }
return m_max;
}
}; };
void throw_nargs_range_validation_error() const { void throw_nargs_range_validation_error() const {
@ -656,7 +648,8 @@ private:
if (m_num_args_range.is_exact()) { if (m_num_args_range.is_exact()) {
stream << m_num_args_range.get_min(); stream << m_num_args_range.get_min();
} else if (m_num_args_range.is_right_bounded()) { } 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 { } else {
stream << m_num_args_range.get_min() << " or more"; stream << m_num_args_range.get_min() << " or more";
} }
@ -855,7 +848,9 @@ private:
* Get argument value given a type * Get argument value given a type
* @throws std::logic_error in case of incompatible types * @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 (!m_values.empty()) {
if constexpr (details::IsContainer<T>) { if constexpr (details::IsContainer<T>) {
return any_cast_container<T>(m_values); return any_cast_container<T>(m_values);
@ -958,10 +953,8 @@ public:
ArgumentParser &operator=(ArgumentParser &&) = default; ArgumentParser &operator=(ArgumentParser &&) = default;
ArgumentParser(const ArgumentParser &other) ArgumentParser(const ArgumentParser &other)
: m_program_name(other.m_program_name), : m_program_name(other.m_program_name), m_version(other.m_version),
m_version(other.m_version), m_description(other.m_description), m_epilog(other.m_epilog),
m_description(other.m_description),
m_epilog(other.m_epilog),
m_is_parsed(other.m_is_parsed), m_is_parsed(other.m_is_parsed),
m_positional_arguments(other.m_positional_arguments), m_positional_arguments(other.m_positional_arguments),
m_optional_arguments(other.m_optional_arguments) { m_optional_arguments(other.m_optional_arguments) {
@ -1056,7 +1049,8 @@ public:
* @throws std::logic_error if the option has no value * @throws std::logic_error if the option has no value
* @throws std::bad_any_cast if the option is not of type T * @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 template <typename T = std::string>
auto get(std::string_view arg_name) const
-> std::conditional_t<details::IsContainer<T>, T, const T &> { -> std::conditional_t<details::IsContainer<T>, T, const T &> {
if (!m_is_parsed) { if (!m_is_parsed) {
throw std::logic_error("Nothing parsed, no arguments are available."); throw std::logic_error("Nothing parsed, no arguments are available.");
@ -1148,17 +1142,16 @@ public:
} }
if (!parser.m_subparser_map.empty()) { if (!parser.m_subparser_map.empty()) {
stream << (parser.m_positional_arguments.empty() ? stream << (parser.m_positional_arguments.empty()
(parser.m_optional_arguments.empty() ? "" : "\n") : ? (parser.m_optional_arguments.empty() ? "" : "\n")
"\n") : "\n")
<< "Subcommands:\n"; << "Subcommands:\n";
stream << "{"; stream << "{";
std::size_t i = 0; std::size_t i = 0;
for (const auto &[argument, unused] : parser.m_subparser_map) { for (const auto &[argument, unused] : parser.m_subparser_map) {
if (i == 0) { if (i == 0) {
stream << argument; stream << argument;
} } else {
else {
stream << ", " << argument; stream << ", " << argument;
} }
++i; ++i;
@ -1191,6 +1184,7 @@ public:
} }
void add_subparser(ArgumentParser &parser) { void add_subparser(ArgumentParser &parser) {
auto it = m_subparsers.emplace(std::cend(m_subparsers), parser); auto it = m_subparsers.emplace(std::cend(m_subparsers), parser);
m_subparser_map.insert_or_assign(parser.m_program_name, it); m_subparser_map.insert_or_assign(parser.m_program_name, it);
} }
@ -1217,11 +1211,13 @@ private:
if (subparser_it != m_subparser_map.end()) { if (subparser_it != m_subparser_map.end()) {
// build list of remaining args // 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 // invoke subparser
m_is_parsed = true; 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( throw std::runtime_error(
@ -1273,7 +1269,8 @@ private:
} }
using argument_it = std::list<Argument>::iterator; 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) { void index_argument(argument_it it) {
for (const auto &name : std::as_const(it->m_names)) { for (const auto &name : std::as_const(it->m_names)) {

View File

@ -1,14 +1,13 @@
#include <doctest.hpp>
#include <argparse/argparse.hpp> #include <argparse/argparse.hpp>
#include <doctest.hpp>
using doctest::test_suite; using doctest::test_suite;
TEST_CASE("Users can use default value inside actions" * TEST_CASE("Users can use default value inside actions" *
test_suite("actions")) { test_suite("actions")) {
argparse::ArgumentParser program("test"); argparse::ArgumentParser program("test");
program.add_argument("input") program.add_argument("input").default_value("bar").action(
.default_value("bar") [=](const std::string &value) {
.action([=](const std::string& value) {
static const std::vector<std::string> choices = {"foo", "bar", "baz"}; static const std::vector<std::string> choices = {"foo", "bar", "baz"};
if (std::find(choices.begin(), choices.end(), value) != choices.end()) { if (std::find(choices.begin(), choices.end(), value) != choices.end()) {
return value; return value;
@ -126,7 +125,9 @@ TEST_CASE("Users can use actions on nargs=ANY arguments" *
argparse::ArgumentParser program("sum"); argparse::ArgumentParser program("sum");
int result = 0; int result = 0;
program.add_argument("all").nargs(argparse::nargs_pattern::any).action( program.add_argument("all")
.nargs(argparse::nargs_pattern::any)
.action(
[](int &sum, std::string const &value) { sum += std::stoi(value); }, [](int &sum, std::string const &value) { sum += std::stoi(value); },
std::ref(result)); std::ref(result));

View File

@ -1,12 +1,11 @@
#include <doctest.hpp>
#include <argparse/argparse.hpp> #include <argparse/argparse.hpp>
#include <doctest.hpp>
using doctest::test_suite; using doctest::test_suite;
TEST_CASE("Simplest .append" * test_suite("append")) { TEST_CASE("Simplest .append" * test_suite("append")) {
argparse::ArgumentParser program("test"); argparse::ArgumentParser program("test");
program.add_argument("--dir") program.add_argument("--dir").append();
.append();
program.parse_args({"test", "--dir", "./Docs"}); program.parse_args({"test", "--dir", "./Docs"});
std::string result{program.get("--dir")}; std::string result{program.get("--dir")};
REQUIRE(result == "./Docs"); REQUIRE(result == "./Docs");
@ -14,8 +13,7 @@ TEST_CASE("Simplest .append" * test_suite("append")) {
TEST_CASE("Two parameter .append" * test_suite("append")) { TEST_CASE("Two parameter .append" * test_suite("append")) {
argparse::ArgumentParser program("test"); argparse::ArgumentParser program("test");
program.add_argument("--dir") program.add_argument("--dir").append();
.append();
program.parse_args({"test", "--dir", "./Docs", "--dir", "./Src"}); program.parse_args({"test", "--dir", "./Docs", "--dir", "./Src"});
auto result{program.get<std::vector<std::string>>("--dir")}; auto result{program.get<std::vector<std::string>>("--dir")};
REQUIRE(result.at(0) == "./Docs"); REQUIRE(result.at(0) == "./Docs");
@ -24,9 +22,7 @@ TEST_CASE("Two parameter .append" * test_suite("append")) {
TEST_CASE("Two int .append" * test_suite("append")) { TEST_CASE("Two int .append" * test_suite("append")) {
argparse::ArgumentParser program("test"); argparse::ArgumentParser program("test");
program.add_argument("--factor") program.add_argument("--factor").append().scan<'i', int>();
.append()
.scan<'i', int>();
program.parse_args({"test", "--factor", "2", "--factor", "5"}); program.parse_args({"test", "--factor", "2", "--factor", "5"});
auto result{program.get<std::vector<int>>("--factor")}; auto result{program.get<std::vector<int>>("--factor")};
REQUIRE(result.at(0) == 2); REQUIRE(result.at(0) == 2);
@ -37,9 +33,7 @@ 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"); argparse::ArgumentParser program("test");
program.add_argument("--dir") program.add_argument("--dir").default_value(expected).append();
.default_value(expected)
.append();
program.parse_args({"test"}); program.parse_args({"test"});
auto result{program.get<std::vector<std::string>>("--dir")}; auto result{program.get<std::vector<std::string>>("--dir")};
REQUIRE(result == expected); REQUIRE(result == expected);

View File

@ -1,5 +1,5 @@
#include <doctest.hpp>
#include <argparse/argparse.hpp> #include <argparse/argparse.hpp>
#include <doctest.hpp>
#include <test_utility.hpp> #include <test_utility.hpp>
using doctest::test_suite; using doctest::test_suite;
@ -7,17 +7,11 @@ using doctest::test_suite;
TEST_CASE("Parse compound toggle arguments with implicit values" * TEST_CASE("Parse compound toggle arguments with implicit values" *
test_suite("compound_arguments")) { test_suite("compound_arguments")) {
argparse::ArgumentParser program("test"); argparse::ArgumentParser program("test");
program.add_argument("-a") program.add_argument("-a").default_value(false).implicit_value(true);
.default_value(false)
.implicit_value(true);
program.add_argument("-u") program.add_argument("-u").default_value(false).implicit_value(true);
.default_value(false)
.implicit_value(true);
program.add_argument("-x") program.add_argument("-x").default_value(false).implicit_value(true);
.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>("-a") == true);
@ -28,20 +22,13 @@ TEST_CASE("Parse compound toggle arguments with implicit values" *
TEST_CASE("Parse compound toggle arguments with implicit values and nargs" * TEST_CASE("Parse compound toggle arguments with implicit values and nargs" *
test_suite("compound_arguments")) { test_suite("compound_arguments")) {
argparse::ArgumentParser program("test"); argparse::ArgumentParser program("test");
program.add_argument("-a") program.add_argument("-a").default_value(false).implicit_value(true);
.default_value(false)
.implicit_value(true);
program.add_argument("-b") program.add_argument("-b").default_value(false).implicit_value(true);
.default_value(false)
.implicit_value(true);
program.add_argument("-c") program.add_argument("-c").nargs(2).scan<'g', float>();
.nargs(2)
.scan<'g', float>();
program.add_argument("--input_files") program.add_argument("--input_files").nargs(3);
.nargs(3);
program.parse_args({"./test.exe", "-abc", "3.14", "2.718", "--input_files", program.parse_args({"./test.exe", "-abc", "3.14", "2.718", "--input_files",
"a.txt", "b.txt", "c.txt"}); "a.txt", "b.txt", "c.txt"});
@ -63,43 +50,30 @@ TEST_CASE("Parse compound toggle arguments with implicit values and nargs and "
test_suite("compound_arguments")) { test_suite("compound_arguments")) {
argparse::ArgumentParser program("test"); argparse::ArgumentParser program("test");
program.add_argument("numbers") program.add_argument("numbers").nargs(3).scan<'i', int>();
.nargs(3)
.scan<'i', int>();
program.add_argument("-a") program.add_argument("-a").default_value(false).implicit_value(true);
.default_value(false)
.implicit_value(true);
program.add_argument("-b") program.add_argument("-b").default_value(false).implicit_value(true);
.default_value(false)
.implicit_value(true);
program.add_argument("-c") program.add_argument("-c").nargs(2).scan<'g', float>();
.nargs(2)
.scan<'g', float>();
program.add_argument("--input_files") program.add_argument("--input_files").nargs(3);
.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_CASE("Parse out-of-order compound arguments" *
test_suite("compound_arguments")) { test_suite("compound_arguments")) {
argparse::ArgumentParser program("test"); argparse::ArgumentParser program("test");
program.add_argument("-a") program.add_argument("-a").default_value(false).implicit_value(true);
.default_value(false)
.implicit_value(true);
program.add_argument("-b") program.add_argument("-b").default_value(false).implicit_value(true);
.default_value(false)
.implicit_value(true);
program.add_argument("-c") program.add_argument("-c").nargs(2).scan<'g', float>();
.nargs(2)
.scan<'g', float>();
program.parse_args({"./main", "-cab", "3.14", "2.718"}); program.parse_args({"./main", "-cab", "3.14", "2.718"});
@ -115,13 +89,9 @@ TEST_CASE("Parse out-of-order compound arguments. Second variation" *
test_suite("compound_arguments")) { test_suite("compound_arguments")) {
argparse::ArgumentParser program("test"); argparse::ArgumentParser program("test");
program.add_argument("-a") program.add_argument("-a").default_value(false).implicit_value(true);
.default_value(false)
.implicit_value(true);
program.add_argument("-b") program.add_argument("-b").default_value(false).implicit_value(true);
.default_value(false)
.implicit_value(true);
program.add_argument("-c") program.add_argument("-c")
.nargs(2) .nargs(2)

View File

@ -1,13 +1,12 @@
#include <doctest.hpp>
#include <argparse/argparse.hpp> #include <argparse/argparse.hpp>
#include <doctest.hpp>
#include <test_utility.hpp> #include <test_utility.hpp>
using doctest::test_suite; using doctest::test_suite;
TEST_CASE("Parse vector of arguments" * test_suite("vector")) { TEST_CASE("Parse vector of arguments" * test_suite("vector")) {
argparse::ArgumentParser program("test"); argparse::ArgumentParser program("test");
program.add_argument("input") program.add_argument("input").nargs(2);
.nargs(2);
program.parse_args({"test", "rocket.mesh", "thrust_profile.csv"}); program.parse_args({"test", "rocket.mesh", "thrust_profile.csv"});
@ -19,8 +18,7 @@ TEST_CASE("Parse vector of arguments" * test_suite("vector")) {
TEST_CASE("Parse list of arguments" * test_suite("vector")) { TEST_CASE("Parse list of arguments" * test_suite("vector")) {
argparse::ArgumentParser program("test"); argparse::ArgumentParser program("test");
program.add_argument("input") program.add_argument("input").nargs(2);
.nargs(2);
program.parse_args({"test", "rocket.mesh", "thrust_profile.csv"}); program.parse_args({"test", "rocket.mesh", "thrust_profile.csv"});
@ -54,9 +52,7 @@ TEST_CASE("Parse list of arguments and save in an object" *
struct ConfigManager { struct ConfigManager {
std::vector<std::string> files; std::vector<std::string> files;
void add_file(const std::string& file) { void add_file(const std::string &file) { files.push_back(file); }
files.push_back(file);
}
}; };
ConfigManager config_manager; ConfigManager config_manager;
@ -64,7 +60,10 @@ TEST_CASE("Parse list of arguments and save in an object" *
argparse::ArgumentParser program("test"); argparse::ArgumentParser program("test");
program.add_argument("--input_files") program.add_argument("--input_files")
.nargs(2) .nargs(2)
.action([&](const std::string& value) { config_manager.add_file(value); return value; }); .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"});
@ -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.size() == 2);
REQUIRE(config_manager.files[0] == "config.xml"); REQUIRE(config_manager.files[0] == "config.xml");
REQUIRE(config_manager.files[1] == "system.json"); 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

@ -1,5 +1,5 @@
#include <doctest.hpp>
#include <argparse/argparse.hpp> #include <argparse/argparse.hpp>
#include <doctest.hpp>
using doctest::test_suite; using doctest::test_suite;
@ -23,8 +23,7 @@ TEST_CASE("Missing argument" * test_suite("ArgumentParser::get")) {
program.add_argument("-s", "--stuff"); program.add_argument("-s", "--stuff");
REQUIRE_NOTHROW(program.parse_args({"test"})); REQUIRE_NOTHROW(program.parse_args({"test"}));
REQUIRE_THROWS_WITH_AS(program.get("--stuff"), REQUIRE_THROWS_WITH_AS(program.get("--stuff"),
"No value provided for '--stuff'.", "No value provided for '--stuff'.", std::logic_error);
std::logic_error);
} }
TEST_CASE("Implicit argument" * test_suite("ArgumentParser::get")) { TEST_CASE("Implicit argument" * test_suite("ArgumentParser::get")) {
@ -32,6 +31,5 @@ TEST_CASE("Implicit argument" * test_suite("ArgumentParser::get")) {
program.add_argument("-s", "--stuff").nargs(1); 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"), REQUIRE_THROWS_WITH_AS(program.get("--stuff"),
"No value provided for '--stuff'.", "No value provided for '--stuff'.", std::logic_error);
std::logic_error);
} }

View File

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

View File

@ -1,5 +1,5 @@
#include <doctest.hpp>
#include <argparse/argparse.hpp> #include <argparse/argparse.hpp>
#include <doctest.hpp>
using doctest::test_suite; using doctest::test_suite;
@ -8,8 +8,7 @@ TEST_CASE("Parse unknown optional argument" *
argparse::ArgumentParser bfm("bfm"); argparse::ArgumentParser bfm("bfm");
bfm.add_argument("-l","--load") bfm.add_argument("-l", "--load").help("load a VMM into the kernel");
.help("load a VMM into the kernel");
bfm.add_argument("-x", "--start") bfm.add_argument("-x", "--start")
.default_value(false) .default_value(false)

View File

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

View File

@ -1,12 +1,11 @@
#include <doctest.hpp>
#include <argparse/argparse.hpp> #include <argparse/argparse.hpp>
#include <doctest.hpp>
using doctest::test_suite; using doctest::test_suite;
TEST_CASE("Issues with implicit values #37" * test_suite("implicit_values")) { TEST_CASE("Issues with implicit values #37" * test_suite("implicit_values")) {
argparse::ArgumentParser m_bfm("test"); argparse::ArgumentParser m_bfm("test");
m_bfm.add_argument("-l", "--load") m_bfm.add_argument("-l", "--load").help("load a VMM into the kernel");
.help("load a VMM into the kernel");
m_bfm.add_argument("-u", "--unload") m_bfm.add_argument("-u", "--unload")
.default_value(false) .default_value(false)

View File

@ -1,5 +1,5 @@
#include <doctest.hpp>
#include <argparse/argparse.hpp> #include <argparse/argparse.hpp>
#include <doctest.hpp>
using doctest::test_suite; using doctest::test_suite;
@ -10,9 +10,7 @@ TEST_CASE("Parse negative integer" * test_suite("positional_arguments")) {
.default_value(false) .default_value(false)
.implicit_value(true); .implicit_value(true);
program.add_argument("number") program.add_argument("number").help("Input number").scan<'i', int>();
.help("Input number")
.scan<'i', int>();
program.parse_args({"./main", "-1"}); program.parse_args({"./main", "-1"});
REQUIRE(program.get<int>("number") == -1); REQUIRE(program.get<int>("number") == -1);
@ -26,10 +24,7 @@ TEST_CASE("Parse negative integers into a vector" *
.default_value(false) .default_value(false)
.implicit_value(true); .implicit_value(true);
program.add_argument("number") program.add_argument("number").help("Input number").nargs(3).scan<'i', int>();
.help("Input number")
.nargs(3)
.scan<'i', int>();
program.parse_args({"./main", "-1", "-2", "3"}); program.parse_args({"./main", "-1", "-2", "3"});
REQUIRE(program["number"] == std::vector<int>{-1, -2, 3}); REQUIRE(program["number"] == std::vector<int>{-1, -2, 3});
@ -42,9 +37,7 @@ TEST_CASE("Parse negative float" * test_suite("positional_arguments")) {
.default_value(false) .default_value(false)
.implicit_value(true); .implicit_value(true);
program.add_argument("number") program.add_argument("number").help("Input number").scan<'g', float>();
.help("Input number")
.scan<'g', float>();
program.parse_args({"./main", "-1.0"}); program.parse_args({"./main", "-1.0"});
REQUIRE(program.get<float>("number") == -1.0); REQUIRE(program.get<float>("number") == -1.0);
@ -74,9 +67,7 @@ TEST_CASE("Parse numbers in E notation" * test_suite("positional_arguments")) {
.default_value(false) .default_value(false)
.implicit_value(true); .implicit_value(true);
program.add_argument("number") program.add_argument("number").help("Input number").scan<'g', double>();
.help("Input number")
.scan<'g', double>();
program.parse_args({"./main", "-1.2e3"}); program.parse_args({"./main", "-1.2e3"});
REQUIRE(program.get<double>("number") == -1200.0); REQUIRE(program.get<double>("number") == -1200.0);
@ -90,9 +81,7 @@ TEST_CASE("Parse numbers in E notation (capital E)" *
.default_value(false) .default_value(false)
.implicit_value(true); .implicit_value(true);
program.add_argument("number") program.add_argument("number").help("Input number").scan<'g', double>();
.help("Input number")
.scan<'g', double>();
program.parse_args({"./main", "-1.32E4"}); program.parse_args({"./main", "-1.32E4"});
REQUIRE(program.get<double>("number") == -13200.0); REQUIRE(program.get<double>("number") == -13200.0);

View File

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

View File

@ -1,5 +1,5 @@
#include <doctest.hpp>
#include <argparse/argparse.hpp> #include <argparse/argparse.hpp>
#include <doctest.hpp>
using doctest::test_suite; using doctest::test_suite;
@ -19,9 +19,7 @@ TEST_CASE("Add parent parsers" * test_suite("parent_parsers")) {
TEST_CASE("Add parent to multiple parent parsers" * TEST_CASE("Add parent to multiple parent parsers" *
test_suite("parent_parsers")) { test_suite("parent_parsers")) {
argparse::ArgumentParser parent_parser("main"); argparse::ArgumentParser parent_parser("main");
parent_parser.add_argument("--parent") parent_parser.add_argument("--parent").default_value(0).scan<'i', int>();
.default_value(0)
.scan<'i', int>();
argparse::ArgumentParser foo_parser("foo"); argparse::ArgumentParser foo_parser("foo");
foo_parser.add_argument("foo"); foo_parser.add_argument("foo");

View File

@ -1,5 +1,5 @@
#include <doctest.hpp>
#include <argparse/argparse.hpp> #include <argparse/argparse.hpp>
#include <doctest.hpp>
using doctest::test_suite; using doctest::test_suite;
@ -21,8 +21,7 @@ TEST_CASE("Parse a string argument with value" * test_suite("parse_args")) {
TEST_CASE("Parse a string argument with default value" * TEST_CASE("Parse a string argument with default value" *
test_suite("parse_args")) { test_suite("parse_args")) {
argparse::ArgumentParser program("test"); argparse::ArgumentParser program("test");
program.add_argument("--config") program.add_argument("--config").default_value(std::string("foo.yml"));
.default_value(std::string("foo.yml"));
program.parse_args({"test", "--config"}); program.parse_args({"test", "--config"});
REQUIRE(program.get("--config") == "foo.yml"); REQUIRE(program.get("--config") == "foo.yml");
} }
@ -55,8 +54,7 @@ TEST_CASE("Parse a string argument without default value" *
TEST_CASE("Parse an int argument with value" * test_suite("parse_args")) { TEST_CASE("Parse an int argument with value" * test_suite("parse_args")) {
argparse::ArgumentParser program("test"); argparse::ArgumentParser program("test");
program.add_argument("--count") program.add_argument("--count").scan<'i', int>();
.scan<'i', int>();
program.parse_args({"test", "--count", "5"}); program.parse_args({"test", "--count", "5"});
REQUIRE(program.get<int>("--count") == 5); REQUIRE(program.get<int>("--count") == 5);
} }
@ -64,17 +62,14 @@ TEST_CASE("Parse an int argument with value" * test_suite("parse_args")) {
TEST_CASE("Parse an int argument with default value" * TEST_CASE("Parse an int argument with default value" *
test_suite("parse_args")) { test_suite("parse_args")) {
argparse::ArgumentParser program("test"); argparse::ArgumentParser program("test");
program.add_argument("--count") program.add_argument("--count").default_value(2).scan<'i', int>();
.default_value(2)
.scan<'i', int>();
program.parse_args({"test", "--count"}); program.parse_args({"test", "--count"});
REQUIRE(program.get<int>("--count") == 2); REQUIRE(program.get<int>("--count") == 2);
} }
TEST_CASE("Parse a float argument with value" * test_suite("parse_args")) { TEST_CASE("Parse a float argument with value" * test_suite("parse_args")) {
argparse::ArgumentParser program("test"); argparse::ArgumentParser program("test");
program.add_argument("--ratio") program.add_argument("--ratio").scan<'g', float>();
.scan<'g', float>();
program.parse_args({"test", "--ratio", "5.6645"}); program.parse_args({"test", "--ratio", "5.6645"});
REQUIRE(program.get<float>("--ratio") == 5.6645f); REQUIRE(program.get<float>("--ratio") == 5.6645f);
} }
@ -82,17 +77,14 @@ TEST_CASE("Parse a float argument with value" * test_suite("parse_args")) {
TEST_CASE("Parse a float argument with default value" * TEST_CASE("Parse a float argument with default value" *
test_suite("parse_args")) { test_suite("parse_args")) {
argparse::ArgumentParser program("test"); argparse::ArgumentParser program("test");
program.add_argument("--ratio") program.add_argument("--ratio").default_value(3.14f).scan<'g', float>();
.default_value(3.14f)
.scan<'g', float>();
program.parse_args({"test", "--ratio"}); program.parse_args({"test", "--ratio"});
REQUIRE(program.get<float>("--ratio") == 3.14f); REQUIRE(program.get<float>("--ratio") == 3.14f);
} }
TEST_CASE("Parse a double argument with value" * test_suite("parse_args")) { TEST_CASE("Parse a double argument with value" * test_suite("parse_args")) {
argparse::ArgumentParser program("test"); argparse::ArgumentParser program("test");
program.add_argument("--ratio") program.add_argument("--ratio").scan<'g', double>();
.scan<'g', double>();
program.parse_args({"test", "--ratio", "5.6645"}); program.parse_args({"test", "--ratio", "5.6645"});
REQUIRE(program.get<double>("--ratio") == 5.6645); REQUIRE(program.get<double>("--ratio") == 5.6645);
} }
@ -100,18 +92,14 @@ TEST_CASE("Parse a double argument with value" * test_suite("parse_args")) {
TEST_CASE("Parse a double argument with default value" * TEST_CASE("Parse a double argument with default value" *
test_suite("parse_args")) { test_suite("parse_args")) {
argparse::ArgumentParser program("test"); argparse::ArgumentParser program("test");
program.add_argument("--ratio") program.add_argument("--ratio").default_value(3.14).scan<'g', double>();
.default_value(3.14)
.scan<'g', double>();
program.parse_args({"test", "--ratio"}); program.parse_args({"test", "--ratio"});
REQUIRE(program.get<double>("--ratio") == 3.14); REQUIRE(program.get<double>("--ratio") == 3.14);
} }
TEST_CASE("Parse a vector of integer arguments" * test_suite("parse_args")) { TEST_CASE("Parse a vector of integer arguments" * test_suite("parse_args")) {
argparse::ArgumentParser program("test"); argparse::ArgumentParser program("test");
program.add_argument("--vector") program.add_argument("--vector").nargs(5).scan<'i', int>();
.nargs(5)
.scan<'i', int>();
program.parse_args({"test", "--vector", "1", "2", "3", "4", "5"}); program.parse_args({"test", "--vector", "1", "2", "3", "4", "5"});
auto vector = program.get<std::vector<int>>("--vector"); auto vector = program.get<std::vector<int>>("--vector");
REQUIRE(vector.size() == 5); REQUIRE(vector.size() == 5);
@ -124,9 +112,7 @@ TEST_CASE("Parse a vector of integer arguments" * test_suite("parse_args")) {
TEST_CASE("Parse a vector of float arguments" * test_suite("parse_args")) { TEST_CASE("Parse a vector of float arguments" * test_suite("parse_args")) {
argparse::ArgumentParser program("test"); argparse::ArgumentParser program("test");
program.add_argument("--vector") program.add_argument("--vector").nargs(5).scan<'g', float>();
.nargs(5)
.scan<'g', float>();
program.parse_args({"test", "--vector", "1.1", "2.2", "3.3", "4.4", "5.5"}); program.parse_args({"test", "--vector", "1.1", "2.2", "3.3", "4.4", "5.5"});
auto vector = program.get<std::vector<float>>("--vector"); auto vector = program.get<std::vector<float>>("--vector");
REQUIRE(vector.size() == 5); REQUIRE(vector.size() == 5);
@ -170,9 +156,7 @@ TEST_CASE("Parse a vector of float without default value" *
TEST_CASE("Parse a vector of double arguments" * test_suite("parse_args")) { TEST_CASE("Parse a vector of double arguments" * test_suite("parse_args")) {
argparse::ArgumentParser program("test"); argparse::ArgumentParser program("test");
program.add_argument("--vector") program.add_argument("--vector").nargs(5).scan<'g', double>();
.nargs(5)
.scan<'g', double>();
program.parse_args({"test", "--vector", "1.1", "2.2", "3.3", "4.4", "5.5"}); program.parse_args({"test", "--vector", "1.1", "2.2", "3.3", "4.4", "5.5"});
auto vector = program.get<std::vector<double>>("--vector"); auto vector = program.get<std::vector<double>>("--vector");
REQUIRE(vector.size() == 5); REQUIRE(vector.size() == 5);
@ -185,8 +169,7 @@ TEST_CASE("Parse a vector of double arguments" * test_suite("parse_args")) {
TEST_CASE("Parse a vector of string arguments" * test_suite("parse_args")) { TEST_CASE("Parse a vector of string arguments" * test_suite("parse_args")) {
argparse::ArgumentParser program("test"); argparse::ArgumentParser program("test");
program.add_argument("--vector") program.add_argument("--vector").nargs(5);
.nargs(5);
program.parse_args({"test", "--vector", "abc", "def", "ghi", "jkl", "mno"}); program.parse_args({"test", "--vector", "abc", "def", "ghi", "jkl", "mno"});
auto vector = program.get<std::vector<std::string>>("--vector"); auto vector = program.get<std::vector<std::string>>("--vector");
REQUIRE(vector.size() == 5); REQUIRE(vector.size() == 5);

View File

@ -1,6 +1,6 @@
#include <doctest.hpp>
#include <argparse/argparse.hpp> #include <argparse/argparse.hpp>
#include <cmath> #include <cmath>
#include <doctest.hpp>
using doctest::test_suite; using doctest::test_suite;
@ -27,7 +27,8 @@ TEST_CASE("Parse positional arguments with fixed nargs" *
argparse::ArgumentParser program("test"); argparse::ArgumentParser program("test");
program.add_argument("input"); program.add_argument("input");
program.add_argument("output").nargs(2); 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"); REQUIRE(program.get("input") == "rocket.mesh");
auto outputs = program.get<std::vector<std::string>>("output"); auto outputs = program.get<std::vector<std::string>>("output");
REQUIRE(outputs.size() == 2); REQUIRE(outputs.size() == 2);
@ -40,9 +41,9 @@ TEST_CASE("Parse positional arguments with optional arguments" *
argparse::ArgumentParser program("test"); argparse::ArgumentParser program("test");
program.add_argument("input"); program.add_argument("input");
program.add_argument("output").nargs(2); program.add_argument("output").nargs(2);
program.add_argument("--num_iterations") program.add_argument("--num_iterations").scan<'i', int>();
.scan<'i', int>(); program.parse_args({"test", "rocket.mesh", "--num_iterations", "15",
program.parse_args({ "test", "rocket.mesh", "--num_iterations", "15", "thrust_profile.csv", "output.mesh" }); "thrust_profile.csv", "output.mesh"});
REQUIRE(program.get<int>("--num_iterations") == 15); REQUIRE(program.get<int>("--num_iterations") == 15);
REQUIRE(program.get("input") == "rocket.mesh"); REQUIRE(program.get("input") == "rocket.mesh");
auto outputs = program.get<std::vector<std::string>>("output"); 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"); argparse::ArgumentParser program("test");
program.add_argument("input"); program.add_argument("input");
program.add_argument("output").nargs(2); program.add_argument("output").nargs(2);
program.add_argument("--num_iterations") program.add_argument("--num_iterations").scan<'i', int>();
.scan<'i', int>(); REQUIRE_THROWS(
REQUIRE_THROWS(program.parse_args({ "test", "rocket.mesh", "thrust_profile.csv", "--num_iterations", "15", "output.mesh" })); program.parse_args({"test", "rocket.mesh", "thrust_profile.csv",
"--num_iterations", "15", "output.mesh"}));
} }
TEST_CASE("Parse positional nargs=1..2 arguments" * TEST_CASE("Parse positional nargs=1..2 arguments" *
test_suite("positional_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"); argparse::ArgumentParser program("test");
program.add_argument("-o"); program.add_argument("-o");
program.add_argument("input").nargs(1, 2); 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") { WHEN("provided an optional in between positional arguments") {
THEN("the program does not accept it") { 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_CASE("Parse positional nargs=ANY arguments" *
test_suite("positional_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"); argparse::ArgumentParser program("test");
program.add_argument("-o"); program.add_argument("-o");
program.add_argument("input").nargs(argparse::nargs_pattern::any); program.add_argument("input").nargs(argparse::nargs_pattern::any);
@ -236,7 +241,8 @@ TEST_CASE("Parse remaining arguments deemed positional" *
TEST_CASE("Reversed order nargs is not allowed" * TEST_CASE("Reversed order nargs is not allowed" *
test_suite("positional_arguments")) { test_suite("positional_arguments")) {
argparse::ArgumentParser program("test"); 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")) { TEST_CASE("Square a number" * test_suite("positional_arguments")) {
@ -248,7 +254,8 @@ TEST_CASE("Square a number" * test_suite("positional_arguments")) {
program.add_argument("square") program.add_argument("square")
.help("display a square of a given number") .help("display a square of a given number")
.action([](const std::string& value) { return pow(std::stoi(value), 2); }); .action(
[](const std::string &value) { return pow(std::stoi(value), 2); });
program.parse_args({"./main", "15"}); program.parse_args({"./main", "15"});
REQUIRE(program.get<double>("square") == 225); REQUIRE(program.get<double>("square") == 225);

View File

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

View File

@ -1,6 +1,6 @@
#include <doctest.hpp>
#include <argparse/argparse.hpp> #include <argparse/argparse.hpp>
#include <cmath> #include <cmath>
#include <doctest.hpp>
using doctest::test_suite; using doctest::test_suite;
@ -38,7 +38,8 @@ TEST_CASE("Parse subparser command" * test_suite("subparsers")) {
SUBCASE("command 1") { 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.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") { SUBCASE("command 2") {
@ -47,11 +48,10 @@ TEST_CASE("Parse subparser command" * test_suite("subparsers")) {
} }
} }
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"); argparse::ArgumentParser program("test");
program.add_argument("--verbose") program.add_argument("--verbose").default_value(false).implicit_value(true);
.default_value(false)
.implicit_value(true);
argparse::ArgumentParser command_1("add"); argparse::ArgumentParser command_1("add");
command_1.add_argument("file"); command_1.add_argument("file");
@ -71,7 +71,40 @@ TEST_CASE("Parse subparser command with optional argument" * test_suite("subpars
} }
SUBCASE("Optional argument AFTER subcommand") { 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); "Unknown argument: --verbose", std::runtime_error);
} }
} }
@ -80,13 +113,10 @@ TEST_CASE("Parse git commands" * test_suite("subparsers")) {
argparse::ArgumentParser program("git"); argparse::ArgumentParser program("git");
argparse::ArgumentParser add_command("add"); argparse::ArgumentParser add_command("add");
add_command.add_argument("files") add_command.add_argument("files").remaining();
.remaining();
argparse::ArgumentParser commit_command("commit"); argparse::ArgumentParser commit_command("commit");
commit_command.add_argument("-a") commit_command.add_argument("-a").default_value(false).implicit_value(true);
.default_value(false)
.implicit_value(true);
commit_command.add_argument("-m"); commit_command.add_argument("-m");
@ -111,13 +141,15 @@ TEST_CASE("Parse git commands" * test_suite("subparsers")) {
SUBCASE("git add") { SUBCASE("git add") {
program.parse_args({"git", "add", "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"})); REQUIRE((add_command.get<std::vector<std::string>>("files") ==
std::vector<std::string>{"main.cpp", "foo.hpp", "foo.cpp"}));
} }
SUBCASE("git commit") { 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<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") { SUBCASE("git cat-file -t") {

View File

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