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 ~TestObserver() override
{}
24 // AppListItemListObserver overriden:
25 void OnListItemAdded(size_t index
, AppListItem
* item
) override
{
29 void OnListItemRemoved(size_t index
, AppListItem
* item
) override
{
33 void OnListItemMoved(size_t from_index
,
35 AppListItem
* item
) override
{
39 size_t items_added() const { return items_added_
; }
40 size_t items_removed() const { return items_removed_
; }
41 size_t items_moved() const { return items_moved_
; }
51 size_t items_removed_
;
54 DISALLOW_COPY_AND_ASSIGN(TestObserver
);
57 std::string
GetItemId(int id
) {
58 return base::StringPrintf("Item %d", id
);
63 class AppListItemListTest
: public testing::Test
{
65 AppListItemListTest() {}
66 ~AppListItemListTest() override
{}
68 // testing::Test overrides:
69 void SetUp() override
{ item_list_
.AddObserver(&observer_
); }
71 void TearDown() override
{ item_list_
.RemoveObserver(&observer_
); }
74 AppListItem
* FindItem(const std::string
& id
) {
75 return item_list_
.FindItem(id
);
78 bool FindItemIndex(const std::string
& id
, size_t* index
) {
79 return item_list_
.FindItemIndex(id
, index
);
82 scoped_ptr
<AppListItem
> CreateItem(const std::string
& name
) {
83 scoped_ptr
<AppListItem
> item(new AppListItem(name
));
84 size_t nitems
= item_list_
.item_count();
85 syncer::StringOrdinal position
;
87 position
= syncer::StringOrdinal::CreateInitialOrdinal();
89 position
= item_list_
.item_at(nitems
- 1)->position().CreateAfter();
90 item
->set_position(position
);
94 AppListItem
* CreateAndAddItem(const std::string
& name
) {
95 scoped_ptr
<AppListItem
> item(CreateItem(name
));
96 return item_list_
.AddItem(item
.Pass());
99 scoped_ptr
<AppListItem
> RemoveItem(const std::string
& id
) {
100 return item_list_
.RemoveItem(id
);
103 scoped_ptr
<AppListItem
> RemoveItemAt(size_t index
) {
104 return item_list_
.RemoveItemAt(index
);
107 syncer::StringOrdinal
CreatePositionBefore(
108 const syncer::StringOrdinal
& position
) {
109 return item_list_
.CreatePositionBefore(position
);
112 bool VerifyItemListOrdinals() {
114 for (size_t i
= 1; i
< item_list_
.item_count(); ++i
) {
115 res
&= (item_list_
.item_at(i
- 1)->position().LessThan(
116 item_list_
.item_at(i
)->position()));
123 bool VerifyItemOrder4(size_t a
, size_t b
, size_t c
, size_t d
) {
124 if ((GetItemId(a
) == item_list_
.item_at(0)->id()) &&
125 (GetItemId(b
) == item_list_
.item_at(1)->id()) &&
126 (GetItemId(c
) == item_list_
.item_at(2)->id()) &&
127 (GetItemId(d
) == item_list_
.item_at(3)->id()))
135 for (size_t i
= 0; i
< item_list_
.item_count(); ++i
)
136 VLOG(1) << " " << item_list_
.item_at(i
)->ToDebugString();
139 AppListItemList item_list_
;
140 TestObserver observer_
;
143 DISALLOW_COPY_AND_ASSIGN(AppListItemListTest
);
146 TEST_F(AppListItemListTest
, FindItemIndex
) {
147 AppListItem
* item_0
= CreateAndAddItem(GetItemId(0));
148 AppListItem
* item_1
= CreateAndAddItem(GetItemId(1));
149 AppListItem
* item_2
= CreateAndAddItem(GetItemId(2));
150 EXPECT_EQ(observer_
.items_added(), 3u);
151 EXPECT_EQ(item_list_
.item_count(), 3u);
152 EXPECT_EQ(item_0
, item_list_
.item_at(0));
153 EXPECT_EQ(item_1
, item_list_
.item_at(1));
154 EXPECT_EQ(item_2
, item_list_
.item_at(2));
155 EXPECT_TRUE(VerifyItemListOrdinals());
158 EXPECT_TRUE(FindItemIndex(item_0
->id(), &index
));
159 EXPECT_EQ(index
, 0u);
160 EXPECT_TRUE(FindItemIndex(item_1
->id(), &index
));
161 EXPECT_EQ(index
, 1u);
162 EXPECT_TRUE(FindItemIndex(item_2
->id(), &index
));
163 EXPECT_EQ(index
, 2u);
165 scoped_ptr
<AppListItem
> item_3(CreateItem(GetItemId(3)));
166 EXPECT_FALSE(FindItemIndex(item_3
->id(), &index
));
169 TEST_F(AppListItemListTest
, RemoveItemAt
) {
170 AppListItem
* item_0
= CreateAndAddItem(GetItemId(0));
171 AppListItem
* item_1
= CreateAndAddItem(GetItemId(1));
172 AppListItem
* item_2
= CreateAndAddItem(GetItemId(2));
173 EXPECT_EQ(item_list_
.item_count(), 3u);
174 EXPECT_EQ(observer_
.items_added(), 3u);
176 EXPECT_TRUE(FindItemIndex(item_1
->id(), &index
));
177 EXPECT_EQ(index
, 1u);
178 EXPECT_TRUE(VerifyItemListOrdinals());
180 scoped_ptr
<AppListItem
> item_removed
= RemoveItemAt(1);
181 EXPECT_EQ(item_removed
, item_1
);
182 EXPECT_FALSE(FindItem(item_1
->id()));
183 EXPECT_EQ(item_list_
.item_count(), 2u);
184 EXPECT_EQ(observer_
.items_removed(), 1u);
185 EXPECT_EQ(item_list_
.item_at(0), item_0
);
186 EXPECT_EQ(item_list_
.item_at(1), item_2
);
187 EXPECT_TRUE(VerifyItemListOrdinals());
190 TEST_F(AppListItemListTest
, RemoveItem
) {
191 AppListItem
* item_0
= CreateAndAddItem(GetItemId(0));
192 AppListItem
* item_1
= CreateAndAddItem(GetItemId(1));
193 AppListItem
* item_2
= CreateAndAddItem(GetItemId(2));
194 EXPECT_EQ(item_list_
.item_count(), 3u);
195 EXPECT_EQ(observer_
.items_added(), 3u);
196 EXPECT_EQ(item_0
, item_list_
.item_at(0));
197 EXPECT_EQ(item_1
, item_list_
.item_at(1));
198 EXPECT_EQ(item_2
, item_list_
.item_at(2));
199 EXPECT_TRUE(VerifyItemListOrdinals());
202 EXPECT_TRUE(FindItemIndex(item_1
->id(), &index
));
203 EXPECT_EQ(index
, 1u);
205 scoped_ptr
<AppListItem
> item_removed
= RemoveItem(item_1
->id());
206 EXPECT_EQ(item_removed
, item_1
);
207 EXPECT_FALSE(FindItem(item_1
->id()));
208 EXPECT_EQ(item_list_
.item_count(), 2u);
209 EXPECT_EQ(observer_
.items_removed(), 1u);
210 EXPECT_TRUE(VerifyItemListOrdinals());
213 TEST_F(AppListItemListTest
, MoveItem
) {
214 CreateAndAddItem(GetItemId(0));
215 CreateAndAddItem(GetItemId(1));
216 CreateAndAddItem(GetItemId(2));
217 CreateAndAddItem(GetItemId(3));
219 EXPECT_TRUE(VerifyItemOrder4(0, 1, 2, 3));
221 item_list_
.MoveItem(0, 0);
222 EXPECT_EQ(0u, observer_
.items_moved());
223 EXPECT_TRUE(VerifyItemOrder4(0, 1, 2, 3));
225 item_list_
.MoveItem(0, 1);
226 EXPECT_EQ(1u, observer_
.items_moved());
227 EXPECT_TRUE(VerifyItemListOrdinals());
228 EXPECT_TRUE(VerifyItemOrder4(1, 0, 2, 3));
230 item_list_
.MoveItem(1, 2);
231 EXPECT_EQ(2u, observer_
.items_moved());
232 EXPECT_TRUE(VerifyItemListOrdinals());
233 EXPECT_TRUE(VerifyItemOrder4(1, 2, 0, 3));
235 item_list_
.MoveItem(2, 1);
236 EXPECT_EQ(3u, observer_
.items_moved());
237 EXPECT_TRUE(VerifyItemListOrdinals());
238 EXPECT_TRUE(VerifyItemOrder4(1, 0, 2, 3));
240 item_list_
.MoveItem(3, 0);
241 EXPECT_EQ(4u, observer_
.items_moved());
242 EXPECT_TRUE(VerifyItemListOrdinals());
243 EXPECT_TRUE(VerifyItemOrder4(3, 1, 0, 2));
245 item_list_
.MoveItem(0, 3);
246 EXPECT_EQ(5u, observer_
.items_moved());
247 EXPECT_TRUE(VerifyItemListOrdinals());
248 EXPECT_TRUE(VerifyItemOrder4(1, 0, 2, 3));
251 TEST_F(AppListItemListTest
, SamePosition
) {
252 CreateAndAddItem(GetItemId(0));
253 CreateAndAddItem(GetItemId(1));
254 CreateAndAddItem(GetItemId(2));
255 CreateAndAddItem(GetItemId(3));
256 item_list_
.SetItemPosition(item_list_
.item_at(2),
257 item_list_
.item_at(1)->position());
258 EXPECT_TRUE(VerifyItemOrder4(0, 1, 2, 3));
259 EXPECT_TRUE(item_list_
.item_at(1)->position().Equals(
260 item_list_
.item_at(2)->position()));
261 // Moving an item to position 1 should fix the position.
262 observer_
.ResetCounts();
263 item_list_
.MoveItem(0, 1);
264 EXPECT_TRUE(VerifyItemOrder4(1, 0, 2, 3));
265 EXPECT_TRUE(item_list_
.item_at(0)->position().LessThan(
266 item_list_
.item_at(1)->position()));
267 EXPECT_TRUE(item_list_
.item_at(1)->position().LessThan(
268 item_list_
.item_at(2)->position()));
269 EXPECT_TRUE(item_list_
.item_at(2)->position().LessThan(
270 item_list_
.item_at(3)->position()));
271 // One extra move notification for fixed position.
272 EXPECT_EQ(2u, observer_
.items_moved());
274 // Restore the original order.
275 item_list_
.MoveItem(1, 0);
276 EXPECT_TRUE(VerifyItemOrder4(0, 1, 2, 3));
278 // Set all four items to the same position.
279 item_list_
.SetItemPosition(item_list_
.item_at(1),
280 item_list_
.item_at(0)->position());
281 item_list_
.SetItemPosition(item_list_
.item_at(2),
282 item_list_
.item_at(0)->position());
283 item_list_
.SetItemPosition(item_list_
.item_at(3),
284 item_list_
.item_at(0)->position());
285 // Move should fix the position of the items.
286 observer_
.ResetCounts();
287 item_list_
.MoveItem(0, 1);
288 EXPECT_TRUE(VerifyItemOrder4(1, 0, 2, 3));
289 EXPECT_TRUE(item_list_
.item_at(0)->position().LessThan(
290 item_list_
.item_at(1)->position()));
291 EXPECT_TRUE(item_list_
.item_at(1)->position().LessThan(
292 item_list_
.item_at(2)->position()));
293 EXPECT_TRUE(item_list_
.item_at(2)->position().LessThan(
294 item_list_
.item_at(3)->position()));
295 // One extra move notification for fixed position.
296 EXPECT_EQ(2u, observer_
.items_moved());
299 TEST_F(AppListItemListTest
, CreatePositionBefore
) {
300 CreateAndAddItem(GetItemId(0));
301 syncer::StringOrdinal position0
= item_list_
.item_at(0)->position();
302 syncer::StringOrdinal new_position
;
303 new_position
= CreatePositionBefore(position0
.CreateBefore());
304 EXPECT_TRUE(new_position
.LessThan(position0
));
305 new_position
= CreatePositionBefore(position0
);
306 EXPECT_TRUE(new_position
.LessThan(position0
));
307 new_position
= CreatePositionBefore(position0
.CreateAfter());
308 EXPECT_TRUE(new_position
.GreaterThan(position0
));
310 CreateAndAddItem(GetItemId(1));
311 syncer::StringOrdinal position1
= item_list_
.item_at(1)->position();
312 EXPECT_TRUE(position1
.GreaterThan(position0
));
313 new_position
= CreatePositionBefore(position1
);
314 EXPECT_TRUE(new_position
.GreaterThan(position0
));
315 EXPECT_TRUE(new_position
.LessThan(position1
));
317 // Invalid ordinal should return a position at the end of the list.
318 new_position
= CreatePositionBefore(syncer::StringOrdinal());
319 EXPECT_TRUE(new_position
.GreaterThan(position1
));
322 TEST_F(AppListItemListTest
, SetItemPosition
) {
323 CreateAndAddItem(GetItemId(0));
324 CreateAndAddItem(GetItemId(1));
325 CreateAndAddItem(GetItemId(2));
326 CreateAndAddItem(GetItemId(3));
327 EXPECT_TRUE(VerifyItemOrder4(0, 1, 2, 3));
329 // No change to position.
330 item_list_
.SetItemPosition(item_list_
.item_at(0),
331 item_list_
.item_at(0)->position());
332 EXPECT_TRUE(VerifyItemListOrdinals());
333 EXPECT_TRUE(VerifyItemOrder4(0, 1, 2, 3));
335 item_list_
.SetItemPosition(item_list_
.item_at(0),
336 item_list_
.item_at(0)->position().CreateBetween(
337 item_list_
.item_at(1)->position()));
338 EXPECT_TRUE(VerifyItemListOrdinals());
339 EXPECT_TRUE(VerifyItemOrder4(0, 1, 2, 3));
341 item_list_
.SetItemPosition(item_list_
.item_at(0),
342 item_list_
.item_at(1)->position().CreateBetween(
343 item_list_
.item_at(2)->position()));
344 EXPECT_TRUE(VerifyItemListOrdinals());
345 EXPECT_TRUE(VerifyItemOrder4(1, 0, 2, 3));
347 item_list_
.SetItemPosition(item_list_
.item_at(1),
348 item_list_
.item_at(2)->position().CreateBetween(
349 item_list_
.item_at(3)->position()));
350 EXPECT_TRUE(VerifyItemListOrdinals());
351 EXPECT_TRUE(VerifyItemOrder4(1, 2, 0, 3));
353 item_list_
.SetItemPosition(item_list_
.item_at(0),
354 item_list_
.item_at(3)->position().CreateAfter());
355 EXPECT_TRUE(VerifyItemListOrdinals());
356 EXPECT_TRUE(VerifyItemOrder4(2, 0, 3, 1));
358 item_list_
.SetItemPosition(item_list_
.item_at(3),
359 item_list_
.item_at(3)->position().CreateAfter());
360 EXPECT_TRUE(VerifyItemListOrdinals());
361 EXPECT_TRUE(VerifyItemOrder4(2, 0, 3, 1));
364 } // namespace app_list