00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "absl/flags/parse.h"
00017
00018 #include <fstream>
00019
00020 #include "gmock/gmock.h"
00021 #include "gtest/gtest.h"
00022 #include "absl/base/internal/raw_logging.h"
00023 #include "absl/base/internal/scoped_set_env.h"
00024 #include "absl/flags/flag.h"
00025 #include "absl/strings/str_cat.h"
00026 #include "absl/strings/substitute.h"
00027 #include "absl/types/span.h"
00028
00029 #ifdef _WIN32
00030 #include <windows.h>
00031 #endif
00032
00033 namespace {
00034
00035 using absl::base_internal::ScopedSetEnv;
00036
00037 struct UDT {
00038 UDT() = default;
00039 UDT(const UDT&) = default;
00040 UDT(int v) : value(v) {}
00041
00042 int value;
00043 };
00044
00045 bool AbslParseFlag(absl::string_view in, UDT* udt, std::string* err) {
00046 if (in == "A") {
00047 udt->value = 1;
00048 return true;
00049 }
00050 if (in == "AAA") {
00051 udt->value = 10;
00052 return true;
00053 }
00054
00055 *err = "Use values A, AAA instead";
00056 return false;
00057 }
00058 std::string AbslUnparseFlag(const UDT& udt) {
00059 return udt.value == 1 ? "A" : "AAA";
00060 }
00061
00062 std::string GetTestTmpDirEnvVar(const char* const env_var_name) {
00063 #ifdef _WIN32
00064 char buf[MAX_PATH];
00065 auto get_res = GetEnvironmentVariableA(env_var_name, buf, sizeof(buf));
00066 if (get_res >= sizeof(buf) || get_res == 0) {
00067 return "";
00068 }
00069
00070 return std::string(buf, get_res);
00071 #else
00072 const char* val = ::getenv(env_var_name);
00073 if (val == nullptr) {
00074 return "";
00075 }
00076
00077 return val;
00078 #endif
00079 }
00080
00081 const std::string& GetTestTempDir() {
00082 static std::string* temp_dir_name = []() -> std::string* {
00083 std::string* res = new std::string(GetTestTmpDirEnvVar("TEST_TMPDIR"));
00084
00085 if (res->empty()) {
00086 *res = GetTestTmpDirEnvVar("TMPDIR");
00087 }
00088
00089 if (res->empty()) {
00090 #ifdef _WIN32
00091 char temp_path_buffer[MAX_PATH];
00092
00093 auto len = GetTempPathA(MAX_PATH, temp_path_buffer);
00094 if (len < MAX_PATH && len != 0) {
00095 std::string temp_dir_name = absl::StrCat(
00096 temp_path_buffer, "\\parse_test.", GetCurrentProcessId());
00097 if (CreateDirectoryA(temp_dir_name.c_str(), nullptr)) {
00098 *res = temp_dir_name;
00099 }
00100 }
00101 #else
00102 char temp_dir_template[] = "/tmp/parse_test.XXXXXX";
00103 if (auto* unique_name = ::mkdtemp(temp_dir_template)) {
00104 *res = unique_name;
00105 }
00106 #endif
00107
00108 if (res->empty()) {
00109 ABSL_INTERNAL_LOG(FATAL,
00110 "Failed to make temporary directory for data files");
00111 }
00112 }
00113
00114 #ifdef _WIN32
00115 *res += "\\";
00116 #else
00117 *res += "/";
00118 #endif
00119
00120 return res;
00121 }();
00122
00123 return *temp_dir_name;
00124 }
00125
00126 struct FlagfileData {
00127 const absl::string_view file_name;
00128 const absl::Span<const char* const> file_lines;
00129 };
00130
00131
00132 constexpr const char* const ff1_data[] = {
00133 "# comment ",
00134 " # comment ",
00135 "",
00136 " ",
00137 "--int_flag=-1",
00138 " --string_flag=q2w2 ",
00139 " ## ",
00140 " --double_flag=0.1",
00141 "--bool_flag=Y "
00142 };
00143
00144 constexpr const char* const ff2_data[] = {
00145 "# Setting legacy flag",
00146 "--legacy_int=1111",
00147 "--legacy_bool",
00148 "--nobool_flag",
00149 "--legacy_str=aqsw",
00150 "--int_flag=100",
00151 " ## ============="
00152 };
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162 const char* GetFlagfileFlag(const std::vector<FlagfileData>& ffd,
00163 std::string* flagfile_flag) {
00164 *flagfile_flag = "--flagfile=";
00165 absl::string_view separator;
00166 for (const auto& flagfile_data : ffd) {
00167 std::string flagfile_name =
00168 absl::StrCat(GetTestTempDir(), flagfile_data.file_name);
00169
00170 std::ofstream flagfile_out(flagfile_name);
00171 for (auto line : flagfile_data.file_lines) {
00172 flagfile_out << absl::Substitute(line, GetTestTempDir()) << "\n";
00173 }
00174
00175 absl::StrAppend(flagfile_flag, separator, flagfile_name);
00176 separator = ",";
00177 }
00178
00179 return flagfile_flag->c_str();
00180 }
00181
00182 }
00183
00184 ABSL_FLAG(int, int_flag, 1, "");
00185 ABSL_FLAG(double, double_flag, 1.1, "");
00186 ABSL_FLAG(std::string, string_flag, "a", "");
00187 ABSL_FLAG(bool, bool_flag, false, "");
00188 ABSL_FLAG(UDT, udt_flag, -1, "");
00189 ABSL_RETIRED_FLAG(int, legacy_int, 1, "");
00190 ABSL_RETIRED_FLAG(bool, legacy_bool, false, "");
00191 ABSL_RETIRED_FLAG(std::string, legacy_str, "l", "");
00192
00193 namespace {
00194
00195 namespace flags = absl::flags_internal;
00196 using testing::ElementsAreArray;
00197
00198 class ParseTest : public testing::Test {
00199 private:
00200 flags::FlagSaver flag_saver_;
00201 };
00202
00203
00204
00205 template <int N>
00206 std::vector<char*> InvokeParse(const char* (&in_argv)[N]) {
00207 return absl::ParseCommandLine(N, const_cast<char**>(in_argv));
00208 }
00209
00210
00211
00212 template <int N>
00213 void TestParse(const char* (&in_argv)[N], int int_flag_value,
00214 double double_flag_val, absl::string_view string_flag_val,
00215 bool bool_flag_val, int exp_position_args = 0) {
00216 auto out_args = InvokeParse(in_argv);
00217
00218 EXPECT_EQ(out_args.size(), 1 + exp_position_args);
00219 EXPECT_STREQ(out_args[0], "testbin");
00220
00221 EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), int_flag_value);
00222 EXPECT_NEAR(absl::GetFlag(FLAGS_double_flag), double_flag_val, 0.0001);
00223 EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), string_flag_val);
00224 EXPECT_EQ(absl::GetFlag(FLAGS_bool_flag), bool_flag_val);
00225 }
00226
00227
00228
00229 TEST_F(ParseTest, TestEmptyArgv) {
00230 const char* in_argv[] = {"testbin"};
00231
00232 auto out_args = InvokeParse(in_argv);
00233
00234 EXPECT_EQ(out_args.size(), 1);
00235 EXPECT_STREQ(out_args[0], "testbin");
00236 }
00237
00238
00239
00240 TEST_F(ParseTest, TestValidIntArg) {
00241 const char* in_args1[] = {
00242 "testbin",
00243 "--int_flag=10",
00244 };
00245 TestParse(in_args1, 10, 1.1, "a", false);
00246
00247 const char* in_args2[] = {
00248 "testbin",
00249 "-int_flag=020",
00250 };
00251 TestParse(in_args2, 20, 1.1, "a", false);
00252
00253 const char* in_args3[] = {
00254 "testbin",
00255 "--int_flag",
00256 "-30",
00257 };
00258 TestParse(in_args3, -30, 1.1, "a", false);
00259
00260 const char* in_args4[] = {
00261 "testbin",
00262 "-int_flag",
00263 "0x21",
00264 };
00265 TestParse(in_args4, 33, 1.1, "a", false);
00266 }
00267
00268
00269
00270 TEST_F(ParseTest, TestValidDoubleArg) {
00271 const char* in_args1[] = {
00272 "testbin",
00273 "--double_flag=2.3",
00274 };
00275 TestParse(in_args1, 1, 2.3, "a", false);
00276
00277 const char* in_args2[] = {
00278 "testbin",
00279 "--double_flag=0x1.2",
00280 };
00281 TestParse(in_args2, 1, 1.125, "a", false);
00282
00283 const char* in_args3[] = {
00284 "testbin",
00285 "--double_flag",
00286 "99.7",
00287 };
00288 TestParse(in_args3, 1, 99.7, "a", false);
00289
00290 const char* in_args4[] = {
00291 "testbin",
00292 "--double_flag",
00293 "0x20.1",
00294 };
00295 TestParse(in_args4, 1, 32.0625, "a", false);
00296 }
00297
00298
00299
00300 TEST_F(ParseTest, TestValidStringArg) {
00301 const char* in_args1[] = {
00302 "testbin",
00303 "--string_flag=aqswde",
00304 };
00305 TestParse(in_args1, 1, 1.1, "aqswde", false);
00306
00307 const char* in_args2[] = {
00308 "testbin",
00309 "-string_flag=a=b=c",
00310 };
00311 TestParse(in_args2, 1, 1.1, "a=b=c", false);
00312
00313 const char* in_args3[] = {
00314 "testbin",
00315 "--string_flag",
00316 "zaxscd",
00317 };
00318 TestParse(in_args3, 1, 1.1, "zaxscd", false);
00319
00320 const char* in_args4[] = {
00321 "testbin",
00322 "-string_flag",
00323 "--int_flag",
00324 };
00325 TestParse(in_args4, 1, 1.1, "--int_flag", false);
00326
00327 const char* in_args5[] = {
00328 "testbin",
00329 "--string_flag",
00330 "--no_a_flag=11",
00331 };
00332 TestParse(in_args5, 1, 1.1, "--no_a_flag=11", false);
00333 }
00334
00335
00336
00337 TEST_F(ParseTest, TestValidBoolArg) {
00338 const char* in_args1[] = {
00339 "testbin",
00340 "--bool_flag",
00341 };
00342 TestParse(in_args1, 1, 1.1, "a", true);
00343
00344 const char* in_args2[] = {
00345 "testbin",
00346 "--nobool_flag",
00347 };
00348 TestParse(in_args2, 1, 1.1, "a", false);
00349
00350 const char* in_args3[] = {
00351 "testbin",
00352 "--bool_flag=true",
00353 };
00354 TestParse(in_args3, 1, 1.1, "a", true);
00355
00356 const char* in_args4[] = {
00357 "testbin",
00358 "-bool_flag=false",
00359 };
00360 TestParse(in_args4, 1, 1.1, "a", false);
00361 }
00362
00363
00364
00365 TEST_F(ParseTest, TestValidUDTArg) {
00366 const char* in_args1[] = {
00367 "testbin",
00368 "--udt_flag=A",
00369 };
00370 InvokeParse(in_args1);
00371
00372 EXPECT_EQ(absl::GetFlag(FLAGS_udt_flag).value, 1);
00373
00374 const char* in_args2[] = {"testbin", "--udt_flag", "AAA"};
00375 InvokeParse(in_args2);
00376
00377 EXPECT_EQ(absl::GetFlag(FLAGS_udt_flag).value, 10);
00378 }
00379
00380
00381
00382 TEST_F(ParseTest, TestValidMultipleArg) {
00383 const char* in_args1[] = {
00384 "testbin", "--bool_flag", "--int_flag=2",
00385 "--double_flag=0.1", "--string_flag=asd",
00386 };
00387 TestParse(in_args1, 2, 0.1, "asd", true);
00388
00389 const char* in_args2[] = {
00390 "testbin", "--string_flag=", "--nobool_flag", "--int_flag",
00391 "-011", "--double_flag", "-1e-2",
00392 };
00393 TestParse(in_args2, -11, -0.01, "", false);
00394
00395 const char* in_args3[] = {
00396 "testbin", "--int_flag", "-0", "--string_flag", "\"\"",
00397 "--bool_flag=true", "--double_flag=1e18",
00398 };
00399 TestParse(in_args3, 0, 1e18, "\"\"", true);
00400 }
00401
00402
00403
00404 TEST_F(ParseTest, TestPositionalArgs) {
00405 const char* in_args1[] = {
00406 "testbin",
00407 "p1",
00408 "p2",
00409 };
00410 TestParse(in_args1, 1, 1.1, "a", false, 2);
00411
00412 auto out_args1 = InvokeParse(in_args1);
00413
00414 EXPECT_STREQ(out_args1[1], "p1");
00415 EXPECT_STREQ(out_args1[2], "p2");
00416
00417 const char* in_args2[] = {
00418 "testbin",
00419 "--int_flag=2",
00420 "p1",
00421 };
00422 TestParse(in_args2, 2, 1.1, "a", false, 1);
00423
00424 auto out_args2 = InvokeParse(in_args2);
00425
00426 EXPECT_STREQ(out_args2[1], "p1");
00427
00428 const char* in_args3[] = {"testbin", "p1", "--int_flag=3",
00429 "p2", "--bool_flag", "true"};
00430 TestParse(in_args3, 3, 1.1, "a", true, 3);
00431
00432 auto out_args3 = InvokeParse(in_args3);
00433
00434 EXPECT_STREQ(out_args3[1], "p1");
00435 EXPECT_STREQ(out_args3[2], "p2");
00436 EXPECT_STREQ(out_args3[3], "true");
00437
00438 const char* in_args4[] = {
00439 "testbin",
00440 "--",
00441 "p1",
00442 "p2",
00443 };
00444 TestParse(in_args4, 3, 1.1, "a", true, 2);
00445
00446 auto out_args4 = InvokeParse(in_args4);
00447
00448 EXPECT_STREQ(out_args4[1], "p1");
00449 EXPECT_STREQ(out_args4[2], "p2");
00450
00451 const char* in_args5[] = {
00452 "testbin", "p1", "--int_flag=4", "--", "--bool_flag", "false", "p2",
00453 };
00454 TestParse(in_args5, 4, 1.1, "a", true, 4);
00455
00456 auto out_args5 = InvokeParse(in_args5);
00457
00458 EXPECT_STREQ(out_args5[1], "p1");
00459 EXPECT_STREQ(out_args5[2], "--bool_flag");
00460 EXPECT_STREQ(out_args5[3], "false");
00461 EXPECT_STREQ(out_args5[4], "p2");
00462 }
00463
00464
00465
00466 using ParseDeathTest = ParseTest;
00467
00468 TEST_F(ParseDeathTest, TestUndefinedArg) {
00469 const char* in_args1[] = {
00470 "testbin",
00471 "--undefined_flag",
00472 };
00473 EXPECT_DEATH(InvokeParse(in_args1),
00474 "Unknown command line flag 'undefined_flag'");
00475
00476 const char* in_args2[] = {
00477 "testbin",
00478 "--noprefixed_flag",
00479 };
00480 EXPECT_DEATH(InvokeParse(in_args2),
00481 "Unknown command line flag 'noprefixed_flag'");
00482
00483 const char* in_args3[] = {
00484 "testbin",
00485 "--Int_flag=1",
00486 };
00487 EXPECT_DEATH(InvokeParse(in_args3), "Unknown command line flag 'Int_flag'");
00488 }
00489
00490
00491
00492 TEST_F(ParseDeathTest, TestInvalidBoolFlagFormat) {
00493 const char* in_args1[] = {
00494 "testbin",
00495 "--bool_flag=",
00496 };
00497 EXPECT_DEATH(
00498 InvokeParse(in_args1),
00499 "Missing the value after assignment for the boolean flag 'bool_flag'");
00500
00501 const char* in_args2[] = {
00502 "testbin",
00503 "--nobool_flag=true",
00504 };
00505 EXPECT_DEATH(InvokeParse(in_args2),
00506 "Negative form with assignment is not valid for the boolean "
00507 "flag 'bool_flag'");
00508 }
00509
00510
00511
00512 TEST_F(ParseDeathTest, TestInvalidNonBoolFlagFormat) {
00513 const char* in_args1[] = {
00514 "testbin",
00515 "--nostring_flag",
00516 };
00517 EXPECT_DEATH(InvokeParse(in_args1),
00518 "Negative form is not valid for the flag 'string_flag'");
00519
00520 const char* in_args2[] = {
00521 "testbin",
00522 "--int_flag",
00523 };
00524 EXPECT_DEATH(InvokeParse(in_args2),
00525 "Missing the value for the flag 'int_flag'");
00526 }
00527
00528
00529
00530 TEST_F(ParseDeathTest, TestInvalidUDTFlagFormat) {
00531 const char* in_args1[] = {
00532 "testbin",
00533 "--udt_flag=1",
00534 };
00535 EXPECT_DEATH(InvokeParse(in_args1),
00536 "Illegal value '1' specified for flag 'udt_flag'; Use values A, "
00537 "AAA instead");
00538
00539 const char* in_args2[] = {
00540 "testbin",
00541 "--udt_flag",
00542 "AA",
00543 };
00544 EXPECT_DEATH(InvokeParse(in_args2),
00545 "Illegal value 'AA' specified for flag 'udt_flag'; Use values "
00546 "A, AAA instead");
00547 }
00548
00549
00550
00551 TEST_F(ParseTest, TestLegacyFlags) {
00552 const char* in_args1[] = {
00553 "testbin",
00554 "--legacy_int=11",
00555 };
00556 TestParse(in_args1, 1, 1.1, "a", false);
00557
00558 const char* in_args2[] = {
00559 "testbin",
00560 "--legacy_bool",
00561 };
00562 TestParse(in_args2, 1, 1.1, "a", false);
00563
00564 const char* in_args3[] = {
00565 "testbin", "--legacy_int", "22", "--int_flag=2",
00566 "--legacy_bool", "true", "--legacy_str", "--string_flag=qwe",
00567 };
00568 TestParse(in_args3, 2, 1.1, "a", false, 1);
00569 }
00570
00571
00572
00573 TEST_F(ParseTest, TestSimpleValidFlagfile) {
00574 std::string flagfile_flag;
00575
00576 const char* in_args1[] = {
00577 "testbin",
00578 GetFlagfileFlag({{"parse_test.ff1", absl::MakeConstSpan(ff1_data)}},
00579 &flagfile_flag),
00580 };
00581 TestParse(in_args1, -1, 0.1, "q2w2 ", true);
00582
00583 const char* in_args2[] = {
00584 "testbin",
00585 GetFlagfileFlag({{"parse_test.ff2", absl::MakeConstSpan(ff2_data)}},
00586 &flagfile_flag),
00587 };
00588 TestParse(in_args2, 100, 0.1, "q2w2 ", false);
00589 }
00590
00591
00592
00593 TEST_F(ParseTest, TestValidMultiFlagfile) {
00594 std::string flagfile_flag;
00595
00596 const char* in_args1[] = {
00597 "testbin",
00598 GetFlagfileFlag({{"parse_test.ff2", absl::MakeConstSpan(ff2_data)},
00599 {"parse_test.ff1", absl::MakeConstSpan(ff1_data)}},
00600 &flagfile_flag),
00601 };
00602 TestParse(in_args1, -1, 0.1, "q2w2 ", true);
00603 }
00604
00605
00606
00607 TEST_F(ParseTest, TestFlagfileMixedWithRegularFlags) {
00608 std::string flagfile_flag;
00609
00610 const char* in_args1[] = {
00611 "testbin", "--int_flag=3",
00612 GetFlagfileFlag({{"parse_test.ff1", absl::MakeConstSpan(ff1_data)}},
00613 &flagfile_flag),
00614 "-double_flag=0.2"};
00615 TestParse(in_args1, -1, 0.2, "q2w2 ", true);
00616 }
00617
00618
00619
00620 TEST_F(ParseTest, TestFlagfileInFlagfile) {
00621 std::string flagfile_flag;
00622
00623 constexpr const char* const ff3_data[] = {
00624 "--flagfile=$0/parse_test.ff1",
00625 "--flagfile=$0/parse_test.ff2",
00626 };
00627
00628 const char* in_args1[] = {
00629 "testbin",
00630 GetFlagfileFlag({{"parse_test.ff3", absl::MakeConstSpan(ff3_data)}},
00631 &flagfile_flag),
00632 };
00633 TestParse(in_args1, 100, 0.1, "q2w2 ", false);
00634 }
00635
00636
00637
00638 TEST_F(ParseDeathTest, TestInvalidFlagfiles) {
00639 std::string flagfile_flag;
00640
00641 constexpr const char* const ff4_data[] = {
00642 "--unknown_flag=10"
00643 };
00644
00645 const char* in_args1[] = {
00646 "testbin",
00647 GetFlagfileFlag({{"parse_test.ff4",
00648 absl::MakeConstSpan(ff4_data)}}, &flagfile_flag),
00649 };
00650 EXPECT_DEATH(InvokeParse(in_args1),
00651 "Unknown command line flag 'unknown_flag'");
00652
00653 constexpr const char* const ff5_data[] = {
00654 "--int_flag 10",
00655 };
00656
00657 const char* in_args2[] = {
00658 "testbin",
00659 GetFlagfileFlag({{"parse_test.ff5",
00660 absl::MakeConstSpan(ff5_data)}}, &flagfile_flag),
00661 };
00662 EXPECT_DEATH(InvokeParse(in_args2),
00663 "Unknown command line flag 'int_flag 10'");
00664
00665 constexpr const char* const ff6_data[] = {
00666 "--int_flag=10", "--", "arg1", "arg2", "arg3",
00667 };
00668
00669 const char* in_args3[] = {
00670 "testbin",
00671 GetFlagfileFlag({{"parse_test.ff6", absl::MakeConstSpan(ff6_data)}},
00672 &flagfile_flag),
00673 };
00674 EXPECT_DEATH(InvokeParse(in_args3),
00675 "Flagfile can't contain position arguments or --");
00676
00677 const char* in_args4[] = {
00678 "testbin",
00679 "--flagfile=invalid_flag_file",
00680 };
00681 EXPECT_DEATH(InvokeParse(in_args4), "Can't open flagfile invalid_flag_file");
00682
00683 constexpr const char* const ff7_data[] = {
00684 "--int_flag=10",
00685 "*bin*",
00686 "--str_flag=aqsw",
00687 };
00688
00689 const char* in_args5[] = {
00690 "testbin",
00691 GetFlagfileFlag({{"parse_test.ff7", absl::MakeConstSpan(ff7_data)}},
00692 &flagfile_flag),
00693 };
00694 EXPECT_DEATH(InvokeParse(in_args5),
00695 "Unexpected line in the flagfile .*: \\*bin\\*");
00696 }
00697
00698
00699
00700 TEST_F(ParseTest, TestReadingRequiredFlagsFromEnv) {
00701 const char* in_args1[] = {"testbin",
00702 "--fromenv=int_flag,bool_flag,string_flag"};
00703
00704 ScopedSetEnv set_int_flag("FLAGS_int_flag", "33");
00705 ScopedSetEnv set_bool_flag("FLAGS_bool_flag", "True");
00706 ScopedSetEnv set_string_flag("FLAGS_string_flag", "AQ12");
00707
00708 TestParse(in_args1, 33, 1.1, "AQ12", true);
00709 }
00710
00711
00712
00713 TEST_F(ParseDeathTest, TestReadingUnsetRequiredFlagsFromEnv) {
00714 const char* in_args1[] = {"testbin", "--fromenv=int_flag"};
00715
00716 EXPECT_DEATH(InvokeParse(in_args1),
00717 "FLAGS_int_flag not found in environment");
00718 }
00719
00720
00721
00722 TEST_F(ParseDeathTest, TestRecursiveFlagsFromEnv) {
00723 const char* in_args1[] = {"testbin", "--fromenv=tryfromenv"};
00724
00725 ScopedSetEnv set_tryfromenv("FLAGS_tryfromenv", "int_flag");
00726
00727 EXPECT_DEATH(InvokeParse(in_args1), "Infinite recursion on flag tryfromenv");
00728 }
00729
00730
00731
00732 TEST_F(ParseTest, TestReadingOptionalFlagsFromEnv) {
00733 const char* in_args1[] = {
00734 "testbin", "--tryfromenv=int_flag,bool_flag,string_flag,other_flag"};
00735
00736 ScopedSetEnv set_int_flag("FLAGS_int_flag", "17");
00737 ScopedSetEnv set_bool_flag("FLAGS_bool_flag", "Y");
00738
00739 TestParse(in_args1, 17, 1.1, "a", true);
00740 }
00741
00742
00743
00744 TEST_F(ParseTest, TestReadingFlagsFromEnvMoxedWithRegularFlags) {
00745 const char* in_args1[] = {
00746 "testbin",
00747 "--bool_flag=T",
00748 "--tryfromenv=int_flag,bool_flag",
00749 "--int_flag=-21",
00750 };
00751
00752 ScopedSetEnv set_int_flag("FLAGS_int_flag", "-15");
00753 ScopedSetEnv set_bool_flag("FLAGS_bool_flag", "F");
00754
00755 TestParse(in_args1, -21, 1.1, "a", false);
00756 }
00757
00758
00759
00760 TEST_F(ParseTest, TestKeepParsedArgs) {
00761 const char* in_args1[] = {
00762 "testbin", "arg1", "--bool_flag",
00763 "--int_flag=211", "arg2", "--double_flag=1.1",
00764 "--string_flag", "asd", "--",
00765 "arg3", "arg4",
00766 };
00767
00768 auto out_args1 = InvokeParse(in_args1);
00769
00770 EXPECT_THAT(
00771 out_args1,
00772 ElementsAreArray({absl::string_view("testbin"), absl::string_view("arg1"),
00773 absl::string_view("arg2"), absl::string_view("arg3"),
00774 absl::string_view("arg4")}));
00775
00776 auto out_args2 = flags::ParseCommandLineImpl(
00777 11, const_cast<char**>(in_args1), flags::ArgvListAction::kKeepParsedArgs,
00778 flags::UsageFlagsAction::kHandleUsage,
00779 flags::OnUndefinedFlag::kAbortIfUndefined);
00780
00781 EXPECT_THAT(
00782 out_args2,
00783 ElementsAreArray({absl::string_view("testbin"),
00784 absl::string_view("--bool_flag"),
00785 absl::string_view("--int_flag=211"),
00786 absl::string_view("--double_flag=1.1"),
00787 absl::string_view("--string_flag"),
00788 absl::string_view("asd"), absl::string_view("--"),
00789 absl::string_view("arg1"), absl::string_view("arg2"),
00790 absl::string_view("arg3"), absl::string_view("arg4")}));
00791 }
00792
00793
00794
00795 TEST_F(ParseTest, TestIgnoreUndefinedFlags) {
00796 const char* in_args1[] = {
00797 "testbin",
00798 "arg1",
00799 "--undef_flag=aa",
00800 "--int_flag=21",
00801 };
00802
00803 auto out_args1 = flags::ParseCommandLineImpl(
00804 4, const_cast<char**>(in_args1), flags::ArgvListAction::kRemoveParsedArgs,
00805 flags::UsageFlagsAction::kHandleUsage,
00806 flags::OnUndefinedFlag::kIgnoreUndefined);
00807
00808 EXPECT_THAT(out_args1, ElementsAreArray({absl::string_view("testbin"),
00809 absl::string_view("arg1")}));
00810
00811 EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 21);
00812
00813 const char* in_args2[] = {
00814 "testbin",
00815 "arg1",
00816 "--undef_flag=aa",
00817 "--string_flag=AA",
00818 };
00819
00820 auto out_args2 = flags::ParseCommandLineImpl(
00821 4, const_cast<char**>(in_args2), flags::ArgvListAction::kKeepParsedArgs,
00822 flags::UsageFlagsAction::kHandleUsage,
00823 flags::OnUndefinedFlag::kIgnoreUndefined);
00824
00825 EXPECT_THAT(
00826 out_args2,
00827 ElementsAreArray(
00828 {absl::string_view("testbin"), absl::string_view("--undef_flag=aa"),
00829 absl::string_view("--string_flag=AA"), absl::string_view("arg1")}));
00830
00831 EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), "AA");
00832 }
00833
00834
00835
00836 TEST_F(ParseDeathTest, TestHelpFlagHandling) {
00837 const char* in_args1[] = {
00838 "testbin",
00839 "--help",
00840 };
00841
00842 EXPECT_EXIT(InvokeParse(in_args1), testing::ExitedWithCode(1), "");
00843
00844 const char* in_args2[] = {
00845 "testbin",
00846 "--help",
00847 "--int_flag=3",
00848 };
00849
00850 auto out_args2 = flags::ParseCommandLineImpl(
00851 3, const_cast<char**>(in_args2), flags::ArgvListAction::kRemoveParsedArgs,
00852 flags::UsageFlagsAction::kIgnoreUsage,
00853 flags::OnUndefinedFlag::kAbortIfUndefined);
00854
00855 EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 3);
00856 }
00857
00858 }