mirror of
https://github.com/CLIUtils/CLI11.git
synced 2025-04-29 12:13:52 +00:00
Fix some minor fuzzing issues. (#1138)
One in the fuzz check handling of NaN's and a pathway to generate a HorribleError. --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
parent
f871b625ee
commit
2d79205521
@ -193,7 +193,18 @@ bool FuzzApp::compare(const FuzzApp &other) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(vv1 != other.vv1) {
|
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) {
|
if(vstr != other.vstr) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -1951,7 +1951,7 @@ App::_parse_arg(std::vector<std::string> &args, detail::Classifier current_type,
|
|||||||
|
|
||||||
// now check for '.' notation of subcommands
|
// now check for '.' notation of subcommands
|
||||||
auto dotloc = arg_name.find_first_of('.', 1);
|
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
|
// using dot notation is equivalent to single argument subcommand
|
||||||
auto *sub = _find_subcommand(arg_name.substr(0, dotloc), true, false);
|
auto *sub = _find_subcommand(arg_name.substr(0, dotloc), true, false);
|
||||||
if(sub != nullptr) {
|
if(sub != nullptr) {
|
||||||
@ -1972,7 +1972,12 @@ App::_parse_arg(std::vector<std::string> &args, detail::Classifier current_type,
|
|||||||
args.push_back(nval);
|
args.push_back(nval);
|
||||||
current_type = detail::Classifier::SHORT;
|
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(val) {
|
||||||
if(!sub->silent_) {
|
if(!sub->silent_) {
|
||||||
parsed_subcommands_.push_back(sub);
|
parsed_subcommands_.push_back(sub);
|
||||||
|
@ -306,14 +306,13 @@ TEST_CASE("fuzz_config_modifier_test1") {
|
|||||||
CHECK(opt3->get_multi_option_policy() == CLI::MultiOptionPolicy::Sum);
|
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") {
|
TEST_CASE("app_roundtrip_custom") {
|
||||||
CLI::FuzzApp fuzzdata;
|
CLI::FuzzApp fuzzdata;
|
||||||
CLI::FuzzApp fuzzdata2;
|
CLI::FuzzApp fuzzdata2;
|
||||||
auto app = fuzzdata.generateApp();
|
auto app = fuzzdata.generateApp();
|
||||||
auto app2 = fuzzdata2.generateApp();
|
auto app2 = fuzzdata2.generateApp();
|
||||||
int index = GENERATE(range(1, 4));
|
int index = GENERATE(range(1, 5));
|
||||||
std::string optionString, flagString;
|
|
||||||
auto parseData = loadFailureFile("round_trip_custom", index);
|
auto parseData = loadFailureFile("round_trip_custom", index);
|
||||||
std::size_t pstring_start{0};
|
std::size_t pstring_start{0};
|
||||||
pstring_start = fuzzdata.add_custom_options(app.get(), parseData);
|
pstring_start = fuzzdata.add_custom_options(app.get(), parseData);
|
||||||
@ -335,3 +334,43 @@ TEST_CASE("app_roundtrip_custom") {
|
|||||||
auto result = fuzzdata2.compare(fuzzdata);
|
auto result = fuzzdata2.compare(fuzzdata);
|
||||||
CHECK(result);
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
1
tests/fuzzFail/parse_fail_check1
Normal file
1
tests/fuzzFail/parse_fail_check1
Normal file
@ -0,0 +1 @@
|
|||||||
|
'--sub1.!-vA '
|
BIN
tests/fuzzFail/parse_fail_check2
Normal file
BIN
tests/fuzzFail/parse_fail_check2
Normal file
Binary file not shown.
1
tests/fuzzFail/round_trip_custom4
Normal file
1
tests/fuzzFail/round_trip_custom4
Normal file
@ -0,0 +1 @@
|
|||||||
|
--vC
=-vA --vopt1=
nan
|
Loading…
x
Reference in New Issue
Block a user