Swiftgram/submodules/AsyncDisplayKit/Tests/ASDisplayLayerTests.mm
Peter 9bc996374f Add 'submodules/AsyncDisplayKit/' from commit '02bedc12816e251ad71777f9d2578329b6d2bef6'
git-subtree-dir: submodules/AsyncDisplayKit
git-subtree-mainline: d06f423e0ed3df1fed9bd10d79ee312a9179b632
git-subtree-split: 02bedc12816e251ad71777f9d2578329b6d2bef6
2019-06-11 18:42:43 +01:00

599 lines
22 KiB
Plaintext

//
// ASDisplayLayerTests.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 <objc/runtime.h>
#import <QuartzCore/QuartzCore.h>
#import <UIKit/UIKit.h>
#import <XCTest/XCTest.h>
#import <AsyncDisplayKit/AsyncDisplayKit.h>
#import "ASDisplayNodeTestsHelper.h"
static UIImage *bogusImage() {
static UIImage *bogusImage = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
UIGraphicsBeginImageContext(CGSizeMake(10, 10));
bogusImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
});
return bogusImage;
}
@interface _ASDisplayLayerTestContainerLayer : CALayer
@property (nonatomic, readonly) NSUInteger didCompleteTransactionCount;
@end
@implementation _ASDisplayLayerTestContainerLayer
- (void)asyncdisplaykit_asyncTransactionContainerDidCompleteTransaction:(_ASAsyncTransaction *)transaction
{
_didCompleteTransactionCount++;
}
@end
@interface ASDisplayNode (HackForTests)
- (id)initWithViewClass:(Class)viewClass;
- (id)initWithLayerClass:(Class)layerClass;
@end
@interface _ASDisplayLayerTestLayer : _ASDisplayLayer
{
BOOL _isInCancelAsyncDisplay;
BOOL _isInDisplay;
}
@property (nonatomic, readonly) NSUInteger displayCount;
@property (nonatomic, readonly) NSUInteger drawInContextCount;
@property (nonatomic, readonly) NSUInteger setContentsAsyncCount;
@property (nonatomic, readonly) NSUInteger setContentsSyncCount;
@property (nonatomic, copy, readonly) NSString *setContentsCounts;
- (BOOL)checkSetContentsCountsWithSyncCount:(NSUInteger)syncCount asyncCount:(NSUInteger)asyncCount;
@end
@implementation _ASDisplayLayerTestLayer
- (NSString *)setContentsCounts
{
return [NSString stringWithFormat:@"syncCount:%tu, asyncCount:%tu", _setContentsSyncCount, _setContentsAsyncCount];
}
- (BOOL)checkSetContentsCountsWithSyncCount:(NSUInteger)syncCount asyncCount:(NSUInteger)asyncCount
{
return ((syncCount == _setContentsSyncCount) &&
(asyncCount == _setContentsAsyncCount));
}
- (void)setContents:(id)contents
{
[super setContents:contents];
if (self.displaysAsynchronously) {
if (_isInDisplay) {
[NSException raise:NSInvalidArgumentException format:@"There is no placeholder logic in _ASDisplayLayer, unknown caller for setContents:"];
} else if (!_isInCancelAsyncDisplay) {
_setContentsAsyncCount++;
}
} else {
_setContentsSyncCount++;
}
}
- (void)display
{
_isInDisplay = YES;
[super display];
_isInDisplay = NO;
_displayCount++;
}
- (void)cancelAsyncDisplay
{
_isInCancelAsyncDisplay = YES;
[super cancelAsyncDisplay];
_isInCancelAsyncDisplay = NO;
}
// This should never get called. This just records if it is.
- (void)drawInContext:(CGContextRef)context
{
[super drawInContext:context];
_drawInContextCount++;
}
@end
typedef NS_ENUM(NSUInteger, _ASDisplayLayerTestDelegateMode)
{
_ASDisplayLayerTestDelegateModeNone = 0,
_ASDisplayLayerTestDelegateModeDrawParameters = 1 << 0,
_ASDisplayLayerTestDelegateModeWillDisplay = 1 << 1,
_ASDisplayLayerTestDelegateModeDidDisplay = 1 << 2,
};
typedef NS_ENUM(NSUInteger, _ASDisplayLayerTestDelegateClassModes) {
_ASDisplayLayerTestDelegateClassModeNone = 0,
_ASDisplayLayerTestDelegateClassModeDisplay = 1 << 0,
_ASDisplayLayerTestDelegateClassModeDrawInContext = 1 << 1,
};
@interface _ASDisplayLayerTestDelegate : ASDisplayNode <_ASDisplayLayerDelegate>
@property (nonatomic) NSUInteger didDisplayCount;
@property (nonatomic) NSUInteger drawParametersCount;
@property (nonatomic) NSUInteger willDisplayCount;
// for _ASDisplayLayerTestDelegateModeClassDisplay
@property (nonatomic) NSUInteger displayCount;
@property (nonatomic) UIImage *(^displayLayerBlock)(void);
// for _ASDisplayLayerTestDelegateModeClassDrawInContext
@property (nonatomic) NSUInteger drawRectCount;
@end
@implementation _ASDisplayLayerTestDelegate {
_ASDisplayLayerTestDelegateMode _modes;
}
static _ASDisplayLayerTestDelegateClassModes _class_modes;
+ (void)setClassModes:(_ASDisplayLayerTestDelegateClassModes)classModes
{
_class_modes = classModes;
}
- (id)initWithModes:(_ASDisplayLayerTestDelegateMode)modes
{
_modes = modes;
if (!(self = [super initWithLayerClass:[_ASDisplayLayerTestLayer class]]))
return nil;
return self;
}
- (void)didDisplayAsyncLayer:(_ASDisplayLayer *)layer
{
_didDisplayCount++;
}
- (NSObject *)drawParametersForAsyncLayer:(_ASDisplayLayer *)layer
{
_drawParametersCount++;
return self;
}
- (void)willDisplayAsyncLayer:(_ASDisplayLayer *)layer
{
_willDisplayCount++;
}
- (BOOL)respondsToSelector:(SEL)selector
{
if (sel_isEqual(selector, @selector(didDisplayAsyncLayer:))) {
return (_modes & _ASDisplayLayerTestDelegateModeDidDisplay);
} else if (sel_isEqual(selector, @selector(drawParametersForAsyncLayer:))) {
return (_modes & _ASDisplayLayerTestDelegateModeDrawParameters);
} else if (sel_isEqual(selector, @selector(willDisplayAsyncLayer:))) {
return (_modes & _ASDisplayLayerTestDelegateModeWillDisplay);
} else {
return [super respondsToSelector:selector];
}
}
+ (BOOL)respondsToSelector:(SEL)selector
{
if (sel_isEqual(selector, @selector(displayWithParameters:isCancelled:))) {
return _class_modes & _ASDisplayLayerTestDelegateClassModeDisplay;
} else if (sel_isEqual(selector, @selector(drawRect:withParameters:isCancelled:isRasterizing:))) {
return _class_modes & _ASDisplayLayerTestDelegateClassModeDrawInContext;
} else {
return [super respondsToSelector:selector];
}
}
// DANGER: Don't use the delegate as the parameters in real code; this is not thread-safe and just for accounting in unit tests!
+ (UIImage *)displayWithParameters:(_ASDisplayLayerTestDelegate *)delegate isCancelled:(NS_NOESCAPE asdisplaynode_iscancelled_block_t)sentinelBlock
{
UIImage *contents = bogusImage();
if (delegate->_displayLayerBlock != NULL) {
contents = delegate->_displayLayerBlock();
}
delegate->_displayCount++;
return contents;
}
// DANGER: Don't use the delegate as the parameters in real code; this is not thread-safe and just for accounting in unit tests!
+ (void)drawRect:(CGRect)bounds withParameters:(_ASDisplayLayerTestDelegate *)delegate isCancelled:(NS_NOESCAPE asdisplaynode_iscancelled_block_t)sentinelBlock isRasterizing:(BOOL)isRasterizing
{
__atomic_add_fetch(&delegate->_drawRectCount, 1, __ATOMIC_SEQ_CST);
}
- (NSUInteger)drawRectCount
{
return(__atomic_load_n(&_drawRectCount, __ATOMIC_SEQ_CST));
}
@end
@interface _ASDisplayLayerTests : XCTestCase
@end
@implementation _ASDisplayLayerTests
- (void)setUp {
[super setUp];
// Force bogusImage() to create+cache its image. This impacts any time-sensitive tests which call the method from
// within the timed portion of the test. It seems that, in rare cases, this image creation can take a bit too long,
// causing a test failure.
bogusImage();
}
// since we're not running in an application, we need to force this display on layer the hierarchy
- (void)displayLayerRecursively:(CALayer *)layer
{
if (layer.needsDisplay) {
[layer displayIfNeeded];
}
for (CALayer *sublayer in layer.sublayers) {
[self displayLayerRecursively:sublayer];
}
}
- (void)waitForDisplayQueue
{
// make sure we don't lock up the tests indefinitely; fail after 1 sec by using an async barrier
__block BOOL didHitBarrier = NO;
dispatch_barrier_async([_ASDisplayLayer displayQueue], ^{
__atomic_store_n(&didHitBarrier, YES, __ATOMIC_SEQ_CST);
});
XCTAssertTrue(ASDisplayNodeRunRunLoopUntilBlockIsTrue(^BOOL{ return __atomic_load_n(&didHitBarrier, __ATOMIC_SEQ_CST); }));
}
- (void)waitForLayer:(_ASDisplayLayerTestLayer *)layer asyncDisplayCount:(NSUInteger)count
{
// make sure we don't lock up the tests indefinitely; fail after 1 sec of waiting for the setContents async count to increment
// NOTE: the layer sets its contents async back on the main queue, so we need to wait for main
XCTAssertTrue(ASDisplayNodeRunRunLoopUntilBlockIsTrue(^BOOL{
return (layer.setContentsAsyncCount == count);
}));
}
- (void)waitForAsyncDelegate:(_ASDisplayLayerTestDelegate *)asyncDelegate
{
XCTAssertTrue(ASDisplayNodeRunRunLoopUntilBlockIsTrue(^BOOL{
return (asyncDelegate.didDisplayCount == 1);
}));
}
- (void)checkDelegateDisplay:(BOOL)displaysAsynchronously
{
[_ASDisplayLayerTestDelegate setClassModes:_ASDisplayLayerTestDelegateClassModeDisplay];
_ASDisplayLayerTestDelegate *asyncDelegate = [[_ASDisplayLayerTestDelegate alloc] initWithModes:_ASDisplayLayerTestDelegateMode(_ASDisplayLayerTestDelegateModeDidDisplay | _ASDisplayLayerTestDelegateModeDrawParameters)];
_ASDisplayLayerTestLayer *layer = (_ASDisplayLayerTestLayer *)asyncDelegate.layer;
layer.displaysAsynchronously = displaysAsynchronously;
if (displaysAsynchronously) {
dispatch_suspend([_ASDisplayLayer displayQueue]);
}
layer.frame = CGRectMake(0.0, 0.0, 100.0, 100.0);
[layer setNeedsDisplay];
[layer displayIfNeeded];
if (displaysAsynchronously) {
XCTAssertTrue([layer checkSetContentsCountsWithSyncCount:0 asyncCount:0], @"%@", layer.setContentsCounts);
XCTAssertEqual(layer.displayCount, 1u);
XCTAssertEqual(layer.drawInContextCount, 0u);
dispatch_resume([_ASDisplayLayer displayQueue]);
[self waitForDisplayQueue];
[self waitForAsyncDelegate:asyncDelegate];
XCTAssertTrue([layer checkSetContentsCountsWithSyncCount:0 asyncCount:1], @"%@", layer.setContentsCounts);
} else {
XCTAssertTrue([layer checkSetContentsCountsWithSyncCount:1 asyncCount:0], @"%@", layer.setContentsCounts);
}
XCTAssertFalse(layer.needsDisplay);
XCTAssertEqual(layer.displayCount, 1u);
XCTAssertEqual(layer.drawInContextCount, 0u);
XCTAssertEqual(asyncDelegate.didDisplayCount, 1u);
XCTAssertEqual(asyncDelegate.displayCount, 1u);
}
- (void)testDelegateDisplaySync
{
[self checkDelegateDisplay:NO];
}
- (void)testDelegateDisplayAsync
{
[self checkDelegateDisplay:YES];
}
- (void)checkDelegateDrawInContext:(BOOL)displaysAsynchronously
{
[_ASDisplayLayerTestDelegate setClassModes:_ASDisplayLayerTestDelegateClassModeDrawInContext];
_ASDisplayLayerTestDelegate *asyncDelegate = [[_ASDisplayLayerTestDelegate alloc] initWithModes:_ASDisplayLayerTestDelegateMode(_ASDisplayLayerTestDelegateModeDidDisplay | _ASDisplayLayerTestDelegateModeDrawParameters)];
_ASDisplayLayerTestLayer *layer = (_ASDisplayLayerTestLayer *)asyncDelegate.layer;
layer.displaysAsynchronously = displaysAsynchronously;
if (displaysAsynchronously) {
dispatch_suspend([_ASDisplayLayer displayQueue]);
}
layer.frame = CGRectMake(0.0, 0.0, 100.0, 100.0);
[layer setNeedsDisplay];
[layer displayIfNeeded];
if (displaysAsynchronously) {
XCTAssertTrue([layer checkSetContentsCountsWithSyncCount:0 asyncCount:0], @"%@", layer.setContentsCounts);
XCTAssertEqual(layer.displayCount, 1u);
XCTAssertEqual(layer.drawInContextCount, 0u);
XCTAssertEqual(asyncDelegate.drawRectCount, 0u);
dispatch_resume([_ASDisplayLayer displayQueue]);
[self waitForLayer:layer asyncDisplayCount:1];
[self waitForAsyncDelegate:asyncDelegate];
XCTAssertTrue([layer checkSetContentsCountsWithSyncCount:0 asyncCount:1], @"%@", layer.setContentsCounts);
} else {
XCTAssertTrue([layer checkSetContentsCountsWithSyncCount:1 asyncCount:0], @"%@", layer.setContentsCounts);
}
XCTAssertFalse(layer.needsDisplay);
XCTAssertEqual(layer.displayCount, 1u);
XCTAssertEqual(layer.drawInContextCount, 0u);
XCTAssertEqual(asyncDelegate.didDisplayCount, 1u);
XCTAssertEqual(asyncDelegate.displayCount, 0u);
XCTAssertEqual(asyncDelegate.drawParametersCount, 1u);
XCTAssertEqual(asyncDelegate.drawRectCount, 1u);
}
- (void)testDelegateDrawInContextSync
{
[self checkDelegateDrawInContext:NO];
}
- (void)testDelegateDrawInContextAsync
{
[self checkDelegateDrawInContext:YES];
}
- (void)checkDelegateDisplayAndDrawInContext:(BOOL)displaysAsynchronously
{
[_ASDisplayLayerTestDelegate setClassModes:_ASDisplayLayerTestDelegateClassModes(_ASDisplayLayerTestDelegateClassModeDisplay | _ASDisplayLayerTestDelegateClassModeDrawInContext)];
_ASDisplayLayerTestDelegate *asyncDelegate = [[_ASDisplayLayerTestDelegate alloc] initWithModes:_ASDisplayLayerTestDelegateMode(_ASDisplayLayerTestDelegateModeDidDisplay | _ASDisplayLayerTestDelegateModeDrawParameters)];
_ASDisplayLayerTestLayer *layer = (_ASDisplayLayerTestLayer *)asyncDelegate.layer;
layer.displaysAsynchronously = displaysAsynchronously;
if (displaysAsynchronously) {
dispatch_suspend([_ASDisplayLayer displayQueue]);
}
layer.frame = CGRectMake(0.0, 0.0, 100.0, 100.0);
[layer setNeedsDisplay];
[layer displayIfNeeded];
if (displaysAsynchronously) {
XCTAssertTrue([layer checkSetContentsCountsWithSyncCount:0 asyncCount:0], @"%@", layer.setContentsCounts);
XCTAssertEqual(layer.displayCount, 1u);
XCTAssertEqual(asyncDelegate.drawParametersCount, 1u);
XCTAssertEqual(asyncDelegate.drawRectCount, 0u);
dispatch_resume([_ASDisplayLayer displayQueue]);
[self waitForDisplayQueue];
[self waitForAsyncDelegate:asyncDelegate];
XCTAssertTrue([layer checkSetContentsCountsWithSyncCount:0 asyncCount:1], @"%@", layer.setContentsCounts);
} else {
XCTAssertTrue([layer checkSetContentsCountsWithSyncCount:1 asyncCount:0], @"%@", layer.setContentsCounts);
}
XCTAssertFalse(layer.needsDisplay);
XCTAssertEqual(layer.displayCount, 1u);
XCTAssertEqual(layer.drawInContextCount, 0u);
XCTAssertEqual(asyncDelegate.didDisplayCount, 1u);
XCTAssertEqual(asyncDelegate.displayCount, 1u);
XCTAssertEqual(asyncDelegate.drawParametersCount, 1u);
XCTAssertEqual(asyncDelegate.drawRectCount, 0u);
}
- (void)testDelegateDisplayAndDrawInContextSync
{
[self checkDelegateDisplayAndDrawInContext:NO];
}
- (void)testDelegateDisplayAndDrawInContextAsync
{
[self checkDelegateDisplayAndDrawInContext:YES];
}
- (void)testCancelAsyncDisplay
{
[_ASDisplayLayerTestDelegate setClassModes:_ASDisplayLayerTestDelegateClassModeDisplay];
_ASDisplayLayerTestDelegate *asyncDelegate = [[_ASDisplayLayerTestDelegate alloc] initWithModes:_ASDisplayLayerTestDelegateModeDidDisplay];
_ASDisplayLayerTestLayer *layer = (_ASDisplayLayerTestLayer *)asyncDelegate.layer;
dispatch_suspend([_ASDisplayLayer displayQueue]);
layer.frame = CGRectMake(0.0, 0.0, 100.0, 100.0);
[layer setNeedsDisplay];
XCTAssertTrue(layer.needsDisplay);
[layer displayIfNeeded];
XCTAssertTrue([layer checkSetContentsCountsWithSyncCount:0 asyncCount:0], @"%@", layer.setContentsCounts);
XCTAssertFalse(layer.needsDisplay);
XCTAssertEqual(layer.displayCount, 1u);
XCTAssertEqual(layer.drawInContextCount, 0u);
[layer cancelAsyncDisplay];
dispatch_resume([_ASDisplayLayer displayQueue]);
[self waitForDisplayQueue];
XCTAssertTrue([layer checkSetContentsCountsWithSyncCount:0 asyncCount:0], @"%@", layer.setContentsCounts);
XCTAssertEqual(layer.displayCount, 1u);
XCTAssertEqual(layer.drawInContextCount, 0u);
XCTAssertEqual(asyncDelegate.didDisplayCount, 0u);
XCTAssertEqual(asyncDelegate.displayCount, 0u);
XCTAssertEqual(asyncDelegate.drawParametersCount, 0u);
}
- (void)DISABLED_testTransaction
{
auto delegateModes = _ASDisplayLayerTestDelegateMode(_ASDisplayLayerTestDelegateModeDidDisplay | _ASDisplayLayerTestDelegateModeDrawParameters);
[_ASDisplayLayerTestDelegate setClassModes:_ASDisplayLayerTestDelegateClassModeDisplay];
// Setup
_ASDisplayLayerTestContainerLayer *containerLayer = [[_ASDisplayLayerTestContainerLayer alloc] init];
containerLayer.asyncdisplaykit_asyncTransactionContainer = YES;
containerLayer.frame = CGRectMake(0.0, 0.0, 100.0, 100.0);
_ASDisplayLayerTestDelegate *layer1Delegate = [[_ASDisplayLayerTestDelegate alloc] initWithModes:delegateModes];
_ASDisplayLayerTestLayer *layer1 = (_ASDisplayLayerTestLayer *)layer1Delegate.layer;
layer1.displaysAsynchronously = YES;
dispatch_semaphore_t displayAsyncLayer1Sema = dispatch_semaphore_create(0);
layer1Delegate.displayLayerBlock = ^UIImage *{
dispatch_semaphore_wait(displayAsyncLayer1Sema, DISPATCH_TIME_FOREVER);
return bogusImage();
};
layer1.backgroundColor = [UIColor blackColor].CGColor;
layer1.frame = CGRectMake(0.0, 0.0, 333.0, 123.0);
[containerLayer addSublayer:layer1];
_ASDisplayLayerTestDelegate *layer2Delegate = [[_ASDisplayLayerTestDelegate alloc] initWithModes:delegateModes];
_ASDisplayLayerTestLayer *layer2 = (_ASDisplayLayerTestLayer *)layer2Delegate.layer;
layer2.displaysAsynchronously = YES;
layer2.backgroundColor = [UIColor blackColor].CGColor;
layer2.frame = CGRectMake(0.0, 50.0, 97.0, 50.0);
[containerLayer addSublayer:layer2];
dispatch_suspend([_ASDisplayLayer displayQueue]);
// display below if needed
[layer1 setNeedsDisplay];
[layer2 setNeedsDisplay];
[containerLayer setNeedsDisplay];
[self displayLayerRecursively:containerLayer];
// check state before running displayQueue
XCTAssertTrue([layer1 checkSetContentsCountsWithSyncCount:0 asyncCount:0], @"%@", layer1.setContentsCounts);
XCTAssertEqual(layer1.displayCount, 1u);
XCTAssertEqual(layer1Delegate.displayCount, 0u);
XCTAssertTrue([layer2 checkSetContentsCountsWithSyncCount:0 asyncCount:0], @"%@", layer2.setContentsCounts);
XCTAssertEqual(layer2.displayCount, 1u);
XCTAssertEqual(layer1Delegate.displayCount, 0u);
XCTAssertEqual(containerLayer.didCompleteTransactionCount, 0u);
// run displayQueue until async display for layer2 has been run
dispatch_resume([_ASDisplayLayer displayQueue]);
XCTAssertTrue(ASDisplayNodeRunRunLoopUntilBlockIsTrue(^BOOL{
return (layer2Delegate.displayCount == 1);
}));
// check layer1 has not had async display run
XCTAssertTrue([layer1 checkSetContentsCountsWithSyncCount:0 asyncCount:0], @"%@", layer1.setContentsCounts);
XCTAssertEqual(layer1.displayCount, 1u);
XCTAssertEqual(layer1Delegate.displayCount, 0u);
// check layer2 has had async display run
XCTAssertTrue([layer2 checkSetContentsCountsWithSyncCount:0 asyncCount:0], @"%@", layer2.setContentsCounts);
XCTAssertEqual(layer2.displayCount, 1u);
XCTAssertEqual(layer2Delegate.displayCount, 1u);
XCTAssertEqual(containerLayer.didCompleteTransactionCount, 0u);
// allow layer1 to complete display
dispatch_semaphore_signal(displayAsyncLayer1Sema);
[self waitForLayer:layer1 asyncDisplayCount:1];
// check that both layers have completed display
XCTAssertTrue([layer1 checkSetContentsCountsWithSyncCount:0 asyncCount:1], @"%@", layer1.setContentsCounts);
XCTAssertEqual(layer1.displayCount, 1u);
XCTAssertEqual(layer1Delegate.displayCount, 1u);
XCTAssertTrue([layer2 checkSetContentsCountsWithSyncCount:0 asyncCount:1], @"%@", layer2.setContentsCounts);
XCTAssertEqual(layer2.displayCount, 1u);
XCTAssertEqual(layer2Delegate.displayCount, 1u);
XCTAssertTrue(ASDisplayNodeRunRunLoopUntilBlockIsTrue(^BOOL{
return (containerLayer.didCompleteTransactionCount == 1);
}));
}
- (void)checkSuspendResume:(BOOL)displaysAsynchronously
{
[_ASDisplayLayerTestDelegate setClassModes:_ASDisplayLayerTestDelegateClassModeDrawInContext];
_ASDisplayLayerTestDelegate *asyncDelegate = [[_ASDisplayLayerTestDelegate alloc] initWithModes:_ASDisplayLayerTestDelegateMode(_ASDisplayLayerTestDelegateModeDidDisplay | _ASDisplayLayerTestDelegateModeDrawParameters)];
_ASDisplayLayerTestLayer *layer = (_ASDisplayLayerTestLayer *)asyncDelegate.layer;
layer.displaysAsynchronously = displaysAsynchronously;
layer.frame = CGRectMake(0.0, 0.0, 100.0, 100.0);
if (displaysAsynchronously) {
dispatch_suspend([_ASDisplayLayer displayQueue]);
}
// Layer shouldn't display because display is suspended
layer.displaySuspended = YES;
[layer setNeedsDisplay];
[layer displayIfNeeded];
XCTAssertEqual(layer.displayCount, 0u, @"Should not have displayed because display is suspended, thus -setNeedsDisplay is a no-op");
XCTAssertFalse(layer.needsDisplay, @"Should not need display");
if (displaysAsynchronously) {
XCTAssertTrue([layer checkSetContentsCountsWithSyncCount:0 asyncCount:0], @"%@", layer.setContentsCounts);
dispatch_resume([_ASDisplayLayer displayQueue]);
[self waitForDisplayQueue];
XCTAssertTrue([layer checkSetContentsCountsWithSyncCount:0 asyncCount:0], @"%@", layer.setContentsCounts);
} else {
XCTAssertTrue([layer checkSetContentsCountsWithSyncCount:0 asyncCount:0], @"%@", layer.setContentsCounts);
}
XCTAssertFalse(layer.needsDisplay);
XCTAssertEqual(layer.drawInContextCount, 0u);
XCTAssertEqual(asyncDelegate.drawRectCount, 0u);
// Layer should display because display is resumed
if (displaysAsynchronously) {
dispatch_suspend([_ASDisplayLayer displayQueue]);
}
layer.displaySuspended = NO;
XCTAssertTrue(layer.needsDisplay);
[layer displayIfNeeded];
XCTAssertEqual(layer.displayCount, 1u);
if (displaysAsynchronously) {
XCTAssertTrue([layer checkSetContentsCountsWithSyncCount:0 asyncCount:0], @"%@", layer.setContentsCounts);
XCTAssertEqual(layer.drawInContextCount, 0u);
XCTAssertEqual(asyncDelegate.drawRectCount, 0u);
dispatch_resume([_ASDisplayLayer displayQueue]);
[self waitForLayer:layer asyncDisplayCount:1];
XCTAssertTrue([layer checkSetContentsCountsWithSyncCount:0 asyncCount:1], @"%@", layer.setContentsCounts);
} else {
XCTAssertTrue([layer checkSetContentsCountsWithSyncCount:1 asyncCount:0], @"%@", layer.setContentsCounts);
}
XCTAssertEqual(layer.drawInContextCount, 0u);
XCTAssertEqual(asyncDelegate.drawParametersCount, 1u);
XCTAssertEqual(asyncDelegate.drawRectCount, 1u);
XCTAssertFalse(layer.needsDisplay);
}
- (void)testSuspendResumeAsync
{
[self checkSuspendResume:YES];
}
- (void)testSuspendResumeSync
{
[self checkSuspendResume:NO];
}
@end