diff options
author | Pavel Belikov <pavel.fuchs.belikov@gmail.com> | 2017-11-08 22:25:08 +0300 |
---|---|---|
committer | Pavel Belikov <pavel.fuchs.belikov@gmail.com> | 2017-11-08 22:25:08 +0300 |
commit | 2477df98fadc281e55fab806ee9c7f6f47f1e661 (patch) | |
tree | 375c428d618bda0792386054b7943c7763737a6b | |
parent | replace badges with Taywee ones so the repository is properly described by it... (diff) | |
download | args.hxx-2477df98fadc281e55fab806ee9c7f6f47f1e661.tar.xz |
add validation for commands
-rw-r--r-- | args.hxx | 55 | ||||
-rw-r--r-- | test.cxx | 40 |
2 files changed, 87 insertions, 8 deletions
@@ -527,7 +527,7 @@ namespace args const std::string help; #ifdef ARGS_NOEXCEPT /// Only for ARGS_NOEXCEPT - Error error; + mutable Error error; #endif public: @@ -544,7 +544,7 @@ namespace args return matched; } - virtual void Validate(const std::string &, const std::string &) + virtual void Validate(const std::string &, const std::string &) const { } @@ -674,7 +674,7 @@ namespace args #ifndef ARGS_NOEXCEPT if (max < min) { - throw std::invalid_argument("Nargs: max > min"); + throw UsageError("Nargs: max > min"); } #endif } @@ -718,7 +718,7 @@ namespace args return nullptr; } - virtual void Validate(const std::string &shortPrefix, const std::string &longPrefix) override + virtual void Validate(const std::string &shortPrefix, const std::string &longPrefix) const override { if (!Matched() && (GetOptions() & Options::Required) != Options::None) { @@ -758,6 +758,20 @@ namespace args return true; } +#ifdef ARGS_NOEXCEPT + /// Only for ARGS_NOEXCEPT + virtual Error GetError() const override + { + const auto nargs = NumberOfArguments(); + if (nargs.min > nargs.max) + { + return Error::Usage; + } + + return error; + } +#endif + /** Defines how many values can be consumed by this option. * * \return closed interval [min, max] @@ -847,7 +861,7 @@ namespace args return { "[" + Name() + ']' }; } - virtual void Validate(const std::string &, const std::string &) override + virtual void Validate(const std::string &, const std::string &) const override { if ((GetOptions() & Options::Required) != Options::None && !Matched()) { @@ -962,7 +976,7 @@ namespace args return nullptr; } - virtual void Validate(const std::string &shortPrefix, const std::string &longPrefix) override + virtual void Validate(const std::string &shortPrefix, const std::string &longPrefix) const override { for (Base *child: Children()) { @@ -1207,6 +1221,7 @@ namespace args mutable std::vector<std::string> subparserProgramLine; mutable bool subparserHasFlag = false; mutable bool subparserHasPositional = false; + mutable bool subparserHasCommand = false; mutable Subparser *subparser = nullptr; protected: @@ -1431,7 +1446,7 @@ namespace args auto res = Group::GetProgramLine(params); res.insert(res.end(), subparserProgramLine.begin(), subparserProgramLine.end()); - if (!params.proglineCommand.empty() && Group::HasCommand()) + if (!params.proglineCommand.empty() && (Group::HasCommand() || subparserHasCommand)) { res.insert(res.begin(), commandIsRequired ? params.proglineCommand : "[" + params.proglineCommand + "]"); } @@ -1577,8 +1592,13 @@ namespace args return descriptions; } - virtual void Validate(const std::string &shortprefix, const std::string &longprefix) override + virtual void Validate(const std::string &shortprefix, const std::string &longprefix) const override { + if (!Matched()) + { + return; + } + for (Base *child: Children()) { if (child->IsGroup() && !child->Matched()) @@ -1594,6 +1614,22 @@ namespace args child->Validate(shortprefix, longprefix); } + + if (subparser != nullptr) + { + subparser->Validate(shortprefix, longprefix); + } + + if (selectedCommand == nullptr && commandIsRequired && (Group::HasCommand() || subparserHasCommand)) + { +#ifdef ARGS_NOEXCEPT + error = Error::Validation; +#else + std::ostringstream problem; + problem << "Command is required"; + throw ValidationError(problem.str()); +#endif + } } virtual void Reset() noexcept override @@ -1604,6 +1640,7 @@ namespace args subparserDescription.clear(); subparserHasFlag = false; subparserHasPositional = false; + subparserHasCommand = false; } }; @@ -2207,6 +2244,7 @@ namespace args command.subparserDescription = GetDescription(helpParams, 0); command.subparserHasFlag = HasFlag(); command.subparserHasPositional = HasPositional(); + command.subparserHasCommand = HasCommand(); command.subparserProgramLine = GetProgramLine(helpParams); if (parser == nullptr) { @@ -2219,6 +2257,7 @@ namespace args } auto it = parser->Parse(args.begin(), args.end()); + command.Validate(parser->ShortPrefix(), parser->LongPrefix()); kicked.assign(it, args.end()); } @@ -857,6 +857,46 @@ TEST_CASE("Subparser help works as expected", "[args]") } +TEST_CASE("Subparser validation works as expected", "[args]") +{ + args::ArgumentParser p("parser"); + args::Command a(p, "a", "command a", [](args::Subparser &s) + { + args::ValueFlag<std::string> f(s, "", "", {'f'}, args::Options::Required); + s.Parse(); + }); + + args::Command b(p, "b", "command b"); + args::ValueFlag<std::string> f(b, "", "", {'f'}, args::Options::Required); + + REQUIRE_NOTHROW(p.ParseArgs(std::vector<std::string>{})); + REQUIRE_THROWS_AS(p.ParseArgs(std::vector<std::string>{"a"}), args::RequiredError); + REQUIRE_NOTHROW(p.ParseArgs(std::vector<std::string>{"a", "-f", "F"})); + REQUIRE_THROWS_AS(p.ParseArgs(std::vector<std::string>{"b"}), args::RequiredError); + REQUIRE_NOTHROW(p.ParseArgs(std::vector<std::string>{"b", "-f", "F"})); + + p.RequireCommand(true); + REQUIRE_THROWS_AS(p.ParseArgs(std::vector<std::string>{}), args::ValidationError); + + p.RequireCommand(false); + REQUIRE_NOTHROW(p.ParseArgs(std::vector<std::string>{})); +} + +TEST_CASE("Global options work as expected", "[args]") +{ + args::Group globals; + args::Flag f(globals, "f", "f", {'f'}); + + args::ArgumentParser p("parser"); + args::GlobalOptions g(p, globals); + args::Command a(p, "a", "command a"); + args::Command b(p, "b", "command b"); + + REQUIRE_NOTHROW(p.ParseArgs(std::vector<std::string>{"-f"})); + REQUIRE_NOTHROW(p.ParseArgs(std::vector<std::string>{"a", "-f"})); + REQUIRE_NOTHROW(p.ParseArgs(std::vector<std::string>{"b", "-f"})); +} + #undef ARGS_HXX #define ARGS_TESTNAMESPACE #define ARGS_NOEXCEPT |