Give ArgumentParser value semantics

fixes: p-ranav/argparse#50
This commit is contained in:
Zhihao Yuan 2019-11-16 14:30:05 -06:00
parent 9007958c1f
commit f84f17d719
No known key found for this signature in database
GPG Key ID: A2E474BDAA37E11C
3 changed files with 118 additions and 1 deletions

View File

@ -380,6 +380,27 @@ public:
.implicit_value(true);
}
ArgumentParser(ArgumentParser &&) noexcept = default;
ArgumentParser &operator=(ArgumentParser &&) = default;
ArgumentParser(const ArgumentParser &other)
: mProgramName(other.mProgramName),
mPositionalArguments(other.mPositionalArguments),
mOptionalArguments(other.mOptionalArguments) {
for (auto it = begin(mPositionalArguments); it != end(mPositionalArguments);
++it)
index_argument(it);
for (auto it = begin(mOptionalArguments); it != end(mOptionalArguments);
++it)
index_argument(it);
}
ArgumentParser &operator=(const ArgumentParser &other) {
auto tmp = other;
std::swap(*this, tmp);
return *this;
}
// Parameter packing
// Call add_argument with variadic number of string arguments
template <typename... Targs> Argument &add_argument(Targs... Fargs) {

View File

@ -12,4 +12,5 @@
#include <test_invalid_arguments.hpp>
#include <test_negative_numbers.hpp>
#include <test_required_arguments.hpp>
#include <test_value_semantics.hpp>
#include <test_issue_37.hpp>

View File

@ -0,0 +1,95 @@
#pragma once
#include <argparse.hpp>
#include <catch.hpp>
TEST_CASE("ArgumentParser is MoveConstructible and MoveAssignable",
"[value_semantics]") {
GIVEN("a parser that has two arguments") {
argparse::ArgumentParser parser("test");
parser.add_argument("foo");
parser.add_argument("-f");
WHEN("move construct a new parser from it") {
auto new_parser = std::move(parser);
THEN("the old parser replaces the new parser") {
new_parser.parse_args({"test", "bar", "-f", "nul"});
REQUIRE(new_parser.get("foo") == "bar");
REQUIRE(new_parser.get("-f") == "nul");
}
}
WHEN("move assign a parser prvalue to it") {
parser = argparse::ArgumentParser("test");
THEN("the old parser is replaced") {
REQUIRE_THROWS_AS(parser.parse_args({"test", "bar"}),
std::runtime_error);
REQUIRE_THROWS_AS(parser.parse_args({"test", "-f", "nul"}),
std::runtime_error);
REQUIRE_NOTHROW(parser.parse_args({"test"}));
}
}
}
}
TEST_CASE("ArgumentParser is CopyConstructible and CopyAssignable",
"[value_semantics]") {
GIVEN("a parser that has two arguments") {
argparse::ArgumentParser parser("test");
parser.add_argument("foo");
parser.add_argument("-f");
WHEN("copy construct a new parser from it") {
auto new_parser = parser;
THEN("the new parser has the old parser's capability") {
new_parser.parse_args({"test", "bar", "-f", "nul"});
REQUIRE(new_parser.get("foo") == "bar");
REQUIRE(new_parser.get("-f") == "nul");
AND_THEN("but does not share states with the old parser") {
REQUIRE_THROWS_AS(parser.get("foo"), std::logic_error);
REQUIRE_THROWS_AS(parser.get("-f"), std::logic_error);
}
}
AND_THEN("the old parser works as a distinct copy") {
new_parser.parse_args({"test", "toe", "-f", "/"});
REQUIRE(new_parser.get("foo") == "toe");
REQUIRE(new_parser.get("-f") == "/");
}
}
WHEN("copy assign a parser lvalue to it") {
argparse::ArgumentParser optional_parser("test");
optional_parser.add_argument("-g");
parser = optional_parser;
THEN("the old parser is replaced") {
REQUIRE_THROWS_AS(parser.parse_args({"test", "bar"}),
std::runtime_error);
REQUIRE_THROWS_AS(parser.parse_args({"test", "-f", "nul"}),
std::runtime_error);
REQUIRE_NOTHROW(parser.parse_args({"test"}));
REQUIRE_NOTHROW(parser.parse_args({"test", "-g", "nul"}));
AND_THEN("but does not share states with the other parser") {
REQUIRE(parser.get("-g") == "nul");
REQUIRE_THROWS_AS(optional_parser.get("-g"), std::logic_error);
}
}
AND_THEN("the other parser works as a distinct copy") {
REQUIRE_NOTHROW(optional_parser.parse_args({"test"}));
REQUIRE_NOTHROW(optional_parser.parse_args({"test", "-g", "nul"}));
REQUIRE_THROWS_AS(
optional_parser.parse_args({"test", "bar", "-g", "nul"}),
std::runtime_error);
}
}
}
}