diff --git a/fuzz/fuzzApp.cpp b/fuzz/fuzzApp.cpp index 7aae17ae..9d050eae 100644 --- a/fuzz/fuzzApp.cpp +++ b/fuzz/fuzzApp.cpp @@ -193,7 +193,18 @@ bool FuzzApp::compare(const FuzzApp &other) const { } if(vv1 != other.vv1) { - return false; + if(vv1.size() != other.vv1.size()) { + return false; + } + // need to check if they are both nan + for(std::size_t index = 0; index < vv1.size(); ++index) { + if(vv1[index] != other.vv1[index]) { + if(std::isnan(vv1[index]) && std::isnan(other.vv1[index])) { + continue; + } + return false; + } + } } if(vstr != other.vstr) { return false; diff --git a/include/CLI/impl/App_inl.hpp b/include/CLI/impl/App_inl.hpp index 10e0a568..2e17cb89 100644 --- a/include/CLI/impl/App_inl.hpp +++ b/include/CLI/impl/App_inl.hpp @@ -1951,7 +1951,7 @@ App::_parse_arg(std::vector &args, detail::Classifier current_type, // now check for '.' notation of subcommands auto dotloc = arg_name.find_first_of('.', 1); - if(dotloc != std::string::npos) { + if(dotloc != std::string::npos && dotloc < arg_name.size() - 1) { // using dot notation is equivalent to single argument subcommand auto *sub = _find_subcommand(arg_name.substr(0, dotloc), true, false); if(sub != nullptr) { @@ -1972,7 +1972,12 @@ App::_parse_arg(std::vector &args, detail::Classifier current_type, args.push_back(nval); current_type = detail::Classifier::SHORT; } - auto val = sub->_parse_arg(args, current_type, true); + std::string dummy1, dummy2; + bool val = false; + if(current_type == detail::Classifier::SHORT || detail::split_long(args.back(), dummy1, dummy2)) { + val = sub->_parse_arg(args, current_type, true); + } + if(val) { if(!sub->silent_) { parsed_subcommands_.push_back(sub); diff --git a/tests/FuzzFailTest.cpp b/tests/FuzzFailTest.cpp index 45617f50..683214a9 100644 --- a/tests/FuzzFailTest.cpp +++ b/tests/FuzzFailTest.cpp @@ -306,14 +306,13 @@ TEST_CASE("fuzz_config_modifier_test1") { CHECK(opt3->get_multi_option_policy() == CLI::MultiOptionPolicy::Sum); } -// this test uses the same tests as above just with a full roundtrip test +// this test enables the custom option creation operation TEST_CASE("app_roundtrip_custom") { CLI::FuzzApp fuzzdata; CLI::FuzzApp fuzzdata2; auto app = fuzzdata.generateApp(); auto app2 = fuzzdata2.generateApp(); - int index = GENERATE(range(1, 4)); - std::string optionString, flagString; + int index = GENERATE(range(1, 5)); auto parseData = loadFailureFile("round_trip_custom", index); std::size_t pstring_start{0}; pstring_start = fuzzdata.add_custom_options(app.get(), parseData); @@ -335,3 +334,43 @@ TEST_CASE("app_roundtrip_custom") { auto result = fuzzdata2.compare(fuzzdata); CHECK(result); } + +// this test +TEST_CASE("app_roundtrip_parse_normal_fail") { + // this is mostly checking that no unexpected errors occur + // like HorribleErrors + CLI::FuzzApp fuzzdata; + auto app = fuzzdata.generateApp(); + int index = GENERATE(range(1, 3)); + std::string optionString, flagString; + auto parseData = loadFailureFile("parse_fail_check", index); + std::size_t pstring_start{0}; + pstring_start = fuzzdata.add_custom_options(app.get(), parseData); + + try { + if(pstring_start > 0) { + app->parse(parseData.substr(pstring_start)); + } else { + app->parse(parseData); + } + } catch(const CLI::HorribleError & /*he*/) { + CHECK(false); + return; + } catch(const CLI::ParseError & /*e*/) { + CHECK(true); + return; + } + try { + // should be able to write the config to a file and read from it again + std::string configOut = app->config_to_str(); + app->clear(); + std::stringstream out(configOut); + app->parse_from_stream(out); + } catch(const CLI::HorribleError & /*he*/) { + CHECK(false); + return; + } catch(const CLI::ParseError & /*e*/) { + CHECK(false); + return; + } +} diff --git a/tests/fuzzFail/parse_fail_check1 b/tests/fuzzFail/parse_fail_check1 new file mode 100644 index 00000000..1d5d319b --- /dev/null +++ b/tests/fuzzFail/parse_fail_check1 @@ -0,0 +1 @@ +'--sub1.!-vA ' \ No newline at end of file diff --git a/tests/fuzzFail/parse_fail_check2 b/tests/fuzzFail/parse_fail_check2 new file mode 100644 index 00000000..a6ca3994 Binary files /dev/null and b/tests/fuzzFail/parse_fail_check2 differ diff --git a/tests/fuzzFail/round_trip_custom4 b/tests/fuzzFail/round_trip_custom4 new file mode 100644 index 00000000..b8202d71 --- /dev/null +++ b/tests/fuzzFail/round_trip_custom4 @@ -0,0 +1 @@ +--vC =-vA --vopt1= nan \ No newline at end of file