From 6f290702a8510fc39aaf9e62abeb4fcb82af496d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Mangano-Tarumi?= Date: Sat, 1 Dec 2018 13:03:44 -0500 Subject: [PATCH] catch getopt's errors --- src/cli.cc | 12 +++++++++--- t/cli.cc | 21 ++++++++++++++++++++- t/opustags.t | 2 +- t/tap.h | 5 ++--- 4 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/cli.cc b/src/cli.cc index e4e2972..cb14c09 100644 --- a/src/cli.cc +++ b/src/cli.cc @@ -17,6 +17,8 @@ #include #include +using namespace std::literals::string_literals; + static const char help_message[] = PROJECT_NAME " version " PROJECT_VERSION R"raw( @@ -59,7 +61,8 @@ ot::status ot::parse_options(int argc, char** argv, ot::options& opt) return {st::bad_arguments, "No arguments specified. Use -h for help."}; int c; - while ((c = getopt_long(argc, argv, "ho:i::yd:a:s:DS", getopt_options, NULL)) != -1) { + optind = 0; + while ((c = getopt_long(argc, argv, ":ho:i::yd:a:s:DS", getopt_options, NULL)) != -1) { switch (c) { case 'h': opt.print_help = true; @@ -104,9 +107,12 @@ ot::status ot::parse_options(int argc, char** argv, ot::options& opt) case 'D': opt.delete_all = true; break; + case ':': + return {st::bad_arguments, + "Missing value for option '"s + argv[optind - 1] + "'."}; default: - /* getopt printed a message */ - return st::bad_arguments; + return {st::bad_arguments, "Unrecognized option '" + + (optopt ? "-"s + static_cast(optopt) : argv[optind - 1]) + "'."}; } } diff --git a/t/cli.cc b/t/cli.cc index 4a5d07d..7ccfc57 100644 --- a/t/cli.cc +++ b/t/cli.cc @@ -18,9 +18,28 @@ void check_read_comments() throw failure("parsed user comments did not match expectations"); } +void check_parse_options() +{ + auto error_case = [](std::vector args, const char* message, const std::string& name) { + ot::options opt; + ot::status rc = parse_options(args.size(), const_cast(args.data()), opt); + if (rc != ot::st::bad_arguments) + throw failure("bad error code when parsing " + name); + if (rc.message != message) + throw failure("bad error message when parsing " + name); + }; + error_case({"opustags", "-a"}, "Missing value for option '-a'.", "short option with missing value"); + error_case({"opustags", "--add"}, "Missing value for option '--add'.", "long option with missing value"); + error_case({"opustags", "-x"}, "Unrecognized option '-x'.", "unrecognized short option"); + error_case({"opustags", "--derp"}, "Unrecognized option '--derp'.", "unrecognized long option"); + error_case({"opustags", "-x=y"}, "Unrecognized option '-x'.", "unrecognized short option with value"); + error_case({"opustags", "--derp=y"}, "Unrecognized option '--derp=y'.", "unrecognized long option with value"); +} + int main(int argc, char **argv) { - std::cout << "1..1\n"; + std::cout << "1..2\n"; run(check_read_comments, "check tags parsing"); + run(check_parse_options, "check options parsing"); return 0; } diff --git a/t/opustags.t b/t/opustags.t index 26f2eaa..9b8e0a7 100644 --- a/t/opustags.t +++ b/t/opustags.t @@ -70,7 +70,7 @@ is_deeply(opustags('--help'), [$expected_help, '', 0], '--help displays the help is_deeply(opustags('-h'), [$expected_help, '', 0], '-h displays the help message too'); is_deeply(opustags('--derp'), ['', <<"EOF", 256], 'unrecognized option shows an error'); -$opustags: unrecognized option '--derp' +error: Unrecognized option '--derp'. EOF #################################################################################################### diff --git a/t/tap.h b/t/tap.h index 709b4fa..b75c044 100644 --- a/t/tap.h +++ b/t/tap.h @@ -10,9 +10,8 @@ #include #include -class failure : public std::runtime_error { -public: - failure(const char *message) : std::runtime_error(message) {} +struct failure : std::runtime_error { + failure(const std::string& what) : std::runtime_error(what) {} }; template