Movatterモバイル変換


[0]ホーム

URL:


Google Git
Sign in
chromium /chromium /src /refs/heads/main /. /base /feature_list_unittest.cc
blob: b84e05642c81eb1a9ba4901e0e60963510f2d98e [file] [log] [blame] [edit]
// Copyright 2015 The Chromium Authors
// 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<array>
#include<ostream>
#include<set>
#include<string>
#include<string_view>
#include<utility>
#include<vector>
#include"base/feature_list_buildflags.h"
#include"base/feature_visitor.h"
#include"base/format_macros.h"
#include"base/memory/read_only_shared_memory_region.h"
#include"base/metrics/field_trial.h"
#include"base/metrics/field_trial_param_associator.h"
#include"base/metrics/persistent_memory_allocator.h"
#include"base/strings/strcat.h"
#include"base/strings/string_util.h"
#include"base/strings/stringprintf.h"
#include"base/test/scoped_feature_list.h"
#include"testing/gtest/include/gtest/gtest.h"
namespace base{
namespace{
constexprchar kFeatureOnByDefaultName[]="OnByDefault";
BASE_FEATURE(kFeatureOnByDefault,
kFeatureOnByDefaultName,
FEATURE_ENABLED_BY_DEFAULT);
constexprchar kFeatureOffByDefaultName[]="OffByDefault";
BASE_FEATURE(kFeatureOffByDefault,
kFeatureOffByDefaultName,
FEATURE_DISABLED_BY_DEFAULT);
std::stringSortFeatureListString(const std::string& feature_list){
std::vector<std::string_view> features=
FeatureList::SplitFeatureListString(feature_list);
std::ranges::sort(features);
returnJoinString(features,",");
}
}// namespace
classFeatureListTest:public testing::Test{
public:
FeatureListTest(){
// Provide an empty FeatureList to each test by default.
scoped_feature_list_.InitWithFeatureList(std::make_unique<FeatureList>());
}
FeatureListTest(constFeatureListTest&)=delete;
FeatureListTest&operator=(constFeatureListTest&)=delete;
~FeatureListTest() override=default;
private:
test::ScopedFeatureList scoped_feature_list_;
};
TEST_F(FeatureListTest,DefaultStates){
EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault));
EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
}
TEST_F(FeatureListTest,InitFromCommandLine){
structTestCases{
constchar* enable_features;
constchar* disable_features;
bool expected_feature_on_state;
bool expected_feature_off_state;
};
auto test_cases= std::to_array<TestCases>({
{"","",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< std::size(test_cases);++i){
constauto& test_case= test_cases[i];
SCOPED_TRACE(base::StringPrintf("Test[%"PRIuS"]: [%s] [%s]", i,
test_case.enable_features,
test_case.disable_features));
auto feature_list= std::make_unique<FeatureList>();
feature_list->InitFromCommandLine(test_case.enable_features,
test_case.disable_features);
test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitWithFeatureList(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;
// Reading the state of each feature again will pull it from their
// respective caches instead of performing the full lookup, which should
// yield the same result.
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,InitFromCommandLineWithFeatureParams){
struct{
const std::string enable_features;
const std::string expected_field_trial_created;
const std::map<std::string, std::string> expected_feature_params;
} test_cases[]={
{"Feature:x/100/y/test","StudyFeature",{{"x","100"},{"y","test"}}},
{"Feature<Trial1:x/200/y/123","Trial1",{{"x","200"},{"y","123"}}},
{"Feature<Trial2.Group2:x/test/y/uma/z/ukm",
"Trial2",
{{"x","test"},{"y","uma"},{"z","ukm"}}},
};
// Clear global state so that repeated runs of this test don't flake.
// When https://crrev.com/c/3694674 is submitted, we should be able to remove
// this.
base::FieldTrialParamAssociator::GetInstance()->ClearAllParamsForTesting();
static BASE_FEATURE(kFeature,"Feature", FEATURE_DISABLED_BY_DEFAULT);
for(constauto& test_case: test_cases){
SCOPED_TRACE(test_case.enable_features);
auto feature_list= std::make_unique<FeatureList>();
feature_list->InitFromCommandLine(test_case.enable_features,"");
test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitWithFeatureList(std::move(feature_list));
EXPECT_TRUE(FeatureList::IsEnabled(kFeature));
EXPECT_TRUE(
FieldTrialList::IsTrialActive(test_case.expected_field_trial_created));
std::map<std::string, std::string> actual_params;
EXPECT_TRUE(GetFieldTrialParamsByFeature(kFeature,&actual_params));
EXPECT_EQ(test_case.expected_feature_params, actual_params);
}
}
TEST_F(FeatureListTest,CheckFeatureIdentity){
// Tests that CheckFeatureIdentity() correctly detects when two different
// structs with the same feature name are passed to it.
test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitWithFeatureList(std::make_unique<FeatureList>());
FeatureList* feature_list=FeatureList::GetInstance();
// 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.
static BASE_FEATURE(kFeatureOnByDefault2, kFeatureOnByDefaultName,
FEATURE_ENABLED_BY_DEFAULT);
EXPECT_FALSE(feature_list->CheckFeatureIdentity(kFeatureOnByDefault2));
}
TEST_F(FeatureListTest,FieldTrialOverrides){
structTestCases{
FeatureList::OverrideState trial1_state;
FeatureList::OverrideState trial2_state;
};
auto test_cases= std::to_array<TestCases>({
{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< std::size(test_cases);++i){
constauto& test_case= test_cases[i];
SCOPED_TRACE(base::StringPrintf("Test[%"PRIuS"]", i));
test::ScopedFeatureList outer_scope;
outer_scope.InitWithEmptyFeatureAndFieldTrialLists();
auto feature_list= std::make_unique<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);
test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitWithFeatureList(std::move(feature_list));
// Initially, neither trial should be active.
EXPECT_FALSE(FieldTrialList::IsTrialActive(trial1->trial_name()));
EXPECT_FALSE(FieldTrialList::IsTrialActive(trial2->trial_name()));
constbool 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()));
constbool 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){
auto feature_list= std::make_unique<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);
test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitWithFeatureList(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,CommandLineEnableTakesPrecedenceOverFieldTrial){
auto feature_list= std::make_unique<FeatureList>();
// The feature is explicitly enabled on the command-line.
feature_list->InitFromCommandLine(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);
test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitWithFeatureList(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,CommandLineDisableTakesPrecedenceOverFieldTrial){
auto feature_list= std::make_unique<FeatureList>();
// The feature is explicitly disabled on the command-line.
feature_list->InitFromCommandLine("", kFeatureOffByDefaultName);
// But the FieldTrial would set the feature to enabled.
FieldTrial* trial=FieldTrialList::CreateFieldTrial("TrialExample2","A");
feature_list->RegisterFieldTrialOverride(
kFeatureOffByDefaultName,FeatureList::OVERRIDE_ENABLE_FEATURE, trial);
test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitWithFeatureList(std::move(feature_list));
EXPECT_FALSE(FieldTrialList::IsTrialActive(trial->trial_name()));
// Command-line should take precedence.
EXPECT_FALSE(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,IsFeatureOverriddenFromFieldTrial){
auto feature_list= std::make_unique<FeatureList>();
// No features are overridden from the field trails yet.
EXPECT_FALSE(feature_list->IsFeatureOverridden(kFeatureOnByDefaultName));
EXPECT_FALSE(feature_list->IsFeatureOverridden(kFeatureOffByDefaultName));
// Now, register field trials to override `kFeatureOnByDefaultName` state and
// keeping `kFeatureOffByDefault` as the default. Check that both are
// considered overridden.
feature_list->RegisterFieldTrialOverride(
kFeatureOffByDefaultName,FeatureList::OVERRIDE_USE_DEFAULT,
FieldTrialList::CreateFieldTrial("Trial1","A"));
feature_list->RegisterFieldTrialOverride(
kFeatureOnByDefaultName,FeatureList::OVERRIDE_DISABLE_FEATURE,
FieldTrialList::CreateFieldTrial("Trial2","A"));
EXPECT_TRUE(feature_list->IsFeatureOverridden(kFeatureOnByDefaultName));
EXPECT_TRUE(feature_list->IsFeatureOverridden(kFeatureOffByDefaultName));
test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitWithFeatureList(std::move(feature_list));
// Check the expected feature states for good measure.
EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault));
}
TEST_F(FeatureListTest,IsFeatureOverriddenFromCommandLine){
auto feature_list= std::make_unique<FeatureList>();
// No features are overridden from the command line yet
EXPECT_FALSE(feature_list->IsFeatureOverridden(kFeatureOnByDefaultName));
EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
kFeatureOnByDefaultName));
EXPECT_FALSE(feature_list->IsFeatureOverridden(kFeatureOffByDefaultName));
EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
kFeatureOffByDefaultName));
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->InitFromCommandLine(kFeatureOffByDefaultName,"");
// It should now be overridden for the enabled group.
EXPECT_TRUE(feature_list->IsFeatureOverridden(kFeatureOffByDefaultName));
EXPECT_TRUE(feature_list->IsFeatureOverriddenFromCommandLine(
kFeatureOffByDefaultName));
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_TRUE(feature_list->IsFeatureOverridden(kFeatureOffByDefaultName));
EXPECT_TRUE(feature_list->IsFeatureOverriddenFromCommandLine(
kFeatureOffByDefaultName));
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_TRUE(feature_list->IsFeatureOverridden(kFeatureOnByDefaultName));
EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
kFeatureOnByDefaultName));
EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
kFeatureOnByDefaultName,FeatureList::OVERRIDE_DISABLE_FEATURE));
EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
kFeatureOnByDefaultName,FeatureList::OVERRIDE_ENABLE_FEATURE));
test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitWithFeatureList(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){
structTestCases{
constchar* enable_features;
constchar* disable_features;
bool expected_enable_trial_created;
bool expected_disable_trial_created;
};
auto test_cases= std::to_array<TestCases>({
// 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},
});
constchar kTrialName[]="ForcingTrial";
constchar kForcedOnGroupName[]="ForcedOn";
constchar kForcedOffGroupName[]="ForcedOff";
for(size_t i=0; i< std::size(test_cases);++i){
constauto& test_case= test_cases[i];
SCOPED_TRACE(base::StringPrintf("Test[%"PRIuS"]: [%s] [%s]", i,
test_case.enable_features,
test_case.disable_features));
test::ScopedFeatureList outer_scope;
outer_scope.InitWithEmptyFeatureAndFieldTrialLists();
auto feature_list= std::make_unique<FeatureList>();
feature_list->InitFromCommandLine(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);
test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitWithFeatureList(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());
}elseif(enable_trial){
EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault));
EXPECT_TRUE(FieldTrialList::IsTrialActive(kTrialName));
EXPECT_EQ(kForcedOnGroupName, enable_trial->group_name());
}
}
}
TEST_F(FeatureListTest,RegisterExtraFeatureOverrides_ReplaceUseDefault){
auto feature_list= std::make_unique<FeatureList>();
FieldTrial* trial1=FieldTrialList::CreateFieldTrial("Trial1","Group");
feature_list->RegisterFieldTrialOverride(
kFeatureOnByDefaultName,FeatureList::OVERRIDE_USE_DEFAULT, trial1);
FieldTrial* trial2=FieldTrialList::CreateFieldTrial("Trial2","Group");
feature_list->RegisterFieldTrialOverride(
kFeatureOffByDefaultName,FeatureList::OVERRIDE_USE_DEFAULT, trial2);
std::vector<FeatureList::FeatureOverrideInfo> overrides;
overrides.emplace_back(std::cref(kFeatureOnByDefault),
FeatureList::OverrideState::OVERRIDE_DISABLE_FEATURE);
overrides.emplace_back(std::cref(kFeatureOffByDefault),
FeatureList::OverrideState::OVERRIDE_ENABLE_FEATURE);
feature_list->RegisterExtraFeatureOverrides(
std::move(overrides),/*replace_use_default_overrides=*/true);
test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitWithFeatureList(std::move(feature_list));
// OVERRIDE_USE_DEFAULT entries should be overridden by AwFeatureOverrides.
// Before querying the feature, the trials shouldn't be active, but should
// be activated after querying.
EXPECT_FALSE(base::FieldTrialList::IsTrialActive("Trial1"));
EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault));
EXPECT_TRUE(base::FieldTrialList::IsTrialActive("Trial1"));
EXPECT_FALSE(base::FieldTrialList::IsTrialActive("Trial2"));
EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault));
EXPECT_TRUE(base::FieldTrialList::IsTrialActive("Trial2"));
}
TEST_F(FeatureListTest,RegisterExtraFeatureOverrides){
auto feature_list= std::make_unique<FeatureList>();
std::vector<FeatureList::FeatureOverrideInfo> overrides;
overrides.emplace_back(std::cref(kFeatureOnByDefault),
FeatureList::OverrideState::OVERRIDE_DISABLE_FEATURE);
overrides.emplace_back(std::cref(kFeatureOffByDefault),
FeatureList::OverrideState::OVERRIDE_ENABLE_FEATURE);
feature_list->RegisterExtraFeatureOverrides(std::move(overrides));
test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitWithFeatureList(std::move(feature_list));
EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault));
EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault));
}
TEST_F(FeatureListTest,InitFromCommandLineThenRegisterExtraOverrides){
auto feature_list= std::make_unique<FeatureList>();
feature_list->InitFromCommandLine(kFeatureOnByDefaultName,
kFeatureOffByDefaultName);
std::vector<FeatureList::FeatureOverrideInfo> overrides;
overrides.emplace_back(std::cref(kFeatureOnByDefault),
FeatureList::OverrideState::OVERRIDE_DISABLE_FEATURE);
overrides.emplace_back(std::cref(kFeatureOffByDefault),
FeatureList::OverrideState::OVERRIDE_ENABLE_FEATURE);
feature_list->RegisterExtraFeatureOverrides(std::move(overrides));
test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitWithFeatureList(std::move(feature_list));
// The InitFromCommandLine supersedes the RegisterExtraFeatureOverrides
// because it was called first.
EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault));
EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
std::string enable_features;
std::string disable_features;
FeatureList::GetInstance()->GetFeatureOverrides(&enable_features,
&disable_features);
EXPECT_EQ(kFeatureOnByDefaultName,SortFeatureListString(enable_features));
EXPECT_EQ(kFeatureOffByDefaultName,SortFeatureListString(disable_features));
}
TEST_F(FeatureListTest,GetFeatureOverrides){
auto feature_list= std::make_unique<FeatureList>();
feature_list->InitFromCommandLine("A,X","D");
static BASE_FEATURE(feature_b,"B", FEATURE_ENABLED_BY_DEFAULT);
static BASE_FEATURE(feature_c,"C", FEATURE_DISABLED_BY_DEFAULT);
std::vector<FeatureList::FeatureOverrideInfo> overrides;
overrides.emplace_back(std::cref(feature_b),
FeatureList::OverrideState::OVERRIDE_DISABLE_FEATURE);
overrides.emplace_back(std::cref(feature_c),
FeatureList::OverrideState::OVERRIDE_ENABLE_FEATURE);
feature_list->RegisterExtraFeatureOverrides(std::move(overrides));
FieldTrial* trial=FieldTrialList::CreateFieldTrial("Trial","Group");
feature_list->RegisterFieldTrialOverride(
kFeatureOffByDefaultName,FeatureList::OVERRIDE_ENABLE_FEATURE, trial);
test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitWithFeatureList(std::move(feature_list));
std::string enable_features;
std::string disable_features;
FeatureList::GetInstance()->GetFeatureOverrides(&enable_features,
&disable_features);
EXPECT_EQ("A,C,OffByDefault<Trial,X",SortFeatureListString(enable_features));
EXPECT_EQ("B,D",SortFeatureListString(disable_features));
FeatureList::GetInstance()->GetCommandLineFeatureOverrides(&enable_features,
&disable_features);
EXPECT_EQ("A,C,X",SortFeatureListString(enable_features));
EXPECT_EQ("B,D",SortFeatureListString(disable_features));
}
TEST_F(FeatureListTest,GetFeatureOverrides_UseDefault){
auto feature_list= std::make_unique<FeatureList>();
feature_list->InitFromCommandLine("A,X","D");
FieldTrial* trial=FieldTrialList::CreateFieldTrial("Trial","Group");
feature_list->RegisterFieldTrialOverride(
kFeatureOffByDefaultName,FeatureList::OVERRIDE_USE_DEFAULT, trial);
test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitWithFeatureList(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){
FieldTrial* trial=FieldTrialList::CreateFieldTrial("Trial","Group");
auto feature_list= std::make_unique<FeatureList>();
feature_list->RegisterFieldTrialOverride(
kFeatureOnByDefaultName,FeatureList::OVERRIDE_USE_DEFAULT, trial);
test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitWithFeatureList(std::move(feature_list));
EXPECT_EQ(trial,FeatureList::GetFieldTrial(kFeatureOnByDefault));
EXPECT_EQ(nullptr,FeatureList::GetFieldTrial(kFeatureOffByDefault));
}
TEST_F(FeatureListTest,InitFromCommandLine_WithFieldTrials){
FieldTrialList::CreateFieldTrial("Trial","Group");
auto feature_list= std::make_unique<FeatureList>();
feature_list->InitFromCommandLine("A,OffByDefault<Trial,X","D");
test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitWithFeatureList(std::move(feature_list));
EXPECT_FALSE(FieldTrialList::IsTrialActive("Trial"));
EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault));
EXPECT_TRUE(FieldTrialList::IsTrialActive("Trial"));
}
TEST_F(FeatureListTest,InitFromCommandLine_UseDefault){
FieldTrialList::CreateFieldTrial("T1","Group");
FieldTrialList::CreateFieldTrial("T2","Group");
auto feature_list= std::make_unique<FeatureList>();
feature_list->InitFromCommandLine("A,*OffByDefault<T1,*OnByDefault<T2,X",
"D");
test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitWithFeatureList(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,InitInstance){
std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitWithFeatureList(std::move(feature_list));
EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault));
EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
// Initialize from command line if we haven't yet.
FeatureList::InitInstance("", kFeatureOnByDefaultName);
EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault));
EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
// Do not initialize from commandline if we have already.
FeatureList::InitInstance(kFeatureOffByDefaultName,"");
EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault));
EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
}
TEST_F(FeatureListTest,UninitializedInstance_IsEnabledReturnsFalse){
std::unique_ptr<FeatureList> original_feature_list=
FeatureList::ClearInstanceForTesting();
// 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));
if(original_feature_list){
FeatureList::RestoreInstanceForTesting(std::move(original_feature_list));
}
}
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.
base::MappedReadOnlyRegion shm=
base::ReadOnlySharedMemoryRegion::Create(4<<10);
WritableSharedPersistentMemoryAllocator allocator(std::move(shm.mapping),1,
"");
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->InitFromSharedMemory(&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){
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.
base::MappedReadOnlyRegion shm=
base::ReadOnlySharedMemoryRegion::Create(4<<10);
WritableSharedPersistentMemoryAllocator allocator(std::move(shm.mapping),1,
"");
feature_list->AddFeaturesToAllocator(&allocator);
std::unique_ptr<base::FeatureList> feature_list2(new base::FeatureList);
feature_list2->InitFromSharedMemory(&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);
}
TEST_F(FeatureListTest,SetEarlyAccessInstance_AllowList){
test::ScopedFeatureList clear_feature_list;
clear_feature_list.InitWithNullFeatureAndFieldTrialLists();
auto early_access_feature_list= std::make_unique<FeatureList>();
early_access_feature_list->InitFromCommandLine("OffByDefault","OnByDefault");
FeatureList::SetEarlyAccessInstance(std::move(early_access_feature_list),
{"DcheckIsFatal","OnByDefault"});
EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault));
EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
EXPECT_EQ(&kFeatureOffByDefault,
FeatureList::GetEarlyAccessedFeatureForTesting());
FeatureList::ResetEarlyFeatureAccessTrackerForTesting();
}
TEST_F(FeatureListTest,SetEarlyAccessInstance_ReplaceByRealList){
test::ScopedFeatureList clear_feature_list;
clear_feature_list.InitWithNullFeatureAndFieldTrialLists();
auto early_access_feature_list= std::make_unique<FeatureList>();
early_access_feature_list->InitFromCommandLine("OffByDefault","OnByDefault");
FeatureList::SetEarlyAccessInstance(
std::move(early_access_feature_list),
{"DcheckIsFatal","OffByDefault","OnByDefault"});
EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault));
EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault));
auto feature_list= std::make_unique<FeatureList>();
feature_list->InitFromCommandLine("","");
FeatureList::SetInstance(std::move(feature_list));
EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault));
EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
}
#if BUILDFLAG(ENABLE_BANNED_BASE_FEATURE_PREFIX) && \
defined(GTEST_HAS_DEATH_TEST)
usingFeatureListDeathTest=FeatureListTest;
TEST_F(FeatureListDeathTest,DiesWithBadFeatureName){
// TODO(dcheng): Add a nocompile version of this test. In general, people
// should not be constructing features at runtime anyway but just in case...
EXPECT_DEATH(
Feature(
StrCat({BUILDFLAG(BANNED_BASE_FEATURE_PREFIX),"MyFeature"}).c_str(),
FEATURE_DISABLED_BY_DEFAULT,
internal::FeatureMacroHandshake::kSecret),
StrCat({"Invalid feature name ", BUILDFLAG(BANNED_BASE_FEATURE_PREFIX),
"MyFeature"}));
}
#endif// BUILDFLAG(ENABLE_BANNED_BASE_FEATURE_PREFIX) &&
// defined(GTEST_HAS_DEATH_TEST)
TEST(FeatureListAccessorTest,DefaultStates){
test::ScopedFeatureList scoped_feature_list;
auto feature_list= std::make_unique<FeatureList>();
auto feature_list_accessor= feature_list->ConstructAccessor();
scoped_feature_list.InitWithFeatureList(std::move(feature_list));
EXPECT_EQ(feature_list_accessor->GetOverrideStateByFeatureName(
kFeatureOnByDefault.name),
FeatureList::OVERRIDE_USE_DEFAULT);
EXPECT_EQ(feature_list_accessor->GetOverrideStateByFeatureName(
kFeatureOffByDefault.name),
FeatureList::OVERRIDE_USE_DEFAULT);
}
TEST(FeatureListAccessorTest,InitFromCommandLine){
structTestCases{
constchar* enable_features;
constchar* disable_features;
FeatureList::OverrideState expected_feature_on_state;
FeatureList::OverrideState expected_feature_off_state;
};
auto test_cases= std::to_array<TestCases>({
{"","",FeatureList::OVERRIDE_USE_DEFAULT,
FeatureList::OVERRIDE_USE_DEFAULT},
{"OffByDefault","",FeatureList::OVERRIDE_USE_DEFAULT,
FeatureList::OVERRIDE_ENABLE_FEATURE},
{"OffByDefault","OnByDefault",FeatureList::OVERRIDE_DISABLE_FEATURE,
FeatureList::OVERRIDE_ENABLE_FEATURE},
{"OnByDefault,OffByDefault","",FeatureList::OVERRIDE_ENABLE_FEATURE,
FeatureList::OVERRIDE_ENABLE_FEATURE},
{"","OnByDefault,OffByDefault",FeatureList::OVERRIDE_DISABLE_FEATURE,
FeatureList::OVERRIDE_DISABLE_FEATURE},
// In the case an entry is both, disable takes precedence.
{"OnByDefault","OnByDefault,OffByDefault",
FeatureList::OVERRIDE_DISABLE_FEATURE,
FeatureList::OVERRIDE_DISABLE_FEATURE},
});
for(size_t i=0; i< std::size(test_cases);++i){
constauto& test_case= test_cases[i];
SCOPED_TRACE(base::StringPrintf("Test[%"PRIuS"]: [%s] [%s]", i,
test_case.enable_features,
test_case.disable_features));
test::ScopedFeatureList scoped_feature_list;
auto feature_list= std::make_unique<FeatureList>();
auto feature_list_accessor= feature_list->ConstructAccessor();
feature_list->InitFromCommandLine(test_case.enable_features,
test_case.disable_features);
scoped_feature_list.InitWithFeatureList(std::move(feature_list));
EXPECT_EQ(test_case.expected_feature_on_state,
feature_list_accessor->GetOverrideStateByFeatureName(
kFeatureOnByDefault.name))
<< i;
EXPECT_EQ(test_case.expected_feature_off_state,
feature_list_accessor->GetOverrideStateByFeatureName(
kFeatureOffByDefault.name))
<< i;
}
}
TEST(FeatureListAccessorTest,InitFromCommandLineWithFeatureParams){
structTestCases{
const std::string enable_features;
const std::map<std::string, std::string> expected_feature_params;
};
auto test_cases= std::to_array<TestCases>({
{"Feature:x/100/y/test",{{"x","100"},{"y","test"}}},
{"Feature<Trial:asdf/ghjkl/y/123",{{"asdf","ghjkl"},{"y","123"}}},
});
// Clear global state so that repeated runs of this test don't flake.
// When https://crrev.com/c/3694674 is submitted, we should be able to remove
// this.
base::FieldTrialParamAssociator::GetInstance()->ClearAllParamsForTesting();
for(size_t i=0; i< std::size(test_cases);++i){
constauto& test_case= test_cases[i];
SCOPED_TRACE(test_case.enable_features);
test::ScopedFeatureList scoped_feature_list;
auto feature_list= std::make_unique<FeatureList>();
auto feature_list_accessor= feature_list->ConstructAccessor();
feature_list->InitFromCommandLine(test_case.enable_features,"");
scoped_feature_list.InitWithFeatureList(std::move(feature_list));
EXPECT_EQ(FeatureList::OVERRIDE_ENABLE_FEATURE,
feature_list_accessor->GetOverrideStateByFeatureName("Feature"))
<< i;
std::map<std::string, std::string> actual_params;
EXPECT_TRUE(feature_list_accessor->GetParamsByFeatureName("Feature",
&actual_params))
<< i;
EXPECT_EQ(test_case.expected_feature_params, actual_params)<< i;
}
}
// Test only class to verify correctness of
// FeatureList::VisitFeaturesAndParams().
classTestFeatureVisitor:publicFeatureVisitor{
public:
TestFeatureVisitor()=default;
TestFeatureVisitor(constTestFeatureVisitor&)=delete;
TestFeatureVisitor&operator=(constTestFeatureVisitor&)=delete;
~TestFeatureVisitor() override=default;
structVisitedFeatureState{
autooperator<=>(constVisitedFeatureState&)const=default;
std::string feature_name;
const base::FeatureList::OverrideState override_state;
base::FieldTrialParams params;
std::string trial_name;
std::string group_name;
};
voidVisit(const std::string& feature_name,
FeatureList::OverrideState override_state,
constFieldTrialParams& params,
const std::string& trial_name,
const std::string& group_name) override{
feature_state_.insert(TestFeatureVisitor::VisitedFeatureState{
feature_name, override_state, params, trial_name, group_name});
}
const std::multiset<TestFeatureVisitor::VisitedFeatureState>&
feature_state(){
return feature_state_;
}
private:
std::multiset<VisitedFeatureState> feature_state_;
};
// Makes test output human readable.
std::ostream&operator<<(std::ostream& out,
constTestFeatureVisitor::VisitedFeatureState& state){
out<<".feature_name='"<< state.feature_name
<<"', .override_state="<< state.override_state<<", .params={";
for(constauto& param: state.params){
out<< param.first<<"="<< param.second<<", ";
}
out<<"}, .trial_name='"<< state.trial_name<<"', .group_name='"
<< state.group_name<<"'";
return out;
}
TEST(TestFeatureVisitor,FeatureWithNoFieldTrial){
base::test::ScopedFeatureList outer_scope;
outer_scope.InitWithEmptyFeatureAndFieldTrialLists();
base::test::ScopedFeatureList feature_list;
feature_list.InitWithFeatures(/*enabled_features=*/{kFeatureOffByDefault},
/*disabled_features=*/{kFeatureOnByDefault});
TestFeatureVisitor visitor;
base::FeatureList::VisitFeaturesAndParams(visitor);
std::multiset<TestFeatureVisitor::VisitedFeatureState> actual_feature_state=
visitor.feature_state();
std::multiset<TestFeatureVisitor::VisitedFeatureState>
expected_feature_state={
{"OnByDefault",FeatureList::OverrideState::OVERRIDE_DISABLE_FEATURE,
FieldTrialParams{},"",""},
{"OffByDefault",FeatureList::OverrideState::OVERRIDE_ENABLE_FEATURE,
FieldTrialParams{},"",""},
};
EXPECT_EQ(actual_feature_state, expected_feature_state);
}
TEST(TestFeatureVisitor,FeatureOverrideUseDefault){
base::test::ScopedFeatureList outer_scope;
outer_scope.InitWithEmptyFeatureAndFieldTrialLists();
auto feature_list= std::make_unique<base::FeatureList>();
base::FieldTrial* trial=
base::FieldTrialList::CreateFieldTrial("TrialExample","A");
feature_list->RegisterFieldTrialOverride(
"TestFeature", base::FeatureList::OVERRIDE_USE_DEFAULT, trial);
base::test::ScopedFeatureList initialized_feature_list;
initialized_feature_list.InitWithFeatureList(std::move(feature_list));
TestFeatureVisitor visitor;
base::FeatureList::VisitFeaturesAndParams(visitor);
std::multiset<TestFeatureVisitor::VisitedFeatureState> actual_feature_state=
visitor.feature_state();
std::multiset<TestFeatureVisitor::VisitedFeatureState>
expected_feature_state={
{"TestFeature",FeatureList::OverrideState::OVERRIDE_USE_DEFAULT,
FieldTrialParams{},"TrialExample","A"}};
EXPECT_EQ(actual_feature_state, expected_feature_state);
}
TEST(TestFeatureVisitor,FeatureHasParams){
base::test::ScopedFeatureList outer_scope;
outer_scope.InitWithEmptyFeatureAndFieldTrialLists();
base::test::ScopedFeatureList initialized_feature_list;
initialized_feature_list.InitFromCommandLine(
/*enable_features=*/"TestFeature<foo.bar:k1/v1/k2/v2",
/*disable_features=*/"");
const std::multiset<TestFeatureVisitor::VisitedFeatureState>
expected_feature_state={
{"TestFeature",FeatureList::OverrideState::OVERRIDE_ENABLE_FEATURE,
FieldTrialParams{{"k1","v1"},{"k2","v2"}},"foo","bar"},
};
{// Check cached params.
TestFeatureVisitor visitor;
base::FeatureList::VisitFeaturesAndParams(visitor);
std::multiset<TestFeatureVisitor::VisitedFeatureState>
actual_feature_state= visitor.feature_state();
EXPECT_EQ(actual_feature_state, expected_feature_state);
}
{// Check that we fetch params from shared memory.
FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded();
FieldTrialParamAssociator::GetInstance()->ClearAllCachedParamsForTesting();
TestFeatureVisitor visitor;
base::FeatureList::VisitFeaturesAndParams(visitor);
std::multiset<TestFeatureVisitor::VisitedFeatureState>
actual_feature_state= visitor.feature_state();
EXPECT_EQ(actual_feature_state, expected_feature_state);
}
}
TEST(TestFeatureVisitor,FeatureWithPrefix){
base::test::ScopedFeatureList outer_scope;
outer_scope.InitWithEmptyFeatureAndFieldTrialLists();
base::test::ScopedFeatureList initialized_feature_list;
initialized_feature_list.InitFromCommandLine(
/*enable_features=*/
"AFeature,AnotherFeature,TestFeature,TestFeature2,PrefixedFeature,"
"PrefixedFeature2",
/*disable_features=*/"");
TestFeatureVisitor visitor;
base::FeatureList::VisitFeaturesAndParams(visitor,"Prefixed");
std::multiset<TestFeatureVisitor::VisitedFeatureState> actual_feature_state=
visitor.feature_state();
std::multiset<TestFeatureVisitor::VisitedFeatureState>
expected_feature_state={
{"PrefixedFeature",
FeatureList::OverrideState::OVERRIDE_ENABLE_FEATURE,
FieldTrialParams{},"",""},
{"PrefixedFeature2",
FeatureList::OverrideState::OVERRIDE_ENABLE_FEATURE,
FieldTrialParams{},"",""},
};
EXPECT_EQ(actual_feature_state, expected_feature_state);
}
}// namespace base

[8]ページ先頭

©2009-2025 Movatter.jp