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/internal/commandlineflag.h"
17 
18 #include <memory>
19 #include <string>
20 
21 #include "gtest/gtest.h"
22 #include "absl/flags/flag.h"
23 #include "absl/flags/internal/registry.h"
24 #include "absl/flags/usage_config.h"
25 #include "absl/memory/memory.h"
26 #include "absl/strings/match.h"
27 #include "absl/strings/str_cat.h"
28 #include "absl/strings/string_view.h"
29 
30 ABSL_FLAG(int, int_flag, 201, "int_flag help");
31 ABSL_FLAG(std::string, string_flag, "dflt",
32           absl::StrCat("string_flag", " help"));
33 ABSL_RETIRED_FLAG(bool, bool_retired_flag, false, "bool_retired_flag help");
34 
35 namespace {
36 
37 namespace flags = absl::flags_internal;
38 
39 class CommandLineFlagTest : public testing::Test {
40  protected:
SetUpTestSuite()41   static void SetUpTestSuite() {
42     // Install a function to normalize filenames before this test is run.
43     absl::FlagsUsageConfig default_config;
44     default_config.normalize_filename = &CommandLineFlagTest::NormalizeFileName;
45     absl::SetFlagsUsageConfig(default_config);
46   }
47 
SetUp()48   void SetUp() override { flag_saver_ = absl::make_unique<flags::FlagSaver>(); }
TearDown()49   void TearDown() override { flag_saver_.reset(); }
50 
51  private:
NormalizeFileName(absl::string_view fname)52   static std::string NormalizeFileName(absl::string_view fname) {
53 #ifdef _WIN32
54     std::string normalized(fname);
55     std::replace(normalized.begin(), normalized.end(), '\\', '/');
56     fname = normalized;
57 #endif
58     return std::string(fname);
59   }
60 
61   std::unique_ptr<flags::FlagSaver> flag_saver_;
62 };
63 
TEST_F(CommandLineFlagTest,TestAttributesAccessMethods)64 TEST_F(CommandLineFlagTest, TestAttributesAccessMethods) {
65   auto* flag_01 = flags::FindCommandLineFlag("int_flag");
66 
67   ASSERT_TRUE(flag_01);
68   EXPECT_EQ(flag_01->Name(), "int_flag");
69   EXPECT_EQ(flag_01->Help(), "int_flag help");
70   EXPECT_EQ(flag_01->Typename(), "");
71   EXPECT_TRUE(!flag_01->IsRetired());
72   EXPECT_TRUE(flag_01->IsOfType<int>());
73   EXPECT_TRUE(
74       absl::EndsWith(flag_01->Filename(),
75                      "absl/flags/internal/commandlineflag_test.cc"))
76       << flag_01->Filename();
77 
78   auto* flag_02 = flags::FindCommandLineFlag("string_flag");
79 
80   ASSERT_TRUE(flag_02);
81   EXPECT_EQ(flag_02->Name(), "string_flag");
82   EXPECT_EQ(flag_02->Help(), "string_flag help");
83   EXPECT_EQ(flag_02->Typename(), "");
84   EXPECT_TRUE(!flag_02->IsRetired());
85   EXPECT_TRUE(flag_02->IsOfType<std::string>());
86   EXPECT_TRUE(
87       absl::EndsWith(flag_02->Filename(),
88                      "absl/flags/internal/commandlineflag_test.cc"))
89       << flag_02->Filename();
90 
91   auto* flag_03 = flags::FindRetiredFlag("bool_retired_flag");
92 
93   ASSERT_TRUE(flag_03);
94   EXPECT_EQ(flag_03->Name(), "bool_retired_flag");
95   EXPECT_EQ(flag_03->Help(), "");
96   EXPECT_EQ(flag_03->Typename(), "");
97   EXPECT_TRUE(flag_03->IsRetired());
98   EXPECT_TRUE(flag_03->IsOfType<bool>());
99   EXPECT_EQ(flag_03->Filename(), "RETIRED");
100 }
101 
102 // --------------------------------------------------------------------
103 
TEST_F(CommandLineFlagTest,TestValueAccessMethods)104 TEST_F(CommandLineFlagTest, TestValueAccessMethods) {
105   absl::SetFlag(&FLAGS_int_flag, 301);
106   auto* flag_01 = flags::FindCommandLineFlag("int_flag");
107 
108   ASSERT_TRUE(flag_01);
109   EXPECT_EQ(flag_01->CurrentValue(), "301");
110   EXPECT_EQ(flag_01->DefaultValue(), "201");
111 
112   absl::SetFlag(&FLAGS_string_flag, "new_str_value");
113   auto* flag_02 = flags::FindCommandLineFlag("string_flag");
114 
115   ASSERT_TRUE(flag_02);
116   EXPECT_EQ(flag_02->CurrentValue(), "new_str_value");
117   EXPECT_EQ(flag_02->DefaultValue(), "dflt");
118 }
119 
120 // --------------------------------------------------------------------
121 
TEST_F(CommandLineFlagTest,TestSetFromStringCurrentValue)122 TEST_F(CommandLineFlagTest, TestSetFromStringCurrentValue) {
123   std::string err;
124 
125   auto* flag_01 = flags::FindCommandLineFlag("int_flag");
126   EXPECT_FALSE(flag_01->IsSpecifiedOnCommandLine());
127 
128   EXPECT_TRUE(flag_01->SetFromString("11", flags::SET_FLAGS_VALUE,
129                                      flags::kProgrammaticChange, &err));
130   EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 11);
131   EXPECT_FALSE(flag_01->IsSpecifiedOnCommandLine());
132 
133   EXPECT_TRUE(flag_01->SetFromString("-123", flags::SET_FLAGS_VALUE,
134                                      flags::kProgrammaticChange, &err));
135   EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), -123);
136   EXPECT_FALSE(flag_01->IsSpecifiedOnCommandLine());
137 
138   EXPECT_TRUE(!flag_01->SetFromString("xyz", flags::SET_FLAGS_VALUE,
139                                       flags::kProgrammaticChange, &err));
140   EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), -123);
141   EXPECT_EQ(err, "Illegal value 'xyz' specified for flag 'int_flag'");
142   EXPECT_FALSE(flag_01->IsSpecifiedOnCommandLine());
143 
144   EXPECT_TRUE(!flag_01->SetFromString("A1", flags::SET_FLAGS_VALUE,
145                                       flags::kProgrammaticChange, &err));
146   EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), -123);
147   EXPECT_EQ(err, "Illegal value 'A1' specified for flag 'int_flag'");
148   EXPECT_FALSE(flag_01->IsSpecifiedOnCommandLine());
149 
150   EXPECT_TRUE(flag_01->SetFromString("0x10", flags::SET_FLAGS_VALUE,
151                                      flags::kProgrammaticChange, &err));
152   EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 16);
153   EXPECT_FALSE(flag_01->IsSpecifiedOnCommandLine());
154 
155   EXPECT_TRUE(flag_01->SetFromString("011", flags::SET_FLAGS_VALUE,
156                                      flags::kCommandLine, &err));
157   EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 11);
158   EXPECT_TRUE(flag_01->IsSpecifiedOnCommandLine());
159 
160   EXPECT_TRUE(!flag_01->SetFromString("", flags::SET_FLAGS_VALUE,
161                                       flags::kProgrammaticChange, &err));
162   EXPECT_EQ(err, "Illegal value '' specified for flag 'int_flag'");
163 
164   auto* flag_02 = flags::FindCommandLineFlag("string_flag");
165   EXPECT_TRUE(flag_02->SetFromString("xyz", flags::SET_FLAGS_VALUE,
166                                      flags::kProgrammaticChange, &err));
167   EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), "xyz");
168 
169   EXPECT_TRUE(flag_02->SetFromString("", flags::SET_FLAGS_VALUE,
170                                      flags::kProgrammaticChange, &err));
171   EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), "");
172 }
173 
174 // --------------------------------------------------------------------
175 
TEST_F(CommandLineFlagTest,TestSetFromStringDefaultValue)176 TEST_F(CommandLineFlagTest, TestSetFromStringDefaultValue) {
177   std::string err;
178 
179   auto* flag_01 = flags::FindCommandLineFlag("int_flag");
180 
181   EXPECT_TRUE(flag_01->SetFromString("111", flags::SET_FLAGS_DEFAULT,
182                                      flags::kProgrammaticChange, &err));
183   EXPECT_EQ(flag_01->DefaultValue(), "111");
184 
185   auto* flag_02 = flags::FindCommandLineFlag("string_flag");
186 
187   EXPECT_TRUE(flag_02->SetFromString("abc", flags::SET_FLAGS_DEFAULT,
188                                      flags::kProgrammaticChange, &err));
189   EXPECT_EQ(flag_02->DefaultValue(), "abc");
190 }
191 
192 // --------------------------------------------------------------------
193 
TEST_F(CommandLineFlagTest,TestSetFromStringIfDefault)194 TEST_F(CommandLineFlagTest, TestSetFromStringIfDefault) {
195   std::string err;
196 
197   auto* flag_01 = flags::FindCommandLineFlag("int_flag");
198 
199   EXPECT_TRUE(flag_01->SetFromString("22", flags::SET_FLAG_IF_DEFAULT,
200                                      flags::kProgrammaticChange, &err))
201       << err;
202   EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 22);
203 
204   EXPECT_TRUE(flag_01->SetFromString("33", flags::SET_FLAG_IF_DEFAULT,
205                                      flags::kProgrammaticChange, &err));
206   EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 22);
207   // EXPECT_EQ(err, "ERROR: int_flag is already set to 22");
208 
209   // Reset back to default value
210   EXPECT_TRUE(flag_01->SetFromString("201", flags::SET_FLAGS_VALUE,
211                                      flags::kProgrammaticChange, &err));
212 
213   EXPECT_TRUE(flag_01->SetFromString("33", flags::SET_FLAG_IF_DEFAULT,
214                                      flags::kProgrammaticChange, &err));
215   EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 201);
216   // EXPECT_EQ(err, "ERROR: int_flag is already set to 201");
217 }
218 
219 }  // namespace
220