mirror of
https://github.com/CLIUtils/CLI11.git
synced 2025-04-29 20:23:55 +00:00
549 lines
12 KiB
C++
549 lines
12 KiB
C++
#ifdef CLI_SINGLE_FILE
|
|
#include "CLI11.hpp"
|
|
#else
|
|
#include "CLI/CLI.hpp"
|
|
#endif
|
|
|
|
#include "gtest/gtest.h"
|
|
#include <fstream>
|
|
|
|
typedef std::vector<std::string> input_t;
|
|
|
|
TEST(Basic, Empty) {
|
|
|
|
{
|
|
CLI::App app;
|
|
input_t simpleput;
|
|
app.parse(simpleput);
|
|
}
|
|
{
|
|
CLI::App app;
|
|
input_t spare = {"spare"};
|
|
EXPECT_THROW(app.parse(spare), CLI::PositionalError);
|
|
}
|
|
{
|
|
CLI::App app;
|
|
input_t simpleput;
|
|
app.parse(simpleput);
|
|
}
|
|
}
|
|
|
|
struct TApp : public ::testing::Test {
|
|
CLI::App app{"My Test Program"};
|
|
input_t args;
|
|
|
|
void run() {
|
|
input_t newargs = args;
|
|
std::reverse(std::begin(newargs), std::end(newargs));
|
|
app.parse(newargs);
|
|
}
|
|
|
|
};
|
|
|
|
TEST_F(TApp, OneFlagShort) {
|
|
app.add_flag("-c,--count");
|
|
args = {"-c"};
|
|
EXPECT_NO_THROW(run());
|
|
EXPECT_EQ(1, app.count("-c"));
|
|
EXPECT_EQ(1, app.count("--count"));
|
|
}
|
|
|
|
TEST_F(TApp, OneFlagLong) {
|
|
app.add_flag("-c,--count");
|
|
args = {"--count"};
|
|
EXPECT_NO_THROW(run());
|
|
EXPECT_EQ(1, app.count("-c"));
|
|
EXPECT_EQ(1, app.count("--count"));
|
|
}
|
|
|
|
TEST_F(TApp, DashedOptions) {
|
|
app.add_flag("-c");
|
|
app.add_flag("--q");
|
|
app.add_flag("--this,--that");
|
|
|
|
args = {"-c", "--q", "--this", "--that"};
|
|
EXPECT_NO_THROW(run());
|
|
EXPECT_EQ(1, app.count("-c"));
|
|
EXPECT_EQ(1, app.count("--q"));
|
|
EXPECT_EQ(2, app.count("--this"));
|
|
EXPECT_EQ(2, app.count("--that"));
|
|
|
|
}
|
|
|
|
|
|
TEST_F(TApp, OneFlagRef) {
|
|
int ref;
|
|
app.add_flag("-c,--count", ref);
|
|
args = {"--count"};
|
|
EXPECT_NO_THROW(run());
|
|
EXPECT_EQ(1, app.count("-c"));
|
|
EXPECT_EQ(1, app.count("--count"));
|
|
EXPECT_EQ(1, ref);
|
|
}
|
|
|
|
TEST_F(TApp, OneString) {
|
|
std::string str;
|
|
app.add_option("-s,--string", str);
|
|
args = {"--string", "mystring"};
|
|
EXPECT_NO_THROW(run());
|
|
EXPECT_EQ(1, app.count("-s"));
|
|
EXPECT_EQ(1, app.count("--string"));
|
|
EXPECT_EQ(str, "mystring");
|
|
}
|
|
|
|
|
|
TEST_F(TApp, TogetherInt) {
|
|
int i;
|
|
app.add_option("-i,--int", i);
|
|
args = {"-i4"};
|
|
EXPECT_NO_THROW(run());
|
|
EXPECT_EQ(1, app.count("--int"));
|
|
EXPECT_EQ(1, app.count("-i"));
|
|
EXPECT_EQ(i, 4);
|
|
}
|
|
|
|
TEST_F(TApp, SepInt) {
|
|
int i;
|
|
app.add_option("-i,--int", i);
|
|
args = {"-i","4"};
|
|
EXPECT_NO_THROW(run());
|
|
EXPECT_EQ(1, app.count("--int"));
|
|
EXPECT_EQ(1, app.count("-i"));
|
|
EXPECT_EQ(i, 4);
|
|
}
|
|
|
|
TEST_F(TApp, OneStringAgain) {
|
|
std::string str;
|
|
app.add_option("-s,--string", str);
|
|
args = {"--string", "mystring"};
|
|
EXPECT_NO_THROW(run());
|
|
EXPECT_EQ(1, app.count("-s"));
|
|
EXPECT_EQ(1, app.count("--string"));
|
|
EXPECT_EQ(str, "mystring");
|
|
}
|
|
|
|
|
|
TEST_F(TApp, DefaultStringAgain) {
|
|
std::string str = "previous";
|
|
app.add_option("-s,--string", str);
|
|
EXPECT_NO_THROW(run());
|
|
EXPECT_EQ(0, app.count("-s"));
|
|
EXPECT_EQ(0, app.count("--string"));
|
|
EXPECT_EQ(str, "previous");
|
|
}
|
|
|
|
TEST_F(TApp, LotsOfFlags) {
|
|
|
|
app.add_flag("-a");
|
|
app.add_flag("-A");
|
|
app.add_flag("-b");
|
|
|
|
args = {"-a","-b","-aA"};
|
|
EXPECT_NO_THROW(run());
|
|
EXPECT_EQ(2, app.count("-a"));
|
|
EXPECT_EQ(1, app.count("-b"));
|
|
EXPECT_EQ(1, app.count("-A"));
|
|
}
|
|
|
|
|
|
TEST_F(TApp, BoolAndIntFlags) {
|
|
|
|
bool bflag;
|
|
int iflag;
|
|
unsigned int uflag;
|
|
|
|
app.add_flag("-b", bflag);
|
|
app.add_flag("-i", iflag);
|
|
app.add_flag("-u", uflag);
|
|
|
|
args = {"-b", "-i", "-u"};
|
|
EXPECT_NO_THROW(run());
|
|
EXPECT_TRUE(bflag);
|
|
EXPECT_EQ(1, iflag);
|
|
EXPECT_EQ((unsigned int) 1, uflag);
|
|
|
|
app.reset();
|
|
|
|
args = {"-b", "-b"};
|
|
EXPECT_THROW(run(), CLI::ParseError);
|
|
|
|
app.reset();
|
|
bflag = false;
|
|
|
|
args = {"-iiiuu"};
|
|
EXPECT_NO_THROW(run());
|
|
EXPECT_FALSE(bflag);
|
|
EXPECT_EQ(3, iflag);
|
|
EXPECT_EQ((unsigned int) 2, uflag);
|
|
}
|
|
|
|
TEST_F(TApp, ShortOpts) {
|
|
|
|
unsigned long long funnyint;
|
|
std::string someopt;
|
|
app.add_flag("-z", funnyint);
|
|
app.add_option("-y", someopt);
|
|
|
|
args = {"-zzyzyz",};
|
|
|
|
EXPECT_NO_THROW(run());
|
|
|
|
EXPECT_EQ(2, app.count("-z"));
|
|
EXPECT_EQ(1, app.count("-y"));
|
|
EXPECT_EQ((unsigned long long) 2, funnyint);
|
|
EXPECT_EQ("zyz", someopt);
|
|
}
|
|
|
|
TEST_F(TApp, Flags) {
|
|
|
|
int i = 3;
|
|
std::string s = "HI";
|
|
|
|
app.add_option("-i,i", i, "", CLI::Default);
|
|
app.add_option("-s,s", s, "", CLI::Default);
|
|
|
|
args = {"-i2", "9"};
|
|
|
|
EXPECT_NO_THROW(run());
|
|
|
|
EXPECT_EQ(1, app.count("i"));
|
|
EXPECT_EQ(1, app.count("-s"));
|
|
EXPECT_EQ(2, i);
|
|
EXPECT_EQ("9", s);
|
|
}
|
|
|
|
TEST_F(TApp, Positionals) {
|
|
|
|
std::string posit1;
|
|
std::string posit2;
|
|
app.add_option("posit1", posit1);
|
|
app.add_option("posit2", posit2);
|
|
|
|
args = {"thing1","thing2"};
|
|
|
|
EXPECT_NO_THROW(run());
|
|
|
|
EXPECT_EQ(1, app.count("posit1"));
|
|
EXPECT_EQ(1, app.count("posit2"));
|
|
EXPECT_EQ("thing1", posit1);
|
|
EXPECT_EQ("thing2", posit2);
|
|
}
|
|
|
|
TEST_F(TApp, MixedPositionals) {
|
|
|
|
int positional_int;
|
|
std::string positional_string;
|
|
app.add_option("posit1,--posit1", positional_int, "");
|
|
app.add_option("posit2,--posit2", positional_string, "");
|
|
|
|
args = {"--posit2","thing2","7"};
|
|
|
|
EXPECT_NO_THROW(run());
|
|
|
|
EXPECT_EQ(1, app.count("posit2"));
|
|
EXPECT_EQ(1, app.count("--posit1"));
|
|
EXPECT_EQ(7, positional_int);
|
|
EXPECT_EQ("thing2", positional_string);
|
|
}
|
|
|
|
TEST_F(TApp, Reset) {
|
|
|
|
app.add_flag("--simple");
|
|
double doub;
|
|
app.add_option("-d,--double", doub);
|
|
|
|
args = {"--simple", "--double", "1.2"};
|
|
|
|
EXPECT_NO_THROW(run());
|
|
|
|
EXPECT_EQ(1, app.count("--simple"));
|
|
EXPECT_EQ(1, app.count("-d"));
|
|
EXPECT_FLOAT_EQ(1.2, doub);
|
|
|
|
app.reset();
|
|
|
|
EXPECT_EQ(0, app.count("--simple"));
|
|
EXPECT_EQ(0, app.count("-d"));
|
|
|
|
EXPECT_NO_THROW(run());
|
|
|
|
EXPECT_EQ(1, app.count("--simple"));
|
|
EXPECT_EQ(1, app.count("-d"));
|
|
EXPECT_FLOAT_EQ(1.2, doub);
|
|
|
|
}
|
|
|
|
|
|
TEST_F(TApp, FileNotExists) {
|
|
std::string myfile{"TestNonFileNotUsed.txt"};
|
|
EXPECT_TRUE(CLI::detail::_NonexistentPath(myfile));
|
|
|
|
std::string filename;
|
|
app.add_option("--file", filename, "", CLI::NonexistentPath);
|
|
args = {"--file", myfile};
|
|
|
|
EXPECT_NO_THROW(run());
|
|
EXPECT_EQ(myfile, filename);
|
|
|
|
app.reset();
|
|
|
|
|
|
bool ok = static_cast<bool>(std::ofstream(myfile.c_str()).put('a')); // create file
|
|
EXPECT_TRUE(ok);
|
|
EXPECT_THROW(run(), CLI::ParseError);
|
|
|
|
std::remove(myfile.c_str());
|
|
EXPECT_FALSE(CLI::detail::_ExistingFile(myfile));
|
|
}
|
|
|
|
TEST_F(TApp, FileExists) {
|
|
std::string myfile{"TestNonFileNotUsed.txt"};
|
|
EXPECT_FALSE(CLI::detail::_ExistingFile(myfile));
|
|
|
|
std::string filename = "Failed";
|
|
app.add_option("--file", filename, "", CLI::ExistingFile);
|
|
args = {"--file", myfile};
|
|
|
|
EXPECT_THROW(run(), CLI::ParseError);
|
|
EXPECT_EQ("Failed", filename);
|
|
|
|
app.reset();
|
|
|
|
bool ok = static_cast<bool>(std::ofstream(myfile.c_str()).put('a')); // create file
|
|
EXPECT_TRUE(ok);
|
|
EXPECT_NO_THROW(run());
|
|
EXPECT_EQ(myfile, filename);
|
|
|
|
std::remove(myfile.c_str());
|
|
EXPECT_FALSE(CLI::detail::_ExistingFile(myfile));
|
|
}
|
|
|
|
TEST_F(TApp, InSet) {
|
|
|
|
std::string choice;
|
|
app.add_set("-q,--quick", choice, {"one", "two", "three"});
|
|
|
|
args = {"--quick", "two"};
|
|
|
|
EXPECT_NO_THROW(run());
|
|
EXPECT_EQ("two", choice);
|
|
|
|
app.reset();
|
|
|
|
args = {"--quick", "four"};
|
|
EXPECT_THROW(run(), CLI::ParseError);
|
|
}
|
|
|
|
TEST_F(TApp, VectorFixedString) {
|
|
std::vector<std::string> strvec;
|
|
std::vector<std::string> answer{"mystring", "mystring2", "mystring3"};
|
|
|
|
CLI::Option* opt = app.add_option("-s,--string", strvec, "", CLI::Args(3));
|
|
EXPECT_EQ(3, opt->expected());
|
|
|
|
args = {"--string", "mystring", "mystring2", "mystring3"};
|
|
run();
|
|
EXPECT_EQ(3, app.count("--string"));
|
|
EXPECT_EQ(answer, strvec);
|
|
}
|
|
|
|
|
|
|
|
TEST_F(TApp, VectorUnlimString) {
|
|
std::vector<std::string> strvec;
|
|
std::vector<std::string> answer{"mystring", "mystring2", "mystring3"};
|
|
|
|
CLI::Option* opt = app.add_option("-s,--string", strvec);
|
|
EXPECT_EQ(-1, opt->expected());
|
|
|
|
args = {"--string", "mystring", "mystring2", "mystring3"};
|
|
EXPECT_NO_THROW(run());
|
|
EXPECT_EQ(3, app.count("--string"));
|
|
EXPECT_EQ(answer, strvec);
|
|
}
|
|
|
|
|
|
|
|
TEST_F(TApp, BasicSubcommands) {
|
|
auto sub1 = app.add_subcommand("sub1");
|
|
auto sub2 = app.add_subcommand("sub2");
|
|
|
|
EXPECT_NO_THROW(run());
|
|
EXPECT_EQ(nullptr, app.get_subcommand());
|
|
|
|
app.reset();
|
|
args = {"sub1"};
|
|
EXPECT_NO_THROW(run());
|
|
EXPECT_EQ(sub1, app.get_subcommand());
|
|
|
|
app.reset();
|
|
EXPECT_EQ(nullptr, app.get_subcommand());
|
|
|
|
args = {"sub2"};
|
|
EXPECT_NO_THROW(run());
|
|
EXPECT_EQ(sub2, app.get_subcommand());
|
|
}
|
|
|
|
|
|
TEST_F(TApp, Callbacks) {
|
|
auto sub1 = app.add_subcommand("sub1");
|
|
sub1->set_callback([](){
|
|
throw CLI::Success();
|
|
});
|
|
auto sub2 = app.add_subcommand("sub2");
|
|
bool val = false;
|
|
sub2->set_callback([&val](){
|
|
val = true;
|
|
});
|
|
|
|
app.reset();
|
|
args = {"sub2"};
|
|
EXPECT_FALSE(val);
|
|
EXPECT_NO_THROW(run());
|
|
EXPECT_TRUE(val);
|
|
|
|
}
|
|
|
|
// TODO: Add directory test
|
|
|
|
|
|
|
|
struct SubcommandProgram : public TApp {
|
|
|
|
CLI::App* start;
|
|
CLI::App* stop;
|
|
|
|
int dummy;
|
|
std::string file;
|
|
int count;
|
|
|
|
SubcommandProgram() {
|
|
start = app.add_subcommand("start", "Start prog");
|
|
stop = app.add_subcommand("stop", "Stop prog");
|
|
|
|
app.add_flag("-d", dummy, "My dummy var");
|
|
start->add_option("-f,--file", file, "File name");
|
|
stop->add_flag("-c,--count", count, "Some flag opt");
|
|
}
|
|
};
|
|
|
|
TEST_F(SubcommandProgram, Working) {
|
|
args = {"-d", "start", "-ffilename"};
|
|
|
|
EXPECT_NO_THROW(run());
|
|
|
|
EXPECT_EQ(1, dummy);
|
|
EXPECT_EQ(start, app.get_subcommand());
|
|
EXPECT_EQ("filename", file);
|
|
}
|
|
|
|
|
|
TEST_F(SubcommandProgram, Spare) {
|
|
args = {"extra", "-d", "start", "-ffilename"};
|
|
|
|
EXPECT_THROW(run(), CLI::PositionalError);
|
|
}
|
|
|
|
TEST_F(SubcommandProgram, SpareSub) {
|
|
args = {"-d", "start", "spare", "-ffilename"};
|
|
|
|
EXPECT_THROW(run(), CLI::PositionalError);
|
|
}
|
|
|
|
class TAppValue : public TApp {};
|
|
|
|
TEST_F(TAppValue, OneString) {
|
|
auto str = app.make_option("-s,--string");
|
|
std::string v;
|
|
args = {"--string", "mystring"};
|
|
EXPECT_FALSE((bool) str);
|
|
EXPECT_THROW(v = *str, CLI::EmptyError);
|
|
//EXPECT_THROW(v = str, CLI::EmptyError);
|
|
EXPECT_FALSE((bool) str);
|
|
EXPECT_NO_THROW(run());
|
|
EXPECT_TRUE((bool) str);
|
|
EXPECT_NO_THROW(v = *str);
|
|
EXPECT_NO_THROW(v = str);
|
|
|
|
EXPECT_EQ(1, app.count("-s"));
|
|
EXPECT_EQ(1, app.count("--string"));
|
|
EXPECT_EQ(*str, "mystring");
|
|
|
|
}
|
|
|
|
TEST_F(TAppValue, SeveralInts) {
|
|
auto value = app.make_option<int>("--first");
|
|
CLI::Value<int> value2 = app.make_option<int>("-s");
|
|
int v;
|
|
args = {"--first", "12", "-s", "19"};
|
|
EXPECT_FALSE((bool) value);
|
|
EXPECT_FALSE((bool) value2);
|
|
|
|
EXPECT_THROW(v = *value, CLI::EmptyError);
|
|
//EXPECT_THROW(v = str, CLI::EmptyError);
|
|
EXPECT_NO_THROW(run());
|
|
EXPECT_TRUE((bool) value);
|
|
EXPECT_NO_THROW(v = *value);
|
|
EXPECT_NO_THROW(v = value);
|
|
|
|
EXPECT_EQ(1, app.count("-s"));
|
|
EXPECT_EQ(1, app.count("--first"));
|
|
EXPECT_EQ(*value, 12);
|
|
EXPECT_EQ(*value2, 19);
|
|
|
|
}
|
|
|
|
TEST_F(TAppValue, Vector) {
|
|
auto value = app.make_option<std::vector<int>>("--first", "", CLI::Args);
|
|
auto value2 = app.make_option<std::vector<std::string>>("--second");
|
|
|
|
std::vector<int> i;
|
|
std::vector<std::string> s;
|
|
|
|
args = {"--first", "12", "3", "9", "--second", "thing", "try"};
|
|
|
|
EXPECT_FALSE((bool) value);
|
|
EXPECT_FALSE((bool) value2);
|
|
|
|
EXPECT_THROW(i = *value, CLI::EmptyError);
|
|
EXPECT_THROW(s = *value2, CLI::EmptyError);
|
|
|
|
EXPECT_NO_THROW(run());
|
|
|
|
EXPECT_TRUE((bool) value);
|
|
EXPECT_TRUE((bool) value2);
|
|
|
|
EXPECT_NO_THROW(i = *value);
|
|
//EXPECT_NO_THROW(i = value);
|
|
|
|
EXPECT_NO_THROW(s = *value2);
|
|
//EXPECT_NO_THROW(s = value2);
|
|
|
|
EXPECT_EQ(3, app.count("--first"));
|
|
EXPECT_EQ(2, app.count("--second"));
|
|
|
|
EXPECT_EQ(std::vector<int>({12,3,9}), *value);
|
|
EXPECT_EQ(std::vector<std::string>({"thing", "try"}), *value2);
|
|
|
|
}
|
|
|
|
TEST_F(TAppValue, DoubleVector) {
|
|
auto value = app.make_option<std::vector<double>>("--simple");
|
|
std::vector<double> d;
|
|
|
|
args = {"--simple", "1.2", "3.4", "-1"};
|
|
|
|
EXPECT_THROW(d = *value, CLI::EmptyError);
|
|
|
|
EXPECT_NO_THROW(run());
|
|
|
|
EXPECT_NO_THROW(d = *value);
|
|
|
|
EXPECT_EQ(3, app.count("--simple"));
|
|
EXPECT_EQ(std::vector<double>({1.2, 3.4, -1}), *value);
|
|
}
|
|
|
|
// TODO: Check help output, better formatting
|
|
// TODO: Add default/type info to help
|
|
// TODO: Add README
|