// Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "ui/app_list/app_list_model.h" #include #include #include "base/strings/utf_string_conversions.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/app_list/app_list_folder_item.h" #include "ui/app_list/app_list_item_model.h" #include "ui/app_list/app_list_model_observer.h" #include "ui/app_list/test/app_list_test_model.h" #include "ui/base/models/list_model_observer.h" namespace app_list { namespace { class TestObserver : public AppListModelObserver, public AppListItemListObserver { public: TestObserver() : status_changed_count_(0), items_added_(0), items_removed_(0), items_moved_(0) { } virtual ~TestObserver() { } // AppListModelObserver virtual void OnAppListModelStatusChanged() OVERRIDE { ++status_changed_count_; } // AppListItemListObserver virtual void OnListItemAdded(size_t index, AppListItemModel* item) OVERRIDE { items_added_++; } virtual void OnListItemRemoved(size_t index, AppListItemModel* item) OVERRIDE { items_removed_++; } virtual void OnListItemMoved(size_t from_index, size_t to_index, AppListItemModel* item) OVERRIDE { items_moved_++; } int status_changed_count() const { return status_changed_count_; } int signin_changed_count() const { return signin_changed_count_; } size_t items_added() { return items_added_; } size_t items_removed() { return items_removed_; } size_t items_moved() { return items_moved_; } void ResetCounts() { status_changed_count_ = 0; signin_changed_count_ = 0; items_added_ = 0; items_removed_ = 0; items_moved_ = 0; } private: int status_changed_count_; int signin_changed_count_; size_t items_added_; size_t items_removed_; size_t items_moved_; DISALLOW_COPY_AND_ASSIGN(TestObserver); }; } // namespace class AppListModelTest : public testing::Test { public: AppListModelTest() {} virtual ~AppListModelTest() {} // testing::Test overrides: virtual void SetUp() OVERRIDE { model_.AddObserver(&observer_); model_.item_list()->AddObserver(&observer_); } virtual void TearDown() OVERRIDE { model_.RemoveObserver(&observer_); model_.item_list()->RemoveObserver(&observer_); } protected: bool ItemObservedByFolder(AppListFolderItem* folder, AppListItemModel* item) { return item->observers_.HasObserver(folder); } test::AppListTestModel model_; TestObserver observer_; private: DISALLOW_COPY_AND_ASSIGN(AppListModelTest); }; TEST_F(AppListModelTest, SetStatus) { EXPECT_EQ(AppListModel::STATUS_NORMAL, model_.status()); model_.SetStatus(AppListModel::STATUS_SYNCING); EXPECT_EQ(1, observer_.status_changed_count()); EXPECT_EQ(AppListModel::STATUS_SYNCING, model_.status()); model_.SetStatus(AppListModel::STATUS_NORMAL); EXPECT_EQ(2, observer_.status_changed_count()); // Set the same status, no change is expected. model_.SetStatus(AppListModel::STATUS_NORMAL); EXPECT_EQ(2, observer_.status_changed_count()); } TEST_F(AppListModelTest, AppsObserver) { const size_t num_apps = 2; model_.PopulateApps(num_apps); EXPECT_EQ(num_apps, observer_.items_added()); } TEST_F(AppListModelTest, ModelGetItem) { const size_t num_apps = 2; model_.PopulateApps(num_apps); AppListItemModel* item0 = model_.item_list()->item_at(0); ASSERT_TRUE(item0); EXPECT_EQ(model_.GetItemName(0), item0->id()); AppListItemModel* item1 = model_.item_list()->item_at(1); ASSERT_TRUE(item1); EXPECT_EQ(model_.GetItemName(1), item1->id()); } TEST_F(AppListModelTest, ModelFindItem) { const size_t num_apps = 2; model_.PopulateApps(num_apps); std::string item_name0 = model_.GetItemName(0); AppListItemModel* item0 = model_.item_list()->FindItem(item_name0); ASSERT_TRUE(item0); EXPECT_EQ(item_name0, item0->id()); std::string item_name1 = model_.GetItemName(1); AppListItemModel* item1 = model_.item_list()->FindItem(item_name1); ASSERT_TRUE(item1); EXPECT_EQ(item_name1, item1->id()); } TEST_F(AppListModelTest, ModelAddItem) { const size_t num_apps = 2; model_.PopulateApps(num_apps); // Adding another item will add it to the end. model_.CreateAndAddItem("Added Item 1"); ASSERT_EQ(num_apps + 1, model_.item_list()->item_count()); EXPECT_EQ("Added Item 1", model_.item_list()->item_at(num_apps)->id()); // Add an item between items 0 and 1. AppListItemModel* item0 = model_.item_list()->item_at(0); ASSERT_TRUE(item0); AppListItemModel* item1 = model_.item_list()->item_at(1); ASSERT_TRUE(item1); AppListItemModel* item2 = model_.CreateItem("Added Item 2", "Added Item 2"); model_.item_list()->AddItem(item2); model_.item_list()->SetItemPosition( item2, item0->position().CreateBetween(item1->position())); EXPECT_EQ(num_apps + 2, model_.item_list()->item_count()); EXPECT_EQ("Added Item 2", model_.item_list()->item_at(1)->id()); } TEST_F(AppListModelTest, ModelMoveItem) { const size_t num_apps = 3; model_.PopulateApps(num_apps); // Adding another item will add it to the end. model_.CreateAndAddItem("Inserted Item"); ASSERT_EQ(num_apps + 1, model_.item_list()->item_count()); // Move it to the position 1. model_.item_list()->MoveItem(num_apps, 1); AppListItemModel* item = model_.item_list()->item_at(1); ASSERT_TRUE(item); EXPECT_EQ("Inserted Item", item->id()); } TEST_F(AppListModelTest, ModelRemoveItem) { const size_t num_apps = 4; model_.PopulateApps(num_apps); // Remove an item in the middle. model_.item_list()->DeleteItem(model_.GetItemName(1)); EXPECT_EQ(num_apps - 1, model_.item_list()->item_count()); EXPECT_EQ(1u, observer_.items_removed()); // Remove the first item in the list. model_.item_list()->DeleteItem(model_.GetItemName(0)); EXPECT_EQ(num_apps - 2, model_.item_list()->item_count()); EXPECT_EQ(2u, observer_.items_removed()); // Remove the last item in the list. model_.item_list()->DeleteItem(model_.GetItemName(num_apps - 1)); EXPECT_EQ(num_apps - 3, model_.item_list()->item_count()); EXPECT_EQ(3u, observer_.items_removed()); // Ensure that the first item is the expected one AppListItemModel* item0 = model_.item_list()->item_at(0); ASSERT_TRUE(item0); EXPECT_EQ(model_.GetItemName(2), item0->id()); } TEST_F(AppListModelTest, ModelRemoveItemByType) { const size_t num_apps = 4; model_.PopulateApps(num_apps); model_.item_list()->AddItem(new AppListFolderItem("folder1")); model_.item_list()->AddItem(new AppListFolderItem("folder2")); model_.item_list()->DeleteItemsByType(test::AppListTestModel::kAppType); EXPECT_EQ(num_apps, observer_.items_removed()); EXPECT_EQ(2u, model_.item_list()->item_count()); model_.item_list()->DeleteItemsByType(AppListFolderItem::kAppType); EXPECT_EQ(num_apps + 2, observer_.items_removed()); EXPECT_EQ(0u, model_.item_list()->item_count()); // Delete all items observer_.ResetCounts(); model_.PopulateApps(num_apps); model_.item_list()->AddItem(new AppListFolderItem("folder1")); model_.item_list()->AddItem(new AppListFolderItem("folder2")); model_.item_list()->DeleteItemsByType(NULL /* all items */); EXPECT_EQ(num_apps + 2, observer_.items_removed()); EXPECT_EQ(0u, model_.item_list()->item_count()); } TEST_F(AppListModelTest, AppOrder) { const size_t num_apps = 5; model_.PopulateApps(num_apps); // Ensure order is preserved. for (size_t i = 1; i < num_apps; ++i) { EXPECT_TRUE(model_.item_list()->item_at(i)->position().GreaterThan( model_.item_list()->item_at(i - 1)->position())); } // Move an app model_.item_list()->MoveItem(num_apps - 1, 1); // Ensure order is preserved. for (size_t i = 1; i < num_apps; ++i) { EXPECT_TRUE(model_.item_list()->item_at(i)->position().GreaterThan( model_.item_list()->item_at(i - 1)->position())); } } TEST_F(AppListModelTest, FolderItem) { scoped_ptr folder(new AppListFolderItem("folder1")); const size_t num_folder_apps = 8; const size_t num_observed_apps = 4; for (int i = 0; static_cast(i) < num_folder_apps; ++i) { std::string name = model_.GetItemName(i); folder->item_list()->AddItem(model_.CreateItem(name, name)); } // Check that items 0 and 3 are observed. EXPECT_TRUE(ItemObservedByFolder( folder.get(), folder->item_list()->item_at(0))); EXPECT_TRUE(ItemObservedByFolder( folder.get(), folder->item_list()->item_at(num_observed_apps - 1))); // Check that item 4 is not observed. EXPECT_FALSE(ItemObservedByFolder( folder.get(), folder->item_list()->item_at(num_observed_apps))); folder->item_list()->MoveItem(num_observed_apps, 0); // Confirm that everything was moved where expected. EXPECT_EQ(model_.GetItemName(num_observed_apps), folder->item_list()->item_at(0)->id()); EXPECT_EQ(model_.GetItemName(0), folder->item_list()->item_at(1)->id()); EXPECT_EQ(model_.GetItemName(num_observed_apps - 1), folder->item_list()->item_at(num_observed_apps)->id()); // Check that items 0 and 3 are observed. EXPECT_TRUE(ItemObservedByFolder( folder.get(), folder->item_list()->item_at(0))); EXPECT_TRUE(ItemObservedByFolder( folder.get(), folder->item_list()->item_at(num_observed_apps - 1))); // Check that item 4 is not observed. EXPECT_FALSE(ItemObservedByFolder( folder.get(), folder->item_list()->item_at(num_observed_apps))); } } // namespace app_list