mirror of
https://github.com/CLIUtils/CLI11.git
synced 2025-04-29 12:13:52 +00:00
Refactor some of the configuration file handling code. Make it easier to get the actual file that was processed, and allow extras in the config file to be ignored (default now), captured or errored. fix std::error reference and formatting add test for required but no default and fix a shadow warning on 'required' from gcc 4.8 Test correctness of config write-read loop fix config generation for flag definitions make the config output conform with toml continue work on the config file interpretation and construction get all the ini tests working again with the cleaned up features. update formatting rename IniTest to ConfigFileTest to better reflect actual tests and add a few more test of the configTOML disambiguate enable/disable by default to an enumeration, and to make room for a configurable option to allow subcommands to be triggered by a config file. add a ConfigBase class to generally reflect a broader class of configuration files formats of similar nature to INI files add configurable to app and allow it to trigger subcommands add test of ini formatting add section support to the config files so sections can be opened and closed and the callbacks triggered as appropriate. add handling of option groups to the config file output add subcommand and option group configuration to config file output subsubcom test on config files fix a few sign comparison warnings and formatting start working on the book edits for configuration and a few more tests more test to check for subcommand close in config files more tests for coverage generalize section opening and closing add more tests and some fixes for different configurations yet more tests of different situations related to configuration files test more paths for configuration file sections remove some unused code and fix some codacy warnings update readme with updates from configuration files more book edits and README formatting remove extra space Apply suggestions from code review Co-Authored-By: Henry Schreiner <HenrySchreinerIII@gmail.com> fix some comments and documentation fix spacing Rename size_t -> std::size_t Fix compiler warnings with -Wsign-conversion Fix new warnings with -Wsign-conversion in PR
750 lines
24 KiB
C++
750 lines
24 KiB
C++
#include "app_helper.hpp"
|
|
#include <cstdlib>
|
|
|
|
TEST_F(TApp, AddingExistingShort) {
|
|
CLI::Option *opt = app.add_flag("-c,--count");
|
|
EXPECT_EQ(opt->get_lnames(), std::vector<std::string>({"count"}));
|
|
EXPECT_EQ(opt->get_snames(), std::vector<std::string>({"c"}));
|
|
|
|
EXPECT_THROW(app.add_flag("--cat,-c"), CLI::OptionAlreadyAdded);
|
|
}
|
|
|
|
TEST_F(TApp, AddingExistingLong) {
|
|
app.add_flag("-q,--count");
|
|
EXPECT_THROW(app.add_flag("--count,-c"), CLI::OptionAlreadyAdded);
|
|
}
|
|
|
|
TEST_F(TApp, AddingExistingShortNoCase) {
|
|
app.add_flag("-C,--count")->ignore_case();
|
|
EXPECT_THROW(app.add_flag("--cat,-c"), CLI::OptionAlreadyAdded);
|
|
}
|
|
|
|
TEST_F(TApp, AddingExistingLongNoCase) {
|
|
app.add_flag("-q,--count")->ignore_case();
|
|
EXPECT_THROW(app.add_flag("--Count,-c"), CLI::OptionAlreadyAdded);
|
|
}
|
|
|
|
TEST_F(TApp, AddingExistingNoCaseReversed) {
|
|
app.add_flag("-c,--count")->ignore_case();
|
|
EXPECT_THROW(app.add_flag("--cat,-C"), CLI::OptionAlreadyAdded);
|
|
}
|
|
|
|
TEST_F(TApp, AddingExistingWithCase) {
|
|
app.add_flag("-c,--count");
|
|
EXPECT_NO_THROW(app.add_flag("--Cat,-C"));
|
|
}
|
|
|
|
TEST_F(TApp, AddingExistingWithCaseAfter) {
|
|
auto count = app.add_flag("-c,--count");
|
|
app.add_flag("--Cat,-C");
|
|
|
|
EXPECT_THROW(count->ignore_case(), CLI::OptionAlreadyAdded);
|
|
}
|
|
|
|
TEST_F(TApp, AddingExistingWithCaseAfter2) {
|
|
app.add_flag("-c,--count");
|
|
auto cat = app.add_flag("--Cat,-C");
|
|
|
|
EXPECT_THROW(cat->ignore_case(), CLI::OptionAlreadyAdded);
|
|
}
|
|
|
|
TEST_F(TApp, AddingExistingWithUnderscoreAfter) {
|
|
auto count = app.add_flag("--underscore");
|
|
app.add_flag("--under_score");
|
|
|
|
EXPECT_THROW(count->ignore_underscore(), CLI::OptionAlreadyAdded);
|
|
}
|
|
|
|
TEST_F(TApp, AddingExistingWithUnderscoreAfter2) {
|
|
auto count = app.add_flag("--under_score");
|
|
app.add_flag("--underscore");
|
|
|
|
EXPECT_THROW(count->ignore_underscore(), CLI::OptionAlreadyAdded);
|
|
}
|
|
|
|
TEST_F(TApp, AddingMultipleInfPositionals) {
|
|
std::vector<std::string> one, two;
|
|
app.add_option("one", one);
|
|
app.add_option("two", two);
|
|
|
|
EXPECT_THROW(run(), CLI::InvalidError);
|
|
}
|
|
|
|
TEST_F(TApp, AddingMultipleInfPositionalsSubcom) {
|
|
std::vector<std::string> one, two;
|
|
CLI::App *below = app.add_subcommand("below");
|
|
below->add_option("one", one);
|
|
below->add_option("two", two);
|
|
|
|
EXPECT_THROW(run(), CLI::InvalidError);
|
|
}
|
|
|
|
TEST_F(TApp, MultipleSubcomMatching) {
|
|
app.add_subcommand("first");
|
|
app.add_subcommand("second");
|
|
app.add_subcommand("Second");
|
|
EXPECT_THROW(app.add_subcommand("first"), CLI::OptionAlreadyAdded);
|
|
}
|
|
|
|
TEST_F(TApp, RecoverSubcommands) {
|
|
CLI::App *app1 = app.add_subcommand("app1");
|
|
CLI::App *app2 = app.add_subcommand("app2");
|
|
CLI::App *app3 = app.add_subcommand("app3");
|
|
CLI::App *app4 = app.add_subcommand("app4");
|
|
|
|
EXPECT_EQ(app.get_subcommands({}), std::vector<CLI::App *>({app1, app2, app3, app4}));
|
|
}
|
|
|
|
TEST_F(TApp, MultipleSubcomMatchingWithCase) {
|
|
app.add_subcommand("first")->ignore_case();
|
|
EXPECT_THROW(app.add_subcommand("fIrst"), CLI::OptionAlreadyAdded);
|
|
}
|
|
|
|
TEST_F(TApp, MultipleSubcomMatchingWithCaseFirst) {
|
|
app.ignore_case();
|
|
app.add_subcommand("first");
|
|
EXPECT_THROW(app.add_subcommand("fIrst"), CLI::OptionAlreadyAdded);
|
|
}
|
|
|
|
TEST_F(TApp, MultipleSubcomMatchingWithUnderscore) {
|
|
app.add_subcommand("first_option")->ignore_underscore();
|
|
EXPECT_THROW(app.add_subcommand("firstoption"), CLI::OptionAlreadyAdded);
|
|
}
|
|
|
|
TEST_F(TApp, MultipleSubcomMatchingWithUnderscoreFirst) {
|
|
app.ignore_underscore();
|
|
app.add_subcommand("first_option");
|
|
EXPECT_THROW(app.add_subcommand("firstoption"), CLI::OptionAlreadyAdded);
|
|
}
|
|
|
|
TEST_F(TApp, MultipleSubcomMatchingWithCaseInplace) {
|
|
app.add_subcommand("first");
|
|
auto first = app.add_subcommand("fIrst");
|
|
|
|
EXPECT_THROW(first->ignore_case(), CLI::OptionAlreadyAdded);
|
|
}
|
|
|
|
TEST_F(TApp, MultipleSubcomMatchingWithCaseInplace2) {
|
|
auto first = app.add_subcommand("first");
|
|
app.add_subcommand("fIrst");
|
|
|
|
EXPECT_THROW(first->ignore_case(), CLI::OptionAlreadyAdded);
|
|
}
|
|
|
|
TEST_F(TApp, MultipleSubcomMatchingWithUnderscoreInplace) {
|
|
app.add_subcommand("first_option");
|
|
auto first = app.add_subcommand("firstoption");
|
|
|
|
EXPECT_THROW(first->ignore_underscore(), CLI::OptionAlreadyAdded);
|
|
}
|
|
|
|
TEST_F(TApp, MultipleSubcomMatchingWithUnderscoreInplace2) {
|
|
auto first = app.add_subcommand("firstoption");
|
|
app.add_subcommand("first_option");
|
|
|
|
EXPECT_THROW(first->ignore_underscore(), CLI::OptionAlreadyAdded);
|
|
}
|
|
|
|
TEST_F(TApp, MultipleSubcomNoMatchingInplace2) {
|
|
auto first = app.add_subcommand("first");
|
|
auto second = app.add_subcommand("second");
|
|
|
|
EXPECT_NO_THROW(first->ignore_case());
|
|
EXPECT_NO_THROW(second->ignore_case());
|
|
}
|
|
|
|
TEST_F(TApp, MultipleSubcomNoMatchingInplaceUnderscore2) {
|
|
auto first = app.add_subcommand("first_option");
|
|
auto second = app.add_subcommand("second_option");
|
|
|
|
EXPECT_NO_THROW(first->ignore_underscore());
|
|
EXPECT_NO_THROW(second->ignore_underscore());
|
|
}
|
|
|
|
TEST_F(TApp, IncorrectConstructionFlagPositional1) { EXPECT_THROW(app.add_flag("cat"), CLI::IncorrectConstruction); }
|
|
|
|
TEST_F(TApp, IncorrectConstructionFlagPositional2) {
|
|
int x;
|
|
EXPECT_THROW(app.add_flag("cat", x), CLI::IncorrectConstruction);
|
|
}
|
|
|
|
TEST_F(TApp, IncorrectConstructionFlagPositional3) {
|
|
bool x;
|
|
EXPECT_THROW(app.add_flag("cat", x), CLI::IncorrectConstruction);
|
|
}
|
|
|
|
TEST_F(TApp, IncorrectConstructionNeedsCannotFind) {
|
|
auto cat = app.add_flag("--cat");
|
|
EXPECT_THROW(cat->needs("--nothing"), CLI::IncorrectConstruction);
|
|
}
|
|
|
|
TEST_F(TApp, IncorrectConstructionExcludesCannotFind) {
|
|
auto cat = app.add_flag("--cat");
|
|
EXPECT_THROW(cat->excludes("--nothing"), CLI::IncorrectConstruction);
|
|
}
|
|
|
|
TEST_F(TApp, IncorrectConstructionDuplicateNeeds) {
|
|
auto cat = app.add_flag("--cat");
|
|
auto other = app.add_flag("--other");
|
|
ASSERT_NO_THROW(cat->needs(other));
|
|
// duplicated needs is redundant but not an error
|
|
EXPECT_NO_THROW(cat->needs(other));
|
|
}
|
|
|
|
TEST_F(TApp, IncorrectConstructionDuplicateNeedsTxt) {
|
|
auto cat = app.add_flag("--cat");
|
|
app.add_flag("--other");
|
|
ASSERT_NO_THROW(cat->needs("--other"));
|
|
// duplicate needs is redundant but not an error
|
|
EXPECT_NO_THROW(cat->needs("--other"));
|
|
}
|
|
|
|
// Now allowed
|
|
TEST_F(TApp, CorrectConstructionDuplicateExcludes) {
|
|
auto cat = app.add_flag("--cat");
|
|
auto other = app.add_flag("--other");
|
|
ASSERT_NO_THROW(cat->excludes(other));
|
|
ASSERT_NO_THROW(other->excludes(cat));
|
|
}
|
|
|
|
// Now allowed
|
|
TEST_F(TApp, CorrectConstructionDuplicateExcludesTxt) {
|
|
auto cat = app.add_flag("--cat");
|
|
auto other = app.add_flag("--other");
|
|
ASSERT_NO_THROW(cat->excludes("--other"));
|
|
ASSERT_NO_THROW(other->excludes("--cat"));
|
|
}
|
|
|
|
TEST_F(TApp, CheckName) {
|
|
auto long1 = app.add_flag("--long1");
|
|
auto long2 = app.add_flag("--Long2");
|
|
auto short1 = app.add_flag("-a");
|
|
auto short2 = app.add_flag("-B");
|
|
int x, y;
|
|
auto pos1 = app.add_option("pos1", x);
|
|
auto pos2 = app.add_option("pOs2", y);
|
|
|
|
EXPECT_TRUE(long1->check_name("--long1"));
|
|
EXPECT_FALSE(long1->check_name("--lonG1"));
|
|
|
|
EXPECT_TRUE(long2->check_name("--Long2"));
|
|
EXPECT_FALSE(long2->check_name("--long2"));
|
|
|
|
EXPECT_TRUE(short1->check_name("-a"));
|
|
EXPECT_FALSE(short1->check_name("-A"));
|
|
|
|
EXPECT_TRUE(short2->check_name("-B"));
|
|
EXPECT_FALSE(short2->check_name("-b"));
|
|
|
|
EXPECT_TRUE(pos1->check_name("pos1"));
|
|
EXPECT_FALSE(pos1->check_name("poS1"));
|
|
|
|
EXPECT_TRUE(pos2->check_name("pOs2"));
|
|
EXPECT_FALSE(pos2->check_name("pos2"));
|
|
}
|
|
|
|
TEST_F(TApp, CheckNameNoCase) {
|
|
auto long1 = app.add_flag("--long1")->ignore_case();
|
|
auto long2 = app.add_flag("--Long2")->ignore_case();
|
|
auto short1 = app.add_flag("-a")->ignore_case();
|
|
auto short2 = app.add_flag("-B")->ignore_case();
|
|
int x, y;
|
|
auto pos1 = app.add_option("pos1", x)->ignore_case();
|
|
auto pos2 = app.add_option("pOs2", y)->ignore_case();
|
|
|
|
EXPECT_TRUE(long1->check_name("--long1"));
|
|
EXPECT_TRUE(long1->check_name("--lonG1"));
|
|
|
|
EXPECT_TRUE(long2->check_name("--Long2"));
|
|
EXPECT_TRUE(long2->check_name("--long2"));
|
|
|
|
EXPECT_TRUE(short1->check_name("-a"));
|
|
EXPECT_TRUE(short1->check_name("-A"));
|
|
|
|
EXPECT_TRUE(short2->check_name("-B"));
|
|
EXPECT_TRUE(short2->check_name("-b"));
|
|
|
|
EXPECT_TRUE(pos1->check_name("pos1"));
|
|
EXPECT_TRUE(pos1->check_name("poS1"));
|
|
|
|
EXPECT_TRUE(pos2->check_name("pOs2"));
|
|
EXPECT_TRUE(pos2->check_name("pos2"));
|
|
}
|
|
|
|
TEST_F(TApp, CheckNameNoUnderscore) {
|
|
auto long1 = app.add_flag("--longoption1")->ignore_underscore();
|
|
auto long2 = app.add_flag("--long_option2")->ignore_underscore();
|
|
|
|
int x, y;
|
|
auto pos1 = app.add_option("pos_option_1", x)->ignore_underscore();
|
|
auto pos2 = app.add_option("posoption2", y)->ignore_underscore();
|
|
|
|
EXPECT_TRUE(long1->check_name("--long_option1"));
|
|
EXPECT_TRUE(long1->check_name("--longoption_1"));
|
|
EXPECT_TRUE(long1->check_name("--longoption1"));
|
|
EXPECT_TRUE(long1->check_name("--long__opt_ion__1"));
|
|
EXPECT_TRUE(long1->check_name("--__l_o_n_g_o_p_t_i_o_n_1"));
|
|
|
|
EXPECT_TRUE(long2->check_name("--long_option2"));
|
|
EXPECT_TRUE(long2->check_name("--longoption2"));
|
|
EXPECT_TRUE(long2->check_name("--longoption_2"));
|
|
EXPECT_TRUE(long2->check_name("--long__opt_ion__2"));
|
|
EXPECT_TRUE(long2->check_name("--__l_o_n_go_p_t_i_o_n_2__"));
|
|
|
|
EXPECT_TRUE(pos1->check_name("pos_option1"));
|
|
EXPECT_TRUE(pos1->check_name("pos_option_1"));
|
|
EXPECT_TRUE(pos1->check_name("pos_o_p_t_i_on_1"));
|
|
EXPECT_TRUE(pos1->check_name("posoption1"));
|
|
|
|
EXPECT_TRUE(pos2->check_name("pos_option2"));
|
|
EXPECT_TRUE(pos2->check_name("pos_option_2"));
|
|
EXPECT_TRUE(pos2->check_name("pos_o_p_t_i_on_2"));
|
|
EXPECT_TRUE(pos2->check_name("posoption2"));
|
|
}
|
|
|
|
TEST_F(TApp, CheckNameNoCaseNoUnderscore) {
|
|
auto long1 = app.add_flag("--LongoptioN1")->ignore_underscore()->ignore_case();
|
|
auto long2 = app.add_flag("--long_Option2")->ignore_case()->ignore_underscore();
|
|
|
|
int x, y;
|
|
auto pos1 = app.add_option("pos_Option_1", x)->ignore_underscore()->ignore_case();
|
|
auto pos2 = app.add_option("posOption2", y)->ignore_case()->ignore_underscore();
|
|
|
|
EXPECT_TRUE(long1->check_name("--Long_Option1"));
|
|
EXPECT_TRUE(long1->check_name("--lONgoption_1"));
|
|
EXPECT_TRUE(long1->check_name("--LongOption1"));
|
|
EXPECT_TRUE(long1->check_name("--long__Opt_ion__1"));
|
|
EXPECT_TRUE(long1->check_name("--__l_o_N_g_o_P_t_i_O_n_1"));
|
|
|
|
EXPECT_TRUE(long2->check_name("--long_Option2"));
|
|
EXPECT_TRUE(long2->check_name("--LongOption2"));
|
|
EXPECT_TRUE(long2->check_name("--longOPTION_2"));
|
|
EXPECT_TRUE(long2->check_name("--long__OPT_ion__2"));
|
|
EXPECT_TRUE(long2->check_name("--__l_o_n_GO_p_t_i_o_n_2__"));
|
|
|
|
EXPECT_TRUE(pos1->check_name("POS_Option1"));
|
|
EXPECT_TRUE(pos1->check_name("pos_option_1"));
|
|
EXPECT_TRUE(pos1->check_name("pos_o_p_t_i_on_1"));
|
|
EXPECT_TRUE(pos1->check_name("posoption1"));
|
|
|
|
EXPECT_TRUE(pos2->check_name("pos_option2"));
|
|
EXPECT_TRUE(pos2->check_name("pos_OPTION_2"));
|
|
EXPECT_TRUE(pos2->check_name("poS_o_p_T_I_on_2"));
|
|
EXPECT_TRUE(pos2->check_name("PosOption2"));
|
|
}
|
|
|
|
TEST_F(TApp, PreSpaces) {
|
|
int x;
|
|
auto myapp = app.add_option(" -a, --long, other", x);
|
|
|
|
EXPECT_TRUE(myapp->check_lname("long"));
|
|
EXPECT_TRUE(myapp->check_sname("a"));
|
|
EXPECT_TRUE(myapp->check_name("other"));
|
|
}
|
|
|
|
TEST_F(TApp, AllSpaces) {
|
|
int x;
|
|
auto myapp = app.add_option(" -a , --long , other ", x);
|
|
|
|
EXPECT_TRUE(myapp->check_lname("long"));
|
|
EXPECT_TRUE(myapp->check_sname("a"));
|
|
EXPECT_TRUE(myapp->check_name("other"));
|
|
}
|
|
|
|
TEST_F(TApp, OptionFromDefaults) {
|
|
app.option_defaults()->required();
|
|
|
|
// Options should remember defaults
|
|
int x;
|
|
auto opt = app.add_option("--simple", x);
|
|
EXPECT_TRUE(opt->get_required());
|
|
|
|
// Flags cannot be required
|
|
auto flag = app.add_flag("--other");
|
|
EXPECT_FALSE(flag->get_required());
|
|
|
|
app.option_defaults()->required(false);
|
|
auto opt2 = app.add_option("--simple2", x);
|
|
EXPECT_FALSE(opt2->get_required());
|
|
|
|
app.option_defaults()->required()->ignore_case();
|
|
|
|
auto opt3 = app.add_option("--simple3", x);
|
|
EXPECT_TRUE(opt3->get_required());
|
|
EXPECT_TRUE(opt3->get_ignore_case());
|
|
|
|
app.option_defaults()->required()->ignore_underscore();
|
|
|
|
auto opt4 = app.add_option("--simple4", x);
|
|
EXPECT_TRUE(opt4->get_required());
|
|
EXPECT_TRUE(opt4->get_ignore_underscore());
|
|
}
|
|
|
|
TEST_F(TApp, OptionFromDefaultsSubcommands) {
|
|
// Initial defaults
|
|
EXPECT_FALSE(app.option_defaults()->get_required());
|
|
EXPECT_EQ(app.option_defaults()->get_multi_option_policy(), CLI::MultiOptionPolicy::Throw);
|
|
EXPECT_FALSE(app.option_defaults()->get_ignore_case());
|
|
EXPECT_FALSE(app.option_defaults()->get_ignore_underscore());
|
|
EXPECT_FALSE(app.option_defaults()->get_disable_flag_override());
|
|
EXPECT_TRUE(app.option_defaults()->get_configurable());
|
|
EXPECT_EQ(app.option_defaults()->get_group(), "Options");
|
|
|
|
app.option_defaults()
|
|
->required()
|
|
->multi_option_policy(CLI::MultiOptionPolicy::TakeLast)
|
|
->ignore_case()
|
|
->ignore_underscore()
|
|
->configurable(false)
|
|
->disable_flag_override()
|
|
->group("Something");
|
|
|
|
auto app2 = app.add_subcommand("app2");
|
|
|
|
EXPECT_TRUE(app2->option_defaults()->get_required());
|
|
EXPECT_EQ(app2->option_defaults()->get_multi_option_policy(), CLI::MultiOptionPolicy::TakeLast);
|
|
EXPECT_TRUE(app2->option_defaults()->get_ignore_case());
|
|
EXPECT_TRUE(app2->option_defaults()->get_ignore_underscore());
|
|
EXPECT_FALSE(app2->option_defaults()->get_configurable());
|
|
EXPECT_TRUE(app.option_defaults()->get_disable_flag_override());
|
|
EXPECT_EQ(app2->option_defaults()->get_group(), "Something");
|
|
}
|
|
|
|
TEST_F(TApp, GetNameCheck) {
|
|
int x;
|
|
auto a = app.add_flag("--that");
|
|
auto b = app.add_flag("-x");
|
|
auto c = app.add_option("pos", x);
|
|
auto d = app.add_option("one,-o,--other", x);
|
|
|
|
EXPECT_EQ(a->get_name(false, true), "--that");
|
|
EXPECT_EQ(b->get_name(false, true), "-x");
|
|
EXPECT_EQ(c->get_name(false, true), "pos");
|
|
|
|
EXPECT_EQ(d->get_name(), "--other");
|
|
EXPECT_EQ(d->get_name(false, false), "--other");
|
|
EXPECT_EQ(d->get_name(false, true), "-o,--other");
|
|
EXPECT_EQ(d->get_name(true, true), "one,-o,--other");
|
|
EXPECT_EQ(d->get_name(true, false), "one");
|
|
}
|
|
|
|
TEST_F(TApp, SubcommandDefaults) {
|
|
// allow_extras, prefix_command, ignore_case, fallthrough, group, min/max subcommand, validate_positionals
|
|
|
|
// Initial defaults
|
|
EXPECT_FALSE(app.get_allow_extras());
|
|
EXPECT_FALSE(app.get_prefix_command());
|
|
EXPECT_FALSE(app.get_immediate_callback());
|
|
EXPECT_FALSE(app.get_ignore_case());
|
|
EXPECT_FALSE(app.get_ignore_underscore());
|
|
#ifdef _WIN32
|
|
EXPECT_TRUE(app.get_allow_windows_style_options());
|
|
#else
|
|
EXPECT_FALSE(app.get_allow_windows_style_options());
|
|
#endif
|
|
EXPECT_FALSE(app.get_fallthrough());
|
|
EXPECT_FALSE(app.get_configurable());
|
|
EXPECT_FALSE(app.get_validate_positionals());
|
|
|
|
EXPECT_EQ(app.get_footer(), "");
|
|
EXPECT_EQ(app.get_group(), "Subcommands");
|
|
EXPECT_EQ(app.get_require_subcommand_min(), 0u);
|
|
EXPECT_EQ(app.get_require_subcommand_max(), 0u);
|
|
|
|
app.allow_extras();
|
|
app.prefix_command();
|
|
app.immediate_callback();
|
|
app.ignore_case();
|
|
app.ignore_underscore();
|
|
app.configurable();
|
|
#ifdef _WIN32
|
|
app.allow_windows_style_options(false);
|
|
#else
|
|
app.allow_windows_style_options();
|
|
#endif
|
|
|
|
app.fallthrough();
|
|
app.validate_positionals();
|
|
app.footer("footy");
|
|
app.group("Stuff");
|
|
app.require_subcommand(2, 3);
|
|
|
|
auto app2 = app.add_subcommand("app2");
|
|
|
|
// Initial defaults
|
|
EXPECT_TRUE(app2->get_allow_extras());
|
|
EXPECT_TRUE(app2->get_prefix_command());
|
|
EXPECT_TRUE(app2->get_immediate_callback());
|
|
EXPECT_TRUE(app2->get_ignore_case());
|
|
EXPECT_TRUE(app2->get_ignore_underscore());
|
|
#ifdef _WIN32
|
|
EXPECT_FALSE(app2->get_allow_windows_style_options());
|
|
#else
|
|
EXPECT_TRUE(app2->get_allow_windows_style_options());
|
|
#endif
|
|
EXPECT_TRUE(app2->get_fallthrough());
|
|
EXPECT_TRUE(app2->get_validate_positionals());
|
|
EXPECT_TRUE(app2->get_configurable());
|
|
EXPECT_EQ(app2->get_footer(), "footy");
|
|
EXPECT_EQ(app2->get_group(), "Stuff");
|
|
EXPECT_EQ(app2->get_require_subcommand_min(), 0u);
|
|
EXPECT_EQ(app2->get_require_subcommand_max(), 3u);
|
|
}
|
|
|
|
TEST_F(TApp, SubcommandMinMax) {
|
|
|
|
EXPECT_EQ(app.get_require_subcommand_min(), 0u);
|
|
EXPECT_EQ(app.get_require_subcommand_max(), 0u);
|
|
|
|
app.require_subcommand();
|
|
|
|
EXPECT_EQ(app.get_require_subcommand_min(), 1u);
|
|
EXPECT_EQ(app.get_require_subcommand_max(), 0u);
|
|
|
|
app.require_subcommand(2);
|
|
|
|
EXPECT_EQ(app.get_require_subcommand_min(), 2u);
|
|
EXPECT_EQ(app.get_require_subcommand_max(), 2u);
|
|
|
|
app.require_subcommand(0);
|
|
|
|
EXPECT_EQ(app.get_require_subcommand_min(), 0u);
|
|
EXPECT_EQ(app.get_require_subcommand_max(), 0u);
|
|
|
|
app.require_subcommand(-2);
|
|
|
|
EXPECT_EQ(app.get_require_subcommand_min(), 0u);
|
|
EXPECT_EQ(app.get_require_subcommand_max(), 2u);
|
|
|
|
app.require_subcommand(3, 7);
|
|
|
|
EXPECT_EQ(app.get_require_subcommand_min(), 3u);
|
|
EXPECT_EQ(app.get_require_subcommand_max(), 7u);
|
|
}
|
|
|
|
TEST_F(TApp, GetOptionList) {
|
|
int two;
|
|
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
|
|
std::vector<const CLI::Option *> opt_list = const_app.get_options();
|
|
|
|
ASSERT_EQ(opt_list.size(), static_cast<std::size_t>(3));
|
|
EXPECT_EQ(opt_list.at(1), flag);
|
|
EXPECT_EQ(opt_list.at(2), opt);
|
|
|
|
std::vector<CLI::Option *> nonconst_opt_list = app.get_options();
|
|
for(std::size_t i = 0; i < opt_list.size(); ++i) {
|
|
EXPECT_EQ(nonconst_opt_list.at(i), opt_list.at(i));
|
|
}
|
|
}
|
|
|
|
TEST(ValidatorTests, TestValidatorCreation) {
|
|
std::function<std::string(std::string &)> op1 = [](std::string &val) {
|
|
return (val.size() >= 5) ? std::string{} : val;
|
|
};
|
|
CLI::Validator V(op1, "", "size");
|
|
|
|
EXPECT_EQ(V.get_name(), "size");
|
|
V.name("harry");
|
|
EXPECT_EQ(V.get_name(), "harry");
|
|
EXPECT_TRUE(V.get_active());
|
|
|
|
EXPECT_EQ(V("test"), "test");
|
|
EXPECT_EQ(V("test5"), std::string{});
|
|
|
|
EXPECT_EQ(V.get_description(), std::string{});
|
|
V.description("this is a description");
|
|
EXPECT_EQ(V.get_description(), "this is a description");
|
|
}
|
|
|
|
TEST(ValidatorTests, TestValidatorOps) {
|
|
std::function<std::string(std::string &)> op1 = [](std::string &val) {
|
|
return (val.size() >= 5) ? std::string{} : val;
|
|
};
|
|
std::function<std::string(std::string &)> op2 = [](std::string &val) {
|
|
return (val.size() >= 9) ? std::string{} : val;
|
|
};
|
|
std::function<std::string(std::string &)> op3 = [](std::string &val) {
|
|
return (val.size() < 3) ? std::string{} : val;
|
|
};
|
|
std::function<std::string(std::string &)> op4 = [](std::string &val) {
|
|
return (val.size() <= 9) ? std::string{} : val;
|
|
};
|
|
CLI::Validator V1(op1, "SIZE >= 5");
|
|
|
|
CLI::Validator V2(op2, "SIZE >= 9");
|
|
CLI::Validator V3(op3, "SIZE < 3");
|
|
CLI::Validator V4(op4, "SIZE <= 9");
|
|
|
|
std::string two(2, 'a');
|
|
std::string four(4, 'a');
|
|
std::string five(5, 'a');
|
|
std::string eight(8, 'a');
|
|
std::string nine(9, 'a');
|
|
std::string ten(10, 'a');
|
|
EXPECT_TRUE(V1(five).empty());
|
|
EXPECT_FALSE(V1(four).empty());
|
|
|
|
EXPECT_TRUE(V2(nine).empty());
|
|
EXPECT_FALSE(V2(eight).empty());
|
|
|
|
EXPECT_TRUE(V3(two).empty());
|
|
EXPECT_FALSE(V3(four).empty());
|
|
|
|
EXPECT_TRUE(V4(eight).empty());
|
|
EXPECT_FALSE(V4(ten).empty());
|
|
|
|
auto V1a2 = V1 & V2;
|
|
EXPECT_EQ(V1a2.get_description(), "(SIZE >= 5) AND (SIZE >= 9)");
|
|
EXPECT_FALSE(V1a2(five).empty());
|
|
EXPECT_TRUE(V1a2(nine).empty());
|
|
|
|
auto V1a4 = V1 & V4;
|
|
EXPECT_EQ(V1a4.get_description(), "(SIZE >= 5) AND (SIZE <= 9)");
|
|
EXPECT_TRUE(V1a4(five).empty());
|
|
EXPECT_TRUE(V1a4(eight).empty());
|
|
EXPECT_FALSE(V1a4(ten).empty());
|
|
EXPECT_FALSE(V1a4(four).empty());
|
|
|
|
auto V1o3 = V1 | V3;
|
|
EXPECT_EQ(V1o3.get_description(), "(SIZE >= 5) OR (SIZE < 3)");
|
|
EXPECT_TRUE(V1o3(two).empty());
|
|
EXPECT_TRUE(V1o3(eight).empty());
|
|
EXPECT_TRUE(V1o3(ten).empty());
|
|
EXPECT_TRUE(V1o3(two).empty());
|
|
EXPECT_FALSE(V1o3(four).empty());
|
|
|
|
auto m1 = V1o3 & V4;
|
|
EXPECT_EQ(m1.get_description(), "((SIZE >= 5) OR (SIZE < 3)) AND (SIZE <= 9)");
|
|
EXPECT_TRUE(m1(two).empty());
|
|
EXPECT_TRUE(m1(eight).empty());
|
|
EXPECT_FALSE(m1(ten).empty());
|
|
EXPECT_TRUE(m1(two).empty());
|
|
EXPECT_TRUE(m1(five).empty());
|
|
EXPECT_FALSE(m1(four).empty());
|
|
|
|
auto m2 = m1 & V2;
|
|
EXPECT_EQ(m2.get_description(), "(((SIZE >= 5) OR (SIZE < 3)) AND (SIZE <= 9)) AND (SIZE >= 9)");
|
|
EXPECT_FALSE(m2(two).empty());
|
|
EXPECT_FALSE(m2(eight).empty());
|
|
EXPECT_FALSE(m2(ten).empty());
|
|
EXPECT_FALSE(m2(two).empty());
|
|
EXPECT_TRUE(m2(nine).empty());
|
|
EXPECT_FALSE(m2(four).empty());
|
|
|
|
auto m3 = m2 | V3;
|
|
EXPECT_EQ(m3.get_description(), "((((SIZE >= 5) OR (SIZE < 3)) AND (SIZE <= 9)) AND (SIZE >= 9)) OR (SIZE < 3)");
|
|
EXPECT_TRUE(m3(two).empty());
|
|
EXPECT_FALSE(m3(eight).empty());
|
|
EXPECT_TRUE(m3(nine).empty());
|
|
EXPECT_FALSE(m3(four).empty());
|
|
|
|
auto m4 = V3 | m2;
|
|
EXPECT_EQ(m4.get_description(), "(SIZE < 3) OR ((((SIZE >= 5) OR (SIZE < 3)) AND (SIZE <= 9)) AND (SIZE >= 9))");
|
|
EXPECT_TRUE(m4(two).empty());
|
|
EXPECT_FALSE(m4(eight).empty());
|
|
EXPECT_TRUE(m4(nine).empty());
|
|
EXPECT_FALSE(m4(four).empty());
|
|
}
|
|
|
|
TEST(ValidatorTests, TestValidatorNegation) {
|
|
|
|
std::function<std::string(std::string &)> op1 = [](std::string &val) {
|
|
return (val.size() >= 5) ? std::string{} : val;
|
|
};
|
|
|
|
CLI::Validator V1(op1, "SIZE >= 5", "size");
|
|
|
|
std::string four(4, 'a');
|
|
std::string five(5, 'a');
|
|
|
|
EXPECT_TRUE(V1(five).empty());
|
|
EXPECT_FALSE(V1(four).empty());
|
|
|
|
auto V2 = !V1;
|
|
EXPECT_FALSE(V2(five).empty());
|
|
EXPECT_TRUE(V2(four).empty());
|
|
EXPECT_EQ(V2.get_description(), "NOT SIZE >= 5");
|
|
|
|
V2.active(false);
|
|
EXPECT_TRUE(V2(five).empty());
|
|
EXPECT_TRUE(V2(four).empty());
|
|
EXPECT_TRUE(V2.get_description().empty());
|
|
}
|
|
|
|
TEST(ValidatorTests, ValidatorDefaults) {
|
|
|
|
CLI::Validator V1{};
|
|
|
|
std::string four(4, 'a');
|
|
std::string five(5, 'a');
|
|
|
|
// make sure this doesn't generate a seg fault or something
|
|
EXPECT_TRUE(V1(five).empty());
|
|
EXPECT_TRUE(V1(four).empty());
|
|
|
|
EXPECT_TRUE(V1.get_name().empty());
|
|
EXPECT_TRUE(V1.get_description().empty());
|
|
EXPECT_TRUE(V1.get_active());
|
|
EXPECT_TRUE(V1.get_modifying());
|
|
|
|
CLI::Validator V2{"check"};
|
|
// make sure this doesn't generate a seg fault or something
|
|
EXPECT_TRUE(V2(five).empty());
|
|
EXPECT_TRUE(V2(four).empty());
|
|
|
|
EXPECT_TRUE(V2.get_name().empty());
|
|
EXPECT_EQ(V2.get_description(), "check");
|
|
EXPECT_TRUE(V2.get_active());
|
|
EXPECT_TRUE(V2.get_modifying());
|
|
// This class only support streaming in, not out
|
|
}
|
|
|
|
class Unstreamable {
|
|
private:
|
|
int x_ = -1;
|
|
|
|
public:
|
|
Unstreamable() = default;
|
|
int get_x() const { return x_; }
|
|
void set_x(int x) { x_ = x; }
|
|
};
|
|
|
|
// this needs to be a different check then the one after the function definition otherwise they conflict
|
|
static_assert(!CLI::detail::is_istreamable<Unstreamable, std::istream>::value, "Unstreamable type is streamable");
|
|
|
|
std::istream &operator>>(std::istream &in, Unstreamable &value) {
|
|
int x;
|
|
in >> x;
|
|
value.set_x(x);
|
|
return in;
|
|
}
|
|
// these need to be different classes otherwise the definitions conflict
|
|
static_assert(CLI::detail::is_istreamable<Unstreamable>::value,
|
|
"Unstreamable type is still unstreamable and it should be");
|
|
|
|
TEST_F(TApp, MakeUnstreamableOptions) {
|
|
Unstreamable value;
|
|
app.add_option("--value", value);
|
|
|
|
// This used to fail to build, since it tries to stream from Unstreamable
|
|
app.add_option("--value2", value, "", false);
|
|
|
|
std::vector<Unstreamable> values;
|
|
app.add_option("--values", values);
|
|
|
|
// This used to fail to build, since it tries to stream from Unstreamable
|
|
app.add_option("--values2", values, "", false);
|
|
|
|
args = {"--value", "45"};
|
|
run();
|
|
EXPECT_EQ(value.get_x(), 45);
|
|
|
|
args = {"--values", "45", "27", "34"};
|
|
run();
|
|
EXPECT_EQ(values.size(), 3u);
|
|
EXPECT_EQ(values[2].get_x(), 34);
|
|
}
|