parse_test.cc
Go to the documentation of this file.
1 //
2 // Copyright 2019 The Abseil Authors.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // https://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 
16 #include "absl/flags/parse.h"
17 
18 #include <fstream>
19 
20 #include "gmock/gmock.h"
21 #include "gtest/gtest.h"
24 #include "absl/flags/flag.h"
25 #include "absl/strings/str_cat.h"
27 #include "absl/types/span.h"
28 
29 #ifdef _WIN32
30 #include <windows.h>
31 #endif
32 
33 namespace {
34 
36 
37 struct UDT {
38  UDT() = default;
39  UDT(const UDT&) = default;
40  UDT(int v) : value(v) {} // NOLINT
41 
42  int value;
43 };
44 
45 bool AbslParseFlag(absl::string_view in, UDT* udt, std::string* err) {
46  if (in == "A") {
47  udt->value = 1;
48  return true;
49  }
50  if (in == "AAA") {
51  udt->value = 10;
52  return true;
53  }
54 
55  *err = "Use values A, AAA instead";
56  return false;
57 }
58 std::string AbslUnparseFlag(const UDT& udt) {
59  return udt.value == 1 ? "A" : "AAA";
60 }
61 
62 std::string GetTestTmpDirEnvVar(const char* const env_var_name) {
63 #ifdef _WIN32
64  char buf[MAX_PATH];
65  auto get_res = GetEnvironmentVariableA(env_var_name, buf, sizeof(buf));
66  if (get_res >= sizeof(buf) || get_res == 0) {
67  return "";
68  }
69 
70  return std::string(buf, get_res);
71 #else
72  const char* val = ::getenv(env_var_name);
73  if (val == nullptr) {
74  return "";
75  }
76 
77  return val;
78 #endif
79 }
80 
81 const std::string& GetTestTempDir() {
82  static std::string* temp_dir_name = []() -> std::string* {
83  std::string* res = new std::string(GetTestTmpDirEnvVar("TEST_TMPDIR"));
84 
85  if (res->empty()) {
86  *res = GetTestTmpDirEnvVar("TMPDIR");
87  }
88 
89  if (res->empty()) {
90 #ifdef _WIN32
91  char temp_path_buffer[MAX_PATH];
92 
93  auto len = GetTempPathA(MAX_PATH, temp_path_buffer);
94  if (len < MAX_PATH && len != 0) {
95  std::string temp_dir_name = absl::StrCat(
96  temp_path_buffer, "\\parse_test.", GetCurrentProcessId());
97  if (CreateDirectoryA(temp_dir_name.c_str(), nullptr)) {
98  *res = temp_dir_name;
99  }
100  }
101 #else
102  char temp_dir_template[] = "/tmp/parse_test.XXXXXX";
103  if (auto* unique_name = ::mkdtemp(temp_dir_template)) {
104  *res = unique_name;
105  }
106 #endif
107 
108  if (res->empty()) {
109  ABSL_INTERNAL_LOG(FATAL,
110  "Failed to make temporary directory for data files");
111  }
112  }
113 
114 #ifdef _WIN32
115  *res += "\\";
116 #else
117  *res += "/";
118 #endif
119 
120  return res;
121  }();
122 
123  return *temp_dir_name;
124 }
125 
126 struct FlagfileData {
127  const absl::string_view file_name;
128  const absl::Span<const char* const> file_lines;
129 };
130 
131 // clang-format off
132 constexpr const char* const ff1_data[] = {
133  "# comment ",
134  " # comment ",
135  "",
136  " ",
137  "--int_flag=-1",
138  " --string_flag=q2w2 ",
139  " ## ",
140  " --double_flag=0.1",
141  "--bool_flag=Y "
142 };
143 
144 constexpr const char* const ff2_data[] = {
145  "# Setting legacy flag",
146  "--legacy_int=1111",
147  "--legacy_bool",
148  "--nobool_flag",
149  "--legacy_str=aqsw",
150  "--int_flag=100",
151  " ## ============="
152 };
153 // clang-format on
154 
155 // Builds flagfile flag in the flagfile_flag buffer and returns it. This
156 // function also creates a temporary flagfile based on FlagfileData input.
157 // We create a flagfile in a temporary directory with the name specified in
158 // FlagfileData and populate it with lines specifed in FlagfileData. If $0 is
159 // referenced in any of the lines in FlagfileData they are replaced with
160 // temporary directory location. This way we can test inclusion of one flagfile
161 // from another flagfile.
162 const char* GetFlagfileFlag(const std::vector<FlagfileData>& ffd,
163  std::string* flagfile_flag) {
164  *flagfile_flag = "--flagfile=";
165  absl::string_view separator;
166  for (const auto& flagfile_data : ffd) {
167  std::string flagfile_name =
168  absl::StrCat(GetTestTempDir(), flagfile_data.file_name);
169 
170  std::ofstream flagfile_out(flagfile_name);
171  for (auto line : flagfile_data.file_lines) {
172  flagfile_out << absl::Substitute(line, GetTestTempDir()) << "\n";
173  }
174 
175  absl::StrAppend(flagfile_flag, separator, flagfile_name);
176  separator = ",";
177  }
178 
179  return flagfile_flag->c_str();
180 }
181 
182 } // namespace
183 
184 ABSL_FLAG(int, int_flag, 1, "");
185 ABSL_FLAG(double, double_flag, 1.1, "");
186 ABSL_FLAG(std::string, string_flag, "a", "");
187 ABSL_FLAG(bool, bool_flag, false, "");
188 ABSL_FLAG(UDT, udt_flag, -1, "");
189 ABSL_RETIRED_FLAG(int, legacy_int, 1, "");
190 ABSL_RETIRED_FLAG(bool, legacy_bool, false, "");
191 ABSL_RETIRED_FLAG(std::string, legacy_str, "l", "");
192 
193 namespace {
194 
195 namespace flags = absl::flags_internal;
196 using testing::ElementsAreArray;
197 
198 class ParseTest : public testing::Test {
199  private:
200  flags::FlagSaver flag_saver_;
201 };
202 
203 // --------------------------------------------------------------------
204 
205 template <int N>
206 std::vector<char*> InvokeParse(const char* (&in_argv)[N]) {
207  return absl::ParseCommandLine(N, const_cast<char**>(in_argv));
208 }
209 
210 // --------------------------------------------------------------------
211 
212 template <int N>
213 void TestParse(const char* (&in_argv)[N], int int_flag_value,
214  double double_flag_val, absl::string_view string_flag_val,
215  bool bool_flag_val, int exp_position_args = 0) {
216  auto out_args = InvokeParse(in_argv);
217 
218  EXPECT_EQ(out_args.size(), 1 + exp_position_args);
219  EXPECT_STREQ(out_args[0], "testbin");
220 
221  EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), int_flag_value);
222  EXPECT_NEAR(absl::GetFlag(FLAGS_double_flag), double_flag_val, 0.0001);
223  EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), string_flag_val);
224  EXPECT_EQ(absl::GetFlag(FLAGS_bool_flag), bool_flag_val);
225 }
226 
227 // --------------------------------------------------------------------
228 
229 TEST_F(ParseTest, TestEmptyArgv) {
230  const char* in_argv[] = {"testbin"};
231 
232  auto out_args = InvokeParse(in_argv);
233 
234  EXPECT_EQ(out_args.size(), 1);
235  EXPECT_STREQ(out_args[0], "testbin");
236 }
237 
238 // --------------------------------------------------------------------
239 
240 TEST_F(ParseTest, TestValidIntArg) {
241  const char* in_args1[] = {
242  "testbin",
243  "--int_flag=10",
244  };
245  TestParse(in_args1, 10, 1.1, "a", false);
246 
247  const char* in_args2[] = {
248  "testbin",
249  "-int_flag=020",
250  };
251  TestParse(in_args2, 20, 1.1, "a", false);
252 
253  const char* in_args3[] = {
254  "testbin",
255  "--int_flag",
256  "-30",
257  };
258  TestParse(in_args3, -30, 1.1, "a", false);
259 
260  const char* in_args4[] = {
261  "testbin",
262  "-int_flag",
263  "0x21",
264  };
265  TestParse(in_args4, 33, 1.1, "a", false);
266 }
267 
268 // --------------------------------------------------------------------
269 
270 TEST_F(ParseTest, TestValidDoubleArg) {
271  const char* in_args1[] = {
272  "testbin",
273  "--double_flag=2.3",
274  };
275  TestParse(in_args1, 1, 2.3, "a", false);
276 
277  const char* in_args2[] = {
278  "testbin",
279  "--double_flag=0x1.2",
280  };
281  TestParse(in_args2, 1, 1.125, "a", false);
282 
283  const char* in_args3[] = {
284  "testbin",
285  "--double_flag",
286  "99.7",
287  };
288  TestParse(in_args3, 1, 99.7, "a", false);
289 
290  const char* in_args4[] = {
291  "testbin",
292  "--double_flag",
293  "0x20.1",
294  };
295  TestParse(in_args4, 1, 32.0625, "a", false);
296 }
297 
298 // --------------------------------------------------------------------
299 
300 TEST_F(ParseTest, TestValidStringArg) {
301  const char* in_args1[] = {
302  "testbin",
303  "--string_flag=aqswde",
304  };
305  TestParse(in_args1, 1, 1.1, "aqswde", false);
306 
307  const char* in_args2[] = {
308  "testbin",
309  "-string_flag=a=b=c",
310  };
311  TestParse(in_args2, 1, 1.1, "a=b=c", false);
312 
313  const char* in_args3[] = {
314  "testbin",
315  "--string_flag",
316  "zaxscd",
317  };
318  TestParse(in_args3, 1, 1.1, "zaxscd", false);
319 
320  const char* in_args4[] = {
321  "testbin",
322  "-string_flag",
323  "--int_flag",
324  };
325  TestParse(in_args4, 1, 1.1, "--int_flag", false);
326 
327  const char* in_args5[] = {
328  "testbin",
329  "--string_flag",
330  "--no_a_flag=11",
331  };
332  TestParse(in_args5, 1, 1.1, "--no_a_flag=11", false);
333 }
334 
335 // --------------------------------------------------------------------
336 
337 TEST_F(ParseTest, TestValidBoolArg) {
338  const char* in_args1[] = {
339  "testbin",
340  "--bool_flag",
341  };
342  TestParse(in_args1, 1, 1.1, "a", true);
343 
344  const char* in_args2[] = {
345  "testbin",
346  "--nobool_flag",
347  };
348  TestParse(in_args2, 1, 1.1, "a", false);
349 
350  const char* in_args3[] = {
351  "testbin",
352  "--bool_flag=true",
353  };
354  TestParse(in_args3, 1, 1.1, "a", true);
355 
356  const char* in_args4[] = {
357  "testbin",
358  "-bool_flag=false",
359  };
360  TestParse(in_args4, 1, 1.1, "a", false);
361 }
362 
363 // --------------------------------------------------------------------
364 
365 TEST_F(ParseTest, TestValidUDTArg) {
366  const char* in_args1[] = {
367  "testbin",
368  "--udt_flag=A",
369  };
370  InvokeParse(in_args1);
371 
372  EXPECT_EQ(absl::GetFlag(FLAGS_udt_flag).value, 1);
373 
374  const char* in_args2[] = {"testbin", "--udt_flag", "AAA"};
375  InvokeParse(in_args2);
376 
377  EXPECT_EQ(absl::GetFlag(FLAGS_udt_flag).value, 10);
378 }
379 
380 // --------------------------------------------------------------------
381 
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",
386  };
387  TestParse(in_args1, 2, 0.1, "asd", true);
388 
389  const char* in_args2[] = {
390  "testbin", "--string_flag=", "--nobool_flag", "--int_flag",
391  "-011", "--double_flag", "-1e-2",
392  };
393  TestParse(in_args2, -11, -0.01, "", false);
394 
395  const char* in_args3[] = {
396  "testbin", "--int_flag", "-0", "--string_flag", "\"\"",
397  "--bool_flag=true", "--double_flag=1e18",
398  };
399  TestParse(in_args3, 0, 1e18, "\"\"", true);
400 }
401 
402 // --------------------------------------------------------------------
403 
404 TEST_F(ParseTest, TestPositionalArgs) {
405  const char* in_args1[] = {
406  "testbin",
407  "p1",
408  "p2",
409  };
410  TestParse(in_args1, 1, 1.1, "a", false, 2);
411 
412  auto out_args1 = InvokeParse(in_args1);
413 
414  EXPECT_STREQ(out_args1[1], "p1");
415  EXPECT_STREQ(out_args1[2], "p2");
416 
417  const char* in_args2[] = {
418  "testbin",
419  "--int_flag=2",
420  "p1",
421  };
422  TestParse(in_args2, 2, 1.1, "a", false, 1);
423 
424  auto out_args2 = InvokeParse(in_args2);
425 
426  EXPECT_STREQ(out_args2[1], "p1");
427 
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);
431 
432  auto out_args3 = InvokeParse(in_args3);
433 
434  EXPECT_STREQ(out_args3[1], "p1");
435  EXPECT_STREQ(out_args3[2], "p2");
436  EXPECT_STREQ(out_args3[3], "true");
437 
438  const char* in_args4[] = {
439  "testbin",
440  "--",
441  "p1",
442  "p2",
443  };
444  TestParse(in_args4, 3, 1.1, "a", true, 2);
445 
446  auto out_args4 = InvokeParse(in_args4);
447 
448  EXPECT_STREQ(out_args4[1], "p1");
449  EXPECT_STREQ(out_args4[2], "p2");
450 
451  const char* in_args5[] = {
452  "testbin", "p1", "--int_flag=4", "--", "--bool_flag", "false", "p2",
453  };
454  TestParse(in_args5, 4, 1.1, "a", true, 4);
455 
456  auto out_args5 = InvokeParse(in_args5);
457 
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");
462 }
463 
464 // --------------------------------------------------------------------
465 
466 using ParseDeathTest = ParseTest;
467 
468 TEST_F(ParseDeathTest, TestUndefinedArg) {
469  const char* in_args1[] = {
470  "testbin",
471  "--undefined_flag",
472  };
473  EXPECT_DEATH(InvokeParse(in_args1),
474  "Unknown command line flag 'undefined_flag'");
475 
476  const char* in_args2[] = {
477  "testbin",
478  "--noprefixed_flag",
479  };
480  EXPECT_DEATH(InvokeParse(in_args2),
481  "Unknown command line flag 'noprefixed_flag'");
482 
483  const char* in_args3[] = {
484  "testbin",
485  "--Int_flag=1",
486  };
487  EXPECT_DEATH(InvokeParse(in_args3), "Unknown command line flag 'Int_flag'");
488 }
489 
490 // --------------------------------------------------------------------
491 
492 TEST_F(ParseDeathTest, TestInvalidBoolFlagFormat) {
493  const char* in_args1[] = {
494  "testbin",
495  "--bool_flag=",
496  };
497  EXPECT_DEATH(
498  InvokeParse(in_args1),
499  "Missing the value after assignment for the boolean flag 'bool_flag'");
500 
501  const char* in_args2[] = {
502  "testbin",
503  "--nobool_flag=true",
504  };
505  EXPECT_DEATH(InvokeParse(in_args2),
506  "Negative form with assignment is not valid for the boolean "
507  "flag 'bool_flag'");
508 }
509 
510 // --------------------------------------------------------------------
511 
512 TEST_F(ParseDeathTest, TestInvalidNonBoolFlagFormat) {
513  const char* in_args1[] = {
514  "testbin",
515  "--nostring_flag",
516  };
517  EXPECT_DEATH(InvokeParse(in_args1),
518  "Negative form is not valid for the flag 'string_flag'");
519 
520  const char* in_args2[] = {
521  "testbin",
522  "--int_flag",
523  };
524  EXPECT_DEATH(InvokeParse(in_args2),
525  "Missing the value for the flag 'int_flag'");
526 }
527 
528 // --------------------------------------------------------------------
529 
530 TEST_F(ParseDeathTest, TestInvalidUDTFlagFormat) {
531  const char* in_args1[] = {
532  "testbin",
533  "--udt_flag=1",
534  };
535  EXPECT_DEATH(InvokeParse(in_args1),
536  "Illegal value '1' specified for flag 'udt_flag'; Use values A, "
537  "AAA instead");
538 
539  const char* in_args2[] = {
540  "testbin",
541  "--udt_flag",
542  "AA",
543  };
544  EXPECT_DEATH(InvokeParse(in_args2),
545  "Illegal value 'AA' specified for flag 'udt_flag'; Use values "
546  "A, AAA instead");
547 }
548 
549 // --------------------------------------------------------------------
550 
551 TEST_F(ParseTest, TestLegacyFlags) {
552  const char* in_args1[] = {
553  "testbin",
554  "--legacy_int=11",
555  };
556  TestParse(in_args1, 1, 1.1, "a", false);
557 
558  const char* in_args2[] = {
559  "testbin",
560  "--legacy_bool",
561  };
562  TestParse(in_args2, 1, 1.1, "a", false);
563 
564  const char* in_args3[] = {
565  "testbin", "--legacy_int", "22", "--int_flag=2",
566  "--legacy_bool", "true", "--legacy_str", "--string_flag=qwe",
567  };
568  TestParse(in_args3, 2, 1.1, "a", false, 1);
569 }
570 
571 // --------------------------------------------------------------------
572 
573 TEST_F(ParseTest, TestSimpleValidFlagfile) {
574  std::string flagfile_flag;
575 
576  const char* in_args1[] = {
577  "testbin",
578  GetFlagfileFlag({{"parse_test.ff1", absl::MakeConstSpan(ff1_data)}},
579  &flagfile_flag),
580  };
581  TestParse(in_args1, -1, 0.1, "q2w2 ", true);
582 
583  const char* in_args2[] = {
584  "testbin",
585  GetFlagfileFlag({{"parse_test.ff2", absl::MakeConstSpan(ff2_data)}},
586  &flagfile_flag),
587  };
588  TestParse(in_args2, 100, 0.1, "q2w2 ", false);
589 }
590 
591 // --------------------------------------------------------------------
592 
593 TEST_F(ParseTest, TestValidMultiFlagfile) {
594  std::string flagfile_flag;
595 
596  const char* in_args1[] = {
597  "testbin",
598  GetFlagfileFlag({{"parse_test.ff2", absl::MakeConstSpan(ff2_data)},
599  {"parse_test.ff1", absl::MakeConstSpan(ff1_data)}},
600  &flagfile_flag),
601  };
602  TestParse(in_args1, -1, 0.1, "q2w2 ", true);
603 }
604 
605 // --------------------------------------------------------------------
606 
607 TEST_F(ParseTest, TestFlagfileMixedWithRegularFlags) {
608  std::string flagfile_flag;
609 
610  const char* in_args1[] = {
611  "testbin", "--int_flag=3",
612  GetFlagfileFlag({{"parse_test.ff1", absl::MakeConstSpan(ff1_data)}},
613  &flagfile_flag),
614  "-double_flag=0.2"};
615  TestParse(in_args1, -1, 0.2, "q2w2 ", true);
616 }
617 
618 // --------------------------------------------------------------------
619 
620 TEST_F(ParseTest, TestFlagfileInFlagfile) {
621  std::string flagfile_flag;
622 
623  constexpr const char* const ff3_data[] = {
624  "--flagfile=$0/parse_test.ff1",
625  "--flagfile=$0/parse_test.ff2",
626  };
627 
628  const char* in_args1[] = {
629  "testbin",
630  GetFlagfileFlag({{"parse_test.ff3", absl::MakeConstSpan(ff3_data)}},
631  &flagfile_flag),
632  };
633  TestParse(in_args1, 100, 0.1, "q2w2 ", false);
634 }
635 
636 // --------------------------------------------------------------------
637 
638 TEST_F(ParseDeathTest, TestInvalidFlagfiles) {
639  std::string flagfile_flag;
640 
641  constexpr const char* const ff4_data[] = {
642  "--unknown_flag=10"
643  };
644 
645  const char* in_args1[] = {
646  "testbin",
647  GetFlagfileFlag({{"parse_test.ff4",
648  absl::MakeConstSpan(ff4_data)}}, &flagfile_flag),
649  };
650  EXPECT_DEATH(InvokeParse(in_args1),
651  "Unknown command line flag 'unknown_flag'");
652 
653  constexpr const char* const ff5_data[] = {
654  "--int_flag 10",
655  };
656 
657  const char* in_args2[] = {
658  "testbin",
659  GetFlagfileFlag({{"parse_test.ff5",
660  absl::MakeConstSpan(ff5_data)}}, &flagfile_flag),
661  };
662  EXPECT_DEATH(InvokeParse(in_args2),
663  "Unknown command line flag 'int_flag 10'");
664 
665  constexpr const char* const ff6_data[] = {
666  "--int_flag=10", "--", "arg1", "arg2", "arg3",
667  };
668 
669  const char* in_args3[] = {
670  "testbin",
671  GetFlagfileFlag({{"parse_test.ff6", absl::MakeConstSpan(ff6_data)}},
672  &flagfile_flag),
673  };
674  EXPECT_DEATH(InvokeParse(in_args3),
675  "Flagfile can't contain position arguments or --");
676 
677  const char* in_args4[] = {
678  "testbin",
679  "--flagfile=invalid_flag_file",
680  };
681  EXPECT_DEATH(InvokeParse(in_args4), "Can't open flagfile invalid_flag_file");
682 
683  constexpr const char* const ff7_data[] = {
684  "--int_flag=10",
685  "*bin*",
686  "--str_flag=aqsw",
687  };
688 
689  const char* in_args5[] = {
690  "testbin",
691  GetFlagfileFlag({{"parse_test.ff7", absl::MakeConstSpan(ff7_data)}},
692  &flagfile_flag),
693  };
694  EXPECT_DEATH(InvokeParse(in_args5),
695  "Unexpected line in the flagfile .*: \\*bin\\*");
696 }
697 
698 // --------------------------------------------------------------------
699 
700 TEST_F(ParseTest, TestReadingRequiredFlagsFromEnv) {
701  const char* in_args1[] = {"testbin",
702  "--fromenv=int_flag,bool_flag,string_flag"};
703 
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");
707 
708  TestParse(in_args1, 33, 1.1, "AQ12", true);
709 }
710 
711 // --------------------------------------------------------------------
712 
713 TEST_F(ParseDeathTest, TestReadingUnsetRequiredFlagsFromEnv) {
714  const char* in_args1[] = {"testbin", "--fromenv=int_flag"};
715 
716  EXPECT_DEATH(InvokeParse(in_args1),
717  "FLAGS_int_flag not found in environment");
718 }
719 
720 // --------------------------------------------------------------------
721 
722 TEST_F(ParseDeathTest, TestRecursiveFlagsFromEnv) {
723  const char* in_args1[] = {"testbin", "--fromenv=tryfromenv"};
724 
725  ScopedSetEnv set_tryfromenv("FLAGS_tryfromenv", "int_flag");
726 
727  EXPECT_DEATH(InvokeParse(in_args1), "Infinite recursion on flag tryfromenv");
728 }
729 
730 // --------------------------------------------------------------------
731 
732 TEST_F(ParseTest, TestReadingOptionalFlagsFromEnv) {
733  const char* in_args1[] = {
734  "testbin", "--tryfromenv=int_flag,bool_flag,string_flag,other_flag"};
735 
736  ScopedSetEnv set_int_flag("FLAGS_int_flag", "17");
737  ScopedSetEnv set_bool_flag("FLAGS_bool_flag", "Y");
738 
739  TestParse(in_args1, 17, 1.1, "a", true);
740 }
741 
742 // --------------------------------------------------------------------
743 
744 TEST_F(ParseTest, TestReadingFlagsFromEnvMoxedWithRegularFlags) {
745  const char* in_args1[] = {
746  "testbin",
747  "--bool_flag=T",
748  "--tryfromenv=int_flag,bool_flag",
749  "--int_flag=-21",
750  };
751 
752  ScopedSetEnv set_int_flag("FLAGS_int_flag", "-15");
753  ScopedSetEnv set_bool_flag("FLAGS_bool_flag", "F");
754 
755  TestParse(in_args1, -21, 1.1, "a", false);
756 }
757 
758 // --------------------------------------------------------------------
759 
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", "--",
765  "arg3", "arg4",
766  };
767 
768  auto out_args1 = InvokeParse(in_args1);
769 
770  EXPECT_THAT(
771  out_args1,
772  ElementsAreArray({absl::string_view("testbin"), absl::string_view("arg1"),
773  absl::string_view("arg2"), absl::string_view("arg3"),
774  absl::string_view("arg4")}));
775 
776  auto out_args2 = flags::ParseCommandLineImpl(
777  11, const_cast<char**>(in_args1), flags::ArgvListAction::kKeepParsedArgs,
778  flags::UsageFlagsAction::kHandleUsage,
779  flags::OnUndefinedFlag::kAbortIfUndefined);
780 
781  EXPECT_THAT(
782  out_args2,
783  ElementsAreArray({absl::string_view("testbin"),
784  absl::string_view("--bool_flag"),
785  absl::string_view("--int_flag=211"),
786  absl::string_view("--double_flag=1.1"),
787  absl::string_view("--string_flag"),
788  absl::string_view("asd"), absl::string_view("--"),
789  absl::string_view("arg1"), absl::string_view("arg2"),
790  absl::string_view("arg3"), absl::string_view("arg4")}));
791 }
792 
793 // --------------------------------------------------------------------
794 
795 TEST_F(ParseTest, TestIgnoreUndefinedFlags) {
796  const char* in_args1[] = {
797  "testbin",
798  "arg1",
799  "--undef_flag=aa",
800  "--int_flag=21",
801  };
802 
803  auto out_args1 = flags::ParseCommandLineImpl(
804  4, const_cast<char**>(in_args1), flags::ArgvListAction::kRemoveParsedArgs,
805  flags::UsageFlagsAction::kHandleUsage,
806  flags::OnUndefinedFlag::kIgnoreUndefined);
807 
808  EXPECT_THAT(out_args1, ElementsAreArray({absl::string_view("testbin"),
809  absl::string_view("arg1")}));
810 
811  EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 21);
812 
813  const char* in_args2[] = {
814  "testbin",
815  "arg1",
816  "--undef_flag=aa",
817  "--string_flag=AA",
818  };
819 
820  auto out_args2 = flags::ParseCommandLineImpl(
821  4, const_cast<char**>(in_args2), flags::ArgvListAction::kKeepParsedArgs,
822  flags::UsageFlagsAction::kHandleUsage,
823  flags::OnUndefinedFlag::kIgnoreUndefined);
824 
825  EXPECT_THAT(
826  out_args2,
827  ElementsAreArray(
828  {absl::string_view("testbin"), absl::string_view("--undef_flag=aa"),
829  absl::string_view("--string_flag=AA"), absl::string_view("arg1")}));
830 
831  EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), "AA");
832 }
833 
834 // --------------------------------------------------------------------
835 
836 TEST_F(ParseDeathTest, TestHelpFlagHandling) {
837  const char* in_args1[] = {
838  "testbin",
839  "--help",
840  };
841 
842  EXPECT_EXIT(InvokeParse(in_args1), testing::ExitedWithCode(1), "");
843 
844  const char* in_args2[] = {
845  "testbin",
846  "--help",
847  "--int_flag=3",
848  };
849 
850  auto out_args2 = flags::ParseCommandLineImpl(
851  3, const_cast<char**>(in_args2), flags::ArgvListAction::kRemoveParsedArgs,
852  flags::UsageFlagsAction::kIgnoreUsage,
853  flags::OnUndefinedFlag::kAbortIfUndefined);
854 
855  EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 3);
856 }
857 
858 } // namespace
int v
Definition: variant_test.cc:81
std::vector< char * > ParseCommandLine(int argc, char *argv[])
Definition: parse.cc:755
std::string AbslUnparseFlag(const UDT &)
Definition: usage_test.cc:42
void StrAppend(std::string *dest, const AlphaNum &a)
Definition: str_cat.cc:193
ABSL_RETIRED_FLAG(int, legacy_int, 1, "")
std::string StrCat(const AlphaNum &a, const AlphaNum &b)
Definition: str_cat.cc:98
UDT()=default
std::vector< char * > ParseCommandLineImpl(int argc, char *argv[], ArgvListAction arg_list_act, UsageFlagsAction usage_flag_act, OnUndefinedFlag on_undef_flag)
Definition: parse.cc:575
char buf[N]
#define ABSL_INTERNAL_LOG(severity, message)
Definition: raw_logging.h:73
size_t value
TEST_F(GraphCyclesTest, NoCycle)
constexpr Span< const T > MakeConstSpan(T *ptr, size_t size) noexcept
Definition: span.h:692
bool AbslParseFlag(absl::string_view, UDT *, std::string *)
Definition: usage_test.cc:41
T GetFlag(const absl::Flag< T > &flag)
Definition: flag.h:86
ABSL_FLAG(int, int_flag, 1, "")
ABSL_MUST_USE_RESULT std::string Substitute(absl::string_view format)
Definition: substitute.h:473
const char * in
Definition: parser_test.cc:350


abseil_cpp
Author(s):
autogenerated on Mon Feb 28 2022 21:31:19