mirror of
https://github.com/CLIUtils/CLI11.git
synced 2026-01-19 04:52:08 +00:00
More fuzzing2 (#1170)
add mechanic for fuzzing subcommands, and several fixes for found issues from longer fuzzer runs This includes some issues with option group positional name ambiguity, issue with join multioption policy and config files, and a few edge cases for configuration of multiline output interpretation. Also added complex variables to the options, no issues found from this addition. --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
@@ -35,6 +35,7 @@ set(CLI11_TESTS
|
||||
HelpersTest
|
||||
ConfigFileTest
|
||||
OptionTypeTest
|
||||
NumericTypeTest
|
||||
SimpleTest
|
||||
AppTest
|
||||
SetTest
|
||||
|
||||
@@ -309,17 +309,50 @@ TEST_CASE("fuzz_config_modifier_test1") {
|
||||
CHECK(opt3->get_multi_option_policy() == CLI::MultiOptionPolicy::Sum);
|
||||
}
|
||||
|
||||
/** test the fuzzer itself to support custom subcommand*/
|
||||
TEST_CASE("fuzz_config_subcommand") {
|
||||
CLI::FuzzApp fuzzdata;
|
||||
auto app = fuzzdata.generateApp();
|
||||
|
||||
std::string config_string =
|
||||
"<subcommand name=sub_custom><option modifiers=R2CG>--new_option</option><flag "
|
||||
"modifiers=cFg>--new_flag</flag><vector modifiers=35s+>--new_vector</vector></subcommand>";
|
||||
auto loc = fuzzdata.add_custom_options(app.get(), config_string);
|
||||
config_string = config_string.substr(loc);
|
||||
CHECK(config_string.empty());
|
||||
auto *sub_c = app->get_subcommand("sub_custom");
|
||||
auto *opt1 = sub_c->get_option_no_throw("--new_option");
|
||||
REQUIRE(opt1 != nullptr);
|
||||
CHECK(opt1->get_required());
|
||||
CHECK(opt1->get_expected_min() == 2);
|
||||
CHECK(opt1->get_configurable());
|
||||
CHECK(opt1->get_ignore_case());
|
||||
auto *opt2 = sub_c->get_option_no_throw("--new_flag");
|
||||
REQUIRE(opt2 != nullptr);
|
||||
CHECK(opt2->get_disable_flag_override());
|
||||
CHECK(!opt2->get_configurable());
|
||||
CHECK(!opt2->get_ignore_case());
|
||||
auto *opt3 = sub_c->get_option_no_throw("--new_vector");
|
||||
REQUIRE(opt3 != nullptr);
|
||||
CHECK(opt3->get_expected_min() == 0);
|
||||
CHECK(opt3->get_expected_max() == 3);
|
||||
CHECK(opt3->get_multi_option_policy() == CLI::MultiOptionPolicy::Sum);
|
||||
}
|
||||
|
||||
// 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, 13));
|
||||
int index = GENERATE(range(1, 24));
|
||||
|
||||
auto parseData = loadFailureFile("round_trip_custom", index);
|
||||
|
||||
std::size_t pstring_start{0};
|
||||
pstring_start = fuzzdata.add_custom_options(app.get(), parseData);
|
||||
|
||||
INFO("Failure in test case " << index << " file length=" << parseData.size() << " pstring start at "
|
||||
<< pstring_start)
|
||||
if(pstring_start > 0) {
|
||||
app->parse(parseData.substr(pstring_start));
|
||||
CHECK_NOTHROW(app->help("", CLI::AppFormatMode::All));
|
||||
@@ -333,14 +366,13 @@ TEST_CASE("app_roundtrip_custom") {
|
||||
if(pstring_start > 0) {
|
||||
fuzzdata2.add_custom_options(app2.get(), parseData);
|
||||
}
|
||||
app2->parse_from_stream(out);
|
||||
CHECK_NOTHROW(app2->parse_from_stream(out));
|
||||
auto result = fuzzdata2.compare(fuzzdata);
|
||||
if(!result) {
|
||||
result = fuzzdata.compare(fuzzdata2, true);
|
||||
std::cout << "\n:parsed:\n" << parseData;
|
||||
std::cout << "\n:config:\n" << configOut << '\n';
|
||||
}
|
||||
INFO("Failure in test case " << index)
|
||||
CHECK(result);
|
||||
}
|
||||
}
|
||||
@@ -351,7 +383,7 @@ TEST_CASE("app_roundtrip_parse_normal_fail") {
|
||||
// like HorribleErrors
|
||||
CLI::FuzzApp fuzzdata;
|
||||
auto app = fuzzdata.generateApp();
|
||||
int index = GENERATE(range(1, 7));
|
||||
int index = GENERATE(range(1, 11));
|
||||
auto parseData = loadFailureFile("parse_fail_check", index);
|
||||
std::size_t pstring_start{0};
|
||||
try {
|
||||
|
||||
412
tests/NumericTypeTest.cpp
Normal file
412
tests/NumericTypeTest.cpp
Normal file
@@ -0,0 +1,412 @@
|
||||
// Copyright (c) 2017-2025, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include "app_helper.hpp"
|
||||
|
||||
#include "catch.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <complex>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <deque>
|
||||
#include <forward_list>
|
||||
#include <limits>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <queue>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
using Catch::Matchers::WithinRel;
|
||||
|
||||
TEST_CASE_METHOD(TApp, "doubleFunction", "[optiontype]") {
|
||||
double res{0.0};
|
||||
app.add_option_function<double>("--val", [&res](double val) { res = std::abs(val + 54); });
|
||||
args = {"--val", "-354.356"};
|
||||
run();
|
||||
CHECK_THAT(res, WithinRel(300.356));
|
||||
// get the original value as entered as an integer
|
||||
CHECK_THAT(app["--val"]->as<float>(), WithinRel(-354.356f));
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "doubleFunctionFail", "[optiontype]") {
|
||||
double res = NAN;
|
||||
app.add_option_function<double>("--val", [&res](double val) { res = std::abs(val + 54); });
|
||||
args = {"--val", "not_double"};
|
||||
CHECK_THROWS_AS(run(), CLI::ConversionError);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "doubleVectorFunction", "[optiontype]") {
|
||||
std::vector<double> res;
|
||||
app.add_option_function<std::vector<double>>("--val", [&res](const std::vector<double> &val) {
|
||||
res = val;
|
||||
std::transform(res.begin(), res.end(), res.begin(), [](double v) { return v + 5.0; });
|
||||
});
|
||||
args = {"--val", "5", "--val", "6", "--val", "7"};
|
||||
run();
|
||||
CHECK(3u == res.size());
|
||||
CHECK_THAT(res[0], WithinRel(10.0));
|
||||
CHECK_THAT(res[2], WithinRel(12.0));
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "doubleVectorFunctionFail", "[optiontype]") {
|
||||
std::vector<double> res;
|
||||
std::string vstring = "--val";
|
||||
app.add_option_function<std::vector<double>>(vstring, [&res](const std::vector<double> &val) {
|
||||
res = val;
|
||||
std::transform(res.begin(), res.end(), res.begin(), [](double v) { return v + 5.0; });
|
||||
});
|
||||
args = {"--val", "five", "--val", "nine", "--val", "7"};
|
||||
CHECK_THROWS_AS(run(), CLI::ConversionError);
|
||||
// check that getting the results through the results function generates the same error
|
||||
CHECK_THROWS_AS(app[vstring]->results(res), CLI::ConversionError);
|
||||
auto strvec = app[vstring]->as<std::vector<std::string>>();
|
||||
CHECK(3u == strvec.size());
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "doubleVectorFunctionRunCallbackOnDefault", "[optiontype]") {
|
||||
std::vector<double> res;
|
||||
auto *opt = app.add_option_function<std::vector<double>>("--val", [&res](const std::vector<double> &val) {
|
||||
res = val;
|
||||
std::transform(res.begin(), res.end(), res.begin(), [](double v) { return v + 5.0; });
|
||||
});
|
||||
args = {"--val", "5", "--val", "6", "--val", "7"};
|
||||
run();
|
||||
CHECK(3u == res.size());
|
||||
CHECK(10.0 == res[0]);
|
||||
CHECK(12.0 == res[2]);
|
||||
CHECK(!opt->get_run_callback_for_default());
|
||||
opt->run_callback_for_default();
|
||||
opt->default_val(std::vector<int>{2, 1, -2});
|
||||
CHECK(7.0 == res[0]);
|
||||
CHECK(3.0 == res[2]);
|
||||
|
||||
CHECK_THROWS_AS(opt->default_val("this is a string"), CLI::ConversionError);
|
||||
auto vec = opt->as<std::vector<double>>();
|
||||
REQUIRE(3U == vec.size());
|
||||
CHECK(5.0 == vec[0]);
|
||||
CHECK(7.0 == vec[2]);
|
||||
opt->check(CLI::Number);
|
||||
opt->run_callback_for_default(false);
|
||||
CHECK_THROWS_AS(opt->default_val("this is a string"), CLI::ValidationError);
|
||||
}
|
||||
|
||||
static const std::map<std::string, double> testValuesDouble{
|
||||
{"3.14159", 3.14159},
|
||||
{"-3.14159", -3.14159},
|
||||
{"-3.14159\t", -3.14159},
|
||||
{"-3.14159 ", -3.14159},
|
||||
{"+1.0", 1.0},
|
||||
{"-0.01", -0.01},
|
||||
{"-.01", -0.01},
|
||||
{"-.3251", -0.3251},
|
||||
{"+.3251", 0.3251},
|
||||
{"5e22", 5e22},
|
||||
{" 5e22", 5e22},
|
||||
{" 5e22 ", 5e22},
|
||||
{"-2E-2", -2e-2},
|
||||
{"5e+22", 5e22},
|
||||
{"1e06", 1e6},
|
||||
{"6.626e-34", 6.626e-34},
|
||||
{"6.626e+34", 6.626e34},
|
||||
{"-6.626e-34", -6.626e-34},
|
||||
{"224_617.445_991", 224617.445991},
|
||||
{"224'617.445'991", 224617.445991},
|
||||
{"inf", std::numeric_limits<double>::infinity()},
|
||||
{"+inf", std::numeric_limits<double>::infinity()},
|
||||
{"-inf", -std::numeric_limits<double>::infinity()},
|
||||
{"nan", std::numeric_limits<double>::signaling_NaN()},
|
||||
{"+nan", std::numeric_limits<double>::signaling_NaN()},
|
||||
{"-nan", -std::numeric_limits<double>::signaling_NaN()},
|
||||
|
||||
};
|
||||
|
||||
TEST_CASE_METHOD(TApp, "floatingConversions", "[optiontype]") {
|
||||
auto test_data = GENERATE(from_range(testValuesDouble));
|
||||
|
||||
double val{0};
|
||||
app.add_option("--val", val);
|
||||
|
||||
args = {"--val", test_data.first};
|
||||
|
||||
run();
|
||||
if(std::isnan(test_data.second)) {
|
||||
CHECK(std::isnan(val));
|
||||
} else {
|
||||
|
||||
CHECK_THAT(val, WithinRel(test_data.second, 1e-11));
|
||||
}
|
||||
}
|
||||
|
||||
static const std::map<std::string, std::int64_t> testValuesInt{
|
||||
{"+99", 99},
|
||||
{"99", 99},
|
||||
{"-99", -99},
|
||||
{"-99 ", -99},
|
||||
{"0xDEADBEEF", 0xDEADBEEF},
|
||||
{"0xdeadbeef", 0xDEADBEEF},
|
||||
{"0XDEADBEEF", 0xDEADBEEF},
|
||||
{"0Xdeadbeef", 0xDEADBEEF},
|
||||
{"0xdead_beef", 0xDEADBEEF},
|
||||
{"0xdead'beef", 0xDEADBEEF},
|
||||
{"0o01234567", 001234567},
|
||||
{"0o755", 0755},
|
||||
{"0755", 0755},
|
||||
{"995862_262", 995862262},
|
||||
{"995862262", 995862262},
|
||||
{"-995862275", -995862275},
|
||||
{"\t-995862275\t", -995862275},
|
||||
{"-995'862'275", -995862275},
|
||||
{"0b11010110", 0xD6},
|
||||
{"0b1101'0110", 0xD6},
|
||||
{"0B11010110", 0xD6},
|
||||
{"0B1101'0110", 0xD6},
|
||||
{"1_2_3_4_5", 12345},
|
||||
};
|
||||
|
||||
TEST_CASE_METHOD(TApp, "intConversions", "[optiontype]") {
|
||||
|
||||
auto test_data = GENERATE(from_range(testValuesInt));
|
||||
|
||||
std::int64_t val{0};
|
||||
app.add_option("--val", val);
|
||||
|
||||
args = {"--val", test_data.first};
|
||||
|
||||
run();
|
||||
|
||||
CHECK(val == test_data.second);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "intConversionsErange", "[optiontype]") {
|
||||
|
||||
std::int64_t val{0};
|
||||
app.add_option("--val", val);
|
||||
|
||||
args = {"--val", "0o11545241241415151512312415123125667"};
|
||||
|
||||
CHECK_THROWS_AS(run(), CLI::ParseError);
|
||||
|
||||
args = {"--val", "0b1011000001101011001100110011111000101010101011111111111111111111111001010111011100"};
|
||||
|
||||
CHECK_THROWS_AS(run(), CLI::ParseError);
|
||||
|
||||
args = {"--val", "0B1011000001101011001100110011111000101010101011111111111111111111111001010111011100"};
|
||||
|
||||
CHECK_THROWS_AS(run(), CLI::ParseError);
|
||||
}
|
||||
|
||||
static const std::map<std::string, std::uint64_t> testValuesUInt{
|
||||
{"+99", 99},
|
||||
{"99", 99},
|
||||
{" 99 ", 99},
|
||||
{"0xDEADBEEF", 0xDEADBEEF},
|
||||
{"0xdeadbeef", 0xDEADBEEF},
|
||||
{"0XDEADBEEF", 0xDEADBEEF},
|
||||
{"0Xdeadbeef", 0xDEADBEEF},
|
||||
{"0xdead_beef", 0xDEADBEEF},
|
||||
{"0xdead'beef", 0xDEADBEEF},
|
||||
{"0o01234567", 001234567},
|
||||
{"0o755", 0755},
|
||||
{"0o755\t", 0755},
|
||||
{"0755", 0755},
|
||||
{"995862_262", 995862262},
|
||||
{"995862262", 995862262},
|
||||
{"+995862275", +995862275},
|
||||
{"+995862275 \n\t", +995862275},
|
||||
{"995'862'275", 995862275},
|
||||
{"0b11010110", 0xD6},
|
||||
{"0b1101'0110", 0xD6},
|
||||
{"0b1101'0110 ", 0xD6},
|
||||
{"0B11010110", 0xD6},
|
||||
{"0B1101'0110", 0xD6},
|
||||
{"1_2_3_4_5", 12345},
|
||||
};
|
||||
|
||||
TEST_CASE_METHOD(TApp, "uintConversions", "[optiontype]") {
|
||||
|
||||
auto test_data = GENERATE(from_range(testValuesUInt));
|
||||
|
||||
std::uint64_t val{0};
|
||||
app.add_option("--val", val);
|
||||
|
||||
args = {"--val", test_data.first};
|
||||
|
||||
run();
|
||||
|
||||
CHECK(val == test_data.second);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "uintConversionsErange", "[optiontype]") {
|
||||
|
||||
std::uint64_t val{0};
|
||||
app.add_option("--val", val);
|
||||
|
||||
args = {"--val", "0o11545241241415151512312415123125667"};
|
||||
|
||||
CHECK_THROWS_AS(run(), CLI::ParseError);
|
||||
|
||||
args = {"--val", "0b1011000001101011001100110011111000101010101011111111111111111111111001010111011100"};
|
||||
|
||||
CHECK_THROWS_AS(run(), CLI::ParseError);
|
||||
|
||||
args = {"--val", "0B1011000001101011001100110011111000101010101011111111111111111111111001010111011100"};
|
||||
|
||||
CHECK_THROWS_AS(run(), CLI::ParseError);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "CharOption", "[optiontype]") {
|
||||
char c1{'t'};
|
||||
app.add_option("-c", c1);
|
||||
|
||||
args = {"-c", "g"};
|
||||
run();
|
||||
CHECK('g' == c1);
|
||||
|
||||
args = {"-c", "1"};
|
||||
run();
|
||||
CHECK('1' == c1);
|
||||
|
||||
args = {"-c", "77"};
|
||||
run();
|
||||
CHECK(77 == c1);
|
||||
|
||||
// convert hex for digit
|
||||
args = {"-c", "0x44"};
|
||||
run();
|
||||
CHECK(0x44 == c1);
|
||||
|
||||
args = {"-c", "751615654161688126132138844896646748852"};
|
||||
CHECK_THROWS_AS(run(), CLI::ConversionError);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "IntegerOverFlowShort", "[optiontype]") {
|
||||
std::int16_t A{0};
|
||||
std::uint16_t B{0};
|
||||
|
||||
app.add_option("-a", A);
|
||||
app.add_option("-b", B);
|
||||
|
||||
args = {"-a", "2626254242"};
|
||||
CHECK_THROWS_AS(run(), CLI::ConversionError);
|
||||
|
||||
args = {"-b", "2626254242"};
|
||||
CHECK_THROWS_AS(run(), CLI::ConversionError);
|
||||
|
||||
args = {"-b", "-26262"};
|
||||
CHECK_THROWS_AS(run(), CLI::ConversionError);
|
||||
|
||||
args = {"-b", "-262624262525"};
|
||||
CHECK_THROWS_AS(run(), CLI::ConversionError);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "IntegerOverFlowInt", "[optiontype]") {
|
||||
int A{0};
|
||||
unsigned int B{0};
|
||||
|
||||
app.add_option("-a", A);
|
||||
app.add_option("-b", B);
|
||||
|
||||
args = {"-a", "262625424225252"};
|
||||
CHECK_THROWS_AS(run(), CLI::ConversionError);
|
||||
|
||||
args = {"-b", "262625424225252"};
|
||||
CHECK_THROWS_AS(run(), CLI::ConversionError);
|
||||
|
||||
args = {"-b", "-2626225252"};
|
||||
CHECK_THROWS_AS(run(), CLI::ConversionError);
|
||||
|
||||
args = {"-b", "-26262426252525252"};
|
||||
CHECK_THROWS_AS(run(), CLI::ConversionError);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "IntegerOverFlowLong", "[optiontype]") {
|
||||
std::int32_t A{0};
|
||||
std::uint32_t B{0};
|
||||
|
||||
app.add_option("-a", A);
|
||||
app.add_option("-b", B);
|
||||
|
||||
args = {"-a", "1111111111111111111111111111"};
|
||||
CHECK_THROWS_AS(run(), CLI::ConversionError);
|
||||
|
||||
args = {"-b", "1111111111111111111111111111"};
|
||||
CHECK_THROWS_AS(run(), CLI::ConversionError);
|
||||
|
||||
args = {"-b", "-2626225252"};
|
||||
CHECK_THROWS_AS(run(), CLI::ConversionError);
|
||||
|
||||
args = {"-b", "-111111111111111111111111"};
|
||||
CHECK_THROWS_AS(run(), CLI::ConversionError);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "IntegerOverFlowLongLong", "[optiontype]") {
|
||||
std::int64_t A{0};
|
||||
std::uint64_t B{0};
|
||||
|
||||
app.add_option("-a", A);
|
||||
app.add_option("-b", B);
|
||||
|
||||
args = {"-a", "1111111111111111111111111111111111111111111111111111111111"};
|
||||
CHECK_THROWS_AS(run(), CLI::ConversionError);
|
||||
|
||||
args = {"-b", "1111111111111111111111111111111111111111111111111111111111"};
|
||||
CHECK_THROWS_AS(run(), CLI::ConversionError);
|
||||
|
||||
args = {"-b", "-2626225252"};
|
||||
CHECK_THROWS_AS(run(), CLI::ConversionError);
|
||||
|
||||
args = {"-b", "-111111111111111111111111111111111111111111111111111111111"};
|
||||
CHECK_THROWS_AS(run(), CLI::ConversionError);
|
||||
}
|
||||
|
||||
// now with tuple support this is possible
|
||||
TEST_CASE_METHOD(TApp, "floatPair", "[optiontype]") {
|
||||
|
||||
std::pair<float, float> custom_opt;
|
||||
|
||||
auto *opt = app.add_option("--fp", custom_opt)->delimiter(',');
|
||||
opt->default_str("3.4,2.7");
|
||||
|
||||
args = {"--fp", "12", "1.5"};
|
||||
|
||||
run();
|
||||
CHECK(12.0f == Approx(custom_opt.first));
|
||||
CHECK(1.5f == Approx(custom_opt.second));
|
||||
args = {};
|
||||
opt->force_callback();
|
||||
run();
|
||||
CHECK(3.4f == Approx(custom_opt.first));
|
||||
CHECK(2.7f == Approx(custom_opt.second));
|
||||
}
|
||||
|
||||
// now with tuple support this is possible
|
||||
TEST_CASE_METHOD(TApp, "doubleVector", "[optiontype]") {
|
||||
|
||||
std::vector<double> custom_opt;
|
||||
|
||||
app.add_option("--fp", custom_opt);
|
||||
|
||||
args = {"--fp", "12.7", "1.5"};
|
||||
run();
|
||||
CHECK(12.7 == Approx(custom_opt[0]));
|
||||
CHECK(1.5 == Approx(custom_opt[1]));
|
||||
args = {"--fp", "12.7", "-.5"};
|
||||
run();
|
||||
CHECK(12.7 == Approx(custom_opt[0]));
|
||||
CHECK(-0.5 == Approx(custom_opt[1]));
|
||||
|
||||
args = {"--fp", "-.7", "+.5"};
|
||||
run();
|
||||
CHECK(-0.7 == Approx(custom_opt[0]));
|
||||
CHECK(0.5 == Approx(custom_opt[1]));
|
||||
}
|
||||
@@ -51,78 +51,6 @@ TEST_CASE_METHOD(TApp, "OneStringFunction", "[optiontype]") {
|
||||
CHECK("mystring" == str);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "doubleFunction", "[optiontype]") {
|
||||
double res{0.0};
|
||||
app.add_option_function<double>("--val", [&res](double val) { res = std::abs(val + 54); });
|
||||
args = {"--val", "-354.356"};
|
||||
run();
|
||||
CHECK_THAT(res, WithinRel(300.356));
|
||||
// get the original value as entered as an integer
|
||||
CHECK_THAT(app["--val"]->as<float>(), WithinRel(-354.356f));
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "doubleFunctionFail", "[optiontype]") {
|
||||
double res = NAN;
|
||||
app.add_option_function<double>("--val", [&res](double val) { res = std::abs(val + 54); });
|
||||
args = {"--val", "not_double"};
|
||||
CHECK_THROWS_AS(run(), CLI::ConversionError);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "doubleVectorFunction", "[optiontype]") {
|
||||
std::vector<double> res;
|
||||
app.add_option_function<std::vector<double>>("--val", [&res](const std::vector<double> &val) {
|
||||
res = val;
|
||||
std::transform(res.begin(), res.end(), res.begin(), [](double v) { return v + 5.0; });
|
||||
});
|
||||
args = {"--val", "5", "--val", "6", "--val", "7"};
|
||||
run();
|
||||
CHECK(3u == res.size());
|
||||
CHECK_THAT(res[0], WithinRel(10.0));
|
||||
CHECK_THAT(res[2], WithinRel(12.0));
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "doubleVectorFunctionFail", "[optiontype]") {
|
||||
std::vector<double> res;
|
||||
std::string vstring = "--val";
|
||||
app.add_option_function<std::vector<double>>(vstring, [&res](const std::vector<double> &val) {
|
||||
res = val;
|
||||
std::transform(res.begin(), res.end(), res.begin(), [](double v) { return v + 5.0; });
|
||||
});
|
||||
args = {"--val", "five", "--val", "nine", "--val", "7"};
|
||||
CHECK_THROWS_AS(run(), CLI::ConversionError);
|
||||
// check that getting the results through the results function generates the same error
|
||||
CHECK_THROWS_AS(app[vstring]->results(res), CLI::ConversionError);
|
||||
auto strvec = app[vstring]->as<std::vector<std::string>>();
|
||||
CHECK(3u == strvec.size());
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "doubleVectorFunctionRunCallbackOnDefault", "[optiontype]") {
|
||||
std::vector<double> res;
|
||||
auto *opt = app.add_option_function<std::vector<double>>("--val", [&res](const std::vector<double> &val) {
|
||||
res = val;
|
||||
std::transform(res.begin(), res.end(), res.begin(), [](double v) { return v + 5.0; });
|
||||
});
|
||||
args = {"--val", "5", "--val", "6", "--val", "7"};
|
||||
run();
|
||||
CHECK(3u == res.size());
|
||||
CHECK(10.0 == res[0]);
|
||||
CHECK(12.0 == res[2]);
|
||||
CHECK(!opt->get_run_callback_for_default());
|
||||
opt->run_callback_for_default();
|
||||
opt->default_val(std::vector<int>{2, 1, -2});
|
||||
CHECK(7.0 == res[0]);
|
||||
CHECK(3.0 == res[2]);
|
||||
|
||||
CHECK_THROWS_AS(opt->default_val("this is a string"), CLI::ConversionError);
|
||||
auto vec = opt->as<std::vector<double>>();
|
||||
REQUIRE(3U == vec.size());
|
||||
CHECK(5.0 == vec[0]);
|
||||
CHECK(7.0 == vec[2]);
|
||||
opt->check(CLI::Number);
|
||||
opt->run_callback_for_default(false);
|
||||
CHECK_THROWS_AS(opt->default_val("this is a string"), CLI::ValidationError);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "BoolAndIntFlags", "[optiontype]") {
|
||||
|
||||
bool bflag{false};
|
||||
@@ -225,195 +153,6 @@ TEST_CASE_METHOD(TApp, "atomic_int_option", "[optiontype]") {
|
||||
CHECK(0 == i);
|
||||
}
|
||||
|
||||
static const std::map<std::string, double> testValuesDouble{
|
||||
{"3.14159", 3.14159},
|
||||
{"-3.14159", -3.14159},
|
||||
{"-3.14159\t", -3.14159},
|
||||
{"-3.14159 ", -3.14159},
|
||||
{"+1.0", 1.0},
|
||||
{"-0.01", -0.01},
|
||||
{"-.01", -0.01},
|
||||
{"-.3251", -0.3251},
|
||||
{"+.3251", 0.3251},
|
||||
{"5e22", 5e22},
|
||||
{" 5e22", 5e22},
|
||||
{" 5e22 ", 5e22},
|
||||
{"-2E-2", -2e-2},
|
||||
{"5e+22", 5e22},
|
||||
{"1e06", 1e6},
|
||||
{"6.626e-34", 6.626e-34},
|
||||
{"6.626e+34", 6.626e34},
|
||||
{"-6.626e-34", -6.626e-34},
|
||||
{"224_617.445_991", 224617.445991},
|
||||
{"224'617.445'991", 224617.445991},
|
||||
{"inf", std::numeric_limits<double>::infinity()},
|
||||
{"+inf", std::numeric_limits<double>::infinity()},
|
||||
{"-inf", -std::numeric_limits<double>::infinity()},
|
||||
{"nan", std::numeric_limits<double>::signaling_NaN()},
|
||||
{"+nan", std::numeric_limits<double>::signaling_NaN()},
|
||||
{"-nan", -std::numeric_limits<double>::signaling_NaN()},
|
||||
|
||||
};
|
||||
|
||||
TEST_CASE_METHOD(TApp, "floatingConversions", "[optiontype]") {
|
||||
auto test_data = GENERATE(from_range(testValuesDouble));
|
||||
|
||||
double val{0};
|
||||
app.add_option("--val", val);
|
||||
|
||||
args = {"--val", test_data.first};
|
||||
|
||||
run();
|
||||
if(std::isnan(test_data.second)) {
|
||||
CHECK(std::isnan(val));
|
||||
} else {
|
||||
|
||||
CHECK_THAT(val, WithinRel(test_data.second, 1e-11));
|
||||
}
|
||||
}
|
||||
|
||||
static const std::map<std::string, std::int64_t> testValuesInt{
|
||||
{"+99", 99},
|
||||
{"99", 99},
|
||||
{"-99", -99},
|
||||
{"-99 ", -99},
|
||||
{"0xDEADBEEF", 0xDEADBEEF},
|
||||
{"0xdeadbeef", 0xDEADBEEF},
|
||||
{"0XDEADBEEF", 0xDEADBEEF},
|
||||
{"0Xdeadbeef", 0xDEADBEEF},
|
||||
{"0xdead_beef", 0xDEADBEEF},
|
||||
{"0xdead'beef", 0xDEADBEEF},
|
||||
{"0o01234567", 001234567},
|
||||
{"0o755", 0755},
|
||||
{"0755", 0755},
|
||||
{"995862_262", 995862262},
|
||||
{"995862262", 995862262},
|
||||
{"-995862275", -995862275},
|
||||
{"\t-995862275\t", -995862275},
|
||||
{"-995'862'275", -995862275},
|
||||
{"0b11010110", 0xD6},
|
||||
{"0b1101'0110", 0xD6},
|
||||
{"0B11010110", 0xD6},
|
||||
{"0B1101'0110", 0xD6},
|
||||
{"1_2_3_4_5", 12345},
|
||||
};
|
||||
|
||||
TEST_CASE_METHOD(TApp, "intConversions", "[optiontype]") {
|
||||
|
||||
auto test_data = GENERATE(from_range(testValuesInt));
|
||||
|
||||
std::int64_t val{0};
|
||||
app.add_option("--val", val);
|
||||
|
||||
args = {"--val", test_data.first};
|
||||
|
||||
run();
|
||||
|
||||
CHECK(val == test_data.second);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "intConversionsErange", "[optiontype]") {
|
||||
|
||||
std::int64_t val{0};
|
||||
app.add_option("--val", val);
|
||||
|
||||
args = {"--val", "0o11545241241415151512312415123125667"};
|
||||
|
||||
CHECK_THROWS_AS(run(), CLI::ParseError);
|
||||
|
||||
args = {"--val", "0b1011000001101011001100110011111000101010101011111111111111111111111001010111011100"};
|
||||
|
||||
CHECK_THROWS_AS(run(), CLI::ParseError);
|
||||
|
||||
args = {"--val", "0B1011000001101011001100110011111000101010101011111111111111111111111001010111011100"};
|
||||
|
||||
CHECK_THROWS_AS(run(), CLI::ParseError);
|
||||
}
|
||||
|
||||
static const std::map<std::string, std::uint64_t> testValuesUInt{
|
||||
{"+99", 99},
|
||||
{"99", 99},
|
||||
{" 99 ", 99},
|
||||
{"0xDEADBEEF", 0xDEADBEEF},
|
||||
{"0xdeadbeef", 0xDEADBEEF},
|
||||
{"0XDEADBEEF", 0xDEADBEEF},
|
||||
{"0Xdeadbeef", 0xDEADBEEF},
|
||||
{"0xdead_beef", 0xDEADBEEF},
|
||||
{"0xdead'beef", 0xDEADBEEF},
|
||||
{"0o01234567", 001234567},
|
||||
{"0o755", 0755},
|
||||
{"0o755\t", 0755},
|
||||
{"0755", 0755},
|
||||
{"995862_262", 995862262},
|
||||
{"995862262", 995862262},
|
||||
{"+995862275", +995862275},
|
||||
{"+995862275 \n\t", +995862275},
|
||||
{"995'862'275", 995862275},
|
||||
{"0b11010110", 0xD6},
|
||||
{"0b1101'0110", 0xD6},
|
||||
{"0b1101'0110 ", 0xD6},
|
||||
{"0B11010110", 0xD6},
|
||||
{"0B1101'0110", 0xD6},
|
||||
{"1_2_3_4_5", 12345},
|
||||
};
|
||||
|
||||
TEST_CASE_METHOD(TApp, "uintConversions", "[optiontype]") {
|
||||
|
||||
auto test_data = GENERATE(from_range(testValuesUInt));
|
||||
|
||||
std::uint64_t val{0};
|
||||
app.add_option("--val", val);
|
||||
|
||||
args = {"--val", test_data.first};
|
||||
|
||||
run();
|
||||
|
||||
CHECK(val == test_data.second);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "uintConversionsErange", "[optiontype]") {
|
||||
|
||||
std::uint64_t val{0};
|
||||
app.add_option("--val", val);
|
||||
|
||||
args = {"--val", "0o11545241241415151512312415123125667"};
|
||||
|
||||
CHECK_THROWS_AS(run(), CLI::ParseError);
|
||||
|
||||
args = {"--val", "0b1011000001101011001100110011111000101010101011111111111111111111111001010111011100"};
|
||||
|
||||
CHECK_THROWS_AS(run(), CLI::ParseError);
|
||||
|
||||
args = {"--val", "0B1011000001101011001100110011111000101010101011111111111111111111111001010111011100"};
|
||||
|
||||
CHECK_THROWS_AS(run(), CLI::ParseError);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "CharOption", "[optiontype]") {
|
||||
char c1{'t'};
|
||||
app.add_option("-c", c1);
|
||||
|
||||
args = {"-c", "g"};
|
||||
run();
|
||||
CHECK('g' == c1);
|
||||
|
||||
args = {"-c", "1"};
|
||||
run();
|
||||
CHECK('1' == c1);
|
||||
|
||||
args = {"-c", "77"};
|
||||
run();
|
||||
CHECK(77 == c1);
|
||||
|
||||
// convert hex for digit
|
||||
args = {"-c", "0x44"};
|
||||
run();
|
||||
CHECK(0x44 == c1);
|
||||
|
||||
args = {"-c", "751615654161688126132138844896646748852"};
|
||||
CHECK_THROWS_AS(run(), CLI::ConversionError);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "vectorDefaults", "[optiontype]") {
|
||||
std::vector<int> vals{4, 5};
|
||||
auto *opt = app.add_option("--long", vals)->capture_default_str();
|
||||
@@ -606,86 +345,6 @@ TEST_CASE_METHOD(TApp, "VectorIndexedValidator", "[optiontype]") {
|
||||
CHECK_THROWS_AS(run(), CLI::ValidationError);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "IntegerOverFlowShort", "[optiontype]") {
|
||||
std::int16_t A{0};
|
||||
std::uint16_t B{0};
|
||||
|
||||
app.add_option("-a", A);
|
||||
app.add_option("-b", B);
|
||||
|
||||
args = {"-a", "2626254242"};
|
||||
CHECK_THROWS_AS(run(), CLI::ConversionError);
|
||||
|
||||
args = {"-b", "2626254242"};
|
||||
CHECK_THROWS_AS(run(), CLI::ConversionError);
|
||||
|
||||
args = {"-b", "-26262"};
|
||||
CHECK_THROWS_AS(run(), CLI::ConversionError);
|
||||
|
||||
args = {"-b", "-262624262525"};
|
||||
CHECK_THROWS_AS(run(), CLI::ConversionError);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "IntegerOverFlowInt", "[optiontype]") {
|
||||
int A{0};
|
||||
unsigned int B{0};
|
||||
|
||||
app.add_option("-a", A);
|
||||
app.add_option("-b", B);
|
||||
|
||||
args = {"-a", "262625424225252"};
|
||||
CHECK_THROWS_AS(run(), CLI::ConversionError);
|
||||
|
||||
args = {"-b", "262625424225252"};
|
||||
CHECK_THROWS_AS(run(), CLI::ConversionError);
|
||||
|
||||
args = {"-b", "-2626225252"};
|
||||
CHECK_THROWS_AS(run(), CLI::ConversionError);
|
||||
|
||||
args = {"-b", "-26262426252525252"};
|
||||
CHECK_THROWS_AS(run(), CLI::ConversionError);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "IntegerOverFlowLong", "[optiontype]") {
|
||||
std::int32_t A{0};
|
||||
std::uint32_t B{0};
|
||||
|
||||
app.add_option("-a", A);
|
||||
app.add_option("-b", B);
|
||||
|
||||
args = {"-a", "1111111111111111111111111111"};
|
||||
CHECK_THROWS_AS(run(), CLI::ConversionError);
|
||||
|
||||
args = {"-b", "1111111111111111111111111111"};
|
||||
CHECK_THROWS_AS(run(), CLI::ConversionError);
|
||||
|
||||
args = {"-b", "-2626225252"};
|
||||
CHECK_THROWS_AS(run(), CLI::ConversionError);
|
||||
|
||||
args = {"-b", "-111111111111111111111111"};
|
||||
CHECK_THROWS_AS(run(), CLI::ConversionError);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "IntegerOverFlowLongLong", "[optiontype]") {
|
||||
std::int64_t A{0};
|
||||
std::uint64_t B{0};
|
||||
|
||||
app.add_option("-a", A);
|
||||
app.add_option("-b", B);
|
||||
|
||||
args = {"-a", "1111111111111111111111111111111111111111111111111111111111"};
|
||||
CHECK_THROWS_AS(run(), CLI::ConversionError);
|
||||
|
||||
args = {"-b", "1111111111111111111111111111111111111111111111111111111111"};
|
||||
CHECK_THROWS_AS(run(), CLI::ConversionError);
|
||||
|
||||
args = {"-b", "-2626225252"};
|
||||
CHECK_THROWS_AS(run(), CLI::ConversionError);
|
||||
|
||||
args = {"-b", "-111111111111111111111111111111111111111111111111111111111"};
|
||||
CHECK_THROWS_AS(run(), CLI::ConversionError);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "VectorUnlimString", "[optiontype]") {
|
||||
std::vector<std::string> strvec;
|
||||
std::vector<std::string> answer{"mystring", "mystring2", "mystring3"};
|
||||
@@ -805,48 +464,6 @@ TEST_CASE_METHOD(TApp, "CustomDoubleOptionAlt", "[optiontype]") {
|
||||
CHECK(1.5 == Approx(custom_opt.second));
|
||||
}
|
||||
|
||||
// now with tuple support this is possible
|
||||
TEST_CASE_METHOD(TApp, "floatPair", "[optiontype]") {
|
||||
|
||||
std::pair<float, float> custom_opt;
|
||||
|
||||
auto *opt = app.add_option("--fp", custom_opt)->delimiter(',');
|
||||
opt->default_str("3.4,2.7");
|
||||
|
||||
args = {"--fp", "12", "1.5"};
|
||||
|
||||
run();
|
||||
CHECK(12.0f == Approx(custom_opt.first));
|
||||
CHECK(1.5f == Approx(custom_opt.second));
|
||||
args = {};
|
||||
opt->force_callback();
|
||||
run();
|
||||
CHECK(3.4f == Approx(custom_opt.first));
|
||||
CHECK(2.7f == Approx(custom_opt.second));
|
||||
}
|
||||
|
||||
// now with tuple support this is possible
|
||||
TEST_CASE_METHOD(TApp, "doubleVector", "[optiontype]") {
|
||||
|
||||
std::vector<double> custom_opt;
|
||||
|
||||
app.add_option("--fp", custom_opt);
|
||||
|
||||
args = {"--fp", "12.7", "1.5"};
|
||||
run();
|
||||
CHECK(12.7 == Approx(custom_opt[0]));
|
||||
CHECK(1.5 == Approx(custom_opt[1]));
|
||||
args = {"--fp", "12.7", "-.5"};
|
||||
run();
|
||||
CHECK(12.7 == Approx(custom_opt[0]));
|
||||
CHECK(-0.5 == Approx(custom_opt[1]));
|
||||
|
||||
args = {"--fp", "-.7", "+.5"};
|
||||
run();
|
||||
CHECK(-0.7 == Approx(custom_opt[0]));
|
||||
CHECK(0.5 == Approx(custom_opt[1]));
|
||||
}
|
||||
|
||||
// now with independent type sizes and expected this is possible
|
||||
TEST_CASE_METHOD(TApp, "vectorPair", "[optiontype]") {
|
||||
|
||||
|
||||
BIN
tests/fuzzFail/parse_fail_check10
Normal file
BIN
tests/fuzzFail/parse_fail_check10
Normal file
Binary file not shown.
BIN
tests/fuzzFail/parse_fail_check7
Normal file
BIN
tests/fuzzFail/parse_fail_check7
Normal file
Binary file not shown.
BIN
tests/fuzzFail/parse_fail_check8
Normal file
BIN
tests/fuzzFail/parse_fail_check8
Normal file
Binary file not shown.
BIN
tests/fuzzFail/parse_fail_check9
Normal file
BIN
tests/fuzzFail/parse_fail_check9
Normal file
Binary file not shown.
28
tests/fuzzFail/round_trip_custom12
Normal file
28
tests/fuzzFail/round_trip_custom12
Normal file
@@ -0,0 +1,28 @@
|
||||
"--vA=
|
||||
|
||||
vA
|
||||
-
|
||||
=--svtup
|
||||
|
||||
vA=
|
||||
-d'=--svt=-
|
||||
v vA
|
||||
-
|
||||
=-
|
||||
v =--svtup
|
||||
|
||||
vA=
|
||||
-d'=--svtup
|
||||
|
||||
vA--svtup
|
||||
|
||||
vA=
|
||||
-d'=--svtup
|
||||
|
||||
vA=
|
||||
-d'
|
||||
|
||||
=
|
||||
-d'
|
||||
|
||||
""
|
||||
BIN
tests/fuzzFail/round_trip_custom14
Normal file
BIN
tests/fuzzFail/round_trip_custom14
Normal file
Binary file not shown.
BIN
tests/fuzzFail/round_trip_custom15
Normal file
BIN
tests/fuzzFail/round_trip_custom15
Normal file
Binary file not shown.
BIN
tests/fuzzFail/round_trip_custom16
Normal file
BIN
tests/fuzzFail/round_trip_custom16
Normal file
Binary file not shown.
BIN
tests/fuzzFail/round_trip_custom17
Normal file
BIN
tests/fuzzFail/round_trip_custom17
Normal file
Binary file not shown.
BIN
tests/fuzzFail/round_trip_custom18
Normal file
BIN
tests/fuzzFail/round_trip_custom18
Normal file
Binary file not shown.
BIN
tests/fuzzFail/round_trip_custom19
Normal file
BIN
tests/fuzzFail/round_trip_custom19
Normal file
Binary file not shown.
BIN
tests/fuzzFail/round_trip_custom20
Normal file
BIN
tests/fuzzFail/round_trip_custom20
Normal file
Binary file not shown.
1
tests/fuzzFail/round_trip_custom21
Normal file
1
tests/fuzzFail/round_trip_custom21
Normal file
@@ -0,0 +1 @@
|
||||
--vSt--vSyt--vSyt
|
||||
4
tests/fuzzFail/round_trip_custom22
Normal file
4
tests/fuzzFail/round_trip_custom22
Normal file
@@ -0,0 +1,4 @@
|
||||
--vD=`=\
|
||||
-3333pt4=
|
||||
|
||||
--vop= -t=0f3*333334==333333333333333#333333opt1333333333333up23334-aa-ccca333aaaaaa66
|
||||
BIN
tests/fuzzFail/round_trip_custom23
Normal file
BIN
tests/fuzzFail/round_trip_custom23
Normal file
Binary file not shown.
Reference in New Issue
Block a user