diff options
author | Devtools Arcadia <arcadia-devtools@yandex-team.ru> | 2022-02-07 18:08:42 +0300 |
---|---|---|
committer | Devtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net> | 2022-02-07 18:08:42 +0300 |
commit | 1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch) | |
tree | e26c9fed0de5d9873cce7e00bc214573dc2195b7 /library/cpp/getopt/ut | |
download | ydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz |
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'library/cpp/getopt/ut')
-rw-r--r-- | library/cpp/getopt/ut/last_getopt_ut.cpp | 794 | ||||
-rw-r--r-- | library/cpp/getopt/ut/modchooser_ut.cpp | 71 | ||||
-rw-r--r-- | library/cpp/getopt/ut/opt2_ut.cpp | 63 | ||||
-rw-r--r-- | library/cpp/getopt/ut/opt_ut.cpp | 52 | ||||
-rw-r--r-- | library/cpp/getopt/ut/posix_getopt_ut.cpp | 119 | ||||
-rw-r--r-- | library/cpp/getopt/ut/wrap.cpp | 96 | ||||
-rw-r--r-- | library/cpp/getopt/ut/ya.make | 15 | ||||
-rw-r--r-- | library/cpp/getopt/ut/ygetopt_ut.cpp | 45 |
8 files changed, 1255 insertions, 0 deletions
diff --git a/library/cpp/getopt/ut/last_getopt_ut.cpp b/library/cpp/getopt/ut/last_getopt_ut.cpp new file mode 100644 index 0000000000..c99a1d053d --- /dev/null +++ b/library/cpp/getopt/ut/last_getopt_ut.cpp @@ -0,0 +1,794 @@ +#include <library/cpp/getopt/last_getopt.h> + +#include <library/cpp/colorizer/colors.h> +#include <library/cpp/testing/unittest/registar.h> + +#include <util/generic/array_size.h> +#include <util/string/subst.h> +#include <util/string/vector.h> +#include <util/string/split.h> + +using namespace NLastGetopt; + +namespace { + struct TOptsNoDefault: public TOpts { + TOptsNoDefault(const TStringBuf& optstring = TStringBuf()) + : TOpts(optstring) + { + } + }; + + class TOptsParseResultTestWrapper: public TOptsParseResultException { + TVector<const char*> Argv_; + + public: + TOptsParseResultTestWrapper(const TOpts* opts, TVector<const char*> argv) + : Argv_(argv) + { + Init(opts, (int)Argv_.size(), Argv_.data()); + } + }; + + using V = TVector<const char*>; +} + +struct TOptsParserTester { + TOptsNoDefault Opts_; + TVector<const char*> Argv_; + + THolder<TOptsParser> Parser_; + + void Initialize() { + if (!Parser_) + Parser_.Reset(new TOptsParser(&Opts_, (int)Argv_.size(), Argv_.data())); + } + + void Accept() { + Initialize(); + UNIT_ASSERT(Parser_->Next()); + } + + void AcceptOption() { + Accept(); + UNIT_ASSERT(!!Parser_->CurOpt()); + } + + void AcceptOption(char c) { + AcceptOption(); + UNIT_ASSERT(Parser_->CurOpt()->CharIs(c)); + } + + void AcceptOption(const TString& optName) { + AcceptOption(); + UNIT_ASSERT(Parser_->CurOpt()->NameIs(optName)); + } + + template <typename TOpt> + void AcceptOptionWithValue(TOpt optName, const TString& value) { + AcceptOption(optName); + UNIT_ASSERT_VALUES_EQUAL_C(value, Parser_->CurValStr(), "; option " << optName); + } + + template <typename TOpt> + void AcceptOptionWithoutValue(TOpt optName) { + AcceptOption(optName); + UNIT_ASSERT_C(!Parser_->CurVal(), ": opt " << optName << " must have no param"); + } + + void AcceptFreeArgInOrder(const TString& expected) { + Accept(); + UNIT_ASSERT(!Parser_->CurOpt()); + UNIT_ASSERT_VALUES_EQUAL(expected, Parser_->CurValStr()); + } + + size_t Pos_; + + void AcceptEndOfOptions() { + Initialize(); + UNIT_ASSERT(!Parser_->Next()); + Pos_ = Parser_->Pos_; + + // pos must not be changed after last meaningful invocation of Next() + UNIT_ASSERT(!Parser_->Next()); + UNIT_ASSERT_VALUES_EQUAL(Pos_, Parser_->Pos_); + UNIT_ASSERT(!Parser_->Next()); + UNIT_ASSERT_VALUES_EQUAL(Pos_, Parser_->Pos_); + } + + void AcceptError() { + Initialize(); + try { + Parser_->Next(); + UNIT_FAIL("expecting exception"); + } catch (const TUsageException&) { + // expecting + } + } + + void AcceptUnexpectedOption() { + Initialize(); + size_t pos = Parser_->Pos_; + size_t sop = Parser_->Sop_; + AcceptError(); + UNIT_ASSERT_VALUES_EQUAL(pos, Parser_->Pos_); + UNIT_ASSERT_VALUES_EQUAL(sop, Parser_->Sop_); + } + + void AcceptFreeArg(const TString& expected) { + UNIT_ASSERT(Pos_ < Parser_->Argc_); + UNIT_ASSERT_VALUES_EQUAL(expected, Parser_->Argv_[Pos_]); + ++Pos_; + } + + void AcceptEndOfFreeArgs() { + UNIT_ASSERT_VALUES_EQUAL(Argv_.size(), Pos_); + } +}; + +namespace { + bool gSimpleFlag = false; + void SimpleHander(void) { + gSimpleFlag = true; + } +} + +Y_UNIT_TEST_SUITE(TLastGetoptTests) { + Y_UNIT_TEST(TestEqual) { + TOptsNoDefault opts; + opts.AddLongOption("from"); + opts.AddLongOption("to"); + TOptsParseResultTestWrapper r(&opts, V({"copy", "--from=/", "--to=/etc"})); + + UNIT_ASSERT_VALUES_EQUAL("copy", r.GetProgramName()); + UNIT_ASSERT_VALUES_EQUAL("/", r.Get("from")); + UNIT_ASSERT_VALUES_EQUAL("/etc", r.Get("to")); + UNIT_ASSERT_VALUES_EQUAL("/etc", r.GetOrElse("to", "trash")); + UNIT_ASSERT(r.Has("from")); + UNIT_ASSERT(r.Has("to")); + + UNIT_ASSERT_EXCEPTION(r.Get("left"), TException); + } + + Y_UNIT_TEST(TestCharOptions) { + TOptsNoDefault opts; + opts.AddCharOption('R', NO_ARGUMENT); + opts.AddCharOption('l', NO_ARGUMENT); + opts.AddCharOption('h', NO_ARGUMENT); + TOptsParseResultTestWrapper r(&opts, V({"cp", "/etc", "-Rl", "/tmp/etc"})); + UNIT_ASSERT(r.Has('R')); + UNIT_ASSERT(r.Has('l')); + UNIT_ASSERT(!r.Has('h')); + + UNIT_ASSERT_VALUES_EQUAL(2u, r.GetFreeArgs().size()); + UNIT_ASSERT_VALUES_EQUAL(2u, r.GetFreeArgCount()); + UNIT_ASSERT_VALUES_EQUAL("/etc", r.GetFreeArgs()[0]); + UNIT_ASSERT_VALUES_EQUAL("/tmp/etc", r.GetFreeArgs()[1]); + } + + Y_UNIT_TEST(TestFreeArgs) { + TOptsNoDefault opts; + opts.SetFreeArgsNum(1, 3); + TOptsParseResultTestWrapper r11(&opts, V({"cp", "/etc"})); + TOptsParseResultTestWrapper r12(&opts, V({"cp", "/etc", "/tmp/etc"})); + TOptsParseResultTestWrapper r13(&opts, V({"cp", "/etc", "/tmp/etc", "verbose"})); + + UNIT_ASSERT_EXCEPTION( + TOptsParseResultTestWrapper(&opts, V({"cp", "/etc", "/tmp/etc", "verbose", "nosymlink"})), + yexception); + + UNIT_ASSERT_EXCEPTION( + TOptsParseResultTestWrapper(&opts, V({"cp"})), + yexception); + + opts.SetFreeArgsNum(2); + TOptsParseResultTestWrapper r22(&opts, V({"cp", "/etc", "/var/tmp"})); + } + + Y_UNIT_TEST(TestCharOptionsRequiredOptional) { + TOptsNoDefault opts; + opts.AddCharOption('d', REQUIRED_ARGUMENT); + opts.AddCharOption('e', REQUIRED_ARGUMENT); + opts.AddCharOption('x', REQUIRED_ARGUMENT); + opts.AddCharOption('y', REQUIRED_ARGUMENT); + opts.AddCharOption('l', NO_ARGUMENT); + TOptsParseResultTestWrapper r(&opts, V({"cmd", "-ld11", "-e", "22", "-lllx33", "-y", "44"})); + UNIT_ASSERT_VALUES_EQUAL("11", r.Get('d')); + UNIT_ASSERT_VALUES_EQUAL("22", r.Get('e')); + UNIT_ASSERT_VALUES_EQUAL("33", r.Get('x')); + UNIT_ASSERT_VALUES_EQUAL("44", r.Get('y')); + } + + Y_UNIT_TEST(TestReturnInOrder) { + TOptsParserTester tester; + tester.Opts_.AddLongOption('v', "value"); + tester.Opts_.ArgPermutation_ = RETURN_IN_ORDER; + + tester.Argv_.push_back("cmd"); + tester.Argv_.push_back("--value=11"); + tester.Argv_.push_back("xx"); + tester.Argv_.push_back("-v12"); + tester.Argv_.push_back("yy"); + tester.Argv_.push_back("--"); + tester.Argv_.push_back("-v13"); + tester.Argv_.push_back("--"); + + tester.AcceptOptionWithValue("value", "11"); + tester.AcceptFreeArgInOrder("xx"); + tester.AcceptOptionWithValue('v', "12"); + tester.AcceptFreeArgInOrder("yy"); + tester.AcceptFreeArgInOrder("-v13"); + tester.AcceptFreeArgInOrder("--"); + tester.AcceptEndOfOptions(); + tester.AcceptEndOfFreeArgs(); + } + + Y_UNIT_TEST(TestRequireOrder) { + TOptsParserTester tester; + tester.Opts_.ArgPermutation_ = REQUIRE_ORDER; + tester.Opts_.AddLongOption('v', "value"); + + tester.Argv_.push_back("cmd"); + tester.Argv_.push_back("--value=11"); + tester.Argv_.push_back("xx"); + tester.Argv_.push_back("-v12"); + tester.Argv_.push_back("yy"); + + tester.AcceptOptionWithValue("value", "11"); + tester.AcceptEndOfOptions(); + + tester.AcceptFreeArg("xx"); + tester.AcceptFreeArg("-v12"); + tester.AcceptFreeArg("yy"); + tester.AcceptEndOfFreeArgs(); + } + + Y_UNIT_TEST(TestPlusForLongOption) { + TOptsParserTester tester; + tester.Opts_.AddLongOption('v', "value"); + tester.Opts_.AllowPlusForLong_ = true; + tester.Argv_.push_back("cmd"); + tester.Argv_.push_back("+value=11"); + tester.Argv_.push_back("xx"); + tester.Argv_.push_back("-v12"); + tester.Argv_.push_back("yy"); + + tester.AcceptOptionWithValue("value", "11"); + tester.AcceptOptionWithValue("value", "12"); + tester.AcceptEndOfOptions(); + + tester.AcceptFreeArg("xx"); + tester.AcceptFreeArg("yy"); + tester.AcceptEndOfFreeArgs(); + } + + Y_UNIT_TEST(TestBug1) { + TOptsParserTester tester; + tester.Opts_.AddCharOptions("A:b:cd:"); + + tester.Argv_.push_back("cmd"); + tester.Argv_.push_back("-A"); + tester.Argv_.push_back("aaaa"); + tester.Argv_.push_back("zz"); + tester.Argv_.push_back("-c"); + tester.Argv_.push_back("-d8"); + tester.Argv_.push_back("ww"); + + tester.AcceptOptionWithValue('A', "aaaa"); + tester.AcceptOptionWithoutValue('c'); + tester.AcceptOptionWithValue('d', "8"); + tester.AcceptEndOfOptions(); + + tester.AcceptFreeArg("zz"); + tester.AcceptFreeArg("ww"); + tester.AcceptEndOfFreeArgs(); + } + + Y_UNIT_TEST(TestPermuteComplex) { + TOptsParserTester tester; + + tester.Opts_.AddCharOption('x').NoArgument(); + tester.Opts_.AddCharOption('y').RequiredArgument(); + tester.Opts_.AddCharOption('z').NoArgument(); + tester.Opts_.AddCharOption('w').RequiredArgument(); + tester.Opts_.ArgPermutation_ = PERMUTE; + + tester.Argv_.push_back("cmd"); + tester.Argv_.push_back("-x"); + tester.Argv_.push_back("-y"); + tester.Argv_.push_back("val"); + tester.Argv_.push_back("freearg1"); + tester.Argv_.push_back("-zw"); + tester.Argv_.push_back("val2"); + tester.Argv_.push_back("freearg2"); + + tester.AcceptOptionWithoutValue('x'); + tester.AcceptOptionWithValue('y', "val"); + tester.AcceptOptionWithoutValue('z'); + tester.AcceptOptionWithValue('w', "val2"); + tester.AcceptEndOfOptions(); + tester.AcceptFreeArg("freearg1"); + tester.AcceptFreeArg("freearg2"); + tester.AcceptEndOfFreeArgs(); + } + + Y_UNIT_TEST(TestFinalDashDash) { + TOptsParserTester tester; + tester.Opts_.AddLongOption("size"); + + tester.Argv_.push_back("cmd"); + tester.Argv_.push_back("--"); + + tester.AcceptEndOfOptions(); + tester.AcceptEndOfFreeArgs(); + } + + Y_UNIT_TEST(TestDashDashAfterDashDash) { + TOptsParserTester tester; + tester.Opts_.AddLongOption("size"); + + tester.Argv_.push_back("cmd"); + tester.Argv_.push_back("--"); + tester.Argv_.push_back("--"); + tester.Argv_.push_back("--"); + + tester.AcceptEndOfOptions(); + tester.AcceptFreeArg("--"); + tester.AcceptFreeArg("--"); + tester.AcceptEndOfFreeArgs(); + } + + Y_UNIT_TEST(TestUnexpectedUnknownOption) { + TOptsParserTester tester; + + tester.Argv_.push_back("cmd"); + tester.Argv_.push_back("-x"); + + tester.AcceptUnexpectedOption(); + } + + Y_UNIT_TEST(TestDuplicatedOptionCrash) { + // this test is broken, cause UNIT_ASSERT(false) always throws + return; + + bool exception = false; + try { + TOpts opts; + opts.AddLongOption('x', "one"); + opts.AddLongOption('x', "two"); + UNIT_ASSERT(false); + } catch (...) { + // we should go here, duplicating options are forbidden + exception = true; + } + UNIT_ASSERT(exception); + } + + Y_UNIT_TEST(TestPositionWhenNoArgs) { + TOptsParserTester tester; + + tester.Argv_.push_back("cmd"); + + tester.Opts_.AddCharOption('c'); + + tester.AcceptEndOfOptions(); + + UNIT_ASSERT_VALUES_EQUAL(1u, tester.Parser_->Pos_); + } + + Y_UNIT_TEST(TestExpectedUnknownCharOption) { + TOptsParserTester tester; + + tester.Argv_.push_back("cmd"); + tester.Argv_.push_back("-x"); + tester.Argv_.push_back("-y"); + tester.Argv_.push_back("val"); + tester.Argv_.push_back("freearg1"); + tester.Argv_.push_back("-zw"); + tester.Argv_.push_back("val2"); + tester.Argv_.push_back("freearg2"); + + tester.Opts_.AllowUnknownCharOptions_ = true; + + tester.AcceptOptionWithoutValue('x'); + tester.AcceptOptionWithValue('y', "val"); + tester.AcceptOptionWithoutValue('z'); + tester.AcceptOptionWithValue('w', "val2"); + tester.AcceptEndOfOptions(); + tester.AcceptFreeArg("freearg1"); + tester.AcceptFreeArg("freearg2"); + tester.AcceptEndOfFreeArgs(); + } + +#if 0 + Y_UNIT_TEST(TestRequiredParams) { + TOptsParserTester tester; + + tester.Argv_.push_back("cmd"); + tester.Argv_.push_back("--port=1231"); + tester.Argv_.push_back("asas"); + + tester.Opts_.AddLongOption("port"); + tester.Opts_.AddLongOption("home").Required(); + + tester.AcceptOptionWithValue("port", "1231"); + tester.AcceptError(); + } +#endif + + Y_UNIT_TEST(TestStoreResult) { + TOptsNoDefault opts; + TString data; + int number; + TMaybe<TString> optionalString0, optionalString1; + TMaybe<int> optionalNumber0, optionalNumber1; + opts.AddLongOption('d', "data").StoreResult(&data); + opts.AddLongOption('n', "number").StoreResult(&number); + opts.AddLongOption("optional-string-0").StoreResult(&optionalString0); + opts.AddLongOption("optional-number-0").StoreResult(&optionalNumber0); + opts.AddLongOption("optional-string-1").StoreResult(&optionalString1); + opts.AddLongOption("optional-number-1").StoreResult(&optionalNumber1); + TOptsParseResultTestWrapper r(&opts, V({"cmd", "--data=jjhh", "-n", "11", "--optional-number-1=8", "--optional-string-1=os1"})); + UNIT_ASSERT_VALUES_EQUAL("jjhh", data); + UNIT_ASSERT_VALUES_EQUAL(11, number); + UNIT_ASSERT(!optionalString0.Defined()); + UNIT_ASSERT(!optionalNumber0.Defined()); + UNIT_ASSERT_VALUES_EQUAL(*optionalString1, "os1"); + UNIT_ASSERT_VALUES_EQUAL(*optionalNumber1, 8); + } + + Y_UNIT_TEST(TestStoreValue) { + int a = 0, b = 0; + size_t c = 0; + EHasArg e = NO_ARGUMENT; + + TOptsNoDefault opts; + opts.AddLongOption('a', "alpha").NoArgument().StoreValue(&a, 42); + opts.AddLongOption('b', "beta").NoArgument().StoreValue(&b, 24); + opts.AddLongOption('e', "enum").NoArgument().StoreValue(&e, REQUIRED_ARGUMENT).StoreValue(&c, 12345); + + TOptsParseResultTestWrapper r(&opts, V({"cmd", "-a", "-e"})); + + UNIT_ASSERT_VALUES_EQUAL(42, a); + UNIT_ASSERT_VALUES_EQUAL(0, b); + UNIT_ASSERT(e == REQUIRED_ARGUMENT); + UNIT_ASSERT_VALUES_EQUAL(12345u, c); + } + + Y_UNIT_TEST(TestSetFlag) { + bool a = false, b = true, c = false, d = true; + + TOptsNoDefault opts; + opts.AddLongOption('a', "alpha").NoArgument().SetFlag(&a); + opts.AddLongOption('b', "beta").NoArgument().SetFlag(&b); + opts.AddCharOption('c').StoreTrue(&c); + opts.AddCharOption('d').StoreTrue(&d); + + TOptsParseResultTestWrapper r(&opts, V({"cmd", "-a", "-c"})); + + UNIT_ASSERT(a); + UNIT_ASSERT(!b); + UNIT_ASSERT(c); + UNIT_ASSERT(!d); + } + + Y_UNIT_TEST(TestDefaultValue) { + TOptsNoDefault opts; + opts.AddLongOption("path").DefaultValue("/etc"); + int value = 42; + opts.AddLongOption("value").StoreResult(&value).DefaultValue(32); + TOptsParseResultTestWrapper r(&opts, V({"cmd", "dfdf"})); + UNIT_ASSERT_VALUES_EQUAL("/etc", r.Get("path")); + UNIT_ASSERT_VALUES_EQUAL(32, value); + } + + Y_UNIT_TEST(TestSplitValue) { + TOptsNoDefault opts; + TVector<TString> vals; + opts.AddLongOption('s', "split").SplitHandler(&vals, ','); + TOptsParseResultTestWrapper r(&opts, V({"prog", "--split=a,b,c"})); + UNIT_ASSERT_EQUAL(vals.size(), 3); + UNIT_ASSERT_EQUAL(vals[0], "a"); + UNIT_ASSERT_EQUAL(vals[1], "b"); + UNIT_ASSERT_EQUAL(vals[2], "c"); + } + + Y_UNIT_TEST(TestRangeSplitValue) { + TOptsNoDefault opts; + TVector<ui32> vals; + opts.AddLongOption('s', "split").RangeSplitHandler(&vals, ',', '-'); + TOptsParseResultTestWrapper r(&opts, V({"prog", "--split=1,8-10", "--split=12-14"})); + UNIT_ASSERT_EQUAL(vals.size(), 7); + UNIT_ASSERT_EQUAL(vals[0], 1); + UNIT_ASSERT_EQUAL(vals[1], 8); + UNIT_ASSERT_EQUAL(vals[2], 9); + UNIT_ASSERT_EQUAL(vals[3], 10); + UNIT_ASSERT_EQUAL(vals[4], 12); + UNIT_ASSERT_EQUAL(vals[5], 13); + UNIT_ASSERT_EQUAL(vals[6], 14); + } + + Y_UNIT_TEST(TestParseArgs) { + TOptsNoDefault o("AbCx:y:z::"); + UNIT_ASSERT_EQUAL(o.GetCharOption('A').HasArg_, NO_ARGUMENT); + UNIT_ASSERT_EQUAL(o.GetCharOption('b').HasArg_, NO_ARGUMENT); + UNIT_ASSERT_EQUAL(o.GetCharOption('C').HasArg_, NO_ARGUMENT); + UNIT_ASSERT_EQUAL(o.GetCharOption('x').HasArg_, REQUIRED_ARGUMENT); + UNIT_ASSERT_EQUAL(o.GetCharOption('y').HasArg_, REQUIRED_ARGUMENT); + UNIT_ASSERT_EQUAL(o.GetCharOption('z').HasArg_, OPTIONAL_ARGUMENT); + } + + Y_UNIT_TEST(TestRequiredOpts) { + TOptsNoDefault opts; + TOpt& opt_d = opts.AddCharOption('d'); + + // test 'not required' + // makes sure that the problem will only be in 'required' + TOptsParseResultTestWrapper r1(&opts, V({"cmd"})); + + // test 'required' + opt_d.Required(); + UNIT_ASSERT_EXCEPTION( + TOptsParseResultTestWrapper(&opts, V({"cmd"})), + TUsageException); + + TOptsParseResultTestWrapper r3(&opts, V({"cmd", "-d11"})); + UNIT_ASSERT_VALUES_EQUAL("11", r3.Get('d')); + } + + class HandlerStoreTrue { + bool* Flag; + + public: + HandlerStoreTrue(bool* flag) + : Flag(flag) + { + } + void operator()() { + *Flag = true; + } + }; + Y_UNIT_TEST(TestHandlers) { + { + TOptsNoDefault opts; + bool flag = false; + opts.AddLongOption("flag").Handler0(HandlerStoreTrue(&flag)).NoArgument(); + TOptsParseResultTestWrapper r(&opts, V({"cmd", "--flag"})); + UNIT_ASSERT(flag); + } + { + TOptsNoDefault opts; + unsigned uval = 5; + double fval = 0.0; + opts.AddLongOption("flag1").RequiredArgument().StoreResult(&uval); + opts.AddLongOption("flag2").RequiredArgument().StoreResultT<int>(&uval); + opts.AddLongOption("flag3").RequiredArgument().StoreMappedResult(&fval, (double (*)(double))fabs); + opts.AddLongOption("flag4").RequiredArgument().StoreMappedResult(&fval, (double (*)(double))sqrt); + UNIT_ASSERT_EXCEPTION( + TOptsParseResultTestWrapper(&opts, V({"cmd", "--flag3", "-2.0", "--flag1", "-1"})), + yexception); + UNIT_ASSERT_VALUES_EQUAL(uval, 5u); + UNIT_ASSERT_VALUES_EQUAL(fval, 2.0); + TOptsParseResultTestWrapper r1(&opts, V({"cmd", "--flag4", "9.0", "--flag2", "-1"})); + UNIT_ASSERT_VALUES_EQUAL(uval, Max<unsigned>()); + UNIT_ASSERT_VALUES_EQUAL(fval, 3.0); + } + } + + Y_UNIT_TEST(TestTitleAndPrintUsage) { + TOpts opts; + const char* prog = "my_program"; + TString title = TString("Sample ") + TString(prog).Quote() + " application"; + opts.SetTitle(title); + int argc = 2; + const char* cmd[] = {prog}; + TOptsParser parser(&opts, argc, cmd); + TStringStream out; + parser.PrintUsage(out); + // find title + UNIT_ASSERT(out.Str().find(title) != TString::npos); + // find usage + UNIT_ASSERT(out.Str().find(" " + TString(prog) + " ") != TString::npos); + } + + Y_UNIT_TEST(TestCustomCmdLineDescr) { + TOpts opts; + const char* prog = "my_program"; + TString customDescr = "<FILE|TABLE> USER [OPTIONS]"; + int argc = 2; + const char* cmd[] = {prog}; + opts.SetCmdLineDescr(customDescr); + TOptsParser parser(&opts, argc, cmd); + TStringStream out; + parser.PrintUsage(out); + // find custom usage + UNIT_ASSERT(out.Str().find(customDescr) != TString::npos); + } + + Y_UNIT_TEST(TestColorPrint) { + TOpts opts; + const char* prog = "my_program"; + opts.AddLongOption("long_option").Required(); + opts.AddLongOption('o', "other"); + opts.AddCharOption('d').DefaultValue("42"); + opts.AddCharOption('s').DefaultValue("str_default"); + opts.SetFreeArgsNum(123, 456); + opts.SetFreeArgTitle(0, "first_free_arg", "help"); + opts.SetFreeArgTitle(2, "second_free_arg"); + opts.AddSection("Section", "Section\n text"); + const char* cmd[] = {prog}; + TOptsParser parser(&opts, Y_ARRAY_SIZE(cmd), cmd); + TStringStream out; + NColorizer::TColors colors(true); + parser.PrintUsage(out, colors); + + // find options and green color + UNIT_ASSERT(out.Str().find(TStringBuilder() << colors.GreenColor() << "--long_option" << colors.OldColor()) != TString::npos); + UNIT_ASSERT(out.Str().find(TStringBuilder() << colors.GreenColor() << "--other" << colors.OldColor()) != TString::npos); + UNIT_ASSERT(out.Str().find(TStringBuilder() << colors.GreenColor() << "-o" << colors.OldColor()) != TString::npos); + UNIT_ASSERT(out.Str().find(TStringBuilder() << colors.GreenColor() << "-d" << colors.OldColor()) != TString::npos); + UNIT_ASSERT(out.Str().find(TStringBuilder() << colors.GreenColor() << "-s" << colors.OldColor()) != TString::npos); + + // find default values + UNIT_ASSERT(out.Str().find(TStringBuilder() << colors.CyanColor() << "42" << colors.OldColor()) != TString::npos); + UNIT_ASSERT(out.Str().find(TStringBuilder() << colors.CyanColor() << "\"str_default\"" << colors.OldColor()) != TString::npos); + + // find free args + UNIT_ASSERT(out.Str().find(TStringBuilder() << colors.GreenColor() << "123" << colors.OldColor()) != TString::npos); + UNIT_ASSERT(out.Str().find(TStringBuilder() << colors.GreenColor() << "456" << colors.OldColor()) != TString::npos); + UNIT_ASSERT(out.Str().find(TStringBuilder() << colors.GreenColor() << "first_free_arg" << colors.OldColor()) != TString::npos); + // free args without help not rendered even if they have custom title + UNIT_ASSERT(out.Str().find(TStringBuilder() << colors.GreenColor() << "second_free_arg" << colors.OldColor()) == TString::npos); + + // find signatures + UNIT_ASSERT(out.Str().find(TStringBuilder() << colors.BoldColor() << "Usage" << colors.OldColor()) != TString::npos); + UNIT_ASSERT(out.Str().find(TStringBuilder() << colors.BoldColor() << "Required parameters" << colors.OldColor()) != TString::npos); + UNIT_ASSERT(out.Str().find(TStringBuilder() << colors.BoldColor() << "Optional parameters" << colors.OldColor()) != TString::npos); + UNIT_ASSERT(out.Str().find(TStringBuilder() << colors.BoldColor() << "Free args" << colors.OldColor()) != TString::npos); + + // find sections + UNIT_ASSERT(out.Str().find(TStringBuilder() << colors.BoldColor() << "Section" << colors.OldColor() << ":") != TString::npos); + UNIT_ASSERT(out.Str().find(TStringBuilder() << " Section\n text") != TString::npos); + + // print without colors + TStringStream out2; + opts.PrintUsage(prog, out2); + UNIT_ASSERT(out2.Str().find(colors.GreenColor()) == TString::npos); + UNIT_ASSERT(out2.Str().find(colors.CyanColor()) == TString::npos); + UNIT_ASSERT(out2.Str().find(colors.BoldColor()) == TString::npos); + UNIT_ASSERT(out2.Str().find(colors.OldColor()) == TString::npos); + } + + Y_UNIT_TEST(TestPadding) { + const bool withColorsOpt[] = {false, true}; + for (bool withColors : withColorsOpt) { + TOpts opts; + const char* prog = "my_program"; + opts.AddLongOption("option", "description 1").Required(); // long option + opts.AddLongOption('o', "other", "description 2"); // char and long option + opts.AddCharOption('d', "description 3").RequiredArgument("DD"); // char option + opts.AddCharOption('s', "description 4\ndescription 5\ndescription 6"); // multiline desc + opts.AddLongOption('l', "very_very_very_loooong_ooooption", "description 7").RequiredArgument("LONG_ARGUMENT"); + const char* cmd[] = {prog}; + TOptsParser parser(&opts, Y_ARRAY_SIZE(cmd), cmd); + + TStringStream out; + NColorizer::TColors colors(withColors); + parser.PrintUsage(out, colors); + + TString printed = out.Str(); + if (withColors) { + // remove not printable characters + SubstGlobal(printed, TString(colors.BoldColor()), ""); + SubstGlobal(printed, TString(colors.GreenColor()), ""); + SubstGlobal(printed, TString(colors.CyanColor()), ""); + SubstGlobal(printed, TString(colors.OldColor()), ""); + } + TVector<TString> lines; + StringSplitter(printed).Split('\n').SkipEmpty().Collect(&lines); + UNIT_ASSERT(!lines.empty()); + TVector<size_t> indents; + for (const TString& line : lines) { + const size_t indent = line.find("description "); + if (indent != TString::npos) + indents.push_back(indent); + } + UNIT_ASSERT_VALUES_EQUAL(indents.size(), 7); + const size_t theOnlyIndent = indents[0]; + for (size_t indent : indents) { + UNIT_ASSERT_VALUES_EQUAL_C(indent, theOnlyIndent, printed); + } + } + } + + Y_UNIT_TEST(TestAppendTo) { + TVector<int> ints; + + TOptsNoDefault opts; + opts.AddLongOption("size").AppendTo(&ints); + + TOptsParseResultTestWrapper r(&opts, V({"cmd", "--size=17", "--size=19"})); + + UNIT_ASSERT_VALUES_EQUAL(size_t(2), ints.size()); + UNIT_ASSERT_VALUES_EQUAL(17, ints.at(0)); + UNIT_ASSERT_VALUES_EQUAL(19, ints.at(1)); + } + + Y_UNIT_TEST(TestEmplaceTo) { + TVector<std::tuple<TString>> richPaths; + + TOptsNoDefault opts; + opts.AddLongOption("path").EmplaceTo(&richPaths); + + TOptsParseResultTestWrapper r(&opts, V({"cmd", "--path=<a=b>//cool", "--path=//nice"})); + + UNIT_ASSERT_VALUES_EQUAL(size_t(2), richPaths.size()); + UNIT_ASSERT_VALUES_EQUAL("<a=b>//cool", std::get<0>(richPaths.at(0))); + UNIT_ASSERT_VALUES_EQUAL("//nice", std::get<0>(richPaths.at(1))); + } + + Y_UNIT_TEST(TestKVHandler) { + TStringBuilder keyvals; + + TOptsNoDefault opts; + opts.AddLongOption("set").KVHandler([&keyvals](TString k, TString v) { keyvals << k << ":" << v << ","; }); + + TOptsParseResultTestWrapper r(&opts, V({"cmd", "--set", "x=1", "--set", "y=2", "--set=z=3"})); + + UNIT_ASSERT_VALUES_EQUAL(keyvals, "x:1,y:2,z:3,"); + } + + Y_UNIT_TEST(TestEasySetup) { + TEasySetup opts; + bool flag = false; + opts('v', "version", "print version information")('a', "abstract", "some abstract param", true)('b', "buffer", "SIZE", "some param with argument")('c', "count", "SIZE", "some param with required argument")('t', "true", HandlerStoreTrue(&flag), "Some arg with handler")("global", SimpleHander, "Another arg with handler"); + + { + gSimpleFlag = false; + TOptsParseResultTestWrapper r(&opts, V({"cmd", "--abstract"})); + UNIT_ASSERT(!flag); + UNIT_ASSERT(!gSimpleFlag); + } + + { + TOptsParseResultTestWrapper r(&opts, V({"cmd", "--abstract", "--global", "-t"})); + UNIT_ASSERT(flag); + UNIT_ASSERT(gSimpleFlag); + } + + { + UNIT_ASSERT_EXCEPTION( + TOptsParseResultTestWrapper(&opts, V({"cmd", "--true"})), + TUsageException); + } + + { + TOptsParseResultTestWrapper r(&opts, V({"cmd", "--abstract", "--buffer=512"})); + UNIT_ASSERT(r.Has('b')); + UNIT_ASSERT_VALUES_EQUAL(r.Get('b', 0), "512"); + } + } + + Y_UNIT_TEST(TestTOptsParseResultException) { + // verify that TOptsParseResultException actually throws a TUsageException instead of exit() + // not using wrapper here because it can hide bugs (see review #243810 and r2737774) + TOptsNoDefault opts; + opts.AddLongOption("required-opt").Required(); + const char* argv[] = {"cmd"}; + // Should throw TUsageException. Other exception types, no exceptions at all and exit(1) are failures + UNIT_ASSERT_EXCEPTION( + TOptsParseResultException(&opts, Y_ARRAY_SIZE(argv), argv), + TUsageException); + } + + Y_UNIT_TEST(TestFreeArgsStoreResult) { + TOptsNoDefault opts; + TString data; + int number = 0; + opts.AddFreeArgBinding("data", data); + opts.AddFreeArgBinding("number", number); + TOptsParseResultTestWrapper r(&opts, V({"cmd", "hello", "25"})); + UNIT_ASSERT_VALUES_EQUAL("hello", data); + UNIT_ASSERT_VALUES_EQUAL(25, number); + UNIT_ASSERT_VALUES_EQUAL(2, r.GetFreeArgCount()); + } +} diff --git a/library/cpp/getopt/ut/modchooser_ut.cpp b/library/cpp/getopt/ut/modchooser_ut.cpp new file mode 100644 index 0000000000..a14c8a5853 --- /dev/null +++ b/library/cpp/getopt/ut/modchooser_ut.cpp @@ -0,0 +1,71 @@ +#include <library/cpp/getopt/modchooser.h> + +#include <library/cpp/testing/unittest/registar.h> + +#include <util/stream/str.h> + +void ValidateArgcArgv(int argc, const char** argv) { + UNIT_ASSERT_EQUAL(argc, 1); + UNIT_ASSERT_EQUAL(argv[argc], nullptr); +} + +int One(int argc, const char** argv) { + ValidateArgcArgv(argc, argv); + return 1; +} + +int Two(int argc, const char** argv) { + ValidateArgcArgv(argc, argv); + return 2; +} + +int Three(int argc, const char** argv) { + ValidateArgcArgv(argc, argv); + return 3; +} + +int Four(int argc, const char** argv) { + ValidateArgcArgv(argc, argv); + return 4; +} + +int Five(int argc, const char** argv) { + ValidateArgcArgv(argc, argv); + return 5; +} + +typedef int (*F_PTR)(int, const char**); +static const F_PTR FUNCTIONS[] = {One, Two, Three, Four, Five}; +static const char* NAMES[] = {"one", "two", "three", "four", "five"}; +static_assert(Y_ARRAY_SIZE(FUNCTIONS) == Y_ARRAY_SIZE(NAMES), "Incorrect input tests data"); + +Y_UNIT_TEST_SUITE(TModChooserTest) { + Y_UNIT_TEST(TestModesSimpleRunner) { + TModChooser chooser; + for (size_t idx = 0; idx < Y_ARRAY_SIZE(NAMES); ++idx) { + chooser.AddMode(NAMES[idx], FUNCTIONS[idx], NAMES[idx]); + } + + // test argc, argv + for (size_t idx = 0; idx < Y_ARRAY_SIZE(NAMES); ++idx) { + int argc = 2; + const char* argv[] = {"UNITTEST", NAMES[idx], nullptr}; + UNIT_ASSERT_EQUAL(static_cast<int>(idx) + 1, chooser.Run(argc, argv)); + } + + // test TVector<TString> argv + for (size_t idx = 0; idx < Y_ARRAY_SIZE(NAMES); ++idx) { + const TVector<TString> argv = {"UNITTEST", NAMES[idx]}; + UNIT_ASSERT_EQUAL(static_cast<int>(idx) + 1, chooser.Run(argv)); + } + } + + Y_UNIT_TEST(TestHelpMessage) { + TModChooser chooser; + + int argc = 2; + const char* argv[] = {"UNITTEST", "-?", nullptr}; + + chooser.Run(argc, argv); + } +} diff --git a/library/cpp/getopt/ut/opt2_ut.cpp b/library/cpp/getopt/ut/opt2_ut.cpp new file mode 100644 index 0000000000..0e7464747c --- /dev/null +++ b/library/cpp/getopt/ut/opt2_ut.cpp @@ -0,0 +1,63 @@ +#include <library/cpp/getopt/opt2.h> + +#include <library/cpp/testing/unittest/registar.h> + +//using namespace NLastGetopt; + +Y_UNIT_TEST_SUITE(Opt2Test) { + Y_UNIT_TEST(TestSimple) { + int argc = 8; + char* argv[] = { + (char*)"cmd", + (char*)"--aaaa=aaaa", + (char*)"zz", + (char*)"-x1", + (char*)"-x2", + (char*)"-c", + (char*)"-d8", + (char*)"ww", + }; + + Opt2 opt(argc, argv, "A:b:cd:e:x:", 2, "aaaa=A"); + + const char* edef = "edef"; + const char* a = opt.Arg('A', "<var_name> - usage of -A"); + int b = opt.Int('b', "<var_name> - usage of -b", 2); + bool c = opt.Has('c', "usage of -c"); + int d = opt.Int('d', "<var_name> - usage of -d", 13); + const char* e = opt.Arg('e', "<unused> - only default is really used", edef); + const TVector<const char*>& x = opt.MArg('x', "<var_name> - usage of -x"); + + UNIT_ASSERT(!opt.AutoUsage("<L> <M>")); + UNIT_ASSERT_VALUES_EQUAL("aaaa", a); + UNIT_ASSERT_VALUES_EQUAL(2, b); + UNIT_ASSERT(c); + UNIT_ASSERT_VALUES_EQUAL(8, d); + UNIT_ASSERT_VALUES_EQUAL((void*)edef, e); + + UNIT_ASSERT_VALUES_EQUAL(2u, opt.Pos.size()); + UNIT_ASSERT_STRINGS_EQUAL("zz", opt.Pos.at(0)); + UNIT_ASSERT_VALUES_EQUAL((void*)argv[2], opt.Pos.at(0)); + UNIT_ASSERT_STRINGS_EQUAL("ww", opt.Pos.at(1)); + UNIT_ASSERT_STRINGS_EQUAL("1", x.at(0)); + UNIT_ASSERT_STRINGS_EQUAL("2", x.at(1)); + } + + Y_UNIT_TEST(TestErrors1) { + int argc = 4; + char* argv[] = { + (char*)"cmd", + (char*)"zz", + (char*)"-c", + (char*)"-e", + }; + + Opt2 opt(argc, argv, "ce:", 2); + + const char* edef = "edef"; + bool c = opt.Has('c', "usage of -c"); + const char* e = opt.Arg('e', "<unused> - only default is really used", edef); + UNIT_ASSERT(c); + UNIT_ASSERT_VALUES_EQUAL((void*)edef, e); + } +} diff --git a/library/cpp/getopt/ut/opt_ut.cpp b/library/cpp/getopt/ut/opt_ut.cpp new file mode 100644 index 0000000000..441aa493a0 --- /dev/null +++ b/library/cpp/getopt/ut/opt_ut.cpp @@ -0,0 +1,52 @@ +#include <library/cpp/getopt/opt.h> + +#include <library/cpp/testing/unittest/registar.h> +#include <util/string/vector.h> + +Y_UNIT_TEST_SUITE(OptTest) { + Y_UNIT_TEST(TestSimple) { + int argc = 3; + char* argv[] = { + (char*)"cmd", (char*)"-x"}; + Opt opt(argc, argv, ""); + opt.Err = false; // be quiet + UNIT_ASSERT_VALUES_EQUAL('?', opt.Get()); + UNIT_ASSERT_VALUES_EQUAL(EOF, opt.Get()); + UNIT_ASSERT_VALUES_EQUAL(EOF, opt.Get()); + UNIT_ASSERT_VALUES_EQUAL(EOF, opt.Get()); + } + + Y_UNIT_TEST(TestFreeArguments) { + Opt::Ion options[] = { + {"some-option", Opt::WithArg, nullptr, 123}, + {nullptr, Opt::WithoutArg, nullptr, 0}}; + const char* argv[] = {"cmd", "ARG1", "-some-option", "ARG2", "ARG3", nullptr}; + int argc = 5; + Opt opts(argc, argv, "", options); + + UNIT_ASSERT_VALUES_EQUAL(JoinStrings(opts.GetFreeArgs(), ", "), "ARG1, ARG3"); + } + + Y_UNIT_TEST(TestLongOption) { + const int SOME_OPTION_ID = 12345678; + Opt::Ion options[] = { + {"some-option", Opt::WithArg, nullptr, SOME_OPTION_ID}, + {nullptr, Opt::WithoutArg, nullptr, 0}}; + for (int doubleDash = 0; doubleDash <= 1; ++doubleDash) { + const char* argv[] = {"cmd", "ARG1", (doubleDash ? "--some-option" : "-some-option"), "ARG2", "ARG3", nullptr}; + int argc = 5; + Opt opts(argc, argv, "", options); + + TString optionValue = ""; + int optlet = 0; + while ((optlet = opts.Get()) != EOF) { + if (optlet == SOME_OPTION_ID) { + optionValue = opts.GetArg(); + } else { + UNIT_FAIL("don't expected any options, except -some-option"); + } + } + UNIT_ASSERT_VALUES_EQUAL(optionValue, "ARG2"); + } + } +} diff --git a/library/cpp/getopt/ut/posix_getopt_ut.cpp b/library/cpp/getopt/ut/posix_getopt_ut.cpp new file mode 100644 index 0000000000..b6d374bf28 --- /dev/null +++ b/library/cpp/getopt/ut/posix_getopt_ut.cpp @@ -0,0 +1,119 @@ +#include <library/cpp/getopt/posix_getopt.h> + +#include <library/cpp/testing/unittest/registar.h> + +using namespace NLastGetopt; + +Y_UNIT_TEST_SUITE(TPosixGetoptTest) { + Y_UNIT_TEST(TestSimple) { + int argc = 6; + const char* argv0[] = {"program", "-b", "-f1", "-f", "2", "zzzz"}; + char** const argv = (char**)argv0; + + NLastGetopt::optreset = 1; + UNIT_ASSERT_VALUES_EQUAL('b', NLastGetopt::getopt(argc, argv, "bf:")); + UNIT_ASSERT_VALUES_EQUAL('f', NLastGetopt::getopt(argc, argv, "bf:")); + UNIT_ASSERT_VALUES_EQUAL(NLastGetopt::optarg, TString("1")); + UNIT_ASSERT_VALUES_EQUAL('f', NLastGetopt::getopt(argc, argv, "bf:")); + UNIT_ASSERT_VALUES_EQUAL(NLastGetopt::optarg, TString("2")); + UNIT_ASSERT_VALUES_EQUAL(-1, NLastGetopt::getopt(argc, argv, "bf:")); + + UNIT_ASSERT_VALUES_EQUAL(5, NLastGetopt::optind); + } + + Y_UNIT_TEST(TestLong) { + int daggerset = 0; + /* options descriptor */ + const NLastGetopt::option longopts[] = { + {"buffy", no_argument, nullptr, 'b'}, + {"fluoride", required_argument, nullptr, 'f'}, + {"daggerset", no_argument, &daggerset, 1}, + {nullptr, 0, nullptr, 0}}; + + int argc = 7; + const char* argv0[] = {"program", "-b", "--buffy", "-f1", "--fluoride=2", "--daggerset", "zzzz"}; + char** const argv = (char**)argv0; + + int longIndex; + + NLastGetopt::optreset = 1; + UNIT_ASSERT_VALUES_EQUAL('b', NLastGetopt::getopt_long(argc, argv, "bf:", longopts, &longIndex)); + UNIT_ASSERT_VALUES_EQUAL(0, longIndex); + UNIT_ASSERT_VALUES_EQUAL('b', NLastGetopt::getopt_long(argc, argv, "bf:", longopts, nullptr)); + UNIT_ASSERT_VALUES_EQUAL('f', NLastGetopt::getopt_long(argc, argv, "bf:", longopts, &longIndex)); + UNIT_ASSERT_VALUES_EQUAL(1, longIndex); + UNIT_ASSERT_VALUES_EQUAL('f', NLastGetopt::getopt_long(argc, argv, "bf:", longopts, nullptr)); + UNIT_ASSERT_VALUES_EQUAL(0, NLastGetopt::getopt_long(argc, argv, "bf:", longopts, nullptr)); + UNIT_ASSERT_VALUES_EQUAL(-1, NLastGetopt::getopt_long(argc, argv, "bf:", longopts, nullptr)); + + UNIT_ASSERT_VALUES_EQUAL(6, NLastGetopt::optind); + } + + Y_UNIT_TEST(TestLongPermutation) { + int daggerset = 0; + /* options descriptor */ + const NLastGetopt::option longopts[] = { + {"buffy", no_argument, nullptr, 'b'}, + {"fluoride", required_argument, nullptr, 'f'}, + {"daggerset", no_argument, &daggerset, 1}, + {nullptr, 0, nullptr, 0}}; + + int argc = 7; + const char* argv0[] = {"program", "aa", "-b", "bb", "cc", "--buffy", "dd"}; + char** const argv = (char**)argv0; + + NLastGetopt::optreset = 1; + UNIT_ASSERT_VALUES_EQUAL('b', NLastGetopt::getopt_long(argc, argv, "bf:", longopts, nullptr)); + UNIT_ASSERT_VALUES_EQUAL('b', NLastGetopt::getopt_long(argc, argv, "bf:", longopts, nullptr)); + UNIT_ASSERT_VALUES_EQUAL(-1, NLastGetopt::getopt_long(argc, argv, "bf:", longopts, nullptr)); + + UNIT_ASSERT_VALUES_EQUAL(3, NLastGetopt::optind); + } + + Y_UNIT_TEST(TestNoOptionsOptionsWithDoubleDash) { + const NLastGetopt::option longopts[] = { + {"buffy", no_argument, nullptr, 'b'}, + {"fluoride", no_argument, nullptr, 'f'}, + {nullptr, 0, nullptr, 0}}; + + int argc = 2; + const char* argv0[] = {"program", "--bf"}; + char** const argv = (char**)argv0; + + NLastGetopt::optreset = 1; + UNIT_ASSERT_VALUES_EQUAL('?', NLastGetopt::getopt_long(argc, argv, "bf", longopts, nullptr)); + } + + Y_UNIT_TEST(TestLongOnly) { + const NLastGetopt::option longopts[] = { + {"foo", no_argument, nullptr, 'F'}, + {"fluoride", no_argument, nullptr, 'f'}, + {"ogogo", no_argument, nullptr, 'o'}, + {nullptr, 0, nullptr, 0}}; + + int argc = 4; + const char* argv0[] = {"program", "--foo", "-foo", "-fo"}; + char** const argv = (char**)argv0; + + NLastGetopt::optreset = 1; + UNIT_ASSERT_VALUES_EQUAL('F', NLastGetopt::getopt_long_only(argc, argv, "fo", longopts, nullptr)); + UNIT_ASSERT_VALUES_EQUAL('F', NLastGetopt::getopt_long_only(argc, argv, "fo", longopts, nullptr)); + UNIT_ASSERT_VALUES_EQUAL('f', NLastGetopt::getopt_long_only(argc, argv, "fo", longopts, nullptr)); + UNIT_ASSERT_VALUES_EQUAL('o', NLastGetopt::getopt_long_only(argc, argv, "fo", longopts, nullptr)); + UNIT_ASSERT_VALUES_EQUAL(-1, NLastGetopt::getopt_long_only(argc, argv, "fo", longopts, nullptr)); + } + + Y_UNIT_TEST(TestLongWithoutOnlySingleDashNowAllowed) { + const NLastGetopt::option longopts[] = { + {"foo", no_argument, nullptr, 'F'}, + {"zoo", no_argument, nullptr, 'z'}, + {nullptr, 0, nullptr, 0}}; + + int argc = 2; + const char* argv0[] = {"program", "-foo"}; + char** const argv = (char**)argv0; + + NLastGetopt::optreset = 1; + UNIT_ASSERT_VALUES_EQUAL('?', NLastGetopt::getopt_long(argc, argv, "z", longopts, nullptr)); + } +} diff --git a/library/cpp/getopt/ut/wrap.cpp b/library/cpp/getopt/ut/wrap.cpp new file mode 100644 index 0000000000..3444eea102 --- /dev/null +++ b/library/cpp/getopt/ut/wrap.cpp @@ -0,0 +1,96 @@ +#include <library/cpp/testing/unittest/registar.h> + +#include <library/cpp/getopt/small/wrap.h> + +Y_UNIT_TEST_SUITE(Wrap) { + Y_UNIT_TEST(TestWrapping) { + UNIT_ASSERT_STRINGS_EQUAL( + NLastGetopt::Wrap(5, "a b c d eeffeff").Quote(), + TString("a b c\nd\neeffeff").Quote() + ); + + UNIT_ASSERT_STRINGS_EQUAL( + NLastGetopt::Wrap(5, "a b\nc d\neeffeff").Quote(), + TString("a b\nc d\neeffeff").Quote() + ); + + UNIT_ASSERT_STRINGS_EQUAL( + NLastGetopt::Wrap(5, "a b\n c d\neeffeff").Quote(), + TString("a b\n c\nd\neeffeff").Quote() + ); + + UNIT_ASSERT_STRINGS_EQUAL( + NLastGetopt::Wrap(5, "a b\nx c d\neeffeff").Quote(), + TString("a b\nx\nc d\neeffeff").Quote() + ); + + UNIT_ASSERT_STRINGS_EQUAL( + NLastGetopt::Wrap(5, "a b\nx \n c d\neeffeff").Quote(), + TString("a b\nx\n c\nd\neeffeff").Quote() + ); + + UNIT_ASSERT_STRINGS_EQUAL( + NLastGetopt::Wrap(5, "a b\nx \n c d\neeffeff").Quote(), + TString("a b\nx\n c\nd\neeffeff").Quote() + ); + } + + Y_UNIT_TEST(TestWrappingIndent) { + UNIT_ASSERT_STRINGS_EQUAL( + NLastGetopt::Wrap(5, "a b c d", "|>").Quote(), + TString("a b\n|>c d").Quote() + ); + + UNIT_ASSERT_STRINGS_EQUAL( + NLastGetopt::Wrap(5, "a b\n\nc d", "|>").Quote(), + TString("a b\n|>\n|>c d").Quote() + ); + } + + Y_UNIT_TEST(TestWrappingAnsi) { + UNIT_ASSERT_STRINGS_EQUAL( + NLastGetopt::Wrap(5, "\033[1;2;3;4;5mx\033[1;2;3;4;5mx\033[1;2;3;4;5mx\033[1;2;3;4;5mx\033[1;2;3;4;5m").Quote(), + TString("\033[1;2;3;4;5mx\033[1;2;3;4;5mx\033[1;2;3;4;5mx\033[1;2;3;4;5mx\033[1;2;3;4;5m").Quote() + ); + + UNIT_ASSERT_STRINGS_EQUAL( + NLastGetopt::Wrap(5, "a \033[1;2;3;4;5mb c\033[1;2;3;4;5m \033[1;2;3;4;5md e f").Quote(), + TString("a \033[1;2;3;4;5mb c\033[1;2;3;4;5m\n\033[1;2;3;4;5md e f").Quote() + ); + + UNIT_ASSERT_STRINGS_EQUAL( + NLastGetopt::Wrap(5, "a b \033[1;2;3;4;5m c d").Quote(), + TString("a b \033[1;2;3;4;5m\nc d").Quote() + ); + + UNIT_ASSERT_STRINGS_EQUAL( + NLastGetopt::Wrap(5, "a b \033[1;2;3;4;5m c d").Quote(), + TString("a b\n\033[1;2;3;4;5m c d").Quote() + ); + } + + Y_UNIT_TEST(TestTextInfo) { + size_t lastLineLen; + bool hasParagraphs; + + NLastGetopt::Wrap(5, "a b c d e", "", &lastLineLen, &hasParagraphs); + UNIT_ASSERT_VALUES_EQUAL(lastLineLen, 3); + UNIT_ASSERT_VALUES_EQUAL(hasParagraphs, false); + + NLastGetopt::Wrap(5, "a b c\n\nd e f h", "", &lastLineLen, &hasParagraphs); + UNIT_ASSERT_VALUES_EQUAL(lastLineLen, 1); + UNIT_ASSERT_VALUES_EQUAL(hasParagraphs, true); + + NLastGetopt::Wrap(5, "a b c\n\n", "", &lastLineLen, &hasParagraphs); + UNIT_ASSERT_VALUES_EQUAL(lastLineLen, 0); + UNIT_ASSERT_VALUES_EQUAL(hasParagraphs, true); + + NLastGetopt::Wrap(5, "\n \na b c", "", &lastLineLen, &hasParagraphs); + UNIT_ASSERT_VALUES_EQUAL(lastLineLen, 5); + UNIT_ASSERT_VALUES_EQUAL(hasParagraphs, true); + + NLastGetopt::Wrap(5, "\nx\na b c", "", &lastLineLen, &hasParagraphs); + UNIT_ASSERT_VALUES_EQUAL(lastLineLen, 5); + UNIT_ASSERT_VALUES_EQUAL(hasParagraphs, false); + } +} diff --git a/library/cpp/getopt/ut/ya.make b/library/cpp/getopt/ut/ya.make new file mode 100644 index 0000000000..8d00669efb --- /dev/null +++ b/library/cpp/getopt/ut/ya.make @@ -0,0 +1,15 @@ +UNITTEST_FOR(library/cpp/getopt) + +OWNER(pg) + +SRCS( + last_getopt_ut.cpp + modchooser_ut.cpp + opt2_ut.cpp + opt_ut.cpp + posix_getopt_ut.cpp + wrap.cpp + ygetopt_ut.cpp +) + +END() diff --git a/library/cpp/getopt/ut/ygetopt_ut.cpp b/library/cpp/getopt/ut/ygetopt_ut.cpp new file mode 100644 index 0000000000..a76f117216 --- /dev/null +++ b/library/cpp/getopt/ut/ygetopt_ut.cpp @@ -0,0 +1,45 @@ +#include <library/cpp/getopt/ygetopt.h> + +#include <library/cpp/testing/unittest/registar.h> + +class TGetOptTest: public TTestBase { + UNIT_TEST_SUITE(TGetOptTest); + UNIT_TEST(TestGetOpt); + UNIT_TEST_EXCEPTION(TestZeroArgC, yexception); + UNIT_TEST_SUITE_END(); + +public: + void TestGetOpt(); + void TestZeroArgC(); +}; + +UNIT_TEST_SUITE_REGISTRATION(TGetOptTest); + +void TGetOptTest::TestZeroArgC() { + TGetOpt opt(0, nullptr, ""); +} + +void TGetOptTest::TestGetOpt() { + const char* argv[] = { + "/usr/bin/bash", + "-f", + "-p", + "qwerty123", + "-z", + "-q", + nullptr}; + + TString res; + const TString format = "qzp:f"; + TGetOpt opt(sizeof(argv) / sizeof(*argv) - 1, argv, format); + + for (TGetOpt::TIterator it = opt.Begin(); it != opt.End(); ++it) { + res += it->Key(); + + if (it->HaveArg()) { + res += it->Arg(); + } + } + + UNIT_ASSERT_EQUAL(res, "fpqwerty123zq"); +} |