Commit b774c57dc2e632f3dc17f6653d8bedb09e3efa88
1 parent
67047b71
Adding help testing, option groups
Showing
5 changed files
with
108 additions
and
22 deletions
cmake/AddGoogletest.cmake
| @@ -14,16 +14,16 @@ download_project(PROJ googletest | @@ -14,16 +14,16 @@ download_project(PROJ googletest | ||
| 14 | ) | 14 | ) |
| 15 | 15 | ||
| 16 | 16 | ||
| 17 | -add_subdirectory(${googletest_SOURCE_DIR}/googletest ${googletest_SOURCE_DIR}) | ||
| 18 | - | ||
| 19 | -mark_as_advanced( | ||
| 20 | - gtest_build_samples | ||
| 21 | - gtest_build_tests | ||
| 22 | - gtest_disable_pthreads | ||
| 23 | - gtest_force_shared_crt | ||
| 24 | - gtest_hide_internal_symbols | ||
| 25 | - BUILD_SHARED_LIBS | ||
| 26 | -) | 17 | +add_subdirectory(${googletest_SOURCE_DIR} ${googletest_SOURCE_DIR}) |
| 18 | + | ||
| 19 | +#mark_as_advanced( | ||
| 20 | +# gtest_build_samples | ||
| 21 | +# gtest_build_tests | ||
| 22 | +# gtest_disable_pthreads | ||
| 23 | +# gtest_force_shared_crt | ||
| 24 | +# gtest_hide_internal_symbols | ||
| 25 | +# BUILD_SHARED_LIBS | ||
| 26 | +#) | ||
| 27 | 27 | ||
| 28 | if (CMAKE_CONFIGURATION_TYPES) | 28 | if (CMAKE_CONFIGURATION_TYPES) |
| 29 | add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} | 29 | add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} |
| @@ -34,14 +34,14 @@ else() | @@ -34,14 +34,14 @@ else() | ||
| 34 | --force-new-ctest-process --output-on-failure) | 34 | --force-new-ctest-process --output-on-failure) |
| 35 | endif() | 35 | endif() |
| 36 | 36 | ||
| 37 | -include_directories(${gtest_SOURCE_DIR}/include) | 37 | +#include_directories(${gtest_SOURCE_DIR}/include) |
| 38 | 38 | ||
| 39 | # More modern way to do the last line, less messy but needs newish CMake: | 39 | # More modern way to do the last line, less messy but needs newish CMake: |
| 40 | # target_include_directories(gtest INTERFACE ${gtest_SOURCE_DIR}/include) | 40 | # target_include_directories(gtest INTERFACE ${gtest_SOURCE_DIR}/include) |
| 41 | 41 | ||
| 42 | # Target must already exist | 42 | # Target must already exist |
| 43 | macro(add_gtest TESTNAME) | 43 | macro(add_gtest TESTNAME) |
| 44 | - target_link_libraries(${TESTNAME} PUBLIC gtest gtest_main) | 44 | + target_link_libraries(${TESTNAME} PUBLIC gtest gmock gtest_main) |
| 45 | add_test(${TESTNAME} ${TESTNAME}) | 45 | add_test(${TESTNAME} ${TESTNAME}) |
| 46 | endmacro() | 46 | endmacro() |
| 47 | 47 |
include/CLI/App.hpp
| @@ -559,15 +559,16 @@ public: | @@ -559,15 +559,16 @@ public: | ||
| 559 | 559 | ||
| 560 | // Check for options | 560 | // Check for options |
| 561 | bool npos = false; | 561 | bool npos = false; |
| 562 | + std::set<std::string> groups; | ||
| 562 | for(const Option_p &opt : options) { | 563 | for(const Option_p &opt : options) { |
| 563 | if(opt->nonpositional()) { | 564 | if(opt->nonpositional()) { |
| 564 | npos = true; | 565 | npos = true; |
| 565 | - break; | 566 | + groups.insert(opt->get_group()); |
| 566 | } | 567 | } |
| 567 | } | 568 | } |
| 568 | 569 | ||
| 569 | if(npos) | 570 | if(npos) |
| 570 | - out << " [OPTIONS...]"; | 571 | + out << " [OPTIONS]"; |
| 571 | 572 | ||
| 572 | // Positionals | 573 | // Positionals |
| 573 | bool pos=false; | 574 | bool pos=false; |
| @@ -593,13 +594,15 @@ public: | @@ -593,13 +594,15 @@ public: | ||
| 593 | 594 | ||
| 594 | // Options | 595 | // Options |
| 595 | if(npos) { | 596 | if(npos) { |
| 596 | - out << "Options:" << std::endl; | ||
| 597 | - for(const Option_p &opt : options) { | ||
| 598 | - if(opt->nonpositional()) | ||
| 599 | - detail::format_help(out, opt->help_name(), opt->get_description(), wid); | ||
| 600 | - | 597 | + for (const std::string& group : groups) { |
| 598 | + out << group << ":" << std::endl; | ||
| 599 | + for(const Option_p &opt : options) { | ||
| 600 | + if(opt->nonpositional() && opt->get_group() == group) | ||
| 601 | + detail::format_help(out, opt->help_name(), opt->get_description(), wid); | ||
| 602 | + | ||
| 603 | + } | ||
| 604 | + out << std::endl; | ||
| 601 | } | 605 | } |
| 602 | - out << std::endl; | ||
| 603 | } | 606 | } |
| 604 | 607 | ||
| 605 | // Subcommands | 608 | // Subcommands |
include/CLI/Option.hpp
| @@ -34,7 +34,7 @@ protected: | @@ -34,7 +34,7 @@ protected: | ||
| 34 | // These are for help strings | 34 | // These are for help strings |
| 35 | std::string defaultval; | 35 | std::string defaultval; |
| 36 | std::string typeval; | 36 | std::string typeval; |
| 37 | - | 37 | + std::string _group {"Options"}; |
| 38 | 38 | ||
| 39 | bool _default {false}; | 39 | bool _default {false}; |
| 40 | bool _required {false}; | 40 | bool _required {false}; |
| @@ -115,6 +115,15 @@ public: | @@ -115,6 +115,15 @@ public: | ||
| 115 | return this; | 115 | return this; |
| 116 | } | 116 | } |
| 117 | 117 | ||
| 118 | + Option* group(std::string name) { | ||
| 119 | + _group = name; | ||
| 120 | + return this; | ||
| 121 | + } | ||
| 122 | + | ||
| 123 | + const std::string& get_group() const { | ||
| 124 | + return _group; | ||
| 125 | + } | ||
| 126 | + | ||
| 118 | /// Get the description | 127 | /// Get the description |
| 119 | const std::string& get_description() const { | 128 | const std::string& get_description() const { |
| 120 | return description; | 129 | return description; |
tests/CMakeLists.txt
tests/HelpTest.cpp
0 → 100644
| 1 | +#ifdef CLI_SINGLE_FILE | ||
| 2 | +#include "CLI11.hpp" | ||
| 3 | +#else | ||
| 4 | +#include "CLI/CLI.hpp" | ||
| 5 | +#endif | ||
| 6 | + | ||
| 7 | +#include "gtest/gtest.h" | ||
| 8 | +#include "gmock/gmock.h" | ||
| 9 | +#include <fstream> | ||
| 10 | + | ||
| 11 | +using ::testing::HasSubstr; | ||
| 12 | + | ||
| 13 | +TEST(THelp, Basic) { | ||
| 14 | + CLI::App app{"My prog"}; | ||
| 15 | + | ||
| 16 | + std::string help = app.help(); | ||
| 17 | + | ||
| 18 | + EXPECT_THAT(help, HasSubstr("My prog")); | ||
| 19 | + EXPECT_THAT(help, HasSubstr("-h,--help")); | ||
| 20 | + EXPECT_THAT(help, HasSubstr("Options:")); | ||
| 21 | + EXPECT_THAT(help, HasSubstr("Usage:")); | ||
| 22 | + | ||
| 23 | +} | ||
| 24 | + | ||
| 25 | +TEST(THelp, OptionalPositional) { | ||
| 26 | + CLI::App app{"My prog"}; | ||
| 27 | + | ||
| 28 | + std::string x; | ||
| 29 | + app.add_option("something", x, "My option here"); | ||
| 30 | + | ||
| 31 | + std::string help = app.help(); | ||
| 32 | + | ||
| 33 | + EXPECT_THAT(help, HasSubstr("My prog")); | ||
| 34 | + EXPECT_THAT(help, HasSubstr("-h,--help")); | ||
| 35 | + EXPECT_THAT(help, HasSubstr("Options:")); | ||
| 36 | + EXPECT_THAT(help, HasSubstr("Positionals:")); | ||
| 37 | + EXPECT_THAT(help, HasSubstr("something STRING")); | ||
| 38 | + EXPECT_THAT(help, HasSubstr("My option here")); | ||
| 39 | + EXPECT_THAT(help, HasSubstr("Usage: program [OPTIONS] [something]")); | ||
| 40 | + | ||
| 41 | +} | ||
| 42 | +TEST(THelp, OptionalPositionalAndOptions) { | ||
| 43 | + CLI::App app{"My prog"}; | ||
| 44 | + app.add_flag("-q,--quick"); | ||
| 45 | + | ||
| 46 | + std::string x; | ||
| 47 | + app.add_option("something", x, "My option here"); | ||
| 48 | + | ||
| 49 | + std::string help = app.help(); | ||
| 50 | + | ||
| 51 | + EXPECT_THAT(help, HasSubstr("My prog")); | ||
| 52 | + EXPECT_THAT(help, HasSubstr("-h,--help")); | ||
| 53 | + EXPECT_THAT(help, HasSubstr("Options:")); | ||
| 54 | + EXPECT_THAT(help, HasSubstr("Usage: program [OPTIONS] [something]")); | ||
| 55 | + | ||
| 56 | +} | ||
| 57 | + | ||
| 58 | +TEST(THelp, RequiredPositionalAndOptions) { | ||
| 59 | + CLI::App app{"My prog"}; | ||
| 60 | + app.add_flag("-q,--quick"); | ||
| 61 | + | ||
| 62 | + std::string x; | ||
| 63 | + app.add_option("something", x, "My option here") | ||
| 64 | + ->required(); | ||
| 65 | + | ||
| 66 | + std::string help = app.help(); | ||
| 67 | + | ||
| 68 | + EXPECT_THAT(help, HasSubstr("My prog")); | ||
| 69 | + EXPECT_THAT(help, HasSubstr("-h,--help")); | ||
| 70 | + EXPECT_THAT(help, HasSubstr("Options:")); | ||
| 71 | + EXPECT_THAT(help, HasSubstr("Positionals:")); | ||
| 72 | + EXPECT_THAT(help, HasSubstr("Usage: program [OPTIONS] something")); | ||
| 73 | + | ||
| 74 | +} |