#include "tst.h" #include "option-parser.h" #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) static const struct wv_option options[] = { { .positional = "first" }, { .positional = "second" }, { .positional = "third" }, { .positional = "command", .is_subcommand = true }, { 'a', "option-a", NULL, "Description of a" }, { 'b', "option-b", NULL, "Description of b" }, { 'v', "value-option", "value", "Description of v" }, { }, }; static const struct wv_option default_options[] = { { .positional = "first" }, { .positional = "second", .default_ = "second_default" }, { 'v', "value-option", "value", "Description of v", .default_ = "v_default" }, { }, }; static int test_simple(void) { struct option_parser parser; option_parser_init(&parser, options); const char* argv[] = { "executable", "-a", "-b", "pos 1", "pos 2", }; ASSERT_INT_EQ(0, option_parser_parse(&parser, ARRAY_SIZE(argv), argv)); ASSERT_STR_EQ("pos 1", option_parser_get_value(&parser, "first")); ASSERT_STR_EQ("pos 2", option_parser_get_value(&parser, "second")); ASSERT_FALSE(option_parser_get_value(&parser, "third")); ASSERT_TRUE(option_parser_get_value(&parser, "a")); ASSERT_TRUE(option_parser_get_value(&parser, "option-b")); ASSERT_FALSE(option_parser_get_value(&parser, "value-option")); ASSERT_INT_EQ(0, parser.remaining_argc); ASSERT_FALSE(parser.remaining_argv); return 0; } static int test_extra_positional_args(void) { struct option_parser parser; option_parser_init(&parser, options); const char* argv[] = { "executable", "pos 1", "pos 2", "-a", "pos 3", "-b", "pos 4", }; ASSERT_INT_EQ(0, option_parser_parse(&parser, ARRAY_SIZE(argv), argv)); ASSERT_STR_EQ("pos 1", option_parser_get_value(&parser, "first")); ASSERT_STR_EQ("pos 2", option_parser_get_value(&parser, "second")); ASSERT_STR_EQ("pos 3", option_parser_get_value(&parser, "third")); ASSERT_TRUE(option_parser_get_value(&parser, "a")); ASSERT_TRUE(option_parser_get_value(&parser, "option-b")); ASSERT_FALSE(option_parser_get_value(&parser, "value-option")); ASSERT_INT_EQ(1, parser.remaining_argc); ASSERT_STR_EQ("pos 4", parser.remaining_argv[0]); return 0; } static int test_short_value_option_with_space(void) { struct option_parser parser; option_parser_init(&parser, options); const char* argv[] = { "executable", "-v", "value" }; ASSERT_INT_EQ(0, option_parser_parse(&parser, ARRAY_SIZE(argv), argv)); ASSERT_STR_EQ("value", option_parser_get_value(&parser, "value-option")); return 0; } static int test_short_value_option_without_space(void) { struct option_parser parser; option_parser_init(&parser, options); const char* argv[] = { "executable", "-vvalue" }; ASSERT_INT_EQ(0, option_parser_parse(&parser, ARRAY_SIZE(argv), argv)); ASSERT_STR_EQ("value", option_parser_get_value(&parser, "value-option")); return 0; } static int test_short_value_option_with_eq(void) { struct option_parser parser; option_parser_init(&parser, options); const char* argv[] = { "executable", "-v=value" }; ASSERT_INT_EQ(0, option_parser_parse(&parser, ARRAY_SIZE(argv), argv)); ASSERT_STR_EQ("value", option_parser_get_value(&parser, "value-option")); return 0; } static int test_long_value_option_with_space(void) { struct option_parser parser; option_parser_init(&parser, options); const char* argv[] = { "executable", "--value-option", "value" }; ASSERT_INT_EQ(0, option_parser_parse(&parser, ARRAY_SIZE(argv), argv)); ASSERT_STR_EQ("value", option_parser_get_value(&parser, "value-option")); return 0; } static int test_long_value_option_without_space(void) { struct option_parser parser; option_parser_init(&parser, options); const char* argv[] = { "executable", "--value-option=value" }; ASSERT_INT_EQ(0, option_parser_parse(&parser, ARRAY_SIZE(argv), argv)); ASSERT_STR_EQ("value", option_parser_get_value(&parser, "value-option")); return 0; } static int test_multi_short_option(void) { struct option_parser parser; option_parser_init(&parser, options); const char* argv[] = { "executable", "-ab" }; ASSERT_INT_EQ(0, option_parser_parse(&parser, ARRAY_SIZE(argv), argv)); ASSERT_TRUE(option_parser_get_value(&parser, "a")); ASSERT_TRUE(option_parser_get_value(&parser, "b")); return 0; } static int test_multi_short_option_with_value(void) { struct option_parser parser; option_parser_init(&parser, options); const char* argv[] = { "executable", "-abvthe-value" }; ASSERT_INT_EQ(0, option_parser_parse(&parser, ARRAY_SIZE(argv), argv)); ASSERT_TRUE(option_parser_get_value(&parser, "a")); ASSERT_TRUE(option_parser_get_value(&parser, "b")); ASSERT_STR_EQ("the-value", option_parser_get_value(&parser, "v")); return 0; } static int test_stop(void) { struct option_parser parser; option_parser_init(&parser, options); const char* argv[] = { "executable", "exec", "-a", "--", "-b"}; ASSERT_INT_EQ(0, option_parser_parse(&parser, ARRAY_SIZE(argv), argv)); ASSERT_TRUE(option_parser_get_value(&parser, "a")); ASSERT_FALSE(option_parser_get_value(&parser, "b")); ASSERT_INT_EQ(1, parser.remaining_argc); ASSERT_STR_EQ("-b", parser.remaining_argv[0]); return 0; } static int test_unknown_short_option(void) { struct option_parser parser; option_parser_init(&parser, options); const char* argv[] = { "executable", "-x" }; ASSERT_INT_EQ(-1, option_parser_parse(&parser, ARRAY_SIZE(argv), argv)); return 0; } static int test_unknown_long_option(void) { struct option_parser parser; option_parser_init(&parser, options); const char* argv[] = { "executable", "--an-unknown-long-option" }; ASSERT_INT_EQ(-1, option_parser_parse(&parser, ARRAY_SIZE(argv), argv)); return 0; } static int test_missing_short_value(void) { struct option_parser parser; option_parser_init(&parser, options); const char* argv[] = { "executable", "-v" }; ASSERT_INT_EQ(-1, option_parser_parse(&parser, ARRAY_SIZE(argv), argv)); return 0; } static int test_missing_long_value(void) { struct option_parser parser; option_parser_init(&parser, options); const char* argv[] = { "executable", "--value-option" }; ASSERT_INT_EQ(-1, option_parser_parse(&parser, ARRAY_SIZE(argv), argv)); return 0; } static int test_subcommand_without_arguments(void) { struct option_parser parser; option_parser_init(&parser, options); const char* argv[] = { "executable", "-ab", "first", "second", "third", "do-stuff" }; ASSERT_INT_EQ(0, option_parser_parse(&parser, ARRAY_SIZE(argv), argv)); ASSERT_STR_EQ("do-stuff", option_parser_get_value(&parser, "command")); ASSERT_INT_EQ(1, parser.remaining_argc); ASSERT_STR_EQ("do-stuff", parser.remaining_argv[0]); return 0; } static int test_subcommand_with_arguments(void) { struct option_parser parser; option_parser_init(&parser, options); const char* argv[] = { "executable", "-ab", "first", "second", "third", "do-stuff", "--some-option", "another-argument"}; ASSERT_INT_EQ(0, option_parser_parse(&parser, ARRAY_SIZE(argv), argv)); ASSERT_STR_EQ("do-stuff", option_parser_get_value(&parser, "command")); ASSERT_INT_EQ(3, parser.remaining_argc); ASSERT_STR_EQ("do-stuff", parser.remaining_argv[0]); ASSERT_STR_EQ("another-argument", parser.remaining_argv[2]); return 0; } static int test_defaults_not_set(void) { struct option_parser parser; option_parser_init(&parser, default_options); const char* argv[] = { "executable", "pos 1", }; ASSERT_INT_EQ(0, option_parser_parse(&parser, ARRAY_SIZE(argv), argv)); ASSERT_STR_EQ("pos 1", option_parser_get_value(&parser, "first")); ASSERT_STR_EQ("second_default", option_parser_get_value(&parser, "second")); ASSERT_FALSE(option_parser_get_value_no_default(&parser, "second")); ASSERT_STR_EQ("v_default", option_parser_get_value(&parser, "value-option")); ASSERT_FALSE(option_parser_get_value_no_default(&parser, "value-option")); ASSERT_STR_EQ("v_default", option_parser_get_value(&parser, "v")); ASSERT_FALSE(option_parser_get_value_no_default(&parser, "v")); ASSERT_INT_EQ(0, parser.remaining_argc); ASSERT_FALSE(parser.remaining_argv); return 0; } static int test_defaults_overridden(void) { struct option_parser parser; option_parser_init(&parser, default_options); const char* argv[] = { "executable", "pos 1", "pos 2", "-v", "v_set", }; ASSERT_INT_EQ(0, option_parser_parse(&parser, ARRAY_SIZE(argv), argv)); ASSERT_STR_EQ("pos 1", option_parser_get_value(&parser, "first")); ASSERT_STR_EQ("pos 2", option_parser_get_value(&parser, "second")); ASSERT_STR_EQ("pos 2", option_parser_get_value_no_default(&parser, "second")); ASSERT_STR_EQ("v_set", option_parser_get_value(&parser, "value-option")); ASSERT_STR_EQ("v_set", option_parser_get_value_no_default(&parser, "value-option")); ASSERT_STR_EQ("v_set", option_parser_get_value(&parser, "v")); ASSERT_STR_EQ("v_set", option_parser_get_value_no_default(&parser, "v")); ASSERT_INT_EQ(0, parser.remaining_argc); ASSERT_FALSE(parser.remaining_argv); return 0; } int main() { int r = 0; RUN_TEST(test_simple); RUN_TEST(test_extra_positional_args); RUN_TEST(test_short_value_option_with_space); RUN_TEST(test_short_value_option_without_space); RUN_TEST(test_short_value_option_with_eq); RUN_TEST(test_long_value_option_with_space); RUN_TEST(test_long_value_option_without_space); RUN_TEST(test_multi_short_option); RUN_TEST(test_multi_short_option_with_value); RUN_TEST(test_stop); RUN_TEST(test_unknown_short_option); RUN_TEST(test_unknown_long_option); RUN_TEST(test_missing_short_value); RUN_TEST(test_missing_long_value); RUN_TEST(test_subcommand_without_arguments); RUN_TEST(test_subcommand_with_arguments); RUN_TEST(test_defaults_not_set); RUN_TEST(test_defaults_overridden); return r; }