Skip to content

Commit

Permalink
[FIX, TEST] flag default patch and unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
eaasna committed Feb 22, 2022
1 parent f702250 commit 262436e
Show file tree
Hide file tree
Showing 9 changed files with 90 additions and 52 deletions.
8 changes: 7 additions & 1 deletion include/sharg/argument_parser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -251,18 +251,24 @@ class argument_parser

/*!\brief Adds a flag to the sharg::argument_parser.
*
* \param[in, out] value The variable in which to store the given command line argument.
* \param[in, out] value The variable which shows if the flag is turned off (default) or on.
* \param[in] short_id The short identifier for the flag (e.g. 'i').
* \param[in] long_id The long identifier for the flag (e.g. "integer").
* \param[in] desc The description of the flag to be shown in the help page.
* \param[in] spec Advanced flag specification, see sharg::option_spec.
*
* \throws sharg::design_error
*
*/
void add_flag(bool & value,
char const short_id,
std::string const & long_id,
std::string const & desc,
option_spec const spec = option_spec::standard)
{
if (value)
throw design_error("A flag's default value must be false.");

verify_identifiers(short_id, long_id);
// copy variables into the lambda because the calls are pushed to a stack
// and the references would go out of scope.
Expand Down
2 changes: 1 addition & 1 deletion include/sharg/detail/format_parse.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -718,7 +718,7 @@ class format_parse : public format_base

/*!\brief Handles command line flags, whether they are set or not.
*
* \param[out] value The variable in which to store the given command line argument.
* \param[out] value The variable which shows if the flag is turned off (default) or on.
* \param[in] short_id The short identifier for the flag (e.g. 'i').
* \param[in] long_id The long identifier for the flag (e.g. "integer").
*
Expand Down
1 change: 1 addition & 0 deletions include/sharg/exceptions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ class validation_error : public argument_parser_error
*
* - Reuse of a short or long identifier (must be unique)
* - Both identifiers must not be empty (one is ok)
* - Flag default value must be false
*/
class design_error : public argument_parser_error
{
Expand Down
57 changes: 32 additions & 25 deletions test/unit/argument_parser_design_error_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,57 +44,64 @@ TEST(parse_test, design_error)
EXPECT_THROW(parser3.add_option(option_value, '\0', "", "oh oh all is empty."),
sharg::design_error);

bool flag_value;
bool true_value{true};

// short flag
// default true
sharg::argument_parser parser4{"test_parser", 1, argv};
parser4.add_flag(flag_value, 'i', "int1", "this is an int option.");
EXPECT_THROW(parser4.add_flag(flag_value, 'i', "int2", "oh oh another id."),
EXPECT_THROW(parser4.add_flag(true_value, 'i', "int", "oh oh default is true."),
sharg::design_error);

// long flag
bool flag_value{false};

// short flag
sharg::argument_parser parser5{"test_parser", 1, argv};
parser5.add_flag(flag_value, 'i', "int", "this is an int option.");
EXPECT_THROW(parser5.add_flag(flag_value, 'a', "int", "oh oh another id."),
parser5.add_flag(flag_value, 'i', "int1", "this is an int option.");
EXPECT_THROW(parser5.add_flag(flag_value, 'i', "int2", "oh oh another id."),
sharg::design_error);

// empty identifier
// long flag
sharg::argument_parser parser6{"test_parser", 1, argv};
EXPECT_THROW(parser6.add_flag(flag_value, '\0', "", "oh oh another id."),
parser6.add_flag(flag_value, 'i', "int", "this is an int option.");
EXPECT_THROW(parser6.add_flag(flag_value, 'a', "int", "oh oh another id."),
sharg::design_error);

// empty identifier
sharg::argument_parser parser7{"test_parser", 1, argv};
EXPECT_THROW(parser7.add_flag(flag_value, '\0', "", "oh oh another id."),
sharg::design_error);

// positional option not at the end
const char * argv2[] = {"./argument_parser_test", "arg1", "arg2", "arg3"};
std::vector<int> vec;
sharg::argument_parser parser7{"test_parser", 4, argv2};
parser7.add_positional_option(vec, "oh oh list not at the end.");
EXPECT_THROW(parser7.add_positional_option(option_value, "desc."), sharg::design_error);
sharg::argument_parser parser8{"test_parser", 4, argv2};
parser8.add_positional_option(vec, "oh oh list not at the end.");
EXPECT_THROW(parser8.add_positional_option(option_value, "desc."), sharg::design_error);

// using h, help, advanced-help, and export-help
sharg::argument_parser parser8{"test_parser", 1, argv};
EXPECT_THROW(parser8.add_option(option_value, 'h', "", "-h is bad."),
sharg::argument_parser parser9{"test_parser", 1, argv};
EXPECT_THROW(parser9.add_option(option_value, 'h', "", "-h is bad."),
sharg::design_error);
EXPECT_THROW(parser8.add_option(option_value, '\0', "help", "help is bad."),
EXPECT_THROW(parser9.add_option(option_value, '\0', "help", "help is bad."),
sharg::design_error);
EXPECT_THROW(parser8.add_option(option_value, '\0', "advanced-help",
EXPECT_THROW(parser9.add_option(option_value, '\0', "advanced-help",
"advanced-help is bad"), sharg::design_error);
EXPECT_THROW(parser8.add_option(option_value, '\0', "export-help",
EXPECT_THROW(parser9.add_option(option_value, '\0', "export-help",
"export-help is bad"), sharg::design_error);

// using one-letter long identifiers.
sharg::argument_parser parser9{"test_parser", 1, argv};
EXPECT_THROW(parser9.add_option(option_value, 'y', "z", "long identifier is one letter"),
sharg::argument_parser parser10{"test_parser", 1, argv};
EXPECT_THROW(parser10.add_option(option_value, 'y', "z", "long identifier is one letter"),
sharg::design_error);
EXPECT_THROW(parser9.add_flag(flag_value, 'y', "z", "long identifier is one letter"),
EXPECT_THROW(parser10.add_flag(flag_value, 'y', "z", "long identifier is one letter"),
sharg::design_error);

// using non-printable characters
sharg::argument_parser parser10{"test_parser", 1, argv};
EXPECT_THROW(parser10.add_option(option_value, '\t', "no\n", "tab and newline don't work!"),
sharg::argument_parser parser11{"test_parser", 1, argv};
EXPECT_THROW(parser11.add_option(option_value, '\t', "no\n", "tab and newline don't work!"),
sharg::design_error);
EXPECT_THROW(parser10.add_flag(flag_value, 'i', "no\n", "tab and newline don't work!"),
EXPECT_THROW(parser11.add_flag(flag_value, 'i', "no\n", "tab and newline don't work!"),
sharg::design_error);
EXPECT_THROW(parser10.add_flag(flag_value, 'a', "-no", "can't start long_id with a hyphen"),
EXPECT_THROW(parser11.add_flag(flag_value, 'a', "-no", "can't start long_id with a hyphen"),
sharg::design_error);
}

Expand All @@ -116,7 +123,7 @@ TEST(parse_test, parse_called_twice)

TEST(parse_test, subcommand_argument_parser_error)
{
bool flag_value{};
bool flag_value{false};

// subcommand parsing was not enabled on construction but get_sub_parser() is called
{
Expand Down
4 changes: 2 additions & 2 deletions test/unit/detail/format_help_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
std::string std_cout;
std::string expected;
int option_value{5};
bool flag_value{};
bool flag_value{false};
std::vector<std::string> pos_opt_value{};
const char * argv0[] = {"./help_add_test --version-check false"};
const char * argv1[] = {"./help_add_test --version-check false", "-h"};
Expand Down Expand Up @@ -292,7 +292,7 @@ TEST(help_page_printing, advanced_options)
{
int32_t option_value{5};
uint8_t another_option_value{2};
bool flag_value{};
bool flag_value{false};

auto set_up = [&option_value, &flag_value, &another_option_value] (sharg::argument_parser & parser)
{
Expand Down
2 changes: 1 addition & 1 deletion test/unit/detail/format_html_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ TEST(html_format, full_information_information)
std::string my_stdout;
std::string expected;
int option_value{5};
bool flag_value;
bool flag_value{false};
int8_t non_list_pos_opt_value{1};
std::vector<std::string> list_pos_opt_value{};

Expand Down
2 changes: 1 addition & 1 deletion test/unit/detail/format_man_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
struct format_man_test : public ::testing::Test
{
int option_value{5};
bool flag_value{};
bool flag_value{false};
int8_t non_list_pos_opt_value{1};
std::vector<std::string> list_pos_opt_value{};
std::string my_stdout{};
Expand Down
4 changes: 2 additions & 2 deletions test/unit/detail/version_check_test.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ struct version_check : public ::testing::Test
parser.info.version = "2.3.4";

// In case we don't want to specify --version-check but avoid that short help format will be set (no arguments)
bool dummy{};
bool dummy{false};
parser.add_flag(dummy, 'f', "dummy-flag", "A dummy flag.");

testing::internal::CaptureStdout();
Expand Down Expand Up @@ -313,7 +313,7 @@ TEST_F(version_check, environment_variable_set)

sharg::argument_parser parser{app_name, 2, argv};
parser.info.version = "2.3.4";
bool dummy{};
bool dummy{false};
parser.add_flag(dummy, 'f', "dummy-flag", "A dummy flag.");

testing::internal::CaptureStdout();
Expand Down
62 changes: 43 additions & 19 deletions test/unit/format_parse_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,12 @@ TEST(parse_type_test, add_option_long_id)
TEST(parse_type_test, add_flag_short_id_single)
{
bool option_value1{false};
bool option_value2{true};
bool option_value2{false};

const char * argv[] = {"./argument_parser_test", "-t"};
const char * argv[] = {"./argument_parser_test", "-f"};
sharg::argument_parser parser{"test_parser", 2, argv, sharg::update_notifications::off};
parser.add_flag(option_value1, 't', "true-flag", "this is a flag.");
parser.add_flag(option_value2, 'f', "false-flag", "this is a flag.");
parser.add_flag(option_value1, 'f', "flag", "this is a flag.");
parser.add_flag(option_value2, 'a', "another-flag", "this is a flag.");

testing::internal::CaptureStderr();
EXPECT_NO_THROW(parser.parse());
Expand All @@ -90,16 +90,16 @@ TEST(parse_type_test, add_flag_short_id_single)
TEST(parse_type_test, add_flag_short_id_multiple)
{
bool option_value1{false};
bool option_value2{true};
bool option_value2{false};
bool option_value3{false};
bool option_value4{false};

const char * argv[] = {"./argument_parser_test", "-tab"};
const char * argv[] = {"./argument_parser_test", "-fbc"};
sharg::argument_parser parser{"test_parser", 2, argv, sharg::update_notifications::off};
parser.add_flag(option_value1, 't', "true-flag", "this is a flag.");
parser.add_flag(option_value2, 'f', "false-flag", "this is a flag.");
parser.add_flag(option_value3, 'a', "additional-flag", "this is a flag.");
parser.add_flag(option_value4, 'b', "another-flag", "this is a flag.");
parser.add_flag(option_value1, 'f', "flag", "this is a flag.");
parser.add_flag(option_value2, 'a', "also-flag", "this is a flag.");
parser.add_flag(option_value3, 'b', "additional-flag", "this is a flag.");
parser.add_flag(option_value4, 'c', "another-flag", "this is a flag.");

testing::internal::CaptureStderr();
EXPECT_NO_THROW(parser.parse());
Expand All @@ -113,18 +113,18 @@ TEST(parse_type_test, add_flag_short_id_multiple)
TEST(parse_type_test, add_flag_long_id)
{
bool option_value1{false};
bool option_value2{true};
bool option_value2{false};

const char * argv[] = {"./argument_parser_test", "--true-flag"};
const char * argv[] = {"./argument_parser_test", "--another-flag"};
sharg::argument_parser parser{"test_parser", 2, argv, sharg::update_notifications::off};
parser.add_flag(option_value1, 't', "true-flag", "this is a flag.");
parser.add_flag(option_value2, 'f', "false-flag", "this is a flag.");
parser.add_flag(option_value1, 'f', "flag", "this is a flag.");
parser.add_flag(option_value2, 'a', "another-flag", "this is a flag.");

testing::internal::CaptureStderr();
EXPECT_NO_THROW(parser.parse());
EXPECT_TRUE((testing::internal::GetCapturedStderr()).empty());
EXPECT_EQ(option_value1, true);
EXPECT_EQ(option_value2, false);
EXPECT_EQ(option_value1, false);
EXPECT_EQ(option_value2, true);
}

TEST(parse_type_test, add_positional_option)
Expand All @@ -146,7 +146,7 @@ TEST(parse_type_test, independent_add_order)
// testing same command line input different add_* order

std::string positional_value;
bool flag_value;
bool flag_value{false};
int option_value;

// Order 1: option, flag, positional
Expand All @@ -163,6 +163,8 @@ TEST(parse_type_test, independent_add_order)
EXPECT_EQ(option_value, 2);
EXPECT_EQ(flag_value, true);

flag_value = false; // reinstate to default value

// Order 1: flag, option, positional
sharg::argument_parser parser2{"test_parser", 5, argv, sharg::update_notifications::off};
parser2.add_flag(flag_value, 'b', "flag", "this is a flag.");
Expand All @@ -176,6 +178,8 @@ TEST(parse_type_test, independent_add_order)
EXPECT_EQ(option_value, 2);
EXPECT_EQ(flag_value, true);

flag_value = false;

// Order 1: option, positional, flag
sharg::argument_parser parser3{"test_parser", 5, argv, sharg::update_notifications::off};
parser3.add_option(option_value, 'i', "int-option", "this is a int option.");
Expand All @@ -189,6 +193,8 @@ TEST(parse_type_test, independent_add_order)
EXPECT_EQ(option_value, 2);
EXPECT_EQ(flag_value, true);

flag_value = false;

// Order 1: flag, positional, option
sharg::argument_parser parser4{"test_parser", 5, argv, sharg::update_notifications::off};
parser4.add_flag(flag_value, 'b', "flag", "this is a flag.");
Expand All @@ -202,6 +208,8 @@ TEST(parse_type_test, independent_add_order)
EXPECT_EQ(option_value, 2);
EXPECT_EQ(flag_value, true);

flag_value = false;

// Order 1: positional, flag, option
sharg::argument_parser parser5{"test_parser", 5, argv, sharg::update_notifications::off};
parser5.add_positional_option(positional_value, "this is a string positional.");
Expand All @@ -215,6 +223,8 @@ TEST(parse_type_test, independent_add_order)
EXPECT_EQ(option_value, 2);
EXPECT_EQ(flag_value, true);

flag_value = false;

// Order 1: positional, option, flag
sharg::argument_parser parser6{"test_parser", 5, argv, sharg::update_notifications::off};
parser6.add_positional_option(positional_value, "this is a string positional.");
Expand All @@ -234,7 +244,7 @@ TEST(parse_type_test, independent_cmd_order)
// testing different command line order

std::string positional_value;
bool flag_value;
bool flag_value{false};
int option_value;

// Order 1: option, flag, positional (POSIX conform)
Expand All @@ -251,6 +261,8 @@ TEST(parse_type_test, independent_cmd_order)
EXPECT_EQ(option_value, 2);
EXPECT_EQ(flag_value, true);

flag_value = false; // reinstate to default value

// Order 1: flag, option, positional (POSIX conform)
const char * argv2[] = {"./argument_parser_test", "-b", "-i", "2", "arg"};
sharg::argument_parser parser2{"test_parser", 5, argv2, sharg::update_notifications::off};
Expand All @@ -265,6 +277,8 @@ TEST(parse_type_test, independent_cmd_order)
EXPECT_EQ(option_value, 2);
EXPECT_EQ(flag_value, true);

flag_value = false;

// Order 1: option, positional, flag
const char * argv3[] = {"./argument_parser_test", "-i", "2", "arg", "-b"};
sharg::argument_parser parser3{"test_parser", 5, argv3, sharg::update_notifications::off};
Expand All @@ -279,6 +293,8 @@ TEST(parse_type_test, independent_cmd_order)
EXPECT_EQ(option_value, 2);
EXPECT_EQ(flag_value, true);

flag_value = false;

// Order 1: flag, positional, option
const char * argv4[] = {"./argument_parser_test", "-b", "arg", "-i", "2"};
sharg::argument_parser parser4{"test_parser", 5, argv4, sharg::update_notifications::off};
Expand All @@ -293,6 +309,8 @@ TEST(parse_type_test, independent_cmd_order)
EXPECT_EQ(option_value, 2);
EXPECT_EQ(flag_value, true);

flag_value = false;

// Order 1: positional, flag, option
const char * argv5[] = {"./argument_parser_test", "arg", "-b", "-i", "2"};
sharg::argument_parser parser5{"test_parser", 5, argv5, sharg::update_notifications::off};
Expand All @@ -307,6 +325,8 @@ TEST(parse_type_test, independent_cmd_order)
EXPECT_EQ(option_value, 2);
EXPECT_EQ(flag_value, true);

flag_value = false;

// Order 1: positional, option, flag
const char * argv6[] = {"./argument_parser_test", "arg", "-i", "2", "-b"};
sharg::argument_parser parser6{"test_parser", 5, argv6, sharg::update_notifications::off};
Expand Down Expand Up @@ -794,7 +814,7 @@ TEST(parse_test, version_check_option_error)

TEST(parse_test, subcommand_argument_parser_success)
{
bool flag_value{};
bool flag_value{false};
std::string option_value{};

// parsing
Expand All @@ -820,6 +840,8 @@ TEST(parse_test, subcommand_argument_parser_success)
EXPECT_EQ("foo", option_value);
}

flag_value = false; // reinstate to default value

// top-level help page
{
const char * argv[]{"./top_level", "-h", "-f", "sub1", "foo"};
Expand All @@ -835,6 +857,8 @@ TEST(parse_test, subcommand_argument_parser_success)
EXPECT_FALSE(std::string{testing::internal::GetCapturedStdout()}.empty());
}

flag_value = false;

// sub-parser help page
{
const char * argv[]{"./top_level", "-f", "sub1", "-h"};
Expand Down

0 comments on commit 262436e

Please sign in to comment.