about_flags_unittest.cc revision 868fa2fe829687343ffae624259930155e16dbd8
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/strings/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 const ListValue* experiments_list = 271 prefs_.GetList(prefs::kEnabledLabsExperiments); 272 ASSERT_TRUE(experiments_list); 273 EXPECT_EQ(2U, experiments_list->GetSize()); 274 std::string s0; 275 ASSERT_TRUE(experiments_list->GetString(0, &s0)); 276 EXPECT_EQ(kFlags1, s0); 277 std::string s1; 278 ASSERT_TRUE(experiments_list->GetString(1, &s1)); 279 EXPECT_EQ(kFlags3, s1); 280} 281 282// Tests that switches which should have values get them in the command 283// line. 284TEST_F(AboutFlagsTest, CheckValues) { 285 // Enable experiments 1 and 2. 286 SetExperimentEnabled(&prefs_, kFlags1, true); 287 SetExperimentEnabled(&prefs_, kFlags2, true); 288 CommandLine command_line(CommandLine::NO_PROGRAM); 289 EXPECT_FALSE(command_line.HasSwitch(kSwitch1)); 290 EXPECT_FALSE(command_line.HasSwitch(kSwitch2)); 291 292 // Convert the flags to switches. 293 ConvertFlagsToSwitches(&prefs_, &command_line); 294 EXPECT_TRUE(command_line.HasSwitch(kSwitch1)); 295 EXPECT_EQ(std::string(), command_line.GetSwitchValueASCII(kSwitch1)); 296 EXPECT_TRUE(command_line.HasSwitch(kSwitch2)); 297 EXPECT_EQ(std::string(kValueForSwitch2), 298 command_line.GetSwitchValueASCII(kSwitch2)); 299 300 // Confirm that there is no '=' in the command line for simple switches. 301 std::string switch1_with_equals = std::string("--") + 302 std::string(kSwitch1) + 303 std::string("="); 304#if defined(OS_WIN) 305 EXPECT_EQ(std::wstring::npos, 306 command_line.GetCommandLineString().find( 307 ASCIIToWide(switch1_with_equals))); 308#else 309 EXPECT_EQ(std::string::npos, 310 command_line.GetCommandLineString().find(switch1_with_equals)); 311#endif 312 313 // And confirm there is a '=' for switches with values. 314 std::string switch2_with_equals = std::string("--") + 315 std::string(kSwitch2) + 316 std::string("="); 317#if defined(OS_WIN) 318 EXPECT_NE(std::wstring::npos, 319 command_line.GetCommandLineString().find( 320 ASCIIToWide(switch2_with_equals))); 321#else 322 EXPECT_NE(std::string::npos, 323 command_line.GetCommandLineString().find(switch2_with_equals)); 324#endif 325 326 // And it should persist. 327 const ListValue* experiments_list = 328 prefs_.GetList(prefs::kEnabledLabsExperiments); 329 ASSERT_TRUE(experiments_list); 330 EXPECT_EQ(2U, experiments_list->GetSize()); 331 std::string s0; 332 ASSERT_TRUE(experiments_list->GetString(0, &s0)); 333 EXPECT_EQ(kFlags1, s0); 334 std::string s1; 335 ASSERT_TRUE(experiments_list->GetString(1, &s1)); 336 EXPECT_EQ(kFlags2, s1); 337} 338 339// Tests multi-value type experiments. 340TEST_F(AboutFlagsTest, MultiValues) { 341 const Experiment& experiment = kExperiments[3]; 342 ASSERT_EQ(kFlags4, experiment.internal_name); 343 344 // Initially, the first "deactivated" option of the multi experiment should 345 // be set. 346 { 347 CommandLine command_line(CommandLine::NO_PROGRAM); 348 ConvertFlagsToSwitches(&prefs_, &command_line); 349 EXPECT_FALSE(command_line.HasSwitch(kMultiSwitch1)); 350 EXPECT_FALSE(command_line.HasSwitch(kMultiSwitch2)); 351 } 352 353 // Enable the 2nd choice of the multi-value. 354 SetExperimentEnabled(&prefs_, experiment.NameForChoice(2), true); 355 { 356 CommandLine command_line(CommandLine::NO_PROGRAM); 357 ConvertFlagsToSwitches(&prefs_, &command_line); 358 EXPECT_FALSE(command_line.HasSwitch(kMultiSwitch1)); 359 EXPECT_TRUE(command_line.HasSwitch(kMultiSwitch2)); 360 EXPECT_EQ(std::string(kValueForMultiSwitch2), 361 command_line.GetSwitchValueASCII(kMultiSwitch2)); 362 } 363 364 // Disable the multi-value experiment. 365 SetExperimentEnabled(&prefs_, experiment.NameForChoice(0), true); 366 { 367 CommandLine command_line(CommandLine::NO_PROGRAM); 368 ConvertFlagsToSwitches(&prefs_, &command_line); 369 EXPECT_FALSE(command_line.HasSwitch(kMultiSwitch1)); 370 EXPECT_FALSE(command_line.HasSwitch(kMultiSwitch2)); 371 } 372} 373 374TEST_F(AboutFlagsTest, EnableDisableValues) { 375 const Experiment& experiment = kExperiments[4]; 376 ASSERT_EQ(kFlags5, experiment.internal_name); 377 378 // Nothing selected. 379 { 380 CommandLine command_line(CommandLine::NO_PROGRAM); 381 ConvertFlagsToSwitches(&prefs_, &command_line); 382 EXPECT_FALSE(command_line.HasSwitch(kSwitch1)); 383 EXPECT_FALSE(command_line.HasSwitch(kSwitch2)); 384 } 385 386 // "Enable" option selected. 387 SetExperimentEnabled(&prefs_, experiment.NameForChoice(1), true); 388 { 389 CommandLine command_line(CommandLine::NO_PROGRAM); 390 ConvertFlagsToSwitches(&prefs_, &command_line); 391 EXPECT_TRUE(command_line.HasSwitch(kSwitch1)); 392 EXPECT_FALSE(command_line.HasSwitch(kSwitch2)); 393 EXPECT_EQ(kEnableDisableValue1, command_line.GetSwitchValueASCII(kSwitch1)); 394 } 395 396 // "Disable" option selected. 397 SetExperimentEnabled(&prefs_, experiment.NameForChoice(2), true); 398 { 399 CommandLine command_line(CommandLine::NO_PROGRAM); 400 ConvertFlagsToSwitches(&prefs_, &command_line); 401 EXPECT_FALSE(command_line.HasSwitch(kSwitch1)); 402 EXPECT_TRUE(command_line.HasSwitch(kSwitch2)); 403 EXPECT_EQ(kEnableDisableValue2, command_line.GetSwitchValueASCII(kSwitch2)); 404 } 405 406 // "Default" option selected, same as nothing selected. 407 SetExperimentEnabled(&prefs_, experiment.NameForChoice(0), true); 408 { 409 CommandLine command_line(CommandLine::NO_PROGRAM); 410 ConvertFlagsToSwitches(&prefs_, &command_line); 411 EXPECT_FALSE(command_line.HasSwitch(kMultiSwitch1)); 412 EXPECT_FALSE(command_line.HasSwitch(kMultiSwitch2)); 413 } 414} 415 416// Makes sure there are no separators in any of the experiment names. 417TEST_F(AboutFlagsTest, NoSeparators) { 418 testing::SetExperiments(NULL, 0); 419 size_t count; 420 const Experiment* experiments = testing::GetExperiments(&count); 421 for (size_t i = 0; i < count; ++i) { 422 std::string name = experiments->internal_name; 423 EXPECT_EQ(std::string::npos, name.find(testing::kMultiSeparator)) << i; 424 } 425} 426 427} // namespace about_flags 428