mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-22 14:20:20 +00:00
Inject an ASDataController class to ASTableView, for testing purposes
- Injection can be done via a new internal initializer. The class will be used by ASTableView to create (and configure) a new data controller. - ASTableViewTests now injects its own type of ASDataController. This facilitates new ways for testing ASTableView-specific behaviours. The first application is counting the number of times relayoutAllNodes is called on the data controller.
This commit is contained in:
@@ -254,6 +254,8 @@
|
||||
AC47D9451B3BB41900AAEE9D /* ASRelativeSize.h in Headers */ = {isa = PBXBuildFile; fileRef = AC47D9431B3BB41900AAEE9D /* ASRelativeSize.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
AC47D9461B3BB41900AAEE9D /* ASRelativeSize.mm in Sources */ = {isa = PBXBuildFile; fileRef = AC47D9441B3BB41900AAEE9D /* ASRelativeSize.mm */; };
|
||||
AC6456091B0A335000CF11B8 /* ASCellNode.m in Sources */ = {isa = PBXBuildFile; fileRef = AC6456071B0A335000CF11B8 /* ASCellNode.m */; };
|
||||
AC7A2C171BDE11DF0093FE1A /* ASTableViewInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = AC7A2C161BDE11DF0093FE1A /* ASTableViewInternal.h */; };
|
||||
AC7A2C181BDE11DF0093FE1A /* ASTableViewInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = AC7A2C161BDE11DF0093FE1A /* ASTableViewInternal.h */; };
|
||||
ACC945A91BA9E7A0005E1FB8 /* ASViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = ACC945A81BA9E7A0005E1FB8 /* ASViewController.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
ACC945AB1BA9E7C1005E1FB8 /* ASViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = ACC945AA1BA9E7C1005E1FB8 /* ASViewController.m */; };
|
||||
ACF6ED1A1B17843500DA7C62 /* ASBackgroundLayoutSpec.h in Headers */ = {isa = PBXBuildFile; fileRef = ACF6ED011B17843500DA7C62 /* ASBackgroundLayoutSpec.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
@@ -617,6 +619,7 @@
|
||||
AC47D9431B3BB41900AAEE9D /* ASRelativeSize.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASRelativeSize.h; path = AsyncDisplayKit/Layout/ASRelativeSize.h; sourceTree = "<group>"; };
|
||||
AC47D9441B3BB41900AAEE9D /* ASRelativeSize.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ASRelativeSize.mm; path = AsyncDisplayKit/Layout/ASRelativeSize.mm; sourceTree = "<group>"; };
|
||||
AC6456071B0A335000CF11B8 /* ASCellNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASCellNode.m; sourceTree = "<group>"; };
|
||||
AC7A2C161BDE11DF0093FE1A /* ASTableViewInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASTableViewInternal.h; sourceTree = "<group>"; };
|
||||
ACC945A81BA9E7A0005E1FB8 /* ASViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASViewController.h; sourceTree = "<group>"; };
|
||||
ACC945AA1BA9E7C1005E1FB8 /* ASViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASViewController.m; sourceTree = "<group>"; };
|
||||
ACF6ED011B17843500DA7C62 /* ASBackgroundLayoutSpec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASBackgroundLayoutSpec.h; path = AsyncDisplayKit/Layout/ASBackgroundLayoutSpec.h; sourceTree = "<group>"; };
|
||||
@@ -803,6 +806,7 @@
|
||||
D785F6611A74327E00291744 /* ASScrollNode.m */,
|
||||
055F1A3219ABD3E3004DAFF1 /* ASTableView.h */,
|
||||
055F1A3319ABD3E3004DAFF1 /* ASTableView.mm */,
|
||||
AC7A2C161BDE11DF0093FE1A /* ASTableViewInternal.h */,
|
||||
0574D5E119C110610097DC25 /* ASTableViewProtocols.h */,
|
||||
058D09DF195D050800B7D73C /* ASTextNode.h */,
|
||||
058D09E0195D050800B7D73C /* ASTextNode.mm */,
|
||||
@@ -1128,6 +1132,7 @@
|
||||
058D0A4C195D05CB00B7D73C /* ASDisplayNode+Subclasses.h in Headers */,
|
||||
058D0A4A195D05CB00B7D73C /* ASDisplayNode.h in Headers */,
|
||||
058D0A84195D060300B7D73C /* ASDisplayNodeExtraIvars.h in Headers */,
|
||||
AC7A2C171BDE11DF0093FE1A /* ASTableViewInternal.h in Headers */,
|
||||
058D0A4D195D05CB00B7D73C /* ASDisplayNodeExtras.h in Headers */,
|
||||
058D0A7B195D05F900B7D73C /* ASDisplayNodeInternal.h in Headers */,
|
||||
0587F9BD1A7309ED00AFF0BA /* ASEditableTextNode.h in Headers */,
|
||||
@@ -1243,6 +1248,7 @@
|
||||
B350625B1B010F070018CF92 /* ASEqualityHelpers.h in Headers */,
|
||||
B350621B1B010EFD0018CF92 /* ASFlowLayoutController.h in Headers */,
|
||||
B350621D1B010EFD0018CF92 /* ASHighlightOverlayLayer.h in Headers */,
|
||||
AC7A2C181BDE11DF0093FE1A /* ASTableViewInternal.h in Headers */,
|
||||
B35062531B010EFD0018CF92 /* ASImageNode+CGExtras.h in Headers */,
|
||||
B35062021B010EFD0018CF92 /* ASImageNode.h in Headers */,
|
||||
B350621F1B010EFD0018CF92 /* ASImageProtocols.h in Headers */,
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
*/
|
||||
|
||||
#import "ASTableView.h"
|
||||
#import "ASTableViewInternal.h"
|
||||
|
||||
#import "ASAssert.h"
|
||||
#import "ASChangeSetDataController.h"
|
||||
@@ -155,7 +156,6 @@ static BOOL _isInterceptedSelector(SEL sel)
|
||||
_ASTableViewProxy *_proxyDataSource;
|
||||
_ASTableViewProxy *_proxyDelegate;
|
||||
|
||||
ASDataController *_dataController;
|
||||
ASFlowLayoutController *_layoutController;
|
||||
|
||||
ASRangeController *_rangeController;
|
||||
@@ -174,6 +174,7 @@ static BOOL _isInterceptedSelector(SEL sel)
|
||||
}
|
||||
|
||||
@property (atomic, assign) BOOL asyncDataSourceLocked;
|
||||
@property (nonatomic, retain, readwrite) ASDataController *dataController;
|
||||
|
||||
@end
|
||||
|
||||
@@ -199,10 +200,15 @@ void ASPerformBlockWithoutAnimation(BOOL withoutAnimation, void (^block)()) {
|
||||
}
|
||||
}
|
||||
|
||||
+ (Class)dataControllerClass
|
||||
{
|
||||
return [ASChangeSetDataController class];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Lifecycle
|
||||
|
||||
- (void)configureWithAsyncDataFetching:(BOOL)asyncDataFetchingEnabled
|
||||
- (void)configureWithDataControllerClass:(Class)dataControllerClass asyncDataFetching:(BOOL)asyncDataFetching
|
||||
{
|
||||
_layoutController = [[ASFlowLayoutController alloc] initWithScrollOption:ASFlowLayoutDirectionVertical];
|
||||
|
||||
@@ -210,13 +216,13 @@ void ASPerformBlockWithoutAnimation(BOOL withoutAnimation, void (^block)()) {
|
||||
_rangeController.layoutController = _layoutController;
|
||||
_rangeController.delegate = self;
|
||||
|
||||
_dataController = [[ASChangeSetDataController alloc] initWithAsyncDataFetching:asyncDataFetchingEnabled];
|
||||
_dataController = [[dataControllerClass alloc] initWithAsyncDataFetching:asyncDataFetching];
|
||||
_dataController.dataSource = self;
|
||||
_dataController.delegate = _rangeController;
|
||||
|
||||
_layoutController.dataSource = _dataController;
|
||||
|
||||
_asyncDataFetchingEnabled = asyncDataFetchingEnabled;
|
||||
_asyncDataFetchingEnabled = asyncDataFetching;
|
||||
_asyncDataSourceLocked = NO;
|
||||
|
||||
_leadingScreensForBatching = 1.0;
|
||||
@@ -236,6 +242,11 @@ void ASPerformBlockWithoutAnimation(BOOL withoutAnimation, void (^block)()) {
|
||||
}
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame style:(UITableViewStyle)style asyncDataFetching:(BOOL)asyncDataFetchingEnabled
|
||||
{
|
||||
return [self initWithFrame:frame style:style dataControllerClass:[self.class dataControllerClass] asyncDataFetching:asyncDataFetchingEnabled];
|
||||
}
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame style:(UITableViewStyle)style dataControllerClass:(Class)dataControllerClass asyncDataFetching:(BOOL)asyncDataFetchingEnabled
|
||||
{
|
||||
if (!(self = [super initWithFrame:frame style:style]))
|
||||
return nil;
|
||||
@@ -244,7 +255,7 @@ void ASPerformBlockWithoutAnimation(BOOL withoutAnimation, void (^block)()) {
|
||||
// https://github.com/facebook/AsyncDisplayKit/issues/385
|
||||
asyncDataFetchingEnabled = NO;
|
||||
|
||||
[self configureWithAsyncDataFetching:asyncDataFetchingEnabled];
|
||||
[self configureWithDataControllerClass:dataControllerClass asyncDataFetching:asyncDataFetchingEnabled];
|
||||
|
||||
return self;
|
||||
}
|
||||
@@ -254,7 +265,7 @@ void ASPerformBlockWithoutAnimation(BOOL withoutAnimation, void (^block)()) {
|
||||
if (!(self = [super initWithCoder:aDecoder]))
|
||||
return nil;
|
||||
|
||||
[self configureWithAsyncDataFetching:NO];
|
||||
[self configureWithDataControllerClass:[self.class dataControllerClass] asyncDataFetching:NO];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
31
AsyncDisplayKit/ASTableViewInternal.h
Normal file
31
AsyncDisplayKit/ASTableViewInternal.h
Normal file
@@ -0,0 +1,31 @@
|
||||
//
|
||||
// ASTableViewInternal.h
|
||||
// AsyncDisplayKit
|
||||
//
|
||||
// Created by Huy Nguyen on 26/10/15.
|
||||
// Copyright (c) 2015 Facebook. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ASTableView.h"
|
||||
|
||||
@class ASDataController;
|
||||
|
||||
@interface ASTableView (Internal)
|
||||
|
||||
@property (nonatomic, retain, readonly) ASDataController *dataController;
|
||||
|
||||
/**
|
||||
* Initializer.
|
||||
*
|
||||
* @param frame A rectangle specifying the initial location and size of the table view in its superview’s coordinates.
|
||||
* The frame of the table view changes as table cells are added and deleted.
|
||||
*
|
||||
* @param style A constant that specifies the style of the table view. See UITableViewStyle for descriptions of valid constants.
|
||||
*
|
||||
* @param dataControllerClass A controller class injected to and used to create a data controller for the table view.
|
||||
*
|
||||
* @param asyncDataFetchingEnabled This option is reserved for future use, and currently a no-op.
|
||||
*/
|
||||
- (instancetype)initWithFrame:(CGRect)frame style:(UITableViewStyle)style dataControllerClass:(Class)dataControllerClass asyncDataFetching:(BOOL)asyncDataFetchingEnabled;
|
||||
|
||||
@end
|
||||
@@ -9,18 +9,44 @@
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
#import "ASTableView.h"
|
||||
#import "ASTableViewInternal.h"
|
||||
#import "ASDisplayNode+Subclasses.h"
|
||||
#import "ASChangeSetDataController.h"
|
||||
|
||||
#define NumberOfSections 10
|
||||
#define NumberOfRowsPerSection 20
|
||||
#define NumberOfReloadIterations 50
|
||||
|
||||
@interface ASTestDataController : ASChangeSetDataController
|
||||
@property (atomic) int numberOfAllNodesRelayouts;
|
||||
@end
|
||||
|
||||
@implementation ASTestDataController
|
||||
|
||||
- (void)relayoutAllNodes
|
||||
{
|
||||
_numberOfAllNodesRelayouts++;
|
||||
[super relayoutAllNodes];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface ASTestTableView : ASTableView
|
||||
@property (atomic, copy) void (^willDeallocBlock)(ASTableView *tableView);
|
||||
@end
|
||||
|
||||
@implementation ASTestTableView
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame style:(UITableViewStyle)style asyncDataFetching:(BOOL)asyncDataFetchingEnabled
|
||||
{
|
||||
return [super initWithFrame:frame style:style dataControllerClass:[ASTestDataController class] asyncDataFetching:asyncDataFetchingEnabled];
|
||||
}
|
||||
|
||||
- (ASTestDataController *)testDataController
|
||||
{
|
||||
return (ASTestDataController *)self.dataController;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
if (_willDeallocBlock) {
|
||||
@@ -219,7 +245,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (void)testRelayoutAllRowsWithNonZeroSizeInitially
|
||||
- (void)testRelayoutAllNodesWithNonZeroSizeInitially
|
||||
{
|
||||
// Initial width of the table view is non-zero and all nodes are measured with this size.
|
||||
// Any subsequence size change must trigger a relayout.
|
||||
@@ -234,11 +260,13 @@
|
||||
tableView.asyncDelegate = dataSource;
|
||||
tableView.asyncDataSource = dataSource;
|
||||
|
||||
[self triggerFirstLayoutMeasurementForTableView:tableView];
|
||||
[self triggerSizeChangeAndAssertRelayoutAllRowsForTableView:tableView newSize:tableViewFinalSize];
|
||||
[tableView layoutIfNeeded];
|
||||
|
||||
XCTAssertEqual(tableView.testDataController.numberOfAllNodesRelayouts, 0);
|
||||
[self triggerSizeChangeAndAssertRelayoutAllNodesForTableView:tableView newSize:tableViewFinalSize];
|
||||
}
|
||||
|
||||
- (void)testRelayoutAllRowsWithZeroSizeInitially
|
||||
- (void)testRelayoutAllNodesWithZeroSizeInitially
|
||||
{
|
||||
// Initial width of the table view is 0. The first size change is part of the initial config.
|
||||
// Any subsequence size change after that must trigger a relayout.
|
||||
@@ -256,10 +284,10 @@
|
||||
[superview addSubview:tableView];
|
||||
// Width and height are swapped so that a later size change will simulate a rotation
|
||||
tableView.frame = CGRectMake(0, 0, tableViewFinalSize.height, tableViewFinalSize.width);
|
||||
// Trigger layout measurement on all nodes
|
||||
[tableView layoutIfNeeded];
|
||||
|
||||
[self triggerSizeChangeAndAssertRelayoutAllRowsForTableView:tableView newSize:tableViewFinalSize];
|
||||
XCTAssertEqual(tableView.testDataController.numberOfAllNodesRelayouts, 0);
|
||||
[self triggerSizeChangeAndAssertRelayoutAllNodesForTableView:tableView newSize:tableViewFinalSize];
|
||||
}
|
||||
|
||||
- (void)testRelayoutVisibleRowsWhenEditingModeIsChanged
|
||||
@@ -407,7 +435,7 @@
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)triggerSizeChangeAndAssertRelayoutAllRowsForTableView:(ASTableView *)tableView newSize:(CGSize)newSize
|
||||
- (void)triggerSizeChangeAndAssertRelayoutAllNodesForTableView:(ASTestTableView *)tableView newSize:(CGSize)newSize
|
||||
{
|
||||
XCTestExpectation *nodesMeasuredUsingNewConstrainedSizeExpectation = [self expectationWithDescription:@"nodesMeasuredUsingNewConstrainedSize"];
|
||||
|
||||
@@ -419,6 +447,8 @@
|
||||
[tableView layoutIfNeeded];
|
||||
|
||||
[tableView endUpdatesAnimated:NO completion:^(BOOL completed) {
|
||||
XCTAssertEqual(tableView.testDataController.numberOfAllNodesRelayouts, 1);
|
||||
|
||||
for (int section = 0; section < NumberOfSections; section++) {
|
||||
for (int row = 0; row < NumberOfRowsPerSection; row++) {
|
||||
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:section];
|
||||
|
||||
Reference in New Issue
Block a user