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.
5 #include "base/feature_list.h"
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"
30 constexpr char kFeatureOnByDefaultName[] = "OnByDefault";
31 CONSTINIT Feature kFeatureOnByDefault(kFeatureOnByDefaultName,
32 FEATURE_ENABLED_BY_DEFAULT);
34 constexpr char kFeatureOffByDefaultName[] = "OffByDefault";
35 CONSTINIT Feature kFeatureOffByDefault(kFeatureOffByDefaultName,
36 FEATURE_DISABLED_BY_DEFAULT);
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, ",");
47 class FeatureListTest : public testing::Test {
50 // Provide an empty FeatureList to each test by default.
51 scoped_feature_list_.InitWithFeatureList(std::make_unique<FeatureList>());
53 FeatureListTest(const FeatureListTest&) = delete;
54 FeatureListTest& operator=(const FeatureListTest&) = delete;
55 ~FeatureListTest() override = default;
58 test::ScopedFeatureList scoped_feature_list_;
61 TEST_F(FeatureListTest, DefaultStates) {
62 EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault));
63 EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
66 TEST_F(FeatureListTest, InitializeFromCommandLine) {
68 const char* enable_features;
69 const char* disable_features;
70 bool expected_feature_on_state;
71 bool expected_feature_off_state;
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},
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));
88 auto feature_list = std::make_unique<FeatureList>();
89 feature_list->InitializeFromCommandLine(test_case.enable_features,
90 test_case.disable_features);
91 test::ScopedFeatureList scoped_feature_list;
92 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
94 EXPECT_EQ(test_case.expected_feature_on_state,
95 FeatureList::IsEnabled(kFeatureOnByDefault))
97 EXPECT_EQ(test_case.expected_feature_off_state,
98 FeatureList::IsEnabled(kFeatureOffByDefault))
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))
107 EXPECT_EQ(test_case.expected_feature_off_state,
108 FeatureList::IsEnabled(kFeatureOffByDefault))
113 TEST_F(FeatureListTest, InitializeFromCommandLineWithFeatureParams) {
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;
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",
123 {{"x", "test"}, {"y", "uma"}, {"z", "ukm"}}},
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
129 base::FieldTrialParamAssociator::GetInstance()->ClearAllParamsForTesting();
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);
135 auto feature_list = std::make_unique<FeatureList>();
136 feature_list->InitializeFromCommandLine(test_case.enable_features, "");
137 test::ScopedFeatureList scoped_feature_list;
138 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
140 EXPECT_TRUE(FeatureList::IsEnabled(kFeature));
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);
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.
153 test::ScopedFeatureList scoped_feature_list;
154 scoped_feature_list.InitWithFeatureList(std::make_unique<FeatureList>());
155 FeatureList* feature_list = FeatureList::GetInstance();
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));
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
169 EXPECT_FALSE(feature_list->CheckFeatureIdentity(kFeatureOnByDefault2));
172 TEST_F(FeatureListTest, FieldTrialOverrides) {
174 FeatureList::OverrideState trial1_state;
175 FeatureList::OverrideState trial2_state;
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},
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));
192 test::ScopedFeatureList outer_scope;
193 outer_scope.InitWithEmptyFeatureAndFieldTrialLists();
195 auto feature_list = std::make_unique<FeatureList>();
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));
206 // Initially, neither trial should be active.
207 EXPECT_FALSE(FieldTrialList::IsTrialActive(trial1->trial_name()));
208 EXPECT_FALSE(FieldTrialList::IsTrialActive(trial2->trial_name()));
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()));
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()));
226 TEST_F(FeatureListTest, FieldTrialAssociateUseDefault) {
227 auto feature_list = std::make_unique<FeatureList>();
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));
238 // Initially, neither trial should be active.
239 EXPECT_FALSE(FieldTrialList::IsTrialActive(trial1->trial_name()));
240 EXPECT_FALSE(FieldTrialList::IsTrialActive(trial2->trial_name()));
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()));
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()));
255 TEST_F(FeatureListTest, CommandLineEnableTakesPrecedenceOverFieldTrial) {
256 auto feature_list = std::make_unique<FeatureList>();
258 // The feature is explicitly enabled on the command-line.
259 feature_list->InitializeFromCommandLine(kFeatureOffByDefaultName, "");
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));
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*
274 EXPECT_FALSE(FieldTrialList::IsTrialActive(trial->trial_name()));
277 TEST_F(FeatureListTest, CommandLineDisableTakesPrecedenceOverFieldTrial) {
278 auto feature_list = std::make_unique<FeatureList>();
280 // The feature is explicitly disabled on the command-line.
281 feature_list->InitializeFromCommandLine("", kFeatureOffByDefaultName);
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));
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*
296 EXPECT_FALSE(FieldTrialList::IsTrialActive(trial->trial_name()));
299 TEST_F(FeatureListTest, IsFeatureOverriddenFromFieldTrial) {
300 auto feature_list = std::make_unique<FeatureList>();
302 // No features are overridden from the field trails yet.
303 EXPECT_FALSE(feature_list->IsFeatureOverridden(kFeatureOnByDefaultName));
304 EXPECT_FALSE(feature_list->IsFeatureOverridden(kFeatureOffByDefaultName));
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));
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));
324 TEST_F(FeatureListTest, IsFeatureOverriddenFromCommandLine) {
325 auto feature_list = std::make_unique<FeatureList>();
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));
343 // Now, enable |kFeatureOffByDefaultName| via the command-line.
344 feature_list->InitializeFromCommandLine(kFeatureOffByDefaultName, "");
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));
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));
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));
383 // Check the expected feature states for good measure.
384 EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault));
385 EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault));
388 TEST_F(FeatureListTest, AssociateReportingFieldTrial) {
390 const char* enable_features;
391 const char* disable_features;
392 bool expected_enable_trial_created;
393 bool expected_disable_trial_created;
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},
403 const char kTrialName[] = "ForcingTrial";
404 const char kForcedOnGroupName[] = "ForcedOn";
405 const char kForcedOffGroupName[] = "ForcedOff";
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));
413 test::ScopedFeatureList outer_scope;
414 outer_scope.InitWithEmptyFeatureAndFieldTrialLists();
416 auto feature_list = std::make_unique<FeatureList>();
417 feature_list->InitializeFromCommandLine(test_case.enable_features,
418 test_case.disable_features);
420 FieldTrial* enable_trial = nullptr;
421 if (feature_list->IsFeatureOverriddenFromCommandLine(
422 kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE)) {
423 enable_trial = base::FieldTrialList::CreateFieldTrial(kTrialName,
425 feature_list->AssociateReportingFieldTrial(
426 kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE,
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,
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));
444 EXPECT_FALSE(FieldTrialList::IsTrialActive(kTrialName));
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());
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));
468 EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault));
469 EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault));
472 TEST_F(FeatureListTest, InitializeFromCommandLineThenRegisterExtraOverrides) {
473 auto feature_list = std::make_unique<FeatureList>();
474 feature_list->InitializeFromCommandLine(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));
485 // The InitializeFromCommandLine supersedes the RegisterExtraFeatureOverrides
486 // because it was called first.
487 EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault));
488 EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
490 std::string enable_features;
491 std::string disable_features;
492 FeatureList::GetInstance()->GetFeatureOverrides(&enable_features,
494 EXPECT_EQ(kFeatureOnByDefaultName, SortFeatureListString(enable_features));
495 EXPECT_EQ(kFeatureOffByDefaultName, SortFeatureListString(disable_features));
498 TEST_F(FeatureListTest, GetFeatureOverrides) {
499 auto feature_list = std::make_unique<FeatureList>();
500 feature_list->InitializeFromCommandLine("A,X", "D");
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));
511 FieldTrial* trial = FieldTrialList::CreateFieldTrial("Trial", "Group");
512 feature_list->RegisterFieldTrialOverride(kFeatureOffByDefaultName,
513 FeatureList::OVERRIDE_ENABLE_FEATURE,
516 test::ScopedFeatureList scoped_feature_list;
517 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
519 std::string enable_features;
520 std::string disable_features;
521 FeatureList::GetInstance()->GetFeatureOverrides(&enable_features,
523 EXPECT_EQ("A,C,OffByDefault<Trial,X", SortFeatureListString(enable_features));
524 EXPECT_EQ("B,D", SortFeatureListString(disable_features));
526 FeatureList::GetInstance()->GetCommandLineFeatureOverrides(&enable_features,
528 EXPECT_EQ("A,C,X", SortFeatureListString(enable_features));
529 EXPECT_EQ("B,D", SortFeatureListString(disable_features));
532 TEST_F(FeatureListTest, GetFeatureOverrides_UseDefault) {
533 auto feature_list = std::make_unique<FeatureList>();
534 feature_list->InitializeFromCommandLine("A,X", "D");
536 FieldTrial* trial = FieldTrialList::CreateFieldTrial("Trial", "Group");
537 feature_list->RegisterFieldTrialOverride(
538 kFeatureOffByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT, trial);
540 test::ScopedFeatureList scoped_feature_list;
541 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
543 std::string enable_features;
544 std::string disable_features;
545 FeatureList::GetInstance()->GetFeatureOverrides(&enable_features,
547 EXPECT_EQ("*OffByDefault<Trial,A,X", SortFeatureListString(enable_features));
548 EXPECT_EQ("D", SortFeatureListString(disable_features));
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));
559 EXPECT_EQ(trial, FeatureList::GetFieldTrial(kFeatureOnByDefault));
560 EXPECT_EQ(nullptr, FeatureList::GetFieldTrial(kFeatureOffByDefault));
563 TEST_F(FeatureListTest, InitializeFromCommandLine_WithFieldTrials) {
564 FieldTrialList::CreateFieldTrial("Trial", "Group");
565 auto feature_list = std::make_unique<FeatureList>();
566 feature_list->InitializeFromCommandLine("A,OffByDefault<Trial,X", "D");
567 test::ScopedFeatureList scoped_feature_list;
568 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
570 EXPECT_FALSE(FieldTrialList::IsTrialActive("Trial"));
571 EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault));
572 EXPECT_TRUE(FieldTrialList::IsTrialActive("Trial"));
575 TEST_F(FeatureListTest, InitializeFromCommandLine_UseDefault) {
576 FieldTrialList::CreateFieldTrial("T1", "Group");
577 FieldTrialList::CreateFieldTrial("T2", "Group");
578 auto feature_list = std::make_unique<FeatureList>();
579 feature_list->InitializeFromCommandLine(
580 "A,*OffByDefault<T1,*OnByDefault<T2,X", "D");
581 test::ScopedFeatureList scoped_feature_list;
582 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
584 EXPECT_FALSE(FieldTrialList::IsTrialActive("T1"));
585 EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
586 EXPECT_TRUE(FieldTrialList::IsTrialActive("T1"));
588 EXPECT_FALSE(FieldTrialList::IsTrialActive("T2"));
589 EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault));
590 EXPECT_TRUE(FieldTrialList::IsTrialActive("T2"));
593 TEST_F(FeatureListTest, InitializeInstance) {
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));
598 EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault));
599 EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
601 // Initialize from command line if we haven't yet.
602 FeatureList::InitializeInstance("", kFeatureOnByDefaultName);
603 EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault));
604 EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
606 // Do not initialize from commandline if we have already.
607 FeatureList::InitializeInstance(kFeatureOffByDefaultName, "");
608 EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault));
609 EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
612 TEST_F(FeatureListTest, UninitializedInstance_IsEnabledReturnsFalse) {
613 std::unique_ptr<FeatureList> original_feature_list =
614 FeatureList::ClearInstanceForTesting();
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));
624 if (original_feature_list)
625 FeatureList::RestoreInstanceForTesting(std::move(original_feature_list));
628 TEST_F(FeatureListTest, StoreAndRetrieveFeaturesFromSharedMemory) {
629 std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
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();
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,
643 feature_list->AddFeaturesToAllocator(&allocator);
645 std::unique_ptr<base::FeatureList> feature_list2(new base::FeatureList);
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));
653 feature_list2->InitializeFromSharedMemory(&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));
661 TEST_F(FeatureListTest, StoreAndRetrieveAssociatedFeaturesFromSharedMemory) {
662 std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
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();
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,
678 feature_list->AddFeaturesToAllocator(&allocator);
680 std::unique_ptr<base::FeatureList> feature_list2(new base::FeatureList);
681 feature_list2->InitializeFromSharedMemory(&allocator);
682 feature_list2->FinalizeInitialization();
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);
693 #if BUILDFLAG(ENABLE_BANNED_BASE_FEATURE_PREFIX) && \
694 defined(GTEST_HAS_DEATH_TEST)
695 using FeatureListDeathTest = FeatureListTest;
696 TEST_F(FeatureListDeathTest, DiesWithBadFeatureName) {
699 StrCat({BUILDFLAG(BANNED_BASE_FEATURE_PREFIX), "MyFeature"}).c_str(),
700 FEATURE_DISABLED_BY_DEFAULT),
701 StrCat({"Invalid feature name ", BUILDFLAG(BANNED_BASE_FEATURE_PREFIX),
704 #endif // BUILDFLAG(ENABLE_BANNED_BASE_FEATURE_PREFIX) &&
705 // defined(GTEST_HAS_DEATH_TEST)
707 TEST(FeatureListAccessorTest, DefaultStates) {
708 test::ScopedFeatureList scoped_feature_list;
709 auto feature_list = std::make_unique<FeatureList>();
710 auto feature_list_accessor = feature_list->ConstructAccessor();
711 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
713 EXPECT_EQ(feature_list_accessor->GetOverrideStateByFeatureName(
714 kFeatureOnByDefault.name),
715 FeatureList::OVERRIDE_USE_DEFAULT);
716 EXPECT_EQ(feature_list_accessor->GetOverrideStateByFeatureName(
717 kFeatureOffByDefault.name),
718 FeatureList::OVERRIDE_USE_DEFAULT);
721 TEST(FeatureListAccessorTest, InitializeFromCommandLine) {
723 const char* enable_features;
724 const char* disable_features;
725 FeatureList::OverrideState expected_feature_on_state;
726 FeatureList::OverrideState expected_feature_off_state;
728 {"", "", FeatureList::OVERRIDE_USE_DEFAULT,
729 FeatureList::OVERRIDE_USE_DEFAULT},
730 {"OffByDefault", "", FeatureList::OVERRIDE_USE_DEFAULT,
731 FeatureList::OVERRIDE_ENABLE_FEATURE},
732 {"OffByDefault", "OnByDefault", FeatureList::OVERRIDE_DISABLE_FEATURE,
733 FeatureList::OVERRIDE_ENABLE_FEATURE},
734 {"OnByDefault,OffByDefault", "", FeatureList::OVERRIDE_ENABLE_FEATURE,
735 FeatureList::OVERRIDE_ENABLE_FEATURE},
736 {"", "OnByDefault,OffByDefault", FeatureList::OVERRIDE_DISABLE_FEATURE,
737 FeatureList::OVERRIDE_DISABLE_FEATURE},
738 // In the case an entry is both, disable takes precedence.
739 {"OnByDefault", "OnByDefault,OffByDefault",
740 FeatureList::OVERRIDE_DISABLE_FEATURE,
741 FeatureList::OVERRIDE_DISABLE_FEATURE},
744 for (size_t i = 0; i < std::size(test_cases); ++i) {
745 const auto& test_case = test_cases[i];
746 SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: [%s] [%s]", i,
747 test_case.enable_features,
748 test_case.disable_features));
750 test::ScopedFeatureList scoped_feature_list;
751 auto feature_list = std::make_unique<FeatureList>();
752 auto feature_list_accessor = feature_list->ConstructAccessor();
753 feature_list->InitializeFromCommandLine(test_case.enable_features,
754 test_case.disable_features);
755 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
757 EXPECT_EQ(test_case.expected_feature_on_state,
758 feature_list_accessor->GetOverrideStateByFeatureName(
759 kFeatureOnByDefault.name))
761 EXPECT_EQ(test_case.expected_feature_off_state,
762 feature_list_accessor->GetOverrideStateByFeatureName(
763 kFeatureOffByDefault.name))
768 TEST(FeatureListAccessorTest, InitializeFromCommandLineWithFeatureParams) {
770 const std::string enable_features;
771 const std::map<std::string, std::string> expected_feature_params;
773 {"Feature:x/100/y/test", {{"x", "100"}, {"y", "test"}}},
774 {"Feature<Trial:asdf/ghjkl/y/123", {{"asdf", "ghjkl"}, {"y", "123"}}},
777 // Clear global state so that repeated runs of this test don't flake.
778 // When https://crrev.com/c/3694674 is submitted, we should be able to remove
780 base::FieldTrialParamAssociator::GetInstance()->ClearAllParamsForTesting();
782 for (size_t i = 0; i < std::size(test_cases); ++i) {
783 const auto& test_case = test_cases[i];
784 SCOPED_TRACE(test_case.enable_features);
786 test::ScopedFeatureList scoped_feature_list;
787 auto feature_list = std::make_unique<FeatureList>();
788 auto feature_list_accessor = feature_list->ConstructAccessor();
789 feature_list->InitializeFromCommandLine(test_case.enable_features, "");
790 scoped_feature_list.InitWithFeatureList(std::move(feature_list));
792 EXPECT_EQ(FeatureList::OVERRIDE_ENABLE_FEATURE,
793 feature_list_accessor->GetOverrideStateByFeatureName("Feature"))
795 std::map<std::string, std::string> actual_params;
796 EXPECT_TRUE(feature_list_accessor->GetParamsByFeatureName("Feature",
799 EXPECT_EQ(test_case.expected_feature_params, actual_params) << i;