Skip to content

Commit

Permalink
YT-CPPAP-5: argument_name class refactor
Browse files Browse the repository at this point in the history
- 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
  • Loading branch information
SpectraL519 committed Apr 8, 2024
1 parent 24137db commit 60dd035
Show file tree
Hide file tree
Showing 9 changed files with 528 additions and 447 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -263,7 +265,7 @@ The supported default arguments are:
.action<ap::void_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))
Expand Down
5 changes: 5 additions & 0 deletions change_log.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,8 @@
* Added the `install_clang17_toolchain.sh` env script
* Added the `format` workflow
* Switched from the `<algorithm>` to the `<ranges>` 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`
313 changes: 147 additions & 166 deletions include/ap/argument_parser.hpp

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions test/include/argument_parser_test_fixture.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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());
}
}

Expand All @@ -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) });
}

Expand Down
185 changes: 131 additions & 54 deletions test/source/test_argument_name.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Loading

0 comments on commit 60dd035

Please sign in to comment.