aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTaylor C. Richberger <taywee@gmx.com>2016-06-14 21:38:52 -0400
committerTaylor C. Richberger <taywee@gmx.com>2016-06-14 21:38:52 -0400
commit8017b5cfece72e5cb3303c720af3314a2a5b2965 (patch)
tree8b5e6ed187fba551236e1dc62ee8fcffea50fd92
parentfixed problem hopefully (diff)
parentbump version number (diff)
downloadargs.hxx-8017b5cfece72e5cb3303c720af3314a2a5b2965.tar.xz
Merge branch '19-disallow-multiple-arguments-for-a-the-same-value-flag' into 'master' 4.2.0
Resolve "Disallow multiple arguments for a the same value flag" Closes #19 See merge request !12
-rw-r--r--Doxyfile2
-rw-r--r--args.hxx34
-rw-r--r--test.cxx30
3 files changed, 60 insertions, 6 deletions
diff --git a/Doxyfile b/Doxyfile
index 51becfa..49b4c39 100644
--- a/Doxyfile
+++ b/Doxyfile
@@ -38,7 +38,7 @@ PROJECT_NAME = "args"
# could be handy for archiving the generated documentation or if some version
# control system is used.
-PROJECT_NUMBER = 4.1.5
+PROJECT_NUMBER = 4.2.0
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
diff --git a/args.hxx b/args.hxx
index ac9ccfc..26cb4f6 100644
--- a/args.hxx
+++ b/args.hxx
@@ -175,6 +175,15 @@ namespace args
virtual ~MapError() {};
};
+ /** Error that occurs when a singular flag is specified multiple times
+ */
+ class ExtraError : public ParseError
+ {
+ public:
+ ExtraError(const std::string &problem) : ParseError(problem) {}
+ virtual ~ExtraError() {};
+ };
+
/** An exception that indicates that the user has requested help
*/
class Help : public Error
@@ -393,11 +402,14 @@ namespace args
*/
class FlagBase : public NamedBase
{
+ private:
+ const bool extraError;
+
protected:
const Matcher matcher;
public:
- FlagBase(const std::string &name, const std::string &help, Matcher &&matcher) : NamedBase(name, help), matcher(std::move(matcher)) {}
+ FlagBase(const std::string &name, const std::string &help, Matcher &&matcher, const bool extraError = false) : NamedBase(name, help), extraError(extraError), matcher(std::move(matcher)) {}
virtual ~FlagBase() {}
@@ -405,6 +417,12 @@ namespace args
{
if (matcher.Match(flag))
{
+ if (extraError && matched)
+ {
+ std::ostringstream problem;
+ problem << "Flag '" << flag << "' was passed multiple times, but should only be allowed to be passed once";
+ throw ExtraError(problem.str());
+ }
matched = true;
return this;
}
@@ -415,6 +433,12 @@ namespace args
{
if (matcher.Match(flag))
{
+ if (extraError && matched)
+ {
+ std::ostringstream problem;
+ problem << "Flag '" << flag << "' was passed multiple times, but should only be allowed to be passed once";
+ throw ExtraError(problem.str());
+ }
matched = true;
return this;
}
@@ -445,7 +469,7 @@ namespace args
class ValueFlagBase : public FlagBase
{
public:
- ValueFlagBase(const std::string &name, const std::string &help, Matcher &&matcher) : FlagBase(name, help, std::move(matcher)) {}
+ ValueFlagBase(const std::string &name, const std::string &help, Matcher &&matcher, const bool extraError = false) : FlagBase(name, help, std::move(matcher), extraError) {}
virtual ~ValueFlagBase() {}
virtual void ParseValue(const std::string &value) = 0;
@@ -1254,7 +1278,7 @@ namespace args
class Flag : public FlagBase
{
public:
- Flag(Group &group, const std::string &name, const std::string &help, Matcher &&matcher): FlagBase(name, help, std::move(matcher))
+ Flag(Group &group, const std::string &name, const std::string &help, Matcher &&matcher, const bool extraError = false): FlagBase(name, help, std::move(matcher), extraError)
{
group.Add(*this);
}
@@ -1389,7 +1413,7 @@ namespace args
public:
- ValueFlag(Group &group, const std::string &name, const std::string &help, Matcher &&matcher, const T &defaultValue = T()): ValueFlagBase(name, help, std::move(matcher)), value(defaultValue)
+ ValueFlag(Group &group, const std::string &name, const std::string &help, Matcher &&matcher, const T &defaultValue = T(), const bool extraError = false): ValueFlagBase(name, help, std::move(matcher), extraError), value(defaultValue)
{
group.Add(*this);
}
@@ -1469,7 +1493,7 @@ namespace args
public:
- MapFlag(Group &group, const std::string &name, const std::string &help, Matcher &&matcher, const Map &map, const T &defaultValue = T()): ValueFlagBase(name, help, std::move(matcher)), map(map), value(defaultValue)
+ MapFlag(Group &group, const std::string &name, const std::string &help, Matcher &&matcher, const Map &map, const T &defaultValue = T(), const bool extraError = false): ValueFlagBase(name, help, std::move(matcher), extraError), map(map), value(defaultValue)
{
group.Add(*this);
}
diff --git a/test.cxx b/test.cxx
index b4c451b..c368bf9 100644
--- a/test.cxx
+++ b/test.cxx
@@ -412,3 +412,33 @@ TEST_CASE("Mapping types work as needed", "[args]")
REQUIRE((args::get(mpl) == std::vector<MappingEnum>{MappingEnum::red, MappingEnum::def}));
REQUIRE_THROWS_AS(parser.ParseArgs(std::vector<std::string>{"--mf=YeLLoW"}), args::MapError);
}
+
+TEST_CASE("An exception should be thrown when a single-argument flag is matched multiple times and the constructor option is specified", "[args]")
+{
+ std::unordered_map<std::string, MappingEnum> map{
+ {"default", MappingEnum::def},
+ {"foo", MappingEnum::foo},
+ {"bar", MappingEnum::bar},
+ {"red", MappingEnum::red},
+ {"yellow", MappingEnum::yellow},
+ {"green", MappingEnum::green}};
+
+ std::ostream null(nullptr);
+ args::ArgumentParser parser("Test command");
+ args::Flag foo(parser, "Foo", "Foo", {'f', "foo"}, true);
+ args::ValueFlag<std::string> bar(parser, "Bar", "Bar", {'b', "bar"}, "", true);
+ args::Flag bix(parser, "Bix", "Bix", {'x', "bix"});
+ args::MapFlag<std::string, MappingEnum> baz(parser, "Baz", "Baz", {'B', "baz"}, map, MappingEnum::def, true);
+ REQUIRE_THROWS_AS(parser.ParseArgs(std::vector<std::string>{"--foo", "-f", "-bblah"}), args::ExtraError);
+ REQUIRE_NOTHROW(parser.ParseArgs(std::vector<std::string>{"--foo", "-xxx", "--bix", "-bblah", "--bix"}));
+ REQUIRE_THROWS_AS(parser.ParseArgs(std::vector<std::string>{"--foo", "-bblah", "-blah"}), args::ExtraError);
+ REQUIRE_THROWS_AS(parser.ParseArgs(std::vector<std::string>{"--foo", "-bblah", "--bar", "blah"}), args::ExtraError);
+ REQUIRE_THROWS_AS(parser.ParseArgs(std::vector<std::string>{"--baz=red", "-B", "yellow"}), args::ExtraError);
+ REQUIRE_THROWS_AS(parser.ParseArgs(std::vector<std::string>{"--baz", "red", "-Byellow"}), args::ExtraError);
+ REQUIRE_NOTHROW(parser.ParseArgs(std::vector<std::string>{"--foo", "-Bgreen"}));
+ REQUIRE(foo);
+ REQUIRE_FALSE(bar);
+ REQUIRE_FALSE(bix);
+ REQUIRE(baz);
+ REQUIRE(args::get(baz) == MappingEnum::green);
+}