Skip to content

Commit

Permalink
[TEST] Add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
eseiler committed Mar 1, 2024
1 parent 8f8e1e1 commit 9cb2421
Show file tree
Hide file tree
Showing 4 changed files with 245 additions and 8 deletions.
1 change: 1 addition & 0 deletions test/unit/parser/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ sharg_test (enumeration_names_test.cpp)
sharg_test (format_parse_test.cpp)
sharg_test (format_parse_validators_test.cpp)
sharg_test (parser_design_error_test.cpp)
sharg_test (subcommand_test.cpp)
9 changes: 6 additions & 3 deletions test/unit/parser/format_parse_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -681,17 +681,20 @@ TEST_F(format_parse_test, subcommand_parser_success)

TEST_F(format_parse_test, subcommand_parser_error)
{
constexpr std::string_view expected_message = "You misspelled the subcommand! Please specify which sub-program "
"you want to use: [sub1]. Use -h/--help for more information.";

// incorrect sub command regardless of following arguments, https://github.com/seqan/seqan3/issues/2172
auto parser = get_subcommand_parser({"subiddysub", "-f"}, {"sub1"});
EXPECT_THROW(parser.parse(), sharg::parser_error);
EXPECT_THROW_MSG(parser.parse(), sharg::user_input_error, expected_message);

// incorrect sub command with no other arguments
parser = get_subcommand_parser({"subiddysub"}, {"sub1"});
EXPECT_THROW(parser.parse(), sharg::parser_error);
EXPECT_THROW_MSG(parser.parse(), sharg::user_input_error, expected_message);

// incorrect sub command with trailing special option, https://github.com/seqan/sharg-parser/issues/171
parser = get_subcommand_parser({"subiddysub", "-h"}, {"sub1"});
EXPECT_THROW(parser.parse(), sharg::parser_error);
EXPECT_THROW_MSG(parser.parse(), sharg::user_input_error, expected_message);
}

TEST_F(format_parse_test, issue1544)
Expand Down
10 changes: 5 additions & 5 deletions test/unit/parser/parser_design_error_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ TEST_F(design_error_test, subcommand_parser_error)
parser = get_subcommand_parser({"-f", "foo"}, {"foo"});

EXPECT_THROW(parser.add_positional_option(flag_value, sharg::config{}), sharg::design_error);
EXPECT_THROW(parser.add_option(flag_value, sharg::config{.short_id = 'o'}), sharg::design_error);
EXPECT_NO_THROW(parser.add_option(flag_value, sharg::config{.short_id = 'o'}));
EXPECT_NO_THROW(parser.add_flag(flag_value, sharg::config{.short_id = 'f'}));
EXPECT_THROW(parser.get_sub_parser(), sharg::design_error);
EXPECT_EQ(flag_value, false);
Expand All @@ -277,14 +277,14 @@ TEST_F(design_error_test, subcommand_parser_error)

flag_value = false;

// no options are allowed
// options are allowed
parser = get_subcommand_parser({"-o", "true"}, {"foo"});

EXPECT_THROW(parser.add_positional_option(flag_value, sharg::config{}), sharg::design_error);
EXPECT_THROW(parser.add_option(flag_value, sharg::config{.short_id = 'o'}), sharg::design_error);
EXPECT_EQ(flag_value, false);
EXPECT_THROW(parser.parse(), sharg::too_few_arguments);
EXPECT_NO_THROW(parser.add_option(flag_value, sharg::config{.short_id = 'o'}));
EXPECT_EQ(flag_value, false);
EXPECT_NO_THROW(parser.parse());
EXPECT_EQ(flag_value, true);
}

TEST_F(design_error_test, not_allowed_after_parse)
Expand Down
233 changes: 233 additions & 0 deletions test/unit/parser/subcommand_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
// SPDX-FileCopyrightText: 2006-2024, Knut Reinert & Freie Universität Berlin
// SPDX-FileCopyrightText: 2016-2024, Knut Reinert & MPI für molekulare Genetik
// SPDX-License-Identifier: BSD-3-Clause

#include <gtest/gtest.h>

#include <ranges>

#include <sharg/parser.hpp>
#include <sharg/test/expect_throw_msg.hpp>
#include <sharg/test/test_fixture.hpp>

class subcommand_test : public sharg::test::test_fixture
{
protected:
static constexpr std::string_view expected_top_short_help = "test_parser\n===========n"
" Try -h or --help for more information.\n";

static inline std::string expected_top_full_help =
"test_parser\n"
"===========\n"
"\n"
"SUBCOMMANDS\n"
" This program must be invoked with one of the following subcommands:\n"
" - build\n"
" See the respective help page for further details (e.g. by calling\n"
" test_parser build -h).\n"
"\n"
" The following options belong to the top-level parser and need to be\n"
" specified before the subcommand key word. Every argument after the\n"
" subcommand key word is passed on to the corresponding sub-parser.\n"
"\n"
"OPTIONS\n"
" -o (std::string)\n"
" Default: \"\"\n"
"\n"
+ basic_options_str + '\n' + version_str();

static constexpr std::string_view expected_sub_short_help = "test_parser-build\n=================\n"
" Try -h or --help for more information.\n";

static inline std::string expected_sub_full_help = "test_parser-build\n"
"=================\n"
"\n"
"OPTIONS\n"
" -o (std::string)\n"
" Default: \"\"\n"
"\n"
+ basic_options_str + '\n' + version_str("-build");

static inline std::string value{};

static inline void clear_and_add_option(sharg::parser & parser)
{
value.clear();
parser.add_option(value, sharg::config{.short_id = 'o'});
}
};

TEST_F(subcommand_test, simple_option)
{
auto parser = get_subcommand_parser({"build", "-o", "foo"}, {"build"});
EXPECT_NO_THROW(parser.parse());

ASSERT_NO_THROW(parser.get_sub_parser());
auto & sub_parser = parser.get_sub_parser();
clear_and_add_option(sub_parser);

EXPECT_NO_THROW(sub_parser.parse());
EXPECT_EQ(value, "foo");
}

TEST_F(subcommand_test, subcommand_is_option_value)
{
auto parser = get_subcommand_parser({"-o", "build", "build", "-o", "build"}, {"build"});
clear_and_add_option(parser);
EXPECT_NO_THROW(parser.parse());
EXPECT_EQ(value, "build");

ASSERT_NO_THROW(parser.get_sub_parser());
auto & sub_parser = parser.get_sub_parser();
clear_and_add_option(sub_parser);

EXPECT_NO_THROW(sub_parser.parse());
EXPECT_EQ(value, "build");
}

TEST_F(subcommand_test, option_value_is_option)
{
auto parser = get_subcommand_parser({"-o", "-o", "build", "-o", "-o"}, {"build"});
clear_and_add_option(parser);
EXPECT_NO_THROW(parser.parse());
EXPECT_EQ(value, "-o");

ASSERT_NO_THROW(parser.get_sub_parser());
auto & sub_parser = parser.get_sub_parser();
clear_and_add_option(sub_parser);

EXPECT_NO_THROW(sub_parser.parse());
EXPECT_EQ(value, "-o");
}

TEST_F(subcommand_test, wrong_subcommand)
{
constexpr std::string_view expected_message = "You misspelled the subcommand! Please specify which sub-program "
"you want to use: [build]. Use -h/--help for more information.";

auto parser = get_subcommand_parser({"-o", "build", "buidl", "-o", "build"}, {"build"});
clear_and_add_option(parser);
EXPECT_THROW_MSG(parser.parse(), sharg::user_input_error, expected_message);
}

TEST_F(subcommand_test, subcommand_is_option_value_equals_syntax)
{
auto parser = get_subcommand_parser({"-o=build", "build", "-o=build"}, {"build"});
clear_and_add_option(parser);
EXPECT_NO_THROW(parser.parse());
EXPECT_EQ(value, "build");

ASSERT_NO_THROW(parser.get_sub_parser());
auto & sub_parser = parser.get_sub_parser();
clear_and_add_option(sub_parser);

EXPECT_NO_THROW(sub_parser.parse());
EXPECT_EQ(value, "build");
}

TEST_F(subcommand_test, subcommand_is_flag)
{
std::array<bool, 5> flag_values{false, false, false, false, false};

auto parser = get_subcommand_parser({"-build", "build", "-o", "build"}, {"build"});
parser.add_flag(flag_values[0], sharg::config{.short_id = 'b'});
parser.add_flag(flag_values[1], sharg::config{.short_id = 'u'});
parser.add_flag(flag_values[2], sharg::config{.short_id = 'i'});
parser.add_flag(flag_values[3], sharg::config{.short_id = 'l'});
parser.add_flag(flag_values[4], sharg::config{.short_id = 'd'});
EXPECT_NO_THROW(parser.parse());
EXPECT_TRUE(std::ranges::all_of(flag_values, std::identity{})); // All true

ASSERT_NO_THROW(parser.get_sub_parser());
auto & sub_parser = parser.get_sub_parser();
clear_and_add_option(sub_parser);

EXPECT_NO_THROW(sub_parser.parse());
EXPECT_EQ(value, "build");
}

TEST_F(subcommand_test, no_help)
{
auto parser = get_subcommand_parser({"-o", "build"}, {"build"});
clear_and_add_option(parser);
EXPECT_NO_THROW(parser.parse());
}

TEST_F(subcommand_test, top_full_help)
{
auto parser = get_subcommand_parser({"-o", "build", "--help"}, {"build"});
clear_and_add_option(parser);
EXPECT_EQ(get_parse_cout_on_exit(parser), expected_top_full_help);
}

TEST_F(subcommand_test, sub_short_help)
{
auto parser = get_subcommand_parser({"-o", "build", "build"}, {"build"});
clear_and_add_option(parser);
EXPECT_NO_THROW(parser.parse());

ASSERT_NO_THROW(parser.get_sub_parser());
auto & sub_parser = parser.get_sub_parser();
clear_and_add_option(sub_parser);

EXPECT_EQ(get_parse_cout_on_exit(sub_parser), expected_sub_short_help);
}

TEST_F(subcommand_test, sub_full_help)
{
auto parser = get_subcommand_parser({"-o", "build", "build", "--help"}, {"build"});
clear_and_add_option(parser);
EXPECT_NO_THROW(parser.parse());

ASSERT_NO_THROW(parser.get_sub_parser());
auto & sub_parser = parser.get_sub_parser();
clear_and_add_option(sub_parser);

EXPECT_EQ(get_parse_cout_on_exit(sub_parser), expected_sub_full_help);
}

TEST_F(subcommand_test, sub_short_help_no_options)
{
auto parser = get_subcommand_parser({"build"}, {"build"});
clear_and_add_option(parser);
EXPECT_NO_THROW(parser.parse());

ASSERT_NO_THROW(parser.get_sub_parser());
auto & sub_parser = parser.get_sub_parser();
clear_and_add_option(sub_parser);

EXPECT_EQ(get_parse_cout_on_exit(sub_parser), expected_sub_short_help);
}

TEST_F(subcommand_test, sub_full_help_no_options)
{
auto parser = get_subcommand_parser({"build", "--help"}, {"build"});
clear_and_add_option(parser);
EXPECT_NO_THROW(parser.parse());

ASSERT_NO_THROW(parser.get_sub_parser());
auto & sub_parser = parser.get_sub_parser();
clear_and_add_option(sub_parser);

EXPECT_EQ(get_parse_cout_on_exit(sub_parser), expected_sub_full_help);
}

TEST_F(subcommand_test, sub_full_help_all_options)
{
auto parser = get_subcommand_parser({"-o", "build", "build", "-o", "build", "--help"}, {"build"});
clear_and_add_option(parser);
EXPECT_NO_THROW(parser.parse());

ASSERT_NO_THROW(parser.get_sub_parser());
auto & sub_parser = parser.get_sub_parser();
clear_and_add_option(sub_parser);

EXPECT_EQ(get_parse_cout_on_exit(sub_parser), expected_sub_full_help);
}

TEST_F(subcommand_test, option_value_is_special_command)
{
auto parser = get_subcommand_parser({"-o", "--help"}, {"build"});
clear_and_add_option(parser);
EXPECT_NO_THROW(parser.parse());
}

0 comments on commit 9cb2421

Please sign in to comment.