diff --git a/include/CLI/TypeTools.hpp b/include/CLI/TypeTools.hpp index d55aec7f6..a2857265a 100644 --- a/include/CLI/TypeTools.hpp +++ b/include/CLI/TypeTools.hpp @@ -816,11 +816,15 @@ inline std::string type_name() { /// Convert to an unsigned integral template ::value, detail::enabler> = detail::dummy> bool integral_conversion(const std::string &input, T &output) noexcept { - if(input.empty()) { + if(input.empty() || input.front() == '-') { return false; } char *val = nullptr; + errno = 0; std::uint64_t output_ll = std::strtoull(input.c_str(), &val, 0); + if(errno == ERANGE) { + return false; + } output = static_cast(output_ll); if(val == (input.c_str() + input.size()) && static_cast(output) == output_ll) { return true; @@ -841,7 +845,11 @@ bool integral_conversion(const std::string &input, T &output) noexcept { return false; } char *val = nullptr; + errno = 0; std::int64_t output_ll = std::strtoll(input.c_str(), &val, 0); + if(errno == ERANGE) { + return false; + } output = static_cast(output_ll); if(val == (input.c_str() + input.size()) && static_cast(output) == output_ll) { return true; diff --git a/tests/AppTest.cpp b/tests/AppTest.cpp index 2caa8ce4b..a37958dc5 100644 --- a/tests/AppTest.cpp +++ b/tests/AppTest.cpp @@ -1995,6 +1995,31 @@ TEST_CASE_METHOD(TApp, "typeCheck", "[app]") { CHECK_THROWS_AS(run(), CLI::ValidationError); } +TEST_CASE_METHOD(TApp, "NeedsTrue", "[app]") { + std::string str; + app.add_option("-s,--string", str); + app.add_flag("--opt1")->check([&](const std::string &) { + return (str != "val_with_opt1") ? std::string("--opt1 requires --string val_with_opt1") : std::string{}; + }); + + run(); + + args = {"--opt1"}; + CHECK_THROWS_AS(run(), CLI::ValidationError); + + args = {"--string", "val"}; + run(); + + args = {"--string", "val", "--opt1"}; + CHECK_THROWS_AS(run(), CLI::ValidationError); + + args = {"--string", "val_with_opt1", "--opt1"}; + run(); + + args = {"--opt1", "--string", "val_with_opt1"}; // order is not revelant + run(); +} + // Check to make sure programmatic access to left over is available TEST_CASE_METHOD(TApp, "AllowExtras", "[app]") { diff --git a/tests/OptionTypeTest.cpp b/tests/OptionTypeTest.cpp index b48ba6d5b..4c23ecc71 100644 --- a/tests/OptionTypeTest.cpp +++ b/tests/OptionTypeTest.cpp @@ -405,6 +405,86 @@ 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 strvec; std::vector answer{"mystring", "mystring2", "mystring3"};