mirror of
https://github.com/CLIUtils/CLI11.git
synced 2025-04-30 12:43:52 +00:00
fix: improve some confusing error situations with config files (#781)
* add some more tests for coverage and fix some confusing error situations with config files. * style: pre-commit.ci fixes * fix warning * ci: fix coverage Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Henry Schreiner <HenrySchreinerIII@gmail.com>
This commit is contained in:
parent
dcbcb4721d
commit
fd30b5989f
10
.github/workflows/tests.yml
vendored
10
.github/workflows/tests.yml
vendored
@ -20,6 +20,8 @@ jobs:
|
|||||||
precompile: ["ON", "OFF"]
|
precompile: ["ON", "OFF"]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Get LCov
|
- name: Get LCov
|
||||||
run: |
|
run: |
|
||||||
@ -50,11 +52,9 @@ jobs:
|
|||||||
lcov --list coverage.info
|
lcov --list coverage.info
|
||||||
working-directory: build
|
working-directory: build
|
||||||
|
|
||||||
- name: Upload coverage
|
- uses: codecov/codecov-action@v3
|
||||||
run: |
|
with:
|
||||||
curl -Os https://uploader.codecov.io/latest/linux/codecov
|
fail_ci_if_error: true
|
||||||
chmod +x codecov
|
|
||||||
./codecov
|
|
||||||
working-directory: build
|
working-directory: build
|
||||||
|
|
||||||
clang-tidy:
|
clang-tidy:
|
||||||
|
@ -1384,17 +1384,24 @@ CLI11_INLINE bool App::_parse_single_config(const ConfigItem &item, std::size_t
|
|||||||
if(op->empty()) {
|
if(op->empty()) {
|
||||||
|
|
||||||
if(op->get_expected_min() == 0) {
|
if(op->get_expected_min() == 0) {
|
||||||
|
if(item.inputs.size() <= 1) {
|
||||||
// Flag parsing
|
// Flag parsing
|
||||||
auto res = config_formatter_->to_flag(item);
|
auto res = config_formatter_->to_flag(item);
|
||||||
res = op->get_flag_value(item.name, res);
|
res = op->get_flag_value(item.name, res);
|
||||||
|
|
||||||
op->add_result(res);
|
op->add_result(res);
|
||||||
|
return true;
|
||||||
} else {
|
}
|
||||||
|
if(static_cast<int>(item.inputs.size()) > op->get_items_expected_max()) {
|
||||||
|
if(op->get_items_expected_max() > 1) {
|
||||||
|
throw ArgumentMismatch::AtMost(item.fullname(), op->get_items_expected_max(), item.inputs.size());
|
||||||
|
}
|
||||||
|
throw ConversionError::TooManyInputsFlag(item.fullname());
|
||||||
|
}
|
||||||
|
}
|
||||||
op->add_result(item.inputs);
|
op->add_result(item.inputs);
|
||||||
op->run_callback();
|
op->run_callback();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -981,7 +981,9 @@ TEST_CASE_METHOD(TApp, "emptyVectorReturn", "[app]") {
|
|||||||
|
|
||||||
std::vector<std::string> strs;
|
std::vector<std::string> strs;
|
||||||
std::vector<std::string> strs2;
|
std::vector<std::string> strs2;
|
||||||
|
std::vector<std::string> strs3;
|
||||||
auto *opt1 = app.add_option("--str", strs)->required()->expected(0, 2);
|
auto *opt1 = app.add_option("--str", strs)->required()->expected(0, 2);
|
||||||
|
app.add_option("--str3", strs3)->expected(1, 3);
|
||||||
app.add_option("--str2", strs2);
|
app.add_option("--str2", strs2);
|
||||||
args = {"--str"};
|
args = {"--str"};
|
||||||
|
|
||||||
@ -1004,6 +1006,11 @@ TEST_CASE_METHOD(TApp, "emptyVectorReturn", "[app]") {
|
|||||||
|
|
||||||
CHECK_NOTHROW(run());
|
CHECK_NOTHROW(run());
|
||||||
CHECK(strs.empty());
|
CHECK(strs.empty());
|
||||||
|
opt1->required(false);
|
||||||
|
args = {"--str3", "{}"};
|
||||||
|
|
||||||
|
CHECK_NOTHROW(run());
|
||||||
|
CHECK_FALSE(strs3.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE_METHOD(TApp, "RequiredOptsDoubleShort", "[app]") {
|
TEST_CASE_METHOD(TApp, "RequiredOptsDoubleShort", "[app]") {
|
||||||
|
@ -1017,17 +1017,19 @@ TEST_CASE_METHOD(TApp, "TOMLStringVector", "[config]") {
|
|||||||
out << "zero1=[]\n";
|
out << "zero1=[]\n";
|
||||||
out << "zero2={}\n";
|
out << "zero2={}\n";
|
||||||
out << "zero3={}\n";
|
out << "zero3={}\n";
|
||||||
|
out << "zero4=[\"{}\",\"\"]\n";
|
||||||
out << "nzero={}\n";
|
out << "nzero={}\n";
|
||||||
out << "one=[\"1\"]\n";
|
out << "one=[\"1\"]\n";
|
||||||
out << "two=[\"2\",\"3\"]\n";
|
out << "two=[\"2\",\"3\"]\n";
|
||||||
out << "three=[\"1\",\"2\",\"3\"]\n";
|
out << "three=[\"1\",\"2\",\"3\"]\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> nzero, zero1, zero2, zero3, one, two, three;
|
std::vector<std::string> nzero, zero1, zero2, zero3, zero4, one, two, three;
|
||||||
app.add_option("--zero1", zero1)->required()->expected(0, 99)->default_str("{}");
|
app.add_option("--zero1", zero1)->required()->expected(0, 99)->default_str("{}");
|
||||||
app.add_option("--zero2", zero2)->required()->expected(0, 99)->default_val(std::vector<std::string>{});
|
app.add_option("--zero2", zero2)->required()->expected(0, 99)->default_val(std::vector<std::string>{});
|
||||||
// if no default is specified the argument results in an empty string
|
// if no default is specified the argument results in an empty string
|
||||||
app.add_option("--zero3", zero3)->required()->expected(0, 99);
|
app.add_option("--zero3", zero3)->required()->expected(0, 99);
|
||||||
|
app.add_option("--zero4", zero4)->required()->expected(0, 99);
|
||||||
app.add_option("--nzero", nzero)->required();
|
app.add_option("--nzero", nzero)->required();
|
||||||
app.add_option("--one", one)->required();
|
app.add_option("--one", one)->required();
|
||||||
app.add_option("--two", two)->required();
|
app.add_option("--two", two)->required();
|
||||||
@ -1038,6 +1040,7 @@ TEST_CASE_METHOD(TApp, "TOMLStringVector", "[config]") {
|
|||||||
CHECK(zero1 == std::vector<std::string>({}));
|
CHECK(zero1 == std::vector<std::string>({}));
|
||||||
CHECK(zero2 == std::vector<std::string>({}));
|
CHECK(zero2 == std::vector<std::string>({}));
|
||||||
CHECK(zero3 == std::vector<std::string>({""}));
|
CHECK(zero3 == std::vector<std::string>({""}));
|
||||||
|
CHECK(zero4 == std::vector<std::string>({"{}"}));
|
||||||
CHECK(nzero == std::vector<std::string>({"{}"}));
|
CHECK(nzero == std::vector<std::string>({"{}"}));
|
||||||
CHECK(one == std::vector<std::string>({"1"}));
|
CHECK(one == std::vector<std::string>({"1"}));
|
||||||
CHECK(two == std::vector<std::string>({"2", "3"}));
|
CHECK(two == std::vector<std::string>({"2", "3"}));
|
||||||
@ -1735,6 +1738,23 @@ TEST_CASE_METHOD(TApp, "IniFlagDual", "[config]") {
|
|||||||
CHECK_THROWS_AS(run(), CLI::ConversionError);
|
CHECK_THROWS_AS(run(), CLI::ConversionError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE_METHOD(TApp, "IniVectorMax", "[config]") {
|
||||||
|
|
||||||
|
TempFile tmpini{"TestIniTmp.ini"};
|
||||||
|
|
||||||
|
std::vector<std::string> v1;
|
||||||
|
app.config_formatter(std::make_shared<CLI::ConfigINI>());
|
||||||
|
app.add_option("--vec", v1)->expected(0, 2);
|
||||||
|
app.set_config("--config", tmpini);
|
||||||
|
|
||||||
|
{
|
||||||
|
std::ofstream out{tmpini};
|
||||||
|
out << "vec=[a,b,c]" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
CHECK_THROWS_AS(run(), CLI::ArgumentMismatch);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE_METHOD(TApp, "IniShort", "[config]") {
|
TEST_CASE_METHOD(TApp, "IniShort", "[config]") {
|
||||||
|
|
||||||
TempFile tmpini{"TestIniTmp.ini"};
|
TempFile tmpini{"TestIniTmp.ini"};
|
||||||
|
@ -974,6 +974,16 @@ TEST_CASE("THelp: GroupOrder", "[help]") {
|
|||||||
CHECK(aee_loc > zee_loc);
|
CHECK(aee_loc > zee_loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("THelp: GroupNameError", "[help]") {
|
||||||
|
CLI::App app;
|
||||||
|
|
||||||
|
auto *f1 = app.add_flag("--one");
|
||||||
|
auto *f2 = app.add_flag("--two");
|
||||||
|
|
||||||
|
CHECK_THROWS_AS(f1->group("evil group name\non two lines"), CLI::IncorrectConstruction);
|
||||||
|
CHECK_THROWS_AS(f2->group(std::string(5, '\0')), CLI::IncorrectConstruction);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE("THelp: ValidatorsText", "[help]") {
|
TEST_CASE("THelp: ValidatorsText", "[help]") {
|
||||||
CLI::App app;
|
CLI::App app;
|
||||||
|
|
||||||
|
@ -492,6 +492,23 @@ TEST_CASE_METHOD(TApp, "FailSet", "[set]") {
|
|||||||
CHECK_THROWS_AS(run(), CLI::ValidationError);
|
CHECK_THROWS_AS(run(), CLI::ValidationError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE_METHOD(TApp, "shortStringCheck", "[set]") {
|
||||||
|
|
||||||
|
std::string choice;
|
||||||
|
app.add_option("-q,--quick", choice)->check([](const std::string &v) {
|
||||||
|
if(v.size() > 5) {
|
||||||
|
return std::string{"string too long"};
|
||||||
|
}
|
||||||
|
return std::string{};
|
||||||
|
});
|
||||||
|
|
||||||
|
args = {"--quick", "3"};
|
||||||
|
CHECK_NOTHROW(run());
|
||||||
|
|
||||||
|
args = {"--quick=hello_goodbye"};
|
||||||
|
CHECK_THROWS_AS(run(), CLI::ValidationError);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE_METHOD(TApp, "FailMutableSet", "[set]") {
|
TEST_CASE_METHOD(TApp, "FailMutableSet", "[set]") {
|
||||||
|
|
||||||
int choice{0};
|
int choice{0};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user