mirror of
https://github.com/CLIUtils/CLI11.git
synced 2025-01-16 07:08:01 +00:00
Compare commits
6 Commits
97e5ebe490
...
a9e8c56499
Author | SHA1 | Date | |
---|---|---|---|
|
a9e8c56499 | ||
|
a7902531c9 | ||
|
69674dc91b | ||
|
e50a75f231 | ||
|
89926dc820 | ||
|
d621be0565 |
@ -422,6 +422,15 @@
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "dfleury2",
|
||||
"name": "D. Fleury",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/4805384?v=4",
|
||||
"profile": "https://github.com/dfleury2",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
}
|
||||
],
|
||||
"contributorsPerLine": 7,
|
||||
|
4
.github/labeler_merged.yml
vendored
Normal file
4
.github/labeler_merged.yml
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
needs changelog:
|
||||
- all: ['!CHANGELOG.md']
|
||||
needs README:
|
||||
- all: ['!README.md']
|
15
.github/workflows/pr_merged.yml
vendored
Normal file
15
.github/workflows/pr_merged.yml
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
name: PR merged
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [closed]
|
||||
|
||||
jobs:
|
||||
label-merged:
|
||||
name: Changelog needed
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event.pull_request.merged == true
|
||||
steps:
|
||||
- uses: actions/labeler@main
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
configuration-path: .github/labeler_merged.yml
|
@ -224,6 +224,8 @@ if(CLI11_INSTALL)
|
||||
NAMESPACE CLI11::
|
||||
FILE CLI11Targets.cmake)
|
||||
|
||||
include(cmake/CLI11GeneratePkgConfig.cmake)
|
||||
|
||||
# Register in the user cmake package registry
|
||||
export(PACKAGE CLI11)
|
||||
endif()
|
||||
|
@ -961,6 +961,7 @@ This project was created by [Henry Schreiner](https://github.com/henryiii) and m
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/jakoblover"><img src="https://avatars0.githubusercontent.com/u/14160441?v=4" width="100px;" alt=""/><br /><sub><b>Jakob Lover</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=jakoblover" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/ZeeD26"><img src="https://avatars2.githubusercontent.com/u/2487468?v=4" width="100px;" alt=""/><br /><sub><b>Dominik Steinberger</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=ZeeD26" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/dfleury2"><img src="https://avatars1.githubusercontent.com/u/4805384?v=4" width="100px;" alt=""/><br /><sub><b>D. Fleury</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/commits?author=dfleury2" title="Code">💻</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
9
cmake/CLI11.pc.in
Normal file
9
cmake/CLI11.pc.in
Normal file
@ -0,0 +1,9 @@
|
||||
prefix=@CMAKE_INSTALL_PREFIX@
|
||||
exec_prefix=${prefix}
|
||||
includedir=${prefix}/include
|
||||
|
||||
Name: CLI11
|
||||
Description: C++ command line parser
|
||||
Version: @PROJECT_VERSION@
|
||||
|
||||
Cflags: -I${includedir}
|
6
cmake/CLI11GeneratePkgConfig.cmake
Normal file
6
cmake/CLI11GeneratePkgConfig.cmake
Normal file
@ -0,0 +1,6 @@
|
||||
configure_file("cmake/CLI11.pc.in" "CLI11.pc" @ONLY)
|
||||
|
||||
install(FILES "${PROJECT_BINARY_DIR}/CLI11.pc"
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
|
||||
|
||||
|
@ -789,7 +789,8 @@ class App {
|
||||
/// Add option for flag with integer result - defaults to allowing multiple passings, but can be forced to one
|
||||
/// if `multi_option_policy(CLI::MultiOptionPolicy::Throw)` is used.
|
||||
template <typename T,
|
||||
enable_if_t<std::is_integral<T>::value && !is_bool<T>::value, detail::enabler> = detail::dummy>
|
||||
enable_if_t<std::is_constructible<T, std::int64_t>::value && !is_bool<T>::value, detail::enabler> =
|
||||
detail::dummy>
|
||||
Option *add_flag(std::string flag_name,
|
||||
T &flag_count, ///< A variable holding the count
|
||||
std::string flag_description = "") {
|
||||
@ -810,7 +811,7 @@ class App {
|
||||
/// that can be converted from a string
|
||||
template <typename T,
|
||||
enable_if_t<!detail::is_mutable_container<T>::value && !std::is_const<T>::value &&
|
||||
(!std::is_integral<T>::value || is_bool<T>::value) &&
|
||||
(!std::is_constructible<T, std::int64_t>::value || is_bool<T>::value) &&
|
||||
!std::is_constructible<std::function<void(int)>, T>::value,
|
||||
detail::enabler> = detail::dummy>
|
||||
Option *add_flag(std::string flag_name,
|
||||
@ -824,9 +825,9 @@ class App {
|
||||
}
|
||||
|
||||
/// Vector version to capture multiple flags.
|
||||
template <
|
||||
typename T,
|
||||
enable_if_t<!std::is_assignable<std::function<void(std::int64_t)>, T>::value, detail::enabler> = detail::dummy>
|
||||
template <typename T,
|
||||
enable_if_t<!std::is_assignable<std::function<void(std::int64_t)> &, T>::value, detail::enabler> =
|
||||
detail::dummy>
|
||||
Option *add_flag(std::string flag_name,
|
||||
std::vector<T> &flag_results, ///< A vector of values with the flag results
|
||||
std::string flag_description = "") {
|
||||
@ -2252,10 +2253,13 @@ class App {
|
||||
}
|
||||
|
||||
if(require_option_min_ > used_options || (require_option_max_ > 0 && require_option_max_ < used_options)) {
|
||||
auto option_list = detail::join(options_, [](const Option_p &ptr) { return ptr->get_name(false, true); });
|
||||
if(option_list.compare(0, 10, "-h,--help,") == 0) {
|
||||
option_list.erase(0, 10);
|
||||
}
|
||||
auto option_list = detail::join(options_, [this](const Option_p &ptr) {
|
||||
if(ptr.get() == help_ptr_ || ptr.get() == help_all_ptr_) {
|
||||
return std::string{};
|
||||
}
|
||||
return ptr->get_name(false, true);
|
||||
});
|
||||
|
||||
auto subc_list = get_subcommands([](App *app) { return ((app->get_name().empty()) && (!app->disabled_)); });
|
||||
if(!subc_list.empty()) {
|
||||
option_list += "," + detail::join(subc_list, [](const App *app) { return app->get_display_name(); });
|
||||
|
@ -211,7 +211,11 @@ inline std::vector<ConfigItem> ConfigBase::from_config(std::istream &input) cons
|
||||
if(pos != std::string::npos) {
|
||||
name = detail::trim_copy(line.substr(0, pos));
|
||||
std::string item = detail::trim_copy(line.substr(pos + 1));
|
||||
if(item.size() > 1 && item.front() == aStart && item.back() == aEnd) {
|
||||
if(item.size() > 1 && item.front() == aStart) {
|
||||
for(std::string multiline; item.back() != aEnd && std::getline(input, multiline);) {
|
||||
detail::trim(multiline);
|
||||
item += multiline;
|
||||
}
|
||||
items_buffer = detail::split_up(item.substr(1, item.length() - 2), aSep);
|
||||
} else if((isDefaultArray || isINIArray) && item.find_first_of(aSep) != std::string::npos) {
|
||||
items_buffer = detail::split_up(item, aSep);
|
||||
|
@ -76,10 +76,14 @@ std::string join(const T &v, Callable func, std::string delim = ",") {
|
||||
std::ostringstream s;
|
||||
auto beg = std::begin(v);
|
||||
auto end = std::end(v);
|
||||
if(beg != end)
|
||||
s << func(*beg++);
|
||||
auto loc = s.tellp();
|
||||
while(beg != end) {
|
||||
s << delim << func(*beg++);
|
||||
auto nloc = s.tellp();
|
||||
if(nloc > loc) {
|
||||
s << delim;
|
||||
loc = nloc;
|
||||
}
|
||||
s << func(*beg++);
|
||||
}
|
||||
return s.str();
|
||||
}
|
||||
|
@ -964,7 +964,22 @@ bool lexical_cast(const std::string &input, T &output) {
|
||||
|
||||
/// wrapper types
|
||||
template <typename T,
|
||||
enable_if_t<classify_object<T>::value == object_category::wrapper_value, detail::enabler> = detail::dummy>
|
||||
enable_if_t<classify_object<T>::value == object_category::wrapper_value &&
|
||||
std::is_assignable<T &, typename T::value_type>::value,
|
||||
detail::enabler> = detail::dummy>
|
||||
bool lexical_cast(const std::string &input, T &output) {
|
||||
typename T::value_type val;
|
||||
if(lexical_cast(input, val)) {
|
||||
output = val;
|
||||
return true;
|
||||
}
|
||||
return from_stream(input, output);
|
||||
}
|
||||
|
||||
template <typename T,
|
||||
enable_if_t<classify_object<T>::value == object_category::wrapper_value &&
|
||||
!std::is_assignable<T &, typename T::value_type>::value && std::is_assignable<T &, T>::value,
|
||||
detail::enabler> = detail::dummy>
|
||||
bool lexical_cast(const std::string &input, T &output) {
|
||||
typename T::value_type val;
|
||||
if(lexical_cast(input, val)) {
|
||||
@ -1019,8 +1034,36 @@ bool lexical_cast(const std::string &input, T &output) {
|
||||
return from_stream(input, output);
|
||||
}
|
||||
|
||||
/// Non-string convertible from an int
|
||||
template <typename T,
|
||||
enable_if_t<classify_object<T>::value == object_category::other && std::is_assignable<T &, int>::value,
|
||||
detail::enabler> = detail::dummy>
|
||||
bool lexical_cast(const std::string &input, T &output) {
|
||||
int val;
|
||||
if(integral_conversion(input, val)) {
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4800)
|
||||
#endif
|
||||
// with Atomic<XX> this could produce a warning due to the conversion but if atomic gets here it is an old style
|
||||
// so will most likely still work
|
||||
output = val;
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
// LCOV_EXCL_START
|
||||
// This version of cast is only used for odd cases in an older compilers the fail over
|
||||
// from_stream is tested elsewhere an not relevent for coverage here
|
||||
return from_stream(input, output);
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
/// Non-string parsable by a stream
|
||||
template <typename T, enable_if_t<classify_object<T>::value == object_category::other, detail::enabler> = detail::dummy>
|
||||
template <typename T,
|
||||
enable_if_t<classify_object<T>::value == object_category::other && !std::is_assignable<T &, int>::value,
|
||||
detail::enabler> = detail::dummy>
|
||||
bool lexical_cast(const std::string &input, T &output) {
|
||||
static_assert(is_istreamable<T>::value,
|
||||
"option object type must have a lexical cast overload or streaming input operator(>>) defined, if it "
|
||||
@ -1043,7 +1086,7 @@ bool lexical_assign(const std::string &input, AssignTo &output) {
|
||||
/// Assign a value through lexical cast operations
|
||||
template <typename AssignTo,
|
||||
typename ConvertTo,
|
||||
enable_if_t<std::is_same<AssignTo, ConvertTo>::value &&
|
||||
enable_if_t<std::is_same<AssignTo, ConvertTo>::value && std::is_assignable<AssignTo &, AssignTo>::value &&
|
||||
classify_object<AssignTo>::value != object_category::string_assignable &&
|
||||
classify_object<AssignTo>::value != object_category::string_constructible,
|
||||
detail::enabler> = detail::dummy>
|
||||
@ -1052,9 +1095,46 @@ bool lexical_assign(const std::string &input, AssignTo &output) {
|
||||
output = AssignTo{};
|
||||
return true;
|
||||
}
|
||||
|
||||
return lexical_cast(input, output);
|
||||
}
|
||||
|
||||
/// Assign a value through lexical cast operations
|
||||
template <typename AssignTo,
|
||||
typename ConvertTo,
|
||||
enable_if_t<std::is_same<AssignTo, ConvertTo>::value && !std::is_assignable<AssignTo &, AssignTo>::value &&
|
||||
classify_object<AssignTo>::value == object_category::wrapper_value,
|
||||
detail::enabler> = detail::dummy>
|
||||
bool lexical_assign(const std::string &input, AssignTo &output) {
|
||||
if(input.empty()) {
|
||||
typename AssignTo::value_type emptyVal{};
|
||||
output = emptyVal;
|
||||
return true;
|
||||
}
|
||||
return lexical_cast(input, output);
|
||||
}
|
||||
|
||||
/// Assign a value through lexical cast operations for int compatible values
|
||||
/// mainly for atomic operations on some compilers
|
||||
template <typename AssignTo,
|
||||
typename ConvertTo,
|
||||
enable_if_t<std::is_same<AssignTo, ConvertTo>::value && !std::is_assignable<AssignTo &, AssignTo>::value &&
|
||||
classify_object<AssignTo>::value != object_category::wrapper_value &&
|
||||
std::is_assignable<AssignTo &, int>::value,
|
||||
detail::enabler> = detail::dummy>
|
||||
bool lexical_assign(const std::string &input, AssignTo &output) {
|
||||
if(input.empty()) {
|
||||
output = 0;
|
||||
return true;
|
||||
}
|
||||
int val;
|
||||
if(lexical_cast(input, val)) {
|
||||
output = val;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Assign a value converted from a string in lexical cast to the output value directly
|
||||
template <typename AssignTo,
|
||||
typename ConvertTo,
|
||||
@ -1366,10 +1446,11 @@ bool lexical_conversion(const std::vector<std ::string> &strings, AssignTo &outp
|
||||
}
|
||||
|
||||
/// conversion for wrapper types
|
||||
template <
|
||||
typename AssignTo,
|
||||
class ConvertTo,
|
||||
enable_if_t<classify_object<ConvertTo>::value == object_category::wrapper_value, detail::enabler> = detail::dummy>
|
||||
template <typename AssignTo,
|
||||
class ConvertTo,
|
||||
enable_if_t<classify_object<ConvertTo>::value == object_category::wrapper_value &&
|
||||
std::is_assignable<ConvertTo &, ConvertTo>::value,
|
||||
detail::enabler> = detail::dummy>
|
||||
bool lexical_conversion(const std::vector<std::string> &strings, AssignTo &output) {
|
||||
if(strings.empty() || strings.front().empty()) {
|
||||
output = ConvertTo{};
|
||||
@ -1383,6 +1464,26 @@ bool lexical_conversion(const std::vector<std::string> &strings, AssignTo &outpu
|
||||
return false;
|
||||
}
|
||||
|
||||
/// conversion for wrapper types
|
||||
template <typename AssignTo,
|
||||
class ConvertTo,
|
||||
enable_if_t<classify_object<ConvertTo>::value == object_category::wrapper_value &&
|
||||
!std::is_assignable<AssignTo &, ConvertTo>::value,
|
||||
detail::enabler> = detail::dummy>
|
||||
bool lexical_conversion(const std::vector<std::string> &strings, AssignTo &output) {
|
||||
using ConvertType = typename ConvertTo::value_type;
|
||||
if(strings.empty() || strings.front().empty()) {
|
||||
output = ConvertType{};
|
||||
return true;
|
||||
}
|
||||
ConvertType val;
|
||||
if(lexical_conversion<typename ConvertTo::value_type, typename ConvertTo::value_type>(strings, val)) {
|
||||
output = val;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Sum a vector of flag representations
|
||||
/// The flag vector produces a series of strings in a vector, simple true is represented by a "1", simple false is
|
||||
/// by
|
||||
@ -1411,5 +1512,32 @@ void sum_flag_vector(const std::vector<std::string> &flags, T &output) {
|
||||
output = static_cast<T>(count);
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4800)
|
||||
#endif
|
||||
// with Atomic<XX> this could produce a warning due to the conversion but if atomic gets here it is an old style so will
|
||||
// most likely still work
|
||||
|
||||
/// Sum a vector of flag representations
|
||||
/// The flag vector produces a series of strings in a vector, simple true is represented by a "1", simple false is
|
||||
/// by
|
||||
/// "-1" an if numbers are passed by some fashion they are captured as well so the function just checks for the most
|
||||
/// common true and false strings then uses stoll to convert the rest for summing
|
||||
template <typename T,
|
||||
enable_if_t<!std::is_signed<T>::value && !std::is_unsigned<T>::value, detail::enabler> = detail::dummy>
|
||||
void sum_flag_vector(const std::vector<std::string> &flags, T &output) {
|
||||
std::int64_t count{0};
|
||||
for(auto &flag : flags) {
|
||||
count += detail::to_flag_value(flag);
|
||||
}
|
||||
std::string out = detail::to_string(count);
|
||||
lexical_cast(out, output);
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
} // namespace detail
|
||||
} // namespace CLI
|
||||
|
@ -135,11 +135,14 @@ TEST_F(TApp, RequireOptionsError) {
|
||||
app.add_flag("-c");
|
||||
app.add_flag("--q");
|
||||
app.add_flag("--this,--that");
|
||||
app.set_help_flag("-h,--help");
|
||||
app.set_help_all_flag("--help_all");
|
||||
app.require_option(1, 2);
|
||||
try {
|
||||
app.parse("-c --q --this --that");
|
||||
} catch(const CLI::RequiredError &re) {
|
||||
EXPECT_THAT(re.what(), Not(HasSubstr("-h,--help")));
|
||||
EXPECT_THAT(re.what(), Not(HasSubstr("help_all")));
|
||||
}
|
||||
|
||||
EXPECT_NO_THROW(app.parse("-c --q"));
|
||||
|
@ -150,6 +150,47 @@ TEST(StringBased, Vector) {
|
||||
EXPECT_EQ("seven", output.at(2).inputs.at(2));
|
||||
}
|
||||
|
||||
TEST(StringBased, TomlVector) {
|
||||
std::stringstream ofile;
|
||||
|
||||
ofile << "one = [three]\n";
|
||||
ofile << "two = [four]\n";
|
||||
ofile << "five = [six, and, seven]\n";
|
||||
ofile << "eight = [nine, \n"
|
||||
"ten, eleven, twelve \n"
|
||||
"]\n";
|
||||
ofile << "one_more = [one, \n"
|
||||
"two, three ] \n";
|
||||
|
||||
ofile.seekg(0, std::ios::beg);
|
||||
|
||||
std::vector<CLI::ConfigItem> output = CLI::ConfigINI().from_config(ofile);
|
||||
|
||||
EXPECT_EQ(5u, output.size());
|
||||
EXPECT_EQ("one", output.at(0).name);
|
||||
EXPECT_EQ(1u, output.at(0).inputs.size());
|
||||
EXPECT_EQ("three", output.at(0).inputs.at(0));
|
||||
EXPECT_EQ("two", output.at(1).name);
|
||||
EXPECT_EQ(1u, output.at(1).inputs.size());
|
||||
EXPECT_EQ("four", output.at(1).inputs.at(0));
|
||||
EXPECT_EQ("five", output.at(2).name);
|
||||
EXPECT_EQ(3u, output.at(2).inputs.size());
|
||||
EXPECT_EQ("six", output.at(2).inputs.at(0));
|
||||
EXPECT_EQ("and", output.at(2).inputs.at(1));
|
||||
EXPECT_EQ("seven", output.at(2).inputs.at(2));
|
||||
EXPECT_EQ("eight", output.at(3).name);
|
||||
EXPECT_EQ(4u, output.at(3).inputs.size());
|
||||
EXPECT_EQ("nine", output.at(3).inputs.at(0));
|
||||
EXPECT_EQ("ten", output.at(3).inputs.at(1));
|
||||
EXPECT_EQ("eleven", output.at(3).inputs.at(2));
|
||||
EXPECT_EQ("twelve", output.at(3).inputs.at(3));
|
||||
EXPECT_EQ("one_more", output.at(4).name);
|
||||
EXPECT_EQ(3u, output.at(4).inputs.size());
|
||||
EXPECT_EQ("one", output.at(4).inputs.at(0));
|
||||
EXPECT_EQ("two", output.at(4).inputs.at(1));
|
||||
EXPECT_EQ("three", output.at(4).inputs.at(2));
|
||||
}
|
||||
|
||||
TEST(StringBased, Spaces) {
|
||||
std::stringstream ofile;
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "app_helper.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <climits>
|
||||
#include <complex>
|
||||
#include <cstdint>
|
||||
@ -991,6 +992,8 @@ TEST(Types, TypeName) {
|
||||
EXPECT_EQ("ENUM", enum_name2);
|
||||
std::string umapName = CLI::detail::type_name<std::unordered_map<int, std::tuple<std::string, double>>>();
|
||||
EXPECT_EQ("[INT,[TEXT,FLOAT]]", umapName);
|
||||
|
||||
vclass = CLI::detail::classify_object<std::atomic<int>>::value;
|
||||
}
|
||||
|
||||
TEST(Types, OverflowSmall) {
|
||||
|
@ -5,6 +5,7 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include "app_helper.hpp"
|
||||
#include <atomic>
|
||||
#include <complex>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
@ -141,6 +142,33 @@ TEST_F(TApp, BoolAndIntFlags) {
|
||||
EXPECT_EQ((unsigned int)2, uflag);
|
||||
}
|
||||
|
||||
TEST_F(TApp, atomic_bool_flags) {
|
||||
|
||||
std::atomic<bool> bflag{false};
|
||||
std::atomic<int> iflag{0};
|
||||
|
||||
app.add_flag("-b", bflag);
|
||||
app.add_flag("-i,--int", iflag);
|
||||
|
||||
args = {"-b", "-i"};
|
||||
run();
|
||||
EXPECT_TRUE(bflag.load());
|
||||
EXPECT_EQ(1, iflag.load());
|
||||
|
||||
args = {"-b", "-b"};
|
||||
ASSERT_NO_THROW(run());
|
||||
EXPECT_TRUE(bflag.load());
|
||||
|
||||
bflag = false;
|
||||
|
||||
args = {"-iii"};
|
||||
run();
|
||||
EXPECT_FALSE(bflag.load());
|
||||
EXPECT_EQ(3, iflag.load());
|
||||
args = {"--int=notanumber"};
|
||||
EXPECT_THROW(run(), CLI::ConversionError);
|
||||
}
|
||||
|
||||
TEST_F(TApp, BoolOption) {
|
||||
bool bflag{false};
|
||||
app.add_option("-b", bflag);
|
||||
@ -167,6 +195,26 @@ TEST_F(TApp, BoolOption) {
|
||||
EXPECT_FALSE(bflag);
|
||||
}
|
||||
|
||||
TEST_F(TApp, atomic_int_option) {
|
||||
std::atomic<int> i{0};
|
||||
auto aopt = app.add_option("-i,--int", i);
|
||||
args = {"-i4"};
|
||||
run();
|
||||
EXPECT_EQ(1u, app.count("--int"));
|
||||
EXPECT_EQ(1u, app.count("-i"));
|
||||
EXPECT_EQ(i, 4);
|
||||
EXPECT_EQ(app["-i"]->as<std::string>(), "4");
|
||||
EXPECT_EQ(app["--int"]->as<double>(), 4.0);
|
||||
|
||||
args = {"--int", "notAnInt"};
|
||||
EXPECT_THROW(run(), CLI::ConversionError);
|
||||
|
||||
aopt->expected(0, 1);
|
||||
args = {"--int"};
|
||||
run();
|
||||
EXPECT_EQ(i, 0);
|
||||
}
|
||||
|
||||
TEST_F(TApp, CharOption) {
|
||||
char c1{'t'};
|
||||
app.add_option("-c", c1);
|
||||
|
Loading…
Reference in New Issue
Block a user