1
0
mirror of https://github.com/CLIUtils/CLI11.git synced 2025-01-15 22:58:02 +00:00

Compare commits

...

2 Commits

Author SHA1 Message Date
Philip Top
967bfe0e02
Set the default configuration file output as TOML (#435)
* Set the default configuration file output as TOML

* update formatting
2020-03-06 00:11:59 -05:00
Christoph Bachhuber
d8a5bdc294
Add and fix cpplint whitespace/comments (#434)
* Add whitespace/comments check

* Adapt spacing in clang-format

* Fix cpplint whitespace/comments issues

* Grammar

* Do not use clang-format for comment spacing

* Fix with clang-format pre-commit hook
2020-03-06 00:04:59 -05:00
32 changed files with 594 additions and 285 deletions

View File

@ -75,7 +75,7 @@ SortIncludes: true
# SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: Never
# SpaceInEmptyParentheses: false
# SpacesBeforeTrailingComments: 1
SpacesBeforeTrailingComments: 2
# SpacesInAngles: false
# SpacesInContainerLiterals: true
# SpacesInCStyleCastParentheses: false

View File

@ -1,7 +1,7 @@
set noparent
linelength=120 # As in .clang-format
# Non-used filters
# Unused filters
filter=-build/include_order # Requires unusual include order that encourages creating not self-contained headers
filter=-readability/nolint # Conflicts with clang-tidy
filter=-runtime/references # Requires fundamental change of API, don't see need for this
@ -9,6 +9,3 @@ filter=-whitespace/blank_line # Unnecessarily strict with blank lines that othe
filter=-whitespace/indent # Requires strange 3-space indent of private/protected/public markers
filter=-whitespace/parens,-whitespace/braces # Conflict with clang-format
# Filters to be included in future
filter=-whitespace/comments

View File

@ -679,8 +679,23 @@ app.set_config(option_name="",
required=false)
```
If this is called with no arguments, it will remove the configuration file option (like `set_help_flag`). Setting a configuration option is special. If it is present, it will be read along with the normal command line arguments. The file will be read if it exists, and does not throw an error unless `required` is `true`. Configuration files are in `ini` format by default, The reader can also accept many files in [TOML] format 🆕. (other formats can be added by an adept user, some variations are available through customization points in the default formatter). An example of a file:
If this is called with no arguments, it will remove the configuration file option (like `set_help_flag`). Setting a configuration option is special. If it is present, it will be read along with the normal command line arguments. The file will be read if it exists, and does not throw an error unless `required` is `true`. Configuration files are in [TOML] format by default 🚧, though the default reader can also accept files in INI format as well 🆕. It should be noted that CLI11 does not contain a full TOML parser but can read strings from most TOML file and run them through the CLI11 parser. Other formats can be added by an adept user, some variations are available through customization points in the default formatter. An example of a TOML file 🆕:
```ini
# Comments are supported, using a #
# The default section is [default], case insensitive
value = 1
str = "A string"
vector = [1,2,3]
str_vector = ["one","two","and three"]
# Sections map to subcommands
[subcommand]
in_subcommand = Wow
sub.subcommand = true
```
or equivalently in INI format
```ini
; Comments are supported, using a ;
; The default section is [default], case insensitive
@ -695,23 +710,8 @@ str_vector = "one" "two" "and three"
in_subcommand = Wow
sub.subcommand = true
```
or equivalently in TOML 🆕
```toml
# Comments are supported, using a #
# The default section is [default], case insensitive
value = 1
str = "A string"
vector = [1,2,3]
str_vector = ["one","two","and three"]
# Sections map to subcommands
[subcommand]
in_subcommand = Wow
sub.subcommand = true
```
Spaces before and after the name and argument are ignored. Multiple arguments are separated by spaces. One set of quotes will be removed, preserving spaces (the same way the command line works). Boolean options can be `true`, `on`, `1`, `yes`, `enable`; or `false`, `off`, `0`, `no`, `disable` (case insensitive). Sections (and `.` separated names) are treated as subcommands (note: this does not necessarily mean that subcommand was passed, it just sets the "defaults"). You cannot set positional-only arguments. 🆕 Subcommands can be triggered from config files if the `configurable` flag was set on the subcommand. Then use `[subcommand]` notation will trigger a subcommand and cause it to act as if it were on the command line.
Spaces before and after the name and argument are ignored. Multiple arguments are separated by spaces. One set of quotes will be removed, preserving spaces (the same way the command line works). Boolean options can be `true`, `on`, `1`, `yes`, `enable`; or `false`, `off`, `0`, `no`, `disable` (case insensitive). Sections (and `.` separated names) are treated as subcommands (note: this does not necessarily mean that subcommand was passed, it just sets the "defaults"). You cannot set positional-only arguments. 🆕 Subcommands can be triggered from configuration files if the `configurable` flag was set on the subcommand. Then the use of `[subcommand]` notation will trigger a subcommand and cause it to act as if it were on the command line.
To print a configuration file from the passed
arguments, use `.config_to_str(default_also=false, prefix="", write_description=false)`, where `default_also` will also show any defaulted arguments, `prefix` will add a prefix, and `write_description` will include option descriptions. See [Config files](https://cliutils.github.io/CLI11/book/chapters/config.html) for some additional details.
@ -744,7 +744,7 @@ The App class was designed allow toolkits to subclass it, to provide preset defa
but before run behavior, while
still giving the user freedom to `callback` on the main app.
The most important parse function is `parse(std::vector<std::string>)`, which takes a reversed list of arguments (so that `pop_back` processes the args in the correct order). `get_help_ptr` and `get_config_ptr` give you access to the help/config option pointers. The standard `parse` manually sets the name from the first argument, so it should not be in this vector. You can also use `parse(string, bool)` to split up and parse a string; the optional bool should be set to true if you are
The most important parse function is `parse(std::vector<std::string>)`, which takes a reversed list of arguments (so that `pop_back` processes the args in the correct order). `get_help_ptr` and `get_config_ptr` give you access to the help/config option pointers. The standard `parse` manually sets the name from the first argument, so it should not be in this vector. You can also use `parse(string, bool)` to split up and parse a string; the optional boolean should be set to true if you are
including the program name in the string, and false otherwise.
Also, in a related note, the `App` you get a pointer to is stored in the parent `App` in a `shared_ptr`s (similar to `Option`s) and are deleted when the main `App` goes out of scope unless the object has another owner.

View File

@ -41,7 +41,26 @@ If it is needed to get the configuration file name used this can be obtained via
## Configure file format
Here is an example configuration file, in INI format:
Here is an example configuration file, in [TOML](https://github.com/toml-lang/toml) format:
```ini
# Comments are supported, using a #
# The default section is [default], case insensitive
value = 1
str = "A string"
vector = [1,2,3]
# Section map to subcommands
[subcommand]
in_subcommand = Wow
[subcommand.sub]
subcommand = true # could also be give as sub.subcommand=true
```
Spaces before and after the name and argument are ignored. Multiple arguments are separated by spaces. One set of quotes will be removed, preserving spaces (the same way the command line works). Boolean options can be `true`, `on`, `1`, `y`, `t`, `+`, `yes`, `enable`; or `false`, `off`, `0`, `no`, `n`, `f`, `-`, `disable`, (case insensitive). Sections (and `.` separated names) are treated as subcommands (note: this does not necessarily mean that subcommand was passed, it just sets the "defaults". If a subcommand is set to `configurable` then passing the subcommand using `[sub]` in a configuration file will trigger the subcommand.)
CLI11 also supports configuration file in INI format.
```ini
; Comments are supported, using a ;
@ -57,25 +76,6 @@ in_subcommand = Wow
sub.subcommand = true
```
Spaces before and after the name and argument are ignored. Multiple arguments are separated by spaces. One set of quotes will be removed, preserving spaces (the same way the command line works). Boolean options can be `true`, `on`, `1`, `y`, `t`, `+`, `yes`, `enable`; or `false`, `off`, `0`, `no`, `n`, `f`, `-`, `disable`, (case insensitive). Sections (and `.` separated names) are treated as subcommands (note: this does not necessarily mean that subcommand was passed, it just sets the "defaults". If a subcommand is set to `configurable` then passing the subcommand using `[sub]` in a configuration file will trigger the subcommand.)
CLI11 also supports configuration file in [TOML](https://github.com/toml-lang/toml) format.
```toml
# Comments are supported, using a #
# The default section is [default], case insensitive
value = 1
str = "A string"
vector = [1,2,3]
# Section map to subcommands
[subcommand]
in_subcommand = Wow
[subcommand.sub]
subcommand = true # could also be give as sub.subcommand=true
```
The main differences are in vector notation and comment character. Note: CLI11 is not a full TOML parser as it just reads values as strings. It is possible (but not recommended) to mix notation.
## Writing out a configure file
@ -83,16 +83,16 @@ The main differences are in vector notation and comment character. Note: CLI11
To print a configuration file from the passed arguments, use `.config_to_str(default_also=false, prefix="", write_description=false)`, where `default_also` will also show any defaulted arguments, `prefix` will add a prefix, and `write_description` will include option descriptions.
### Customization of configure file output
The default config parser/generator has some customization points that allow variations on the INI format. The default formatter has a base configuration that matches the INI format. It defines 5 characters that define how different aspects of the configuration are handled
The default config parser/generator has some customization points that allow variations on the TOML format. The default formatter has a base configuration that matches the TOML format. It defines 5 characters that define how different aspects of the configuration are handled
```cpp
/// the character used for comments
char commentChar = ';';
char commentChar = '#';
/// the character used to start an array '\0' is a default to not use
char arrayStart = '\0';
char arrayStart = '[';
/// the character used to end an array '\0' is a default to not use
char arrayEnd = '\0';
char arrayEnd = ']';
/// the character used to separate elements in an array
char arraySeparator = ' ';
char arraySeparator = ',';
/// the character used separate the name from the value
char valueDelimiter = '=';
```
@ -111,11 +111,11 @@ auto config_base=app.get_config_formatter_base();
config_base->valueSeparator(':');
```
The default configuration file will read TOML files, but will write out files in the INI format. To specify outputting TOML formatted files use
The default configuration file will read INI files, but will write out files in the TOML format. To specify outputting INI formatted files use
```cpp
app.config_formatter(std::make_shared<CLI::ConfigTOML>());
app.config_formatter(std::make_shared<CLI::ConfigINI>());
```
which makes use of a predefined modification of the ConfigBase class which INI also uses.
which makes use of a predefined modification of the ConfigBase class which TOML also uses.
## Custom formats

View File

@ -20,7 +20,7 @@ int main(int argc, char **argv) {
int count{0};
CLI::Option *copt = app.add_flag("-c,--count", count, "Counter")->required()->group("Important");
double value{0.0}; // = 3.14;
double value{0.0}; // = 3.14;
app.add_option("-d,--double", value, "Some Value")->group("Other");
try {

View File

@ -14,7 +14,7 @@ int main(int argc, char **argv) {
app.add_flag("--version", "Get version");
CLI::App *cameraApp = app.add_subcommand("camera", "Configure the app camera");
cameraApp->require_subcommand(0, 1); // 0 (default) or 1 camera
cameraApp->require_subcommand(0, 1); // 0 (default) or 1 camera
std::string mvcamera_config_file = "mvcamera_config.json";
CLI::App *mvcameraApp = cameraApp->add_subcommand("mvcamera", "MatrixVision Camera Configuration");

View File

@ -21,7 +21,7 @@ int main(int argc, char **argv) {
int v{0};
CLI::Option *flag = app.add_flag("--flag", v, "Some flag that can be passed multiple times");
double value{0.0}; // = 3.14;
double value{0.0}; // = 3.14;
app.add_option("-d,--double", value, "Some Value");
CLI11_PARSE(app, argc, argv);

View File

@ -23,7 +23,7 @@ int main(int argc, char **argv) {
CLI::Option *copt = impOpt->add_flag("-c,--count", count, "Counter")->required();
CLI::App_p otherOpt = std::make_shared<CLI::App>("Other");
double value{0.0}; // = 3.14;
double value{0.0}; // = 3.14;
otherOpt->add_option("-d,--double", value, "Some Value");
// add the subapps to the main one

View File

@ -15,7 +15,7 @@ int main(int argc, char **argv) {
app.add_flag("--random", "Some random flag");
CLI::App *start = app.add_subcommand("start", "A great subcommand");
CLI::App *stop = app.add_subcommand("stop", "Do you really want to stop?");
app.require_subcommand(); // 1 or more
app.require_subcommand(); // 1 or more
std::string file;
start->add_option("-f,--file", file, "File name");

View File

@ -43,12 +43,12 @@ namespace CLI {
namespace detail {
enum class Classifier { NONE, POSITIONAL_MARK, SHORT, LONG, WINDOWS, SUBCOMMAND, SUBCOMMAND_TERMINATOR };
struct AppFriend;
} // namespace detail
} // namespace detail
namespace FailureMessage {
std::string simple(const App *app, const Error &e);
std::string help(const App *app, const Error &e);
} // namespace FailureMessage
} // namespace FailureMessage
/// enumeration of modes of how to deal with extras in config files
@ -247,7 +247,7 @@ class App {
Option *config_ptr_{nullptr};
/// This is the formatter for help printing. Default provided. INHERITABLE (same pointer)
std::shared_ptr<Config> config_formatter_{new ConfigINI()};
std::shared_ptr<Config> config_formatter_{new ConfigTOML()};
///@}
@ -464,7 +464,7 @@ class App {
auto *p = (parent_ != nullptr) ? _get_fallthrough_parent() : this;
auto &match = _compare_subcommand_names(*this, *p);
if(!match.empty()) {
ignore_case_ = false; // we are throwing so need to be exception invariant
ignore_case_ = false; // we are throwing so need to be exception invariant
throw OptionAlreadyAdded("ignore case would cause subcommand name conflicts: " + match);
}
}
@ -586,7 +586,7 @@ class App {
}
}
// this line should not be reached the above loop should trigger the throw
throw(OptionAlreadyAdded("added option matched existing option name")); // LCOV_EXCL_LINE
throw(OptionAlreadyAdded("added option matched existing option name")); // LCOV_EXCL_LINE
}
/// Add option for assigning to a variable
@ -594,11 +594,11 @@ class App {
typename ConvertTo = AssignTo,
enable_if_t<!std::is_const<ConvertTo>::value, detail::enabler> = detail::dummy>
Option *add_option(std::string option_name,
AssignTo &variable, ///< The variable to set
AssignTo &variable, ///< The variable to set
std::string option_description = "",
bool defaulted = false) {
auto fun = [&variable](const CLI::results_t &res) { // comment for spacing
auto fun = [&variable](const CLI::results_t &res) { // comment for spacing
return detail::lexical_conversion<AssignTo, ConvertTo>(res, variable);
};
@ -619,7 +619,7 @@ class App {
/// Add option for a callback of a specific type
template <typename T>
Option *add_option_function(std::string option_name,
const std::function<void(const T &)> &func, ///< the callback to execute
const std::function<void(const T &)> &func, ///< the callback to execute
std::string option_description = "") {
auto fun = [func](const CLI::results_t &res) {
@ -731,7 +731,7 @@ class App {
template <typename T,
enable_if_t<std::is_integral<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
T &flag_count, ///< A variable holding the count
std::string flag_description = "") {
flag_count = 0;
CLI::callback_t fun = [&flag_count](const CLI::results_t &res) {
@ -754,7 +754,7 @@ class App {
!std::is_constructible<std::function<void(int)>, T>::value,
detail::enabler> = detail::dummy>
Option *add_flag(std::string flag_name,
T &flag_result, ///< A variable holding true if passed
T &flag_result, ///< A variable holding true if passed
std::string flag_description = "") {
CLI::callback_t fun = [&flag_result](const CLI::results_t &res) {
@ -768,7 +768,7 @@ class App {
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::vector<T> &flag_results, ///< A vector of values with the flag results
std::string flag_description = "") {
CLI::callback_t fun = [&flag_results](const CLI::results_t &res) {
bool retval = true;
@ -785,7 +785,7 @@ class App {
/// Add option for callback that is triggered with a true flag and takes no arguments
Option *add_flag_callback(std::string flag_name,
std::function<void(void)> function, ///< A function to call, void(void)
std::function<void(void)> function, ///< A function to call, void(void)
std::string flag_description = "") {
CLI::callback_t fun = [function](const CLI::results_t &res) {
@ -801,7 +801,7 @@ class App {
/// Add option for callback with an integer value
Option *add_flag_function(std::string flag_name,
std::function<void(std::int64_t)> function, ///< A function to call, void(int)
std::function<void(std::int64_t)> function, ///< A function to call, void(int)
std::string flag_description = "") {
CLI::callback_t fun = [function](const CLI::results_t &res) {
@ -817,7 +817,7 @@ class App {
#ifdef CLI11_CPP14
/// Add option for callback (C++14 or better only)
Option *add_flag(std::string flag_name,
std::function<void(std::int64_t)> function, ///< A function to call, void(std::int64_t)
std::function<void(std::int64_t)> function, ///< A function to call, void(std::int64_t)
std::string flag_description = "") {
return add_flag_function(std::move(flag_name), std::move(function), std::move(flag_description));
}
@ -826,8 +826,8 @@ class App {
/// Add set of options (No default, temp reference, such as an inline set) DEPRECATED
template <typename T>
Option *add_set(std::string option_name,
T &member, ///< The selected member of the set
std::set<T> options, ///< The set of possibilities
T &member, ///< The selected member of the set
std::set<T> options, ///< The set of possibilities
std::string option_description = "") {
Option *opt = add_option(option_name, member, std::move(option_description));
@ -838,8 +838,8 @@ class App {
/// Add set of options (No default, set can be changed afterwards - do not destroy the set) DEPRECATED
template <typename T>
Option *add_mutable_set(std::string option_name,
T &member, ///< The selected member of the set
const std::set<T> &options, ///< The set of possibilities
T &member, ///< The selected member of the set
const std::set<T> &options, ///< The set of possibilities
std::string option_description = "") {
Option *opt = add_option(option_name, member, std::move(option_description));
@ -850,8 +850,8 @@ class App {
/// Add set of options (with default, static set, such as an inline set) DEPRECATED
template <typename T>
Option *add_set(std::string option_name,
T &member, ///< The selected member of the set
std::set<T> options, ///< The set of possibilities
T &member, ///< The selected member of the set
std::set<T> options, ///< The set of possibilities
std::string option_description,
bool defaulted) {
@ -863,8 +863,8 @@ class App {
/// Add set of options (with default, set can be changed afterwards - do not destroy the set) DEPRECATED
template <typename T>
Option *add_mutable_set(std::string option_name,
T &member, ///< The selected member of the set
const std::set<T> &options, ///< The set of possibilities
T &member, ///< The selected member of the set
const std::set<T> &options, ///< The set of possibilities
std::string option_description,
bool defaulted) {
@ -932,7 +932,7 @@ class App {
// Remove existing config if present
if(config_ptr_ != nullptr) {
remove_option(config_ptr_);
config_ptr_ = nullptr; // need to remove the config_ptr completely
config_ptr_ = nullptr; // need to remove the config_ptr completely
}
// Only add config if option passed
@ -1107,7 +1107,7 @@ class App {
for(auto &sub : subcommands_) {
cnt += sub->count_all();
}
if(!get_name().empty()) { // for named subcommands add the number of times the subcommand was called
if(!get_name().empty()) { // for named subcommands add the number of times the subcommand was called
cnt += parsed_;
}
return cnt;
@ -1881,7 +1881,7 @@ class App {
app->name_.clear();
}
if(app->name_.empty()) {
app->fallthrough_ = false; // make sure fallthrough_ is false to prevent infinite loop
app->fallthrough_ = false; // make sure fallthrough_ is false to prevent infinite loop
app->prefix_command_ = false;
}
// make sure the parent is set to be this object in preparation for parse
@ -2657,14 +2657,14 @@ class App {
int max_num = op->get_items_expected_max();
// Make sure we always eat the minimum for unlimited vectors
int collected = 0; // total number of arguments collected
int result_count = 0; // local variable for number of results in a single arg string
int collected = 0; // total number of arguments collected
int result_count = 0; // local variable for number of results in a single arg string
// deal with purely flag like things
if(max_num == 0) {
auto res = op->get_flag_value(arg_name, value);
op->add_result(res);
parse_order_.push_back(op.get());
} else if(!value.empty()) { // --this=value
} else if(!value.empty()) { // --this=value
op->add_result(value, result_count);
parse_order_.push_back(op.get());
collected += result_count;
@ -2685,11 +2685,11 @@ class App {
collected += result_count;
}
if(min_num > collected) { // if we have run out of arguments and the minimum was not met
if(min_num > collected) { // if we have run out of arguments and the minimum was not met
throw ArgumentMismatch::TypedAtLeast(op->get_name(), min_num, op->get_type_name());
}
if(max_num > collected || op->get_allow_extra_args()) { // we allow optional arguments
if(max_num > collected || op->get_allow_extra_args()) { // we allow optional arguments
auto remreqpos = _count_remaining_positionals(true);
// we have met the minimum now optionally check up to the maximum
while((collected < max_num || op->get_allow_extra_args()) && !args.empty() &&
@ -2866,7 +2866,7 @@ class App {
throw OptionNotFound("could not locate the given Option");
}
}
}; // namespace CLI
}; // namespace CLI
/// Extension of App to better manage groups of options
class Option_group : public App {
@ -3050,7 +3050,7 @@ inline std::string help(const App *app, const Error &e) {
return header;
}
} // namespace FailureMessage
} // namespace FailureMessage
namespace detail {
/// This class is simply to allow tests access to App's protected functions
@ -3072,6 +3072,6 @@ struct AppFriend {
/// Wrap the fallthrough parent function to make sure that is working correctly
static App *get_fallthrough_parent(App *app) { return app->_get_fallthrough_parent(); }
};
} // namespace detail
} // namespace detail
} // namespace CLI
} // namespace CLI

View File

@ -160,17 +160,18 @@ inline void checkParentSegments(std::vector<ConfigItem> &output, const std::stri
output.back().parents = std::move(parents);
output.back().name = "++";
}
} // namespace detail
} // namespace detail
inline std::vector<ConfigItem> ConfigBase::from_config(std::istream &input) const {
std::string line;
std::string section = "default";
std::vector<ConfigItem> output;
bool defaultArray = (arrayStart == '\0' || arrayStart == ' ') && arrayStart == arrayEnd;
char aStart = (defaultArray) ? '[' : arrayStart;
char aEnd = (defaultArray) ? ']' : arrayEnd;
char aSep = (defaultArray && arraySeparator == ' ') ? ',' : arraySeparator;
bool isDefaultArray = (arrayStart == '[' && arrayEnd == ']' && arraySeparator == ',');
bool isINIArray = (arrayStart == '\0' || arrayStart == ' ') && arrayStart == arrayEnd;
char aStart = (isINIArray) ? '[' : arrayStart;
char aEnd = (isINIArray) ? ']' : arrayEnd;
char aSep = (isINIArray && arraySeparator == ' ') ? ',' : arraySeparator;
while(getline(input, line)) {
std::vector<std::string> items_buffer;
@ -212,9 +213,9 @@ inline std::vector<ConfigItem> ConfigBase::from_config(std::istream &input) cons
std::string item = detail::trim_copy(line.substr(pos + 1));
if(item.size() > 1 && item.front() == aStart && item.back() == aEnd) {
items_buffer = detail::split_up(item.substr(1, item.length() - 2), aSep);
} else if(defaultArray && item.find_first_of(aSep) != std::string::npos) {
} else if((isDefaultArray || isINIArray) && item.find_first_of(aSep) != std::string::npos) {
items_buffer = detail::split_up(item, aSep);
} else if(defaultArray && item.find_first_of(' ') != std::string::npos) {
} else if((isDefaultArray || isINIArray) && item.find_first_of(' ') != std::string::npos) {
items_buffer = detail::split_up(item);
} else {
items_buffer = {item};
@ -343,4 +344,4 @@ ConfigBase::to_config(const App *app, bool default_also, bool write_description,
return out.str();
}
} // namespace CLI
} // namespace CLI

View File

@ -71,17 +71,17 @@ class Config {
virtual ~Config() = default;
};
/// This converter works with INI/TOML files; to write proper TOML files use ConfigTOML
/// This converter works with INI/TOML files; to write INI files use ConfigINI
class ConfigBase : public Config {
protected:
/// the character used for comments
char commentChar = ';';
char commentChar = '#';
/// the character used to start an array '\0' is a default to not use
char arrayStart = '\0';
char arrayStart = '[';
/// the character used to end an array '\0' is a default to not use
char arrayEnd = '\0';
char arrayEnd = ']';
/// the character used to separate elements in an array
char arraySeparator = ' ';
char arraySeparator = ',';
/// the character used separate the name from the value
char valueDelimiter = '=';
@ -113,19 +113,19 @@ class ConfigBase : public Config {
}
};
/// the default Config is the INI file format
using ConfigINI = ConfigBase;
/// the default Config is the TOML file format
using ConfigTOML = ConfigBase;
/// ConfigTOML generates a TOML compliant output
class ConfigTOML : public ConfigINI {
/// ConfigINI generates a "standard" INI compliant output
class ConfigINI : public ConfigTOML {
public:
ConfigTOML() {
commentChar = '#';
arrayStart = '[';
arrayEnd = ']';
arraySeparator = ',';
ConfigINI() {
commentChar = ';';
arrayStart = '\0';
arrayEnd = '\0';
arraySeparator = ' ';
valueDelimiter = '=';
}
};
} // namespace CLI
} // namespace CLI

View File

@ -337,4 +337,4 @@ class OptionNotFound : public Error {
/// @}
} // namespace CLI
} // namespace CLI

View File

@ -44,11 +44,11 @@ inline std::string Formatter::make_groups(const App *app, AppFormatMode mode) co
// Options
for(const std::string &group : groups) {
std::vector<const Option *> opts = app->get_options([app, mode, &group](const Option *opt) {
return opt->get_group() == group // Must be in the right group
&& opt->nonpositional() // Must not be a positional
&& (mode != AppFormatMode::Sub // If mode is Sub, then
|| (app->get_help_ptr() != opt // Ignore help pointer
&& app->get_help_all_ptr() != opt)); // Ignore help all pointer
return opt->get_group() == group // Must be in the right group
&& opt->nonpositional() // Must not be a positional
&& (mode != AppFormatMode::Sub // If mode is Sub, then
|| (app->get_help_ptr() != opt // Ignore help pointer
&& app->get_help_all_ptr() != opt)); // Ignore help all pointer
});
if(!group.empty() && !opts.empty()) {
out << make_group(group, false, opts);
@ -220,7 +220,7 @@ inline std::string Formatter::make_expanded(const App *sub) const {
// Drop blank spaces
std::string tmp = detail::find_and_replace(out.str(), "\n\n", "\n");
tmp = tmp.substr(0, tmp.size() - 1); // Remove the final '\n'
tmp = tmp.substr(0, tmp.size() - 1); // Remove the final '\n'
// Indent all but the first line (the name)
return detail::find_and_replace(tmp, "\n", "\n ") + "\n";
@ -278,4 +278,4 @@ inline std::string Formatter::make_option_usage(const Option *opt) const {
return opt->get_required() ? out.str() : "[" + out.str() + "]";
}
} // namespace CLI
} // namespace CLI

View File

@ -24,9 +24,9 @@ class App;
/// the second argument.
enum class AppFormatMode {
Normal, //< The normal, detailed help
All, //< A fully expanded help
Sub, //< Used when printed as part of expanded subcommand
Normal, //< The normal, detailed help
All, //< A fully expanded help
Sub, //< Used when printed as part of expanded subcommand
};
/// This is the minimum requirements to run a formatter.
@ -55,7 +55,7 @@ class FormatterBase {
FormatterBase(FormatterBase &&) = default;
/// Adding a destructor in this form to work around bug in GCC 4.7
virtual ~FormatterBase() noexcept {} // NOLINT(modernize-use-equals-default)
virtual ~FormatterBase() noexcept {} // NOLINT(modernize-use-equals-default)
/// This is the key method that puts together help
virtual std::string make_help(const App *, std::string, AppFormatMode) const = 0;
@ -100,7 +100,7 @@ class FormatterLambda final : public FormatterBase {
explicit FormatterLambda(funct_t funct) : lambda_(std::move(funct)) {}
/// Adding a destructor (mostly to make GCC 4.7 happy)
~FormatterLambda() noexcept override {} // NOLINT(modernize-use-equals-default)
~FormatterLambda() noexcept override {} // NOLINT(modernize-use-equals-default)
/// This will simply call the lambda function
std::string make_help(const App *app, std::string name, AppFormatMode mode) const override {
@ -177,4 +177,4 @@ class Formatter : public FormatterBase {
///@}
};
} // namespace CLI
} // namespace CLI

View File

@ -33,11 +33,11 @@ class App;
using Option_p = std::unique_ptr<Option>;
/// Enumeration of the multiOption Policy selection
enum class MultiOptionPolicy : char {
Throw, //!< Throw an error if any extra arguments were given
TakeLast, //!< take only the last Expected number of arguments
TakeFirst, //!< take only the first Expected number of arguments
Join, //!< merge all the arguments together into a single string via the delimiter character default('\n')
TakeAll //!< just get all the passed argument regardless
Throw, //!< Throw an error if any extra arguments were given
TakeLast, //!< take only the last Expected number of arguments
TakeFirst, //!< take only the first Expected number of arguments
Join, //!< merge all the arguments together into a single string via the delimiter character default('\n')
TakeAll //!< just get all the passed argument regardless
};
/// This is the CRTP base class for Option and OptionDefaults. It was designed this way
@ -316,10 +316,10 @@ class Option : public OptionBase<Option> {
results_t proc_results_{};
/// enumeration for the option state machine
enum class option_state {
parsing = 0, //!< The option is currently collecting parsed results
validated = 2, //!< the results have been validated
reduced = 4, //!< a subset of results has been generated
callback_run = 6, //!< the callback has been executed
parsing = 0, //!< The option is currently collecting parsed results
validated = 2, //!< the results have been validated
reduced = 4, //!< a subset of results has been generated
callback_run = 6, //!< the callback has been executed
};
/// Whether the callback has run (needed for INI parsing)
option_state current_option_state_{option_state::parsing};
@ -631,8 +631,8 @@ class Option : public OptionBase<Option> {
Option *multi_option_policy(MultiOptionPolicy value = MultiOptionPolicy::Throw) {
if(value != multi_option_policy_) {
if(multi_option_policy_ == MultiOptionPolicy::Throw && expected_max_ == detail::expected_max_vector_size &&
expected_min_ > 1) { // this bizarre condition is to maintain backwards compatibility
// with the previous behavior of expected_ with vectors
expected_min_ > 1) { // this bizarre condition is to maintain backwards compatibility
// with the previous behavior of expected_ with vectors
expected_max_ = expected_min_;
}
multi_option_policy_ = value;
@ -727,11 +727,11 @@ class Option : public OptionBase<Option> {
/// Will include / prefer the positional name if positional is true.
/// If all_options is false, pick just the most descriptive name to show.
/// Use `get_name(true)` to get the positional name (replaces `get_pname`)
std::string get_name(bool positional = false, //<[input] Show the positional name
bool all_options = false //<[input] Show every option
std::string get_name(bool positional = false, ///< Show the positional name
bool all_options = false ///< Show every option
) const {
if(get_group().empty())
return {}; // Hidden
return {}; // Hidden
if(all_options) {
@ -822,7 +822,7 @@ class Option : public OptionBase<Option> {
return lname;
if(ignore_case_ ||
ignore_underscore_) { // We need to do the inverse, in case we are ignore_case or ignore underscore
ignore_underscore_) { // We need to do the inverse, in case we are ignore_case or ignore underscore
for(const std::string &sname : other.snames_)
if(check_sname(sname))
return sname;
@ -974,7 +974,7 @@ class Option : public OptionBase<Option> {
results_t res;
if(results_.empty()) {
if(!default_str_.empty()) {
//_add_results takes an rvalue only
// _add_results takes an rvalue only
_add_result(std::string(default_str_), res);
_validate_results(res);
results_t extra;
@ -1090,7 +1090,7 @@ class Option : public OptionBase<Option> {
try {
add_result(val_str);
if(run_callback_for_default_) {
run_callback(); // run callback sets the state we need to reset it again
run_callback(); // run callback sets the state we need to reset it again
current_option_state_ = option_state::parsing;
} else {
_validate_results(results_);
@ -1126,7 +1126,7 @@ class Option : public OptionBase<Option> {
void _validate_results(results_t &res) const {
// Run the Validators (can change the string)
if(!validators_.empty()) {
if(type_size_max_ > 1) { // in this context index refers to the index in the type
if(type_size_max_ > 1) { // in this context index refers to the index in the type
int index = 0;
if(get_items_expected_max() < static_cast<int>(res.size()) &&
multi_option_policy_ == CLI::MultiOptionPolicy::TakeLast) {
@ -1136,7 +1136,7 @@ class Option : public OptionBase<Option> {
for(std::string &result : res) {
if(result.empty() && type_size_max_ != type_size_min_ && index >= 0) {
index = 0; // reset index for variable size chunks
index = 0; // reset index for variable size chunks
continue;
}
auto err_msg = _validate(result, (index >= 0) ? (index % type_size_max_) : index);
@ -1242,7 +1242,7 @@ class Option : public OptionBase<Option> {
int _add_result(std::string &&result, std::vector<std::string> &res) const {
int result_count = 0;
if(allow_extra_args_ && !result.empty() && result.front() == '[' &&
result.back() == ']') { // this is now a vector string likely from the default or user entry
result.back() == ']') { // this is now a vector string likely from the default or user entry
result.pop_back();
for(auto &var : CLI::detail::split(result.substr(1), ',')) {
@ -1270,6 +1270,6 @@ class Option : public OptionBase<Option> {
}
return result_count;
}
}; // namespace CLI
}; // namespace CLI
} // namespace CLI
} // namespace CLI

View File

@ -134,5 +134,5 @@ get_names(const std::vector<std::string> &input) {
short_names, long_names, pos_name);
}
} // namespace detail
} // namespace CLI
} // namespace detail
} // namespace CLI

View File

@ -28,7 +28,7 @@ std::ostream &operator<<(std::ostream &in, const T &item) {
return in << static_cast<typename std::underlying_type<T>::type>(item);
}
} // namespace enums
} // namespace enums
/// Export to CLI namespace
using enums::operator<<;
@ -298,7 +298,7 @@ inline std::vector<std::string> split_up(std::string str, char delimiter = '\0')
if(delims.find_first_of(str[0]) != std::string::npos) {
keyChar = str[0];
auto end = str.find_first_of(keyChar, 1);
while((end != std::string::npos) && (str[end - 1] == '\\')) { // deal with escaped quotes
while((end != std::string::npos) && (str[end - 1] == '\\')) { // deal with escaped quotes
end = str.find_first_of(keyChar, end + 1);
embeddedQuote = true;
}
@ -356,7 +356,7 @@ inline std::size_t escape_detect(std::string &str, std::size_t offset) {
auto astart = str.find_last_of("-/ \"\'`", offset - 1);
if(astart != std::string::npos) {
if(str[astart] == ((str[offset] == '=') ? '-' : '/'))
str[offset] = ' '; // interpret this as a space so the split_up works properly
str[offset] = ' '; // interpret this as a space so the split_up works properly
}
}
return offset + 1;
@ -374,6 +374,6 @@ inline std::string &add_quotes_if_needed(std::string &str) {
return str;
}
} // namespace detail
} // namespace detail
} // namespace CLI
} // namespace CLI

View File

@ -13,7 +13,7 @@
#endif
#include <array>
#include <chrono> // NOLINT(build/c++11)
#include <chrono> // NOLINT(build/c++11)
#include <functional>
#include <iostream>
#include <string>
@ -128,7 +128,7 @@ class AutoTimer : public Timer {
~AutoTimer() { std::cout << to_string() << std::endl; }
};
} // namespace CLI
} // namespace CLI
/// This prints out the time if shifted into a std::cout like stream.
inline std::ostream &operator<<(std::ostream &in, const CLI::Timer &timer) { return in << timer.to_string(); }

View File

@ -27,7 +27,7 @@ enum class enabler {};
/// An instance to use in EnableIf
constexpr enabler dummy = {};
} // namespace detail
} // namespace detail
/// A copy of enable_if_t from C++14, compatible with C++11.
///
@ -624,7 +624,7 @@ template <typename T,
enable_if_t<classify_object<T>::value == object_category::unsigned_integral, detail::enabler> = detail::dummy>
bool lexical_cast(const std::string &input, T &output) {
if(!input.empty() && input.front() == '-')
return false; // std::stoull happily converts negative values to junk without any errors.
return false; // std::stoull happily converts negative values to junk without any errors.
try {
std::size_t n = 0;
@ -804,7 +804,7 @@ bool lexical_assign(const std::string &input, T &output) {
XC val{};
bool parse_result = input.empty() ? true : lexical_cast<XC>(input, val);
if(parse_result) {
output = T(val); // use () form of constructor to allow some implicit conversions
output = T(val); // use () form of constructor to allow some implicit conversions
}
return parse_result;
}
@ -1007,5 +1007,5 @@ void sum_flag_vector(const std::vector<std::string> &flags, T &output) {
output = static_cast<T>(count);
}
} // namespace detail
} // namespace CLI
} // namespace detail
} // namespace CLI

View File

@ -42,7 +42,7 @@
#endif
#if defined CLI11_HAS_FILESYSTEM && CLI11_HAS_FILESYSTEM > 0
#include <filesystem> // NOLINT(build/include)
#include <filesystem> // NOLINT(build/include)
#else
#include <sys/stat.h>
#include <sys/types.h>
@ -270,7 +270,7 @@ class Validator {
return std::string(1, '(') + f1 + ')' + merger + '(' + f2 + ')';
};
}
}; // namespace CLI
}; // namespace CLI
/// Class wrapping some of the accessors of Validator
class CustomValidator : public Validator {
@ -459,7 +459,7 @@ class Number : public Validator {
}
};
} // namespace detail
} // namespace detail
// Static is not needed here, because global const implies static.
@ -561,7 +561,7 @@ typename std::remove_reference<T>::type &smart_deref(T &value) {
/// Generate a string representation of a set
template <typename T> std::string generate_set(const T &set) {
using element_t = typename detail::element_type<T>::type;
using iteration_type_t = typename detail::pair_adaptor<element_t>::value_type; // the type of the object pair
using iteration_type_t = typename detail::pair_adaptor<element_t>::value_type; // the type of the object pair
std::string out(1, '{');
out.append(detail::join(
detail::smart_deref(set),
@ -574,7 +574,7 @@ template <typename T> std::string generate_set(const T &set) {
/// Generate a string representation of a map
template <typename T> std::string generate_map(const T &map, bool key_only = false) {
using element_t = typename detail::element_type<T>::type;
using iteration_type_t = typename detail::pair_adaptor<element_t>::value_type; // the type of the object pair
using iteration_type_t = typename detail::pair_adaptor<element_t>::value_type; // the type of the object pair
std::string out(1, '{');
out.append(detail::join(
detail::smart_deref(map),
@ -685,7 +685,7 @@ typename std::enable_if<std::is_floating_point<T>::value, bool>::type checked_mu
return true;
}
} // namespace detail
} // namespace detail
/// Verify items are in a set
class IsMember : public Validator {
public:
@ -705,11 +705,11 @@ class IsMember : public Validator {
// Get the type of the contained item - requires a container have ::value_type
// if the type does not have first_type and second_type, these are both value_type
using element_t = typename detail::element_type<T>::type; // Removes (smart) pointers if needed
using item_t = typename detail::pair_adaptor<element_t>::first_type; // Is value_type if not a map
using element_t = typename detail::element_type<T>::type; // Removes (smart) pointers if needed
using item_t = typename detail::pair_adaptor<element_t>::first_type; // Is value_type if not a map
using local_item_t = typename IsMemberType<item_t>::type; // This will convert bad types to good ones
// (const char * to std::string)
using local_item_t = typename IsMemberType<item_t>::type; // This will convert bad types to good ones
// (const char * to std::string)
// Make a local copy of the filter function, using a std::function if not one already
std::function<local_item_t(local_item_t)> filter_fn = filter_function;
@ -722,7 +722,7 @@ class IsMember : public Validator {
func_ = [set, filter_fn](std::string &input) {
local_item_t b;
if(!detail::lexical_cast(input, b)) {
throw ValidationError(input); // name is added later
throw ValidationError(input); // name is added later
}
if(filter_fn) {
b = filter_fn(b);
@ -778,10 +778,10 @@ class Transformer : public Validator {
"mapping must produce value pairs");
// Get the type of the contained item - requires a container have ::value_type
// if the type does not have first_type and second_type, these are both value_type
using element_t = typename detail::element_type<T>::type; // Removes (smart) pointers if needed
using item_t = typename detail::pair_adaptor<element_t>::first_type; // Is value_type if not a map
using local_item_t = typename IsMemberType<item_t>::type; // This will convert bad types to good ones
// (const char * to std::string)
using element_t = typename detail::element_type<T>::type; // Removes (smart) pointers if needed
using item_t = typename detail::pair_adaptor<element_t>::first_type; // Is value_type if not a map
using local_item_t = typename IsMemberType<item_t>::type; // Will convert bad types to good ones
// (const char * to std::string)
// Make a local copy of the filter function, using a std::function if not one already
std::function<local_item_t(local_item_t)> filter_fn = filter_function;
@ -836,12 +836,11 @@ class CheckedTransformer : public Validator {
"mapping must produce value pairs");
// Get the type of the contained item - requires a container have ::value_type
// if the type does not have first_type and second_type, these are both value_type
using element_t = typename detail::element_type<T>::type; // Removes (smart) pointers if needed
using item_t = typename detail::pair_adaptor<element_t>::first_type; // Is value_type if not a map
using local_item_t = typename IsMemberType<item_t>::type; // This will convert bad types to good ones
// (const char * to std::string)
using iteration_type_t = typename detail::pair_adaptor<element_t>::value_type; // the type of the object pair //
// the type of the object pair
using element_t = typename detail::element_type<T>::type; // Removes (smart) pointers if needed
using item_t = typename detail::pair_adaptor<element_t>::first_type; // Is value_type if not a map
using local_item_t = typename IsMemberType<item_t>::type; // Will convert bad types to good ones
// (const char * to std::string)
using iteration_type_t = typename detail::pair_adaptor<element_t>::value_type; // the type of the object pair
// Make a local copy of the filter function, using a std::function if not one already
std::function<local_item_t(local_item_t)> filter_fn = filter_function;
@ -1125,7 +1124,7 @@ inline std::pair<std::string, std::string> split_program_name(std::string comman
return vals;
}
} // namespace detail
} // namespace detail
/// @}
} // namespace CLI
} // namespace CLI

View File

@ -684,7 +684,7 @@ TEST_F(TApp, FlagLikeOption) {
EXPECT_EQ(1u, app.count("--flag"));
EXPECT_TRUE(val);
val = false;
opt->type_size(0, 0); // should be the same as above
opt->type_size(0, 0); // should be the same as above
EXPECT_EQ(opt->get_type_size_min(), 0);
EXPECT_EQ(opt->get_type_size_max(), 0);
run();
@ -797,7 +797,7 @@ TEST_F(TApp, DefaultOpts) {
std::string s = "HI";
app.add_option("-i,i", i);
app.add_option("-s,s", s)->capture_default_str(); // Used to be different
app.add_option("-s,s", s)->capture_default_str(); // Used to be different
args = {"-i2", "9"};
@ -1191,7 +1191,7 @@ TEST_F(TApp, RequiredPositionalVector) {
// Tests positionals at end
TEST_F(TApp, RequiredPositionalValidation) {
std::vector<std::string> sources;
int dest; // required
int dest; // required
std::string d2;
app.add_option("src", sources);
app.add_option("dest", dest)->required()->check(CLI::PositiveNumber);
@ -1416,7 +1416,7 @@ TEST_F(TApp, NotRequiredExpectedDoubleShort) {
TEST_F(TApp, RequiredFlags) {
app.add_flag("-a")->required();
app.add_flag("-b")->mandatory(); // Alternate term
app.add_flag("-b")->mandatory(); // Alternate term
EXPECT_THROW(run(), CLI::RequiredError);
@ -1686,7 +1686,7 @@ TEST_F(TApp, RemoveExcludesLinks) {
args = {"--two"};
run(); // Mostly hoping it does not crash
run(); // Mostly hoping it does not crash
}
TEST_F(TApp, FileNotExists) {
@ -1700,7 +1700,7 @@ TEST_F(TApp, FileNotExists) {
run();
EXPECT_EQ(myfile, filename);
bool ok = static_cast<bool>(std::ofstream(myfile.c_str()).put('a')); // create file
bool ok = static_cast<bool>(std::ofstream(myfile.c_str()).put('a')); // create file
EXPECT_TRUE(ok);
EXPECT_THROW(run(), CLI::ValidationError);
// deactivate the check, so it should run now
@ -1720,7 +1720,7 @@ TEST_F(TApp, FileExists) {
EXPECT_THROW(run(), CLI::ValidationError);
bool ok = static_cast<bool>(std::ofstream(myfile.c_str()).put('a')); // create file
bool ok = static_cast<bool>(std::ofstream(myfile.c_str()).put('a')); // create file
EXPECT_TRUE(ok);
run();
EXPECT_EQ(myfile, filename);
@ -1739,7 +1739,7 @@ TEST_F(TApp, NotFileExists) {
EXPECT_NO_THROW(run());
bool ok = static_cast<bool>(std::ofstream(myfile.c_str()).put('a')); // create file
bool ok = static_cast<bool>(std::ofstream(myfile.c_str()).put('a')); // create file
EXPECT_TRUE(ok);
EXPECT_THROW(run(), CLI::ValidationError);
@ -1749,7 +1749,7 @@ TEST_F(TApp, NotFileExists) {
TEST_F(TApp, pair_check) {
std::string myfile{"pair_check_file.txt"};
bool ok = static_cast<bool>(std::ofstream(myfile.c_str()).put('a')); // create file
bool ok = static_cast<bool>(std::ofstream(myfile.c_str()).put('a')); // create file
EXPECT_TRUE(ok);
EXPECT_TRUE(CLI::ExistingFile(myfile).empty());
@ -1781,7 +1781,7 @@ TEST_F(TApp, pair_check) {
TEST_F(TApp, pair_check_take_first) {
std::string myfile{"pair_check_file2.txt"};
bool ok = static_cast<bool>(std::ofstream(myfile.c_str()).put('a')); // create file
bool ok = static_cast<bool>(std::ofstream(myfile.c_str()).put('a')); // create file
EXPECT_TRUE(ok);
EXPECT_TRUE(CLI::ExistingFile(myfile).empty());
@ -1924,7 +1924,7 @@ TEST_F(TApp, VectorExpectedRange) {
EXPECT_EQ(opt->get_expected_max(), 4);
EXPECT_EQ(opt->get_expected_min(), 2);
opt->expected(4, 2); // just test the handling of reversed arguments
opt->expected(4, 2); // just test the handling of reversed arguments
EXPECT_EQ(opt->get_expected_max(), 4);
EXPECT_EQ(opt->get_expected_min(), 2);
opt->expected(-5);
@ -2459,7 +2459,7 @@ TEST_F(TApp, vectorPairTypeRange) {
auto opt = app.add_option("--dict", custom_opt);
opt->type_size(2, 1); // just test switched arguments
opt->type_size(2, 1); // just test switched arguments
EXPECT_EQ(opt->get_type_size_min(), 1);
EXPECT_EQ(opt->get_type_size_max(), 2);
@ -2477,7 +2477,7 @@ TEST_F(TApp, vectorPairTypeRange) {
EXPECT_EQ(custom_opt[2].first, -1);
EXPECT_EQ(custom_opt[2].second, "str4");
opt->type_size(-2, -1); // test negative arguments
opt->type_size(-2, -1); // test negative arguments
EXPECT_EQ(opt->get_type_size_min(), 1);
EXPECT_EQ(opt->get_type_size_max(), 2);
// this type size spec should run exactly as before

View File

@ -690,12 +690,12 @@ TEST_F(TApp, IniVector) {
}
TEST_F(TApp, TOMLVector) {
TempFile tmpini{"TestIniTmp.ini"};
TempFile tmptoml{"TestTomlTmp.toml"};
app.set_config("--config", tmpini);
app.set_config("--config", tmptoml);
{
std::ofstream out{tmpini};
std::ofstream out{tmptoml};
out << "#this is a comment line\n";
out << "[default]\n";
out << "two=[2,3]\n";
@ -1045,17 +1045,17 @@ TEST_F(TApp, IniSubcommandMultipleSections) {
EXPECT_EQ(parse_c[0], 68U);
EXPECT_EQ(parse_c[1], 58U);
EXPECT_EQ(subsubcom->count(), 1u);
EXPECT_EQ(subcom2->count(), 0u); // not configurable but value is updated
EXPECT_EQ(subcom2->count(), 0u); // not configurable but value is updated
}
TEST_F(TApp, DuplicateSubcommandCallbacks) {
TempFile tmpini{"TestIniTmp.ini"};
TempFile tmptoml{"TesttomlTmp.toml"};
app.set_config("--config", tmpini);
app.set_config("--config", tmptoml);
{
std::ofstream out{tmpini};
std::ofstream out{tmptoml};
out << "[[foo]]" << std::endl;
out << "[[foo]]" << std::endl;
out << "[[foo]]" << std::endl;
@ -1195,6 +1195,7 @@ TEST_F(TApp, IniFlagDual) {
TempFile tmpini{"TestIniTmp.ini"};
bool boo{false};
app.config_formatter(std::make_shared<CLI::ConfigINI>());
app.add_flag("--flag", boo);
app.set_config("--config", tmpini);
@ -1362,7 +1363,7 @@ TEST_F(TApp, IniFalseFlagsDefDisableOverrideSuccess) {
EXPECT_EQ(15, val);
}
TEST_F(TApp, IniOutputSimple) {
TEST_F(TApp, TomlOutputSimple) {
int v{0};
app.add_option("--simple", v);
@ -1375,7 +1376,7 @@ TEST_F(TApp, IniOutputSimple) {
EXPECT_EQ("simple=3\n", str);
}
TEST_F(TApp, IniOutputNoConfigurable) {
TEST_F(TApp, TomlOutputNoConfigurable) {
int v1{0}, v2{0};
app.add_option("--simple", v1);
@ -1389,7 +1390,7 @@ TEST_F(TApp, IniOutputNoConfigurable) {
EXPECT_EQ("simple=3\n", str);
}
TEST_F(TApp, IniOutputShortSingleDescription) {
TEST_F(TApp, TomlOutputShortSingleDescription) {
std::string flag = "some_flag";
const std::string description = "Some short description.";
app.add_flag("--" + flag, description);
@ -1397,10 +1398,10 @@ TEST_F(TApp, IniOutputShortSingleDescription) {
run();
std::string str = app.config_to_str(true, true);
EXPECT_THAT(str, HasSubstr("; " + description + "\n" + flag + "=false\n"));
EXPECT_THAT(str, HasSubstr("# " + description + "\n" + flag + "=false\n"));
}
TEST_F(TApp, IniOutputShortDoubleDescription) {
TEST_F(TApp, TomlOutputShortDoubleDescription) {
std::string flag1 = "flagnr1";
std::string flag2 = "flagnr2";
const std::string description1 = "First description.";
@ -1412,10 +1413,10 @@ TEST_F(TApp, IniOutputShortDoubleDescription) {
std::string str = app.config_to_str(true, true);
EXPECT_THAT(
str, HasSubstr("; " + description1 + "\n" + flag1 + "=false\n\n; " + description2 + "\n" + flag2 + "=false\n"));
str, HasSubstr("# " + description1 + "\n" + flag1 + "=false\n\n# " + description2 + "\n" + flag2 + "=false\n"));
}
TEST_F(TApp, IniOutputGroups) {
TEST_F(TApp, TomlOutputGroups) {
std::string flag1 = "flagnr1";
std::string flag2 = "flagnr2";
const std::string description1 = "First description.";
@ -1430,7 +1431,7 @@ TEST_F(TApp, IniOutputGroups) {
EXPECT_THAT(str, HasSubstr("group2"));
}
TEST_F(TApp, IniOutputHiddenOptions) {
TEST_F(TApp, TomlOutputHiddenOptions) {
std::string flag1 = "flagnr1";
std::string flag2 = "flagnr2";
double val{12.7};
@ -1454,7 +1455,7 @@ TEST_F(TApp, IniOutputHiddenOptions) {
EXPECT_EQ(loc, std::string::npos);
}
TEST_F(TApp, IniOutputMultiLineDescription) {
TEST_F(TApp, TomlOutputMultiLineDescription) {
std::string flag = "some_flag";
const std::string description = "Some short description.\nThat has lines.";
app.add_flag("--" + flag, description);
@ -1462,12 +1463,12 @@ TEST_F(TApp, IniOutputMultiLineDescription) {
run();
std::string str = app.config_to_str(true, true);
EXPECT_THAT(str, HasSubstr("; Some short description.\n"));
EXPECT_THAT(str, HasSubstr("; That has lines.\n"));
EXPECT_THAT(str, HasSubstr("# Some short description.\n"));
EXPECT_THAT(str, HasSubstr("# That has lines.\n"));
EXPECT_THAT(str, HasSubstr(flag + "=false\n"));
}
TEST_F(TApp, IniOutputOptionGroup) {
TEST_F(TApp, TomlOutputOptionGroup) {
std::string flag1 = "flagnr1";
std::string flag2 = "flagnr2";
double val{12.7};
@ -1496,20 +1497,7 @@ TEST_F(TApp, IniOutputOptionGroup) {
EXPECT_GT(locg3, locg1);
}
TEST_F(TApp, IniOutputVector) {
std::vector<int> v;
app.add_option("--vector", v);
args = {"--vector", "1", "2", "3"};
run();
std::string str = app.config_to_str();
EXPECT_EQ("vector=1 2 3\n", str);
}
TEST_F(TApp, IniOutputVectorTOML) {
TEST_F(TApp, TomlOutputVector) {
std::vector<int> v;
app.add_option("--vector", v);
@ -1522,7 +1510,7 @@ TEST_F(TApp, IniOutputVectorTOML) {
EXPECT_EQ("vector=[1, 2, 3]\n", str);
}
TEST_F(TApp, IniOutputVectorCustom) {
TEST_F(TApp, ConfigOutputVectorCustom) {
std::vector<int> v;
app.add_option("--vector", v);
@ -1537,7 +1525,7 @@ TEST_F(TApp, IniOutputVectorCustom) {
EXPECT_EQ("vector:{1; 2; 3}\n", str);
}
TEST_F(TApp, IniOutputFlag) {
TEST_F(TApp, TomlOutputFlag) {
int v{0}, q{0};
app.add_option("--simple", v);
@ -1553,13 +1541,13 @@ TEST_F(TApp, IniOutputFlag) {
EXPECT_THAT(str, HasSubstr("simple=3"));
EXPECT_THAT(str, Not(HasSubstr("nothing")));
EXPECT_THAT(str, HasSubstr("onething=true"));
EXPECT_THAT(str, HasSubstr("something=true true"));
EXPECT_THAT(str, HasSubstr("something=[true, true]"));
str = app.config_to_str(true);
EXPECT_THAT(str, HasSubstr("nothing"));
}
TEST_F(TApp, IniOutputSet) {
TEST_F(TApp, TomlOutputSet) {
int v{0};
app.add_option("--simple", v)->check(CLI::IsMember({1, 2, 3}));
@ -1572,7 +1560,7 @@ TEST_F(TApp, IniOutputSet) {
EXPECT_THAT(str, HasSubstr("simple=2"));
}
TEST_F(TApp, IniOutputDefault) {
TEST_F(TApp, TomlOutputDefault) {
int v{7};
app.add_option("--simple", v, "", true);
@ -1586,7 +1574,7 @@ TEST_F(TApp, IniOutputDefault) {
EXPECT_THAT(str, HasSubstr("simple=7"));
}
TEST_F(TApp, IniOutputSubcom) {
TEST_F(TApp, TomlOutputSubcom) {
app.add_flag("--simple");
auto subcom = app.add_subcommand("other");
@ -1600,7 +1588,7 @@ TEST_F(TApp, IniOutputSubcom) {
EXPECT_THAT(str, HasSubstr("other.newer=true"));
}
TEST_F(TApp, IniOutputSubcomConfigurable) {
TEST_F(TApp, TomlOutputSubcomConfigurable) {
app.add_flag("--simple");
auto subcom = app.add_subcommand("other")->configurable();
@ -1616,7 +1604,7 @@ TEST_F(TApp, IniOutputSubcomConfigurable) {
EXPECT_EQ(str.find("other.newer=true"), std::string::npos);
}
TEST_F(TApp, IniOutputSubsubcom) {
TEST_F(TApp, TomlOutputSubsubcom) {
app.add_flag("--simple");
auto subcom = app.add_subcommand("other");
@ -1633,7 +1621,7 @@ TEST_F(TApp, IniOutputSubsubcom) {
EXPECT_THAT(str, HasSubstr("other.sub2.newest=true"));
}
TEST_F(TApp, IniOutputSubsubcomConfigurable) {
TEST_F(TApp, TomlOutputSubsubcomConfigurable) {
app.add_flag("--simple");
auto subcom = app.add_subcommand("other")->configurable();
@ -1654,7 +1642,7 @@ TEST_F(TApp, IniOutputSubsubcomConfigurable) {
EXPECT_EQ(str.find("sub2.newest=true"), std::string::npos);
}
TEST_F(TApp, IniOutputSubsubcomConfigurableDeep) {
TEST_F(TApp, TomlOutputSubsubcomConfigurableDeep) {
app.add_flag("--simple");
auto subcom = app.add_subcommand("other")->configurable();
@ -1677,7 +1665,7 @@ TEST_F(TApp, IniOutputSubsubcomConfigurableDeep) {
EXPECT_EQ(str.find(".absolute_newest=true"), std::string::npos);
}
TEST_F(TApp, IniQuotedOutput) {
TEST_F(TApp, TomlOutputQuoted) {
std::string val1;
app.add_option("--val1", val1);
@ -1697,7 +1685,7 @@ TEST_F(TApp, IniQuotedOutput) {
EXPECT_THAT(str, HasSubstr("val2='I am a \"confusing\" string'"));
}
TEST_F(TApp, DefaultsIniQuotedOutput) {
TEST_F(TApp, DefaultsTomlOutputQuoted) {
std::string val1{"I am a string"};
app.add_option("--val1", val1, "", true);
@ -1718,7 +1706,7 @@ TEST_F(TApp, StopReadingConfigOnClear) {
TempFile tmpini{"TestIniTmp.ini"};
app.set_config("--config", tmpini);
auto ptr = app.set_config(); // Should *not* read config file
auto ptr = app.set_config(); // Should *not* read config file
EXPECT_EQ(ptr, nullptr);
{
@ -1755,3 +1743,327 @@ TEST_F(TApp, ConfigWriteReadWrite) {
EXPECT_EQ(config1, config2);
}
///////INI output tests
TEST_F(TApp, IniOutputSimple) {
int v{0};
app.add_option("--simple", v);
app.config_formatter(std::make_shared<CLI::ConfigINI>());
args = {"--simple=3"};
run();
std::string str = app.config_to_str();
EXPECT_EQ("simple=3\n", str);
}
TEST_F(TApp, IniOutputNoConfigurable) {
int v1{0}, v2{0};
app.add_option("--simple", v1);
app.add_option("--noconf", v2)->configurable(false);
app.config_formatter(std::make_shared<CLI::ConfigINI>());
args = {"--simple=3", "--noconf=2"};
run();
std::string str = app.config_to_str();
EXPECT_EQ("simple=3\n", str);
}
TEST_F(TApp, IniOutputShortSingleDescription) {
std::string flag = "some_flag";
const std::string description = "Some short description.";
app.add_flag("--" + flag, description);
app.config_formatter(std::make_shared<CLI::ConfigINI>());
run();
std::string str = app.config_to_str(true, true);
EXPECT_THAT(str, HasSubstr("; " + description + "\n" + flag + "=false\n"));
}
TEST_F(TApp, IniOutputShortDoubleDescription) {
std::string flag1 = "flagnr1";
std::string flag2 = "flagnr2";
const std::string description1 = "First description.";
const std::string description2 = "Second description.";
app.add_flag("--" + flag1, description1);
app.add_flag("--" + flag2, description2);
app.config_formatter(std::make_shared<CLI::ConfigINI>());
run();
std::string str = app.config_to_str(true, true);
EXPECT_THAT(
str, HasSubstr("; " + description1 + "\n" + flag1 + "=false\n\n; " + description2 + "\n" + flag2 + "=false\n"));
}
TEST_F(TApp, IniOutputGroups) {
std::string flag1 = "flagnr1";
std::string flag2 = "flagnr2";
const std::string description1 = "First description.";
const std::string description2 = "Second description.";
app.add_flag("--" + flag1, description1)->group("group1");
app.add_flag("--" + flag2, description2)->group("group2");
app.config_formatter(std::make_shared<CLI::ConfigINI>());
run();
std::string str = app.config_to_str(true, true);
EXPECT_THAT(str, HasSubstr("group1"));
EXPECT_THAT(str, HasSubstr("group2"));
}
TEST_F(TApp, IniOutputHiddenOptions) {
std::string flag1 = "flagnr1";
std::string flag2 = "flagnr2";
double val{12.7};
const std::string description1 = "First description.";
const std::string description2 = "Second description.";
app.add_flag("--" + flag1, description1)->group("group1");
app.add_flag("--" + flag2, description2)->group("group2");
app.add_option("--dval", val, "", true)->group("");
app.config_formatter(std::make_shared<CLI::ConfigINI>());
run();
std::string str = app.config_to_str(true, true);
EXPECT_THAT(str, HasSubstr("group1"));
EXPECT_THAT(str, HasSubstr("group2"));
EXPECT_THAT(str, HasSubstr("dval=12.7"));
auto loc = str.find("dval=12.7");
auto locg1 = str.find("group1");
EXPECT_GT(locg1, loc);
// make sure it doesn't come twice
loc = str.find("dval=12.7", loc + 4);
EXPECT_EQ(loc, std::string::npos);
}
TEST_F(TApp, IniOutputMultiLineDescription) {
std::string flag = "some_flag";
const std::string description = "Some short description.\nThat has lines.";
app.add_flag("--" + flag, description);
app.config_formatter(std::make_shared<CLI::ConfigINI>());
run();
std::string str = app.config_to_str(true, true);
EXPECT_THAT(str, HasSubstr("; Some short description.\n"));
EXPECT_THAT(str, HasSubstr("; That has lines.\n"));
EXPECT_THAT(str, HasSubstr(flag + "=false\n"));
}
TEST_F(TApp, IniOutputOptionGroup) {
std::string flag1 = "flagnr1";
std::string flag2 = "flagnr2";
double val{12.7};
const std::string description1 = "First description.";
const std::string description2 = "Second description.";
app.add_flag("--" + flag1, description1)->group("group1");
app.add_flag("--" + flag2, description2)->group("group2");
auto og = app.add_option_group("group3", "g3 desc");
og->add_option("--dval", val, "", true)->group("");
app.config_formatter(std::make_shared<CLI::ConfigINI>());
run();
std::string str = app.config_to_str(true, true);
EXPECT_THAT(str, HasSubstr("group1"));
EXPECT_THAT(str, HasSubstr("group2"));
EXPECT_THAT(str, HasSubstr("dval=12.7"));
EXPECT_THAT(str, HasSubstr("group3"));
EXPECT_THAT(str, HasSubstr("g3 desc"));
auto loc = str.find("dval=12.7");
auto locg1 = str.find("group1");
auto locg3 = str.find("group3");
EXPECT_LT(locg1, loc);
// make sure it doesn't come twice
loc = str.find("dval=12.7", loc + 4);
EXPECT_EQ(loc, std::string::npos);
EXPECT_GT(locg3, locg1);
}
TEST_F(TApp, IniOutputVector) {
std::vector<int> v;
app.add_option("--vector", v);
args = {"--vector", "1", "2", "3"};
app.config_formatter(std::make_shared<CLI::ConfigINI>());
run();
std::string str = app.config_to_str();
EXPECT_EQ("vector=1 2 3\n", str);
}
TEST_F(TApp, IniOutputFlag) {
int v{0}, q{0};
app.add_option("--simple", v);
app.add_flag("--nothing");
app.add_flag("--onething");
app.add_flag("--something", q);
args = {"--simple=3", "--onething", "--something", "--something"};
app.config_formatter(std::make_shared<CLI::ConfigINI>());
run();
std::string str = app.config_to_str();
EXPECT_THAT(str, HasSubstr("simple=3"));
EXPECT_THAT(str, Not(HasSubstr("nothing")));
EXPECT_THAT(str, HasSubstr("onething=true"));
EXPECT_THAT(str, HasSubstr("something=true true"));
str = app.config_to_str(true);
EXPECT_THAT(str, HasSubstr("nothing"));
}
TEST_F(TApp, IniOutputSet) {
int v{0};
app.add_option("--simple", v)->check(CLI::IsMember({1, 2, 3}));
args = {"--simple=2"};
app.config_formatter(std::make_shared<CLI::ConfigINI>());
run();
std::string str = app.config_to_str();
EXPECT_THAT(str, HasSubstr("simple=2"));
}
TEST_F(TApp, IniOutputDefault) {
int v{7};
app.add_option("--simple", v, "", true);
app.config_formatter(std::make_shared<CLI::ConfigINI>());
run();
std::string str = app.config_to_str();
EXPECT_THAT(str, Not(HasSubstr("simple=7")));
str = app.config_to_str(true);
EXPECT_THAT(str, HasSubstr("simple=7"));
}
TEST_F(TApp, IniOutputSubcom) {
app.add_flag("--simple");
auto subcom = app.add_subcommand("other");
subcom->add_flag("--newer");
app.config_formatter(std::make_shared<CLI::ConfigINI>());
args = {"--simple", "other", "--newer"};
run();
std::string str = app.config_to_str();
EXPECT_THAT(str, HasSubstr("simple=true"));
EXPECT_THAT(str, HasSubstr("other.newer=true"));
}
TEST_F(TApp, IniOutputSubcomConfigurable) {
app.add_flag("--simple");
auto subcom = app.add_subcommand("other")->configurable();
subcom->add_flag("--newer");
app.config_formatter(std::make_shared<CLI::ConfigINI>());
args = {"--simple", "other", "--newer"};
run();
std::string str = app.config_to_str();
EXPECT_THAT(str, HasSubstr("simple=true"));
EXPECT_THAT(str, HasSubstr("[other]"));
EXPECT_THAT(str, HasSubstr("newer=true"));
EXPECT_EQ(str.find("other.newer=true"), std::string::npos);
}
TEST_F(TApp, IniOutputSubsubcom) {
app.add_flag("--simple");
auto subcom = app.add_subcommand("other");
subcom->add_flag("--newer");
auto subsubcom = subcom->add_subcommand("sub2");
subsubcom->add_flag("--newest");
app.config_formatter(std::make_shared<CLI::ConfigINI>());
args = {"--simple", "other", "--newer", "sub2", "--newest"};
run();
std::string str = app.config_to_str();
EXPECT_THAT(str, HasSubstr("simple=true"));
EXPECT_THAT(str, HasSubstr("other.newer=true"));
EXPECT_THAT(str, HasSubstr("other.sub2.newest=true"));
}
TEST_F(TApp, IniOutputSubsubcomConfigurable) {
app.add_flag("--simple");
auto subcom = app.add_subcommand("other")->configurable();
subcom->add_flag("--newer");
auto subsubcom = subcom->add_subcommand("sub2");
subsubcom->add_flag("--newest");
app.config_formatter(std::make_shared<CLI::ConfigINI>());
args = {"--simple", "other", "--newer", "sub2", "--newest"};
run();
std::string str = app.config_to_str();
EXPECT_THAT(str, HasSubstr("simple=true"));
EXPECT_THAT(str, HasSubstr("[other]"));
EXPECT_THAT(str, HasSubstr("newer=true"));
EXPECT_THAT(str, HasSubstr("[other.sub2]"));
EXPECT_THAT(str, HasSubstr("newest=true"));
EXPECT_EQ(str.find("sub2.newest=true"), std::string::npos);
}
TEST_F(TApp, IniOutputSubsubcomConfigurableDeep) {
app.add_flag("--simple");
auto subcom = app.add_subcommand("other")->configurable();
subcom->add_flag("--newer");
auto subsubcom = subcom->add_subcommand("sub2");
subsubcom->add_flag("--newest");
auto sssscom = subsubcom->add_subcommand("sub-level2");
subsubcom->add_flag("--still_newer");
auto s5com = sssscom->add_subcommand("sub-level3");
s5com->add_flag("--absolute_newest");
app.config_formatter(std::make_shared<CLI::ConfigINI>());
args = {"--simple", "other", "sub2", "sub-level2", "sub-level3", "--absolute_newest"};
run();
std::string str = app.config_to_str();
EXPECT_THAT(str, HasSubstr("simple=true"));
EXPECT_THAT(str, HasSubstr("[other.sub2.sub-level2.sub-level3]"));
EXPECT_THAT(str, HasSubstr("absolute_newest=true"));
EXPECT_EQ(str.find(".absolute_newest=true"), std::string::npos);
}
TEST_F(TApp, IniOutputQuoted) {
std::string val1;
app.add_option("--val1", val1);
std::string val2;
app.add_option("--val2", val2);
app.config_formatter(std::make_shared<CLI::ConfigINI>());
args = {"--val1", "I am a string", "--val2", R"(I am a "confusing" string)"};
run();
EXPECT_EQ("I am a string", val1);
EXPECT_EQ("I am a \"confusing\" string", val2);
std::string str = app.config_to_str();
EXPECT_THAT(str, HasSubstr("val1=\"I am a string\""));
EXPECT_THAT(str, HasSubstr("val2='I am a \"confusing\" string'"));
}
TEST_F(TApp, DefaultsIniOutputQuoted) {
std::string val1{"I am a string"};
app.add_option("--val1", val1, "", true);
std::string val2{R"(I am a "confusing" string)"};
app.add_option("--val2", val2, "", true);
app.config_formatter(std::make_shared<CLI::ConfigINI>());
run();
std::string str = app.config_to_str(true);
EXPECT_THAT(str, HasSubstr("val1=\"I am a string\""));
EXPECT_THAT(str, HasSubstr("val2='I am a \"confusing\" string'"));
}

View File

@ -527,7 +527,7 @@ TEST_F(TApp, GetOptionList) {
auto flag = app.add_flag("--one");
auto opt = app.add_option("--two", two);
const CLI::App &const_app = app; // const alias to force use of const-methods
const CLI::App &const_app = app; // const alias to force use of const-methods
std::vector<const CLI::Option *> opt_list = const_app.get_options();
ASSERT_EQ(opt_list.size(), static_cast<std::size_t>(3));

View File

@ -715,7 +715,7 @@ TEST(Exit, ExitCodes) {
EXPECT_EQ(0, app.exit(CLI::CallForHelp()));
EXPECT_EQ(i, app.exit(CLI::ExtrasError({"Thing"})));
EXPECT_EQ(42, app.exit(CLI::RuntimeError(42)));
EXPECT_EQ(1, app.exit(CLI::RuntimeError())); // Not sure if a default here is a good thing
EXPECT_EQ(1, app.exit(CLI::RuntimeError())); // Not sure if a default here is a good thing
}
struct CapturedHelp : public ::testing::Test {
@ -945,7 +945,7 @@ TEST(THelp, ValidatorsText) {
std::string help = app.help();
EXPECT_THAT(help, HasSubstr("TEXT:FILE"));
EXPECT_THAT(help, HasSubstr("INT in [1 - 4]"));
EXPECT_THAT(help, HasSubstr("UINT:INT in [0 - 12]")); // Loses UINT
EXPECT_THAT(help, HasSubstr("UINT:INT in [0 - 12]")); // Loses UINT
}
TEST(THelp, ValidatorsTextCustom) {

View File

@ -218,7 +218,7 @@ TEST(Trim, TrimCopy) {
TEST(Validators, FileExists) {
std::string myfile{"TestFileNotUsed.txt"};
EXPECT_FALSE(CLI::ExistingFile(myfile).empty());
bool ok = static_cast<bool>(std::ofstream(myfile.c_str()).put('a')); // create file
bool ok = static_cast<bool>(std::ofstream(myfile.c_str()).put('a')); // create file
EXPECT_TRUE(ok);
EXPECT_TRUE(CLI::ExistingFile(myfile).empty());
@ -229,7 +229,7 @@ TEST(Validators, FileExists) {
TEST(Validators, FileNotExists) {
std::string myfile{"TestFileNotUsed.txt"};
EXPECT_TRUE(CLI::NonexistentPath(myfile).empty());
bool ok = static_cast<bool>(std::ofstream(myfile.c_str()).put('a')); // create file
bool ok = static_cast<bool>(std::ofstream(myfile.c_str()).put('a')); // create file
EXPECT_TRUE(ok);
EXPECT_FALSE(CLI::NonexistentPath(myfile).empty());
@ -255,7 +255,7 @@ TEST(Validators, DirectoryNotExists) {
TEST(Validators, DirectoryIsFile) {
std::string myfile{"TestFileNotUsed.txt"};
EXPECT_TRUE(CLI::NonexistentPath(myfile).empty());
bool ok = static_cast<bool>(std::ofstream(myfile.c_str()).put('a')); // create file
bool ok = static_cast<bool>(std::ofstream(myfile.c_str()).put('a')); // create file
EXPECT_TRUE(ok);
EXPECT_FALSE(CLI::ExistingDirectory(myfile).empty());
@ -271,7 +271,7 @@ TEST(Validators, PathExistsDir) {
TEST(Validators, PathExistsFile) {
std::string myfile{"TestFileNotUsed.txt"};
EXPECT_FALSE(CLI::ExistingPath(myfile).empty());
bool ok = static_cast<bool>(std::ofstream(myfile.c_str()).put('a')); // create file
bool ok = static_cast<bool>(std::ofstream(myfile.c_str()).put('a')); // create file
EXPECT_TRUE(ok);
EXPECT_TRUE(CLI::ExistingPath(myfile).empty());
@ -383,7 +383,7 @@ TEST(Validators, CombinedOrRange) {
TEST(Validators, CombinedPaths) {
std::string myfile{"TestFileNotUsed.txt"};
EXPECT_FALSE(CLI::ExistingFile(myfile).empty());
bool ok = static_cast<bool>(std::ofstream(myfile.c_str()).put('a')); // create file
bool ok = static_cast<bool>(std::ofstream(myfile.c_str()).put('a')); // create file
EXPECT_TRUE(ok);
std::string dir{"../tests"};
@ -435,7 +435,7 @@ TEST(Validators, ProgramNameSplit) {
EXPECT_EQ(res.second, "this is a bunch of extra stuff");
res = CLI::detail::split_program_name("./program_name this is a bunch of extra stuff ");
EXPECT_EQ(res.first, "./program_name"); // test sectioning of first argument even if it can't detect the file
EXPECT_EQ(res.first, "./program_name"); // test sectioning of first argument even if it can't detect the file
EXPECT_EQ(res.second, "this is a bunch of extra stuff");
res = CLI::detail::split_program_name(std::string(" ./") + std::string(myfile) + " ");
@ -663,7 +663,7 @@ TEST(AppHelper, TempfileCreated) {
EXPECT_FALSE(CLI::ExistingFile(myfile).empty());
bool ok = static_cast<bool>(std::ofstream(myfile.c_str()).put('a')); // create file
bool ok = static_cast<bool>(std::ofstream(myfile.c_str()).put('a')); // create file
EXPECT_TRUE(ok);
EXPECT_TRUE(CLI::ExistingFile(name).empty());
EXPECT_THROW({ TempFile otherfile(name); }, std::runtime_error);
@ -994,12 +994,12 @@ TEST(Types, LexicalCastParsable) {
std::complex<double> output;
EXPECT_TRUE(CLI::detail::lexical_cast(input, output));
EXPECT_DOUBLE_EQ(output.real(), 4.2); // Doing this in one go sometimes has trouble
EXPECT_DOUBLE_EQ(output.imag(), 7.3); // on clang + c++4.8 due to missing const
EXPECT_DOUBLE_EQ(output.real(), 4.2); // Doing this in one go sometimes has trouble
EXPECT_DOUBLE_EQ(output.imag(), 7.3); // on clang + c++4.8 due to missing const
EXPECT_TRUE(CLI::detail::lexical_cast("2.456", output));
EXPECT_DOUBLE_EQ(output.real(), 2.456); // Doing this in one go sometimes has trouble
EXPECT_DOUBLE_EQ(output.imag(), 0.0); // on clang + c++4.8 due to missing const
EXPECT_DOUBLE_EQ(output.real(), 2.456); // Doing this in one go sometimes has trouble
EXPECT_DOUBLE_EQ(output.imag(), 0.0); // on clang + c++4.8 due to missing const
EXPECT_FALSE(CLI::detail::lexical_cast(fail_input, output));
EXPECT_FALSE(CLI::detail::lexical_cast(extra_input, output));

View File

@ -222,8 +222,8 @@ template <> bool lexical_cast<spair>(const std::string &input, spair &output) {
output = {input.substr(0, sep), input.substr(sep + 1)};
return true;
}
} // namespace detail
} // namespace CLI
} // namespace detail
} // namespace CLI
TEST_F(TApp, custom_string_converter) {
spair val;
@ -295,14 +295,14 @@ template <> bool lexical_cast<std::complex<double>>(const std::string &input, st
}
return worked;
}
} // namespace detail
} // namespace CLI
} // namespace detail
} // namespace CLI
TEST_F(TApp, AddingComplexParserDetail) {
bool skip_tests = false;
try { // check if the library actually supports regex, it is possible to link against a non working regex in the
// standard library
try { // check if the library actually supports regex, it is possible to link against a non working regex in the
// standard library
std::smatch m;
std::string input = "1.5+2.5j";
static const std::regex creg(

View File

@ -768,6 +768,6 @@ TEST_F(ManyGroupsPreTrigger, PreTriggerTestsSubcommand) {
EXPECT_EQ(triggerMain, 4u);
EXPECT_EQ(trigger1, 1u);
EXPECT_EQ(trigger2, 3u);
EXPECT_EQ(trigger3, 1u); // processes the first argument in group3 which includes the entire subcommand, which will
// go until the sub1 command is given
EXPECT_EQ(trigger3, 1u); // processes the first argument in group3 which includes the entire subcommand, which will
// go until the sub1 command is given
}

View File

@ -508,11 +508,11 @@ TEST_F(TApp, InSetIgnoreCase) {
args = {"--quick", "two"};
run();
EXPECT_EQ("Two", choice); // Keeps caps from set
EXPECT_EQ("Two", choice); // Keeps caps from set
args = {"--quick", "ThrEE"};
run();
EXPECT_EQ("THREE", choice); // Keeps caps from set
EXPECT_EQ("THREE", choice); // Keeps caps from set
args = {"--quick", "four"};
EXPECT_THROW(run(), CLI::ValidationError);
@ -533,11 +533,11 @@ TEST_F(TApp, InSetIgnoreCaseMutableValue) {
args = {"--quick", "two"};
run();
EXPECT_EQ("Two", choice); // Keeps caps from set
EXPECT_EQ("Two", choice); // Keeps caps from set
args = {"--quick", "ThrEE"};
run();
EXPECT_EQ("THREE", choice); // Keeps caps from set
EXPECT_EQ("THREE", choice); // Keeps caps from set
options.clear();
args = {"--quick", "ThrEE"};
@ -556,16 +556,16 @@ TEST_F(TApp, InSetIgnoreCasePointer) {
args = {"--quick", "two"};
run();
EXPECT_EQ("Two", choice); // Keeps caps from set
EXPECT_EQ("Two", choice); // Keeps caps from set
args = {"--quick", "ThrEE"};
run();
EXPECT_EQ("THREE", choice); // Keeps caps from set
EXPECT_EQ("THREE", choice); // Keeps caps from set
delete options;
args = {"--quick", "ThrEE"};
run();
EXPECT_EQ("THREE", choice); // this does not throw a segfault
EXPECT_EQ("THREE", choice); // this does not throw a segfault
args = {"--quick", "four"};
EXPECT_THROW(run(), CLI::ValidationError);
@ -600,11 +600,11 @@ TEST_F(TApp, InSetIgnoreUnderscore) {
args = {"--quick", "optiontwo"};
run();
EXPECT_EQ("option_two", choice); // Keeps underscore from set
EXPECT_EQ("option_two", choice); // Keeps underscore from set
args = {"--quick", "_option_thr_ee"};
run();
EXPECT_EQ("optionthree", choice); // no underscore
EXPECT_EQ("optionthree", choice); // no underscore
args = {"--quick", "Option4"};
EXPECT_THROW(run(), CLI::ValidationError);
@ -626,11 +626,11 @@ TEST_F(TApp, InSetIgnoreCaseUnderscore) {
args = {"--quick", "OptionTwo"};
run();
EXPECT_EQ("option_two", choice); // Keeps underscore and case from set
EXPECT_EQ("option_two", choice); // Keeps underscore and case from set
args = {"--quick", "_OPTION_thr_ee"};
run();
EXPECT_EQ("OptionThree", choice); // no underscore
EXPECT_EQ("OptionThree", choice); // no underscore
args = {"--quick", "Option4"};
EXPECT_THROW(run(), CLI::ValidationError);

View File

@ -104,7 +104,7 @@ TEST_F(TApp, CrazyNameSubcommand) {
EXPECT_EQ(sub1->count(), 1u);
}
TEST_F(TApp, RequiredAndSubcommands) { // #23
TEST_F(TApp, RequiredAndSubcommands) { // #23
std::string baz;
app.add_option("baz", baz, "Baz Description", true)->required();
@ -631,13 +631,13 @@ TEST_F(TApp, CallbackOrderingImmediateMain) {
EXPECT_EQ(0, sub_val);
// the main app callback should run before the subcommand callbacks
app.immediate_callback();
val = 0; // reset value
val = 0; // reset value
run();
EXPECT_EQ(2, val);
EXPECT_EQ(1, sub_val);
// the subcommand callback now runs immediately after processing and before the main app callback again
sub->immediate_callback();
val = 0; // reset value
val = 0; // reset value
run();
EXPECT_EQ(1, val);
EXPECT_EQ(0, sub_val);
@ -1213,7 +1213,7 @@ TEST_F(ManySubcommands, Unlimited) {
run();
EXPECT_EQ(app.remaining(true), vs_t());
app.require_subcommand(2, 0); // 2 or more
app.require_subcommand(2, 0); // 2 or more
run();
EXPECT_EQ(app.remaining(true), vs_t());

View File

@ -4,7 +4,7 @@
struct TApp_TBO : public TApp, public ::testing::WithParamInterface<const char *> {};
TEST_P(TApp_TBO, TrueBoolOption) {
bool value{false}; // Not used, but set just in case
bool value{false}; // Not used, but set just in case
app.add_option("-b,--bool", value);
args = {"--bool", GetParam()};
run();
@ -19,7 +19,7 @@ INSTANTIATE_TEST_CASE_P(TrueBoolOptions, TApp_TBO, ::testing::Values("true", "on
struct TApp_FBO : public TApp, public ::testing::WithParamInterface<const char *> {};
TEST_P(TApp_FBO, FalseBoolOptions) {
bool value{true}; // Not used, but set just in case
bool value{true}; // Not used, but set just in case
app.add_option("-b,--bool", value);
args = {"--bool", GetParam()};
run();

View File

@ -33,7 +33,7 @@ class TempFile {
}
~TempFile() {
std::remove(_name.c_str()); // Doesn't matter if returns 0 or not
std::remove(_name.c_str()); // Doesn't matter if returns 0 or not
}
operator const std::string &() const { return _name; }