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. 4 5#include "ui/app_list/app_list_item_list.h" 6 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" 13 14namespace app_list { 15 16namespace { 17 18class TestObserver : public AppListItemListObserver { 19 public: 20 TestObserver() : items_added_(0), items_removed_(0), items_moved_(0) {} 21 22 virtual ~TestObserver() { 23 } 24 25 // AppListItemListObserver overriden: 26 virtual void OnListItemAdded(size_t index, AppListItem* item) OVERRIDE { 27 ++items_added_; 28 } 29 30 virtual void OnListItemRemoved(size_t index, AppListItem* item) OVERRIDE { 31 ++items_removed_; 32 } 33 34 virtual void OnListItemMoved(size_t from_index, 35 size_t to_index, 36 AppListItem* item) OVERRIDE { 37 ++items_moved_; 38 } 39 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_; } 43 44 void ResetCounts() { 45 items_added_ = 0; 46 items_removed_ = 0; 47 items_moved_ = 0; 48 } 49 50 private: 51 size_t items_added_; 52 size_t items_removed_; 53 size_t items_moved_; 54 55 DISALLOW_COPY_AND_ASSIGN(TestObserver); 56}; 57 58std::string GetItemId(int id) { 59 return base::StringPrintf("Item %d", id); 60} 61 62} // namespace 63 64class AppListItemListTest : public testing::Test { 65 public: 66 AppListItemListTest() {} 67 virtual ~AppListItemListTest() {} 68 69 // testing::Test overrides: 70 virtual void SetUp() OVERRIDE { 71 item_list_.AddObserver(&observer_); 72 } 73 74 virtual void TearDown() OVERRIDE { 75 item_list_.RemoveObserver(&observer_); 76 } 77 78 protected: 79 AppListItem* FindItem(const std::string& id) { 80 return item_list_.FindItem(id); 81 } 82 83 bool FindItemIndex(const std::string& id, size_t* index) { 84 return item_list_.FindItemIndex(id, index); 85 } 86 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; 91 if (nitems == 0) 92 position = syncer::StringOrdinal::CreateInitialOrdinal(); 93 else 94 position = item_list_.item_at(nitems - 1)->position().CreateAfter(); 95 item->set_position(position); 96 return item.Pass(); 97 } 98 99 AppListItem* CreateAndAddItem(const std::string& name) { 100 scoped_ptr<AppListItem> item(CreateItem(name)); 101 return item_list_.AddItem(item.Pass()); 102 } 103 104 scoped_ptr<AppListItem> RemoveItem(const std::string& id) { 105 return item_list_.RemoveItem(id); 106 } 107 108 scoped_ptr<AppListItem> RemoveItemAt(size_t index) { 109 return item_list_.RemoveItemAt(index); 110 } 111 112 syncer::StringOrdinal CreatePositionBefore( 113 const syncer::StringOrdinal& position) { 114 return item_list_.CreatePositionBefore(position); 115 } 116 117 bool VerifyItemListOrdinals() { 118 bool res = true; 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())); 122 } 123 if (!res) 124 PrintItems(); 125 return res; 126 } 127 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())) 133 return true; 134 PrintItems(); 135 return false; 136 } 137 138 void PrintItems() { 139 VLOG(1) << "ITEMS:"; 140 for (size_t i = 0; i < item_list_.item_count(); ++i) 141 VLOG(1) << " " << item_list_.item_at(i)->ToDebugString(); 142 } 143 144 AppListItemList item_list_; 145 TestObserver observer_; 146 147 private: 148 DISALLOW_COPY_AND_ASSIGN(AppListItemListTest); 149}; 150 151TEST_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()); 161 162 size_t index; 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); 169 170 scoped_ptr<AppListItem> item_3(CreateItem(GetItemId(3))); 171 EXPECT_FALSE(FindItemIndex(item_3->id(), &index)); 172} 173 174TEST_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); 180 size_t index; 181 EXPECT_TRUE(FindItemIndex(item_1->id(), &index)); 182 EXPECT_EQ(index, 1u); 183 EXPECT_TRUE(VerifyItemListOrdinals()); 184 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()); 193} 194 195TEST_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()); 205 206 size_t index; 207 EXPECT_TRUE(FindItemIndex(item_1->id(), &index)); 208 EXPECT_EQ(index, 1u); 209 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()); 216} 217 218TEST_F(AppListItemListTest, MoveItem) { 219 CreateAndAddItem(GetItemId(0)); 220 CreateAndAddItem(GetItemId(1)); 221 CreateAndAddItem(GetItemId(2)); 222 CreateAndAddItem(GetItemId(3)); 223 224 EXPECT_TRUE(VerifyItemOrder4(0, 1, 2, 3)); 225 226 item_list_.MoveItem(0, 0); 227 EXPECT_EQ(0u, observer_.items_moved()); 228 EXPECT_TRUE(VerifyItemOrder4(0, 1, 2, 3)); 229 230 item_list_.MoveItem(0, 1); 231 EXPECT_EQ(1u, observer_.items_moved()); 232 EXPECT_TRUE(VerifyItemListOrdinals()); 233 EXPECT_TRUE(VerifyItemOrder4(1, 0, 2, 3)); 234 235 item_list_.MoveItem(1, 2); 236 EXPECT_EQ(2u, observer_.items_moved()); 237 EXPECT_TRUE(VerifyItemListOrdinals()); 238 EXPECT_TRUE(VerifyItemOrder4(1, 2, 0, 3)); 239 240 item_list_.MoveItem(2, 1); 241 EXPECT_EQ(3u, observer_.items_moved()); 242 EXPECT_TRUE(VerifyItemListOrdinals()); 243 EXPECT_TRUE(VerifyItemOrder4(1, 0, 2, 3)); 244 245 item_list_.MoveItem(3, 0); 246 EXPECT_EQ(4u, observer_.items_moved()); 247 EXPECT_TRUE(VerifyItemListOrdinals()); 248 EXPECT_TRUE(VerifyItemOrder4(3, 1, 0, 2)); 249 250 item_list_.MoveItem(0, 3); 251 EXPECT_EQ(5u, observer_.items_moved()); 252 EXPECT_TRUE(VerifyItemListOrdinals()); 253 EXPECT_TRUE(VerifyItemOrder4(1, 0, 2, 3)); 254} 255 256TEST_F(AppListItemListTest, SamePosition) { 257 CreateAndAddItem(GetItemId(0)); 258 CreateAndAddItem(GetItemId(1)); 259 CreateAndAddItem(GetItemId(2)); 260 CreateAndAddItem(GetItemId(3)); 261 item_list_.SetItemPosition(item_list_.item_at(2), 262 item_list_.item_at(1)->position()); 263 EXPECT_TRUE(VerifyItemOrder4(0, 1, 2, 3)); 264 EXPECT_TRUE(item_list_.item_at(1)->position().Equals( 265 item_list_.item_at(2)->position())); 266 // Moving an item to position 1 should fix the position. 267 observer_.ResetCounts(); 268 item_list_.MoveItem(0, 1); 269 EXPECT_TRUE(VerifyItemOrder4(1, 0, 2, 3)); 270 EXPECT_TRUE(item_list_.item_at(0)->position().LessThan( 271 item_list_.item_at(1)->position())); 272 EXPECT_TRUE(item_list_.item_at(1)->position().LessThan( 273 item_list_.item_at(2)->position())); 274 EXPECT_TRUE(item_list_.item_at(2)->position().LessThan( 275 item_list_.item_at(3)->position())); 276 // One extra move notification for fixed position. 277 EXPECT_EQ(2u, observer_.items_moved()); 278 279 // Restore the original order. 280 item_list_.MoveItem(1, 0); 281 EXPECT_TRUE(VerifyItemOrder4(0, 1, 2, 3)); 282 283 // Set all four items to the same position. 284 item_list_.SetItemPosition(item_list_.item_at(1), 285 item_list_.item_at(0)->position()); 286 item_list_.SetItemPosition(item_list_.item_at(2), 287 item_list_.item_at(0)->position()); 288 item_list_.SetItemPosition(item_list_.item_at(3), 289 item_list_.item_at(0)->position()); 290 // Move should fix the position of the items. 291 observer_.ResetCounts(); 292 item_list_.MoveItem(0, 1); 293 EXPECT_TRUE(VerifyItemOrder4(1, 0, 2, 3)); 294 EXPECT_TRUE(item_list_.item_at(0)->position().LessThan( 295 item_list_.item_at(1)->position())); 296 EXPECT_TRUE(item_list_.item_at(1)->position().LessThan( 297 item_list_.item_at(2)->position())); 298 EXPECT_TRUE(item_list_.item_at(2)->position().LessThan( 299 item_list_.item_at(3)->position())); 300 // One extra move notification for fixed position. 301 EXPECT_EQ(2u, observer_.items_moved()); 302} 303 304TEST_F(AppListItemListTest, CreatePositionBefore) { 305 CreateAndAddItem(GetItemId(0)); 306 syncer::StringOrdinal position0 = item_list_.item_at(0)->position(); 307 syncer::StringOrdinal new_position; 308 new_position = CreatePositionBefore(position0.CreateBefore()); 309 EXPECT_TRUE(new_position.LessThan(position0)); 310 new_position = CreatePositionBefore(position0); 311 EXPECT_TRUE(new_position.LessThan(position0)); 312 new_position = CreatePositionBefore(position0.CreateAfter()); 313 EXPECT_TRUE(new_position.GreaterThan(position0)); 314 315 CreateAndAddItem(GetItemId(1)); 316 syncer::StringOrdinal position1 = item_list_.item_at(1)->position(); 317 EXPECT_TRUE(position1.GreaterThan(position0)); 318 new_position = CreatePositionBefore(position1); 319 EXPECT_TRUE(new_position.GreaterThan(position0)); 320 EXPECT_TRUE(new_position.LessThan(position1)); 321 322 // Invalid ordinal should return a position at the end of the list. 323 new_position = CreatePositionBefore(syncer::StringOrdinal()); 324 EXPECT_TRUE(new_position.GreaterThan(position1)); 325} 326 327TEST_F(AppListItemListTest, SetItemPosition) { 328 CreateAndAddItem(GetItemId(0)); 329 CreateAndAddItem(GetItemId(1)); 330 CreateAndAddItem(GetItemId(2)); 331 CreateAndAddItem(GetItemId(3)); 332 EXPECT_TRUE(VerifyItemOrder4(0, 1, 2, 3)); 333 334 // No change to position. 335 item_list_.SetItemPosition(item_list_.item_at(0), 336 item_list_.item_at(0)->position()); 337 EXPECT_TRUE(VerifyItemListOrdinals()); 338 EXPECT_TRUE(VerifyItemOrder4(0, 1, 2, 3)); 339 // No order change. 340 item_list_.SetItemPosition(item_list_.item_at(0), 341 item_list_.item_at(0)->position().CreateBetween( 342 item_list_.item_at(1)->position())); 343 EXPECT_TRUE(VerifyItemListOrdinals()); 344 EXPECT_TRUE(VerifyItemOrder4(0, 1, 2, 3)); 345 // 0 -> 1 346 item_list_.SetItemPosition(item_list_.item_at(0), 347 item_list_.item_at(1)->position().CreateBetween( 348 item_list_.item_at(2)->position())); 349 EXPECT_TRUE(VerifyItemListOrdinals()); 350 EXPECT_TRUE(VerifyItemOrder4(1, 0, 2, 3)); 351 // 1 -> 2 352 item_list_.SetItemPosition(item_list_.item_at(1), 353 item_list_.item_at(2)->position().CreateBetween( 354 item_list_.item_at(3)->position())); 355 EXPECT_TRUE(VerifyItemListOrdinals()); 356 EXPECT_TRUE(VerifyItemOrder4(1, 2, 0, 3)); 357 // 0 -> last 358 item_list_.SetItemPosition(item_list_.item_at(0), 359 item_list_.item_at(3)->position().CreateAfter()); 360 EXPECT_TRUE(VerifyItemListOrdinals()); 361 EXPECT_TRUE(VerifyItemOrder4(2, 0, 3, 1)); 362 // last -> last 363 item_list_.SetItemPosition(item_list_.item_at(3), 364 item_list_.item_at(3)->position().CreateAfter()); 365 EXPECT_TRUE(VerifyItemListOrdinals()); 366 EXPECT_TRUE(VerifyItemOrder4(2, 0, 3, 1)); 367} 368 369} // namespace app_list 370