• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/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 
15 const char kFlags1[] = "flag1";
16 const char kFlags2[] = "flag2";
17 const char kFlags3[] = "flag3";
18 const char kFlags4[] = "flag4";
19 
20 const char kSwitch1[] = "switch";
21 const char kSwitch2[] = "switch2";
22 const char kSwitch3[] = "switch3";
23 const char kValueForSwitch2[] = "value_for_switch2";
24 
25 const char kMultiSwitch1[] = "multi_switch1";
26 const char kMultiSwitch2[] = "multi_switch2";
27 const char kValueForMultiSwitch2[] = "value_for_multi_switch2";
28 
29 namespace about_flags {
30 
31 const 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.
39 static 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 
86 class AboutFlagsTest : public ::testing::Test {
87  protected:
AboutFlagsTest()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 
SetUp()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 
TearDown()110   virtual void TearDown() {
111     testing::SetExperiments(NULL, 0);
112   }
113 
114   TestingPrefService prefs_;
115 };
116 
TEST_F(AboutFlagsTest,ChangeNeedsRestart)117 TEST_F(AboutFlagsTest, ChangeNeedsRestart) {
118   EXPECT_FALSE(IsRestartNeededToCommitChanges());
119   SetExperimentEnabled(&prefs_, kFlags1, true);
120   EXPECT_TRUE(IsRestartNeededToCommitChanges());
121 }
122 
TEST_F(AboutFlagsTest,AddTwoFlagsRemoveOne)123 TEST_F(AboutFlagsTest, AddTwoFlagsRemoveOne) {
124   // Add two experiments, check they're there.
125   SetExperimentEnabled(&prefs_, kFlags1, true);
126   SetExperimentEnabled(&prefs_, kFlags2, true);
127 
128   const ListValue* experiments_list = prefs_.GetList(
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_.GetList(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 
TEST_F(AboutFlagsTest,AddTwoFlagsRemoveBoth)152 TEST_F(AboutFlagsTest, AddTwoFlagsRemoveBoth) {
153   // Add two experiments, check the pref exists.
154   SetExperimentEnabled(&prefs_, kFlags1, true);
155   SetExperimentEnabled(&prefs_, kFlags2, true);
156   const ListValue* experiments_list = prefs_.GetList(
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_.GetList(prefs::kEnabledLabsExperiments);
164   EXPECT_TRUE(experiments_list == NULL || experiments_list->GetSize() == 0);
165 }
166 
TEST_F(AboutFlagsTest,ConvertFlagsToSwitches)167 TEST_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 
TEST_F(AboutFlagsTest,RemoveFlagSwitches)182 TEST_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.
TEST_F(AboutFlagsTest,PersistAndPrune)213 TEST_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.
TEST_F(AboutFlagsTest,CheckValues)235 TEST_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.
TEST_F(AboutFlagsTest,MultiValues)285 TEST_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.
TEST_F(AboutFlagsTest,NoSeparators)321 TEST_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