// Copyright 2017 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/test/scoped_feature_list.h"
#include <map>
#include <string>
#include <utility>
#include "base/metrics/field_trial.h"
#include "base/metrics/field_trial_params.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
namespace test {
namespace {
const Feature kTestFeature1{"TestFeature1", FEATURE_DISABLED_BY_DEFAULT};
const Feature kTestFeature2{"TestFeature2", FEATURE_DISABLED_BY_DEFAULT};
void ExpectFeatures(const std::string& enabled_features,
const std::string& disabled_features) {
FeatureList* list = FeatureList::GetInstance();
std::string actual_enabled_features;
std::string actual_disabled_features;
list->GetFeatureOverrides(&actual_enabled_features,
&actual_disabled_features);
EXPECT_EQ(enabled_features, actual_enabled_features);
EXPECT_EQ(disabled_features, actual_disabled_features);
}
} // namespace
class ScopedFeatureListTest : public testing::Test {
public:
ScopedFeatureListTest() {
// Clear default feature list.
std::unique_ptr<FeatureList> feature_list(new FeatureList);
feature_list->InitializeFromCommandLine(std::string(), std::string());
original_feature_list_ = FeatureList::ClearInstanceForTesting();
FeatureList::SetInstance(std::move(feature_list));
}
~ScopedFeatureListTest() override {
// Restore feature list.
if (original_feature_list_) {
FeatureList::ClearInstanceForTesting();
FeatureList::RestoreInstanceForTesting(std::move(original_feature_list_));
}
}
private:
// Save the present FeatureList and restore it after test finish.
std::unique_ptr<FeatureList> original_feature_list_;
DISALLOW_COPY_AND_ASSIGN(ScopedFeatureListTest);
};
TEST_F(ScopedFeatureListTest, BasicScoped) {
ExpectFeatures(std::string(), std::string());
EXPECT_FALSE(FeatureList::IsEnabled(kTestFeature1));
{
test::ScopedFeatureList feature_list1;
feature_list1.InitFromCommandLine("TestFeature1", std::string());
ExpectFeatures("TestFeature1", std::string());
EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
}
ExpectFeatures(std::string(), std::string());
EXPECT_FALSE(FeatureList::IsEnabled(kTestFeature1));
}
TEST_F(ScopedFeatureListTest, EnableWithFeatureParameters) {
const char kParam1[] = "param_1";
const char kParam2[] = "param_2";
const char kValue1[] = "value_1";
const char kValue2[] = "value_2";
std::map<std::string, std::string> parameters;
parameters[kParam1] = kValue1;
parameters[kParam2] = kValue2;
ExpectFeatures(std::string(), std::string());
EXPECT_EQ(nullptr, FeatureList::GetFieldTrial(kTestFeature1));
EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature1, kParam1));
EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature1, kParam2));
FieldTrial::ActiveGroups active_groups;
FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
EXPECT_EQ(0u, active_groups.size());
{
test::ScopedFeatureList feature_list;
feature_list.InitAndEnableFeatureWithParameters(kTestFeature1, parameters);
EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
EXPECT_EQ(kValue1,
GetFieldTrialParamValueByFeature(kTestFeature1, kParam1));
EXPECT_EQ(kValue2,
GetFieldTrialParamValueByFeature(kTestFeature1, kParam2));
active_groups.clear();
FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
EXPECT_EQ(1u, active_groups.size());
}
ExpectFeatures(std::string(), std::string());
EXPECT_EQ(nullptr, FeatureList::GetFieldTrial(kTestFeature1));
EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature1, kParam1));
EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature1, kParam2));
active_groups.clear();
FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
EXPECT_EQ(0u, active_groups.size());
}
TEST_F(ScopedFeatureListTest, OverrideWithFeatureParameters) {
FieldTrialList field_trial_list(nullptr);
scoped_refptr<FieldTrial> trial =
FieldTrialList::CreateFieldTrial("foo", "bar");
const char kParam[] = "param_1";
const char kValue[] = "value_1";
std::map<std::string, std::string> parameters;
parameters[kParam] = kValue;
test::ScopedFeatureList feature_list1;
feature_list1.InitFromCommandLine("TestFeature1<foo,TestFeature2",
std::string());
// Check initial state.
ExpectFeatures("TestFeature1<foo,TestFeature2", std::string());
EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature2));
EXPECT_EQ(trial.get(), FeatureList::GetFieldTrial(kTestFeature1));
EXPECT_EQ(nullptr, FeatureList::GetFieldTrial(kTestFeature2));
EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature1, kParam));
EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature2, kParam));
{
// Override feature with existing field trial.
test::ScopedFeatureList feature_list2;
feature_list2.InitAndEnableFeatureWithParameters(kTestFeature1, parameters);
EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature2));
EXPECT_EQ(kValue, GetFieldTrialParamValueByFeature(kTestFeature1, kParam));
EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature2, kParam));
EXPECT_NE(trial.get(), FeatureList::GetFieldTrial(kTestFeature1));
EXPECT_NE(nullptr, FeatureList::GetFieldTrial(kTestFeature1));
EXPECT_EQ(nullptr, FeatureList::GetFieldTrial(kTestFeature2));
}
// Check that initial state is restored.
ExpectFeatures("TestFeature1<foo,TestFeature2", std::string());
EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature2));
EXPECT_EQ(trial.get(), FeatureList::GetFieldTrial(kTestFeature1));
EXPECT_EQ(nullptr, FeatureList::GetFieldTrial(kTestFeature2));
EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature1, kParam));
EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature2, kParam));
{
// Override feature with no existing field trial.
test::ScopedFeatureList feature_list2;
feature_list2.InitAndEnableFeatureWithParameters(kTestFeature2, parameters);
EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature2));
EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature1, kParam));
EXPECT_EQ(kValue, GetFieldTrialParamValueByFeature(kTestFeature2, kParam));
EXPECT_EQ(trial.get(), FeatureList::GetFieldTrial(kTestFeature1));
EXPECT_NE(nullptr, FeatureList::GetFieldTrial(kTestFeature2));
}
// Check that initial state is restored.
ExpectFeatures("TestFeature1<foo,TestFeature2", std::string());
EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature2));
EXPECT_EQ(trial.get(), FeatureList::GetFieldTrial(kTestFeature1));
EXPECT_EQ(nullptr, FeatureList::GetFieldTrial(kTestFeature2));
EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature1, kParam));
EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature2, kParam));
}
TEST_F(ScopedFeatureListTest, EnableFeatureOverrideDisable) {
test::ScopedFeatureList feature_list1;
feature_list1.InitWithFeatures({}, {kTestFeature1});
{
test::ScopedFeatureList feature_list2;
feature_list2.InitWithFeatures({kTestFeature1}, {});
ExpectFeatures("TestFeature1", std::string());
}
}
TEST_F(ScopedFeatureListTest, FeatureOverrideNotMakeDuplicate) {
test::ScopedFeatureList feature_list1;
feature_list1.InitWithFeatures({}, {kTestFeature1});
{
test::ScopedFeatureList feature_list2;
feature_list2.InitWithFeatures({}, {kTestFeature1});
ExpectFeatures(std::string(), "TestFeature1");
}
}
TEST_F(ScopedFeatureListTest, FeatureOverrideFeatureWithDefault) {
test::ScopedFeatureList feature_list1;
feature_list1.InitFromCommandLine("*TestFeature1", std::string());
{
test::ScopedFeatureList feature_list2;
feature_list2.InitWithFeatures({kTestFeature1}, {});
ExpectFeatures("TestFeature1", std::string());
}
}
TEST_F(ScopedFeatureListTest, FeatureOverrideFeatureWithDefault2) {
test::ScopedFeatureList feature_list1;
feature_list1.InitFromCommandLine("*TestFeature1", std::string());
{
test::ScopedFeatureList feature_list2;
feature_list2.InitWithFeatures({}, {kTestFeature1});
ExpectFeatures(std::string(), "TestFeature1");
}
}
TEST_F(ScopedFeatureListTest, FeatureOverrideFeatureWithEnabledFieldTrial) {
test::ScopedFeatureList feature_list1;
std::unique_ptr<FeatureList> feature_list(new FeatureList);
FieldTrialList field_trial_list(nullptr);
FieldTrial* trial = FieldTrialList::CreateFieldTrial("TrialExample", "A");
feature_list->RegisterFieldTrialOverride(
kTestFeature1.name, FeatureList::OVERRIDE_ENABLE_FEATURE, trial);
feature_list1.InitWithFeatureList(std::move(feature_list));
{
test::ScopedFeatureList feature_list2;
feature_list2.InitWithFeatures({kTestFeature1}, {});
ExpectFeatures("TestFeature1", std::string());
}
}
TEST_F(ScopedFeatureListTest, FeatureOverrideFeatureWithDisabledFieldTrial) {
test::ScopedFeatureList feature_list1;
std::unique_ptr<FeatureList> feature_list(new FeatureList);
FieldTrialList field_trial_list(nullptr);
FieldTrial* trial = FieldTrialList::CreateFieldTrial("TrialExample", "A");
feature_list->RegisterFieldTrialOverride(
kTestFeature1.name, FeatureList::OVERRIDE_DISABLE_FEATURE, trial);
feature_list1.InitWithFeatureList(std::move(feature_list));
{
test::ScopedFeatureList feature_list2;
feature_list2.InitWithFeatures({kTestFeature1}, {});
ExpectFeatures("TestFeature1", std::string());
}
}
TEST_F(ScopedFeatureListTest, FeatureOverrideKeepsOtherExistingFeature) {
test::ScopedFeatureList feature_list1;
feature_list1.InitWithFeatures({}, {kTestFeature1});
{
test::ScopedFeatureList feature_list2;
feature_list2.InitWithFeatures({}, {kTestFeature2});
EXPECT_FALSE(FeatureList::IsEnabled(kTestFeature1));
EXPECT_FALSE(FeatureList::IsEnabled(kTestFeature2));
}
}
TEST_F(ScopedFeatureListTest, FeatureOverrideKeepsOtherExistingFeature2) {
test::ScopedFeatureList feature_list1;
feature_list1.InitWithFeatures({}, {kTestFeature1});
{
test::ScopedFeatureList feature_list2;
feature_list2.InitWithFeatures({kTestFeature2}, {});
ExpectFeatures("TestFeature2", "TestFeature1");
}
}
TEST_F(ScopedFeatureListTest, FeatureOverrideKeepsOtherExistingDefaultFeature) {
test::ScopedFeatureList feature_list1;
feature_list1.InitFromCommandLine("*TestFeature1", std::string());
{
test::ScopedFeatureList feature_list2;
feature_list2.InitWithFeatures({}, {kTestFeature2});
ExpectFeatures("*TestFeature1", "TestFeature2");
}
}
TEST_F(ScopedFeatureListTest, ScopedFeatureListIsNoopWhenNotInitialized) {
test::ScopedFeatureList feature_list1;
feature_list1.InitFromCommandLine("*TestFeature1", std::string());
// A ScopedFeatureList on which Init() is not called should not reset things
// when going out of scope.
{ test::ScopedFeatureList feature_list2; }
ExpectFeatures("*TestFeature1", std::string());
}
} // namespace test
} // namespace base