Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

YT-CPPAP-5: argument_name class refactor #43

Merged
merged 7 commits into from
Apr 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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`
SpectraL519 marked this conversation as resolved.
Show resolved Hide resolved
* 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);
}

SpectraL519 marked this conversation as resolved.
Show resolved Hide resolved
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
Loading