Home | History | Annotate | Download | only in browser
      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