From 1d01903303f16ab0e2ba7dc4a72f4a1cd814dbfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Musia=C5=82?= <111433005+SpectraL519@users.noreply.github.com> Date: Mon, 8 Apr 2024 20:14:34 +0200 Subject: [PATCH] YT-CPPAP-5: argument_name class refactor * Renamed the `argument_name` structure members: * `name` -> `primary` * `short_name` -> `secondary` * Added the `argument_name::match` functions * Aligned the code and unit tests to use the new names and functions --- README.md | 4 +- change_log.md | 5 + include/ap/argument_parser.hpp | 313 ++++++++---------- test/include/argument_parser_test_fixture.hpp | 12 +- test/source/test_argument_name.cpp | 185 ++++++++--- .../test_argument_parser_add_argument.cpp | 114 ++++--- .../test_argument_parser_parse_args.cpp | 171 +++++----- test/source/test_optional_argument.cpp | 93 +++--- test/source/test_positional_argument.cpp | 78 ++--- 9 files changed, 528 insertions(+), 447 deletions(-) diff --git a/README.md b/README.md index a0af400..7bf39c7 100644 --- a/README.md +++ b/README.md @@ -219,9 +219,11 @@ The `CPP-AP` library has a few default arguments defined. To add a default argum ```c++ // add positional arguments - pass a std::vector of default positional arguments parser.default_positional_arguments({...}); +// here ... represents a list of ap::default_argument::positional values (or alternatively ap::default_posarg) // add optional arguments - pass a std::vector of default optional arguments parser.default_positional_arguments({...}); +// here ... represents a list of ap::default_argument::optional values (or alternatively ap::default_optarg) ``` The supported default arguments are: @@ -263,7 +265,7 @@ The supported default arguments are: .action(ap::action::check_file_exists_action) .help("Input file path"); - // multi_input - equivalen to: + // multi_input - equivalent to: parser.add_optional_argument("input", "i") .required() .nargs(ap::nargs::at_least(1)) diff --git a/change_log.md b/change_log.md index b09d6e4..74727e9 100644 --- a/change_log.md +++ b/change_log.md @@ -31,3 +31,8 @@ * Added the `install_clang17_toolchain.sh` env script * Added the `format` workflow * Switched from the `` to the `` library for all current container operations +* Modified the `argument_name` structure - renamed members: `name` to `primary`, `short_name` to `secondary` +* Added `argument_name::match(string_view)` and `argument_name::match(argument_name)` functions +* Added aliases for default argument enum classes: + * `ap::default_argument::positional` = `ap::default_posarg` + * `ap::default_argument::optional` = `ap::default_optarg` diff --git a/include/ap/argument_parser.hpp b/include/ap/argument_parser.hpp index dfc9416..2ed25a3 100644 --- a/include/ap/argument_parser.hpp +++ b/include/ap/argument_parser.hpp @@ -36,6 +36,7 @@ SOFTWARE. #pragma once +#include #include #include #include @@ -329,17 +330,17 @@ struct argument_name { /** * @brief Primary name constructor. - * @param name The primary name of the argument. + * @param primary The primary name of the argument. */ - explicit argument_name(std::string_view name) : name(name) {} + argument_name(std::string_view primary) : primary(primary) {} /** * @brief Primary and secondary name constructor. - * @param name The primary name of the argument. - * @param short_name The secondary (short) name of the argument. + * @param primary The primary name of the argument. + * @param secondary The secondary (short) name of the argument. */ - explicit argument_name(std::string_view name, std::string_view short_name) - : name(name), short_name(short_name) {} + argument_name(std::string_view primary, std::string_view secondary) + : primary(primary), secondary(secondary) {} /// @brief Class destructor. ~argument_name() = default; @@ -350,23 +351,44 @@ struct argument_name { * @return Equality of argument names. */ bool operator==(const argument_name& other) const noexcept { - return this->name == other.name; + if (not (this->secondary and other.secondary) and (this->secondary or other.secondary)) + return false; + + if (this->primary != other.primary) + return false; + + return this->secondary ? this->secondary.value() == other.secondary.value() : true; } /** - * @brief Equality comparison operator for string variables representing argument names. - * @param name The string view to compare with. - * @return Equality of names comparison (either full or short name). + * @brief Matches the given string to the argument_name instance. + * @param arg_name The name string to match. + * @return True if name is equal to either the primary or the secondary name of the argument_name instance. */ - bool operator==(std::string_view name) const noexcept { - return name == this->name or (this->short_name and name == this->short_name.value()); + [[nodiscard]] bool match(std::string_view arg_name) const noexcept { + return arg_name == this->primary or (this->secondary and arg_name == this->secondary.value()); + } + + /** + * @brief Matches the given argument name to the argument_name instance. + * @param arg_name The argument_name instance to match. + * @return True if arg_name's primary or secondary value matches the argument_name instance. + */ + [[nodiscard]] bool match(const argument_name& arg_name) const noexcept { + if (this->match(arg_name.primary)) + return true; + + if (arg_name.secondary) + return this->match(arg_name.secondary.value()); + + return false; } /// @brief Get a string representation of the argument_name. [[nodiscard]] std::string str() const noexcept { - return this->short_name - ? ("[" + this->name + "," + this->short_name.value() + "]") - : ("[" + this->name + "]"); + return this->secondary + ? ("[" + this->primary + "," + this->secondary.value() + "]") + : ("[" + this->primary + "]"); } /** @@ -380,11 +402,8 @@ struct argument_name { return os; } - // TODO: rename - // * name -> primary - // * short_name -> secondary - const std::string name; ///< The primary name of the argument. - const std::optional short_name; ///< The optional short name of the argument. + const std::string primary; ///< The primary name of the argument. + const std::optional secondary; ///< The optional (short) name of the argument. }; /// @brief Argument class interface @@ -524,20 +543,10 @@ class argument_name_used_error : public argument_parser_error { public: /** * @brief Constructor for the argument_name_used_error class. - * @param given_arg_name The name of the argument causing the collision. + * @param arg_name The name of the argument causing the collision. */ - explicit argument_name_used_error(const std::string_view& given_arg_name) - : argument_parser_error("Given name `" + std::string(given_arg_name) + "` already used") {} - - /** - * @brief Constructor for the argument_name_used_error class with a short name. - * @param given_arg_name The name of the argument causing the collision. - * @param given_arg_name_short The short name of the argument causing the collision. - */ - explicit argument_name_used_error(const std::string_view& given_arg_name, const std::string_view& given_arg_name_short) - : argument_parser_error( - "Given name " + argument::detail::argument_name(given_arg_name, given_arg_name_short).str() + " already used" - ) {} + explicit argument_name_used_error(const argument::detail::argument_name& arg_name) + : argument_parser_error("Given name `" + arg_name.str() + "` already used") {} }; /// @brief Exception thrown when an argument with a specific name is not found. @@ -557,11 +566,11 @@ class invalid_value_type_error : public argument_parser_error { /** * @brief Constructor for the invalid_value_type_error class. * @param arg_name The name of the argument that had invalid value type. - * @param given_arg_type The type information that failed to cast. + * @param value_type The type information that failed to cast. */ - explicit invalid_value_type_error(const argument::detail::argument_name& arg_name, const std::type_info& given_arg_type) + explicit invalid_value_type_error(const argument::detail::argument_name& arg_name, const std::type_info& value_type) : argument_parser_error( - "Invalid value type specified for argument " + arg_name.str() + " - " + given_arg_type.name() + "Invalid value type specified for argument " + arg_name.str() + " - " + value_type.name() ) {} }; @@ -630,18 +639,10 @@ class positional_argument : public detail::argument_interface { positional_argument() = delete; /** - * @brief Constructor for positional_argument with a name. - * @param name The primary name of the positional argument. - */ - positional_argument(std::string_view name) : _name(name) {} - - /** - * @brief Constructor for positional_argument with a name and a short name. - * @param name The primary name of the positional argument. - * @param short_name The short name of the positional argument (optional). + * @brief Constructor for positional_argument with the `name` identifier. + * @param name The `name` identifier of the positional argument. */ - positional_argument(std::string_view name, std::string_view short_name) - : _name(name, short_name) {} + positional_argument(const detail::argument_name& name) : _name(name) {} /// @brief Destructor for positional argument. ~positional_argument() = default; @@ -792,7 +793,7 @@ class positional_argument : public detail::argument_interface { /// @return Reference to the vector of parsed values for the positional argument. [[nodiscard]] const std::vector& values() const override { - throw std::logic_error("Positional argument " + this->_name.name + "has only 1 value."); + throw std::logic_error("Positional argument " + this->_name.primary + "has only 1 value."); } /** @@ -847,18 +848,10 @@ class optional_argument : public detail::argument_interface { optional_argument() = delete; /** - * @brief Constructor for optional_argument with a name. - * @param name The primary name of the optional argument. - */ - optional_argument(std::string_view name) : _name(name) {} - - /** - * @brief Constructor for optional_argument with a name and a short name. - * @param name The primary name of the optional argument. - * @param short_name The short name of the optional argument (optional). + * @brief Constructor for optional_argument with the `name` identifier. + * @param name The `name` identifier of the optional argument. */ - optional_argument(std::string_view name, std::string_view short_name) - : _name(name, short_name) {} + optional_argument(const detail::argument_name& name) : _name(name) {} /// @brief Destructor for optional_argument. ~optional_argument() = default; @@ -1149,6 +1142,9 @@ enum class optional : uint8_t { help, input, output, multi_input, multi_output } } // namespace default_argument +using default_posarg = default_argument::positional; +using default_optarg = default_argument::optional; + /// @brief Main argument parser class. class argument_parser { public: @@ -1185,121 +1181,126 @@ class argument_parser { /** * @brief Set default positional arguments. - * @param args Vector of default positional argument categories. + * @param arg_discriminator_list Vector of default positional argument categories. * @return Reference to the argument parser. */ - argument_parser& default_positional_arguments(const std::vector& args + argument_parser& default_positional_arguments(const std::vector& arg_discriminator_list ) noexcept { - for (const auto arg : args) - this->_add_default_positional_argument(arg); + for (const auto arg_discriminator : arg_discriminator_list) + this->_add_default_positional_argument(arg_discriminator); return *this; } /** * @brief Set default optional arguments. - * @param args Vector of default optional argument categories. + * @param arg_discriminator_list Vector of default optional argument categories. * @return Reference to the argument parser. */ - argument_parser& default_optional_arguments(const std::vector& args) noexcept { - for (const auto arg : args) - this->_add_default_optional_argument(arg); + argument_parser& default_optional_arguments(const std::vector& arg_discriminator_list + ) noexcept { + for (const auto arg_discriminator : arg_discriminator_list) + this->_add_default_optional_argument(arg_discriminator); return *this; } /** - * @brief Add a positional argument to the parser. + * @brief Adds a positional argument to the parser's configuration. * @tparam T Type of the argument value. - * @param name The name of the argument. + * @param primary_name The primary name of the argument. * @return Reference to the added positional argument. */ template - argument::positional_argument& add_positional_argument(std::string_view name) { + argument::positional_argument& add_positional_argument(std::string_view primary_name) { // TODO: check forbidden characters - if (this->_is_arg_name_used(name)) - throw error::argument_name_used_error(name); + const argument::detail::argument_name arg_name = { primary_name }; + if (this->_is_arg_name_used(arg_name)) + throw error::argument_name_used_error(arg_name); - this->_positional_args.push_back(std::make_unique>(name)); + this->_positional_args.push_back(std::make_unique>(arg_name)); return static_cast&>(*this->_positional_args.back()); } /** - * @brief Add a positional argument with a short name to the parser. + * @brief Adds a positional argument to the parser's configuration. * @tparam T Type of the argument value. - * @param name The name of the argument. - * @param short_name The short name of the argument. + * @param primary_name The primary name of the argument. + * @param secondary_name The secondary name of the argument. * @return Reference to the added positional argument. */ template - argument::positional_argument& add_positional_argument(std::string_view name, std::string_view short_name) { + argument::positional_argument& add_positional_argument(std::string_view primary_name, std::string_view secondary_name) { // TODO: check forbidden characters - if (this->_is_arg_name_used(name, short_name)) - throw error::argument_name_used_error(name, short_name); + const argument::detail::argument_name arg_name = { primary_name, secondary_name }; + if (this->_is_arg_name_used(arg_name)) + throw error::argument_name_used_error(arg_name); - this->_positional_args.push_back(std::make_unique>(name, short_name)); + this->_positional_args.push_back(std::make_unique>(arg_name)); return static_cast&>(*this->_positional_args.back()); } /** - * @brief Add an optional argument to the parser. + * @brief Adds a positional argument to the parser's configuration. * @tparam T Type of the argument value. - * @param name The name of the argument. + * @param primary_name The primary name of the argument. * @return Reference to the added optional argument. */ template - argument::optional_argument& add_optional_argument(std::string_view name) { + argument::optional_argument& add_optional_argument(std::string_view primary_name) { // TODO: check forbidden characters - if (this->_is_arg_name_used(name)) - throw error::argument_name_used_error(name); + const argument::detail::argument_name arg_name = { primary_name }; + if (this->_is_arg_name_used(arg_name)) + throw error::argument_name_used_error(arg_name); - this->_optional_args.push_back(std::make_unique>(name)); + this->_optional_args.push_back(std::make_unique>(arg_name)); return static_cast&>(*this->_optional_args.back()); } /** - * @brief Add an optional argument with a short name to the parser. + * @brief Adds a positional argument to the parser's configuration. * @tparam T Type of the argument value. - * @param name The name of the argument. - * @param short_name The short name of the argument. + * @param primary_name The primary name of the argument. + * @param secondary_name The secondary name of the argument. * @return Reference to the added optional argument. */ template - argument::optional_argument& add_optional_argument(std::string_view name, std::string_view short_name) { + argument::optional_argument& add_optional_argument(std::string_view primary_name, std::string_view secondary_name) { // TODO: check forbidden characters - if (this->_is_arg_name_used(name, short_name)) - throw error::argument_name_used_error(name, short_name); + const argument::detail::argument_name arg_name = { primary_name, secondary_name }; + if (this->_is_arg_name_used(arg_name)) + throw error::argument_name_used_error(arg_name); - this->_optional_args.push_back(std::make_unique>(name, short_name)); + this->_optional_args.push_back(std::make_unique>(arg_name)); return static_cast&>(*this->_optional_args.back()); } /** - * @brief Add a boolean flag to the parser. + * @brief Adds a boolean flag argument to the parser's configuration. * @tparam StoreImplicitly Flag indicating whether to store implicitly. - * @param name The name of the flag. + * @param primary_name The primary name of the flag. * @return Reference to the added boolean flag argument. */ template - argument::optional_argument& add_flag(std::string_view name) { - return this->add_optional_argument(name) + argument::optional_argument& add_flag(std::string_view primary_name) { + return this->add_optional_argument(primary_name) .default_value(not StoreImplicitly) .implicit_value(StoreImplicitly) .nargs(0); } /** - * @brief Add a boolean flag with a short name to the parser. + * @brief Adds a boolean flag argument to the parser's configuration. * @tparam StoreImplicitly Flag indicating whether to store implicitly. - * @param name The name of the flag. - * @param short_name The short name of the flag. + * @param primary_name The primary name of the flag. + * @param secondary_name The secondary name of the flag. * @return Reference to the added boolean flag argument. */ template - argument::optional_argument& add_flag(std::string_view name, std::string_view short_name) { - return this->add_optional_argument(name, short_name) + argument::optional_argument& add_flag(std::string_view primary_name, std::string_view secondary_name) { + return this->add_optional_argument(primary_name, secondary_name) .default_value(not StoreImplicitly) .implicit_value(StoreImplicitly) .nargs(0); @@ -1327,7 +1328,7 @@ class argument_parser { */ bool has_value(std::string_view arg_name) const noexcept { const auto arg_opt = this->_get_argument(arg_name); - return arg_opt ? arg_opt->get().has_value() : false; // TODO: throw + return arg_opt ? arg_opt->get().has_value() : false; } /** @@ -1337,7 +1338,7 @@ class argument_parser { */ std::size_t count(std::string_view arg_name) const noexcept { const auto arg_opt = this->_get_argument(arg_name); - return arg_opt ? arg_opt->get().nused() : 0ull; // TODO: throw + return arg_opt ? arg_opt->get().nused() : 0ull; } /** @@ -1380,6 +1381,7 @@ class argument_parser { return std::vector{ std::any_cast(arg.value()) }; std::vector values; + // TODO: use std::ranges::to after transition to C++23 std::ranges::copy( std::views::transform( arg.values(), [](const std::any& value) { return std::any_cast(value); } @@ -1422,34 +1424,34 @@ class argument_parser { private: /** - * @brief Add default positional argument based on the specified category. - * @param arg The default positional argument category. + * @brief Add default positional argument based on the specified discriminator. + * @param arg_discriminator The default positional argument discriminator. */ - void _add_default_positional_argument(const default_argument::positional arg) noexcept { - switch (arg) { - case default_argument::positional::input: + void _add_default_positional_argument(const default_posarg arg_discriminator) noexcept { + switch (arg_discriminator) { + case default_posarg::input: this->add_positional_argument("input") .action(ap::action::check_file_exists_action()) .help("Input file path"); break; - case default_argument::positional::output: + case default_posarg::output: this->add_positional_argument("output").help("Output file path"); break; } } /** - * @brief Add default optional argument based on the specified category. - * @param arg The default optional argument category. + * @brief Add default optional argument based on the specified discriminator. + * @param arg_discriminator The default optional argument discriminator. */ - void _add_default_optional_argument(const default_argument::optional arg) noexcept { - switch (arg) { - case default_argument::optional::help: + void _add_default_optional_argument(const default_optarg arg_discriminator) noexcept { + switch (arg_discriminator) { + case default_optarg::help: this->add_flag("help", "h").bypass_required().help("Display help message"); break; - case default_argument::optional::input: + case default_optarg::input: this->add_optional_argument("input", "i") .required() .nargs(1) @@ -1457,11 +1459,11 @@ class argument_parser { .help("Input file path"); break; - case default_argument::optional::output: + case default_optarg::output: this->add_optional_argument("output", "o").required().nargs(1).help("Output file path"); break; - case default_argument::optional::multi_input: + case default_optarg::multi_input: this->add_optional_argument("input", "i") .required() .nargs(ap::nargs::at_least(1)) @@ -1469,7 +1471,7 @@ class argument_parser { .help("Input files paths"); break; - case default_argument::optional::multi_output: + case default_optarg::multi_output: this->add_optional_argument("output", "o").required().nargs(ap::nargs::at_least(1)).help("Output files paths"); break; } @@ -1483,6 +1485,7 @@ class argument_parser { cmd_argument(const cmd_argument&) = default; cmd_argument(cmd_argument&&) = default; cmd_argument& operator=(const cmd_argument&) = default; + cmd_argument& operator=(cmd_argument&&) = default; /** * @brief Constructor of a command-line argument. @@ -1518,53 +1521,31 @@ class argument_parser { using argument_predicate_type = std::function; /** - * @brief Function to create a predicate for finding arguments by name. - * @param name The name of the argument. + * @brief Returns an unary predicate function which checks if the given name matches the argument's name + * @param arg_name The name of the argument. * @return Argument predicate based on the provided name. */ - [[nodiscard]] argument_predicate_type _name_eq_predicate(const std::string_view& name) const noexcept { - return [&name](const argument_ptr_type& arg) { return name == arg->name(); }; + [[nodiscard]] argument_predicate_type _name_match_predicate(std::string_view arg_name) const noexcept { + return [arg_name](const argument_ptr_type& arg) { return arg->name().match(arg_name); }; } /** - * @brief Function to create a predicate for finding arguments by name and short name. - * @param name The name of the argument. - * @param short_name The short name of the argument. - * @return Argument predicate based on the provided name and short name. + * @brief Returns an unary predicate function which checks if the given name matches the argument's name + * @param arg_name The name of the argument. + * @return Argument predicate based on the provided name. */ - [[nodiscard]] argument_predicate_type _name_eq_predicate( - const std::string_view& name, const std::string_view& short_name + [[nodiscard]] argument_predicate_type _name_match_predicate(const argument::detail::argument_name& arg_name ) const noexcept { - return [&name, &short_name](const argument_ptr_type& arg) { - return name == arg->name() or short_name == arg->name(); - }; + return [&arg_name](const argument_ptr_type& arg) { return arg->name().match(arg_name); }; } /** * @brief Check if an argument name is already used. - * @param name The name of the argument. + * @param arg_name The name of the argument. * @return True if the argument name is already used, false otherwise. */ - [[nodiscard]] bool _is_arg_name_used(const std::string_view& name) const noexcept { - const auto predicate = this->_name_eq_predicate(name); - - if (std::ranges::find_if(this->_positional_args, predicate) != this->_positional_args.end()) - return true; - - if (std::ranges::find_if(this->_optional_args, predicate) != this->_optional_args.end()) - return true; - - return false; - } - - /** - * @brief Check if an argument name and short name pair is already used. - * @param name The name of the argument. - * @param short_name The short name of the argument. - * @return True if the argument name or short name is already used, false otherwise. - */ - [[nodiscard]] bool _is_arg_name_used(const std::string_view& name, const std::string_view& short_name) const noexcept { - const auto predicate = this->_name_eq_predicate(name, short_name); + [[nodiscard]] bool _is_arg_name_used(const argument::detail::argument_name& arg_name) const noexcept { + const auto predicate = this->_name_match_predicate(arg_name); if (std::ranges::find_if(this->_positional_args, predicate) != this->_positional_args.end()) return true; @@ -1604,28 +1585,28 @@ class argument_parser { /** * @brief Check if an argument is a flag based on its value. - * @param arg The argument value. + * @param arg The cmd argument's value. * @return True if the argument is a flag, false otherwise. */ [[nodiscard]] bool _is_flag(const std::string& arg) const noexcept { if (arg.starts_with(this->_flag_prefix)) - return this->_is_arg_name_used(arg.substr(this->_flag_prefix_length)); + return this->_is_arg_name_used({ arg.substr(this->_flag_prefix_length) }); if (arg.starts_with(this->_flag_prefix_char)) - return this->_is_arg_name_used(arg.substr(this->_flag_prefix_char_length)); + return this->_is_arg_name_used({ arg.substr(this->_flag_prefix_char_length) }); return false; } /** * @brief Remove the flag prefix from the argument. - * @param arg The argument to strip the prefix from. + * @param arg_flag The argument flag to strip the prefix from. */ - void _strip_flag_prefix(std::string& arg) const noexcept { - if (arg.starts_with(this->_flag_prefix)) - arg.erase(0, this->_flag_prefix_length); + void _strip_flag_prefix(std::string& arg_flag) const noexcept { + if (arg_flag.starts_with(this->_flag_prefix)) + arg_flag.erase(0, this->_flag_prefix_length); else - arg.erase(0, this->_flag_prefix_char_length); + arg_flag.erase(0, this->_flag_prefix_char_length); } /** @@ -1668,7 +1649,7 @@ class argument_parser { while (cmd_it != cmd_args.end()) { if (cmd_it->discriminator == cmd_argument::type_discriminator::flag) { auto opt_arg_it = - std::ranges::find_if(this->_optional_args, this->_name_eq_predicate(cmd_it->value)); + std::ranges::find_if(this->_optional_args, this->_name_match_predicate(cmd_it->value)); if (opt_arg_it == this->_optional_args.end()) throw error::argument_not_found_error(cmd_it->value); @@ -1692,7 +1673,7 @@ class argument_parser { * @return True if optional arguments can bypass required arguments, false otherwise. */ [[nodiscard]] bool _bypass_required_args() const noexcept { - return std::any_of(std::cbegin(this->_optional_args), std::cend(this->_optional_args), [](const argument_ptr_type& arg) { + return std::ranges::any_of(this->_optional_args, [](const argument_ptr_type& arg) { return arg->is_used() and arg->bypass_required_enabled(); }); } @@ -1725,11 +1706,11 @@ class argument_parser { /** * @brief Get the argument with the specified name. - * @param name The name of the argument. + * @param arg_name The name of the argument. * @return The argument with the specified name, if found; otherwise, std::nullopt. */ - argument_opt_type _get_argument(const std::string_view& name) const noexcept { - const auto predicate = this->_name_eq_predicate(name); + argument_opt_type _get_argument(std::string_view arg_name) const noexcept { + const auto predicate = this->_name_match_predicate(arg_name); if (auto pos_arg_it = std::ranges::find_if(this->_positional_args, predicate); pos_arg_it != this->_positional_args.end()) { diff --git a/test/include/argument_parser_test_fixture.hpp b/test/include/argument_parser_test_fixture.hpp index 0b7cffb..b5963dd 100644 --- a/test/include/argument_parser_test_fixture.hpp +++ b/test/include/argument_parser_test_fixture.hpp @@ -23,11 +23,11 @@ struct argument_parser_test_fixture { using invalid_argument_value_type = int; // test utility functions - [[nodiscard]] std::string prepare_arg_flag(std::size_t i) const { + [[nodiscard]] std::string prepare_arg_flag_primary(std::size_t i) const { return "--test_arg_" + std::to_string(i); } - [[nodiscard]] std::string prepare_arg_flag_short(std::size_t i) const { + [[nodiscard]] std::string prepare_arg_flag_secondary(std::size_t i) const { return "-ta_" + std::to_string(i); } @@ -58,7 +58,7 @@ struct argument_parser_test_fixture { } for (std::size_t i = args_split; i < num_args; i++) { // optional args - std::string arg = prepare_arg_flag(i); + std::string arg = prepare_arg_flag_primary(i); std::string arg_v = prepare_arg_value(i); const std::size_t arg_i = 2 * i - args_split + 1; @@ -87,12 +87,12 @@ struct argument_parser_test_fixture { void add_arguments(ap::argument_parser& parser, std::size_t num_args, std::size_t args_split) const { for (std::size_t i = 0; i < args_split; i++) { // positional args const auto arg_name = prepare_arg_name(i); - parser.add_positional_argument(arg_name.name, arg_name.short_name.value()); + parser.add_positional_argument(arg_name.primary, arg_name.secondary.value()); } for (std::size_t i = args_split; i < num_args; i++) { // optional args const auto arg_name = prepare_arg_name(i); - parser.add_optional_argument(arg_name.name, arg_name.short_name.value()); + parser.add_optional_argument(arg_name.primary, arg_name.secondary.value()); } } @@ -105,7 +105,7 @@ struct argument_parser_test_fixture { } for (std::size_t i = args_split; i < num_args; i++) { // optional args cmd_args.push_back(cmd_argument{ - cmd_argument::type_discriminator::flag, prepare_arg_name(i).name }); + cmd_argument::type_discriminator::flag, prepare_arg_name(i).primary }); cmd_args.push_back(cmd_argument{ cmd_argument::type_discriminator::value, prepare_arg_value(i) }); } diff --git a/test/source/test_argument_name.cpp b/test/source/test_argument_name.cpp index 634a96c..9610acf 100644 --- a/test/source/test_argument_name.cpp +++ b/test/source/test_argument_name.cpp @@ -12,105 +12,182 @@ using namespace ap::argument::detail; namespace { -constexpr std::string_view name = "test"; -constexpr std::string_view short_name = "t"; +constexpr std::string_view primary_name = "test"; +constexpr std::string_view secondary_name = "t"; -constexpr std::string_view other_name = "other"; -constexpr std::string_view other_short_name = "o"; +constexpr std::string_view other_primary_name = "other"; +constexpr std::string_view other_secondary_name = "o"; -argument_name default_argument_name_long_name() { - return argument_name(name); +argument_name default_argument_name_primary() { + return argument_name(primary_name); } -argument_name default_argument_name_both_names() { - return argument_name(name, short_name); +argument_name default_argument_name_primary_and_secondary() { + return argument_name(primary_name, secondary_name); } } // namespace TEST_SUITE_BEGIN("test_argument_name"); -TEST_CASE("argument_name.name member should be correctly " - "initialized") { - const auto arg_name = default_argument_name_long_name(); +TEST_CASE("argument_name.primary member should be correctly initialized") { + const auto arg_name = default_argument_name_primary(); - REQUIRE_EQ(arg_name.name, name); + REQUIRE_EQ(arg_name.primary, primary_name); } -TEST_CASE("argument_name members should be correctly " - "initialized") { - const auto arg_name = default_argument_name_both_names(); +TEST_CASE("argument_name members should be correctly initialized") { + const auto arg_name = default_argument_name_primary_and_secondary(); - REQUIRE_EQ(arg_name.name, name); + REQUIRE_EQ(arg_name.primary, primary_name); - REQUIRE(arg_name.short_name); - REQUIRE_EQ(arg_name.short_name.value(), short_name); + REQUIRE(arg_name.secondary); + REQUIRE_EQ(arg_name.secondary.value(), secondary_name); } -TEST_CASE("argument_name::operator==(argument_name) should " - "return true if " - "long names are equal") { - const auto arg_name_a = default_argument_name_long_name(); - const auto arg_name_b = default_argument_name_both_names(); +TEST_CASE("argument_name::operator==(argument_name) should return false if only one argument has " + "both primary and secondary values") { + const auto arg_name_a = default_argument_name_primary(); + const auto arg_name_b = default_argument_name_primary_and_secondary(); - REQUIRE(arg_name_a == arg_name_b); + REQUIRE_NE(arg_name_a, arg_name_b); + REQUIRE_NE(arg_name_b, arg_name_a); } -TEST_CASE("argument_name::operator==(argument_name) should " - "return false if " - "long names are not equal") { - const auto arg_name_a = default_argument_name_long_name(); - const auto arg_name_b = argument_name(other_name, other_short_name); +TEST_CASE("argument_name::operator==(argument_name) should return false if primary names are not " + "equal") { + const auto arg_name_a = default_argument_name_primary(); + const auto arg_name_b = argument_name{ other_primary_name }; - REQUIRE_FALSE(arg_name_a == arg_name_b); + REQUIRE_NE(arg_name_a, arg_name_b); } -TEST_CASE("argument_name::operator==(string_view) should " - "return true if at " - "least one name matches") { - SUBCASE("argument_name with long name only") { - const auto arg_name = default_argument_name_long_name(); +TEST_CASE("argument_name::operator==(argument_name) should return false if secondary names are not " + "equal") { + const auto arg_name_a = default_argument_name_primary_and_secondary(); + const auto arg_name_b = argument_name{ primary_name, other_primary_name }; - REQUIRE(arg_name == name); + REQUIRE_NE(arg_name_a, arg_name_b); +} + +TEST_CASE("argument_name::operator==(argument_name) should return true if primary names are equal " + "and secondary names are null") { + const auto arg_name_a = default_argument_name_primary(); + const auto arg_name_b = default_argument_name_primary(); + + REQUIRE_EQ(arg_name_a, arg_name_b); +} + +TEST_CASE("argument_name::operator==(argument_name) should return true if both primary and " + "secondary names are equal") { + const auto arg_name_a = default_argument_name_primary_and_secondary(); + const auto arg_name_b = default_argument_name_primary_and_secondary(); + + REQUIRE_EQ(arg_name_a, arg_name_b); +} + +TEST_CASE("argument_name::match(string_view) should return true if the given string matches at " + "least one name") { + SUBCASE("argument_name with primary name only") { + const auto arg_name = default_argument_name_primary(); + + REQUIRE(arg_name.match(primary_name)); } SUBCASE("argument_name with both names") { - const auto arg_name = default_argument_name_both_names(); + const auto arg_name = default_argument_name_primary_and_secondary(); - REQUIRE(arg_name == name); - REQUIRE(arg_name == short_name); + REQUIRE(arg_name.match(primary_name)); + REQUIRE(arg_name.match(secondary_name)); } } -TEST_CASE("argument_name::operator==(string_view) should " - "return false if no " - "name matches") { - SUBCASE("argument_name with long name only") { - const auto arg_name = default_argument_name_long_name(); +TEST_CASE("argument_name::match(string_view) should return false if the given string dosn't match " + "any name") { + SUBCASE("argument_name with primary name only") { + const auto arg_name = default_argument_name_primary(); + + REQUIRE_FALSE(arg_name.match(other_primary_name)); + REQUIRE_FALSE(arg_name.match(other_secondary_name)); + } + + SUBCASE("argument_name with both names") { + const auto arg_name = default_argument_name_primary_and_secondary(); + + REQUIRE_FALSE(arg_name.match(other_primary_name)); + REQUIRE_FALSE(arg_name.match(other_secondary_name)); + } +} - REQUIRE_FALSE(arg_name == other_name); - REQUIRE_FALSE(arg_name == other_short_name); +TEST_CASE("argument_name::match(argument_name) should return true if either the primary or the " + "secondary name " + "of the passed argument_name matches at least one name") { + SUBCASE("argument_name with primary name only") { + const auto arg_name = default_argument_name_primary(); + + SUBCASE("matching primary to primary") { + const auto arg_name_to_match = argument_name{ primary_name }; + REQUIRE(arg_name.match(arg_name_to_match)); + } + + SUBCASE("matching secondary to primary") { + const auto arg_name_to_match = argument_name{ other_primary_name, primary_name }; + REQUIRE(arg_name.match(arg_name_to_match)); + } } SUBCASE("argument_name with both names") { - const auto arg_name = default_argument_name_both_names(); + const auto arg_name = default_argument_name_primary_and_secondary(); + + SUBCASE("matching primary to primary") { + const auto arg_name_to_match = argument_name{ primary_name, other_secondary_name }; + REQUIRE(arg_name.match(arg_name_to_match)); + } + + SUBCASE("matching primary to secondary") { + const auto arg_name_to_match = argument_name{ secondary_name, primary_name }; + REQUIRE(arg_name.match(arg_name_to_match)); + } + + SUBCASE("matching secondary to primary") { + const auto arg_name_to_match = argument_name{ other_primary_name, primary_name }; + REQUIRE(arg_name.match(arg_name_to_match)); + } + + SUBCASE("matching secondary to secondary") { + const auto arg_name_to_match = argument_name{ other_primary_name, secondary_name }; + REQUIRE(arg_name.match(arg_name_to_match)); + } + } +} + +TEST_CASE("argument_name::match(argument_name) should return false if neither the primary nor the " + "secondary name " + "of the passed argument_name matches at least one name") { + const auto arg_name_to_match = argument_name{ other_primary_name, other_secondary_name }; - REQUIRE_FALSE(arg_name == other_name); - REQUIRE_FALSE(arg_name == other_short_name); + SUBCASE("argument_name with primary name only") { + const auto arg_name = default_argument_name_primary(); + REQUIRE_FALSE(arg_name.match(arg_name_to_match)); + } + + SUBCASE("argument_name with both names") { + const auto arg_name = default_argument_name_primary_and_secondary(); + REQUIRE_FALSE(arg_name.match(arg_name_to_match)); } } TEST_CASE("operator<< should push correct data to the output stream") { std::stringstream ss, expected_ss; - SUBCASE("argument_name with long name only") { - ss << default_argument_name_long_name(); - expected_ss << "[" << name << "]"; + SUBCASE("argument_name with primary name only") { + ss << default_argument_name_primary(); + expected_ss << "[" << primary_name << "]"; } SUBCASE("argument_name with both names") { - ss << default_argument_name_both_names(); - expected_ss << "[" << name << "," << short_name << "]"; + ss << default_argument_name_primary_and_secondary(); + expected_ss << "[" << primary_name << "," << secondary_name << "]"; } CAPTURE(ss); diff --git a/test/source/test_argument_parser_add_argument.cpp b/test/source/test_argument_parser_add_argument.cpp index 24c16cc..6fd66ba 100644 --- a/test/source/test_argument_parser_add_argument.cpp +++ b/test/source/test_argument_parser_add_argument.cpp @@ -6,18 +6,16 @@ #include -#include - using namespace ap_testing; using namespace ap::argument; namespace { -constexpr std::string_view name = "test"; -constexpr std::string_view short_name = "t"; +constexpr std::string_view primary_name = "test"; +constexpr std::string_view secondary_name = "t"; -constexpr std::string_view other_name = "other"; -constexpr std::string_view other_short_name = "o"; +constexpr std::string_view other_primary_name = "other"; +constexpr std::string_view other_secondary_name = "o"; } // namespace @@ -28,8 +26,13 @@ TEST_CASE_FIXTURE(argument_parser_test_fixture, "default_positional_arguments sh { ap::default_argument::positional::input, ap::default_argument::positional::output } ); - REQUIRE_FALSE(sut_get_argument("input")->get().is_optional()); - REQUIRE_FALSE(sut_get_argument("output")->get().is_optional()); + const auto input_arg = sut_get_argument("input"); + REQUIRE(input_arg); + REQUIRE_FALSE(input_arg->get().is_optional()); + + const auto output_arg = sut_get_argument("output"); + REQUIRE(output_arg); + REQUIRE_FALSE(output_arg->get().is_optional()); } TEST_CASE_FIXTURE(argument_parser_test_fixture, "default_optional_arguments should add the specified arguments") { @@ -39,18 +42,41 @@ TEST_CASE_FIXTURE(argument_parser_test_fixture, "default_optional_arguments shou ap::default_argument::optional::output } ); - REQUIRE(sut_get_argument("help")->get().is_optional()); - REQUIRE(sut_get_argument("h")->get().is_optional()); + std::string help_flag; + std::string input_flag; + std::string output_flag; + + SUBCASE("using primary flags") { + help_flag = "help"; + input_flag = "input"; + output_flag = "output"; + } + + SUBCASE("using secondary flags") { + help_flag = "h"; + input_flag = "i"; + output_flag = "o"; + } + + CAPTURE(help_flag); + CAPTURE(input_flag); + CAPTURE(output_flag); + + const auto help_arg = sut_get_argument(help_flag); + REQUIRE(help_arg); + REQUIRE(help_arg->get().is_optional()); - REQUIRE(sut_get_argument("input")->get().is_optional()); - REQUIRE(sut_get_argument("i")->get().is_optional()); + const auto input_arg = sut_get_argument(input_flag); + REQUIRE(input_arg); + REQUIRE(input_arg->get().is_optional()); - REQUIRE(sut_get_argument("output")->get().is_optional()); - REQUIRE(sut_get_argument("o")->get().is_optional()); + const auto output_arg = sut_get_argument(output_flag); + REQUIRE(output_arg); + REQUIRE(output_arg->get().is_optional()); } TEST_CASE_FIXTURE(argument_parser_test_fixture, "add_positional_argument should return a positional argument reference") { - const auto& argument = sut.add_positional_argument(name, short_name); + const auto& argument = sut.add_positional_argument(primary_name, secondary_name); REQUIRE_FALSE(argument.is_optional()); } @@ -59,23 +85,27 @@ TEST_CASE_FIXTURE( "add_positional_argument should throw only when adding an" "argument with a previously used name" ) { - sut.add_positional_argument(name, short_name); + sut.add_positional_argument(primary_name, secondary_name); SUBCASE("adding argument with a unique name") { - REQUIRE_NOTHROW(sut.add_positional_argument(other_name, other_short_name)); + REQUIRE_NOTHROW(sut.add_positional_argument(other_primary_name, other_secondary_name)); } - SUBCASE("adding argument with a previously used long name") { - REQUIRE_THROWS_AS(sut.add_positional_argument(name, other_short_name), ap::error::argument_name_used_error); + SUBCASE("adding argument with a previously used primary name") { + REQUIRE_THROWS_AS( + sut.add_positional_argument(primary_name, other_secondary_name), ap::error::argument_name_used_error + ); } - SUBCASE("adding argument with a previously used short name") { - REQUIRE_THROWS_AS(sut.add_positional_argument(other_name, short_name), ap::error::argument_name_used_error); + SUBCASE("adding argument with a previously used secondary name") { + REQUIRE_THROWS_AS( + sut.add_positional_argument(other_primary_name, secondary_name), ap::error::argument_name_used_error + ); } } TEST_CASE_FIXTURE(argument_parser_test_fixture, "add_optional_argument should return an optional argument reference") { - const auto& argument = sut.add_optional_argument(name, short_name); + const auto& argument = sut.add_optional_argument(primary_name, secondary_name); REQUIRE(argument.is_optional()); } @@ -84,18 +114,22 @@ TEST_CASE_FIXTURE( "add_optional_argument should throw only when adding an" "argument with a previously used name" ) { - sut.add_optional_argument(name, short_name); + sut.add_optional_argument(primary_name, secondary_name); SUBCASE("adding argument with a unique name") { - REQUIRE_NOTHROW(sut.add_optional_argument(other_name, other_short_name)); + REQUIRE_NOTHROW(sut.add_optional_argument(other_primary_name, other_secondary_name)); } - SUBCASE("adding argument with a previously used long name") { - REQUIRE_THROWS_AS(sut.add_optional_argument(name, other_short_name), ap::error::argument_name_used_error); + SUBCASE("adding argument with a previously used primary name") { + REQUIRE_THROWS_AS( + sut.add_optional_argument(primary_name, other_secondary_name), ap::error::argument_name_used_error + ); } - SUBCASE("adding argument with a previously used short name") { - REQUIRE_THROWS_AS(sut.add_optional_argument(other_name, short_name), ap::error::argument_name_used_error); + SUBCASE("adding argument with a previously used secondary name") { + REQUIRE_THROWS_AS( + sut.add_optional_argument(other_primary_name, secondary_name), ap::error::argument_name_used_error + ); } } @@ -103,39 +137,39 @@ TEST_CASE_FIXTURE(argument_parser_test_fixture, "add_flag should return an optio const optional_argument_test_fixture opt_arg_fixture; SUBCASE("StoreImplicitly = true") { - auto& argument = sut.add_flag(name, short_name); + auto& argument = sut.add_flag(primary_name, secondary_name); REQUIRE(argument.is_optional()); - REQUIRE_FALSE(sut.value(name)); + REQUIRE_FALSE(sut.value(primary_name)); opt_arg_fixture.sut_set_used(argument); - REQUIRE(sut.value(name)); + REQUIRE(sut.value(primary_name)); } SUBCASE("StoreImplicitly = false") { - auto& argument = sut.add_flag(name, short_name); + auto& argument = sut.add_flag(primary_name, secondary_name); REQUIRE(argument.is_optional()); - REQUIRE(sut.value(name)); + REQUIRE(sut.value(primary_name)); opt_arg_fixture.sut_set_used(argument); - REQUIRE_FALSE(sut.value(name)); + REQUIRE_FALSE(sut.value(primary_name)); } } TEST_CASE_FIXTURE(argument_parser_test_fixture, "add_flag should throw only when adding and argument with a previously used name") { - sut.add_flag(name, short_name); + sut.add_flag(primary_name, secondary_name); SUBCASE("adding argument with a unique name") { - REQUIRE_NOTHROW(sut.add_flag(other_name, other_short_name)); + REQUIRE_NOTHROW(sut.add_flag(other_primary_name, other_secondary_name)); } - SUBCASE("adding argument with a previously used long name") { - REQUIRE_THROWS_AS(sut.add_flag(name, other_short_name), ap::error::argument_name_used_error); + SUBCASE("adding argument with a previously used primary name") { + REQUIRE_THROWS_AS(sut.add_flag(primary_name, other_secondary_name), ap::error::argument_name_used_error); } - SUBCASE("adding argument with a previously used short name") { - REQUIRE_THROWS_AS(sut.add_flag(other_name, short_name), ap::error::argument_name_used_error); + SUBCASE("adding argument with a previously used secondary name") { + REQUIRE_THROWS_AS(sut.add_flag(other_primary_name, secondary_name), ap::error::argument_name_used_error); } } diff --git a/test/source/test_argument_parser_parse_args.cpp b/test/source/test_argument_parser_parse_args.cpp index a435e64..6e273f0 100644 --- a/test/source/test_argument_parser_parse_args.cpp +++ b/test/source/test_argument_parser_parse_args.cpp @@ -19,16 +19,16 @@ constexpr std::size_t non_default_args_split = non_default_num_args / 2; const std::string invalid_arg_name = "invalid_arg"; -const std::string positional_arg_name = "positional_arg"; -const std::string positional_arg_short_name = "pa"; -const std::string optional_arg_name = "optional_arg"; -const std::string optional_arg_short_name = "oa"; +const std::string positional_primary_name = "positional_arg"; +const std::string positional_secondary_name = "pa"; +const std::string optional_primary_name = "optional_arg"; +const std::string optional_secondary_name = "oa"; } // namespace TEST_SUITE_BEGIN("test_argument_parser_parse_args"); -TEST_SUITE_BEGIN("test_argument_parser_parse_args::_preprocess_input"); +// _preprocess_input TEST_CASE_FIXTURE(argument_parser_test_fixture, "_preprocess_input should return an empty vector for no command-line arguments") { const auto argc = get_argc(default_num_args, default_num_args); @@ -59,7 +59,7 @@ TEST_CASE_FIXTURE(argument_parser_test_fixture, "_preprocess_input should return std::size_t opt_arg_idx = non_default_args_split; for (std::size_t i = non_default_args_split; i < cmd_args.size(); i += 2) { // optional args REQUIRE_EQ(cmd_args.at(i).discriminator, cmd_argument::type_discriminator::flag); - REQUIRE_EQ(cmd_args.at(i).value, prepare_arg_name(opt_arg_idx)); + REQUIRE(prepare_arg_name(opt_arg_idx).match(cmd_args.at(i).value)); REQUIRE_EQ(cmd_args.at(i + 1).discriminator, cmd_argument::type_discriminator::value); REQUIRE_EQ(cmd_args.at(i + 1).value, prepare_arg_value(opt_arg_idx)); opt_arg_idx++; @@ -68,10 +68,7 @@ TEST_CASE_FIXTURE(argument_parser_test_fixture, "_preprocess_input should return free_argv(argc, argv); } -TEST_SUITE_END(); // test_argument_parser_parse_args::_preprocess_input - - -TEST_SUITE_BEGIN("test_argument_parser_parse_args::_parse_args_impl"); +// _parse_args_impl TEST_CASE_FIXTURE( argument_parser_test_fixture, @@ -94,10 +91,7 @@ TEST_CASE_FIXTURE(argument_parser_test_fixture, "_parse_args_impl should not thr REQUIRE_NOTHROW(sut_parse_args_impl(cmd_args)); } -TEST_SUITE_END(); // test_argument_parser_parse_args::_parse_args_impl - - -TEST_SUITE_BEGIN("test_argument_parser_parse_args::_get_argument"); +// _get_argument TEST_CASE_FIXTURE( argument_parser_test_fixture, @@ -118,18 +112,18 @@ TEST_CASE_FIXTURE( for (std::size_t i = 0; i < non_default_num_args; i++) { const auto arg_name = prepare_arg_name(i); - REQUIRE(sut_get_argument(arg_name.name)); - REQUIRE(sut_get_argument(arg_name.short_name.value())); + REQUIRE(sut_get_argument(arg_name.primary)); + REQUIRE(sut_get_argument(arg_name.secondary.value())); } } -TEST_SUITE_END(); // test_argument_parser_parse_args::_get_argument +// parse_args TEST_CASE_FIXTURE(argument_parser_test_fixture, "parse_args should throw when there is no value specified for a required optional argument") { add_arguments(sut, non_default_num_args, non_default_args_split); const auto required_arg_name = prepare_arg_name(non_default_num_args); - sut.add_optional_argument(required_arg_name.name, required_arg_name.short_name.value()).required(); + sut.add_optional_argument(required_arg_name.primary, required_arg_name.secondary.value()).required(); const auto argc = get_argc(non_default_num_args, non_default_args_split); auto argv = prepare_argv(non_default_num_args, non_default_args_split); @@ -146,7 +140,7 @@ TEST_CASE_FIXTURE(argument_parser_test_fixture, "parse_args should throw when an auto argv = prepare_argv(non_default_num_args, non_default_args_split); const auto range_arg_name = prepare_arg_name(non_default_num_args); - sut.add_optional_argument(range_arg_name.name, range_arg_name.short_name.value()).nargs(at_least(1)); + sut.add_optional_argument(range_arg_name.primary, range_arg_name.secondary.value()).nargs(at_least(1)); REQUIRE_THROWS_AS(sut.parse_args(argc, argv), ap::error::invalid_nvalues_error); @@ -161,7 +155,7 @@ TEST_CASE_FIXTURE( add_arguments(sut, non_default_num_args, non_default_args_split); const auto required_arg_name = prepare_arg_name(non_default_num_args); - sut.add_optional_argument(required_arg_name.name, required_arg_name.short_name.value()).required(); + sut.add_optional_argument(required_arg_name.primary, required_arg_name.secondary.value()).required(); int argc; char** argv; @@ -177,7 +171,7 @@ TEST_CASE_FIXTURE( argv = prepare_argv(correct_num_args, non_default_args_split); const auto arg_i = non_default_num_args; - std::strcpy(argv[argc - 2], prepare_arg_flag(arg_i).c_str()); + std::strcpy(argv[argc - 2], prepare_arg_flag_primary(arg_i).c_str()); std::strcpy(argv[argc - 1], prepare_arg_value(arg_i).c_str()); } @@ -198,7 +192,7 @@ TEST_CASE_FIXTURE( const auto bypass_required_arg_name = prepare_arg_name(non_default_num_args); sut.add_optional_argument( - bypass_required_arg_name.name, bypass_required_arg_name.short_name.value() + bypass_required_arg_name.primary, bypass_required_arg_name.secondary.value() ) .default_value(false) .implicit_value(true) @@ -213,11 +207,11 @@ TEST_CASE_FIXTURE( std::string arg_flag; - SUBCASE("long flag") { - arg_flag = prepare_arg_flag(non_default_num_args); + SUBCASE("primary flag") { + arg_flag = prepare_arg_flag_primary(non_default_num_args); } - SUBCASE("short flag") { - arg_flag = prepare_arg_flag_short(non_default_num_args); + SUBCASE("secondary flag") { + arg_flag = prepare_arg_flag_secondary(non_default_num_args); } CAPTURE(arg_flag); @@ -226,12 +220,12 @@ TEST_CASE_FIXTURE( std::strcpy(argv[1], arg_flag.c_str()); REQUIRE_NOTHROW(sut.parse_args(argc, argv)); - REQUIRE(sut.value(bypass_required_arg_name.name)); + REQUIRE(sut.value(bypass_required_arg_name.primary)); free_argv(argc, argv); } -TEST_SUITE_BEGIN("test_argument_parser_parse_args::has_value"); +// has_value TEST_CASE_FIXTURE(argument_parser_test_fixture, "has_value should return false if there is no argument with given name present") { add_arguments(sut, non_default_num_args, non_default_args_split); @@ -250,7 +244,7 @@ TEST_CASE_FIXTURE(argument_parser_test_fixture, "has_value should return false w const auto required_arg_name = prepare_arg_name(non_default_num_args); - sut.add_optional_argument(required_arg_name.name, required_arg_name.short_name.value()).required(); + sut.add_optional_argument(required_arg_name.primary, required_arg_name.secondary.value()).required(); const auto num_args = non_default_num_args + 1; @@ -266,8 +260,8 @@ TEST_CASE_FIXTURE(argument_parser_test_fixture, "has_value should return false w for (std::size_t i = 0; i < non_default_num_args; i++) { const auto arg_name = prepare_arg_name(i); - REQUIRE(sut.has_value(arg_name.name)); - REQUIRE(sut.has_value(arg_name.short_name.value())); + REQUIRE(sut.has_value(arg_name.primary)); + REQUIRE(sut.has_value(arg_name.secondary.value())); } } SUBCASE("only the necessary arguments have values") { @@ -276,25 +270,25 @@ TEST_CASE_FIXTURE(argument_parser_test_fixture, "has_value should return false w argv = prepare_argv(num_args_passed_as_input, non_default_args_split); const auto arg_i = non_default_num_args; - std::strcpy(argv[argc - 2], prepare_arg_flag(arg_i).c_str()); + std::strcpy(argv[argc - 2], prepare_arg_flag_primary(arg_i).c_str()); std::strcpy(argv[argc - 1], prepare_arg_value(arg_i).c_str()); REQUIRE_NOTHROW(sut.parse_args(argc, argv)); for (std::size_t i = 0; i < non_default_args_split; i++) { const auto arg_name = prepare_arg_name(i); - REQUIRE(sut.has_value(arg_name.name)); - REQUIRE(sut.has_value(arg_name.short_name.value())); + REQUIRE(sut.has_value(arg_name.primary)); + REQUIRE(sut.has_value(arg_name.secondary.value())); } for (std::size_t i = non_default_args_split; i < non_default_num_args; i++) { const auto arg_name = prepare_arg_name(i); - REQUIRE_FALSE(sut.has_value(arg_name.name)); - REQUIRE_FALSE(sut.has_value(arg_name.short_name.value())); + REQUIRE_FALSE(sut.has_value(arg_name.primary)); + REQUIRE_FALSE(sut.has_value(arg_name.secondary.value())); } for (std::size_t i = non_default_num_args; i < num_args; i++) { const auto arg_name = prepare_arg_name(i); - REQUIRE(sut.has_value(arg_name.name)); - REQUIRE(sut.has_value(arg_name.short_name.value())); + REQUIRE(sut.has_value(arg_name.primary)); + REQUIRE(sut.has_value(arg_name.secondary.value())); } } @@ -304,10 +298,7 @@ TEST_CASE_FIXTURE(argument_parser_test_fixture, "has_value should return false w free_argv(argc, argv); } -TEST_SUITE_END(); // test_argument_parser_parse_args::has_value - - -TEST_SUITE_BEGIN("test_argument_parser_parse_args::value"); +// value TEST_CASE_FIXTURE(argument_parser_test_fixture, "value() should throw if there is no argument with given name present") { add_arguments(sut, non_default_num_args, non_default_args_split); @@ -327,8 +318,8 @@ TEST_CASE_FIXTURE(argument_parser_test_fixture, "value() should throw before cal for (std::size_t i = 0; i < non_default_num_args; i++) { const auto arg_name = prepare_arg_name(i); - REQUIRE_THROWS_AS(sut.value(arg_name.name), ap::error::invalid_value_type_error); - REQUIRE_THROWS_AS(sut.value(arg_name.short_name.value()), ap::error::invalid_value_type_error); + REQUIRE_THROWS_AS(sut.value(arg_name.primary), ap::error::invalid_value_type_error); + REQUIRE_THROWS_AS(sut.value(arg_name.secondary.value()), ap::error::invalid_value_type_error); } } @@ -337,7 +328,7 @@ TEST_CASE_FIXTURE(argument_parser_test_fixture, "value() should throw if the giv const auto required_arg_name = prepare_arg_name(non_default_num_args); - sut.add_optional_argument(required_arg_name.name, required_arg_name.short_name.value()).required(); + sut.add_optional_argument(required_arg_name.primary, required_arg_name.secondary.value()).required(); const auto num_args = non_default_num_args + 1; @@ -346,25 +337,25 @@ TEST_CASE_FIXTURE(argument_parser_test_fixture, "value() should throw if the giv auto argv = prepare_argv(num_args_passed_as_input, non_default_args_split); const auto arg_i = non_default_num_args; - std::strcpy(argv[argc - 2], prepare_arg_flag(arg_i).c_str()); + std::strcpy(argv[argc - 2], prepare_arg_flag_primary(arg_i).c_str()); std::strcpy(argv[argc - 1], prepare_arg_value(arg_i).c_str()); REQUIRE_NOTHROW(sut.parse_args(argc, argv)); for (std::size_t i = 0; i < non_default_args_split; i++) { const auto arg_name = prepare_arg_name(i); - REQUIRE_NOTHROW(sut.value(arg_name.name)); - REQUIRE_NOTHROW(sut.value(arg_name.short_name.value())); + REQUIRE_NOTHROW(sut.value(arg_name.primary)); + REQUIRE_NOTHROW(sut.value(arg_name.secondary.value())); } for (std::size_t i = non_default_args_split; i < non_default_num_args; i++) { const auto arg_name = prepare_arg_name(i); - REQUIRE_THROWS_AS(sut.value(arg_name.name), ap::error::invalid_value_type_error); - REQUIRE_THROWS_AS(sut.value(arg_name.short_name.value()), ap::error::invalid_value_type_error); + REQUIRE_THROWS_AS(sut.value(arg_name.primary), ap::error::invalid_value_type_error); + REQUIRE_THROWS_AS(sut.value(arg_name.secondary.value()), ap::error::invalid_value_type_error); } for (std::size_t i = non_default_num_args; i < num_args; i++) { const auto arg_name = prepare_arg_name(i); - REQUIRE_NOTHROW(sut.value(arg_name.name)); - REQUIRE_NOTHROW(sut.value(arg_name.short_name.value())); + REQUIRE_NOTHROW(sut.value(arg_name.primary)); + REQUIRE_NOTHROW(sut.value(arg_name.secondary.value())); } free_argv(argc, argv); @@ -385,8 +376,8 @@ TEST_CASE_FIXTURE(argument_parser_test_fixture, "value() should throw if an argu for (std::size_t i = 0; i < non_default_num_args; i++) { const auto arg_name = prepare_arg_name(i); - REQUIRE(sut.has_value(arg_name.name)); - REQUIRE_THROWS_AS(sut.value(arg_name.name), ap::error::invalid_value_type_error); + REQUIRE(sut.has_value(arg_name.primary)); + REQUIRE_THROWS_AS(sut.value(arg_name.primary), ap::error::invalid_value_type_error); } free_argv(argc, argv); @@ -401,7 +392,7 @@ TEST_CASE_FIXTURE( const auto required_arg_name = prepare_arg_name(non_default_num_args); - sut.add_optional_argument(required_arg_name.name, required_arg_name.short_name.value()).required(); + sut.add_optional_argument(required_arg_name.primary, required_arg_name.secondary.value()).required(); const auto num_args = non_default_num_args + 1; @@ -414,26 +405,23 @@ TEST_CASE_FIXTURE( const auto arg_name = prepare_arg_name(i); const auto arg_value = prepare_arg_value(i); - REQUIRE(sut.has_value(arg_name.name)); - REQUIRE_EQ(sut.value(arg_name.name), arg_value); - REQUIRE_EQ(sut.value(arg_name.short_name.value()), arg_value); + REQUIRE(sut.has_value(arg_name.primary)); + REQUIRE_EQ(sut.value(arg_name.primary), arg_value); + REQUIRE_EQ(sut.value(arg_name.secondary.value()), arg_value); } free_argv(argc, argv); } -TEST_SUITE_END(); // test_argument_parser_parse_args::value - - -TEST_SUITE_BEGIN("test_argument_parser_parse_args::count"); +// count TEST_CASE_FIXTURE(argument_parser_test_fixture, "count should return 0 before calling parse_args") { add_arguments(sut, non_default_num_args, non_default_args_split); for (std::size_t i = 0; i < non_default_num_args; i++) { const auto arg_name = prepare_arg_name(i); - REQUIRE_EQ(sut.count(arg_name.name), 0u); - REQUIRE_EQ(sut.count(arg_name.short_name.value()), 0u); + REQUIRE_EQ(sut.count(arg_name.primary), 0u); + REQUIRE_EQ(sut.count(arg_name.secondary.value()), 0u); } } @@ -451,8 +439,8 @@ TEST_CASE_FIXTURE(argument_parser_test_fixture, "count should return 0 if there TEST_CASE_FIXTURE(argument_parser_test_fixture, "count should return the number of argument's flag usage") { // prepare sut - sut.add_positional_argument(positional_arg_name, positional_arg_short_name); - sut.add_optional_argument(optional_arg_name, optional_arg_short_name).nargs(ap::nargs::any()); + sut.add_positional_argument(positional_primary_name, positional_secondary_name); + sut.add_optional_argument(optional_primary_name, optional_secondary_name).nargs(ap::nargs::any()); // expected values const std::size_t positional_count = 1u; @@ -469,8 +457,8 @@ TEST_CASE_FIXTURE(argument_parser_test_fixture, "count should return the number argv[1] = new char[positional_arg_value.length() + 1]; std::strcpy(argv[1], positional_arg_value.c_str()); - const std::string optional_arg_flag = "--" + optional_arg_name; - const std::string optional_arg_value = optional_arg_name + "_value"; + const std::string optional_arg_flag = "--" + optional_primary_name; + const std::string optional_arg_value = optional_primary_name + "_value"; for (std::size_t i = 2; i < argc; i += 2) { if (i == argc - 1) { argv[i] = new char[optional_arg_value.length() + 1]; @@ -489,41 +477,38 @@ TEST_CASE_FIXTURE(argument_parser_test_fixture, "count should return the number sut.parse_args(argc, argv); // test count - REQUIRE_EQ(sut.count(positional_arg_name), positional_count); - REQUIRE_EQ(sut.count(optional_arg_name), optional_count); + REQUIRE_EQ(sut.count(positional_primary_name), positional_count); + REQUIRE_EQ(sut.count(optional_primary_name), optional_count); // free argv free_argv(argc, argv); } -TEST_SUITE_END(); // test_argument_parser_parse_args::count - - -TEST_SUITE_BEGIN("test_argument_parser_parse_args::values"); +// values TEST_CASE_FIXTURE(argument_parser_test_fixture, "values() should throw when calling with a positional argument's name") { - sut.add_positional_argument(positional_arg_name, positional_arg_short_name); + sut.add_positional_argument(positional_primary_name, positional_secondary_name); - REQUIRE_THROWS_AS(sut.values(positional_arg_name), std::logic_error); - REQUIRE_THROWS_AS(sut.values(positional_arg_short_name), std::logic_error); + REQUIRE_THROWS_AS(sut.values(positional_primary_name), std::logic_error); + REQUIRE_THROWS_AS(sut.values(positional_secondary_name), std::logic_error); } TEST_CASE_FIXTURE(argument_parser_test_fixture, "values() should return an empty vector if an argument has no values") { - sut.add_optional_argument(optional_arg_name, optional_arg_short_name); + sut.add_optional_argument(optional_primary_name, optional_secondary_name); - SUBCASE("calling with argument's long name") { - const auto& values = sut.values(optional_arg_name); + SUBCASE("calling with argument's primary name") { + const auto& values = sut.values(optional_primary_name); REQUIRE(values.empty()); } - SUBCASE("calling with argument's short name") { - const auto& values = sut.values(optional_arg_short_name); + SUBCASE("calling with argument's secondary name") { + const auto& values = sut.values(optional_secondary_name); REQUIRE(values.empty()); } } TEST_CASE_FIXTURE(argument_parser_test_fixture, "values() should throw when an argument has values but the given type is invalid") { - sut.add_optional_argument(optional_arg_name, optional_arg_short_name).nargs(at_least(1)); + sut.add_optional_argument(optional_primary_name, optional_secondary_name).nargs(at_least(1)); // prepare argc & argv const int argc = 5; @@ -532,7 +517,7 @@ TEST_CASE_FIXTURE(argument_parser_test_fixture, "values() should throw when an a argv[0] = new char[8]; std::strcpy(argv[0], "program"); - const std::string flag = "--" + optional_arg_name; + const std::string flag = "--" + optional_primary_name; argv[1] = new char[flag.length() + 1]; std::strcpy(argv[1], flag.c_str()); for (int i = 2; i < argc; i++) { @@ -544,9 +529,9 @@ TEST_CASE_FIXTURE(argument_parser_test_fixture, "values() should throw when an a // parse args sut.parse_args(argc, argv); - REQUIRE_THROWS_AS(sut.values(optional_arg_name), ap::error::invalid_value_type_error); + REQUIRE_THROWS_AS(sut.values(optional_primary_name), ap::error::invalid_value_type_error); REQUIRE_THROWS_AS( - sut.values(optional_arg_short_name), ap::error::invalid_value_type_error + sut.values(optional_secondary_name), ap::error::invalid_value_type_error ); free_argv(argc, argv); @@ -560,7 +545,7 @@ TEST_CASE_FIXTURE( const std::string default_value = "default_value"; const std::string implicit_value = "implicit_value"; - sut.add_optional_argument(optional_arg_name, optional_arg_short_name) + sut.add_optional_argument(optional_primary_name, optional_secondary_name) .default_value(default_value) .implicit_value(implicit_value); @@ -579,7 +564,7 @@ TEST_CASE_FIXTURE( argc = 2; argv = new char*[argc]; - const auto optional_arg_flag = "--" + optional_arg_name; + const auto optional_arg_flag = "--" + optional_primary_name; argv[1] = new char[optional_arg_flag.length() + 1]; std::strcpy(argv[1], optional_arg_flag.c_str()); expected_value = implicit_value; @@ -595,7 +580,7 @@ TEST_CASE_FIXTURE( // parse args sut.parse_args(argc, argv); - const auto& stored_values = sut.values(optional_arg_name); + const auto& stored_values = sut.values(optional_primary_name); REQUIRE_EQ(stored_values.size(), 1); REQUIRE_EQ(stored_values.front(), expected_value); @@ -608,7 +593,7 @@ TEST_CASE_FIXTURE( "values() should return a correct vector of values when there is an argument with " "a given name and parsed values present" ) { - sut.add_optional_argument(optional_arg_name, optional_arg_short_name).nargs(at_least(1)); + sut.add_optional_argument(optional_primary_name, optional_secondary_name).nargs(at_least(1)); // prepare argc & argv const int argc = 5; @@ -617,7 +602,7 @@ TEST_CASE_FIXTURE( argv[0] = new char[8]; std::strcpy(argv[0], "program"); - const std::string flag = "--" + optional_arg_name; + const std::string flag = "--" + optional_primary_name; argv[1] = new char[flag.length() + 1]; std::strcpy(argv[1], flag.c_str()); @@ -633,7 +618,7 @@ TEST_CASE_FIXTURE( // parse args sut.parse_args(argc, argv); - const auto& stored_values = sut.values(optional_arg_name); + const auto& stored_values = sut.values(optional_primary_name); REQUIRE_EQ(stored_values.size(), values.size()); for (std::size_t i = 0; i < stored_values.size(); i++) @@ -642,6 +627,4 @@ TEST_CASE_FIXTURE( free_argv(argc, argv); } -TEST_SUITE_END(); // test_argument_parser_parse_args::values - TEST_SUITE_END(); // test_argument_parser_parse_args diff --git a/test/source/test_optional_argument.cpp b/test/source/test_optional_argument.cpp index dbca2f8..792d3fe 100644 --- a/test/source/test_optional_argument.cpp +++ b/test/source/test_optional_argument.cpp @@ -12,22 +12,23 @@ using namespace ap_testing; using namespace ap::nargs; using ap::argument::optional_argument; +using ap::argument::detail::argument_name; namespace { -constexpr std::string_view long_name = "test"; -constexpr std::string_view short_name = "t"; +constexpr std::string_view primary_name = "test"; +constexpr std::string_view secondary_name = "t"; using test_value_type = int; using invalid_value_type = double; using sut_type = optional_argument; -sut_type prepare_argument(std::string_view name) { - return sut_type(name); +sut_type prepare_argument(std::string_view primary_name) { + return sut_type(argument_name{ primary_name }); } -sut_type prepare_argument(std::string_view name, std::string_view long_name) { - return sut_type(name, long_name); +sut_type prepare_argument(std::string_view primary_name, std::string_view secondary_name) { + return sut_type(argument_name{ primary_name, secondary_name }); } const std::string empty_str = ""; @@ -48,41 +49,39 @@ const range non_default_range = range(1u, default_choices.size()); TEST_SUITE_BEGIN("test_optional_argument"); TEST_CASE_FIXTURE(optional_argument_test_fixture, "is_optional() should return true") { - const auto sut = prepare_argument(long_name); + const auto sut = prepare_argument(primary_name); REQUIRE(sut.is_optional()); } -TEST_CASE_FIXTURE(optional_argument_test_fixture, "name() should return value passed to the optional argument constructor for long name") { - const auto sut = prepare_argument(long_name); - +TEST_CASE_FIXTURE(optional_argument_test_fixture, "name() should return value passed to the optional argument constructor for primary name") { + const auto sut = prepare_argument(primary_name); const auto name = sut_get_name(sut); - REQUIRE_EQ(name, long_name); - REQUIRE_NE(name, short_name); + REQUIRE(name.match(primary_name)); + REQUIRE_FALSE(name.match(secondary_name)); } TEST_CASE_FIXTURE( optional_argument_test_fixture, - "name() and short_name() should return value passed to the optional" - "argument constructor for both long and short names" + "name() and secondary_name() should return value passed to the optional" + "argument constructor for both primary and secondary names" ) { - const auto sut = prepare_argument(long_name, short_name); - + const auto sut = prepare_argument(primary_name, secondary_name); const auto name = sut_get_name(sut); - REQUIRE_EQ(name, long_name); - REQUIRE_EQ(name, short_name); + REQUIRE(name.match(primary_name)); + REQUIRE(name.match(secondary_name)); } TEST_CASE_FIXTURE(optional_argument_test_fixture, "help() should return nullopt by default") { - const auto sut = prepare_argument(long_name); + const auto sut = prepare_argument(primary_name); REQUIRE_FALSE(sut_get_help(sut)); } TEST_CASE_FIXTURE(optional_argument_test_fixture, "help() should return message if one has been provided") { - auto sut = prepare_argument(long_name); + auto sut = prepare_argument(primary_name); constexpr std::string_view help_msg = "test help msg"; sut.help(help_msg); @@ -94,13 +93,13 @@ TEST_CASE_FIXTURE(optional_argument_test_fixture, "help() should return message } TEST_CASE_FIXTURE(optional_argument_test_fixture, "is_required() should return false by default") { - auto sut = prepare_argument(long_name); + auto sut = prepare_argument(primary_name); REQUIRE_FALSE(sut_is_required(sut)); } TEST_CASE_FIXTURE(optional_argument_test_fixture, "is_required() should return true is argument is set to be required") { - auto sut = prepare_argument(long_name); + auto sut = prepare_argument(primary_name); sut.required(); @@ -108,20 +107,20 @@ TEST_CASE_FIXTURE(optional_argument_test_fixture, "is_required() should return t } TEST_CASE_FIXTURE(optional_argument_test_fixture, "is_used() should return false by default") { - const auto sut = prepare_argument(long_name); + const auto sut = prepare_argument(primary_name); REQUIRE_FALSE(sut_is_used(sut)); } TEST_CASE_FIXTURE(optional_argument_test_fixture, "is_used() should return true when argument contains value") { - auto sut = prepare_argument(long_name); + auto sut = prepare_argument(primary_name); sut_set_value(sut, std::to_string(value_1)); REQUIRE(sut_is_used(sut)); } TEST_CASE_FIXTURE(optional_argument_test_fixture, "nused() should return 0 by default") { - const auto sut = prepare_argument(long_name); + const auto sut = prepare_argument(primary_name); REQUIRE_EQ(sut_get_nused(sut), 0u); } @@ -131,7 +130,7 @@ TEST_CASE_FIXTURE( "is_used() should return the number of times the argument's flag has been used " "[number of set_used() function calls]" ) { - auto sut = prepare_argument(long_name); + auto sut = prepare_argument(primary_name); constexpr std::size_t nused = 5u; for (std::size_t n = 0; n < nused; n++) @@ -141,13 +140,13 @@ TEST_CASE_FIXTURE( } TEST_CASE_FIXTURE(optional_argument_test_fixture, "has_value() should return false by default") { - const auto sut = prepare_argument(long_name); + const auto sut = prepare_argument(primary_name); REQUIRE_FALSE(sut_has_value(sut)); } TEST_CASE_FIXTURE(optional_argument_test_fixture, "has_value() should return true if value is set") { - auto sut = prepare_argument(long_name); + auto sut = prepare_argument(primary_name); sut_set_value(sut, std::to_string(value_1)); @@ -155,7 +154,7 @@ TEST_CASE_FIXTURE(optional_argument_test_fixture, "has_value() should return tru } TEST_CASE_FIXTURE(optional_argument_test_fixture, "has_value() should return true if a default value is set") { - auto sut = prepare_argument(long_name); + auto sut = prepare_argument(primary_name); sut.default_value(default_value); REQUIRE(sut_has_value(sut)); @@ -163,14 +162,14 @@ TEST_CASE_FIXTURE(optional_argument_test_fixture, "has_value() should return tru } TEST_CASE_FIXTURE(optional_argument_test_fixture, "has_value() should return false if an implicit value is set but the argument is not used") { - auto sut = prepare_argument(long_name); + auto sut = prepare_argument(primary_name); sut.implicit_value(implicit_value); REQUIRE_FALSE(sut_has_value(sut)); } TEST_CASE_FIXTURE(optional_argument_test_fixture, "has_value() should return true if an implicit value is set and the agument is used") { - auto sut = prepare_argument(long_name); + auto sut = prepare_argument(primary_name); sut.implicit_value(implicit_value); sut_set_used(sut); @@ -180,7 +179,7 @@ TEST_CASE_FIXTURE(optional_argument_test_fixture, "has_value() should return tru } TEST_CASE_FIXTURE(optional_argument_test_fixture, "has_parsed_values() should return false by default") { - const auto sut = prepare_argument(long_name); + const auto sut = prepare_argument(primary_name); REQUIRE_FALSE(sut_has_parsed_values(sut)); } @@ -190,7 +189,7 @@ TEST_CASE_FIXTURE( "has_parsed_values() should return false regardles of the " "default_value and implicit_value parameters" ) { - auto sut = prepare_argument(long_name); + auto sut = prepare_argument(primary_name); SUBCASE("default_value") { sut.default_value(default_value); @@ -210,7 +209,7 @@ TEST_CASE_FIXTURE( } TEST_CASE_FIXTURE(optional_argument_test_fixture, "has_parsed_values() should true if the value is set") { - auto sut = prepare_argument(long_name); + auto sut = prepare_argument(primary_name); sut_set_value(sut, std::to_string(value_1)); @@ -218,13 +217,13 @@ TEST_CASE_FIXTURE(optional_argument_test_fixture, "has_parsed_values() should tr } TEST_CASE_FIXTURE(optional_argument_test_fixture, "value() should return default any object if argument's value has not been set") { - auto sut = prepare_argument(long_name); + auto sut = prepare_argument(primary_name); REQUIRE_FALSE(sut_get_value(sut).has_value()); } TEST_CASE_FIXTURE(optional_argument_test_fixture, "value() should return the argument's value if it has been set") { - auto sut = prepare_argument(long_name); + auto sut = prepare_argument(primary_name); sut_set_value(sut, std::to_string(value_1)); @@ -233,7 +232,7 @@ TEST_CASE_FIXTURE(optional_argument_test_fixture, "value() should return the arg } TEST_CASE_FIXTURE(optional_argument_test_fixture, "value() should return the default value if one has been provided and argument is not used") { - auto sut = prepare_argument(long_name); + auto sut = prepare_argument(primary_name); sut.default_value(value_1); REQUIRE(sut_has_value(sut)); @@ -241,7 +240,7 @@ TEST_CASE_FIXTURE(optional_argument_test_fixture, "value() should return the def } TEST_CASE_FIXTURE(optional_argument_test_fixture, "value() should return the implicit value if one has been provided and argument is used") { - auto sut = prepare_argument(long_name); + auto sut = prepare_argument(primary_name); sut.implicit_value(implicit_value); sut_set_used(sut); @@ -251,7 +250,7 @@ TEST_CASE_FIXTURE(optional_argument_test_fixture, "value() should return the imp } TEST_CASE_FIXTURE(optional_argument_test_fixture, "set_value(any) should throw when value_type cannot be obtained from given string") { - auto sut = prepare_argument(long_name); + auto sut = prepare_argument(primary_name); SUBCASE("given string is empty") { REQUIRE_THROWS_AS(sut_set_value(sut, empty_str), ap::error::invalid_value_error); @@ -268,7 +267,7 @@ TEST_CASE_FIXTURE(optional_argument_test_fixture, "set_value(any) should throw w TEST_CASE_FIXTURE( optional_argument_test_fixture, "set_value(any) should throw when parameter passed to value() is not present in the choices set" ) { - auto sut = prepare_argument(long_name); + auto sut = prepare_argument(primary_name); sut_set_choices(sut, default_choices); @@ -278,7 +277,7 @@ TEST_CASE_FIXTURE( } TEST_CASE_FIXTURE(optional_argument_test_fixture, "set_value(any) should accept the given value when it's present in the choices set") { - auto sut = prepare_argument(long_name); + auto sut = prepare_argument(primary_name); sut_set_choices(sut, default_choices); const std::vector correct_values = default_choices; @@ -298,7 +297,7 @@ TEST_CASE_FIXTURE(optional_argument_test_fixture, "set_value(any) should accept } TEST_CASE_FIXTURE(optional_argument_test_fixture, "set_value(any) should throw when a value has already been set when nargs is default") { - auto sut = prepare_argument(long_name); + auto sut = prepare_argument(primary_name); REQUIRE_NOTHROW(sut_set_value(sut, std::to_string(value_1))); REQUIRE(sut_has_value(sut)); @@ -307,7 +306,7 @@ TEST_CASE_FIXTURE(optional_argument_test_fixture, "set_value(any) should throw w } TEST_CASE_FIXTURE(optional_argument_test_fixture, "set_value(any) should accept multiple values if nargs is not detault") { - auto sut = prepare_argument(long_name); + auto sut = prepare_argument(primary_name); sut.nargs(non_default_range); for (const auto value : default_choices) { @@ -323,7 +322,7 @@ TEST_CASE_FIXTURE(optional_argument_test_fixture, "set_value(any) should accept } TEST_CASE_FIXTURE(optional_argument_test_fixture, "set_value(any) should perform the specified action") { - auto sut = prepare_argument(long_name); + auto sut = prepare_argument(primary_name); SUBCASE("valued action") { const auto double_valued_action = [](const test_value_type& value) { return 2 * value; }; @@ -348,13 +347,13 @@ TEST_CASE_FIXTURE(optional_argument_test_fixture, "set_value(any) should perform } TEST_CASE_FIXTURE(optional_argument_test_fixture, "nvalues_in_range() should return equivalent if nargs has not been set") { - const auto sut = prepare_argument(long_name); + const auto sut = prepare_argument(primary_name); REQUIRE(std::is_eq(sut_nvalues_in_range(sut))); } TEST_CASE_FIXTURE(optional_argument_test_fixture, "nvalues_in_range() should return equivalent if a default value has been set") { - auto sut = prepare_argument(long_name); + auto sut = prepare_argument(primary_name); sut.nargs(non_default_range); sut.default_value(default_value); @@ -367,7 +366,7 @@ TEST_CASE_FIXTURE( "nvalues_in_range() should return equivalent only when the number of values " "is in the specified range" ) { - auto sut = prepare_argument(long_name); + auto sut = prepare_argument(primary_name); sut.nargs(non_default_range); REQUIRE(std::is_lt(sut_nvalues_in_range(sut))); diff --git a/test/source/test_positional_argument.cpp b/test/source/test_positional_argument.cpp index d03c6af..378dee3 100644 --- a/test/source/test_positional_argument.cpp +++ b/test/source/test_positional_argument.cpp @@ -8,22 +8,24 @@ #include using namespace ap_testing; + using ap::argument::positional_argument; +using ap::argument::detail::argument_name; namespace { -constexpr std::string_view long_name = "test"; -constexpr std::string_view short_name = "t"; +constexpr std::string_view primary_name = "test"; +constexpr std::string_view secondary_name = "t"; using test_value_type = int; using sut_type = positional_argument; -sut_type prepare_argument(std::string_view name) { - return sut_type(name); +sut_type prepare_argument(std::string_view primary_name) { + return sut_type(argument_name{ primary_name }); } -sut_type prepare_argument(std::string_view name, std::string_view long_name) { - return sut_type(name, long_name); +sut_type prepare_argument(std::string_view primary_name, std::string_view secondary_name) { + return sut_type(argument_name{ primary_name, secondary_name }); } const std::string empty_str = ""; @@ -40,41 +42,39 @@ constexpr test_value_type invalid_choice = 4; TEST_SUITE_BEGIN("test_positional_argument"); TEST_CASE_FIXTURE(positional_argument_test_fixture, "is_optional() should return false") { - const auto sut = prepare_argument(long_name); + const auto sut = prepare_argument(primary_name); REQUIRE_FALSE(sut.is_optional()); } -TEST_CASE_FIXTURE(positional_argument_test_fixture, "name() should return value passed to the optional argument constructor for long name") { - const auto sut = prepare_argument(long_name); - +TEST_CASE_FIXTURE(positional_argument_test_fixture, "name() should return value passed to the optional argument constructor for primary name") { + const auto sut = prepare_argument(primary_name); const auto name = sut_get_name(sut); - REQUIRE_EQ(name, long_name); - REQUIRE_NE(name, short_name); + REQUIRE(name.match(primary_name)); + REQUIRE_FALSE(name.match(secondary_name)); } TEST_CASE_FIXTURE( positional_argument_test_fixture, - "name() and short_name() should return value passed to the optional" - "argument constructor for both long and short names" + "name() and secondary_name() should return value passed to the optional" + "argument constructor for both primary and secondary names" ) { - const auto sut = prepare_argument(long_name, short_name); - + const auto sut = prepare_argument(primary_name, secondary_name); const auto name = sut_get_name(sut); - REQUIRE_EQ(name, long_name); - REQUIRE_EQ(name, short_name); + REQUIRE(name.match(primary_name)); + REQUIRE(name.match(secondary_name)); } TEST_CASE_FIXTURE(positional_argument_test_fixture, "help() should return nullopt by default") { - const auto sut = prepare_argument(long_name); + const auto sut = prepare_argument(primary_name); REQUIRE_FALSE(sut_get_help(sut)); } TEST_CASE_FIXTURE(positional_argument_test_fixture, "help() should return message if one has been provided") { - auto sut = prepare_argument(long_name); + auto sut = prepare_argument(primary_name); constexpr std::string_view help_msg = "test help msg"; sut.help(help_msg); @@ -86,45 +86,45 @@ TEST_CASE_FIXTURE(positional_argument_test_fixture, "help() should return messag } TEST_CASE_FIXTURE(positional_argument_test_fixture, "is_required() should return true") { - auto sut = prepare_argument(long_name); + auto sut = prepare_argument(primary_name); REQUIRE(sut_is_required(sut)); } TEST_CASE_FIXTURE(positional_argument_test_fixture, "is_used() should return false by default") { - const auto sut = prepare_argument(long_name); + const auto sut = prepare_argument(primary_name); REQUIRE_FALSE(sut_is_used(sut)); } TEST_CASE_FIXTURE(positional_argument_test_fixture, "is_used() should return true when argument contains value") { - auto sut = prepare_argument(long_name); + auto sut = prepare_argument(primary_name); sut_set_value(sut, std::to_string(value_1)); REQUIRE(sut_is_used(sut)); } TEST_CASE_FIXTURE(positional_argument_test_fixture, "nused() should return 0 by default") { - const auto sut = prepare_argument(long_name); + const auto sut = prepare_argument(primary_name); REQUIRE_EQ(sut_get_nused(sut), 0u); } TEST_CASE_FIXTURE(positional_argument_test_fixture, "is_used() should return 1 when argument contains value") { - auto sut = prepare_argument(long_name); + auto sut = prepare_argument(primary_name); sut_set_value(sut, std::to_string(value_1)); REQUIRE_EQ(sut_get_nused(sut), 1u); } TEST_CASE_FIXTURE(positional_argument_test_fixture, "has_value() should return false by default") { - const auto sut = prepare_argument(long_name); + const auto sut = prepare_argument(primary_name); REQUIRE_FALSE(sut_has_value(sut)); } TEST_CASE_FIXTURE(positional_argument_test_fixture, "has_value() should return true is value is set") { - auto sut = prepare_argument(long_name); + auto sut = prepare_argument(primary_name); sut_set_value(sut, std::to_string(value_1)); @@ -132,13 +132,13 @@ TEST_CASE_FIXTURE(positional_argument_test_fixture, "has_value() should return t } TEST_CASE_FIXTURE(positional_argument_test_fixture, "has_parsed_values() should return false by default") { - const auto sut = prepare_argument(long_name); + const auto sut = prepare_argument(primary_name); REQUIRE_FALSE(sut_has_parsed_values(sut)); } TEST_CASE_FIXTURE(positional_argument_test_fixture, "has_parsed_values() should true if the value is set") { - auto sut = prepare_argument(long_name); + auto sut = prepare_argument(primary_name); sut_set_value(sut, std::to_string(value_1)); @@ -146,7 +146,7 @@ TEST_CASE_FIXTURE(positional_argument_test_fixture, "has_parsed_values() should } TEST_CASE_FIXTURE(positional_argument_test_fixture, "set_value(any) should throw when a value has already been set") { - auto sut = prepare_argument(long_name); + auto sut = prepare_argument(primary_name); REQUIRE_NOTHROW(sut_set_value(sut, std::to_string(value_1))); REQUIRE(sut_has_value(sut)); @@ -155,7 +155,7 @@ TEST_CASE_FIXTURE(positional_argument_test_fixture, "set_value(any) should throw } TEST_CASE_FIXTURE(positional_argument_test_fixture, "set_value(any) should throw when value_type cannot be obtained from given string") { - auto sut = prepare_argument(long_name); + auto sut = prepare_argument(primary_name); SUBCASE("given string is empty") { REQUIRE_THROWS_AS(sut_set_value(sut, empty_str), ap::error::invalid_value_error); @@ -172,7 +172,7 @@ TEST_CASE_FIXTURE(positional_argument_test_fixture, "set_value(any) should throw TEST_CASE_FIXTURE( positional_argument_test_fixture, "set_value(any) should throw when parameter passed to value() is not present in the choices set" ) { - auto sut = prepare_argument(long_name); + auto sut = prepare_argument(primary_name); sut_set_choices(sut, default_choices); @@ -186,7 +186,7 @@ TEST_CASE_FIXTURE( "set_value(any) should accept the given value only when no value has been set yet " "and if the given value is present in the choices set" ) { - auto sut = prepare_argument(long_name); + auto sut = prepare_argument(primary_name); sut_set_choices(sut, default_choices); const std::vector correct_values = default_choices; @@ -206,7 +206,7 @@ TEST_CASE_FIXTURE( } TEST_CASE_FIXTURE(positional_argument_test_fixture, "set_value(any) should perform the specified action") { - auto sut = prepare_argument(long_name); + auto sut = prepare_argument(primary_name); SUBCASE("valued action") { const auto double_valued_action = [](const test_value_type& value) { return 2 * value; }; @@ -231,14 +231,14 @@ TEST_CASE_FIXTURE(positional_argument_test_fixture, "set_value(any) should perfo } TEST_CASE_FIXTURE(positional_argument_test_fixture, "value() should return default any object if argument's value has not been set") { - auto sut = prepare_argument(long_name); + auto sut = prepare_argument(primary_name); REQUIRE_FALSE(sut_has_value(sut)); REQUIRE_THROWS_AS(std::any_cast(sut_get_value(sut)), std::bad_any_cast); } TEST_CASE_FIXTURE(positional_argument_test_fixture, "value() should return the argument's value if it has been set") { - auto sut = prepare_argument(long_name); + auto sut = prepare_argument(primary_name); sut_set_value(sut, std::to_string(value_1)); @@ -247,19 +247,19 @@ TEST_CASE_FIXTURE(positional_argument_test_fixture, "value() should return the a } TEST_CASE_FIXTURE(positional_argument_test_fixture, "values() should throw logic_error") { - auto sut = prepare_argument(long_name); + auto sut = prepare_argument(primary_name); REQUIRE_THROWS_AS(sut_get_values(sut), std::logic_error); } TEST_CASE_FIXTURE(positional_argument_test_fixture, "nvalues_in_range() should return less by default") { - const auto sut = prepare_argument(long_name); + const auto sut = prepare_argument(primary_name); REQUIRE(std::is_lt(sut_nvalues_in_range(sut))); } TEST_CASE_FIXTURE(positional_argument_test_fixture, "nvalues_in_range() should return equivalent if a value has been set") { - auto sut = prepare_argument(long_name); + auto sut = prepare_argument(primary_name); sut_set_value(sut, std::to_string(value_1));