#ifdef UNSAFE_BUFFERS_BUILD
#pragma allow_unsafe_buffers
#endif
#include "base/feature_list.h"
#include <stddef.h>
#include <ostream>
#include <set>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
#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_util.h"
#include "base/strings/stringprintf.h"
#include "base/test/scoped_feature_list.h"
#include "build/chromeos_buildflags.h"
#include "testing/gtest/include/gtest/gtest.h"
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "base/feature_visitor.h"
#endif
namespace base {
namespace {
constexpr char kFeatureOnByDefaultName[] = …;
BASE_FEATURE(…);
constexpr char kFeatureOffByDefaultName[] = …;
BASE_FEATURE(…);
std::string SortFeatureListString(const std::string& feature_list) { … }
}
class FeatureListTest : public testing::Test { … };
TEST_F(FeatureListTest, DefaultStates) { … }
TEST_F(FeatureListTest, InitFromCommandLine) { … }
TEST_F(FeatureListTest, InitFromCommandLineWithFeatureParams) { … }
TEST_F(FeatureListTest, CheckFeatureIdentity) { … }
TEST_F(FeatureListTest, FieldTrialOverrides) { … }
TEST_F(FeatureListTest, FieldTrialAssociateUseDefault) { … }
TEST_F(FeatureListTest, CommandLineEnableTakesPrecedenceOverFieldTrial) { … }
TEST_F(FeatureListTest, CommandLineDisableTakesPrecedenceOverFieldTrial) { … }
TEST_F(FeatureListTest, IsFeatureOverriddenFromFieldTrial) { … }
TEST_F(FeatureListTest, IsFeatureOverriddenFromCommandLine) { … }
TEST_F(FeatureListTest, AssociateReportingFieldTrial) { … }
TEST_F(FeatureListTest, RegisterExtraFeatureOverrides) { … }
TEST_F(FeatureListTest, InitFromCommandLineThenRegisterExtraOverrides) { … }
TEST_F(FeatureListTest, GetFeatureOverrides) { … }
TEST_F(FeatureListTest, GetFeatureOverrides_UseDefault) { … }
TEST_F(FeatureListTest, GetFieldTrial) { … }
TEST_F(FeatureListTest, InitFromCommandLine_WithFieldTrials) { … }
TEST_F(FeatureListTest, InitFromCommandLine_UseDefault) { … }
TEST_F(FeatureListTest, InitInstance) { … }
TEST_F(FeatureListTest, UninitializedInstance_IsEnabledReturnsFalse) { … }
TEST_F(FeatureListTest, StoreAndRetrieveFeaturesFromSharedMemory) { … }
TEST_F(FeatureListTest, StoreAndRetrieveAssociatedFeaturesFromSharedMemory) { … }
TEST_F(FeatureListTest, SetEarlyAccessInstance_AllowList) { … }
TEST_F(FeatureListTest, SetEarlyAccessInstance_ReplaceByRealList) { … }
#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,
internal::FeatureMacroHandshake::kSecret),
StrCat({"Invalid feature name ", BUILDFLAG(BANNED_BASE_FEATURE_PREFIX),
"MyFeature"}));
}
#endif
TEST(FeatureListAccessorTest, DefaultStates) { … }
TEST(FeatureListAccessorTest, InitFromCommandLine) { … }
TEST(FeatureListAccessorTest, InitFromCommandLineWithFeatureParams) { … }
#if BUILDFLAG(IS_CHROMEOS_ASH)
class TestFeatureVisitor : public FeatureVisitor {
public:
TestFeatureVisitor() = default;
TestFeatureVisitor(const TestFeatureVisitor&) = delete;
TestFeatureVisitor& operator=(const TestFeatureVisitor&) = delete;
~TestFeatureVisitor() override = default;
struct VisitedFeatureState {
auto operator<=>(const VisitedFeatureState&) const = default;
std::string feature_name;
const base::FeatureList::OverrideState override_state;
base::FieldTrialParams params;
std::string trial_name;
std::string group_name;
};
void Visit(const std::string& feature_name,
FeatureList::OverrideState override_state,
const FieldTrialParams& 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_;
};
std::ostream& operator<<(std::ostream& out,
const TestFeatureVisitor::VisitedFeatureState& state) {
out << ".feature_name='" << state.feature_name
<< "', .override_state=" << state.override_state << ", .params={";
for (const auto& 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({kFeatureOffByDefault},
{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(
"TestFeature<foo.bar:k1/v1/k2/v2",
"");
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_ENABLE_FEATURE,
FieldTrialParams{{"k1", "v1"}, {"k2", "v2"}}, "foo", "bar"},
};
EXPECT_EQ(actual_feature_state, expected_feature_state);
}
#endif
}