aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTaylor C. Richberger <Taywee@gmx.com>2016-06-30 12:15:20 -0600
committerTaylor C. Richberger <Taywee@gmx.com>2016-06-30 12:15:20 -0600
commitf4fd39821ac05baabfe13590e9b71e3088a77bc4 (patch)
treec24993b7a166693f708f3b1c7ec45e6ffcbbdccb
parentadd proglinepostfix to gitlike (diff)
downloadargs.hxx-f4fd39821ac05baabfe13590e9b71e3088a77bc4.tar.xz
add noexcept functionality5.1.0
-rw-r--r--Doxyfile2
-rw-r--r--args.hxx292
-rw-r--r--test.cxx69
3 files changed, 299 insertions, 64 deletions
diff --git a/Doxyfile b/Doxyfile
index 26d547e..1ba8d5e 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 = 5.0.0
+PROJECT_NUMBER = 5.1.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 6d5be60..5f8dec8 100644
--- a/args.hxx
+++ b/args.hxx
@@ -36,11 +36,17 @@
#include <unordered_set>
#include <type_traits>
+#ifdef ARGS_TESTNAMESPACE
+namespace argstest
+{
+#else
+
/** \namespace args
* \brief contains all the functionality of the args library
*/
namespace args
{
+#endif
/** Getter to grab the value from the argument type.
*
* If the Get() function of the type returns a reference, so does this, and
@@ -139,6 +145,18 @@ namespace args
return output;
}
+#ifdef ARGS_NOEXCEPT
+ enum class Error
+ {
+ None,
+ Usage,
+ Parse,
+ Validation,
+ Map,
+ Extra,
+ Help
+ };
+#else
/** Base error class
*/
class Error : public std::runtime_error
@@ -148,6 +166,15 @@ namespace args
virtual ~Error() {};
};
+ /** Errors that occur during usage
+ */
+ class UsageError : public Error
+ {
+ public:
+ UsageError(const std::string &problem) : Error(problem) {}
+ virtual ~UsageError() {};
+ };
+
/** Errors that occur during regular parsing
*/
class ParseError : public Error
@@ -192,6 +219,7 @@ namespace args
Help(const std::string &flag) : Error(flag) {}
virtual ~Help() {};
};
+#endif
/** A simple unified option type for unified initializer lists for the Matcher class.
*/
@@ -346,6 +374,9 @@ namespace args
protected:
bool matched;
const std::string help;
+#ifdef ARGS_NOEXCEPT
+ Error error;
+#endif
public:
Base(const std::string &help) : matched(false), help(help) {}
@@ -368,10 +399,20 @@ namespace args
return description;
}
- virtual void ResetMatched()
+ virtual void Reset() noexcept
{
matched = false;
+#ifdef ARGS_NOEXCEPT
+ error = Error::None;
+#endif
}
+
+#ifdef ARGS_NOEXCEPT
+ virtual Error GetError() const
+ {
+ return error;
+ }
+#endif
};
/** Base class for all match types that have a name
@@ -432,9 +473,13 @@ namespace args
{
if (extraError && matched)
{
+#ifdef ARGS_NOEXCEPT
+ error = Error::Extra;
+#else
std::ostringstream problem;
problem << "Flag '" << flag << "' was passed multiple times, but is only allowed to be passed once";
throw ExtraError(problem.str());
+#endif
}
matched = true;
return this;
@@ -448,9 +493,13 @@ namespace args
{
if (extraError && matched)
{
+#ifdef ARGS_NOEXCEPT
+ error = Error::Extra;
+#else
std::ostringstream problem;
problem << "Flag '" << flag << "' was passed multiple times, but is only allowed to be passed once";
throw ExtraError(problem.str());
+#endif
}
matched = true;
return this;
@@ -545,33 +594,8 @@ namespace args
* \param flag The flag with prefixes stripped
* \return the first matching FlagBase pointer, or nullptr if there is no match
*/
- FlagBase *Match(const std::string &flag)
- {
- for (Base *child: children)
- {
- if (FlagBase *flagBase = dynamic_cast<FlagBase *>(child))
- {
- if (FlagBase *match = flagBase->Match(flag))
- {
- return match;
- }
- } else if (Group *group = dynamic_cast<Group *>(child))
- {
- if (FlagBase *match = group->Match(flag))
- {
- return match;
- }
- }
- }
- return nullptr;
- }
-
- /** Return the first FlagBase that matches flag, or nullptr
- *
- * \param flag The flag with prefixes stripped
- * \return the first matching FlagBase pointer, or nullptr if there is no match
- */
- FlagBase *Match(const char flag)
+ template <typename T>
+ FlagBase *Match(const T &flag)
{
for (Base *child: children)
{
@@ -655,15 +679,7 @@ namespace args
*/
std::vector<Base *>::size_type MatchedChildren() const
{
- std::vector<Base *>::size_type sum = 0;
- for (const Base * child: children)
- {
- if (child->Matched())
- {
- ++sum;
- }
- }
- return sum;
+ return std::count_if(std::begin(children), std::end(children), [](const Base *child){return child->Matched();});
}
/** Whether or not this group matches validation
@@ -732,13 +748,35 @@ namespace args
return names;
}
- virtual void ResetMatched() override
+ virtual void Reset() noexcept override
{
for (auto &child: children)
{
- child->ResetMatched();
+ child->Reset();
+ }
+#ifdef ARGS_NOEXCEPT
+ error = Error::None;
+#endif
+ }
+
+#ifdef ARGS_NOEXCEPT
+ virtual Error GetError() const override
+ {
+ if (error != Error::None)
+ {
+ return error;
+ }
+
+ auto it = std::find_if(std::begin(children), std::end(children), [](const Base *child){return child->GetError() != Error::None;});
+ if (it == std::end(children))
+ {
+ return Error::None;
+ } else
+ {
+ return (*it)->GetError();
}
}
+#endif
/** Default validators
*/
@@ -943,9 +981,15 @@ namespace args
{
if (longseparator.empty())
{
- throw std::runtime_error("longseparator can not be set to empty");
+#ifdef ARGS_NOEXCEPT
+ error = Error::Usage;
+#else
+ throw UsageError("longseparator can not be set to empty");
+#endif
+ } else
+ {
+ this->longseparator = longseparator;
}
- this->longseparator = longseparator;
}
/** The terminator that forcibly separates flags from positionals
@@ -1111,8 +1155,8 @@ namespace args
template <typename It>
It ParseArgs(It begin, It end)
{
- // Reset all Matched statuses to false, for validation. Don't reset values.
- ResetMatched();
+ // Reset all Matched statuses and errors
+ Reset();
bool terminated = false;
// Check all arg chunks
@@ -1145,18 +1189,28 @@ namespace args
argbase->ParseValue(argchunk.substr(separator + longseparator.size()));
} else
{
+#ifdef ARGS_NOEXCEPT
+ error = Error::Parse;
+ return it;
+#else
std::ostringstream problem;
problem << "Flag '" << arg << "' was passed a joined argument, but these are disallowed";
throw ParseError(problem.str());
+#endif
}
} else
{
++it;
if (it == end)
{
+#ifdef ARGS_NOEXCEPT
+ error = Error::Parse;
+ return it;
+#else
std::ostringstream problem;
problem << "Flag '" << arg << "' requires an argument but received none";
throw ParseError(problem.str());
+#endif
}
if (allowSeparateLongValue)
@@ -1164,16 +1218,26 @@ namespace args
argbase->ParseValue(*it);
} else
{
+#ifdef ARGS_NOEXCEPT
+ error = Error::Parse;
+ return it;
+#else
std::ostringstream problem;
problem << "Flag '" << arg << "' was passed a separate argument, but these are disallowed";
throw ParseError(problem.str());
+#endif
}
}
} else if (separator != argchunk.npos)
{
+#ifdef ARGS_NOEXCEPT
+ error = Error::Parse;
+ return it;
+#else
std::ostringstream problem;
problem << "Passed an argument into a non-argument flag: " << chunk;
throw ParseError(problem.str());
+#endif
}
if (base->KickOut())
@@ -1182,9 +1246,14 @@ namespace args
}
} else
{
+#ifdef ARGS_NOEXCEPT
+ error = Error::Parse;
+ return it;
+#else
std::ostringstream problem;
problem << "Flag could not be matched: " << arg;
throw ParseError(problem.str());
+#endif
}
// Check short args
} else if (!terminated && chunk.find(shortprefix) == 0 && chunk.size() > shortprefix.size())
@@ -1206,18 +1275,28 @@ namespace args
argbase->ParseValue(value);
} else
{
+#ifdef ARGS_NOEXCEPT
+ error = Error::Parse;
+ return it;
+#else
std::ostringstream problem;
problem << "Flag '" << arg << "' was passed a joined argument, but these are disallowed";
throw ParseError(problem.str());
+#endif
}
} else
{
++it;
if (it == end)
{
+#ifdef ARGS_NOEXCEPT
+ error = Error::Parse;
+ return it;
+#else
std::ostringstream problem;
problem << "Flag '" << arg << "' requires an argument but received none";
throw ParseError(problem.str());
+#endif
}
if (allowSeparateShortValue)
@@ -1225,9 +1304,14 @@ namespace args
argbase->ParseValue(*it);
} else
{
+#ifdef ARGS_NOEXCEPT
+ error = Error::Parse;
+ return it;
+#else
std::ostringstream problem;
problem << "Flag '" << arg << "' was passed a separate argument, but these are disallowed";
throw ParseError(problem.str());
+#endif
}
}
// Because this argchunk is done regardless
@@ -1240,9 +1324,14 @@ namespace args
}
} else
{
+#ifdef ARGS_NOEXCEPT
+ error = Error::Parse;
+ return it;
+#else
std::ostringstream problem;
problem << "Flag could not be matched: '" << arg << "'";
throw ParseError(problem.str());
+#endif
}
}
} else
@@ -1258,17 +1347,26 @@ namespace args
}
} else
{
+#ifdef ARGS_NOEXCEPT
+ error = Error::Parse;
+ return it;
+#else
std::ostringstream problem;
problem << "Passed in argument, but no positional arguments were ready to receive it: " << chunk;
throw ParseError(problem.str());
+#endif
}
}
}
if (!Matched())
{
+#ifdef ARGS_NOEXCEPT
+ error = Error::Validation;
+#else
std::ostringstream problem;
problem << "Group validation failed somewhere!";
throw ValidationError(problem.str());
+#endif
}
return end;
}
@@ -1342,7 +1440,12 @@ namespace args
{
if (FlagBase::Match(arg))
{
+#ifdef ARGS_NOEXCEPT
+ error = Error::Help;
+#else
throw Help(arg);
+#endif
+ return this;
}
return nullptr;
}
@@ -1351,7 +1454,12 @@ namespace args
{
if (FlagBase::Match(arg))
{
+#ifdef ARGS_NOEXCEPT
+ error = Error::Help;
+#else
throw Help(std::string(1, arg));
+#endif
+ return this;
}
return nullptr;
}
@@ -1410,17 +1518,22 @@ namespace args
* raises a ParseError if there are any characters left.
*/
template <typename T>
- void ValueReader(const std::string &name, const std::string &value, T &destination)
+ bool ValueReader(const std::string &name, const std::string &value, T &destination)
{
std::istringstream ss(value);
ss >> destination;
if (ss.rdbuf()->in_avail() > 0)
{
+#ifdef ARGS_NOEXCEPT
+ return false;
+#else
std::ostringstream problem;
problem << "Argument '" << name << "' received invalid value type '" << value << "'";
throw ParseError(problem.str());
+#endif
}
+ return true;
}
/** std::string specialization for ValueReader
@@ -1429,9 +1542,10 @@ namespace args
* it is more efficient to ust copy a string into the destination.
*/
template <>
- void ValueReader<std::string>(const std::string &name, const std::string &value, std::string &destination)
+ bool ValueReader<std::string>(const std::string &name, const std::string &value, std::string &destination)
{
destination.assign(value);
+ return true;
}
/** An argument-accepting flag class
@@ -1439,7 +1553,7 @@ namespace args
* \tparam T the type to extract the argument as
* \tparam Reader The function used to read the argument, taking the name, value, and destination reference
*/
- template <typename T, void (*Reader)(const std::string &, const std::string &, T&) = ValueReader<T>>
+ template <typename T, bool (*Reader)(const std::string &, const std::string &, T&) = ValueReader<T>>
class ValueFlag : public ValueFlagBase
{
private:
@@ -1456,7 +1570,12 @@ namespace args
virtual void ParseValue(const std::string &value) override
{
- Reader(name, value, this->value);
+ if (!Reader(name, value, this->value))
+ {
+#ifdef ARGS_NOEXCEPT
+ error = Error::Parse;
+#endif
+ }
}
/** Get the value
@@ -1476,7 +1595,7 @@ namespace args
template <
typename T,
typename List = std::vector<T>,
- void (*Reader)(const std::string &, const std::string &, T&) = ValueReader<T>>
+ bool (*Reader)(const std::string &, const std::string &, T&) = ValueReader<T>>
class ValueFlagList : public ValueFlagBase
{
private:
@@ -1494,7 +1613,12 @@ namespace args
virtual void ParseValue(const std::string &value) override
{
T v;
- Reader(name, value, v);
+ if (!Reader(name, value, v))
+ {
+#ifdef ARGS_NOEXCEPT
+ error = Error::Parse;
+#endif
+ }
values.insert(std::end(values), v);
}
@@ -1518,7 +1642,7 @@ namespace args
* \tparam Reader The function used to read the argument into the key type, taking the name, value, and destination reference
* \tparam Map The Map type. Should operate like std::map or std::unordered_map
*/
- template <typename K, typename T, void (*Reader)(const std::string &, const std::string &, K&) = ValueReader<K>, typename Map = std::unordered_map<K, T>>
+ template <typename K, typename T, bool (*Reader)(const std::string &, const std::string &, K&) = ValueReader<K>, typename Map = std::unordered_map<K, T>>
class MapFlag : public ValueFlagBase
{
private:
@@ -1537,13 +1661,22 @@ namespace args
virtual void ParseValue(const std::string &value) override
{
K key;
- Reader(name, value, key);
+ if (!Reader(name, value, key))
+ {
+#ifdef ARGS_NOEXCEPT
+ error = Error::Parse;
+#endif
+ }
auto it = map.find(key);
if (it == std::end(map))
{
+#ifdef ARGS_NOEXCEPT
+ error = Error::Map;
+#else
std::ostringstream problem;
problem << "Could not find key '" << key << "' in map for arg '" << name << "'";
throw MapError(problem.str());
+#endif
} else
{
this->value = it->second;
@@ -1566,7 +1699,7 @@ namespace args
* \tparam Reader The function used to read the argument into the key type, taking the name, value, and destination reference
* \tparam Map The Map type. Should operate like std::map or std::unordered_map
*/
- template <typename K, typename T, typename List = std::vector<T>, void (*Reader)(const std::string &, const std::string &, K&) = ValueReader<K>, typename Map = std::unordered_map<K, T>>
+ template <typename K, typename T, typename List = std::vector<T>, bool (*Reader)(const std::string &, const std::string &, K&) = ValueReader<K>, typename Map = std::unordered_map<K, T>>
class MapFlagList : public ValueFlagBase
{
private:
@@ -1585,13 +1718,22 @@ namespace args
virtual void ParseValue(const std::string &value) override
{
K key;
- Reader(name, value, key);
+ if (!Reader(name, value, key))
+ {
+#ifdef ARGS_NOEXCEPT
+ error = Error::Parse;
+#endif
+ }
auto it = map.find(key);
if (it == std::end(map))
{
+#ifdef ARGS_NOEXCEPT
+ error = Error::Map;
+#else
std::ostringstream problem;
problem << "Could not find key '" << key << "' in map for arg '" << name << "'";
throw MapError(problem.str());
+#endif
} else
{
this->values.emplace_back(it->second);
@@ -1616,7 +1758,7 @@ namespace args
* \tparam T the type to extract the argument as
* \tparam Reader The function used to read the argument, taking the name, value, and destination reference
*/
- template <typename T, void (*Reader)(const std::string &, const std::string &, T&) = ValueReader<T>>
+ template <typename T, bool (*Reader)(const std::string &, const std::string &, T&) = ValueReader<T>>
class Positional : public PositionalBase
{
private:
@@ -1631,7 +1773,12 @@ namespace args
virtual void ParseValue(const std::string &value) override
{
- Reader(name, value, this->value);
+ if (!Reader(name, value, this->value))
+ {
+#ifdef ARGS_NOEXCEPT
+ error = Error::Parse;
+#endif
+ }
ready = false;
matched = true;
}
@@ -1653,7 +1800,7 @@ namespace args
template <
typename T,
typename List = std::vector<T>,
- void (*Reader)(const std::string &, const std::string &, T&) = ValueReader<T>>
+ bool (*Reader)(const std::string &, const std::string &, T&) = ValueReader<T>>
class PositionalList : public PositionalBase
{
private:
@@ -1670,7 +1817,12 @@ namespace args
virtual void ParseValue(const std::string &value) override
{
T v;
- Reader(name, value, v);
+ if (!Reader(name, value, v))
+ {
+#ifdef ARGS_NOEXCEPT
+ error = Error::Parse;
+#endif
+ }
values.insert(std::end(values), v);
matched = true;
}
@@ -1695,7 +1847,7 @@ namespace args
* \tparam Reader The function used to read the argument into the key type, taking the name, value, and destination reference
* \tparam Map The Map type. Should operate like std::map or std::unordered_map
*/
- template <typename K, typename T, void (*Reader)(const std::string &, const std::string &, K&) = ValueReader<K>, typename Map = std::unordered_map<K, T>>
+ template <typename K, typename T, bool (*Reader)(const std::string &, const std::string &, K&) = ValueReader<K>, typename Map = std::unordered_map<K, T>>
class MapPositional : public PositionalBase
{
private:
@@ -1714,13 +1866,22 @@ namespace args
virtual void ParseValue(const std::string &value) override
{
K key;
- Reader(name, value, key);
+ if (!Reader(name, value, key))
+ {
+#ifdef ARGS_NOEXCEPT
+ error = Error::Parse;
+#endif
+ }
auto it = map.find(key);
if (it == std::end(map))
{
+#ifdef ARGS_NOEXCEPT
+ error = Error::Map;
+#else
std::ostringstream problem;
problem << "Could not find key '" << key << "' in map for arg '" << name << "'";
throw MapError(problem.str());
+#endif
} else
{
this->value = it->second;
@@ -1745,7 +1906,7 @@ namespace args
* \tparam Reader The function used to read the argument into the key type, taking the name, value, and destination reference
* \tparam Map The Map type. Should operate like std::map or std::unordered_map
*/
- template <typename K, typename T, typename List = std::vector<T>, void (*Reader)(const std::string &, const std::string &, K&) = ValueReader<K>, typename Map = std::unordered_map<K, T>>
+ template <typename K, typename T, typename List = std::vector<T>, bool (*Reader)(const std::string &, const std::string &, K&) = ValueReader<K>, typename Map = std::unordered_map<K, T>>
class MapPositionalList : public PositionalBase
{
private:
@@ -1764,13 +1925,22 @@ namespace args
virtual void ParseValue(const std::string &value) override
{
K key;
- Reader(name, value, key);
+ if (!Reader(name, value, key))
+ {
+#ifdef ARGS_NOEXCEPT
+ error = Error::Parse;
+#endif
+ }
auto it = map.find(key);
if (it == std::end(map))
{
+#ifdef ARGS_NOEXCEPT
+ error = Error::Map;
+#else
std::ostringstream problem;
problem << "Could not find key '" << key << "' in map for arg '" << name << "'";
throw MapError(problem.str());
+#endif
} else
{
this->values.emplace_back(it->second);
diff --git a/test.cxx b/test.cxx
index 8113943..b4cc9fc 100644
--- a/test.cxx
+++ b/test.cxx
@@ -251,11 +251,12 @@ TEST_CASE("Argument groups should nest", "[args]")
REQUIRE_THROWS_AS(parser.ParseArgs(std::vector<std::string>{"-a", "-dg"}), args::ValidationError);
}
-void DoublesReader(const std::string &name, const std::string &value, std::tuple<double, double> &destination)
+bool DoublesReader(const std::string &name, const std::string &value, std::tuple<double, double> &destination)
{
size_t commapos = 0;
std::get<0>(destination) = std::stod(value, &commapos);
std::get<1>(destination) = std::stod(std::string(value, commapos + 1));
+ return true;
}
TEST_CASE("Custom types work", "[args]")
@@ -375,10 +376,11 @@ enum class MappingEnum
#include <algorithm>
#include <string>
-void ToLowerReader(const std::string &name, const std::string &value, std::string &destination)
+bool ToLowerReader(const std::string &name, const std::string &value, std::string &destination)
{
destination = value;
std::transform(destination.begin(), destination.end(), destination.begin(), ::tolower);
+ return true;
}
TEST_CASE("Mapping types work as needed", "[args]")
@@ -522,3 +524,66 @@ TEST_CASE("Kick-out should work via all flags and value flags", "[args]")
REQUIRE_FALSE(c3);
REQUIRE(d3);
}
+
+#define ARGS_TESTNAMESPACE
+#define ARGS_NOEXCEPT
+#include <args.hxx>
+
+TEST_CASE("Noexcept mode works as expected", "[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}};
+
+ argstest::ArgumentParser parser("This is a test program.", "This goes after the options.");
+ argstest::HelpFlag help(parser, "help", "Display this help menu", {'h', "help"});
+ argstest::Flag bar(parser, "BAR", "test flag", {'b', "bar"}, true);
+ argstest::ValueFlag<int> foo(parser, "FOO", "test flag", {'f', "foo"});
+ argstest::Group nandgroup(parser, "this group provides nand validation", argstest::Group::Validators::AtMostOne);
+ argstest::Flag x(nandgroup, "x", "test flag", {'x'});
+ argstest::Flag y(nandgroup, "y", "test flag", {'y'});
+ argstest::Flag z(nandgroup, "z", "test flag", {'z'});
+ argstest::MapFlag<std::string, MappingEnum> mf(parser, "MF", "Maps string to an enum", {"mf"}, map);
+ parser.ParseArgs(std::vector<std::string>{"-h"});
+ REQUIRE(parser.GetError() == argstest::Error::Help);
+ parser.ParseArgs(std::vector<std::string>{"--Help"});
+ REQUIRE(parser.GetError() == argstest::Error::Parse);
+ parser.ParseArgs(std::vector<std::string>{"--bar=test"});
+ REQUIRE(parser.GetError() == argstest::Error::Parse);
+ parser.ParseArgs(std::vector<std::string>{"--bar"});
+ REQUIRE(parser.GetError() == argstest::Error::None);
+ parser.ParseArgs(std::vector<std::string>{"--bar", "-b"});
+ REQUIRE(parser.GetError() == argstest::Error::Extra);
+
+ parser.ParseArgs(std::vector<std::string>{"--foo=7.5"});
+ REQUIRE(parser.GetError() == argstest::Error::Parse);
+ parser.ParseArgs(std::vector<std::string>{"--foo", "7a"});
+ REQUIRE(parser.GetError() == argstest::Error::Parse);
+ parser.ParseArgs(std::vector<std::string>{"--foo", "7e4"});
+ REQUIRE(parser.GetError() == argstest::Error::Parse);
+ parser.ParseArgs(std::vector<std::string>{"--foo"});
+ REQUIRE(parser.GetError() == argstest::Error::Parse);
+
+ parser.ParseArgs(std::vector<std::string>{"--foo=85"});
+ REQUIRE(parser.GetError() == argstest::Error::None);
+
+ parser.ParseArgs(std::vector<std::string>{"this is a test flag again", "1", "this has no positional available"});
+ REQUIRE(parser.GetError() == argstest::Error::Parse);
+
+ parser.ParseArgs(std::vector<std::string>{"-x"});
+ REQUIRE(parser.GetError() == argstest::Error::None);
+ parser.ParseArgs(std::vector<std::string>{"-xz"});
+ REQUIRE(parser.GetError() == argstest::Error::Validation);
+ parser.ParseArgs(std::vector<std::string>{"-y"});
+ REQUIRE(parser.GetError() == argstest::Error::None);
+ parser.ParseArgs(std::vector<std::string>{"-y", "-xz"});
+ REQUIRE(parser.GetError() == argstest::Error::Validation);
+ parser.ParseArgs(std::vector<std::string>{"--mf", "YeLLoW"});
+ REQUIRE(parser.GetError() == argstest::Error::Map);
+ parser.ParseArgs(std::vector<std::string>{"--mf", "yellow"});
+ REQUIRE(parser.GetError() == argstest::Error::None);
+}