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.
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/strings/utf_string_conversions.h"
9 #include "base/values.h"
10 #include "chrome/browser/about_flags.h"
11 #include "chrome/browser/pref_service_flags_storage.h"
12 #include "chrome/common/chrome_switches.h"
13 #include "chrome/common/pref_names.h"
14 #include "grit/chromium_strings.h"
15 #include "testing/gtest/include/gtest/gtest.h"
17 const char kFlags1
[] = "flag1";
18 const char kFlags2
[] = "flag2";
19 const char kFlags3
[] = "flag3";
20 const char kFlags4
[] = "flag4";
21 const char kFlags5
[] = "flag5";
23 const char kSwitch1
[] = "switch";
24 const char kSwitch2
[] = "switch2";
25 const char kSwitch3
[] = "switch3";
26 const char kValueForSwitch2
[] = "value_for_switch2";
28 const char kMultiSwitch1
[] = "multi_switch1";
29 const char kMultiSwitch2
[] = "multi_switch2";
30 const char kValueForMultiSwitch2
[] = "value_for_multi_switch2";
32 const char kEnableDisableValue1
[] = "value1";
33 const char kEnableDisableValue2
[] = "value2";
35 namespace about_flags
{
37 const Experiment::Choice kMultiChoices
[] = {
38 { IDS_PRODUCT_NAME
, "", "" },
39 { IDS_PRODUCT_NAME
, kMultiSwitch1
, "" },
40 { IDS_PRODUCT_NAME
, kMultiSwitch2
, kValueForMultiSwitch2
},
43 // The experiments that are set for these tests. The 3rd experiment is not
44 // supported on the current platform, all others are.
45 static Experiment kExperiments
[] = {
50 0, // Ends up being mapped to the current platform.
51 Experiment::SINGLE_VALUE
,
63 0, // Ends up being mapped to the current platform.
64 Experiment::SINGLE_VALUE
,
76 0, // This ends up enabling for an OS other than the current.
77 Experiment::SINGLE_VALUE
,
89 0, // Ends up being mapped to the current platform.
90 Experiment::MULTI_VALUE
,
96 arraysize(kMultiChoices
)
102 0, // Ends up being mapped to the current platform.
103 Experiment::ENABLE_DISABLE_VALUE
,
105 kEnableDisableValue1
,
107 kEnableDisableValue2
,
113 class AboutFlagsTest
: public ::testing::Test
{
115 AboutFlagsTest() : flags_storage_(&prefs_
) {
116 prefs_
.registry()->RegisterListPref(prefs::kEnabledLabsExperiments
);
117 testing::ClearState();
120 virtual void SetUp() OVERRIDE
{
121 for (size_t i
= 0; i
< arraysize(kExperiments
); ++i
)
122 kExperiments
[i
].supported_platforms
= GetCurrentPlatform();
124 int os_other_than_current
= 1;
125 while (os_other_than_current
== GetCurrentPlatform())
126 os_other_than_current
<<= 1;
127 kExperiments
[2].supported_platforms
= os_other_than_current
;
129 testing::SetExperiments(kExperiments
, arraysize(kExperiments
));
132 virtual void TearDown() OVERRIDE
{
133 testing::SetExperiments(NULL
, 0);
136 TestingPrefServiceSimple prefs_
;
137 PrefServiceFlagsStorage flags_storage_
;
141 TEST_F(AboutFlagsTest
, NoChangeNoRestart
) {
142 EXPECT_FALSE(IsRestartNeededToCommitChanges());
143 SetExperimentEnabled(&flags_storage_
, kFlags1
, false);
144 EXPECT_FALSE(IsRestartNeededToCommitChanges());
147 TEST_F(AboutFlagsTest
, ChangeNeedsRestart
) {
148 EXPECT_FALSE(IsRestartNeededToCommitChanges());
149 SetExperimentEnabled(&flags_storage_
, kFlags1
, true);
150 EXPECT_TRUE(IsRestartNeededToCommitChanges());
153 TEST_F(AboutFlagsTest
, MultiFlagChangeNeedsRestart
) {
154 const Experiment
& experiment
= kExperiments
[3];
155 ASSERT_EQ(kFlags4
, experiment
.internal_name
);
156 EXPECT_FALSE(IsRestartNeededToCommitChanges());
157 // Enable the 2nd choice of the multi-value.
158 SetExperimentEnabled(&flags_storage_
, experiment
.NameForChoice(2), true);
159 EXPECT_TRUE(IsRestartNeededToCommitChanges());
160 testing::ClearState();
161 EXPECT_FALSE(IsRestartNeededToCommitChanges());
162 // Enable the default choice now.
163 SetExperimentEnabled(&flags_storage_
, experiment
.NameForChoice(0), true);
164 EXPECT_TRUE(IsRestartNeededToCommitChanges());
167 TEST_F(AboutFlagsTest
, AddTwoFlagsRemoveOne
) {
168 // Add two experiments, check they're there.
169 SetExperimentEnabled(&flags_storage_
, kFlags1
, true);
170 SetExperimentEnabled(&flags_storage_
, kFlags2
, true);
172 const base::ListValue
* experiments_list
= prefs_
.GetList(
173 prefs::kEnabledLabsExperiments
);
174 ASSERT_TRUE(experiments_list
!= NULL
);
176 ASSERT_EQ(2u, experiments_list
->GetSize());
179 ASSERT_TRUE(experiments_list
->GetString(0, &s0
));
181 ASSERT_TRUE(experiments_list
->GetString(1, &s1
));
183 EXPECT_TRUE(s0
== kFlags1
|| s1
== kFlags1
);
184 EXPECT_TRUE(s0
== kFlags2
|| s1
== kFlags2
);
186 // Remove one experiment, check the other's still around.
187 SetExperimentEnabled(&flags_storage_
, kFlags2
, false);
189 experiments_list
= prefs_
.GetList(prefs::kEnabledLabsExperiments
);
190 ASSERT_TRUE(experiments_list
!= NULL
);
191 ASSERT_EQ(1u, experiments_list
->GetSize());
192 ASSERT_TRUE(experiments_list
->GetString(0, &s0
));
193 EXPECT_TRUE(s0
== kFlags1
);
196 TEST_F(AboutFlagsTest
, AddTwoFlagsRemoveBoth
) {
197 // Add two experiments, check the pref exists.
198 SetExperimentEnabled(&flags_storage_
, kFlags1
, true);
199 SetExperimentEnabled(&flags_storage_
, kFlags2
, true);
200 const base::ListValue
* experiments_list
= prefs_
.GetList(
201 prefs::kEnabledLabsExperiments
);
202 ASSERT_TRUE(experiments_list
!= NULL
);
204 // Remove both, the pref should have been removed completely.
205 SetExperimentEnabled(&flags_storage_
, kFlags1
, false);
206 SetExperimentEnabled(&flags_storage_
, kFlags2
, false);
207 experiments_list
= prefs_
.GetList(prefs::kEnabledLabsExperiments
);
208 EXPECT_TRUE(experiments_list
== NULL
|| experiments_list
->GetSize() == 0);
211 TEST_F(AboutFlagsTest
, ConvertFlagsToSwitches
) {
212 SetExperimentEnabled(&flags_storage_
, kFlags1
, true);
214 CommandLine
command_line(CommandLine::NO_PROGRAM
);
215 command_line
.AppendSwitch("foo");
217 EXPECT_TRUE(command_line
.HasSwitch("foo"));
218 EXPECT_FALSE(command_line
.HasSwitch(kSwitch1
));
220 ConvertFlagsToSwitches(&flags_storage_
, &command_line
, kAddSentinels
);
222 EXPECT_TRUE(command_line
.HasSwitch("foo"));
223 EXPECT_TRUE(command_line
.HasSwitch(kSwitch1
));
224 EXPECT_TRUE(command_line
.HasSwitch(switches::kFlagSwitchesBegin
));
225 EXPECT_TRUE(command_line
.HasSwitch(switches::kFlagSwitchesEnd
));
227 CommandLine
command_line2(CommandLine::NO_PROGRAM
);
229 ConvertFlagsToSwitches(&flags_storage_
, &command_line2
, kNoSentinels
);
231 EXPECT_TRUE(command_line2
.HasSwitch(kSwitch1
));
232 EXPECT_FALSE(command_line2
.HasSwitch(switches::kFlagSwitchesBegin
));
233 EXPECT_FALSE(command_line2
.HasSwitch(switches::kFlagSwitchesEnd
));
236 TEST_F(AboutFlagsTest
, CompareSwitchesToCurrentCommandLine
) {
237 SetExperimentEnabled(&flags_storage_
, kFlags1
, true);
239 CommandLine
command_line(CommandLine::NO_PROGRAM
);
240 command_line
.AppendSwitch("foo");
242 CommandLine
new_command_line(CommandLine::NO_PROGRAM
);
243 ConvertFlagsToSwitches(&flags_storage_
, &new_command_line
, kAddSentinels
);
245 EXPECT_FALSE(AreSwitchesIdenticalToCurrentCommandLine(new_command_line
,
248 ConvertFlagsToSwitches(&flags_storage_
, &command_line
, kAddSentinels
);
250 EXPECT_TRUE(AreSwitchesIdenticalToCurrentCommandLine(new_command_line
,
253 // Now both have flags but different.
254 SetExperimentEnabled(&flags_storage_
, kFlags1
, false);
255 SetExperimentEnabled(&flags_storage_
, kFlags2
, true);
257 CommandLine
another_command_line(CommandLine::NO_PROGRAM
);
258 ConvertFlagsToSwitches(&flags_storage_
, &another_command_line
, kAddSentinels
);
260 EXPECT_FALSE(AreSwitchesIdenticalToCurrentCommandLine(new_command_line
,
261 another_command_line
));
264 TEST_F(AboutFlagsTest
, RemoveFlagSwitches
) {
265 std::map
<std::string
, CommandLine::StringType
> switch_list
;
266 switch_list
[kSwitch1
] = CommandLine::StringType();
267 switch_list
[switches::kFlagSwitchesBegin
] = CommandLine::StringType();
268 switch_list
[switches::kFlagSwitchesEnd
] = CommandLine::StringType();
269 switch_list
["foo"] = CommandLine::StringType();
271 SetExperimentEnabled(&flags_storage_
, kFlags1
, true);
273 // This shouldn't do anything before ConvertFlagsToSwitches() wasn't called.
274 RemoveFlagsSwitches(&switch_list
);
275 ASSERT_EQ(4u, switch_list
.size());
276 EXPECT_TRUE(switch_list
.find(kSwitch1
) != switch_list
.end());
277 EXPECT_TRUE(switch_list
.find(switches::kFlagSwitchesBegin
) !=
279 EXPECT_TRUE(switch_list
.find(switches::kFlagSwitchesEnd
) !=
281 EXPECT_TRUE(switch_list
.find("foo") != switch_list
.end());
283 // Call ConvertFlagsToSwitches(), then RemoveFlagsSwitches() again.
284 CommandLine
command_line(CommandLine::NO_PROGRAM
);
285 command_line
.AppendSwitch("foo");
286 ConvertFlagsToSwitches(&flags_storage_
, &command_line
, kAddSentinels
);
287 RemoveFlagsSwitches(&switch_list
);
289 // Now the about:flags-related switch should have been removed.
290 ASSERT_EQ(1u, switch_list
.size());
291 EXPECT_TRUE(switch_list
.find("foo") != switch_list
.end());
294 // Tests enabling experiments that aren't supported on the current platform.
295 TEST_F(AboutFlagsTest
, PersistAndPrune
) {
296 // Enable experiments 1 and 3.
297 SetExperimentEnabled(&flags_storage_
, kFlags1
, true);
298 SetExperimentEnabled(&flags_storage_
, kFlags3
, true);
299 CommandLine
command_line(CommandLine::NO_PROGRAM
);
300 EXPECT_FALSE(command_line
.HasSwitch(kSwitch1
));
301 EXPECT_FALSE(command_line
.HasSwitch(kSwitch3
));
303 // Convert the flags to switches. Experiment 3 shouldn't be among the switches
304 // as it is not applicable to the current platform.
305 ConvertFlagsToSwitches(&flags_storage_
, &command_line
, kAddSentinels
);
306 EXPECT_TRUE(command_line
.HasSwitch(kSwitch1
));
307 EXPECT_FALSE(command_line
.HasSwitch(kSwitch3
));
309 // Experiment 3 should show still be persisted in preferences though.
310 const base::ListValue
* experiments_list
=
311 prefs_
.GetList(prefs::kEnabledLabsExperiments
);
312 ASSERT_TRUE(experiments_list
);
313 EXPECT_EQ(2U, experiments_list
->GetSize());
315 ASSERT_TRUE(experiments_list
->GetString(0, &s0
));
316 EXPECT_EQ(kFlags1
, s0
);
318 ASSERT_TRUE(experiments_list
->GetString(1, &s1
));
319 EXPECT_EQ(kFlags3
, s1
);
322 // Tests that switches which should have values get them in the command
324 TEST_F(AboutFlagsTest
, CheckValues
) {
325 // Enable experiments 1 and 2.
326 SetExperimentEnabled(&flags_storage_
, kFlags1
, true);
327 SetExperimentEnabled(&flags_storage_
, kFlags2
, true);
328 CommandLine
command_line(CommandLine::NO_PROGRAM
);
329 EXPECT_FALSE(command_line
.HasSwitch(kSwitch1
));
330 EXPECT_FALSE(command_line
.HasSwitch(kSwitch2
));
332 // Convert the flags to switches.
333 ConvertFlagsToSwitches(&flags_storage_
, &command_line
, kAddSentinels
);
334 EXPECT_TRUE(command_line
.HasSwitch(kSwitch1
));
335 EXPECT_EQ(std::string(), command_line
.GetSwitchValueASCII(kSwitch1
));
336 EXPECT_TRUE(command_line
.HasSwitch(kSwitch2
));
337 EXPECT_EQ(std::string(kValueForSwitch2
),
338 command_line
.GetSwitchValueASCII(kSwitch2
));
340 // Confirm that there is no '=' in the command line for simple switches.
341 std::string switch1_with_equals
= std::string("--") +
342 std::string(kSwitch1
) +
345 EXPECT_EQ(std::wstring::npos
,
346 command_line
.GetCommandLineString().find(
347 base::ASCIIToWide(switch1_with_equals
)));
349 EXPECT_EQ(std::string::npos
,
350 command_line
.GetCommandLineString().find(switch1_with_equals
));
353 // And confirm there is a '=' for switches with values.
354 std::string switch2_with_equals
= std::string("--") +
355 std::string(kSwitch2
) +
358 EXPECT_NE(std::wstring::npos
,
359 command_line
.GetCommandLineString().find(
360 base::ASCIIToWide(switch2_with_equals
)));
362 EXPECT_NE(std::string::npos
,
363 command_line
.GetCommandLineString().find(switch2_with_equals
));
366 // And it should persist.
367 const base::ListValue
* experiments_list
=
368 prefs_
.GetList(prefs::kEnabledLabsExperiments
);
369 ASSERT_TRUE(experiments_list
);
370 EXPECT_EQ(2U, experiments_list
->GetSize());
372 ASSERT_TRUE(experiments_list
->GetString(0, &s0
));
373 EXPECT_EQ(kFlags1
, s0
);
375 ASSERT_TRUE(experiments_list
->GetString(1, &s1
));
376 EXPECT_EQ(kFlags2
, s1
);
379 // Tests multi-value type experiments.
380 TEST_F(AboutFlagsTest
, MultiValues
) {
381 const Experiment
& experiment
= kExperiments
[3];
382 ASSERT_EQ(kFlags4
, experiment
.internal_name
);
384 // Initially, the first "deactivated" option of the multi experiment should
387 CommandLine
command_line(CommandLine::NO_PROGRAM
);
388 ConvertFlagsToSwitches(&flags_storage_
, &command_line
, kAddSentinels
);
389 EXPECT_FALSE(command_line
.HasSwitch(kMultiSwitch1
));
390 EXPECT_FALSE(command_line
.HasSwitch(kMultiSwitch2
));
393 // Enable the 2nd choice of the multi-value.
394 SetExperimentEnabled(&flags_storage_
, experiment
.NameForChoice(2), true);
396 CommandLine
command_line(CommandLine::NO_PROGRAM
);
397 ConvertFlagsToSwitches(&flags_storage_
, &command_line
, kAddSentinels
);
398 EXPECT_FALSE(command_line
.HasSwitch(kMultiSwitch1
));
399 EXPECT_TRUE(command_line
.HasSwitch(kMultiSwitch2
));
400 EXPECT_EQ(std::string(kValueForMultiSwitch2
),
401 command_line
.GetSwitchValueASCII(kMultiSwitch2
));
404 // Disable the multi-value experiment.
405 SetExperimentEnabled(&flags_storage_
, experiment
.NameForChoice(0), true);
407 CommandLine
command_line(CommandLine::NO_PROGRAM
);
408 ConvertFlagsToSwitches(&flags_storage_
, &command_line
, kAddSentinels
);
409 EXPECT_FALSE(command_line
.HasSwitch(kMultiSwitch1
));
410 EXPECT_FALSE(command_line
.HasSwitch(kMultiSwitch2
));
414 TEST_F(AboutFlagsTest
, EnableDisableValues
) {
415 const Experiment
& experiment
= kExperiments
[4];
416 ASSERT_EQ(kFlags5
, experiment
.internal_name
);
420 CommandLine
command_line(CommandLine::NO_PROGRAM
);
421 ConvertFlagsToSwitches(&flags_storage_
, &command_line
, kAddSentinels
);
422 EXPECT_FALSE(command_line
.HasSwitch(kSwitch1
));
423 EXPECT_FALSE(command_line
.HasSwitch(kSwitch2
));
426 // "Enable" option selected.
427 SetExperimentEnabled(&flags_storage_
, experiment
.NameForChoice(1), true);
429 CommandLine
command_line(CommandLine::NO_PROGRAM
);
430 ConvertFlagsToSwitches(&flags_storage_
, &command_line
, kAddSentinels
);
431 EXPECT_TRUE(command_line
.HasSwitch(kSwitch1
));
432 EXPECT_FALSE(command_line
.HasSwitch(kSwitch2
));
433 EXPECT_EQ(kEnableDisableValue1
, command_line
.GetSwitchValueASCII(kSwitch1
));
436 // "Disable" option selected.
437 SetExperimentEnabled(&flags_storage_
, experiment
.NameForChoice(2), true);
439 CommandLine
command_line(CommandLine::NO_PROGRAM
);
440 ConvertFlagsToSwitches(&flags_storage_
, &command_line
, kAddSentinels
);
441 EXPECT_FALSE(command_line
.HasSwitch(kSwitch1
));
442 EXPECT_TRUE(command_line
.HasSwitch(kSwitch2
));
443 EXPECT_EQ(kEnableDisableValue2
, command_line
.GetSwitchValueASCII(kSwitch2
));
446 // "Default" option selected, same as nothing selected.
447 SetExperimentEnabled(&flags_storage_
, experiment
.NameForChoice(0), true);
449 CommandLine
command_line(CommandLine::NO_PROGRAM
);
450 ConvertFlagsToSwitches(&flags_storage_
, &command_line
, kAddSentinels
);
451 EXPECT_FALSE(command_line
.HasSwitch(kMultiSwitch1
));
452 EXPECT_FALSE(command_line
.HasSwitch(kMultiSwitch2
));
456 // Makes sure there are no separators in any of the experiment names.
457 TEST_F(AboutFlagsTest
, NoSeparators
) {
458 testing::SetExperiments(NULL
, 0);
460 const Experiment
* experiments
= testing::GetExperiments(&count
);
461 for (size_t i
= 0; i
< count
; ++i
) {
462 std::string name
= experiments
->internal_name
;
463 EXPECT_EQ(std::string::npos
, name
.find(testing::kMultiSeparator
)) << i
;
467 } // namespace about_flags