aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPavel Belikov <pavel.fuchs.belikov@gmail.com>2017-11-08 22:25:08 +0300
committerPavel Belikov <pavel.fuchs.belikov@gmail.com>2017-11-08 22:25:08 +0300
commit2477df98fadc281e55fab806ee9c7f6f47f1e661 (patch)
tree375c428d618bda0792386054b7943c7763737a6b
parentreplace badges with Taywee ones so the repository is properly described by it... (diff)
downloadargs.hxx-2477df98fadc281e55fab806ee9c7f6f47f1e661.tar.xz
add validation for commands
-rw-r--r--args.hxx55
-rw-r--r--test.cxx40
2 files changed, 87 insertions, 8 deletions
diff --git a/args.hxx b/args.hxx
index 4eff869..c290d6b 100644
--- a/args.hxx
+++ b/args.hxx
@@ -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());
}
diff --git a/test.cxx b/test.cxx
index 135d1ee..7f92f26 100644
--- a/test.cxx
+++ b/test.cxx
@@ -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