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