216 lines
9.2 KiB
C++
216 lines
9.2 KiB
C++
// Copyright 2016 The Chromium Authors
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#ifndef BASE_TEST_SCOPED_FEATURE_LIST_H_
|
|
#define BASE_TEST_SCOPED_FEATURE_LIST_H_
|
|
|
|
#include <map>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "base/feature_list.h"
|
|
#include "base/memory/raw_ptr.h"
|
|
#include "base/memory/raw_ref.h"
|
|
#include "base/metrics/field_trial.h"
|
|
#include "base/metrics/field_trial_params.h"
|
|
#include "base/types/pass_key.h"
|
|
#include "third_party/abseil-cpp/absl/base/attributes.h"
|
|
|
|
namespace base::test {
|
|
|
|
// A reference to a base::Feature and field trial params that should be force
|
|
// enabled and overwritten for test purposes.
|
|
struct FeatureRefAndParams {
|
|
FeatureRefAndParams(const Feature& feature ABSL_ATTRIBUTE_LIFETIME_BOUND,
|
|
const FieldTrialParams& params);
|
|
|
|
FeatureRefAndParams(const FeatureRefAndParams& other);
|
|
|
|
~FeatureRefAndParams();
|
|
|
|
const raw_ref<const Feature> feature;
|
|
const FieldTrialParams params;
|
|
};
|
|
|
|
// A lightweight wrapper for a reference to a base::Feature. Allows lists of
|
|
// features to be enabled/disabled to be easily passed without actually copying
|
|
// the underlying base::Feature. Actual C++ references do not work well for this
|
|
// purpose, as vectors of references are disallowed.
|
|
class FeatureRef {
|
|
public:
|
|
// NOLINTNEXTLINE(google-explicit-constructor)
|
|
FeatureRef(const Feature& feature ABSL_ATTRIBUTE_LIFETIME_BOUND)
|
|
: feature_(feature) {}
|
|
|
|
const Feature& operator*() const { return *feature_; }
|
|
const Feature* operator->() const { return &*feature_; }
|
|
|
|
private:
|
|
friend bool operator==(const FeatureRef& lhs, const FeatureRef& rhs) {
|
|
return &*lhs == &*rhs;
|
|
}
|
|
friend bool operator<(const FeatureRef& lhs, const FeatureRef& rhs) {
|
|
return &*lhs < &*rhs;
|
|
}
|
|
|
|
raw_ref<const Feature> feature_;
|
|
};
|
|
|
|
// ScopedFeatureList resets the global FeatureList instance to a new empty
|
|
// instance and restores the original instance upon destruction. When using the
|
|
// non-deprecated APIs, a corresponding FieldTrialList is also created.
|
|
//
|
|
// Note: Re-using the same object is allowed. To reset the feature list and
|
|
// initialize it anew, call `Reset` and then one of the `Init` methods.
|
|
//
|
|
// If multiple instances of this class are used in a nested fashion, they
|
|
// should be destroyed in the opposite order of their Init*() methods being
|
|
// called.
|
|
//
|
|
// ScopedFeatureList needs to be initialized on the main thread (via one of
|
|
// Init*() methods) before running code that inspects the state of features,
|
|
// such as in the constructor of the test harness.
|
|
//
|
|
// WARNING: To be clear, in multithreaded test environments (such as browser
|
|
// tests) there may background threads using FeatureList before the test body is
|
|
// even entered. In these cases it is imperative that ScopedFeatureList be
|
|
// initialized BEFORE those threads are started, hence the recommendation to do
|
|
// initialization in the test harness's constructor.
|
|
class ScopedFeatureList final {
|
|
public:
|
|
struct Features;
|
|
struct FeatureWithStudyGroup;
|
|
|
|
// Constructs the instance in a non-initialized state.
|
|
ScopedFeatureList();
|
|
|
|
// Shorthand for immediately initializing with InitAndEnableFeature().
|
|
explicit ScopedFeatureList(const Feature& enable_feature);
|
|
|
|
ScopedFeatureList(const ScopedFeatureList&) = delete;
|
|
ScopedFeatureList& operator=(const ScopedFeatureList&) = delete;
|
|
|
|
~ScopedFeatureList();
|
|
|
|
// Resets the instance to a non-initialized state.
|
|
void Reset();
|
|
|
|
// Initializes and registers a FeatureList instance without any additional
|
|
// enabled or disabled features. Existing state, if any, will be kept.
|
|
// This is equivalent to calling InitWithFeatures({}, {}).
|
|
void Init();
|
|
|
|
// Initializes a FeatureList instance without any additional enabled or
|
|
// disabled features. Existing state, if any, will be discarded.
|
|
// Using this function is not generally recommended, as doing so in a test
|
|
// removes the ability to run the test while passing additional
|
|
// --enable-features flags from the command line.
|
|
void InitWithEmptyFeatureAndFieldTrialLists();
|
|
|
|
// Initializes a FeatureList instance and FieldTrialLists to be null and
|
|
// clear all field trial parameters.
|
|
// WARNING: This should not be generally used except for tests that require
|
|
// manually instantiating objects like FieldTrialList, for example when
|
|
// mocking an EntropyProvider.
|
|
void InitWithNullFeatureAndFieldTrialLists();
|
|
|
|
// WARNING: This method will reset any globally configured features to their
|
|
// default values, which can hide feature interaction bugs. Please use
|
|
// sparingly. https://crbug.com/713390
|
|
// Initializes and registers the given FeatureList instance.
|
|
void InitWithFeatureList(std::unique_ptr<FeatureList> feature_list);
|
|
|
|
// Initializes and registers a FeatureList instance based on the current
|
|
// FeatureList and overridden with the given enabled features and the
|
|
// specified field trial parameters, and the given disabled features
|
|
// with the given enabled and disabled features (comma-separated names).
|
|
// Note: This creates a scoped global field trial list if there is not
|
|
// currently one.
|
|
void InitFromCommandLine(const std::string& enable_features,
|
|
const std::string& disable_features);
|
|
|
|
// Initializes and registers a FeatureList instance based on the current
|
|
// FeatureList and overridden with the given enabled and disabled features.
|
|
// Any feature overrides already present in the global FeatureList will
|
|
// continue to apply, unless they conflict with the overrides passed into this
|
|
// method. This is important for testing potentially unexpected feature
|
|
// interactions.
|
|
void InitWithFeatures(const std::vector<FeatureRef>& enabled_features,
|
|
const std::vector<FeatureRef>& disabled_features);
|
|
|
|
// Initializes and registers a FeatureList instance based on the current
|
|
// FeatureList and overridden with single enabled feature.
|
|
void InitAndEnableFeature(const Feature& feature);
|
|
|
|
// Initializes and registers a FeatureList instance based on the current
|
|
// FeatureList and overridden with single enabled feature and associated field
|
|
// trial parameters.
|
|
// Note: this creates a scoped global field trial list if there is not
|
|
// currently one.
|
|
void InitAndEnableFeatureWithParameters(
|
|
const Feature& feature,
|
|
const FieldTrialParams& feature_parameters);
|
|
|
|
// Initializes and registers a FeatureList instance based on the current
|
|
// FeatureList and overridden with the given enabled features and the
|
|
// specified field trial parameters, and the given disabled features.
|
|
// Note: This creates a scoped global field trial list if there is not
|
|
// currently one.
|
|
void InitWithFeaturesAndParameters(
|
|
const std::vector<FeatureRefAndParams>& enabled_features,
|
|
const std::vector<FeatureRef>& disabled_features);
|
|
|
|
// Initializes and registers a FeatureList instance based on the current
|
|
// FeatureList and overridden with single disabled feature.
|
|
void InitAndDisableFeature(const Feature& feature);
|
|
|
|
// Initializes and registers a FeatureList instance based on the current
|
|
// FeatureList and overridden with a single feature either enabled or
|
|
// disabled depending on |enabled|.
|
|
void InitWithFeatureState(const Feature& feature, bool enabled);
|
|
|
|
private:
|
|
using PassKey = base::PassKey<ScopedFeatureList>;
|
|
|
|
// Initializes and registers a FeatureList instance based on the current
|
|
// FeatureList and overridden with the given enabled and disabled features.
|
|
// Any feature overrides already present in the global FeatureList will
|
|
// continue to apply, unless they conflict with the overrides passed into this
|
|
// method.
|
|
// Features to enable may be specified through either |enabled_features| or
|
|
// |enabled_feature_and_params|, but not both (i.e. one of these must be
|
|
// empty).
|
|
void InitWithFeaturesImpl(
|
|
const std::vector<FeatureRef>& enabled_features,
|
|
const std::vector<FeatureRefAndParams>& enabled_features_and_params,
|
|
const std::vector<FeatureRef>& disabled_features,
|
|
bool keep_existing_states = true);
|
|
|
|
// Initializes and registers a FeatureList instance based on the current
|
|
// FeatureList and overridden with the given enabled and disabled features.
|
|
// Any feature overrides already present in the global FeatureList will
|
|
// continue to apply, unless they conflict with the overrides passed into this
|
|
// method.
|
|
// If |create_associated_field_trials| is true, associated field trials are
|
|
// always created independent of feature parameters. If false, field trials
|
|
// for features whose parameters are specified will be created.
|
|
// If |keep_existing_states| is true, keep all states and override them
|
|
// according to the |merged_features|. Otherwise, clear all states and
|
|
// newly initialize all states with |merged_features|.
|
|
void InitWithMergedFeatures(Features&& merged_features,
|
|
bool create_associated_field_trials,
|
|
bool keep_existing_states);
|
|
|
|
bool init_called_ = false;
|
|
std::unique_ptr<FeatureList> original_feature_list_;
|
|
raw_ptr<base::FieldTrialList> original_field_trial_list_ = nullptr;
|
|
std::string original_params_;
|
|
std::unique_ptr<base::FieldTrialList> field_trial_list_;
|
|
};
|
|
|
|
} // namespace base::test
|
|
|
|
#endif // BASE_TEST_SCOPED_FEATURE_LIST_H_
|