#include "common.hh" #include "args.hh" #include #include #include #include #include namespace { bool run(Args* args, std::vector const& argv, std::ostream& err, std::vector* out) { auto ptrs = std::make_unique(argv.size()); for (size_t i = 0; i < argv.size(); ++i) ptrs[i] = const_cast(argv[i].c_str()); return args->run(argv.size(), ptrs.get(), argv.empty() ? "test" : argv[0], err, out); } } // namespace TEST(args, empty) { auto args = Args::create(); std::vector argv; std::stringstream err; std::vector arguments; EXPECT_TRUE(run(args.get(), argv, err, &arguments)); EXPECT_TRUE(err.str().empty()); EXPECT_TRUE(arguments.empty()); } TEST(args, only_arguments) { auto args = Args::create(); auto* help = args->add_option('h', "help", ""); auto* config = args->add_option_with_arg('C', "config", "", ""); std::vector argv{"test", "foo", "bar"}; std::stringstream err; std::vector arguments; EXPECT_TRUE(run(args.get(), argv, err, &arguments)); EXPECT_TRUE(err.str().empty()); EXPECT_FALSE(help->is_set()); EXPECT_FALSE(config->is_set()); ASSERT_EQ(2, arguments.size()); EXPECT_EQ("foo", arguments[0]); EXPECT_EQ("bar", arguments[1]); } TEST(args, everything) { auto args = Args::create(); auto* help = args->add_option('h', "help", ""); auto* config = args->add_option_with_arg('C', "config", "", ""); std::vector argv{"test", "--help", "-C", "config.txt", "arg"}; std::stringstream err; std::vector arguments; EXPECT_TRUE(run(args.get(), argv, err, &arguments)); EXPECT_TRUE(err.str().empty()); EXPECT_TRUE(help->is_set()); EXPECT_TRUE(config->is_set()); EXPECT_EQ("config.txt", config->arg()); ASSERT_EQ(1, arguments.size()); EXPECT_EQ("arg", arguments[0]); } TEST(args, option_with_arg_short) { auto args = Args::create(); auto* config = args->add_option_with_arg('C', "config", "", ""); std::vector argv{"test", "-C", "config.txt"}; std::stringstream err; std::vector arguments; EXPECT_TRUE(run(args.get(), argv, err, &arguments)); EXPECT_TRUE(err.str().empty()); EXPECT_TRUE(config->is_set()); EXPECT_EQ("config.txt", config->arg()); EXPECT_TRUE(arguments.empty()); } TEST(args, option_with_arg_long_1) { auto args = Args::create(); auto* config = args->add_option_with_arg('C', "config", "", ""); std::vector argv{"test", "--config", "config.txt"}; std::stringstream err; std::vector arguments; EXPECT_TRUE(run(args.get(), argv, err, &arguments)); EXPECT_TRUE(err.str().empty()); EXPECT_TRUE(config->is_set()); EXPECT_EQ("config.txt", config->arg()); EXPECT_TRUE(arguments.empty()); } TEST(args, option_with_arg_long_2) { auto args = Args::create(); auto* config = args->add_option_with_arg('C', "config", "", ""); std::vector argv{"test", "--config=config.txt"}; std::stringstream err; std::vector arguments; EXPECT_TRUE(run(args.get(), argv, err, &arguments)); EXPECT_TRUE(err.str().empty()); EXPECT_TRUE(config->is_set()); EXPECT_EQ("config.txt", config->arg()); EXPECT_TRUE(arguments.empty()); } TEST(args, multiple_options_with_args) { auto args = Args::create(); auto* config = args->add_option_with_arg('C', "config", "", ""); auto* pid = args->add_option_with_arg('p', "pid", "", ""); std::vector argv{"test", "-Cp", "config.txt", "pid"}; std::stringstream err; std::vector arguments; EXPECT_TRUE(run(args.get(), argv, err, &arguments)); EXPECT_TRUE(err.str().empty()); EXPECT_TRUE(config->is_set()); EXPECT_EQ("config.txt", config->arg()); EXPECT_TRUE(pid->is_set()); EXPECT_EQ("pid", pid->arg()); EXPECT_TRUE(arguments.empty()); } TEST(args, end_of_options) { auto args = Args::create(); auto* config = args->add_option_with_arg('C', "config", "", ""); std::vector argv{"test", "--", "--config", "-C"}; std::stringstream err; std::vector arguments; EXPECT_TRUE(run(args.get(), argv, err, &arguments)); EXPECT_TRUE(err.str().empty()); EXPECT_FALSE(config->is_set()); ASSERT_EQ(2, arguments.size()); EXPECT_EQ("--config", arguments[0]); EXPECT_EQ("-C", arguments[1]); } TEST(args, unknown_long_option) { auto args = Args::create(); std::vector argv{"test", "--help"}; std::stringstream err; std::vector arguments; EXPECT_FALSE(run(args.get(), argv, err, &arguments)); EXPECT_EQ("test: unrecognized option '--help'\n", err.str()); } TEST(args, unknown_short_option) { auto args = Args::create(); std::vector argv{"test", "-H"}; std::stringstream err; std::vector arguments; EXPECT_FALSE(run(args.get(), argv, err, &arguments)); EXPECT_EQ("test: invalid option -- 'H'\n", err.str()); } TEST(args, option_not_expecting_argument) { auto args = Args::create(); args->add_option('h', "help", ""); std::vector argv{"test", "--help=foo"}; std::stringstream err; std::vector arguments; EXPECT_FALSE(run(args.get(), argv, err, &arguments)); EXPECT_EQ("test: option '--help' doesn't allow an argument\n", err.str()); } TEST(args, short_option_expecting_argument) { auto args = Args::create(); args->add_option_with_arg('C', "config", "", ""); std::vector argv{"test", "-C"}; std::stringstream err; std::vector arguments; EXPECT_FALSE(run(args.get(), argv, err, &arguments)); EXPECT_EQ("test: option requires an argument -- 'C'\n", err.str()); } TEST(args, long_option_expecting_argument) { auto args = Args::create(); args->add_option_with_arg('C', "config", "", ""); std::vector argv{"test", "--config"}; std::stringstream err; std::vector arguments; EXPECT_FALSE(run(args.get(), argv, err, &arguments)); EXPECT_EQ("test: option '--config' requires an argument\n", err.str()); } TEST(args, descriptions) { auto args = Args::create(); args->add_option('h', "help", "display this text and exit."); args->add_option_with_arg( 'C', "config", "use FILE instead of the default", "FILE"); std::stringstream out; // if the text fits it is (which is does) 80 is always used. args->print_descriptions(out, 60); EXPECT_EQ(" -h, --help " "display this text and exit.\n" " -C, --config=FILE " "use FILE instead of the default\n", out.str()); } TEST(args, descriptions_only_long_or_short) { auto args = Args::create(); args->add_option('\0', "help", "display this text and exit."); args->add_option_with_arg( 'C', "", "use FILE instead of the default", "FILE"); std::stringstream out; // if the text fits it is (which is does) 80 is always used. args->print_descriptions(out, 60); EXPECT_EQ(" --help " "display this text and exit.\n" " -C FILE " "use FILE instead of the default\n", out.str()); } TEST(args, descriptions_wrap) { auto args = Args::create(); args->add_option('h', "help", "display this text and exit."); args->add_option_with_arg( 'C', "config", "use FILE instead of the default", "FILE"); std::stringstream out; args->print_descriptions(out, 45); EXPECT_EQ(" -h, --help display this text and\n" " exit.\n" " -C, --config=FILE use FILE instead of the\n" " default\n", out.str()); } TEST(args, descriptions_multiline_wrap) { auto args = Args::create(); args->add_option('h', "help", "display this text and exit." " Or not, I'm not the boss of you." " But you really should be doing something with your life."); std::stringstream out; args->print_descriptions(out, 45); EXPECT_EQ(" -h, --help display this text and exit. Or\n" " not, I'm not the boss of you.\n" " But you really should be doing\n" " something with your life.\n", out.str()); } TEST(args, descriptions_wrap_too_long_word) { auto args = Args::create(); args->add_option('h', "help", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); std::stringstream out; args->print_descriptions(out, 40); EXPECT_EQ(" -h, --help aaaaaaaaaaaaaaaaaaaaaaaaaa\n" " aaaaaaaaaaaaaaaaaaa\n", out.str()); } TEST(args, descriptions_fallback) { auto args = Args::create(); args->add_option('h', "help", "display this text and exit."); args->add_option_with_arg( 'C', "config", "use FILE instead of the default", "FILE"); std::stringstream out; args->print_descriptions(out, 40); EXPECT_EQ("-h, --help\n" "display this text and exit.\n" "-C, --config=FILE\n" "use FILE instead of the default\n", out.str()); }