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 "ui/app_list/app_list_item_list.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "base/strings/stringprintf.h"
9 #include "testing/gtest/include/gtest/gtest.h"
10 #include "ui/app_list/app_list_folder_item.h"
11 #include "ui/app_list/app_list_item.h"
12 #include "ui/app_list/app_list_item_list_observer.h"
18 class TestObserver
: public AppListItemListObserver
{
20 TestObserver() : items_added_(0), items_removed_(0), items_moved_(0) {}
22 virtual ~TestObserver() {
25 // AppListItemListObserver overriden:
26 virtual void OnListItemAdded(size_t index
, AppListItem
* item
) OVERRIDE
{
30 virtual void OnListItemRemoved(size_t index
, AppListItem
* item
) OVERRIDE
{
34 virtual void OnListItemMoved(size_t from_index
,
36 AppListItem
* item
) OVERRIDE
{
40 size_t items_added() const { return items_added_
; }
41 size_t items_removed() const { return items_removed_
; }
42 size_t items_moved() const { return items_moved_
; }
52 size_t items_removed_
;
55 DISALLOW_COPY_AND_ASSIGN(TestObserver
);
58 std::string
GetItemId(int id
) {
59 return base::StringPrintf("Item %d", id
);
64 class AppListItemListTest
: public testing::Test
{
66 AppListItemListTest() {}
67 virtual ~AppListItemListTest() {}
69 // testing::Test overrides:
70 virtual void SetUp() OVERRIDE
{
71 item_list_
.AddObserver(&observer_
);
74 virtual void TearDown() OVERRIDE
{
75 item_list_
.RemoveObserver(&observer_
);
79 AppListItem
* FindItem(const std::string
& id
) {
80 return item_list_
.FindItem(id
);
83 bool FindItemIndex(const std::string
& id
, size_t* index
) {
84 return item_list_
.FindItemIndex(id
, index
);
87 scoped_ptr
<AppListItem
> CreateItem(const std::string
& name
) {
88 scoped_ptr
<AppListItem
> item(new AppListItem(name
));
89 size_t nitems
= item_list_
.item_count();
90 syncer::StringOrdinal position
;
92 position
= syncer::StringOrdinal::CreateInitialOrdinal();
94 position
= item_list_
.item_at(nitems
- 1)->position().CreateAfter();
95 item
->set_position(position
);
99 AppListItem
* CreateAndAddItem(const std::string
& name
) {
100 scoped_ptr
<AppListItem
> item(CreateItem(name
));
101 return item_list_
.AddItem(item
.Pass());
104 scoped_ptr
<AppListItem
> RemoveItem(const std::string
& id
) {
105 return item_list_
.RemoveItem(id
);
108 scoped_ptr
<AppListItem
> RemoveItemAt(size_t index
) {
109 return item_list_
.RemoveItemAt(index
);
112 syncer::StringOrdinal
CreatePositionBefore(
113 const syncer::StringOrdinal
& position
) {
114 return item_list_
.CreatePositionBefore(position
);
117 bool VerifyItemListOrdinals() {
119 for (size_t i
= 1; i
< item_list_
.item_count(); ++i
) {
120 res
&= (item_list_
.item_at(i
- 1)->position().LessThan(
121 item_list_
.item_at(i
)->position()));
128 bool VerifyItemOrder4(size_t a
, size_t b
, size_t c
, size_t d
) {
129 if ((GetItemId(a
) == item_list_
.item_at(0)->id()) &&
130 (GetItemId(b
) == item_list_
.item_at(1)->id()) &&
131 (GetItemId(c
) == item_list_
.item_at(2)->id()) &&
132 (GetItemId(d
) == item_list_
.item_at(3)->id()))
140 for (size_t i
= 0; i
< item_list_
.item_count(); ++i
)
141 VLOG(1) << " " << item_list_
.item_at(i
)->ToDebugString();
144 AppListItemList item_list_
;
145 TestObserver observer_
;
148 DISALLOW_COPY_AND_ASSIGN(AppListItemListTest
);
151 TEST_F(AppListItemListTest
, FindItemIndex
) {
152 AppListItem
* item_0
= CreateAndAddItem(GetItemId(0));
153 AppListItem
* item_1
= CreateAndAddItem(GetItemId(1));
154 AppListItem
* item_2
= CreateAndAddItem(GetItemId(2));
155 EXPECT_EQ(observer_
.items_added(), 3u);
156 EXPECT_EQ(item_list_
.item_count(), 3u);
157 EXPECT_EQ(item_0
, item_list_
.item_at(0));
158 EXPECT_EQ(item_1
, item_list_
.item_at(1));
159 EXPECT_EQ(item_2
, item_list_
.item_at(2));
160 EXPECT_TRUE(VerifyItemListOrdinals());
163 EXPECT_TRUE(FindItemIndex(item_0
->id(), &index
));
164 EXPECT_EQ(index
, 0u);
165 EXPECT_TRUE(FindItemIndex(item_1
->id(), &index
));
166 EXPECT_EQ(index
, 1u);
167 EXPECT_TRUE(FindItemIndex(item_2
->id(), &index
));
168 EXPECT_EQ(index
, 2u);
170 scoped_ptr
<AppListItem
> item_3(CreateItem(GetItemId(3)));
171 EXPECT_FALSE(FindItemIndex(item_3
->id(), &index
));
174 TEST_F(AppListItemListTest
, RemoveItemAt
) {
175 AppListItem
* item_0
= CreateAndAddItem(GetItemId(0));
176 AppListItem
* item_1
= CreateAndAddItem(GetItemId(1));
177 AppListItem
* item_2
= CreateAndAddItem(GetItemId(2));
178 EXPECT_EQ(item_list_
.item_count(), 3u);
179 EXPECT_EQ(observer_
.items_added(), 3u);
181 EXPECT_TRUE(FindItemIndex(item_1
->id(), &index
));
182 EXPECT_EQ(index
, 1u);
183 EXPECT_TRUE(VerifyItemListOrdinals());
185 scoped_ptr
<AppListItem
> item_removed
= RemoveItemAt(1);
186 EXPECT_EQ(item_removed
, item_1
);
187 EXPECT_FALSE(FindItem(item_1
->id()));
188 EXPECT_EQ(item_list_
.item_count(), 2u);
189 EXPECT_EQ(observer_
.items_removed(), 1u);
190 EXPECT_EQ(item_list_
.item_at(0), item_0
);
191 EXPECT_EQ(item_list_
.item_at(1), item_2
);
192 EXPECT_TRUE(VerifyItemListOrdinals());
195 TEST_F(AppListItemListTest
, RemoveItem
) {
196 AppListItem
* item_0
= CreateAndAddItem(GetItemId(0));
197 AppListItem
* item_1
= CreateAndAddItem(GetItemId(1));
198 AppListItem
* item_2
= CreateAndAddItem(GetItemId(2));
199 EXPECT_EQ(item_list_
.item_count(), 3u);
200 EXPECT_EQ(observer_
.items_added(), 3u);
201 EXPECT_EQ(item_0
, item_list_
.item_at(0));
202 EXPECT_EQ(item_1
, item_list_
.item_at(1));
203 EXPECT_EQ(item_2
, item_list_
.item_at(2));
204 EXPECT_TRUE(VerifyItemListOrdinals());
207 EXPECT_TRUE(FindItemIndex(item_1
->id(), &index
));
208 EXPECT_EQ(index
, 1u);
210 scoped_ptr
<AppListItem
> item_removed
= RemoveItem(item_1
->id());
211 EXPECT_EQ(item_removed
, item_1
);
212 EXPECT_FALSE(FindItem(item_1
->id()));
213 EXPECT_EQ(item_list_
.item_count(), 2u);
214 EXPECT_EQ(observer_
.items_removed(), 1u);
215 EXPECT_TRUE(VerifyItemListOrdinals());
217 scoped_ptr
<AppListItem
> not_found_item
= RemoveItem("Bogus");
218 EXPECT_FALSE(not_found_item
.get());
221 TEST_F(AppListItemListTest
, MoveItem
) {
222 CreateAndAddItem(GetItemId(0));
223 CreateAndAddItem(GetItemId(1));
224 CreateAndAddItem(GetItemId(2));
225 CreateAndAddItem(GetItemId(3));
227 EXPECT_TRUE(VerifyItemOrder4(0, 1, 2, 3));
229 item_list_
.MoveItem(0, 0);
230 EXPECT_EQ(0u, observer_
.items_moved());
231 EXPECT_TRUE(VerifyItemOrder4(0, 1, 2, 3));
233 item_list_
.MoveItem(0, 1);
234 EXPECT_EQ(1u, observer_
.items_moved());
235 EXPECT_TRUE(VerifyItemListOrdinals());
236 EXPECT_TRUE(VerifyItemOrder4(1, 0, 2, 3));
238 item_list_
.MoveItem(1, 2);
239 EXPECT_EQ(2u, observer_
.items_moved());
240 EXPECT_TRUE(VerifyItemListOrdinals());
241 EXPECT_TRUE(VerifyItemOrder4(1, 2, 0, 3));
243 item_list_
.MoveItem(2, 1);
244 EXPECT_EQ(3u, observer_
.items_moved());
245 EXPECT_TRUE(VerifyItemListOrdinals());
246 EXPECT_TRUE(VerifyItemOrder4(1, 0, 2, 3));
248 item_list_
.MoveItem(3, 0);
249 EXPECT_EQ(4u, observer_
.items_moved());
250 EXPECT_TRUE(VerifyItemListOrdinals());
251 EXPECT_TRUE(VerifyItemOrder4(3, 1, 0, 2));
253 item_list_
.MoveItem(0, 3);
254 EXPECT_EQ(5u, observer_
.items_moved());
255 EXPECT_TRUE(VerifyItemListOrdinals());
256 EXPECT_TRUE(VerifyItemOrder4(1, 0, 2, 3));
259 TEST_F(AppListItemListTest
, SamePosition
) {
260 CreateAndAddItem(GetItemId(0));
261 CreateAndAddItem(GetItemId(1));
262 CreateAndAddItem(GetItemId(2));
263 CreateAndAddItem(GetItemId(3));
264 item_list_
.SetItemPosition(item_list_
.item_at(2),
265 item_list_
.item_at(1)->position());
266 EXPECT_TRUE(VerifyItemOrder4(0, 1, 2, 3));
267 EXPECT_TRUE(item_list_
.item_at(1)->position().Equals(
268 item_list_
.item_at(2)->position()));
269 // Moving an item to position 1 should fix the position.
270 observer_
.ResetCounts();
271 item_list_
.MoveItem(0, 1);
272 EXPECT_TRUE(VerifyItemOrder4(1, 0, 2, 3));
273 EXPECT_TRUE(item_list_
.item_at(0)->position().LessThan(
274 item_list_
.item_at(1)->position()));
275 EXPECT_TRUE(item_list_
.item_at(1)->position().LessThan(
276 item_list_
.item_at(2)->position()));
277 EXPECT_TRUE(item_list_
.item_at(2)->position().LessThan(
278 item_list_
.item_at(3)->position()));
279 // One extra move notification for fixed position.
280 EXPECT_EQ(2u, observer_
.items_moved());
282 // Restore the original order.
283 item_list_
.MoveItem(1, 0);
284 EXPECT_TRUE(VerifyItemOrder4(0, 1, 2, 3));
286 // Set all four items to the same position.
287 item_list_
.SetItemPosition(item_list_
.item_at(1),
288 item_list_
.item_at(0)->position());
289 item_list_
.SetItemPosition(item_list_
.item_at(2),
290 item_list_
.item_at(0)->position());
291 item_list_
.SetItemPosition(item_list_
.item_at(3),
292 item_list_
.item_at(0)->position());
293 // Move should fix the position of the items.
294 observer_
.ResetCounts();
295 item_list_
.MoveItem(0, 1);
296 EXPECT_TRUE(VerifyItemOrder4(1, 0, 2, 3));
297 EXPECT_TRUE(item_list_
.item_at(0)->position().LessThan(
298 item_list_
.item_at(1)->position()));
299 EXPECT_TRUE(item_list_
.item_at(1)->position().LessThan(
300 item_list_
.item_at(2)->position()));
301 EXPECT_TRUE(item_list_
.item_at(2)->position().LessThan(
302 item_list_
.item_at(3)->position()));
303 // One extra move notification for fixed position.
304 EXPECT_EQ(2u, observer_
.items_moved());
307 TEST_F(AppListItemListTest
, CreatePositionBefore
) {
308 CreateAndAddItem(GetItemId(0));
309 syncer::StringOrdinal position0
= item_list_
.item_at(0)->position();
310 syncer::StringOrdinal new_position
;
311 new_position
= CreatePositionBefore(position0
.CreateBefore());
312 EXPECT_TRUE(new_position
.LessThan(position0
));
313 new_position
= CreatePositionBefore(position0
);
314 EXPECT_TRUE(new_position
.LessThan(position0
));
315 new_position
= CreatePositionBefore(position0
.CreateAfter());
316 EXPECT_TRUE(new_position
.GreaterThan(position0
));
318 CreateAndAddItem(GetItemId(1));
319 syncer::StringOrdinal position1
= item_list_
.item_at(1)->position();
320 EXPECT_TRUE(position1
.GreaterThan(position0
));
321 new_position
= CreatePositionBefore(position1
);
322 EXPECT_TRUE(new_position
.GreaterThan(position0
));
323 EXPECT_TRUE(new_position
.LessThan(position1
));
325 // Invalid ordinal should return a position at the end of the list.
326 new_position
= CreatePositionBefore(syncer::StringOrdinal());
327 EXPECT_TRUE(new_position
.GreaterThan(position1
));
330 TEST_F(AppListItemListTest
, SetItemPosition
) {
331 CreateAndAddItem(GetItemId(0));
332 CreateAndAddItem(GetItemId(1));
333 CreateAndAddItem(GetItemId(2));
334 CreateAndAddItem(GetItemId(3));
335 EXPECT_TRUE(VerifyItemOrder4(0, 1, 2, 3));
337 // No change to position.
338 item_list_
.SetItemPosition(item_list_
.item_at(0),
339 item_list_
.item_at(0)->position());
340 EXPECT_TRUE(VerifyItemListOrdinals());
341 EXPECT_TRUE(VerifyItemOrder4(0, 1, 2, 3));
343 item_list_
.SetItemPosition(item_list_
.item_at(0),
344 item_list_
.item_at(0)->position().CreateBetween(
345 item_list_
.item_at(1)->position()));
346 EXPECT_TRUE(VerifyItemListOrdinals());
347 EXPECT_TRUE(VerifyItemOrder4(0, 1, 2, 3));
349 item_list_
.SetItemPosition(item_list_
.item_at(0),
350 item_list_
.item_at(1)->position().CreateBetween(
351 item_list_
.item_at(2)->position()));
352 EXPECT_TRUE(VerifyItemListOrdinals());
353 EXPECT_TRUE(VerifyItemOrder4(1, 0, 2, 3));
355 item_list_
.SetItemPosition(item_list_
.item_at(1),
356 item_list_
.item_at(2)->position().CreateBetween(
357 item_list_
.item_at(3)->position()));
358 EXPECT_TRUE(VerifyItemListOrdinals());
359 EXPECT_TRUE(VerifyItemOrder4(1, 2, 0, 3));
361 item_list_
.SetItemPosition(item_list_
.item_at(0),
362 item_list_
.item_at(3)->position().CreateAfter());
363 EXPECT_TRUE(VerifyItemListOrdinals());
364 EXPECT_TRUE(VerifyItemOrder4(2, 0, 3, 1));
366 item_list_
.SetItemPosition(item_list_
.item_at(3),
367 item_list_
.item_at(3)->position().CreateAfter());
368 EXPECT_TRUE(VerifyItemListOrdinals());
369 EXPECT_TRUE(VerifyItemOrder4(2, 0, 3, 1));
372 } // namespace app_list