[go: nahoru, domu]

blob: 94e38e50e4e5d920c67b86c7474f15677cbf2df6 [file] [log] [blame]
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_view_controller.h"
#import "base/apple/foundation_util.h"
#import "base/numerics/safe_conversions.h"
#import "base/test/ios/wait_util.h"
#import "ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_view_controller+private.h"
#import "ios/chrome/browser/ui/tab_switcher/tab_switcher_item.h"
#import "ios/chrome/test/ios_chrome_scoped_testing_local_state.h"
#import "ios/chrome/test/root_view_controller_test.h"
#import "testing/gtest/include/gtest/gtest.h"
#import "testing/gtest_mac.h"
// Fake object that conforms to GridViewControllerDelegate.
@interface FakeGridViewControllerDelegate
: NSObject <GridViewControllerDelegate>
@property(nonatomic, assign) NSUInteger itemCount;
@end
@implementation FakeGridViewControllerDelegate
@synthesize itemCount = _itemCount;
- (void)gridViewController:(GridViewController*)gridViewController
contentNeedsAuthenticationChanged:(BOOL)needsAuth {
}
- (void)gridViewController:(GridViewController*)gridViewController
didChangeItemCount:(NSUInteger)count {
self.itemCount = count;
}
- (void)gridViewController:(GridViewController*)gridViewController
didSelectItemWithID:(NSString*)itemID {
// No-op for unittests. This is only called when a user taps on a cell, not
// generically when selectedIndex is updated.
}
- (void)gridViewController:(GridViewController*)gridViewController
didMoveItemWithID:(NSString*)itemID
toIndex:(NSUInteger)destinationIndex {
// No-op for unittests. This is only called when a user interactively moves
// an item, not generically when items are moved in the data source.
}
- (void)gridViewController:(GridViewController*)gridViewController
didCloseItemWithID:(NSString*)itemID {
// No-op for unittests. This is only called when a user taps to close a cell,
// not generically when items are removed from the data source.
}
- (void)gridViewController:(GridViewController*)gridViewController
didRemoveItemWIthID:(NSString*)itemID {
// No-op for unittests. This is only called when an item has been removed.
}
- (void)didTapPlusSignInGridViewController:
(GridViewController*)gridViewController {
// No-op for unittests. This is only called when a user taps on a
// plus sign cell, not generically when items are added to the data source.
}
- (void)didChangeLastItemVisibilityInGridViewController:
(GridViewController*)gridViewController {
// No-op for unittests.
}
- (void)gridViewControllerWillBeginDragging:
(GridViewController*)gridViewController {
// No-op for unittests.
}
- (void)gridViewControllerDragSessionWillBegin:
(GridViewController*)gridViewController {
// No-op for unittests.
}
- (void)gridViewControllerDragSessionDidEnd:
(GridViewController*)gridViewController {
// No-op for unittests.
}
- (void)gridViewControllerScrollViewDidScroll:
(GridViewController*)gridViewController {
// No-op for unittests.
}
- (void)gridViewControllerDropAnimationWillBegin:
(GridViewController*)gridViewController {
// No-op for unittests.
}
- (void)gridViewControllerDropAnimationDidEnd:
(GridViewController*)gridViewController {
// No-op for unittests.
}
- (void)didTapInactiveTabsButtonInGridViewController:
(GridViewController*)gridViewController {
// No-op for unittests.
}
- (void)didTapInactiveTabsSettingsLinkInGridViewController:
(GridViewController*)gridViewController {
// No-op for unittests.
}
@end
class GridViewControllerTest : public RootViewControllerTest {
public:
GridViewControllerTest() {
view_controller_ = [[GridViewController alloc] init];
// Load the view and notify its content will appear. This sets the data
// source and loads the initial snapshot.
[view_controller_ loadView];
[view_controller_ contentWillAppearAnimated:NO];
NSArray* items = @[
[[TabSwitcherItem alloc] initWithIdentifier:@"A"],
[[TabSwitcherItem alloc] initWithIdentifier:@"B"]
];
[view_controller_ populateItems:items selectedItemID:@"A"];
delegate_ = [[FakeGridViewControllerDelegate alloc] init];
delegate_.itemCount = 2;
view_controller_.delegate = delegate_;
}
protected:
IOSChromeScopedTestingLocalState local_state_;
GridViewController* view_controller_;
FakeGridViewControllerDelegate* delegate_;
};
// Tests that items are initialized and delegate is updated with a new
// itemCount.
TEST_F(GridViewControllerTest, InitializeItems) {
// Previously: The grid had 2 items and selectedIndex was 0. The delegate had
// an itemCount of 2.
TabSwitcherItem* item =
[[TabSwitcherItem alloc] initWithIdentifier:@"NEW-ITEM"];
[view_controller_ populateItems:@[ item ] selectedItemID:@"NEW-ITEM"];
EXPECT_NSEQ(@"NEW-ITEM", view_controller_.items[0].identifier);
EXPECT_EQ(1U, view_controller_.items.count);
EXPECT_EQ(0U, view_controller_.selectedIndex);
EXPECT_EQ(1U, delegate_.itemCount);
}
// Tests that an item is inserted and delegate is updated with a new itemCount.
TEST_F(GridViewControllerTest, InsertItem) {
// Previously: The grid had 2 items and selectedIndex was 0. The delegate had
// an itemCount of 2.
[view_controller_
insertItem:[[TabSwitcherItem alloc] initWithIdentifier:@"NEW-ITEM"]
atIndex:2
selectedItemID:@"NEW-ITEM"];
EXPECT_EQ(3U, view_controller_.items.count);
EXPECT_EQ(2U, view_controller_.selectedIndex);
EXPECT_EQ(3U, delegate_.itemCount);
}
// Tests that an item is removed and delegate is updated with a new itemCount.
TEST_F(GridViewControllerTest, RemoveItem) {
// Previously: The grid had 2 items and selectedIndex was 0. The delegate had
// an itemCount of 2.
[view_controller_ removeItemWithID:@"A" selectedItemID:@"B"];
EXPECT_EQ(1U, view_controller_.items.count);
EXPECT_EQ(0U, view_controller_.selectedIndex);
EXPECT_EQ(1U, delegate_.itemCount);
}
// Tests that an item is selected.
TEST_F(GridViewControllerTest, SelectItem) {
// Previously: The grid had 2 items and selectedIndex was 0. The delegate had
// an itemCount of 2.
[view_controller_ selectItemWithID:@"B"];
EXPECT_EQ(1U, view_controller_.selectedIndex);
EXPECT_EQ(2U, delegate_.itemCount);
}
// Tests that when a nonexistent item is selected, the selected item index is
// NSNotFound
TEST_F(GridViewControllerTest, SelectNonexistentItem) {
// Previously: The grid had 2 items and selectedIndex was 0. The delegate had
// an itemCount of 2.
[view_controller_ selectItemWithID:@"NOT-A-KNOWN-ITEM"];
EXPECT_EQ(base::checked_cast<NSUInteger>(NSNotFound),
view_controller_.selectedIndex);
EXPECT_EQ(2U, delegate_.itemCount);
}
// Tests that an item is replaced with a new identifier.
TEST_F(GridViewControllerTest, ReplaceItem) {
// Previously: The grid had 2 items and selectedIndex was 0. The delegate had
// an itemCount of 2.
TabSwitcherItem* item =
[[TabSwitcherItem alloc] initWithIdentifier:@"NEW-ITEM"];
[view_controller_ replaceItemID:@"A" withItem:item];
EXPECT_NSEQ(@"NEW-ITEM", view_controller_.items[0].identifier);
EXPECT_EQ(2U, delegate_.itemCount);
}
// Tests that an item is replaced with same identifier.
TEST_F(GridViewControllerTest, ReplaceItemSameIdentifier) {
// Previously: The grid had 2 items and selectedIndex was 0. The delegate had
// an itemCount of 2.
TabSwitcherItem* item = [[TabSwitcherItem alloc] initWithIdentifier:@"A"];
item.title = @"NEW-ITEM-TITLE";
[view_controller_ replaceItemID:@"A" withItem:item];
EXPECT_NSEQ(@"A", view_controller_.items[0].identifier);
EXPECT_NSEQ(@"NEW-ITEM-TITLE", view_controller_.items[0].title);
EXPECT_EQ(2U, delegate_.itemCount);
}
// Tests that an item is not replaced if it doesn't exist.
TEST_F(GridViewControllerTest, ReplaceItemNotFound) {
// Previously: The grid had 2 items and selectedIndex was 0. The delegate had
// an itemCount of 2.
TabSwitcherItem* item =
[[TabSwitcherItem alloc] initWithIdentifier:@"NOT-FOUND"];
[view_controller_ replaceItemID:@"NOT-FOUND" withItem:item];
EXPECT_NSNE(@"NOT-FOUND", view_controller_.items[0].identifier);
EXPECT_NSNE(@"NOT-FOUND", view_controller_.items[1].identifier);
EXPECT_EQ(2U, delegate_.itemCount);
}
// Tests that the selected item is moved.
TEST_F(GridViewControllerTest, MoveSelectedItem) {
// Previously: The grid had 2 items and selectedIndex was 0. The delegate had
// an itemCount of 2.
[view_controller_ moveItemWithID:@"A" toIndex:1];
EXPECT_NSEQ(@"A", view_controller_.items[1].identifier);
EXPECT_EQ(1U, view_controller_.selectedIndex);
EXPECT_EQ(2U, delegate_.itemCount);
}
// Tests that a non-selected item is moved.
TEST_F(GridViewControllerTest, MoveUnselectedItem) {
// Previously: The grid had 2 items and selectedIndex was 0. The delegate had
// an itemCount of 2.
[view_controller_ moveItemWithID:@"B" toIndex:0];
EXPECT_NSEQ(@"A", view_controller_.items[1].identifier);
EXPECT_EQ(1U, view_controller_.selectedIndex);
EXPECT_EQ(2U, delegate_.itemCount);
}
// Tests that `-replaceItemID:withItem:` does not crash when updating an item
// that is scrolled offscreen.
TEST_F(GridViewControllerTest, ReplaceScrolledOffScreenCell) {
// This test requires that the collection view be placed on the screen.
SetRootViewController(view_controller_);
EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout(
base::test::ios::kWaitForUIElementTimeout, ^bool {
return view_controller_.collectionView.visibleCells.count > 0;
}));
NSArray* items = view_controller_.items;
// Keep adding items until we get an item that is offscreen. Since device
// sizes may vary, this is better than creating a fixed number of items that
// we think will overflow to offscreen items.
NSUInteger visibleCellsCount =
view_controller_.collectionView.visibleCells.count;
while (visibleCellsCount >= items.count) {
NSString* uniqueID =
[NSString stringWithFormat:@"%d", base::checked_cast<int>(items.count)];
TabSwitcherItem* item =
[[TabSwitcherItem alloc] initWithIdentifier:uniqueID];
[view_controller_ insertItem:item atIndex:0 selectedItemID:@"A"];
// Spin the runloop to make sure that the visible cells are updated.
base::test::ios::SpinRunLoopWithMinDelay(base::Milliseconds(1));
visibleCellsCount = view_controller_.collectionView.visibleCells.count;
}
// The last item ("B") is scrolled off screen.
TabSwitcherItem* item =
[[TabSwitcherItem alloc] initWithIdentifier:@"NEW-ITEM"];
// Do not crash due to cell being nil.
[view_controller_ replaceItemID:@"B" withItem:item];
}