From 35aa92d71a9de52f559df5805ec321a8cf59cd6a Mon Sep 17 00:00:00 2001 From: Philip Top Date: Mon, 8 Jan 2024 05:40:26 -0800 Subject: [PATCH] update supported cmake versions and add some tests with newer compilers (#972) Update and test with some newer compilers and cmake versions --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .ci/azure-cmake-new.yml | 17 + .clang-tidy | 3 + .github/workflows/tests.yml | 12 +- CMakeLists.txt | 8 +- azure-pipelines.yml | 25 ++ book/chapters/options.md | 2 +- examples/arg_capture.cpp | 4 +- examples/config_app.cpp | 6 +- examples/custom_parse.cpp | 2 +- examples/digit_args.cpp | 2 +- examples/enum.cpp | 2 +- examples/enum_ostream.cpp | 2 +- examples/formatter.cpp | 2 +- examples/groups.cpp | 6 +- examples/inter_argument_order.cpp | 2 +- examples/modhelp.cpp | 4 +- examples/option_groups.cpp | 8 +- examples/prefix_command.cpp | 4 +- examples/shapes.cpp | 6 +- examples/simple.cpp | 6 +- examples/subcom_help.cpp | 2 +- examples/subcom_in_files/subcommand_a.cpp | 4 +- examples/subcom_partitioned.cpp | 6 +- examples/subcommands.cpp | 9 +- examples/testEXE.cpp | 4 +- examples/validators.cpp | 2 +- include/CLI/Timer.hpp | 2 +- include/CLI/TypeTools.hpp | 4 +- include/CLI/impl/App_inl.hpp | 2 +- include/CLI/impl/Config_inl.hpp | 16 +- include/CLI/impl/Formatter_inl.hpp | 2 +- include/CLI/impl/Option_inl.hpp | 6 +- tests/ConfigFileTest.cpp | 520 +++++++++++----------- tests/FuzzFailTest.cpp | 5 +- tests/HelpersTest.cpp | 6 +- tests/OptionalTest.cpp | 47 +- tests/StringParseTest.cpp | 6 +- tests/TimerTest.cpp | 2 +- tests/fuzzFail/fuzz_file_fail7 | 1 + tests/fuzzFail/fuzz_file_fail8 | 1 + tests/informational.cpp | 2 +- 41 files changed, 416 insertions(+), 356 deletions(-) create mode 100644 .ci/azure-cmake-new.yml create mode 100644 tests/fuzzFail/fuzz_file_fail7 create mode 100644 tests/fuzzFail/fuzz_file_fail8 diff --git a/.ci/azure-cmake-new.yml b/.ci/azure-cmake-new.yml new file mode 100644 index 00000000..56a2fb4d --- /dev/null +++ b/.ci/azure-cmake-new.yml @@ -0,0 +1,17 @@ +steps: + # Note that silkeh/clang does not include ca-certificates, so check the shasum for verification + - bash: | + wget --no-check-certificate "https://cmake.org/files/v3.28/cmake-3.28.0-linux-x86_64.tar.gz" + echo "898f0b5ca6e2ea5286998e97bd33f030d7d09f18ca4b88be661fdfbad5dadd88 cmake-3.28.0-linux-x86_64.tar.gz" | shasum -sca 256 + displayName: Download CMake + + - task: ExtractFiles@1 + inputs: + archiveFilePatterns: "cmake*.tar.gz" + destinationFolder: "cmake_program" + displayName: Extract CMake + + - bash: + echo + "##vso[task.prependpath]$(Build.SourcesDirectory)/cmake_program/cmake-3.28.0-linux-x86_64/bin" + displayName: Add CMake to PATH diff --git a/.clang-tidy b/.clang-tidy index 82450d1b..727b7652 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -6,6 +6,7 @@ # modernize-avoid-c-arrays trips up in TEMPLATE_TEST_CASE catch macro # modernize-return-braced-init-list triggers on lambdas ? # modernize-make-unique requires C++14 +# modernize-type_traits requires C++17 # readability-avoid-const-params-in-decls Affected by the pre-compile split Checks: | @@ -37,6 +38,8 @@ Checks: | -modernize-concat-nested-namespaces, -modernize-return-braced-init-list, -modernize-make-unique, + -modernize-type-traits, + -modernize-macro-to-enum, *performance*, -performance-unnecessary-value-param, -performance-inefficient-string-concatenation, diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 19f99f4e..2482cdb2 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -60,7 +60,7 @@ jobs: clang-tidy: name: Clang-Tidy runs-on: ubuntu-latest - container: silkeh/clang:14 + container: silkeh/clang:17 steps: - uses: actions/checkout@v4 @@ -91,7 +91,7 @@ jobs: cuda12-build: name: CUDA 12 build only runs-on: ubuntu-latest - container: nvidia/cuda:12.1.0-devel-ubuntu22.04 + container: nvidia/cuda:12.3.1-devel-ubuntu22.04 steps: - name: Add build tools run: apt-get update && apt-get install -y wget git cmake @@ -336,9 +336,15 @@ jobs: args: -DCLI11_SANITIZERS=ON -DCLI11_BUILD_EXAMPLES_JSON=ON if: success() || failure() - - name: Check CMake 3.27 (full) + - name: Check CMake 3.27 uses: ./.github/actions/quick_cmake with: cmake-version: "3.27" + if: success() || failure() + + - name: Check CMake 3.28 (full) + uses: ./.github/actions/quick_cmake + with: + cmake-version: "3.28" args: -DCLI11_SANITIZERS=ON -DCLI11_BUILD_EXAMPLES_JSON=ON if: success() || failure() diff --git a/CMakeLists.txt b/CMakeLists.txt index 92fdc444..512553f8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,14 +2,14 @@ cmake_minimum_required(VERSION 3.5) # Note: this is a header only library. If you have an older CMake than 3.5, # just add the CLI11/include directory and that's all you need to do. -# Make sure users don't get warnings on a tested (3.5 to 3.26) version +# Make sure users don't get warnings on a tested (3.5 to 3.28) version # of CMake. For most of the policies, the new version is better (hence the change). -# We don't use the 3.5...3.26 syntax because of a bug in an older MSVC's +# We don't use the 3.5...3.28 syntax because of a bug in an older MSVC's # built-in and modified CMake 3.11 -if(${CMAKE_VERSION} VERSION_LESS 3.26) +if(${CMAKE_VERSION} VERSION_LESS 3.28) cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) else() - cmake_policy(VERSION 3.26) + cmake_policy(VERSION 3.28) endif() set(VERSION_REGEX "#define CLI11_VERSION[ \t]+\"(.+)\"") diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 7206be09..647c7982 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -150,3 +150,28 @@ jobs: - template: .ci/azure-cmake.yml - template: .ci/azure-build.yml - template: .ci/azure-test.yml + + - job: Docker_new + variables: + cli11.single: OFF + pool: + vmImage: "ubuntu-latest" + strategy: + matrix: + gcc13: + containerImage: gcc:13 + cli11.std: 17 + cli11.options: -DCMAKE_CXX_FLAGS="-Wstrict-overflow=5" + gcc12: + containerImage: gcc:12 + cli11.std: 20 + cli11.options: -DCMAKE_CXX_FLAGS="-Wredundant-decls -Wconversion" + clang17_20: + containerImage: silkeh/clang:17 + cli11.std: 23 + cli11.options: -DCMAKE_CXX_FLAGS=-std=c++23 + container: $[ variables['containerImage'] ] + steps: + - template: .ci/azure-cmake-new.yml + - template: .ci/azure-build.yml + - template: .ci/azure-test.yml diff --git a/book/chapters/options.md b/book/chapters/options.md index 8cfec13e..67fb9e55 100644 --- a/book/chapters/options.md +++ b/book/chapters/options.md @@ -283,7 +283,7 @@ CLI::Option* opt = app.add_flag("--opt"); CLI11_PARSE(app, argv, argc); if(* opt) - std::cout << "Flag received " << opt->count() << " times." << std::endl; + std::cout << "Flag received " << opt->count() << " times." << '\n'; ``` ## Inheritance of defaults diff --git a/examples/arg_capture.cpp b/examples/arg_capture.cpp index a7097754..bdf3afeb 100644 --- a/examples/arg_capture.cpp +++ b/examples/arg_capture.cpp @@ -25,10 +25,10 @@ int main(int argc, const char *argv[]) { subcom->alias("--sub"); CLI11_PARSE(app, argc, argv); - std::cout << "value=" << value << std::endl; + std::cout << "value=" << value << '\n'; std::cout << "after Args:"; for(const auto &aarg : subcom->remaining()) { std::cout << aarg << " "; } - std::cout << std::endl; + std::cout << '\n'; } diff --git a/examples/config_app.cpp b/examples/config_app.cpp index 08731ee8..ccd98242 100644 --- a/examples/config_app.cpp +++ b/examples/config_app.cpp @@ -40,11 +40,11 @@ int main(int argc, char **argv) { } std::cout << "Working on file: " << file << ", direct count: " << app.count("--file") - << ", opt count: " << opt->count() << std::endl; + << ", opt count: " << opt->count() << '\n'; std::cout << "Working on count: " << count << ", direct count: " << app.count("--count") - << ", opt count: " << copt->count() << std::endl; + << ", opt count: " << copt->count() << '\n'; std::cout << "Received flag: " << v << " (" << flag->count() << ") times\n"; - std::cout << "Some value: " << value << std::endl; + std::cout << "Some value: " << value << '\n'; return 0; } diff --git a/examples/custom_parse.cpp b/examples/custom_parse.cpp index 74df7e61..2f9c2a08 100644 --- a/examples/custom_parse.cpp +++ b/examples/custom_parse.cpp @@ -23,7 +23,7 @@ using DoubleValues = Values; // the lexical cast operator should be in the same namespace as the type for ADL to work properly bool lexical_cast(const std::string &input, Values & /*v*/) { - std::cout << "called correct lexical_cast function ! val: " << input << std::endl; + std::cout << "called correct lexical_cast function ! val: " << input << '\n'; return true; } diff --git a/examples/digit_args.cpp b/examples/digit_args.cpp index d73ece48..2144f22d 100644 --- a/examples/digit_args.cpp +++ b/examples/digit_args.cpp @@ -16,6 +16,6 @@ int main(int argc, char **argv) { CLI11_PARSE(app, argc, argv); - std::cout << "value = " << val << std::endl; + std::cout << "value = " << val << '\n'; return 0; } diff --git a/examples/enum.cpp b/examples/enum.cpp index ab7e385e..863eda4d 100644 --- a/examples/enum.cpp +++ b/examples/enum.cpp @@ -27,7 +27,7 @@ int main(int argc, char **argv) { // CLI11's built in enum streaming can be used outside CLI11 like this: using CLI::enums::operator<<; - std::cout << "Enum received: " << level << std::endl; + std::cout << "Enum received: " << level << '\n'; return 0; } diff --git a/examples/enum_ostream.cpp b/examples/enum_ostream.cpp index 90642614..939a3fa7 100644 --- a/examples/enum_ostream.cpp +++ b/examples/enum_ostream.cpp @@ -44,7 +44,7 @@ int main(int argc, char **argv) { // CLI11's built in enum streaming can be used outside CLI11 like this: using CLI::enums::operator<<; - std::cout << "Enum received: " << level << std::endl; + std::cout << "Enum received: " << level << '\n'; return 0; } diff --git a/examples/formatter.cpp b/examples/formatter.cpp index 8f4f70d7..b9afb1f9 100644 --- a/examples/formatter.cpp +++ b/examples/formatter.cpp @@ -31,7 +31,7 @@ int main(int argc, char **argv) { CLI11_PARSE(app, argc, argv); - std::cout << "This app was meant to show off the formatter, run with -h" << std::endl; + std::cout << "This app was meant to show off the formatter, run with -h" << '\n'; return 0; } diff --git a/examples/groups.cpp b/examples/groups.cpp index 0048e12a..8084f751 100644 --- a/examples/groups.cpp +++ b/examples/groups.cpp @@ -30,10 +30,10 @@ int main(int argc, char **argv) { } std::cout << "Working on file: " << file << ", direct count: " << app.count("--file") - << ", opt count: " << opt->count() << std::endl; + << ", opt count: " << opt->count() << '\n'; std::cout << "Working on count: " << count << ", direct count: " << app.count("--count") - << ", opt count: " << copt->count() << std::endl; - std::cout << "Some value: " << value << std::endl; + << ", opt count: " << copt->count() << '\n'; + std::cout << "Some value: " << value << '\n'; return 0; } diff --git a/examples/inter_argument_order.cpp b/examples/inter_argument_order.cpp index 4b9c010e..d0a8ba55 100644 --- a/examples/inter_argument_order.cpp +++ b/examples/inter_argument_order.cpp @@ -46,6 +46,6 @@ int main(int argc, char **argv) { // Prove the vector is correct for(auto &pair : keyval) { - std::cout << pair.first << " : " << pair.second << std::endl; + std::cout << pair.first << " : " << pair.second << '\n'; } } diff --git a/examples/modhelp.cpp b/examples/modhelp.cpp index d2856c8f..472e3024 100644 --- a/examples/modhelp.cpp +++ b/examples/modhelp.cpp @@ -26,10 +26,10 @@ Note that this will not shortcut `->required` and other similar options.)raw"}; if(*help) throw CLI::CallForHelp(); } catch(const CLI::Error &e) { - std::cout << "Option -a string in help: " << some_option << std::endl; + std::cout << "Option -a string in help: " << some_option << '\n'; return test.exit(e); } - std::cout << "Option -a string: " << some_option << std::endl; + std::cout << "Option -a string: " << some_option << '\n'; return 0; } diff --git a/examples/option_groups.cpp b/examples/option_groups.cpp index 7a66b404..f95671a1 100644 --- a/examples/option_groups.cpp +++ b/examples/option_groups.cpp @@ -33,13 +33,13 @@ int main(int argc, char **argv) { CLI11_PARSE(app, argc, argv); std::string format_type = (csv) ? std::string("CSV") : ((human) ? "human readable" : "binary"); - std::cout << "Selected " << format_type << " format" << std::endl; + std::cout << "Selected " << format_type << " format\n"; if(!fileLoc.empty()) { - std::cout << " sent to file " << fileLoc << std::endl; + std::cout << " sent to file " << fileLoc << '\n'; } else if(!networkAddress.empty()) { - std::cout << " sent over network to " << networkAddress << std::endl; + std::cout << " sent over network to " << networkAddress << '\n'; } else { - std::cout << " sent to std::cout" << std::endl; + std::cout << " sent to std::cout\n"; } return 0; diff --git a/examples/prefix_command.cpp b/examples/prefix_command.cpp index e6d121e2..f681a046 100644 --- a/examples/prefix_command.cpp +++ b/examples/prefix_command.cpp @@ -25,11 +25,11 @@ int main(int argc, char **argv) { for(int v : vals) std::cout << ": " << v << " "; - std::cout << std::endl << "Remaining commands: "; + std::cout << '\n' << "Remaining commands: "; for(const auto &com : more_comms) std::cout << com << " "; - std::cout << std::endl; + std::cout << '\n'; return 0; } diff --git a/examples/shapes.cpp b/examples/shapes.cpp index 76b6a2c3..39ea5792 100644 --- a/examples/shapes.cpp +++ b/examples/shapes.cpp @@ -18,7 +18,7 @@ int main(int argc, char **argv) { int circle_counter{0}; circle->callback([&radius, &circle_counter] { ++circle_counter; - std::cout << "circle" << circle_counter << " with radius " << radius << std::endl; + std::cout << "circle" << circle_counter << " with radius " << radius << '\n'; }); circle->add_option("radius", radius, "the radius of the circle")->required(); @@ -32,7 +32,7 @@ int main(int argc, char **argv) { if(edge2 == 0) { edge2 = edge1; } - std::cout << "rectangle" << rect_counter << " with edges [" << edge1 << ',' << edge2 << "]" << std::endl; + std::cout << "rectangle" << rect_counter << " with edges [" << edge1 << ',' << edge2 << "]\n"; edge2 = 0; }); @@ -45,7 +45,7 @@ int main(int argc, char **argv) { tri->callback([&sides, &tri_counter] { ++tri_counter; - std::cout << "triangle" << tri_counter << " with sides [" << CLI::detail::join(sides) << "]" << std::endl; + std::cout << "triangle" << tri_counter << " with sides [" << CLI::detail::join(sides) << "]\n"; }); tri->add_option("sides", sides, "the side lengths of the triangle"); diff --git a/examples/simple.cpp b/examples/simple.cpp index 78931705..c33037d2 100644 --- a/examples/simple.cpp +++ b/examples/simple.cpp @@ -28,11 +28,11 @@ int main(int argc, char **argv) { CLI11_PARSE(app, argc, argv); std::cout << "Working on file: " << file << ", direct count: " << app.count("--file") - << ", opt count: " << opt->count() << std::endl; + << ", opt count: " << opt->count() << '\n'; std::cout << "Working on count: " << count << ", direct count: " << app.count("--count") - << ", opt count: " << copt->count() << std::endl; + << ", opt count: " << copt->count() << '\n'; std::cout << "Received flag: " << v << " (" << flag->count() << ") times\n"; - std::cout << "Some value: " << value << std::endl; + std::cout << "Some value: " << value << '\n'; return 0; } diff --git a/examples/subcom_help.cpp b/examples/subcom_help.cpp index e2e6f7a9..d7cfadaa 100644 --- a/examples/subcom_help.cpp +++ b/examples/subcom_help.cpp @@ -15,7 +15,7 @@ int main(int argc, char *argv[]) { cli_sub.add_option("sub_arg", sub_arg, "Argument for subcommand")->required(); CLI11_PARSE(cli_global, argc, argv); if(cli_sub) { - std::cout << "Got: " << sub_arg << std::endl; + std::cout << "Got: " << sub_arg << '\n'; } return 0; } diff --git a/examples/subcom_in_files/subcommand_a.cpp b/examples/subcom_in_files/subcommand_a.cpp index f28e50b3..19d30914 100644 --- a/examples/subcom_in_files/subcommand_a.cpp +++ b/examples/subcom_in_files/subcommand_a.cpp @@ -30,8 +30,8 @@ void setup_subcommand_a(CLI::App &app) { /// but having a separate function is cleaner. void run_subcommand_a(SubcommandAOptions const &opt) { // Do stuff... - std::cout << "Working on file: " << opt.file << std::endl; + std::cout << "Working on file: " << opt.file << '\n'; if(opt.with_foo) { - std::cout << "Using foo!" << std::endl; + std::cout << "Using foo!" << '\n'; } } diff --git a/examples/subcom_partitioned.cpp b/examples/subcom_partitioned.cpp index 19ed561c..a46eea1c 100644 --- a/examples/subcom_partitioned.cpp +++ b/examples/subcom_partitioned.cpp @@ -37,10 +37,10 @@ int main(int argc, char **argv) { } std::cout << "Working on file: " << file << ", direct count: " << impOpt->count("--file") - << ", opt count: " << opt->count() << std::endl; + << ", opt count: " << opt->count() << '\n'; std::cout << "Working on count: " << count << ", direct count: " << impOpt->count("--count") - << ", opt count: " << copt->count() << std::endl; - std::cout << "Some value: " << value << std::endl; + << ", opt count: " << copt->count() << '\n'; + std::cout << "Some value: " << value << '\n'; return 0; } diff --git a/examples/subcommands.cpp b/examples/subcommands.cpp index 5cec0c61..fe93edc2 100644 --- a/examples/subcommands.cpp +++ b/examples/subcommands.cpp @@ -24,12 +24,11 @@ int main(int argc, char **argv) { CLI11_PARSE(app, argc, argv); - std::cout << "Working on --file from start: " << file << std::endl; - std::cout << "Working on --count from stop: " << s->count() << ", direct count: " << stop->count("--count") - << std::endl; - std::cout << "Count of --random flag: " << app.count("--random") << std::endl; + std::cout << "Working on --file from start: " << file << '\n'; + std::cout << "Working on --count from stop: " << s->count() << ", direct count: " << stop->count("--count") << '\n'; + std::cout << "Count of --random flag: " << app.count("--random") << '\n'; for(auto *subcom : app.get_subcommands()) - std::cout << "Subcommand: " << subcom->get_name() << std::endl; + std::cout << "Subcommand: " << subcom->get_name() << '\n'; return 0; } diff --git a/examples/testEXE.cpp b/examples/testEXE.cpp index 922ab09a..b42c60f2 100644 --- a/examples/testEXE.cpp +++ b/examples/testEXE.cpp @@ -19,10 +19,10 @@ int main(int argc, const char *argv[]) { auto *subcom = app.add_subcommand("sub", "")->prefix_command(); CLI11_PARSE(app, argc, argv); - std::cout << "value =" << value << std::endl; + std::cout << "value =" << value << '\n'; std::cout << "after Args:"; for(const auto &aarg : subcom->remaining()) { std::cout << aarg << " "; } - std::cout << std::endl; + std::cout << '\n'; } diff --git a/examples/validators.cpp b/examples/validators.cpp index 0f60dbd7..44ff1554 100644 --- a/examples/validators.cpp +++ b/examples/validators.cpp @@ -19,7 +19,7 @@ int main(int argc, char **argv) { app.add_option("-v,--value", count, "Value in range")->check(CLI::Range(3, 6)); CLI11_PARSE(app, argc, argv); - std::cout << "Try printing help or failing the validator" << std::endl; + std::cout << "Try printing help or failing the validator" << '\n'; return 0; } diff --git a/include/CLI/Timer.hpp b/include/CLI/Timer.hpp index 99115678..7ffc2d9b 100644 --- a/include/CLI/Timer.hpp +++ b/include/CLI/Timer.hpp @@ -126,7 +126,7 @@ class AutoTimer : public Timer { // GCC 4.7 does not support using inheriting constructors. /// This destructor prints the string - ~AutoTimer() { std::cout << to_string() << std::endl; } + ~AutoTimer() { std::cout << to_string() << '\n'; } }; } // namespace CLI diff --git a/include/CLI/TypeTools.hpp b/include/CLI/TypeTools.hpp index 31327ee4..7e66c6ad 100644 --- a/include/CLI/TypeTools.hpp +++ b/include/CLI/TypeTools.hpp @@ -1384,9 +1384,7 @@ bool lexical_conversion(const std::vector &strings, AssignTo &outp FirstType v1; SecondType v2; bool retval = lexical_assign(strings[0], v1); - if(strings.size() > 1) { - retval = retval && lexical_assign(strings[1], v2); - } + retval = retval && lexical_assign((strings.size() > 1) ? strings[1] : std::string{}, v2); if(retval) { output = AssignTo{v1, v2}; } diff --git a/include/CLI/impl/App_inl.hpp b/include/CLI/impl/App_inl.hpp index b12d076c..ae8b5f33 100644 --- a/include/CLI/impl/App_inl.hpp +++ b/include/CLI/impl/App_inl.hpp @@ -658,7 +658,7 @@ CLI11_INLINE int App::exit(const Error &e, std::ostream &out, std::ostream &err) } if(e.get_name() == "CallForVersion") { - out << e.what() << std::endl; + out << e.what() << '\n'; return e.get_exit_code(); } diff --git a/include/CLI/impl/Config_inl.hpp b/include/CLI/impl/Config_inl.hpp index 7042c92a..92537c0e 100644 --- a/include/CLI/impl/Config_inl.hpp +++ b/include/CLI/impl/Config_inl.hpp @@ -134,7 +134,11 @@ generate_parents(const std::string §ion, std::string &name, char parentSepar parents.insert(parents.end(), plist.begin(), plist.end()); } // clean up quotes on the parents - detail::remove_quotes(parents); + try { + detail::remove_quotes(parents); + } catch(const std::invalid_argument &iarg) { + throw CLI::ParseError(iarg.what(), CLI::ExitCodes::InvalidError); + } return parents; } @@ -341,8 +345,8 @@ inline std::vector ConfigBase::from_config(std::istream &input) cons if(keyChar == '\"') { try { item = detail::remove_escaped_characters(item); - } catch(const std::invalid_argument &ia) { - throw CLI::ParseError(ia.what(), CLI::ExitCodes::InvalidError); + } catch(const std::invalid_argument &iarg) { + throw CLI::ParseError(iarg.what(), CLI::ExitCodes::InvalidError); } } } else { @@ -366,7 +370,11 @@ inline std::vector ConfigBase::from_config(std::istream &input) cons detail::trim(multiline); item += multiline; } - items_buffer = detail::split_up(item.substr(1, item.length() - 2), aSep); + if(item.back() == aEnd) { + items_buffer = detail::split_up(item.substr(1, item.length() - 2), aSep); + } else { + items_buffer = detail::split_up(item.substr(1, std::string::npos), aSep); + } } else if((isDefaultArray || isINIArray) && item.find_first_of(aSep) != std::string::npos) { items_buffer = detail::split_up(item, aSep); } else if((isDefaultArray || isINIArray) && item.find_first_of(' ') != std::string::npos) { diff --git a/include/CLI/impl/Formatter_inl.hpp b/include/CLI/impl/Formatter_inl.hpp index 5b17918f..3b1c8c28 100644 --- a/include/CLI/impl/Formatter_inl.hpp +++ b/include/CLI/impl/Formatter_inl.hpp @@ -132,7 +132,7 @@ CLI11_INLINE std::string Formatter::make_usage(const App *app, std::string name) << (app->get_require_subcommand_min() == 0 ? "]" : ""); } - out << std::endl; + out << '\n'; return out.str(); } diff --git a/include/CLI/impl/Option_inl.hpp b/include/CLI/impl/Option_inl.hpp index 2976d32c..aa6f4657 100644 --- a/include/CLI/impl/Option_inl.hpp +++ b/include/CLI/impl/Option_inl.hpp @@ -623,11 +623,11 @@ CLI11_INLINE void Option::_reduce_results(results_t &out, const results_t &origi // {} is the indicator for an empty container if(out.empty()) { if(original.size() == 1 && original[0] == "{}" && get_items_expected_min() > 0) { - out.push_back("{}"); - out.push_back("%%"); + out.emplace_back("{}"); + out.emplace_back("%%"); } } else if(out.size() == 1 && out[0] == "{}" && get_items_expected_min() > 0) { - out.push_back("%%"); + out.emplace_back("%%"); } } diff --git a/tests/ConfigFileTest.cpp b/tests/ConfigFileTest.cpp index cd799c0b..708e71ee 100644 --- a/tests/ConfigFileTest.cpp +++ b/tests/ConfigFileTest.cpp @@ -614,9 +614,9 @@ TEST_CASE_METHOD(TApp, "IniNotRequired", "[config]") { { std::ofstream out{tmpini}; - out << "[default]" << std::endl; - out << "two=99" << std::endl; - out << "three=3" << std::endl; + out << "[default]" << '\n'; + out << "two=99" << '\n'; + out << "three=3" << '\n'; } int one = 0, two = 0, three = 0; @@ -651,8 +651,8 @@ TEST_CASE_METHOD(TApp, "IniSuccessOnUnknownOption", "[config]") { { std::ofstream out{tmpini}; - out << "three=3" << std::endl; - out << "two=99" << std::endl; + out << "three=3" << '\n'; + out << "two=99" << '\n'; } int two{0}; @@ -671,8 +671,8 @@ TEST_CASE_METHOD(TApp, "IniGetRemainingOption", "[config]") { std::string ExtraOptionValue = "3"; { std::ofstream out{tmpini}; - out << ExtraOption << "=" << ExtraOptionValue << std::endl; - out << "two=99" << std::endl; + out << ExtraOption << "=" << ExtraOptionValue << '\n'; + out << "two=99" << '\n'; } int two{0}; @@ -694,7 +694,7 @@ TEST_CASE_METHOD(TApp, "IniRemainingSub", "[config]") { out << "[map]\n"; out << "a = 1\n"; out << "b=[1,2,3]\n"; - out << "c = 3" << std::endl; + out << "c = 3" << '\n'; } REQUIRE_NOTHROW(run()); @@ -727,7 +727,7 @@ TEST_CASE_METHOD(TApp, "IniGetNoRemaining", "[config]") { { std::ofstream out{tmpini}; - out << "two=99" << std::endl; + out << "two=99" << '\n'; } int two{0}; @@ -773,9 +773,9 @@ TEST_CASE_METHOD(TApp, "IniRequiredbadConfigurator", "[config]") { { std::ofstream out{tmpini}; - out << "[default]" << std::endl; - out << "two=99" << std::endl; - out << "three=3" << std::endl; + out << "[default]" << '\n'; + out << "two=99" << '\n'; + out << "three=3" << '\n'; } app.set_config("--config", tmpini)->required(); @@ -791,9 +791,9 @@ TEST_CASE_METHOD(TApp, "IniNotRequiredbadConfigurator", "[config]") { { std::ofstream out{tmpini}; - out << "[default]" << std::endl; - out << "two=99" << std::endl; - out << "three=3" << std::endl; + out << "[default]" << '\n'; + out << "two=99" << '\n'; + out << "three=3" << '\n'; } app.set_config("--config", tmpini); @@ -814,16 +814,16 @@ TEST_CASE_METHOD(TApp, "IniNotRequiredNotDefault", "[config]") { { std::ofstream out{tmpini}; - out << "[default]" << std::endl; - out << "two=99" << std::endl; - out << "three=3" << std::endl; + out << "[default]" << '\n'; + out << "two=99" << '\n'; + out << "three=3" << '\n'; } { std::ofstream out{tmpini2}; - out << "[default]" << std::endl; - out << "two=98" << std::endl; - out << "three=4" << std::endl; + out << "[default]" << '\n'; + out << "two=98" << '\n'; + out << "three=4" << '\n'; } int one{0}, two{0}, three{0}; @@ -852,9 +852,9 @@ TEST_CASE_METHOD(TApp, "IniEnvironmentalFileName", "[config]") { { std::ofstream out{tmpini}; - out << "[default]" << std::endl; - out << "two=99" << std::endl; - out << "three=3" << std::endl; + out << "[default]" << '\n'; + out << "two=99" << '\n'; + out << "three=3" << '\n'; } int one{0}, two{0}, three{0}; @@ -883,16 +883,16 @@ TEST_CASE_METHOD(TApp, "MultiConfig", "[config]") { { std::ofstream out{tmpini}; - out << "[default]" << std::endl; - out << "two=99" << std::endl; - out << "three=3" << std::endl; + out << "[default]" << '\n'; + out << "two=99" << '\n'; + out << "three=3" << '\n'; } { std::ofstream out{tmpini2}; - out << "[default]" << std::endl; - out << "one=55" << std::endl; - out << "three=4" << std::endl; + out << "[default]" << '\n'; + out << "one=55" << '\n'; + out << "three=4" << '\n'; } int one{0}, two{0}, three{0}; @@ -924,16 +924,16 @@ TEST_CASE_METHOD(TApp, "MultiConfig_takelast", "[config]") { { std::ofstream out{tmpini}; - out << "[default]" << std::endl; - out << "two=99" << std::endl; - out << "three=3" << std::endl; + out << "[default]" << '\n'; + out << "two=99" << '\n'; + out << "three=3" << '\n'; } { std::ofstream out{tmpini2}; - out << "[default]" << std::endl; - out << "one=55" << std::endl; - out << "three=4" << std::endl; + out << "[default]" << '\n'; + out << "one=55" << '\n'; + out << "three=4" << '\n'; } int one{0}, two{0}, three{0}; @@ -966,16 +966,16 @@ TEST_CASE_METHOD(TApp, "MultiConfig_takeAll", "[config]") { { std::ofstream out{tmpini}; - out << "[default]" << std::endl; - out << "two=99" << std::endl; - out << "three=3" << std::endl; + out << "[default]" << '\n'; + out << "two=99" << '\n'; + out << "three=3" << '\n'; } { std::ofstream out{tmpini2}; - out << "[default]" << std::endl; - out << "one=55" << std::endl; - out << "three=4" << std::endl; + out << "[default]" << '\n'; + out << "one=55" << '\n'; + out << "three=4" << '\n'; } int one{0}, two{0}, three{0}; @@ -1008,16 +1008,16 @@ TEST_CASE_METHOD(TApp, "MultiConfig_single", "[config]") { { std::ofstream out{tmpini}; - out << "[default]" << std::endl; - out << "two=99" << std::endl; - out << "three=3" << std::endl; + out << "[default]" << '\n'; + out << "two=99" << '\n'; + out << "three=3" << '\n'; } { std::ofstream out{tmpini2}; - out << "[default]" << std::endl; - out << "one=55" << std::endl; - out << "three=4" << std::endl; + out << "[default]" << '\n'; + out << "one=55" << '\n'; + out << "three=4" << '\n'; } int one{0}, two{0}, three{0}; @@ -1063,8 +1063,8 @@ TEST_CASE_METHOD(TApp, "IniOverwrite", "[config]") { TempFile tmpini{"TestIniTmp.ini"}; { std::ofstream out{tmpini}; - out << "[default]" << std::endl; - out << "two=99" << std::endl; + out << "[default]" << '\n'; + out << "two=99" << '\n'; } std::string orig = "filename_not_exist.ini"; @@ -1088,9 +1088,9 @@ TEST_CASE_METHOD(TApp, "IniRequired", "[config]") { { std::ofstream out{tmpini}; - out << "[default]" << std::endl; - out << "two=99" << std::endl; - out << "three=3" << std::endl; + out << "[default]" << '\n'; + out << "two=99" << '\n'; + out << "three=3" << '\n'; } int one{0}, two{0}, three{0}; @@ -1131,9 +1131,9 @@ TEST_CASE_METHOD(TApp, "IniInlineComment", "[config]") { { std::ofstream out{tmpini}; - out << "[default]" << std::endl; - out << "two=99 ; this is a two" << std::endl; - out << "three=3; this is a three" << std::endl; + out << "[default]" << '\n'; + out << "two=99 ; this is a two" << '\n'; + out << "three=3; this is a three" << '\n'; } int one{0}, two{0}, three{0}; @@ -1173,9 +1173,9 @@ TEST_CASE_METHOD(TApp, "TomlInlineComment", "[config]") { { std::ofstream out{tmpini}; - out << "[default]" << std::endl; - out << "two=99 # this is a two" << std::endl; - out << "three=3# this is a three" << std::endl; + out << "[default]" << '\n'; + out << "two=99 # this is a two" << '\n'; + out << "three=3# this is a three" << '\n'; } int one{0}, two{0}, three{0}; @@ -1215,12 +1215,12 @@ TEST_CASE_METHOD(TApp, "TomlDocStringComment", "[config]") { { std::ofstream out{tmpini}; - out << "[default]" << std::endl; - out << "two=99" << std::endl; - out << "three=3" << std::endl; - out << R"(""")" << std::endl; - out << "one=35" << std::endl; - out << R"(""")" << std::endl; + out << "[default]" << '\n'; + out << "two=99" << '\n'; + out << "three=3" << '\n'; + out << R"(""")" << '\n'; + out << "one=35" << '\n'; + out << R"(""")" << '\n'; } int one{0}, two{0}, three{0}; @@ -1242,12 +1242,12 @@ TEST_CASE_METHOD(TApp, "TomlDocStringComment2", "[config]") { { std::ofstream out{tmpini}; - out << "[default]" << std::endl; - out << "two=99" << std::endl; - out << "'''" << std::endl; - out << "one=35" << std::endl; - out << "last comment line three=6 '''" << std::endl; - out << "three=3" << std::endl; + out << "[default]" << '\n'; + out << "two=99" << '\n'; + out << "'''" << '\n'; + out << "one=35" << '\n'; + out << "last comment line three=6 '''" << '\n'; + out << "three=3" << '\n'; } int one{0}, two{0}, three{0}; @@ -1269,11 +1269,11 @@ TEST_CASE_METHOD(TApp, "TomlDocStringComment3", "[config]") { { std::ofstream out{tmpini}; - out << "[default]" << std::endl; - out << "two=99" << std::endl; - out << "three=3" << std::endl; - out << "'''" << std::endl; - out << "one=35" << std::endl; + out << "[default]" << '\n'; + out << "two=99" << '\n'; + out << "three=3" << '\n'; + out << "'''" << '\n'; + out << "one=35" << '\n'; } int one{0}, two{0}, three{0}; @@ -1318,9 +1318,9 @@ TEST_CASE_METHOD(TApp, "IniVector", "[config]") { { std::ofstream out{tmpini}; - out << "[default]" << std::endl; - out << "two=2 3" << std::endl; - out << "three=1 2 3" << std::endl; + out << "[default]" << '\n'; + out << "two=2 3" << '\n'; + out << "three=1 2 3" << '\n'; } std::vector two, three; @@ -1519,11 +1519,11 @@ TEST_CASE_METHOD(TApp, "IniLayered", "[config]") { { std::ofstream out{tmpini}; - out << "[default]" << std::endl; - out << "val=1" << std::endl; - out << "[subcom]" << std::endl; - out << "val=2" << std::endl; - out << "subsubcom.val=3" << std::endl; + out << "[default]" << '\n'; + out << "val=1" << '\n'; + out << "[subcom]" << '\n'; + out << "val=2" << '\n'; + out << "subsubcom.val=3" << '\n'; } int one{0}, two{0}, three{0}; @@ -1551,11 +1551,11 @@ TEST_CASE_METHOD(TApp, "IniLayeredStream", "[config]") { { std::ofstream out{tmpini}; - out << "[default]" << std::endl; - out << "val=1" << std::endl; - out << "[subcom]" << std::endl; - out << "val=2" << std::endl; - out << "subsubcom.val=3" << std::endl; + out << "[default]" << '\n'; + out << "val=1" << '\n'; + out << "[subcom]" << '\n'; + out << "val=2" << '\n'; + out << "subsubcom.val=3" << '\n'; } int one{0}, two{0}, three{0}; @@ -1584,12 +1584,12 @@ TEST_CASE_METHOD(TApp, "IniLayeredDotSection", "[config]") { { std::ofstream out{tmpini}; - out << "[default]" << std::endl; - out << "val=1" << std::endl; - out << "[subcom]" << std::endl; - out << "val=2" << std::endl; - out << "[subcom.subsubcom]" << std::endl; - out << "val=3" << std::endl; + out << "[default]" << '\n'; + out << "val=1" << '\n'; + out << "[subcom]" << '\n'; + out << "val=2" << '\n'; + out << "[subcom.subsubcom]" << '\n'; + out << "val=3" << '\n'; } int one{0}, two{0}, three{0}; @@ -1623,12 +1623,12 @@ TEST_CASE_METHOD(TApp, "IniLayeredDotSectionInQuotes", "[config]") { { std::ofstream out{tmpini}; - out << "[default]" << std::endl; - out << "val=1" << std::endl; - out << "['subcom']" << std::endl; - out << "val=2" << std::endl; - out << "['subcom'.\"subsubcom\"]" << std::endl; - out << "val=3" << std::endl; + out << "[default]" << '\n'; + out << "val=1" << '\n'; + out << "['subcom']" << '\n'; + out << "val=2" << '\n'; + out << "['subcom'.\"subsubcom\"]" << '\n'; + out << "val=3" << '\n'; } int one{0}, two{0}, three{0}; @@ -1662,12 +1662,12 @@ TEST_CASE_METHOD(TApp, "IniLayeredCustomSectionSeparator", "[config]") { { std::ofstream out{tmpini}; - out << "[default]" << std::endl; - out << "val=1" << std::endl; - out << "[subcom]" << std::endl; - out << "val=2" << std::endl; - out << "[subcom|subsubcom]" << std::endl; - out << "val=3" << std::endl; + out << "[default]" << '\n'; + out << "val=1" << '\n'; + out << "[subcom]" << '\n'; + out << "val=2" << '\n'; + out << "[subcom|subsubcom]" << '\n'; + out << "val=3" << '\n'; } app.get_config_formatter_base()->parentSeparator('|'); int one{0}, two{0}, three{0}; @@ -1695,10 +1695,10 @@ TEST_CASE_METHOD(TApp, "IniLayeredOptionGroupAlias", "[config]") { { std::ofstream out{tmpini}; - out << "[default]" << std::endl; - out << "val=1" << std::endl; - out << "[ogroup]" << std::endl; - out << "val2=2" << std::endl; + out << "[default]" << '\n'; + out << "val=1" << '\n'; + out << "[ogroup]" << '\n'; + out << "val2=2" << '\n'; } int one{0}, two{0}; app.add_option("--val", one); @@ -1719,11 +1719,11 @@ TEST_CASE_METHOD(TApp, "IniSubcommandConfigurable", "[config]") { { std::ofstream out{tmpini}; - out << "[default]" << std::endl; - out << "val=1" << std::endl; - out << "[subcom]" << std::endl; - out << "val=2" << std::endl; - out << "subsubcom.val=3" << std::endl; + out << "[default]" << '\n'; + out << "val=1" << '\n'; + out << "[subcom]" << '\n'; + out << "val=2" << '\n'; + out << "subsubcom.val=3" << '\n'; } int one{0}, two{0}, three{0}; @@ -1753,11 +1753,11 @@ TEST_CASE_METHOD(TApp, "IniSubcommandConfigurableInQuotes", "[config]") { { std::ofstream out{tmpini}; - out << "[default]" << std::endl; - out << "val=1" << std::endl; - out << "[subcom]" << std::endl; - out << "val=2" << std::endl; - out << "\"subsubcom\".'val'=3" << std::endl; + out << "[default]" << '\n'; + out << "val=1" << '\n'; + out << "[subcom]" << '\n'; + out << "val=2" << '\n'; + out << "\"subsubcom\".'val'=3" << '\n'; } int one{0}, two{0}, three{0}; @@ -1787,11 +1787,11 @@ TEST_CASE_METHOD(TApp, "IniSubcommandConfigurableInQuotesAlias", "[config]") { { std::ofstream out{tmpini}; - out << "[default]" << std::endl; - out << "val=1" << std::endl; - out << "[subcom]" << std::endl; - out << "val=2" << std::endl; - out << R"("sub\tsub\t.com".'val'=3)" << std::endl; + out << "[default]" << '\n'; + out << "val=1" << '\n'; + out << "[subcom]" << '\n'; + out << "val=2" << '\n'; + out << R"("sub\tsub\t.com".'val'=3)" << '\n'; } int one{0}, two{0}, three{0}; @@ -1821,11 +1821,11 @@ TEST_CASE_METHOD(TApp, "IniSubcommandConfigurableInQuotesAliasWithEquals", "[con { std::ofstream out{tmpini}; - out << "[default]" << std::endl; - out << "val=1" << std::endl; - out << "[subcom]" << std::endl; - out << "val=2" << std::endl; - out << R"("sub=sub=.com".'val'=3)" << std::endl; + out << "[default]" << '\n'; + out << "val=1" << '\n'; + out << "[subcom]" << '\n'; + out << "val=2" << '\n'; + out << R"("sub=sub=.com".'val'=3)" << '\n'; } int one{0}, two{0}, three{0}; @@ -1855,11 +1855,11 @@ TEST_CASE_METHOD(TApp, "IniSubcommandConfigurableInQuotesAliasWithComment", "[co { std::ofstream out{tmpini}; - out << "[default]" << std::endl; - out << "val=1" << std::endl; - out << "[subcom]" << std::endl; - out << "val=2" << std::endl; - out << R"("sub#sub;.com".'val'=3)" << std::endl; + out << "[default]" << '\n'; + out << "val=1" << '\n'; + out << "[subcom]" << '\n'; + out << "val=2" << '\n'; + out << R"("sub#sub;.com".'val'=3)" << '\n'; } int one{0}, two{0}, three{0}; @@ -1885,11 +1885,11 @@ TEST_CASE_METHOD(TApp, "IniSubcommandConfigurablePreParse", "[config]") { { std::ofstream out{tmpini}; - out << "[default]" << std::endl; - out << "val=1" << std::endl; - out << "[subcom]" << std::endl; - out << "val=2" << std::endl; - out << "subsubcom.val=3" << std::endl; + out << "[default]" << '\n'; + out << "val=1" << '\n'; + out << "[subcom]" << '\n'; + out << "val=2" << '\n'; + out << "subsubcom.val=3" << '\n'; } int one{0}, two{0}, three{0}, four{0}; @@ -1927,11 +1927,11 @@ TEST_CASE_METHOD(TApp, "IniSection", "[config]") { { std::ofstream out{tmpini}; - out << "[config]" << std::endl; - out << "val=2" << std::endl; - out << "subsubcom.val=3" << std::endl; - out << "[default]" << std::endl; - out << "val=1" << std::endl; + out << "[config]" << '\n'; + out << "val=2" << '\n'; + out << "subsubcom.val=3" << '\n'; + out << "[default]" << '\n'; + out << "val=1" << '\n'; } int val{0}; @@ -1951,11 +1951,11 @@ TEST_CASE_METHOD(TApp, "IniSection2", "[config]") { { std::ofstream out{tmpini}; - out << "[default]" << std::endl; - out << "val=1" << std::endl; - out << "[config]" << std::endl; - out << "val=2" << std::endl; - out << "subsubcom.val=3" << std::endl; + out << "[default]" << '\n'; + out << "val=1" << '\n'; + out << "[config]" << '\n'; + out << "val=2" << '\n'; + out << "subsubcom.val=3" << '\n'; } int val{0}; @@ -1975,11 +1975,11 @@ TEST_CASE_METHOD(TApp, "jsonLikeParsing", "[config]") { { std::ofstream out{tmpjson}; - out << "{" << std::endl; - out << "\"val\":1," << std::endl; - out << R"("val2":"test",)" << std::endl; - out << "\"flag\":true" << std::endl; - out << "}" << std::endl; + out << "{" << '\n'; + out << "\"val\":1," << '\n'; + out << R"("val2":"test",)" << '\n'; + out << "\"flag\":true" << '\n'; + out << "}" << '\n'; } int val{0}; @@ -2006,17 +2006,17 @@ TEST_CASE_METHOD(TApp, "TomlSectionNumber", "[config]") { { std::ofstream out{tmpini}; - out << "[default]" << std::endl; - out << "val=1" << std::endl; - out << "[[config]]" << std::endl; - out << "val=2" << std::endl; - out << "subsubcom.val=3" << std::endl; - out << "[[config]]" << std::endl; - out << "val=4" << std::endl; - out << "subsubcom.val=3" << std::endl; - out << "[[config]]" << std::endl; - out << "val=6" << std::endl; - out << "subsubcom.val=3" << std::endl; + out << "[default]" << '\n'; + out << "val=1" << '\n'; + out << "[[config]]" << '\n'; + out << "val=2" << '\n'; + out << "subsubcom.val=3" << '\n'; + out << "[[config]]" << '\n'; + out << "val=4" << '\n'; + out << "subsubcom.val=3" << '\n'; + out << "[[config]]" << '\n'; + out << "val=6" << '\n'; + out << "subsubcom.val=3" << '\n'; } int val{0}; @@ -2050,12 +2050,12 @@ TEST_CASE_METHOD(TApp, "IniSubcommandConfigurableParseComplete", "[config]") { { std::ofstream out{tmpini}; - out << "[default]" << std::endl; - out << "val=1" << std::endl; - out << "[subcom]" << std::endl; - out << "val=2" << std::endl; - out << "[subcom.subsubcom]" << std::endl; - out << "val=3" << std::endl; + out << "[default]" << '\n'; + out << "val=1" << '\n'; + out << "[subcom]" << '\n'; + out << "val=2" << '\n'; + out << "[subcom.subsubcom]" << '\n'; + out << "val=3" << '\n'; } int one{0}, two{0}, three{0}, four{0}; @@ -2095,14 +2095,14 @@ TEST_CASE_METHOD(TApp, "IniSubcommandMultipleSections", "[config]") { { std::ofstream out{tmpini}; - out << "[default]" << std::endl; - out << "val=1" << std::endl; - out << "[subcom]" << std::endl; - out << "val=2" << std::endl; - out << "[subcom.subsubcom]" << std::endl; - out << "val=3" << std::endl; - out << "[subcom2]" << std::endl; - out << "val=4" << std::endl; + out << "[default]" << '\n'; + out << "val=1" << '\n'; + out << "[subcom]" << '\n'; + out << "val=2" << '\n'; + out << "[subcom.subsubcom]" << '\n'; + out << "val=3" << '\n'; + out << "[subcom2]" << '\n'; + out << "val=4" << '\n'; } int one{0}, two{0}, three{0}, four{0}; @@ -2143,9 +2143,9 @@ TEST_CASE_METHOD(TApp, "DuplicateSubcommandCallbacks", "[config]") { { std::ofstream out{tmptoml}; - out << "[[foo]]" << std::endl; - out << "[[foo]]" << std::endl; - out << "[[foo]]" << std::endl; + out << "[[foo]]" << '\n'; + out << "[[foo]]" << '\n'; + out << "[[foo]]" << '\n'; } auto *foo = app.add_subcommand("foo"); @@ -2167,7 +2167,7 @@ TEST_CASE_METHOD(TApp, "SubcommandCallbackSingle", "[config]") { { std::ofstream out{tmptoml}; - out << "[foo]" << std::endl; + out << "[foo]" << '\n'; } int count{0}; auto *foo = app.add_subcommand("foo"); @@ -2186,8 +2186,8 @@ TEST_CASE_METHOD(TApp, "IniFailure", "[config]") { app.allow_config_extras(false); { std::ofstream out{tmpini}; - out << "[default]" << std::endl; - out << "val=1" << std::endl; + out << "[default]" << '\n'; + out << "val=1" << '\n'; } CHECK_THROWS_AS(run(), CLI::ConfigError); @@ -2203,8 +2203,8 @@ TEST_CASE_METHOD(TApp, "IniConfigurable", "[config]") { { std::ofstream out{tmpini}; - out << "[default]" << std::endl; - out << "val=1" << std::endl; + out << "[default]" << '\n'; + out << "val=1" << '\n'; } REQUIRE_NOTHROW(run()); @@ -2221,8 +2221,8 @@ TEST_CASE_METHOD(TApp, "IniNotConfigurable", "[config]") { { std::ofstream out{tmpini}; - out << "[default]" << std::endl; - out << "val=1" << std::endl; + out << "[default]" << '\n'; + out << "val=1" << '\n'; } CHECK_THROWS_AS(run(), CLI::ConfigError); @@ -2240,8 +2240,8 @@ TEST_CASE_METHOD(TApp, "IniFlagDisableOverrideFlagArray", "[config]") { { std::ofstream out{tmpini}; - out << "[default]" << std::endl; - out << "val=[1,true,false,true]" << std::endl; + out << "[default]" << '\n'; + out << "val=[1,true,false,true]" << '\n'; } REQUIRE_NOTHROW(run()); @@ -2258,8 +2258,8 @@ TEST_CASE_METHOD(TApp, "IniFlagInvalidDisableOverrideFlagArray", "[config]") { { std::ofstream out{tmpini}; - out << "[default]" << std::endl; - out << "val=[1,true,false,not_valid]" << std::endl; + out << "[default]" << '\n'; + out << "val=[1,true,false,not_valid]" << '\n'; } CHECK_THROWS_AS(run(), CLI::InvalidError); @@ -2274,8 +2274,8 @@ TEST_CASE_METHOD(TApp, "IniSubFailure", "[config]") { app.allow_config_extras(false); { std::ofstream out{tmpini}; - out << "[other]" << std::endl; - out << "val=1" << std::endl; + out << "[other]" << '\n'; + out << "val=1" << '\n'; } CHECK_THROWS_AS(run(), CLI::ConfigError); @@ -2289,8 +2289,8 @@ TEST_CASE_METHOD(TApp, "IniNoSubFailure", "[config]") { app.allow_config_extras(CLI::config_extras_mode::error); { std::ofstream out{tmpini}; - out << "[other]" << std::endl; - out << "val=1" << std::endl; + out << "[other]" << '\n'; + out << "val=1" << '\n'; } CHECK_THROWS_AS(run(), CLI::ConfigError); @@ -2305,7 +2305,7 @@ TEST_CASE_METHOD(TApp, "IniFlagConvertFailure", "[config]") { { std::ofstream out{tmpini}; - out << "flag=moobook" << std::endl; + out << "flag=moobook" << '\n'; } run(); bool result{false}; @@ -2326,7 +2326,7 @@ TEST_CASE_METHOD(TApp, "IniFlagNumbers", "[config]") { { std::ofstream out{tmpini}; - out << "flag=3" << std::endl; + out << "flag=3" << '\n'; } REQUIRE_NOTHROW(run()); @@ -2344,7 +2344,7 @@ TEST_CASE_METHOD(TApp, "IniFlagDual", "[config]") { { std::ofstream out{tmpini}; - out << "flag=1 1" << std::endl; + out << "flag=1 1" << '\n'; } CHECK_THROWS_AS(run(), CLI::ConversionError); @@ -2361,7 +2361,7 @@ TEST_CASE_METHOD(TApp, "IniVectorMax", "[config]") { { std::ofstream out{tmpini}; - out << "vec=[a,b,c]" << std::endl; + out << "vec=[a,b,c]" << '\n'; } CHECK_THROWS_AS(run(), CLI::ArgumentMismatch); @@ -2377,7 +2377,7 @@ TEST_CASE_METHOD(TApp, "IniShort", "[config]") { { std::ofstream out{tmpini}; - out << "f=3" << std::endl; + out << "f=3" << '\n'; } REQUIRE_NOTHROW(run()); @@ -2394,7 +2394,7 @@ TEST_CASE_METHOD(TApp, "IniShortQuote1", "[config]") { { std::ofstream out{tmpini}; - out << "\"f\"=3" << std::endl; + out << "\"f\"=3" << '\n'; } REQUIRE_NOTHROW(run()); @@ -2411,7 +2411,7 @@ TEST_CASE_METHOD(TApp, "IniShortQuote2", "[config]") { { std::ofstream out{tmpini}; - out << "'f'=3" << std::endl; + out << "'f'=3" << '\n'; } REQUIRE_NOTHROW(run()); @@ -2428,7 +2428,7 @@ TEST_CASE_METHOD(TApp, "IniShortQuote3", "[config]") { { std::ofstream out{tmpini}; - out << "`f`=3" << std::endl; + out << "`f`=3" << '\n'; } REQUIRE_NOTHROW(run()); @@ -2445,7 +2445,7 @@ TEST_CASE_METHOD(TApp, "IniDefaultPath", "[config]") { { std::ofstream out{tmpini}; - out << "f=3" << std::endl; + out << "f=3" << '\n'; } REQUIRE_NOTHROW(run()); @@ -2464,7 +2464,7 @@ TEST_CASE_METHOD(TApp, "IniMultipleDefaultPath", "[config]") { { std::ofstream out{tmpini}; - out << "f=3" << std::endl; + out << "f=3" << '\n'; } args = {"--config", "TestIniTmp.ini"}; @@ -2484,7 +2484,7 @@ TEST_CASE_METHOD(TApp, "IniMultipleDefaultPathAlternate", "[config]") { { std::ofstream out{tmpini}; - out << "f=3" << std::endl; + out << "f=3" << '\n'; } args = {"--config", "TestIniTmp.ini"}; @@ -2503,7 +2503,7 @@ TEST_CASE_METHOD(TApp, "IniPositional", "[config]") { { std::ofstream out{tmpini}; - out << "key=3" << std::endl; + out << "key=3" << '\n'; } REQUIRE_NOTHROW(run()); @@ -2520,7 +2520,7 @@ TEST_CASE_METHOD(TApp, "IniEnvironmental", "[config]") { { std::ofstream out{tmpini}; - out << "CLI11_TEST_ENV_KEY_TMP=3" << std::endl; + out << "CLI11_TEST_ENV_KEY_TMP=3" << '\n'; } REQUIRE_NOTHROW(run()); @@ -2540,10 +2540,10 @@ TEST_CASE_METHOD(TApp, "IniFlagText", "[config]") { { std::ofstream out{tmpini}; - out << "flag1=true" << std::endl; - out << "flag2=on" << std::endl; - out << "flag3=off" << std::endl; - out << "flag4=1" << std::endl; + out << "flag1=true" << '\n'; + out << "flag2=on" << '\n'; + out << "flag3=off" << '\n'; + out << "flag4=1" << '\n'; } run(); @@ -2560,11 +2560,11 @@ TEST_CASE_METHOD(TApp, "IniFlags", "[config]") { { std::ofstream out{tmpini}; - out << "[default]" << std::endl; - out << "two=2" << std::endl; - out << "three=true" << std::endl; - out << "four=on" << std::endl; - out << "five" << std::endl; + out << "[default]" << '\n'; + out << "two=2" << '\n'; + out << "three=true" << '\n'; + out << "four=on" << '\n'; + out << "five" << '\n'; } int two{0}; @@ -2588,12 +2588,12 @@ TEST_CASE_METHOD(TApp, "IniFlagsComment", "[config]") { { std::ofstream out{tmpini}; - out << "[default]" << std::endl; - out << "two=2 # comment 1" << std::endl; - out << "three=true" << std::endl; - out << "four=on #comment 2" << std::endl; - out << "five #comment 3" << std::endl; - out << std::endl; + out << "[default]" << '\n'; + out << "two=2 # comment 1" << '\n'; + out << "three=true" << '\n'; + out << "four=on #comment 2" << '\n'; + out << "five #comment 3" << '\n'; + out << '\n'; } int two{0}; @@ -2617,12 +2617,12 @@ TEST_CASE_METHOD(TApp, "IniFlagsAltComment", "[config]") { { std::ofstream out{tmpini}; - out << "[default]" << std::endl; - out << "two=2 % comment 1" << std::endl; - out << "three=true" << std::endl; - out << "four=on %% comment 2" << std::endl; - out << "five %= 3" << std::endl; - out << std::endl; + out << "[default]" << '\n'; + out << "two=2 % comment 1" << '\n'; + out << "three=true" << '\n'; + out << "four=on %% comment 2" << '\n'; + out << "five %= 3" << '\n'; + out << '\n'; } auto config = app.get_config_formatter_base(); @@ -2648,11 +2648,11 @@ TEST_CASE_METHOD(TApp, "IniFalseFlags", "[config]") { { std::ofstream out{tmpini}; - out << "[default]" << std::endl; - out << "two=-2" << std::endl; - out << "three=false" << std::endl; - out << "four=1" << std::endl; - out << "five" << std::endl; + out << "[default]" << '\n'; + out << "two=-2" << '\n'; + out << "three=false" << '\n'; + out << "four=1" << '\n'; + out << "five" << '\n'; } int two{0}; @@ -2676,11 +2676,11 @@ TEST_CASE_METHOD(TApp, "IniFalseFlagsDef", "[config]") { { std::ofstream out{tmpini}; - out << "[default]" << std::endl; - out << "two=2" << std::endl; - out << "three=true" << std::endl; - out << "four=on" << std::endl; - out << "five" << std::endl; + out << "[default]" << '\n'; + out << "two=2" << '\n'; + out << "three=true" << '\n'; + out << "four=on" << '\n'; + out << "five" << '\n'; } int two{0}; @@ -2704,10 +2704,10 @@ TEST_CASE_METHOD(TApp, "IniFalseFlagsDefDisableOverrideError", "[config]") { { std::ofstream out{tmpini}; - out << "[default]" << std::endl; - out << "two=2" << std::endl; - out << "four=on" << std::endl; - out << "five" << std::endl; + out << "[default]" << '\n'; + out << "two=2" << '\n'; + out << "four=on" << '\n'; + out << "five" << '\n'; } int two{0}; @@ -2725,10 +2725,10 @@ TEST_CASE_METHOD(TApp, "IniFalseFlagsDefDisableOverrideSuccess", "[config]") { { std::ofstream out{tmpini}; - out << "[default]" << std::endl; - out << "two=2" << std::endl; - out << "four={}" << std::endl; - out << "val=15" << std::endl; + out << "[default]" << '\n'; + out << "two=2" << '\n'; + out << "four={}" << '\n'; + out << "val=15" << '\n'; } int two{0}, four{0}, val{0}; @@ -2755,20 +2755,20 @@ TEST_CASE_METHOD(TApp, "IniDisableFlagOverride", "[config]") { { std::ofstream out{tmpini}; - out << "[default]" << std::endl; - out << "two=2" << std::endl; + out << "[default]" << '\n'; + out << "two=2" << '\n'; } { std::ofstream out{tmpini2}; - out << "[default]" << std::endl; - out << "two=7" << std::endl; + out << "[default]" << '\n'; + out << "two=7" << '\n'; } { std::ofstream out{tmpini3}; - out << "[default]" << std::endl; - out << "three=true" << std::endl; + out << "[default]" << '\n'; + out << "three=true" << '\n'; } int val{0}; @@ -3284,7 +3284,7 @@ TEST_CASE_METHOD(TApp, "StopReadingConfigOnClear", "[config]") { { std::ofstream out{tmpini}; - out << "volume=1" << std::endl; + out << "volume=1" << '\n'; } int volume{0}; @@ -3306,7 +3306,7 @@ TEST_CASE_METHOD(TApp, "ConfigWriteReadWrite", "[config]") { std::string config1 = app.config_to_str(true, true); { std::ofstream out{tmpini}; - out << config1 << std::endl; + out << config1 << '\n'; } app.set_config("--config", tmpini, "Read an ini file", true); @@ -3329,7 +3329,7 @@ TEST_CASE_METHOD(TApp, "ConfigWriteReadNegated", "[config]") { std::string config1 = app.config_to_str(false, false); { std::ofstream out{tmpini}; - out << config1 << std::endl; + out << config1 << '\n'; } CHECK_FALSE(flag); args.clear(); diff --git a/tests/FuzzFailTest.cpp b/tests/FuzzFailTest.cpp index ed7f3d92..124c8f42 100644 --- a/tests/FuzzFailTest.cpp +++ b/tests/FuzzFailTest.cpp @@ -41,8 +41,10 @@ TEST_CASE("app_fail") { try { app->parse(parseData); } catch(const CLI::ParseError & /*e*/) { + CHECK(true); } } catch(const CLI::ConstructionError & /*e*/) { + CHECK(true); } } @@ -50,12 +52,13 @@ TEST_CASE("file_fail") { CLI::FuzzApp fuzzdata; auto app = fuzzdata.generateApp(); - int index = GENERATE(range(1, 7)); + int index = GENERATE(range(1, 9)); auto parseData = loadFailureFile("fuzz_file_fail", index); std::stringstream out(parseData); try { app->parse_from_stream(out); } catch(const CLI::ParseError & /*e*/) { + CHECK(true); } } diff --git a/tests/HelpersTest.cpp b/tests/HelpersTest.cpp index 7fc74a54..44262417 100644 --- a/tests/HelpersTest.cpp +++ b/tests/HelpersTest.cpp @@ -696,7 +696,7 @@ TEST_CASE("Validators: ProgramNameSplit", "[helpers]") { TempFile myfile{"program_name1.exe"}; { std::ofstream out{myfile}; - out << "useless string doesn't matter" << std::endl; + out << "useless string doesn't matter" << '\n'; } auto res = CLI::detail::split_program_name(std::string("./") + std::string(myfile) + " this is a bunch of extra stuff "); @@ -706,7 +706,7 @@ TEST_CASE("Validators: ProgramNameSplit", "[helpers]") { TempFile myfile2{"program name1.exe"}; { std::ofstream out{myfile2}; - out << "useless string doesn't matter" << std::endl; + out << "useless string doesn't matter" << '\n'; } res = CLI::detail::split_program_name(std::string(" ") + std::string("./") + std::string(myfile2) + " this is a bunch of extra stuff "); @@ -972,7 +972,7 @@ TEST_CASE("AppHelper: Ofstream", "[helpers]") { { std::ofstream out{myfile}; - out << "this is output" << std::endl; + out << "this is output" << '\n'; } CHECK(CLI::ExistingFile(myfile).empty()); diff --git a/tests/OptionalTest.cpp b/tests/OptionalTest.cpp index 6147d66c..6906fc9d 100644 --- a/tests/OptionalTest.cpp +++ b/tests/OptionalTest.cpp @@ -70,13 +70,11 @@ TEST_CASE_METHOD(TApp, "StdOptionalTest", "[optional]") { args = {"-c", "1"}; run(); - CHECK(opt); - CHECK(1 == *opt); + CHECK((opt && (1 == *opt))); args = {"--count", "3"}; run(); - CHECK(opt); - CHECK(3 == *opt); + CHECK((opt && (3 == *opt))); } TEST_CASE_METHOD(TApp, "StdOptionalVectorEmptyDirect", "[optional]") { @@ -91,7 +89,7 @@ TEST_CASE_METHOD(TApp, "StdOptionalVectorEmptyDirect", "[optional]") { CHECK(!opt); args = {"-v", "1", "4", "5"}; run(); - CHECK(opt); + REQUIRE(opt); std::vector expV{1, 4, 5}; CHECK(expV == *opt); } @@ -125,7 +123,7 @@ TEST_CASE_METHOD(TApp, "StdOptionalUint", "[optional]") { args = {"-i", "15"}; run(); - CHECK(15U == *opt); + CHECK((opt && (15U == *opt))); static_assert(CLI::detail::classify_object>::value == CLI::detail::object_category::wrapper_value); } @@ -140,13 +138,14 @@ TEST_CASE_METHOD(TApp, "StdOptionalbool", "[optional]") { args = {"--opt"}; run(); - CHECK(opt); - CHECK(*opt); + CHECK((opt && *opt)); args = {"--no-opt"}; run(); - CHECK(opt); - CHECK_FALSE(*opt); + REQUIRE(opt); + if(opt) { + CHECK_FALSE(*opt); + } static_assert(CLI::detail::classify_object>::value == CLI::detail::object_category::wrapper_value); } @@ -186,12 +185,12 @@ TEST_CASE_METHOD(TApp, "BoostOptionalTest", "[optional]") { args = {"-c", "1"}; run(); - CHECK(opt); + REQUIRE(opt); CHECK(1 == *opt); opt = {}; args = {"--count", "3"}; run(); - CHECK(opt); + REQUIRE(opt); CHECK(3 == *opt); } @@ -203,7 +202,7 @@ TEST_CASE_METHOD(TApp, "BoostOptionalTestZarg", "[optional]") { args = {"-c", "1"}; run(); - CHECK(opt); + REQUIRE(opt); CHECK(1 == *opt); opt = {}; args = {"--count"}; @@ -219,12 +218,12 @@ TEST_CASE_METHOD(TApp, "BoostOptionalint64Test", "[optional]") { args = {"-c", "1"}; run(); - CHECK(opt); + REQUIRE(opt); CHECK(1 == *opt); opt = {}; args = {"--count", "3"}; run(); - CHECK(opt); + REQUIRE(opt); CHECK(3 == *opt); } @@ -236,12 +235,12 @@ TEST_CASE_METHOD(TApp, "BoostOptionalStringTest", "[optional]") { args = {"-s", "strval"}; run(); - CHECK(opt); + REQUIRE(opt); CHECK("strval" == *opt); opt = {}; args = {"--string", "strv"}; run(); - CHECK(opt); + REQUIRE(opt); CHECK("strv" == *opt); } namespace boost { @@ -266,13 +265,13 @@ TEST_CASE_METHOD(TApp, "BoostOptionalEnumTest", "[optional]") { args = {"-v", "3"}; run(); checkOpt = static_cast(opt); - CHECK(checkOpt); + REQUIRE(checkOpt); CHECK(*opt == eval::val3); opt = {}; args = {"--val", "1"}; run(); checkOpt = static_cast(opt); - CHECK(checkOpt); + REQUIRE(checkOpt); CHECK(*opt == eval::val1); } @@ -288,7 +287,7 @@ TEST_CASE_METHOD(TApp, "BoostOptionalVector", "[optional]") { args = {"-v", "1", "4", "5"}; run(); checkOpt = static_cast(opt); - CHECK(checkOpt); + REQUIRE(checkOpt); std::vector expV{1, 4, 5}; CHECK(expV == *opt); } @@ -308,7 +307,7 @@ TEST_CASE_METHOD(TApp, "BoostOptionalVectorEmpty", "[optional]") { args = {"-v", "1", "4", "5"}; run(); checkOpt = static_cast(opt); - CHECK(checkOpt); + REQUIRE(checkOpt); std::vector expV{1, 4, 5}; CHECK(expV == *opt); } @@ -328,7 +327,7 @@ TEST_CASE_METHOD(TApp, "BoostOptionalVectorEmptyDirect", "[optional]") { args = {"-v", "1", "4", "5"}; run(); checkOpt = static_cast(opt); - CHECK(checkOpt); + REQUIRE(checkOpt); std::vector expV{1, 4, 5}; CHECK(expV == *opt); } @@ -344,12 +343,12 @@ TEST_CASE_METHOD(TApp, "BoostOptionalComplexDirect", "[optional]") { CHECK(!opt); args = {"-c", "1+2j"}; run(); - CHECK(opt); + REQUIRE(opt); std::complex val{1, 2}; CHECK(val == *opt); args = {"-c", "3", "-4"}; run(); - CHECK(opt); + REQUIRE(opt); std::complex val2{3, -4}; CHECK(val2 == *opt); } diff --git a/tests/StringParseTest.cpp b/tests/StringParseTest.cpp index 2f0a039d..839baf7a 100644 --- a/tests/StringParseTest.cpp +++ b/tests/StringParseTest.cpp @@ -20,7 +20,7 @@ TEST_CASE_METHOD(TApp, "ExistingExeCheck", "[stringparse]") { { std::ofstream out{tmpexe}; - out << "useless string doesn't matter" << std::endl; + out << "useless string doesn't matter" << '\n'; } app.parse(std::string("./") + std::string(tmpexe) + @@ -42,7 +42,7 @@ TEST_CASE_METHOD(TApp, "ExistingExeCheckWithSpace", "[stringparse]") { { std::ofstream out{tmpexe}; - out << "useless string doesn't matter" << std::endl; + out << "useless string doesn't matter" << '\n'; } app.parse(std::string("./") + std::string(tmpexe) + @@ -66,7 +66,7 @@ TEST_CASE_METHOD(TApp, "ExistingExeCheckWithLotsOfSpace", "[stringparse]") { { std::ofstream out{tmpexe}; - out << "useless string doesn't matter" << std::endl; + out << "useless string doesn't matter" << '\n'; } app.parse(std::string("./") + std::string(tmpexe) + diff --git a/tests/TimerTest.cpp b/tests/TimerTest.cpp index 03d02857..0dc2ca94 100644 --- a/tests/TimerTest.cpp +++ b/tests/TimerTest.cpp @@ -63,6 +63,6 @@ TEST_CASE("Timer: PrintTimer", "[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; + std::cout << output << '\n'; CHECK_THAT(output, Contains("ms")); } diff --git a/tests/fuzzFail/fuzz_file_fail7 b/tests/fuzzFail/fuzz_file_fail7 new file mode 100644 index 00000000..1714e4cb --- /dev/null +++ b/tests/fuzzFail/fuzz_file_fail7 @@ -0,0 +1 @@ +--vdtr5=[| diff --git a/tests/fuzzFail/fuzz_file_fail8 b/tests/fuzzFail/fuzz_file_fail8 new file mode 100644 index 00000000..f060d946 --- /dev/null +++ b/tests/fuzzFail/fuzz_file_fail8 @@ -0,0 +1 @@ +[ÏqÏq[]1."È"\ ".saopt1[[]1."È"\ ".saopt1[] diff --git a/tests/informational.cpp b/tests/informational.cpp index f2e1f6b8..ae221ea7 100644 --- a/tests/informational.cpp +++ b/tests/informational.cpp @@ -52,5 +52,5 @@ int main() { std::cout << " boost::optional support active\n"; #endif - std::cout << std::endl; + std::cout << '\n'; }