20 #include "gmock/gmock.h" 21 #include "gtest/gtest.h" 39 UDT(
const UDT&) =
default;
55 *err =
"Use values A, AAA instead";
59 return udt.value == 1 ?
"A" :
"AAA";
62 std::string GetTestTmpDirEnvVar(
const char*
const env_var_name) {
65 auto get_res = GetEnvironmentVariableA(env_var_name, buf,
sizeof(buf));
66 if (get_res >=
sizeof(buf) || get_res == 0) {
70 return std::string(buf, get_res);
72 const char* val = ::getenv(env_var_name);
81 const std::string& GetTestTempDir() {
82 static std::string* temp_dir_name = []() -> std::string* {
83 std::string* res =
new std::string(GetTestTmpDirEnvVar(
"TEST_TMPDIR"));
86 *res = GetTestTmpDirEnvVar(
"TMPDIR");
91 char temp_path_buffer[MAX_PATH];
93 auto len = GetTempPathA(MAX_PATH, temp_path_buffer);
94 if (
len < MAX_PATH &&
len != 0) {
96 temp_path_buffer,
"\\parse_test.", GetCurrentProcessId());
97 if (CreateDirectoryA(temp_dir_name.c_str(),
nullptr)) {
102 char temp_dir_template[] =
"/tmp/parse_test.XXXXXX";
103 if (
auto* unique_name = ::mkdtemp(temp_dir_template)) {
110 "Failed to make temporary directory for data files");
123 return *temp_dir_name;
126 struct FlagfileData {
132 constexpr
const char*
const ff1_data[] = {
138 " --string_flag=q2w2 ",
140 " --double_flag=0.1",
144 constexpr
const char*
const ff2_data[] = {
145 "# Setting legacy flag",
162 const char* GetFlagfileFlag(
const std::vector<FlagfileData>& ffd,
163 std::string* flagfile_flag) {
164 *flagfile_flag =
"--flagfile=";
166 for (
const auto& flagfile_data : ffd) {
167 std::string flagfile_name =
168 absl::StrCat(GetTestTempDir(), flagfile_data.file_name);
170 std::ofstream flagfile_out(flagfile_name);
171 for (
auto line : flagfile_data.file_lines) {
179 return flagfile_flag->c_str();
186 ABSL_FLAG(std::string, string_flag,
"a",
"");
196 using testing::ElementsAreArray;
198 class ParseTest :
public testing::Test {
206 std::vector<char*> InvokeParse(
const char* (&in_argv)[N]) {
213 void TestParse(
const char* (&in_argv)[N],
int int_flag_value,
215 bool bool_flag_val,
int exp_position_args = 0) {
216 auto out_args = InvokeParse(in_argv);
218 EXPECT_EQ(out_args.size(), 1 + exp_position_args);
219 EXPECT_STREQ(out_args[0],
"testbin");
222 EXPECT_NEAR(
absl::GetFlag(FLAGS_double_flag), double_flag_val, 0.0001);
223 EXPECT_EQ(
absl::GetFlag(FLAGS_string_flag), string_flag_val);
229 TEST_F(ParseTest, TestEmptyArgv) {
230 const char* in_argv[] = {
"testbin"};
232 auto out_args = InvokeParse(in_argv);
234 EXPECT_EQ(out_args.size(), 1);
235 EXPECT_STREQ(out_args[0],
"testbin");
240 TEST_F(ParseTest, TestValidIntArg) {
241 const char* in_args1[] = {
245 TestParse(in_args1, 10, 1.1,
"a",
false);
247 const char* in_args2[] = {
251 TestParse(in_args2, 20, 1.1,
"a",
false);
253 const char* in_args3[] = {
258 TestParse(in_args3, -30, 1.1,
"a",
false);
260 const char* in_args4[] = {
265 TestParse(in_args4, 33, 1.1,
"a",
false);
270 TEST_F(ParseTest, TestValidDoubleArg) {
271 const char* in_args1[] = {
275 TestParse(in_args1, 1, 2.3,
"a",
false);
277 const char* in_args2[] = {
279 "--double_flag=0x1.2",
281 TestParse(in_args2, 1, 1.125,
"a",
false);
283 const char* in_args3[] = {
288 TestParse(in_args3, 1, 99.7,
"a",
false);
290 const char* in_args4[] = {
295 TestParse(in_args4, 1, 32.0625,
"a",
false);
300 TEST_F(ParseTest, TestValidStringArg) {
301 const char* in_args1[] = {
303 "--string_flag=aqswde",
305 TestParse(in_args1, 1, 1.1,
"aqswde",
false);
307 const char* in_args2[] = {
309 "-string_flag=a=b=c",
311 TestParse(in_args2, 1, 1.1,
"a=b=c",
false);
313 const char* in_args3[] = {
318 TestParse(in_args3, 1, 1.1,
"zaxscd",
false);
320 const char* in_args4[] = {
325 TestParse(in_args4, 1, 1.1,
"--int_flag",
false);
327 const char* in_args5[] = {
332 TestParse(in_args5, 1, 1.1,
"--no_a_flag=11",
false);
337 TEST_F(ParseTest, TestValidBoolArg) {
338 const char* in_args1[] = {
342 TestParse(in_args1, 1, 1.1,
"a",
true);
344 const char* in_args2[] = {
348 TestParse(in_args2, 1, 1.1,
"a",
false);
350 const char* in_args3[] = {
354 TestParse(in_args3, 1, 1.1,
"a",
true);
356 const char* in_args4[] = {
360 TestParse(in_args4, 1, 1.1,
"a",
false);
365 TEST_F(ParseTest, TestValidUDTArg) {
366 const char* in_args1[] = {
370 InvokeParse(in_args1);
374 const char* in_args2[] = {
"testbin",
"--udt_flag",
"AAA"};
375 InvokeParse(in_args2);
382 TEST_F(ParseTest, TestValidMultipleArg) {
383 const char* in_args1[] = {
384 "testbin",
"--bool_flag",
"--int_flag=2",
385 "--double_flag=0.1",
"--string_flag=asd",
387 TestParse(in_args1, 2, 0.1,
"asd",
true);
389 const char* in_args2[] = {
390 "testbin",
"--string_flag=",
"--nobool_flag",
"--int_flag",
391 "-011",
"--double_flag",
"-1e-2",
393 TestParse(in_args2, -11, -0.01,
"",
false);
395 const char* in_args3[] = {
396 "testbin",
"--int_flag",
"-0",
"--string_flag",
"\"\"",
397 "--bool_flag=true",
"--double_flag=1e18",
399 TestParse(in_args3, 0, 1e18,
"\"\"",
true);
404 TEST_F(ParseTest, TestPositionalArgs) {
405 const char* in_args1[] = {
410 TestParse(in_args1, 1, 1.1,
"a",
false, 2);
412 auto out_args1 = InvokeParse(in_args1);
414 EXPECT_STREQ(out_args1[1],
"p1");
415 EXPECT_STREQ(out_args1[2],
"p2");
417 const char* in_args2[] = {
422 TestParse(in_args2, 2, 1.1,
"a",
false, 1);
424 auto out_args2 = InvokeParse(in_args2);
426 EXPECT_STREQ(out_args2[1],
"p1");
428 const char* in_args3[] = {
"testbin",
"p1",
"--int_flag=3",
429 "p2",
"--bool_flag",
"true"};
430 TestParse(in_args3, 3, 1.1,
"a",
true, 3);
432 auto out_args3 = InvokeParse(in_args3);
434 EXPECT_STREQ(out_args3[1],
"p1");
435 EXPECT_STREQ(out_args3[2],
"p2");
436 EXPECT_STREQ(out_args3[3],
"true");
438 const char* in_args4[] = {
444 TestParse(in_args4, 3, 1.1,
"a",
true, 2);
446 auto out_args4 = InvokeParse(in_args4);
448 EXPECT_STREQ(out_args4[1],
"p1");
449 EXPECT_STREQ(out_args4[2],
"p2");
451 const char* in_args5[] = {
452 "testbin",
"p1",
"--int_flag=4",
"--",
"--bool_flag",
"false",
"p2",
454 TestParse(in_args5, 4, 1.1,
"a",
true, 4);
456 auto out_args5 = InvokeParse(in_args5);
458 EXPECT_STREQ(out_args5[1],
"p1");
459 EXPECT_STREQ(out_args5[2],
"--bool_flag");
460 EXPECT_STREQ(out_args5[3],
"false");
461 EXPECT_STREQ(out_args5[4],
"p2");
466 using ParseDeathTest = ParseTest;
468 TEST_F(ParseDeathTest, TestUndefinedArg) {
469 const char* in_args1[] = {
473 EXPECT_DEATH(InvokeParse(in_args1),
474 "Unknown command line flag 'undefined_flag'");
476 const char* in_args2[] = {
480 EXPECT_DEATH(InvokeParse(in_args2),
481 "Unknown command line flag 'noprefixed_flag'");
483 const char* in_args3[] = {
487 EXPECT_DEATH(InvokeParse(in_args3),
"Unknown command line flag 'Int_flag'");
492 TEST_F(ParseDeathTest, TestInvalidBoolFlagFormat) {
493 const char* in_args1[] = {
498 InvokeParse(in_args1),
499 "Missing the value after assignment for the boolean flag 'bool_flag'");
501 const char* in_args2[] = {
503 "--nobool_flag=true",
505 EXPECT_DEATH(InvokeParse(in_args2),
506 "Negative form with assignment is not valid for the boolean " 512 TEST_F(ParseDeathTest, TestInvalidNonBoolFlagFormat) {
513 const char* in_args1[] = {
517 EXPECT_DEATH(InvokeParse(in_args1),
518 "Negative form is not valid for the flag 'string_flag'");
520 const char* in_args2[] = {
524 EXPECT_DEATH(InvokeParse(in_args2),
525 "Missing the value for the flag 'int_flag'");
530 TEST_F(ParseDeathTest, TestInvalidUDTFlagFormat) {
531 const char* in_args1[] = {
535 EXPECT_DEATH(InvokeParse(in_args1),
536 "Illegal value '1' specified for flag 'udt_flag'; Use values A, " 539 const char* in_args2[] = {
544 EXPECT_DEATH(InvokeParse(in_args2),
545 "Illegal value 'AA' specified for flag 'udt_flag'; Use values " 551 TEST_F(ParseTest, TestLegacyFlags) {
552 const char* in_args1[] = {
556 TestParse(in_args1, 1, 1.1,
"a",
false);
558 const char* in_args2[] = {
562 TestParse(in_args2, 1, 1.1,
"a",
false);
564 const char* in_args3[] = {
565 "testbin",
"--legacy_int",
"22",
"--int_flag=2",
566 "--legacy_bool",
"true",
"--legacy_str",
"--string_flag=qwe",
568 TestParse(in_args3, 2, 1.1,
"a",
false, 1);
573 TEST_F(ParseTest, TestSimpleValidFlagfile) {
574 std::string flagfile_flag;
576 const char* in_args1[] = {
581 TestParse(in_args1, -1, 0.1,
"q2w2 ",
true);
583 const char* in_args2[] = {
588 TestParse(in_args2, 100, 0.1,
"q2w2 ",
false);
593 TEST_F(ParseTest, TestValidMultiFlagfile) {
594 std::string flagfile_flag;
596 const char* in_args1[] = {
602 TestParse(in_args1, -1, 0.1,
"q2w2 ",
true);
607 TEST_F(ParseTest, TestFlagfileMixedWithRegularFlags) {
608 std::string flagfile_flag;
610 const char* in_args1[] = {
611 "testbin",
"--int_flag=3",
615 TestParse(in_args1, -1, 0.2,
"q2w2 ",
true);
620 TEST_F(ParseTest, TestFlagfileInFlagfile) {
621 std::string flagfile_flag;
623 constexpr
const char*
const ff3_data[] = {
624 "--flagfile=$0/parse_test.ff1",
625 "--flagfile=$0/parse_test.ff2",
628 const char* in_args1[] = {
633 TestParse(in_args1, 100, 0.1,
"q2w2 ",
false);
638 TEST_F(ParseDeathTest, TestInvalidFlagfiles) {
639 std::string flagfile_flag;
641 constexpr
const char*
const ff4_data[] = {
645 const char* in_args1[] = {
647 GetFlagfileFlag({{
"parse_test.ff4",
650 EXPECT_DEATH(InvokeParse(in_args1),
651 "Unknown command line flag 'unknown_flag'");
653 constexpr
const char*
const ff5_data[] = {
657 const char* in_args2[] = {
659 GetFlagfileFlag({{
"parse_test.ff5",
662 EXPECT_DEATH(InvokeParse(in_args2),
663 "Unknown command line flag 'int_flag 10'");
665 constexpr
const char*
const ff6_data[] = {
666 "--int_flag=10",
"--",
"arg1",
"arg2",
"arg3",
669 const char* in_args3[] = {
674 EXPECT_DEATH(InvokeParse(in_args3),
675 "Flagfile can't contain position arguments or --");
677 const char* in_args4[] = {
679 "--flagfile=invalid_flag_file",
681 EXPECT_DEATH(InvokeParse(in_args4),
"Can't open flagfile invalid_flag_file");
683 constexpr
const char*
const ff7_data[] = {
689 const char* in_args5[] = {
694 EXPECT_DEATH(InvokeParse(in_args5),
695 "Unexpected line in the flagfile .*: \\*bin\\*");
700 TEST_F(ParseTest, TestReadingRequiredFlagsFromEnv) {
701 const char* in_args1[] = {
"testbin",
702 "--fromenv=int_flag,bool_flag,string_flag"};
704 ScopedSetEnv set_int_flag(
"FLAGS_int_flag",
"33");
705 ScopedSetEnv set_bool_flag(
"FLAGS_bool_flag",
"True");
706 ScopedSetEnv set_string_flag(
"FLAGS_string_flag",
"AQ12");
708 TestParse(in_args1, 33, 1.1,
"AQ12",
true);
713 TEST_F(ParseDeathTest, TestReadingUnsetRequiredFlagsFromEnv) {
714 const char* in_args1[] = {
"testbin",
"--fromenv=int_flag"};
716 EXPECT_DEATH(InvokeParse(in_args1),
717 "FLAGS_int_flag not found in environment");
722 TEST_F(ParseDeathTest, TestRecursiveFlagsFromEnv) {
723 const char* in_args1[] = {
"testbin",
"--fromenv=tryfromenv"};
725 ScopedSetEnv set_tryfromenv(
"FLAGS_tryfromenv",
"int_flag");
727 EXPECT_DEATH(InvokeParse(in_args1),
"Infinite recursion on flag tryfromenv");
732 TEST_F(ParseTest, TestReadingOptionalFlagsFromEnv) {
733 const char* in_args1[] = {
734 "testbin",
"--tryfromenv=int_flag,bool_flag,string_flag,other_flag"};
736 ScopedSetEnv set_int_flag(
"FLAGS_int_flag",
"17");
737 ScopedSetEnv set_bool_flag(
"FLAGS_bool_flag",
"Y");
739 TestParse(in_args1, 17, 1.1,
"a",
true);
744 TEST_F(ParseTest, TestReadingFlagsFromEnvMoxedWithRegularFlags) {
745 const char* in_args1[] = {
748 "--tryfromenv=int_flag,bool_flag",
752 ScopedSetEnv set_int_flag(
"FLAGS_int_flag",
"-15");
753 ScopedSetEnv set_bool_flag(
"FLAGS_bool_flag",
"F");
755 TestParse(in_args1, -21, 1.1,
"a",
false);
760 TEST_F(ParseTest, TestKeepParsedArgs) {
761 const char* in_args1[] = {
762 "testbin",
"arg1",
"--bool_flag",
763 "--int_flag=211",
"arg2",
"--double_flag=1.1",
764 "--string_flag",
"asd",
"--",
768 auto out_args1 = InvokeParse(in_args1);
777 11, const_cast<char**>(in_args1), flags::ArgvListAction::kKeepParsedArgs,
778 flags::UsageFlagsAction::kHandleUsage,
779 flags::OnUndefinedFlag::kAbortIfUndefined);
795 TEST_F(ParseTest, TestIgnoreUndefinedFlags) {
796 const char* in_args1[] = {
804 4, const_cast<char**>(in_args1), flags::ArgvListAction::kRemoveParsedArgs,
805 flags::UsageFlagsAction::kHandleUsage,
806 flags::OnUndefinedFlag::kIgnoreUndefined);
813 const char* in_args2[] = {
821 4, const_cast<char**>(in_args2), flags::ArgvListAction::kKeepParsedArgs,
822 flags::UsageFlagsAction::kHandleUsage,
823 flags::OnUndefinedFlag::kIgnoreUndefined);
836 TEST_F(ParseDeathTest, TestHelpFlagHandling) {
837 const char* in_args1[] = {
842 EXPECT_EXIT(InvokeParse(in_args1), testing::ExitedWithCode(1),
"");
844 const char* in_args2[] = {
851 3, const_cast<char**>(in_args2), flags::ArgvListAction::kRemoveParsedArgs,
852 flags::UsageFlagsAction::kIgnoreUsage,
853 flags::OnUndefinedFlag::kAbortIfUndefined);
std::vector< char * > ParseCommandLine(int argc, char *argv[])
std::string AbslUnparseFlag(const UDT &)
void StrAppend(std::string *dest, const AlphaNum &a)
ABSL_RETIRED_FLAG(int, legacy_int, 1, "")
std::string StrCat(const AlphaNum &a, const AlphaNum &b)
std::vector< char * > ParseCommandLineImpl(int argc, char *argv[], ArgvListAction arg_list_act, UsageFlagsAction usage_flag_act, OnUndefinedFlag on_undef_flag)
#define ABSL_INTERNAL_LOG(severity, message)
TEST_F(GraphCyclesTest, NoCycle)
constexpr Span< const T > MakeConstSpan(T *ptr, size_t size) noexcept
bool AbslParseFlag(absl::string_view, UDT *, std::string *)
T GetFlag(const absl::Flag< T > &flag)
ABSL_FLAG(int, int_flag, 1, "")
ABSL_MUST_USE_RESULT std::string Substitute(absl::string_view format)