mirror of
https://github.com/CLIUtils/CLI11.git
synced 2026-01-19 04:52:08 +00:00
Tests (#1165)
Handle RTTI in a consistent way for locale inclusion for integral conversion. Resolve some missing code coverage lines. --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Alexander Galanin <agalanin@nvidia.com>
This commit is contained in:
@@ -122,6 +122,32 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/** rtti enabled */
|
||||
#ifndef CLI11_HAS_RTTI
|
||||
#if defined(__GXX_RTTI) && __GXX_RTTI == 1
|
||||
// gcc
|
||||
#define CLI11_HAS_RTTI 1
|
||||
#elif defined(_CPPRTTI) && _CPPRTTI == 1
|
||||
// msvc
|
||||
#define CLI11_HAS_RTTI 1
|
||||
#elif defined(__NO_RTTI__) && __NO_RTTI__ == 1
|
||||
// intel
|
||||
#define CLI11_HAS_RTTI 0
|
||||
#elif defined(__has_feature)
|
||||
// clang and other newer compilers
|
||||
#if __has_feature(cxx_rtti)
|
||||
#define CLI11_HAS_RTTI 1
|
||||
#else
|
||||
#define CLI11_HAS_RTTI 0
|
||||
#endif
|
||||
#elif defined(__RTTI) || defined(__INTEL_RTTI__)
|
||||
// more intel and some other compilers
|
||||
#define CLI11_HAS_RTTI 1
|
||||
#else
|
||||
#define CLI11_HAS_RTTI 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/** disable deprecations */
|
||||
#if defined(__GNUC__) // GCC or clang
|
||||
#define CLI11_DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push")
|
||||
|
||||
@@ -194,6 +194,10 @@ inline std::string remove_underscore(std::string str) {
|
||||
return str;
|
||||
}
|
||||
|
||||
/// @brief get valid group separators _' + local separator if different
|
||||
/// @return a string containing the group separators
|
||||
CLI11_INLINE std::string get_group_separators();
|
||||
|
||||
/// Find and replace a substring with another substring
|
||||
CLI11_INLINE std::string find_and_replace(std::string str, std::string from, std::string to);
|
||||
|
||||
|
||||
@@ -961,20 +961,18 @@ bool integral_conversion(const std::string &input, T &output) noexcept {
|
||||
output = (output_sll < 0) ? static_cast<T>(0) : static_cast<T>(output_sll);
|
||||
return (static_cast<std::int64_t>(output) == output_sll);
|
||||
}
|
||||
// remove locale-specific group separators
|
||||
char group_separator = std::use_facet<std::numpunct<char>>(std::locale()).thousands_sep();
|
||||
if(input.find_first_of(group_separator) != std::string::npos) {
|
||||
// remove separators if present
|
||||
auto group_separators = get_group_separators();
|
||||
if(input.find_first_of(group_separators) != std::string::npos) {
|
||||
std::string nstring = input;
|
||||
nstring.erase(std::remove(nstring.begin(), nstring.end(), group_separator), nstring.end());
|
||||
return integral_conversion(nstring, output);
|
||||
}
|
||||
// remove separators
|
||||
if(input.find_first_of("_'") != std::string::npos) {
|
||||
std::string nstring = input;
|
||||
nstring.erase(std::remove(nstring.begin(), nstring.end(), '_'), nstring.end());
|
||||
nstring.erase(std::remove(nstring.begin(), nstring.end(), '\''), nstring.end());
|
||||
for(auto &separator : group_separators) {
|
||||
if(input.find_first_of(separator) != std::string::npos) {
|
||||
nstring.erase(std::remove(nstring.begin(), nstring.end(), separator), nstring.end());
|
||||
}
|
||||
}
|
||||
return integral_conversion(nstring, output);
|
||||
}
|
||||
|
||||
if(std::isspace(static_cast<unsigned char>(input.back()))) {
|
||||
return integral_conversion(trim_copy(input), output);
|
||||
}
|
||||
@@ -1026,19 +1024,16 @@ bool integral_conversion(const std::string &input, T &output) noexcept {
|
||||
output = static_cast<T>(1);
|
||||
return true;
|
||||
}
|
||||
// remove locale-specific group separators
|
||||
char group_separator = std::use_facet<std::numpunct<char>>(std::locale()).thousands_sep();
|
||||
if(input.find_first_of(group_separator) != std::string::npos) {
|
||||
std::string nstring = input;
|
||||
nstring.erase(std::remove(nstring.begin(), nstring.end(), group_separator), nstring.end());
|
||||
return integral_conversion(nstring, output);
|
||||
}
|
||||
// remove separators and trailing spaces
|
||||
if(input.find_first_of("_'") != std::string::npos) {
|
||||
std::string nstring = input;
|
||||
nstring.erase(std::remove(nstring.begin(), nstring.end(), '_'), nstring.end());
|
||||
nstring.erase(std::remove(nstring.begin(), nstring.end(), '\''), nstring.end());
|
||||
return integral_conversion(nstring, output);
|
||||
// remove separators if present
|
||||
auto group_separators = get_group_separators();
|
||||
if(input.find_first_of(group_separators) != std::string::npos) {
|
||||
for(auto &separator : group_separators) {
|
||||
if(input.find_first_of(separator) != std::string::npos) {
|
||||
std::string nstring = input;
|
||||
nstring.erase(std::remove(nstring.begin(), nstring.end(), separator), nstring.end());
|
||||
return integral_conversion(nstring, output);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(std::isspace(static_cast<unsigned char>(input.back()))) {
|
||||
return integral_conversion(trim_copy(input), output);
|
||||
@@ -1174,19 +1169,16 @@ bool lexical_cast(const std::string &input, T &output) {
|
||||
}
|
||||
}
|
||||
|
||||
// remove locale-specific group separators
|
||||
char group_separator = std::use_facet<std::numpunct<char>>(std::locale()).thousands_sep();
|
||||
if(input.find_first_of(group_separator) != std::string::npos) {
|
||||
std::string nstring = input;
|
||||
nstring.erase(std::remove(nstring.begin(), nstring.end(), group_separator), nstring.end());
|
||||
return lexical_cast(nstring, output);
|
||||
}
|
||||
// remove separators
|
||||
if(input.find_first_of("_'") != std::string::npos) {
|
||||
std::string nstring = input;
|
||||
nstring.erase(std::remove(nstring.begin(), nstring.end(), '_'), nstring.end());
|
||||
nstring.erase(std::remove(nstring.begin(), nstring.end(), '\''), nstring.end());
|
||||
return lexical_cast(nstring, output);
|
||||
// remove separators if present
|
||||
auto group_separators = get_group_separators();
|
||||
if(input.find_first_of(group_separators) != std::string::npos) {
|
||||
for(auto &separator : group_separators) {
|
||||
if(input.find_first_of(separator) != std::string::npos) {
|
||||
std::string nstring = input;
|
||||
nstring.erase(std::remove(nstring.begin(), nstring.end(), separator), nstring.end());
|
||||
return lexical_cast(nstring, output);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -419,6 +419,8 @@ CLI11_INLINE bool App::remove_option(Option *opt) {
|
||||
help_ptr_ = nullptr;
|
||||
if(help_all_ptr_ == opt)
|
||||
help_all_ptr_ = nullptr;
|
||||
if(config_ptr_ == opt)
|
||||
config_ptr_ = nullptr;
|
||||
|
||||
auto iterator =
|
||||
std::find_if(std::begin(options_), std::end(options_), [opt](const Option_p &v) { return v.get() == opt; });
|
||||
@@ -1790,9 +1792,8 @@ CLI11_INLINE bool App::_parse_positional(std::vector<std::string> &args, bool ha
|
||||
ConfigItem item;
|
||||
item.name = posOpt->pname_;
|
||||
item.inputs.push_back(positional);
|
||||
if(!_add_flag_like_result(posOpt, item, item.inputs)) {
|
||||
posOpt->add_result(positional);
|
||||
}
|
||||
// input is singular guaranteed to return true in that case
|
||||
_add_flag_like_result(posOpt, item, item.inputs);
|
||||
} else {
|
||||
posOpt->add_result(positional);
|
||||
}
|
||||
|
||||
@@ -123,6 +123,15 @@ CLI11_INLINE bool valid_name_string(const std::string &str) {
|
||||
return true;
|
||||
}
|
||||
|
||||
CLI11_INLINE std::string get_group_separators() {
|
||||
std::string separators{"_'"};
|
||||
#if CLI11_HAS_RTTI != 0
|
||||
char group_separator = std::use_facet<std::numpunct<char>>(std::locale()).thousands_sep();
|
||||
separators.push_back(group_separator);
|
||||
#endif
|
||||
return separators;
|
||||
}
|
||||
|
||||
CLI11_INLINE std::string find_and_replace(std::string str, std::string from, std::string to) {
|
||||
|
||||
std::size_t start_pos = 0;
|
||||
|
||||
@@ -315,7 +315,7 @@ TEST_CASE("app_roundtrip_custom") {
|
||||
CLI::FuzzApp fuzzdata2;
|
||||
auto app = fuzzdata.generateApp();
|
||||
auto app2 = fuzzdata2.generateApp();
|
||||
int index = GENERATE(range(1, 12));
|
||||
int index = GENERATE(range(1, 13));
|
||||
auto parseData = loadFailureFile("round_trip_custom", index);
|
||||
std::size_t pstring_start{0};
|
||||
pstring_start = fuzzdata.add_custom_options(app.get(), parseData);
|
||||
|
||||
@@ -206,6 +206,13 @@ TEST_CASE_METHOD(TApp, "subcommandPrefixMultiple", "[subcom]") {
|
||||
|
||||
args = {"sub_"};
|
||||
CHECK_THROWS_AS(run(), CLI::ExtrasError);
|
||||
args = {"sub_long"};
|
||||
// now turning prefix matching off on main app but left on in subcommands
|
||||
app.allow_subcommand_prefix_matching(false);
|
||||
run();
|
||||
// as the subcommands can specifically match on prefix the first is matched even if there is ambiguity
|
||||
CHECK(app.got_subcommand("sub_long_prefix"));
|
||||
CHECK(1u == sub1->count());
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(TApp, "RequiredAndSubcommands", "[subcom]") {
|
||||
|
||||
BIN
tests/fuzzFail/round_trip_custom13
Normal file
BIN
tests/fuzzFail/round_trip_custom13
Normal file
Binary file not shown.
@@ -23,6 +23,7 @@ class CustomThousandsSeparator : public std::numpunct<char> {
|
||||
std::string do_grouping() const override { return "\2"; } // Group digits in sets of 2
|
||||
};
|
||||
|
||||
#if CLI11_HAS_RTTI != 0
|
||||
// derived from https://github.com/CLIUtils/CLI11/pull/1160
|
||||
TEST_CASE_METHOD(TApp, "locale", "[separators]") {
|
||||
std::locale customLocale(std::locale::classic(), new CustomThousandsSeparator);
|
||||
@@ -30,9 +31,9 @@ TEST_CASE_METHOD(TApp, "locale", "[separators]") {
|
||||
|
||||
// Ensure standard streams use the custom locale automatically
|
||||
std::cout.imbue(std::locale());
|
||||
std::int64_t foo;
|
||||
std::uint64_t bar;
|
||||
float qux;
|
||||
std::int64_t foo{0};
|
||||
std::uint64_t bar{0};
|
||||
float qux{0};
|
||||
|
||||
app.add_option("FOO", foo, "Foo option")->default_val(1234567)->force_callback();
|
||||
app.add_option("BAR", bar, "Bar option")->default_val(2345678)->force_callback();
|
||||
@@ -43,3 +44,4 @@ TEST_CASE_METHOD(TApp, "locale", "[separators]") {
|
||||
CHECK(bar == 2345678);
|
||||
CHECK_THAT(qux, Catch::Matchers::WithinAbs(3456.78, 0.01));
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user