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 void ShelfItemAdded(int index
) override
{ added_count_
++; }
44 void ShelfItemRemoved(int index
, ShelfID id
) override
{ removed_count_
++; }
45 void ShelfItemChanged(int index
, const ShelfItem
& old_item
) override
{
48 void ShelfItemMoved(int start_index
, int target_index
) override
{
51 void ShelfStatusChanged() override
{}
54 void AddToResult(const std::string
& format
, int count
, std::string
* result
) {
59 *result
+= base::StringPrintf(format
.c_str(), count
);
67 DISALLOW_COPY_AND_ASSIGN(TestShelfModelObserver
);
72 class ShelfModelTest
: public testing::Test
{
75 ~ShelfModelTest() override
{}
77 void SetUp() override
{
78 model_
.reset(new ShelfModel
);
79 observer_
.reset(new TestShelfModelObserver
);
80 EXPECT_EQ(0, model_
->item_count());
83 item
.type
= TYPE_APP_LIST
;
85 EXPECT_EQ(1, model_
->item_count());
87 model_
->AddObserver(observer_
.get());
90 void TearDown() override
{
95 scoped_ptr
<ShelfModel
> model_
;
96 scoped_ptr
<TestShelfModelObserver
> observer_
;
99 DISALLOW_COPY_AND_ASSIGN(ShelfModelTest
);
102 TEST_F(ShelfModelTest
, BasicAssertions
) {
105 item
.type
= TYPE_APP_SHORTCUT
;
106 int index
= model_
->Add(item
);
107 EXPECT_EQ(2, model_
->item_count());
108 EXPECT_EQ("added=1", observer_
->StateStringAndClear());
110 // Change to a platform app item.
111 ShelfID original_id
= model_
->items()[index
].id
;
112 item
.type
= TYPE_PLATFORM_APP
;
113 model_
->Set(index
, item
);
114 EXPECT_EQ(original_id
, model_
->items()[index
].id
);
115 EXPECT_EQ("changed=1", observer_
->StateStringAndClear());
116 EXPECT_EQ(TYPE_PLATFORM_APP
, model_
->items()[index
].type
);
119 model_
->RemoveItemAt(index
);
120 EXPECT_EQ(1, model_
->item_count());
121 EXPECT_EQ("removed=1", observer_
->StateStringAndClear());
124 item
.type
= TYPE_APP_SHORTCUT
;
125 index
= model_
->Add(item
);
126 observer_
->StateStringAndClear();
128 // Change everything.
129 model_
->Set(index
, item
);
130 EXPECT_EQ("changed=1", observer_
->StateStringAndClear());
131 EXPECT_EQ(TYPE_APP_SHORTCUT
, model_
->items()[index
].type
);
134 item
.type
= TYPE_APP_SHORTCUT
;
136 observer_
->StateStringAndClear();
138 // Move the second to the first.
140 EXPECT_EQ("moved=1", observer_
->StateStringAndClear());
144 EXPECT_EQ("moved=1", observer_
->StateStringAndClear());
146 // Verifies all the items get unique ids.
147 std::set
<ShelfID
> ids
;
148 for (int i
= 0; i
< model_
->item_count(); ++i
)
149 ids
.insert(model_
->items()[i
].id
);
150 EXPECT_EQ(model_
->item_count(), static_cast<int>(ids
.size()));
153 // Assertions around where items are added.
154 TEST_F(ShelfModelTest
, AddIndices
) {
155 // Insert browser short cut at index 1.
156 ShelfItem browser_shortcut
;
157 browser_shortcut
.type
= TYPE_BROWSER_SHORTCUT
;
158 int browser_shortcut_index
= model_
->Add(browser_shortcut
);
159 EXPECT_EQ(1, browser_shortcut_index
);
161 // platform app items should be after browser shortcut.
163 item
.type
= TYPE_PLATFORM_APP
;
164 int platform_app_index1
= model_
->Add(item
);
165 EXPECT_EQ(2, platform_app_index1
);
167 // Add another platform app item, it should follow first.
168 int platform_app_index2
= model_
->Add(item
);
169 EXPECT_EQ(3, platform_app_index2
);
171 // APP_SHORTCUT priority is higher than PLATFORM_APP but same as
172 // BROWSER_SHORTCUT. So APP_SHORTCUT is located after BROWSER_SHORCUT.
173 item
.type
= TYPE_APP_SHORTCUT
;
174 int app_shortcut_index1
= model_
->Add(item
);
175 EXPECT_EQ(2, app_shortcut_index1
);
177 item
.type
= TYPE_APP_SHORTCUT
;
178 int app_shortcut_index2
= model_
->Add(item
);
179 EXPECT_EQ(3, app_shortcut_index2
);
181 // Check that AddAt() figures out the correct indexes for app shortcuts.
182 // APP_SHORTCUT and BROWSER_SHORTCUT has the same weight.
183 // So APP_SHORTCUT is located at index 0. And, BROWSER_SHORTCUT is located at
185 item
.type
= TYPE_APP_SHORTCUT
;
186 int app_shortcut_index3
= model_
->AddAt(1, item
);
187 EXPECT_EQ(1, app_shortcut_index3
);
189 item
.type
= TYPE_APP_SHORTCUT
;
190 int app_shortcut_index4
= model_
->AddAt(6, item
);
191 EXPECT_EQ(5, app_shortcut_index4
);
193 item
.type
= TYPE_APP_SHORTCUT
;
194 int app_shortcut_index5
= model_
->AddAt(3, item
);
195 EXPECT_EQ(3, app_shortcut_index5
);
197 // Before there are any panels, no icons should be right aligned.
198 EXPECT_EQ(model_
->item_count(), model_
->FirstPanelIndex());
200 // Check that AddAt() figures out the correct indexes for platform apps and
202 item
.type
= TYPE_PLATFORM_APP
;
203 int platform_app_index3
= model_
->AddAt(3, item
);
204 EXPECT_EQ(7, platform_app_index3
);
206 item
.type
= TYPE_APP_PANEL
;
207 int app_panel_index1
= model_
->AddAt(2, item
);
208 EXPECT_EQ(10, app_panel_index1
);
210 item
.type
= TYPE_PLATFORM_APP
;
211 int platform_app_index4
= model_
->AddAt(11, item
);
212 EXPECT_EQ(10, platform_app_index4
);
214 item
.type
= TYPE_APP_PANEL
;
215 int app_panel_index2
= model_
->AddAt(12, item
);
216 EXPECT_EQ(12, app_panel_index2
);
218 item
.type
= TYPE_PLATFORM_APP
;
219 int platform_app_index5
= model_
->AddAt(7, item
);
220 EXPECT_EQ(7, platform_app_index5
);
222 item
.type
= TYPE_APP_PANEL
;
223 int app_panel_index3
= model_
->AddAt(13, item
);
224 EXPECT_EQ(13, app_panel_index3
);
226 // Right aligned index should be the first app panel index.
227 EXPECT_EQ(12, model_
->FirstPanelIndex());
229 EXPECT_EQ(TYPE_BROWSER_SHORTCUT
, model_
->items()[2].type
);
230 EXPECT_EQ(TYPE_APP_LIST
, model_
->items()[0].type
);
233 // Test that the indexes for the running applications are properly determined
234 // when the first running application is a windowed application.
235 TEST_F(ShelfModelTest
, FirstRunningAppIndexUsingWindowedAppFirst
) {
236 // Insert the browser shortcut at index 1 and check that the running
237 // application index would be behind it.
239 item
.type
= TYPE_BROWSER_SHORTCUT
;
240 EXPECT_EQ(1, model_
->Add(item
));
241 EXPECT_EQ(2, model_
->FirstRunningAppIndex());
243 // Insert a panel application at the end and check that the running
244 // application index would be at / before the application panel.
245 item
.type
= TYPE_APP_PANEL
;
246 EXPECT_EQ(2, model_
->Add(item
));
247 EXPECT_EQ(2, model_
->FirstRunningAppIndex());
249 // Insert an application shortcut and make sure that the running application
250 // index would be behind it.
251 item
.type
= TYPE_APP_SHORTCUT
;
252 EXPECT_EQ(2, model_
->Add(item
));
253 EXPECT_EQ(3, model_
->FirstRunningAppIndex());
255 // Insert different running application shortcuts - but first a windowed
256 // application - and make sure that the same index gets returned.
257 item
.type
= TYPE_WINDOWED_APP
;
258 int running_app_index
= model_
->Add(item
);
259 EXPECT_EQ(3, running_app_index
);
260 EXPECT_EQ(running_app_index
, model_
->FirstRunningAppIndex());
261 item
.type
= TYPE_PLATFORM_APP
;
262 EXPECT_EQ(running_app_index
+ 1, model_
->Add(item
));
263 EXPECT_EQ(running_app_index
, model_
->FirstRunningAppIndex());
266 // Test that the indexes for the running applications are properly determined
267 // when the first running application is a platform application.
268 TEST_F(ShelfModelTest
, FirstRunningAppIndexUsingPlatformAppFirst
) {
269 // Insert the browser shortcut at index 1 and check that the running
270 // application index would be behind it.
272 item
.type
= TYPE_BROWSER_SHORTCUT
;
273 EXPECT_EQ(1, model_
->Add(item
));
274 EXPECT_EQ(2, model_
->FirstRunningAppIndex());
276 // Insert a panel application at the end and check that the running
277 // application index would be at / before the application panel.
278 item
.type
= TYPE_APP_PANEL
;
279 EXPECT_EQ(2, model_
->Add(item
));
280 EXPECT_EQ(2, model_
->FirstRunningAppIndex());
282 // Insert an application shortcut and make sure that the running application
283 // index would be behind it.
284 item
.type
= TYPE_APP_SHORTCUT
;
285 EXPECT_EQ(2, model_
->Add(item
));
286 EXPECT_EQ(3, model_
->FirstRunningAppIndex());
288 // Insert different running application shortcuts - but first a platfom
289 // application - and make sure that the same index gets returned.
290 item
.type
= TYPE_PLATFORM_APP
;
291 int running_app_index
= model_
->Add(item
);
292 EXPECT_EQ(3, running_app_index
);
293 EXPECT_EQ(running_app_index
, model_
->FirstRunningAppIndex());
294 item
.type
= TYPE_WINDOWED_APP
;
295 EXPECT_EQ(running_app_index
+ 1, model_
->Add(item
));
296 EXPECT_EQ(running_app_index
, model_
->FirstRunningAppIndex());
299 // Assertions around id generation and usage.
300 TEST_F(ShelfModelTest
, ShelfIDTests
) {
301 // Get the next to use ID counter.
302 ShelfID id
= model_
->next_id();
304 // Calling this function multiple times does not change the returned ID.
305 EXPECT_EQ(model_
->next_id(), id
);
307 // Check that when we reserve a value it will be the previously retrieved ID,
308 // but it will not change the item count and retrieving the next ID should
309 // produce something new.
310 EXPECT_EQ(model_
->reserve_external_id(), id
);
311 EXPECT_EQ(1, model_
->item_count());
312 ShelfID id2
= model_
->next_id();
315 // Adding another item to the list should also produce a new ID.
317 item
.type
= TYPE_PLATFORM_APP
;
319 EXPECT_NE(model_
->next_id(), id2
);
322 // This verifies that converting an existing item into a lower weight category
323 // (e.g. shortcut to running but not pinned app) will move it to the proper
324 // location. See crbug.com/248769.
325 TEST_F(ShelfModelTest
, CorrectMoveItemsWhenStateChange
) {
326 // The first item is the app list and last item is the browser.
327 ShelfItem browser_shortcut
;
328 browser_shortcut
.type
= TYPE_BROWSER_SHORTCUT
;
329 int browser_shortcut_index
= model_
->Add(browser_shortcut
);
330 EXPECT_EQ(TYPE_APP_LIST
, model_
->items()[0].type
);
331 EXPECT_EQ(1, browser_shortcut_index
);
333 // Add three shortcuts. They should all be moved between the two.
335 item
.type
= TYPE_APP_SHORTCUT
;
336 int app1_index
= model_
->Add(item
);
337 EXPECT_EQ(2, app1_index
);
338 int app2_index
= model_
->Add(item
);
339 EXPECT_EQ(3, app2_index
);
340 int app3_index
= model_
->Add(item
);
341 EXPECT_EQ(4, app3_index
);
343 // Now change the type of the second item and make sure that it is moving
344 // behind the shortcuts.
345 item
.type
= TYPE_PLATFORM_APP
;
346 model_
->Set(app2_index
, item
);
348 // The item should have moved in front of the app launcher.
349 EXPECT_EQ(TYPE_PLATFORM_APP
, model_
->items()[4].type
);