about_flags_unittest.cc revision 72a454cd3513ac24fbdd0e0cb9ad70b86a99b801
1// Copyright (c) 2010 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#include "base/string_number_conversions.h"
6#include "base/utf_string_conversions.h"
7#include "base/values.h"
8#include "chrome/browser/about_flags.h"
9#include "chrome/common/chrome_switches.h"
10#include "chrome/common/pref_names.h"
11#include "chrome/test/testing_pref_service.h"
12#include "grit/chromium_strings.h"
13#include "testing/gtest/include/gtest/gtest.h"
14
15const char kFlags1[] = "flag1";
16const char kFlags2[] = "flag2";
17const char kFlags3[] = "flag3";
18const char kFlags4[] = "flag4";
19
20const char kSwitch1[] = "switch";
21const char kSwitch2[] = "switch2";
22const char kSwitch3[] = "switch3";
23const char kValueForSwitch2[] = "value_for_switch2";
24
25const char kMultiSwitch1[] = "multi_switch1";
26const char kMultiSwitch2[] = "multi_switch2";
27const char kValueForMultiSwitch2[] = "value_for_multi_switch2";
28
29namespace about_flags {
30
31const Experiment::Choice kMultiChoices[] = {
32  { IDS_PRODUCT_NAME, "", "" },
33  { IDS_PRODUCT_NAME, kMultiSwitch1, "" },
34  { IDS_PRODUCT_NAME, kMultiSwitch2, kValueForMultiSwitch2 },
35};
36
37// The experiments that are set for these tests. The 3rd experiment is not
38// supported on the current platform, all others are.
39static Experiment kExperiments[] = {
40  {
41    kFlags1,
42    IDS_PRODUCT_NAME,
43    IDS_PRODUCT_NAME,
44    0,  // Ends up being mapped to the current platform.
45    Experiment::SINGLE_VALUE,
46    kSwitch1,
47    "",
48    NULL,
49    0
50  },
51  {
52    kFlags2,
53    IDS_PRODUCT_NAME,
54    IDS_PRODUCT_NAME,
55    0,  // Ends up being mapped to the current platform.
56    Experiment::SINGLE_VALUE,
57    kSwitch2,
58    kValueForSwitch2,
59    NULL,
60    0
61  },
62  {
63    kFlags3,
64    IDS_PRODUCT_NAME,
65    IDS_PRODUCT_NAME,
66    0,  // This ends up enabling for an OS other than the current.
67    Experiment::SINGLE_VALUE,
68    kSwitch3,
69    "",
70    NULL,
71    0
72  },
73  {
74    kFlags4,
75    IDS_PRODUCT_NAME,
76    IDS_PRODUCT_NAME,
77    0,  // Ends up being mapped to the current platform.
78    Experiment::MULTI_VALUE,
79    "",
80    "",
81    kMultiChoices,
82    arraysize(kMultiChoices)
83  },
84};
85
86class AboutFlagsTest : public ::testing::Test {
87 protected:
88  AboutFlagsTest() {
89    prefs_.RegisterListPref(prefs::kEnabledLabsExperiments);
90#if defined(OS_CHROMEOS)
91    prefs_.RegisterBooleanPref(prefs::kLabsMediaplayerEnabled, false);
92    prefs_.RegisterBooleanPref(prefs::kLabsAdvancedFilesystemEnabled, false);
93    prefs_.RegisterBooleanPref(prefs::kUseVerticalTabs, false);
94#endif
95    testing::ClearState();
96  }
97
98  virtual void SetUp() {
99    for (size_t i = 0; i < arraysize(kExperiments); ++i)
100      kExperiments[i].supported_platforms = GetCurrentPlatform();
101
102    int os_other_than_current = 1;
103    while (os_other_than_current == GetCurrentPlatform())
104      os_other_than_current <<= 1;
105    kExperiments[2].supported_platforms = os_other_than_current;
106
107    testing::SetExperiments(kExperiments, arraysize(kExperiments));
108  }
109
110  virtual void TearDown() {
111    testing::SetExperiments(NULL, 0);
112  }
113
114  TestingPrefService prefs_;
115};
116
117TEST_F(AboutFlagsTest, ChangeNeedsRestart) {
118  EXPECT_FALSE(IsRestartNeededToCommitChanges());
119  SetExperimentEnabled(&prefs_, kFlags1, true);
120  EXPECT_TRUE(IsRestartNeededToCommitChanges());
121}
122
123TEST_F(AboutFlagsTest, AddTwoFlagsRemoveOne) {
124  // Add two experiments, check they're there.
125  SetExperimentEnabled(&prefs_, kFlags1, true);
126  SetExperimentEnabled(&prefs_, kFlags2, true);
127
128  ListValue* experiments_list = prefs_.GetMutableList(
129      prefs::kEnabledLabsExperiments);
130  ASSERT_TRUE(experiments_list != NULL);
131
132  ASSERT_EQ(2u, experiments_list->GetSize());
133
134  std::string s0;
135  ASSERT_TRUE(experiments_list->GetString(0, &s0));
136  std::string s1;
137  ASSERT_TRUE(experiments_list->GetString(1, &s1));
138
139  EXPECT_TRUE(s0 == kFlags1 || s1 == kFlags1);
140  EXPECT_TRUE(s0 == kFlags2 || s1 == kFlags2);
141
142  // Remove one experiment, check the other's still around.
143  SetExperimentEnabled(&prefs_, kFlags2, false);
144
145  experiments_list = prefs_.GetMutableList(prefs::kEnabledLabsExperiments);
146  ASSERT_TRUE(experiments_list != NULL);
147  ASSERT_EQ(1u, experiments_list->GetSize());
148  ASSERT_TRUE(experiments_list->GetString(0, &s0));
149  EXPECT_TRUE(s0 == kFlags1);
150}
151
152TEST_F(AboutFlagsTest, AddTwoFlagsRemoveBoth) {
153  // Add two experiments, check the pref exists.
154  SetExperimentEnabled(&prefs_, kFlags1, true);
155  SetExperimentEnabled(&prefs_, kFlags2, true);
156  ListValue* experiments_list = prefs_.GetMutableList(
157      prefs::kEnabledLabsExperiments);
158  ASSERT_TRUE(experiments_list != NULL);
159
160  // Remove both, the pref should have been removed completely.
161  SetExperimentEnabled(&prefs_, kFlags1, false);
162  SetExperimentEnabled(&prefs_, kFlags2, false);
163  experiments_list = prefs_.GetMutableList(prefs::kEnabledLabsExperiments);
164  EXPECT_TRUE(experiments_list == NULL || experiments_list->GetSize() == 0);
165}
166
167TEST_F(AboutFlagsTest, ConvertFlagsToSwitches) {
168  SetExperimentEnabled(&prefs_, kFlags1, true);
169
170  CommandLine command_line(CommandLine::NO_PROGRAM);
171  command_line.AppendSwitch("foo");
172
173  EXPECT_TRUE(command_line.HasSwitch("foo"));
174  EXPECT_FALSE(command_line.HasSwitch(kSwitch1));
175
176  ConvertFlagsToSwitches(&prefs_, &command_line);
177
178  EXPECT_TRUE(command_line.HasSwitch("foo"));
179  EXPECT_TRUE(command_line.HasSwitch(kSwitch1));
180}
181
182TEST_F(AboutFlagsTest, RemoveFlagSwitches) {
183  std::map<std::string, CommandLine::StringType> switch_list;
184  switch_list[kSwitch1] = CommandLine::StringType();
185  switch_list[switches::kFlagSwitchesBegin] = CommandLine::StringType();
186  switch_list[switches::kFlagSwitchesEnd] = CommandLine::StringType();
187  switch_list["foo"] = CommandLine::StringType();
188
189  SetExperimentEnabled(&prefs_, kFlags1, true);
190
191  // This shouldn't do anything before ConvertFlagsToSwitches() wasn't called.
192  RemoveFlagsSwitches(&switch_list);
193  ASSERT_EQ(4u, switch_list.size());
194  EXPECT_TRUE(switch_list.find(kSwitch1) != switch_list.end());
195  EXPECT_TRUE(switch_list.find(switches::kFlagSwitchesBegin) !=
196              switch_list.end());
197  EXPECT_TRUE(switch_list.find(switches::kFlagSwitchesEnd) !=
198              switch_list.end());
199  EXPECT_TRUE(switch_list.find("foo") != switch_list.end());
200
201  // Call ConvertFlagsToSwitches(), then RemoveFlagsSwitches() again.
202  CommandLine command_line(CommandLine::NO_PROGRAM);
203  command_line.AppendSwitch("foo");
204  ConvertFlagsToSwitches(&prefs_, &command_line);
205  RemoveFlagsSwitches(&switch_list);
206
207  // Now the about:flags-related switch should have been removed.
208  ASSERT_EQ(1u, switch_list.size());
209  EXPECT_TRUE(switch_list.find("foo") != switch_list.end());
210}
211
212// Tests enabling experiments that aren't supported on the current platform.
213TEST_F(AboutFlagsTest, PersistAndPrune) {
214  // Enable experiments 1 and 3.
215  SetExperimentEnabled(&prefs_, kFlags1, true);
216  SetExperimentEnabled(&prefs_, kFlags3, true);
217  CommandLine command_line(CommandLine::NO_PROGRAM);
218  EXPECT_FALSE(command_line.HasSwitch(kSwitch1));
219  EXPECT_FALSE(command_line.HasSwitch(kSwitch3));
220
221  // Convert the flags to switches. Experiment 3 shouldn't be among the switches
222  // as it is not applicable to the current platform.
223  ConvertFlagsToSwitches(&prefs_, &command_line);
224  EXPECT_TRUE(command_line.HasSwitch(kSwitch1));
225  EXPECT_FALSE(command_line.HasSwitch(kSwitch3));
226
227  // Experiment 3 should show still be persisted in preferences though.
228  scoped_ptr<ListValue> switch_prefs(GetFlagsExperimentsData(&prefs_));
229  ASSERT_TRUE(switch_prefs.get());
230  EXPECT_EQ(arraysize(kExperiments) - 1, switch_prefs->GetSize());
231}
232
233// Tests that switches which should have values get them in the command
234// line.
235TEST_F(AboutFlagsTest, CheckValues) {
236  // Enable experiments 1 and 2.
237  SetExperimentEnabled(&prefs_, kFlags1, true);
238  SetExperimentEnabled(&prefs_, kFlags2, true);
239  CommandLine command_line(CommandLine::NO_PROGRAM);
240  EXPECT_FALSE(command_line.HasSwitch(kSwitch1));
241  EXPECT_FALSE(command_line.HasSwitch(kSwitch2));
242
243  // Convert the flags to switches.
244  ConvertFlagsToSwitches(&prefs_, &command_line);
245  EXPECT_TRUE(command_line.HasSwitch(kSwitch1));
246  EXPECT_EQ(std::string(""),
247            command_line.GetSwitchValueASCII(kSwitch1));
248  EXPECT_TRUE(command_line.HasSwitch(kSwitch2));
249  EXPECT_EQ(std::string(kValueForSwitch2),
250            command_line.GetSwitchValueASCII(kSwitch2));
251
252  // Confirm that there is no '=' in the command line for simple switches.
253  std::string switch1_with_equals = std::string("--") +
254                                    std::string(kSwitch1) +
255                                    std::string("=");
256#if defined(OS_WIN)
257  EXPECT_EQ(std::wstring::npos,
258            command_line.command_line_string().find(
259                ASCIIToWide(switch1_with_equals)));
260#else
261  EXPECT_EQ(std::string::npos,
262            command_line.command_line_string().find(switch1_with_equals));
263#endif
264
265  // And confirm there is a '=' for switches with values.
266  std::string switch2_with_equals = std::string("--") +
267                                    std::string(kSwitch2) +
268                                    std::string("=");
269#if defined(OS_WIN)
270  EXPECT_NE(std::wstring::npos,
271            command_line.command_line_string().find(
272                ASCIIToWide(switch2_with_equals)));
273#else
274  EXPECT_NE(std::string::npos,
275            command_line.command_line_string().find(switch2_with_equals));
276#endif
277
278  // And it should persist
279  scoped_ptr<ListValue> switch_prefs(GetFlagsExperimentsData(&prefs_));
280  ASSERT_TRUE(switch_prefs.get());
281  EXPECT_EQ(arraysize(kExperiments) - 1, switch_prefs->GetSize());
282}
283
284// Tests multi-value type experiments.
285TEST_F(AboutFlagsTest, MultiValues) {
286  // Initially, the first "deactivated" option of the multi experiment should
287  // be set.
288  {
289    CommandLine command_line(CommandLine::NO_PROGRAM);
290    ConvertFlagsToSwitches(&prefs_, &command_line);
291    EXPECT_FALSE(command_line.HasSwitch(kMultiSwitch1));
292    EXPECT_FALSE(command_line.HasSwitch(kMultiSwitch2));
293  }
294
295  // Enable the 2nd choice of the multi-value.
296  SetExperimentEnabled(&prefs_, std::string(kFlags4) +
297                       std::string(testing::kMultiSeparator) +
298                       base::IntToString(2), true);
299  {
300    CommandLine command_line(CommandLine::NO_PROGRAM);
301    ConvertFlagsToSwitches(&prefs_, &command_line);
302    EXPECT_FALSE(command_line.HasSwitch(kMultiSwitch1));
303    EXPECT_TRUE(command_line.HasSwitch(kMultiSwitch2));
304    EXPECT_EQ(std::string(kValueForMultiSwitch2),
305              command_line.GetSwitchValueASCII(kMultiSwitch2));
306  }
307
308  // Disable the multi-value experiment.
309  SetExperimentEnabled(&prefs_, std::string(kFlags4) +
310                       std::string(testing::kMultiSeparator) +
311                       base::IntToString(0), true);
312  {
313    CommandLine command_line(CommandLine::NO_PROGRAM);
314    ConvertFlagsToSwitches(&prefs_, &command_line);
315    EXPECT_FALSE(command_line.HasSwitch(kMultiSwitch1));
316    EXPECT_FALSE(command_line.HasSwitch(kMultiSwitch2));
317  }
318}
319
320// Makes sure there are no separators in any of the experiment names.
321TEST_F(AboutFlagsTest, NoSeparators) {
322  testing::SetExperiments(NULL, 0);
323  size_t count;
324  const Experiment* experiments = testing::GetExperiments(&count);
325    for (size_t i = 0; i < count; ++i) {
326    std::string name = experiments->internal_name;
327    EXPECT_EQ(std::string::npos, name.find(testing::kMultiSeparator)) << i;
328  }
329}
330
331}  // namespace about_flags
332