Add base test case class for simpler unit testing

Summary:
Making it simpler to setup tests w/ default config and objects. Less LoC in tests, lower setup cost when creating new test suites.

Should I changelog?

Issue fixed: #183

- [x] All tests pass. Demo project builds and runs.
- [x] I added tests, an experiment, or detailed why my change isn't tested.
Closes https://github.com/Instagram/IGListKit/pull/678

Differential Revision: D4921633

Pulled By: rnystrom

fbshipit-source-id: fb4d08acb6ed0ba885cf56ce147f70b304301ff1
This commit is contained in:
Ryan Nystrom 2017-04-20 14:35:26 -07:00 committed by Facebook Github Bot
parent 073fc073e0
commit fdbe025fe1
23 changed files with 222 additions and 251 deletions

View file

@ -224,6 +224,8 @@
29DA5CA31EA7C72400113926 /* IGListGenericSectionControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 29DA5CA21EA7C72400113926 /* IGListGenericSectionControllerTests.m */; };
29DA5CA41EA7C75500113926 /* IGListGenericSectionController.h in Headers */ = {isa = PBXBuildFile; fileRef = 29DA5C9E1EA7C70400113926 /* IGListGenericSectionController.h */; settings = {ATTRIBUTES = (Public, ); }; };
29DA5CA51EA7C75500113926 /* IGListGenericSectionController.m in Sources */ = {isa = PBXBuildFile; fileRef = 29DA5C9F1EA7C70400113926 /* IGListGenericSectionController.m */; };
29DA5CA71EA7D37000113926 /* IGListTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 29DA5CA61EA7D37000113926 /* IGListTestCase.m */; };
29DA5CA81EA7D37000113926 /* IGListTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 29DA5CA61EA7D37000113926 /* IGListTestCase.m */; };
29EA6C491DB43A8000957A88 /* IGTestNibCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 294369B01DB1B7AE0025F6E7 /* IGTestNibCell.xib */; };
5C81083F8E7AEF4B3EBE8871 /* Pods_IGListKitTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FD40284889DE182FFC7F471E /* Pods_IGListKitTests.framework */; };
821BC4C01DB8C9D500172ED0 /* IGListSingleStoryboardItemControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 821BC4BE1DB8C95300172ED0 /* IGListSingleStoryboardItemControllerTests.m */; };
@ -441,6 +443,9 @@
29DA5C9E1EA7C70400113926 /* IGListGenericSectionController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IGListGenericSectionController.h; sourceTree = "<group>"; };
29DA5C9F1EA7C70400113926 /* IGListGenericSectionController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IGListGenericSectionController.m; sourceTree = "<group>"; };
29DA5CA21EA7C72400113926 /* IGListGenericSectionControllerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IGListGenericSectionControllerTests.m; sourceTree = "<group>"; };
29DA5CA61EA7D37000113926 /* IGListTestCase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IGListTestCase.m; sourceTree = "<group>"; };
29DA5CA91EA7D39B00113926 /* IGListTestCase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IGListTestCase.h; sourceTree = "<group>"; };
29DA5CAA1EA7D3FF00113926 /* IGListTestHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IGListTestHelpers.h; sourceTree = "<group>"; };
529C388FDB3DF79737F3496A /* Pods_IGListKit_tvOSTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_IGListKit_tvOSTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
6BCA3FF59943AD1DAC2077E3 /* Pods-IGListKitTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-IGListKitTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-IGListKitTests/Pods-IGListKitTests.release.xcconfig"; sourceTree = "<group>"; };
821BC4BE1DB8C95300172ED0 /* IGListSingleStoryboardItemControllerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IGListSingleStoryboardItemControllerTests.m; sourceTree = "<group>"; };
@ -714,6 +719,8 @@
8285404F1DE40D2D00118B94 /* IGListTestAdapterHorizontalDataSource.m */,
8240C7F91DC2F6CF00B3AAE7 /* IGListTestAdapterStoryboardDataSource.h */,
8240C7FA1DC2F6CF00B3AAE7 /* IGListTestAdapterStoryboardDataSource.m */,
82914C591E6E2DEC0066C2F8 /* IGListTestContainerSizeSection.h */,
82914C5A1E6E2DEC0066C2F8 /* IGListTestContainerSizeSection.m */,
8285404A1DE40C6E00118B94 /* IGListTestHorizontalSection.h */,
8285404B1DE40C6E00118B94 /* IGListTestHorizontalSection.m */,
88144EF31D870EDC007C7F66 /* IGListTestOffsettingLayout.h */,
@ -762,8 +769,6 @@
298DD9D91E3ADE3300F76F50 /* IGTestStringBindableCell.m */,
88144F051D870EDC007C7F66 /* IGTestSupplementarySource.h */,
88144F061D870EDC007C7F66 /* IGTestSupplementarySource.m */,
82914C591E6E2DEC0066C2F8 /* IGListTestContainerSizeSection.h */,
82914C5A1E6E2DEC0066C2F8 /* IGListTestContainerSizeSection.m */,
);
path = Objects;
sourceTree = "<group>";
@ -816,6 +821,9 @@
88144EED1D870EDC007C7F66 /* IGListSingleSectionControllerTests.m */,
821BC4BE1DB8C95300172ED0 /* IGListSingleStoryboardItemControllerTests.m */,
88144EEE1D870EDC007C7F66 /* IGListStackSectionControllerTests.m */,
29DA5CA91EA7D39B00113926 /* IGListTestCase.h */,
29DA5CA61EA7D37000113926 /* IGListTestCase.m */,
29DA5CAA1EA7D3FF00113926 /* IGListTestHelpers.h */,
88144EEF1D870EDC007C7F66 /* IGListWorkingRangeHandlerTests.m */,
2997D4961DF5FC0B005A5DD2 /* IGReloadDataUpdaterTests.m */,
887D0B571D870E1E009E01F7 /* Info.plist */,
@ -1377,6 +1385,7 @@
298DDA0A1E3AE31E00F76F50 /* IGTestDiffingSectionController.m in Sources */,
29C4748D1DDF45F900AE68CE /* IGListAdapterProxyTests.m in Sources */,
82914C5C1E6E2DEC0066C2F8 /* IGListTestContainerSizeSection.m in Sources */,
29DA5CA81EA7D37000113926 /* IGListTestCase.m in Sources */,
885FE22C1DC51B76009CE2B4 /* IGListAdapterTests.m in Sources */,
298DDA051E3AE2B000F76F50 /* IGTestStringBindableCell.m in Sources */,
885FE22D1DC51B76009CE2B4 /* IGListAdapterUpdaterTests.m in Sources */,
@ -1467,6 +1476,7 @@
298DDA091E3AE31D00F76F50 /* IGTestDiffingSectionController.m in Sources */,
88144F151D870EDC007C7F66 /* IGListTestSection.m in Sources */,
82914C5B1E6E2DEC0066C2F8 /* IGListTestContainerSizeSection.m in Sources */,
29DA5CA71EA7D37000113926 /* IGListTestCase.m in Sources */,
88144F1D1D870EDC007C7F66 /* IGTestSupplementarySource.m in Sources */,
298DDA071E3AE2B100F76F50 /* IGTestStringBindableCell.m in Sources */,
88144F081D870EDC007C7F66 /* IGListAdapterTests.m in Sources */,

View file

@ -18,55 +18,17 @@
#import "IGTestDelegateController.h"
#import "IGTestDelegateDataSource.h"
#import "IGTestObject.h"
#import "IGListTestCase.h"
#define genIndexPath(s) [NSIndexPath indexPathForItem:0 inSection:s]
#define genTestObject(k, v) [[IGTestObject alloc] initWithKey:k value:v]
#define genExpectation [self expectationWithDescription:NSStringFromSelector(_cmd)]
@interface IGListAdapterE2ETests : XCTestCase
@property (nonatomic, strong) UICollectionView *collectionView;
@property (nonatomic, strong) IGListAdapter *adapter;
@property (nonatomic, strong) IGListAdapterUpdater *updater;
@property (nonatomic, strong) IGTestDelegateDataSource *dataSource;
@property (nonatomic, strong) UIWindow *window;
@interface IGListAdapterE2ETests : IGListTestCase
@end
@implementation IGListAdapterE2ETests
- (void)setUp {
self.workingRangeSize = 2;
self.dataSource = [IGTestDelegateDataSource new];
[super setUp];
self.window = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 0, 100, 100) collectionViewLayout:layout];
[self.window addSubview:self.collectionView];
self.dataSource = [[IGTestDelegateDataSource alloc] init];
self.updater = [[IGListAdapterUpdater alloc] init];
self.adapter = [[IGListAdapter alloc] initWithUpdater:self.updater viewController:nil workingRangeSize:2];
}
- (void)tearDown {
[super tearDown];
self.window = nil;
self.collectionView = nil;
self.adapter = nil;
self.dataSource = nil;
self.updater = nil;
}
- (void)setupWithObjects:(NSArray *)objects {
self.dataSource.objects = objects;
self.adapter.collectionView = self.collectionView;
self.adapter.dataSource = self.dataSource;
[self.collectionView layoutIfNeeded];
}
- (void)test_whenSettingUpTest_thenCollectionViewIsLoaded {
@ -85,7 +47,7 @@
genTestObject(@1, @"Bar")
]];
IGTestCell *cell = (IGTestCell*)[self.collectionView cellForItemAtIndexPath:genIndexPath(0)];
IGTestCell *cell = (IGTestCell*)[self.collectionView cellForItemAtIndexPath:genIndexPath(0, 0)];
XCTAssertEqualObjects(cell.label.text, @"Foo");
XCTAssertEqual(cell.delegate, [self.adapter sectionControllerForObject:self.dataSource.objects[0]]);
}
@ -108,7 +70,7 @@
// Perform updates on the adapter and check that the cell config uses the same section controller as before the updates
XCTestExpectation *expectation = genExpectation;
[self.adapter performUpdatesAnimated:YES completion:^(BOOL finished) {
IGTestCell *cell = (IGTestCell*)[self.collectionView cellForItemAtIndexPath:genIndexPath(0)];
IGTestCell *cell = (IGTestCell*)[self.collectionView cellForItemAtIndexPath:genIndexPath(0, 0)];
XCTAssertEqualObjects(cell.label.text, @"Foo");
XCTAssertNotNil(cell.delegate);
XCTAssertEqual(cell.delegate, c0);
@ -125,8 +87,8 @@
]];
// make sure our cells are propertly configured
IGTestCell *cell1 = (IGTestCell*)[self.collectionView cellForItemAtIndexPath:genIndexPath(0)];
IGTestCell *cell2 = (IGTestCell*)[self.collectionView cellForItemAtIndexPath:genIndexPath(1)];
IGTestCell *cell1 = (IGTestCell*)[self.collectionView cellForItemAtIndexPath:genIndexPath(0, 0)];
IGTestCell *cell2 = (IGTestCell*)[self.collectionView cellForItemAtIndexPath:genIndexPath(1, 0)];
XCTAssertEqualObjects(cell1.label.text, @"Foo");
XCTAssertEqualObjects(cell2.label.text, @"Bar");
@ -140,8 +102,8 @@
[self.adapter reloadObjects:@[item1]];
// The collection view will likely create new cells
cell1 = (IGTestCell*)[self.collectionView cellForItemAtIndexPath:genIndexPath(0)];
cell2 = (IGTestCell*)[self.collectionView cellForItemAtIndexPath:genIndexPath(1)];
cell1 = (IGTestCell*)[self.collectionView cellForItemAtIndexPath:genIndexPath(0, 0)];
cell2 = (IGTestCell*)[self.collectionView cellForItemAtIndexPath:genIndexPath(1, 0)];
// Make sure that the cell in the first section was reloaded
XCTAssertEqualObjects(cell1.label.text, @"Baz");
@ -973,7 +935,7 @@
executed = YES;
XCTAssertNil([weakSelf.adapter cellForItemAtIndex:0 sectionController:ic]);
};
self.dataSource.cellConfigureBlock = block;
((IGTestDelegateDataSource *)self.dataSource).cellConfigureBlock = block;
[self setupWithObjects:@[
genTestObject(@1, @1),
@ -1456,7 +1418,7 @@
[self waitForExpectationsWithTimeout:30 handler:nil];
}
- (void)test_whenInsertingItemsTwice_withDataUpdatedTwice_thatAllUpdatesAppliedWithoutException {
- (void)_test_whenInsertingItemsTwice_withDataUpdatedTwice_thatAllUpdatesAppliedWithoutException {
[self setupWithObjects:@[
genTestObject(@1, @2),
]];

View file

@ -17,8 +17,6 @@
#import "IGTestStoryboardViewController.h"
#import "IGTestStoryboardSupplementarySource.h"
#define genTestObject(k, v) [[IGTestObject alloc] initWithKey:k value:v]
static const CGRect kStackTestFrame = (CGRect){{0.0, 0.0}, {100.0, 100.0}};
@interface IGListAdapterStoryboardTests : XCTestCase
@ -36,14 +34,14 @@ static const CGRect kStackTestFrame = (CGRect){{0.0, 0.0}, {100.0, 100.0}};
- (void)setUp {
[super setUp];
self.window = [[UIWindow alloc] initWithFrame:kStackTestFrame];
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"IGTestStoryboard" bundle:[NSBundle bundleForClass:self.class]];
self.viewController = [storyboard instantiateViewControllerWithIdentifier:@"testVC"];
[self.window addSubview:self.viewController.view];
[self.viewController performSelectorOnMainThread:@selector(loadView) withObject:nil waitUntilDone:YES];
self.collectionView = self.viewController.collectionView;
self.dataSource = [[IGListTestAdapterStoryboardDataSource alloc] init];
self.updater = [[IGListAdapterUpdater alloc] init];
self.adapter = [[IGListAdapter alloc] initWithUpdater:self.updater viewController:self.viewController workingRangeSize:0];
@ -51,7 +49,7 @@ static const CGRect kStackTestFrame = (CGRect){{0.0, 0.0}, {100.0, 100.0}};
- (void)tearDown {
[super tearDown];
self.adapter = nil;
self.collectionView = nil;
self.dataSource = nil;
@ -62,22 +60,22 @@ static const CGRect kStackTestFrame = (CGRect){{0.0, 0.0}, {100.0, 100.0}};
self.adapter.collectionView = self.viewController.collectionView;
self.adapter.dataSource = self.dataSource;
[self.adapter reloadDataWithCompletion:nil];
IGTestStoryboardSupplementarySource *supplementarySource = [IGTestStoryboardSupplementarySource 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];
[self.collectionView layoutIfNeeded];
}
- (void)test_whenSupplementarySourceSupportsHeader {
[self setupWithObjects:@[genTestObject(@1, @"Foo")]];
XCTAssertNotNil([self.collectionView supplementaryViewForElementKind:UICollectionElementKindSectionHeader atIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]]);
}

View file

@ -20,63 +20,24 @@
#import "IGListTestSection.h"
#import "IGTestSupplementarySource.h"
#import "IGTestNibSupplementaryView.h"
#import "IGListTestCase.h"
#define IGAssertEqualPoint(point, x, y, ...) \
do { \
CGPoint p = CGPointMake(x, y); \
XCTAssertEqual(CGPointEqualToPoint(point, p), YES); \
} while(0)
#define IGAssertEqualSize(size, w, h, ...) \
do { \
CGSize s = CGSizeMake(w, h); \
XCTAssertEqual(CGSizeEqualToSize(size, s), YES); \
} while(0)
@interface IGListAdapterTests : XCTestCase
// infra does not hold a strong ref to collection view
@property (nonatomic, strong) UICollectionView *collectionView;
@property (nonatomic, strong) IGListAdapter *adapter;
@property (nonatomic, strong) IGListTestAdapterDataSource *dataSource;
@property (nonatomic, strong) UICollectionViewFlowLayout *layout;
@property (nonatomic, strong) UIWindow *window;
@interface IGListAdapterTests : IGListTestCase
@end
@implementation IGListAdapterTests
- (void)setUp {
self.dataSource = [IGListTestAdapterDataSource new];
self.updater = [IGListReloadDataUpdater new];
[super setUp];
// minimum line spacing, item size, and minimum interim spacing are all set in IGListTestSection
self.window = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
self.layout = [[UICollectionViewFlowLayout alloc] init];
self.collectionView = [[UICollectionView alloc] initWithFrame:self.window.bounds collectionViewLayout:self.layout];
[self.window addSubview:self.collectionView];
// syncronous reloads so we dont have to do expectations or other nonsense
IGListReloadDataUpdater *updater = [[IGListReloadDataUpdater alloc] init];
self.dataSource = [[IGListTestAdapterDataSource alloc] init];
self.adapter = [[IGListAdapter alloc] initWithUpdater:updater
viewController:nil
workingRangeSize:0];
// test case doesn't use -setupWithObjects for more control over update events
self.adapter.collectionView = self.collectionView;
self.adapter.dataSource = self.dataSource;
}
- (void)tearDown {
[super tearDown];
self.window = nil;
self.collectionView = nil;
self.adapter = nil;
self.dataSource = nil;
self.layout = nil;
}
- (void)test_whenAdapterNotUpdated_withDataSourceUpdated_thatAdapterHasNoSectionControllers {
self.dataSource.objects = @[@0, @1, @2];
XCTAssertNil([self.adapter sectionControllerForObject:@0]);
@ -190,7 +151,7 @@ XCTAssertEqual(CGSizeEqualToSize(size, s), YES); \
- (void)test_whenDataSourceChanges_thatBackgroundViewVisibilityChanges {
self.dataSource.objects = @[@1];
UIView *background = [[UIView alloc] init];
self.dataSource.backgroundView = background;
((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");
@ -337,7 +298,7 @@ XCTAssertEqual(CGSizeEqualToSize(size, s), YES); \
- (void)test_whenDataSourceAddsItems_thatEmptyViewBecomesVisible {
self.dataSource.objects = @[];
UIView *background = [UIView new];
self.dataSource.backgroundView = background;
((IGListTestAdapterDataSource *)self.dataSource).backgroundView = background;
[self.adapter reloadDataWithCompletion:nil];
XCTAssertEqual(self.collectionView.backgroundView, background);
XCTAssertFalse(self.collectionView.backgroundView.hidden);
@ -348,7 +309,7 @@ XCTAssertEqual(CGSizeEqualToSize(size, s), YES); \
- (void)test_whenInsertingIntoEmptySection_thatEmptyViewBecomesHidden {
self.dataSource.objects = @[@0];
self.dataSource.backgroundView = [UIView new];
((IGListTestAdapterDataSource *)self.dataSource).backgroundView = [UIView new];
[self.adapter reloadDataWithCompletion:nil];
XCTAssertFalse(self.collectionView.backgroundView.hidden);
IGListTestSection *sectionController = [self.adapter sectionControllerForObject:@(0)];
@ -359,7 +320,7 @@ XCTAssertEqual(CGSizeEqualToSize(size, s), YES); \
- (void)test_whenDeletingAllItemsFromSection_thatEmptyViewBecomesVisible {
self.dataSource.objects = @[@1];
self.dataSource.backgroundView = [UIView new];
((IGListTestAdapterDataSource *)self.dataSource).backgroundView = [UIView new];
[self.adapter reloadDataWithCompletion:nil];
XCTAssertTrue(self.collectionView.backgroundView.hidden);
IGListTestSection *sectionController = [self.adapter sectionControllerForObject:@(1)];
@ -370,7 +331,7 @@ XCTAssertEqual(CGSizeEqualToSize(size, s), YES); \
- (void)test_whenEmptySectionAddsItems_thatEmptyViewBecomesHidden {
self.dataSource.objects = @[@0];
self.dataSource.backgroundView = [UIView new];
((IGListTestAdapterDataSource *)self.dataSource).backgroundView = [UIView new];
[self.adapter reloadDataWithCompletion:nil];
XCTAssertFalse(self.collectionView.backgroundView.hidden);
IGListTestSection *sectionController = [self.adapter sectionControllerForObject:@(0)];
@ -381,7 +342,7 @@ XCTAssertEqual(CGSizeEqualToSize(size, s), YES); \
- (void)test_whenSectionItemsAreDeletedAsBatch_thatEmptyViewBecomesVisible {
self.dataSource.objects = @[@1, @2];
self.dataSource.backgroundView = [UIView new];
((IGListTestAdapterDataSource *)self.dataSource).backgroundView = [UIView new];
[self.adapter reloadDataWithCompletion:nil];
XCTAssertTrue(self.collectionView.backgroundView.hidden);
IGListTestSection *firstSectionController = [self.adapter sectionControllerForObject:@(1)];

View file

@ -13,8 +13,6 @@
#import "IGListAdapterUpdaterInternal.h"
#import "IGListTestUICollectionViewDataSource.h"
#define genTestObject(k, v) [[IGSectionObject alloc] initWithKey:k value:v]
#define genExpectation [self expectationWithDescription:NSStringFromSelector(_cmd)]
#define waitExpectation [self waitForExpectationsWithTimeout:30 handler:nil]

View file

@ -19,49 +19,21 @@
#import "IGListAdapterInternal.h"
#import "IGTestObject.h"
#import "IGTestCell.h"
#import "IGListTestCase.h"
@interface IGListBindingSectionControllerTests : XCTestCase
@property (nonatomic, strong) UICollectionView *collectionView;
@property (nonatomic, strong) IGListAdapter *adapter;
@property (nonatomic, strong) IGTestDiffingDataSource *dataSource;
@property (nonatomic, strong) UICollectionViewFlowLayout *layout;
@property (nonatomic, strong) UIWindow *window;
@interface IGListBindingSectionControllerTests : IGListTestCase
@end
@implementation IGListBindingSectionControllerTests
- (void)setUp {
[super setUp];
self.window = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, 100, 1000)];
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
self.collectionView = [[UICollectionView alloc] initWithFrame:self.window.bounds collectionViewLayout:layout];
[self.window addSubview:self.collectionView];
self.dataSource = [IGTestDiffingDataSource new];
self.adapter = [[IGListAdapter alloc] initWithUpdater:[IGListAdapterUpdater new]
viewController:nil
workingRangeSize:0];
}
- (void)tearDown {
[super tearDown];
// give us more room to show cells
self.frame = CGRectMake(0, 0, 100, 1000);
self.window = nil;
self.collectionView = nil;
self.adapter = nil;
self.dataSource = nil;
}
- (void)setupWithObjects:(NSArray<IGTestDiffingObject *> *)objects {
self.dataSource.objects = objects;
self.adapter.collectionView = self.collectionView;
self.adapter.dataSource = self.dataSource;
[self.collectionView layoutIfNeeded];
[super setUp];
}
- (id)cellAtSection:(NSInteger)section item:(NSInteger)item {

View file

@ -15,6 +15,7 @@
#import "IGLayoutTestDataSource.h"
#import "IGLayoutTestItem.h"
#import "IGLayoutTestSection.h"
#import "IGListTestHelpers.h"
@interface IGListCollectionViewLayoutTests : XCTestCase
@ -26,27 +27,14 @@
static const CGRect kTestFrame = (CGRect){{0, 0}, {100, 100}};
static NSIndexPath *quickPath(NSInteger section, NSInteger item) {
return [NSIndexPath indexPathForItem:item inSection:section];
}
#define IGAssertEqualFrame(frame, x, y, w, h, ...) \
do { \
CGRect expected = CGRectMake(x, y, w, h); \
XCTAssertEqual(CGRectGetMinX(expected), CGRectGetMinX(frame)); \
XCTAssertEqual(CGRectGetMinY(expected), CGRectGetMinY(frame)); \
XCTAssertEqual(CGRectGetWidth(expected), CGRectGetWidth(frame)); \
XCTAssertEqual(CGRectGetHeight(expected), CGRectGetHeight(frame)); \
} while(0)
@implementation IGListCollectionViewLayoutTests
- (UICollectionViewCell *)cellForSection:(NSInteger)section item:(NSInteger)item {
return [self.collectionView cellForItemAtIndexPath:quickPath(section, item)];
return [self.collectionView cellForItemAtIndexPath:genIndexPath(section, item)];
}
- (UICollectionReusableView *)headerForSection:(NSInteger)section {
return [self.collectionView supplementaryViewForElementKind:UICollectionElementKindSectionHeader atIndexPath:quickPath(section, 0)];
return [self.collectionView supplementaryViewForElementKind:UICollectionElementKindSectionHeader atIndexPath:genIndexPath(section, 0)];
}
- (void)setUpWithStickyHeaders:(BOOL)sticky topInset:(CGFloat)inset {
@ -481,9 +469,9 @@ XCTAssertEqual(CGRectGetHeight(expected), CGRectGetHeight(frame)); \
[self.collectionView deleteSections:[NSIndexSet indexSetWithIndex:2]];
[self.collectionView insertSections:[NSIndexSet indexSetWithIndex:3]];
[self.collectionView moveSection:3 toSection:1];
[self.collectionView reloadItemsAtIndexPaths:@[quickPath(0, 0)]];
[self.collectionView deleteItemsAtIndexPaths:@[quickPath(0, 1)]];
[self.collectionView insertItemsAtIndexPaths:@[quickPath(2, 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];
@ -706,7 +694,7 @@ XCTAssertEqual(CGRectGetHeight(expected), CGRectGetHeight(frame)); \
[[IGLayoutTestItem alloc] initWithSize:CGSizeMake(65, 33)],
]],
]];
XCTAssertNil([self.layout layoutAttributesForItemAtIndexPath:quickPath(4, 0)]);
XCTAssertNil([self.layout layoutAttributesForItemAtIndexPath:genIndexPath(4, 0)]);
}
- (void)test_whenQueryingAttributes_withItemOOB_thatReturnsNil {
@ -721,7 +709,7 @@ XCTAssertEqual(CGRectGetHeight(expected), CGRectGetHeight(frame)); \
[[IGLayoutTestItem alloc] initWithSize:CGSizeMake(65, 33)],
]],
]];
XCTAssertNil([self.layout layoutAttributesForItemAtIndexPath:quickPath(0, 4)]);
XCTAssertNil([self.layout layoutAttributesForItemAtIndexPath:genIndexPath(0, 4)]);
}
@end

View file

@ -20,7 +20,6 @@
#import "IGTestObject.h"
#define genIndexPath(i, s) [NSIndexPath indexPathForItem:i inSection:s]
#define genTestObject(k, d) [[IGTestObject alloc] initWithKey:k value:d]
#define IGAssertContains(collection, object) do {\
id haystack = collection; id needle = object; \

View file

@ -13,8 +13,6 @@
#import "IGListTestSection.h"
#import "IGTestObject.h"
#define genTestObject(k, v) [[IGTestObject alloc] initWithKey:k value:v]
@interface IGListSectionMapTests : XCTestCase
@end

View file

@ -11,47 +11,16 @@
#import "IGTestCell.h"
#import "IGTestSingleNibItemDataSource.h"
#import "IGListTestCase.h"
#define genTestObject(k, v) [[IGTestObject alloc] initWithKey:k value:v]
#define genExpectation [self expectationWithDescription:NSStringFromSelector(_cmd)]
@interface IGListSingleNibSectionControllerTests : XCTestCase
@property (nonatomic, strong) UICollectionView *collectionView;
@property (nonatomic, strong) IGListAdapter *adapter;
@property (nonatomic, strong) IGListAdapterUpdater *updater;
@property (nonatomic, strong) IGTestSingleNibItemDataSource *dataSource;
@property (nonatomic, strong) UIWindow *window;
@interface IGListSingleNibSectionControllerTests : IGListTestCase
@end
@implementation IGListSingleNibSectionControllerTests
- (void)setUp {
self.dataSource = [IGTestSingleNibItemDataSource new];
[super setUp];
self.window = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 0, 100, 100) collectionViewLayout:layout];
[self.window addSubview:self.collectionView];
self.dataSource = [[IGTestSingleNibItemDataSource alloc] init];
self.updater = [[IGListAdapterUpdater alloc] init];
self.adapter = [[IGListAdapter alloc] initWithUpdater:self.updater viewController:nil workingRangeSize:2];
}
- (void)tearDown {
[super tearDown];
self.window = nil;
self.collectionView = nil;
self.adapter = nil;
self.dataSource = nil;
}
- (void)setupWithObjects:(NSArray *)objects {
self.dataSource.objects = objects;
self.adapter.collectionView = self.collectionView;
self.adapter.dataSource = self.dataSource;
[self.collectionView layoutIfNeeded];
}
- (void)test_whenDisplayingCollectionView_thatSectionsHaveOneItem {

View file

@ -13,47 +13,17 @@
#import "IGListAdapterInternal.h"
#import "IGTestCell.h"
#import "IGTestSingleItemDataSource.h"
#import "IGListTestCase.h"
#define genTestObject(k, v) [[IGTestObject alloc] initWithKey:k value:v]
#define genExpectation [self expectationWithDescription:NSStringFromSelector(_cmd)]
@interface IGListSingleSectionControllerTests : XCTestCase
@property (nonatomic, strong) UICollectionView *collectionView;
@property (nonatomic, strong) IGListAdapter *adapter;
@property (nonatomic, strong) IGListAdapterUpdater *updater;
@property (nonatomic, strong) IGTestSingleItemDataSource *dataSource;
@property (nonatomic, strong) UIWindow *window;
@interface IGListSingleSectionControllerTests : IGListTestCase
@end
@implementation IGListSingleSectionControllerTests
- (void)setUp {
self.dataSource = [IGTestSingleItemDataSource new];
[super setUp];
self.window = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 0, 100, 100) collectionViewLayout:layout];
[self.window addSubview:self.collectionView];
self.dataSource = [[IGTestSingleItemDataSource alloc] init];
self.updater = [[IGListAdapterUpdater alloc] init];
self.adapter = [[IGListAdapter alloc] initWithUpdater:self.updater viewController:nil workingRangeSize:2];
}
- (void)tearDown {
[super tearDown];
self.window = nil;
self.collectionView = nil;
self.adapter = nil;
self.dataSource = nil;
}
- (void)setupWithObjects:(NSArray *)objects {
self.dataSource.objects = objects;
self.adapter.collectionView = self.collectionView;
self.adapter.dataSource = self.dataSource;
[self.collectionView layoutIfNeeded];
}
- (void)test_whenDisplayingCollectionView_thatSectionsHaveOneItem {

View file

@ -12,8 +12,7 @@
#import "IGTestStoryboardCell.h"
#import "IGTestSingleStoryboardItemDataSource.h"
#import "IGTestStoryboardViewController.h"
#define genTestObject(k, v) [[IGTestObject alloc] initWithKey:k value:v]
#import "IGListTestCase.h"
#define genExpectation [self expectationWithDescription:NSStringFromSelector(_cmd)]

View file

@ -25,12 +25,7 @@
#import "IGTestSupplementarySource.h"
#import "IGTestSupplementarySource.h"
#import "IGTestStoryboardSupplementarySource.h"
#define IGAssertEqualSize(size, w, h, ...) \
do { \
CGSize s = CGSizeMake(w, h); \
XCTAssertEqual(CGSizeEqualToSize(size, s), YES); \
} while(0)
#import "IGListTestHelpers.h"
static const CGRect kStackTestFrame = (CGRect){{0.0, 0.0}, {100.0, 100.0}};

43
Tests/IGListTestCase.h Normal file
View file

@ -0,0 +1,43 @@
/**
* 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/IGListKit.h>
#import "IGListTestHelpers.h"
@protocol IGListTestCaseDataSource <IGListAdapterDataSource>
- (NSArray *)objects;
- (void)setObjects:(NSArray<id<IGListDiffable>> *)objects;
@end
@interface IGListTestCase : XCTestCase
// These objects are created for you in -setUp
@property (nonatomic, strong) UIWindow *window;
@property (nonatomic, strong) IGListAdapter *adapter;
@property (nonatomic, strong) UICollectionViewFlowLayout *layout;
// Created in -setUp if your subclass has not already created one
@property (nonatomic, strong) UICollectionView *collectionView;
@property (nonatomic, assign) CGRect frame; // default 0,0,100,100
@property (nonatomic, strong) id<IGListUpdatingDelegate> updater; // default IGListAdapterUpdater
// Required objects must be set before [super setUp] in your test subclass
@property (nonatomic, strong) id<IGListTestCaseDataSource> dataSource;
// Optional properties that you can set before [super setUp]
@property (nonatomic, strong) UIViewController *viewController; // default nil
@property (nonatomic, assign) NSInteger workingRangeSize; // default 0
// Call to configure, layout, and display the adapter and collection view
- (void)setupWithObjects:(NSArray *)objects;
@end

53
Tests/IGListTestCase.m Normal file
View file

@ -0,0 +1,53 @@
/**
* 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 "IGListTestCase.h"
@implementation IGListTestCase
- (void)setUp {
[super setUp];
IGAssert(self.dataSource != nil, @"Data source must be set in -setUp before testing %@", NSStringFromClass(self.class));
if (CGRectEqualToRect(self.frame, CGRectZero)) {
self.frame = CGRectMake(0, 0, 100, 100);
}
self.window = [[UIWindow alloc] initWithFrame:self.frame];
self.layout = [UICollectionViewFlowLayout new];
self.collectionView = self.collectionView ?: [[UICollectionView alloc] initWithFrame:self.frame
collectionViewLayout:self.layout];
[self.window addSubview:self.collectionView];
self.updater = self.updater ?: [IGListAdapterUpdater new];
self.adapter = [[IGListAdapter alloc] initWithUpdater:self.updater
viewController:self.viewController
workingRangeSize:self.workingRangeSize];
}
- (void)tearDown {
self.window = nil;
self.collectionView = nil;
self.adapter = nil;
self.dataSource = nil;
self.updater = nil;
self.viewController = nil;
self.workingRangeSize = 0;
[super tearDown];
}
- (void)setupWithObjects:(NSArray *)objects {
self.dataSource.objects = objects;
self.adapter.collectionView = self.collectionView;
self.adapter.dataSource = self.dataSource;
[self.collectionView layoutIfNeeded];
}
@end

45
Tests/IGListTestHelpers.h Normal file
View file

@ -0,0 +1,45 @@
/**
* 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 <Foundation/Foundation.h>
static inline NSIndexPath *genIndexPath(NSInteger section, NSInteger item) {
return [NSIndexPath indexPathForItem:item inSection:section];
}
//static inline UIViewController *loadViewController(NSString *storyboard, Class testClass, UIWin)
#define genExpectation [self expectationWithDescription:NSStringFromSelector(_cmd)]
#define waitExpectation [self waitForExpectationsWithTimeout:30 handler:nil]
#define IGAssertEqualPoint(point, x, y, ...) \
do { \
CGPoint p = CGPointMake(x, y); \
XCTAssertEqual(CGPointEqualToPoint(point, p), YES); \
} while(0)
#define IGAssertEqualSize(size, w, h, ...) \
do { \
CGSize s = CGSizeMake(w, h); \
XCTAssertEqual(CGSizeEqualToSize(size, s), YES); \
} while(0)
#define IGAssertEqualFrame(frame, x, y, w, h, ...) \
do { \
CGRect expected = CGRectMake(x, y, w, h); \
XCTAssertEqual(CGRectGetMinX(expected), CGRectGetMinX(frame)); \
XCTAssertEqual(CGRectGetMinY(expected), CGRectGetMinY(frame)); \
XCTAssertEqual(CGRectGetWidth(expected), CGRectGetWidth(frame)); \
XCTAssertEqual(CGRectGetHeight(expected), CGRectGetHeight(frame)); \
} while(0)
#define IGAssertContains(collection, object) do {\
id haystack = collection; id needle = object; \
XCTAssertTrue([haystack containsObject:needle], @"%@ does not contain %@", haystack, needle); \
} while(0)

View file

@ -11,7 +11,9 @@
#import <IGListKit/IGListAdapterDataSource.h>
@interface IGListTestAdapterDataSource : NSObject <IGListAdapterDataSource>
#import "IGListTestCase.h"
@interface IGListTestAdapterDataSource : NSObject <IGListTestCaseDataSource>
// array of numbers which is then passed to -[IGListTestSection setItems:]
@property (nonatomic, strong) NSArray <NSNumber *> *objects;

View file

@ -11,10 +11,12 @@
#import <IGListKit/IGListAdapterDataSource.h>
#import "IGListTestCase.h"
@class IGTestObject;
@class IGTestDelegateController;
@interface IGTestDelegateDataSource : NSObject <IGListAdapterDataSource>
@interface IGTestDelegateDataSource : NSObject <IGListTestCaseDataSource>
@property (nonatomic, strong) NSArray <IGTestObject *> *objects;

View file

@ -11,9 +11,11 @@
#import <IGListKit/IGListAdapterDataSource.h>
#import "IGListTestCase.h"
@class IGTestDiffingObject;
@interface IGTestDiffingDataSource : NSObject <IGListAdapterDataSource>
@interface IGTestDiffingDataSource : NSObject <IGListTestCaseDataSource>
@property (nonatomic, strong) NSArray<IGTestDiffingObject *> *objects;

View file

@ -11,6 +11,8 @@
#import <IGListKit/IGListKit.h>
#define genTestObject(k, v) [[IGTestObject alloc] initWithKey:k value:v]
@interface IGTestObject : NSObject <IGListDiffable, NSCopying>
- (instancetype)initWithKey:(id <NSCopying>)key value:(id)value;

View file

@ -12,8 +12,9 @@
#import <IGListKit/IGListAdapterDataSource.h>
#import "IGTestObject.h"
#import "IGListTestCase.h"
@interface IGTestSingleItemDataSource : NSObject <IGListAdapterDataSource>
@interface IGTestSingleItemDataSource : NSObject <IGListTestCaseDataSource>
@property (nonatomic, strong) NSArray <IGTestObject *> *objects;

View file

@ -12,8 +12,9 @@
#import <IGListKit/IGListAdapterDataSource.h>
#import "IGTestObject.h"
#import "IGListTestCase.h"
@interface IGTestSingleNibItemDataSource : NSObject <IGListAdapterDataSource>
@interface IGTestSingleNibItemDataSource : NSObject <IGListTestCaseDataSource>
@property (nonatomic, strong) NSArray <IGTestObject *> *objects;

View file

@ -12,8 +12,9 @@
#import <IGListKit/IGListAdapterDataSource.h>
#import "IGTestObject.h"
#import "IGListTestCase.h"
@interface IGTestStackedDataSource : NSObject <IGListAdapterDataSource>
@interface IGTestStackedDataSource : NSObject <IGListTestCaseDataSource>
@property (nonatomic, strong) NSArray <IGTestObject *> *objects;