From b774c57dc2e632f3dc17f6653d8bedb09e3efa88 Mon Sep 17 00:00:00 2001 From: Henry Fredrick Schreiner Date: Sat, 11 Feb 2017 09:38:35 -0500 Subject: [PATCH] Adding help testing, option groups --- cmake/AddGoogletest.cmake | 24 ++++++++++++------------ include/CLI/App.hpp | 19 +++++++++++-------- include/CLI/Option.hpp | 11 ++++++++++- tests/CMakeLists.txt | 2 +- tests/HelpTest.cpp | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 108 insertions(+), 22 deletions(-) create mode 100644 tests/HelpTest.cpp diff --git a/cmake/AddGoogletest.cmake b/cmake/AddGoogletest.cmake index dc41f3b..ff7900f 100644 --- a/cmake/AddGoogletest.cmake +++ b/cmake/AddGoogletest.cmake @@ -14,16 +14,16 @@ download_project(PROJ googletest ) -add_subdirectory(${googletest_SOURCE_DIR}/googletest ${googletest_SOURCE_DIR}) - -mark_as_advanced( - gtest_build_samples - gtest_build_tests - gtest_disable_pthreads - gtest_force_shared_crt - gtest_hide_internal_symbols - BUILD_SHARED_LIBS -) +add_subdirectory(${googletest_SOURCE_DIR} ${googletest_SOURCE_DIR}) + +#mark_as_advanced( +# gtest_build_samples +# gtest_build_tests +# gtest_disable_pthreads +# gtest_force_shared_crt +# gtest_hide_internal_symbols +# BUILD_SHARED_LIBS +#) if (CMAKE_CONFIGURATION_TYPES) add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} @@ -34,14 +34,14 @@ else() --force-new-ctest-process --output-on-failure) endif() -include_directories(${gtest_SOURCE_DIR}/include) +#include_directories(${gtest_SOURCE_DIR}/include) # More modern way to do the last line, less messy but needs newish CMake: # target_include_directories(gtest INTERFACE ${gtest_SOURCE_DIR}/include) # Target must already exist macro(add_gtest TESTNAME) - target_link_libraries(${TESTNAME} PUBLIC gtest gtest_main) + target_link_libraries(${TESTNAME} PUBLIC gtest gmock gtest_main) add_test(${TESTNAME} ${TESTNAME}) endmacro() diff --git a/include/CLI/App.hpp b/include/CLI/App.hpp index d568351..d4a5b90 100644 --- a/include/CLI/App.hpp +++ b/include/CLI/App.hpp @@ -559,15 +559,16 @@ public: // Check for options bool npos = false; + std::set groups; for(const Option_p &opt : options) { if(opt->nonpositional()) { npos = true; - break; + groups.insert(opt->get_group()); } } if(npos) - out << " [OPTIONS...]"; + out << " [OPTIONS]"; // Positionals bool pos=false; @@ -593,13 +594,15 @@ public: // Options if(npos) { - out << "Options:" << std::endl; - for(const Option_p &opt : options) { - if(opt->nonpositional()) - detail::format_help(out, opt->help_name(), opt->get_description(), wid); - + for (const std::string& group : groups) { + out << group << ":" << std::endl; + for(const Option_p &opt : options) { + if(opt->nonpositional() && opt->get_group() == group) + detail::format_help(out, opt->help_name(), opt->get_description(), wid); + + } + out << std::endl; } - out << std::endl; } // Subcommands diff --git a/include/CLI/Option.hpp b/include/CLI/Option.hpp index c5093b6..a47540e 100644 --- a/include/CLI/Option.hpp +++ b/include/CLI/Option.hpp @@ -34,7 +34,7 @@ protected: // These are for help strings std::string defaultval; std::string typeval; - + std::string _group {"Options"}; bool _default {false}; bool _required {false}; @@ -115,6 +115,15 @@ public: return this; } + Option* group(std::string name) { + _group = name; + return this; + } + + const std::string& get_group() const { + return _group; + } + /// Get the description const std::string& get_description() const { return description; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 0670a1d..43e0c21 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,6 +1,6 @@ include(AddGoogletest) -set(CLI_TESTS SmallTest IniTest CLITest) +set(CLI_TESTS SmallTest IniTest CLITest HelpTest) foreach(T ${CLI_TESTS}) diff --git a/tests/HelpTest.cpp b/tests/HelpTest.cpp new file mode 100644 index 0000000..7257b46 --- /dev/null +++ b/tests/HelpTest.cpp @@ -0,0 +1,74 @@ +#ifdef CLI_SINGLE_FILE +#include "CLI11.hpp" +#else +#include "CLI/CLI.hpp" +#endif + +#include "gtest/gtest.h" +#include "gmock/gmock.h" +#include + +using ::testing::HasSubstr; + +TEST(THelp, Basic) { + CLI::App app{"My prog"}; + + std::string help = app.help(); + + EXPECT_THAT(help, HasSubstr("My prog")); + EXPECT_THAT(help, HasSubstr("-h,--help")); + EXPECT_THAT(help, HasSubstr("Options:")); + EXPECT_THAT(help, HasSubstr("Usage:")); + +} + +TEST(THelp, OptionalPositional) { + CLI::App app{"My prog"}; + + std::string x; + app.add_option("something", x, "My option here"); + + std::string help = app.help(); + + EXPECT_THAT(help, HasSubstr("My prog")); + EXPECT_THAT(help, HasSubstr("-h,--help")); + EXPECT_THAT(help, HasSubstr("Options:")); + EXPECT_THAT(help, HasSubstr("Positionals:")); + EXPECT_THAT(help, HasSubstr("something STRING")); + EXPECT_THAT(help, HasSubstr("My option here")); + EXPECT_THAT(help, HasSubstr("Usage: program [OPTIONS] [something]")); + +} +TEST(THelp, OptionalPositionalAndOptions) { + CLI::App app{"My prog"}; + app.add_flag("-q,--quick"); + + std::string x; + app.add_option("something", x, "My option here"); + + std::string help = app.help(); + + EXPECT_THAT(help, HasSubstr("My prog")); + EXPECT_THAT(help, HasSubstr("-h,--help")); + EXPECT_THAT(help, HasSubstr("Options:")); + EXPECT_THAT(help, HasSubstr("Usage: program [OPTIONS] [something]")); + +} + +TEST(THelp, RequiredPositionalAndOptions) { + CLI::App app{"My prog"}; + app.add_flag("-q,--quick"); + + std::string x; + app.add_option("something", x, "My option here") + ->required(); + + std::string help = app.help(); + + EXPECT_THAT(help, HasSubstr("My prog")); + EXPECT_THAT(help, HasSubstr("-h,--help")); + EXPECT_THAT(help, HasSubstr("Options:")); + EXPECT_THAT(help, HasSubstr("Positionals:")); + EXPECT_THAT(help, HasSubstr("Usage: program [OPTIONS] something")); + +} -- libgit2 0.21.4