mirror of
https://github.com/Instagram/IGListKit
synced 2026-05-22 00:38:42 +00:00
Summary: Relicensing IGListKit under MIT Reviewed By: calimarkus Differential Revision: D7764125 fbshipit-source-id: 6c773195ef3184202725fe7f08de754f979cb83f
1728 lines
90 KiB
Objective-C
1728 lines
90 KiB
Objective-C
/**
|
|
* Copyright (c) 2016-present, Facebook, Inc.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*/
|
|
|
|
#import <objc/runtime.h>
|
|
|
|
#import <XCTest/XCTest.h>
|
|
#import <OCMock/OCMock.h>
|
|
|
|
#import <IGListKit/IGListExperiments.h>
|
|
#import <IGListKit/IGListKit.h>
|
|
|
|
#import "IGListAdapterInternal.h"
|
|
#import "IGListTestAdapterDataSource.h"
|
|
#import "IGListTestAdapterReorderingDataSource.h"
|
|
#import "IGListTestAdapterHorizontalDataSource.h"
|
|
#import "IGListTestOffsettingLayout.h"
|
|
#import "IGListTestSection.h"
|
|
#import "IGTestReorderableSection.h"
|
|
#import "IGTestSupplementarySource.h"
|
|
#import "IGTestNibSupplementaryView.h"
|
|
#import "IGListTestCase.h"
|
|
|
|
#import "UICollectionViewLayout+InteractiveReordering.h"
|
|
|
|
@interface IGListAdapterTests : IGListTestCase
|
|
@end
|
|
|
|
@implementation IGListAdapterTests
|
|
|
|
- (void)setUp {
|
|
self.dataSource = [IGListTestAdapterDataSource new];
|
|
self.updater = [IGListReloadDataUpdater new];
|
|
|
|
[super setUp];
|
|
|
|
// test case doesn't use -setupWithObjects for more control over update events
|
|
self.adapter.collectionView = self.collectionView;
|
|
self.adapter.dataSource = self.dataSource;
|
|
}
|
|
|
|
- (void)test_whenAdapterNotUpdated_withDataSourceUpdated_thatAdapterHasNoSectionControllers {
|
|
self.dataSource.objects = @[@0, @1, @2];
|
|
XCTAssertNil([self.adapter sectionControllerForObject:@0]);
|
|
XCTAssertNil([self.adapter sectionControllerForObject:@1]);
|
|
XCTAssertNil([self.adapter sectionControllerForObject:@2]);
|
|
}
|
|
|
|
- (void)test_whenAdapterUpdated_thatAdapterHasSectionControllers {
|
|
self.dataSource.objects = @[@0, @1, @2];
|
|
[self.adapter performUpdatesAnimated:YES completion:nil];
|
|
XCTAssertNotNil([self.adapter sectionControllerForObject:@0]);
|
|
XCTAssertNotNil([self.adapter sectionControllerForObject:@1]);
|
|
XCTAssertNotNil([self.adapter sectionControllerForObject:@2]);
|
|
}
|
|
|
|
- (void)test_whenAdapterReloaded_thatAdapterHasSectionControllers {
|
|
self.dataSource.objects = @[@0, @1, @2];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
XCTAssertNotNil([self.adapter sectionControllerForObject:@0]);
|
|
XCTAssertNotNil([self.adapter sectionControllerForObject:@1]);
|
|
XCTAssertNotNil([self.adapter sectionControllerForObject:@2]);
|
|
}
|
|
|
|
- (void)test_whenAdapterUpdated_thatSectionControllerHasSection {
|
|
self.dataSource.objects = @[@0, @1, @2];
|
|
[self.adapter performUpdatesAnimated:YES completion:nil];
|
|
IGListSectionController * list = [self.adapter sectionControllerForObject:@1];
|
|
XCTAssertEqual([self.adapter sectionForSectionController:list], 1);
|
|
}
|
|
|
|
- (void)test_whenAdapterUpdated_withUnknownItem_thatSectionControllerHasNoSection {
|
|
self.dataSource.objects = @[@0, @1, @2];
|
|
[self.adapter performUpdatesAnimated:YES completion:nil];
|
|
IGListSectionController * randomList = [[IGListTestSection alloc] init];
|
|
XCTAssertEqual([self.adapter sectionForSectionController:randomList], NSNotFound);
|
|
}
|
|
|
|
- (void)test_whenQueryingAdapter_withUnknownItem_thatSectionControllerIsNil {
|
|
self.dataSource.objects = @[@0, @1, @2];
|
|
[self.adapter performUpdatesAnimated:YES completion:nil];
|
|
XCTAssertNil([self.adapter sectionControllerForObject:@3]);
|
|
}
|
|
|
|
- (void)test_whenAdapterUpdated_thatSectionControllerHasCorrectObject {
|
|
self.dataSource.objects = @[@0, @1, @2];
|
|
[self.adapter performUpdatesAnimated:YES completion:nil];
|
|
IGListSectionController * list = [self.adapter sectionControllerForObject:@1];
|
|
XCTAssertEqual([self.adapter objectForSectionController:list], @1);
|
|
}
|
|
|
|
- (void)test_whenQueryingAdapter_withUnknownItem_thatObjectForSectionControllerIsNil {
|
|
self.dataSource.objects = @[@0, @1, @2];
|
|
[self.adapter performUpdatesAnimated:YES completion:nil];
|
|
IGListSectionController * randomList = [[IGListTestSection alloc] init];
|
|
XCTAssertNil([self.adapter objectForSectionController:randomList]);
|
|
}
|
|
|
|
- (void)test_whenQueryingIndexPaths_withSectionController_thatPathsAreEqual {
|
|
self.dataSource.objects = @[@0, @1, @2];
|
|
[self.adapter performUpdatesAnimated:YES completion:nil];
|
|
IGListSectionController * second = [self.adapter sectionControllerForObject:@1];
|
|
NSArray *paths0 = [self.adapter indexPathsFromSectionController:second
|
|
indexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(2, 4)]
|
|
usePreviousIfInUpdateBlock:NO];
|
|
NSArray *expected = @[
|
|
[NSIndexPath indexPathForItem:2 inSection:1],
|
|
[NSIndexPath indexPathForItem:3 inSection:1],
|
|
[NSIndexPath indexPathForItem:4 inSection:1],
|
|
[NSIndexPath indexPathForItem:5 inSection:1],
|
|
];
|
|
XCTAssertEqualObjects(paths0, expected);
|
|
}
|
|
|
|
- (void)test_whenQueryingIndexPaths_insideBatchUpdateBlock_thatPathsAreEqual {
|
|
self.dataSource.objects = @[@0, @1, @2];
|
|
[self.adapter performUpdatesAnimated:YES completion:nil];
|
|
IGListSectionController * second = [self.adapter sectionControllerForObject:@1];
|
|
|
|
__block BOOL executed = NO;
|
|
[self.adapter performBatchAnimated:YES updates:^(id<IGListBatchContext> batchContext) {
|
|
NSArray *paths = [self.adapter indexPathsFromSectionController:second
|
|
indexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(2, 2)]
|
|
usePreviousIfInUpdateBlock:YES];
|
|
NSArray *expected = @[
|
|
[NSIndexPath indexPathForItem:2 inSection:1],
|
|
[NSIndexPath indexPathForItem:3 inSection:1],
|
|
];
|
|
XCTAssertEqualObjects(paths, expected);
|
|
|
|
executed = YES;
|
|
} completion:nil];
|
|
XCTAssertTrue(executed);
|
|
}
|
|
|
|
- (void)test_whenQueryingReusableIdentifier_thatIdentifierEqualsClassName {
|
|
NSString *identifier = IGListReusableViewIdentifier(UICollectionViewCell.class, nil, nil, nil);
|
|
XCTAssertEqualObjects(identifier, @"UICollectionViewCell");
|
|
}
|
|
|
|
- (void)test_whenQueryingReusableIdentifierWithGivenIdentifier_tahtIdentifierEqualsGivenIdentifierAndClassName {
|
|
NSString *identifier = IGListReusableViewIdentifier(UICollectionViewCell.class, nil, nil, @"MyCoolID");
|
|
XCTAssertEqualObjects(identifier, @"MyCoolIDUICollectionViewCell");
|
|
}
|
|
|
|
- (void)test_whenQueryingReusableIdentifier_thatIdentifierEqualsClassNameAndSupplimentaryKind {
|
|
NSString *identifier = IGListReusableViewIdentifier(UICollectionViewCell.class, nil, UICollectionElementKindSectionFooter, nil);
|
|
XCTAssertEqualObjects(identifier, @"UICollectionElementKindSectionFooterUICollectionViewCell");
|
|
}
|
|
|
|
- (void)test_whenQueryingReusableIdentifier_thatIdentifierEqualsClassNameAndNibName {
|
|
NSString *nibName = @"IGNibName";
|
|
NSString *identifier = IGListReusableViewIdentifier(UICollectionViewCell.class, nibName, nil, nil);
|
|
XCTAssertEqualObjects(identifier, @"IGNibNameUICollectionViewCell");
|
|
}
|
|
|
|
- (void)test_whenDataSourceChanges_thatBackgroundViewVisibilityChanges {
|
|
self.dataSource.objects = @[@1];
|
|
UIView *background = [[UIView alloc] init];
|
|
((IGListTestAdapterDataSource *)self.dataSource).backgroundView = background;
|
|
__block BOOL executed = NO;
|
|
[self.adapter reloadDataWithCompletion:^(BOOL finished) {
|
|
XCTAssertTrue(self.adapter.collectionView.backgroundView.hidden, @"Background view should be hidden");
|
|
XCTAssertEqualObjects(background, self.adapter.collectionView.backgroundView, @"Background view not correctly assigned");
|
|
|
|
self.dataSource.objects = @[];
|
|
[self.adapter reloadDataWithCompletion:^(BOOL finished2) {
|
|
XCTAssertFalse(self.adapter.collectionView.backgroundView.hidden, @"Background view should be visible");
|
|
XCTAssertEqualObjects(background, self.adapter.collectionView.backgroundView, @"Background view not correctly assigned");
|
|
executed = YES;
|
|
}];
|
|
}];
|
|
XCTAssertTrue(executed);
|
|
}
|
|
|
|
- (void)test_whenReloadingData_thatNewSectionControllersAreCreated {
|
|
self.dataSource.objects = @[@0, @1, @2];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
IGListSectionController *oldSectionController = [self.adapter sectionControllerForObject:@1];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
IGListSectionController *newSectionController = [self.adapter sectionControllerForObject:@1];
|
|
XCTAssertNotEqual(oldSectionController, newSectionController);
|
|
}
|
|
|
|
- (void)test_whenSettingCollectionView_thenSettingDataSource_thatViewControllerIsSet {
|
|
self.dataSource.objects = @[@0, @1, @2];
|
|
UIViewController *controller = [UIViewController new];
|
|
IGListAdapter *adapter = [[IGListAdapter alloc] initWithUpdater:[IGListReloadDataUpdater new]
|
|
viewController:controller];
|
|
adapter.collectionView = self.collectionView;
|
|
adapter.dataSource = self.dataSource;
|
|
IGListSectionController *sectionController = [adapter sectionControllerForObject:@1];
|
|
XCTAssertEqual(controller, sectionController.viewController);
|
|
}
|
|
|
|
- (void)test_whenSettingCollectionView_thenSettingDataSource_thatCellExists {
|
|
self.dataSource.objects = @[@1];
|
|
IGListAdapter *adapter = [[IGListAdapter alloc] initWithUpdater:[IGListReloadDataUpdater new]
|
|
viewController:nil];
|
|
adapter.collectionView = self.collectionView;
|
|
adapter.dataSource = self.dataSource;
|
|
[self.collectionView layoutIfNeeded];
|
|
XCTAssertNotNil([self.collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]]);
|
|
}
|
|
|
|
- (void)test_whenSettingDataSource_thenSettingCollectionView_thatCellExists {
|
|
self.dataSource.objects = @[@1];
|
|
IGListAdapter *adapter = [[IGListAdapter alloc] initWithUpdater:[IGListReloadDataUpdater new]
|
|
viewController:nil];
|
|
adapter.dataSource = self.dataSource;
|
|
adapter.collectionView = self.collectionView;
|
|
[self.collectionView layoutIfNeeded];
|
|
XCTAssertNotNil([self.collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]]);
|
|
}
|
|
|
|
- (void)test_whenChangingCollectionViews_thatCellsExist {
|
|
self.dataSource.objects = @[@1];
|
|
IGListAdapterUpdater *updater = [[IGListAdapterUpdater alloc] init];
|
|
IGListAdapter *adapter = [[IGListAdapter alloc] initWithUpdater:updater viewController:nil];
|
|
adapter.dataSource = self.dataSource;
|
|
adapter.collectionView = self.collectionView;
|
|
[self.collectionView layoutIfNeeded];
|
|
XCTAssertNotNil([self.collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]]);
|
|
|
|
UICollectionView *otherCollectionView = [[UICollectionView alloc] initWithFrame:self.collectionView.frame collectionViewLayout:self.collectionView.collectionViewLayout];
|
|
adapter.collectionView = otherCollectionView;
|
|
[otherCollectionView layoutIfNeeded];
|
|
XCTAssertNotNil([otherCollectionView cellForItemAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]]);
|
|
}
|
|
|
|
- (void)test_whenChangingCollectionViewsToACollectionViewInUseByAnotherAdapter_thatCollectionViewDelegateIsUpdated {
|
|
IGListTestAdapterDataSource *dataSource1 = [[IGListTestAdapterDataSource alloc] init];
|
|
dataSource1.objects = @[@1];
|
|
IGListAdapterUpdater *updater1 = [[IGListAdapterUpdater alloc] init];
|
|
IGListAdapter *adapter1 = [[IGListAdapter alloc] initWithUpdater:updater1 viewController:nil];
|
|
adapter1.dataSource = dataSource1;
|
|
|
|
IGListTestAdapterDataSource *dataSource2 = [[IGListTestAdapterDataSource alloc] init];
|
|
dataSource1.objects = @[@1];
|
|
IGListAdapterUpdater *updater2 = [[IGListAdapterUpdater alloc] init];
|
|
IGListAdapter *adapter2 = [[IGListAdapter alloc] initWithUpdater:updater2 viewController:nil];
|
|
adapter1.dataSource = dataSource2;
|
|
|
|
// associate collection view with adapter1
|
|
adapter1.collectionView = self.collectionView;
|
|
XCTAssertEqual(self.collectionView.dataSource, adapter1);
|
|
|
|
// associate collection view with adapter2
|
|
adapter2.collectionView = self.collectionView;
|
|
XCTAssertEqual(self.collectionView.dataSource, adapter2);
|
|
|
|
// associate collection view with adapter1
|
|
adapter1.collectionView = self.collectionView;
|
|
XCTAssertEqual(self.collectionView.dataSource, adapter1);
|
|
}
|
|
|
|
- (void)test_whenCellsExtendBeyondBounds_thatVisibleSectionControllersAreLimited {
|
|
// # of items for each object == [item integerValue], so @2 has 2 items (cells)
|
|
self.dataSource.objects = @[@1, @2, @3, @4, @5, @6, @7, @8, @9, @10, @11, @12];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
XCTAssertEqual([self.collectionView numberOfSections], 12);
|
|
NSArray *visibleSectionControllers = [self.adapter visibleSectionControllers];
|
|
// UIWindow is 100x100, each cell is 100x10 so should have the following section/cell count: 1 + 2 + 3 + 4 = 10 (100 tall)
|
|
XCTAssertEqual(visibleSectionControllers.count, 4);
|
|
XCTAssertTrue([visibleSectionControllers containsObject:[self.adapter sectionControllerForObject:@1]]);
|
|
XCTAssertTrue([visibleSectionControllers containsObject:[self.adapter sectionControllerForObject:@2]]);
|
|
XCTAssertTrue([visibleSectionControllers containsObject:[self.adapter sectionControllerForObject:@3]]);
|
|
XCTAssertTrue([visibleSectionControllers containsObject:[self.adapter sectionControllerForObject:@4]]);
|
|
}
|
|
|
|
- (void)test_whenCellsExtendBeyondBounds_withFasterExperiment_thatVisibleSectionControllersAreLimited {
|
|
// add experiment
|
|
self.adapter.experiments |= IGListExperimentFasterVisibleSectionController;
|
|
// # of items for each object == [item integerValue], so @2 has 2 items (cells)
|
|
self.dataSource.objects = @[@1, @2, @3, @4, @5, @6, @7, @8, @9, @10, @11, @12];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
XCTAssertEqual([self.collectionView numberOfSections], 12);
|
|
NSArray *visibleSectionControllers = [self.adapter visibleSectionControllers];
|
|
// UIWindow is 100x100, each cell is 100x10 so should have the following section/cell count: 1 + 2 + 3 + 4 = 10 (100 tall)
|
|
XCTAssertEqual(visibleSectionControllers.count, 4);
|
|
XCTAssertTrue([visibleSectionControllers containsObject:[self.adapter sectionControllerForObject:@1]]);
|
|
XCTAssertTrue([visibleSectionControllers containsObject:[self.adapter sectionControllerForObject:@2]]);
|
|
XCTAssertTrue([visibleSectionControllers containsObject:[self.adapter sectionControllerForObject:@3]]);
|
|
XCTAssertTrue([visibleSectionControllers containsObject:[self.adapter sectionControllerForObject:@4]]);
|
|
}
|
|
|
|
- (void) test_withEmptySectionPlusFooter_thatVisibleSectionControllersAreCorrect {
|
|
self.dataSource.objects = @[@0];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
IGTestSupplementarySource *supplementarySource = [IGTestSupplementarySource new];
|
|
supplementarySource.dequeueFromNib = YES;
|
|
supplementarySource.collectionContext = self.adapter;
|
|
supplementarySource.supportedElementKinds = @[UICollectionElementKindSectionFooter];
|
|
IGListSectionController *controller = [self.adapter sectionControllerForObject:@0];
|
|
controller.supplementaryViewSource = supplementarySource;
|
|
supplementarySource.sectionController = controller;
|
|
[self.adapter performUpdatesAnimated:NO completion:nil];
|
|
NSArray<IGListSectionController *> *visibleSectionControllers = [self.adapter visibleSectionControllers];
|
|
|
|
XCTAssertTrue([visibleSectionControllers count] == 1);
|
|
XCTAssertTrue(visibleSectionControllers.firstObject.supplementaryViewSource == supplementarySource);
|
|
}
|
|
|
|
- (void) test_withEmptySectionPlusFooter_withFasterExperiment_thatVisibleSectionControllersAreCorrect {
|
|
// add experiment
|
|
self.adapter.experiments |= IGListExperimentFasterVisibleSectionController;
|
|
self.dataSource.objects = @[@0];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
IGTestSupplementarySource *supplementarySource = [IGTestSupplementarySource new];
|
|
supplementarySource.dequeueFromNib = YES;
|
|
supplementarySource.collectionContext = self.adapter;
|
|
supplementarySource.supportedElementKinds = @[UICollectionElementKindSectionFooter];
|
|
IGListSectionController *controller = [self.adapter sectionControllerForObject:@0];
|
|
controller.supplementaryViewSource = supplementarySource;
|
|
supplementarySource.sectionController = controller;
|
|
[self.adapter performUpdatesAnimated:NO completion:nil];
|
|
NSArray<IGListSectionController *> *visibleSectionControllers = [self.adapter visibleSectionControllers];
|
|
|
|
XCTAssertTrue([visibleSectionControllers count] == 1);
|
|
XCTAssertTrue(visibleSectionControllers.firstObject.supplementaryViewSource == supplementarySource);
|
|
}
|
|
|
|
- (void)test_whenCellsExtendBeyondBounds_thatVisibleCellsExistForSectionControllers {
|
|
self.dataSource.objects = @[@2, @3, @4, @5, @6];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
id sectionController2 = [self.adapter sectionControllerForObject:@2];
|
|
id sectionController3 = [self.adapter sectionControllerForObject:@3];
|
|
id sectionController4 = [self.adapter sectionControllerForObject:@4];
|
|
id sectionController5 = [self.adapter sectionControllerForObject:@5];
|
|
id sectionController6 = [self.adapter sectionControllerForObject:@6];
|
|
XCTAssertEqual([self.adapter visibleCellsForSectionController:sectionController2].count, 2);
|
|
XCTAssertEqual([self.adapter visibleCellsForSectionController:sectionController3].count, 3);
|
|
XCTAssertEqual([self.adapter visibleCellsForSectionController:sectionController4].count, 4);
|
|
XCTAssertEqual([self.adapter visibleCellsForSectionController:sectionController5].count, 1);
|
|
XCTAssertEqual([self.adapter visibleCellsForSectionController:sectionController6].count, 0);
|
|
}
|
|
|
|
- (void)test_whenCellsExtendBeyondBounds_thatVisibleIndexPathsExistForSectionControllers {
|
|
self.dataSource.objects = @[@2, @3, @4, @5, @6];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
id sectionController2 = [self.adapter sectionControllerForObject:@2];
|
|
id sectionController3 = [self.adapter sectionControllerForObject:@3];
|
|
id sectionController4 = [self.adapter sectionControllerForObject:@4];
|
|
id sectionController5 = [self.adapter sectionControllerForObject:@5];
|
|
id sectionController6 = [self.adapter sectionControllerForObject:@6];
|
|
XCTAssertEqual([self.adapter visibleIndexPathsForSectionController:sectionController2].count, 2);
|
|
XCTAssertEqual([self.adapter visibleIndexPathsForSectionController:sectionController3].count, 3);
|
|
XCTAssertEqual([self.adapter visibleIndexPathsForSectionController:sectionController4].count, 4);
|
|
XCTAssertEqual([self.adapter visibleIndexPathsForSectionController:sectionController5].count, 1);
|
|
XCTAssertEqual([self.adapter visibleIndexPathsForSectionController:sectionController6].count, 0);
|
|
}
|
|
|
|
- (void)test_whenDataSourceAddsItems_thatEmptyViewBecomesVisible {
|
|
self.dataSource.objects = @[];
|
|
UIView *background = [UIView new];
|
|
((IGListTestAdapterDataSource *)self.dataSource).backgroundView = background;
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
XCTAssertEqual(self.collectionView.backgroundView, background);
|
|
XCTAssertFalse(self.collectionView.backgroundView.hidden);
|
|
self.dataSource.objects = @[@2];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
XCTAssertTrue(self.collectionView.backgroundView.hidden);
|
|
}
|
|
|
|
- (void)test_whenInsertingIntoEmptySection_thatEmptyViewBecomesHidden {
|
|
self.dataSource.objects = @[@0];
|
|
((IGListTestAdapterDataSource *)self.dataSource).backgroundView = [UIView new];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
XCTAssertFalse(self.collectionView.backgroundView.hidden);
|
|
IGListTestSection *sectionController = [self.adapter sectionControllerForObject:@(0)];
|
|
sectionController.items = 1;
|
|
[self.adapter insertInSectionController:sectionController atIndexes:[NSIndexSet indexSetWithIndex:0]];
|
|
XCTAssertTrue(self.collectionView.backgroundView.hidden);
|
|
}
|
|
|
|
- (void)test_whenDeletingAllItemsFromSection_thatEmptyViewBecomesVisible {
|
|
self.dataSource.objects = @[@1];
|
|
((IGListTestAdapterDataSource *)self.dataSource).backgroundView = [UIView new];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
XCTAssertTrue(self.collectionView.backgroundView.hidden);
|
|
IGListTestSection *sectionController = [self.adapter sectionControllerForObject:@(1)];
|
|
sectionController.items = 0;
|
|
[self.adapter deleteInSectionController:sectionController atIndexes:[NSIndexSet indexSetWithIndex:0]];
|
|
XCTAssertFalse(self.collectionView.backgroundView.hidden);
|
|
}
|
|
|
|
- (void)test_whenEmptySectionAddsItems_thatEmptyViewBecomesHidden {
|
|
self.dataSource.objects = @[@0];
|
|
((IGListTestAdapterDataSource *)self.dataSource).backgroundView = [UIView new];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
XCTAssertFalse(self.collectionView.backgroundView.hidden);
|
|
IGListTestSection *sectionController = [self.adapter sectionControllerForObject:@(0)];
|
|
sectionController.items = 2;
|
|
[self.adapter reloadSectionController:sectionController];
|
|
XCTAssertTrue(self.collectionView.backgroundView.hidden);
|
|
}
|
|
|
|
- (void)test_whenSectionItemsAreDeletedAsBatch_thatEmptyViewBecomesVisible {
|
|
self.dataSource.objects = @[@1, @2];
|
|
((IGListTestAdapterDataSource *)self.dataSource).backgroundView = [UIView new];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
XCTAssertTrue(self.collectionView.backgroundView.hidden);
|
|
IGListTestSection *firstSectionController = [self.adapter sectionControllerForObject:@(1)];
|
|
IGListTestSection *secondSectionController = [self.adapter sectionControllerForObject:@(2)];
|
|
XCTestExpectation *expectation = [self expectationWithDescription:NSStringFromSelector(_cmd)];
|
|
[self.adapter performBatchAnimated:YES updates:^(id<IGListBatchContext> batchContext) {
|
|
firstSectionController.items = 0;
|
|
[self.adapter deleteInSectionController:firstSectionController atIndexes:[NSIndexSet indexSetWithIndex:0]];
|
|
secondSectionController.items = 0;
|
|
NSIndexSet *indexesToDelete = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, 2)];
|
|
[self.adapter deleteInSectionController:secondSectionController atIndexes:indexesToDelete];
|
|
} completion:^(BOOL finished) {
|
|
XCTAssertFalse(self.collectionView.backgroundView.hidden);
|
|
[expectation fulfill];
|
|
}];
|
|
[self waitForExpectationsWithTimeout:30 handler:nil];
|
|
}
|
|
|
|
- (void)test_whenScrollViewDelegateSet_thatDelegateReceivesEvents {
|
|
id mockDelegate = [OCMockObject mockForProtocol:@protocol(UIScrollViewDelegate)];
|
|
|
|
self.adapter.collectionViewDelegate = nil;
|
|
self.adapter.scrollViewDelegate = mockDelegate;
|
|
|
|
[[mockDelegate expect] scrollViewDidScroll:self.collectionView];
|
|
|
|
[self.adapter scrollViewDidScroll:self.collectionView];
|
|
|
|
[mockDelegate verify];
|
|
}
|
|
|
|
- (void)test_whenCollectionViewDelegateSet_thatDelegateReceivesEvents {
|
|
// silence display handler asserts
|
|
self.dataSource.objects = @[@1, @2];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
|
|
id mockDelegate = [OCMockObject mockForProtocol:@protocol(UICollectionViewDelegate)];
|
|
|
|
self.adapter.collectionViewDelegate = mockDelegate;
|
|
self.adapter.scrollViewDelegate = nil;
|
|
|
|
NSIndexPath *path = [NSIndexPath indexPathForItem:0 inSection:0];
|
|
UICollectionViewCell *cell = [self.collectionView cellForItemAtIndexPath:path];
|
|
[[mockDelegate expect] collectionView:self.collectionView didEndDisplayingCell:cell forItemAtIndexPath:path];
|
|
|
|
[self.adapter collectionView:self.collectionView didEndDisplayingCell:cell forItemAtIndexPath:path];
|
|
|
|
[mockDelegate verify];
|
|
}
|
|
|
|
- (void)test_whenCollectionViewDelegateSet_withScrollViewDelegateSet_thatDelegatesReceiveUniqueEvents {
|
|
// silence display handler asserts
|
|
self.dataSource.objects = @[@1, @2];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
|
|
id mockCollectionViewDelegate = [OCMockObject mockForProtocol:@protocol(UICollectionViewDelegate)];
|
|
id mockScrollViewDelegate = [OCMockObject mockForProtocol:@protocol(UIScrollViewDelegate)];
|
|
|
|
self.adapter.collectionViewDelegate = mockCollectionViewDelegate;
|
|
self.adapter.scrollViewDelegate = mockScrollViewDelegate;
|
|
|
|
NSIndexPath *path = [NSIndexPath indexPathForItem:0 inSection:0];
|
|
UICollectionViewCell *cell = [self.collectionView cellForItemAtIndexPath:path];
|
|
|
|
[[mockScrollViewDelegate expect] scrollViewDidScroll:self.collectionView];
|
|
|
|
[[mockCollectionViewDelegate reject] scrollViewDidScroll:self.collectionView];
|
|
[[mockCollectionViewDelegate expect] collectionView:self.collectionView didEndDisplayingCell:cell forItemAtIndexPath:path];
|
|
|
|
[self.adapter scrollViewDidScroll:self.collectionView];
|
|
[self.adapter collectionView:self.collectionView didEndDisplayingCell:cell forItemAtIndexPath:path];
|
|
|
|
[mockScrollViewDelegate verify];
|
|
[mockCollectionViewDelegate verify];
|
|
}
|
|
|
|
- (void)test_whenSupplementarySourceSupportsFooter_thatHeaderViewsAreNil {
|
|
self.dataSource.objects = @[@1, @2];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
|
|
IGTestSupplementarySource *supplementarySource = [IGTestSupplementarySource new];
|
|
supplementarySource.collectionContext = self.adapter;
|
|
supplementarySource.supportedElementKinds = @[UICollectionElementKindSectionFooter];
|
|
|
|
IGListSectionController *controller = [self.adapter sectionControllerForObject:@1];
|
|
controller.supplementaryViewSource = supplementarySource;
|
|
supplementarySource.sectionController = controller;
|
|
|
|
[self.adapter performUpdatesAnimated:NO completion:nil];
|
|
|
|
XCTAssertNotNil([self.collectionView supplementaryViewForElementKind:UICollectionElementKindSectionFooter atIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]]);
|
|
XCTAssertNil([self.collectionView supplementaryViewForElementKind:UICollectionElementKindSectionHeader atIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]]);
|
|
XCTAssertNil([self.collectionView supplementaryViewForElementKind:UICollectionElementKindSectionHeader atIndexPath:[NSIndexPath indexPathForItem:0 inSection:1]]);
|
|
XCTAssertNil([self.collectionView supplementaryViewForElementKind:UICollectionElementKindSectionFooter atIndexPath:[NSIndexPath indexPathForItem:0 inSection:1]]);
|
|
}
|
|
|
|
- (void)test_whenSupplementarySourceSupportsFooter_withNibs_thatHeaderViewsAreNil {
|
|
self.dataSource.objects = @[@1, @2];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
|
|
IGTestSupplementarySource *supplementarySource = [IGTestSupplementarySource new];
|
|
supplementarySource.dequeueFromNib = YES;
|
|
supplementarySource.collectionContext = self.adapter;
|
|
supplementarySource.supportedElementKinds = @[UICollectionElementKindSectionFooter];
|
|
|
|
IGListSectionController *controller = [self.adapter sectionControllerForObject:@1];
|
|
controller.supplementaryViewSource = supplementarySource;
|
|
supplementarySource.sectionController = controller;
|
|
|
|
[self.adapter performUpdatesAnimated:NO completion:nil];
|
|
|
|
id view = [self.collectionView supplementaryViewForElementKind:UICollectionElementKindSectionFooter atIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]];
|
|
XCTAssertTrue([view isKindOfClass:IGTestNibSupplementaryView.class]);
|
|
XCTAssertEqualObjects([[(IGTestNibSupplementaryView *)view label] text], @"Foo bar baz");
|
|
|
|
XCTAssertNil([self.collectionView supplementaryViewForElementKind:UICollectionElementKindSectionHeader atIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]]);
|
|
XCTAssertNil([self.collectionView supplementaryViewForElementKind:UICollectionElementKindSectionHeader atIndexPath:[NSIndexPath indexPathForItem:0 inSection:1]]);
|
|
XCTAssertNil([self.collectionView supplementaryViewForElementKind:UICollectionElementKindSectionFooter atIndexPath:[NSIndexPath indexPathForItem:0 inSection:1]]);
|
|
}
|
|
|
|
- (void)test_whenAdapterReleased_withSectionControllerStrongRefToCell_thatSectionControllersRelease {
|
|
__weak id weakCollectionView = nil, weakAdapter = nil, weakSectionController = nil;
|
|
|
|
@autoreleasepool {
|
|
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
|
|
UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)
|
|
collectionViewLayout:layout];
|
|
weakCollectionView = collectionView;
|
|
|
|
IGListTestAdapterDataSource *dataSource = [[IGListTestAdapterDataSource alloc] init];
|
|
dataSource.objects = @[@0, @1, @2];
|
|
|
|
IGListReloadDataUpdater *updater = [[IGListReloadDataUpdater alloc] init];
|
|
IGListAdapter *adapter = [[IGListAdapter alloc] initWithUpdater:updater viewController:nil];
|
|
adapter.collectionView = collectionView;
|
|
adapter.dataSource = dataSource;
|
|
weakAdapter = adapter;
|
|
|
|
IGListSectionController *sectionController = [adapter sectionControllerForObject:@1];
|
|
weakSectionController = sectionController;
|
|
|
|
// force the collection view to layout and generate cells
|
|
[collectionView layoutIfNeeded];
|
|
|
|
UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:1]];
|
|
XCTAssertNotNil(cell);
|
|
// strongly attach the cell to an section controller
|
|
objc_setAssociatedObject(sectionController, @"some_random_key", cell, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
|
|
|
// weak refs should exist at this point
|
|
XCTAssertNotNil(weakCollectionView);
|
|
XCTAssertNotNil(weakAdapter);
|
|
XCTAssertNotNil(weakSectionController);
|
|
}
|
|
|
|
XCTAssertNil(weakCollectionView);
|
|
XCTAssertNil(weakAdapter);
|
|
XCTAssertNil(weakSectionController);
|
|
}
|
|
|
|
- (void)test_whenAdapterReleased_withSectionControllerStrongRefToCollectionView_thatSectionControllersRelease {
|
|
__weak id weakCollectionView = nil, weakAdapter = nil, weakSectionController = nil;
|
|
|
|
@autoreleasepool {
|
|
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
|
|
UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)
|
|
collectionViewLayout:layout];
|
|
weakCollectionView = collectionView;
|
|
|
|
IGListTestAdapterDataSource *dataSource = [[IGListTestAdapterDataSource alloc] init];
|
|
dataSource.objects = @[@0, @1, @2];
|
|
|
|
IGListReloadDataUpdater *updater = [[IGListReloadDataUpdater alloc] init];
|
|
IGListAdapter *adapter = [[IGListAdapter alloc] initWithUpdater:updater viewController:nil];
|
|
adapter.collectionView = collectionView;
|
|
adapter.dataSource = dataSource;
|
|
weakAdapter = adapter;
|
|
|
|
IGListSectionController *sectionController = [adapter sectionControllerForObject:@1];
|
|
weakSectionController = sectionController;
|
|
|
|
// force the collection view to layout and generate cells
|
|
[collectionView layoutIfNeeded];
|
|
|
|
// strongly attach the cell to an section controller
|
|
objc_setAssociatedObject(sectionController, @"some_random_key", collectionView, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
|
|
|
// weak refs should exist at this point
|
|
XCTAssertNotNil(weakCollectionView);
|
|
XCTAssertNotNil(weakAdapter);
|
|
XCTAssertNotNil(weakSectionController);
|
|
}
|
|
|
|
XCTAssertNil(weakCollectionView);
|
|
XCTAssertNil(weakAdapter);
|
|
XCTAssertNil(weakSectionController);
|
|
}
|
|
|
|
- (void)test_whenAdapterUpdatedTwice_withThreeSections_thatSectionsUpdatedFirstLast {
|
|
self.dataSource.objects = @[@0, @1, @2];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
|
|
XCTAssertTrue([[self.adapter sectionControllerForObject:@0] isFirstSection]);
|
|
XCTAssertFalse([[self.adapter sectionControllerForObject:@1] isFirstSection]);
|
|
XCTAssertFalse([[self.adapter sectionControllerForObject:@2] isFirstSection]);
|
|
|
|
XCTAssertFalse([[self.adapter sectionControllerForObject:@0] isLastSection]);
|
|
XCTAssertFalse([[self.adapter sectionControllerForObject:@1] isLastSection]);
|
|
XCTAssertTrue([[self.adapter sectionControllerForObject:@2] isLastSection]);
|
|
|
|
// update and shift objects to test that first/last flags are also updated
|
|
self.dataSource.objects = @[@2, @0, @1];
|
|
[self.adapter performUpdatesAnimated:NO completion:nil];
|
|
|
|
XCTAssertFalse([[self.adapter sectionControllerForObject:@0] isFirstSection]);
|
|
XCTAssertFalse([[self.adapter sectionControllerForObject:@1] isFirstSection]);
|
|
XCTAssertTrue([[self.adapter sectionControllerForObject:@2] isFirstSection]);
|
|
|
|
XCTAssertFalse([[self.adapter sectionControllerForObject:@0] isLastSection]);
|
|
XCTAssertTrue([[self.adapter sectionControllerForObject:@1] isLastSection]);
|
|
XCTAssertFalse([[self.adapter sectionControllerForObject:@2] isLastSection]);
|
|
}
|
|
|
|
- (void)test_whenAdapterUpdated_withObjectsOverflow_thatVisibleObjectsIsSubsetOfAllObjects {
|
|
// each section controller returns n items sized 100x10
|
|
self.dataSource.objects = @[@1, @2, @3, @4, @5, @6];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
self.collectionView.contentOffset = CGPointMake(0, 30);
|
|
[self.collectionView layoutIfNeeded];
|
|
|
|
NSArray *visibleObjects = [[self.adapter visibleObjects] sortedArrayUsingSelector:@selector(compare:)];
|
|
NSArray *expectedObjects = @[@3, @4, @5];
|
|
XCTAssertEqualObjects(visibleObjects, expectedObjects);
|
|
}
|
|
|
|
- (void)test_whenAdapterUpdated_thatVisibleCellsForObjectAreFound {
|
|
// each section controller returns n items sized 100x10
|
|
self.dataSource.objects = @[@2, @10, @5];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
self.collectionView.contentOffset = CGPointMake(0, 80);
|
|
[self.collectionView layoutIfNeeded];
|
|
|
|
UICollectionView *collectionView = self.collectionView;
|
|
NSArray *visibleCellsForObject = [[self.adapter visibleCellsForObject:@10] sortedArrayUsingComparator:^NSComparisonResult(UICollectionViewCell* lhs, UICollectionViewCell* rhs) {
|
|
NSIndexPath *lhsIndexPath = [collectionView indexPathForCell:lhs];
|
|
NSIndexPath *rhsIndexPath = [collectionView indexPathForCell:rhs];
|
|
|
|
if (lhsIndexPath.section == rhsIndexPath.section) {
|
|
return lhsIndexPath.item > rhsIndexPath.item;
|
|
}
|
|
|
|
return lhsIndexPath.section > rhsIndexPath.section;
|
|
}];
|
|
|
|
XCTAssertEqual(visibleCellsForObject.count, 4);
|
|
XCTAssertEqual([self.collectionView indexPathForCell:visibleCellsForObject[0]].item, 6);
|
|
XCTAssertEqual([self.collectionView indexPathForCell:visibleCellsForObject[1]].item, 7);
|
|
XCTAssertEqual([self.collectionView indexPathForCell:visibleCellsForObject[2]].item, 8);
|
|
XCTAssertEqual([self.collectionView indexPathForCell:visibleCellsForObject[3]].item, 9);
|
|
|
|
NSArray *visibleCellsForObjectTwo = [self.adapter visibleCellsForObject:@5];
|
|
XCTAssertEqual(visibleCellsForObjectTwo.count, 5);
|
|
}
|
|
|
|
- (void)test_whenAdapterUpdated_thatVisibleCellsForNilObjectIsEmpty {
|
|
// each section controller returns n items sized 100x10
|
|
self.dataSource.objects = @[@2, @10, @5];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
self.collectionView.contentOffset = CGPointMake(0, 80);
|
|
[self.collectionView layoutIfNeeded];
|
|
|
|
NSArray *visibleCellsForObject = [self.adapter visibleCellsForObject:@3];
|
|
XCTAssertEqual(visibleCellsForObject.count, 0);
|
|
}
|
|
|
|
- (void)test_whenScrollVerticallyToItem {
|
|
// # of items for each object == [item integerValue], so @2 has 2 items (cells)
|
|
self.dataSource.objects = @[@1, @2, @3, @4, @5, @6];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
XCTAssertEqual([self.collectionView numberOfSections], 6);
|
|
[self.adapter scrollToObject:@1 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionNone animated:NO];
|
|
IGAssertEqualPoint([self.collectionView contentOffset], 0, 0);
|
|
[self.adapter scrollToObject:@2 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionNone animated:NO];
|
|
IGAssertEqualPoint([self.collectionView contentOffset], 0, 10);
|
|
[self.adapter scrollToObject:@3 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionNone animated:NO];
|
|
IGAssertEqualPoint([self.collectionView contentOffset], 0, 30);
|
|
[self.adapter scrollToObject:@6 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionNone animated:NO];
|
|
// Content height minus collection view height is 110, can't scroll more than that
|
|
IGAssertEqualPoint([self.collectionView contentOffset], 0, 110);
|
|
[self.adapter scrollToObject:@6 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionCenteredVertically animated:NO];
|
|
IGAssertEqualPoint([self.collectionView contentOffset], 0, 110);
|
|
[self.adapter scrollToObject:@6 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionBottom animated:NO];
|
|
IGAssertEqualPoint([self.collectionView contentOffset], 0, 110);
|
|
}
|
|
|
|
- (void)test_whenScrollVerticallyToItemInASectionWithNoCellsAndNoSupplymentaryView {
|
|
self.dataSource.objects = @[@1, @0, @300];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
XCTAssertEqual([self.collectionView numberOfSections], 3);
|
|
[self.adapter scrollToObject:@1 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionNone animated:NO];
|
|
IGAssertEqualPoint([self.collectionView contentOffset], 0, 0);
|
|
[self.adapter scrollToObject:@0 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionNone animated:NO];
|
|
IGAssertEqualPoint([self.collectionView contentOffset], 0, 0);
|
|
[self.adapter scrollToObject:@300 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionNone animated:NO];
|
|
IGAssertEqualPoint([self.collectionView contentOffset], 0, 10);
|
|
}
|
|
|
|
- (void)test_whenScrollVerticallyToItemInASectionWithNoCellsButAHeaderSupplymentaryView {
|
|
self.dataSource.objects = @[@1, @0, @300];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
|
|
IGTestSupplementarySource *supplementarySource = [IGTestSupplementarySource new];
|
|
supplementarySource.collectionContext = self.adapter;
|
|
supplementarySource.supportedElementKinds = @[UICollectionElementKindSectionHeader];
|
|
|
|
IGListSectionController *controller = [self.adapter sectionControllerForObject:@0];
|
|
controller.supplementaryViewSource = supplementarySource;
|
|
supplementarySource.sectionController = controller;
|
|
|
|
[self.adapter performUpdatesAnimated:NO completion:nil];
|
|
|
|
XCTAssertEqual([self.collectionView numberOfSections], 3);
|
|
[self.adapter scrollToObject:@1 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionNone animated:NO];
|
|
IGAssertEqualPoint([self.collectionView contentOffset], 0, 0);
|
|
[self.adapter scrollToObject:@0 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionNone animated:NO];
|
|
IGAssertEqualPoint([self.collectionView contentOffset], 0, 0);
|
|
[self.adapter scrollToObject:@0 supplementaryKinds:@[UICollectionElementKindSectionHeader] scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionTop animated:NO];
|
|
IGAssertEqualPoint([self.collectionView contentOffset], 0, 10);
|
|
[self.adapter scrollToObject:@300 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionNone animated:NO];
|
|
IGAssertEqualPoint([self.collectionView contentOffset], 0, 20);
|
|
}
|
|
|
|
- (void)test_whenScrollVerticallyToItemWithPositionning {
|
|
self.dataSource.objects = @[@1, @100, @200];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
[self.adapter scrollToObject:@1 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionNone animated:NO];
|
|
IGAssertEqualPoint([self.collectionView contentOffset], 0, 0);
|
|
[self.adapter scrollToObject:@1 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionTop animated:NO];
|
|
IGAssertEqualPoint([self.collectionView contentOffset], 0, 0);
|
|
[self.adapter scrollToObject:@1 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionCenteredVertically animated:NO];
|
|
IGAssertEqualPoint([self.collectionView contentOffset], 0, 0);
|
|
[self.adapter scrollToObject:@1 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionBottom animated:NO];
|
|
IGAssertEqualPoint([self.collectionView contentOffset], 0, 0);
|
|
|
|
[self.adapter scrollToObject:@100 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionNone animated:NO];
|
|
IGAssertEqualPoint([self.collectionView contentOffset], 0, 10);
|
|
[self.adapter scrollToObject:@100 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionTop animated:NO];
|
|
IGAssertEqualPoint([self.collectionView contentOffset], 0, 10);
|
|
[self.adapter scrollToObject:@100 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionCenteredVertically animated:NO];
|
|
IGAssertEqualPoint([self.collectionView contentOffset], 0, 460);
|
|
[self.adapter scrollToObject:@100 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionBottom animated:NO];
|
|
IGAssertEqualPoint([self.collectionView contentOffset], 0, 910);
|
|
|
|
[self.adapter scrollToObject:@200 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionBottom animated:NO];
|
|
IGAssertEqualPoint([self.collectionView contentOffset], 0, self.collectionView.contentSize.height - self.collectionView.frame.size.height);
|
|
}
|
|
|
|
- (void)test_whenScrollVerticallyToBottom_withContentInsets_thatBottomFlushWithCollectionViewBounds {
|
|
self.dataSource.objects = @[@100];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
|
|
// no insets
|
|
self.collectionView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0);
|
|
[self.collectionView layoutIfNeeded];
|
|
[self.adapter scrollToObject:@100 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionBottom animated:NO];
|
|
IGAssertEqualPoint([self.collectionView contentOffset], 0, 900);
|
|
|
|
// top 100
|
|
self.collectionView.contentInset = UIEdgeInsetsMake(100, 0, 0, 0);
|
|
[self.adapter scrollToObject:@100 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionBottom animated:NO];
|
|
IGAssertEqualPoint([self.collectionView contentOffset], 0, 900);
|
|
|
|
// bottom 100
|
|
self.collectionView.contentInset = UIEdgeInsetsMake(0, 0, 100, 0);
|
|
[self.collectionView layoutIfNeeded];
|
|
[self.adapter scrollToObject:@100 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionBottom animated:NO];
|
|
IGAssertEqualPoint([self.collectionView contentOffset], 0, 900);
|
|
|
|
// top 50, bottom 100
|
|
self.collectionView.contentInset = UIEdgeInsetsMake(50, 0, 100, 0);
|
|
[self.collectionView layoutIfNeeded];
|
|
[self.adapter scrollToObject:@100 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionBottom animated:NO];
|
|
IGAssertEqualPoint([self.collectionView contentOffset], 0, 900);
|
|
}
|
|
|
|
- (void)test_whenScrollHorizontallyToItem {
|
|
// # of items for each object == [item integerValue], so @2 has 2 items (cells)
|
|
IGListTestAdapterHorizontalDataSource *dataSource = [[IGListTestAdapterHorizontalDataSource alloc] init];
|
|
self.adapter.dataSource = dataSource;
|
|
dataSource.objects = @[@1, @2, @3, @4, @5, @6];
|
|
self.layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
XCTAssertEqual([self.collectionView numberOfSections], 6);
|
|
[self.adapter scrollToObject:@1 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionHorizontal scrollPosition:UICollectionViewScrollPositionNone animated:NO];
|
|
IGAssertEqualPoint([self.collectionView contentOffset], 0, 0);
|
|
[self.adapter scrollToObject:@2 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionHorizontal scrollPosition:UICollectionViewScrollPositionNone animated:NO];
|
|
IGAssertEqualPoint([self.collectionView contentOffset], 10, 0);
|
|
[self.adapter scrollToObject:@3 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionHorizontal scrollPosition:UICollectionViewScrollPositionNone animated:NO];
|
|
IGAssertEqualPoint([self.collectionView contentOffset], 30, 0);
|
|
[self.adapter scrollToObject:@6 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionHorizontal scrollPosition:UICollectionViewScrollPositionNone animated:NO];
|
|
// Content width minus collection view width is 110, can't scroll more than that
|
|
IGAssertEqualPoint([self.collectionView contentOffset], 110, 0);
|
|
[self.adapter scrollToObject:@6 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionHorizontal scrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:NO];
|
|
IGAssertEqualPoint([self.collectionView contentOffset], 110, 0);
|
|
[self.adapter scrollToObject:@6 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionHorizontal scrollPosition:UICollectionViewScrollPositionRight animated:NO];
|
|
IGAssertEqualPoint([self.collectionView contentOffset], 110, 0);
|
|
self.layout.scrollDirection = UICollectionViewScrollDirectionVertical;
|
|
self.adapter.dataSource = self.dataSource;
|
|
}
|
|
|
|
- (void)test_whenScrollToItem_thatSupplementarySourceSupportsSingleHeader {
|
|
self.dataSource.objects = @[@1, @2];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
|
|
IGTestSupplementarySource *supplementarySource = [IGTestSupplementarySource new];
|
|
supplementarySource.collectionContext = self.adapter;
|
|
supplementarySource.supportedElementKinds = @[UICollectionElementKindSectionHeader];
|
|
|
|
IGListSectionController *controller = [self.adapter sectionControllerForObject:@1];
|
|
controller.supplementaryViewSource = supplementarySource;
|
|
supplementarySource.sectionController = controller;
|
|
|
|
[self.adapter performUpdatesAnimated:NO completion:nil];
|
|
|
|
XCTAssertNotNil([self.collectionView supplementaryViewForElementKind:UICollectionElementKindSectionHeader atIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]]);
|
|
[self.adapter scrollToObject:@1 supplementaryKinds:@[UICollectionElementKindSectionHeader] scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionNone animated:NO];
|
|
IGAssertEqualPoint([self.collectionView contentOffset], 0, 0);
|
|
[self.adapter scrollToObject:@2 supplementaryKinds:@[UICollectionElementKindSectionHeader] scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionNone animated:NO];
|
|
// Content height smaller than collection view height, won't scroll
|
|
IGAssertEqualPoint([self.collectionView contentOffset], 0, 0);
|
|
}
|
|
|
|
- (void)test_whenScrollToItem_thatSupplementarySourceSupportsHeaderAndFooter {
|
|
self.dataSource.objects = @[@1, @2];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
|
|
IGTestSupplementarySource *supplementarySource = [IGTestSupplementarySource new];
|
|
supplementarySource.collectionContext = self.adapter;
|
|
supplementarySource.supportedElementKinds = @[UICollectionElementKindSectionHeader, UICollectionElementKindSectionFooter];
|
|
|
|
IGListSectionController *controller = [self.adapter sectionControllerForObject:@1];
|
|
controller.supplementaryViewSource = supplementarySource;
|
|
supplementarySource.sectionController = controller;
|
|
|
|
[self.adapter performUpdatesAnimated:NO completion:nil];
|
|
|
|
XCTAssertNotNil([self.collectionView supplementaryViewForElementKind:UICollectionElementKindSectionHeader atIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]]);
|
|
XCTAssertNotNil([self.collectionView supplementaryViewForElementKind:UICollectionElementKindSectionFooter atIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]]);
|
|
[self.adapter scrollToObject:@1 supplementaryKinds:@[UICollectionElementKindSectionHeader, UICollectionElementKindSectionFooter] scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionNone animated:NO];
|
|
IGAssertEqualPoint([self.collectionView contentOffset], 0, 0);
|
|
[self.adapter scrollToObject:@2 supplementaryKinds:@[UICollectionElementKindSectionHeader, UICollectionElementKindSectionFooter] scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionNone animated:NO];
|
|
// Content height smaller than collection view height, won't scroll
|
|
IGAssertEqualPoint([self.collectionView contentOffset], 0, 0);
|
|
}
|
|
|
|
- (void)test_whenScrollVerticallyToItem_thatFeedIsEmpty {
|
|
self.dataSource.objects = @[];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
XCTAssertEqual([self.collectionView numberOfSections], 0);
|
|
[self.adapter scrollToObject:@1 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionNone animated:NO];
|
|
IGAssertEqualPoint([self.collectionView contentOffset], 0, 0);
|
|
}
|
|
|
|
- (void)test_whenScrollVerticallyToItem_thatItemNotInFeed {
|
|
// # of items for each object == [item integerValue], so @2 has 2 items (cells)
|
|
self.dataSource.objects = @[@1, @2, @3, @4];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
XCTAssertEqual([self.collectionView numberOfSections], 4);
|
|
[self.adapter scrollToObject:@1 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionNone animated:NO];
|
|
IGAssertEqualPoint([self.collectionView contentOffset], 0, 0);
|
|
[self.adapter scrollToObject:@5 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionNone animated:NO];
|
|
IGAssertEqualPoint([self.collectionView contentOffset], 0, 0);
|
|
[self.adapter scrollToObject:@2 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionNone animated:NO];
|
|
// Content height is smaller than collection view height, can't scroll
|
|
IGAssertEqualPoint([self.collectionView contentOffset], 0, 0);
|
|
[self.adapter scrollToObject:@5 supplementaryKinds:nil scrollDirection:UICollectionViewScrollDirectionVertical scrollPosition:UICollectionViewScrollPositionNone animated:NO];
|
|
// Content height is smaller than collection view height, can't scroll
|
|
IGAssertEqualPoint([self.collectionView contentOffset], 0, 0);
|
|
}
|
|
|
|
- (void)test_whenQueryingIndexPath_withOOBSectionController_thatNilReturned {
|
|
self.dataSource.objects = @[@0, @1, @2];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
|
|
id randomSectionController = [IGListSectionController new];
|
|
XCTAssertNil([self.adapter indexPathForSectionController:randomSectionController index:0 usePreviousIfInUpdateBlock:NO]);
|
|
}
|
|
|
|
- (void)test_whenQueryingSectionForObject_thatSectionReturned {
|
|
self.dataSource.objects = @[@0, @1, @2];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
XCTAssertEqual([self.adapter sectionForObject:@0], 0);
|
|
XCTAssertEqual([self.adapter sectionForObject:@1], 1);
|
|
XCTAssertEqual([self.adapter sectionForObject:@2], 2);
|
|
XCTAssertEqual([self.adapter sectionForObject:@3], NSNotFound);
|
|
}
|
|
|
|
- (void)test_whenQueryingSectionControllerForSection_thatControllerReturned {
|
|
self.dataSource.objects = @[@0, @1, @2];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
|
|
XCTAssertEqual([self.adapter sectionControllerForSection:0], [self.adapter sectionControllerForObject:@0]);
|
|
XCTAssertEqual([self.adapter sectionControllerForSection:1], [self.adapter sectionControllerForObject:@1]);
|
|
XCTAssertEqual([self.adapter sectionControllerForSection:2], [self.adapter sectionControllerForObject:@2]);
|
|
}
|
|
|
|
- (void)test_whenReloadingData_withNoDataSource_thatCompletionCalledWithNO {
|
|
self.dataSource.objects = @[@1];
|
|
IGListAdapter *adapter = [[IGListAdapter alloc] initWithUpdater:[IGListReloadDataUpdater new]
|
|
viewController:nil];
|
|
adapter.collectionView = self.collectionView;
|
|
|
|
__block BOOL executed = NO;
|
|
[adapter reloadDataWithCompletion:^(BOOL finished) {
|
|
executed = YES;
|
|
XCTAssertFalse(finished);
|
|
}];
|
|
XCTAssertTrue(executed);
|
|
}
|
|
|
|
- (void)test_whenReloadingData_withNoCollectionView_thatCompletionCalledWithNO {
|
|
self.dataSource.objects = @[@1];
|
|
IGListAdapter *adapter = [[IGListAdapter alloc] initWithUpdater:[IGListReloadDataUpdater new]
|
|
viewController:nil];
|
|
adapter.dataSource = self.dataSource;
|
|
|
|
__block BOOL executed = NO;
|
|
[adapter reloadDataWithCompletion:^(BOOL finished) {
|
|
executed = YES;
|
|
XCTAssertFalse(finished);
|
|
}];
|
|
XCTAssertTrue(executed);
|
|
}
|
|
|
|
- (void)test_whenSectionControllerDeleting_withEmptyIndexes_thatNoUpdatesHappen {
|
|
self.dataSource.objects = @[@0, @1, @2];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
|
|
id mockDelegate = [OCMockObject mockForProtocol:@protocol(IGListUpdatingDelegate)];
|
|
[[mockDelegate reject] deleteItemsFromCollectionView:[OCMArg any] indexPaths:[OCMArg any]];
|
|
self.adapter.updater = mockDelegate;
|
|
|
|
id sectionController = [self.adapter sectionControllerForObject:@1];
|
|
[self.adapter deleteInSectionController:sectionController atIndexes:[NSIndexSet new]];
|
|
|
|
[mockDelegate verify];
|
|
}
|
|
|
|
- (void)test_whenSectionControllerInserting_withEmptyIndexes_thatNoUpdatesHappen {
|
|
self.dataSource.objects = @[@0, @1, @2];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
|
|
id mockDelegate = [OCMockObject mockForProtocol:@protocol(IGListUpdatingDelegate)];
|
|
[[mockDelegate reject] insertItemsIntoCollectionView:[OCMArg any] indexPaths:[OCMArg any]];
|
|
self.adapter.updater = mockDelegate;
|
|
|
|
id sectionController = [self.adapter sectionControllerForObject:@1];
|
|
[self.adapter insertInSectionController:sectionController atIndexes:[NSIndexSet new]];
|
|
|
|
[mockDelegate verify];
|
|
}
|
|
|
|
- (void)test_whenReloading_withSectionControllerNotFound_thatNoUpdatesHappen {
|
|
self.dataSource.objects = @[@0, @1, @2];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
|
|
id mockDelegate = [OCMockObject mockForProtocol:@protocol(IGListUpdatingDelegate)];
|
|
[[mockDelegate reject] reloadCollectionView:[OCMArg any] sections:[OCMArg any]];
|
|
self.adapter.updater = mockDelegate;
|
|
|
|
id sectionController = [IGListSectionController new];
|
|
[self.adapter reloadSectionController:sectionController];
|
|
|
|
[mockDelegate verify];
|
|
}
|
|
|
|
- (void)test_whenSelectingCell_thatCollectionViewDelegateReceivesMethod {
|
|
self.dataSource.objects = @[@0, @1, @2];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
|
|
id mockDelegate = [OCMockObject mockForProtocol:@protocol(UICollectionViewDelegate)];
|
|
self.adapter.collectionViewDelegate = mockDelegate;
|
|
|
|
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
|
|
[[mockDelegate expect] collectionView:self.collectionView didSelectItemAtIndexPath:indexPath];
|
|
|
|
// simulates the collectionview telling its delegate that it was tapped
|
|
[self.adapter collectionView:self.collectionView didSelectItemAtIndexPath:indexPath];
|
|
|
|
[mockDelegate verify];
|
|
}
|
|
|
|
- (void)test_whenSelectingCell_thatSectionControllerReceivesMethod {
|
|
self.dataSource.objects = @[@0, @1, @2];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
|
|
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
|
|
|
|
// simulates the collectionview telling its delegate that it was tapped
|
|
[self.adapter collectionView:self.collectionView didSelectItemAtIndexPath:indexPath];
|
|
|
|
IGListTestSection *s0 = [self.adapter sectionControllerForObject:@0];
|
|
IGListTestSection *s1 = [self.adapter sectionControllerForObject:@1];
|
|
IGListTestSection *s2 = [self.adapter sectionControllerForObject:@2];
|
|
|
|
XCTAssertTrue(s0.wasSelected);
|
|
XCTAssertFalse(s1.wasSelected);
|
|
XCTAssertFalse(s2.wasSelected);
|
|
}
|
|
|
|
- (void)test_whenDeselectingCell_thatCollectionViewDelegateReceivesMethod {
|
|
self.dataSource.objects = @[@0, @1, @2];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
|
|
id mockDelegate = [OCMockObject mockForProtocol:@protocol(UICollectionViewDelegate)];
|
|
self.adapter.collectionViewDelegate = mockDelegate;
|
|
|
|
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
|
|
[[mockDelegate expect] collectionView:self.collectionView didDeselectItemAtIndexPath:indexPath];
|
|
|
|
// simulates the collectionview telling its delegate that it was tapped
|
|
[self.adapter collectionView:self.collectionView didDeselectItemAtIndexPath:indexPath];
|
|
|
|
[mockDelegate verify];
|
|
}
|
|
|
|
- (void)test_whenDeselectingCell_thatSectionControllerReceivesMethod {
|
|
self.dataSource.objects = @[@0, @1, @2];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
|
|
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
|
|
|
|
// simulates the collectionview telling its delegate that it was tapped
|
|
[self.adapter collectionView:self.collectionView didDeselectItemAtIndexPath:indexPath];
|
|
|
|
IGListTestSection *s0 = [self.adapter sectionControllerForObject:@0];
|
|
IGListTestSection *s1 = [self.adapter sectionControllerForObject:@1];
|
|
IGListTestSection *s2 = [self.adapter sectionControllerForObject:@2];
|
|
|
|
XCTAssertTrue(s0.wasDeselected);
|
|
XCTAssertFalse(s1.wasDeselected);
|
|
XCTAssertFalse(s2.wasDeselected);
|
|
}
|
|
|
|
- (void)test_whenDisplayingCell_thatCollectionViewDelegateReceivesMethod {
|
|
self.dataSource.objects = @[@0, @1, @2];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
|
|
id mockDelegate = [OCMockObject mockForProtocol:@protocol(UICollectionViewDelegate)];
|
|
self.adapter.collectionViewDelegate = mockDelegate;
|
|
|
|
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
|
|
UICollectionViewCell *cell = [UICollectionViewCell new];
|
|
[[mockDelegate expect] collectionView:self.collectionView willDisplayCell:cell forItemAtIndexPath:indexPath];
|
|
|
|
// simulates the collectionview telling its delegate that a cell will be displayed
|
|
[self.adapter collectionView:self.collectionView willDisplayCell:cell forItemAtIndexPath:indexPath];
|
|
|
|
[mockDelegate verify];
|
|
}
|
|
|
|
- (void)test_whenWillBeginDragging_thatScrollViewDelegateReceivesMethod {
|
|
self.dataSource.objects = @[@0, @1, @2];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
|
|
id mockCollectionDelegate = [OCMockObject mockForProtocol:@protocol(UICollectionViewDelegate)];
|
|
id mockScrollDelegate = [OCMockObject mockForProtocol:@protocol(UIScrollViewDelegate)];
|
|
self.adapter.collectionViewDelegate = mockCollectionDelegate;
|
|
self.adapter.scrollViewDelegate = mockScrollDelegate;
|
|
|
|
[[mockCollectionDelegate reject] scrollViewWillBeginDragging:self.collectionView];
|
|
[[mockScrollDelegate expect] scrollViewWillBeginDragging:self.collectionView];
|
|
|
|
// simulates the scrollview delegate telling the adapter that it will begin dragging
|
|
[self.adapter scrollViewWillBeginDragging:self.collectionView];
|
|
|
|
[mockCollectionDelegate verify];
|
|
[mockScrollDelegate verify];
|
|
}
|
|
|
|
- (void)test_whenDidEndDragging_thatScrollViewDelegateReceivesMethod {
|
|
self.dataSource.objects = @[@0, @1, @2];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
|
|
id mockCollectionDelegate = [OCMockObject mockForProtocol:@protocol(UICollectionViewDelegate)];
|
|
id mockScrollDelegate = [OCMockObject mockForProtocol:@protocol(UIScrollViewDelegate)];
|
|
self.adapter.collectionViewDelegate = mockCollectionDelegate;
|
|
self.adapter.scrollViewDelegate = mockScrollDelegate;
|
|
|
|
[[mockCollectionDelegate reject] scrollViewDidEndDragging:self.collectionView willDecelerate:NO];
|
|
[[mockScrollDelegate expect] scrollViewDidEndDragging:self.collectionView willDecelerate:NO];
|
|
|
|
// simulates the scrollview delegate telling the adapter that it will end dragging
|
|
[self.adapter scrollViewDidEndDragging:self.collectionView willDecelerate:NO];
|
|
|
|
[mockCollectionDelegate verify];
|
|
[mockScrollDelegate verify];
|
|
}
|
|
|
|
- (void)test_whenDidEndDecelerating_thatScrollViewDelegateReceivesMethod {
|
|
self.dataSource.objects = @[@0, @1, @2];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
|
|
id mockCollectionDelegate = [OCMockObject mockForProtocol:@protocol(UICollectionViewDelegate)];
|
|
id mockScrollDelegate = [OCMockObject mockForProtocol:@protocol(UIScrollViewDelegate)];
|
|
self.adapter.collectionViewDelegate = mockCollectionDelegate;
|
|
self.adapter.scrollViewDelegate = mockScrollDelegate;
|
|
|
|
[[mockCollectionDelegate reject] scrollViewDidEndDecelerating:self.collectionView];
|
|
[[mockScrollDelegate expect] scrollViewDidEndDecelerating:self.collectionView];
|
|
|
|
// simulates the scrollview delegate telling the adapter that it ended decelerating
|
|
[self.adapter scrollViewDidEndDecelerating:self.collectionView];
|
|
|
|
[mockCollectionDelegate verify];
|
|
[mockScrollDelegate verify];
|
|
}
|
|
|
|
- (void)test_whenReloadingObjectsThatDontExist_thatAdapterContinues {
|
|
self.dataSource.objects = @[@0, @1, @2];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
[self.adapter reloadObjects:@[@1, @3]];
|
|
XCTAssertEqual(self.collectionView.numberOfSections, 3);
|
|
}
|
|
|
|
- (void)test_whenDeselectingThroughContext_thatCellDeselected {
|
|
self.dataSource.objects = @[@1, @2, @3];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
|
|
NSIndexPath *path = [NSIndexPath indexPathForItem:0 inSection:0];
|
|
[self.collectionView selectItemAtIndexPath:path animated:NO scrollPosition:UICollectionViewScrollPositionTop];
|
|
XCTAssertTrue([[self.collectionView cellForItemAtIndexPath:path] isSelected]);
|
|
|
|
id section = [self.adapter sectionControllerForObject:@1];
|
|
[self.adapter deselectItemAtIndex:0 sectionController:section animated:NO];
|
|
XCTAssertFalse([[self.collectionView cellForItemAtIndexPath:path] isSelected]);
|
|
}
|
|
|
|
- (void)test_whenSelectingThroughContext_thatCellSelected {
|
|
self.dataSource.objects = @[@1, @2, @3];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
|
|
NSIndexPath *path = [NSIndexPath indexPathForItem:0 inSection:0];
|
|
[self.adapter selectItemAtIndex:0 sectionController:[self.adapter sectionControllerForObject:@1] animated:NO scrollPosition:UICollectionViewScrollPositionTop];
|
|
XCTAssertTrue([[self.collectionView cellForItemAtIndexPath:path] isSelected]);
|
|
}
|
|
|
|
- (void)test_whenScrollingToIndex_withSectionController_thatPositionCorrect {
|
|
self.dataSource.objects = @[@1, @2, @3, @4, @5, @6, @7, @8, @9, @10, @11, @12, @13, @14, @15, @16, @17, @18, @19];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
|
|
IGListSectionController *section = [self.adapter sectionControllerForObject:@8];
|
|
[section.collectionContext scrollToSectionController:section atIndex:0 scrollPosition:UICollectionViewScrollPositionTop animated:NO];
|
|
XCTAssertEqual(self.collectionView.contentOffset.x, 0);
|
|
XCTAssertEqual(self.collectionView.contentOffset.y, 280);
|
|
}
|
|
|
|
- (void)test_whenDisplayingSectionController_withOnlySupplementaryView_thatDisplayEventStillSent {
|
|
self.dataSource.objects = @[@0];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
XCTAssertNil([self.collectionView supplementaryViewForElementKind:UICollectionElementKindSectionHeader atIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]]);
|
|
|
|
IGTestSupplementarySource *supplementarySource = [IGTestSupplementarySource new];
|
|
supplementarySource.collectionContext = self.adapter;
|
|
supplementarySource.supportedElementKinds = @[UICollectionElementKindSectionHeader];
|
|
|
|
IGListSectionController *controller = [self.adapter sectionControllerForObject:@0];
|
|
controller.supplementaryViewSource = supplementarySource;
|
|
supplementarySource.sectionController = controller;
|
|
|
|
id mockDisplayDelegate = [OCMockObject mockForProtocol:@protocol(IGListDisplayDelegate)];
|
|
[[mockDisplayDelegate expect] listAdapter:self.adapter willDisplaySectionController:controller];
|
|
[[mockDisplayDelegate reject] listAdapter:self.adapter willDisplaySectionController:controller cell:[OCMArg any] atIndex:0];
|
|
|
|
controller.displayDelegate = mockDisplayDelegate;
|
|
|
|
[self.adapter performUpdatesAnimated:NO completion:nil];
|
|
XCTAssertNotNil([self.collectionView supplementaryViewForElementKind:UICollectionElementKindSectionHeader atIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]]);
|
|
|
|
[mockDisplayDelegate verify];
|
|
}
|
|
|
|
- (void)test_whenEndingDisplayOfSectionController_withOnlySupplementaryView_thatDisplayEventStillSent {
|
|
self.dataSource.objects = @[@0];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
XCTAssertNil([self.collectionView supplementaryViewForElementKind:UICollectionElementKindSectionHeader atIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]]);
|
|
|
|
IGTestSupplementarySource *supplementarySource = [IGTestSupplementarySource new];
|
|
supplementarySource.collectionContext = self.adapter;
|
|
supplementarySource.supportedElementKinds = @[UICollectionElementKindSectionHeader];
|
|
|
|
IGListSectionController *controller = [self.adapter sectionControllerForObject:@0];
|
|
controller.supplementaryViewSource = supplementarySource;
|
|
supplementarySource.sectionController = controller;
|
|
|
|
[self.adapter performUpdatesAnimated:NO completion:nil];
|
|
XCTAssertNotNil([self.collectionView supplementaryViewForElementKind:UICollectionElementKindSectionHeader atIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]]);
|
|
|
|
id mockDisplayDelegate = [OCMockObject mockForProtocol:@protocol(IGListDisplayDelegate)];
|
|
[[mockDisplayDelegate expect] listAdapter:self.adapter didEndDisplayingSectionController:controller];
|
|
[[mockDisplayDelegate reject] listAdapter:self.adapter didEndDisplayingSectionController:controller cell:[OCMArg any] atIndex:0];
|
|
|
|
controller.displayDelegate = mockDisplayDelegate;
|
|
|
|
controller.supplementaryViewSource = nil;
|
|
[self.adapter performUpdatesAnimated:NO completion:nil];
|
|
XCTAssertNil([self.collectionView supplementaryViewForElementKind:UICollectionElementKindSectionHeader atIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]]);
|
|
|
|
[mockDisplayDelegate verify];
|
|
}
|
|
|
|
- (void)test_whenWillDisplaySupplementaryView_thatCollectionViewDelegateReceivesEvents {
|
|
// silence display handler asserts
|
|
self.dataSource.objects = @[@1, @2];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
|
|
id mockDelegate = [OCMockObject mockForProtocol:@protocol(UICollectionViewDelegate)];
|
|
self.adapter.collectionViewDelegate = mockDelegate;
|
|
UICollectionReusableView *view = [UICollectionReusableView new];
|
|
NSString *kind = @"kind";
|
|
NSIndexPath *path = [NSIndexPath indexPathForItem:0 inSection:0];
|
|
[[mockDelegate expect] collectionView:self.collectionView willDisplaySupplementaryView:view forElementKind:kind atIndexPath:path];
|
|
[self.adapter collectionView:self.collectionView willDisplaySupplementaryView:view forElementKind:kind atIndexPath:path];
|
|
[mockDelegate verify];
|
|
}
|
|
|
|
- (void)test_whenEndDisplayingSupplementaryView_thatCollectionViewDelegateReceivesEvents {
|
|
// silence display handler asserts
|
|
self.dataSource.objects = @[@1, @2];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
|
|
id mockDelegate = [OCMockObject mockForProtocol:@protocol(UICollectionViewDelegate)];
|
|
self.adapter.collectionViewDelegate = mockDelegate;
|
|
UICollectionReusableView *view = [UICollectionReusableView new];
|
|
NSString *kind = @"kind";
|
|
NSIndexPath *path = [NSIndexPath indexPathForItem:0 inSection:0];
|
|
[[mockDelegate expect] collectionView:self.collectionView didEndDisplayingSupplementaryView:view forElementOfKind:kind atIndexPath:path];
|
|
[self.adapter collectionView:self.collectionView didEndDisplayingSupplementaryView:view forElementOfKind:kind atIndexPath:path];
|
|
[mockDelegate verify];
|
|
}
|
|
|
|
- (void)test_whenHighlightingCell_thatCollectionViewDelegateReceivesMethod {
|
|
self.dataSource.objects = @[@0, @1, @2];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
|
|
id mockDelegate = [OCMockObject mockForProtocol:@protocol(UICollectionViewDelegate)];
|
|
self.adapter.collectionViewDelegate = mockDelegate;
|
|
|
|
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
|
|
[[mockDelegate expect] collectionView:self.collectionView didHighlightItemAtIndexPath:indexPath];
|
|
|
|
// simulates the collectionview telling its delegate that it was highlighted
|
|
[self.adapter collectionView:self.collectionView didHighlightItemAtIndexPath:indexPath];
|
|
|
|
[mockDelegate verify];
|
|
}
|
|
|
|
- (void)test_whenHighlightingCell_thatSectionControllerReceivesMethod {
|
|
self.dataSource.objects = @[@0, @1, @2];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
|
|
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
|
|
|
|
// simulates the collectionview telling its delegate that it was highlighted
|
|
[self.adapter collectionView:self.collectionView didHighlightItemAtIndexPath:indexPath];
|
|
|
|
IGListTestSection *s0 = [self.adapter sectionControllerForObject:@0];
|
|
IGListTestSection *s1 = [self.adapter sectionControllerForObject:@1];
|
|
IGListTestSection *s2 = [self.adapter sectionControllerForObject:@2];
|
|
|
|
XCTAssertTrue(s0.wasHighlighted);
|
|
XCTAssertFalse(s1.wasHighlighted);
|
|
XCTAssertFalse(s2.wasHighlighted);
|
|
}
|
|
|
|
- (void)test_whenUnhighlightingCell_thatCollectionViewDelegateReceivesMethod {
|
|
self.dataSource.objects = @[@0, @1, @2];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
|
|
id mockDelegate = [OCMockObject mockForProtocol:@protocol(UICollectionViewDelegate)];
|
|
self.adapter.collectionViewDelegate = mockDelegate;
|
|
|
|
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
|
|
[[mockDelegate expect] collectionView:self.collectionView didUnhighlightItemAtIndexPath:indexPath];
|
|
|
|
// simulates the collectionview telling its delegate that it was unhighlighted
|
|
[self.adapter collectionView:self.collectionView didUnhighlightItemAtIndexPath:indexPath];
|
|
|
|
[mockDelegate verify];
|
|
}
|
|
|
|
- (void)test_whenUnlighlightingCell_thatSectionControllerReceivesMethod {
|
|
self.dataSource.objects = @[@0, @1, @2];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
|
|
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
|
|
|
|
// simulates the collectionview telling its delegate that it was unhighlighted
|
|
[self.adapter collectionView:self.collectionView didUnhighlightItemAtIndexPath:indexPath];
|
|
|
|
IGListTestSection *s0 = [self.adapter sectionControllerForObject:@0];
|
|
IGListTestSection *s1 = [self.adapter sectionControllerForObject:@1];
|
|
IGListTestSection *s2 = [self.adapter sectionControllerForObject:@2];
|
|
|
|
XCTAssertTrue(s0.wasUnhighlighted);
|
|
XCTAssertFalse(s1.wasUnhighlighted);
|
|
XCTAssertFalse(s2.wasUnhighlighted);
|
|
}
|
|
|
|
- (void)test_whenDataSourceDoesntHandleObject_thatObjectIsDropped {
|
|
// IGListTestAdapterDataSource does not handle NSStrings
|
|
self.dataSource.objects = @[@1, @"dog", @2];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
NSArray *expected = @[@1, @2];
|
|
XCTAssertEqualObjects(self.adapter.objects, expected);
|
|
}
|
|
|
|
- (void)test_whenSectionEdgeInsetIsNotZero {
|
|
// IGListTestAdapterDataSource does not handle NSStrings
|
|
self.dataSource.objects = @[@42];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
IGListSectionController *controller = [self.adapter sectionControllerForObject:@42];
|
|
IGAssertEqualSize([self.adapter containerSizeForSectionController:controller], 98, 98);
|
|
}
|
|
|
|
- (void)test_whenSectionControllerReturnsNegativeSize_thatAdapterReturnsZero {
|
|
self.dataSource.objects = @[@1];
|
|
IGListTestSection *section = [self.adapter sectionControllerForObject:self.dataSource.objects[0]];
|
|
section.size = CGSizeMake(-1, -1);
|
|
const CGSize size = [self.adapter sizeForItemAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]];
|
|
XCTAssertEqual(size.width, 0.0);
|
|
XCTAssertEqual(size.height, 0.0);
|
|
}
|
|
|
|
- (void)test_whenSupplementarySourceReturnsNegativeSize_thatAdapterReturnsZero {
|
|
self.dataSource.objects = @[@1];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
|
|
IGTestSupplementarySource *supplementarySource = [IGTestSupplementarySource new];
|
|
supplementarySource.collectionContext = self.adapter;
|
|
supplementarySource.supportedElementKinds = @[UICollectionElementKindSectionFooter];
|
|
supplementarySource.size = CGSizeMake(-1, -1);
|
|
|
|
IGListSectionController *controller = [self.adapter sectionControllerForObject:@1];
|
|
controller.supplementaryViewSource = supplementarySource;
|
|
supplementarySource.sectionController = controller;
|
|
|
|
const CGSize size = [self.adapter sizeForSupplementaryViewOfKind:UICollectionElementKindSectionHeader
|
|
atIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]];
|
|
XCTAssertEqual(size.width, 0.0);
|
|
XCTAssertEqual(size.height, 0.0);
|
|
}
|
|
|
|
- (void)test_whenQueryingContainerInset_thatMatchesCollectionView {
|
|
self.dataSource.objects = @[@2];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
self.collectionView.contentInset = UIEdgeInsetsMake(1, 2, 3, 4);
|
|
IGListSectionController *controller = [self.adapter sectionControllerForObject:@2];
|
|
const UIEdgeInsets inset = [controller.collectionContext containerInset];
|
|
XCTAssertEqual(inset.top, 1);
|
|
XCTAssertEqual(inset.left, 2);
|
|
XCTAssertEqual(inset.bottom, 3);
|
|
XCTAssertEqual(inset.right, 4);
|
|
}
|
|
|
|
- (void)test_whenQueryingInsetContainerSize_thatResultIsBoundsInsetByContent {
|
|
self.dataSource.objects = @[@2];
|
|
[self.adapter reloadDataWithCompletion:nil];
|
|
self.collectionView.contentInset = UIEdgeInsetsMake(1, 2, 3, 4);
|
|
IGListSectionController *controller = [self.adapter sectionControllerForObject:@2];
|
|
const CGSize size = [controller.collectionContext insetContainerSize];
|
|
XCTAssertEqual(size.width, 94);
|
|
XCTAssertEqual(size.height, 96);
|
|
}
|
|
|
|
- (void)test_whenInsertingAtBeginning_thatAllSectionControllerIndexesUpdateCorrectly_forInsertAtHead {
|
|
NSNumber *zero = @0;
|
|
NSNumber *one = @1;
|
|
NSNumber *two = @2;
|
|
NSNumber *three = @3;
|
|
self.dataSource.objects = @[one, two, three];
|
|
[self.adapter performUpdatesAnimated:NO completion:nil];
|
|
|
|
IGListSectionController *controller1a = [self.adapter sectionControllerForObject:one];
|
|
XCTAssertEqual(controller1a.section, 0);
|
|
XCTAssertTrue(controller1a.isFirstSection);
|
|
|
|
XCTAssertEqual([self.adapter sectionControllerForObject:two].section, 1);
|
|
XCTAssertEqual([self.adapter sectionControllerForObject:three].section, 2);
|
|
XCTAssertTrue([self.adapter sectionControllerForObject:three].isLastSection);
|
|
|
|
self.dataSource.objects = @[zero, one, two, three];
|
|
[self.adapter performUpdatesAnimated:NO completion:nil];
|
|
|
|
IGListSectionController *controller0 = [self.adapter sectionControllerForObject:zero];
|
|
XCTAssertEqual(controller0.section, 0);
|
|
XCTAssertTrue(controller0.isFirstSection);
|
|
|
|
IGListSectionController *controller1b = [self.adapter sectionControllerForObject:one];
|
|
XCTAssertEqual(controller1b.section, 1);
|
|
XCTAssertFalse(controller1b.isFirstSection);
|
|
|
|
XCTAssertEqual([self.adapter sectionControllerForObject:two].section, 2);
|
|
XCTAssertEqual([self.adapter sectionControllerForObject:three].section, 3);
|
|
XCTAssertTrue([self.adapter sectionControllerForObject:three].isLastSection);
|
|
}
|
|
|
|
- (void)test_whenRemovingFromHead_thatAllSectionControllerIndexesUpdateCorrectly_RemovedSectionControllerIsNotFound {
|
|
NSNumber *zero = @0;
|
|
NSNumber *one = @1;
|
|
NSNumber *two = @2;
|
|
NSNumber *three = @3;
|
|
self.dataSource.objects = @[zero, one, two, three];
|
|
[self.adapter performUpdatesAnimated:NO completion:nil];
|
|
|
|
IGListSectionController *zeroController = [self.adapter sectionControllerForSection:0];
|
|
XCTAssertEqual(zeroController.section, 0);
|
|
XCTAssertTrue(zeroController.isFirstSection);
|
|
|
|
IGListSectionController *oneController = [self.adapter sectionControllerForSection:1];
|
|
XCTAssertEqual(oneController.section, 1);
|
|
XCTAssertFalse(oneController.isFirstSection);
|
|
|
|
IGListSectionController *threeController = [self.adapter sectionControllerForSection:3];
|
|
XCTAssertEqual(threeController.section, 3);
|
|
XCTAssertTrue(threeController.isLastSection);
|
|
|
|
self.dataSource.objects = @[one, two, three];
|
|
[self.adapter performUpdatesAnimated:NO completion:nil];
|
|
|
|
XCTAssertEqual(zeroController.section, NSNotFound);
|
|
XCTAssertFalse(zeroController.isFirstSection);
|
|
|
|
XCTAssertEqual(oneController.section, 0);
|
|
XCTAssertTrue(oneController.isFirstSection);
|
|
|
|
XCTAssertEqual(threeController.section, 2);
|
|
XCTAssertTrue(threeController.isLastSection);
|
|
}
|
|
|
|
- (void)test_whenRemovingFromMiddle_thatAllSectionControllerIndexesUpdateCorrectly_removedSectionControllerIsNotFound {
|
|
NSNumber *zero = @0;
|
|
NSNumber *one = @1;
|
|
NSNumber *two = @2;
|
|
NSNumber *three = @3;
|
|
self.dataSource.objects = @[zero, one, two, three];
|
|
[self.adapter performUpdatesAnimated:NO completion:nil];
|
|
|
|
IGListSectionController *zeroController = [self.adapter sectionControllerForSection:0];
|
|
XCTAssertEqual(zeroController.section, 0);
|
|
XCTAssertTrue(zeroController.isFirstSection);
|
|
|
|
IGListSectionController *oneController = [self.adapter sectionControllerForSection:1];
|
|
XCTAssertEqual(oneController.section, 1);
|
|
XCTAssertFalse(oneController.isFirstSection);
|
|
|
|
IGListSectionController *threeController = [self.adapter sectionControllerForSection:3];
|
|
XCTAssertEqual(threeController.section, 3);
|
|
XCTAssertTrue(threeController.isLastSection);
|
|
|
|
self.dataSource.objects = @[zero, two, three];
|
|
[self.adapter performUpdatesAnimated:NO completion:nil];
|
|
|
|
XCTAssertEqual(zeroController.section, 0);
|
|
XCTAssertTrue(zeroController.isFirstSection);
|
|
|
|
XCTAssertEqual(oneController.section, NSNotFound);
|
|
XCTAssertFalse(oneController.isFirstSection);
|
|
|
|
XCTAssertEqual(threeController.section, 2);
|
|
XCTAssertTrue(threeController.isLastSection);
|
|
}
|
|
|
|
- (void)test_withStrongRefToSectionController_thatAdaptersectionIsZero_thatSectionControllerIndexDoesNotChange {
|
|
IGListSectionController *sc = nil;
|
|
|
|
// hold a weak reference to simulate what would happen to the collectionContext object on a section controller
|
|
// if the section controller were held strongly by an async block and the rest of the infra was deallocated
|
|
__weak IGListAdapter *wAdapter = nil;
|
|
|
|
@autoreleasepool {
|
|
IGListTestAdapterDataSource *dataSource = [IGListTestAdapterDataSource new];
|
|
IGListReloadDataUpdater *updater = [IGListReloadDataUpdater new];
|
|
IGListAdapter *adapter = [[IGListAdapter alloc] initWithUpdater:updater
|
|
viewController:nil];
|
|
adapter.dataSource = dataSource;
|
|
adapter.collectionView = self.collectionView;
|
|
wAdapter = adapter;
|
|
|
|
dataSource.objects = @[@0, @1, @2];
|
|
[adapter performUpdatesAnimated:NO completion:nil];
|
|
|
|
sc = [adapter sectionControllerForSection:1];
|
|
XCTAssertEqual(sc.section, 1);
|
|
}
|
|
|
|
XCTAssertEqual(sc.section, NSNotFound);
|
|
XCTAssertEqual([wAdapter sectionForSectionController:sc], 0);
|
|
}
|
|
|
|
- (void)test_whenSwappingCollectionViews_withMultipleAdapters_thatDoesntNilOtherAdaptersCollectionView {
|
|
IGListTestAdapterDataSource *dataSource1 = [IGListTestAdapterDataSource new];
|
|
IGListAdapter *adapter1 = [[IGListAdapter alloc] initWithUpdater:[IGListAdapterUpdater new] viewController:nil];
|
|
adapter1.dataSource = dataSource1;
|
|
|
|
IGListTestAdapterDataSource *dataSource2 = [IGListTestAdapterDataSource new];
|
|
IGListAdapter *adapter2 = [[IGListAdapter alloc] initWithUpdater:[IGListAdapterUpdater new] viewController:nil];
|
|
adapter2.dataSource = dataSource2;
|
|
|
|
UICollectionView *collectionView1 = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:[UICollectionViewFlowLayout new]];
|
|
UICollectionView *collectionView2 = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:[UICollectionViewFlowLayout new]];
|
|
|
|
adapter1.collectionView = collectionView1;
|
|
adapter2.collectionView = collectionView2;
|
|
|
|
XCTAssertEqual(adapter1.collectionView, collectionView1);
|
|
XCTAssertEqual(collectionView1.dataSource, adapter1);
|
|
XCTAssertEqual(adapter2.collectionView, collectionView2);
|
|
XCTAssertEqual(collectionView2.dataSource, adapter2);
|
|
|
|
adapter2.collectionView = collectionView1;
|
|
|
|
XCTAssertEqual(adapter2.collectionView, collectionView1);
|
|
XCTAssertEqual(collectionView1.dataSource, adapter2);
|
|
XCTAssertNil(adapter1.collectionView);
|
|
|
|
adapter1.collectionView = collectionView2;
|
|
|
|
XCTAssertEqual(adapter1.collectionView, collectionView2);
|
|
XCTAssertEqual(collectionView2.dataSource, adapter1);
|
|
XCTAssertEqual(adapter2.collectionView, collectionView1);
|
|
XCTAssertEqual(collectionView1.dataSource, adapter2);
|
|
}
|
|
|
|
- (void)test_whenPrefetchingEnabled_thatSetterDisables {
|
|
UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:[UICollectionViewFlowLayout new]];
|
|
collectionView.prefetchingEnabled = YES;
|
|
|
|
IGListAdapter *adapter = [[IGListAdapter alloc] initWithUpdater:[IGListAdapterUpdater new] viewController:nil];
|
|
adapter.collectionView = collectionView;
|
|
|
|
XCTAssertFalse(collectionView.prefetchingEnabled);
|
|
}
|
|
|
|
- (void)test_whenSectionControllerReorderDisabled_thatAdapterReorderDisabled {
|
|
BOOL isReorderable = NO;
|
|
|
|
IGListTestAdapterReorderingDataSource *dataSource = [IGListTestAdapterReorderingDataSource new];
|
|
dataSource.objects = @[@0, @1, @2];
|
|
self.adapter.dataSource = dataSource;
|
|
self.adapter.moveDelegate = dataSource;
|
|
|
|
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
|
|
IGTestReorderableSection *section = (IGTestReorderableSection *)[self.adapter sectionControllerForSection:0];
|
|
section.isReorderable = isReorderable;
|
|
|
|
[self.adapter performUpdatesAnimated:NO completion:nil];
|
|
|
|
BOOL canMove = [self.adapter collectionView:self.collectionView canMoveItemAtIndexPath:indexPath];
|
|
XCTAssertFalse(canMove);
|
|
}
|
|
|
|
- (void)test_whenSectionControllerReorderEnabled_thatAdapterReorderEnabled {
|
|
BOOL isReorderable = YES;
|
|
|
|
IGListTestAdapterReorderingDataSource *dataSource = [IGListTestAdapterReorderingDataSource new];
|
|
dataSource.objects = @[@0, @1, @2];
|
|
self.adapter.dataSource = dataSource;
|
|
self.adapter.moveDelegate = dataSource;
|
|
|
|
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
|
|
IGTestReorderableSection *section = (IGTestReorderableSection *)[self.adapter sectionControllerForSection:0];
|
|
section.isReorderable = isReorderable;
|
|
|
|
[self.adapter performUpdatesAnimated:NO completion:nil];
|
|
|
|
BOOL canMove = [self.adapter collectionView:self.collectionView canMoveItemAtIndexPath:indexPath];
|
|
XCTAssertTrue(canMove);
|
|
}
|
|
|
|
- (NSIndexPath *)interpretedIndexPathFromIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath {
|
|
UICollectionViewLayout *layout = self.collectionView.collectionViewLayout;
|
|
NSIndexPath *updatedIndexPath = [layout updatedTargetForInteractivelyMovingItem:fromIndexPath
|
|
toIndexPath:toIndexPath
|
|
adapter:self.adapter];
|
|
if (!updatedIndexPath) {
|
|
return toIndexPath;
|
|
}
|
|
return updatedIndexPath;
|
|
}
|
|
|
|
- (void)test_whenSectionIsInteractivelyReordered_thatIndexesUpdateCorrectly {
|
|
IGListTestAdapterReorderingDataSource *dataSource = [IGListTestAdapterReorderingDataSource new];
|
|
dataSource.objects = @[@0, @1, @2];
|
|
self.adapter.dataSource = dataSource;
|
|
self.adapter.moveDelegate = dataSource;
|
|
|
|
IGTestReorderableSection *section0 = (IGTestReorderableSection *)[self.adapter sectionControllerForSection:0];
|
|
IGTestReorderableSection *section1 = (IGTestReorderableSection *)[self.adapter sectionControllerForSection:1];
|
|
IGTestReorderableSection *section2 = (IGTestReorderableSection *)[self.adapter sectionControllerForSection:2];
|
|
section0.sectionObject = [IGTestReorderableSectionObject sectionWithObjects:@[@0]];
|
|
section1.sectionObject = [IGTestReorderableSectionObject sectionWithObjects:@[@0]];
|
|
section2.sectionObject = [IGTestReorderableSectionObject sectionWithObjects:@[@0]];
|
|
section2.isReorderable = YES;
|
|
|
|
[self.adapter performUpdatesAnimated:NO completion:nil];
|
|
|
|
NSIndexPath *fromIndexPath, *toIndexPath, *interpretedPath;
|
|
|
|
// move the last section into the first position, dropping into the end of the first section
|
|
fromIndexPath = [NSIndexPath indexPathForItem:0 inSection:2];
|
|
toIndexPath = [NSIndexPath indexPathForItem:1 inSection:0];
|
|
interpretedPath = [self interpretedIndexPathFromIndexPath:fromIndexPath toIndexPath:toIndexPath];
|
|
[self.adapter collectionView:self.collectionView moveItemAtIndexPath:fromIndexPath toIndexPath:interpretedPath];
|
|
|
|
XCTAssertEqual(section0, [self.adapter sectionControllerForSection:0]);
|
|
XCTAssertEqual(section2, [self.adapter sectionControllerForSection:1]);
|
|
XCTAssertEqual(section1, [self.adapter sectionControllerForSection:2]);
|
|
|
|
// move the last section into the first position, dropping into the start of the first section
|
|
fromIndexPath = [NSIndexPath indexPathForItem:0 inSection:2];
|
|
toIndexPath = [NSIndexPath indexPathForItem:0 inSection:0];
|
|
interpretedPath = [self interpretedIndexPathFromIndexPath:fromIndexPath toIndexPath:toIndexPath];
|
|
[self.adapter collectionView:self.collectionView moveItemAtIndexPath:fromIndexPath toIndexPath:interpretedPath];
|
|
|
|
XCTAssertEqual(section1, [self.adapter sectionControllerForSection:0]);
|
|
XCTAssertEqual(section0, [self.adapter sectionControllerForSection:1]);
|
|
XCTAssertEqual(section2, [self.adapter sectionControllerForSection:2]);
|
|
|
|
// move the first section into the last position, dropping into the start of the last section
|
|
fromIndexPath = [NSIndexPath indexPathForItem:0 inSection:0];
|
|
toIndexPath = [NSIndexPath indexPathForItem:0 inSection:2];
|
|
interpretedPath = [self interpretedIndexPathFromIndexPath:fromIndexPath toIndexPath:toIndexPath];
|
|
[self.adapter collectionView:self.collectionView moveItemAtIndexPath:fromIndexPath toIndexPath:interpretedPath];
|
|
|
|
XCTAssertEqual(section0, [self.adapter sectionControllerForSection:0]);
|
|
XCTAssertEqual(section1, [self.adapter sectionControllerForSection:1]);
|
|
XCTAssertEqual(section2, [self.adapter sectionControllerForSection:2]);
|
|
|
|
// move the first section into the last position, dropping into the end of the last section
|
|
fromIndexPath = [NSIndexPath indexPathForItem:0 inSection:0];
|
|
toIndexPath = [NSIndexPath indexPathForItem:1 inSection:2];
|
|
interpretedPath = [self interpretedIndexPathFromIndexPath:fromIndexPath toIndexPath:toIndexPath];
|
|
[self.adapter collectionView:self.collectionView moveItemAtIndexPath:fromIndexPath toIndexPath:interpretedPath];
|
|
|
|
XCTAssertEqual(section1, [self.adapter sectionControllerForSection:0]);
|
|
XCTAssertEqual(section2, [self.adapter sectionControllerForSection:1]);
|
|
XCTAssertEqual(section0, [self.adapter sectionControllerForSection:2]);
|
|
}
|
|
|
|
- (void)test_whenItemsInSectionAreInteractivelyReordered_thatIndexesUpdateCorrectly {
|
|
IGListTestAdapterReorderingDataSource *dataSource = [IGListTestAdapterReorderingDataSource new];
|
|
dataSource.objects = @[@0];
|
|
self.adapter.dataSource = dataSource;
|
|
self.adapter.moveDelegate = dataSource;
|
|
|
|
NSArray *sectionObjects = @[@0, @1, @2];
|
|
|
|
IGTestReorderableSection *section = (IGTestReorderableSection *)[self.adapter sectionControllerForSection:0];
|
|
section.sectionObject = [IGTestReorderableSectionObject sectionWithObjects:sectionObjects];
|
|
section.isReorderable = YES;
|
|
|
|
[self.adapter performUpdatesAnimated:NO completion:nil];
|
|
|
|
NSIndexPath *fromIndexPath, *toIndexPath;
|
|
|
|
// move the last item into the first position
|
|
fromIndexPath = [NSIndexPath indexPathForItem:2 inSection:0];
|
|
toIndexPath = [NSIndexPath indexPathForItem:0 inSection:0];
|
|
[self.adapter collectionView:self.collectionView moveItemAtIndexPath:fromIndexPath toIndexPath:toIndexPath];
|
|
|
|
XCTAssertEqual(sectionObjects[2], section.sectionObject.objects[0]);
|
|
XCTAssertEqual(sectionObjects[0], section.sectionObject.objects[1]);
|
|
XCTAssertEqual(sectionObjects[1], section.sectionObject.objects[2]);
|
|
|
|
// move the last item into the middle position
|
|
fromIndexPath = [NSIndexPath indexPathForItem:2 inSection:0];
|
|
toIndexPath = [NSIndexPath indexPathForItem:1 inSection:0];
|
|
[self.adapter collectionView:self.collectionView moveItemAtIndexPath:fromIndexPath toIndexPath:toIndexPath];
|
|
|
|
XCTAssertEqual(sectionObjects[2], section.sectionObject.objects[0]);
|
|
XCTAssertEqual(sectionObjects[1], section.sectionObject.objects[1]);
|
|
XCTAssertEqual(sectionObjects[0], section.sectionObject.objects[2]);
|
|
}
|
|
|
|
- (void)test_whenItemsAreInteractivelyReorderedAcrossSections_thatIndexesRevertToOriginalState {
|
|
IGListTestAdapterReorderingDataSource *dataSource = [IGListTestAdapterReorderingDataSource new];
|
|
dataSource.objects = @[@0, @1];
|
|
self.adapter.dataSource = dataSource;
|
|
self.adapter.moveDelegate = dataSource;
|
|
|
|
NSArray *section0Objects = @[@0, @1, @2];
|
|
NSArray *section1Objects = @[@3, @4, @5];
|
|
|
|
IGTestReorderableSection *section0 = (IGTestReorderableSection *)[self.adapter sectionControllerForSection:0];
|
|
section0.sectionObject = [IGTestReorderableSectionObject sectionWithObjects:section0Objects];
|
|
IGTestReorderableSection *section1 = (IGTestReorderableSection *)[self.adapter sectionControllerForSection:1];
|
|
section1.sectionObject = [IGTestReorderableSectionObject sectionWithObjects:section1Objects];
|
|
section1.isReorderable = YES;
|
|
|
|
[self.adapter performUpdatesAnimated:NO completion:nil];
|
|
|
|
NSIndexPath *fromIndexPath, *toIndexPath;
|
|
|
|
// move an item from section 1 to section 0 and check that they are reverted
|
|
fromIndexPath = [NSIndexPath indexPathForItem:0 inSection:1];
|
|
toIndexPath = [NSIndexPath indexPathForItem:0 inSection:0];
|
|
|
|
[self.collectionView performBatchUpdates:^{
|
|
[self.collectionView moveItemAtIndexPath:fromIndexPath toIndexPath:toIndexPath];
|
|
|
|
[self.collectionView.dataSource collectionView:self.collectionView
|
|
moveItemAtIndexPath:fromIndexPath
|
|
toIndexPath:toIndexPath];
|
|
} completion:nil];
|
|
|
|
XCTAssertEqual(section0Objects[0], section0.sectionObject.objects[0]);
|
|
XCTAssertEqual(section0Objects[1], section0.sectionObject.objects[1]);
|
|
XCTAssertEqual(section0Objects[2], section0.sectionObject.objects[2]);
|
|
XCTAssertEqual(section1Objects[0], section1.sectionObject.objects[0]);
|
|
XCTAssertEqual(section1Objects[1], section1.sectionObject.objects[1]);
|
|
XCTAssertEqual(section1Objects[2], section1.sectionObject.objects[2]);
|
|
}
|
|
|
|
@end
|