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.
5 #include "ash/shelf/shelf_model.h"
10 #include "ash/ash_switches.h"
11 #include "ash/shelf/shelf_model_observer.h"
12 #include "base/command_line.h"
13 #include "base/strings/stringprintf.h"
14 #include "testing/gtest/include/gtest/gtest.h"
20 // ShelfModelObserver implementation that tracks what message are invoked.
21 class TestShelfModelObserver
: public ShelfModelObserver
{
23 TestShelfModelObserver()
30 // Returns a string description of the changes that have occurred since this
31 // was last invoked. Resets state to initial state.
32 std::string
StateStringAndClear() {
34 AddToResult("added=%d", added_count_
, &result
);
35 AddToResult("removed=%d", removed_count_
, &result
);
36 AddToResult("changed=%d", changed_count_
, &result
);
37 AddToResult("moved=%d", moved_count_
, &result
);
38 added_count_
= removed_count_
= changed_count_
= moved_count_
= 0;
42 // ShelfModelObserver overrides:
43 virtual void ShelfItemAdded(int index
) OVERRIDE
{
46 virtual void ShelfItemRemoved(int index
, ShelfID id
) OVERRIDE
{
49 virtual void ShelfItemChanged(int index
,
50 const ShelfItem
& old_item
) OVERRIDE
{
53 virtual void ShelfItemMoved(int start_index
, int target_index
) OVERRIDE
{
56 virtual void ShelfStatusChanged() OVERRIDE
{
60 void AddToResult(const std::string
& format
, int count
, std::string
* result
) {
65 *result
+= base::StringPrintf(format
.c_str(), count
);
73 DISALLOW_COPY_AND_ASSIGN(TestShelfModelObserver
);
78 class ShelfModelTest
: public testing::Test
{
81 virtual ~ShelfModelTest() {}
83 virtual void SetUp() {
84 model_
.reset(new ShelfModel
);
85 observer_
.reset(new TestShelfModelObserver
);
86 EXPECT_EQ(0, model_
->item_count());
89 item
.type
= TYPE_APP_LIST
;
91 EXPECT_EQ(1, model_
->item_count());
93 model_
->AddObserver(observer_
.get());
96 virtual void TearDown() {
101 scoped_ptr
<ShelfModel
> model_
;
102 scoped_ptr
<TestShelfModelObserver
> observer_
;
105 DISALLOW_COPY_AND_ASSIGN(ShelfModelTest
);
108 TEST_F(ShelfModelTest
, BasicAssertions
) {
111 item
.type
= TYPE_APP_SHORTCUT
;
112 int index
= model_
->Add(item
);
113 EXPECT_EQ(2, model_
->item_count());
114 EXPECT_EQ("added=1", observer_
->StateStringAndClear());
116 // Change to a platform app item.
117 ShelfID original_id
= model_
->items()[index
].id
;
118 item
.type
= TYPE_PLATFORM_APP
;
119 model_
->Set(index
, item
);
120 EXPECT_EQ(original_id
, model_
->items()[index
].id
);
121 EXPECT_EQ("changed=1", observer_
->StateStringAndClear());
122 EXPECT_EQ(TYPE_PLATFORM_APP
, model_
->items()[index
].type
);
125 model_
->RemoveItemAt(index
);
126 EXPECT_EQ(1, model_
->item_count());
127 EXPECT_EQ("removed=1", observer_
->StateStringAndClear());
130 item
.type
= TYPE_APP_SHORTCUT
;
131 index
= model_
->Add(item
);
132 observer_
->StateStringAndClear();
134 // Change everything.
135 model_
->Set(index
, item
);
136 EXPECT_EQ("changed=1", observer_
->StateStringAndClear());
137 EXPECT_EQ(TYPE_APP_SHORTCUT
, model_
->items()[index
].type
);
140 item
.type
= TYPE_APP_SHORTCUT
;
142 observer_
->StateStringAndClear();
144 // Move the second to the first.
146 EXPECT_EQ("moved=1", observer_
->StateStringAndClear());
150 EXPECT_EQ("moved=1", observer_
->StateStringAndClear());
152 // Verifies all the items get unique ids.
153 std::set
<ShelfID
> ids
;
154 for (int i
= 0; i
< model_
->item_count(); ++i
)
155 ids
.insert(model_
->items()[i
].id
);
156 EXPECT_EQ(model_
->item_count(), static_cast<int>(ids
.size()));
159 // Assertions around where items are added.
160 TEST_F(ShelfModelTest
, AddIndices
) {
161 // Insert browser short cut at index 1.
162 ShelfItem browser_shortcut
;
163 browser_shortcut
.type
= TYPE_BROWSER_SHORTCUT
;
164 int browser_shortcut_index
= model_
->Add(browser_shortcut
);
165 EXPECT_EQ(1, browser_shortcut_index
);
167 // platform app items should be after browser shortcut.
169 item
.type
= TYPE_PLATFORM_APP
;
170 int platform_app_index1
= model_
->Add(item
);
171 EXPECT_EQ(2, platform_app_index1
);
173 // Add another platform app item, it should follow first.
174 int platform_app_index2
= model_
->Add(item
);
175 EXPECT_EQ(3, platform_app_index2
);
177 // APP_SHORTCUT priority is higher than PLATFORM_APP but same as
178 // BROWSER_SHORTCUT. So APP_SHORTCUT is located after BROWSER_SHORCUT.
179 item
.type
= TYPE_APP_SHORTCUT
;
180 int app_shortcut_index1
= model_
->Add(item
);
181 EXPECT_EQ(2, app_shortcut_index1
);
183 item
.type
= TYPE_APP_SHORTCUT
;
184 int app_shortcut_index2
= model_
->Add(item
);
185 EXPECT_EQ(3, app_shortcut_index2
);
187 // Check that AddAt() figures out the correct indexes for app shortcuts.
188 // APP_SHORTCUT and BROWSER_SHORTCUT has the same weight.
189 // So APP_SHORTCUT is located at index 0. And, BROWSER_SHORTCUT is located at
191 item
.type
= TYPE_APP_SHORTCUT
;
192 int app_shortcut_index3
= model_
->AddAt(1, item
);
193 EXPECT_EQ(1, app_shortcut_index3
);
195 item
.type
= TYPE_APP_SHORTCUT
;
196 int app_shortcut_index4
= model_
->AddAt(6, item
);
197 EXPECT_EQ(5, app_shortcut_index4
);
199 item
.type
= TYPE_APP_SHORTCUT
;
200 int app_shortcut_index5
= model_
->AddAt(3, item
);
201 EXPECT_EQ(3, app_shortcut_index5
);
203 // Before there are any panels, no icons should be right aligned.
204 EXPECT_EQ(model_
->item_count(), model_
->FirstPanelIndex());
206 // Check that AddAt() figures out the correct indexes for platform apps and
208 item
.type
= TYPE_PLATFORM_APP
;
209 int platform_app_index3
= model_
->AddAt(3, item
);
210 EXPECT_EQ(7, platform_app_index3
);
212 item
.type
= TYPE_APP_PANEL
;
213 int app_panel_index1
= model_
->AddAt(2, item
);
214 EXPECT_EQ(10, app_panel_index1
);
216 item
.type
= TYPE_PLATFORM_APP
;
217 int platform_app_index4
= model_
->AddAt(11, item
);
218 EXPECT_EQ(10, platform_app_index4
);
220 item
.type
= TYPE_APP_PANEL
;
221 int app_panel_index2
= model_
->AddAt(12, item
);
222 EXPECT_EQ(12, app_panel_index2
);
224 item
.type
= TYPE_PLATFORM_APP
;
225 int platform_app_index5
= model_
->AddAt(7, item
);
226 EXPECT_EQ(7, platform_app_index5
);
228 item
.type
= TYPE_APP_PANEL
;
229 int app_panel_index3
= model_
->AddAt(13, item
);
230 EXPECT_EQ(13, app_panel_index3
);
232 // Right aligned index should be the first app panel index.
233 EXPECT_EQ(12, model_
->FirstPanelIndex());
235 EXPECT_EQ(TYPE_BROWSER_SHORTCUT
, model_
->items()[2].type
);
236 EXPECT_EQ(TYPE_APP_LIST
, model_
->items()[0].type
);
239 // Test that the indexes for the running applications are properly determined
240 // when the first running application is a windowed application.
241 TEST_F(ShelfModelTest
, FirstRunningAppIndexUsingWindowedAppFirst
) {
242 // Insert the browser shortcut at index 1 and check that the running
243 // application index would be behind it.
245 item
.type
= TYPE_BROWSER_SHORTCUT
;
246 EXPECT_EQ(1, model_
->Add(item
));
247 EXPECT_EQ(2, model_
->FirstRunningAppIndex());
249 // Insert a panel application at the end and check that the running
250 // application index would be at / before the application panel.
251 item
.type
= TYPE_APP_PANEL
;
252 EXPECT_EQ(2, model_
->Add(item
));
253 EXPECT_EQ(2, model_
->FirstRunningAppIndex());
255 // Insert an application shortcut and make sure that the running application
256 // index would be behind it.
257 item
.type
= TYPE_APP_SHORTCUT
;
258 EXPECT_EQ(2, model_
->Add(item
));
259 EXPECT_EQ(3, model_
->FirstRunningAppIndex());
261 // Insert different running application shortcuts - but first a windowed
262 // application - and make sure that the same index gets returned.
263 item
.type
= TYPE_WINDOWED_APP
;
264 int running_app_index
= model_
->Add(item
);
265 EXPECT_EQ(3, running_app_index
);
266 EXPECT_EQ(running_app_index
, model_
->FirstRunningAppIndex());
267 item
.type
= TYPE_PLATFORM_APP
;
268 EXPECT_EQ(running_app_index
+ 1, model_
->Add(item
));
269 EXPECT_EQ(running_app_index
, model_
->FirstRunningAppIndex());
272 // Test that the indexes for the running applications are properly determined
273 // when the first running application is a platform application.
274 TEST_F(ShelfModelTest
, FirstRunningAppIndexUsingPlatformAppFirst
) {
275 // Insert the browser shortcut at index 1 and check that the running
276 // application index would be behind it.
278 item
.type
= TYPE_BROWSER_SHORTCUT
;
279 EXPECT_EQ(1, model_
->Add(item
));
280 EXPECT_EQ(2, model_
->FirstRunningAppIndex());
282 // Insert a panel application at the end and check that the running
283 // application index would be at / before the application panel.
284 item
.type
= TYPE_APP_PANEL
;
285 EXPECT_EQ(2, model_
->Add(item
));
286 EXPECT_EQ(2, model_
->FirstRunningAppIndex());
288 // Insert an application shortcut and make sure that the running application
289 // index would be behind it.
290 item
.type
= TYPE_APP_SHORTCUT
;
291 EXPECT_EQ(2, model_
->Add(item
));
292 EXPECT_EQ(3, model_
->FirstRunningAppIndex());
294 // Insert different running application shortcuts - but first a platfom
295 // application - and make sure that the same index gets returned.
296 item
.type
= TYPE_PLATFORM_APP
;
297 int running_app_index
= model_
->Add(item
);
298 EXPECT_EQ(3, running_app_index
);
299 EXPECT_EQ(running_app_index
, model_
->FirstRunningAppIndex());
300 item
.type
= TYPE_WINDOWED_APP
;
301 EXPECT_EQ(running_app_index
+ 1, model_
->Add(item
));
302 EXPECT_EQ(running_app_index
, model_
->FirstRunningAppIndex());
305 // Assertions around id generation and usage.
306 TEST_F(ShelfModelTest
, ShelfIDTests
) {
307 // Get the next to use ID counter.
308 ShelfID id
= model_
->next_id();
310 // Calling this function multiple times does not change the returned ID.
311 EXPECT_EQ(model_
->next_id(), id
);
313 // Check that when we reserve a value it will be the previously retrieved ID,
314 // but it will not change the item count and retrieving the next ID should
315 // produce something new.
316 EXPECT_EQ(model_
->reserve_external_id(), id
);
317 EXPECT_EQ(1, model_
->item_count());
318 ShelfID id2
= model_
->next_id();
321 // Adding another item to the list should also produce a new ID.
323 item
.type
= TYPE_PLATFORM_APP
;
325 EXPECT_NE(model_
->next_id(), id2
);
328 // This verifies that converting an existing item into a lower weight category
329 // (e.g. shortcut to running but not pinned app) will move it to the proper
330 // location. See crbug.com/248769.
331 TEST_F(ShelfModelTest
, CorrectMoveItemsWhenStateChange
) {
332 // The first item is the app list and last item is the browser.
333 ShelfItem browser_shortcut
;
334 browser_shortcut
.type
= TYPE_BROWSER_SHORTCUT
;
335 int browser_shortcut_index
= model_
->Add(browser_shortcut
);
336 EXPECT_EQ(TYPE_APP_LIST
, model_
->items()[0].type
);
337 EXPECT_EQ(1, browser_shortcut_index
);
339 // Add three shortcuts. They should all be moved between the two.
341 item
.type
= TYPE_APP_SHORTCUT
;
342 int app1_index
= model_
->Add(item
);
343 EXPECT_EQ(2, app1_index
);
344 int app2_index
= model_
->Add(item
);
345 EXPECT_EQ(3, app2_index
);
346 int app3_index
= model_
->Add(item
);
347 EXPECT_EQ(4, app3_index
);
349 // Now change the type of the second item and make sure that it is moving
350 // behind the shortcuts.
351 item
.type
= TYPE_PLATFORM_APP
;
352 model_
->Set(app2_index
, item
);
354 // The item should have moved in front of the app launcher.
355 EXPECT_EQ(TYPE_PLATFORM_APP
, model_
->items()[4].type
);