5f6233a072b7e111472ceb69be4068fd05faa8b2
[platform/framework/web/crosswalk.git] / src / ui / app_list / app_list_model_unittest.cc
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_model.h"
6
7 #include <map>
8 #include <string>
9
10 #include "base/command_line.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13 #include "ui/app_list/app_list_folder_item.h"
14 #include "ui/app_list/app_list_item.h"
15 #include "ui/app_list/app_list_model_observer.h"
16 #include "ui/app_list/app_list_switches.h"
17 #include "ui/app_list/test/app_list_test_model.h"
18 #include "ui/base/models/list_model_observer.h"
19
20 namespace app_list {
21
22 namespace {
23
24 class TestObserver : public AppListModelObserver {
25  public:
26   TestObserver()
27       : status_changed_count_(0),
28         items_added_(0),
29         items_removed_(0),
30         items_moved_(0) {
31   }
32   virtual ~TestObserver() {
33   }
34
35   // AppListModelObserver
36   virtual void OnAppListModelStatusChanged() OVERRIDE {
37     ++status_changed_count_;
38   }
39
40   virtual void OnAppListItemAdded(AppListItem* item) OVERRIDE {
41     items_added_++;
42   }
43
44   virtual void OnAppListItemWillBeDeleted(AppListItem* item) OVERRIDE {
45     items_removed_++;
46   }
47
48   virtual void OnAppListItemUpdated(AppListItem* item) OVERRIDE {
49     items_moved_++;
50   }
51
52   int status_changed_count() const { return status_changed_count_; }
53   size_t items_added() { return items_added_; }
54   size_t items_removed() { return items_removed_; }
55   size_t items_moved() { return items_moved_; }
56
57   void ResetCounts() {
58     status_changed_count_ = 0;
59     items_added_ = 0;
60     items_removed_ = 0;
61     items_moved_ = 0;
62   }
63
64  private:
65   int status_changed_count_;
66   size_t items_added_;
67   size_t items_removed_;
68   size_t items_moved_;
69
70   DISALLOW_COPY_AND_ASSIGN(TestObserver);
71 };
72
73 }  // namespace
74
75 class AppListModelTest : public testing::Test {
76  public:
77   AppListModelTest() {}
78   virtual ~AppListModelTest() {}
79
80   // testing::Test overrides:
81   virtual void SetUp() OVERRIDE {
82     model_.AddObserver(&observer_);
83   }
84   virtual void TearDown() OVERRIDE {
85     model_.RemoveObserver(&observer_);
86   }
87
88  protected:
89   bool ItemObservedByFolder(AppListFolderItem* folder,
90                             AppListItem* item) {
91     return item->observers_.HasObserver(folder);
92   }
93
94   std::string GetItemListContents(AppListItemList* item_list) {
95     std::string s;
96     for (size_t i = 0; i < item_list->item_count(); ++i) {
97       if (i != 0)
98         s += ",";
99       s += item_list->item_at(i)->id();
100     }
101     return s;
102   }
103
104   std::string GetModelContents() {
105     return GetItemListContents(model_.item_list());
106   }
107
108   test::AppListTestModel model_;
109   TestObserver observer_;
110
111  private:
112   DISALLOW_COPY_AND_ASSIGN(AppListModelTest);
113 };
114
115 TEST_F(AppListModelTest, SetStatus) {
116   EXPECT_EQ(AppListModel::STATUS_NORMAL, model_.status());
117   model_.SetStatus(AppListModel::STATUS_SYNCING);
118   EXPECT_EQ(1, observer_.status_changed_count());
119   EXPECT_EQ(AppListModel::STATUS_SYNCING, model_.status());
120   model_.SetStatus(AppListModel::STATUS_NORMAL);
121   EXPECT_EQ(2, observer_.status_changed_count());
122   // Set the same status, no change is expected.
123   model_.SetStatus(AppListModel::STATUS_NORMAL);
124   EXPECT_EQ(2, observer_.status_changed_count());
125 }
126
127 TEST_F(AppListModelTest, AppsObserver) {
128   const size_t num_apps = 2;
129   model_.PopulateApps(num_apps);
130   EXPECT_EQ(num_apps, observer_.items_added());
131 }
132
133 TEST_F(AppListModelTest, ModelGetItem) {
134   const size_t num_apps = 2;
135   model_.PopulateApps(num_apps);
136   AppListItem* item0 = model_.item_list()->item_at(0);
137   ASSERT_TRUE(item0);
138   EXPECT_EQ(model_.GetItemName(0), item0->id());
139   AppListItem* item1 = model_.item_list()->item_at(1);
140   ASSERT_TRUE(item1);
141   EXPECT_EQ(model_.GetItemName(1), item1->id());
142 }
143
144 TEST_F(AppListModelTest, ModelFindItem) {
145   const size_t num_apps = 2;
146   model_.PopulateApps(num_apps);
147   std::string item_name0 = model_.GetItemName(0);
148   AppListItem* item0 = model_.FindItem(item_name0);
149   ASSERT_TRUE(item0);
150   EXPECT_EQ(item_name0, item0->id());
151   std::string item_name1 = model_.GetItemName(1);
152   AppListItem* item1 = model_.FindItem(item_name1);
153   ASSERT_TRUE(item1);
154   EXPECT_EQ(item_name1, item1->id());
155 }
156
157 TEST_F(AppListModelTest, SetItemPosition) {
158   const size_t num_apps = 2;
159   model_.PopulateApps(num_apps);
160   // Adding another item will add it to the end.
161   model_.CreateAndAddItem("Added Item 1");
162   ASSERT_EQ(num_apps + 1, model_.item_list()->item_count());
163   EXPECT_EQ("Added Item 1", model_.item_list()->item_at(num_apps)->id());
164   // Add an item between items 0 and 1.
165   AppListItem* item0 = model_.item_list()->item_at(0);
166   ASSERT_TRUE(item0);
167   AppListItem* item1 = model_.item_list()->item_at(1);
168   ASSERT_TRUE(item1);
169   AppListItem* item2 = model_.CreateItem("Added Item 2", "Added Item 2");
170   model_.AddItem(item2);
171   EXPECT_EQ("Item 0,Item 1,Added Item 1,Added Item 2", GetModelContents());
172   model_.SetItemPosition(
173       item2, item0->position().CreateBetween(item1->position()));
174   EXPECT_EQ(num_apps + 2, model_.item_list()->item_count());
175   EXPECT_EQ(num_apps + 2, observer_.items_added());
176   EXPECT_EQ("Item 0,Added Item 2,Item 1,Added Item 1", GetModelContents());
177 }
178
179 TEST_F(AppListModelTest, ModelMoveItem) {
180   const size_t num_apps = 3;
181   model_.PopulateApps(num_apps);
182   // Adding another item will add it to the end.
183   model_.CreateAndAddItem("Inserted Item");
184   ASSERT_EQ(num_apps + 1, model_.item_list()->item_count());
185   // Move it to the position 1.
186   model_.item_list()->MoveItem(num_apps, 1);
187   EXPECT_EQ(1u, observer_.items_moved());
188   EXPECT_EQ("Item 0,Inserted Item,Item 1,Item 2", GetModelContents());
189 }
190
191 TEST_F(AppListModelTest, ModelRemoveItem) {
192   const size_t num_apps = 4;
193   model_.PopulateApps(num_apps);
194   // Remove an item in the middle.
195   model_.DeleteItem(model_.GetItemName(1));
196   EXPECT_EQ(num_apps - 1, model_.item_list()->item_count());
197   EXPECT_EQ(1u, observer_.items_removed());
198   EXPECT_EQ("Item 0,Item 2,Item 3", GetModelContents());
199   // Remove the first item in the list.
200   model_.DeleteItem(model_.GetItemName(0));
201   EXPECT_EQ(num_apps - 2, model_.item_list()->item_count());
202   EXPECT_EQ(2u, observer_.items_removed());
203   EXPECT_EQ("Item 2,Item 3", GetModelContents());
204   // Remove the last item in the list.
205   model_.DeleteItem(model_.GetItemName(num_apps - 1));
206   EXPECT_EQ(num_apps - 3, model_.item_list()->item_count());
207   EXPECT_EQ(3u, observer_.items_removed());
208   EXPECT_EQ("Item 2", GetModelContents());
209 }
210
211 TEST_F(AppListModelTest, AppOrder) {
212   const size_t num_apps = 5;
213   model_.PopulateApps(num_apps);
214   // Ensure order is preserved.
215   for (size_t i = 1; i < num_apps; ++i) {
216     EXPECT_TRUE(model_.item_list()->item_at(i)->position().GreaterThan(
217         model_.item_list()->item_at(i - 1)->position()));
218   }
219   // Move an app
220   model_.item_list()->MoveItem(num_apps - 1, 1);
221   // Ensure order is preserved.
222   for (size_t i = 1; i < num_apps; ++i) {
223     EXPECT_TRUE(model_.item_list()->item_at(i)->position().GreaterThan(
224         model_.item_list()->item_at(i - 1)->position()));
225   }
226 }
227
228 class AppListModelFolderTest : public AppListModelTest {
229  public:
230   AppListModelFolderTest() {}
231   virtual ~AppListModelFolderTest() {}
232
233   // testing::Test overrides:
234   virtual void SetUp() OVERRIDE {
235     CommandLine::ForCurrentProcess()->AppendSwitch(switches::kEnableFolderUI);
236     AppListModelTest::SetUp();
237   }
238   virtual void TearDown() OVERRIDE {
239     AppListModelTest::TearDown();
240   }
241
242  private:
243   DISALLOW_COPY_AND_ASSIGN(AppListModelFolderTest);
244 };
245
246 TEST_F(AppListModelFolderTest, FolderItem) {
247   AppListFolderItem* folder = new AppListFolderItem("folder1");
248   const size_t num_folder_apps = 8;
249   const size_t num_observed_apps = 4;
250   model_.AddItem(folder);
251   for (int i = 0; static_cast<size_t>(i) < num_folder_apps; ++i) {
252     std::string name = model_.GetItemName(i);
253     model_.AddItemToFolder(model_.CreateItem(name, name), folder->id());
254   }
255   ASSERT_EQ(num_folder_apps, folder->item_list()->item_count());
256   // Check that items 0 and 3 are observed.
257   EXPECT_TRUE(ItemObservedByFolder(
258       folder, folder->item_list()->item_at(0)));
259   EXPECT_TRUE(ItemObservedByFolder(
260       folder, folder->item_list()->item_at(num_observed_apps - 1)));
261   // Check that item 4 is not observed.
262   EXPECT_FALSE(ItemObservedByFolder(
263       folder, folder->item_list()->item_at(num_observed_apps)));
264   folder->item_list()->MoveItem(num_observed_apps, 0);
265   // Confirm that everything was moved where expected.
266   EXPECT_EQ(model_.GetItemName(num_observed_apps),
267             folder->item_list()->item_at(0)->id());
268   EXPECT_EQ(model_.GetItemName(0),
269             folder->item_list()->item_at(1)->id());
270   EXPECT_EQ(model_.GetItemName(num_observed_apps - 1),
271             folder->item_list()->item_at(num_observed_apps)->id());
272   // Check that items 0 and 3 are observed.
273   EXPECT_TRUE(ItemObservedByFolder(
274       folder, folder->item_list()->item_at(0)));
275   EXPECT_TRUE(ItemObservedByFolder(
276       folder, folder->item_list()->item_at(num_observed_apps - 1)));
277   // Check that item 4 is not observed.
278   EXPECT_FALSE(ItemObservedByFolder(
279       folder, folder->item_list()->item_at(num_observed_apps)));
280 }
281
282 TEST_F(AppListModelFolderTest, MergeItems) {
283   model_.PopulateApps(3);
284   ASSERT_EQ(3u, model_.item_list()->item_count());
285   AppListItem* item0 = model_.item_list()->item_at(0);
286   AppListItem* item1 = model_.item_list()->item_at(1);
287   AppListItem* item2 = model_.item_list()->item_at(2);
288
289   // Merge two items.
290   std::string folder1_id = model_.MergeItems(item0->id(), item1->id());
291   ASSERT_EQ(2u, model_.item_list()->item_count());  // Folder + 1 item
292   AppListFolderItem* folder1_item = model_.FindFolderItem(folder1_id);
293   ASSERT_TRUE(folder1_item);
294   EXPECT_EQ("Item 0,Item 1", GetItemListContents(folder1_item->item_list()));
295
296   // Merge an item from the new folder into the third item.
297   std::string folder2_id = model_.MergeItems(item2->id(), item1->id());
298   ASSERT_EQ(2u, model_.item_list()->item_count());  // 2 folders
299   AppListFolderItem* folder2_item = model_.FindFolderItem(folder2_id);
300   EXPECT_EQ("Item 0", GetItemListContents(folder1_item->item_list()));
301   EXPECT_EQ("Item 2,Item 1", GetItemListContents(folder2_item->item_list()));
302
303   // Merge the remaining item to the new folder, ensure it is added to the end.
304   std::string folder_id = model_.MergeItems(folder2_id, item0->id());
305   EXPECT_EQ(folder2_id, folder_id);
306   EXPECT_EQ("Item 2,Item 1,Item 0",
307             GetItemListContents(folder2_item->item_list()));
308
309   // The empty folder should be deleted.
310   folder1_item = model_.FindFolderItem(folder1_id);
311   EXPECT_FALSE(folder1_item);
312 }
313
314 TEST_F(AppListModelFolderTest, AddItemToFolder) {
315   AppListFolderItem* folder = new AppListFolderItem("folder1");
316   model_.AddItem(folder);
317   AppListItem* item0 = new AppListItem("Item 0");
318   model_.AddItemToFolder(item0, folder->id());
319   ASSERT_EQ(1u, model_.item_list()->item_count());
320   AppListFolderItem* folder_item = model_.FindFolderItem(folder->id());
321   ASSERT_TRUE(folder_item);
322   ASSERT_EQ(1u, folder_item->item_list()->item_count());
323   EXPECT_EQ(item0, folder_item->item_list()->item_at(0));
324   EXPECT_EQ(folder->id(), item0->folder_id());
325 }
326
327 TEST_F(AppListModelFolderTest, MoveItemToFolder) {
328   AppListFolderItem* folder = new AppListFolderItem("folder1");
329   model_.AddItem(folder);
330   AppListItem* item0 = new AppListItem("Item 0");
331   AppListItem* item1 = new AppListItem("Item 1");
332   model_.AddItem(item0);
333   model_.AddItem(item1);
334   ASSERT_EQ(3u, model_.item_list()->item_count());
335   // Move item0 and item1 to folder.
336   std::string folder_id = folder->id();
337   model_.MoveItemToFolder(item0, folder_id);
338   model_.MoveItemToFolder(item1, folder_id);
339   AppListFolderItem* folder_item = model_.FindFolderItem(folder_id);
340   ASSERT_TRUE(folder_item);
341   EXPECT_EQ(folder_id, item0->folder_id());
342   EXPECT_EQ(folder_id, item1->folder_id());
343   EXPECT_EQ("Item 0,Item 1", GetItemListContents(folder_item->item_list()));
344   // Move item0 out of folder.
345   model_.MoveItemToFolder(item0, "");
346   EXPECT_EQ("", item0->folder_id());
347   folder_item = model_.FindFolderItem(folder_id);
348   ASSERT_TRUE(folder_item);
349   // Move item1 out of folder, folder should be deleted.
350   model_.MoveItemToFolder(item1, "");
351   EXPECT_EQ("", item1->folder_id());
352   folder_item = model_.FindFolderItem(folder_id);
353   EXPECT_FALSE(folder_item);
354 }
355
356 TEST_F(AppListModelFolderTest, MoveItemToFolderAt) {
357   model_.AddItem(new AppListItem("Item 0"));
358   model_.AddItem(new AppListItem("Item 1"));
359   AppListFolderItem* folder1 = static_cast<AppListFolderItem*>(
360       model_.AddItem(new AppListFolderItem("folder1")));
361   model_.AddItem(new AppListItem("Item 2"));
362   model_.AddItem(new AppListItem("Item 3"));
363   ASSERT_EQ(5u, model_.item_list()->item_count());
364   EXPECT_EQ("Item 0,Item 1,folder1,Item 2,Item 3", GetModelContents());
365   // Move Item 1 to folder1, then Item 2 before Item 1.
366   model_.MoveItemToFolderAt(
367       model_.item_list()->item_at(1), folder1->id(), syncer::StringOrdinal());
368   EXPECT_EQ("Item 0,folder1,Item 2,Item 3", GetModelContents());
369   model_.MoveItemToFolderAt(
370       model_.item_list()->item_at(2), folder1->id(),
371       folder1->item_list()->item_at(0)->position());
372   EXPECT_EQ("Item 2,Item 1", GetItemListContents(folder1->item_list()));
373   EXPECT_EQ("Item 0,folder1,Item 3", GetModelContents());
374   // Move Item 2 out of folder to before folder.
375   model_.MoveItemToFolderAt(
376       folder1->item_list()->item_at(0), "", folder1->position());
377   EXPECT_EQ("Item 0,Item 2,folder1,Item 3", GetModelContents());
378   // Move remaining folder item, (Item 1) out of folder to folder position.
379   ASSERT_EQ(1u, folder1->item_list()->item_count());
380   model_.MoveItemToFolderAt(
381       folder1->item_list()->item_at(0), "", folder1->position());
382   EXPECT_EQ("Item 0,Item 2,Item 1,Item 3", GetModelContents());
383 }
384
385 TEST_F(AppListModelFolderTest, MoveItemFromFolderToFolder) {
386   AppListFolderItem* folder0 = new AppListFolderItem("folder0");
387   AppListFolderItem* folder1 = new AppListFolderItem("folder1");
388   model_.AddItem(folder0);
389   model_.AddItem(folder1);
390   EXPECT_EQ("folder0,folder1", GetModelContents());
391   AppListItem* item0 = new AppListItem("Item 0");
392   AppListItem* item1 = new AppListItem("Item 1");
393   model_.AddItemToFolder(item0, folder0->id());
394   model_.AddItemToFolder(item1, folder0->id());
395   EXPECT_EQ(folder0->id(), item0->folder_id());
396   EXPECT_EQ(folder0->id(), item1->folder_id());
397   EXPECT_EQ("Item 0,Item 1", GetItemListContents(folder0->item_list()));
398
399   // Move item0 from folder0 to folder1.
400   model_.MoveItemToFolder(item0, folder1->id());
401   ASSERT_EQ(1u, folder0->item_list()->item_count());
402   ASSERT_EQ(1u, folder1->item_list()->item_count());
403   EXPECT_EQ(folder1->id(), item0->folder_id());
404   EXPECT_EQ("Item 1", GetItemListContents(folder0->item_list()));
405   EXPECT_EQ("Item 0", GetItemListContents(folder1->item_list()));
406
407   // Move item1 from folder0 to folder1. folder0 should get deleted.
408   model_.MoveItemToFolder(item1, folder1->id());
409   ASSERT_EQ(1u, model_.item_list()->item_count());
410   ASSERT_EQ(2u, folder1->item_list()->item_count());
411   EXPECT_EQ(folder1->id(), item1->folder_id());
412   EXPECT_EQ("Item 0,Item 1", GetItemListContents(folder1->item_list()));
413
414   // Move item1 to a non-existant folder2 which should get created.
415   model_.MoveItemToFolder(item1, "folder2");
416   ASSERT_EQ(2u, model_.item_list()->item_count());
417   ASSERT_EQ(1u, folder1->item_list()->item_count());
418   EXPECT_EQ("folder2", item1->folder_id());
419   AppListFolderItem* folder2 = model_.FindFolderItem("folder2");
420   ASSERT_TRUE(folder2);
421 }
422
423 TEST_F(AppListModelFolderTest, FindItemInFolder) {
424   AppListFolderItem* folder = new AppListFolderItem("folder1");
425   EXPECT_TRUE(folder);
426   model_.AddItem(folder);
427   std::string folder_id = folder->id();
428   AppListItem* item0 = new AppListItem("Item 0");
429   model_.AddItemToFolder(item0, folder_id);
430   AppListItem* found_item = model_.FindItem(item0->id());
431   ASSERT_EQ(item0, found_item);
432   EXPECT_EQ(folder_id, found_item->folder_id());
433 }
434
435 }  // namespace app_list