diff --git a/CHANGELOG.md b/CHANGELOG.md index bab4cbcfc..6fdff12d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,9 +18,11 @@ Other, non-user facing changes: * Informational printout now added to CTest [#95] * Better single file generation [#95] * Added support for GTest on MSVC 2017 (but not in C++17 mode, will need next version of GTest) +* Types now have a specific size, separate from the expected number - cleaner and more powerful internally [#92] [#64]: https://github.com/CLIUtils/CLI11/issues/64 [#90]: https://github.com/CLIUtils/CLI11/issues/90 +[#92]: https://github.com/CLIUtils/CLI11/issues/92 [#95]: https://github.com/CLIUtils/CLI11/pull/95 diff --git a/cmake/AddGoogletest.cmake b/cmake/AddGoogletest.cmake index 9801238d6..91e04659f 100644 --- a/cmake/AddGoogletest.cmake +++ b/cmake/AddGoogletest.cmake @@ -4,24 +4,39 @@ # gives output on failed tests without having to set an environment variable. # # -set(UPDATE_DISCONNECTED_IF_AVAILABLE "UPDATE_DISCONNECTED 1") +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) -include(DownloadProject) -download_project(PROJ googletest - GIT_REPOSITORY https://github.com/google/googletest.git - GIT_TAG release-1.8.0 - UPDATE_DISCONNECTED 1 - QUIET -) +if(CMAKE_VERSION VERSION_LESS 3.11) + set(UPDATE_DISCONNECTED_IF_AVAILABLE "UPDATE_DISCONNECTED 1") + include(DownloadProject) + download_project(PROJ googletest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG release-1.8.0 + UPDATE_DISCONNECTED 1 + QUIET + ) + + # CMake warning suppression will not be needed in version 1.9 + set(CMAKE_SUPPRESS_DEVELOPER_WARNINGS 1 CACHE BOOL "") + add_subdirectory(${googletest_SOURCE_DIR} ${googletest_SOURCE_DIR} EXCLUDE_FROM_ALL) + unset(CMAKE_SUPPRESS_DEVELOPER_WARNINGS) +else() + include(FetchContent) + FetchContent_Declare(googletest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG release-1.8.0) + FetchContent_GetProperties(googletest) + if(NOT googletest_POPULATED) + FetchContent_Populate(googletest) + set(CMAKE_SUPPRESS_DEVELOPER_WARNINGS 1 CACHE BOOL "") + add_subdirectory(${googletest_SOURCE_DIR} ${googletest_BINARY_DIR} EXCLUDE_FROM_ALL) + unset(CMAKE_SUPPRESS_DEVELOPER_WARNINGS) + endif() +endif() -set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) -# CMake warning suppression will not be needed in version 1.9 -set(CMAKE_SUPPRESS_DEVELOPER_WARNINGS 1 CACHE BOOL "") -add_subdirectory(${googletest_SOURCE_DIR} ${googletest_SOURCE_DIR} EXCLUDE_FROM_ALL) -unset(CMAKE_SUPPRESS_DEVELOPER_WARNINGS) -if (CMAKE_CONFIGURATION_TYPES) +if(CMAKE_CONFIGURATION_TYPES) add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} --force-new-ctest-process --output-on-failure --build-config "$") @@ -54,16 +69,17 @@ macro(add_gtest TESTNAME) gtest_add_tests(TARGET ${TESTNAME} TEST_PREFIX "${TESTNAME}." TEST_LIST TmpTestList) + set_tests_properties(${TmpTestList} PROPERTIES FOLDER "Tests") else() gtest_discover_tests(${TESTNAME} TEST_PREFIX "${TESTNAME}." - ) + PROPERTIES FOLDER "Tests") endif() else() add_test(${TESTNAME} ${TESTNAME}) + set_target_properties(${TESTNAME} PROPERTIES FOLDER "Tests") endif() - set_target_properties(${TESTNAME} PROPERTIES FOLDER "Tests") endmacro() diff --git a/include/CLI/App.hpp b/include/CLI/App.hpp index 237aeedcd..0c8907281 100644 --- a/include/CLI/App.hpp +++ b/include/CLI/App.hpp @@ -835,7 +835,7 @@ class App { std::string value; // Non-flags - if(opt->get_expected() != 0) { + if(opt->get_type_size() != 0) { // If the option was found on command line if(opt->count() > 0) @@ -1069,7 +1069,7 @@ class App { /// Currently checks to see if multiple positionals exist with -1 args void _validate() const { auto count = std::count_if(std::begin(options_), std::end(options_), [](const Option_p &opt) { - return opt->get_expected() == -1 && opt->get_positional(); + return opt->get_items_expected() < 0 && opt->get_positional(); }); if(count > 1) throw InvalidError(name_); @@ -1189,8 +1189,8 @@ class App { // Required or partially filled if(opt->get_required() || opt->count() != 0) { // Make sure enough -N arguments parsed (+N is already handled in parsing function) - if(opt->get_expected() < 0 && opt->count() < static_cast(-opt->get_expected())) - throw ArgumentMismatch::AtLeast(opt->single_name(), -opt->get_expected()); + if(opt->get_items_expected() < 0 && opt->count() < static_cast(-opt->get_items_expected())) + throw ArgumentMismatch::AtLeast(opt->single_name(), -opt->get_items_expected()); // Required but empty if(opt->get_required() && opt->count() == 0) @@ -1260,7 +1260,7 @@ class App { if(op->results_.empty()) { // Flag parsing - if(op->get_expected() == 0) { + if(op->get_type_size() == 0) { if(current.inputs.size() == 1) { std::string val = current.inputs.at(0); val = detail::to_lower(val); @@ -1320,9 +1320,9 @@ class App { size_t _count_remaining_positionals(bool required = false) const { size_t retval = 0; for(const Option_p &opt : options_) - if(opt->get_positional() && (!required || opt->get_required()) && opt->get_expected() > 0 && - static_cast(opt->count()) < opt->get_expected()) - retval = static_cast(opt->get_expected()) - opt->count(); + if(opt->get_positional() && (!required || opt->get_required()) && opt->get_items_expected() > 0 && + static_cast(opt->count()) < opt->get_items_expected()) + retval = static_cast(opt->get_items_expected()) - opt->count(); return retval; } @@ -1334,7 +1334,7 @@ class App { for(const Option_p &opt : options_) { // Eat options, one by one, until done if(opt->get_positional() && - (static_cast(opt->count()) < opt->get_expected() || opt->get_expected() < 0)) { + (static_cast(opt->count()) < opt->get_items_expected() || opt->get_items_expected() < 0)) { opt->add_result(positional); parse_order_.push_back(opt.get()); @@ -1421,7 +1421,7 @@ class App { // Get a reference to the pointer to make syntax bearable Option_p &op = *op_ptr; - int num = op->get_expected(); + int num = op->get_items_expected(); // Make sure we always eat the minimum for unlimited vectors int collected = 0; @@ -1459,7 +1459,7 @@ class App { // If there are any unlimited positionals, those also take priority if(std::any_of(std::begin(options_), std::end(options_), [](const Option_p &opt) { - return opt->get_positional() && opt->get_expected() < 0; + return opt->get_positional() && opt->get_items_expected() < 0; })) break; } diff --git a/include/CLI/Error.hpp b/include/CLI/Error.hpp index bd47806b0..09104a651 100644 --- a/include/CLI/Error.hpp +++ b/include/CLI/Error.hpp @@ -91,6 +91,9 @@ class IncorrectConstruction : public ConstructionError { static IncorrectConstruction Set0Opt(std::string name) { return IncorrectConstruction(name + ": Cannot set 0 expected, use a flag instead"); } + static IncorrectConstruction SetFlag(std::string name) { + return IncorrectConstruction(name + ": Cannot set an expected number for flags"); + } static IncorrectConstruction ChangeNotVector(std::string name) { return IncorrectConstruction(name + ": You can only change the expected arguments for vectors"); } @@ -102,7 +105,7 @@ class IncorrectConstruction : public ConstructionError { return IncorrectConstruction("Option " + name + " is not defined"); } static IncorrectConstruction MultiOptionPolicy(std::string name) { - return IncorrectConstruction(name + ": multi_option_policy only works for flags and single value options"); + return IncorrectConstruction(name + ": multi_option_policy only works for flags and exact value options"); } }; diff --git a/include/CLI/Option.hpp b/include/CLI/Option.hpp index 0cb1033d4..dd61dfd9d 100644 --- a/include/CLI/Option.hpp +++ b/include/CLI/Option.hpp @@ -180,11 +180,13 @@ class Option : public OptionBase