Squashed 'libs/cli11/' content from commit dcbcb47
git-subtree-dir: libs/cli11 git-subtree-split: dcbcb4721dda5dab0a56d9faaaee50e6a30f7758
This commit is contained in:
1
tests/.syntastic_cpp_config
Normal file
1
tests/.syntastic_cpp_config
Normal file
@@ -0,0 +1 @@
|
||||
- I../ build / googletest - src / googletest / include / -I../ build / googletest - src / googlemock / include /
|
||||
2430
tests/AppTest.cpp
Normal file
2430
tests/AppTest.cpp
Normal file
File diff suppressed because it is too large
Load Diff
126
tests/BoostOptionTypeTest.cpp
Normal file
126
tests/BoostOptionTypeTest.cpp
Normal file
@@ -0,0 +1,126 @@
|
||||
// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include "app_helper.hpp"
|
||||
#include <boost/container/flat_map.hpp>
|
||||
#include <boost/container/flat_set.hpp>
|
||||
#include <boost/container/slist.hpp>
|
||||
#include <boost/container/small_vector.hpp>
|
||||
#include <boost/container/stable_vector.hpp>
|
||||
#include <boost/container/static_vector.hpp>
|
||||
#include <boost/container/vector.hpp>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace boost::container;
|
||||
|
||||
TEMPLATE_TEST_CASE("Boost container single",
|
||||
"[boost][optional]",
|
||||
(small_vector<int, 2>),
|
||||
(small_vector<int, 3>),
|
||||
flat_set<int>,
|
||||
stable_vector<int>,
|
||||
slist<int>) {
|
||||
TApp tapp;
|
||||
TestType cv;
|
||||
CLI::Option *opt = tapp.app.add_option("-v", cv);
|
||||
|
||||
tapp.args = {"-v", "1", "-1", "-v", "3", "-v", "-976"};
|
||||
tapp.run();
|
||||
CHECK(tapp.app.count("-v") == 4u);
|
||||
CHECK(cv.size() == 4u);
|
||||
opt->check(CLI::PositiveNumber.application_index(0));
|
||||
opt->check((!CLI::PositiveNumber).application_index(1));
|
||||
CHECK_NOTHROW(tapp.run());
|
||||
CHECK(cv.size() == 4u);
|
||||
// v[3] would be negative
|
||||
opt->check(CLI::PositiveNumber.application_index(3));
|
||||
CHECK_THROWS_AS(tapp.run(), CLI::ValidationError);
|
||||
}
|
||||
|
||||
using isp = std::pair<int, std::string>;
|
||||
|
||||
TEMPLATE_TEST_CASE("Boost container pair",
|
||||
"[boost][optional]",
|
||||
stable_vector<isp>,
|
||||
(small_vector<isp, 2>),
|
||||
flat_set<isp>,
|
||||
slist<isp>,
|
||||
vector<isp>,
|
||||
(flat_map<int, std::string>)) {
|
||||
|
||||
TApp tapp;
|
||||
TestType cv;
|
||||
|
||||
tapp.app.add_option("--dict", cv);
|
||||
|
||||
tapp.args = {"--dict", "1", "str1", "--dict", "3", "str3"};
|
||||
|
||||
tapp.run();
|
||||
CHECK(2u == cv.size());
|
||||
|
||||
tapp.args = {"--dict", "1", "str1", "--dict", "3", "--dict", "-1", "str4"};
|
||||
tapp.run();
|
||||
CHECK(3u == cv.size());
|
||||
}
|
||||
|
||||
using tup_obj = std::tuple<int, std::string, double>;
|
||||
|
||||
TEMPLATE_TEST_CASE("Boost container tuple",
|
||||
"[boost][optional]",
|
||||
(small_vector<tup_obj, 3>),
|
||||
stable_vector<tup_obj>,
|
||||
flat_set<tup_obj>,
|
||||
slist<tup_obj>) {
|
||||
TApp tapp;
|
||||
TestType cv;
|
||||
|
||||
tapp.app.add_option("--dict", cv);
|
||||
|
||||
tapp.args = {"--dict", "1", "str1", "4.3", "--dict", "3", "str3", "2.7"};
|
||||
|
||||
tapp.run();
|
||||
CHECK(2u == cv.size());
|
||||
|
||||
tapp.args = {"--dict", "1", "str1", "4.3", "--dict", "3", "str3", "2.7", "--dict", "-1", "str4", "-1.87"};
|
||||
tapp.run();
|
||||
CHECK(3u == cv.size());
|
||||
}
|
||||
|
||||
using icontainer1 = vector<int>;
|
||||
using icontainer2 = flat_set<int>;
|
||||
using icontainer3 = slist<int>;
|
||||
|
||||
TEMPLATE_TEST_CASE("Boost container container",
|
||||
"[boost][optional]",
|
||||
std::vector<icontainer1>,
|
||||
slist<icontainer1>,
|
||||
flat_set<icontainer1>,
|
||||
(small_vector<icontainer1, 2>),
|
||||
std::vector<icontainer2>,
|
||||
slist<icontainer2>,
|
||||
flat_set<icontainer2>,
|
||||
stable_vector<icontainer2>,
|
||||
(static_vector<icontainer2, 10>),
|
||||
slist<icontainer3>,
|
||||
flat_set<icontainer3>,
|
||||
(static_vector<icontainer3, 10>)) {
|
||||
|
||||
TApp tapp;
|
||||
TestType cv;
|
||||
|
||||
tapp.app.add_option("--dict", cv);
|
||||
|
||||
tapp.args = {"--dict", "1", "2", "4", "--dict", "3", "1"};
|
||||
|
||||
tapp.run();
|
||||
CHECK(2u == cv.size());
|
||||
|
||||
tapp.args = {"--dict", "1", "2", "4", "--dict", "3", "1", "--dict", "3", "--dict",
|
||||
"3", "3", "3", "3", "3", "3", "3", "3", "3", "-3"};
|
||||
tapp.run();
|
||||
CHECK(4u == cv.size());
|
||||
}
|
||||
219
tests/CMakeLists.txt
Normal file
219
tests/CMakeLists.txt
Normal file
@@ -0,0 +1,219 @@
|
||||
if(CLI11_SANITIZERS)
|
||||
message(STATUS "Using arsenm/sanitizers-cmake")
|
||||
FetchContent_Declare(
|
||||
sanitizers
|
||||
GIT_REPOSITORY https://github.com/arsenm/sanitizers-cmake.git
|
||||
GIT_SHALLOW 1
|
||||
GIT_TAG 99e159e)
|
||||
|
||||
FetchContent_GetProperties(sanitizers)
|
||||
|
||||
if(NOT sanitizers_POPULATED)
|
||||
FetchContent_Populate(sanitizers)
|
||||
endif()
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${sanitizers_SOURCE_DIR}/cmake")
|
||||
|
||||
find_package(Sanitizers)
|
||||
if(SANITIZE_ADDRESS)
|
||||
message(STATUS "You might want to use \"${ASan_WRAPPER}\" to run your program")
|
||||
endif()
|
||||
else()
|
||||
macro(add_sanitizers)
|
||||
|
||||
endmacro()
|
||||
endif()
|
||||
|
||||
# Add boost to test boost::optional (currently explicitly requested)"
|
||||
option(CLI11_BOOST "Turn on boost test (currently may fail with Boost 1.70)" OFF)
|
||||
if(CLI11_BOOST)
|
||||
find_package(Boost 1.61 REQUIRED)
|
||||
endif()
|
||||
set(boost-optional-def $<$<BOOL:${Boost_FOUND}>:CLI11_BOOST_OPTIONAL>)
|
||||
|
||||
set(CLI11_TESTS
|
||||
HelpersTest
|
||||
ConfigFileTest
|
||||
OptionTypeTest
|
||||
SimpleTest
|
||||
AppTest
|
||||
SetTest
|
||||
TransformTest
|
||||
CreationTest
|
||||
SubcommandTest
|
||||
HelpTest
|
||||
FormatterTest
|
||||
NewParseTest
|
||||
OptionalTest
|
||||
DeprecatedTest
|
||||
StringParseTest
|
||||
ComplexTypeTest
|
||||
TrueFalseTest
|
||||
OptionGroupTest)
|
||||
|
||||
if(WIN32)
|
||||
list(APPEND CLI11_TESTS WindowsTest)
|
||||
endif()
|
||||
|
||||
if(Boost_FOUND)
|
||||
list(APPEND CLI11_TESTS BoostOptionTypeTest)
|
||||
endif()
|
||||
|
||||
set(CLI11_MULTIONLY_TESTS TimerTest)
|
||||
|
||||
add_library(catch_main main.cpp catch.hpp)
|
||||
target_include_directories(catch_main PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
|
||||
find_package(Catch2 CONFIG)
|
||||
|
||||
if(Catch2_FOUND)
|
||||
if(NOT TARGET Catch2::Catch2)
|
||||
message(FATAL_ERROR "Found Catch2 at ${Catch2_DIR} but targets are missing.")
|
||||
endif()
|
||||
message(STATUS "Found Catch2")
|
||||
target_link_libraries(catch_main PUBLIC Catch2::Catch2)
|
||||
else()
|
||||
message(STATUS "Downloading Catch2")
|
||||
|
||||
# FetchContent would be better, but requires newer CMake.
|
||||
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/catch2")
|
||||
set(url https://github.com/philsquared/Catch/releases/download/v2.13.7/catch.hpp)
|
||||
file(
|
||||
DOWNLOAD ${url} "${CMAKE_CURRENT_BINARY_DIR}/catch2/catch.hpp"
|
||||
STATUS status
|
||||
EXPECTED_HASH SHA256=ea379c4a3cb5799027b1eb451163dff065a3d641aaba23bf4e24ee6b536bd9bc)
|
||||
list(GET status 0 error)
|
||||
if(error)
|
||||
message(FATAL_ERROR "Could not download ${url}, and Catch2 not found on your system.")
|
||||
endif()
|
||||
target_include_directories(catch_main PUBLIC "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
endif()
|
||||
|
||||
# Target must already exist
|
||||
macro(add_catch_test TESTNAME)
|
||||
target_link_libraries(${TESTNAME} PUBLIC catch_main)
|
||||
|
||||
add_test(${TESTNAME} ${TESTNAME})
|
||||
set_target_properties(${TESTNAME} PROPERTIES FOLDER "Tests")
|
||||
if(CLI11_FORCE_LIBCXX)
|
||||
set_property(
|
||||
TARGET ${T}
|
||||
APPEND_STRING
|
||||
PROPERTY LINK_FLAGS -stdlib=libc++)
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
foreach(T IN LISTS CLI11_TESTS)
|
||||
if(CLI11_CUDA_TESTS)
|
||||
set_property(SOURCE ${T}.cpp PROPERTY LANGUAGE CUDA)
|
||||
endif()
|
||||
add_executable(${T} ${T}.cpp)
|
||||
add_sanitizers(${T})
|
||||
if(NOT CLI11_CUDA_TESTS)
|
||||
target_link_libraries(${T} PRIVATE CLI11_warnings)
|
||||
endif()
|
||||
target_link_libraries(${T} PRIVATE CLI11)
|
||||
add_catch_test(${T})
|
||||
|
||||
if(CLI11_SINGLE_FILE AND CLI11_SINGLE_FILE_TESTS)
|
||||
add_executable(${T}_Single ${T}.cpp)
|
||||
target_link_libraries(${T}_Single PRIVATE CLI11_SINGLE)
|
||||
add_catch_test(${T}_Single)
|
||||
set_property(TARGET ${T}_Single PROPERTY FOLDER "Tests Single File")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
foreach(T IN LISTS CLI11_MULTIONLY_TESTS)
|
||||
add_executable(${T} ${T}.cpp)
|
||||
add_sanitizers(${T})
|
||||
target_link_libraries(${T} PUBLIC CLI11)
|
||||
add_catch_test(${T})
|
||||
endforeach()
|
||||
|
||||
# Add -Wno-deprecated-declarations to DeprecatedTest
|
||||
set(no-deprecated-declarations $<$<CXX_COMPILER_ID:MSVC>:/wd4996>
|
||||
$<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-Wno-deprecated-declarations>)
|
||||
target_compile_options(DeprecatedTest PRIVATE ${no-deprecated-declarations})
|
||||
if(TARGET DeprecatedTest_Single)
|
||||
target_compile_options(DeprecatedTest_Single PRIVATE ${no-deprecated-declarations})
|
||||
endif()
|
||||
|
||||
# Link test (build error if inlines missing)
|
||||
add_library(link_test_1 link_test_1.cpp)
|
||||
target_link_libraries(link_test_1 PUBLIC CLI11)
|
||||
set_target_properties(link_test_1 PROPERTIES FOLDER "Tests")
|
||||
add_executable(link_test_2 link_test_2.cpp)
|
||||
target_link_libraries(link_test_2 PUBLIC CLI11 link_test_1)
|
||||
add_catch_test(link_test_2)
|
||||
if(CLI11_FORCE_LIBCXX)
|
||||
set_property(
|
||||
TARGET link_test_1
|
||||
APPEND_STRING
|
||||
PROPERTY LINK_FLAGS -stdlib=libc++)
|
||||
set_property(
|
||||
TARGET link_test_2
|
||||
APPEND_STRING
|
||||
PROPERTY LINK_FLAGS -stdlib=libc++)
|
||||
endif()
|
||||
|
||||
# Add informational printout
|
||||
add_executable(informational informational.cpp)
|
||||
target_link_libraries(informational PUBLIC CLI11)
|
||||
if(CLI11_FORCE_LIBCXX)
|
||||
set_property(
|
||||
TARGET informational
|
||||
APPEND_STRING
|
||||
PROPERTY LINK_FLAGS -stdlib=libc++)
|
||||
endif()
|
||||
|
||||
# Force this to be in a standard location so CTest can find it
|
||||
set_target_properties(
|
||||
informational
|
||||
PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}"
|
||||
RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}"
|
||||
RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}"
|
||||
RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_BINARY_DIR}"
|
||||
RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_BINARY_DIR}")
|
||||
|
||||
# Adding this printout to CTest
|
||||
file(WRITE "${PROJECT_BINARY_DIR}/CTestCustom.cmake"
|
||||
"set(CTEST_CUSTOM_PRE_TEST \"${CMAKE_BINARY_DIR}/informational\")")
|
||||
|
||||
target_compile_definitions(informational PRIVATE ${boost-optional-def})
|
||||
target_compile_definitions(OptionalTest PRIVATE ${boost-optional-def})
|
||||
|
||||
if(TARGET Boost::boost)
|
||||
message(STATUS "including boost target")
|
||||
target_link_libraries(informational PRIVATE Boost::boost)
|
||||
target_link_libraries(OptionalTest PRIVATE Boost::boost)
|
||||
target_link_libraries(BoostOptionTypeTest PRIVATE Boost::boost)
|
||||
if(CLI11_SINGLE_FILE AND CLI11_SINGLE_FILE_TESTS)
|
||||
target_link_libraries(OptionalTest_Single PRIVATE Boost::boost)
|
||||
target_link_libraries(BoostOptionTypeTest_Single PRIVATE Boost::boost)
|
||||
endif()
|
||||
message(STATUS "Boost libs=${Boost_INCLUDE_DIRS}")
|
||||
elseif(BOOST_FOUND)
|
||||
message(STATUS "no boost target")
|
||||
target_include_directories(informational PRIVATE ${Boost_INCLUDE_DIRS})
|
||||
target_include_directories(OptionalTest PRIVATE ${Boost_INCLUDE_DIRS})
|
||||
target_include_directories(BoostOptionTypeTest PRIVATE ${Boost_INCLUDE_DIRS})
|
||||
if(CLI11_SINGLE_FILE AND CLI11_SINGLE_FILE_TESTS)
|
||||
target_include_directories(OptionalTest_Single PRIVATE ${Boost_INCLUDE_DIRS})
|
||||
target_include_directories(BoostOptionTypeTest_Single PRIVATE ${Boost_INCLUDE_DIRS})
|
||||
endif()
|
||||
message(STATUS "Boost libs=${Boost_INCLUDE_DIRS}")
|
||||
else()
|
||||
message(STATUS "Boost not found, not adding boost tests")
|
||||
endif()
|
||||
|
||||
if(CMAKE_BUILD_TYPE STREQUAL Coverage)
|
||||
include(CodeCoverage)
|
||||
setup_target_for_coverage(
|
||||
NAME
|
||||
CLI11_coverage
|
||||
EXECUTABLE
|
||||
ctest
|
||||
DEPENDENCIES
|
||||
${CLI11_TESTS}
|
||||
${CLI11_MULTIONLY_TESTS})
|
||||
endif()
|
||||
191
tests/ComplexTypeTest.cpp
Normal file
191
tests/ComplexTypeTest.cpp
Normal file
@@ -0,0 +1,191 @@
|
||||
// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include "app_helper.hpp"
|
||||
|
||||
#include <complex>
|
||||
#include <cstdint>
|
||||
|
||||
using Catch::Matchers::Contains;
|
||||
|
||||
using cx = std::complex<double>;
|
||||
|
||||
CLI::Option *
|
||||
add_option(CLI::App &app, std::string name, cx &variable, std::string description = "", bool defaulted = false) {
|
||||
CLI::callback_t fun = [&variable](CLI::results_t res) {
|
||||
double x = 0, y = 0;
|
||||
bool worked = CLI::detail::lexical_cast(res[0], x) && CLI::detail::lexical_cast(res[1], y);
|
||||
if(worked)
|
||||
variable = cx(x, y);
|
||||
return worked;
|
||||
};
|
||||
|
||||
CLI::Option *opt = app.add_option(name, fun, description, defaulted);
|
||||
opt->type_name("COMPLEX")->type_size(2);
|
||||
if(defaulted) {
|
||||
std::stringstream out;
|
||||
out << variable;
|
||||
opt->default_str(out.str());
|
||||
}
|
||||
return opt;
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "AddingComplexParser", "[complex]") {
|
||||
|
||||
cx comp{0, 0};
|
||||
add_option(app, "-c,--complex", comp);
|
||||
args = {"-c", "1.5", "2.5"};
|
||||
|
||||
run();
|
||||
|
||||
CHECK(comp.real() == Approx(1.5));
|
||||
CHECK(comp.imag() == Approx(2.5));
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "DefaultedComplex", "[complex]") {
|
||||
|
||||
cx comp{1, 2};
|
||||
add_option(app, "-c,--complex", comp, "", true);
|
||||
args = {"-c", "4", "3"};
|
||||
|
||||
std::string help = app.help();
|
||||
CHECK_THAT(help, Contains("1"));
|
||||
CHECK_THAT(help, Contains("2"));
|
||||
|
||||
CHECK(comp.real() == Approx(1));
|
||||
CHECK(comp.imag() == Approx(2));
|
||||
|
||||
run();
|
||||
|
||||
CHECK(comp.real() == Approx(4));
|
||||
CHECK(comp.imag() == Approx(3));
|
||||
}
|
||||
|
||||
// an example of custom complex number converter that can be used to add new parsing options
|
||||
#if defined(__has_include)
|
||||
#if __has_include(<regex>)
|
||||
// an example of custom converter that can be used to add new parsing options
|
||||
#define HAS_REGEX_INCLUDE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HAS_REGEX_INCLUDE
|
||||
// Gcc 4.8 and older and the corresponding standard libraries have a broken <regex> so this would
|
||||
// fail. And if a clang compiler is using libstd++ then this will generate an error as well so this is just a check to
|
||||
// simplify compilation and prevent a much more complicated #if expression
|
||||
#include <regex>
|
||||
namespace CLI {
|
||||
namespace detail {
|
||||
|
||||
// On MSVC and possibly some other new compilers this can be a free standing function without the template
|
||||
// specialization but this is compiler dependent
|
||||
template <> bool lexical_cast<std::complex<double>>(const std::string &input, std::complex<double> &output) {
|
||||
// regular expression to handle complex numbers of various formats
|
||||
static const std::regex creg(
|
||||
R"(([+-]?(\d+(\.\d+)?|\.\d+)([eE][+-]?\d+)?)\s*([+-]\s*(\d+(\.\d+)?|\.\d+)([eE][+-]?\d+)?)[ji]*)");
|
||||
|
||||
std::smatch m;
|
||||
double x{0.0}, y{0.0};
|
||||
bool worked = false;
|
||||
std::regex_search(input, m, creg);
|
||||
if(m.size() == 9) {
|
||||
worked = CLI::detail::lexical_cast(m[1], x) && CLI::detail::lexical_cast(m[6], y);
|
||||
if(worked) {
|
||||
if(*m[5].first == '-') {
|
||||
y = -y;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if((input.back() == 'j') || (input.back() == 'i')) {
|
||||
auto strval = input.substr(0, input.size() - 1);
|
||||
CLI::detail::trim(strval);
|
||||
worked = CLI::detail::lexical_cast(strval, y);
|
||||
} else {
|
||||
std::string ival = input;
|
||||
CLI::detail::trim(ival);
|
||||
worked = CLI::detail::lexical_cast(ival, x);
|
||||
}
|
||||
}
|
||||
if(worked) {
|
||||
output = cx{x, y};
|
||||
}
|
||||
return worked;
|
||||
}
|
||||
} // namespace detail
|
||||
} // namespace CLI
|
||||
|
||||
TEST_CASE_METHOD(TApp, "AddingComplexParserDetail", "[complex]") {
|
||||
|
||||
bool skip_tests = false;
|
||||
try { // check if the library actually supports regex, it is possible to link against a non working regex in the
|
||||
// standard library
|
||||
std::smatch m;
|
||||
std::string input = "1.5+2.5j";
|
||||
static const std::regex creg(
|
||||
R"(([+-]?(\d+(\.\d+)?|\.\d+)([eE][+-]?\d+)?)\s*([+-]\s*(\d+(\.\d+)?|\.\d+)([eE][+-]?\d+)?)[ji]*)");
|
||||
|
||||
auto rsearch = std::regex_search(input, m, creg);
|
||||
if(!rsearch) {
|
||||
skip_tests = true;
|
||||
} else {
|
||||
CHECK(9u == m.size());
|
||||
}
|
||||
|
||||
} catch(...) {
|
||||
skip_tests = true;
|
||||
}
|
||||
static_assert(CLI::detail::is_complex<cx>::value, "complex should register as complex in this situation");
|
||||
if(!skip_tests) {
|
||||
cx comp{0, 0};
|
||||
|
||||
app.add_option("-c,--complex", comp, "add a complex number option");
|
||||
args = {"-c", "1.5+2.5j"};
|
||||
|
||||
run();
|
||||
|
||||
CHECK(comp.real() == Approx(1.5));
|
||||
CHECK(comp.imag() == Approx(2.5));
|
||||
args = {"-c", "1.5-2.5j"};
|
||||
|
||||
run();
|
||||
|
||||
CHECK(comp.real() == Approx(1.5));
|
||||
CHECK(comp.imag() == Approx(-2.5));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// defining a new complex class
|
||||
class complex_new {
|
||||
public:
|
||||
complex_new() = default;
|
||||
complex_new(double v1, double v2) : val1_{v1}, val2_{v2} {};
|
||||
CLI11_NODISCARD double real() const { return val1_; }
|
||||
CLI11_NODISCARD double imag() const { return val2_; }
|
||||
|
||||
private:
|
||||
double val1_{0.0};
|
||||
double val2_{0.0};
|
||||
};
|
||||
|
||||
TEST_CASE_METHOD(TApp, "newComplex", "[complex]") {
|
||||
complex_new cval;
|
||||
static_assert(CLI::detail::is_complex<complex_new>::value, "complex new does not register as a complex type");
|
||||
static_assert(CLI::detail::classify_object<complex_new>::value == CLI::detail::object_category::complex_number,
|
||||
"complex new does not result in complex number categorization");
|
||||
app.add_option("-c,--complex", cval, "add a complex number option");
|
||||
args = {"-c", "1.5+2.5j"};
|
||||
|
||||
run();
|
||||
|
||||
CHECK(cval.real() == Approx(1.5));
|
||||
CHECK(cval.imag() == Approx(2.5));
|
||||
args = {"-c", "1.5-2.5j"};
|
||||
|
||||
run();
|
||||
|
||||
CHECK(cval.real() == Approx(1.5));
|
||||
CHECK(cval.imag() == Approx(-2.5));
|
||||
}
|
||||
2920
tests/ConfigFileTest.cpp
Normal file
2920
tests/ConfigFileTest.cpp
Normal file
File diff suppressed because it is too large
Load Diff
777
tests/CreationTest.cpp
Normal file
777
tests/CreationTest.cpp
Normal file
@@ -0,0 +1,777 @@
|
||||
// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include "app_helper.hpp"
|
||||
#include <cstdlib>
|
||||
|
||||
TEST_CASE_METHOD(TApp, "AddingExistingShort", "[creation]") {
|
||||
CLI::Option *opt = app.add_flag("-c,--count");
|
||||
CHECK(std::vector<std::string>({"count"}) == opt->get_lnames());
|
||||
CHECK(std::vector<std::string>({"c"}) == opt->get_snames());
|
||||
|
||||
CHECK_THROWS_AS(app.add_flag("--cat,-c"), CLI::OptionAlreadyAdded);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "AddingExistingLong", "[creation]") {
|
||||
app.add_flag("-q,--count");
|
||||
CHECK_THROWS_AS(app.add_flag("--count,-c"), CLI::OptionAlreadyAdded);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "AddingExistingShortNoCase", "[creation]") {
|
||||
app.add_flag("-C,--count")->ignore_case();
|
||||
CHECK_THROWS_AS(app.add_flag("--cat,-c"), CLI::OptionAlreadyAdded);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "AddingExistingLongNoCase", "[creation]") {
|
||||
app.add_flag("-q,--count")->ignore_case();
|
||||
CHECK_THROWS_AS(app.add_flag("--Count,-c"), CLI::OptionAlreadyAdded);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "AddingExistingNoCaseReversed", "[creation]") {
|
||||
app.add_flag("-c,--count")->ignore_case();
|
||||
CHECK_THROWS_AS(app.add_flag("--cat,-C"), CLI::OptionAlreadyAdded);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "AddingExistingWithCase", "[creation]") {
|
||||
app.add_flag("-c,--count");
|
||||
CHECK_NOTHROW(app.add_flag("--Cat,-C"));
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "AddingExistingWithCaseAfter", "[creation]") {
|
||||
auto *count = app.add_flag("-c,--count");
|
||||
app.add_flag("--Cat,-C");
|
||||
|
||||
CHECK_THROWS_AS(count->ignore_case(), CLI::OptionAlreadyAdded);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "AddingExistingWithCaseAfter2", "[creation]") {
|
||||
app.add_flag("-c,--count");
|
||||
auto *cat = app.add_flag("--Cat,-C");
|
||||
|
||||
CHECK_THROWS_AS(cat->ignore_case(), CLI::OptionAlreadyAdded);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "AddingExistingWithUnderscoreAfter", "[creation]") {
|
||||
auto *count = app.add_flag("--underscore");
|
||||
app.add_flag("--under_score");
|
||||
|
||||
CHECK_THROWS_AS(count->ignore_underscore(), CLI::OptionAlreadyAdded);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "AddingExistingWithUnderscoreAfter2", "[creation]") {
|
||||
auto *count = app.add_flag("--under_score");
|
||||
app.add_flag("--underscore");
|
||||
|
||||
CHECK_THROWS_AS(count->ignore_underscore(), CLI::OptionAlreadyAdded);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "AddingMultipleInfPositionals", "[creation]") {
|
||||
std::vector<std::string> one, two;
|
||||
app.add_option("one", one);
|
||||
app.add_option("two", two);
|
||||
|
||||
CHECK_THROWS_AS(run(), CLI::InvalidError);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "AddingMultipleInfPositionalsSubcom", "[creation]") {
|
||||
std::vector<std::string> one, two;
|
||||
CLI::App *below = app.add_subcommand("below");
|
||||
below->add_option("one", one);
|
||||
below->add_option("two", two);
|
||||
|
||||
CHECK_THROWS_AS(run(), CLI::InvalidError);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "MultipleSubcomMatching", "[creation]") {
|
||||
app.add_subcommand("first");
|
||||
app.add_subcommand("second");
|
||||
app.add_subcommand("Second");
|
||||
CHECK_THROWS_AS(app.add_subcommand("first"), CLI::OptionAlreadyAdded);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "RecoverSubcommands", "[creation]") {
|
||||
CLI::App *app1 = app.add_subcommand("app1");
|
||||
CLI::App *app2 = app.add_subcommand("app2");
|
||||
CLI::App *app3 = app.add_subcommand("app3");
|
||||
CLI::App *app4 = app.add_subcommand("app4");
|
||||
|
||||
CHECK(std::vector<CLI::App *>({app1, app2, app3, app4}) == app.get_subcommands({}));
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "MultipleSubcomMatchingWithCase", "[creation]") {
|
||||
app.add_subcommand("first")->ignore_case();
|
||||
CHECK_THROWS_AS(app.add_subcommand("fIrst"), CLI::OptionAlreadyAdded);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "MultipleSubcomMatchingWithCaseFirst", "[creation]") {
|
||||
app.ignore_case();
|
||||
app.add_subcommand("first");
|
||||
CHECK_THROWS_AS(app.add_subcommand("fIrst"), CLI::OptionAlreadyAdded);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "MultipleSubcomMatchingWithUnderscore", "[creation]") {
|
||||
app.add_subcommand("first_option")->ignore_underscore();
|
||||
CHECK_THROWS_AS(app.add_subcommand("firstoption"), CLI::OptionAlreadyAdded);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "MultipleSubcomMatchingWithUnderscoreFirst", "[creation]") {
|
||||
app.ignore_underscore();
|
||||
app.add_subcommand("first_option");
|
||||
CHECK_THROWS_AS(app.add_subcommand("firstoption"), CLI::OptionAlreadyAdded);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "MultipleSubcomMatchingWithCaseInplace", "[creation]") {
|
||||
app.add_subcommand("first");
|
||||
auto *first = app.add_subcommand("fIrst");
|
||||
|
||||
CHECK_THROWS_AS(first->ignore_case(), CLI::OptionAlreadyAdded);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "MultipleSubcomMatchingWithCaseInplace2", "[creation]") {
|
||||
auto *first = app.add_subcommand("first");
|
||||
app.add_subcommand("fIrst");
|
||||
|
||||
CHECK_THROWS_AS(first->ignore_case(), CLI::OptionAlreadyAdded);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "MultipleSubcomMatchingWithUnderscoreInplace", "[creation]") {
|
||||
app.add_subcommand("first_option");
|
||||
auto *first = app.add_subcommand("firstoption");
|
||||
|
||||
CHECK_THROWS_AS(first->ignore_underscore(), CLI::OptionAlreadyAdded);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "MultipleSubcomMatchingWithUnderscoreInplace2", "[creation]") {
|
||||
auto *first = app.add_subcommand("firstoption");
|
||||
app.add_subcommand("first_option");
|
||||
|
||||
CHECK_THROWS_AS(first->ignore_underscore(), CLI::OptionAlreadyAdded);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "MultipleSubcomNoMatchingInplace2", "[creation]") {
|
||||
auto *first = app.add_subcommand("first");
|
||||
auto *second = app.add_subcommand("second");
|
||||
|
||||
CHECK_NOTHROW(first->ignore_case());
|
||||
CHECK_NOTHROW(second->ignore_case());
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "MultipleSubcomNoMatchingInplaceUnderscore2", "[creation]") {
|
||||
auto *first = app.add_subcommand("first_option");
|
||||
auto *second = app.add_subcommand("second_option");
|
||||
|
||||
CHECK_NOTHROW(first->ignore_underscore());
|
||||
CHECK_NOTHROW(second->ignore_underscore());
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "IncorrectConstructionFlagPositional1", "[creation]") {
|
||||
// This wants to be one line with clang-format
|
||||
CHECK_THROWS_AS(app.add_flag("cat"), CLI::IncorrectConstruction);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "IncorrectConstructionFlagPositional2", "[creation]") {
|
||||
int x{0};
|
||||
CHECK_THROWS_AS(app.add_flag("cat", x), CLI::IncorrectConstruction);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "IncorrectConstructionFlagPositional3", "[creation]") {
|
||||
bool x{false};
|
||||
CHECK_THROWS_AS(app.add_flag("cat", x), CLI::IncorrectConstruction);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "IncorrectConstructionNeedsCannotFind", "[creation]") {
|
||||
auto *cat = app.add_flag("--cat");
|
||||
CHECK_THROWS_AS(cat->needs("--nothing"), CLI::IncorrectConstruction);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "IncorrectConstructionExcludesCannotFind", "[creation]") {
|
||||
auto *cat = app.add_flag("--cat");
|
||||
CHECK_THROWS_AS(cat->excludes("--nothing"), CLI::IncorrectConstruction);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "IncorrectConstructionDuplicateNeeds", "[creation]") {
|
||||
auto *cat = app.add_flag("--cat");
|
||||
auto *other = app.add_flag("--other");
|
||||
REQUIRE_NOTHROW(cat->needs(other));
|
||||
// duplicated needs is redundant but not an error
|
||||
CHECK_NOTHROW(cat->needs(other));
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "IncorrectConstructionDuplicateNeedsTxt", "[creation]") {
|
||||
auto *cat = app.add_flag("--cat");
|
||||
app.add_flag("--other");
|
||||
REQUIRE_NOTHROW(cat->needs("--other"));
|
||||
// duplicate needs is redundant but not an error
|
||||
CHECK_NOTHROW(cat->needs("--other"));
|
||||
}
|
||||
|
||||
// Now allowed
|
||||
TEST_CASE_METHOD(TApp, "CorrectConstructionDuplicateExcludes", "[creation]") {
|
||||
auto *cat = app.add_flag("--cat");
|
||||
auto *other = app.add_flag("--other");
|
||||
REQUIRE_NOTHROW(cat->excludes(other));
|
||||
REQUIRE_NOTHROW(other->excludes(cat));
|
||||
}
|
||||
|
||||
// Now allowed
|
||||
TEST_CASE_METHOD(TApp, "CorrectConstructionDuplicateExcludesTxt", "[creation]") {
|
||||
auto *cat = app.add_flag("--cat");
|
||||
auto *other = app.add_flag("--other");
|
||||
REQUIRE_NOTHROW(cat->excludes("--other"));
|
||||
REQUIRE_NOTHROW(other->excludes("--cat"));
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "CheckName", "[creation]") {
|
||||
auto *long1 = app.add_flag("--long1");
|
||||
auto *long2 = app.add_flag("--Long2");
|
||||
auto *short1 = app.add_flag("-a");
|
||||
auto *short2 = app.add_flag("-B");
|
||||
int x{0}, y{0};
|
||||
auto *pos1 = app.add_option("pos1", x);
|
||||
auto *pos2 = app.add_option("pOs2", y);
|
||||
|
||||
CHECK(long1->check_name("--long1"));
|
||||
CHECK(!long1->check_name("--lonG1"));
|
||||
|
||||
CHECK(long2->check_name("--Long2"));
|
||||
CHECK(!long2->check_name("--long2"));
|
||||
|
||||
CHECK(short1->check_name("-a"));
|
||||
CHECK(!short1->check_name("-A"));
|
||||
|
||||
CHECK(short2->check_name("-B"));
|
||||
CHECK(!short2->check_name("-b"));
|
||||
|
||||
CHECK(pos1->check_name("pos1"));
|
||||
CHECK(!pos1->check_name("poS1"));
|
||||
|
||||
CHECK(pos2->check_name("pOs2"));
|
||||
CHECK(!pos2->check_name("pos2"));
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "CheckNameNoCase", "[creation]") {
|
||||
auto *long1 = app.add_flag("--long1")->ignore_case();
|
||||
auto *long2 = app.add_flag("--Long2")->ignore_case();
|
||||
auto *short1 = app.add_flag("-a")->ignore_case();
|
||||
auto *short2 = app.add_flag("-B")->ignore_case();
|
||||
int x{0}, y{0};
|
||||
auto *pos1 = app.add_option("pos1", x)->ignore_case();
|
||||
auto *pos2 = app.add_option("pOs2", y)->ignore_case();
|
||||
|
||||
CHECK(long1->check_name("--long1"));
|
||||
CHECK(long1->check_name("--lonG1"));
|
||||
|
||||
CHECK(long2->check_name("--Long2"));
|
||||
CHECK(long2->check_name("--long2"));
|
||||
|
||||
CHECK(short1->check_name("-a"));
|
||||
CHECK(short1->check_name("-A"));
|
||||
|
||||
CHECK(short2->check_name("-B"));
|
||||
CHECK(short2->check_name("-b"));
|
||||
|
||||
CHECK(pos1->check_name("pos1"));
|
||||
CHECK(pos1->check_name("poS1"));
|
||||
|
||||
CHECK(pos2->check_name("pOs2"));
|
||||
CHECK(pos2->check_name("pos2"));
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "CheckNameNoUnderscore", "[creation]") {
|
||||
auto *long1 = app.add_flag("--longoption1")->ignore_underscore();
|
||||
auto *long2 = app.add_flag("--long_option2")->ignore_underscore();
|
||||
|
||||
int x{0}, y{0};
|
||||
auto *pos1 = app.add_option("pos_option_1", x)->ignore_underscore();
|
||||
auto *pos2 = app.add_option("posoption2", y)->ignore_underscore();
|
||||
|
||||
CHECK(long1->check_name("--long_option1"));
|
||||
CHECK(long1->check_name("--longoption_1"));
|
||||
CHECK(long1->check_name("--longoption1"));
|
||||
CHECK(long1->check_name("--long__opt_ion__1"));
|
||||
CHECK(long1->check_name("--__l_o_n_g_o_p_t_i_o_n_1"));
|
||||
|
||||
CHECK(long2->check_name("--long_option2"));
|
||||
CHECK(long2->check_name("--longoption2"));
|
||||
CHECK(long2->check_name("--longoption_2"));
|
||||
CHECK(long2->check_name("--long__opt_ion__2"));
|
||||
CHECK(long2->check_name("--__l_o_n_go_p_t_i_o_n_2__"));
|
||||
|
||||
CHECK(pos1->check_name("pos_option1"));
|
||||
CHECK(pos1->check_name("pos_option_1"));
|
||||
CHECK(pos1->check_name("pos_o_p_t_i_on_1"));
|
||||
CHECK(pos1->check_name("posoption1"));
|
||||
|
||||
CHECK(pos2->check_name("pos_option2"));
|
||||
CHECK(pos2->check_name("pos_option_2"));
|
||||
CHECK(pos2->check_name("pos_o_p_t_i_on_2"));
|
||||
CHECK(pos2->check_name("posoption2"));
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "CheckNameNoCaseNoUnderscore", "[creation]") {
|
||||
auto *long1 = app.add_flag("--LongoptioN1")->ignore_underscore()->ignore_case();
|
||||
auto *long2 = app.add_flag("--long_Option2")->ignore_case()->ignore_underscore();
|
||||
|
||||
int x{0}, y{0};
|
||||
auto *pos1 = app.add_option("pos_Option_1", x)->ignore_underscore()->ignore_case();
|
||||
auto *pos2 = app.add_option("posOption2", y)->ignore_case()->ignore_underscore();
|
||||
|
||||
CHECK(long1->check_name("--Long_Option1"));
|
||||
CHECK(long1->check_name("--lONgoption_1"));
|
||||
CHECK(long1->check_name("--LongOption1"));
|
||||
CHECK(long1->check_name("--long__Opt_ion__1"));
|
||||
CHECK(long1->check_name("--__l_o_N_g_o_P_t_i_O_n_1"));
|
||||
|
||||
CHECK(long2->check_name("--long_Option2"));
|
||||
CHECK(long2->check_name("--LongOption2"));
|
||||
CHECK(long2->check_name("--longOPTION_2"));
|
||||
CHECK(long2->check_name("--long__OPT_ion__2"));
|
||||
CHECK(long2->check_name("--__l_o_n_GO_p_t_i_o_n_2__"));
|
||||
|
||||
CHECK(pos1->check_name("POS_Option1"));
|
||||
CHECK(pos1->check_name("pos_option_1"));
|
||||
CHECK(pos1->check_name("pos_o_p_t_i_on_1"));
|
||||
CHECK(pos1->check_name("posoption1"));
|
||||
|
||||
CHECK(pos2->check_name("pos_option2"));
|
||||
CHECK(pos2->check_name("pos_OPTION_2"));
|
||||
CHECK(pos2->check_name("poS_o_p_T_I_on_2"));
|
||||
CHECK(pos2->check_name("PosOption2"));
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "PreSpaces", "[creation]") {
|
||||
int x{0};
|
||||
auto *myapp = app.add_option(" -a, --long, other", x);
|
||||
|
||||
CHECK(myapp->check_lname("long"));
|
||||
CHECK(myapp->check_sname("a"));
|
||||
CHECK(myapp->check_name("other"));
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "AllSpaces", "[creation]") {
|
||||
int x{0};
|
||||
auto *myapp = app.add_option(" -a , --long , other ", x);
|
||||
|
||||
CHECK(myapp->check_lname("long"));
|
||||
CHECK(myapp->check_sname("a"));
|
||||
CHECK(myapp->check_name("other"));
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "OptionFromDefaults", "[creation]") {
|
||||
app.option_defaults()->required();
|
||||
|
||||
// Options should remember defaults
|
||||
int x{0};
|
||||
auto *opt = app.add_option("--simple", x);
|
||||
CHECK(opt->get_required());
|
||||
|
||||
// Flags cannot be required
|
||||
auto *flag = app.add_flag("--other");
|
||||
CHECK(!flag->get_required());
|
||||
|
||||
app.option_defaults()->required(false);
|
||||
auto *opt2 = app.add_option("--simple2", x);
|
||||
CHECK(!opt2->get_required());
|
||||
|
||||
app.option_defaults()->required()->ignore_case();
|
||||
|
||||
auto *opt3 = app.add_option("--simple3", x);
|
||||
CHECK(opt3->get_required());
|
||||
CHECK(opt3->get_ignore_case());
|
||||
|
||||
app.option_defaults()->required()->ignore_underscore();
|
||||
|
||||
auto *opt4 = app.add_option("--simple4", x);
|
||||
CHECK(opt4->get_required());
|
||||
CHECK(opt4->get_ignore_underscore());
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "OptionFromDefaultsSubcommands", "[creation]") {
|
||||
// Initial defaults
|
||||
CHECK(!app.option_defaults()->get_required());
|
||||
CHECK(CLI::MultiOptionPolicy::Throw == app.option_defaults()->get_multi_option_policy());
|
||||
CHECK(!app.option_defaults()->get_ignore_case());
|
||||
CHECK(!app.option_defaults()->get_ignore_underscore());
|
||||
CHECK(!app.option_defaults()->get_disable_flag_override());
|
||||
CHECK(app.option_defaults()->get_configurable());
|
||||
CHECK("Options" == app.option_defaults()->get_group());
|
||||
|
||||
app.option_defaults()
|
||||
->required()
|
||||
->multi_option_policy(CLI::MultiOptionPolicy::TakeLast)
|
||||
->ignore_case()
|
||||
->ignore_underscore()
|
||||
->configurable(false)
|
||||
->disable_flag_override()
|
||||
->group("Something");
|
||||
|
||||
auto *app2 = app.add_subcommand("app2");
|
||||
|
||||
CHECK(app2->option_defaults()->get_required());
|
||||
CHECK(CLI::MultiOptionPolicy::TakeLast == app2->option_defaults()->get_multi_option_policy());
|
||||
CHECK(app2->option_defaults()->get_ignore_case());
|
||||
CHECK(app2->option_defaults()->get_ignore_underscore());
|
||||
CHECK(!app2->option_defaults()->get_configurable());
|
||||
CHECK(app.option_defaults()->get_disable_flag_override());
|
||||
CHECK("Something" == app2->option_defaults()->get_group());
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "GetNameCheck", "[creation]") {
|
||||
int x{0};
|
||||
auto *a = app.add_flag("--that");
|
||||
auto *b = app.add_flag("-x");
|
||||
auto *c = app.add_option("pos", x);
|
||||
auto *d = app.add_option("one,-o,--other", x);
|
||||
|
||||
CHECK("--that" == a->get_name(false, true));
|
||||
CHECK("-x" == b->get_name(false, true));
|
||||
CHECK("pos" == c->get_name(false, true));
|
||||
|
||||
CHECK("--other" == d->get_name());
|
||||
CHECK("--other" == d->get_name(false, false));
|
||||
CHECK("-o,--other" == d->get_name(false, true));
|
||||
CHECK("one,-o,--other" == d->get_name(true, true));
|
||||
CHECK("one" == d->get_name(true, false));
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "SubcommandDefaults", "[creation]") {
|
||||
// allow_extras, prefix_command, ignore_case, fallthrough, group, min/max subcommand, validate_positionals
|
||||
|
||||
// Initial defaults
|
||||
CHECK(!app.get_allow_extras());
|
||||
CHECK(!app.get_prefix_command());
|
||||
CHECK(!app.get_immediate_callback());
|
||||
CHECK(!app.get_ignore_case());
|
||||
CHECK(!app.get_ignore_underscore());
|
||||
#ifdef _WIN32
|
||||
CHECK(app.get_allow_windows_style_options());
|
||||
#else
|
||||
CHECK(!app.get_allow_windows_style_options());
|
||||
#endif
|
||||
CHECK(!app.get_fallthrough());
|
||||
CHECK(!app.get_configurable());
|
||||
CHECK(!app.get_validate_positionals());
|
||||
|
||||
CHECK(app.get_footer().empty());
|
||||
CHECK("Subcommands" == app.get_group());
|
||||
CHECK(0u == app.get_require_subcommand_min());
|
||||
CHECK(0u == app.get_require_subcommand_max());
|
||||
|
||||
app.allow_extras();
|
||||
app.prefix_command();
|
||||
app.immediate_callback();
|
||||
app.ignore_case();
|
||||
app.ignore_underscore();
|
||||
app.configurable();
|
||||
#ifdef _WIN32
|
||||
app.allow_windows_style_options(false);
|
||||
#else
|
||||
app.allow_windows_style_options();
|
||||
#endif
|
||||
|
||||
app.fallthrough();
|
||||
app.validate_positionals();
|
||||
app.footer("footy");
|
||||
app.group("Stuff");
|
||||
app.require_subcommand(2, 3);
|
||||
|
||||
auto *app2 = app.add_subcommand("app2");
|
||||
|
||||
// Initial defaults
|
||||
CHECK(app2->get_allow_extras());
|
||||
CHECK(app2->get_prefix_command());
|
||||
CHECK(app2->get_immediate_callback());
|
||||
CHECK(app2->get_ignore_case());
|
||||
CHECK(app2->get_ignore_underscore());
|
||||
#ifdef _WIN32
|
||||
CHECK(!app2->get_allow_windows_style_options());
|
||||
#else
|
||||
CHECK(app2->get_allow_windows_style_options());
|
||||
#endif
|
||||
CHECK(app2->get_fallthrough());
|
||||
CHECK(app2->get_validate_positionals());
|
||||
CHECK(app2->get_configurable());
|
||||
CHECK("footy" == app2->get_footer());
|
||||
CHECK("Stuff" == app2->get_group());
|
||||
CHECK(0u == app2->get_require_subcommand_min());
|
||||
CHECK(3u == app2->get_require_subcommand_max());
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "SubcommandMinMax", "[creation]") {
|
||||
|
||||
CHECK(0u == app.get_require_subcommand_min());
|
||||
CHECK(0u == app.get_require_subcommand_max());
|
||||
|
||||
app.require_subcommand();
|
||||
|
||||
CHECK(1u == app.get_require_subcommand_min());
|
||||
CHECK(0u == app.get_require_subcommand_max());
|
||||
|
||||
app.require_subcommand(2);
|
||||
|
||||
CHECK(2u == app.get_require_subcommand_min());
|
||||
CHECK(2u == app.get_require_subcommand_max());
|
||||
|
||||
app.require_subcommand(0);
|
||||
|
||||
CHECK(0u == app.get_require_subcommand_min());
|
||||
CHECK(0u == app.get_require_subcommand_max());
|
||||
|
||||
app.require_subcommand(-2);
|
||||
|
||||
CHECK(0u == app.get_require_subcommand_min());
|
||||
CHECK(2u == app.get_require_subcommand_max());
|
||||
|
||||
app.require_subcommand(3, 7);
|
||||
|
||||
CHECK(3u == app.get_require_subcommand_min());
|
||||
CHECK(7u == app.get_require_subcommand_max());
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "GetOptionList", "[creation]") {
|
||||
int two{0};
|
||||
auto *flag = app.add_flag("--one");
|
||||
auto *opt = app.add_option("--two", two);
|
||||
|
||||
const CLI::App &const_app = app; // const alias to force use of const-methods
|
||||
std::vector<const CLI::Option *> opt_list = const_app.get_options();
|
||||
|
||||
REQUIRE(static_cast<std::size_t>(3) == opt_list.size());
|
||||
CHECK(flag == opt_list.at(1));
|
||||
CHECK(opt == opt_list.at(2));
|
||||
|
||||
std::vector<CLI::Option *> nonconst_opt_list = app.get_options();
|
||||
for(std::size_t i = 0; i < opt_list.size(); ++i) {
|
||||
CHECK(opt_list.at(i) == nonconst_opt_list.at(i));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "GetOptionListFilter", "[creation]") {
|
||||
int two{0};
|
||||
auto *flag = app.add_flag("--one");
|
||||
app.add_option("--two", two);
|
||||
|
||||
const CLI::App &const_app = app; // const alias to force use of const-methods
|
||||
std::vector<const CLI::Option *> opt_listc =
|
||||
const_app.get_options([](const CLI::Option *opt) { return opt->get_name() == "--one"; });
|
||||
|
||||
REQUIRE(static_cast<std::size_t>(1) == opt_listc.size());
|
||||
CHECK(flag == opt_listc.at(0));
|
||||
|
||||
std::vector<CLI::Option *> opt_list =
|
||||
app.get_options([](const CLI::Option *opt) { return opt->get_name() == "--one"; });
|
||||
|
||||
REQUIRE(static_cast<std::size_t>(1) == opt_list.size());
|
||||
CHECK(flag == opt_list.at(0));
|
||||
}
|
||||
|
||||
TEST_CASE("ValidatorTests: TestValidatorCreation", "[creation]") {
|
||||
std::function<std::string(std::string &)> op1 = [](std::string &val) {
|
||||
return (val.size() >= 5) ? std::string{} : val;
|
||||
};
|
||||
CLI::Validator V(op1, "", "size");
|
||||
|
||||
CHECK("size" == V.get_name());
|
||||
V.name("harry");
|
||||
CHECK("harry" == V.get_name());
|
||||
CHECK(V.get_active());
|
||||
|
||||
CHECK("test" == V("test"));
|
||||
CHECK(V("test5").empty());
|
||||
|
||||
CHECK(V.get_description().empty());
|
||||
V.description("this is a description");
|
||||
CHECK("this is a description" == V.get_description());
|
||||
}
|
||||
|
||||
TEST_CASE("ValidatorTests: TestValidatorOps", "[creation]") {
|
||||
std::function<std::string(std::string &)> op1 = [](std::string &val) {
|
||||
return (val.size() >= 5) ? std::string{} : val;
|
||||
};
|
||||
std::function<std::string(std::string &)> op2 = [](std::string &val) {
|
||||
return (val.size() >= 9) ? std::string{} : val;
|
||||
};
|
||||
std::function<std::string(std::string &)> op3 = [](std::string &val) {
|
||||
return (val.size() < 3) ? std::string{} : val;
|
||||
};
|
||||
std::function<std::string(std::string &)> op4 = [](std::string &val) {
|
||||
return (val.size() <= 9) ? std::string{} : val;
|
||||
};
|
||||
CLI::Validator V1(op1, "SIZE >= 5");
|
||||
|
||||
CLI::Validator V2(op2, "SIZE >= 9");
|
||||
CLI::Validator V3(op3, "SIZE < 3");
|
||||
CLI::Validator V4(op4, "SIZE <= 9");
|
||||
|
||||
std::string two(2, 'a');
|
||||
std::string four(4, 'a');
|
||||
std::string five(5, 'a');
|
||||
std::string eight(8, 'a');
|
||||
std::string nine(9, 'a');
|
||||
std::string ten(10, 'a');
|
||||
CHECK(V1(five).empty());
|
||||
CHECK(!V1(four).empty());
|
||||
|
||||
CHECK(V2(nine).empty());
|
||||
CHECK(!V2(eight).empty());
|
||||
|
||||
CHECK(V3(two).empty());
|
||||
CHECK(!V3(four).empty());
|
||||
|
||||
CHECK(V4(eight).empty());
|
||||
CHECK(!V4(ten).empty());
|
||||
|
||||
auto V1a2 = V1 & V2;
|
||||
CHECK("(SIZE >= 5) AND (SIZE >= 9)" == V1a2.get_description());
|
||||
CHECK(!V1a2(five).empty());
|
||||
CHECK(V1a2(nine).empty());
|
||||
|
||||
auto V1a4 = V1 & V4;
|
||||
CHECK("(SIZE >= 5) AND (SIZE <= 9)" == V1a4.get_description());
|
||||
CHECK(V1a4(five).empty());
|
||||
CHECK(V1a4(eight).empty());
|
||||
CHECK(!V1a4(ten).empty());
|
||||
CHECK(!V1a4(four).empty());
|
||||
|
||||
auto V1o3 = V1 | V3;
|
||||
CHECK("(SIZE >= 5) OR (SIZE < 3)" == V1o3.get_description());
|
||||
CHECK(V1o3(two).empty());
|
||||
CHECK(V1o3(eight).empty());
|
||||
CHECK(V1o3(ten).empty());
|
||||
CHECK(V1o3(two).empty());
|
||||
CHECK(!V1o3(four).empty());
|
||||
|
||||
auto m1 = V1o3 & V4;
|
||||
CHECK("((SIZE >= 5) OR (SIZE < 3)) AND (SIZE <= 9)" == m1.get_description());
|
||||
CHECK(m1(two).empty());
|
||||
CHECK(m1(eight).empty());
|
||||
CHECK(!m1(ten).empty());
|
||||
CHECK(m1(two).empty());
|
||||
CHECK(m1(five).empty());
|
||||
CHECK(!m1(four).empty());
|
||||
|
||||
auto m2 = m1 & V2;
|
||||
CHECK("(((SIZE >= 5) OR (SIZE < 3)) AND (SIZE <= 9)) AND (SIZE >= 9)" == m2.get_description());
|
||||
CHECK(!m2(two).empty());
|
||||
CHECK(!m2(eight).empty());
|
||||
CHECK(!m2(ten).empty());
|
||||
CHECK(!m2(two).empty());
|
||||
CHECK(m2(nine).empty());
|
||||
CHECK(!m2(four).empty());
|
||||
|
||||
auto m3 = m2 | V3;
|
||||
CHECK("((((SIZE >= 5) OR (SIZE < 3)) AND (SIZE <= 9)) AND (SIZE >= 9)) OR (SIZE < 3)" == m3.get_description());
|
||||
CHECK(m3(two).empty());
|
||||
CHECK(!m3(eight).empty());
|
||||
CHECK(m3(nine).empty());
|
||||
CHECK(!m3(four).empty());
|
||||
|
||||
auto m4 = V3 | m2;
|
||||
CHECK("(SIZE < 3) OR ((((SIZE >= 5) OR (SIZE < 3)) AND (SIZE <= 9)) AND (SIZE >= 9))" == m4.get_description());
|
||||
CHECK(m4(two).empty());
|
||||
CHECK(!m4(eight).empty());
|
||||
CHECK(m4(nine).empty());
|
||||
CHECK(!m4(four).empty());
|
||||
}
|
||||
|
||||
TEST_CASE("ValidatorTests: TestValidatorNegation", "[creation]") {
|
||||
|
||||
std::function<std::string(std::string &)> op1 = [](std::string &val) {
|
||||
return (val.size() >= 5) ? std::string{} : val;
|
||||
};
|
||||
|
||||
CLI::Validator V1(op1, "SIZE >= 5", "size");
|
||||
|
||||
std::string four(4, 'a');
|
||||
std::string five(5, 'a');
|
||||
|
||||
CHECK(V1(five).empty());
|
||||
CHECK(!V1(four).empty());
|
||||
|
||||
auto V2 = !V1;
|
||||
CHECK(!V2(five).empty());
|
||||
CHECK(V2(four).empty());
|
||||
CHECK("NOT SIZE >= 5" == V2.get_description());
|
||||
|
||||
V2.active(false);
|
||||
CHECK(V2(five).empty());
|
||||
CHECK(V2(four).empty());
|
||||
CHECK(V2.get_description().empty());
|
||||
}
|
||||
|
||||
TEST_CASE("ValidatorTests: ValidatorDefaults", "[creation]") {
|
||||
|
||||
CLI::Validator V1{};
|
||||
|
||||
std::string four(4, 'a');
|
||||
std::string five(5, 'a');
|
||||
|
||||
// make sure this doesn't generate a seg fault or something
|
||||
CHECK(V1(five).empty());
|
||||
CHECK(V1(four).empty());
|
||||
|
||||
CHECK(V1.get_name().empty());
|
||||
CHECK(V1.get_description().empty());
|
||||
CHECK(V1.get_active());
|
||||
CHECK(V1.get_modifying());
|
||||
|
||||
CLI::Validator V2{"check"};
|
||||
// make sure this doesn't generate a seg fault or something
|
||||
CHECK(V2(five).empty());
|
||||
CHECK(V2(four).empty());
|
||||
|
||||
CHECK(V2.get_name().empty());
|
||||
CHECK("check" == V2.get_description());
|
||||
CHECK(V2.get_active());
|
||||
CHECK(V2.get_modifying());
|
||||
// This class only support streaming in, not out
|
||||
}
|
||||
|
||||
class Unstreamable {
|
||||
private:
|
||||
int x_{-1};
|
||||
|
||||
public:
|
||||
Unstreamable() = default;
|
||||
CLI11_NODISCARD int get_x() const { return x_; }
|
||||
void set_x(int x) { x_ = x; }
|
||||
};
|
||||
|
||||
// this needs to be a different check then the one after the function definition otherwise they conflict
|
||||
static_assert(!CLI::detail::is_istreamable<Unstreamable, std::istream>::value, "Unstreamable type is streamable");
|
||||
|
||||
std::istream &operator>>(std::istream &in, Unstreamable &value) {
|
||||
int x = 0;
|
||||
in >> x;
|
||||
value.set_x(x);
|
||||
return in;
|
||||
}
|
||||
// these need to be different classes otherwise the definitions conflict
|
||||
static_assert(CLI::detail::is_istreamable<Unstreamable>::value,
|
||||
"Unstreamable type is still unstreamable and it should be");
|
||||
|
||||
TEST_CASE_METHOD(TApp, "MakeUnstreamableOptions", "[creation]") {
|
||||
Unstreamable value;
|
||||
app.add_option("--value", value);
|
||||
|
||||
// This used to fail to build, since it tries to stream from Unstreamable
|
||||
app.add_option("--value2", value);
|
||||
|
||||
std::vector<Unstreamable> values;
|
||||
app.add_option("--values", values);
|
||||
|
||||
// This used to fail to build, since it tries to stream from Unstreamable
|
||||
app.add_option("--values2", values);
|
||||
|
||||
args = {"--value", "45"};
|
||||
run();
|
||||
CHECK(45 == value.get_x());
|
||||
|
||||
args = {"--values", "45", "27", "34"};
|
||||
run();
|
||||
CHECK(3u == values.size());
|
||||
CHECK(34 == values[2].get_x());
|
||||
}
|
||||
14
tests/DeprecatedTest.cpp
Normal file
14
tests/DeprecatedTest.cpp
Normal file
@@ -0,0 +1,14 @@
|
||||
// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include "app_helper.hpp"
|
||||
|
||||
using Catch::Matchers::Contains;
|
||||
|
||||
TEST_CASE("Deprecated: Empty", "[deprecated]") {
|
||||
// No deprecated features at this time.
|
||||
CHECK(true);
|
||||
}
|
||||
211
tests/FormatterTest.cpp
Normal file
211
tests/FormatterTest.cpp
Normal file
@@ -0,0 +1,211 @@
|
||||
// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#ifdef CLI11_SINGLE_FILE
|
||||
#include "CLI11.hpp"
|
||||
#else
|
||||
#include "CLI/CLI.hpp"
|
||||
#endif
|
||||
|
||||
#include "catch.hpp"
|
||||
#include <fstream>
|
||||
|
||||
using Catch::Matchers::Contains;
|
||||
|
||||
class SimpleFormatter : public CLI::FormatterBase {
|
||||
public:
|
||||
SimpleFormatter() : FormatterBase() {}
|
||||
|
||||
std::string make_help(const CLI::App *, std::string, CLI::AppFormatMode) const override {
|
||||
return "This is really simple";
|
||||
}
|
||||
};
|
||||
|
||||
TEST_CASE("Formatter: Nothing", "[formatter]") {
|
||||
CLI::App app{"My prog"};
|
||||
|
||||
app.formatter(std::make_shared<SimpleFormatter>());
|
||||
|
||||
std::string help = app.help();
|
||||
|
||||
CHECK("This is really simple" == help);
|
||||
}
|
||||
|
||||
TEST_CASE("Formatter: NothingLambda", "[formatter]") {
|
||||
CLI::App app{"My prog"};
|
||||
|
||||
app.formatter_fn(
|
||||
[](const CLI::App *, std::string, CLI::AppFormatMode) { return std::string("This is really simple"); });
|
||||
|
||||
std::string help = app.help();
|
||||
|
||||
CHECK("This is really simple" == help);
|
||||
}
|
||||
|
||||
TEST_CASE("Formatter: OptCustomize", "[formatter]") {
|
||||
CLI::App app{"My prog"};
|
||||
|
||||
auto optfmt = std::make_shared<CLI::Formatter>();
|
||||
optfmt->column_width(25);
|
||||
optfmt->label("REQUIRED", "(MUST HAVE)");
|
||||
app.formatter(optfmt);
|
||||
|
||||
int v{0};
|
||||
app.add_option("--opt", v, "Something")->required();
|
||||
|
||||
std::string help = app.help();
|
||||
|
||||
CHECK_THAT(help, Contains("(MUST HAVE)"));
|
||||
CHECK(help == "My prog\n"
|
||||
"Usage: [OPTIONS]\n\n"
|
||||
"Options:\n"
|
||||
" -h,--help Print this help message and exit\n"
|
||||
" --opt INT (MUST HAVE) Something\n\n");
|
||||
}
|
||||
|
||||
TEST_CASE("Formatter: OptCustomizeSimple", "[formatter]") {
|
||||
CLI::App app{"My prog"};
|
||||
|
||||
app.get_formatter()->column_width(25);
|
||||
app.get_formatter()->label("REQUIRED", "(MUST HAVE)");
|
||||
|
||||
int v{0};
|
||||
app.add_option("--opt", v, "Something")->required();
|
||||
|
||||
std::string help = app.help();
|
||||
|
||||
CHECK_THAT(help, Contains("(MUST HAVE)"));
|
||||
CHECK(help == "My prog\n"
|
||||
"Usage: [OPTIONS]\n\n"
|
||||
"Options:\n"
|
||||
" -h,--help Print this help message and exit\n"
|
||||
" --opt INT (MUST HAVE) Something\n\n");
|
||||
}
|
||||
|
||||
TEST_CASE("Formatter: OptCustomizeOptionText", "[formatter]") {
|
||||
CLI::App app{"My prog"};
|
||||
|
||||
app.get_formatter()->column_width(25);
|
||||
|
||||
int v{0};
|
||||
app.add_option("--opt", v, "Something")->option_text("(ARG)");
|
||||
|
||||
std::string help = app.help();
|
||||
|
||||
CHECK_THAT(help, Contains("(ARG)"));
|
||||
CHECK(help == "My prog\n"
|
||||
"Usage: [OPTIONS]\n\n"
|
||||
"Options:\n"
|
||||
" -h,--help Print this help message and exit\n"
|
||||
" --opt (ARG) Something\n\n");
|
||||
}
|
||||
|
||||
TEST_CASE("Formatter: FalseFlagExample", "[formatter]") {
|
||||
CLI::App app{"My prog"};
|
||||
|
||||
app.get_formatter()->column_width(25);
|
||||
app.get_formatter()->label("REQUIRED", "(MUST HAVE)");
|
||||
|
||||
int v{0};
|
||||
app.add_flag("--opt,!--no_opt", v, "Something");
|
||||
|
||||
bool flag{false};
|
||||
app.add_flag("!-O,--opt2,--no_opt2{false}", flag, "Something else");
|
||||
|
||||
std::string help = app.help();
|
||||
|
||||
CHECK_THAT(help, Contains("--no_opt{false}"));
|
||||
CHECK_THAT(help, Contains("--no_opt2{false}"));
|
||||
CHECK_THAT(help, Contains("-O{false}"));
|
||||
}
|
||||
|
||||
TEST_CASE("Formatter: AppCustomize", "[formatter]") {
|
||||
CLI::App app{"My prog"};
|
||||
app.add_subcommand("subcom1", "This");
|
||||
|
||||
auto appfmt = std::make_shared<CLI::Formatter>();
|
||||
appfmt->column_width(20);
|
||||
appfmt->label("Usage", "Run");
|
||||
app.formatter(appfmt);
|
||||
|
||||
app.add_subcommand("subcom2", "This");
|
||||
|
||||
std::string help = app.help();
|
||||
CHECK(help == "My prog\n"
|
||||
"Run: [OPTIONS] [SUBCOMMAND]\n\n"
|
||||
"Options:\n"
|
||||
" -h,--help Print this help message and exit\n\n"
|
||||
"Subcommands:\n"
|
||||
" subcom1 This\n"
|
||||
" subcom2 This\n\n");
|
||||
}
|
||||
|
||||
TEST_CASE("Formatter: AppCustomizeSimple", "[formatter]") {
|
||||
CLI::App app{"My prog"};
|
||||
app.add_subcommand("subcom1", "This");
|
||||
|
||||
app.get_formatter()->column_width(20);
|
||||
app.get_formatter()->label("Usage", "Run");
|
||||
|
||||
app.add_subcommand("subcom2", "This");
|
||||
|
||||
std::string help = app.help();
|
||||
CHECK(help == "My prog\n"
|
||||
"Run: [OPTIONS] [SUBCOMMAND]\n\n"
|
||||
"Options:\n"
|
||||
" -h,--help Print this help message and exit\n\n"
|
||||
"Subcommands:\n"
|
||||
" subcom1 This\n"
|
||||
" subcom2 This\n\n");
|
||||
}
|
||||
|
||||
TEST_CASE("Formatter: AllSub", "[formatter]") {
|
||||
CLI::App app{"My prog"};
|
||||
CLI::App *sub = app.add_subcommand("subcom", "This");
|
||||
sub->add_flag("--insub", "MyFlag");
|
||||
|
||||
std::string help = app.help("", CLI::AppFormatMode::All);
|
||||
CHECK_THAT(help, Contains("--insub"));
|
||||
CHECK_THAT(help, Contains("subcom"));
|
||||
}
|
||||
|
||||
TEST_CASE("Formatter: AllSubRequired", "[formatter]") {
|
||||
CLI::App app{"My prog"};
|
||||
CLI::App *sub = app.add_subcommand("subcom", "This");
|
||||
sub->add_flag("--insub", "MyFlag");
|
||||
sub->required();
|
||||
std::string help = app.help("", CLI::AppFormatMode::All);
|
||||
CHECK_THAT(help, Contains("--insub"));
|
||||
CHECK_THAT(help, Contains("subcom"));
|
||||
CHECK_THAT(help, Contains("REQUIRED"));
|
||||
}
|
||||
|
||||
TEST_CASE("Formatter: NamelessSub", "[formatter]") {
|
||||
CLI::App app{"My prog"};
|
||||
CLI::App *sub = app.add_subcommand("", "This subcommand");
|
||||
sub->add_flag("--insub", "MyFlag");
|
||||
|
||||
std::string help = app.help("", CLI::AppFormatMode::Normal);
|
||||
CHECK_THAT(help, Contains("--insub"));
|
||||
CHECK_THAT(help, Contains("This subcommand"));
|
||||
}
|
||||
|
||||
TEST_CASE("Formatter: NamelessSubInGroup", "[formatter]") {
|
||||
CLI::App app{"My prog"};
|
||||
CLI::App *sub = app.add_subcommand("", "This subcommand");
|
||||
CLI::App *sub2 = app.add_subcommand("sub2", "subcommand2");
|
||||
sub->add_flag("--insub", "MyFlag");
|
||||
int val{0};
|
||||
sub2->add_option("pos", val, "positional");
|
||||
sub->group("group1");
|
||||
sub2->group("group1");
|
||||
std::string help = app.help("", CLI::AppFormatMode::Normal);
|
||||
CHECK_THAT(help, Contains("--insub"));
|
||||
CHECK_THAT(help, Contains("This subcommand"));
|
||||
CHECK_THAT(help, Contains("group1"));
|
||||
CHECK_THAT(help, Contains("sub2"));
|
||||
CHECK(help.find("pos") == std::string::npos);
|
||||
}
|
||||
1275
tests/HelpTest.cpp
Normal file
1275
tests/HelpTest.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1335
tests/HelpersTest.cpp
Normal file
1335
tests/HelpersTest.cpp
Normal file
File diff suppressed because it is too large
Load Diff
495
tests/NewParseTest.cpp
Normal file
495
tests/NewParseTest.cpp
Normal file
@@ -0,0 +1,495 @@
|
||||
// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include "app_helper.hpp"
|
||||
|
||||
#include <complex>
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
|
||||
using Catch::Matchers::Contains;
|
||||
|
||||
using cx = std::complex<double>;
|
||||
|
||||
TEST_CASE_METHOD(TApp, "ComplexOption", "[newparse]") {
|
||||
cx comp{1, 2};
|
||||
app.add_option("-c,--complex", comp)->capture_default_str();
|
||||
|
||||
args = {"-c", "4", "3"};
|
||||
|
||||
std::string help = app.help();
|
||||
CHECK_THAT(help, Contains("1"));
|
||||
CHECK_THAT(help, Contains("2"));
|
||||
CHECK_THAT(help, Contains("COMPLEX"));
|
||||
|
||||
CHECK(comp.real() == Approx(1));
|
||||
CHECK(comp.imag() == Approx(2));
|
||||
|
||||
run();
|
||||
|
||||
CHECK(comp.real() == Approx(4));
|
||||
CHECK(comp.imag() == Approx(3));
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "ComplexFloatOption", "[newparse]") {
|
||||
std::complex<float> comp{1, 2};
|
||||
app.add_option("-c,--complex", comp)->capture_default_str();
|
||||
|
||||
args = {"-c", "4", "3"};
|
||||
|
||||
std::string help = app.help();
|
||||
CHECK_THAT(help, Contains("1"));
|
||||
CHECK_THAT(help, Contains("2"));
|
||||
CHECK_THAT(help, Contains("COMPLEX"));
|
||||
|
||||
CHECK(comp.real() == Approx(1));
|
||||
CHECK(comp.imag() == Approx(2));
|
||||
|
||||
run();
|
||||
|
||||
CHECK(comp.real() == Approx(4));
|
||||
CHECK(comp.imag() == Approx(3));
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "ComplexWithDelimiterOption", "[newparse]") {
|
||||
cx comp{1, 2};
|
||||
app.add_option("-c,--complex", comp)->capture_default_str()->delimiter('+');
|
||||
|
||||
args = {"-c", "4+3i"};
|
||||
|
||||
std::string help = app.help();
|
||||
CHECK_THAT(help, Contains("1"));
|
||||
CHECK_THAT(help, Contains("2"));
|
||||
CHECK_THAT(help, Contains("COMPLEX"));
|
||||
|
||||
CHECK(comp.real() == Approx(1));
|
||||
CHECK(comp.imag() == Approx(2));
|
||||
|
||||
run();
|
||||
|
||||
CHECK(comp.real() == Approx(4));
|
||||
CHECK(comp.imag() == Approx(3));
|
||||
|
||||
args = {"-c", "5+-3i"};
|
||||
run();
|
||||
|
||||
CHECK(comp.real() == Approx(5));
|
||||
CHECK(comp.imag() == Approx(-3));
|
||||
|
||||
args = {"-c", "6", "-4i"};
|
||||
run();
|
||||
|
||||
CHECK(comp.real() == Approx(6));
|
||||
CHECK(comp.imag() == Approx(-4));
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "ComplexIgnoreIOption", "[newparse]") {
|
||||
cx comp{1, 2};
|
||||
app.add_option("-c,--complex", comp);
|
||||
|
||||
args = {"-c", "4", "3i"};
|
||||
|
||||
run();
|
||||
|
||||
CHECK(comp.real() == Approx(4));
|
||||
CHECK(comp.imag() == Approx(3));
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "ComplexSingleArgOption", "[newparse]") {
|
||||
cx comp{1, 2};
|
||||
app.add_option("-c,--complex", comp);
|
||||
|
||||
args = {"-c", "4"};
|
||||
run();
|
||||
CHECK(comp.real() == Approx(4));
|
||||
CHECK(comp.imag() == Approx(0));
|
||||
|
||||
args = {"-c", "4-2i"};
|
||||
run();
|
||||
CHECK(comp.real() == Approx(4));
|
||||
CHECK(comp.imag() == Approx(-2));
|
||||
args = {"-c", "4+2i"};
|
||||
run();
|
||||
CHECK(comp.real() == Approx(4));
|
||||
CHECK(comp.imag() == Approx(2));
|
||||
|
||||
args = {"-c", "-4+2j"};
|
||||
run();
|
||||
CHECK(comp.real() == Approx(-4));
|
||||
CHECK(comp.imag() == Approx(2));
|
||||
|
||||
args = {"-c", "-4.2-2j"};
|
||||
run();
|
||||
CHECK(comp.real() == Approx(-4.2));
|
||||
CHECK(comp.imag() == Approx(-2));
|
||||
|
||||
args = {"-c", "-4.2-2.7i"};
|
||||
run();
|
||||
CHECK(comp.real() == Approx(-4.2));
|
||||
CHECK(comp.imag() == Approx(-2.7));
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "ComplexSingleImagOption", "[newparse]") {
|
||||
cx comp{1, 2};
|
||||
app.add_option("-c,--complex", comp);
|
||||
|
||||
args = {"-c", "4j"};
|
||||
run();
|
||||
CHECK(comp.real() == Approx(0));
|
||||
CHECK(comp.imag() == Approx(4));
|
||||
|
||||
args = {"-c", "-4j"};
|
||||
run();
|
||||
CHECK(comp.real() == Approx(0));
|
||||
CHECK(comp.imag() == Approx(-4));
|
||||
args = {"-c", "-4"};
|
||||
run();
|
||||
CHECK(comp.real() == Approx(-4));
|
||||
CHECK(comp.imag() == Approx(0));
|
||||
args = {"-c", "+4"};
|
||||
run();
|
||||
CHECK(comp.real() == Approx(4));
|
||||
CHECK(comp.imag() == Approx(0));
|
||||
}
|
||||
|
||||
/// Simple class containing two strings useful for testing lexical cast and conversions
|
||||
class spair {
|
||||
public:
|
||||
spair() = default;
|
||||
spair(std::string s1, std::string s2) : first(std::move(s1)), second(std::move(s2)) {}
|
||||
std::string first{};
|
||||
std::string second{};
|
||||
};
|
||||
// an example of custom converter that can be used to add new parsing options
|
||||
// On MSVC and possibly some other new compilers this can be a free standing function without the template
|
||||
// specialization but this is compiler dependent
|
||||
namespace CLI {
|
||||
namespace detail {
|
||||
|
||||
template <> bool lexical_cast<spair>(const std::string &input, spair &output) {
|
||||
|
||||
auto sep = input.find_first_of(':');
|
||||
if((sep == std::string::npos) && (sep > 0)) {
|
||||
return false;
|
||||
}
|
||||
output = {input.substr(0, sep), input.substr(sep + 1)};
|
||||
return true;
|
||||
}
|
||||
} // namespace detail
|
||||
} // namespace CLI
|
||||
|
||||
TEST_CASE_METHOD(TApp, "custom_string_converter", "[newparse]") {
|
||||
spair val;
|
||||
app.add_option("-d,--dual_string", val);
|
||||
|
||||
args = {"-d", "string1:string2"};
|
||||
|
||||
run();
|
||||
CHECK("string1" == val.first);
|
||||
CHECK("string2" == val.second);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "custom_string_converterFail", "[newparse]") {
|
||||
spair val;
|
||||
app.add_option("-d,--dual_string", val);
|
||||
|
||||
args = {"-d", "string2"};
|
||||
|
||||
CHECK_THROWS_AS(run(), CLI::ConversionError);
|
||||
}
|
||||
|
||||
/// simple class to wrap another with a very specific type constructor and assignment operators to test out some of the
|
||||
/// option assignments
|
||||
template <class X> class objWrapper {
|
||||
public:
|
||||
objWrapper() = default;
|
||||
explicit objWrapper(X obj) : val_{std::move(obj)} {};
|
||||
objWrapper(const objWrapper &ow) = default;
|
||||
template <class TT> objWrapper(const TT &obj) = delete;
|
||||
objWrapper &operator=(const objWrapper &) = default;
|
||||
// noexcept not allowed below by GCC 4.8
|
||||
objWrapper &operator=(objWrapper &&) = default; // NOLINT(performance-noexcept-move-constructor)
|
||||
// delete all other assignment operators
|
||||
template <typename TT> void operator=(TT &&obj) = delete;
|
||||
|
||||
CLI11_NODISCARD const X &value() const { return val_; }
|
||||
|
||||
private:
|
||||
X val_{};
|
||||
};
|
||||
|
||||
// I think there is a bug with the is_assignable in visual studio 2015 it is fixed in later versions
|
||||
// so this test will not compile in that compiler
|
||||
#if !defined(_MSC_VER) || _MSC_VER >= 1910
|
||||
|
||||
static_assert(CLI::detail::is_direct_constructible<objWrapper<std::string>, std::string>::value,
|
||||
"string wrapper isn't properly constructible");
|
||||
|
||||
static_assert(!std::is_assignable<objWrapper<std::string>, std::string>::value,
|
||||
"string wrapper is improperly assignable");
|
||||
TEST_CASE_METHOD(TApp, "stringWrapper", "[newparse]") {
|
||||
objWrapper<std::string> sWrapper;
|
||||
app.add_option("-v", sWrapper);
|
||||
args = {"-v", "string test"};
|
||||
|
||||
run();
|
||||
|
||||
CHECK("string test" == sWrapper.value());
|
||||
}
|
||||
|
||||
static_assert(CLI::detail::is_direct_constructible<objWrapper<double>, double>::value,
|
||||
"double wrapper isn't properly assignable");
|
||||
|
||||
static_assert(!CLI::detail::is_direct_constructible<objWrapper<double>, int>::value,
|
||||
"double wrapper can be assigned from int");
|
||||
|
||||
static_assert(!CLI::detail::is_istreamable<objWrapper<double>>::value,
|
||||
"double wrapper is input streamable and it shouldn't be");
|
||||
|
||||
TEST_CASE_METHOD(TApp, "doubleWrapper", "[newparse]") {
|
||||
objWrapper<double> dWrapper;
|
||||
app.add_option("-v", dWrapper);
|
||||
args = {"-v", "2.36"};
|
||||
|
||||
run();
|
||||
|
||||
CHECK(2.36 == dWrapper.value());
|
||||
|
||||
args = {"-v", "thing"};
|
||||
|
||||
CHECK_THROWS_AS(run(), CLI::ConversionError);
|
||||
}
|
||||
|
||||
static_assert(CLI::detail::is_direct_constructible<objWrapper<int>, int>::value,
|
||||
"int wrapper is not constructible from int64");
|
||||
|
||||
static_assert(!CLI::detail::is_direct_constructible<objWrapper<int>, double>::value,
|
||||
"int wrapper is constructible from double");
|
||||
|
||||
static_assert(!CLI::detail::is_istreamable<objWrapper<int>>::value,
|
||||
"int wrapper is input streamable and it shouldn't be");
|
||||
|
||||
TEST_CASE_METHOD(TApp, "intWrapper", "[newparse]") {
|
||||
objWrapper<int> iWrapper;
|
||||
app.add_option("-v", iWrapper);
|
||||
args = {"-v", "45"};
|
||||
|
||||
run();
|
||||
|
||||
CHECK(45 == iWrapper.value());
|
||||
args = {"-v", "thing"};
|
||||
|
||||
CHECK_THROWS_AS(run(), CLI::ConversionError);
|
||||
}
|
||||
|
||||
static_assert(!CLI::detail::is_direct_constructible<objWrapper<float>, int>::value,
|
||||
"float wrapper is constructible from int");
|
||||
static_assert(!CLI::detail::is_direct_constructible<objWrapper<float>, double>::value,
|
||||
"float wrapper is constructible from double");
|
||||
|
||||
static_assert(!CLI::detail::is_istreamable<objWrapper<float>>::value,
|
||||
"float wrapper is input streamable and it shouldn't be");
|
||||
|
||||
TEST_CASE_METHOD(TApp, "floatWrapper", "[newparse]") {
|
||||
objWrapper<float> iWrapper;
|
||||
app.add_option<objWrapper<float>, float>("-v", iWrapper);
|
||||
args = {"-v", "45.3"};
|
||||
|
||||
run();
|
||||
|
||||
CHECK(45.3f == iWrapper.value());
|
||||
args = {"-v", "thing"};
|
||||
|
||||
CHECK_THROWS_AS(run(), CLI::ConversionError);
|
||||
}
|
||||
|
||||
#endif
|
||||
/// simple class to wrap another with a very specific type constructor to test out some of the option assignments
|
||||
class dobjWrapper {
|
||||
public:
|
||||
dobjWrapper() = default;
|
||||
explicit dobjWrapper(double obj) : dval_{obj} {};
|
||||
explicit dobjWrapper(int obj) : ival_{obj} {};
|
||||
|
||||
CLI11_NODISCARD double dvalue() const { return dval_; }
|
||||
CLI11_NODISCARD int ivalue() const { return ival_; }
|
||||
|
||||
private:
|
||||
double dval_{0.0};
|
||||
int ival_{0};
|
||||
};
|
||||
|
||||
TEST_CASE_METHOD(TApp, "dobjWrapper", "[newparse]") {
|
||||
dobjWrapper iWrapper;
|
||||
app.add_option("-v", iWrapper);
|
||||
args = {"-v", "45"};
|
||||
|
||||
run();
|
||||
|
||||
CHECK(45 == iWrapper.ivalue());
|
||||
CHECK(0.0 == iWrapper.dvalue());
|
||||
|
||||
args = {"-v", "thing"};
|
||||
|
||||
CHECK_THROWS_AS(run(), CLI::ConversionError);
|
||||
iWrapper = dobjWrapper{};
|
||||
|
||||
args = {"-v", "45.1"};
|
||||
|
||||
run();
|
||||
CHECK(0 == iWrapper.ivalue());
|
||||
CHECK(45.1 == iWrapper.dvalue());
|
||||
}
|
||||
|
||||
/// simple class to wrap another with a very specific type constructor and assignment operators to test out some of the
|
||||
/// option assignments
|
||||
template <class X> class AobjWrapper {
|
||||
public:
|
||||
AobjWrapper() = default;
|
||||
// delete all other constructors
|
||||
template <class TT> AobjWrapper(TT &&obj) = delete;
|
||||
// single assignment operator
|
||||
AobjWrapper &operator=(X val) {
|
||||
val_ = val;
|
||||
return *this;
|
||||
}
|
||||
// delete all other assignment operators
|
||||
template <typename TT> void operator=(TT &&obj) = delete;
|
||||
|
||||
CLI11_NODISCARD const X &value() const { return val_; }
|
||||
|
||||
private:
|
||||
X val_{};
|
||||
};
|
||||
|
||||
static_assert(std::is_assignable<AobjWrapper<std::uint16_t> &, std::uint16_t>::value,
|
||||
"AobjWrapper not assignable like it should be ");
|
||||
|
||||
TEST_CASE_METHOD(TApp, "uint16Wrapper", "[newparse]") {
|
||||
AobjWrapper<std::uint16_t> sWrapper;
|
||||
app.add_option<AobjWrapper<std::uint16_t>, std::uint16_t>("-v", sWrapper);
|
||||
args = {"-v", "9"};
|
||||
|
||||
run();
|
||||
|
||||
CHECK(9u == sWrapper.value());
|
||||
args = {"-v", "thing"};
|
||||
|
||||
CHECK_THROWS_AS(run(), CLI::ConversionError);
|
||||
|
||||
args = {"-v", "72456245754"};
|
||||
|
||||
CHECK_THROWS_AS(run(), CLI::ConversionError);
|
||||
|
||||
args = {"-v", "-3"};
|
||||
|
||||
CHECK_THROWS_AS(run(), CLI::ConversionError);
|
||||
}
|
||||
|
||||
template <class T> class SimpleWrapper {
|
||||
public:
|
||||
SimpleWrapper() = default;
|
||||
|
||||
explicit SimpleWrapper(T initial) : val_{std::move(initial)} {};
|
||||
T &getRef() { return val_; }
|
||||
using value_type = T;
|
||||
|
||||
private:
|
||||
T val_{};
|
||||
};
|
||||
|
||||
TEST_CASE_METHOD(TApp, "wrapperInt", "[newparse]") {
|
||||
SimpleWrapper<int> wrap;
|
||||
app.add_option("--val", wrap);
|
||||
args = {"--val", "2"};
|
||||
|
||||
run();
|
||||
CHECK(2 == wrap.getRef());
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "wrapperString", "[newparse]") {
|
||||
SimpleWrapper<std::string> wrap;
|
||||
app.add_option("--val", wrap);
|
||||
args = {"--val", "str"};
|
||||
|
||||
run();
|
||||
CHECK("str" == wrap.getRef());
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "wrapperVector", "[newparse]") {
|
||||
SimpleWrapper<std::vector<int>> wrap;
|
||||
app.add_option("--val", wrap);
|
||||
args = {"--val", "1", "2", "3", "4"};
|
||||
|
||||
run();
|
||||
auto v1 = wrap.getRef();
|
||||
auto v2 = std::vector<int>{1, 2, 3, 4};
|
||||
CHECK(v2 == v1);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "wrapperwrapperString", "[newparse]") {
|
||||
SimpleWrapper<SimpleWrapper<std::string>> wrap;
|
||||
app.add_option("--val", wrap);
|
||||
args = {"--val", "arg"};
|
||||
|
||||
run();
|
||||
auto v1 = wrap.getRef().getRef();
|
||||
const auto *v2 = "arg";
|
||||
CHECK(v2 == v1);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "wrapperwrapperVector", "[newparse]") {
|
||||
SimpleWrapper<SimpleWrapper<std::vector<int>>> wrap;
|
||||
auto *opt = app.add_option("--val", wrap);
|
||||
args = {"--val", "1", "2", "3", "4"};
|
||||
|
||||
run();
|
||||
auto v1 = wrap.getRef().getRef();
|
||||
auto v2 = std::vector<int>{1, 2, 3, 4};
|
||||
CHECK(v2 == v1);
|
||||
opt->type_size(0, 5);
|
||||
|
||||
args = {"--val"};
|
||||
|
||||
run();
|
||||
CHECK(wrap.getRef().getRef().empty());
|
||||
|
||||
args = {"--val", "happy", "sad"};
|
||||
|
||||
CHECK_THROWS_AS(run(), CLI::ConversionError);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "wrapperComplex", "[newparse]") {
|
||||
SimpleWrapper<std::complex<double>> wrap;
|
||||
app.add_option("--val", wrap);
|
||||
args = {"--val", "1", "2"};
|
||||
|
||||
run();
|
||||
auto &v1 = wrap.getRef();
|
||||
auto v2 = std::complex<double>{1, 2};
|
||||
CHECK(v2.real() == v1.real());
|
||||
CHECK(v2.imag() == v1.imag());
|
||||
args = {"--val", "1.4-4j"};
|
||||
|
||||
run();
|
||||
v2 = std::complex<double>{1.4, -4};
|
||||
CHECK(v2.real() == v1.real());
|
||||
CHECK(v2.imag() == v1.imag());
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "vectorComplex", "[newparse]") {
|
||||
std::vector<std::complex<double>> vcomplex;
|
||||
app.add_option("--val", vcomplex);
|
||||
args = {"--val", "1", "2", "--val", "1.4-4j"};
|
||||
|
||||
run();
|
||||
|
||||
REQUIRE(2U == vcomplex.size());
|
||||
CHECK(1.0 == vcomplex[0].real());
|
||||
CHECK(2.0 == vcomplex[0].imag());
|
||||
CHECK(1.4 == vcomplex[1].real());
|
||||
CHECK(-4.0 == vcomplex[1].imag());
|
||||
}
|
||||
797
tests/OptionGroupTest.cpp
Normal file
797
tests/OptionGroupTest.cpp
Normal file
@@ -0,0 +1,797 @@
|
||||
// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include "app_helper.hpp"
|
||||
|
||||
using Catch::Matchers::Contains;
|
||||
|
||||
using vs_t = std::vector<std::string>;
|
||||
|
||||
TEST_CASE_METHOD(TApp, "BasicOptionGroup", "[optiongroup]") {
|
||||
auto *ogroup = app.add_option_group("clusters");
|
||||
int res = 0;
|
||||
ogroup->add_option("--test1", res);
|
||||
ogroup->add_option("--test2", res);
|
||||
ogroup->add_option("--test3", res);
|
||||
|
||||
args = {"--test1", "5"};
|
||||
run();
|
||||
CHECK(5 == res);
|
||||
CHECK(1u == app.count_all());
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "OptionGroupInvalidNames", "[optiongroup]") {
|
||||
CHECK_THROWS_AS(app.add_option_group("clusters\ncluster2", "description"), CLI::IncorrectConstruction);
|
||||
|
||||
std::string groupName("group1");
|
||||
groupName += '\0';
|
||||
groupName.append("group2");
|
||||
|
||||
CHECK_THROWS_AS(app.add_option_group(groupName), CLI::IncorrectConstruction);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "BasicOptionGroupExact", "[optiongroup]") {
|
||||
auto *ogroup = app.add_option_group("clusters");
|
||||
int res{0};
|
||||
ogroup->add_option("--test1", res);
|
||||
ogroup->add_option("--test2", res);
|
||||
ogroup->add_option("--test3", res);
|
||||
int val2{0};
|
||||
app.add_option("--option", val2);
|
||||
ogroup->require_option(1);
|
||||
args = {"--test1", "5"};
|
||||
run();
|
||||
CHECK(5 == res);
|
||||
|
||||
args = {"--test1", "5", "--test2", "4"};
|
||||
CHECK_THROWS_AS(run(), CLI::RequiredError);
|
||||
|
||||
args = {"--option", "9"};
|
||||
CHECK_THROWS_AS(run(), CLI::RequiredError);
|
||||
|
||||
std::string help = ogroup->help();
|
||||
auto exactloc = help.find("[Exactly 1");
|
||||
CHECK(std::string::npos != exactloc);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "BasicOptionGroupExactTooMany", "[optiongroup]") {
|
||||
auto *ogroup = app.add_option_group("clusters");
|
||||
int res{0};
|
||||
ogroup->add_option("--test1", res);
|
||||
ogroup->add_option("--test2", res);
|
||||
ogroup->add_option("--test3", res);
|
||||
int val2{0};
|
||||
app.add_option("--option", val2);
|
||||
ogroup->require_option(10);
|
||||
args = {"--test1", "5"};
|
||||
CHECK_THROWS_AS(run(), CLI::InvalidError);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "BasicOptionGroupMinMax", "[optiongroup]") {
|
||||
auto *ogroup = app.add_option_group("clusters");
|
||||
int res{0};
|
||||
ogroup->add_option("--test1", res);
|
||||
ogroup->add_option("--test2", res);
|
||||
ogroup->add_option("--test3", res);
|
||||
int val2{0};
|
||||
app.add_option("--option", val2);
|
||||
ogroup->require_option(1, 1);
|
||||
args = {"--test1", "5"};
|
||||
run();
|
||||
CHECK(5 == res);
|
||||
|
||||
args = {"--test1", "5", "--test2", "4"};
|
||||
CHECK_THROWS_AS(run(), CLI::RequiredError);
|
||||
|
||||
args = {"--option", "9"};
|
||||
CHECK_THROWS_AS(run(), CLI::RequiredError);
|
||||
|
||||
std::string help = ogroup->help();
|
||||
auto exactloc = help.find("[Exactly 1");
|
||||
CHECK(std::string::npos != exactloc);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "BasicOptionGroupMinMaxDifferent", "[optiongroup]") {
|
||||
auto *ogroup = app.add_option_group("clusters");
|
||||
int res{0};
|
||||
ogroup->add_option("--test1", res);
|
||||
ogroup->add_option("--test2", res);
|
||||
ogroup->add_option("--test3", res);
|
||||
int val2{0};
|
||||
app.add_option("--option", val2);
|
||||
ogroup->require_option(1, 2);
|
||||
args = {"--test1", "5"};
|
||||
run();
|
||||
CHECK(5 == res);
|
||||
|
||||
args = {"--test1", "5", "--test2", "4"};
|
||||
CHECK_NOTHROW(run());
|
||||
CHECK(2u == app.count_all());
|
||||
|
||||
args = {"--option", "9"};
|
||||
CHECK_THROWS_AS(run(), CLI::RequiredError);
|
||||
|
||||
args = {"--test1", "5", "--test2", "4", "--test3=5"};
|
||||
CHECK_THROWS_AS(run(), CLI::RequiredError);
|
||||
|
||||
std::string help = ogroup->help();
|
||||
auto exactloc = help.find("[Between 1 and 2");
|
||||
CHECK(std::string::npos != exactloc);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "BasicOptionGroupMinMaxDifferentReversed", "[optiongroup]") {
|
||||
auto *ogroup = app.add_option_group("clusters");
|
||||
int res{0};
|
||||
ogroup->add_option("--test1", res);
|
||||
ogroup->add_option("--test2", res);
|
||||
ogroup->add_option("--test3", res);
|
||||
int val2{0};
|
||||
app.add_option("--option", val2);
|
||||
ogroup->require_option(2, 1);
|
||||
CHECK(2u == ogroup->get_require_option_min());
|
||||
CHECK(1u == ogroup->get_require_option_max());
|
||||
args = {"--test1", "5"};
|
||||
CHECK_THROWS_AS(run(), CLI::InvalidError);
|
||||
ogroup->require_option(1, 2);
|
||||
CHECK_NOTHROW(run());
|
||||
CHECK(5 == res);
|
||||
CHECK(1u == ogroup->get_require_option_min());
|
||||
CHECK(2u == ogroup->get_require_option_max());
|
||||
args = {"--test1", "5", "--test2", "4"};
|
||||
CHECK_NOTHROW(run());
|
||||
|
||||
args = {"--option", "9"};
|
||||
CHECK_THROWS_AS(run(), CLI::RequiredError);
|
||||
|
||||
args = {"--test1", "5", "--test2", "4", "--test3=5"};
|
||||
CHECK_THROWS_AS(run(), CLI::RequiredError);
|
||||
|
||||
std::string help = ogroup->help();
|
||||
auto exactloc = help.find("[Between 1 and 2");
|
||||
CHECK(std::string::npos != exactloc);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "BasicOptionGroupMax", "[optiongroup]") {
|
||||
auto *ogroup = app.add_option_group("clusters");
|
||||
int res{0};
|
||||
ogroup->add_option("--test1", res);
|
||||
ogroup->add_option("--test2", res);
|
||||
ogroup->add_option("--test3", res);
|
||||
int val2 = 0;
|
||||
app.add_option("--option", val2);
|
||||
ogroup->require_option(-2);
|
||||
args = {"--test1", "5"};
|
||||
run();
|
||||
CHECK(5 == res);
|
||||
|
||||
args = {"--option", "9"};
|
||||
CHECK_NOTHROW(run());
|
||||
|
||||
args = {"--test1", "5", "--test2", "4", "--test3=5"};
|
||||
CHECK_THROWS_AS(run(), CLI::RequiredError);
|
||||
|
||||
std::string help = ogroup->help();
|
||||
auto exactloc = help.find("[At most 2");
|
||||
CHECK(std::string::npos != exactloc);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "BasicOptionGroupMax1", "[optiongroup]") {
|
||||
auto *ogroup = app.add_option_group("clusters");
|
||||
int res{0};
|
||||
ogroup->add_option("--test1", res);
|
||||
ogroup->add_option("--test2", res);
|
||||
ogroup->add_option("--test3", res);
|
||||
int val2{0};
|
||||
app.add_option("--option", val2);
|
||||
ogroup->require_option(-1);
|
||||
args = {"--test1", "5"};
|
||||
run();
|
||||
CHECK(5 == res);
|
||||
|
||||
args = {"--option", "9"};
|
||||
CHECK_NOTHROW(run());
|
||||
|
||||
args = {"--test1", "5", "--test2", "4"};
|
||||
CHECK_THROWS_AS(run(), CLI::RequiredError);
|
||||
|
||||
std::string help = ogroup->help();
|
||||
auto exactloc = help.find("[At most 1");
|
||||
CHECK(std::string::npos != exactloc);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "BasicOptionGroupMin", "[optiongroup]") {
|
||||
auto *ogroup = app.add_option_group("clusters");
|
||||
int res{0};
|
||||
ogroup->add_option("--test1", res);
|
||||
ogroup->add_option("--test2", res);
|
||||
ogroup->add_option("--test3", res);
|
||||
int val2{0};
|
||||
app.add_option("--option", val2);
|
||||
ogroup->require_option();
|
||||
|
||||
args = {"--option", "9"};
|
||||
CHECK_THROWS_AS(run(), CLI::RequiredError);
|
||||
|
||||
args = {"--test1", "5", "--test2", "4", "--test3=5"};
|
||||
CHECK_NOTHROW(run());
|
||||
|
||||
std::string help = ogroup->help();
|
||||
auto exactloc = help.find("[At least 1");
|
||||
CHECK(std::string::npos != exactloc);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "BasicOptionGroupExact2", "[optiongroup]") {
|
||||
auto *ogroup = app.add_option_group("clusters");
|
||||
int res{0};
|
||||
ogroup->add_option("--test1", res);
|
||||
ogroup->add_option("--test2", res);
|
||||
ogroup->add_option("--test3", res);
|
||||
int val2{0};
|
||||
app.add_option("--option", val2);
|
||||
ogroup->require_option(2);
|
||||
|
||||
args = {"--option", "9"};
|
||||
CHECK_THROWS_AS(run(), CLI::RequiredError);
|
||||
|
||||
args = {"--test1", "5", "--test2", "4", "--test3=5"};
|
||||
CHECK_THROWS_AS(run(), CLI::RequiredError);
|
||||
|
||||
args = {"--test1", "5", "--test3=5"};
|
||||
CHECK_NOTHROW(run());
|
||||
|
||||
std::string help = ogroup->help();
|
||||
auto exactloc = help.find("[Exactly 2");
|
||||
CHECK(std::string::npos != exactloc);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "BasicOptionGroupMin2", "[optiongroup]") {
|
||||
auto *ogroup = app.add_option_group("clusters");
|
||||
int res{0};
|
||||
ogroup->add_option("--test1", res);
|
||||
ogroup->add_option("--test2", res);
|
||||
ogroup->add_option("--test3", res);
|
||||
int val2{0};
|
||||
app.add_option("--option", val2);
|
||||
ogroup->require_option(2, 0);
|
||||
|
||||
args = {"--option", "9"};
|
||||
CHECK_THROWS_AS(run(), CLI::RequiredError);
|
||||
|
||||
args = {"--test1", "5", "--test2", "4", "--test3=5"};
|
||||
CHECK_NOTHROW(run());
|
||||
|
||||
std::string help = ogroup->help();
|
||||
auto exactloc = help.find("[At least 2");
|
||||
CHECK(std::string::npos != exactloc);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "BasicOptionGroupMinMoved", "[optiongroup]") {
|
||||
|
||||
int res{0};
|
||||
auto *opt1 = app.add_option("--test1", res);
|
||||
auto *opt2 = app.add_option("--test2", res);
|
||||
auto *opt3 = app.add_option("--test3", res);
|
||||
int val2{0};
|
||||
app.add_option("--option", val2);
|
||||
|
||||
auto *ogroup = app.add_option_group("clusters");
|
||||
ogroup->require_option();
|
||||
ogroup->add_option(opt1);
|
||||
ogroup->add_option(opt2);
|
||||
ogroup->add_option(opt3);
|
||||
|
||||
args = {"--option", "9"};
|
||||
CHECK_THROWS_AS(run(), CLI::RequiredError);
|
||||
|
||||
args = {"--test1", "5", "--test2", "4", "--test3=5"};
|
||||
CHECK_NOTHROW(run());
|
||||
|
||||
std::string help = app.help();
|
||||
auto exactloc = help.find("[At least 1");
|
||||
auto oloc = help.find("--test1");
|
||||
CHECK(std::string::npos != exactloc);
|
||||
CHECK(std::string::npos != oloc);
|
||||
CHECK(oloc > exactloc);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "BasicOptionGroupMinMovedAsGroup", "[optiongroup]") {
|
||||
|
||||
int res{0};
|
||||
auto *opt1 = app.add_option("--test1", res);
|
||||
auto *opt2 = app.add_option("--test2", res);
|
||||
auto *opt3 = app.add_option("--test3", res);
|
||||
int val2{0};
|
||||
app.add_option("--option", val2);
|
||||
|
||||
auto *ogroup = app.add_option_group("clusters");
|
||||
ogroup->require_option();
|
||||
ogroup->add_options(opt1, opt2, opt3);
|
||||
|
||||
CHECK_THROWS_AS(ogroup->add_options(opt1), CLI::OptionNotFound);
|
||||
args = {"--option", "9"};
|
||||
CHECK_THROWS_AS(run(), CLI::RequiredError);
|
||||
|
||||
args = {"--test1", "5", "--test2", "4", "--test3=5"};
|
||||
CHECK_NOTHROW(run());
|
||||
|
||||
std::string help = app.help();
|
||||
auto exactloc = help.find("[At least 1");
|
||||
auto oloc = help.find("--test1");
|
||||
CHECK(std::string::npos != exactloc);
|
||||
CHECK(std::string::npos != oloc);
|
||||
CHECK(oloc > exactloc);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "BasicOptionGroupAddFailures", "[optiongroup]") {
|
||||
|
||||
int res{0};
|
||||
auto *opt1 = app.add_option("--test1", res);
|
||||
app.set_config("--config");
|
||||
int val2{0};
|
||||
app.add_option("--option", val2);
|
||||
|
||||
auto *ogroup = app.add_option_group("clusters");
|
||||
CHECK_THROWS_AS(ogroup->add_options(app.get_config_ptr()), CLI::OptionAlreadyAdded);
|
||||
CHECK_THROWS_AS(ogroup->add_options(app.get_help_ptr()), CLI::OptionAlreadyAdded);
|
||||
|
||||
auto *sub = app.add_subcommand("sub", "subcommand");
|
||||
auto *opt2 = sub->add_option("--option2", val2);
|
||||
|
||||
CHECK_THROWS_AS(ogroup->add_option(opt2), CLI::OptionNotFound);
|
||||
|
||||
CHECK_THROWS_AS(ogroup->add_options(nullptr), CLI::OptionNotFound);
|
||||
|
||||
ogroup->add_option(opt1);
|
||||
|
||||
auto *opt3 = app.add_option("--test1", res);
|
||||
|
||||
CHECK_THROWS_AS(ogroup->add_option(opt3), CLI::OptionAlreadyAdded);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "BasicOptionGroupScrewedUpMove", "[optiongroup]") {
|
||||
|
||||
int res{0};
|
||||
auto *opt1 = app.add_option("--test1", res);
|
||||
auto *opt2 = app.add_option("--test2", res);
|
||||
int val2{0};
|
||||
app.add_option("--option", val2);
|
||||
|
||||
auto *ogroup = app.add_option_group("clusters");
|
||||
ogroup->require_option();
|
||||
auto *ogroup2 = ogroup->add_option_group("clusters2");
|
||||
CHECK_THROWS_AS(ogroup2->add_options(opt1, opt2), CLI::OptionNotFound);
|
||||
|
||||
CLI::Option_group EmptyGroup("description", "new group", nullptr);
|
||||
|
||||
CHECK_THROWS_AS(EmptyGroup.add_option(opt2), CLI::OptionNotFound);
|
||||
CHECK_THROWS_AS(app._move_option(opt2, ogroup2), CLI::OptionNotFound);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "InvalidOptions", "[optiongroup]") {
|
||||
auto *ogroup = app.add_option_group("clusters");
|
||||
CLI::Option *opt = nullptr;
|
||||
CHECK_THROWS_AS(ogroup->excludes(opt), CLI::OptionNotFound);
|
||||
CLI::App *app_p = nullptr;
|
||||
CHECK_THROWS_AS(ogroup->excludes(app_p), CLI::OptionNotFound);
|
||||
CHECK_THROWS_AS(ogroup->excludes(ogroup), CLI::OptionNotFound);
|
||||
CHECK_THROWS_AS(ogroup->add_option(opt), CLI::OptionNotFound);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "OptionGroupInheritedOptionDefaults", "[optiongroup]") {
|
||||
app.option_defaults()->ignore_case();
|
||||
auto *ogroup = app.add_option_group("clusters");
|
||||
int res{0};
|
||||
ogroup->add_option("--test1", res);
|
||||
|
||||
args = {"--Test1", "5"};
|
||||
run();
|
||||
CHECK(5 == res);
|
||||
CHECK(1u == app.count_all());
|
||||
}
|
||||
|
||||
struct ManyGroups : public TApp {
|
||||
|
||||
CLI::Option_group *main{nullptr};
|
||||
CLI::Option_group *g1{nullptr};
|
||||
CLI::Option_group *g2{nullptr};
|
||||
CLI::Option_group *g3{nullptr};
|
||||
std::string name1{};
|
||||
std::string name2{};
|
||||
std::string name3{};
|
||||
std::string val1{};
|
||||
std::string val2{};
|
||||
std::string val3{};
|
||||
|
||||
ManyGroups(const ManyGroups &) = delete;
|
||||
ManyGroups &operator=(const ManyGroups &) = delete;
|
||||
|
||||
ManyGroups() {
|
||||
main = app.add_option_group("main", "the main outer group");
|
||||
g1 = main->add_option_group("g1", "group1 description");
|
||||
g2 = main->add_option_group("g2", "group2 description");
|
||||
g3 = main->add_option_group("g3", "group3 description");
|
||||
g1->add_option("--name1", name1)->required();
|
||||
g1->add_option("--val1", val1);
|
||||
g2->add_option("--name2", name2)->required();
|
||||
g2->add_option("--val2", val2);
|
||||
g3->add_option("--name3", name3)->required();
|
||||
g3->add_option("--val3", val3);
|
||||
}
|
||||
|
||||
void remove_required() { // NOLINT(readability-make-member-function-const)
|
||||
g1->get_option("--name1")->required(false);
|
||||
g2->get_option("--name2")->required(false);
|
||||
g3->get_option("--name3")->required(false);
|
||||
g1->required(false);
|
||||
g2->required(false);
|
||||
g3->required(false);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_CASE_METHOD(ManyGroups, "SingleGroup", "[optiongroup]") {
|
||||
// only 1 group can be used
|
||||
main->require_option(1);
|
||||
args = {"--name1", "test"};
|
||||
run();
|
||||
CHECK("test" == name1);
|
||||
|
||||
args = {"--name2", "test", "--val2", "tval"};
|
||||
|
||||
run();
|
||||
CHECK("tval" == val2);
|
||||
|
||||
args = {"--name1", "test", "--val2", "tval"};
|
||||
|
||||
CHECK_THROWS_AS(run(), CLI::RequiredError);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(ManyGroups, "ExcludesGroup", "[optiongroup]") {
|
||||
// only 1 group can be used
|
||||
g1->excludes(g2);
|
||||
g1->excludes(g3);
|
||||
args = {"--name1", "test"};
|
||||
run();
|
||||
CHECK("test" == name1);
|
||||
|
||||
args = {"--name1", "test", "--name2", "test2"};
|
||||
|
||||
CHECK_THROWS_AS(run(), CLI::ExcludesError);
|
||||
|
||||
CHECK(g1->remove_excludes(g2));
|
||||
CHECK_NOTHROW(run());
|
||||
CHECK(!g1->remove_excludes(g1));
|
||||
CHECK(!g1->remove_excludes(g2));
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(ManyGroups, "NeedsGroup", "[optiongroup]") {
|
||||
remove_required();
|
||||
// all groups needed if g1 is used
|
||||
g1->needs(g2);
|
||||
g1->needs(g3);
|
||||
args = {"--name1", "test"};
|
||||
CHECK_THROWS_AS(run(), CLI::RequiresError);
|
||||
// other groups should run fine
|
||||
args = {"--name2", "test2"};
|
||||
|
||||
run();
|
||||
// all three groups should be fine
|
||||
args = {"--name1", "test", "--name2", "test2", "--name3", "test3"};
|
||||
|
||||
CHECK_NOTHROW(run());
|
||||
}
|
||||
|
||||
// test adding an option group with existing subcommands to an app
|
||||
TEST_CASE_METHOD(TApp, "ExistingSubcommandMatch", "[optiongroup]") {
|
||||
auto sshared = std::make_shared<CLI::Option_group>("documenting the subcommand", "sub1g", nullptr);
|
||||
auto *s1 = sshared->add_subcommand("sub1");
|
||||
auto *o1 = sshared->add_option_group("opt1");
|
||||
o1->add_subcommand("sub3")->alias("sub4");
|
||||
|
||||
app.add_subcommand("sub1");
|
||||
|
||||
try {
|
||||
app.add_subcommand(sshared);
|
||||
// this should throw the next line should never be reached
|
||||
CHECK(!true);
|
||||
} catch(const CLI::OptionAlreadyAdded &oaa) {
|
||||
CHECK_THAT(oaa.what(), Contains("sub1"));
|
||||
}
|
||||
sshared->remove_subcommand(s1);
|
||||
|
||||
app.add_subcommand("sub3");
|
||||
// now check that the subsubcommand overlaps
|
||||
try {
|
||||
app.add_subcommand(sshared);
|
||||
// this should throw the next line should never be reached
|
||||
CHECK(!true);
|
||||
} catch(const CLI::OptionAlreadyAdded &oaa) {
|
||||
CHECK_THAT(oaa.what(), Contains("sub3"));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(ManyGroups, "SingleGroupError", "[optiongroup]") {
|
||||
// only 1 group can be used
|
||||
main->require_option(1);
|
||||
args = {"--name1", "test", "--name2", "test3"};
|
||||
CHECK_THROWS_AS(run(), CLI::RequiredError);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(ManyGroups, "AtMostOneGroup", "[optiongroup]") {
|
||||
// only 1 group can be used
|
||||
main->require_option(0, 1);
|
||||
args = {"--name1", "test", "--name2", "test3"};
|
||||
CHECK_THROWS_AS(run(), CLI::RequiredError);
|
||||
|
||||
args = {};
|
||||
CHECK_NOTHROW(run());
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(ManyGroups, "AtLeastTwoGroups", "[optiongroup]") {
|
||||
// only 1 group can be used
|
||||
main->require_option(2, 0);
|
||||
args = {"--name1", "test", "--name2", "test3"};
|
||||
run();
|
||||
|
||||
args = {"--name1", "test"};
|
||||
CHECK_THROWS_AS(run(), CLI::RequiredError);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(ManyGroups, "BetweenOneAndTwoGroups", "[optiongroup]") {
|
||||
// only 1 group can be used
|
||||
main->require_option(1, 2);
|
||||
args = {"--name1", "test", "--name2", "test3"};
|
||||
run();
|
||||
|
||||
args = {"--name1", "test"};
|
||||
run();
|
||||
|
||||
args = {};
|
||||
CHECK_THROWS_AS(run(), CLI::RequiredError);
|
||||
|
||||
args = {"--name1", "test", "--name2", "test3", "--name3=test3"};
|
||||
CHECK_THROWS_AS(run(), CLI::RequiredError);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(ManyGroups, "RequiredFirst", "[optiongroup]") {
|
||||
// only 1 group can be used
|
||||
remove_required();
|
||||
g1->required();
|
||||
|
||||
CHECK(g1->get_required());
|
||||
CHECK(!g2->get_required());
|
||||
args = {"--name1", "test", "--name2", "test3"};
|
||||
run();
|
||||
|
||||
args = {"--name2", "test"};
|
||||
try {
|
||||
run();
|
||||
} catch(const CLI::RequiredError &re) {
|
||||
CHECK_THAT(re.what(), Contains("g1"));
|
||||
}
|
||||
|
||||
args = {"--name1", "test", "--name2", "test3", "--name3=test3"};
|
||||
CHECK_NOTHROW(run());
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(ManyGroups, "DisableFirst", "[optiongroup]") {
|
||||
// only 1 group can be used if remove_required not used
|
||||
remove_required();
|
||||
g1->disabled();
|
||||
|
||||
CHECK(g1->get_disabled());
|
||||
CHECK(!g2->get_disabled());
|
||||
args = {"--name2", "test"};
|
||||
|
||||
run();
|
||||
|
||||
args = {"--name1", "test", "--name2", "test3"};
|
||||
CHECK_THROWS_AS(run(), CLI::ExtrasError);
|
||||
g1->disabled(false);
|
||||
args = {"--name1", "test", "--name2", "test3", "--name3=test3"};
|
||||
CHECK_NOTHROW(run());
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(ManyGroups, "SameSubcommand", "[optiongroup]") {
|
||||
// only 1 group can be used if remove_required not used
|
||||
remove_required();
|
||||
auto *sub1 = g1->add_subcommand("sub1")->disabled();
|
||||
auto *sub2 = g2->add_subcommand("sub1")->disabled();
|
||||
auto *sub3 = g3->add_subcommand("sub1");
|
||||
// so when the subcommands are disabled they can have the same name
|
||||
sub1->disabled(false);
|
||||
sub2->disabled(false);
|
||||
// if they are re-enabled they are not checked for overlap on enabling so they can have the same name
|
||||
args = {"sub1", "sub1", "sub1"};
|
||||
|
||||
run();
|
||||
|
||||
CHECK(*sub1);
|
||||
CHECK(*sub2);
|
||||
CHECK(*sub3);
|
||||
auto subs = app.get_subcommands();
|
||||
CHECK(3u == subs.size());
|
||||
CHECK(sub1 == subs[0]);
|
||||
CHECK(sub2 == subs[1]);
|
||||
CHECK(sub3 == subs[2]);
|
||||
|
||||
args = {"sub1", "sub1", "sub1", "sub1"};
|
||||
// for the 4th and future ones they will route to the first one
|
||||
run();
|
||||
CHECK(2u == sub1->count());
|
||||
CHECK(1u == sub2->count());
|
||||
CHECK(1u == sub3->count());
|
||||
|
||||
// subs should remain the same since the duplicate would not be registered there
|
||||
subs = app.get_subcommands();
|
||||
CHECK(3u == subs.size());
|
||||
CHECK(sub1 == subs[0]);
|
||||
CHECK(sub2 == subs[1]);
|
||||
CHECK(sub3 == subs[2]);
|
||||
}
|
||||
TEST_CASE_METHOD(ManyGroups, "CallbackOrder", "[optiongroup]") {
|
||||
// only 1 group can be used if remove_required not used
|
||||
remove_required();
|
||||
std::vector<int> callback_order;
|
||||
g1->callback([&callback_order]() { callback_order.push_back(1); });
|
||||
g2->callback([&callback_order]() { callback_order.push_back(2); });
|
||||
main->callback([&callback_order]() { callback_order.push_back(3); });
|
||||
|
||||
args = {"--name2", "test"};
|
||||
run();
|
||||
CHECK(std::vector<int>({2, 3}) == callback_order);
|
||||
|
||||
callback_order.clear();
|
||||
args = {"--name1", "t2", "--name2", "test"};
|
||||
g2->immediate_callback();
|
||||
run();
|
||||
CHECK(std::vector<int>({2, 1, 3}) == callback_order);
|
||||
callback_order.clear();
|
||||
|
||||
args = {"--name2", "test", "--name1", "t2"};
|
||||
g2->immediate_callback(false);
|
||||
run();
|
||||
CHECK(std::vector<int>({1, 2, 3}) == callback_order);
|
||||
}
|
||||
|
||||
// Test the fallthrough for extra arguments
|
||||
TEST_CASE_METHOD(ManyGroups, "ExtrasFallDown", "[optiongroup]") {
|
||||
// only 1 group can be used if remove_required not used
|
||||
remove_required();
|
||||
|
||||
args = {"--test1", "--flag", "extra"};
|
||||
CHECK_THROWS_AS(run(), CLI::ExtrasError);
|
||||
main->allow_extras();
|
||||
CHECK_NOTHROW(run());
|
||||
|
||||
CHECK(3u == app.remaining_size(true));
|
||||
CHECK(3u == main->remaining_size());
|
||||
|
||||
std::vector<std::string> extras{"--test1", "--flag", "extra"};
|
||||
CHECK(extras == app.remaining(true));
|
||||
CHECK(extras == main->remaining());
|
||||
}
|
||||
|
||||
// Test the option Inheritance
|
||||
TEST_CASE_METHOD(ManyGroups, "Inheritance", "[optiongroup]") {
|
||||
remove_required();
|
||||
g1->ignore_case();
|
||||
g1->ignore_underscore();
|
||||
auto *t2 = g1->add_subcommand("t2");
|
||||
args = {"T2", "t_2"};
|
||||
CHECK(t2->get_ignore_underscore());
|
||||
CHECK(t2->get_ignore_case());
|
||||
run();
|
||||
CHECK(2u == t2->count());
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(ManyGroups, "Moving", "[optiongroup]") {
|
||||
remove_required();
|
||||
auto *mg = app.add_option_group("maing");
|
||||
mg->add_subcommand(g1);
|
||||
mg->add_subcommand(g2);
|
||||
|
||||
CHECK(mg == g1->get_parent());
|
||||
CHECK(mg == g2->get_parent());
|
||||
CHECK(main == g3->get_parent());
|
||||
}
|
||||
|
||||
struct ManyGroupsPreTrigger : public ManyGroups {
|
||||
std::size_t triggerMain{0u}, trigger1{87u}, trigger2{34u}, trigger3{27u};
|
||||
ManyGroupsPreTrigger() {
|
||||
remove_required();
|
||||
app.preparse_callback([this](std::size_t count) { triggerMain = count; });
|
||||
|
||||
g1->preparse_callback([this](std::size_t count) { trigger1 = count; });
|
||||
g2->preparse_callback([this](std::size_t count) { trigger2 = count; });
|
||||
g3->preparse_callback([this](std::size_t count) { trigger3 = count; });
|
||||
}
|
||||
};
|
||||
|
||||
TEST_CASE_METHOD(ManyGroupsPreTrigger, "PreTriggerTestsOptions", "[optiongroup]") {
|
||||
|
||||
args = {"--name1", "test", "--name2", "test3"};
|
||||
run();
|
||||
CHECK(4u == triggerMain);
|
||||
CHECK(2u == trigger1);
|
||||
CHECK(0u == trigger2);
|
||||
CHECK(27u == trigger3);
|
||||
|
||||
args = {"--name1", "test"};
|
||||
trigger2 = 34u;
|
||||
run();
|
||||
CHECK(2u == triggerMain);
|
||||
CHECK(0u == trigger1);
|
||||
CHECK(34u == trigger2);
|
||||
|
||||
args = {};
|
||||
run();
|
||||
CHECK(0u == triggerMain);
|
||||
|
||||
args = {"--name1", "test", "--val1", "45", "--name2", "test3", "--name3=test3", "--val2=37"};
|
||||
run();
|
||||
CHECK(8u == triggerMain);
|
||||
CHECK(6u == trigger1);
|
||||
CHECK(2u == trigger2);
|
||||
CHECK(1u == trigger3);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(ManyGroupsPreTrigger, "PreTriggerTestsPositionals", "[optiongroup]") {
|
||||
// only 1 group can be used
|
||||
g1->add_option("pos1");
|
||||
g2->add_option("pos2");
|
||||
g3->add_option("pos3");
|
||||
|
||||
args = {"pos1"};
|
||||
run();
|
||||
CHECK(1u == triggerMain);
|
||||
CHECK(0u == trigger1);
|
||||
CHECK(34u == trigger2);
|
||||
CHECK(27u == trigger3);
|
||||
|
||||
args = {"pos1", "pos2"};
|
||||
run();
|
||||
CHECK(2u == triggerMain);
|
||||
CHECK(1u == trigger1);
|
||||
CHECK(0u == trigger2);
|
||||
|
||||
args = {"pos1", "pos2", "pos3"};
|
||||
run();
|
||||
CHECK(3u == triggerMain);
|
||||
CHECK(2u == trigger1);
|
||||
CHECK(1u == trigger2);
|
||||
CHECK(0u == trigger3);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(ManyGroupsPreTrigger, "PreTriggerTestsSubcommand", "[optiongroup]") {
|
||||
|
||||
auto *sub1 = g1->add_subcommand("sub1")->fallthrough();
|
||||
g2->add_subcommand("sub2")->fallthrough();
|
||||
g3->add_subcommand("sub3")->fallthrough();
|
||||
|
||||
std::size_t subtrigger = 0;
|
||||
sub1->preparse_callback([&subtrigger](std::size_t count) { subtrigger = count; });
|
||||
args = {"sub1"};
|
||||
run();
|
||||
CHECK(1u == triggerMain);
|
||||
CHECK(0u == trigger1);
|
||||
CHECK(34u == trigger2);
|
||||
CHECK(27u == trigger3);
|
||||
|
||||
args = {"sub1", "sub2"};
|
||||
run();
|
||||
CHECK(2u == triggerMain);
|
||||
CHECK(1u == subtrigger);
|
||||
CHECK(1u == trigger1);
|
||||
CHECK(0u == trigger2);
|
||||
|
||||
args = {"sub2", "sub3", "--name1=test", "sub1"};
|
||||
run();
|
||||
CHECK(4u == triggerMain);
|
||||
CHECK(1u == trigger1);
|
||||
CHECK(3u == trigger2);
|
||||
CHECK(1u == trigger3);
|
||||
// go until the sub1 command is given
|
||||
}
|
||||
1062
tests/OptionTypeTest.cpp
Normal file
1062
tests/OptionTypeTest.cpp
Normal file
File diff suppressed because it is too large
Load Diff
357
tests/OptionalTest.cpp
Normal file
357
tests/OptionalTest.cpp
Normal file
@@ -0,0 +1,357 @@
|
||||
// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include <complex>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
|
||||
#include "app_helper.hpp"
|
||||
|
||||
// You can explicitly enable or disable support
|
||||
// by defining to 1 or 0. Extra check here to ensure it's in the stdlib too.
|
||||
// We nest the check for __has_include and it's usage
|
||||
#ifndef CLI11_STD_OPTIONAL
|
||||
#ifdef __has_include
|
||||
#if defined(CLI11_CPP17) && __has_include(<optional>)
|
||||
#define CLI11_STD_OPTIONAL 1
|
||||
#else
|
||||
#define CLI11_STD_OPTIONAL 0
|
||||
#endif
|
||||
#else
|
||||
#define CLI11_STD_OPTIONAL 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef CLI11_EXPERIMENTAL_OPTIONAL
|
||||
#define CLI11_EXPERIMENTAL_OPTIONAL 0
|
||||
#endif
|
||||
|
||||
#ifndef CLI11_BOOST_OPTIONAL
|
||||
#define CLI11_BOOST_OPTIONAL 0
|
||||
#endif
|
||||
|
||||
#if CLI11_BOOST_OPTIONAL
|
||||
#include <boost/version.hpp>
|
||||
#if BOOST_VERSION < 106100
|
||||
#error "This boost::optional version is not supported, use 1.61 or better"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if CLI11_STD_OPTIONAL
|
||||
#include <optional>
|
||||
#endif
|
||||
#if CLI11_EXPERIMENTAL_OPTIONAL
|
||||
#include <experimental/optional>
|
||||
#endif
|
||||
#if CLI11_BOOST_OPTIONAL
|
||||
#include <boost/optional.hpp>
|
||||
#include <boost/optional/optional_io.hpp>
|
||||
#endif
|
||||
// [CLI11:verbatim]
|
||||
|
||||
#if CLI11_STD_OPTIONAL
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// this warning suppresses double to int conversions that are inherent in the test
|
||||
// on windows. This may be able to removed in the future as the add_option capability
|
||||
// improves
|
||||
#pragma warning(disable : 4244)
|
||||
#endif
|
||||
|
||||
TEST_CASE_METHOD(TApp, "StdOptionalTest", "[optional]") {
|
||||
std::optional<int> opt;
|
||||
app.add_option("-c,--count", opt);
|
||||
run();
|
||||
CHECK(!opt);
|
||||
|
||||
args = {"-c", "1"};
|
||||
run();
|
||||
CHECK(opt);
|
||||
CHECK(1 == *opt);
|
||||
|
||||
args = {"--count", "3"};
|
||||
run();
|
||||
CHECK(opt);
|
||||
CHECK(3 == *opt);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "StdOptionalVectorEmptyDirect", "[optional]") {
|
||||
std::optional<std::vector<int>> opt;
|
||||
app.add_option("-v,--vec", opt)->expected(0, 3)->allow_extra_args();
|
||||
// app.add_option("-v,--vec", opt)->expected(0, 3)->allow_extra_args();
|
||||
run();
|
||||
CHECK(!opt);
|
||||
args = {"-v"};
|
||||
opt = std::vector<int>{4, 3};
|
||||
run();
|
||||
CHECK(!opt);
|
||||
args = {"-v", "1", "4", "5"};
|
||||
run();
|
||||
CHECK(opt);
|
||||
std::vector<int> expV{1, 4, 5};
|
||||
CHECK(expV == *opt);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "StdOptionalComplexDirect", "[optional]") {
|
||||
std::optional<std::complex<double>> opt;
|
||||
app.add_option("-c,--complex", opt)->type_size(0, 2);
|
||||
run();
|
||||
CHECK(!opt);
|
||||
args = {"-c"};
|
||||
opt = std::complex<double>{4.0, 3.0};
|
||||
run();
|
||||
CHECK(!opt);
|
||||
args = {"-c", "1+2j"};
|
||||
run();
|
||||
CHECK(opt);
|
||||
std::complex<double> val{1, 2};
|
||||
CHECK(val == *opt);
|
||||
args = {"-c", "3", "-4"};
|
||||
run();
|
||||
CHECK(opt);
|
||||
std::complex<double> val2{3, -4};
|
||||
CHECK(val2 == *opt);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "StdOptionalUint", "[optional]") {
|
||||
std::optional<std::uint64_t> opt;
|
||||
app.add_option("-i,--int", opt);
|
||||
run();
|
||||
CHECK(!opt);
|
||||
|
||||
args = {"-i", "15"};
|
||||
run();
|
||||
CHECK(15U == *opt);
|
||||
static_assert(CLI::detail::classify_object<std::optional<std::uint64_t>>::value ==
|
||||
CLI::detail::object_category::wrapper_value);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "StdOptionalbool", "[optional]") {
|
||||
std::optional<bool> opt{};
|
||||
CHECK(!opt);
|
||||
app.add_flag("--opt,!--no-opt", opt);
|
||||
CHECK(!opt);
|
||||
run();
|
||||
CHECK(!opt);
|
||||
|
||||
args = {"--opt"};
|
||||
run();
|
||||
CHECK(opt);
|
||||
CHECK(*opt);
|
||||
|
||||
args = {"--no-opt"};
|
||||
run();
|
||||
CHECK(opt);
|
||||
CHECK_FALSE(*opt);
|
||||
static_assert(CLI::detail::classify_object<std::optional<bool>>::value ==
|
||||
CLI::detail::object_category::wrapper_value);
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(default : 4244)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#if CLI11_EXPERIMENTAL_OPTIONAL
|
||||
|
||||
TEST_CASE_METHOD(TApp, "ExperimentalOptionalTest", "[optional]") {
|
||||
std::experimental::optional<int> opt;
|
||||
app.add_option("-c,--count", opt);
|
||||
run();
|
||||
CHECK(!opt);
|
||||
|
||||
args = {"-c", "1"};
|
||||
run();
|
||||
CHECK(opt);
|
||||
CHECK(1 == *opt);
|
||||
|
||||
args = {"--count", "3"};
|
||||
run();
|
||||
CHECK(opt);
|
||||
CHECK(3 == *opt);
|
||||
}
|
||||
|
||||
#endif
|
||||
#if CLI11_BOOST_OPTIONAL
|
||||
|
||||
TEST_CASE_METHOD(TApp, "BoostOptionalTest", "[optional]") {
|
||||
boost::optional<int> opt;
|
||||
app.add_option("-c,--count", opt);
|
||||
run();
|
||||
CHECK(!opt);
|
||||
|
||||
args = {"-c", "1"};
|
||||
run();
|
||||
CHECK(opt);
|
||||
CHECK(1 == *opt);
|
||||
opt = {};
|
||||
args = {"--count", "3"};
|
||||
run();
|
||||
CHECK(opt);
|
||||
CHECK(3 == *opt);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "BoostOptionalTestZarg", "[optional]") {
|
||||
boost::optional<int> opt;
|
||||
app.add_option("-c,--count", opt)->expected(0, 1);
|
||||
run();
|
||||
CHECK(!opt);
|
||||
|
||||
args = {"-c", "1"};
|
||||
run();
|
||||
CHECK(opt);
|
||||
CHECK(1 == *opt);
|
||||
opt = {};
|
||||
args = {"--count"};
|
||||
run();
|
||||
CHECK(!opt);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "BoostOptionalint64Test", "[optional]") {
|
||||
boost::optional<std::int64_t> opt;
|
||||
app.add_option("-c,--count", opt);
|
||||
run();
|
||||
CHECK(!opt);
|
||||
|
||||
args = {"-c", "1"};
|
||||
run();
|
||||
CHECK(opt);
|
||||
CHECK(1 == *opt);
|
||||
opt = {};
|
||||
args = {"--count", "3"};
|
||||
run();
|
||||
CHECK(opt);
|
||||
CHECK(3 == *opt);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "BoostOptionalStringTest", "[optional]") {
|
||||
boost::optional<std::string> opt;
|
||||
app.add_option("-s,--string", opt);
|
||||
run();
|
||||
CHECK(!opt);
|
||||
|
||||
args = {"-s", "strval"};
|
||||
run();
|
||||
CHECK(opt);
|
||||
CHECK("strval" == *opt);
|
||||
opt = {};
|
||||
args = {"--string", "strv"};
|
||||
run();
|
||||
CHECK(opt);
|
||||
CHECK("strv" == *opt);
|
||||
}
|
||||
namespace boost {
|
||||
using CLI::enums::operator<<;
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "BoostOptionalEnumTest", "[optional]") {
|
||||
|
||||
enum class eval : char { val0 = 0, val1 = 1, val2 = 2, val3 = 3, val4 = 4 };
|
||||
boost::optional<eval> opt, opt2;
|
||||
|
||||
auto optptr = app.add_option<decltype(opt), eval>("-v,--val", opt);
|
||||
app.add_option_no_stream("-e,--eval", opt2);
|
||||
optptr->capture_default_str();
|
||||
|
||||
auto dstring = optptr->get_default_str();
|
||||
CHECK(dstring.empty());
|
||||
run();
|
||||
auto checkOpt = static_cast<bool>(opt);
|
||||
CHECK_FALSE(checkOpt);
|
||||
|
||||
args = {"-v", "3"};
|
||||
run();
|
||||
checkOpt = static_cast<bool>(opt);
|
||||
CHECK(checkOpt);
|
||||
CHECK(*opt == eval::val3);
|
||||
opt = {};
|
||||
args = {"--val", "1"};
|
||||
run();
|
||||
checkOpt = static_cast<bool>(opt);
|
||||
CHECK(checkOpt);
|
||||
CHECK(*opt == eval::val1);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "BoostOptionalVector", "[optional]") {
|
||||
boost::optional<std::vector<int>> opt;
|
||||
app.add_option_function<std::vector<int>>(
|
||||
"-v,--vec", [&opt](const std::vector<int> &v) { opt = v; }, "some vector")
|
||||
->expected(3);
|
||||
run();
|
||||
bool checkOpt = static_cast<bool>(opt);
|
||||
CHECK(!checkOpt);
|
||||
|
||||
args = {"-v", "1", "4", "5"};
|
||||
run();
|
||||
checkOpt = static_cast<bool>(opt);
|
||||
CHECK(checkOpt);
|
||||
std::vector<int> expV{1, 4, 5};
|
||||
CHECK(expV == *opt);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "BoostOptionalVectorEmpty", "[optional]") {
|
||||
boost::optional<std::vector<int>> opt;
|
||||
app.add_option<decltype(opt), std::vector<int>>("-v,--vec", opt)->expected(0, 3)->allow_extra_args();
|
||||
// app.add_option("-v,--vec", opt)->expected(0, 3)->allow_extra_args();
|
||||
run();
|
||||
bool checkOpt = static_cast<bool>(opt);
|
||||
CHECK(!checkOpt);
|
||||
args = {"-v"};
|
||||
opt = std::vector<int>{4, 3};
|
||||
run();
|
||||
checkOpt = static_cast<bool>(opt);
|
||||
CHECK(!checkOpt);
|
||||
args = {"-v", "1", "4", "5"};
|
||||
run();
|
||||
checkOpt = static_cast<bool>(opt);
|
||||
CHECK(checkOpt);
|
||||
std::vector<int> expV{1, 4, 5};
|
||||
CHECK(expV == *opt);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "BoostOptionalVectorEmptyDirect", "[optional]") {
|
||||
boost::optional<std::vector<int>> opt;
|
||||
app.add_option_no_stream("-v,--vec", opt)->expected(0, 3)->allow_extra_args();
|
||||
// app.add_option("-v,--vec", opt)->expected(0, 3)->allow_extra_args();
|
||||
run();
|
||||
bool checkOpt = static_cast<bool>(opt);
|
||||
CHECK(!checkOpt);
|
||||
args = {"-v"};
|
||||
opt = std::vector<int>{4, 3};
|
||||
run();
|
||||
checkOpt = static_cast<bool>(opt);
|
||||
CHECK(!checkOpt);
|
||||
args = {"-v", "1", "4", "5"};
|
||||
run();
|
||||
checkOpt = static_cast<bool>(opt);
|
||||
CHECK(checkOpt);
|
||||
std::vector<int> expV{1, 4, 5};
|
||||
CHECK(expV == *opt);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "BoostOptionalComplexDirect", "[optional]") {
|
||||
boost::optional<std::complex<double>> opt;
|
||||
app.add_option("-c,--complex", opt)->type_size(0, 2);
|
||||
run();
|
||||
CHECK(!opt);
|
||||
args = {"-c"};
|
||||
opt = std::complex<double>{4.0, 3.0};
|
||||
run();
|
||||
CHECK(!opt);
|
||||
args = {"-c", "1+2j"};
|
||||
run();
|
||||
CHECK(opt);
|
||||
std::complex<double> val{1, 2};
|
||||
CHECK(val == *opt);
|
||||
args = {"-c", "3", "-4"};
|
||||
run();
|
||||
CHECK(opt);
|
||||
std::complex<double> val2{3, -4};
|
||||
CHECK(val2 == *opt);
|
||||
}
|
||||
|
||||
#endif
|
||||
712
tests/SetTest.cpp
Normal file
712
tests/SetTest.cpp
Normal file
@@ -0,0 +1,712 @@
|
||||
// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include "app_helper.hpp"
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
static_assert(CLI::is_shared_ptr<std::shared_ptr<int>>::value == true, "is_shared_ptr should work on shared pointers");
|
||||
static_assert(CLI::is_shared_ptr<int *>::value == false, "is_shared_ptr should work on pointers");
|
||||
static_assert(CLI::is_shared_ptr<int>::value == false, "is_shared_ptr should work on non-pointers");
|
||||
static_assert(CLI::is_shared_ptr<const std::shared_ptr<int>>::value == true,
|
||||
"is_shared_ptr should work on const shared pointers");
|
||||
static_assert(CLI::is_shared_ptr<const int *>::value == false, "is_shared_ptr should work on const pointers");
|
||||
static_assert(CLI::is_shared_ptr<const int &>::value == false, "is_shared_ptr should work on const references");
|
||||
static_assert(CLI::is_shared_ptr<int &>::value == false, "is_shared_ptr should work on non-const references");
|
||||
|
||||
static_assert(CLI::is_copyable_ptr<std::shared_ptr<int>>::value == true,
|
||||
"is_copyable_ptr should work on shared pointers");
|
||||
static_assert(CLI::is_copyable_ptr<int *>::value == true, "is_copyable_ptr should work on pointers");
|
||||
static_assert(CLI::is_copyable_ptr<int>::value == false, "is_copyable_ptr should work on non-pointers");
|
||||
static_assert(CLI::is_copyable_ptr<const std::shared_ptr<int>>::value == true,
|
||||
"is_copyable_ptr should work on const shared pointers");
|
||||
static_assert(CLI::is_copyable_ptr<const int *>::value == true, "is_copyable_ptr should work on const pointers");
|
||||
static_assert(CLI::is_copyable_ptr<const int &>::value == false, "is_copyable_ptr should work on const references");
|
||||
static_assert(CLI::is_copyable_ptr<int &>::value == false, "is_copyable_ptr should work on non-const references");
|
||||
|
||||
static_assert(CLI::detail::pair_adaptor<std::set<int>>::value == false, "Should not have pairs");
|
||||
static_assert(CLI::detail::pair_adaptor<std::vector<std::string>>::value == false, "Should not have pairs");
|
||||
static_assert(CLI::detail::pair_adaptor<std::map<int, int>>::value == true, "Should have pairs");
|
||||
static_assert(CLI::detail::pair_adaptor<std::vector<std::pair<int, int>>>::value == true, "Should have pairs");
|
||||
|
||||
TEST_CASE_METHOD(TApp, "SimpleMaps", "[set]") {
|
||||
int value{0};
|
||||
std::map<std::string, int> map = {{"one", 1}, {"two", 2}};
|
||||
auto *opt = app.add_option("-s,--set", value)->transform(CLI::Transformer(map));
|
||||
args = {"-s", "one"};
|
||||
run();
|
||||
CHECK(app.count("-s") == 1u);
|
||||
CHECK(app.count("--set") == 1u);
|
||||
CHECK(opt->count() == 1u);
|
||||
CHECK(1 == value);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "StringStringMap", "[set]") {
|
||||
std::string value;
|
||||
std::map<std::string, std::string> map = {{"a", "b"}, {"b", "c"}};
|
||||
app.add_option("-s,--set", value)->transform(CLI::CheckedTransformer(map));
|
||||
args = {"-s", "a"};
|
||||
run();
|
||||
CHECK("b" == value);
|
||||
|
||||
args = {"-s", "b"};
|
||||
run();
|
||||
CHECK("c" == value);
|
||||
|
||||
args = {"-s", "c"};
|
||||
CHECK("c" == value);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "StringStringMapNoModify", "[set]") {
|
||||
std::string value;
|
||||
std::map<std::string, std::string> map = {{"a", "b"}, {"b", "c"}};
|
||||
app.add_option("-s,--set", value)->check(CLI::IsMember(map));
|
||||
args = {"-s", "a"};
|
||||
run();
|
||||
CHECK("a" == value);
|
||||
|
||||
args = {"-s", "b"};
|
||||
run();
|
||||
CHECK("b" == value);
|
||||
|
||||
args = {"-s", "c"};
|
||||
CHECK_THROWS_AS(run(), CLI::ValidationError);
|
||||
}
|
||||
|
||||
enum SimpleEnum { SE_one = 1, SE_two = 2 };
|
||||
|
||||
TEST_CASE_METHOD(TApp, "EnumMap", "[set]") {
|
||||
SimpleEnum value; // NOLINT(cppcoreguidelines-init-variables)
|
||||
std::map<std::string, SimpleEnum> map = {{"one", SE_one}, {"two", SE_two}};
|
||||
auto *opt = app.add_option("-s,--set", value)->transform(CLI::Transformer(map));
|
||||
args = {"-s", "one"};
|
||||
run();
|
||||
CHECK(app.count("-s") == 1u);
|
||||
CHECK(app.count("--set") == 1u);
|
||||
CHECK(opt->count() == 1u);
|
||||
CHECK(SE_one == value);
|
||||
}
|
||||
|
||||
enum class SimpleEnumC { one = 1, two = 2 };
|
||||
|
||||
TEST_CASE_METHOD(TApp, "EnumCMap", "[set]") {
|
||||
SimpleEnumC value; // NOLINT(cppcoreguidelines-init-variables)
|
||||
std::map<std::string, SimpleEnumC> map = {{"one", SimpleEnumC::one}, {"two", SimpleEnumC::two}};
|
||||
auto *opt = app.add_option("-s,--set", value)->transform(CLI::Transformer(map));
|
||||
args = {"-s", "one"};
|
||||
run();
|
||||
CHECK(app.count("-s") == 1u);
|
||||
CHECK(app.count("--set") == 1u);
|
||||
CHECK(opt->count() == 1u);
|
||||
CHECK(SimpleEnumC::one == value);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "structMap", "[set]") {
|
||||
struct tstruct {
|
||||
int val2;
|
||||
double val3;
|
||||
std::string v4;
|
||||
};
|
||||
std::string struct_name;
|
||||
std::map<std::string, struct tstruct> map = {{"sone", {4, 32.4, "foo"}}, {"stwo", {5, 99.7, "bar"}}};
|
||||
auto *opt = app.add_option("-s,--set", struct_name)->check(CLI::IsMember(map));
|
||||
args = {"-s", "sone"};
|
||||
run();
|
||||
CHECK(app.count("-s") == 1u);
|
||||
CHECK(app.count("--set") == 1u);
|
||||
CHECK(opt->count() == 1u);
|
||||
CHECK("sone" == struct_name);
|
||||
|
||||
args = {"-s", "sthree"};
|
||||
CHECK_THROWS_AS(run(), CLI::ValidationError);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "structMapChange", "[set]") {
|
||||
struct tstruct {
|
||||
int val2;
|
||||
double val3;
|
||||
std::string v4;
|
||||
};
|
||||
std::string struct_name;
|
||||
std::map<std::string, struct tstruct> map = {{"sone", {4, 32.4, "foo"}}, {"stwo", {5, 99.7, "bar"}}};
|
||||
auto *opt = app.add_option("-s,--set", struct_name)
|
||||
->transform(CLI::IsMember(map, CLI::ignore_case, CLI::ignore_underscore, CLI::ignore_space));
|
||||
args = {"-s", "s one"};
|
||||
run();
|
||||
CHECK(app.count("-s") == 1u);
|
||||
CHECK(app.count("--set") == 1u);
|
||||
CHECK(opt->count() == 1u);
|
||||
CHECK("sone" == struct_name);
|
||||
|
||||
args = {"-s", "sthree"};
|
||||
CHECK_THROWS_AS(run(), CLI::ValidationError);
|
||||
|
||||
args = {"-s", "S_t_w_o"};
|
||||
run();
|
||||
CHECK("stwo" == struct_name);
|
||||
args = {"-s", "S two"};
|
||||
run();
|
||||
CHECK("stwo" == struct_name);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "structMapNoChange", "[set]") {
|
||||
struct tstruct {
|
||||
int val2;
|
||||
double val3;
|
||||
std::string v4;
|
||||
};
|
||||
std::string struct_name;
|
||||
std::map<std::string, struct tstruct> map = {{"sone", {4, 32.4, "foo"}}, {"stwo", {5, 99.7, "bar"}}};
|
||||
auto *opt = app.add_option("-s,--set", struct_name)
|
||||
->check(CLI::IsMember(map, CLI::ignore_case, CLI::ignore_underscore, CLI::ignore_space));
|
||||
args = {"-s", "SONE"};
|
||||
run();
|
||||
CHECK(app.count("-s") == 1u);
|
||||
CHECK(app.count("--set") == 1u);
|
||||
CHECK(opt->count() == 1u);
|
||||
CHECK("SONE" == struct_name);
|
||||
|
||||
args = {"-s", "sthree"};
|
||||
CHECK_THROWS_AS(run(), CLI::ValidationError);
|
||||
|
||||
args = {"-s", "S_t_w_o"};
|
||||
run();
|
||||
CHECK("S_t_w_o" == struct_name);
|
||||
|
||||
args = {"-s", "S two"};
|
||||
run();
|
||||
CHECK("S two" == struct_name);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "NonCopyableMap", "[set]") {
|
||||
|
||||
std::string map_name;
|
||||
std::map<std::string, std::unique_ptr<double>> map;
|
||||
map["e1"].reset(new double(5.7));
|
||||
map["e3"].reset(new double(23.8));
|
||||
auto *opt = app.add_option("-s,--set", map_name)->check(CLI::IsMember(&map));
|
||||
args = {"-s", "e1"};
|
||||
run();
|
||||
CHECK(app.count("-s") == 1u);
|
||||
CHECK(app.count("--set") == 1u);
|
||||
CHECK(opt->count() == 1u);
|
||||
CHECK("e1" == map_name);
|
||||
|
||||
args = {"-s", "e45"};
|
||||
CHECK_THROWS_AS(run(), CLI::ValidationError);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "NonCopyableMapWithFunction", "[set]") {
|
||||
|
||||
std::string map_name;
|
||||
std::map<std::string, std::unique_ptr<double>> map;
|
||||
map["e1"].reset(new double(5.7));
|
||||
map["e3"].reset(new double(23.8));
|
||||
auto *opt = app.add_option("-s,--set", map_name)->transform(CLI::IsMember(&map, CLI::ignore_underscore));
|
||||
args = {"-s", "e_1"};
|
||||
run();
|
||||
CHECK(app.count("-s") == 1u);
|
||||
CHECK(app.count("--set") == 1u);
|
||||
CHECK(opt->count() == 1u);
|
||||
CHECK("e1" == map_name);
|
||||
|
||||
args = {"-s", "e45"};
|
||||
CHECK_THROWS_AS(run(), CLI::ValidationError);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "NonCopyableMapNonStringMap", "[set]") {
|
||||
|
||||
std::string map_name;
|
||||
std::map<int, std::unique_ptr<double>> map;
|
||||
map[4].reset(new double(5.7));
|
||||
map[17].reset(new double(23.8));
|
||||
auto *opt = app.add_option("-s,--set", map_name)->check(CLI::IsMember(&map));
|
||||
args = {"-s", "4"};
|
||||
run();
|
||||
CHECK(app.count("-s") == 1u);
|
||||
CHECK(app.count("--set") == 1u);
|
||||
CHECK(opt->count() == 1u);
|
||||
CHECK("4" == map_name);
|
||||
|
||||
args = {"-s", "e45"};
|
||||
CHECK_THROWS_AS(run(), CLI::ValidationError);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "CopyableMapMove", "[set]") {
|
||||
|
||||
std::string map_name;
|
||||
std::map<int, double> map;
|
||||
map[4] = 5.7;
|
||||
map[17] = 23.8;
|
||||
auto *opt = app.add_option("-s,--set", map_name)->check(CLI::IsMember(std::move(map)));
|
||||
args = {"-s", "4"};
|
||||
run();
|
||||
CHECK(app.count("-s") == 1u);
|
||||
CHECK(app.count("--set") == 1u);
|
||||
CHECK(opt->count() == 1u);
|
||||
CHECK("4" == map_name);
|
||||
|
||||
args = {"-s", "e45"};
|
||||
CHECK_THROWS_AS(run(), CLI::ValidationError);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "SimpleSets", "[set]") {
|
||||
std::string value;
|
||||
auto *opt = app.add_option("-s,--set", value)->check(CLI::IsMember{std::set<std::string>({"one", "two", "three"})});
|
||||
args = {"-s", "one"};
|
||||
run();
|
||||
CHECK(app.count("-s") == 1u);
|
||||
CHECK(app.count("--set") == 1u);
|
||||
CHECK(opt->count() == 1u);
|
||||
CHECK("one" == value);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "SimpleSetsPtrs", "[set]") {
|
||||
auto set = std::make_shared<std::set<std::string>>(std::set<std::string>{"one", "two", "three"});
|
||||
std::string value;
|
||||
auto *opt = app.add_option("-s,--set", value)->check(CLI::IsMember{set});
|
||||
args = {"-s", "one"};
|
||||
run();
|
||||
CHECK(app.count("-s") == 1u);
|
||||
CHECK(app.count("--set") == 1u);
|
||||
CHECK(opt->count() == 1u);
|
||||
CHECK("one" == value);
|
||||
|
||||
set->insert("four");
|
||||
|
||||
args = {"-s", "four"};
|
||||
run();
|
||||
CHECK(app.count("-s") == 1u);
|
||||
CHECK(app.count("--set") == 1u);
|
||||
CHECK(opt->count() == 1u);
|
||||
CHECK("four" == value);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "SimiShortcutSets", "[set]") {
|
||||
std::string value;
|
||||
auto *opt = app.add_option("--set", value)->check(CLI::IsMember({"one", "two", "three"}));
|
||||
args = {"--set", "one"};
|
||||
run();
|
||||
CHECK(app.count("--set") == 1u);
|
||||
CHECK(opt->count() == 1u);
|
||||
CHECK("one" == value);
|
||||
|
||||
std::string value2;
|
||||
auto *opt2 = app.add_option("--set2", value2)->transform(CLI::IsMember({"One", "two", "three"}, CLI::ignore_case));
|
||||
args = {"--set2", "onE"};
|
||||
run();
|
||||
CHECK(app.count("--set2") == 1u);
|
||||
CHECK(opt2->count() == 1u);
|
||||
CHECK("One" == value2);
|
||||
|
||||
std::string value3;
|
||||
auto *opt3 = app.add_option("--set3", value3)
|
||||
->transform(CLI::IsMember({"O_ne", "two", "three"}, CLI::ignore_case, CLI::ignore_underscore));
|
||||
args = {"--set3", "onE"};
|
||||
run();
|
||||
CHECK(app.count("--set3") == 1u);
|
||||
CHECK(opt3->count() == 1u);
|
||||
CHECK("O_ne" == value3);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "SetFromCharStarArrayVector", "[set]") {
|
||||
constexpr const char *names[3]{"one", "two", "three"}; // NOLINT(modernize-avoid-c-arrays)
|
||||
std::string value;
|
||||
auto *opt = app.add_option("-s,--set", value)
|
||||
->check(CLI::IsMember{std::vector<std::string>(std::begin(names), std::end(names))});
|
||||
args = {"-s", "one"};
|
||||
run();
|
||||
CHECK(app.count("-s") == 1u);
|
||||
CHECK(app.count("--set") == 1u);
|
||||
CHECK(opt->count() == 1u);
|
||||
CHECK("one" == value);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "OtherTypeSets", "[set]") {
|
||||
int value{0};
|
||||
std::vector<int> set = {2, 3, 4};
|
||||
auto *opt = app.add_option("--set", value)->check(CLI::IsMember(set));
|
||||
args = {"--set", "3"};
|
||||
run();
|
||||
CHECK(app.count("--set") == 1u);
|
||||
CHECK(opt->count() == 1u);
|
||||
CHECK(3 == value);
|
||||
|
||||
args = {"--set", "5"};
|
||||
CHECK_THROWS_AS(run(), CLI::ValidationError);
|
||||
|
||||
std::vector<int> set2 = {-2, 3, 4};
|
||||
auto *opt2 = app.add_option("--set2", value)->transform(CLI::IsMember(set2, [](int x) { return std::abs(x); }));
|
||||
args = {"--set2", "-3"};
|
||||
run();
|
||||
CHECK(app.count("--set2") == 1u);
|
||||
CHECK(opt2->count() == 1u);
|
||||
CHECK(3 == value);
|
||||
|
||||
args = {"--set2", "-3"};
|
||||
run();
|
||||
CHECK(app.count("--set2") == 1u);
|
||||
CHECK(opt2->count() == 1u);
|
||||
CHECK(3 == value);
|
||||
|
||||
args = {"--set2", "2"};
|
||||
run();
|
||||
CHECK(app.count("--set2") == 1u);
|
||||
CHECK(opt2->count() == 1u);
|
||||
CHECK(-2 == value);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "NumericalSets", "[set]") {
|
||||
int value{0};
|
||||
auto *opt = app.add_option("-s,--set", value)->check(CLI::IsMember{std::set<int>({1, 2, 3})});
|
||||
args = {"-s", "1"};
|
||||
run();
|
||||
CHECK(app.count("-s") == 1u);
|
||||
CHECK(app.count("--set") == 1u);
|
||||
CHECK(opt->count() == 1u);
|
||||
CHECK(1 == value);
|
||||
}
|
||||
|
||||
// Converted original set tests
|
||||
|
||||
TEST_CASE_METHOD(TApp, "SetWithDefaults", "[set]") {
|
||||
int someint{2};
|
||||
app.add_option("-a", someint)->capture_default_str()->check(CLI::IsMember({1, 2, 3, 4}));
|
||||
|
||||
args = {"-a1", "-a2"};
|
||||
|
||||
CHECK_THROWS_AS(run(), CLI::ArgumentMismatch);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "SetWithDefaultsConversion", "[set]") {
|
||||
int someint{2};
|
||||
app.add_option("-a", someint)->capture_default_str()->check(CLI::IsMember({1, 2, 3, 4}));
|
||||
|
||||
args = {"-a", "hi"};
|
||||
|
||||
CHECK_THROWS_AS(run(), CLI::ValidationError);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "SetWithDefaultsIC", "[set]") {
|
||||
std::string someint = "ho";
|
||||
app.add_option("-a", someint)->capture_default_str()->check(CLI::IsMember({"Hi", "Ho"}));
|
||||
|
||||
args = {"-aHi", "-aHo"};
|
||||
|
||||
CHECK_THROWS_AS(run(), CLI::ArgumentMismatch);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "InSet", "[set]") {
|
||||
|
||||
std::string choice;
|
||||
app.add_option("-q,--quick", choice)->check(CLI::IsMember({"one", "two", "three"}));
|
||||
|
||||
args = {"--quick", "two"};
|
||||
|
||||
run();
|
||||
CHECK(choice == "two");
|
||||
|
||||
args = {"--quick", "four"};
|
||||
CHECK_THROWS_AS(run(), CLI::ValidationError);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "InSetWithDefault", "[set]") {
|
||||
|
||||
std::string choice = "one";
|
||||
app.add_option("-q,--quick", choice)->capture_default_str()->check(CLI::IsMember({"one", "two", "three"}));
|
||||
|
||||
run();
|
||||
CHECK(choice == "one");
|
||||
|
||||
args = {"--quick", "two"};
|
||||
|
||||
run();
|
||||
CHECK(choice == "two");
|
||||
|
||||
args = {"--quick", "four"};
|
||||
CHECK_THROWS_AS(run(), CLI::ValidationError);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "InCaselessSetWithDefault", "[set]") {
|
||||
|
||||
std::string choice = "one";
|
||||
app.add_option("-q,--quick", choice)
|
||||
->capture_default_str()
|
||||
->transform(CLI::IsMember({"one", "two", "three"}, CLI::ignore_case));
|
||||
|
||||
run();
|
||||
CHECK(choice == "one");
|
||||
|
||||
args = {"--quick", "tWo"};
|
||||
|
||||
run();
|
||||
CHECK(choice == "two");
|
||||
|
||||
args = {"--quick", "four"};
|
||||
CHECK_THROWS_AS(run(), CLI::ValidationError);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "InIntSet", "[set]") {
|
||||
|
||||
int choice{0};
|
||||
app.add_option("-q,--quick", choice)->check(CLI::IsMember({1, 2, 3}));
|
||||
|
||||
args = {"--quick", "2"};
|
||||
|
||||
run();
|
||||
CHECK(choice == 2);
|
||||
|
||||
args = {"--quick", "4"};
|
||||
CHECK_THROWS_AS(run(), CLI::ValidationError);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "InIntSetWindows", "[set]") {
|
||||
|
||||
int choice{0};
|
||||
app.add_option("-q,--quick", choice)->check(CLI::IsMember({1, 2, 3}));
|
||||
app.allow_windows_style_options();
|
||||
args = {"/q", "2"};
|
||||
|
||||
run();
|
||||
CHECK(choice == 2);
|
||||
|
||||
args = {"/q", "4"};
|
||||
CHECK_THROWS_AS(run(), CLI::ValidationError);
|
||||
|
||||
args = {"/q4"};
|
||||
CHECK_THROWS_AS(run(), CLI::ExtrasError);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "FailSet", "[set]") {
|
||||
|
||||
int choice{0};
|
||||
app.add_option("-q,--quick", choice)->check(CLI::IsMember({1, 2, 3}));
|
||||
|
||||
args = {"--quick", "3", "--quick=2"};
|
||||
CHECK_THROWS_AS(run(), CLI::ArgumentMismatch);
|
||||
|
||||
args = {"--quick=hello"};
|
||||
CHECK_THROWS_AS(run(), CLI::ValidationError);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "FailMutableSet", "[set]") {
|
||||
|
||||
int choice{0};
|
||||
auto vals = std::make_shared<std::set<int>>(std::set<int>{1, 2, 3});
|
||||
app.add_option("-q,--quick", choice)->check(CLI::IsMember(vals));
|
||||
app.add_option("-s,--slow", choice)->capture_default_str()->check(CLI::IsMember(vals));
|
||||
|
||||
args = {"--quick=hello"};
|
||||
CHECK_THROWS_AS(run(), CLI::ValidationError);
|
||||
|
||||
args = {"--slow=hello"};
|
||||
CHECK_THROWS_AS(run(), CLI::ValidationError);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "InSetIgnoreCase", "[set]") {
|
||||
|
||||
std::string choice;
|
||||
app.add_option("-q,--quick", choice)->transform(CLI::IsMember({"one", "Two", "THREE"}, CLI::ignore_case));
|
||||
|
||||
args = {"--quick", "One"};
|
||||
run();
|
||||
CHECK(choice == "one");
|
||||
|
||||
args = {"--quick", "two"};
|
||||
run();
|
||||
CHECK(choice == "Two");
|
||||
|
||||
args = {"--quick", "ThrEE"};
|
||||
run();
|
||||
CHECK(choice == "THREE");
|
||||
|
||||
args = {"--quick", "four"};
|
||||
CHECK_THROWS_AS(run(), CLI::ValidationError);
|
||||
|
||||
args = {"--quick=one", "--quick=two"};
|
||||
CHECK_THROWS_AS(run(), CLI::ArgumentMismatch);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "InSetIgnoreCaseMutableValue", "[set]") {
|
||||
|
||||
std::set<std::string> options{"one", "Two", "THREE"};
|
||||
std::string choice;
|
||||
app.add_option("-q,--quick", choice)->transform(CLI::IsMember(&options, CLI::ignore_case));
|
||||
|
||||
args = {"--quick", "One"};
|
||||
run();
|
||||
CHECK(choice == "one");
|
||||
|
||||
args = {"--quick", "two"};
|
||||
run();
|
||||
CHECK(choice == "Two");
|
||||
|
||||
args = {"--quick", "ThrEE"};
|
||||
run();
|
||||
CHECK(choice == "THREE");
|
||||
|
||||
options.clear();
|
||||
args = {"--quick", "ThrEE"};
|
||||
CHECK_THROWS_AS(run(), CLI::ValidationError);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "InSetIgnoreCasePointer", "[set]") {
|
||||
|
||||
auto *options = new std::set<std::string>{"one", "Two", "THREE"};
|
||||
std::string choice;
|
||||
app.add_option("-q,--quick", choice)->transform(CLI::IsMember(*options, CLI::ignore_case));
|
||||
|
||||
args = {"--quick", "One"};
|
||||
run();
|
||||
CHECK(choice == "one");
|
||||
|
||||
args = {"--quick", "two"};
|
||||
run();
|
||||
CHECK(choice == "Two");
|
||||
|
||||
args = {"--quick", "ThrEE"};
|
||||
run();
|
||||
CHECK(choice == "THREE");
|
||||
|
||||
delete options;
|
||||
args = {"--quick", "ThrEE"};
|
||||
run();
|
||||
CHECK(choice == "THREE");
|
||||
|
||||
args = {"--quick", "four"};
|
||||
CHECK_THROWS_AS(run(), CLI::ValidationError);
|
||||
|
||||
args = {"--quick=one", "--quick=two"};
|
||||
CHECK_THROWS_AS(run(), CLI::ArgumentMismatch);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "NotInSetIgnoreCasePointer", "[set]") {
|
||||
|
||||
auto *options = new std::set<std::string>{"one", "Two", "THREE"};
|
||||
std::string choice;
|
||||
app.add_option("-q,--quick", choice)->check(!CLI::IsMember(*options, CLI::ignore_case));
|
||||
|
||||
args = {"--quick", "One"};
|
||||
CHECK_THROWS_AS(run(), CLI::ValidationError);
|
||||
|
||||
args = {"--quick", "four"};
|
||||
run();
|
||||
CHECK("four" == choice);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "InSetIgnoreUnderscore", "[set]") {
|
||||
|
||||
std::string choice;
|
||||
app.add_option("-q,--quick", choice)
|
||||
->transform(CLI::IsMember({"option_one", "option_two", "optionthree"}, CLI::ignore_underscore));
|
||||
|
||||
args = {"--quick", "option_one"};
|
||||
run();
|
||||
CHECK(choice == "option_one");
|
||||
|
||||
args = {"--quick", "optiontwo"};
|
||||
run();
|
||||
CHECK(choice == "option_two");
|
||||
|
||||
args = {"--quick", "_option_thr_ee"};
|
||||
run();
|
||||
CHECK(choice == "optionthree");
|
||||
|
||||
args = {"--quick", "Option4"};
|
||||
CHECK_THROWS_AS(run(), CLI::ValidationError);
|
||||
|
||||
args = {"--quick=option_one", "--quick=option_two"};
|
||||
CHECK_THROWS_AS(run(), CLI::ArgumentMismatch);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "InSetIgnoreCaseUnderscore", "[set]") {
|
||||
|
||||
std::string choice;
|
||||
app.add_option("-q,--quick", choice)
|
||||
->transform(
|
||||
CLI::IsMember({"Option_One", "option_two", "OptionThree"}, CLI::ignore_case, CLI::ignore_underscore));
|
||||
|
||||
args = {"--quick", "option_one"};
|
||||
run();
|
||||
CHECK(choice == "Option_One");
|
||||
|
||||
args = {"--quick", "OptionTwo"};
|
||||
run();
|
||||
CHECK(choice == "option_two");
|
||||
|
||||
args = {"--quick", "_OPTION_thr_ee"};
|
||||
run();
|
||||
CHECK(choice == "OptionThree");
|
||||
|
||||
args = {"--quick", "Option4"};
|
||||
CHECK_THROWS_AS(run(), CLI::ValidationError);
|
||||
|
||||
args = {"--quick=option_one", "--quick=option_two"};
|
||||
CHECK_THROWS_AS(run(), CLI::ArgumentMismatch);
|
||||
}
|
||||
|
||||
// #113
|
||||
TEST_CASE_METHOD(TApp, "AddRemoveSetItems", "[set]") {
|
||||
std::set<std::string> items{"TYPE1", "TYPE2", "TYPE3", "TYPE4", "TYPE5"};
|
||||
|
||||
std::string type1, type2;
|
||||
app.add_option("--type1", type1)->check(CLI::IsMember(&items));
|
||||
app.add_option("--type2", type2)->capture_default_str()->check(CLI::IsMember(&items));
|
||||
|
||||
args = {"--type1", "TYPE1", "--type2", "TYPE2"};
|
||||
|
||||
run();
|
||||
CHECK("TYPE1" == type1);
|
||||
CHECK("TYPE2" == type2);
|
||||
|
||||
items.insert("TYPE6");
|
||||
items.insert("TYPE7");
|
||||
|
||||
items.erase("TYPE1");
|
||||
items.erase("TYPE2");
|
||||
|
||||
args = {"--type1", "TYPE6", "--type2", "TYPE7"};
|
||||
run();
|
||||
CHECK("TYPE6" == type1);
|
||||
CHECK("TYPE7" == type2);
|
||||
|
||||
args = {"--type1", "TYPE1"};
|
||||
CHECK_THROWS_AS(run(), CLI::ValidationError);
|
||||
|
||||
args = {"--type2", "TYPE2"};
|
||||
CHECK_THROWS_AS(run(), CLI::ValidationError);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "AddRemoveSetItemsNoCase", "[set]") {
|
||||
std::set<std::string> items{"TYPE1", "TYPE2", "TYPE3", "TYPE4", "TYPE5"};
|
||||
|
||||
std::string type1, type2;
|
||||
app.add_option("--type1", type1)->transform(CLI::IsMember(&items, CLI::ignore_case));
|
||||
app.add_option("--type2", type2)->capture_default_str()->transform(CLI::IsMember(&items, CLI::ignore_case));
|
||||
|
||||
args = {"--type1", "TYPe1", "--type2", "TyPE2"};
|
||||
|
||||
run();
|
||||
CHECK("TYPE1" == type1);
|
||||
CHECK("TYPE2" == type2);
|
||||
|
||||
items.insert("TYPE6");
|
||||
items.insert("TYPE7");
|
||||
|
||||
items.erase("TYPE1");
|
||||
items.erase("TYPE2");
|
||||
|
||||
args = {"--type1", "TyPE6", "--type2", "tYPE7"};
|
||||
run();
|
||||
CHECK("TYPE6" == type1);
|
||||
CHECK("TYPE7" == type2);
|
||||
|
||||
args = {"--type1", "TYPe1"};
|
||||
CHECK_THROWS_AS(run(), CLI::ValidationError);
|
||||
|
||||
args = {"--type2", "TYpE2"};
|
||||
CHECK_THROWS_AS(run(), CLI::ValidationError);
|
||||
}
|
||||
34
tests/SimpleTest.cpp
Normal file
34
tests/SimpleTest.cpp
Normal file
@@ -0,0 +1,34 @@
|
||||
// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#ifdef CLI11_SINGLE_FILE
|
||||
#include "CLI11.hpp"
|
||||
#else
|
||||
#include "CLI/CLI.hpp"
|
||||
#endif
|
||||
|
||||
#include "catch.hpp"
|
||||
|
||||
using input_t = std::vector<std::string>;
|
||||
|
||||
TEST_CASE("Basic: Empty", "[simple]") {
|
||||
|
||||
{
|
||||
CLI::App app;
|
||||
input_t simpleput;
|
||||
app.parse(simpleput);
|
||||
}
|
||||
{
|
||||
CLI::App app;
|
||||
input_t spare = {"spare"};
|
||||
CHECK_THROWS_AS(app.parse(spare), CLI::ExtrasError);
|
||||
}
|
||||
{
|
||||
CLI::App app;
|
||||
input_t simpleput;
|
||||
app.parse(simpleput);
|
||||
}
|
||||
}
|
||||
117
tests/StringParseTest.cpp
Normal file
117
tests/StringParseTest.cpp
Normal file
@@ -0,0 +1,117 @@
|
||||
// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include "app_helper.hpp"
|
||||
|
||||
#include <cstdio>
|
||||
#include <sstream>
|
||||
|
||||
TEST_CASE_METHOD(TApp, "ExistingExeCheck", "[stringparse]") {
|
||||
|
||||
TempFile tmpexe{"existingExe.out"};
|
||||
|
||||
std::string str, str2, str3;
|
||||
app.add_option("-s,--string", str);
|
||||
app.add_option("-t,--tstr", str2);
|
||||
app.add_option("-m,--mstr", str3);
|
||||
|
||||
{
|
||||
std::ofstream out{tmpexe};
|
||||
out << "useless string doesn't matter" << std::endl;
|
||||
}
|
||||
|
||||
app.parse(std::string("./") + std::string(tmpexe) +
|
||||
R"( --string="this is my quoted string" -t 'qstring 2' -m=`"quoted string"`)",
|
||||
true);
|
||||
CHECK("this is my quoted string" == str);
|
||||
CHECK("qstring 2" == str2);
|
||||
CHECK("\"quoted string\"" == str3);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "ExistingExeCheckWithSpace", "[stringparse]") {
|
||||
|
||||
TempFile tmpexe{"Space File.out"};
|
||||
|
||||
std::string str, str2, str3;
|
||||
app.add_option("-s,--string", str);
|
||||
app.add_option("-t,--tstr", str2);
|
||||
app.add_option("-m,--mstr", str3);
|
||||
|
||||
{
|
||||
std::ofstream out{tmpexe};
|
||||
out << "useless string doesn't matter" << std::endl;
|
||||
}
|
||||
|
||||
app.parse(std::string("./") + std::string(tmpexe) +
|
||||
R"( --string="this is my quoted string" -t 'qstring 2' -m=`"quoted string"`)",
|
||||
true);
|
||||
CHECK("this is my quoted string" == str);
|
||||
CHECK("qstring 2" == str2);
|
||||
CHECK("\"quoted string\"" == str3);
|
||||
|
||||
CHECK(std::string("./") + std::string(tmpexe) == app.get_name());
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "ExistingExeCheckWithLotsOfSpace", "[stringparse]") {
|
||||
|
||||
TempFile tmpexe{"this is a weird file.exe"};
|
||||
|
||||
std::string str, str2, str3;
|
||||
app.add_option("-s,--string", str);
|
||||
app.add_option("-t,--tstr", str2);
|
||||
app.add_option("-m,--mstr", str3);
|
||||
|
||||
{
|
||||
std::ofstream out{tmpexe};
|
||||
out << "useless string doesn't matter" << std::endl;
|
||||
}
|
||||
|
||||
app.parse(std::string("./") + std::string(tmpexe) +
|
||||
R"( --string="this is my quoted string" -t 'qstring 2' -m=`"quoted string"`)",
|
||||
true);
|
||||
CHECK("this is my quoted string" == str);
|
||||
CHECK("qstring 2" == str2);
|
||||
CHECK("\"quoted string\"" == str3);
|
||||
|
||||
CHECK(std::string("./") + std::string(tmpexe) == app.get_name());
|
||||
}
|
||||
|
||||
// From GitHub issue #591 https://github.com/CLIUtils/CLI11/issues/591
|
||||
TEST_CASE_METHOD(TApp, "ProgNameWithSpace", "[stringparse]") {
|
||||
|
||||
app.add_flag("--foo");
|
||||
CHECK_NOTHROW(app.parse("\"Foo Bar\" --foo", true));
|
||||
|
||||
CHECK(app["--foo"]->as<bool>());
|
||||
CHECK(app.get_name() == "Foo Bar");
|
||||
}
|
||||
|
||||
// From GitHub issue #739 https://github.com/CLIUtils/CLI11/issues/739
|
||||
TEST_CASE_METHOD(TApp, "ProgNameOnly", "[stringparse]") {
|
||||
|
||||
app.add_flag("--foo");
|
||||
CHECK_NOTHROW(app.parse("\"C:\\example.exe\"", true));
|
||||
|
||||
CHECK(app.get_name() == "C:\\example.exe");
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "ProgNameWithSpaceEmbeddedQuote", "[stringparse]") {
|
||||
|
||||
app.add_flag("--foo");
|
||||
CHECK_NOTHROW(app.parse("\"Foo\\\" Bar\" --foo", true));
|
||||
|
||||
CHECK(app["--foo"]->as<bool>());
|
||||
CHECK(app.get_name() == "Foo\" Bar");
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "ProgNameWithSpaceSingleQuote", "[stringparse]") {
|
||||
|
||||
app.add_flag("--foo");
|
||||
CHECK_NOTHROW(app.parse(R"('Foo\' Bar' --foo)", true));
|
||||
|
||||
CHECK(app["--foo"]->as<bool>());
|
||||
CHECK(app.get_name() == "Foo' Bar");
|
||||
}
|
||||
1986
tests/SubcommandTest.cpp
Normal file
1986
tests/SubcommandTest.cpp
Normal file
File diff suppressed because it is too large
Load Diff
70
tests/TimerTest.cpp
Normal file
70
tests/TimerTest.cpp
Normal file
@@ -0,0 +1,70 @@
|
||||
// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include "CLI/Timer.hpp"
|
||||
|
||||
#include "catch.hpp"
|
||||
#include <chrono>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
using Catch::Matchers::Contains;
|
||||
|
||||
TEST_CASE("Timer: MSTimes", "[timer]") {
|
||||
CLI::Timer timer{"My Timer"};
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(123));
|
||||
std::string output = timer.to_string();
|
||||
std::string new_output = (timer / 1000000).to_string();
|
||||
CHECK_THAT(output, Contains("My Timer"));
|
||||
CHECK_THAT(output, Contains(" ms"));
|
||||
CHECK_THAT(new_output, Contains(" ns"));
|
||||
}
|
||||
|
||||
/* Takes too long
|
||||
TEST_CASE("Timer: STimes", "[timer]") {
|
||||
CLI::Timer timer;
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
std::string output = timer.to_string();
|
||||
CHECK_THAT (output, Contains(" s"));
|
||||
}
|
||||
*/
|
||||
|
||||
// Fails on Windows
|
||||
// TEST_CASE("Timer: UStimes", "[timer]") {
|
||||
// CLI::Timer timer;
|
||||
// std::this_thread::sleep_for(std::chrono::microseconds(2));
|
||||
// std::string output = timer.to_string();
|
||||
// CHECK_THAT (output, Contains(" ms"));
|
||||
//}
|
||||
|
||||
TEST_CASE("Timer: BigTimer", "[timer]") {
|
||||
CLI::Timer timer{"My Timer", CLI::Timer::Big};
|
||||
std::string output = timer.to_string();
|
||||
CHECK_THAT(output, Contains("Time ="));
|
||||
CHECK_THAT(output, Contains("-----------"));
|
||||
}
|
||||
|
||||
TEST_CASE("Timer: AutoTimer", "[timer]") {
|
||||
CLI::AutoTimer timer;
|
||||
std::string output = timer.to_string();
|
||||
CHECK_THAT(output, Contains("Timer"));
|
||||
}
|
||||
|
||||
TEST_CASE("Timer: PrintTimer", "[timer]") {
|
||||
std::stringstream out;
|
||||
CLI::AutoTimer timer;
|
||||
out << timer;
|
||||
std::string output = out.str();
|
||||
CHECK_THAT(output, Contains("Timer"));
|
||||
}
|
||||
|
||||
TEST_CASE("Timer: TimeItTimer", "[timer]") {
|
||||
CLI::Timer timer;
|
||||
std::string output = timer.time_it([]() { std::this_thread::sleep_for(std::chrono::milliseconds(10)); }, .1);
|
||||
std::cout << output << std::endl;
|
||||
CHECK_THAT(output, Contains("ms"));
|
||||
}
|
||||
971
tests/TransformTest.cpp
Normal file
971
tests/TransformTest.cpp
Normal file
@@ -0,0 +1,971 @@
|
||||
// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include "app_helper.hpp"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <unordered_map>
|
||||
|
||||
#if defined(CLI11_CPP17)
|
||||
#if defined(__has_include)
|
||||
#if __has_include(<string_view>)
|
||||
#include <string_view>
|
||||
#define CLI11_HAS_STRING_VIEW
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
TEST_CASE_METHOD(TApp, "SimpleTransform", "[transform]") {
|
||||
int value{0};
|
||||
auto *opt = app.add_option("-s", value)->transform(CLI::Transformer({{"one", std::string("1")}}));
|
||||
args = {"-s", "one"};
|
||||
run();
|
||||
CHECK(app.count("-s") == 1u);
|
||||
CHECK(opt->count() == 1u);
|
||||
CHECK(1 == value);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "SimpleTransformInitList", "[transform]") {
|
||||
int value{0};
|
||||
auto *opt = app.add_option("-s", value)->transform(CLI::Transformer({{"one", "1"}}));
|
||||
args = {"-s", "one"};
|
||||
run();
|
||||
CHECK(app.count("-s") == 1u);
|
||||
CHECK(opt->count() == 1u);
|
||||
CHECK(1 == value);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "SimpleNumericalTransform", "[transform]") {
|
||||
int value{0};
|
||||
auto *opt = app.add_option("-s", value)->transform(CLI::Transformer(CLI::TransformPairs<int>{{"one", 1}}));
|
||||
args = {"-s", "one"};
|
||||
run();
|
||||
CHECK(app.count("-s") == 1u);
|
||||
CHECK(opt->count() == 1u);
|
||||
CHECK(1 == value);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "EnumTransform", "[transform]") {
|
||||
enum class test_cli : std::int16_t { val1 = 3, val2 = 4, val3 = 17 };
|
||||
test_cli value{test_cli::val2};
|
||||
auto *opt = app.add_option("-s", value)
|
||||
->transform(CLI::Transformer(CLI::TransformPairs<test_cli>{
|
||||
{"val1", test_cli::val1}, {"val2", test_cli::val2}, {"val3", test_cli::val3}}));
|
||||
args = {"-s", "val1"};
|
||||
run();
|
||||
CHECK(app.count("-s") == 1u);
|
||||
CHECK(opt->count() == 1u);
|
||||
CHECK(test_cli::val1 == value);
|
||||
|
||||
args = {"-s", "val2"};
|
||||
run();
|
||||
CHECK(test_cli::val2 == value);
|
||||
|
||||
args = {"-s", "val3"};
|
||||
run();
|
||||
CHECK(test_cli::val3 == value);
|
||||
|
||||
args = {"-s", "val4"};
|
||||
CHECK_THROWS_AS(run(), CLI::ConversionError);
|
||||
|
||||
// transformer doesn't do any checking so this still works
|
||||
args = {"-s", "5"};
|
||||
run();
|
||||
CHECK(std::int16_t(5) == static_cast<std::int16_t>(value));
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "EnumCheckedTransform", "[transform]") {
|
||||
enum class test_cli : std::int16_t { val1 = 3, val2 = 4, val3 = 17 };
|
||||
test_cli value{test_cli::val1};
|
||||
auto *opt = app.add_option("-s", value)
|
||||
->transform(CLI::CheckedTransformer(CLI::TransformPairs<test_cli>{
|
||||
{"val1", test_cli::val1}, {"val2", test_cli::val2}, {"val3", test_cli::val3}}));
|
||||
args = {"-s", "val1"};
|
||||
run();
|
||||
CHECK(app.count("-s") == 1u);
|
||||
CHECK(opt->count() == 1u);
|
||||
CHECK(test_cli::val1 == value);
|
||||
|
||||
args = {"-s", "val2"};
|
||||
run();
|
||||
CHECK(test_cli::val2 == value);
|
||||
|
||||
args = {"-s", "val3"};
|
||||
run();
|
||||
CHECK(test_cli::val3 == value);
|
||||
|
||||
args = {"-s", "17"};
|
||||
run();
|
||||
CHECK(test_cli::val3 == value);
|
||||
|
||||
args = {"-s", "val4"};
|
||||
CHECK_THROWS_AS(run(), CLI::ValidationError);
|
||||
|
||||
args = {"-s", "5"};
|
||||
CHECK_THROWS_AS(run(), CLI::ValidationError);
|
||||
}
|
||||
|
||||
// from jzakrzewski Issue #330
|
||||
TEST_CASE_METHOD(TApp, "EnumCheckedDefaultTransform", "[transform]") {
|
||||
enum class existing : std::int16_t { abort, overwrite, remove };
|
||||
app.add_option("--existing", "What to do if file already exists in the destination")
|
||||
->transform(
|
||||
CLI::CheckedTransformer(std::unordered_map<std::string, existing>{{"abort", existing::abort},
|
||||
{"overwrite", existing ::overwrite},
|
||||
{"delete", existing::remove},
|
||||
{"remove", existing::remove}}))
|
||||
->default_val("abort");
|
||||
args = {"--existing", "overwrite"};
|
||||
run();
|
||||
CHECK(existing::overwrite == app.get_option("--existing")->as<existing>());
|
||||
args.clear();
|
||||
run();
|
||||
CHECK(existing::abort == app.get_option("--existing")->as<existing>());
|
||||
}
|
||||
|
||||
// test from https://github.com/CLIUtils/CLI11/issues/369 [Jakub Zakrzewski](https://github.com/jzakrzewski)
|
||||
TEST_CASE_METHOD(TApp, "EnumCheckedDefaultTransformCallback", "[transform]") {
|
||||
enum class existing : std::int16_t { abort, overwrite, remove };
|
||||
auto cmd = std::make_shared<CLI::App>("deploys the repository somewhere", "deploy");
|
||||
cmd->add_option("--existing", "What to do if file already exists in the destination")
|
||||
->transform(
|
||||
CLI::CheckedTransformer(std::unordered_map<std::string, existing>{{"abort", existing::abort},
|
||||
{"overwrite", existing::overwrite},
|
||||
{"delete", existing::remove},
|
||||
{"remove", existing::remove}}))
|
||||
->default_val("abort");
|
||||
|
||||
cmd->callback([cmd]() { CHECK(cmd->get_option("--existing")->as<existing>() == existing::abort); });
|
||||
app.add_subcommand(cmd);
|
||||
|
||||
args = {"deploy"};
|
||||
run();
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "SimpleTransformFn", "[transform]") {
|
||||
int value{0};
|
||||
auto *opt = app.add_option("-s", value)->transform(CLI::Transformer({{"one", "1"}}, CLI::ignore_case));
|
||||
args = {"-s", "ONE"};
|
||||
run();
|
||||
CHECK(app.count("-s") == 1u);
|
||||
CHECK(opt->count() == 1u);
|
||||
CHECK(1 == value);
|
||||
}
|
||||
|
||||
#if defined(CLI11_HAS_STRING_VIEW)
|
||||
TEST_CASE_METHOD(TApp, "StringViewTransformFn", "[transform]") {
|
||||
std::string value;
|
||||
std::map<std::string_view, std::string_view> map = {// key length > std::string().capacity() [SSO length]
|
||||
{"a-rather-long-argument", "mapped"}};
|
||||
app.add_option("-s", value)->transform(CLI::CheckedTransformer(map));
|
||||
args = {"-s", "a-rather-long-argument"};
|
||||
run();
|
||||
CHECK("mapped" == value);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
TEST_CASE_METHOD(TApp, "SimpleNumericalTransformFn", "[transform]") {
|
||||
int value{0};
|
||||
auto *opt =
|
||||
app.add_option("-s", value)
|
||||
->transform(CLI::Transformer(std::vector<std::pair<std::string, int>>{{"one", 1}}, CLI::ignore_case));
|
||||
args = {"-s", "ONe"};
|
||||
run();
|
||||
CHECK(app.count("-s") == 1u);
|
||||
CHECK(opt->count() == 1u);
|
||||
CHECK(1 == value);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "SimpleNumericalTransformFnVector", "[transform]") {
|
||||
std::vector<std::pair<std::string, int>> conversions{{"one", 1}, {"two", 2}};
|
||||
int value{0};
|
||||
auto *opt = app.add_option("-s", value)->transform(CLI::Transformer(conversions, CLI::ignore_case));
|
||||
args = {"-s", "ONe"};
|
||||
run();
|
||||
CHECK(app.count("-s") == 1u);
|
||||
CHECK(opt->count() == 1u);
|
||||
CHECK(1 == value);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "SimpleNumericalTransformFnArray", "[transform]") {
|
||||
std::array<std::pair<std::string, int>, 2> conversions;
|
||||
conversions[0] = std::make_pair(std::string("one"), 1);
|
||||
conversions[1] = std::make_pair(std::string("two"), 2);
|
||||
|
||||
int value{0};
|
||||
auto *opt = app.add_option("-s", value)->transform(CLI::Transformer(conversions, CLI::ignore_case));
|
||||
args = {"-s", "ONe"};
|
||||
run();
|
||||
CHECK(app.count("-s") == 1u);
|
||||
CHECK(opt->count() == 1u);
|
||||
CHECK(1 == value);
|
||||
}
|
||||
|
||||
#ifdef CLI11_CPP14
|
||||
// zero copy constexpr array operation with transformer example and test
|
||||
TEST_CASE_METHOD(TApp, "SimpleNumericalTransformFnconstexprArray", "[transform]") {
|
||||
constexpr std::pair<const char *, int> p1{"one", 1};
|
||||
constexpr std::pair<const char *, int> p2{"two", 2};
|
||||
constexpr std::array<std::pair<const char *, int>, 2> conversions_c{{p1, p2}};
|
||||
|
||||
int value{0};
|
||||
auto *opt = app.add_option("-s", value)->transform(CLI::Transformer(&conversions_c, CLI::ignore_case));
|
||||
args = {"-s", "ONe"};
|
||||
run();
|
||||
CHECK(app.count("-s") == 1u);
|
||||
CHECK(opt->count() == 1u);
|
||||
CHECK(1 == value);
|
||||
|
||||
args = {"-s", "twO"};
|
||||
run();
|
||||
CHECK(app.count("-s") == 1u);
|
||||
CHECK(opt->count() == 1u);
|
||||
CHECK(2 == value);
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_CASE_METHOD(TApp, "EnumTransformFn", "[transform]") {
|
||||
enum class test_cli : std::int16_t { val1 = 3, val2 = 4, val3 = 17 };
|
||||
test_cli value{test_cli::val2};
|
||||
auto *opt = app.add_option("-s", value)
|
||||
->transform(CLI::Transformer(CLI::TransformPairs<test_cli>{{"val1", test_cli::val1},
|
||||
{"val2", test_cli::val2},
|
||||
{"val3", test_cli::val3}},
|
||||
CLI::ignore_case,
|
||||
CLI::ignore_underscore));
|
||||
args = {"-s", "val_1"};
|
||||
run();
|
||||
CHECK(app.count("-s") == 1u);
|
||||
CHECK(opt->count() == 1u);
|
||||
CHECK(test_cli::val1 == value);
|
||||
|
||||
args = {"-s", "VAL_2"};
|
||||
run();
|
||||
CHECK(test_cli::val2 == value);
|
||||
|
||||
args = {"-s", "VAL3"};
|
||||
run();
|
||||
CHECK(test_cli::val3 == value);
|
||||
|
||||
args = {"-s", "val_4"};
|
||||
CHECK_THROWS_AS(run(), CLI::ConversionError);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "EnumTransformFnMap", "[transform]") {
|
||||
enum class test_cli : std::int16_t { val1 = 3, val2 = 4, val3 = 17 };
|
||||
std::map<std::string, test_cli> map{{"val1", test_cli::val1}, {"val2", test_cli::val2}, {"val3", test_cli::val3}};
|
||||
test_cli value{test_cli::val3};
|
||||
auto *opt = app.add_option("-s", value)->transform(CLI::Transformer(map, CLI::ignore_case, CLI::ignore_underscore));
|
||||
args = {"-s", "val_1"};
|
||||
run();
|
||||
CHECK(app.count("-s") == 1u);
|
||||
CHECK(opt->count() == 1u);
|
||||
CHECK(test_cli::val1 == value);
|
||||
|
||||
args = {"-s", "VAL_2"};
|
||||
run();
|
||||
CHECK(test_cli::val2 == value);
|
||||
|
||||
args = {"-s", "VAL3"};
|
||||
run();
|
||||
CHECK(test_cli::val3 == value);
|
||||
|
||||
args = {"-s", "val_4"};
|
||||
CHECK_THROWS_AS(run(), CLI::ConversionError);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "EnumTransformFnPtrMap", "[transform]") {
|
||||
enum class test_cli : std::int16_t { val1 = 3, val2 = 4, val3 = 17, val4 = 37 };
|
||||
std::map<std::string, test_cli> map{{"val1", test_cli::val1}, {"val2", test_cli::val2}, {"val3", test_cli::val3}};
|
||||
test_cli value{test_cli::val2};
|
||||
auto *opt =
|
||||
app.add_option("-s", value)->transform(CLI::Transformer(&map, CLI::ignore_case, CLI::ignore_underscore));
|
||||
args = {"-s", "val_1"};
|
||||
run();
|
||||
CHECK(app.count("-s") == 1u);
|
||||
CHECK(opt->count() == 1u);
|
||||
CHECK(test_cli::val1 == value);
|
||||
|
||||
args = {"-s", "VAL_2"};
|
||||
run();
|
||||
CHECK(test_cli::val2 == value);
|
||||
|
||||
args = {"-s", "VAL3"};
|
||||
run();
|
||||
CHECK(test_cli::val3 == value);
|
||||
|
||||
args = {"-s", "val_4"};
|
||||
CHECK_THROWS_AS(run(), CLI::ConversionError);
|
||||
|
||||
map["val4"] = test_cli::val4;
|
||||
run();
|
||||
CHECK(test_cli::val4 == value);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "EnumTransformFnSharedPtrMap", "[transform]") {
|
||||
enum class test_cli : std::int16_t { val1 = 3, val2 = 4, val3 = 17, val4 = 37 };
|
||||
auto map = std::make_shared<std::unordered_map<std::string, test_cli>>();
|
||||
auto &mp = *map;
|
||||
mp["val1"] = test_cli::val1;
|
||||
mp["val2"] = test_cli::val2;
|
||||
mp["val3"] = test_cli::val3;
|
||||
|
||||
test_cli value{test_cli::val2};
|
||||
auto *opt = app.add_option("-s", value)->transform(CLI::Transformer(map, CLI::ignore_case, CLI::ignore_underscore));
|
||||
args = {"-s", "val_1"};
|
||||
run();
|
||||
CHECK(app.count("-s") == 1u);
|
||||
CHECK(opt->count() == 1u);
|
||||
CHECK(test_cli::val1 == value);
|
||||
|
||||
args = {"-s", "VAL_2"};
|
||||
run();
|
||||
CHECK(test_cli::val2 == value);
|
||||
|
||||
args = {"-s", "VAL3"};
|
||||
run();
|
||||
CHECK(test_cli::val3 == value);
|
||||
|
||||
args = {"-s", "val_4"};
|
||||
CHECK_THROWS_AS(run(), CLI::ConversionError);
|
||||
|
||||
mp["val4"] = test_cli::val4;
|
||||
run();
|
||||
CHECK(test_cli::val4 == value);
|
||||
}
|
||||
|
||||
// Test a cascade of transform functions
|
||||
TEST_CASE_METHOD(TApp, "TransformCascade", "[transform]") {
|
||||
|
||||
std::string output;
|
||||
auto *opt = app.add_option("-s", output);
|
||||
opt->transform(CLI::Transformer({{"abc", "abcd"}, {"bbc", "bbcd"}, {"cbc", "cbcd"}}, CLI::ignore_case));
|
||||
opt->transform(
|
||||
CLI::Transformer({{"ab", "abc"}, {"bc", "bbc"}, {"cb", "cbc"}}, CLI::ignore_case, CLI::ignore_underscore));
|
||||
opt->transform(CLI::Transformer({{"a", "ab"}, {"b", "bb"}, {"c", "cb"}}, CLI::ignore_case));
|
||||
opt->check(CLI::IsMember({"abcd", "bbcd", "cbcd"}));
|
||||
args = {"-s", "abcd"};
|
||||
run();
|
||||
CHECK("abcd" == output);
|
||||
|
||||
args = {"-s", "Bbc"};
|
||||
run();
|
||||
CHECK("bbcd" == output);
|
||||
|
||||
args = {"-s", "C_B"};
|
||||
run();
|
||||
CHECK("cbcd" == output);
|
||||
|
||||
args = {"-s", "A"};
|
||||
run();
|
||||
CHECK("abcd" == output);
|
||||
}
|
||||
|
||||
// Test a cascade of transform functions
|
||||
TEST_CASE_METHOD(TApp, "TransformCascadeDeactivate", "[transform]") {
|
||||
|
||||
std::string output;
|
||||
auto *opt = app.add_option("-s", output);
|
||||
opt->transform(
|
||||
CLI::Transformer({{"abc", "abcd"}, {"bbc", "bbcd"}, {"cbc", "cbcd"}}, CLI::ignore_case).name("tform1"));
|
||||
opt->transform(
|
||||
CLI::Transformer({{"ab", "abc"}, {"bc", "bbc"}, {"cb", "cbc"}}, CLI::ignore_case, CLI::ignore_underscore)
|
||||
.name("tform2")
|
||||
.active(false));
|
||||
opt->transform(CLI::Transformer({{"a", "ab"}, {"b", "bb"}, {"c", "cb"}}, CLI::ignore_case).name("tform3"));
|
||||
opt->check(CLI::IsMember({"abcd", "bbcd", "cbcd"}).name("check"));
|
||||
args = {"-s", "abcd"};
|
||||
run();
|
||||
CHECK("abcd" == output);
|
||||
|
||||
args = {"-s", "Bbc"};
|
||||
run();
|
||||
CHECK("bbcd" == output);
|
||||
|
||||
args = {"-s", "C_B"};
|
||||
CHECK_THROWS_AS(run(), CLI::ValidationError);
|
||||
|
||||
auto *validator = opt->get_validator("tform2");
|
||||
CHECK(!validator->get_active());
|
||||
CHECK("tform2" == validator->get_name());
|
||||
validator->active();
|
||||
CHECK(validator->get_active());
|
||||
args = {"-s", "C_B"};
|
||||
run();
|
||||
CHECK("cbcd" == output);
|
||||
|
||||
opt->get_validator("check")->active(false);
|
||||
args = {"-s", "gsdgsgs"};
|
||||
run();
|
||||
CHECK("gsdgsgs" == output);
|
||||
|
||||
CHECK_THROWS_AS(opt->get_validator("sdfsdf"), CLI::OptionNotFound);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "IntTransformFn", "[transform]") {
|
||||
std::string value;
|
||||
app.add_option("-s", value)
|
||||
->transform(
|
||||
CLI::CheckedTransformer(std::map<int, int>{{15, 5}, {18, 6}, {21, 7}}, [](int in) { return in - 10; }));
|
||||
args = {"-s", "25"};
|
||||
run();
|
||||
CHECK("5" == value);
|
||||
|
||||
args = {"-s", "6"};
|
||||
run();
|
||||
CHECK("6" == value);
|
||||
|
||||
args = {"-s", "45"};
|
||||
CHECK_THROWS_AS(run(), CLI::ValidationError);
|
||||
|
||||
args = {"-s", "val_4"};
|
||||
CHECK_THROWS_AS(run(), CLI::ValidationError);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "IntTransformNonConvertible", "[transform]") {
|
||||
std::string value;
|
||||
app.add_option("-s", value)->transform(CLI::Transformer(std::map<int, int>{{15, 5}, {18, 6}, {21, 7}}));
|
||||
args = {"-s", "15"};
|
||||
run();
|
||||
CHECK("5" == value);
|
||||
|
||||
args = {"-s", "18"};
|
||||
run();
|
||||
CHECK("6" == value);
|
||||
|
||||
// value can't be converted to int so it is just ignored
|
||||
args = {"-s", "abcd"};
|
||||
run();
|
||||
CHECK("abcd" == value);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "IntTransformNonMerge", "[transform]") {
|
||||
std::string value;
|
||||
app.add_option("-s", value)
|
||||
->transform(CLI::Transformer(std::map<int, int>{{15, 5}, {18, 6}, {21, 7}}) &
|
||||
CLI::Transformer(std::map<int, int>{{25, 5}, {28, 6}, {31, 7}}),
|
||||
"merge");
|
||||
args = {"-s", "15"};
|
||||
run();
|
||||
CHECK("5" == value);
|
||||
|
||||
args = {"-s", "18"};
|
||||
run();
|
||||
CHECK("6" == value);
|
||||
|
||||
// value can't be converted to int so it is just ignored
|
||||
args = {"-s", "abcd"};
|
||||
run();
|
||||
CHECK("abcd" == value);
|
||||
|
||||
args = {"-s", "25"};
|
||||
run();
|
||||
CHECK("5" == value);
|
||||
|
||||
args = {"-s", "31"};
|
||||
run();
|
||||
CHECK("7" == value);
|
||||
|
||||
auto help = app.help();
|
||||
CHECK(help.find("15->5") != std::string::npos);
|
||||
CHECK(help.find("25->5") != std::string::npos);
|
||||
|
||||
auto *validator = app.get_option("-s")->get_validator();
|
||||
help = validator->get_description();
|
||||
CHECK(help.find("15->5") != std::string::npos);
|
||||
CHECK(help.find("25->5") != std::string::npos);
|
||||
|
||||
auto *validator2 = app.get_option("-s")->get_validator("merge");
|
||||
CHECK(validator == validator2);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "IntTransformMergeWithCustomValidator", "[transform]") {
|
||||
std::string value;
|
||||
auto *opt = app.add_option("-s", value)
|
||||
->transform(CLI::Transformer(std::map<int, int>{{15, 5}, {18, 6}, {21, 7}}) |
|
||||
CLI::Validator(
|
||||
[](std::string &element) {
|
||||
if(element == "frog") {
|
||||
element = "hops";
|
||||
}
|
||||
return std::string{};
|
||||
},
|
||||
std::string{}),
|
||||
"check");
|
||||
args = {"-s", "15"};
|
||||
run();
|
||||
CHECK("5" == value);
|
||||
|
||||
args = {"-s", "18"};
|
||||
run();
|
||||
CHECK("6" == value);
|
||||
|
||||
// value can't be converted to int so it is just ignored
|
||||
args = {"-s", "frog"};
|
||||
run();
|
||||
CHECK("hops" == value);
|
||||
|
||||
args = {"-s", "25"};
|
||||
run();
|
||||
CHECK("25" == value);
|
||||
|
||||
auto help = app.help();
|
||||
CHECK(help.find("15->5") != std::string::npos);
|
||||
CHECK(help.find("OR") == std::string::npos);
|
||||
|
||||
auto *validator = opt->get_validator("check");
|
||||
CHECK("check" == validator->get_name());
|
||||
validator->active(false);
|
||||
help = app.help();
|
||||
CHECK(help.find("15->5") == std::string::npos);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "BoundTests", "[transform]") {
|
||||
double value = NAN;
|
||||
app.add_option("-s", value)->transform(CLI::Bound(3.4, 5.9));
|
||||
args = {"-s", "15"};
|
||||
run();
|
||||
CHECK(5.9 == value);
|
||||
|
||||
args = {"-s", "3.689"};
|
||||
run();
|
||||
CHECK(std::stod("3.689") == value);
|
||||
|
||||
// value can't be converted to int so it is just ignored
|
||||
args = {"-s", "abcd"};
|
||||
CHECK_THROWS_AS(run(), CLI::ValidationError);
|
||||
|
||||
args = {"-s", "2.5"};
|
||||
run();
|
||||
CHECK(3.4 == value);
|
||||
|
||||
auto help = app.help();
|
||||
CHECK(help.find("bounded to") != std::string::npos);
|
||||
CHECK(help.find("[3.4 - 5.9]") != std::string::npos);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "NumberWithUnitCorrectlySplitNumber", "[transform]") {
|
||||
std::map<std::string, int> mapping{{"a", 10}, {"b", 100}, {"cc", 1000}};
|
||||
|
||||
int value = 0;
|
||||
app.add_option("-n", value)->transform(CLI::AsNumberWithUnit(mapping));
|
||||
|
||||
args = {"-n", "42"};
|
||||
run();
|
||||
CHECK(42 == value);
|
||||
|
||||
args = {"-n", "42a"};
|
||||
run();
|
||||
CHECK(420 == value);
|
||||
|
||||
args = {"-n", " 42 cc "};
|
||||
run();
|
||||
CHECK(42000 == value);
|
||||
args = {"-n", " -42 cc "};
|
||||
run();
|
||||
CHECK(-42000 == value);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "NumberWithUnitFloatTest", "[transform]") {
|
||||
std::map<std::string, double> mapping{{"a", 10}, {"b", 100}, {"cc", 1000}};
|
||||
double value{0.0};
|
||||
app.add_option("-n", value)->transform(CLI::AsNumberWithUnit(mapping));
|
||||
|
||||
args = {"-n", "42"};
|
||||
run();
|
||||
CHECK(42 == Approx(value));
|
||||
|
||||
args = {"-n", ".5"};
|
||||
run();
|
||||
CHECK(.5 == Approx(value));
|
||||
|
||||
args = {"-n", "42.5 a"};
|
||||
run();
|
||||
CHECK(425 == Approx(value));
|
||||
|
||||
args = {"-n", "42.cc"};
|
||||
run();
|
||||
CHECK(42000 == Approx(value));
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "NumberWithUnitCaseSensitive", "[transform]") {
|
||||
std::map<std::string, int> mapping{{"a", 10}, {"A", 100}};
|
||||
|
||||
int value{0};
|
||||
app.add_option("-n", value)->transform(CLI::AsNumberWithUnit(mapping, CLI::AsNumberWithUnit::CASE_SENSITIVE));
|
||||
|
||||
args = {"-n", "42a"};
|
||||
run();
|
||||
CHECK(420 == value);
|
||||
|
||||
args = {"-n", "42A"};
|
||||
run();
|
||||
CHECK(4200 == value);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "NumberWithUnitCaseInsensitive", "[transform]") {
|
||||
std::map<std::string, int> mapping{{"a", 10}, {"B", 100}};
|
||||
|
||||
int value{0};
|
||||
app.add_option("-n", value)->transform(CLI::AsNumberWithUnit(mapping, CLI::AsNumberWithUnit::CASE_INSENSITIVE));
|
||||
|
||||
args = {"-n", "42a"};
|
||||
run();
|
||||
CHECK(420 == value);
|
||||
|
||||
args = {"-n", "42A"};
|
||||
run();
|
||||
CHECK(420 == value);
|
||||
|
||||
args = {"-n", "42b"};
|
||||
run();
|
||||
CHECK(4200 == value);
|
||||
|
||||
args = {"-n", "42B"};
|
||||
run();
|
||||
CHECK(4200 == value);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "NumberWithUnitMandatoryUnit", "[transform]") {
|
||||
std::map<std::string, int> mapping{{"a", 10}, {"A", 100}};
|
||||
|
||||
int value{0};
|
||||
app.add_option("-n", value)
|
||||
->transform(CLI::AsNumberWithUnit(
|
||||
mapping, CLI::AsNumberWithUnit::UNIT_REQUIRED | CLI::AsNumberWithUnit::CASE_SENSITIVE));
|
||||
|
||||
args = {"-n", "42a"};
|
||||
run();
|
||||
CHECK(420 == value);
|
||||
|
||||
args = {"-n", "42A"};
|
||||
run();
|
||||
CHECK(4200 == value);
|
||||
|
||||
args = {"-n", "42"};
|
||||
CHECK_THROWS_AS(run(), CLI::ValidationError);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "NumberWithUnitMandatoryUnit2", "[transform]") {
|
||||
std::map<std::string, int> mapping{{"a", 10}, {"B", 100}};
|
||||
|
||||
int value{0};
|
||||
app.add_option("-n", value)
|
||||
->transform(CLI::AsNumberWithUnit(
|
||||
mapping, CLI::AsNumberWithUnit::UNIT_REQUIRED | CLI::AsNumberWithUnit::CASE_INSENSITIVE));
|
||||
|
||||
args = {"-n", "42A"};
|
||||
run();
|
||||
CHECK(420 == value);
|
||||
|
||||
args = {"-n", "42b"};
|
||||
run();
|
||||
CHECK(4200 == value);
|
||||
|
||||
args = {"-n", "42"};
|
||||
CHECK_THROWS_AS(run(), CLI::ValidationError);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "NumberWithUnitBadMapping", "[transform]") {
|
||||
CHECK_THROWS_AS(CLI::AsNumberWithUnit(std::map<std::string, int>{{"a", 10}, {"A", 100}},
|
||||
CLI::AsNumberWithUnit::CASE_INSENSITIVE),
|
||||
CLI::ValidationError);
|
||||
CHECK_THROWS_AS(CLI::AsNumberWithUnit(std::map<std::string, int>{{"a", 10}, {"9", 100}}), CLI::ValidationError);
|
||||
CHECK_THROWS_AS(CLI::AsNumberWithUnit(std::map<std::string, int>{{"a", 10}, {"AA A", 100}}), CLI::ValidationError);
|
||||
CHECK_THROWS_AS(CLI::AsNumberWithUnit(std::map<std::string, int>{{"a", 10}, {"", 100}}), CLI::ValidationError);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "NumberWithUnitBadInput", "[transform]") {
|
||||
std::map<std::string, int> mapping{{"a", 10}, {"b", 100}};
|
||||
|
||||
int value{0};
|
||||
app.add_option("-n", value)->transform(CLI::AsNumberWithUnit(mapping));
|
||||
|
||||
args = {"-n", "13 a b"};
|
||||
CHECK_THROWS_AS(run(), CLI::ValidationError);
|
||||
args = {"-n", "13 c"};
|
||||
CHECK_THROWS_AS(run(), CLI::ValidationError);
|
||||
args = {"-n", "a"};
|
||||
// Assume 1.0 unit
|
||||
CHECK_NOTHROW(run());
|
||||
args = {"-n", "12.0a"};
|
||||
CHECK_THROWS_AS(run(), CLI::ValidationError);
|
||||
args = {"-n", "a5"};
|
||||
CHECK_THROWS_AS(run(), CLI::ValidationError);
|
||||
args = {"-n", ""};
|
||||
CHECK_THROWS_AS(run(), CLI::ValidationError);
|
||||
args = {"-n", "13 a-"};
|
||||
CHECK_THROWS_AS(run(), CLI::ValidationError);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "NumberWithUnitIntOverflow", "[transform]") {
|
||||
std::map<std::string, int> mapping{{"a", 1000000}, {"b", 100}, {"c", 101}};
|
||||
|
||||
std::int32_t value = 0;
|
||||
app.add_option("-n", value)->transform(CLI::AsNumberWithUnit(mapping));
|
||||
|
||||
args = {"-n", "1000 a"};
|
||||
run();
|
||||
CHECK(1000000000 == value);
|
||||
|
||||
args = {"-n", "1000000 a"};
|
||||
CHECK_THROWS_AS(run(), CLI::ValidationError);
|
||||
|
||||
args = {"-n", "-1000000 a"};
|
||||
CHECK_THROWS_AS(run(), CLI::ValidationError);
|
||||
|
||||
args = {"-n", "21474836 b"};
|
||||
run();
|
||||
CHECK(2147483600 == value);
|
||||
|
||||
args = {"-n", "21474836 c"};
|
||||
CHECK_THROWS_AS(run(), CLI::ValidationError);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "NumberWithUnitFloatOverflow", "[transform]") {
|
||||
std::map<std::string, float> mapping{{"a", 2.f}, {"b", 1.f}, {"c", 0.f}};
|
||||
|
||||
float value{0.0F};
|
||||
app.add_option("-n", value)->transform(CLI::AsNumberWithUnit(mapping));
|
||||
|
||||
args = {"-n", "3e+38 a"};
|
||||
CHECK_THROWS_AS(run(), CLI::ValidationError);
|
||||
|
||||
args = {"-n", "3e+38 b"};
|
||||
run();
|
||||
CHECK(3e+38f == Approx(value));
|
||||
|
||||
args = {"-n", "3e+38 c"};
|
||||
run();
|
||||
CHECK(0.f == Approx(value));
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "AsSizeValue1000_1024", "[transform]") {
|
||||
std::uint64_t value{0};
|
||||
app.add_option("-s", value)->transform(CLI::AsSizeValue(true));
|
||||
|
||||
args = {"-s", "10240"};
|
||||
run();
|
||||
CHECK(10240u == value);
|
||||
|
||||
args = {"-s", "1b"};
|
||||
run();
|
||||
CHECK(1u == value);
|
||||
|
||||
std::uint64_t k_value{1000u};
|
||||
std::uint64_t ki_value{1024u};
|
||||
args = {"-s", "1k"};
|
||||
run();
|
||||
CHECK(k_value == value);
|
||||
args = {"-s", "1kb"};
|
||||
run();
|
||||
CHECK(k_value == value);
|
||||
args = {"-s", "1 Kb"};
|
||||
run();
|
||||
CHECK(k_value == value);
|
||||
args = {"-s", "1ki"};
|
||||
run();
|
||||
CHECK(ki_value == value);
|
||||
args = {"-s", "1kib"};
|
||||
run();
|
||||
CHECK(ki_value == value);
|
||||
|
||||
k_value = 1000ull * 1000u;
|
||||
ki_value = 1024ull * 1024u;
|
||||
args = {"-s", "1m"};
|
||||
run();
|
||||
CHECK(k_value == value);
|
||||
args = {"-s", "1mb"};
|
||||
run();
|
||||
CHECK(k_value == value);
|
||||
args = {"-s", "1mi"};
|
||||
run();
|
||||
CHECK(ki_value == value);
|
||||
args = {"-s", "1mib"};
|
||||
run();
|
||||
CHECK(ki_value == value);
|
||||
|
||||
k_value = 1000ull * 1000u * 1000u;
|
||||
ki_value = 1024ull * 1024u * 1024u;
|
||||
args = {"-s", "1g"};
|
||||
run();
|
||||
CHECK(k_value == value);
|
||||
args = {"-s", "1gb"};
|
||||
run();
|
||||
CHECK(k_value == value);
|
||||
args = {"-s", "1gi"};
|
||||
run();
|
||||
CHECK(ki_value == value);
|
||||
args = {"-s", "1gib"};
|
||||
run();
|
||||
CHECK(ki_value == value);
|
||||
|
||||
k_value = 1000ull * 1000u * 1000u * 1000u;
|
||||
ki_value = 1024ull * 1024u * 1024u * 1024u;
|
||||
args = {"-s", "1t"};
|
||||
run();
|
||||
CHECK(k_value == value);
|
||||
args = {"-s", "1tb"};
|
||||
run();
|
||||
CHECK(k_value == value);
|
||||
args = {"-s", "1ti"};
|
||||
run();
|
||||
CHECK(ki_value == value);
|
||||
args = {"-s", "1tib"};
|
||||
run();
|
||||
CHECK(ki_value == value);
|
||||
|
||||
k_value = 1000ull * 1000u * 1000u * 1000u * 1000u;
|
||||
ki_value = 1024ull * 1024u * 1024u * 1024u * 1024u;
|
||||
args = {"-s", "1p"};
|
||||
run();
|
||||
CHECK(k_value == value);
|
||||
args = {"-s", "1pb"};
|
||||
run();
|
||||
CHECK(k_value == value);
|
||||
args = {"-s", "1pi"};
|
||||
run();
|
||||
CHECK(ki_value == value);
|
||||
args = {"-s", "1pib"};
|
||||
run();
|
||||
CHECK(ki_value == value);
|
||||
|
||||
k_value = 1000ull * 1000u * 1000u * 1000u * 1000u * 1000u;
|
||||
ki_value = 1024ull * 1024u * 1024u * 1024u * 1024u * 1024u;
|
||||
args = {"-s", "1e"};
|
||||
run();
|
||||
CHECK(k_value == value);
|
||||
args = {"-s", "1eb"};
|
||||
run();
|
||||
CHECK(k_value == value);
|
||||
args = {"-s", "1ei"};
|
||||
run();
|
||||
CHECK(ki_value == value);
|
||||
args = {"-s", "1eib"};
|
||||
run();
|
||||
CHECK(ki_value == value);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "duration_test", "[transform]") {
|
||||
std::chrono::seconds duration{1};
|
||||
|
||||
app.option_defaults()->ignore_case();
|
||||
app.add_option_function<std::size_t>(
|
||||
"--duration",
|
||||
[&](size_t a_value) { duration = std::chrono::seconds{a_value}; },
|
||||
"valid units: sec, min, h, day.")
|
||||
->capture_default_str()
|
||||
->transform(CLI::AsNumberWithUnit(
|
||||
std::map<std::string, std::size_t>{{"sec", 1}, {"min", 60}, {"h", 3600}, {"day", 24 * 3600}}));
|
||||
CHECK_NOTHROW(app.parse(std::vector<std::string>{"1 day", "--duration"}));
|
||||
|
||||
CHECK(std::chrono::seconds(86400) == duration);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "AsSizeValue1024", "[transform]") {
|
||||
std::uint64_t value{0};
|
||||
app.add_option("-s", value)->transform(CLI::AsSizeValue(false));
|
||||
|
||||
args = {"-s", "10240"};
|
||||
run();
|
||||
CHECK(10240u == value);
|
||||
|
||||
args = {"-s", "1b"};
|
||||
run();
|
||||
CHECK(1u == value);
|
||||
|
||||
std::uint64_t ki_value{1024u};
|
||||
args = {"-s", "1k"};
|
||||
run();
|
||||
CHECK(ki_value == value);
|
||||
args = {"-s", "1kb"};
|
||||
run();
|
||||
CHECK(ki_value == value);
|
||||
args = {"-s", "1 Kb"};
|
||||
run();
|
||||
CHECK(ki_value == value);
|
||||
args = {"-s", "1ki"};
|
||||
run();
|
||||
CHECK(ki_value == value);
|
||||
args = {"-s", "1kib"};
|
||||
run();
|
||||
CHECK(ki_value == value);
|
||||
|
||||
ki_value = 1024ull * 1024u;
|
||||
args = {"-s", "1m"};
|
||||
run();
|
||||
CHECK(ki_value == value);
|
||||
args = {"-s", "1mb"};
|
||||
run();
|
||||
CHECK(ki_value == value);
|
||||
args = {"-s", "1mi"};
|
||||
run();
|
||||
CHECK(ki_value == value);
|
||||
args = {"-s", "1mib"};
|
||||
run();
|
||||
CHECK(ki_value == value);
|
||||
|
||||
ki_value = 1024ull * 1024u * 1024u;
|
||||
args = {"-s", "1g"};
|
||||
run();
|
||||
CHECK(ki_value == value);
|
||||
args = {"-s", "1gb"};
|
||||
run();
|
||||
CHECK(ki_value == value);
|
||||
args = {"-s", "1gi"};
|
||||
run();
|
||||
CHECK(ki_value == value);
|
||||
args = {"-s", "1gib"};
|
||||
run();
|
||||
CHECK(ki_value == value);
|
||||
|
||||
ki_value = 1024ull * 1024u * 1024u * 1024u;
|
||||
args = {"-s", "1t"};
|
||||
run();
|
||||
CHECK(ki_value == value);
|
||||
args = {"-s", "1tb"};
|
||||
run();
|
||||
CHECK(ki_value == value);
|
||||
args = {"-s", "1ti"};
|
||||
run();
|
||||
CHECK(ki_value == value);
|
||||
args = {"-s", "1tib"};
|
||||
run();
|
||||
CHECK(ki_value == value);
|
||||
|
||||
ki_value = 1024ull * 1024u * 1024u * 1024u * 1024u;
|
||||
args = {"-s", "1p"};
|
||||
run();
|
||||
CHECK(ki_value == value);
|
||||
args = {"-s", "1pb"};
|
||||
run();
|
||||
CHECK(ki_value == value);
|
||||
args = {"-s", "1pi"};
|
||||
run();
|
||||
CHECK(ki_value == value);
|
||||
args = {"-s", "1pib"};
|
||||
run();
|
||||
CHECK(ki_value == value);
|
||||
|
||||
ki_value = 1024ull * 1024u * 1024u * 1024u * 1024u * 1024u;
|
||||
args = {"-s", "1e"};
|
||||
run();
|
||||
CHECK(ki_value == value);
|
||||
args = {"-s", "1eb"};
|
||||
run();
|
||||
CHECK(ki_value == value);
|
||||
args = {"-s", "1ei"};
|
||||
run();
|
||||
CHECK(ki_value == value);
|
||||
args = {"-s", "1eib"};
|
||||
run();
|
||||
CHECK(ki_value == value);
|
||||
}
|
||||
29
tests/TrueFalseTest.cpp
Normal file
29
tests/TrueFalseTest.cpp
Normal file
@@ -0,0 +1,29 @@
|
||||
// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include "app_helper.hpp"
|
||||
|
||||
TEST_CASE_METHOD(TApp, "True Bool Option", "[bool][flag]") {
|
||||
// Strings needed here due to MSVC 2015.
|
||||
auto param = GENERATE(as<std::string>{}, "true", "on", "True", "ON");
|
||||
bool value{false}; // Not used, but set just in case
|
||||
app.add_option("-b,--bool", value);
|
||||
args = {"--bool", param};
|
||||
run();
|
||||
CHECK(app.count("--bool") == 1u);
|
||||
CHECK(value);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "False Bool Option", "[bool][flag]") {
|
||||
auto param = GENERATE(as<std::string>{}, "false", "off", "False", "OFF");
|
||||
|
||||
bool value{true}; // Not used, but set just in case
|
||||
app.add_option("-b,--bool", value);
|
||||
args = {"--bool", param};
|
||||
run();
|
||||
CHECK(app.count("--bool") == 1u);
|
||||
CHECK_FALSE(value);
|
||||
}
|
||||
19
tests/WindowsTest.cpp
Normal file
19
tests/WindowsTest.cpp
Normal file
@@ -0,0 +1,19 @@
|
||||
// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include "app_helper.hpp"
|
||||
#include <Windows.h>
|
||||
|
||||
// This test verifies that CLI11 still works if
|
||||
// Windows.h is included. #145
|
||||
|
||||
TEST_CASE_METHOD(TApp, "WindowsTestSimple", "[windows]") {
|
||||
app.add_flag("-c,--count");
|
||||
args = {"-c"};
|
||||
run();
|
||||
CHECK(app.count("-c") == 1u);
|
||||
CHECK(app.count("--count") == 1u);
|
||||
}
|
||||
67
tests/app_helper.hpp
Normal file
67
tests/app_helper.hpp
Normal file
@@ -0,0 +1,67 @@
|
||||
// Copyright (c) 2017-2021, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef CLI11_SINGLE_FILE
|
||||
#include "CLI11.hpp"
|
||||
#else
|
||||
#include "CLI/CLI.hpp"
|
||||
#endif
|
||||
|
||||
#include "catch.hpp"
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
using input_t = std::vector<std::string>;
|
||||
|
||||
class TApp {
|
||||
public:
|
||||
CLI::App app{"My Test Program"};
|
||||
input_t args{};
|
||||
virtual ~TApp() = default;
|
||||
void run() {
|
||||
// It is okay to re-parse - clear is called automatically before a parse.
|
||||
input_t newargs = args;
|
||||
std::reverse(std::begin(newargs), std::end(newargs));
|
||||
app.parse(newargs);
|
||||
}
|
||||
};
|
||||
|
||||
class TempFile {
|
||||
std::string _name{};
|
||||
|
||||
public:
|
||||
explicit TempFile(std::string name) : _name(std::move(name)) {
|
||||
if(!CLI::NonexistentPath(_name).empty())
|
||||
throw std::runtime_error(_name);
|
||||
}
|
||||
|
||||
~TempFile() {
|
||||
std::remove(_name.c_str()); // Doesn't matter if returns 0 or not
|
||||
}
|
||||
|
||||
operator const std::string &() const { return _name; } // NOLINT(google-explicit-constructor)
|
||||
CLI11_NODISCARD const char *c_str() const { return _name.c_str(); }
|
||||
};
|
||||
|
||||
inline void put_env(std::string name, std::string value) {
|
||||
#ifdef _WIN32
|
||||
_putenv_s(name.c_str(), value.c_str());
|
||||
#else
|
||||
setenv(name.c_str(), value.c_str(), 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void unset_env(std::string name) {
|
||||
#ifdef _WIN32
|
||||
_putenv_s(name.c_str(), "");
|
||||
#else
|
||||
unsetenv(name.c_str());
|
||||
#endif
|
||||
}
|
||||
9
tests/catch.hpp
Normal file
9
tests/catch.hpp
Normal file
@@ -0,0 +1,9 @@
|
||||
// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <catch2/catch.hpp>
|
||||
56
tests/informational.cpp
Normal file
56
tests/informational.cpp
Normal file
@@ -0,0 +1,56 @@
|
||||
// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#ifdef CLI11_SINGLE_FILE
|
||||
#include "CLI11.hpp"
|
||||
#else
|
||||
#include "CLI/CLI.hpp"
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
|
||||
int main() {
|
||||
std::cout << "\nCLI11 information:\n";
|
||||
|
||||
std::cout << " C++ standard: ";
|
||||
#if defined(CLI11_CPP20)
|
||||
std::cout << 20;
|
||||
#elif defined(CLI11_CPP17)
|
||||
std::cout << 17;
|
||||
#elif defined(CLI11_CPP14)
|
||||
std::cout << 14;
|
||||
#else
|
||||
std::cout << 11;
|
||||
#endif
|
||||
std::cout << "\n";
|
||||
|
||||
std::cout << " __has_include: ";
|
||||
#ifdef __has_include
|
||||
std::cout << "yes\n";
|
||||
#else
|
||||
std::cout << "no\n";
|
||||
#endif
|
||||
|
||||
#if CLI11_OPTIONAL
|
||||
std::cout << " [Available as CLI::optional]";
|
||||
#else
|
||||
std::cout << " No optional library found\n";
|
||||
#endif
|
||||
|
||||
#if CLI11_STD_OPTIONAL
|
||||
std::cout << " std::optional support active\n";
|
||||
#endif
|
||||
|
||||
#if CLI11_EXPERIMENTAL_OPTIONAL
|
||||
std::cout << " std::experimental::optional support active\n";
|
||||
#endif
|
||||
|
||||
#if CLI11_BOOST_OPTIONAL
|
||||
std::cout << " boost::optional support active\n";
|
||||
#endif
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
10
tests/link_test_1.cpp
Normal file
10
tests/link_test_1.cpp
Normal file
@@ -0,0 +1,10 @@
|
||||
// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include "CLI/CLI.hpp"
|
||||
#include "CLI/Timer.hpp"
|
||||
|
||||
int do_nothing() { return 7; }
|
||||
17
tests/link_test_2.cpp
Normal file
17
tests/link_test_2.cpp
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include "CLI/CLI.hpp"
|
||||
#include "CLI/Timer.hpp"
|
||||
#include "catch.hpp"
|
||||
|
||||
int do_nothing();
|
||||
|
||||
// Verifies there are no unguarded inlines
|
||||
TEST_CASE("Link: DoNothing", "[link]") {
|
||||
int a = do_nothing();
|
||||
CHECK(a == 7);
|
||||
}
|
||||
8
tests/main.cpp
Normal file
8
tests/main.cpp
Normal file
@@ -0,0 +1,8 @@
|
||||
// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#define CATCH_CONFIG_MAIN
|
||||
#include "catch.hpp"
|
||||
78
tests/meson.build
Normal file
78
tests/meson.build
Normal file
@@ -0,0 +1,78 @@
|
||||
catch2 = dependency('catch2')
|
||||
|
||||
testmain = static_library(
|
||||
'catch_main',
|
||||
'main.cpp', 'catch.hpp',
|
||||
dependencies: catch2,
|
||||
)
|
||||
testdep = declare_dependency(
|
||||
link_with: testmain,
|
||||
dependencies: [catch2, CLI11_dep]
|
||||
)
|
||||
|
||||
link_test_lib = library(
|
||||
'link_test_1',
|
||||
'link_test_1.cpp',
|
||||
dependencies: CLI11_dep,
|
||||
)
|
||||
|
||||
if cxx.get_id() == 'msvc'
|
||||
nodeprecated = ['/wd4996']
|
||||
else
|
||||
nodeprecated = ['-Wno-deprecated-declarations']
|
||||
endif
|
||||
|
||||
boost = dependency('boost', required: false)
|
||||
if boost.found()
|
||||
boost_dep = declare_dependency(
|
||||
dependencies: boost,
|
||||
compile_args: '-DCLI11_BOOST_OPTIONAL',
|
||||
)
|
||||
else
|
||||
boost_dep = declare_dependency()
|
||||
endif
|
||||
|
||||
testnames = [
|
||||
['HelpersTest', {}],
|
||||
['ConfigFileTest', {}],
|
||||
['OptionTypeTest', {}],
|
||||
['SimpleTest', {}],
|
||||
['AppTest', {}],
|
||||
['SetTest', {}],
|
||||
['TransformTest', {}],
|
||||
['CreationTest', {}],
|
||||
['SubcommandTest', {}],
|
||||
['HelpTest', {}],
|
||||
['FormatterTest', {}],
|
||||
['NewParseTest', {}],
|
||||
['OptionalTest', {'dependencies': boost_dep}],
|
||||
['DeprecatedTest', {'cpp_args': nodeprecated}],
|
||||
['StringParseTest', {}],
|
||||
['ComplexTypeTest', {}],
|
||||
['TrueFalseTest', {}],
|
||||
['OptionGroupTest', {}],
|
||||
# multi-only
|
||||
['TimerTest', {}],
|
||||
# link_test
|
||||
['link_test_2', {'link_with': link_test_lib}],
|
||||
]
|
||||
|
||||
if host_machine.system() == 'windows'
|
||||
testnames += [['WindowsTest', {}]]
|
||||
endif
|
||||
|
||||
if boost.found()
|
||||
testnames += [['BoostOptionTypeTest', {'dependencies': boost_dep}]]
|
||||
endif
|
||||
|
||||
foreach n: testnames
|
||||
name = n[0]
|
||||
kwargs = n[1]
|
||||
t = executable(name, name + '.cpp',
|
||||
cpp_args: kwargs.get('cpp_args', []),
|
||||
build_by_default: false,
|
||||
dependencies: [testdep] + kwargs.get('dependencies', []),
|
||||
link_with: kwargs.get('link_with', [])
|
||||
)
|
||||
test(name, t)
|
||||
endforeach
|
||||
10
tests/mesonTest/README.md
Normal file
10
tests/mesonTest/README.md
Normal file
@@ -0,0 +1,10 @@
|
||||
# CLI11 Meson test / example
|
||||
|
||||
Requirements: meson, ninja
|
||||
|
||||
## Build
|
||||
|
||||
```bash
|
||||
meson build
|
||||
ninja -C build
|
||||
```
|
||||
17
tests/mesonTest/main.cpp
Normal file
17
tests/mesonTest/main.cpp
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright (c) 2017-2021, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include <CLI/CLI.hpp>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
CLI::App app{"App description"};
|
||||
|
||||
std::string filename = "default";
|
||||
app.add_option("-f,--file", filename, "A help string");
|
||||
|
||||
CLI11_PARSE(app, argc, argv);
|
||||
return 0;
|
||||
}
|
||||
5
tests/mesonTest/meson.build
Normal file
5
tests/mesonTest/meson.build
Normal file
@@ -0,0 +1,5 @@
|
||||
project('mesonTest', ['c', 'cpp'], default_options: ['cpp_std=c++11'])
|
||||
|
||||
cli11_dep = subproject('CLI11').get_variable('CLI11_dep')
|
||||
|
||||
mainExe = executable('main', ['main.cpp'], dependencies: [cli11_dep])
|
||||
Reference in New Issue
Block a user