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: 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 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 110 virtual void TearDown() { 111 testing::SetExperiments(NULL, 0); 112 } 113 114 TestingPrefService prefs_; 115 }; 116 117 TEST_F(AboutFlagsTest, ChangeNeedsRestart) { 118 EXPECT_FALSE(IsRestartNeededToCommitChanges()); 119 SetExperimentEnabled(&prefs_, kFlags1, true); 120 EXPECT_TRUE(IsRestartNeededToCommitChanges()); 121 } 122 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 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 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 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. 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. 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. 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. 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