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