blob: 6fbf912726fb8cfddc535f603b0505654a21922c [file] [log] [blame]
// 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 <map>
#include <string>
#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),
signin_changed_count_(0),
items_added_(0),
items_removed_(0),
items_moved_(0) {
}
virtual ~TestObserver() {
}
// AppListModelObserver
virtual void OnAppListModelStatusChanged() OVERRIDE {
++status_changed_count_;
}
virtual void OnAppListModelSigninStatusChanged() OVERRIDE {
++signin_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, SetSignedIn) {
EXPECT_TRUE(model_.signed_in());
model_.SetSignedIn(false);
EXPECT_EQ(1, observer_.signin_changed_count());
EXPECT_FALSE(model_.signed_in());
model_.SetSignedIn(true);
EXPECT_EQ(2, observer_.signin_changed_count());
EXPECT_TRUE(model_.signed_in());
// Set the same signin state, no change is expected.
model_.SetSignedIn(true);
EXPECT_EQ(2, observer_.signin_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.
app_list::AppListItemModel* item0 = model_.item_list()->item_at(0);
ASSERT_TRUE(item0);
app_list::AppListItemModel* item1 = model_.item_list()->item_at(1);
ASSERT_TRUE(item1);
app_list::AppListItemModel* item2 =
model_.CreateItem("Added Item 2", "Added Item 2");
item2->set_position(item0->position().CreateBetween(item1->position()));
model_.item_list()->AddItem(item2);
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<AppListFolderItem> folder(new AppListFolderItem("folder1"));
const size_t num_folder_apps = 8;
const size_t num_observed_apps = 4;
for (int i = 0; static_cast<size_t>(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