#define private public
#define protected public
#include "base/feature_list.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/field_trial_param_associator.h"
#include "base/test/scoped_feature_list.h"
#undef protected
#undef private
#include <stddef.h>
#include <utility>
#include <vector>
#include "base/feature_list.cc"
#include "base/feature_list_buildflags.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/ranges/algorithm.h"
#include "base/strings/strcat.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
class MockSharedMemoryMapper : public SharedMemoryMapper {
public:
MOCK_METHOD(absl::optional<span<uint8_t>>,
Map,
(subtle::PlatformSharedMemoryHandle handle,
bool write_allowed,
uint64_t offset,
size_t size),
(override));
MOCK_METHOD(void, Unmap, (span<uint8_t> mapping), (override));
};
namespace {
#ifdef OHOS_SCROLLBAR
constexpr char kFeatureOverlayScrollbarName[] = "OverlayScrollbar";
#endif
constexpr char kFeatureOnByDefaultName[] = "OnByDefault";
CONSTINIT Feature kFeatureOnByDefault(kFeatureOnByDefaultName,
FEATURE_ENABLED_BY_DEFAULT);
constexpr char kFeatureOffByDefaultName[] = "OffByDefault";
CONSTINIT Feature kFeatureOffByDefault(kFeatureOffByDefaultName,
FEATURE_DISABLED_BY_DEFAULT);
std::string SortFeatureListString(const std::string& feature_list) {
std::vector<base::StringPiece> features =
FeatureList::SplitFeatureListString(feature_list);
ranges::sort(features);
return JoinString(features, ",");
}
}
class FeatureListTest : public testing::Test {
public:
FeatureListTest() {
scoped_feature_list_.InitWithFeatureList(std::make_unique<FeatureList>());
}
FeatureListTest(const FeatureListTest&) = delete;
FeatureListTest& operator=(const FeatureListTest&) = delete;
~FeatureListTest() override = default;
void SetUp() override {
auto feature_list = std::make_unique<FeatureList>();
test_feature_list_ = feature_list.get();
scoped_feature_list_.InitWithFeatureList(std::move(feature_list));
}
void TearDown() override { g_feature_list_instance = nullptr; }
protected:
test::ScopedFeatureList scoped_feature_list_;
FeatureList* test_feature_list_;
};
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},
{"OnByDefault", "OnByDefault,OffByDefault", false, false},
};
for (size_t i = 0; i < std::size(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));
auto feature_list = std::make_unique<FeatureList>();
feature_list->InitializeFromCommandLine(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;
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, InitializeFromCommandLineWithFeatureParams) {
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"}}},
};
base::FieldTrialParamAssociator::GetInstance()->ClearAllParamsForTesting();
static BASE_FEATURE(kFeature, "Feature", FEATURE_DISABLED_BY_DEFAULT);
for (const auto& test_case : test_cases) {
SCOPED_TRACE(test_case.enable_features);
auto feature_list = std::make_unique<FeatureList>();
feature_list->InitializeFromCommandLine(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) {
test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitWithFeatureList(std::make_unique<FeatureList>());
FeatureList* feature_list = FeatureList::GetInstance();
EXPECT_TRUE(feature_list->CheckFeatureIdentity(kFeatureOnByDefault));
EXPECT_TRUE(feature_list->CheckFeatureIdentity(kFeatureOnByDefault));
EXPECT_TRUE(feature_list->CheckFeatureIdentity(kFeatureOffByDefault));
EXPECT_TRUE(feature_list->CheckFeatureIdentity(kFeatureOffByDefault));
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 < std::size(test_cases); ++i) {
const auto& 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));
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));
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));
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));
EXPECT_FALSE(FieldTrialList::IsTrialActive(trial1->trial_name()));
EXPECT_FALSE(FieldTrialList::IsTrialActive(trial2->trial_name()));
EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault));
EXPECT_TRUE(FieldTrialList::IsTrialActive(trial1->trial_name()));
EXPECT_FALSE(FieldTrialList::IsTrialActive(trial2->trial_name()));
EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
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>();
feature_list->InitializeFromCommandLine(kFeatureOffByDefaultName, "");
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()));
EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault));
EXPECT_FALSE(FieldTrialList::IsTrialActive(trial->trial_name()));
}
TEST_F(FeatureListTest, CommandLineDisableTakesPrecedenceOverFieldTrial) {
auto feature_list = std::make_unique<FeatureList>();
feature_list->InitializeFromCommandLine("", kFeatureOffByDefaultName);
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()));
EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
EXPECT_FALSE(FieldTrialList::IsTrialActive(trial->trial_name()));
}
TEST_F(FeatureListTest, IsFeatureOverriddenFromFieldTrial) {
auto feature_list = std::make_unique<FeatureList>();
EXPECT_FALSE(feature_list->IsFeatureOverridden(kFeatureOnByDefaultName));
EXPECT_FALSE(feature_list->IsFeatureOverridden(kFeatureOffByDefaultName));
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));
EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault));
}
TEST_F(FeatureListTest, IsFeatureOverriddenFromCommandLine) {
auto feature_list = std::make_unique<FeatureList>();
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));
feature_list->InitializeFromCommandLine(kFeatureOffByDefaultName, "");
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));
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));
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));
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[] = {
{"", "", false, false},
{kFeatureOffByDefaultName, "", true, false},
{"", kFeatureOffByDefaultName, false, true},
};
const char kTrialName[] = "ForcingTrial";
const char kForcedOnGroupName[] = "ForcedOn";
const char kForcedOffGroupName[] = "ForcedOff";
for (size_t i = 0; i < std::size(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));
test::ScopedFeatureList outer_scope;
outer_scope.InitWithEmptyFeatureAndFieldTrialLists();
auto feature_list = std::make_unique<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);
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());
} else if (enable_trial) {
EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault));
EXPECT_TRUE(FieldTrialList::IsTrialActive(kTrialName));
EXPECT_EQ(kForcedOnGroupName, enable_trial->group_name());
}
}
}
TEST_F(FeatureListTest, RegisterExtraFeatureOverrides) {
auto feature_list = std::make_unique<FeatureList>();
std::vector<FeatureList::FeatureOverrideInfo> overrides;
overrides.push_back({std::cref(kFeatureOnByDefault),
FeatureList::OverrideState::OVERRIDE_DISABLE_FEATURE});
overrides.push_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, InitializeFromCommandLineThenRegisterExtraOverrides) {
auto feature_list = std::make_unique<FeatureList>();
feature_list->InitializeFromCommandLine(kFeatureOnByDefaultName,
kFeatureOffByDefaultName);
std::vector<FeatureList::FeatureOverrideInfo> overrides;
overrides.push_back({std::cref(kFeatureOnByDefault),
FeatureList::OverrideState::OVERRIDE_DISABLE_FEATURE});
overrides.push_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_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->InitializeFromCommandLine("A,X", "D");
Feature feature_b = {"B", FEATURE_ENABLED_BY_DEFAULT};
Feature feature_c = {"C", FEATURE_DISABLED_BY_DEFAULT};
std::vector<FeatureList::FeatureOverrideInfo> overrides;
overrides.push_back({std::cref(feature_b),
FeatureList::OverrideState::OVERRIDE_DISABLE_FEATURE});
overrides.push_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->InitializeFromCommandLine("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, InitializeFromCommandLine_WithFieldTrials) {
FieldTrialList::CreateFieldTrial("Trial", "Group");
auto feature_list = std::make_unique<FeatureList>();
feature_list->InitializeFromCommandLine("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, InitializeFromCommandLine_UseDefault) {
FieldTrialList::CreateFieldTrial("T1", "Group");
FieldTrialList::CreateFieldTrial("T2", "Group");
auto feature_list = std::make_unique<FeatureList>();
feature_list->InitializeFromCommandLine(
"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, InitializeInstance) {
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));
FeatureList::InitializeInstance("", kFeatureOnByDefaultName);
EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault));
EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
FeatureList::InitializeInstance(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();
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);
feature_list->RegisterOverride(kFeatureOffByDefaultName,
FeatureList::OVERRIDE_ENABLE_FEATURE, nullptr);
feature_list->RegisterOverride(
kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE, nullptr);
feature_list->FinalizeInitialization();
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);
EXPECT_FALSE(feature_list2->IsFeatureOverriddenFromCommandLine(
kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE));
EXPECT_FALSE(feature_list2->IsFeatureOverriddenFromCommandLine(
kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE));
feature_list2->InitializeFromSharedMemory(&allocator);
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);
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();
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->InitializeFromSharedMemory(&allocator);
feature_list2->FinalizeInitialization();
FieldTrial* associated_trial1 =
feature_list2->GetAssociatedFieldTrial(kFeatureOnByDefault);
FieldTrial* associated_trial2 =
feature_list2->GetAssociatedFieldTrial(kFeatureOffByDefault);
EXPECT_EQ(associated_trial1, trial1);
EXPECT_EQ(associated_trial2, trial2);
}
#ifdef OHOS_SCROLLBAR
TEST_F(FeatureListTest, ModifyFeaturesToAllocatorFromSharedMemory) {
std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
feature_list->RegisterOverride(kFeatureOverlayScrollbarName,
FeatureList::OVERRIDE_ENABLE_FEATURE, nullptr);
feature_list->FinalizeInitialization();
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);
EXPECT_FALSE(feature_list2->IsFeatureOverriddenFromCommandLine(
kFeatureOverlayScrollbarName, FeatureList::OVERRIDE_ENABLE_FEATURE));
feature_list2->InitializeFromSharedMemory(&allocator);
EXPECT_TRUE(feature_list2->IsFeatureOverriddenFromCommandLine(
kFeatureOverlayScrollbarName, FeatureList::OVERRIDE_ENABLE_FEATURE));
}
TEST_F(FeatureListTest, SetOverrideStateByFeatureNameUseDefault) {
auto feature_list = std::make_unique<FeatureList>();
EXPECT_FALSE(feature_list->IsFeatureOverridden(kFeatureOverlayScrollbarName));
feature_list->RegisterFieldTrialOverride(
kFeatureOverlayScrollbarName, FeatureList::OVERRIDE_USE_DEFAULT,
FieldTrialList::CreateFieldTrial("Trial1", "A"));
EXPECT_TRUE(feature_list->IsFeatureOverridden(kFeatureOverlayScrollbarName));
FeatureList::OverrideState state = FeatureList::OVERRIDE_ENABLE_FEATURE;
feature_list->SetOverrideStateByFeatureName(kFeatureOverlayScrollbarName,
state);
EXPECT_TRUE(feature_list->IsFeatureOverridden(kFeatureOverlayScrollbarName));
}
TEST_F(FeatureListTest, SetScrollbarEnable) {
auto feature_list = std::make_unique<FeatureList>();
EXPECT_FALSE(feature_list->IsFeatureOverridden(kFeatureOverlayScrollbarName));
feature_list->RegisterFieldTrialOverride(
kFeatureOverlayScrollbarName, FeatureList::OVERRIDE_USE_DEFAULT,
FieldTrialList::CreateFieldTrial("Trial1", "A"));
EXPECT_TRUE(feature_list->IsFeatureOverridden(kFeatureOverlayScrollbarName));
feature_list->SetScrollbarEnable(true);
EXPECT_TRUE(feature_list->IsFeatureOverridden(kFeatureOverlayScrollbarName));
}
TEST_F(FeatureListTest, ModifyFeaturesToAllocator) {
std::unique_ptr<base::FeatureList> feature_list =
std::make_unique<FeatureList>();
ASSERT_NE(feature_list, nullptr);
base::MappedReadOnlyRegion shm =
base::ReadOnlySharedMemoryRegion::Create(4 << 10);
WritableSharedPersistentMemoryAllocator allocator(std::move(shm.mapping), 1,
"");
feature_list->initialized_ = false;
feature_list->ModifyFeaturesToAllocator(&allocator);
}
TEST_F(FeatureListTest, AddFeaturesToAllocator) {
std::unique_ptr<base::FeatureList> feature_list =
std::make_unique<FeatureList>();
feature_list->RegisterOverride(kFeatureOffByDefaultName,
FeatureList::OVERRIDE_ENABLE_FEATURE, nullptr);
feature_list->RegisterOverride(
kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE, nullptr);
feature_list->FinalizeInitialization();
SharedMemoryMapper* shared_mapper_ptr =
SharedMemoryMapper::GetDefaultInstance();
base::MappedReadOnlyRegion shm =
base::ReadOnlySharedMemoryRegion::Create(4 << 10, shared_mapper_ptr);
WritableSharedPersistentMemoryAllocator allocator(std::move(shm.mapping), 1,
"");
feature_list->AddFeaturesToAllocator(&allocator);
std::unique_ptr<base::FeatureList> feature_list2(new base::FeatureList);
EXPECT_FALSE(feature_list2->IsFeatureOverriddenFromCommandLine(
kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE));
EXPECT_FALSE(feature_list2->IsFeatureOverriddenFromCommandLine(
kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE));
feature_list2->InitializeFromSharedMemory(&allocator);
EXPECT_TRUE(feature_list2->IsFeatureOverriddenFromCommandLine(
kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE));
EXPECT_TRUE(feature_list2->IsFeatureOverriddenFromCommandLine(
kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE));
}
TEST_F(FeatureListTest, SetScrollbarEnable1) {
std::unique_ptr<base::FeatureList> feature_list =
std::make_unique<FeatureList>();
feature_list->SetScrollbarEnable(true);
EXPECT_FALSE(feature_list->IsFeatureOverridden(kFeatureOverlayScrollbarName));
}
TEST_F(FeatureListTest, SetScrollbarEnable2) {
std::unique_ptr<base::FeatureList> feature_list =
std::make_unique<FeatureList>();
FeatureList::SetScrollbarEnable(false);
EXPECT_FALSE(feature_list->IsFeatureOverridden(kFeatureOverlayScrollbarName));
}
TEST_F(FeatureListTest, AddFeatureToField) {
std::unique_ptr<base::FeatureList> feature_list =
std::make_unique<FeatureList>();
ASSERT_NE(feature_list, nullptr);
feature_list->RegisterOverride(kFeatureOffByDefaultName,
FeatureList::OVERRIDE_ENABLE_FEATURE, nullptr);
feature_list->RegisterOverride(
kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE, nullptr);
feature_list->RegisterOverride(
kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE, nullptr);
feature_list->FinalizeInitialization();
base::MappedReadOnlyRegion shm =
base::ReadOnlySharedMemoryRegion::Create(4 << 10);
WritableSharedPersistentMemoryAllocator allocator(std::move(shm.mapping), 1,
"");
int cnt = 0;
size_t total_size;
for (auto& override : feature_list->overrides_) {
if (cnt == 0) {
override.first = "OverlayScrollbar";
}
if (cnt == 1) {
override.first = "ForceScrollbar";
}
if (cnt == 2) {
override.first = "NotOverlayScrollbar";
Pickle pickle;
pickle.WriteString(override.first);
total_size = sizeof(FeatureEntry) + pickle.size();
}
++cnt;
}
feature_list->AddFeaturesToAllocator(&allocator);
ASSERT_NE(allocator.New<FeatureEntry>(total_size), nullptr);
}
#endif
#if BUILDFLAG(ENABLE_BANNED_BASE_FEATURE_PREFIX) && \
defined(GTEST_HAS_DEATH_TEST)
using FeatureListDeathTest = FeatureListTest;
TEST_F(FeatureListDeathTest, DiesWithBadFeatureName) {
EXPECT_DEATH(
Feature(
StrCat({BUILDFLAG(BANNED_BASE_FEATURE_PREFIX), "MyFeature"}).c_str(),
FEATURE_DISABLED_BY_DEFAULT),
StrCat({"Invalid feature name ", BUILDFLAG(BANNED_BASE_FEATURE_PREFIX),
"MyFeature"}));
}
#endif
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, InitializeFromCommandLine) {
struct {
const char* enable_features;
const char* disable_features;
FeatureList::OverrideState expected_feature_on_state;
FeatureList::OverrideState expected_feature_off_state;
} test_cases[] = {
{"", "", 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},
{"OnByDefault", "OnByDefault,OffByDefault",
FeatureList::OVERRIDE_DISABLE_FEATURE,
FeatureList::OVERRIDE_DISABLE_FEATURE},
};
for (size_t i = 0; i < std::size(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));
test::ScopedFeatureList scoped_feature_list;
auto feature_list = std::make_unique<FeatureList>();
auto feature_list_accessor = feature_list->ConstructAccessor();
feature_list->InitializeFromCommandLine(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, InitializeFromCommandLineWithFeatureParams) {
struct {
const std::string enable_features;
const std::map<std::string, std::string> expected_feature_params;
} test_cases[] = {
{"Feature:x/100/y/test", {{"x", "100"}, {"y", "test"}}},
{"Feature<Trial:asdf/ghjkl/y/123", {{"asdf", "ghjkl"}, {"y", "123"}}},
};
base::FieldTrialParamAssociator::GetInstance()->ClearAllParamsForTesting();
for (size_t i = 0; i < std::size(test_cases); ++i) {
const auto& 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->InitializeFromCommandLine(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_F(FeatureListTest, SetScrollbarEnableTest001) {
g_feature_list_instance = nullptr;
testing::internal::CaptureStderr();
test_feature_list_->SetScrollbarEnable(true);
std::string log_output = testing::internal::GetCapturedStderr();
EXPECT_NE(log_output.find("set Scrollbar error"), std::string::npos);
}
TEST_F(FeatureListTest, SetScrollbarEnableTest002) {
test_feature_list_->SetScrollbarEnable(true);
EXPECT_EQ(
test_feature_list_->GetOverrideStateByFeatureName("OverlayScrollbar"),
FeatureList::OVERRIDE_DISABLE_FEATURE);
EXPECT_EQ(test_feature_list_->GetOverrideStateByFeatureName("ForceScrollbar"),
FeatureList::OVERRIDE_DISABLE_FEATURE);
}
TEST_F(FeatureListTest, SetScrollbarEnableTest003) {
test_feature_list_->SetScrollbarEnable(false);
EXPECT_EQ(
test_feature_list_->GetOverrideStateByFeatureName("OverlayScrollbar"),
FeatureList::OVERRIDE_ENABLE_FEATURE);
EXPECT_EQ(test_feature_list_->GetOverrideStateByFeatureName("ForceScrollbar"),
FeatureList::OVERRIDE_ENABLE_FEATURE);
}
TEST_F(FeatureListTest, IsFeatureEnabled001) {
Feature overlay_scrollbar_feature{"OverlayScrollbar",
FEATURE_DISABLED_BY_DEFAULT};
test_feature_list_->SetOverrideStateByFeatureName(
overlay_scrollbar_feature.name, FeatureList::OVERRIDE_ENABLE_FEATURE);
testing::internal::CaptureStderr();
test_feature_list_->IsFeatureEnabled(overlay_scrollbar_feature);
std::string log_output = testing::internal::GetCapturedStderr();
EXPECT_NE(log_output.find("Overlay Scrollbar"), std::string::npos);
}
TEST_F(FeatureListTest, IsFeatureEnabled002) {
Feature overlay_scrollbar_feature{"ForceScrollbar",
FEATURE_DISABLED_BY_DEFAULT};
test_feature_list_->SetOverrideStateByFeatureName(
overlay_scrollbar_feature.name, FeatureList::OVERRIDE_ENABLE_FEATURE);
testing::internal::CaptureStderr();
auto a = test_feature_list_->IsFeatureEnabled(overlay_scrollbar_feature);
std::string log_output = testing::internal::GetCapturedStderr();
EXPECT_NE(log_output.find("Force Scrollbar:2"), std::string::npos);
EXPECT_FALSE(a);
}
TEST_F(FeatureListTest, IsFeatureEnabled003) {
Feature overlay_scrollbar_feature{"TestFeature", FEATURE_ENABLED_BY_DEFAULT};
test_feature_list_->SetOverrideStateByFeatureName(
overlay_scrollbar_feature.name, FeatureList::OVERRIDE_USE_DEFAULT);
EXPECT_TRUE(test_feature_list_->IsFeatureEnabled(overlay_scrollbar_feature));
}
}