|  | // Copyright 2015 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "base/feature_list.h" | 
|  |  | 
|  | #include <stddef.h> | 
|  |  | 
|  | #include <algorithm> | 
|  | #include <utility> | 
|  |  | 
|  | #include "base/format_macros.h" | 
|  | #include "base/macros.h" | 
|  | #include "base/memory/ptr_util.h" | 
|  | #include "base/metrics/field_trial.h" | 
|  | #include "base/metrics/persistent_memory_allocator.h" | 
|  | #include "base/strings/string_piece.h" | 
|  | #include "base/strings/string_util.h" | 
|  | #include "base/strings/stringprintf.h" | 
|  | #include "testing/gtest/include/gtest/gtest.h" | 
|  |  | 
|  | namespace base { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | constexpr char kFeatureOnByDefaultName[] = "OnByDefault"; | 
|  | struct Feature kFeatureOnByDefault { | 
|  | kFeatureOnByDefaultName, FEATURE_ENABLED_BY_DEFAULT | 
|  | }; | 
|  |  | 
|  | constexpr char kFeatureOffByDefaultName[] = "OffByDefault"; | 
|  | struct Feature kFeatureOffByDefault { | 
|  | kFeatureOffByDefaultName, FEATURE_DISABLED_BY_DEFAULT | 
|  | }; | 
|  |  | 
|  | std::string SortFeatureListString(const std::string& feature_list) { | 
|  | std::vector<base::StringPiece> features = | 
|  | FeatureList::SplitFeatureListString(feature_list); | 
|  | std::sort(features.begin(), features.end()); | 
|  | return JoinString(features, ","); | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | class FeatureListTest : public testing::Test { | 
|  | public: | 
|  | FeatureListTest() : feature_list_(nullptr) { | 
|  | RegisterFeatureListInstance(WrapUnique(new FeatureList)); | 
|  | } | 
|  | ~FeatureListTest() override { ClearFeatureListInstance(); } | 
|  |  | 
|  | void RegisterFeatureListInstance(std::unique_ptr<FeatureList> feature_list) { | 
|  | FeatureList::ClearInstanceForTesting(); | 
|  | feature_list_ = feature_list.get(); | 
|  | FeatureList::SetInstance(std::move(feature_list)); | 
|  | } | 
|  | void ClearFeatureListInstance() { | 
|  | FeatureList::ClearInstanceForTesting(); | 
|  | feature_list_ = nullptr; | 
|  | } | 
|  |  | 
|  | FeatureList* feature_list() { return feature_list_; } | 
|  |  | 
|  | private: | 
|  | // Weak. Owned by the FeatureList::SetInstance(). | 
|  | FeatureList* feature_list_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(FeatureListTest); | 
|  | }; | 
|  |  | 
|  | TEST_F(FeatureListTest, DefaultStates) { | 
|  | EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault)); | 
|  | EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault)); | 
|  | } | 
|  |  | 
|  | TEST_F(FeatureListTest, InitializeFromCommandLine) { | 
|  | struct { | 
|  | const char* enable_features; | 
|  | const char* disable_features; | 
|  | bool expected_feature_on_state; | 
|  | bool expected_feature_off_state; | 
|  | } test_cases[] = { | 
|  | {"", "", true, false}, | 
|  | {"OffByDefault", "", true, true}, | 
|  | {"OffByDefault", "OnByDefault", false, true}, | 
|  | {"OnByDefault,OffByDefault", "", true, true}, | 
|  | {"", "OnByDefault,OffByDefault", false, false}, | 
|  | // In the case an entry is both, disable takes precedence. | 
|  | {"OnByDefault", "OnByDefault,OffByDefault", false, false}, | 
|  | }; | 
|  |  | 
|  | for (size_t i = 0; i < arraysize(test_cases); ++i) { | 
|  | const auto& test_case = test_cases[i]; | 
|  | SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: [%s] [%s]", i, | 
|  | test_case.enable_features, | 
|  | test_case.disable_features)); | 
|  |  | 
|  | ClearFeatureListInstance(); | 
|  | std::unique_ptr<FeatureList> feature_list(new FeatureList); | 
|  | feature_list->InitializeFromCommandLine(test_case.enable_features, | 
|  | test_case.disable_features); | 
|  | RegisterFeatureListInstance(std::move(feature_list)); | 
|  |  | 
|  | EXPECT_EQ(test_case.expected_feature_on_state, | 
|  | FeatureList::IsEnabled(kFeatureOnByDefault)) | 
|  | << i; | 
|  | EXPECT_EQ(test_case.expected_feature_off_state, | 
|  | FeatureList::IsEnabled(kFeatureOffByDefault)) | 
|  | << i; | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_F(FeatureListTest, CheckFeatureIdentity) { | 
|  | // Tests that CheckFeatureIdentity() correctly detects when two different | 
|  | // structs with the same feature name are passed to it. | 
|  |  | 
|  | // Call it twice for each feature at the top of the file, since the first call | 
|  | // makes it remember the entry and the second call will verify it. | 
|  | EXPECT_TRUE(feature_list()->CheckFeatureIdentity(kFeatureOnByDefault)); | 
|  | EXPECT_TRUE(feature_list()->CheckFeatureIdentity(kFeatureOnByDefault)); | 
|  | EXPECT_TRUE(feature_list()->CheckFeatureIdentity(kFeatureOffByDefault)); | 
|  | EXPECT_TRUE(feature_list()->CheckFeatureIdentity(kFeatureOffByDefault)); | 
|  |  | 
|  | // Now, call it with a distinct struct for |kFeatureOnByDefaultName|, which | 
|  | // should return false. | 
|  | struct Feature kFeatureOnByDefault2 { | 
|  | kFeatureOnByDefaultName, FEATURE_ENABLED_BY_DEFAULT | 
|  | }; | 
|  | EXPECT_FALSE(feature_list()->CheckFeatureIdentity(kFeatureOnByDefault2)); | 
|  | } | 
|  |  | 
|  | TEST_F(FeatureListTest, FieldTrialOverrides) { | 
|  | struct { | 
|  | FeatureList::OverrideState trial1_state; | 
|  | FeatureList::OverrideState trial2_state; | 
|  | } test_cases[] = { | 
|  | {FeatureList::OVERRIDE_DISABLE_FEATURE, | 
|  | FeatureList::OVERRIDE_DISABLE_FEATURE}, | 
|  | {FeatureList::OVERRIDE_DISABLE_FEATURE, | 
|  | FeatureList::OVERRIDE_ENABLE_FEATURE}, | 
|  | {FeatureList::OVERRIDE_ENABLE_FEATURE, | 
|  | FeatureList::OVERRIDE_DISABLE_FEATURE}, | 
|  | {FeatureList::OVERRIDE_ENABLE_FEATURE, | 
|  | FeatureList::OVERRIDE_ENABLE_FEATURE}, | 
|  | }; | 
|  |  | 
|  | FieldTrial::ActiveGroup active_group; | 
|  | for (size_t i = 0; i < arraysize(test_cases); ++i) { | 
|  | const auto& test_case = test_cases[i]; | 
|  | SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]", i)); | 
|  |  | 
|  | ClearFeatureListInstance(); | 
|  |  | 
|  | FieldTrialList field_trial_list(nullptr); | 
|  | std::unique_ptr<FeatureList> feature_list(new FeatureList); | 
|  |  | 
|  | FieldTrial* trial1 = FieldTrialList::CreateFieldTrial("TrialExample1", "A"); | 
|  | FieldTrial* trial2 = FieldTrialList::CreateFieldTrial("TrialExample2", "B"); | 
|  | feature_list->RegisterFieldTrialOverride(kFeatureOnByDefaultName, | 
|  | test_case.trial1_state, trial1); | 
|  | feature_list->RegisterFieldTrialOverride(kFeatureOffByDefaultName, | 
|  | test_case.trial2_state, trial2); | 
|  | RegisterFeatureListInstance(std::move(feature_list)); | 
|  |  | 
|  | // Initially, neither trial should be active. | 
|  | EXPECT_FALSE(FieldTrialList::IsTrialActive(trial1->trial_name())); | 
|  | EXPECT_FALSE(FieldTrialList::IsTrialActive(trial2->trial_name())); | 
|  |  | 
|  | const bool expected_enabled_1 = | 
|  | (test_case.trial1_state == FeatureList::OVERRIDE_ENABLE_FEATURE); | 
|  | EXPECT_EQ(expected_enabled_1, FeatureList::IsEnabled(kFeatureOnByDefault)); | 
|  | // The above should have activated |trial1|. | 
|  | EXPECT_TRUE(FieldTrialList::IsTrialActive(trial1->trial_name())); | 
|  | EXPECT_FALSE(FieldTrialList::IsTrialActive(trial2->trial_name())); | 
|  |  | 
|  | const bool expected_enabled_2 = | 
|  | (test_case.trial2_state == FeatureList::OVERRIDE_ENABLE_FEATURE); | 
|  | EXPECT_EQ(expected_enabled_2, FeatureList::IsEnabled(kFeatureOffByDefault)); | 
|  | // The above should have activated |trial2|. | 
|  | EXPECT_TRUE(FieldTrialList::IsTrialActive(trial1->trial_name())); | 
|  | EXPECT_TRUE(FieldTrialList::IsTrialActive(trial2->trial_name())); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_F(FeatureListTest, FieldTrialAssociateUseDefault) { | 
|  | FieldTrialList field_trial_list(nullptr); | 
|  | std::unique_ptr<FeatureList> feature_list(new FeatureList); | 
|  |  | 
|  | FieldTrial* trial1 = FieldTrialList::CreateFieldTrial("TrialExample1", "A"); | 
|  | FieldTrial* trial2 = FieldTrialList::CreateFieldTrial("TrialExample2", "B"); | 
|  | feature_list->RegisterFieldTrialOverride( | 
|  | kFeatureOnByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT, trial1); | 
|  | feature_list->RegisterFieldTrialOverride( | 
|  | kFeatureOffByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT, trial2); | 
|  | RegisterFeatureListInstance(std::move(feature_list)); | 
|  |  | 
|  | // Initially, neither trial should be active. | 
|  | EXPECT_FALSE(FieldTrialList::IsTrialActive(trial1->trial_name())); | 
|  | EXPECT_FALSE(FieldTrialList::IsTrialActive(trial2->trial_name())); | 
|  |  | 
|  | // Check the feature enabled state is its default. | 
|  | EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault)); | 
|  | // The above should have activated |trial1|. | 
|  | EXPECT_TRUE(FieldTrialList::IsTrialActive(trial1->trial_name())); | 
|  | EXPECT_FALSE(FieldTrialList::IsTrialActive(trial2->trial_name())); | 
|  |  | 
|  | // Check the feature enabled state is its default. | 
|  | EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault)); | 
|  | // The above should have activated |trial2|. | 
|  | EXPECT_TRUE(FieldTrialList::IsTrialActive(trial1->trial_name())); | 
|  | EXPECT_TRUE(FieldTrialList::IsTrialActive(trial2->trial_name())); | 
|  | } | 
|  |  | 
|  | TEST_F(FeatureListTest, CommandLineTakesPrecedenceOverFieldTrial) { | 
|  | ClearFeatureListInstance(); | 
|  |  | 
|  | FieldTrialList field_trial_list(nullptr); | 
|  | std::unique_ptr<FeatureList> feature_list(new FeatureList); | 
|  |  | 
|  | // The feature is explicitly enabled on the command-line. | 
|  | feature_list->InitializeFromCommandLine(kFeatureOffByDefaultName, ""); | 
|  |  | 
|  | // But the FieldTrial would set the feature to disabled. | 
|  | FieldTrial* trial = FieldTrialList::CreateFieldTrial("TrialExample2", "A"); | 
|  | feature_list->RegisterFieldTrialOverride( | 
|  | kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE, trial); | 
|  | RegisterFeatureListInstance(std::move(feature_list)); | 
|  |  | 
|  | EXPECT_FALSE(FieldTrialList::IsTrialActive(trial->trial_name())); | 
|  | // Command-line should take precedence. | 
|  | EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault)); | 
|  | // Since the feature is on due to the command-line, and not as a result of the | 
|  | // field trial, the field trial should not be activated (since the Associate* | 
|  | // API wasn't used.) | 
|  | EXPECT_FALSE(FieldTrialList::IsTrialActive(trial->trial_name())); | 
|  | } | 
|  |  | 
|  | TEST_F(FeatureListTest, IsFeatureOverriddenFromCommandLine) { | 
|  | ClearFeatureListInstance(); | 
|  |  | 
|  | FieldTrialList field_trial_list(nullptr); | 
|  | std::unique_ptr<FeatureList> feature_list(new FeatureList); | 
|  |  | 
|  | // No features are overridden from the command line yet | 
|  | EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine( | 
|  | kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE)); | 
|  | EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine( | 
|  | kFeatureOnByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE)); | 
|  | EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine( | 
|  | kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE)); | 
|  | EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine( | 
|  | kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE)); | 
|  |  | 
|  | // Now, enable |kFeatureOffByDefaultName| via the command-line. | 
|  | feature_list->InitializeFromCommandLine(kFeatureOffByDefaultName, ""); | 
|  |  | 
|  | // It should now be overridden for the enabled group. | 
|  | EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine( | 
|  | kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE)); | 
|  | EXPECT_TRUE(feature_list->IsFeatureOverriddenFromCommandLine( | 
|  | kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE)); | 
|  |  | 
|  | // Register a field trial to associate with the feature and ensure that the | 
|  | // results are still the same. | 
|  | feature_list->AssociateReportingFieldTrial( | 
|  | kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE, | 
|  | FieldTrialList::CreateFieldTrial("Trial1", "A")); | 
|  | EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine( | 
|  | kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE)); | 
|  | EXPECT_TRUE(feature_list->IsFeatureOverriddenFromCommandLine( | 
|  | kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE)); | 
|  |  | 
|  | // Now, register a field trial to override |kFeatureOnByDefaultName| state | 
|  | // and check that the function still returns false for that feature. | 
|  | feature_list->RegisterFieldTrialOverride( | 
|  | kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE, | 
|  | FieldTrialList::CreateFieldTrial("Trial2", "A")); | 
|  | EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine( | 
|  | kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE)); | 
|  | EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine( | 
|  | kFeatureOnByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE)); | 
|  | RegisterFeatureListInstance(std::move(feature_list)); | 
|  |  | 
|  | // Check the expected feature states for good measure. | 
|  | EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault)); | 
|  | EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault)); | 
|  | } | 
|  |  | 
|  | TEST_F(FeatureListTest, AssociateReportingFieldTrial) { | 
|  | struct { | 
|  | const char* enable_features; | 
|  | const char* disable_features; | 
|  | bool expected_enable_trial_created; | 
|  | bool expected_disable_trial_created; | 
|  | } test_cases[] = { | 
|  | // If no enable/disable flags are specified, no trials should be created. | 
|  | {"", "", false, false}, | 
|  | // Enabling the feature should result in the enable trial created. | 
|  | {kFeatureOffByDefaultName, "", true, false}, | 
|  | // Disabling the feature should result in the disable trial created. | 
|  | {"", kFeatureOffByDefaultName, false, true}, | 
|  | }; | 
|  |  | 
|  | const char kTrialName[] = "ForcingTrial"; | 
|  | const char kForcedOnGroupName[] = "ForcedOn"; | 
|  | const char kForcedOffGroupName[] = "ForcedOff"; | 
|  |  | 
|  | for (size_t i = 0; i < arraysize(test_cases); ++i) { | 
|  | const auto& test_case = test_cases[i]; | 
|  | SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: [%s] [%s]", i, | 
|  | test_case.enable_features, | 
|  | test_case.disable_features)); | 
|  |  | 
|  | ClearFeatureListInstance(); | 
|  |  | 
|  | FieldTrialList field_trial_list(nullptr); | 
|  | std::unique_ptr<FeatureList> feature_list(new FeatureList); | 
|  | feature_list->InitializeFromCommandLine(test_case.enable_features, | 
|  | test_case.disable_features); | 
|  |  | 
|  | FieldTrial* enable_trial = nullptr; | 
|  | if (feature_list->IsFeatureOverriddenFromCommandLine( | 
|  | kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE)) { | 
|  | enable_trial = base::FieldTrialList::CreateFieldTrial(kTrialName, | 
|  | kForcedOnGroupName); | 
|  | feature_list->AssociateReportingFieldTrial( | 
|  | kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE, | 
|  | enable_trial); | 
|  | } | 
|  | FieldTrial* disable_trial = nullptr; | 
|  | if (feature_list->IsFeatureOverriddenFromCommandLine( | 
|  | kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE)) { | 
|  | disable_trial = base::FieldTrialList::CreateFieldTrial( | 
|  | kTrialName, kForcedOffGroupName); | 
|  | feature_list->AssociateReportingFieldTrial( | 
|  | kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE, | 
|  | disable_trial); | 
|  | } | 
|  | EXPECT_EQ(test_case.expected_enable_trial_created, enable_trial != nullptr); | 
|  | EXPECT_EQ(test_case.expected_disable_trial_created, | 
|  | disable_trial != nullptr); | 
|  | RegisterFeatureListInstance(std::move(feature_list)); | 
|  |  | 
|  | EXPECT_FALSE(FieldTrialList::IsTrialActive(kTrialName)); | 
|  | if (disable_trial) { | 
|  | EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault)); | 
|  | EXPECT_TRUE(FieldTrialList::IsTrialActive(kTrialName)); | 
|  | EXPECT_EQ(kForcedOffGroupName, disable_trial->group_name()); | 
|  | } else if (enable_trial) { | 
|  | EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault)); | 
|  | EXPECT_TRUE(FieldTrialList::IsTrialActive(kTrialName)); | 
|  | EXPECT_EQ(kForcedOnGroupName, enable_trial->group_name()); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_F(FeatureListTest, GetFeatureOverrides) { | 
|  | ClearFeatureListInstance(); | 
|  | FieldTrialList field_trial_list(nullptr); | 
|  | std::unique_ptr<FeatureList> feature_list(new FeatureList); | 
|  | feature_list->InitializeFromCommandLine("A,X", "D"); | 
|  |  | 
|  | FieldTrial* trial = FieldTrialList::CreateFieldTrial("Trial", "Group"); | 
|  | feature_list->RegisterFieldTrialOverride(kFeatureOffByDefaultName, | 
|  | FeatureList::OVERRIDE_ENABLE_FEATURE, | 
|  | trial); | 
|  |  | 
|  | RegisterFeatureListInstance(std::move(feature_list)); | 
|  |  | 
|  | std::string enable_features; | 
|  | std::string disable_features; | 
|  | FeatureList::GetInstance()->GetFeatureOverrides(&enable_features, | 
|  | &disable_features); | 
|  | EXPECT_EQ("A,OffByDefault<Trial,X", SortFeatureListString(enable_features)); | 
|  | EXPECT_EQ("D", SortFeatureListString(disable_features)); | 
|  |  | 
|  | FeatureList::GetInstance()->GetCommandLineFeatureOverrides(&enable_features, | 
|  | &disable_features); | 
|  | EXPECT_EQ("A,X", SortFeatureListString(enable_features)); | 
|  | EXPECT_EQ("D", SortFeatureListString(disable_features)); | 
|  | } | 
|  |  | 
|  | TEST_F(FeatureListTest, GetFeatureOverrides_UseDefault) { | 
|  | ClearFeatureListInstance(); | 
|  | FieldTrialList field_trial_list(nullptr); | 
|  | std::unique_ptr<FeatureList> feature_list(new FeatureList); | 
|  | feature_list->InitializeFromCommandLine("A,X", "D"); | 
|  |  | 
|  | FieldTrial* trial = FieldTrialList::CreateFieldTrial("Trial", "Group"); | 
|  | feature_list->RegisterFieldTrialOverride( | 
|  | kFeatureOffByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT, trial); | 
|  |  | 
|  | RegisterFeatureListInstance(std::move(feature_list)); | 
|  |  | 
|  | std::string enable_features; | 
|  | std::string disable_features; | 
|  | FeatureList::GetInstance()->GetFeatureOverrides(&enable_features, | 
|  | &disable_features); | 
|  | EXPECT_EQ("*OffByDefault<Trial,A,X", SortFeatureListString(enable_features)); | 
|  | EXPECT_EQ("D", SortFeatureListString(disable_features)); | 
|  | } | 
|  |  | 
|  | TEST_F(FeatureListTest, GetFieldTrial) { | 
|  | ClearFeatureListInstance(); | 
|  | FieldTrialList field_trial_list(nullptr); | 
|  | FieldTrial* trial = FieldTrialList::CreateFieldTrial("Trial", "Group"); | 
|  | std::unique_ptr<FeatureList> feature_list(new FeatureList); | 
|  | feature_list->RegisterFieldTrialOverride( | 
|  | kFeatureOnByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT, trial); | 
|  | RegisterFeatureListInstance(std::move(feature_list)); | 
|  |  | 
|  | EXPECT_EQ(trial, FeatureList::GetFieldTrial(kFeatureOnByDefault)); | 
|  | EXPECT_EQ(nullptr, FeatureList::GetFieldTrial(kFeatureOffByDefault)); | 
|  | } | 
|  |  | 
|  | TEST_F(FeatureListTest, InitializeFromCommandLine_WithFieldTrials) { | 
|  | ClearFeatureListInstance(); | 
|  | FieldTrialList field_trial_list(nullptr); | 
|  | FieldTrialList::CreateFieldTrial("Trial", "Group"); | 
|  | std::unique_ptr<FeatureList> feature_list(new FeatureList); | 
|  | feature_list->InitializeFromCommandLine("A,OffByDefault<Trial,X", "D"); | 
|  | RegisterFeatureListInstance(std::move(feature_list)); | 
|  |  | 
|  | EXPECT_FALSE(FieldTrialList::IsTrialActive("Trial")); | 
|  | EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault)); | 
|  | EXPECT_TRUE(FieldTrialList::IsTrialActive("Trial")); | 
|  | } | 
|  |  | 
|  | TEST_F(FeatureListTest, InitializeFromCommandLine_UseDefault) { | 
|  | ClearFeatureListInstance(); | 
|  | FieldTrialList field_trial_list(nullptr); | 
|  | FieldTrialList::CreateFieldTrial("T1", "Group"); | 
|  | FieldTrialList::CreateFieldTrial("T2", "Group"); | 
|  | std::unique_ptr<FeatureList> feature_list(new FeatureList); | 
|  | feature_list->InitializeFromCommandLine( | 
|  | "A,*OffByDefault<T1,*OnByDefault<T2,X", "D"); | 
|  | RegisterFeatureListInstance(std::move(feature_list)); | 
|  |  | 
|  | EXPECT_FALSE(FieldTrialList::IsTrialActive("T1")); | 
|  | EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault)); | 
|  | EXPECT_TRUE(FieldTrialList::IsTrialActive("T1")); | 
|  |  | 
|  | EXPECT_FALSE(FieldTrialList::IsTrialActive("T2")); | 
|  | EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault)); | 
|  | EXPECT_TRUE(FieldTrialList::IsTrialActive("T2")); | 
|  | } | 
|  |  | 
|  | TEST_F(FeatureListTest, InitializeInstance) { | 
|  | ClearFeatureListInstance(); | 
|  |  | 
|  | std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList); | 
|  | FeatureList::SetInstance(std::move(feature_list)); | 
|  | EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault)); | 
|  | EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault)); | 
|  |  | 
|  | // Initialize from command line if we haven't yet. | 
|  | FeatureList::InitializeInstance("", kFeatureOnByDefaultName); | 
|  | EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault)); | 
|  | EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault)); | 
|  |  | 
|  | // Do not initialize from commandline if we have already. | 
|  | FeatureList::InitializeInstance(kFeatureOffByDefaultName, ""); | 
|  | EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault)); | 
|  | EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault)); | 
|  | } | 
|  |  | 
|  | TEST_F(FeatureListTest, UninitializedInstance_IsEnabledReturnsFalse) { | 
|  | ClearFeatureListInstance(); | 
|  | // This test case simulates the calling pattern found in code which does not | 
|  | // explicitly initialize the features list. | 
|  | // All IsEnabled() calls should return the default value in this scenario. | 
|  | EXPECT_EQ(nullptr, FeatureList::GetInstance()); | 
|  | EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault)); | 
|  | EXPECT_EQ(nullptr, FeatureList::GetInstance()); | 
|  | EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault)); | 
|  | } | 
|  |  | 
|  | TEST_F(FeatureListTest, StoreAndRetrieveFeaturesFromSharedMemory) { | 
|  | std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList); | 
|  |  | 
|  | // Create some overrides. | 
|  | feature_list->RegisterOverride(kFeatureOffByDefaultName, | 
|  | FeatureList::OVERRIDE_ENABLE_FEATURE, nullptr); | 
|  | feature_list->RegisterOverride( | 
|  | kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE, nullptr); | 
|  | feature_list->FinalizeInitialization(); | 
|  |  | 
|  | // Create an allocator and store the overrides. | 
|  | std::unique_ptr<SharedMemory> shm(new SharedMemory()); | 
|  | shm->CreateAndMapAnonymous(4 << 10); | 
|  | SharedPersistentMemoryAllocator allocator(std::move(shm), 1, "", false); | 
|  | feature_list->AddFeaturesToAllocator(&allocator); | 
|  |  | 
|  | std::unique_ptr<base::FeatureList> feature_list2(new base::FeatureList); | 
|  |  | 
|  | // Check that the new feature list is empty. | 
|  | EXPECT_FALSE(feature_list2->IsFeatureOverriddenFromCommandLine( | 
|  | kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE)); | 
|  | EXPECT_FALSE(feature_list2->IsFeatureOverriddenFromCommandLine( | 
|  | kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE)); | 
|  |  | 
|  | feature_list2->InitializeFromSharedMemory(&allocator); | 
|  | // Check that the new feature list now has 2 overrides. | 
|  | EXPECT_TRUE(feature_list2->IsFeatureOverriddenFromCommandLine( | 
|  | kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE)); | 
|  | EXPECT_TRUE(feature_list2->IsFeatureOverriddenFromCommandLine( | 
|  | kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE)); | 
|  | } | 
|  |  | 
|  | TEST_F(FeatureListTest, StoreAndRetrieveAssociatedFeaturesFromSharedMemory) { | 
|  | FieldTrialList field_trial_list(nullptr); | 
|  | std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList); | 
|  |  | 
|  | // Create some overrides. | 
|  | FieldTrial* trial1 = FieldTrialList::CreateFieldTrial("TrialExample1", "A"); | 
|  | FieldTrial* trial2 = FieldTrialList::CreateFieldTrial("TrialExample2", "B"); | 
|  | feature_list->RegisterFieldTrialOverride( | 
|  | kFeatureOnByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT, trial1); | 
|  | feature_list->RegisterFieldTrialOverride( | 
|  | kFeatureOffByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT, trial2); | 
|  | feature_list->FinalizeInitialization(); | 
|  |  | 
|  | // Create an allocator and store the overrides. | 
|  | std::unique_ptr<SharedMemory> shm(new SharedMemory()); | 
|  | shm->CreateAndMapAnonymous(4 << 10); | 
|  | SharedPersistentMemoryAllocator allocator(std::move(shm), 1, "", false); | 
|  | feature_list->AddFeaturesToAllocator(&allocator); | 
|  |  | 
|  | std::unique_ptr<base::FeatureList> feature_list2(new base::FeatureList); | 
|  | feature_list2->InitializeFromSharedMemory(&allocator); | 
|  | feature_list2->FinalizeInitialization(); | 
|  |  | 
|  | // Check that the field trials are still associated. | 
|  | FieldTrial* associated_trial1 = | 
|  | feature_list2->GetAssociatedFieldTrial(kFeatureOnByDefault); | 
|  | FieldTrial* associated_trial2 = | 
|  | feature_list2->GetAssociatedFieldTrial(kFeatureOffByDefault); | 
|  | EXPECT_EQ(associated_trial1, trial1); | 
|  | EXPECT_EQ(associated_trial2, trial2); | 
|  | } | 
|  |  | 
|  | }  // namespace base |