OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2015 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 <algorithm> | |
6 #include <map> | |
7 #include <string> | |
8 #include <vector> | |
9 | |
10 #include "base/files/file_path.h" | |
11 #include "base/files/file_util.h" | |
12 #include "base/task_runner_util.h" | |
13 #include "chrome/browser/ui/app_list/app_list_test_util.h" | |
14 #include "chrome/browser/ui/app_list/arc_app_item.h" | |
15 #include "chrome/browser/ui/app_list/arc_app_list_prefs.h" | |
16 #include "chrome/browser/ui/app_list/arc_app_model_builder.h" | |
17 #include "chrome/browser/ui/app_list/test/fake_arc_bridge_service_for_app_launch er.h" | |
18 #include "chrome/browser/ui/app_list/test/test_app_list_controller_delegate.h" | |
19 #include "chrome/test/base/testing_profile.h" | |
20 #include "components/arc/arc_bridge_service.h" | |
21 #include "content/public/browser/browser_thread.h" | |
22 #include "testing/gtest/include/gtest/gtest.h" | |
23 #include "ui/app_list/app_list_model.h" | |
24 #include "ui/gfx/image/image_skia.h" | |
25 | |
26 namespace { | |
27 | |
28 const struct FakeArcBridgeServiceForAppLauncher::AppInfo kFakeApps[] = { | |
29 {"Arc app 1", "fake.app.1", "fake.app.1.Activity"}, | |
30 {"Arc app 2", "fake.app.2", "fake.app.2.Activity"}, | |
31 {"Arc app 3", "fake.app.3", "fake.app.3.Activity"}, | |
32 }; | |
33 | |
34 const size_t kFakeAppCnt = sizeof(kFakeApps) / | |
35 sizeof(FakeArcBridgeServiceForAppLauncher::AppInfo); | |
xiyuan
2015/11/18 03:42:16
nit: use arraysize in base/macros.h
https://code.
khmel1
2015/11/18 06:10:04
Good to know, thanks!
| |
36 | |
37 } // namespace | |
38 | |
39 class ArcAppModelBuilderTest : public AppListTestBase { | |
40 public: | |
41 ArcAppModelBuilderTest() {} | |
42 ~ArcAppModelBuilderTest() override { | |
43 // Release profile file in order to keep right sequence. | |
44 profile_.reset(); | |
45 } | |
46 | |
47 void SetUp() override { | |
48 AppListTestBase::SetUp(); | |
49 | |
50 // Make sure we have enough data for test. | |
51 static_assert(kFakeAppCnt >= 2, "Not enough data for test"); | |
52 | |
53 bridge_service_.reset(new FakeArcBridgeServiceForAppLauncher()); | |
54 | |
55 // Check initial conditions. | |
56 EXPECT_EQ(bridge_service_.get(), arc::ArcBridgeService::Get()); | |
57 EXPECT_EQ(false, arc::ArcBridgeService::Get()->available()); | |
58 EXPECT_EQ(arc::ArcBridgeService::State::STOPPED, | |
59 arc::ArcBridgeService::Get()->state()); | |
60 | |
61 CreateBuilder(); | |
62 | |
63 // At this point we should have ArcAppListPrefs as observer of service. | |
64 EXPECT_EQ( | |
65 true, | |
66 bridge_service_->HasObserver(ArcAppListPrefs::Get(profile_.get()))); | |
67 } | |
68 | |
69 void TearDown() override { ResetBuilder(); } | |
70 | |
71 protected: | |
72 // Creates a new builder, destroying any existing one. | |
73 void CreateBuilder() { | |
74 ResetBuilder(); // Destroy any existing builder in the correct order. | |
75 | |
76 model_.reset(new app_list::AppListModel); | |
77 controller_.reset(new test::TestAppListControllerDelegate); | |
78 builder_.reset(new ArcAppModelBuilder(controller_.get())); | |
79 builder_->InitializeWithProfile(profile_.get(), model_.get()); | |
80 } | |
81 | |
82 void ResetBuilder() { | |
83 builder_.reset(); | |
84 controller_.reset(); | |
85 model_.reset(); | |
86 } | |
87 | |
88 size_t GetModelItemCnt() const { | |
xiyuan
2015/11/18 03:42:16
nit: GetModelItemCnt -> GetArcItemCount to be more
khmel1
2015/11/18 06:10:04
Done.
| |
89 size_t arc_cnt = 0; | |
90 const size_t cnt = model_->top_level_item_list()->item_count(); | |
91 for (size_t i = 0; i < cnt; ++i) { | |
92 app_list::AppListItem* item = model_->top_level_item_list()->item_at(i); | |
93 if (item->GetItemType() == ArcAppItem::kItemType) { | |
94 ++arc_cnt; | |
95 } | |
96 } | |
97 return arc_cnt; | |
98 } | |
99 | |
100 ArcAppItem* GetModelItem(size_t index) const { | |
xiyuan
2015/11/18 03:42:16
nit: GetModelItem -> GetArcItem
khmel1
2015/11/18 06:10:04
Done.
| |
101 size_t arc_cnt = 0; | |
102 const size_t cnt = model_->top_level_item_list()->item_count(); | |
103 ArcAppItem* arc_item = nullptr; | |
104 for (size_t i = 0; i < cnt; ++i) { | |
105 app_list::AppListItem* item = model_->top_level_item_list()->item_at(i); | |
106 if (item->GetItemType() == ArcAppItem::kItemType) { | |
107 if (arc_cnt++ == index) { | |
108 arc_item = reinterpret_cast<ArcAppItem*>(item); | |
109 break; | |
110 } | |
111 } | |
112 } | |
113 EXPECT_NE(nullptr, arc_item); | |
114 return arc_item; | |
115 } | |
116 | |
117 ArcAppItem* FindModelItem(const std::string& id) const { | |
xiyuan
2015/11/18 03:42:16
nit: FindModelItem -> FindArcItem
khmel1
2015/11/18 06:10:04
Done.
| |
118 const size_t cnt = GetModelItemCnt(); | |
119 for (size_t i = 0; i < cnt; ++i) { | |
120 ArcAppItem* item = GetModelItem(i); | |
121 if (item && item->id() == id) { | |
122 return item; | |
123 } | |
124 } | |
125 return nullptr; | |
126 } | |
127 | |
128 // Validate that prefs and model have right content. | |
129 void ValidateHaveApps( | |
130 size_t app_cnt, | |
131 const FakeArcBridgeServiceForAppLauncher::AppInfo* apps) { | |
132 ArcAppListPrefs* prefs = ArcAppListPrefs::Get(profile_.get()); | |
133 const std::vector<std::string> ids = prefs->GetAppIds(); | |
134 ASSERT_EQ(app_cnt, ids.size()); | |
135 ASSERT_EQ(app_cnt, GetModelItemCnt()); | |
136 // In principle, order of items is not defined. | |
137 for (size_t i = 0; i < app_cnt; ++i) { | |
138 const std::string id = apps[i].id(); | |
139 EXPECT_NE(std::find(ids.begin(), ids.end(), id), ids.end()); | |
140 scoped_ptr<ArcAppListPrefs::AppInfo> app_info = prefs->GetApp(ids[i]); | |
141 ASSERT_NE(nullptr, app_info.get()); | |
142 EXPECT_EQ(apps[i].name, app_info->name); | |
143 EXPECT_EQ(apps[i].package, app_info->package); | |
144 EXPECT_EQ(apps[i].activity, app_info->activity); | |
145 | |
146 const ArcAppItem* app_item = FindModelItem(ids[i]); | |
147 ASSERT_NE(nullptr, app_item); | |
148 EXPECT_EQ(apps[i].name, app_item->GetDisplayName()); | |
149 } | |
150 } | |
151 | |
152 // Validate that requested apps have required ready state and other apps have | |
153 // opposite state. | |
154 void ValidateAppReadyState( | |
155 size_t app_cnt, | |
156 const FakeArcBridgeServiceForAppLauncher::AppInfo* apps, | |
157 bool ready) { | |
158 ArcAppListPrefs* prefs = ArcAppListPrefs::Get(profile_.get()); | |
159 ASSERT_NE(nullptr, prefs); | |
160 | |
161 std::vector<std::string> ids = prefs->GetAppIds(); | |
162 EXPECT_EQ(ids.size(), GetModelItemCnt()); | |
163 | |
164 // Process requested apps. | |
165 for (size_t i = 0; i < app_cnt; ++i) { | |
166 const std::string id = apps[i].id(); | |
167 std::vector<std::string>::iterator it_id = std::find(ids.begin(), | |
168 ids.end(), | |
169 id); | |
170 ASSERT_NE(it_id, ids.end()); | |
171 ids.erase(it_id); | |
172 | |
173 scoped_ptr<ArcAppListPrefs::AppInfo> app_info = prefs->GetApp(id); | |
174 ASSERT_NE(nullptr, app_info.get()); | |
175 EXPECT_EQ(ready, app_info->ready); | |
176 const ArcAppItem* app_item = FindModelItem(id); | |
177 ASSERT_NE(nullptr, app_item); | |
178 EXPECT_EQ(ready, app_item->ready()); | |
179 } | |
180 | |
181 // Process the rest apps. | |
182 for (size_t i = 0; i < ids.size(); ++i) { | |
183 const std::string id = ids[i]; | |
184 scoped_ptr<ArcAppListPrefs::AppInfo> app_info = prefs->GetApp(id); | |
185 ASSERT_NE(nullptr, app_info.get()); | |
186 EXPECT_NE(ready, app_info->ready); | |
187 const ArcAppItem* app_item = FindModelItem(id); | |
188 ASSERT_NE(nullptr, app_item); | |
189 EXPECT_NE(ready, app_item->ready()); | |
190 } | |
191 } | |
192 | |
193 scoped_ptr<app_list::AppListModel> model_; | |
194 scoped_ptr<test::TestAppListControllerDelegate> controller_; | |
195 scoped_ptr<ArcAppModelBuilder> builder_; | |
196 scoped_ptr<FakeArcBridgeServiceForAppLauncher> bridge_service_; | |
197 | |
198 private: | |
199 DISALLOW_COPY_AND_ASSIGN(ArcAppModelBuilderTest); | |
200 }; | |
201 | |
202 TEST_F(ArcAppModelBuilderTest, RefreshAllOnReady) { | |
203 EXPECT_EQ(0, bridge_service_->refresh_apps_cnt()); | |
204 bridge_service_->SetReady(); | |
205 EXPECT_EQ(1, bridge_service_->refresh_apps_cnt()); | |
206 } | |
207 | |
208 TEST_F(ArcAppModelBuilderTest, RefreshAllFillsContent) { | |
209 ValidateHaveApps(0, nullptr); | |
210 bridge_service_->SetReady(); | |
211 bridge_service_->SendRefreshApps(kFakeAppCnt, kFakeApps); | |
212 ValidateHaveApps(kFakeAppCnt, kFakeApps); | |
213 } | |
214 | |
215 TEST_F(ArcAppModelBuilderTest, MultipleRefreshAll) { | |
216 ValidateHaveApps(0, nullptr); | |
217 bridge_service_->SetReady(); | |
218 // Send info about all fake apps except last. | |
219 bridge_service_->SendRefreshApps(kFakeAppCnt - 1, kFakeApps); | |
220 // At this point all apps (except last) should exist and be ready. | |
221 ValidateHaveApps(kFakeAppCnt - 1, kFakeApps); | |
222 ValidateAppReadyState(kFakeAppCnt - 1, kFakeApps, true); | |
223 | |
224 // Send info about all fake apps except first. | |
225 bridge_service_->SendRefreshApps(kFakeAppCnt - 1, kFakeApps + 1); | |
226 // At this point all apps should exist but first one should be non-ready. | |
227 ValidateHaveApps(kFakeAppCnt, kFakeApps); | |
228 ValidateAppReadyState(kFakeAppCnt - 1, kFakeApps + 1, true); | |
229 | |
230 // Send info about all fake apps. | |
231 bridge_service_->SendRefreshApps(kFakeAppCnt, kFakeApps); | |
232 // At this point all apps should exist and be ready. | |
233 ValidateHaveApps(kFakeAppCnt, kFakeApps); | |
234 ValidateAppReadyState(kFakeAppCnt, kFakeApps, true); | |
235 | |
236 // Send info no app available. | |
237 bridge_service_->SendRefreshApps(0, nullptr); | |
238 // At this point all apps should exist and be non-ready. | |
239 ValidateHaveApps(kFakeAppCnt, kFakeApps); | |
240 ValidateAppReadyState(kFakeAppCnt, kFakeApps, false); | |
241 } | |
242 | |
243 TEST_F(ArcAppModelBuilderTest, StopServiceDisablesApps) { | |
244 ArcAppListPrefs* prefs = ArcAppListPrefs::Get(profile_.get()); | |
245 ASSERT_NE(nullptr, prefs); | |
246 | |
247 bridge_service_->SetReady(); | |
248 EXPECT_EQ(static_cast<size_t>(0), GetModelItemCnt()); | |
249 EXPECT_EQ(static_cast<size_t>(0), prefs->GetAppIds().size()); | |
250 | |
251 bridge_service_->SendRefreshApps(kFakeAppCnt, kFakeApps); | |
252 std::vector<std::string> ids = prefs->GetAppIds(); | |
253 EXPECT_EQ(kFakeAppCnt, ids.size()); | |
254 ValidateAppReadyState(kFakeAppCnt, kFakeApps, true); | |
255 | |
256 // Stopping service does not delete items. It makes them non-ready. | |
257 bridge_service_->SetStopped(); | |
258 // Ids should be the same. | |
259 EXPECT_EQ(ids, prefs->GetAppIds()); | |
260 ValidateAppReadyState(kFakeAppCnt, kFakeApps, false); | |
261 } | |
262 | |
263 TEST_F(ArcAppModelBuilderTest, LaunchApps) { | |
264 bridge_service_->SetReady(); | |
265 bridge_service_->SendRefreshApps(kFakeAppCnt, kFakeApps); | |
266 | |
267 // Simulate item activate. | |
268 ArcAppItem* item_first = FindModelItem(kFakeApps[0].id()); | |
269 ArcAppItem* item_last = FindModelItem(kFakeApps[kFakeAppCnt - 1].id()); | |
270 ASSERT_NE(nullptr, item_first); | |
271 ASSERT_NE(nullptr, item_last); | |
272 item_first->Activate(0); | |
273 item_last->Activate(0); | |
274 item_first->Activate(0); | |
275 | |
276 const std::vector<std::string> launch_requests = | |
277 bridge_service_->launch_requests(); | |
278 EXPECT_EQ(static_cast<size_t>(3), launch_requests.size()); | |
279 EXPECT_EQ(kFakeApps[0].id(), launch_requests[0]); | |
280 EXPECT_EQ(kFakeApps[kFakeAppCnt - 1].id(), launch_requests[1]); | |
281 EXPECT_EQ(kFakeApps[0].id(), launch_requests[2]); | |
282 } | |
283 | |
284 TEST_F(ArcAppModelBuilderTest, RequestIcons) { | |
285 base::MessageLoop* current = base::MessageLoop::current(); | |
xiyuan
2015/11/18 03:42:16
New code should use base::RunLoop instead of using
khmel1
2015/11/18 06:10:04
Done.
| |
286 // Make sure we are on UI thread. | |
287 ASSERT_EQ(true, | |
288 content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
289 | |
290 bridge_service_->SetReady(); | |
291 bridge_service_->SendRefreshApps(kFakeAppCnt, kFakeApps); | |
292 | |
293 // Validate that no icon exists at the beginning and request icon for | |
294 // each supported scale factor. This will start asynchronous loading. | |
295 uint32_t expected_mask = 0; | |
296 const std::vector<ui::ScaleFactor>& scale_factors = | |
297 ui::GetSupportedScaleFactors(); | |
298 for (size_t i = 0; i < scale_factors.size(); ++i) { | |
299 const ui::ScaleFactor scale_factor = scale_factors[i]; | |
300 expected_mask |= 1 << scale_factor; | |
301 for (size_t j = 0; j < kFakeAppCnt; ++j) { | |
302 ArcAppItem* app_item = FindModelItem(kFakeApps[j].id()); | |
303 ASSERT_NE(nullptr, app_item); | |
304 const float scale = ui::GetScaleForScaleFactor(scale_factor); | |
305 app_item->icon().GetRepresentation(scale); | |
306 } | |
307 } | |
308 | |
309 // Process pending tasks. | |
310 content::BrowserThread::GetBlockingPool()->FlushForTesting(); | |
311 current->RunUntilIdle(); | |
312 | |
313 // At this moment we should receive all requests for icon loading. | |
314 const std::vector<FakeArcBridgeServiceForAppLauncher::IconRequest>& | |
315 icon_requests = bridge_service_->icon_requests(); | |
316 EXPECT_EQ(scale_factors.size() * kFakeAppCnt, icon_requests.size()); | |
317 std::map<std::string, uint32_t> app_masks; | |
318 for (size_t i = 0; i < icon_requests.size(); ++i) { | |
319 const FakeArcBridgeServiceForAppLauncher::IconRequest icon_request = | |
320 icon_requests[i]; | |
321 const std::string id = ArcAppListPrefs::GetAppId(icon_request.package, | |
322 icon_request.activity); | |
323 // Make sure no double requests. | |
324 EXPECT_NE(app_masks[id], app_masks[id] | (1 << icon_request.scale_factor)); | |
325 app_masks[id] |= (1 << icon_request.scale_factor); | |
326 } | |
327 | |
328 // Validate that we have a request for each icon for each supported scale | |
329 // factor. | |
330 EXPECT_EQ(kFakeAppCnt, app_masks.size()); | |
331 for (size_t i = 0; i < kFakeAppCnt; ++i) { | |
332 const std::string id = kFakeApps[i].id(); | |
333 ASSERT_NE(app_masks.find(id), app_masks.end()); | |
334 EXPECT_EQ(app_masks[id], expected_mask); | |
335 } | |
336 } | |
337 | |
338 TEST_F(ArcAppModelBuilderTest, InstallIcon) { | |
339 base::MessageLoop* current = base::MessageLoop::current(); | |
340 // Make sure we are on UI thread. | |
341 ASSERT_EQ(true, | |
342 content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
343 | |
344 bridge_service_->SetReady(); | |
345 bridge_service_->SendRefreshApps(1, kFakeApps); | |
346 | |
347 ArcAppListPrefs* prefs = ArcAppListPrefs::Get(profile_.get()); | |
348 ASSERT_NE(nullptr, prefs); | |
349 | |
350 const ui::ScaleFactor scale_factor = ui::GetSupportedScaleFactors()[0]; | |
351 const float scale = ui::GetScaleForScaleFactor(scale_factor); | |
352 const base::FilePath icon_path = prefs->GetIconPath(kFakeApps[0].id(), | |
353 scale_factor); | |
354 EXPECT_EQ(false, base::PathExists(icon_path)); | |
355 | |
356 const ArcAppItem* app_item = FindModelItem(kFakeApps[0].id()); | |
357 EXPECT_NE(nullptr, app_item); | |
358 // This initiates async loading. | |
359 app_item->icon().GetRepresentation(scale); | |
360 | |
361 // Process pending tasks. | |
362 content::BrowserThread::GetBlockingPool()->FlushForTesting(); | |
363 current->RunUntilIdle(); | |
364 | |
365 // Now send generated icon for the app. | |
366 std::vector<unsigned char> png_data; | |
367 EXPECT_EQ(true, bridge_service_->GenerateAndSendIcon(kFakeApps[0], | |
368 scale_factor, | |
369 &png_data)); | |
370 | |
371 // Process pending tasks. | |
372 content::BrowserThread::GetBlockingPool()->FlushForTesting(); | |
373 current->RunUntilIdle(); | |
374 | |
375 // Validate that icons are installed, have right content and icon is | |
376 // refreshed for ARC app item. | |
377 EXPECT_EQ(true, base::PathExists(icon_path)); | |
378 | |
379 std::string icon_data; | |
380 // Read the file from disk and compare with reference data. | |
381 EXPECT_EQ(true, base::ReadFileToString(icon_path, &icon_data)); | |
382 ASSERT_EQ(icon_data.size(), png_data.size()); | |
383 EXPECT_EQ(0, memcmp(&icon_data[0], &png_data[0], png_data.size())); | |
384 | |
385 // Validating decoded content does not fit well for unit tests. Each image is | |
386 // decoded in separate process and under such condition this unit test takes | |
387 // noticeable time to complete. | |
388 } | |
OLD | NEW |