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


grpc
Author(s):
autogenerated on Fri May 16 2025 02:59:39