• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/feature_list.h"
6 
7 #include <stddef.h>
8 
9 #include <utility>
10 #include <vector>
11 
12 #include "base/feature_list_buildflags.h"
13 #include "base/format_macros.h"
14 #include "base/memory/read_only_shared_memory_region.h"
15 #include "base/metrics/field_trial.h"
16 #include "base/metrics/field_trial_param_associator.h"
17 #include "base/metrics/persistent_memory_allocator.h"
18 #include "base/ranges/algorithm.h"
19 #include "base/strings/strcat.h"
20 #include "base/strings/string_piece.h"
21 #include "base/strings/string_util.h"
22 #include "base/strings/stringprintf.h"
23 #include "base/test/scoped_feature_list.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25 
26 namespace base {
27 
28 namespace {
29 
30 constexpr char kFeatureOnByDefaultName[] = "OnByDefault";
31 CONSTINIT Feature kFeatureOnByDefault(kFeatureOnByDefaultName,
32                                       FEATURE_ENABLED_BY_DEFAULT);
33 
34 constexpr char kFeatureOffByDefaultName[] = "OffByDefault";
35 CONSTINIT Feature kFeatureOffByDefault(kFeatureOffByDefaultName,
36                                        FEATURE_DISABLED_BY_DEFAULT);
37 
SortFeatureListString(const std::string & feature_list)38 std::string SortFeatureListString(const std::string& feature_list) {
39   std::vector<base::StringPiece> features =
40       FeatureList::SplitFeatureListString(feature_list);
41   ranges::sort(features);
42   return JoinString(features, ",");
43 }
44 
45 }  // namespace
46 
47 class FeatureListTest : public testing::Test {
48  public:
FeatureListTest()49   FeatureListTest() {
50     // Provide an empty FeatureList to each test by default.
51     scoped_feature_list_.InitWithFeatureList(std::make_unique<FeatureList>());
52   }
53   FeatureListTest(const FeatureListTest&) = delete;
54   FeatureListTest& operator=(const FeatureListTest&) = delete;
55   ~FeatureListTest() override = default;
56 
57  private:
58   test::ScopedFeatureList scoped_feature_list_;
59 };
60 
TEST_F(FeatureListTest,DefaultStates)61 TEST_F(FeatureListTest, DefaultStates) {
62   EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault));
63   EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
64 }
65 
TEST_F(FeatureListTest,InitFromCommandLine)66 TEST_F(FeatureListTest, InitFromCommandLine) {
67   struct {
68     const char* enable_features;
69     const char* disable_features;
70     bool expected_feature_on_state;
71     bool expected_feature_off_state;
72   } test_cases[] = {
73       {"", "", true, false},
74       {"OffByDefault", "", true, true},
75       {"OffByDefault", "OnByDefault", false, true},
76       {"OnByDefault,OffByDefault", "", true, true},
77       {"", "OnByDefault,OffByDefault", false, false},
78       // In the case an entry is both, disable takes precedence.
79       {"OnByDefault", "OnByDefault,OffByDefault", false, false},
80   };
81 
82   for (size_t i = 0; i < std::size(test_cases); ++i) {
83     const auto& test_case = test_cases[i];
84     SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: [%s] [%s]", i,
85                                     test_case.enable_features,
86                                     test_case.disable_features));
87 
88     auto feature_list = std::make_unique<FeatureList>();
89     feature_list->InitFromCommandLine(test_case.enable_features,
90                                       test_case.disable_features);
91     test::ScopedFeatureList scoped_feature_list;
92     scoped_feature_list.InitWithFeatureList(std::move(feature_list));
93 
94     EXPECT_EQ(test_case.expected_feature_on_state,
95               FeatureList::IsEnabled(kFeatureOnByDefault))
96         << i;
97     EXPECT_EQ(test_case.expected_feature_off_state,
98               FeatureList::IsEnabled(kFeatureOffByDefault))
99         << i;
100 
101     // Reading the state of each feature again will pull it from their
102     // respective caches instead of performing the full lookup, which should
103     // yield the same result.
104     EXPECT_EQ(test_case.expected_feature_on_state,
105               FeatureList::IsEnabled(kFeatureOnByDefault))
106         << i;
107     EXPECT_EQ(test_case.expected_feature_off_state,
108               FeatureList::IsEnabled(kFeatureOffByDefault))
109         << i;
110   }
111 }
112 
TEST_F(FeatureListTest,InitFromCommandLineWithFeatureParams)113 TEST_F(FeatureListTest, InitFromCommandLineWithFeatureParams) {
114   struct {
115     const std::string enable_features;
116     const std::string expected_field_trial_created;
117     const std::map<std::string, std::string> expected_feature_params;
118   } test_cases[] = {
119       {"Feature:x/100/y/test", "StudyFeature", {{"x", "100"}, {"y", "test"}}},
120       {"Feature<Trial1:x/200/y/123", "Trial1", {{"x", "200"}, {"y", "123"}}},
121       {"Feature<Trial2.Group2:x/test/y/uma/z/ukm",
122        "Trial2",
123        {{"x", "test"}, {"y", "uma"}, {"z", "ukm"}}},
124   };
125 
126   // Clear global state so that repeated runs of this test don't flake.
127   // When https://crrev.com/c/3694674 is submitted, we should be able to remove
128   // this.
129   base::FieldTrialParamAssociator::GetInstance()->ClearAllParamsForTesting();
130 
131   static BASE_FEATURE(kFeature, "Feature", FEATURE_DISABLED_BY_DEFAULT);
132   for (const auto& test_case : test_cases) {
133     SCOPED_TRACE(test_case.enable_features);
134 
135     auto feature_list = std::make_unique<FeatureList>();
136     feature_list->InitFromCommandLine(test_case.enable_features, "");
137     test::ScopedFeatureList scoped_feature_list;
138     scoped_feature_list.InitWithFeatureList(std::move(feature_list));
139 
140     EXPECT_TRUE(FeatureList::IsEnabled(kFeature));
141     EXPECT_TRUE(
142         FieldTrialList::IsTrialActive(test_case.expected_field_trial_created));
143     std::map<std::string, std::string> actual_params;
144     EXPECT_TRUE(GetFieldTrialParamsByFeature(kFeature, &actual_params));
145     EXPECT_EQ(test_case.expected_feature_params, actual_params);
146   }
147 }
148 
TEST_F(FeatureListTest,CheckFeatureIdentity)149 TEST_F(FeatureListTest, CheckFeatureIdentity) {
150   // Tests that CheckFeatureIdentity() correctly detects when two different
151   // structs with the same feature name are passed to it.
152 
153   test::ScopedFeatureList scoped_feature_list;
154   scoped_feature_list.InitWithFeatureList(std::make_unique<FeatureList>());
155   FeatureList* feature_list = FeatureList::GetInstance();
156 
157   // Call it twice for each feature at the top of the file, since the first call
158   // makes it remember the entry and the second call will verify it.
159   EXPECT_TRUE(feature_list->CheckFeatureIdentity(kFeatureOnByDefault));
160   EXPECT_TRUE(feature_list->CheckFeatureIdentity(kFeatureOnByDefault));
161   EXPECT_TRUE(feature_list->CheckFeatureIdentity(kFeatureOffByDefault));
162   EXPECT_TRUE(feature_list->CheckFeatureIdentity(kFeatureOffByDefault));
163 
164   // Now, call it with a distinct struct for |kFeatureOnByDefaultName|, which
165   // should return false.
166   struct Feature kFeatureOnByDefault2 {
167     kFeatureOnByDefaultName, FEATURE_ENABLED_BY_DEFAULT
168   };
169   EXPECT_FALSE(feature_list->CheckFeatureIdentity(kFeatureOnByDefault2));
170 }
171 
TEST_F(FeatureListTest,FieldTrialOverrides)172 TEST_F(FeatureListTest, FieldTrialOverrides) {
173   struct {
174     FeatureList::OverrideState trial1_state;
175     FeatureList::OverrideState trial2_state;
176   } test_cases[] = {
177       {FeatureList::OVERRIDE_DISABLE_FEATURE,
178        FeatureList::OVERRIDE_DISABLE_FEATURE},
179       {FeatureList::OVERRIDE_DISABLE_FEATURE,
180        FeatureList::OVERRIDE_ENABLE_FEATURE},
181       {FeatureList::OVERRIDE_ENABLE_FEATURE,
182        FeatureList::OVERRIDE_DISABLE_FEATURE},
183       {FeatureList::OVERRIDE_ENABLE_FEATURE,
184        FeatureList::OVERRIDE_ENABLE_FEATURE},
185   };
186 
187   FieldTrial::ActiveGroup active_group;
188   for (size_t i = 0; i < std::size(test_cases); ++i) {
189     const auto& test_case = test_cases[i];
190     SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]", i));
191 
192     test::ScopedFeatureList outer_scope;
193     outer_scope.InitWithEmptyFeatureAndFieldTrialLists();
194 
195     auto feature_list = std::make_unique<FeatureList>();
196 
197     FieldTrial* trial1 = FieldTrialList::CreateFieldTrial("TrialExample1", "A");
198     FieldTrial* trial2 = FieldTrialList::CreateFieldTrial("TrialExample2", "B");
199     feature_list->RegisterFieldTrialOverride(kFeatureOnByDefaultName,
200                                              test_case.trial1_state, trial1);
201     feature_list->RegisterFieldTrialOverride(kFeatureOffByDefaultName,
202                                              test_case.trial2_state, trial2);
203     test::ScopedFeatureList scoped_feature_list;
204     scoped_feature_list.InitWithFeatureList(std::move(feature_list));
205 
206     // Initially, neither trial should be active.
207     EXPECT_FALSE(FieldTrialList::IsTrialActive(trial1->trial_name()));
208     EXPECT_FALSE(FieldTrialList::IsTrialActive(trial2->trial_name()));
209 
210     const bool expected_enabled_1 =
211         (test_case.trial1_state == FeatureList::OVERRIDE_ENABLE_FEATURE);
212     EXPECT_EQ(expected_enabled_1, FeatureList::IsEnabled(kFeatureOnByDefault));
213     // The above should have activated |trial1|.
214     EXPECT_TRUE(FieldTrialList::IsTrialActive(trial1->trial_name()));
215     EXPECT_FALSE(FieldTrialList::IsTrialActive(trial2->trial_name()));
216 
217     const bool expected_enabled_2 =
218         (test_case.trial2_state == FeatureList::OVERRIDE_ENABLE_FEATURE);
219     EXPECT_EQ(expected_enabled_2, FeatureList::IsEnabled(kFeatureOffByDefault));
220     // The above should have activated |trial2|.
221     EXPECT_TRUE(FieldTrialList::IsTrialActive(trial1->trial_name()));
222     EXPECT_TRUE(FieldTrialList::IsTrialActive(trial2->trial_name()));
223   }
224 }
225 
TEST_F(FeatureListTest,FieldTrialAssociateUseDefault)226 TEST_F(FeatureListTest, FieldTrialAssociateUseDefault) {
227   auto feature_list = std::make_unique<FeatureList>();
228 
229   FieldTrial* trial1 = FieldTrialList::CreateFieldTrial("TrialExample1", "A");
230   FieldTrial* trial2 = FieldTrialList::CreateFieldTrial("TrialExample2", "B");
231   feature_list->RegisterFieldTrialOverride(
232       kFeatureOnByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT, trial1);
233   feature_list->RegisterFieldTrialOverride(
234       kFeatureOffByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT, trial2);
235   test::ScopedFeatureList scoped_feature_list;
236   scoped_feature_list.InitWithFeatureList(std::move(feature_list));
237 
238   // Initially, neither trial should be active.
239   EXPECT_FALSE(FieldTrialList::IsTrialActive(trial1->trial_name()));
240   EXPECT_FALSE(FieldTrialList::IsTrialActive(trial2->trial_name()));
241 
242   // Check the feature enabled state is its default.
243   EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault));
244   // The above should have activated |trial1|.
245   EXPECT_TRUE(FieldTrialList::IsTrialActive(trial1->trial_name()));
246   EXPECT_FALSE(FieldTrialList::IsTrialActive(trial2->trial_name()));
247 
248   // Check the feature enabled state is its default.
249   EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
250   // The above should have activated |trial2|.
251   EXPECT_TRUE(FieldTrialList::IsTrialActive(trial1->trial_name()));
252   EXPECT_TRUE(FieldTrialList::IsTrialActive(trial2->trial_name()));
253 }
254 
TEST_F(FeatureListTest,CommandLineEnableTakesPrecedenceOverFieldTrial)255 TEST_F(FeatureListTest, CommandLineEnableTakesPrecedenceOverFieldTrial) {
256   auto feature_list = std::make_unique<FeatureList>();
257 
258   // The feature is explicitly enabled on the command-line.
259   feature_list->InitFromCommandLine(kFeatureOffByDefaultName, "");
260 
261   // But the FieldTrial would set the feature to disabled.
262   FieldTrial* trial = FieldTrialList::CreateFieldTrial("TrialExample2", "A");
263   feature_list->RegisterFieldTrialOverride(
264       kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE, trial);
265   test::ScopedFeatureList scoped_feature_list;
266   scoped_feature_list.InitWithFeatureList(std::move(feature_list));
267 
268   EXPECT_FALSE(FieldTrialList::IsTrialActive(trial->trial_name()));
269   // Command-line should take precedence.
270   EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault));
271   // Since the feature is on due to the command-line, and not as a result of the
272   // field trial, the field trial should not be activated (since the Associate*
273   // API wasn't used.)
274   EXPECT_FALSE(FieldTrialList::IsTrialActive(trial->trial_name()));
275 }
276 
TEST_F(FeatureListTest,CommandLineDisableTakesPrecedenceOverFieldTrial)277 TEST_F(FeatureListTest, CommandLineDisableTakesPrecedenceOverFieldTrial) {
278   auto feature_list = std::make_unique<FeatureList>();
279 
280   // The feature is explicitly disabled on the command-line.
281   feature_list->InitFromCommandLine("", kFeatureOffByDefaultName);
282 
283   // But the FieldTrial would set the feature to enabled.
284   FieldTrial* trial = FieldTrialList::CreateFieldTrial("TrialExample2", "A");
285   feature_list->RegisterFieldTrialOverride(
286       kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE, trial);
287   test::ScopedFeatureList scoped_feature_list;
288   scoped_feature_list.InitWithFeatureList(std::move(feature_list));
289 
290   EXPECT_FALSE(FieldTrialList::IsTrialActive(trial->trial_name()));
291   // Command-line should take precedence.
292   EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
293   // Since the feature is on due to the command-line, and not as a result of the
294   // field trial, the field trial should not be activated (since the Associate*
295   // API wasn't used.)
296   EXPECT_FALSE(FieldTrialList::IsTrialActive(trial->trial_name()));
297 }
298 
TEST_F(FeatureListTest,IsFeatureOverriddenFromFieldTrial)299 TEST_F(FeatureListTest, IsFeatureOverriddenFromFieldTrial) {
300   auto feature_list = std::make_unique<FeatureList>();
301 
302   // No features are overridden from the field trails yet.
303   EXPECT_FALSE(feature_list->IsFeatureOverridden(kFeatureOnByDefaultName));
304   EXPECT_FALSE(feature_list->IsFeatureOverridden(kFeatureOffByDefaultName));
305 
306   // Now, register a field trial to override |kFeatureOnByDefaultName| state
307   // and check that the function still returns false for that feature.
308   feature_list->RegisterFieldTrialOverride(
309       kFeatureOffByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT,
310       FieldTrialList::CreateFieldTrial("Trial1", "A"));
311   feature_list->RegisterFieldTrialOverride(
312       kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE,
313       FieldTrialList::CreateFieldTrial("Trial2", "A"));
314   EXPECT_TRUE(feature_list->IsFeatureOverridden(kFeatureOnByDefaultName));
315   EXPECT_TRUE(feature_list->IsFeatureOverridden(kFeatureOffByDefaultName));
316 
317   test::ScopedFeatureList scoped_feature_list;
318   scoped_feature_list.InitWithFeatureList(std::move(feature_list));
319   // Check the expected feature states for good measure.
320   EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
321   EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault));
322 }
323 
TEST_F(FeatureListTest,IsFeatureOverriddenFromCommandLine)324 TEST_F(FeatureListTest, IsFeatureOverriddenFromCommandLine) {
325   auto feature_list = std::make_unique<FeatureList>();
326 
327   // No features are overridden from the command line yet
328   EXPECT_FALSE(feature_list->IsFeatureOverridden(kFeatureOnByDefaultName));
329   EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
330       kFeatureOnByDefaultName));
331   EXPECT_FALSE(feature_list->IsFeatureOverridden(kFeatureOffByDefaultName));
332   EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
333       kFeatureOffByDefaultName));
334   EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
335       kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE));
336   EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
337       kFeatureOnByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE));
338   EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
339       kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE));
340   EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
341       kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE));
342 
343   // Now, enable |kFeatureOffByDefaultName| via the command-line.
344   feature_list->InitFromCommandLine(kFeatureOffByDefaultName, "");
345 
346   // It should now be overridden for the enabled group.
347   EXPECT_TRUE(feature_list->IsFeatureOverridden(kFeatureOffByDefaultName));
348   EXPECT_TRUE(feature_list->IsFeatureOverriddenFromCommandLine(
349       kFeatureOffByDefaultName));
350   EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
351       kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE));
352   EXPECT_TRUE(feature_list->IsFeatureOverriddenFromCommandLine(
353       kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE));
354 
355   // Register a field trial to associate with the feature and ensure that the
356   // results are still the same.
357   feature_list->AssociateReportingFieldTrial(
358       kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE,
359       FieldTrialList::CreateFieldTrial("Trial1", "A"));
360   EXPECT_TRUE(feature_list->IsFeatureOverridden(kFeatureOffByDefaultName));
361   EXPECT_TRUE(feature_list->IsFeatureOverriddenFromCommandLine(
362       kFeatureOffByDefaultName));
363   EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
364       kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE));
365   EXPECT_TRUE(feature_list->IsFeatureOverriddenFromCommandLine(
366       kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE));
367 
368   // Now, register a field trial to override |kFeatureOnByDefaultName| state
369   // and check that the function still returns false for that feature.
370   feature_list->RegisterFieldTrialOverride(
371       kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE,
372       FieldTrialList::CreateFieldTrial("Trial2", "A"));
373   EXPECT_TRUE(feature_list->IsFeatureOverridden(kFeatureOnByDefaultName));
374   EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
375       kFeatureOnByDefaultName));
376   EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
377       kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE));
378   EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
379       kFeatureOnByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE));
380   test::ScopedFeatureList scoped_feature_list;
381   scoped_feature_list.InitWithFeatureList(std::move(feature_list));
382 
383   // Check the expected feature states for good measure.
384   EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault));
385   EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault));
386 }
387 
TEST_F(FeatureListTest,AssociateReportingFieldTrial)388 TEST_F(FeatureListTest, AssociateReportingFieldTrial) {
389   struct {
390     const char* enable_features;
391     const char* disable_features;
392     bool expected_enable_trial_created;
393     bool expected_disable_trial_created;
394   } test_cases[] = {
395       // If no enable/disable flags are specified, no trials should be created.
396       {"", "", false, false},
397       // Enabling the feature should result in the enable trial created.
398       {kFeatureOffByDefaultName, "", true, false},
399       // Disabling the feature should result in the disable trial created.
400       {"", kFeatureOffByDefaultName, false, true},
401   };
402 
403   const char kTrialName[] = "ForcingTrial";
404   const char kForcedOnGroupName[] = "ForcedOn";
405   const char kForcedOffGroupName[] = "ForcedOff";
406 
407   for (size_t i = 0; i < std::size(test_cases); ++i) {
408     const auto& test_case = test_cases[i];
409     SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: [%s] [%s]", i,
410                                     test_case.enable_features,
411                                     test_case.disable_features));
412 
413     test::ScopedFeatureList outer_scope;
414     outer_scope.InitWithEmptyFeatureAndFieldTrialLists();
415 
416     auto feature_list = std::make_unique<FeatureList>();
417     feature_list->InitFromCommandLine(test_case.enable_features,
418                                       test_case.disable_features);
419 
420     FieldTrial* enable_trial = nullptr;
421     if (feature_list->IsFeatureOverriddenFromCommandLine(
422             kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE)) {
423       enable_trial = base::FieldTrialList::CreateFieldTrial(kTrialName,
424                                                             kForcedOnGroupName);
425       feature_list->AssociateReportingFieldTrial(
426           kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE,
427           enable_trial);
428     }
429     FieldTrial* disable_trial = nullptr;
430     if (feature_list->IsFeatureOverriddenFromCommandLine(
431             kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE)) {
432       disable_trial = base::FieldTrialList::CreateFieldTrial(
433           kTrialName, kForcedOffGroupName);
434       feature_list->AssociateReportingFieldTrial(
435           kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE,
436           disable_trial);
437     }
438     EXPECT_EQ(test_case.expected_enable_trial_created, enable_trial != nullptr);
439     EXPECT_EQ(test_case.expected_disable_trial_created,
440               disable_trial != nullptr);
441     test::ScopedFeatureList scoped_feature_list;
442     scoped_feature_list.InitWithFeatureList(std::move(feature_list));
443 
444     EXPECT_FALSE(FieldTrialList::IsTrialActive(kTrialName));
445     if (disable_trial) {
446       EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
447       EXPECT_TRUE(FieldTrialList::IsTrialActive(kTrialName));
448       EXPECT_EQ(kForcedOffGroupName, disable_trial->group_name());
449     } else if (enable_trial) {
450       EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault));
451       EXPECT_TRUE(FieldTrialList::IsTrialActive(kTrialName));
452       EXPECT_EQ(kForcedOnGroupName, enable_trial->group_name());
453     }
454   }
455 }
456 
TEST_F(FeatureListTest,RegisterExtraFeatureOverrides)457 TEST_F(FeatureListTest, RegisterExtraFeatureOverrides) {
458   auto feature_list = std::make_unique<FeatureList>();
459   std::vector<FeatureList::FeatureOverrideInfo> overrides;
460   overrides.push_back({std::cref(kFeatureOnByDefault),
461                        FeatureList::OverrideState::OVERRIDE_DISABLE_FEATURE});
462   overrides.push_back({std::cref(kFeatureOffByDefault),
463                        FeatureList::OverrideState::OVERRIDE_ENABLE_FEATURE});
464   feature_list->RegisterExtraFeatureOverrides(std::move(overrides));
465   test::ScopedFeatureList scoped_feature_list;
466   scoped_feature_list.InitWithFeatureList(std::move(feature_list));
467 
468   EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault));
469   EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault));
470 }
471 
TEST_F(FeatureListTest,InitFromCommandLineThenRegisterExtraOverrides)472 TEST_F(FeatureListTest, InitFromCommandLineThenRegisterExtraOverrides) {
473   auto feature_list = std::make_unique<FeatureList>();
474   feature_list->InitFromCommandLine(kFeatureOnByDefaultName,
475                                     kFeatureOffByDefaultName);
476   std::vector<FeatureList::FeatureOverrideInfo> overrides;
477   overrides.push_back({std::cref(kFeatureOnByDefault),
478                        FeatureList::OverrideState::OVERRIDE_DISABLE_FEATURE});
479   overrides.push_back({std::cref(kFeatureOffByDefault),
480                        FeatureList::OverrideState::OVERRIDE_ENABLE_FEATURE});
481   feature_list->RegisterExtraFeatureOverrides(std::move(overrides));
482   test::ScopedFeatureList scoped_feature_list;
483   scoped_feature_list.InitWithFeatureList(std::move(feature_list));
484 
485   // The InitFromCommandLine supersedes the RegisterExtraFeatureOverrides
486   // because it was called first.
487   EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault));
488   EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
489 
490   std::string enable_features;
491   std::string disable_features;
492   FeatureList::GetInstance()->GetFeatureOverrides(&enable_features,
493                                                   &disable_features);
494   EXPECT_EQ(kFeatureOnByDefaultName, SortFeatureListString(enable_features));
495   EXPECT_EQ(kFeatureOffByDefaultName, SortFeatureListString(disable_features));
496 }
497 
TEST_F(FeatureListTest,GetFeatureOverrides)498 TEST_F(FeatureListTest, GetFeatureOverrides) {
499   auto feature_list = std::make_unique<FeatureList>();
500   feature_list->InitFromCommandLine("A,X", "D");
501 
502   Feature feature_b = {"B", FEATURE_ENABLED_BY_DEFAULT};
503   Feature feature_c = {"C", FEATURE_DISABLED_BY_DEFAULT};
504   std::vector<FeatureList::FeatureOverrideInfo> overrides;
505   overrides.push_back({std::cref(feature_b),
506                        FeatureList::OverrideState::OVERRIDE_DISABLE_FEATURE});
507   overrides.push_back({std::cref(feature_c),
508                        FeatureList::OverrideState::OVERRIDE_ENABLE_FEATURE});
509   feature_list->RegisterExtraFeatureOverrides(std::move(overrides));
510 
511   FieldTrial* trial = FieldTrialList::CreateFieldTrial("Trial", "Group");
512   feature_list->RegisterFieldTrialOverride(kFeatureOffByDefaultName,
513                                            FeatureList::OVERRIDE_ENABLE_FEATURE,
514                                            trial);
515 
516   test::ScopedFeatureList scoped_feature_list;
517   scoped_feature_list.InitWithFeatureList(std::move(feature_list));
518 
519   std::string enable_features;
520   std::string disable_features;
521   FeatureList::GetInstance()->GetFeatureOverrides(&enable_features,
522                                                   &disable_features);
523   EXPECT_EQ("A,C,OffByDefault<Trial,X", SortFeatureListString(enable_features));
524   EXPECT_EQ("B,D", SortFeatureListString(disable_features));
525 
526   FeatureList::GetInstance()->GetCommandLineFeatureOverrides(&enable_features,
527                                                              &disable_features);
528   EXPECT_EQ("A,C,X", SortFeatureListString(enable_features));
529   EXPECT_EQ("B,D", SortFeatureListString(disable_features));
530 }
531 
TEST_F(FeatureListTest,GetFeatureOverrides_UseDefault)532 TEST_F(FeatureListTest, GetFeatureOverrides_UseDefault) {
533   auto feature_list = std::make_unique<FeatureList>();
534   feature_list->InitFromCommandLine("A,X", "D");
535 
536   FieldTrial* trial = FieldTrialList::CreateFieldTrial("Trial", "Group");
537   feature_list->RegisterFieldTrialOverride(
538       kFeatureOffByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT, trial);
539 
540   test::ScopedFeatureList scoped_feature_list;
541   scoped_feature_list.InitWithFeatureList(std::move(feature_list));
542 
543   std::string enable_features;
544   std::string disable_features;
545   FeatureList::GetInstance()->GetFeatureOverrides(&enable_features,
546                                                   &disable_features);
547   EXPECT_EQ("*OffByDefault<Trial,A,X", SortFeatureListString(enable_features));
548   EXPECT_EQ("D", SortFeatureListString(disable_features));
549 }
550 
TEST_F(FeatureListTest,GetFieldTrial)551 TEST_F(FeatureListTest, GetFieldTrial) {
552   FieldTrial* trial = FieldTrialList::CreateFieldTrial("Trial", "Group");
553   auto feature_list = std::make_unique<FeatureList>();
554   feature_list->RegisterFieldTrialOverride(
555       kFeatureOnByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT, trial);
556   test::ScopedFeatureList scoped_feature_list;
557   scoped_feature_list.InitWithFeatureList(std::move(feature_list));
558 
559   EXPECT_EQ(trial, FeatureList::GetFieldTrial(kFeatureOnByDefault));
560   EXPECT_EQ(nullptr, FeatureList::GetFieldTrial(kFeatureOffByDefault));
561 }
562 
TEST_F(FeatureListTest,InitFromCommandLine_WithFieldTrials)563 TEST_F(FeatureListTest, InitFromCommandLine_WithFieldTrials) {
564   FieldTrialList::CreateFieldTrial("Trial", "Group");
565   auto feature_list = std::make_unique<FeatureList>();
566   feature_list->InitFromCommandLine("A,OffByDefault<Trial,X", "D");
567   test::ScopedFeatureList scoped_feature_list;
568   scoped_feature_list.InitWithFeatureList(std::move(feature_list));
569 
570   EXPECT_FALSE(FieldTrialList::IsTrialActive("Trial"));
571   EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault));
572   EXPECT_TRUE(FieldTrialList::IsTrialActive("Trial"));
573 }
574 
TEST_F(FeatureListTest,InitFromCommandLine_UseDefault)575 TEST_F(FeatureListTest, InitFromCommandLine_UseDefault) {
576   FieldTrialList::CreateFieldTrial("T1", "Group");
577   FieldTrialList::CreateFieldTrial("T2", "Group");
578   auto feature_list = std::make_unique<FeatureList>();
579   feature_list->InitFromCommandLine("A,*OffByDefault<T1,*OnByDefault<T2,X",
580                                     "D");
581   test::ScopedFeatureList scoped_feature_list;
582   scoped_feature_list.InitWithFeatureList(std::move(feature_list));
583 
584   EXPECT_FALSE(FieldTrialList::IsTrialActive("T1"));
585   EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
586   EXPECT_TRUE(FieldTrialList::IsTrialActive("T1"));
587 
588   EXPECT_FALSE(FieldTrialList::IsTrialActive("T2"));
589   EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault));
590   EXPECT_TRUE(FieldTrialList::IsTrialActive("T2"));
591 }
592 
TEST_F(FeatureListTest,InitInstance)593 TEST_F(FeatureListTest, InitInstance) {
594   std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
595   test::ScopedFeatureList scoped_feature_list;
596   scoped_feature_list.InitWithFeatureList(std::move(feature_list));
597 
598   EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault));
599   EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
600 
601   // Initialize from command line if we haven't yet.
602   FeatureList::InitInstance("", kFeatureOnByDefaultName);
603   EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault));
604   EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
605 
606   // Do not initialize from commandline if we have already.
607   FeatureList::InitInstance(kFeatureOffByDefaultName, "");
608   EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault));
609   EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
610 }
611 
TEST_F(FeatureListTest,UninitializedInstance_IsEnabledReturnsFalse)612 TEST_F(FeatureListTest, UninitializedInstance_IsEnabledReturnsFalse) {
613   std::unique_ptr<FeatureList> original_feature_list =
614       FeatureList::ClearInstanceForTesting();
615 
616   // This test case simulates the calling pattern found in code which does not
617   // explicitly initialize the features list.
618   // All IsEnabled() calls should return the default value in this scenario.
619   EXPECT_EQ(nullptr, FeatureList::GetInstance());
620   EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault));
621   EXPECT_EQ(nullptr, FeatureList::GetInstance());
622   EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
623 
624   if (original_feature_list)
625     FeatureList::RestoreInstanceForTesting(std::move(original_feature_list));
626 }
627 
TEST_F(FeatureListTest,StoreAndRetrieveFeaturesFromSharedMemory)628 TEST_F(FeatureListTest, StoreAndRetrieveFeaturesFromSharedMemory) {
629   std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
630 
631   // Create some overrides.
632   feature_list->RegisterOverride(kFeatureOffByDefaultName,
633                                  FeatureList::OVERRIDE_ENABLE_FEATURE, nullptr);
634   feature_list->RegisterOverride(
635       kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE, nullptr);
636   feature_list->FinalizeInitialization();
637 
638   // Create an allocator and store the overrides.
639   base::MappedReadOnlyRegion shm =
640       base::ReadOnlySharedMemoryRegion::Create(4 << 10);
641   WritableSharedPersistentMemoryAllocator allocator(std::move(shm.mapping), 1,
642                                                     "");
643   feature_list->AddFeaturesToAllocator(&allocator);
644 
645   std::unique_ptr<base::FeatureList> feature_list2(new base::FeatureList);
646 
647   // Check that the new feature list is empty.
648   EXPECT_FALSE(feature_list2->IsFeatureOverriddenFromCommandLine(
649       kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE));
650   EXPECT_FALSE(feature_list2->IsFeatureOverriddenFromCommandLine(
651       kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE));
652 
653   feature_list2->InitFromSharedMemory(&allocator);
654   // Check that the new feature list now has 2 overrides.
655   EXPECT_TRUE(feature_list2->IsFeatureOverriddenFromCommandLine(
656       kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE));
657   EXPECT_TRUE(feature_list2->IsFeatureOverriddenFromCommandLine(
658       kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE));
659 }
660 
TEST_F(FeatureListTest,StoreAndRetrieveAssociatedFeaturesFromSharedMemory)661 TEST_F(FeatureListTest, StoreAndRetrieveAssociatedFeaturesFromSharedMemory) {
662   std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
663 
664   // Create some overrides.
665   FieldTrial* trial1 = FieldTrialList::CreateFieldTrial("TrialExample1", "A");
666   FieldTrial* trial2 = FieldTrialList::CreateFieldTrial("TrialExample2", "B");
667   feature_list->RegisterFieldTrialOverride(
668       kFeatureOnByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT, trial1);
669   feature_list->RegisterFieldTrialOverride(
670       kFeatureOffByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT, trial2);
671   feature_list->FinalizeInitialization();
672 
673   // Create an allocator and store the overrides.
674   base::MappedReadOnlyRegion shm =
675       base::ReadOnlySharedMemoryRegion::Create(4 << 10);
676   WritableSharedPersistentMemoryAllocator allocator(std::move(shm.mapping), 1,
677                                                     "");
678   feature_list->AddFeaturesToAllocator(&allocator);
679 
680   std::unique_ptr<base::FeatureList> feature_list2(new base::FeatureList);
681   feature_list2->InitFromSharedMemory(&allocator);
682   feature_list2->FinalizeInitialization();
683 
684   // Check that the field trials are still associated.
685   FieldTrial* associated_trial1 =
686       feature_list2->GetAssociatedFieldTrial(kFeatureOnByDefault);
687   FieldTrial* associated_trial2 =
688       feature_list2->GetAssociatedFieldTrial(kFeatureOffByDefault);
689   EXPECT_EQ(associated_trial1, trial1);
690   EXPECT_EQ(associated_trial2, trial2);
691 }
692 
TEST_F(FeatureListTest,SetEarlyAccessInstance_AllowList)693 TEST_F(FeatureListTest, SetEarlyAccessInstance_AllowList) {
694   test::ScopedFeatureList clear_feature_list;
695   clear_feature_list.InitWithNullFeatureAndFieldTrialLists();
696 
697   auto early_access_feature_list = std::make_unique<FeatureList>();
698   early_access_feature_list->InitFromCommandLine("OffByDefault", "OnByDefault");
699   FeatureList::SetEarlyAccessInstance(std::move(early_access_feature_list),
700                                       {"OnByDefault"});
701   EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault));
702   EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
703   EXPECT_EQ(&kFeatureOffByDefault,
704             FeatureList::GetEarlyAccessedFeatureForTesting());
705   FeatureList::ResetEarlyFeatureAccessTrackerForTesting();
706 }
707 
TEST_F(FeatureListTest,SetEarlyAccessInstance_ReplaceByRealList)708 TEST_F(FeatureListTest, SetEarlyAccessInstance_ReplaceByRealList) {
709   test::ScopedFeatureList clear_feature_list;
710   clear_feature_list.InitWithNullFeatureAndFieldTrialLists();
711 
712   auto early_access_feature_list = std::make_unique<FeatureList>();
713   early_access_feature_list->InitFromCommandLine("OffByDefault", "OnByDefault");
714   FeatureList::SetEarlyAccessInstance(std::move(early_access_feature_list),
715                                       {"OffByDefault", "OnByDefault"});
716   EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault));
717   EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault));
718 
719   auto feature_list = std::make_unique<FeatureList>();
720   feature_list->InitFromCommandLine("", "");
721   FeatureList::SetInstance(std::move(feature_list));
722   EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault));
723   EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
724 }
725 
726 #if BUILDFLAG(ENABLE_BANNED_BASE_FEATURE_PREFIX) && \
727     defined(GTEST_HAS_DEATH_TEST)
728 using FeatureListDeathTest = FeatureListTest;
TEST_F(FeatureListDeathTest,DiesWithBadFeatureName)729 TEST_F(FeatureListDeathTest, DiesWithBadFeatureName) {
730   EXPECT_DEATH(
731       Feature(
732           StrCat({BUILDFLAG(BANNED_BASE_FEATURE_PREFIX), "MyFeature"}).c_str(),
733           FEATURE_DISABLED_BY_DEFAULT),
734       StrCat({"Invalid feature name ", BUILDFLAG(BANNED_BASE_FEATURE_PREFIX),
735               "MyFeature"}));
736 }
737 #endif  // BUILDFLAG(ENABLE_BANNED_BASE_FEATURE_PREFIX) &&
738         // defined(GTEST_HAS_DEATH_TEST)
739 
TEST(FeatureListAccessorTest,DefaultStates)740 TEST(FeatureListAccessorTest, DefaultStates) {
741   test::ScopedFeatureList scoped_feature_list;
742   auto feature_list = std::make_unique<FeatureList>();
743   auto feature_list_accessor = feature_list->ConstructAccessor();
744   scoped_feature_list.InitWithFeatureList(std::move(feature_list));
745 
746   EXPECT_EQ(feature_list_accessor->GetOverrideStateByFeatureName(
747                 kFeatureOnByDefault.name),
748             FeatureList::OVERRIDE_USE_DEFAULT);
749   EXPECT_EQ(feature_list_accessor->GetOverrideStateByFeatureName(
750                 kFeatureOffByDefault.name),
751             FeatureList::OVERRIDE_USE_DEFAULT);
752 }
753 
TEST(FeatureListAccessorTest,InitFromCommandLine)754 TEST(FeatureListAccessorTest, InitFromCommandLine) {
755   struct {
756     const char* enable_features;
757     const char* disable_features;
758     FeatureList::OverrideState expected_feature_on_state;
759     FeatureList::OverrideState expected_feature_off_state;
760   } test_cases[] = {
761       {"", "", FeatureList::OVERRIDE_USE_DEFAULT,
762        FeatureList::OVERRIDE_USE_DEFAULT},
763       {"OffByDefault", "", FeatureList::OVERRIDE_USE_DEFAULT,
764        FeatureList::OVERRIDE_ENABLE_FEATURE},
765       {"OffByDefault", "OnByDefault", FeatureList::OVERRIDE_DISABLE_FEATURE,
766        FeatureList::OVERRIDE_ENABLE_FEATURE},
767       {"OnByDefault,OffByDefault", "", FeatureList::OVERRIDE_ENABLE_FEATURE,
768        FeatureList::OVERRIDE_ENABLE_FEATURE},
769       {"", "OnByDefault,OffByDefault", FeatureList::OVERRIDE_DISABLE_FEATURE,
770        FeatureList::OVERRIDE_DISABLE_FEATURE},
771       // In the case an entry is both, disable takes precedence.
772       {"OnByDefault", "OnByDefault,OffByDefault",
773        FeatureList::OVERRIDE_DISABLE_FEATURE,
774        FeatureList::OVERRIDE_DISABLE_FEATURE},
775   };
776 
777   for (size_t i = 0; i < std::size(test_cases); ++i) {
778     const auto& test_case = test_cases[i];
779     SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: [%s] [%s]", i,
780                                     test_case.enable_features,
781                                     test_case.disable_features));
782 
783     test::ScopedFeatureList scoped_feature_list;
784     auto feature_list = std::make_unique<FeatureList>();
785     auto feature_list_accessor = feature_list->ConstructAccessor();
786     feature_list->InitFromCommandLine(test_case.enable_features,
787                                       test_case.disable_features);
788     scoped_feature_list.InitWithFeatureList(std::move(feature_list));
789 
790     EXPECT_EQ(test_case.expected_feature_on_state,
791               feature_list_accessor->GetOverrideStateByFeatureName(
792                   kFeatureOnByDefault.name))
793         << i;
794     EXPECT_EQ(test_case.expected_feature_off_state,
795               feature_list_accessor->GetOverrideStateByFeatureName(
796                   kFeatureOffByDefault.name))
797         << i;
798   }
799 }
800 
TEST(FeatureListAccessorTest,InitFromCommandLineWithFeatureParams)801 TEST(FeatureListAccessorTest, InitFromCommandLineWithFeatureParams) {
802   struct {
803     const std::string enable_features;
804     const std::map<std::string, std::string> expected_feature_params;
805   } test_cases[] = {
806       {"Feature:x/100/y/test", {{"x", "100"}, {"y", "test"}}},
807       {"Feature<Trial:asdf/ghjkl/y/123", {{"asdf", "ghjkl"}, {"y", "123"}}},
808   };
809 
810   // Clear global state so that repeated runs of this test don't flake.
811   // When https://crrev.com/c/3694674 is submitted, we should be able to remove
812   // this.
813   base::FieldTrialParamAssociator::GetInstance()->ClearAllParamsForTesting();
814 
815   for (size_t i = 0; i < std::size(test_cases); ++i) {
816     const auto& test_case = test_cases[i];
817     SCOPED_TRACE(test_case.enable_features);
818 
819     test::ScopedFeatureList scoped_feature_list;
820     auto feature_list = std::make_unique<FeatureList>();
821     auto feature_list_accessor = feature_list->ConstructAccessor();
822     feature_list->InitFromCommandLine(test_case.enable_features, "");
823     scoped_feature_list.InitWithFeatureList(std::move(feature_list));
824 
825     EXPECT_EQ(FeatureList::OVERRIDE_ENABLE_FEATURE,
826               feature_list_accessor->GetOverrideStateByFeatureName("Feature"))
827         << i;
828     std::map<std::string, std::string> actual_params;
829     EXPECT_TRUE(feature_list_accessor->GetParamsByFeatureName("Feature",
830                                                               &actual_params))
831         << i;
832     EXPECT_EQ(test_case.expected_feature_params, actual_params) << i;
833   }
834 }
835 
836 }  // namespace base
837