Add support for multiply calling lambda parsers in Clara

Previously a lambda parser in Clara could only be invoked once,
even if it internally was ok with being invoked multiple times.

With this change, a lambda parser can mark itself as `accept_many`,
in which case it will be invoked multiple times if the appropriate
flag was supplied multiple times by the user.
This commit is contained in:
Martin Hořeňovský 2021-10-27 18:57:56 +02:00
parent f17725a186
commit 12d14a3c63
No known key found for this signature in database
GPG Key ID: DE48307B8B0D381A
11 changed files with 292 additions and 20 deletions

View File

@ -29,14 +29,17 @@
# endif
#endif
#include <catch2/internal/catch_noncopyable.hpp>
#include <catch2/internal/catch_move_and_forward.hpp>
#include <catch2/internal/catch_noncopyable.hpp>
#include <catch2/internal/catch_void_type.hpp>
#include <cassert>
#include <cctype>
#include <memory>
#include <ostream>
#include <sstream>
#include <string>
#include <type_traits>
#include <vector>
namespace Catch {
@ -53,7 +56,25 @@ namespace Catch {
ShortCircuitSame
};
struct accept_many_t {};
constexpr accept_many_t accept_many {};
namespace Detail {
struct fake_arg {
template <typename T>
operator T();
};
template <typename F, typename = void>
struct is_unary_function : std::false_type {};
template <typename F>
struct is_unary_function<
F,
Catch::Detail::void_t<decltype(
std::declval<F>()( fake_arg() ) )
>
> : std::true_type {};
// Traits for extracting arg and return type of lambdas (for single
// argument lambdas)
@ -393,6 +414,11 @@ namespace Catch {
}
};
template <typename L> struct BoundManyLambda : BoundLambda<L> {
explicit BoundManyLambda( L const& lambda ): BoundLambda<L>( lambda ) {}
bool isContainer() const override { return true; }
};
template <typename L> struct BoundFlagLambda : BoundFlagRefBase {
L m_lambda;
@ -447,12 +473,23 @@ namespace Catch {
m_ref( ref ) {}
public:
template <typename T>
template <typename LambdaT>
ParserRefImpl( accept_many_t,
LambdaT const& ref,
std::string const& hint ):
m_ref( std::make_shared<BoundManyLambda<LambdaT>>( ref ) ),
m_hint( hint ) {}
template <typename T,
typename = typename std::enable_if_t<
!Detail::is_unary_function<T>::value>>
ParserRefImpl( T& ref, std::string const& hint ):
m_ref( std::make_shared<BoundValueRef<T>>( ref ) ),
m_hint( hint ) {}
template <typename LambdaT>
template <typename LambdaT,
typename = typename std::enable_if_t<
Detail::is_unary_function<LambdaT>::value>>
ParserRefImpl( LambdaT const& ref, std::string const& hint ):
m_ref( std::make_shared<BoundLambda<LambdaT>>( ref ) ),
m_hint( hint ) {}
@ -513,13 +550,21 @@ namespace Catch {
explicit Opt(bool& ref);
template <typename LambdaT>
Opt(LambdaT const& ref, std::string const& hint) :
ParserRefImpl(ref, hint) {}
template <typename LambdaT,
typename = typename std::enable_if_t<
Detail::is_unary_function<LambdaT>::value>>
Opt( LambdaT const& ref, std::string const& hint ):
ParserRefImpl( ref, hint ) {}
template <typename T>
Opt(T& ref, std::string const& hint) :
ParserRefImpl(ref, hint) {}
template <typename LambdaT>
Opt( accept_many_t, LambdaT const& ref, std::string const& hint ):
ParserRefImpl( accept_many, ref, hint ) {}
template <typename T,
typename = typename std::enable_if_t<
!Detail::is_unary_function<T>::value>>
Opt( T& ref, std::string const& hint ):
ParserRefImpl( ref, hint ) {}
auto operator[](std::string const& optName) -> Opt& {
m_optNames.push_back(optName);

View File

@ -102,6 +102,7 @@ Nor would this
:test-result: PASS Capture and info messages
:test-result: PASS Character pretty printing
:test-result: PASS Clara::Arg supports single-arg parse the way Opt does
:test-result: PASS Clara::Opt supports accept-many lambdas
:test-result: PASS Combining MatchAllOfGeneric does not nest
:test-result: PASS Combining MatchAnyOfGeneric does not nest
:test-result: PASS Combining MatchNotOfGeneric does not nest
@ -297,6 +298,7 @@ Message from section two
:test-result: FAIL first tag
loose text artifact
:test-result: FAIL has printf
:test-result: PASS is_unary_function
:test-result: FAIL just failure
:test-result: FAIL just failure after unscoped info
:test-result: FAIL just info

View File

@ -350,6 +350,9 @@ ToStringGeneral.tests.cpp:<line number>: passed: c == i for: 4 == 4
ToStringGeneral.tests.cpp:<line number>: passed: c == i for: 5 == 5
Clara.tests.cpp:<line number>: passed: name.empty() for: true
Clara.tests.cpp:<line number>: passed: name == "foo" for: "foo" == "foo"
Clara.tests.cpp:<line number>: passed: !(parse_result) for: !{?}
Clara.tests.cpp:<line number>: passed: parse_result for: {?}
Clara.tests.cpp:<line number>: passed: res == std::vector<std::string>{ "aaa", "bbb" } for: { "aaa", "bbb" } == { "aaa", "bbb" }
Matchers.tests.cpp:<line number>: passed: with 1 message: 'std::is_same< decltype( ( MatcherA() && MatcherB() ) && MatcherC() ), Catch::Matchers::Detail:: MatchAllOfGeneric<MatcherA, MatcherB, MatcherC>>::value'
Matchers.tests.cpp:<line number>: passed: 1, ( MatcherA() && MatcherB() ) && MatcherC() for: 1 ( equals: (int) 1 or (float) 1.0f and equals: (long long) 1 and equals: (T) 1 )
Matchers.tests.cpp:<line number>: passed: with 1 message: 'std::is_same< decltype( MatcherA() && ( MatcherB() && MatcherC() ) ), Catch::Matchers::Detail:: MatchAllOfGeneric<MatcherA, MatcherB, MatcherC>>::value'
@ -2111,6 +2114,18 @@ Misc.tests.cpp:<line number>: passed:
Misc.tests.cpp:<line number>: passed:
Misc.tests.cpp:<line number>: passed:
loose text artifact
Clara.tests.cpp:<line number>: passed: with 1 message: 'Catch::Clara::Detail::is_unary_function<decltype(unary1)>::value'
Clara.tests.cpp:<line number>: passed: with 1 message: 'Catch::Clara::Detail::is_unary_function<decltype(unary2)>::value'
Clara.tests.cpp:<line number>: passed: with 1 message: 'Catch::Clara::Detail::is_unary_function<decltype(unary3)>::value'
Clara.tests.cpp:<line number>: passed: with 1 message: 'Catch::Clara::Detail::is_unary_function<decltype(unary4)>::value'
Clara.tests.cpp:<line number>: passed: with 1 message: 'Catch::Clara::Detail::is_unary_function<decltype(unary5)>::value'
Clara.tests.cpp:<line number>: passed: with 1 message: 'Catch::Clara::Detail::is_unary_function<decltype(unary6)>::value'
Clara.tests.cpp:<line number>: passed: with 1 message: '!(Catch::Clara::Detail::is_unary_function<decltype(binary1)>::value)'
Clara.tests.cpp:<line number>: passed: with 1 message: '!(Catch::Clara::Detail::is_unary_function<decltype(binary2)>::value)'
Clara.tests.cpp:<line number>: passed: with 1 message: '!(Catch::Clara::Detail::is_unary_function<decltype(nullary1)>::value)'
Clara.tests.cpp:<line number>: passed: with 1 message: '!(Catch::Clara::Detail::is_unary_function<decltype(nullary2)>::value)'
Clara.tests.cpp:<line number>: passed: with 1 message: '!(Catch::Clara::Detail::is_unary_function<int>::value)'
Clara.tests.cpp:<line number>: passed: with 1 message: '!(Catch::Clara::Detail::is_unary_function<std::string const&>::value)'
Message.tests.cpp:<line number>: failed: explicitly with 1 message: 'Previous info should not be seen'
Message.tests.cpp:<line number>: failed: explicitly with 1 message: 'previous unscoped info SHOULD not be seen'
Misc.tests.cpp:<line number>: passed: l == std::numeric_limits<long long>::max() for: 9223372036854775807 (0x<hex digits>)

View File

@ -1426,6 +1426,6 @@ due to unexpected exception with message:
Why would you throw a std::string?
===============================================================================
test cases: 374 | 297 passed | 70 failed | 7 failed as expected
assertions: 2127 | 1971 passed | 129 failed | 27 failed as expected
test cases: 376 | 299 passed | 70 failed | 7 failed as expected
assertions: 2142 | 1986 passed | 129 failed | 27 failed as expected

View File

@ -2908,6 +2908,35 @@ Clara.tests.cpp:<line number>: PASSED:
with expansion:
"foo" == "foo"
-------------------------------------------------------------------------------
Clara::Opt supports accept-many lambdas
Parsing fails on multiple options without accept_many
-------------------------------------------------------------------------------
Clara.tests.cpp:<line number>
...............................................................................
Clara.tests.cpp:<line number>: PASSED:
CHECK_FALSE( parse_result )
with expansion:
!{?}
-------------------------------------------------------------------------------
Clara::Opt supports accept-many lambdas
Parsing succeeds on multiple options with accept_many
-------------------------------------------------------------------------------
Clara.tests.cpp:<line number>
...............................................................................
Clara.tests.cpp:<line number>: PASSED:
CHECK( parse_result )
with expansion:
{?}
Clara.tests.cpp:<line number>: PASSED:
CHECK( res == std::vector<std::string>{ "aaa", "bbb" } )
with expansion:
{ "aaa", "bbb" } == { "aaa", "bbb" }
-------------------------------------------------------------------------------
Combining MatchAllOfGeneric does not nest
-------------------------------------------------------------------------------
@ -14962,6 +14991,60 @@ Tricky.tests.cpp:<line number>
No assertions in test case 'has printf'
-------------------------------------------------------------------------------
is_unary_function
-------------------------------------------------------------------------------
Clara.tests.cpp:<line number>
...............................................................................
Clara.tests.cpp:<line number>: PASSED:
with message:
Catch::Clara::Detail::is_unary_function<decltype(unary1)>::value
Clara.tests.cpp:<line number>: PASSED:
with message:
Catch::Clara::Detail::is_unary_function<decltype(unary2)>::value
Clara.tests.cpp:<line number>: PASSED:
with message:
Catch::Clara::Detail::is_unary_function<decltype(unary3)>::value
Clara.tests.cpp:<line number>: PASSED:
with message:
Catch::Clara::Detail::is_unary_function<decltype(unary4)>::value
Clara.tests.cpp:<line number>: PASSED:
with message:
Catch::Clara::Detail::is_unary_function<decltype(unary5)>::value
Clara.tests.cpp:<line number>: PASSED:
with message:
Catch::Clara::Detail::is_unary_function<decltype(unary6)>::value
Clara.tests.cpp:<line number>: PASSED:
with message:
!(Catch::Clara::Detail::is_unary_function<decltype(binary1)>::value)
Clara.tests.cpp:<line number>: PASSED:
with message:
!(Catch::Clara::Detail::is_unary_function<decltype(binary2)>::value)
Clara.tests.cpp:<line number>: PASSED:
with message:
!(Catch::Clara::Detail::is_unary_function<decltype(nullary1)>::value)
Clara.tests.cpp:<line number>: PASSED:
with message:
!(Catch::Clara::Detail::is_unary_function<decltype(nullary2)>::value)
Clara.tests.cpp:<line number>: PASSED:
with message:
!(Catch::Clara::Detail::is_unary_function<int>::value)
Clara.tests.cpp:<line number>: PASSED:
with message:
!(Catch::Clara::Detail::is_unary_function<std::string const&>::value)
-------------------------------------------------------------------------------
just failure
-------------------------------------------------------------------------------
@ -17144,6 +17227,6 @@ Misc.tests.cpp:<line number>
Misc.tests.cpp:<line number>: PASSED:
===============================================================================
test cases: 374 | 281 passed | 86 failed | 7 failed as expected
assertions: 2144 | 1971 passed | 146 failed | 27 failed as expected
test cases: 376 | 283 passed | 86 failed | 7 failed as expected
assertions: 2159 | 1986 passed | 146 failed | 27 failed as expected

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<testsuitesloose text artifact
>
<testsuite name="<exe-name>" errors="17" failures="129" tests="2144" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
<testsuite name="<exe-name>" errors="17" failures="129" tests="2159" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
<properties>
<property name="random-seed" value="1"/>
<property name="filters" value="~[!nonportable]~[!benchmark]~[approvals] *"/>
@ -382,6 +382,8 @@ Exception.tests.cpp:<line number>
<testcase classname="<exe-name>.global" name="Character pretty printing/General chars" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Character pretty printing/Low ASCII" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Clara::Arg supports single-arg parse the way Opt does" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Clara::Opt supports accept-many lambdas/Parsing fails on multiple options without accept_many" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Clara::Opt supports accept-many lambdas/Parsing succeeds on multiple options with accept_many" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Combining MatchAllOfGeneric does not nest" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Combining MatchAnyOfGeneric does not nest" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Combining MatchNotOfGeneric does not nest" time="{duration}" status="run"/>
@ -1601,6 +1603,7 @@ Misc.tests.cpp:<line number>
<testcase classname="<exe-name>.global" name="even more nested SECTION tests/c/d (leaf)" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="even more nested SECTION tests/c/e (leaf)" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="even more nested SECTION tests/f (leaf)" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="is_unary_function" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="just failure" time="{duration}" status="run">
<failure type="FAIL">
FAILED:

View File

@ -3,6 +3,9 @@
>
<file path="tests/<exe-name>/IntrospectiveTests/Clara.tests.cpp">
<testCase name="Clara::Arg supports single-arg parse the way Opt does" duration="{duration}"/>
<testCase name="Clara::Opt supports accept-many lambdas/Parsing fails on multiple options without accept_many" duration="{duration}"/>
<testCase name="Clara::Opt supports accept-many lambdas/Parsing succeeds on multiple options with accept_many" duration="{duration}"/>
<testCase name="is_unary_function" duration="{duration}"/>
</file>
<file path="tests/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp">
<testCase name="#1905 -- test spec parser properly clears internal state between compound tests" duration="{duration}"/>

View File

@ -698,6 +698,12 @@ ok {test-number} - c == i for: 5 == 5
ok {test-number} - name.empty() for: true
# Clara::Arg supports single-arg parse the way Opt does
ok {test-number} - name == "foo" for: "foo" == "foo"
# Clara::Opt supports accept-many lambdas
ok {test-number} - !(parse_result) for: !{?}
# Clara::Opt supports accept-many lambdas
ok {test-number} - parse_result for: {?}
# Clara::Opt supports accept-many lambdas
ok {test-number} - res == std::vector<std::string>{ "aaa", "bbb" } for: { "aaa", "bbb" } == { "aaa", "bbb" }
# Combining MatchAllOfGeneric does not nest
ok {test-number} - with 1 message: 'std::is_same< decltype( ( MatcherA() && MatcherB() ) && MatcherC() ), Catch::Matchers::Detail:: MatchAllOfGeneric<MatcherA, MatcherB, MatcherC>>::value'
# Combining MatchAllOfGeneric does not nest
@ -3786,6 +3792,30 @@ ok {test-number} -
# even more nested SECTION tests
ok {test-number} -
loose text artifact
# is_unary_function
ok {test-number} - with 1 message: 'Catch::Clara::Detail::is_unary_function<decltype(unary1)>::value'
# is_unary_function
ok {test-number} - with 1 message: 'Catch::Clara::Detail::is_unary_function<decltype(unary2)>::value'
# is_unary_function
ok {test-number} - with 1 message: 'Catch::Clara::Detail::is_unary_function<decltype(unary3)>::value'
# is_unary_function
ok {test-number} - with 1 message: 'Catch::Clara::Detail::is_unary_function<decltype(unary4)>::value'
# is_unary_function
ok {test-number} - with 1 message: 'Catch::Clara::Detail::is_unary_function<decltype(unary5)>::value'
# is_unary_function
ok {test-number} - with 1 message: 'Catch::Clara::Detail::is_unary_function<decltype(unary6)>::value'
# is_unary_function
ok {test-number} - with 1 message: '!(Catch::Clara::Detail::is_unary_function<decltype(binary1)>::value)'
# is_unary_function
ok {test-number} - with 1 message: '!(Catch::Clara::Detail::is_unary_function<decltype(binary2)>::value)'
# is_unary_function
ok {test-number} - with 1 message: '!(Catch::Clara::Detail::is_unary_function<decltype(nullary1)>::value)'
# is_unary_function
ok {test-number} - with 1 message: '!(Catch::Clara::Detail::is_unary_function<decltype(nullary2)>::value)'
# is_unary_function
ok {test-number} - with 1 message: '!(Catch::Clara::Detail::is_unary_function<int>::value)'
# is_unary_function
ok {test-number} - with 1 message: '!(Catch::Clara::Detail::is_unary_function<std::string const&>::value)'
# just failure
not ok {test-number} - explicitly with 1 message: 'Previous info should not be seen'
# just failure after unscoped info
@ -4290,5 +4320,5 @@ ok {test-number} - q3 == 23. for: 23.0 == 23.0
ok {test-number} -
# xmlentitycheck
ok {test-number} -
1..2144
1..2159

View File

@ -237,6 +237,8 @@ Exception.tests.cpp:<line number>|nunexpected exception with message:|n "unexpe
##teamcity[testFinished name='Character pretty printing' duration="{duration}"]
##teamcity[testStarted name='Clara::Arg supports single-arg parse the way Opt does']
##teamcity[testFinished name='Clara::Arg supports single-arg parse the way Opt does' duration="{duration}"]
##teamcity[testStarted name='Clara::Opt supports accept-many lambdas']
##teamcity[testFinished name='Clara::Opt supports accept-many lambdas' duration="{duration}"]
##teamcity[testStarted name='Combining MatchAllOfGeneric does not nest']
##teamcity[testFinished name='Combining MatchAllOfGeneric does not nest' duration="{duration}"]
##teamcity[testStarted name='Combining MatchAnyOfGeneric does not nest']
@ -723,6 +725,8 @@ Misc.tests.cpp:<line number>|nexpression failed|n REQUIRE( testCheckedIf( false
##teamcity[testStarted name='has printf']
loose text artifact
##teamcity[testFinished name='has printf' duration="{duration}"]
##teamcity[testStarted name='is_unary_function']
##teamcity[testFinished name='is_unary_function' duration="{duration}"]
##teamcity[testStarted name='just failure']
Message.tests.cpp:<line number>|nexplicit failure with message:|n "Previous info should not be seen"']
##teamcity[testFinished name='just failure' duration="{duration}"]

View File

@ -3156,6 +3156,39 @@ Nor would this
</Expression>
<OverallResult success="true"/>
</TestCase>
<TestCase name="Clara::Opt supports accept-many lambdas" tags="[clara][opt]" filename="tests/<exe-name>/IntrospectiveTests/Clara.tests.cpp" >
<Section name="Parsing fails on multiple options without accept_many" filename="tests/<exe-name>/IntrospectiveTests/Clara.tests.cpp" >
<Expression success="true" type="CHECK_FALSE" filename="tests/<exe-name>/IntrospectiveTests/Clara.tests.cpp" >
<Original>
!(parse_result)
</Original>
<Expanded>
!{?}
</Expanded>
</Expression>
<OverallResults successes="1" failures="0" expectedFailures="0"/>
</Section>
<Section name="Parsing succeeds on multiple options with accept_many" filename="tests/<exe-name>/IntrospectiveTests/Clara.tests.cpp" >
<Expression success="true" type="CHECK" filename="tests/<exe-name>/IntrospectiveTests/Clara.tests.cpp" >
<Original>
parse_result
</Original>
<Expanded>
{?}
</Expanded>
</Expression>
<Expression success="true" type="CHECK" filename="tests/<exe-name>/IntrospectiveTests/Clara.tests.cpp" >
<Original>
res == std::vector&lt;std::string>{ "aaa", "bbb" }
</Original>
<Expanded>
{ "aaa", "bbb" } == { "aaa", "bbb" }
</Expanded>
</Expression>
<OverallResults successes="2" failures="0" expectedFailures="0"/>
</Section>
<OverallResult success="true"/>
</TestCase>
<TestCase name="Combining MatchAllOfGeneric does not nest" tags="[matchers][templated]" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Original>
@ -17633,6 +17666,9 @@ There is no extra whitespace here
loose text artifact
<OverallResult success="false"/>
</TestCase>
<TestCase name="is_unary_function" tags="[clara][compilation]" filename="tests/<exe-name>/IntrospectiveTests/Clara.tests.cpp" >
<OverallResult success="true"/>
</TestCase>
<TestCase name="just failure" tags="[.][fail][isolated info][messages]" filename="tests/<exe-name>/UsageTests/Message.tests.cpp" >
<Failure filename="tests/<exe-name>/UsageTests/Message.tests.cpp" >
Previous info should not be seen
@ -20147,6 +20183,6 @@ loose text artifact
</Section>
<OverallResult success="true"/>
</TestCase>
<OverallResults successes="1971" failures="146" expectedFailures="27"/>
<OverallResultsCases successes="281" failures="86" expectedFailures="7"/>
<OverallResults successes="1986" failures="146" expectedFailures="27"/>
<OverallResultsCases successes="283" failures="86" expectedFailures="7"/>
</Catch2TestRun>

View File

@ -4,19 +4,70 @@
// https://www.boost.org/LICENSE_1_0.txt)
// SPDX-License-Identifier: BSL-1.0
#include <catch2/catch_test_macros.hpp>
#include <catch2/internal/catch_clara.hpp>
#include <string>
TEST_CASE("is_unary_function", "[clara][compilation]") {
auto unary1 = [](int) {};
auto unary2 = [](std::string const&) {};
auto const unary3 = [](std::string const&) {};
auto unary4 = [](int) { return 42; };
void unary5(char);
double unary6(long);
double binary1(long, int);
auto binary2 = [](int, char) {};
auto nullary1 = []() {};
auto nullary2 = []() {return 42;};
STATIC_REQUIRE(Catch::Clara::Detail::is_unary_function<decltype(unary1)>::value);
STATIC_REQUIRE(Catch::Clara::Detail::is_unary_function<decltype(unary2)>::value);
STATIC_REQUIRE(Catch::Clara::Detail::is_unary_function<decltype(unary3)>::value);
STATIC_REQUIRE(Catch::Clara::Detail::is_unary_function<decltype(unary4)>::value);
STATIC_REQUIRE(Catch::Clara::Detail::is_unary_function<decltype(unary5)>::value);
STATIC_REQUIRE(Catch::Clara::Detail::is_unary_function<decltype(unary6)>::value);
STATIC_REQUIRE_FALSE(Catch::Clara::Detail::is_unary_function<decltype(binary1)>::value);
STATIC_REQUIRE_FALSE(Catch::Clara::Detail::is_unary_function<decltype(binary2)>::value);
STATIC_REQUIRE_FALSE(Catch::Clara::Detail::is_unary_function<decltype(nullary1)>::value);
STATIC_REQUIRE_FALSE(Catch::Clara::Detail::is_unary_function<decltype(nullary2)>::value);
STATIC_REQUIRE_FALSE(Catch::Clara::Detail::is_unary_function<int>::value);
STATIC_REQUIRE_FALSE(Catch::Clara::Detail::is_unary_function<std::string const&>::value);
}
TEST_CASE("Clara::Arg supports single-arg parse the way Opt does", "[clara][arg][compilation]") {
std::string name;
auto p = Catch::Clara::Arg(name, "just one arg");
CHECK(name.empty());
p.parse( Catch::Clara::Args{ "UnitTest", "foo" } );
REQUIRE(name == "foo");
}
TEST_CASE("Clara::Opt supports accept-many lambdas", "[clara][opt]") {
std::string name;
using namespace Catch::Clara;
std::vector<std::string> res;
const auto push_to_res = [&](std::string const& s) {
res.push_back(s);
return ParserResult::ok();
};
SECTION("Parsing fails on multiple options without accept_many") {
auto p = Parser() | Opt(push_to_res, "value")["-o"];
auto parse_result = p.parse( Args{ "UnitTest", "-o", "aaa", "-o", "bbb" } );
CHECK_FALSE(parse_result);
}
SECTION("Parsing succeeds on multiple options with accept_many") {
auto p = Parser() | Opt(accept_many, push_to_res, "value")["-o"];
auto parse_result = p.parse( Args{ "UnitTest", "-o", "aaa", "-o", "bbb" } );
CHECK(parse_result);
CHECK(res == std::vector<std::string>{ "aaa", "bbb" });
}
}