1 // Copyright 2015 The Chromium Authors. All rights reserved.
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/format_macros.h"
13 #include "base/memory/read_only_shared_memory_region.h"
14 #include "base/metrics/field_trial.h"
15 #include "base/metrics/persistent_memory_allocator.h"
16 #include "base/ranges/algorithm.h"
17 #include "base/stl_util.h"
18 #include "base/strings/string_piece.h"
19 #include "base/strings/string_util.h"
20 #include "base/strings/stringprintf.h"
21 #include "base/test/scoped_feature_list.h"
22 #include "base/test/scoped_field_trial_list_resetter.h"
23 #include "testing/gtest/include/gtest/gtest.h"
24 
25 namespace base {
26 
27 namespace {
28 
29 constexpr char kFeatureOnByDefaultName[] = "OnByDefault";
30 struct Feature kFeatureOnByDefault {
31   kFeatureOnByDefaultName, FEATURE_ENABLED_BY_DEFAULT
32 };
33 
34 constexpr char kFeatureOffByDefaultName[] = "OffByDefault";
35 struct Feature kFeatureOffByDefault {
36   kFeatureOffByDefaultName, FEATURE_DISABLED_BY_DEFAULT
37 };
38 
SortFeatureListString(const std::string & feature_list)39 std::string SortFeatureListString(const std::string& feature_list) {
40   std::vector<base::StringPiece> features =
41       FeatureList::SplitFeatureListString(feature_list);
42   ranges::sort(features);
43   return JoinString(features, ",");
44 }
45 
46 }  // namespace
47 
48 class FeatureListTest : public testing::Test {
49  public:
FeatureListTest()50   FeatureListTest() {
51     // Provide an empty FeatureList to each test by default.
52     scoped_feature_list_.InitWithFeatureList(std::make_unique<FeatureList>());
53   }
54   FeatureListTest(const FeatureListTest&) = delete;
55   FeatureListTest& operator=(const FeatureListTest&) = delete;
56   ~FeatureListTest() override = default;
57 
58  private:
59   test::ScopedFeatureList scoped_feature_list_;
60 };
61 
TEST_F(FeatureListTest,DefaultStates)62 TEST_F(FeatureListTest, DefaultStates) {
63   EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault));
64   EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
65 }
66 
TEST_F(FeatureListTest,InitializeFromCommandLine)67 TEST_F(FeatureListTest, InitializeFromCommandLine) {
68   struct {
69     const char* enable_features;
70     const char* disable_features;
71     bool expected_feature_on_state;
72     bool expected_feature_off_state;
73   } test_cases[] = {
74       {"", "", true, false},
75       {"OffByDefault", "", true, true},
76       {"OffByDefault", "OnByDefault", false, true},
77       {"OnByDefault,OffByDefault", "", true, true},
78       {"", "OnByDefault,OffByDefault", false, false},
79       // In the case an entry is both, disable takes precedence.
80       {"OnByDefault", "OnByDefault,OffByDefault", false, false},
81   };
82 
83   for (size_t i = 0; i < base::size(test_cases); ++i) {
84     const auto& test_case = test_cases[i];
85     SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: [%s] [%s]", i,
86                                     test_case.enable_features,
87                                     test_case.disable_features));
88 
89     auto feature_list = std::make_unique<FeatureList>();
90     feature_list->InitializeFromCommandLine(test_case.enable_features,
91                                             test_case.disable_features);
92     test::ScopedFeatureList scoped_feature_list;
93     scoped_feature_list.InitWithFeatureList(std::move(feature_list));
94 
95     EXPECT_EQ(test_case.expected_feature_on_state,
96               FeatureList::IsEnabled(kFeatureOnByDefault))
97         << i;
98     EXPECT_EQ(test_case.expected_feature_off_state,
99               FeatureList::IsEnabled(kFeatureOffByDefault))
100         << i;
101   }
102 }
103 
TEST_F(FeatureListTest,InitializeFromCommandLineWithFeatureParams)104 TEST_F(FeatureListTest, InitializeFromCommandLineWithFeatureParams) {
105   struct {
106     const std::string enable_features;
107     const std::string expected_field_trial_created;
108     const std::map<std::string, std::string> expected_feature_params;
109   } test_cases[] = {
110       {"Feature:x/100/y/test", "StudyFeature", {{"x", "100"}, {"y", "test"}}},
111       {"Feature<Trial1:x/200/y/123", "Trial1", {{"x", "200"}, {"y", "123"}}},
112       {"Feature<Trial2.Group2:x/test/y/uma/z/ukm",
113        "Trial2",
114        {{"x", "test"}, {"y", "uma"}, {"z", "ukm"}}},
115   };
116 
117   const Feature kFeature = {"Feature", FEATURE_DISABLED_BY_DEFAULT};
118   for (const auto& test_case : test_cases) {
119     SCOPED_TRACE(test_case.enable_features);
120 
121     auto feature_list = std::make_unique<FeatureList>();
122     feature_list->InitializeFromCommandLine(test_case.enable_features, "");
123     test::ScopedFeatureList scoped_feature_list;
124     scoped_feature_list.InitWithFeatureList(std::move(feature_list));
125 
126     EXPECT_TRUE(FeatureList::IsEnabled(kFeature));
127     EXPECT_TRUE(
128         FieldTrialList::IsTrialActive(test_case.expected_field_trial_created));
129     std::map<std::string, std::string> actualParams;
130     EXPECT_TRUE(GetFieldTrialParamsByFeature(kFeature, &actualParams));
131     EXPECT_EQ(test_case.expected_feature_params, actualParams);
132   }
133 }
134 
TEST_F(FeatureListTest,CheckFeatureIdentity)135 TEST_F(FeatureListTest, CheckFeatureIdentity) {
136   // Tests that CheckFeatureIdentity() correctly detects when two different
137   // structs with the same feature name are passed to it.
138 
139   test::ScopedFeatureList scoped_feature_list;
140   scoped_feature_list.InitWithFeatureList(std::make_unique<FeatureList>());
141   FeatureList* feature_list = FeatureList::GetInstance();
142 
143   // Call it twice for each feature at the top of the file, since the first call
144   // makes it remember the entry and the second call will verify it.
145   EXPECT_TRUE(feature_list->CheckFeatureIdentity(kFeatureOnByDefault));
146   EXPECT_TRUE(feature_list->CheckFeatureIdentity(kFeatureOnByDefault));
147   EXPECT_TRUE(feature_list->CheckFeatureIdentity(kFeatureOffByDefault));
148   EXPECT_TRUE(feature_list->CheckFeatureIdentity(kFeatureOffByDefault));
149 
150   // Now, call it with a distinct struct for |kFeatureOnByDefaultName|, which
151   // should return false.
152   struct Feature kFeatureOnByDefault2 {
153     kFeatureOnByDefaultName, FEATURE_ENABLED_BY_DEFAULT
154   };
155   EXPECT_FALSE(feature_list->CheckFeatureIdentity(kFeatureOnByDefault2));
156 }
157 
TEST_F(FeatureListTest,FieldTrialOverrides)158 TEST_F(FeatureListTest, FieldTrialOverrides) {
159   struct {
160     FeatureList::OverrideState trial1_state;
161     FeatureList::OverrideState trial2_state;
162   } test_cases[] = {
163       {FeatureList::OVERRIDE_DISABLE_FEATURE,
164        FeatureList::OVERRIDE_DISABLE_FEATURE},
165       {FeatureList::OVERRIDE_DISABLE_FEATURE,
166        FeatureList::OVERRIDE_ENABLE_FEATURE},
167       {FeatureList::OVERRIDE_ENABLE_FEATURE,
168        FeatureList::OVERRIDE_DISABLE_FEATURE},
169       {FeatureList::OVERRIDE_ENABLE_FEATURE,
170        FeatureList::OVERRIDE_ENABLE_FEATURE},
171   };
172 
173   FieldTrial::ActiveGroup active_group;
174   for (size_t i = 0; i < base::size(test_cases); ++i) {
175     const auto& test_case = test_cases[i];
176     SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]", i));
177 
178     test::ScopedFieldTrialListResetter resetter;
179     FieldTrialList field_trial_list(nullptr);
180     auto feature_list = std::make_unique<FeatureList>();
181 
182     FieldTrial* trial1 = FieldTrialList::CreateFieldTrial("TrialExample1", "A");
183     FieldTrial* trial2 = FieldTrialList::CreateFieldTrial("TrialExample2", "B");
184     feature_list->RegisterFieldTrialOverride(kFeatureOnByDefaultName,
185                                              test_case.trial1_state, trial1);
186     feature_list->RegisterFieldTrialOverride(kFeatureOffByDefaultName,
187                                              test_case.trial2_state, trial2);
188     test::ScopedFeatureList scoped_feature_list;
189     scoped_feature_list.InitWithFeatureList(std::move(feature_list));
190 
191     // Initially, neither trial should be active.
192     EXPECT_FALSE(FieldTrialList::IsTrialActive(trial1->trial_name()));
193     EXPECT_FALSE(FieldTrialList::IsTrialActive(trial2->trial_name()));
194 
195     const bool expected_enabled_1 =
196         (test_case.trial1_state == FeatureList::OVERRIDE_ENABLE_FEATURE);
197     EXPECT_EQ(expected_enabled_1, FeatureList::IsEnabled(kFeatureOnByDefault));
198     // The above should have activated |trial1|.
199     EXPECT_TRUE(FieldTrialList::IsTrialActive(trial1->trial_name()));
200     EXPECT_FALSE(FieldTrialList::IsTrialActive(trial2->trial_name()));
201 
202     const bool expected_enabled_2 =
203         (test_case.trial2_state == FeatureList::OVERRIDE_ENABLE_FEATURE);
204     EXPECT_EQ(expected_enabled_2, FeatureList::IsEnabled(kFeatureOffByDefault));
205     // The above should have activated |trial2|.
206     EXPECT_TRUE(FieldTrialList::IsTrialActive(trial1->trial_name()));
207     EXPECT_TRUE(FieldTrialList::IsTrialActive(trial2->trial_name()));
208   }
209 }
210 
TEST_F(FeatureListTest,FieldTrialAssociateUseDefault)211 TEST_F(FeatureListTest, FieldTrialAssociateUseDefault) {
212   auto feature_list = std::make_unique<FeatureList>();
213 
214   FieldTrial* trial1 = FieldTrialList::CreateFieldTrial("TrialExample1", "A");
215   FieldTrial* trial2 = FieldTrialList::CreateFieldTrial("TrialExample2", "B");
216   feature_list->RegisterFieldTrialOverride(
217       kFeatureOnByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT, trial1);
218   feature_list->RegisterFieldTrialOverride(
219       kFeatureOffByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT, trial2);
220   test::ScopedFeatureList scoped_feature_list;
221   scoped_feature_list.InitWithFeatureList(std::move(feature_list));
222 
223   // Initially, neither trial should be active.
224   EXPECT_FALSE(FieldTrialList::IsTrialActive(trial1->trial_name()));
225   EXPECT_FALSE(FieldTrialList::IsTrialActive(trial2->trial_name()));
226 
227   // Check the feature enabled state is its default.
228   EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault));
229   // The above should have activated |trial1|.
230   EXPECT_TRUE(FieldTrialList::IsTrialActive(trial1->trial_name()));
231   EXPECT_FALSE(FieldTrialList::IsTrialActive(trial2->trial_name()));
232 
233   // Check the feature enabled state is its default.
234   EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
235   // The above should have activated |trial2|.
236   EXPECT_TRUE(FieldTrialList::IsTrialActive(trial1->trial_name()));
237   EXPECT_TRUE(FieldTrialList::IsTrialActive(trial2->trial_name()));
238 }
239 
TEST_F(FeatureListTest,CommandLineEnableTakesPrecedenceOverFieldTrial)240 TEST_F(FeatureListTest, CommandLineEnableTakesPrecedenceOverFieldTrial) {
241   auto feature_list = std::make_unique<FeatureList>();
242 
243   // The feature is explicitly enabled on the command-line.
244   feature_list->InitializeFromCommandLine(kFeatureOffByDefaultName, "");
245 
246   // But the FieldTrial would set the feature to disabled.
247   FieldTrial* trial = FieldTrialList::CreateFieldTrial("TrialExample2", "A");
248   feature_list->RegisterFieldTrialOverride(
249       kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE, trial);
250   test::ScopedFeatureList scoped_feature_list;
251   scoped_feature_list.InitWithFeatureList(std::move(feature_list));
252 
253   EXPECT_FALSE(FieldTrialList::IsTrialActive(trial->trial_name()));
254   // Command-line should take precedence.
255   EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault));
256   // Since the feature is on due to the command-line, and not as a result of the
257   // field trial, the field trial should not be activated (since the Associate*
258   // API wasn't used.)
259   EXPECT_FALSE(FieldTrialList::IsTrialActive(trial->trial_name()));
260 }
261 
TEST_F(FeatureListTest,CommandLineDisableTakesPrecedenceOverFieldTrial)262 TEST_F(FeatureListTest, CommandLineDisableTakesPrecedenceOverFieldTrial) {
263   auto feature_list = std::make_unique<FeatureList>();
264 
265   // The feature is explicitly disabled on the command-line.
266   feature_list->InitializeFromCommandLine("", kFeatureOffByDefaultName);
267 
268   // But the FieldTrial would set the feature to enabled.
269   FieldTrial* trial = FieldTrialList::CreateFieldTrial("TrialExample2", "A");
270   feature_list->RegisterFieldTrialOverride(
271       kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE, trial);
272   test::ScopedFeatureList scoped_feature_list;
273   scoped_feature_list.InitWithFeatureList(std::move(feature_list));
274 
275   EXPECT_FALSE(FieldTrialList::IsTrialActive(trial->trial_name()));
276   // Command-line should take precedence.
277   EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
278   // Since the feature is on due to the command-line, and not as a result of the
279   // field trial, the field trial should not be activated (since the Associate*
280   // API wasn't used.)
281   EXPECT_FALSE(FieldTrialList::IsTrialActive(trial->trial_name()));
282 }
283 
TEST_F(FeatureListTest,IsFeatureOverriddenFromFieldTrial)284 TEST_F(FeatureListTest, IsFeatureOverriddenFromFieldTrial) {
285   auto feature_list = std::make_unique<FeatureList>();
286 
287   // No features are overridden from the field trails yet.
288   EXPECT_FALSE(feature_list->IsFeatureOverridden(kFeatureOnByDefaultName));
289   EXPECT_FALSE(feature_list->IsFeatureOverridden(kFeatureOffByDefaultName));
290 
291   // Now, register a field trial to override |kFeatureOnByDefaultName| state
292   // and check that the function still returns false for that feature.
293   feature_list->RegisterFieldTrialOverride(
294       kFeatureOffByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT,
295       FieldTrialList::CreateFieldTrial("Trial1", "A"));
296   feature_list->RegisterFieldTrialOverride(
297       kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE,
298       FieldTrialList::CreateFieldTrial("Trial2", "A"));
299   EXPECT_TRUE(feature_list->IsFeatureOverridden(kFeatureOnByDefaultName));
300   EXPECT_TRUE(feature_list->IsFeatureOverridden(kFeatureOffByDefaultName));
301 
302   test::ScopedFeatureList scoped_feature_list;
303   scoped_feature_list.InitWithFeatureList(std::move(feature_list));
304   // Check the expected feature states for good measure.
305   EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
306   EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault));
307 }
308 
TEST_F(FeatureListTest,IsFeatureOverriddenFromCommandLine)309 TEST_F(FeatureListTest, IsFeatureOverriddenFromCommandLine) {
310   auto feature_list = std::make_unique<FeatureList>();
311 
312   // No features are overridden from the command line yet
313   EXPECT_FALSE(feature_list->IsFeatureOverridden(kFeatureOnByDefaultName));
314   EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
315       kFeatureOnByDefaultName));
316   EXPECT_FALSE(feature_list->IsFeatureOverridden(kFeatureOffByDefaultName));
317   EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
318       kFeatureOffByDefaultName));
319   EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
320       kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE));
321   EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
322       kFeatureOnByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE));
323   EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
324       kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE));
325   EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
326       kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE));
327 
328   // Now, enable |kFeatureOffByDefaultName| via the command-line.
329   feature_list->InitializeFromCommandLine(kFeatureOffByDefaultName, "");
330 
331   // It should now be overridden for the enabled group.
332   EXPECT_TRUE(feature_list->IsFeatureOverridden(kFeatureOffByDefaultName));
333   EXPECT_TRUE(feature_list->IsFeatureOverriddenFromCommandLine(
334       kFeatureOffByDefaultName));
335   EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
336       kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE));
337   EXPECT_TRUE(feature_list->IsFeatureOverriddenFromCommandLine(
338       kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE));
339 
340   // Register a field trial to associate with the feature and ensure that the
341   // results are still the same.
342   feature_list->AssociateReportingFieldTrial(
343       kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE,
344       FieldTrialList::CreateFieldTrial("Trial1", "A"));
345   EXPECT_TRUE(feature_list->IsFeatureOverridden(kFeatureOffByDefaultName));
346   EXPECT_TRUE(feature_list->IsFeatureOverriddenFromCommandLine(
347       kFeatureOffByDefaultName));
348   EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
349       kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE));
350   EXPECT_TRUE(feature_list->IsFeatureOverriddenFromCommandLine(
351       kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE));
352 
353   // Now, register a field trial to override |kFeatureOnByDefaultName| state
354   // and check that the function still returns false for that feature.
355   feature_list->RegisterFieldTrialOverride(
356       kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE,
357       FieldTrialList::CreateFieldTrial("Trial2", "A"));
358   EXPECT_TRUE(feature_list->IsFeatureOverridden(kFeatureOnByDefaultName));
359   EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
360       kFeatureOnByDefaultName));
361   EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
362       kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE));
363   EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
364       kFeatureOnByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE));
365   test::ScopedFeatureList scoped_feature_list;
366   scoped_feature_list.InitWithFeatureList(std::move(feature_list));
367 
368   // Check the expected feature states for good measure.
369   EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault));
370   EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault));
371 }
372 
TEST_F(FeatureListTest,AssociateReportingFieldTrial)373 TEST_F(FeatureListTest, AssociateReportingFieldTrial) {
374   struct {
375     const char* enable_features;
376     const char* disable_features;
377     bool expected_enable_trial_created;
378     bool expected_disable_trial_created;
379   } test_cases[] = {
380       // If no enable/disable flags are specified, no trials should be created.
381       {"", "", false, false},
382       // Enabling the feature should result in the enable trial created.
383       {kFeatureOffByDefaultName, "", true, false},
384       // Disabling the feature should result in the disable trial created.
385       {"", kFeatureOffByDefaultName, false, true},
386   };
387 
388   const char kTrialName[] = "ForcingTrial";
389   const char kForcedOnGroupName[] = "ForcedOn";
390   const char kForcedOffGroupName[] = "ForcedOff";
391 
392   for (size_t i = 0; i < base::size(test_cases); ++i) {
393     const auto& test_case = test_cases[i];
394     SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: [%s] [%s]", i,
395                                     test_case.enable_features,
396                                     test_case.disable_features));
397 
398     test::ScopedFieldTrialListResetter resetter;
399     FieldTrialList field_trial_list(nullptr);
400     auto feature_list = std::make_unique<FeatureList>();
401     feature_list->InitializeFromCommandLine(test_case.enable_features,
402                                             test_case.disable_features);
403 
404     FieldTrial* enable_trial = nullptr;
405     if (feature_list->IsFeatureOverriddenFromCommandLine(
406             kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE)) {
407       enable_trial = base::FieldTrialList::CreateFieldTrial(kTrialName,
408                                                             kForcedOnGroupName);
409       feature_list->AssociateReportingFieldTrial(
410           kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE,
411           enable_trial);
412     }
413     FieldTrial* disable_trial = nullptr;
414     if (feature_list->IsFeatureOverriddenFromCommandLine(
415             kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE)) {
416       disable_trial = base::FieldTrialList::CreateFieldTrial(
417           kTrialName, kForcedOffGroupName);
418       feature_list->AssociateReportingFieldTrial(
419           kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE,
420           disable_trial);
421     }
422     EXPECT_EQ(test_case.expected_enable_trial_created, enable_trial != nullptr);
423     EXPECT_EQ(test_case.expected_disable_trial_created,
424               disable_trial != nullptr);
425     test::ScopedFeatureList scoped_feature_list;
426     scoped_feature_list.InitWithFeatureList(std::move(feature_list));
427 
428     EXPECT_FALSE(FieldTrialList::IsTrialActive(kTrialName));
429     if (disable_trial) {
430       EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
431       EXPECT_TRUE(FieldTrialList::IsTrialActive(kTrialName));
432       EXPECT_EQ(kForcedOffGroupName, disable_trial->group_name());
433     } else if (enable_trial) {
434       EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault));
435       EXPECT_TRUE(FieldTrialList::IsTrialActive(kTrialName));
436       EXPECT_EQ(kForcedOnGroupName, enable_trial->group_name());
437     }
438   }
439 }
440 
TEST_F(FeatureListTest,RegisterExtraFeatureOverrides)441 TEST_F(FeatureListTest, RegisterExtraFeatureOverrides) {
442   auto feature_list = std::make_unique<FeatureList>();
443   std::vector<FeatureList::FeatureOverrideInfo> overrides;
444   overrides.push_back({std::cref(kFeatureOnByDefault),
445                        FeatureList::OverrideState::OVERRIDE_DISABLE_FEATURE});
446   overrides.push_back({std::cref(kFeatureOffByDefault),
447                        FeatureList::OverrideState::OVERRIDE_ENABLE_FEATURE});
448   feature_list->RegisterExtraFeatureOverrides(std::move(overrides));
449   test::ScopedFeatureList scoped_feature_list;
450   scoped_feature_list.InitWithFeatureList(std::move(feature_list));
451 
452   EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault));
453   EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault));
454 }
455 
TEST_F(FeatureListTest,InitializeFromCommandLineThenRegisterExtraOverrides)456 TEST_F(FeatureListTest, InitializeFromCommandLineThenRegisterExtraOverrides) {
457   auto feature_list = std::make_unique<FeatureList>();
458   feature_list->InitializeFromCommandLine(kFeatureOnByDefaultName,
459                                           kFeatureOffByDefaultName);
460   std::vector<FeatureList::FeatureOverrideInfo> overrides;
461   overrides.push_back({std::cref(kFeatureOnByDefault),
462                        FeatureList::OverrideState::OVERRIDE_DISABLE_FEATURE});
463   overrides.push_back({std::cref(kFeatureOffByDefault),
464                        FeatureList::OverrideState::OVERRIDE_ENABLE_FEATURE});
465   feature_list->RegisterExtraFeatureOverrides(std::move(overrides));
466   test::ScopedFeatureList scoped_feature_list;
467   scoped_feature_list.InitWithFeatureList(std::move(feature_list));
468 
469   // The InitializeFromCommandLine supersedes the RegisterExtraFeatureOverrides
470   // because it was called first.
471   EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault));
472   EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
473 
474   std::string enable_features;
475   std::string disable_features;
476   FeatureList::GetInstance()->GetFeatureOverrides(&enable_features,
477                                                   &disable_features);
478   EXPECT_EQ(kFeatureOnByDefaultName, SortFeatureListString(enable_features));
479   EXPECT_EQ(kFeatureOffByDefaultName, SortFeatureListString(disable_features));
480 }
481 
TEST_F(FeatureListTest,GetFeatureOverrides)482 TEST_F(FeatureListTest, GetFeatureOverrides) {
483   auto feature_list = std::make_unique<FeatureList>();
484   feature_list->InitializeFromCommandLine("A,X", "D");
485 
486   Feature feature_b = {"B", FEATURE_ENABLED_BY_DEFAULT};
487   Feature feature_c = {"C", FEATURE_DISABLED_BY_DEFAULT};
488   std::vector<FeatureList::FeatureOverrideInfo> overrides;
489   overrides.push_back({std::cref(feature_b),
490                        FeatureList::OverrideState::OVERRIDE_DISABLE_FEATURE});
491   overrides.push_back({std::cref(feature_c),
492                        FeatureList::OverrideState::OVERRIDE_ENABLE_FEATURE});
493   feature_list->RegisterExtraFeatureOverrides(std::move(overrides));
494 
495   FieldTrial* trial = FieldTrialList::CreateFieldTrial("Trial", "Group");
496   feature_list->RegisterFieldTrialOverride(kFeatureOffByDefaultName,
497                                            FeatureList::OVERRIDE_ENABLE_FEATURE,
498                                            trial);
499 
500   test::ScopedFeatureList scoped_feature_list;
501   scoped_feature_list.InitWithFeatureList(std::move(feature_list));
502 
503   std::string enable_features;
504   std::string disable_features;
505   FeatureList::GetInstance()->GetFeatureOverrides(&enable_features,
506                                                   &disable_features);
507   EXPECT_EQ("A,C,OffByDefault<Trial,X", SortFeatureListString(enable_features));
508   EXPECT_EQ("B,D", SortFeatureListString(disable_features));
509 
510   FeatureList::GetInstance()->GetCommandLineFeatureOverrides(&enable_features,
511                                                              &disable_features);
512   EXPECT_EQ("A,C,X", SortFeatureListString(enable_features));
513   EXPECT_EQ("B,D", SortFeatureListString(disable_features));
514 }
515 
TEST_F(FeatureListTest,GetFeatureOverrides_UseDefault)516 TEST_F(FeatureListTest, GetFeatureOverrides_UseDefault) {
517   auto feature_list = std::make_unique<FeatureList>();
518   feature_list->InitializeFromCommandLine("A,X", "D");
519 
520   FieldTrial* trial = FieldTrialList::CreateFieldTrial("Trial", "Group");
521   feature_list->RegisterFieldTrialOverride(
522       kFeatureOffByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT, trial);
523 
524   test::ScopedFeatureList scoped_feature_list;
525   scoped_feature_list.InitWithFeatureList(std::move(feature_list));
526 
527   std::string enable_features;
528   std::string disable_features;
529   FeatureList::GetInstance()->GetFeatureOverrides(&enable_features,
530                                                   &disable_features);
531   EXPECT_EQ("*OffByDefault<Trial,A,X", SortFeatureListString(enable_features));
532   EXPECT_EQ("D", SortFeatureListString(disable_features));
533 }
534 
TEST_F(FeatureListTest,GetFieldTrial)535 TEST_F(FeatureListTest, GetFieldTrial) {
536   FieldTrial* trial = FieldTrialList::CreateFieldTrial("Trial", "Group");
537   auto feature_list = std::make_unique<FeatureList>();
538   feature_list->RegisterFieldTrialOverride(
539       kFeatureOnByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT, trial);
540   test::ScopedFeatureList scoped_feature_list;
541   scoped_feature_list.InitWithFeatureList(std::move(feature_list));
542 
543   EXPECT_EQ(trial, FeatureList::GetFieldTrial(kFeatureOnByDefault));
544   EXPECT_EQ(nullptr, FeatureList::GetFieldTrial(kFeatureOffByDefault));
545 }
546 
TEST_F(FeatureListTest,InitializeFromCommandLine_WithFieldTrials)547 TEST_F(FeatureListTest, InitializeFromCommandLine_WithFieldTrials) {
548   FieldTrialList::CreateFieldTrial("Trial", "Group");
549   auto feature_list = std::make_unique<FeatureList>();
550   feature_list->InitializeFromCommandLine("A,OffByDefault<Trial,X", "D");
551   test::ScopedFeatureList scoped_feature_list;
552   scoped_feature_list.InitWithFeatureList(std::move(feature_list));
553 
554   EXPECT_FALSE(FieldTrialList::IsTrialActive("Trial"));
555   EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault));
556   EXPECT_TRUE(FieldTrialList::IsTrialActive("Trial"));
557 }
558 
TEST_F(FeatureListTest,InitializeFromCommandLine_UseDefault)559 TEST_F(FeatureListTest, InitializeFromCommandLine_UseDefault) {
560   FieldTrialList::CreateFieldTrial("T1", "Group");
561   FieldTrialList::CreateFieldTrial("T2", "Group");
562   auto feature_list = std::make_unique<FeatureList>();
563   feature_list->InitializeFromCommandLine(
564       "A,*OffByDefault<T1,*OnByDefault<T2,X", "D");
565   test::ScopedFeatureList scoped_feature_list;
566   scoped_feature_list.InitWithFeatureList(std::move(feature_list));
567 
568   EXPECT_FALSE(FieldTrialList::IsTrialActive("T1"));
569   EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
570   EXPECT_TRUE(FieldTrialList::IsTrialActive("T1"));
571 
572   EXPECT_FALSE(FieldTrialList::IsTrialActive("T2"));
573   EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault));
574   EXPECT_TRUE(FieldTrialList::IsTrialActive("T2"));
575 }
576 
TEST_F(FeatureListTest,InitializeInstance)577 TEST_F(FeatureListTest, InitializeInstance) {
578   std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
579   test::ScopedFeatureList scoped_feature_list;
580   scoped_feature_list.InitWithFeatureList(std::move(feature_list));
581 
582   EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault));
583   EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
584 
585   // Initialize from command line if we haven't yet.
586   FeatureList::InitializeInstance("", kFeatureOnByDefaultName);
587   EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault));
588   EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
589 
590   // Do not initialize from commandline if we have already.
591   FeatureList::InitializeInstance(kFeatureOffByDefaultName, "");
592   EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault));
593   EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
594 }
595 
TEST_F(FeatureListTest,UninitializedInstance_IsEnabledReturnsFalse)596 TEST_F(FeatureListTest, UninitializedInstance_IsEnabledReturnsFalse) {
597   std::unique_ptr<FeatureList> original_feature_list =
598       FeatureList::ClearInstanceForTesting();
599 
600   // This test case simulates the calling pattern found in code which does not
601   // explicitly initialize the features list.
602   // All IsEnabled() calls should return the default value in this scenario.
603   EXPECT_EQ(nullptr, FeatureList::GetInstance());
604   EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault));
605   EXPECT_EQ(nullptr, FeatureList::GetInstance());
606   EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
607 
608   if (original_feature_list)
609     FeatureList::RestoreInstanceForTesting(std::move(original_feature_list));
610 }
611 
TEST_F(FeatureListTest,StoreAndRetrieveFeaturesFromSharedMemory)612 TEST_F(FeatureListTest, StoreAndRetrieveFeaturesFromSharedMemory) {
613   std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
614 
615   // Create some overrides.
616   feature_list->RegisterOverride(kFeatureOffByDefaultName,
617                                  FeatureList::OVERRIDE_ENABLE_FEATURE, nullptr);
618   feature_list->RegisterOverride(
619       kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE, nullptr);
620   feature_list->FinalizeInitialization();
621 
622   // Create an allocator and store the overrides.
623   base::MappedReadOnlyRegion shm =
624       base::ReadOnlySharedMemoryRegion::Create(4 << 10);
625   WritableSharedPersistentMemoryAllocator allocator(std::move(shm.mapping), 1,
626                                                     "");
627   feature_list->AddFeaturesToAllocator(&allocator);
628 
629   std::unique_ptr<base::FeatureList> feature_list2(new base::FeatureList);
630 
631   // Check that the new feature list is empty.
632   EXPECT_FALSE(feature_list2->IsFeatureOverriddenFromCommandLine(
633       kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE));
634   EXPECT_FALSE(feature_list2->IsFeatureOverriddenFromCommandLine(
635       kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE));
636 
637   feature_list2->InitializeFromSharedMemory(&allocator);
638   // Check that the new feature list now has 2 overrides.
639   EXPECT_TRUE(feature_list2->IsFeatureOverriddenFromCommandLine(
640       kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE));
641   EXPECT_TRUE(feature_list2->IsFeatureOverriddenFromCommandLine(
642       kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE));
643 }
644 
TEST_F(FeatureListTest,StoreAndRetrieveAssociatedFeaturesFromSharedMemory)645 TEST_F(FeatureListTest, StoreAndRetrieveAssociatedFeaturesFromSharedMemory) {
646   std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
647 
648   // Create some overrides.
649   FieldTrial* trial1 = FieldTrialList::CreateFieldTrial("TrialExample1", "A");
650   FieldTrial* trial2 = FieldTrialList::CreateFieldTrial("TrialExample2", "B");
651   feature_list->RegisterFieldTrialOverride(
652       kFeatureOnByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT, trial1);
653   feature_list->RegisterFieldTrialOverride(
654       kFeatureOffByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT, trial2);
655   feature_list->FinalizeInitialization();
656 
657   // Create an allocator and store the overrides.
658   base::MappedReadOnlyRegion shm =
659       base::ReadOnlySharedMemoryRegion::Create(4 << 10);
660   WritableSharedPersistentMemoryAllocator allocator(std::move(shm.mapping), 1,
661                                                     "");
662   feature_list->AddFeaturesToAllocator(&allocator);
663 
664   std::unique_ptr<base::FeatureList> feature_list2(new base::FeatureList);
665   feature_list2->InitializeFromSharedMemory(&allocator);
666   feature_list2->FinalizeInitialization();
667 
668   // Check that the field trials are still associated.
669   FieldTrial* associated_trial1 =
670       feature_list2->GetAssociatedFieldTrial(kFeatureOnByDefault);
671   FieldTrial* associated_trial2 =
672       feature_list2->GetAssociatedFieldTrial(kFeatureOffByDefault);
673   EXPECT_EQ(associated_trial1, trial1);
674   EXPECT_EQ(associated_trial2, trial2);
675 }
676 
677 }  // namespace base
678