Skip to content

Commit

Permalink
Give ArgumentParser value semantics
Browse files Browse the repository at this point in the history
fixes: p-ranav#50
  • Loading branch information
lichray committed Nov 16, 2019
1 parent 9007958 commit ff1009f
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 1 deletion.
21 changes: 21 additions & 0 deletions include/argparse.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,27 @@ class ArgumentParser {
.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) {
Expand Down
3 changes: 2 additions & 1 deletion test/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@
#include <test_invalid_arguments.hpp>
#include <test_negative_numbers.hpp>
#include <test_required_arguments.hpp>
#include <test_issue_37.hpp>
#include <test_value_semantics.hpp>
#include <test_issue_37.hpp>
95 changes: 95 additions & 0 deletions test/test_value_semantics.hpp
Original file line number Diff line number Diff line change
@@ -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);
}
}
}
}

0 comments on commit ff1009f

Please sign in to comment.