Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Start a thrash test suite for the collection node #1246

Merged
merged 12 commits into from
Jan 3, 2019
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
184 changes: 184 additions & 0 deletions Tests/ASCollectionViewThrashTests.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
//
// ASTableViewThrashTests.mm
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// ASTableViewThrashTests.mm
// 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 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per our coding convention, brackets should be on the following line (and ASTableViewThrashTests.mm doesn't adhere to it). Can you update the rest of this PR to follow this rule?

// 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

// Disabled temporarily due to issue where cell nodes are not marked invisible before deallocation.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Remove the comment since the test is enabled now.

- (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];
// why is ds.collectionView.test_enableSuperUpdateCallLogging available on table view but now collection view>?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We just didn't need it before. May worth adding it if you think it'd be helpful.

// ds.collectionView.test_enableSuperUpdateCallLogging = YES;
[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)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