1// Copyright 2013 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/command_line.h"
6#include "base/files/file_path.h"
7#include "base/memory/scoped_ptr.h"
8#include "base/prefs/pref_registry_simple.h"
9#include "base/prefs/pref_service.h"
10#include "base/prefs/pref_service_factory.h"
11#include "base/prefs/testing_pref_store.h"
12#include "chrome/browser/profiles/profile.h"
13#include "chrome/browser/profiles/profiles_state.h"
14#include "chrome/browser/ui/app_list/app_list_service.h"
15#include "chrome/browser/ui/app_list/app_list_service_impl.h"
16#include "chrome/browser/ui/app_list/test/fake_profile.h"
17#include "chrome/browser/ui/app_list/test/fake_profile_store.h"
18#include "chrome/common/chrome_constants.h"
19#include "chrome/common/chrome_switches.h"
20#include "chrome/common/pref_names.h"
21#include "testing/gtest/include/gtest/gtest.h"
22
23class TestingAppListServiceImpl : public AppListServiceImpl {
24 public:
25  TestingAppListServiceImpl(const CommandLine& command_line,
26                            PrefService* local_state,
27                            scoped_ptr<ProfileStore> profile_store)
28      : AppListServiceImpl(command_line, local_state, profile_store.Pass()),
29        showing_for_profile_(NULL),
30        destroy_app_list_call_count_(0) {}
31
32  Profile* showing_for_profile() const {
33    return showing_for_profile_;
34  }
35
36  int destroy_app_list_call_count() const {
37    return destroy_app_list_call_count_;
38  }
39
40  void PerformStartupChecks(Profile* profile) {
41    AppListServiceImpl::PerformStartupChecks(profile);
42  }
43
44  // AppListService overrides:
45  virtual Profile* GetCurrentAppListProfile() OVERRIDE {
46    // We don't return showing_for_profile_ here because that is only defined if
47    // the app list is visible.
48    return NULL;
49  }
50
51  virtual void CreateForProfile(Profile* requested_profile) OVERRIDE {
52  }
53
54  virtual void ShowForProfile(Profile* requested_profile) OVERRIDE {
55    showing_for_profile_ = requested_profile;
56    RecordAppListLaunch();
57  }
58
59  virtual void DismissAppList() OVERRIDE {
60    showing_for_profile_ = NULL;
61  }
62
63  virtual bool IsAppListVisible() const OVERRIDE {
64    return !!showing_for_profile_;
65  }
66
67  virtual gfx::NativeWindow GetAppListWindow() OVERRIDE {
68    return NULL;
69  }
70
71  virtual AppListControllerDelegate* GetControllerDelegate() OVERRIDE {
72    return NULL;
73  }
74
75  // AppListServiceImpl overrides:
76  virtual void DestroyAppList() OVERRIDE { ++destroy_app_list_call_count_; }
77
78 private:
79  Profile* showing_for_profile_;
80  int destroy_app_list_call_count_;
81
82  DISALLOW_COPY_AND_ASSIGN(TestingAppListServiceImpl);
83};
84
85class AppListServiceUnitTest : public testing::Test {
86 public:
87  AppListServiceUnitTest() {}
88
89  virtual void SetUp() OVERRIDE {
90    SetupWithCommandLine(CommandLine(CommandLine::NO_PROGRAM));
91  }
92
93 protected:
94  void SetupWithCommandLine(const CommandLine& command_line) {
95    user_data_dir_ = base::FilePath(FILE_PATH_LITERAL("udd"));
96    profile1_.reset(
97        new FakeProfile("p1", user_data_dir_.AppendASCII("profile1")));
98    profile2_.reset(
99        new FakeProfile("p2", user_data_dir_.AppendASCII("profile2")));
100    PrefRegistrySimple* pref_registry = new PrefRegistrySimple;
101
102    AppListService::RegisterPrefs(pref_registry);
103    profiles::RegisterPrefs(pref_registry);
104
105    base::PrefServiceFactory factory;
106    factory.set_user_prefs(make_scoped_refptr(new TestingPrefStore));
107    local_state_ = factory.Create(pref_registry).Pass();
108
109    profile_store_ = new FakeProfileStore(user_data_dir_);
110    service_.reset(new TestingAppListServiceImpl(
111        command_line,
112        local_state_.get(),
113        scoped_ptr<ProfileStore>(profile_store_)));
114  }
115
116  void EnableAppList() {
117    service_->EnableAppList(profile1_.get(),
118                            AppListService::ENABLE_VIA_COMMAND_LINE);
119  }
120
121  base::FilePath user_data_dir_;
122  scoped_ptr<PrefService> local_state_;
123  FakeProfileStore* profile_store_;
124  scoped_ptr<TestingAppListServiceImpl> service_;
125  scoped_ptr<FakeProfile> profile1_;
126  scoped_ptr<FakeProfile> profile2_;
127
128  DISALLOW_COPY_AND_ASSIGN(AppListServiceUnitTest);
129};
130
131TEST_F(AppListServiceUnitTest, EnablingStateIsPersisted) {
132  EXPECT_FALSE(local_state_->GetBoolean(prefs::kAppLauncherHasBeenEnabled));
133  EnableAppList();
134  EXPECT_TRUE(local_state_->GetBoolean(prefs::kAppLauncherHasBeenEnabled));
135  EXPECT_EQ(profile1_->GetPath(), user_data_dir_.Append(
136      local_state_->GetFilePath(prefs::kAppListProfile)));
137}
138
139TEST_F(AppListServiceUnitTest, ShowingForProfileLoadsAProfile) {
140  profile_store_->LoadProfile(profile1_.get());
141  EnableAppList();
142  service_->Show();
143  EXPECT_EQ(profile1_.get(), service_->showing_for_profile());
144  EXPECT_TRUE(service_->IsAppListVisible());
145}
146
147TEST_F(AppListServiceUnitTest, RemovedProfileResetsToInitialProfile) {
148  EnableAppList();
149  profile_store_->RemoveProfile(profile1_.get());
150  base::FilePath initial_profile_path =
151      user_data_dir_.AppendASCII(chrome::kInitialProfile);
152  EXPECT_EQ(initial_profile_path,
153            service_->GetProfilePath(profile_store_->GetUserDataDir()));
154}
155
156TEST_F(AppListServiceUnitTest,
157       RemovedProfileResetsToLastUsedProfileIfExists) {
158  local_state_->SetString(prefs::kProfileLastUsed, "last-used");
159  EnableAppList();
160  profile_store_->RemoveProfile(profile1_.get());
161
162  base::FilePath last_used_profile_path =
163      user_data_dir_.AppendASCII("last-used");
164  EXPECT_EQ(last_used_profile_path,
165            service_->GetProfilePath(profile_store_->GetUserDataDir()));
166
167  // For this test, the AppListViewDelegate is not created because the
168  // app list is never shown, so there is nothing to destroy.
169  EXPECT_EQ(0, service_->destroy_app_list_call_count());
170}
171
172TEST_F(AppListServiceUnitTest, SwitchingProfilesPersists) {
173  profile_store_->LoadProfile(profile1_.get());
174  profile_store_->LoadProfile(profile2_.get());
175  EnableAppList();
176  service_->SetProfilePath(profile2_->GetPath());
177  service_->Show();
178  EXPECT_EQ(profile2_.get(), service_->showing_for_profile());
179  EXPECT_EQ(profile2_->GetPath(),
180            service_->GetProfilePath(profile_store_->GetUserDataDir()));
181  service_->SetProfilePath(profile1_->GetPath());
182  EXPECT_EQ(profile1_->GetPath(),
183            service_->GetProfilePath(profile_store_->GetUserDataDir()));
184}
185
186TEST_F(AppListServiceUnitTest, EnableViaCommandLineFlag) {
187  CommandLine command_line(CommandLine::NO_PROGRAM);
188  command_line.AppendSwitch(switches::kEnableAppList);
189  SetupWithCommandLine(command_line);
190  service_->PerformStartupChecks(profile1_.get());
191  EXPECT_TRUE(local_state_->GetBoolean(prefs::kAppLauncherHasBeenEnabled));
192}
193
194TEST_F(AppListServiceUnitTest, DisableViaCommandLineFlag) {
195  CommandLine command_line(CommandLine::NO_PROGRAM);
196  command_line.AppendSwitch(switches::kResetAppListInstallState);
197  SetupWithCommandLine(command_line);
198  service_->PerformStartupChecks(profile1_.get());
199  EXPECT_FALSE(local_state_->GetBoolean(prefs::kAppLauncherHasBeenEnabled));
200}
201
202TEST_F(AppListServiceUnitTest, UMAPrefStates) {
203  EXPECT_FALSE(local_state_->GetBoolean(prefs::kAppLauncherHasBeenEnabled));
204  EXPECT_EQ(AppListService::ENABLE_NOT_RECORDED,
205            local_state_->GetInteger(prefs::kAppListEnableMethod));
206  EXPECT_EQ(0, local_state_->GetInt64(prefs::kAppListEnableTime));
207
208  service_->EnableAppList(profile1_.get(),
209                          AppListService::ENABLE_FOR_APP_INSTALL);
210
211  // After enable, method and time should be recorded.
212  EXPECT_TRUE(local_state_->GetBoolean(prefs::kAppLauncherHasBeenEnabled));
213  EXPECT_EQ(AppListService::ENABLE_FOR_APP_INSTALL,
214            local_state_->GetInteger(prefs::kAppListEnableMethod));
215  EXPECT_NE(0, local_state_->GetInt64(prefs::kAppListEnableTime));
216
217  service_->ShowForProfile(profile1_.get());
218
219  // After a regular "show", time should be cleared, so UMA is not re-recorded.
220  EXPECT_EQ(AppListService::ENABLE_FOR_APP_INSTALL,
221            local_state_->GetInteger(prefs::kAppListEnableMethod));
222  EXPECT_EQ(0, local_state_->GetInt64(prefs::kAppListEnableTime));
223
224  // A second enable should be a no-op.
225  service_->EnableAppList(profile1_.get(),
226                          AppListService::ENABLE_FOR_APP_INSTALL);
227  EXPECT_EQ(AppListService::ENABLE_FOR_APP_INSTALL,
228            local_state_->GetInteger(prefs::kAppListEnableMethod));
229  EXPECT_EQ(0, local_state_->GetInt64(prefs::kAppListEnableTime));
230
231  // An auto-show here should keep the recorded enable method.
232  service_->AutoShowForProfile(profile1_.get());
233  EXPECT_EQ(AppListService::ENABLE_FOR_APP_INSTALL,
234            local_state_->GetInteger(prefs::kAppListEnableMethod));
235
236  // Clear the enable state, so we can enable again.
237  local_state_->SetBoolean(prefs::kAppLauncherHasBeenEnabled, false);
238  service_->EnableAppList(profile1_.get(),
239                          AppListService::ENABLE_FOR_APP_INSTALL);
240
241  EXPECT_EQ(AppListService::ENABLE_FOR_APP_INSTALL,
242            local_state_->GetInteger(prefs::kAppListEnableMethod));
243  EXPECT_NE(0, local_state_->GetInt64(prefs::kAppListEnableTime));
244
245  // An auto-show here should update the enable method to prevent recording it
246  // as ENABLE_FOR_APP_INSTALL.
247  service_->AutoShowForProfile(profile1_.get());
248  EXPECT_EQ(AppListService::ENABLE_SHOWN_UNDISCOVERED,
249            local_state_->GetInteger(prefs::kAppListEnableMethod));
250}
251