Skip to content

Commit

Permalink
Start a thrash test suite for the collection node (TextureGroup#1246)
Browse files Browse the repository at this point in the history
* Split up table view thrash tests

* Fix license

* Fix license

* Reenable thrash tests for table view

* Creating the collection view thrash tests

* Batch update animated tests

* Thrash wildly dispatch main

* Reset the thrash count

* One more test

* Lint

* Update Tests/ASThrashUtility.h

Co-Authored-By: mikezucc <mikezuccarino@gmail.com>

* Tiny code style change in ASCollectionViewThrashTests.mm
  • Loading branch information
mikezucc authored and nguyenhuy committed Jan 3, 2019
1 parent 17e5604 commit 22acb98
Show file tree
Hide file tree
Showing 5 changed files with 826 additions and 462 deletions.
10 changes: 10 additions & 0 deletions AsyncDisplayKit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,8 @@
92DD2FE61BF4D05E0074C9DD /* MapKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 92DD2FE51BF4D05E0074C9DD /* MapKit.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
92DD2FE71BF4D0850074C9DD /* ASMapNode.mm in Sources */ = {isa = PBXBuildFile; fileRef = 92DD2FE21BF4B97E0074C9DD /* ASMapNode.mm */; };
92DD2FE81BF4D0A80074C9DD /* ASMapNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 92DD2FE11BF4B97E0074C9DD /* ASMapNode.h */; settings = {ATTRIBUTES = (Public, ); }; };
9644CFE02193777C00213478 /* ASThrashUtility.m in Sources */ = {isa = PBXBuildFile; fileRef = 9644CFDF2193777C00213478 /* ASThrashUtility.m */; };
9692B4FF219E12370060C2C3 /* ASCollectionViewThrashTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9692B4FE219E12370060C2C3 /* ASCollectionViewThrashTests.mm */; };
9C49C3701B853961000B0DD5 /* ASStackLayoutElement.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C49C36E1B853957000B0DD5 /* ASStackLayoutElement.h */; settings = {ATTRIBUTES = (Public, ); }; };
9C55866B1BD54A1900B50E3A /* ASAsciiArtBoxCreator.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9C5586681BD549CB00B50E3A /* ASAsciiArtBoxCreator.mm */; };
9C55866C1BD54A3000B50E3A /* ASAsciiArtBoxCreator.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C5586671BD549CB00B50E3A /* ASAsciiArtBoxCreator.h */; settings = {ATTRIBUTES = (Public, ); }; };
Expand Down Expand Up @@ -759,6 +761,9 @@
92DD2FE11BF4B97E0074C9DD /* ASMapNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASMapNode.h; sourceTree = "<group>"; };
92DD2FE21BF4B97E0074C9DD /* ASMapNode.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASMapNode.mm; sourceTree = "<group>"; };
92DD2FE51BF4D05E0074C9DD /* MapKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MapKit.framework; path = System/Library/Frameworks/MapKit.framework; sourceTree = SDKROOT; };
9644CFDE2193777C00213478 /* ASThrashUtility.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ASThrashUtility.h; sourceTree = "<group>"; };
9644CFDF2193777C00213478 /* ASThrashUtility.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ASThrashUtility.m; sourceTree = "<group>"; };
9692B4FE219E12370060C2C3 /* ASCollectionViewThrashTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ASCollectionViewThrashTests.mm; sourceTree = "<group>"; };
9C49C36E1B853957000B0DD5 /* ASStackLayoutElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASStackLayoutElement.h; sourceTree = "<group>"; };
9C5586671BD549CB00B50E3A /* ASAsciiArtBoxCreator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASAsciiArtBoxCreator.h; sourceTree = "<group>"; };
9C5586681BD549CB00B50E3A /* ASAsciiArtBoxCreator.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASAsciiArtBoxCreator.mm; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1284,6 +1289,7 @@
058D09C5195D04C000B7D73C /* Tests */ = {
isa = PBXGroup;
children = (
9692B4FE219E12370060C2C3 /* ASCollectionViewThrashTests.mm */,
F325E48F217460B000AC93A4 /* ASTextNode2Tests.mm */,
F325E48B21745F9E00AC93A4 /* ASButtonNodeTests.mm */,
F3F698D1211CAD4600800CB1 /* ASDisplayViewAccessibilityTests.mm */,
Expand Down Expand Up @@ -1355,6 +1361,8 @@
81E95C131D62639600336598 /* ASTextNodeSnapshotTests.mm */,
058D0A36195D057000B7D73C /* ASTextNodeTests.mm */,
058D0A37195D057000B7D73C /* ASTextNodeWordKernerTests.mm */,
9644CFDE2193777C00213478 /* ASThrashUtility.h */,
9644CFDF2193777C00213478 /* ASThrashUtility.m */,
CCE4F9BC1F0ECE5200062E4E /* ASTLayoutFixture.h */,
CCE4F9BD1F0ECE5200062E4E /* ASTLayoutFixture.mm */,
CC0AEEA31D66316E005D1C78 /* ASUICollectionViewTests.mm */,
Expand Down Expand Up @@ -2287,6 +2295,7 @@
CCB2F34D1D63CCC6004E6DE9 /* ASDisplayNodeSnapshotTests.mm in Sources */,
AE6987C11DD04E1000B9E458 /* ASPagerNodeTests.mm in Sources */,
058D0A3A195D057000B7D73C /* ASDisplayNodeTests.mm in Sources */,
9644CFE02193777C00213478 /* ASThrashUtility.m in Sources */,
696FCB311D6E46050093471E /* ASBackgroundLayoutSpecSnapshotTests.mm in Sources */,
CC583AD81EF9BDC300134156 /* OCMockObject+ASAdditions.mm in Sources */,
69FEE53D1D95A9AF0086F066 /* ASLayoutElementStyleTests.mm in Sources */,
Expand All @@ -2305,6 +2314,7 @@
052EE0661A159FEF002C6279 /* ASMultiplexImageNodeTests.mm in Sources */,
058D0A3C195D057000B7D73C /* ASMutableAttributedStringBuilderTests.mm in Sources */,
F325E48C21745F9E00AC93A4 /* ASButtonNodeTests.mm in Sources */,
9692B4FF219E12370060C2C3 /* ASCollectionViewThrashTests.mm in Sources */,
E586F96C1F9F9E2900ECE00E /* ASScrollNodeTests.mm in Sources */,
CC8B05D81D73979700F54286 /* ASTextNodePerformanceTests.mm in Sources */,
CC583AD91EF9BDC600134156 /* ASDisplayNode+OCMock.mm in Sources */,
Expand Down
217 changes: 217 additions & 0 deletions Tests/ASCollectionViewThrashTests.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
//
// ASCollectionViewThrashTests.mm
// Texture
//
// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
//

#import <XCTest/XCTest.h>
#import <AsyncDisplayKit/AsyncDisplayKit.h>
#import <AsyncDisplayKit/ASCollectionView.h>
#import <stdatomic.h>

#import "ASThrashUtility.h"

@interface ASCollectionViewThrashTests : XCTestCase

@end

@implementation ASCollectionViewThrashTests
{
// The current update, which will be logged in case of a failure.
ASThrashUpdate *_update;
BOOL _failed;
}

- (void)tearDown
{
if (_failed && _update != nil) {
NSLog(@"Failed update %@: %@", _update, _update.logFriendlyBase64Representation);
}
_failed = NO;
_update = nil;
}

// NOTE: Despite the documentation, this is not always called if an exception is caught.
- (void)recordFailureWithDescription:(NSString *)description inFile:(NSString *)filePath atLine:(NSUInteger)lineNumber expected:(BOOL)expected
{
_failed = YES;
[super recordFailureWithDescription:description inFile:filePath atLine:lineNumber expected:expected];
}

- (void)verifyDataSource:(ASThrashDataSource *)ds
{
CollectionView *collectionView = ds.collectionView;
NSArray <ASThrashTestSection *> *data = [ds data];
for (NSInteger i = 0; i < collectionView.numberOfSections; i++) {
XCTAssertEqual([collectionView numberOfItemsInSection:i], data[i].items.count);

for (NSInteger j = 0; j < [collectionView numberOfItemsInSection:i]; j++) {
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:j inSection:i];
ASThrashTestItem *item = data[i].items[j];
ASThrashTestNode *node = (ASThrashTestNode *)[collectionView nodeForItemAtIndexPath:indexPath];
XCTAssertEqualObjects(node.item, item, @"Wrong node at index path %@", indexPath);
}
}
}

#pragma mark Test Methods

- (void)testInitialDataRead
{
ASThrashDataSource *ds = [[ASThrashDataSource alloc] initCollectionViewDataSourceWithData:[ASThrashTestSection sectionsWithCount:kInitialSectionCount]];
[self verifyDataSource:ds];
}

/// Replays the Base64 representation of an ASThrashUpdate from "ASThrashTestRecordedCase" file
- (void)testRecordedThrashCase
{
NSURL *caseURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"ASThrashTestRecordedCase" withExtension:nil subdirectory:@"TestResources"];
NSString *base64 = [NSString stringWithContentsOfURL:caseURL encoding:NSUTF8StringEncoding error:NULL];

_update = [ASThrashUpdate thrashUpdateWithBase64String:base64];
if (_update == nil) {
return;
}

ASThrashDataSource *ds = [[ASThrashDataSource alloc] initCollectionViewDataSourceWithData:_update.oldData];
[self applyUpdateUsingBatchUpdates:_update
toDataSource:ds
animated:NO
useXCTestWait:YES];
[self verifyDataSource:ds];
}

- (void)testThrashingWildly
{
for (NSInteger i = 0; i < kThrashingIterationCount; i++) {
[self setUp];
@autoreleasepool {
NSArray *sections = [ASThrashTestSection sectionsWithCount:kInitialSectionCount];
_update = [[ASThrashUpdate alloc] initWithData:sections];
ASThrashDataSource *ds = [[ASThrashDataSource alloc] initCollectionViewDataSourceWithData:sections];

[self applyUpdateUsingBatchUpdates:_update
toDataSource:ds
animated:NO
useXCTestWait:NO];
[self verifyDataSource:ds];
[self expectationForPredicate:[ds predicateForDeallocatedHierarchy] evaluatedWithObject:(id)kCFNull handler:nil];
}
[self waitForExpectationsWithTimeout:3 handler:nil];

[self tearDown];
}
}

- (void)testThrashingWildlyOnSameCollectionView
{
XCTestExpectation *expectation = [self expectationWithDescription:@"last test ran"];
ASThrashDataSource *ds = [[ASThrashDataSource alloc] initCollectionViewDataSourceWithData:nil];
for (NSInteger i = 0; i < 1000; i++) {
[self setUp];
@autoreleasepool {
NSArray *sections = [ASThrashTestSection sectionsWithCount:kInitialSectionCount];
_update = [[ASThrashUpdate alloc] initWithData:sections];
[ds setData:sections];
[ds.collectionView reloadData];

[self applyUpdateUsingBatchUpdates:_update
toDataSource:ds
animated:NO
useXCTestWait:NO];
[self verifyDataSource:ds];
if (i == 999) {
[expectation fulfill];
}
}

[self tearDown];
}
[self waitForExpectationsWithTimeout:3 handler:nil];
}

- (void)testThrashingWildlyDispatchWildly
{
XCTestExpectation *expectation = [self expectationWithDescription:@"last test ran"];
for (NSInteger i = 0; i < kThrashingIterationCount; i++) {
[self setUp];
@autoreleasepool {
dispatch_async(dispatch_get_main_queue(), ^{
NSArray *sections = [ASThrashTestSection sectionsWithCount:kInitialSectionCount];
_update = [[ASThrashUpdate alloc] initWithData:sections];
ASThrashDataSource *ds = [[ASThrashDataSource alloc] initCollectionViewDataSourceWithData:sections];

[self applyUpdateUsingBatchUpdates:_update
toDataSource:ds
animated:NO
useXCTestWait:NO];
[self verifyDataSource:ds];
if (i == kThrashingIterationCount-1) {
[expectation fulfill];
}
});
}

[self tearDown];
}

[self waitForExpectationsWithTimeout:100 handler:nil];
}

#pragma mark Helpers

- (void)applyUpdateUsingBatchUpdates:(ASThrashUpdate *)update
toDataSource:(ASThrashDataSource *)dataSource animated:(BOOL)animated
useXCTestWait:(BOOL)wait
{
CollectionView *collectionView = dataSource.collectionView;

XCTestExpectation *expectation;
if (wait) {
expectation = [self expectationWithDescription:@"Wait for collection view to update"];
}

void (^updateBlock)() = ^ void (){
dataSource.data = update.data;

[collectionView insertSections:update.insertedSectionIndexes];
[collectionView deleteSections:update.deletedSectionIndexes];
[collectionView reloadSections:update.replacedSectionIndexes];

[update.insertedItemIndexes enumerateObjectsUsingBlock:^(NSMutableIndexSet * _Nonnull indexes, NSUInteger idx, BOOL * _Nonnull stop) {
NSArray *indexPaths = [indexes indexPathsInSection:idx];
[collectionView insertItemsAtIndexPaths:indexPaths];
}];

[update.deletedItemIndexes enumerateObjectsUsingBlock:^(NSMutableIndexSet * _Nonnull indexes, NSUInteger idx, BOOL * _Nonnull stop) {
NSArray *indexPaths = [indexes indexPathsInSection:idx];
[collectionView deleteItemsAtIndexPaths:indexPaths];
}];

[update.replacedItemIndexes enumerateObjectsUsingBlock:^(NSMutableIndexSet * _Nonnull indexes, NSUInteger idx, BOOL * _Nonnull stop) {
NSArray *indexPaths = [indexes indexPathsInSection:idx];
[collectionView reloadItemsAtIndexPaths:indexPaths];
}];
};

@try {
[collectionView performBatchAnimated:animated
updates:updateBlock
completion:^(BOOL finished) {
[expectation fulfill];
}];
} @catch (NSException *exception) {
_failed = YES;
XCTFail("TEST FAILED");
@throw exception;
}

if (wait) {
[self waitForExpectationsWithTimeout:1 handler:nil];
}
}

@end
Loading

0 comments on commit 22acb98

Please sign in to comment.