1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef BASE_TEST_SCOPED_FEATURE_LIST_H_
6 #define BASE_TEST_SCOPED_FEATURE_LIST_H_
7 
8 #include <map>
9 #include <memory>
10 #include <string>
11 #include <vector>
12 
13 #include "base/feature_list.h"
14 #include "base/memory/ref_counted.h"
15 #include "base/metrics/field_trial.h"
16 
17 namespace base {
18 namespace test {
19 
20 // ScopedFeatureList resets the global FeatureList instance to a new empty
21 // instance and restores the original instance upon destruction.
22 // Note: Re-using the same object is not allowed. To reset the feature
23 // list and initialize it anew, destroy an existing scoped list and init
24 // a new one.
25 //
26 // ScopedFeatureList needs to be initialized (via one of Init... methods)
27 // before running code that inspects the state of features.  In practice this
28 // means:
29 // - In browser tests, one of Init... methods should be called from the
30 //   overriden ::testing::Test::SetUp method. For example:
31 //     void SetUp() override {
32 //       scoped_feature_list_.InitAndEnableFeature(features::kMyFeatureHere);
33 //       InProcessBrowserTest::SetUp();
34 //     }
35 class ScopedFeatureList final {
36  public:
37   ScopedFeatureList();
38   ~ScopedFeatureList();
39 
40   // WARNING: This method will reset any globally configured features to their
41   // default values, which can hide feature interaction bugs. Please use
42   // sparingly.  https://crbug.com/713390
43   // Initializes and registers a FeatureList instance with no overrides.
44   void Init();
45 
46   // WARNING: This method will reset any globally configured features to their
47   // default values, which can hide feature interaction bugs. Please use
48   // sparingly.  https://crbug.com/713390
49   // Initializes and registers the given FeatureList instance.
50   void InitWithFeatureList(std::unique_ptr<FeatureList> feature_list);
51 
52   // WARNING: This method will reset any globally configured features to their
53   // default values, which can hide feature interaction bugs. Please use
54   // sparingly.  https://crbug.com/713390
55   // Initializes and registers a FeatureList instance with only the given
56   // enabled and disabled features (comma-separated names).
57   void InitFromCommandLine(const std::string& enable_features,
58                            const std::string& disable_features);
59 
60   // Initializes and registers a FeatureList instance based on present
61   // FeatureList and overridden with the given enabled and disabled features.
62   // Any feature overrides already present in the global FeatureList will
63   // continue to apply, unless they conflict with the overrides passed into this
64   // method. This is important for testing potentially unexpected feature
65   // interactions.
66   void InitWithFeatures(const std::vector<Feature>& enabled_features,
67                         const std::vector<Feature>& disabled_features);
68 
69   // Initializes and registers a FeatureList instance based on present
70   // FeatureList and overridden with single enabled feature.
71   void InitAndEnableFeature(const Feature& feature);
72 
73   // Initializes and registers a FeatureList instance based on present
74   // FeatureList and overridden with single enabled feature and associated field
75   // trial parameters.
76   // Note: this creates a scoped global field trial list if there is not
77   // currently one.
78   void InitAndEnableFeatureWithParameters(
79       const Feature& feature,
80       const std::map<std::string, std::string>& feature_parameters);
81 
82   // Initializes and registers a FeatureList instance based on present
83   // FeatureList and overridden with single disabled feature.
84   void InitAndDisableFeature(const Feature& feature);
85 
86   // Initializes and registers a FeatureList instance based on present
87   // FeatureList and overriden with a single feature either enabled or
88   // disabled depending on |enabled|.
89   void InitWithFeatureState(const Feature& feature, bool enabled);
90 
91  private:
92   // Initializes and registers a FeatureList instance based on present
93   // FeatureList and overridden with the given enabled and disabled features.
94   // Any feature overrides already present in the global FeatureList will
95   // continue to apply, unless they conflict with the overrides passed into this
96   // method.
97   // Field trials will apply to the enabled features, in the same order. The
98   // number of trials must be less (or equal) than the number of enabled
99   // features.
100   // Trials are expected to outlive the ScopedFeatureList.
101   void InitWithFeaturesAndFieldTrials(
102       const std::vector<Feature>& enabled_features,
103       const std::vector<FieldTrial*>& trials_for_enabled_features,
104       const std::vector<Feature>& disabled_features);
105 
106   // Initializes and registers a FeatureList instance based on present
107   // FeatureList and overridden with single enabled feature and associated field
108   // trial override.
109   // |trial| is expected to outlive the ScopedFeatureList.
110   void InitAndEnableFeatureWithFieldTrialOverride(const Feature& feature,
111                                                   FieldTrial* trial);
112 
113   bool init_called_ = false;
114   std::unique_ptr<FeatureList> original_feature_list_;
115   scoped_refptr<FieldTrial> field_trial_override_;
116   std::unique_ptr<base::FieldTrialList> field_trial_list_;
117 
118   DISALLOW_COPY_AND_ASSIGN(ScopedFeatureList);
119 };
120 
121 }  // namespace test
122 }  // namespace base
123 
124 #endif  // BASE_TEST_SCOPED_FEATURE_LIST_H_
125