Files
IGListKit/Tests/IGListCollectionViewLayoutTests.m
Artem Goncharov e729ab8211 Fixed empty space bug in CollectionView
Summary:
Fixed situation when cells with small height don't intersect with the _Rect_ and stop the enumeration that cause empty spaces in _collectionView_.

Issue fixed: # [680](https://github.com/Instagram/IGListKit/issues/680)

- [x] All tests pass. Demo project builds and runs.
- [x] I added tests, an experiment, or detailed why my change isn't tested.
- [x] I added an entry to the `CHANGELOG.md` for any breaking changes, enhancements, or bug fixes.
- [x] I have reviewed the [contributing guide](https://github.com/Instagram/IGListKit/blob/master/.github/CONTRIBUTING.md)
Closes https://github.com/Instagram/IGListKit/pull/684

Differential Revision: D4929315

Pulled By: rnystrom

fbshipit-source-id: 4437df21772697a9a6421d213f4fed7b8470371b
2017-04-21 08:20:16 -07:00

774 lines
48 KiB
Objective-C

/**
* Copyright (c) 2016-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import <XCTest/XCTest.h>
#import <IGListKit/IGListCollectionViewLayout.h>
#import "IGListCollectionViewLayoutInternal.h"
#import "IGLayoutTestDataSource.h"
#import "IGLayoutTestItem.h"
#import "IGLayoutTestSection.h"
#import "IGListTestHelpers.h"
@interface IGListCollectionViewLayoutTests : XCTestCase
@property (nonatomic, strong) IGListCollectionViewLayout *layout;
@property (nonatomic, strong) UICollectionView *collectionView;
@property (nonatomic, strong) IGLayoutTestDataSource *dataSource;
@end
static const CGRect kTestFrame = (CGRect){{0, 0}, {100, 100}};
@implementation IGListCollectionViewLayoutTests
- (UICollectionViewCell *)cellForSection:(NSInteger)section item:(NSInteger)item {
return [self.collectionView cellForItemAtIndexPath:genIndexPath(section, item)];
}
- (UICollectionReusableView *)headerForSection:(NSInteger)section {
return [self.collectionView supplementaryViewForElementKind:UICollectionElementKindSectionHeader atIndexPath:genIndexPath(section, 0)];
}
- (void)setUpWithStickyHeaders:(BOOL)sticky topInset:(CGFloat)inset {
[self setUpWithStickyHeaders:sticky topInset:inset stretchToEdge:NO];
}
- (void)setUpWithStickyHeaders:(BOOL)sticky topInset:(CGFloat)inset stretchToEdge:(BOOL)stretchToEdge {
self.layout = [[IGListCollectionViewLayout alloc] initWithStickyHeaders:sticky topContentInset:inset stretchToEdge:stretchToEdge];
self.dataSource = [IGLayoutTestDataSource new];
self.collectionView = [[UICollectionView alloc] initWithFrame:kTestFrame collectionViewLayout:self.layout];
self.collectionView.dataSource = self.dataSource;
self.collectionView.delegate = self.dataSource;
[self.dataSource configCollectionView:self.collectionView];
}
- (void)tearDown {
[super tearDown];
self.collectionView = nil;
self.layout = nil;
self.dataSource = nil;
}
- (void)prepareWithData:(NSArray<IGLayoutTestSection *> *)data {
self.dataSource.sections = data;
[self.collectionView reloadData];
[self.collectionView layoutIfNeeded];
}
- (void)test_whenEmptyData_thatContentSizeZero {
[self setUpWithStickyHeaders:YES topInset:0];
[self prepareWithData:nil];
// check so that nil messaging doesn't default size to 0
XCTAssertEqual(self.layout.collectionView, self.collectionView);
XCTAssertTrue(CGSizeEqualToSize(CGSizeZero, self.collectionView.contentSize));
}
- (void)test_whenLayingOutCells_withHeaderHeight_withLineSpacing_withInsets_thatFramesCorrect {
[self setUpWithStickyHeaders:NO topInset:0];
const CGFloat headerHeight = 10;
const CGFloat lineSpacing = 10;
const UIEdgeInsets insets = UIEdgeInsetsMake(10, 10, 5, 5);
[self prepareWithData:@[
[[IGLayoutTestSection alloc] initWithInsets:insets
lineSpacing:lineSpacing
interitemSpacing:0
headerHeight:headerHeight
items:@[
[[IGLayoutTestItem alloc] initWithSize:(CGSize){85,10}],
[[IGLayoutTestItem alloc] initWithSize:(CGSize){85,20}],
]],
[[IGLayoutTestSection alloc] initWithInsets:insets
lineSpacing:lineSpacing
interitemSpacing:0
headerHeight:headerHeight
items:@[
[[IGLayoutTestItem alloc] initWithSize:(CGSize){85,30}],
]],
]];
XCTAssertEqual(self.collectionView.contentSize.height, 120);
IGAssertEqualFrame([self headerForSection:0].frame, 10, 10, 85, 10);
IGAssertEqualFrame([self cellForSection:0 item:0].frame, 10, 20, 85, 10);
IGAssertEqualFrame([self cellForSection:0 item:1].frame, 10, 40, 85, 20);
IGAssertEqualFrame([self headerForSection:1].frame, 10, 75, 85, 10);
IGAssertEqualFrame([self cellForSection:1 item:0].frame, 10, 85, 85, 30);
}
- (void)test_whenUsingStickyHeaders_withSimulatedScrolling_thatYPositionsAdjusted {
[self setUpWithStickyHeaders:YES topInset:10];
[self prepareWithData:@[
[[IGLayoutTestSection alloc] initWithInsets:UIEdgeInsetsZero
lineSpacing:0
interitemSpacing:0
headerHeight:10
items:@[
[[IGLayoutTestItem alloc] initWithSize:(CGSize){100,20}],
[[IGLayoutTestItem alloc] initWithSize:(CGSize){100,20}],
]],
[[IGLayoutTestSection alloc] initWithInsets:UIEdgeInsetsZero
lineSpacing:0
interitemSpacing:0
headerHeight:10
items:@[
[[IGLayoutTestItem alloc] initWithSize:(CGSize){100,30}],
[[IGLayoutTestItem alloc] initWithSize:(CGSize){100,30}],
[[IGLayoutTestItem alloc] initWithSize:(CGSize){100,30}],
]],
]];
// scroll header 0 halfway
self.collectionView.contentOffset = CGPointMake(0, 5);
[self.collectionView layoutIfNeeded];
IGAssertEqualFrame([self headerForSection:0].frame, 0, 15, 100, 10);
IGAssertEqualFrame([self headerForSection:1].frame, 0, 50, 100, 10);
// scroll header 0 off and 1 up
self.collectionView.contentOffset = CGPointMake(0, 45);
[self.collectionView layoutIfNeeded];
IGAssertEqualFrame([self headerForSection:0].frame, 0, 40, 100, 10);
IGAssertEqualFrame([self headerForSection:1].frame, 0, 55, 100, 10);
}
- (void)test_whenAdjustingTopYInset_withVaryingHeaderHeights_thatYPositionsUpdated {
[self setUpWithStickyHeaders:YES topInset:10];
[self prepareWithData:@[
[[IGLayoutTestSection alloc] initWithInsets:UIEdgeInsetsZero
lineSpacing:0
interitemSpacing:0
headerHeight:10
items:@[
[[IGLayoutTestItem alloc] initWithSize:(CGSize){100,10}],
[[IGLayoutTestItem alloc] initWithSize:(CGSize){100,20}],
]],
[[IGLayoutTestSection alloc] initWithInsets:UIEdgeInsetsZero
lineSpacing:0
interitemSpacing:0
headerHeight:10
items:@[
[[IGLayoutTestItem alloc] initWithSize:(CGSize){100,30}],
[[IGLayoutTestItem alloc] initWithSize:(CGSize){100,40}],
[[IGLayoutTestItem alloc] initWithSize:(CGSize){100,50}],
]],
]];
// scroll header 0 off and 1 up
self.collectionView.contentOffset = CGPointMake(0, 35);
[self.collectionView layoutIfNeeded];
IGAssertEqualFrame([self headerForSection:0].frame, 0, 30, 100, 10);
IGAssertEqualFrame([self headerForSection:1].frame, 0, 45, 100, 10);
self.layout.stickyHeaderOriginYAdjustment = -10;
[self.collectionView layoutIfNeeded];
IGAssertEqualFrame([self headerForSection:0].frame, 0, 30, 100, 10);
IGAssertEqualFrame([self headerForSection:1].frame, 0, 40, 100, 10);
self.layout.stickyHeaderOriginYAdjustment = 10;
[self.collectionView layoutIfNeeded];
IGAssertEqualFrame([self headerForSection:0].frame, 0, 30, 100, 10);
IGAssertEqualFrame([self headerForSection:1].frame, 0, 55, 100, 10);
}
- (void)test_whenItemsSmallerThanContainerWidth_with0Insets_with0LineSpacing_with0Interitem_thatItemsFitSameRow {
[self setUpWithStickyHeaders:NO topInset:0];
[self prepareWithData:@[
[[IGLayoutTestSection alloc] initWithInsets:UIEdgeInsetsZero
lineSpacing:0
interitemSpacing:0
headerHeight:0
items:@[
[[IGLayoutTestItem alloc] initWithSize:(CGSize){33,33}],
[[IGLayoutTestItem alloc] initWithSize:(CGSize){33,33}],
[[IGLayoutTestItem alloc] initWithSize:(CGSize){33,33}],
]],
[[IGLayoutTestSection alloc] initWithInsets:UIEdgeInsetsZero
lineSpacing:0
interitemSpacing:0
headerHeight:0
items:@[
[[IGLayoutTestItem alloc] initWithSize:(CGSize){33,33}],
]],
]];
XCTAssertEqual(self.collectionView.contentSize.height, 66);
IGAssertEqualFrame([self cellForSection:0 item:0].frame, 0, 0, 33, 33);
IGAssertEqualFrame([self cellForSection:0 item:1].frame, 33, 0, 33, 33);
IGAssertEqualFrame([self cellForSection:0 item:2].frame, 66, 0, 33, 33);
IGAssertEqualFrame([self cellForSection:1 item:0].frame, 0, 33, 33, 33);
}
- (void)test_whenItemsSmallerThanContainerWidth_withHalfPointItemSpacing_with0Insets_with0LineSpacing_thatItemsFitSameRow {
[self setUpWithStickyHeaders:NO topInset:0];
[self prepareWithData:@[
[[IGLayoutTestSection alloc] initWithInsets:UIEdgeInsetsZero
lineSpacing:0
interitemSpacing:0.5
headerHeight:0
items:@[
[[IGLayoutTestItem alloc] initWithSize:(CGSize){33,33}],
[[IGLayoutTestItem alloc] initWithSize:(CGSize){33,33}],
[[IGLayoutTestItem alloc] initWithSize:(CGSize){33,33}],
]],
]];
XCTAssertEqual(self.collectionView.contentSize.height, 33);
IGAssertEqualFrame([self cellForSection:0 item:0].frame, 0, 0, 33, 33);
const CGRect rect = IGListRectIntegralScaled(CGRectMake(33.5, 0, 33, 33));
IGAssertEqualFrame([self cellForSection:0 item:1].frame, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
IGAssertEqualFrame([self cellForSection:0 item:2].frame, 67, 0, 33, 33);
}
- (void)test_whenSectionsSmallerThanContainerWidth_with0ItemSpacing_with0Insets_with0LineSpacing_thatSectionsFitSameRow {
[self setUpWithStickyHeaders:NO topInset:0];
[self prepareWithData:@[
[[IGLayoutTestSection alloc] initWithInsets:UIEdgeInsetsZero
lineSpacing:0
interitemSpacing:0
headerHeight:0
items:@[
[[IGLayoutTestItem alloc] initWithSize:(CGSize){33,33}],
]],
[[IGLayoutTestSection alloc] initWithInsets:UIEdgeInsetsZero
lineSpacing:0
interitemSpacing:0
headerHeight:0
items:@[
[[IGLayoutTestItem alloc] initWithSize:(CGSize){33,33}],
]],
[[IGLayoutTestSection alloc] initWithInsets:UIEdgeInsetsZero
lineSpacing:0
interitemSpacing:0
headerHeight:0
items:@[
[[IGLayoutTestItem alloc] initWithSize:(CGSize){33,33}],
]],
]];
XCTAssertEqual(self.collectionView.contentSize.height, 33);
IGAssertEqualFrame([self cellForSection:0 item:0].frame, 0, 0, 33, 33);
IGAssertEqualFrame([self cellForSection:1 item:0].frame, 33, 0, 33, 33);
IGAssertEqualFrame([self cellForSection:2 item:0].frame, 66, 0, 33, 33);
}
- (void)test_whenSectionsSmallerThanContainerWidth_withHalfPointSpacing_with0Insets_with0LineSpacing_thatSectionsFitSameRow {
[self setUpWithStickyHeaders:NO topInset:0];
[self prepareWithData:@[
[[IGLayoutTestSection alloc] initWithInsets:UIEdgeInsetsZero
lineSpacing:0
interitemSpacing:0.5
headerHeight:0
items:@[
[[IGLayoutTestItem alloc] initWithSize:(CGSize){33,33}],
]],
[[IGLayoutTestSection alloc] initWithInsets:UIEdgeInsetsZero
lineSpacing:0
interitemSpacing:0.5
headerHeight:0
items:@[
[[IGLayoutTestItem alloc] initWithSize:(CGSize){33,33}],
]],
[[IGLayoutTestSection alloc] initWithInsets:UIEdgeInsetsZero
lineSpacing:0
interitemSpacing:0.5
headerHeight:0
items:@[
[[IGLayoutTestItem alloc] initWithSize:(CGSize){33,33}],
]],
]];
XCTAssertEqual(self.collectionView.contentSize.height, 33);
IGAssertEqualFrame([self cellForSection:0 item:0].frame, 0, 0, 33, 33);
const CGRect rect = IGListRectIntegralScaled(CGRectMake(33.5, 0, 33, 33));
IGAssertEqualFrame([self cellForSection:1 item:0].frame, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
IGAssertEqualFrame([self cellForSection:2 item:0].frame, 67, 0, 33, 33);
}
- (void)test_whenSectionsSmallerThanContainerWidth_with0ItemSpacing_withMiddleItemHasInsets_with0LineSpacing_thatNextSectionSnapsBelow {
[self setUpWithStickyHeaders:NO topInset:0];
[self prepareWithData:@[
[[IGLayoutTestSection alloc] initWithInsets:UIEdgeInsetsZero
lineSpacing:0
interitemSpacing:0
headerHeight:0
items:@[
[[IGLayoutTestItem alloc] initWithSize:(CGSize){33,33}],
]],
[[IGLayoutTestSection alloc] initWithInsets:UIEdgeInsetsMake(10, 10, 10, 10)
lineSpacing:0
interitemSpacing:0
headerHeight:0
items:@[
[[IGLayoutTestItem alloc] initWithSize:(CGSize){13,50}],
]],
[[IGLayoutTestSection alloc] initWithInsets:UIEdgeInsetsZero
lineSpacing:0
interitemSpacing:0
headerHeight:0
items:@[
[[IGLayoutTestItem alloc] initWithSize:(CGSize){33,33}],
]],
[[IGLayoutTestSection alloc] initWithInsets:UIEdgeInsetsZero
lineSpacing:0
interitemSpacing:0
headerHeight:0
items:@[
[[IGLayoutTestItem alloc] initWithSize:(CGSize){33,33}],
]],
]];
XCTAssertEqual(self.collectionView.contentSize.height, 103);
IGAssertEqualFrame([self cellForSection:0 item:0].frame, 0, 0, 33, 33);
IGAssertEqualFrame([self cellForSection:1 item:0].frame, 43, 10, 13, 50);
IGAssertEqualFrame([self cellForSection:2 item:0].frame, 66, 0, 33, 33);
IGAssertEqualFrame([self cellForSection:3 item:0].frame, 0, 70, 33, 33);
}
- (void)test_whenSectionBustingRow_thatNewlineAppliesSectionInset {
[self setUpWithStickyHeaders:NO topInset:0];
[self prepareWithData:@[
[[IGLayoutTestSection alloc] initWithInsets:UIEdgeInsetsZero
lineSpacing:0
interitemSpacing:0
headerHeight:0
items:@[
[[IGLayoutTestItem alloc] initWithSize:(CGSize){33,33}],
]],
[[IGLayoutTestSection alloc] initWithInsets:UIEdgeInsetsMake(10, 10, 5, 5)
lineSpacing:0
interitemSpacing:0
headerHeight:0
items:@[
[[IGLayoutTestItem alloc] initWithSize:(CGSize){85,50}],
]],
]];
XCTAssertEqual(self.collectionView.contentSize.height, 98);
IGAssertEqualFrame([self cellForSection:0 item:0].frame, 0, 0, 33, 33);
IGAssertEqualFrame([self cellForSection:1 item:0].frame, 10, 43, 85, 50);
}
- (void)test_whenSectionsSmallerThanWidth_withSectionHeader_thatHeaderCausesNewline {
[self setUpWithStickyHeaders:NO topInset:0];
[self prepareWithData:@[
[[IGLayoutTestSection alloc] initWithInsets:UIEdgeInsetsZero
lineSpacing:0
interitemSpacing:0
headerHeight:0
items:@[
[[IGLayoutTestItem alloc] initWithSize:(CGSize){33,33}],
]],
[[IGLayoutTestSection alloc] initWithInsets:UIEdgeInsetsZero
lineSpacing:0
interitemSpacing:0
headerHeight:10
items:@[
[[IGLayoutTestItem alloc] initWithSize:(CGSize){33,33}],
]],
]];
XCTAssertEqual(self.collectionView.contentSize.height, 76);
IGAssertEqualFrame([self cellForSection:0 item:0].frame, 0, 0, 33, 33);
IGAssertEqualFrame([self cellForSection:1 item:0].frame, 0, 43, 33, 33);
}
- (void)test_whenBatchItemUpdates_withHeaderHeight_withLineSpacing_withInsets_thatLayoutCorrectAfterUpdates {
[self setUpWithStickyHeaders:NO topInset:0];
const CGFloat headerHeight = 10;
const CGFloat lineSpacing = 10;
const UIEdgeInsets insets = UIEdgeInsetsMake(10, 10, 5, 5);
// making the view bigger so that we can check all cell frames
self.collectionView.frame = CGRectMake(0, 0, 100, 400);
[self prepareWithData:@[
[[IGLayoutTestSection alloc] initWithInsets:insets
lineSpacing:lineSpacing
interitemSpacing:0
headerHeight:headerHeight
items:@[
[[IGLayoutTestItem alloc] initWithSize:(CGSize){85,10}],
[[IGLayoutTestItem alloc] initWithSize:(CGSize){85,20}],
]],
[[IGLayoutTestSection alloc] initWithInsets:insets
lineSpacing:lineSpacing
interitemSpacing:0
headerHeight:headerHeight
items:@[
[[IGLayoutTestItem alloc] initWithSize:(CGSize){85,30}],
]],
[[IGLayoutTestSection alloc] initWithInsets:insets
lineSpacing:lineSpacing
interitemSpacing:0
headerHeight:headerHeight
items:@[
[[IGLayoutTestItem alloc] initWithSize:(CGSize){85,60}],
]],
[[IGLayoutTestSection alloc] initWithInsets:insets
lineSpacing:lineSpacing
interitemSpacing:0
headerHeight:headerHeight
items:@[
[[IGLayoutTestItem alloc] initWithSize:(CGSize){85,40}],
]],
]];
XCTestExpectation *expectation = [self expectationWithDescription:NSStringFromSelector(_cmd)];
[self.collectionView performBatchUpdates:^{
self.dataSource.sections = @[
[[IGLayoutTestSection alloc] initWithInsets:insets
lineSpacing:lineSpacing
interitemSpacing:0
headerHeight:headerHeight
items:@[
[[IGLayoutTestItem alloc] initWithSize:(CGSize){85,30}], // reloaded
// deleted
]],
// moved from section 3 to 1
[[IGLayoutTestSection alloc] initWithInsets:insets
lineSpacing:lineSpacing
interitemSpacing:0
headerHeight:headerHeight
items:@[
[[IGLayoutTestItem alloc] initWithSize:(CGSize){85,40}],
]],
// deleted section 2
[[IGLayoutTestSection alloc] initWithInsets:insets
lineSpacing:lineSpacing
interitemSpacing:0
headerHeight:headerHeight
items:@[
[[IGLayoutTestItem alloc] initWithSize:(CGSize){85,30}],
[[IGLayoutTestItem alloc] initWithSize:(CGSize){85,10}], // inserted
]],
// inserted
[[IGLayoutTestSection alloc] initWithInsets:insets
lineSpacing:lineSpacing
interitemSpacing:0
headerHeight:headerHeight
items:@[
[[IGLayoutTestItem alloc] initWithSize:(CGSize){85,10}],
[[IGLayoutTestItem alloc] initWithSize:(CGSize){85,20}],
]],
];
[self.collectionView deleteSections:[NSIndexSet indexSetWithIndex:2]];
[self.collectionView insertSections:[NSIndexSet indexSetWithIndex:3]];
[self.collectionView moveSection:3 toSection:1];
[self.collectionView reloadItemsAtIndexPaths:@[genIndexPath(0, 0)]];
[self.collectionView deleteItemsAtIndexPaths:@[genIndexPath(0, 1)]];
[self.collectionView insertItemsAtIndexPaths:@[genIndexPath(2, 1)]];
} completion:^(BOOL finished) {
[self.collectionView layoutIfNeeded];
[expectation fulfill];
XCTAssertEqual(self.collectionView.contentSize.height, 260);
IGAssertEqualFrame([self headerForSection:0].frame, 10, 10, 85, 10);
IGAssertEqualFrame([self cellForSection:0 item:0].frame, 10, 20, 85, 30);
IGAssertEqualFrame([self headerForSection:1].frame, 10, 65, 85, 10);
IGAssertEqualFrame([self cellForSection:1 item:0].frame, 10, 75, 85, 40);
IGAssertEqualFrame([self headerForSection:2].frame, 10, 130, 85, 10);
IGAssertEqualFrame([self cellForSection:2 item:0].frame, 10, 140, 85, 30);
IGAssertEqualFrame([self cellForSection:2 item:1].frame, 10, 180, 85, 10);
IGAssertEqualFrame([self headerForSection:3].frame, 10, 205, 85, 10);
IGAssertEqualFrame([self cellForSection:3 item:0].frame, 10, 215, 85, 10);
IGAssertEqualFrame([self cellForSection:3 item:1].frame, 10, 235, 85, 20);
}];
[self waitForExpectationsWithTimeout:30 handler:^(NSError * _Nullable error) {
XCTAssertNil(error);
}];
}
- (void)test_whenQueryingLayoutAttributes_withLotsOfCells_thatExactFramesFetched {
[self setUpWithStickyHeaders:NO topInset:0];
NSMutableArray *items = [NSMutableArray new];
for (NSInteger i = 0; i < 1000; i++) {
[items addObject:[[IGLayoutTestItem alloc] initWithSize:(CGSize){100,20}]];
}
[self prepareWithData:@[
[[IGLayoutTestSection alloc] initWithInsets:UIEdgeInsetsZero
lineSpacing:0
interitemSpacing:0
headerHeight:0
items:items]
]];
XCTAssertEqual([self.layout layoutAttributesForElementsInRect:CGRectMake(0, 500, 100, 100)].count, 5);
XCTAssertEqual([self.layout layoutAttributesForElementsInRect:CGRectMake(0, 0, 100, 1000)].count, 50);
XCTAssertEqual([self.layout layoutAttributesForElementsInRect:CGRectMake(0, 250, 100, 100)].count, 6);
XCTAssertEqual([self.layout layoutAttributesForElementsInRect:CGRectMake(0, 250, 100, 1)].count, 1);
}
- (void)test_whenSecondItemDoesntIntersectRect_thatOtherAttributesExist {
[self setUpWithStickyHeaders:NO topInset:0];
NSMutableArray *data = [NSMutableArray new];
for (NSInteger i = 0; i < 6; i++) {
[data addObject:[[IGLayoutTestSection alloc] initWithInsets:UIEdgeInsetsZero
lineSpacing:0
interitemSpacing:0
headerHeight:0
items:@[
[[IGLayoutTestItem alloc] initWithSize:(CGSize){50, 100}],
[[IGLayoutTestItem alloc] initWithSize:(CGSize){50, 10}],
]]];
}
[self prepareWithData:data];
NSArray *attributes = [self.layout layoutAttributesForElementsInRect:CGRectMake(0, 50, 100, 100)];
NSArray *paths = [[attributes valueForKeyPath:@"indexPath"] sortedArrayUsingSelector:@selector(compare:)];
NSArray *expectation = @[
genIndexPath(0, 0),
genIndexPath(1, 0),
genIndexPath(1, 1),
];
// should include 2 of the 100-height items and one of the 10-height
XCTAssertEqualObjects(paths, expectation);
}
- (void)test_whenTwoConsecutiveItemsDontIntersectRect_thatOtherAttributesExist {
[self setUpWithStickyHeaders:NO topInset:0];
NSMutableArray *data = [NSMutableArray new];
for (NSInteger i = 0; i < 6; i++) {
[data addObject:[[IGLayoutTestSection alloc] initWithInsets:UIEdgeInsetsZero
lineSpacing:0
interitemSpacing:0
headerHeight:0
items:@[
[[IGLayoutTestItem alloc] initWithSize:(CGSize){30, 100}],
[[IGLayoutTestItem alloc] initWithSize:(CGSize){30, 10}],
[[IGLayoutTestItem alloc] initWithSize:(CGSize){30, 10}],
]]];
}
[self prepareWithData:data];
NSArray *attributes = [self.layout layoutAttributesForElementsInRect:CGRectMake(0, 50, 100, 100)];
NSArray *paths = [[attributes valueForKeyPath:@"indexPath"] sortedArrayUsingSelector:@selector(compare:)];
NSArray *expectation = @[
genIndexPath(0, 0),
genIndexPath(1, 0),
genIndexPath(1, 1),
genIndexPath(1, 2),
];
// should include 2 of the 100-height items and two of the 10-height
XCTAssertEqualObjects(paths, expectation);
}
- (void)test_whenChangingBoundsSize_withItemsThatNewlineAfterChange_thatLayoutShiftsItems {
[self setUpWithStickyHeaders:NO topInset:0];
[self prepareWithData:@[
[[IGLayoutTestSection alloc] initWithInsets:UIEdgeInsetsZero
lineSpacing:0
interitemSpacing:0
headerHeight:0
items:@[
[[IGLayoutTestItem alloc] initWithSize:(CGSize){33,33}],
]],
[[IGLayoutTestSection alloc] initWithInsets:UIEdgeInsetsZero
lineSpacing:0
interitemSpacing:0
headerHeight:0
items:@[
[[IGLayoutTestItem alloc] initWithSize:(CGSize){33,33}],
]],
[[IGLayoutTestSection alloc] initWithInsets:UIEdgeInsetsZero
lineSpacing:0
interitemSpacing:0
headerHeight:0
items:@[
[[IGLayoutTestItem alloc] initWithSize:(CGSize){33,33}],
]],
]];
XCTAssertEqual(self.collectionView.contentSize.height, 33);
IGAssertEqualFrame([self cellForSection:0 item:0].frame, 0, 0, 33, 33);
IGAssertEqualFrame([self cellForSection:1 item:0].frame, 33, 0, 33, 33);
IGAssertEqualFrame([self cellForSection:2 item:0].frame, 66, 0, 33, 33);
// can no longer fit 3 items in one section
self.collectionView.frame = CGRectMake(0, 0, 70, 100);
[self.collectionView layoutIfNeeded];
XCTAssertEqual(self.collectionView.contentSize.height, 66);
IGAssertEqualFrame([self cellForSection:0 item:0].frame, 0, 0, 33, 33);
IGAssertEqualFrame([self cellForSection:1 item:0].frame, 33, 0, 33, 33);
IGAssertEqualFrame([self cellForSection:2 item:0].frame, 0, 33, 33, 33);
}
- (void)test_whenCollectionViewContentInset_withFullWidthItems_thatItemsPinchedIn {
[self setUpWithStickyHeaders:NO topInset:0];
self.collectionView.contentInset = UIEdgeInsetsMake(0, 30, 0, 30);
[self prepareWithData:@[
[[IGLayoutTestSection alloc] initWithInsets:UIEdgeInsetsZero
lineSpacing:0
interitemSpacing:0
headerHeight:10
items:@[
[[IGLayoutTestItem alloc] initWithSize:(CGSize){40,10}],
[[IGLayoutTestItem alloc] initWithSize:(CGSize){40,20}],
]],
]];
XCTAssertEqual(self.collectionView.contentSize.height, 40);
IGAssertEqualFrame([self headerForSection:0].frame, 0, 0, 40, 10);
IGAssertEqualFrame([self cellForSection:0 item:0].frame, 0, 10, 40, 10);
IGAssertEqualFrame([self cellForSection:0 item:1].frame, 0, 20, 40, 20);
}
- (void)test_whenItemsAddedWidthSmallerThanWidth_DifferenceSmallerThanEpsilon {
[self setUpWithStickyHeaders:NO topInset:0 stretchToEdge:YES];
const CGSize size = CGSizeMake(33, 33);
[self prepareWithData:@[
[[IGLayoutTestSection alloc] initWithInsets:UIEdgeInsetsZero
lineSpacing:0
interitemSpacing:0
headerHeight:0
items:@[
[[IGLayoutTestItem alloc] initWithSize:size],
[[IGLayoutTestItem alloc] initWithSize:size],
[[IGLayoutTestItem alloc] initWithSize:size],
]],
]];
IGAssertEqualFrame([self cellForSection:0 item:0].frame, 0, 0, 33, 33);
IGAssertEqualFrame([self cellForSection:0 item:1].frame, 33, 0, 33, 33);
IGAssertEqualFrame([self cellForSection:0 item:2].frame, 66, 0, 34, 33);
}
- (void)test_whenItemsAddedWidthSmallerThanWidth_DifferenceBiggerThanEpsilon {
[self setUpWithStickyHeaders:NO topInset:0 stretchToEdge:YES];
[self prepareWithData:@[
[[IGLayoutTestSection alloc] initWithInsets:UIEdgeInsetsZero
lineSpacing:0
interitemSpacing:0
headerHeight:0
items:@[
[[IGLayoutTestItem alloc] initWithSize:CGSizeMake(33, 33)],
[[IGLayoutTestItem alloc] initWithSize:CGSizeMake(65, 33)],
]],
]];
IGAssertEqualFrame([self cellForSection:0 item:0].frame, 0, 0, 33, 33);
IGAssertEqualFrame([self cellForSection:0 item:1].frame, 33, 0, 65, 33);
}
- (void)test_whenItemsAddedWithBiggerThanWidth_DifferenceSmallerThanEpsilon {
[self setUpWithStickyHeaders:NO topInset:0];
[self prepareWithData:@[
[[IGLayoutTestSection alloc] initWithInsets:UIEdgeInsetsZero
lineSpacing:0
interitemSpacing:0
headerHeight:0
items:@[
[[IGLayoutTestItem alloc] initWithSize:CGSizeMake(50, 50)],
[[IGLayoutTestItem alloc] initWithSize:CGSizeMake(51, 50)],
]],
]];
IGAssertEqualFrame([self cellForSection:0 item:0].frame, 0, 0, 50, 50);
IGAssertEqualFrame([self cellForSection:0 item:1].frame, 50, 0, 51, 50);
}
- (void)test_whenItemsAddedWithBiggerThanWidth_DifferenceBiggerThanEpsilon {
[self setUpWithStickyHeaders:NO topInset:0];
[self prepareWithData:@[
[[IGLayoutTestSection alloc] initWithInsets:UIEdgeInsetsZero
lineSpacing:0
interitemSpacing:0
headerHeight:0
items:@[
[[IGLayoutTestItem alloc] initWithSize:CGSizeMake(50, 50)],
[[IGLayoutTestItem alloc] initWithSize:CGSizeMake(52, 50)],
]],
]];
IGAssertEqualFrame([self cellForSection:0 item:0].frame, 0, 0, 50, 50);
IGAssertEqualFrame([self cellForSection:0 item:1].frame, 0, 50, 52, 50);
}
- (void)test_ {
[self setUpWithStickyHeaders:NO topInset:0];
self.collectionView.frame = CGRectMake(0, 0, 414, 736);
NSMutableArray *data = [NSMutableArray new];
for (NSInteger i = 0; i < 6; i++) {
[data addObject:[[IGLayoutTestSection alloc] initWithInsets:UIEdgeInsetsMake(1, 1, 1, 1)
lineSpacing:0
interitemSpacing:0
headerHeight:0
items:@[
[[IGLayoutTestItem alloc] initWithSize:(CGSize){136, 136}],
]]];
}
[self prepareWithData:data];
XCTAssertEqual(self.collectionView.contentSize.height, 276);
IGAssertEqualFrame([self cellForSection:0 item:0].frame, 1, 1, 136, 136);
IGAssertEqualFrame([self cellForSection:1 item:0].frame, 139, 1, 136, 136);
IGAssertEqualFrame([self cellForSection:2 item:0].frame, 277, 1, 136, 136);
IGAssertEqualFrame([self cellForSection:3 item:0].frame, 1, 139, 136, 136);
IGAssertEqualFrame([self cellForSection:4 item:0].frame, 139, 139, 136, 136);
IGAssertEqualFrame([self cellForSection:5 item:0].frame, 277, 139, 136, 136);
}
- (void)test_whenQueryingAttributes_withSectionOOB_thatReturnsNil {
[self setUpWithStickyHeaders:NO topInset:0 stretchToEdge:YES];
[self prepareWithData:@[
[[IGLayoutTestSection alloc] initWithInsets:UIEdgeInsetsZero
lineSpacing:0
interitemSpacing:0
headerHeight:0
items:@[
[[IGLayoutTestItem alloc] initWithSize:CGSizeMake(33, 33)],
[[IGLayoutTestItem alloc] initWithSize:CGSizeMake(65, 33)],
]],
]];
XCTAssertNil([self.layout layoutAttributesForItemAtIndexPath:genIndexPath(4, 0)]);
}
- (void)test_whenQueryingAttributes_withItemOOB_thatReturnsNil {
[self setUpWithStickyHeaders:NO topInset:0 stretchToEdge:YES];
[self prepareWithData:@[
[[IGLayoutTestSection alloc] initWithInsets:UIEdgeInsetsZero
lineSpacing:0
interitemSpacing:0
headerHeight:0
items:@[
[[IGLayoutTestItem alloc] initWithSize:CGSizeMake(33, 33)],
[[IGLayoutTestItem alloc] initWithSize:CGSizeMake(65, 33)],
]],
]];
XCTAssertNil([self.layout layoutAttributesForItemAtIndexPath:genIndexPath(0, 4)]);
}
@end