UnitTests/UnitTests.m
/* |
File: UnitTests.m |
Contains: Unit test for the QRunLoopOperation class. |
Written by: DTS |
Copyright: Copyright (c) 2011-2013 Apple Inc. All Rights Reserved. |
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. |
("Apple") in consideration of your agreement to the following |
terms, and your use, installation, modification or |
redistribution of this Apple software constitutes acceptance of |
these terms. If you do not agree with these terms, please do |
not use, install, modify or redistribute this Apple software. |
In consideration of your agreement to abide by the following |
terms, and subject to these terms, Apple grants you a personal, |
non-exclusive license, under Apple's copyrights in this |
original Apple software (the "Apple Software"), to use, |
reproduce, modify and redistribute the Apple Software, with or |
without modifications, in source and/or binary forms; provided |
that if you redistribute the Apple Software in its entirety and |
without modifications, you must retain this notice and the |
following text and disclaimers in all such redistributions of |
the Apple Software. Neither the name, trademarks, service marks |
or logos of Apple Inc. may be used to endorse or promote |
products derived from the Apple Software without specific prior |
written permission from Apple. Except as expressly stated in |
this notice, no other rights or licenses, express or implied, |
are granted by Apple herein, including but not limited to any |
patent rights that may be infringed by your derivative works or |
by other works in which the Apple Software may be incorporated. |
The Apple Software is provided by Apple on an "AS IS" basis. |
APPLE MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING |
WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, |
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING |
THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN |
COMBINATION WITH YOUR PRODUCTS. |
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, |
INCIDENTAL OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED |
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY |
OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION |
OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY |
OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR |
OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF |
SUCH DAMAGE. |
*/ |
#if defined(NDEBUG) |
#error The UnitTest target will only work in the Debug configuration. |
#endif |
// ... because it relies on properties of QRunLoopOperation that are not available |
// in the Release configuration. |
#import "UnitTests.h" |
#include "TimerOperation.h" |
#include "DelayOperation.h" |
@interface UnitTests () |
@property (atomic, strong, readwrite) NSOperationQueue * queue; |
@property (atomic, strong, readwrite) NSOperation * op1; |
@property (atomic, strong, readwrite) NSOperation * op2; |
@property (atomic, strong, readwrite) NSOperation * op3; |
@property (atomic, strong, readonly ) TimerOperation * timerOp1; |
@property (atomic, strong, readonly ) TimerOperation * timerOp2; |
@property (atomic, strong, readonly ) TimerOperation * timerOp3; |
@property (atomic, strong, readwrite) NSMutableArray * operations; |
@end |
@implementation UnitTests |
@synthesize queue = _queue; |
@synthesize op1 = _op1; |
@synthesize op2 = _op2; |
@synthesize op3 = _op3; |
@synthesize operations = _operations; |
- (TimerOperation *)timerOp1 |
{ |
assert([self.op1 isKindOfClass:[TimerOperation class]]); |
return (TimerOperation *) self.op1; |
} |
- (TimerOperation *)timerOp2 |
{ |
assert([self.op2 isKindOfClass:[TimerOperation class]]); |
return (TimerOperation *) self.op2; |
} |
- (TimerOperation *)timerOp3 |
{ |
assert([self.op3 isKindOfClass:[TimerOperation class]]); |
return (TimerOperation *) self.op3; |
} |
- (void)setUp |
{ |
[super setUp]; |
self.queue = [[[NSOperationQueue alloc] init] autorelease]; |
[self.queue setMaxConcurrentOperationCount:1]; |
} |
- (void)tearDown |
{ |
self.queue = nil; |
[super tearDown]; |
} |
#pragma mark * No Execute |
- (TimerOperation *)timerOperationWithDuration:(NSTimeInterval)duration name:(NSString *)name |
{ |
TimerOperation * result; |
result = [[[TimerOperation alloc] initWithDuration:duration] autorelease]; |
assert(result != nil); |
result.debugName = name; |
[result debugEnableEventLog]; |
return result; |
} |
- (void)testNoExecute |
{ |
TimerOperation * op; |
// tests state transition sequence 1 |
op = [self timerOperationWithDuration:0.2 name:@"op"]; |
assert(op != nil); |
STAssertEqualObjects([op.debugEventLog componentsJoinedByString:@"/"], @"", @"sequence error"); |
// tests state transition sequence 2 |
op = [self timerOperationWithDuration:0.2 name:@"op"]; |
assert(op != nil); |
[op cancel]; |
STAssertTrue([op isCancelled], @"Can should be immediate"); |
STAssertEqualObjects([op.debugEventLog componentsJoinedByString:@"/"], @">cancel/-cancel.winner/<cancel", @"sequence error"); |
} |
#pragma mark * Cancel before Start |
- (void)testCancelBeforeStart |
{ |
NSDate * endDate; |
self.op1 = [self timerOperationWithDuration:0.2 name:@"op1"]; |
assert(self.op1 != nil); |
STAssertFalse([self.op1 isExecuting], @"shouldn't start executing"); |
STAssertFalse([self.op1 isCancelled], @"shouldn't start cancelled"); |
STAssertFalse([self.op1 isFinished], @"shouldn't start finished"); |
[self.op1 cancel]; |
[self.queue addOperation:self.op1]; |
// STAssertFalse([self.op1 isExecuting], @"shouldn't start executing"); -- it may be executing at this point |
STAssertTrue( [self.op1 isCancelled], @"shouldn't start cancelled"); |
// STAssertFalse([self.op1 isFinished], @"shouldn't start finished"); -- ditto |
[self performSelector:@selector(cancelBeforeStartAfterOp1Done) withObject:nil afterDelay:0.1]; |
endDate = [NSDate dateWithTimeIntervalSinceNow:0.5]; |
while (self.op1 != nil) { |
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:endDate]; |
} |
} |
- (void)cancelBeforeStartAfterOp1Done |
{ |
STAssertNotNil(self.op1, @"op1 shouldn't be already done"); |
STAssertFalse([self.op1 isExecuting], @"shouldn't be executing"); |
STAssertTrue( [self.op1 isCancelled], @"should be cancelled"); |
STAssertTrue( [self.op1 isFinished], @"should be finished"); |
STAssertEqualObjects([self.timerOp1.debugEventLog componentsJoinedByString:@"/"], @">cancel/-cancel.winner/<cancel/>start/-setState.executing/<start/>startOnRunLoopThread/-startOnRunLoopThread.cancelled/>finishWithError/-finishWithError.error/-setState.finished/<finishWithError/<startOnRunLoopThread", @"sequence error"); |
self.op1 = nil; |
} |
#pragma mark * Cancel during start |
- (void)testCancelDuringStart |
{ |
NSDate * endDate; |
self.op1 = [self timerOperationWithDuration:0.2 name:@"op1"]; |
assert(self.op1 != nil); |
STAssertFalse([self.op1 isExecuting], @"shouldn't start executing"); |
STAssertFalse([self.op1 isCancelled], @"shouldn't start cancelled"); |
STAssertFalse([self.op1 isFinished], @"shouldn't start finished"); |
self.op2 = [self timerOperationWithDuration:0.2 name:@"op2"]; |
assert(self.op2 != nil); |
STAssertFalse([self.op1 isExecuting], @"shouldn't start executing"); |
STAssertFalse([self.op1 isCancelled], @"shouldn't start cancelled"); |
STAssertFalse([self.op1 isFinished], @"shouldn't start finished"); |
self.timerOp1.debugCancelSelfBeforeSchedulingStart = YES; |
self.timerOp2.debugCancelSelfAfterSchedulingStart = YES; |
[self.queue addOperation:self.op1]; |
[self.queue addOperation:self.op2]; |
[self performSelector:@selector(cancelDuringStartAllDone) withObject:nil afterDelay:0.1]; |
endDate = [NSDate dateWithTimeIntervalSinceNow:0.5]; |
while (self.op1 != nil) { |
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:endDate]; |
} |
} |
- (void)cancelDuringStartAllDone |
{ |
STAssertNotNil(self.op1, @"op1 shouldn't be already done"); |
STAssertFalse([self.op1 isExecuting], @"shouldn't be executing"); |
STAssertTrue( [self.op1 isCancelled], @"should be cancelled"); |
STAssertTrue( [self.op1 isFinished], @"should be finished"); |
STAssertEqualObjects([self.timerOp1.debugEventLog componentsJoinedByString:@"/"], @">start/-setState.executing/-start.cancelBefore/>cancel/-cancel.winner/-cancel.schedule/<cancel/<start/>cancelOnRunLoopThread/-cancelOnRunLoopThread.cancel/>finishWithError/-finishWithError.error/-setState.finished/<finishWithError/<cancelOnRunLoopThread/>startOnRunLoopThread/-startOnRunLoopThread.bounce/<startOnRunLoopThread", @"sequence error"); |
STAssertNotNil(self.op2, @"op2 shouldn't be already done"); |
STAssertFalse([self.op2 isExecuting], @"shouldn't be executing"); |
STAssertTrue( [self.op2 isCancelled], @"should be cancelled"); |
STAssertTrue( [self.op2 isFinished], @"should be finished"); |
STAssertEqualObjects([self.timerOp2.debugEventLog componentsJoinedByString:@"/"], @">start/-setState.executing/-start.cancelAfter/>cancel/-cancel.winner/-cancel.schedule/<cancel/<start/>startOnRunLoopThread/-startOnRunLoopThread.cancelled/>finishWithError/-finishWithError.error/-setState.finished/<finishWithError/<startOnRunLoopThread/>cancelOnRunLoopThread/-cancelOnRunLoopThread.bounce/<cancelOnRunLoopThread", @"sequence error"); |
self.op1 = nil; |
self.op2 = nil; |
} |
#pragma mark * Basics |
// Tests that stuff works at all. |
- (void)testBasics |
{ |
NSDate * endDate; |
self.op1 = [self timerOperationWithDuration:0.2 name:@"op1"]; |
assert(self.op1 != nil); |
STAssertFalse([self.op1 isExecuting], @"shouldn't start executing"); |
STAssertFalse([self.op1 isCancelled], @"shouldn't start cancelled"); |
STAssertFalse([self.op1 isFinished], @"shouldn't start finished"); |
[self.queue addOperation:self.op1]; |
// STAssertFalse([self.op1 isExecuting], @"shouldn't start executing"); -- it may be executing at this point |
STAssertFalse([self.op1 isCancelled], @"shouldn't start cancelled"); |
STAssertFalse([self.op1 isFinished], @"shouldn't start finished"); |
[self performSelector:@selector(basicsBeforeOp1Done) withObject:nil afterDelay:0.1]; |
[self performSelector:@selector(basicsAfterOp1Done) withObject:nil afterDelay:0.3]; |
endDate = [NSDate dateWithTimeIntervalSinceNow:0.5]; |
while (self.op1 != nil) { |
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:endDate]; |
} |
} |
- (void)basicsBeforeOp1Done |
{ |
STAssertNotNil(self.op1, @"op1 shouldn't be already done"); |
STAssertTrue( [self.op1 isExecuting], @"should be executing"); |
STAssertFalse([self.op1 isCancelled], @"shouldn't be cancelled"); |
STAssertFalse([self.op1 isFinished], @"shouldn't be finished"); |
} |
- (void)basicsAfterOp1Done |
{ |
STAssertNotNil(self.op1, @"op1 shouldn't be already done"); |
STAssertFalse([self.op1 isExecuting], @"shouldn't be executing"); |
STAssertFalse([self.op1 isCancelled], @"shouldn't be cancelled"); |
STAssertTrue( [self.op1 isFinished], @"should be finished"); |
STAssertEqualObjects([self.timerOp1.debugEventLog componentsJoinedByString:@"/"], @">start/-setState.executing/<start/>startOnRunLoopThread/-startOnRunLoopThread.start/<startOnRunLoopThread/>finishWithError/-finishWithError.noError/-setState.finished/<finishWithError", @"sequence error"); |
self.op1 = nil; |
} |
#pragma mark * Basics with Cancel |
// Tests that cancellation works at all. |
- (void)testBasicsCancel |
{ |
NSDate * endDate; |
self.op1 = [self timerOperationWithDuration:0.2 name:@"op1"]; |
assert(self.op1 != nil); |
STAssertFalse([self.op1 isExecuting], @"shouldn't start executing"); |
STAssertFalse([self.op1 isCancelled], @"shouldn't start cancelled"); |
STAssertFalse([self.op1 isFinished], @"shouldn't start finished"); |
[self.queue addOperation:self.op1]; |
// STAssertFalse([self.op1 isExecuting], @"shouldn't start executing"); -- it may be executing at this point |
STAssertFalse([self.op1 isCancelled], @"shouldn't start cancelled"); |
STAssertFalse([self.op1 isFinished], @"shouldn't start finished"); |
[self performSelector:@selector(basicsCancelBeforeOp1Done) withObject:nil afterDelay:0.1]; |
[self performSelector:@selector(basicsCancelAfterOp1Done) withObject:nil afterDelay:0.125]; |
endDate = [NSDate dateWithTimeIntervalSinceNow:0.3]; |
while (self.op1 != nil) { |
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:endDate]; |
} |
} |
- (void)basicsCancelBeforeOp1Done |
{ |
STAssertNotNil(self.op1, @"op1 shouldn't be already done"); |
STAssertTrue( [self.op1 isExecuting], @"should be executing"); |
STAssertFalse([self.op1 isCancelled], @"shouldn't be cancelled"); |
STAssertFalse([self.op1 isFinished], @"shouldn't be finished"); |
[self.op1 cancel]; |
} |
- (void)basicsCancelAfterOp1Done |
{ |
STAssertNotNil(self.op1, @"op1 shouldn't be already done"); |
STAssertFalse([self.op1 isExecuting], @"shouldn't be executing"); |
STAssertTrue( [self.op1 isCancelled], @"should be cancelled"); |
STAssertTrue( [self.op1 isFinished], @"should be finished"); |
STAssertEqualObjects([self.timerOp1.debugEventLog componentsJoinedByString:@"/"], @">start/-setState.executing/<start/>startOnRunLoopThread/-startOnRunLoopThread.start/<startOnRunLoopThread/>cancel/-cancel.winner/-cancel.schedule/<cancel/>cancelOnRunLoopThread/-cancelOnRunLoopThread.cancel/>finishWithError/-finishWithError.error/-setState.finished/<finishWithError/<cancelOnRunLoopThread", @"sequence error"); |
self.op1 = nil; |
} |
#pragma mark * Basics with Late Cancellation |
- (void)testBasicsCancelLate |
{ |
NSDate * endDate; |
self.op1 = [self timerOperationWithDuration:0.1 name:@"op1"]; |
assert(self.op1 != nil); |
STAssertFalse([self.op1 isExecuting], @"shouldn't start executing"); |
STAssertFalse([self.op1 isCancelled], @"shouldn't start cancelled"); |
STAssertFalse([self.op1 isFinished], @"shouldn't start finished"); |
[self.queue addOperation:self.op1]; |
// STAssertFalse([self.op1 isExecuting], @"shouldn't start executing"); -- it may be executing at this point |
STAssertFalse([self.op1 isCancelled], @"shouldn't start cancelled"); |
STAssertFalse([self.op1 isFinished], @"shouldn't start finished"); |
[self performSelector:@selector(basicsCancelLateAfterOp1Done) withObject:nil afterDelay:0.11]; |
[self performSelector:@selector(basicsCancelLateAllDone) withObject:nil afterDelay:0.15]; |
endDate = [NSDate dateWithTimeIntervalSinceNow:0.2]; |
while (self.op1 != nil) { |
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:endDate]; |
} |
} |
- (void)basicsCancelLateAfterOp1Done |
{ |
STAssertNotNil(self.op1, @"op1 shouldn't be already done"); |
STAssertFalse([self.op1 isExecuting], @"shouldn't be executing"); |
STAssertFalse([self.op1 isCancelled], @"shouldn't be cancelled"); |
STAssertTrue( [self.op1 isFinished], @"should be finished"); |
[self.op1 cancel]; |
STAssertFalse([self.op1 isCancelled], @"shouldn't be cancelled"); |
} |
- (void)basicsCancelLateAllDone |
{ |
STAssertNotNil(self.op1, @"op1 shouldn't be already done"); |
STAssertFalse([self.op1 isExecuting], @"shouldn't be executing"); |
STAssertFalse([self.op1 isCancelled], @"shouldn't be cancelled"); |
STAssertTrue( [self.op1 isFinished], @"should be finished"); |
STAssertEqualObjects([self.timerOp1.debugEventLog componentsJoinedByString:@"/"], @">start/-setState.executing/<start/>startOnRunLoopThread/-startOnRunLoopThread.start/<startOnRunLoopThread/>finishWithError/-finishWithError.noError/-setState.finished/<finishWithError/>cancel/-cancel.winner/<cancel", @"sequence error"); |
self.op1 = nil; |
} |
#pragma mark * Basics with Cancel Early |
// Tests that cancellation works at all. |
- (void)testBasicsCancelEarly |
{ |
NSDate * endDate; |
self.op1 = [self timerOperationWithDuration:0.2 name:@"op1"]; |
assert(self.op1 != nil); |
STAssertFalse([self.op1 isExecuting], @"shouldn't start executing"); |
STAssertFalse([self.op1 isCancelled], @"shouldn't start cancelled"); |
STAssertFalse([self.op1 isFinished], @"shouldn't start finished"); |
self.op2 = [self timerOperationWithDuration:0.2 name:@"op2"]; |
assert(self.op2 != nil); |
STAssertFalse([self.op2 isExecuting], @"shouldn't start executing"); |
STAssertFalse([self.op2 isCancelled], @"shouldn't start cancelled"); |
STAssertFalse([self.op2 isFinished], @"shouldn't start finished"); |
[self.op1 cancel]; |
[self.queue addOperation:self.op1]; |
[self.queue addOperation:self.op2]; |
[self.op2 cancel]; |
// STAssertFalse([self.op1 isExecuting], @"shouldn't start executing"); -- it may be executing at this point |
STAssertTrue( [self.op1 isCancelled], @"should start cancelled"); |
// STAssertFalse([self.op1 isFinished], @"shouldn't start finished"); |
// STAssertFalse([self.op2 isExecuting], @"shouldn't start executing"); -- it may be executing at this point |
STAssertTrue([self.op2 isCancelled], @"should start cancelled"); |
// STAssertFalse([self.op2 isFinished], @"shouldn't start finished"); |
[self performSelector:@selector(basicsCancelEarlyDone) withObject:nil afterDelay:0.025]; |
endDate = [NSDate dateWithTimeIntervalSinceNow:0.3]; |
while (self.op1 != nil) { |
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:endDate]; |
} |
} |
- (void)basicsCancelEarlyDone |
{ |
STAssertNotNil(self.op1, @"op1 shouldn't be already done"); |
STAssertFalse([self.op1 isExecuting], @"shouldn't be executing"); |
STAssertTrue( [self.op1 isCancelled], @"should be cancelled"); |
STAssertTrue( [self.op1 isFinished], @"should be finished"); |
STAssertNotNil(self.op2, @"op1 shouldn't be already done"); |
STAssertFalse([self.op2 isExecuting], @"shouldn't be executing"); |
STAssertTrue( [self.op2 isCancelled], @"should be cancelled"); |
STAssertTrue( [self.op2 isFinished], @"should be finished"); |
STAssertEqualObjects([self.timerOp1.debugEventLog componentsJoinedByString:@"/"], @">cancel/-cancel.winner/<cancel/>start/-setState.executing/<start/>startOnRunLoopThread/-startOnRunLoopThread.cancelled/>finishWithError/-finishWithError.error/-setState.finished/<finishWithError/<startOnRunLoopThread", @"sequence error"); |
STAssertEqualObjects([self.timerOp2.debugEventLog componentsJoinedByString:@"/"], @">cancel/-cancel.winner/<cancel/>start/-setState.executing/<start/>startOnRunLoopThread/-startOnRunLoopThread.cancelled/>finishWithError/-finishWithError.error/-setState.finished/<finishWithError/<startOnRunLoopThread", @"sequence error"); |
self.op1 = nil; |
self.op2 = nil; |
} |
#pragma mark * Turnover |
// Tests that one operation will start the next operation. |
- (void)testTurnover |
{ |
NSDate * endDate; |
self.op1 = [self timerOperationWithDuration:0.2 name:@"op1"]; |
assert(self.op1 != nil); |
STAssertFalse([self.op1 isExecuting], @"shouldn't start executing"); |
STAssertFalse([self.op1 isCancelled], @"shouldn't start cancelled"); |
STAssertFalse([self.op1 isFinished], @"shouldn't start finished"); |
self.op2 = [self timerOperationWithDuration:0.2 name:@"op2"]; |
assert(self.op2 != nil); |
STAssertFalse([self.op2 isExecuting], @"shouldn't start executing"); |
STAssertFalse([self.op2 isCancelled], @"shouldn't start cancelled"); |
STAssertFalse([self.op2 isFinished], @"shouldn't start finished"); |
self.op3 = [self timerOperationWithDuration:0.2 name:@"op3"]; |
assert(self.op3 != nil); |
STAssertFalse([self.op3 isExecuting], @"shouldn't start executing"); |
STAssertFalse([self.op3 isCancelled], @"shouldn't start cancelled"); |
STAssertFalse([self.op3 isFinished], @"shouldn't start finished"); |
[self.queue addOperation:self.op1]; |
[self.queue addOperation:self.op2]; |
[self.queue addOperation:self.op3]; |
// STAssertFalse([self.op1 isExecuting], @"shouldn't start executing"); -- it may be executing at this point |
STAssertFalse([self.op1 isCancelled], @"shouldn't start cancelled"); |
STAssertFalse([self.op1 isFinished], @"shouldn't start finished"); |
STAssertFalse([self.op2 isExecuting], @"shouldn't start executing"); |
STAssertFalse([self.op2 isCancelled], @"shouldn't start cancelled"); |
STAssertFalse([self.op2 isFinished], @"shouldn't start finished"); |
STAssertFalse([self.op3 isExecuting], @"shouldn't start executing"); |
STAssertFalse([self.op3 isCancelled], @"shouldn't start cancelled"); |
STAssertFalse([self.op3 isFinished], @"shouldn't start finished"); |
[self performSelector:@selector(turnoverBeforeOp1Done) withObject:nil afterDelay:0.1]; |
[self performSelector:@selector(turnoverAfterOp1Done) withObject:nil afterDelay:0.3]; |
[self performSelector:@selector(turnoverAfterOp2Done) withObject:nil afterDelay:0.5]; |
[self performSelector:@selector(turnoverAfterOp3Done) withObject:nil afterDelay:0.7]; |
endDate = [NSDate dateWithTimeIntervalSinceNow:0.8]; |
while (self.op3 != nil) { |
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:endDate]; |
} |
} |
- (void)turnoverBeforeOp1Done |
{ |
STAssertNotNil(self.op1, @"op1 should be present"); |
STAssertTrue( [self.op1 isExecuting], @"op1 should be executing"); |
STAssertFalse([self.op1 isCancelled], @"op1 shouldn't be cancelled"); |
STAssertFalse([self.op1 isFinished], @"op1 shouldn't be finished"); |
STAssertNotNil(self.op2, @"op2 should be present"); |
STAssertFalse([self.op2 isExecuting], @"op2 shouldn't be executing"); |
STAssertFalse([self.op2 isCancelled], @"op2 shouldn't be cancelled"); |
STAssertFalse([self.op2 isFinished], @"op2 shouldn't be finished"); |
STAssertNotNil(self.op3, @"op3 should be present"); |
STAssertFalse([self.op3 isExecuting], @"op3 shouldn't be executing"); |
STAssertFalse([self.op3 isCancelled], @"op3 shouldn't be cancelled"); |
STAssertFalse([self.op3 isFinished], @"op3 shouldn't be finished"); |
} |
- (void)turnoverAfterOp1Done |
{ |
STAssertNotNil(self.op1, @"op1 should be present"); |
STAssertFalse([self.op1 isExecuting], @"op1 should be executing"); |
STAssertFalse([self.op1 isCancelled], @"op1 shouldn't be cancelled"); |
STAssertTrue( [self.op1 isFinished], @"op1 should be finished"); |
STAssertNotNil(self.op2, @"op2 should be present"); |
STAssertTrue( [self.op2 isExecuting], @"op2 should be executing"); |
STAssertFalse([self.op2 isCancelled], @"op2 shouldn't be cancelled"); |
STAssertFalse([self.op2 isFinished], @"op2 shouldn't be finished"); |
STAssertNotNil(self.op3, @"op3 should be present"); |
STAssertFalse([self.op3 isExecuting], @"op3 shouldn't be executing"); |
STAssertFalse([self.op3 isCancelled], @"op3 shouldn't be cancelled"); |
STAssertFalse([self.op3 isFinished], @"op3 shouldn't be finished"); |
} |
- (void)turnoverAfterOp2Done |
{ |
STAssertNotNil(self.op1, @"op1 should be present"); |
STAssertFalse([self.op1 isExecuting], @"op1 should be executing"); |
STAssertFalse([self.op1 isCancelled], @"op1 shouldn't be cancelled"); |
STAssertTrue( [self.op1 isFinished], @"op1 should be finished"); |
STAssertNotNil(self.op2, @"op2 should be present"); |
STAssertFalse([self.op2 isExecuting], @"op2 shouldn't be executing"); |
STAssertFalse([self.op2 isCancelled], @"op2 shouldn't be cancelled"); |
STAssertTrue( [self.op2 isFinished], @"op2 should be finished"); |
STAssertNotNil(self.op3, @"op3 should be present"); |
STAssertTrue( [self.op3 isExecuting], @"op3 should be executing"); |
STAssertFalse([self.op3 isCancelled], @"op3 shouldn't be cancelled"); |
STAssertFalse([self.op3 isFinished], @"op3 shouldn't be finished"); |
} |
- (void)turnoverAfterOp3Done |
{ |
STAssertNotNil(self.op1, @"op1 should be present"); |
STAssertFalse([self.op1 isExecuting], @"op1 should be executing"); |
STAssertFalse([self.op1 isCancelled], @"op1 shouldn't be cancelled"); |
STAssertTrue( [self.op1 isFinished], @"op1 should be finished"); |
STAssertNotNil(self.op2, @"op2 should be present"); |
STAssertFalse([self.op2 isExecuting], @"op2 shouldn't be executing"); |
STAssertFalse([self.op2 isCancelled], @"op2 shouldn't be cancelled"); |
STAssertTrue( [self.op2 isFinished], @"op2 should be finished"); |
STAssertNotNil(self.op3, @"op3 should be present"); |
STAssertFalse([self.op3 isExecuting], @"op3 shouldn't be executing"); |
STAssertFalse([self.op3 isCancelled], @"op3 shouldn't be cancelled"); |
STAssertTrue( [self.op3 isFinished], @"op3 should be finished"); |
STAssertEqualObjects([self.timerOp1.debugEventLog componentsJoinedByString:@"/"], @">start/-setState.executing/<start/>startOnRunLoopThread/-startOnRunLoopThread.start/<startOnRunLoopThread/>finishWithError/-finishWithError.noError/-setState.finished/<finishWithError", @"sequence error"); |
STAssertEqualObjects([self.timerOp2.debugEventLog componentsJoinedByString:@"/"], @">start/-setState.executing/<start/>startOnRunLoopThread/-startOnRunLoopThread.start/<startOnRunLoopThread/>finishWithError/-finishWithError.noError/-setState.finished/<finishWithError", @"sequence error"); |
STAssertEqualObjects([self.timerOp3.debugEventLog componentsJoinedByString:@"/"], @">start/-setState.executing/<start/>startOnRunLoopThread/-startOnRunLoopThread.start/<startOnRunLoopThread/>finishWithError/-finishWithError.noError/-setState.finished/<finishWithError", @"sequence error"); |
self.op1 = nil; |
self.op2 = nil; |
self.op3 = nil; |
} |
#pragma mark * Turnover Thread First |
// Tests main to thread to run loop to thread turn over. |
- (void)testTurnoverThreadFirst |
{ |
NSDate * endDate; |
self.op1 = [[[DelayOperation alloc] initWithDuration:0.2] autorelease]; |
assert(self.op1 != nil); |
((DelayOperation *) self.op1).debugName = @"op1"; |
STAssertFalse([self.op1 isExecuting], @"shouldn't start executing"); |
STAssertFalse([self.op1 isCancelled], @"shouldn't start cancelled"); |
STAssertFalse([self.op1 isFinished], @"shouldn't start finished"); |
self.op2 = [self timerOperationWithDuration:0.2 name:@"op2"]; |
assert(self.op2 != nil); |
STAssertFalse([self.op2 isExecuting], @"shouldn't start executing"); |
STAssertFalse([self.op2 isCancelled], @"shouldn't start cancelled"); |
STAssertFalse([self.op2 isFinished], @"shouldn't start finished"); |
self.op3 = [[[DelayOperation alloc] initWithDuration:0.2] autorelease]; |
assert(self.op3 != nil); |
((DelayOperation *) self.op3).debugName = @"op3"; |
STAssertFalse([self.op3 isExecuting], @"shouldn't start executing"); |
STAssertFalse([self.op3 isCancelled], @"shouldn't start cancelled"); |
STAssertFalse([self.op3 isFinished], @"shouldn't start finished"); |
[self.queue addOperation:self.op1]; |
[self.queue addOperation:self.op2]; |
[self.queue addOperation:self.op3]; |
// STAssertFalse([self.op1 isExecuting], @"shouldn't start executing"); -- it may be executing at this point |
STAssertFalse([self.op1 isCancelled], @"shouldn't start cancelled"); |
STAssertFalse([self.op1 isFinished], @"shouldn't start finished"); |
STAssertFalse([self.op2 isExecuting], @"shouldn't start executing"); |
STAssertFalse([self.op2 isCancelled], @"shouldn't start cancelled"); |
STAssertFalse([self.op2 isFinished], @"shouldn't start finished"); |
STAssertFalse([self.op3 isExecuting], @"shouldn't start executing"); |
STAssertFalse([self.op3 isCancelled], @"shouldn't start cancelled"); |
STAssertFalse([self.op3 isFinished], @"shouldn't start finished"); |
[self performSelector:@selector(turnoverThreadFirstBeforeOp1Done) withObject:nil afterDelay:0.1]; |
[self performSelector:@selector(turnoverThreadFirstAfterOp1Done) withObject:nil afterDelay:0.3]; |
[self performSelector:@selector(turnoverThreadFirstAfterOp2Done) withObject:nil afterDelay:0.5]; |
[self performSelector:@selector(turnoverThreadFirstAfterOp3Done) withObject:nil afterDelay:0.7]; |
endDate = [NSDate dateWithTimeIntervalSinceNow:0.8]; |
while (self.op3 != nil) { |
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:endDate]; |
} |
} |
- (void)turnoverThreadFirstBeforeOp1Done |
{ |
// NSLog(@"turnoverThreadFirstBeforeOp1Done"); |
STAssertNotNil(self.op1, @"op1 should be present"); |
STAssertTrue( [self.op1 isExecuting], @"op1 should be executing"); |
STAssertFalse([self.op1 isCancelled], @"op1 shouldn't be cancelled"); |
STAssertFalse([self.op1 isFinished], @"op1 shouldn't be finished"); |
STAssertNotNil(self.op2, @"op2 should be present"); |
STAssertFalse([self.op2 isExecuting], @"op2 shouldn't be executing"); |
STAssertFalse([self.op2 isCancelled], @"op2 shouldn't be cancelled"); |
STAssertFalse([self.op2 isFinished], @"op2 shouldn't be finished"); |
STAssertNotNil(self.op3, @"op3 should be present"); |
STAssertFalse([self.op3 isExecuting], @"op3 shouldn't be executing"); |
STAssertFalse([self.op3 isCancelled], @"op3 shouldn't be cancelled"); |
STAssertFalse([self.op3 isFinished], @"op3 shouldn't be finished"); |
} |
- (void)turnoverThreadFirstAfterOp1Done |
{ |
// NSLog(@"turnoverThreadFirstAfterOp1Done"); |
STAssertNotNil(self.op1, @"op1 should be present"); |
STAssertFalse([self.op1 isExecuting], @"op1 should be executing"); |
STAssertFalse([self.op1 isCancelled], @"op1 shouldn't be cancelled"); |
STAssertTrue( [self.op1 isFinished], @"op1 should be finished"); |
STAssertNotNil(self.op2, @"op2 should be present"); |
STAssertTrue( [self.op2 isExecuting], @"op2 should be executing"); |
STAssertFalse([self.op2 isCancelled], @"op2 shouldn't be cancelled"); |
STAssertFalse([self.op2 isFinished], @"op2 shouldn't be finished"); |
STAssertNotNil(self.op3, @"op3 should be present"); |
STAssertFalse([self.op3 isExecuting], @"op3 shouldn't be executing"); |
STAssertFalse([self.op3 isCancelled], @"op3 shouldn't be cancelled"); |
STAssertFalse([self.op3 isFinished], @"op3 shouldn't be finished"); |
} |
- (void)turnoverThreadFirstAfterOp2Done |
{ |
// NSLog(@"turnoverThreadFirstAfterOp2Done"); |
STAssertNotNil(self.op1, @"op1 should be present"); |
STAssertFalse([self.op1 isExecuting], @"op1 should be executing"); |
STAssertFalse([self.op1 isCancelled], @"op1 shouldn't be cancelled"); |
STAssertTrue( [self.op1 isFinished], @"op1 should be finished"); |
STAssertNotNil(self.op2, @"op2 should be present"); |
STAssertFalse([self.op2 isExecuting], @"op2 shouldn't be executing"); |
STAssertFalse([self.op2 isCancelled], @"op2 shouldn't be cancelled"); |
STAssertTrue( [self.op2 isFinished], @"op2 should be finished"); |
STAssertNotNil(self.op3, @"op3 should be present"); |
STAssertTrue( [self.op3 isExecuting], @"op3 should be executing"); |
STAssertFalse([self.op3 isCancelled], @"op3 shouldn't be cancelled"); |
STAssertFalse([self.op3 isFinished], @"op3 shouldn't be finished"); |
} |
- (void)turnoverThreadFirstAfterOp3Done |
{ |
// NSLog(@"turnoverThreadFirstAfterOp3Done"); |
STAssertNotNil(self.op1, @"op1 should be present"); |
STAssertFalse([self.op1 isExecuting], @"op1 should be executing"); |
STAssertFalse([self.op1 isCancelled], @"op1 shouldn't be cancelled"); |
STAssertTrue( [self.op1 isFinished], @"op1 should be finished"); |
STAssertNotNil(self.op2, @"op2 should be present"); |
STAssertFalse([self.op2 isExecuting], @"op2 shouldn't be executing"); |
STAssertFalse([self.op2 isCancelled], @"op2 shouldn't be cancelled"); |
STAssertTrue( [self.op2 isFinished], @"op2 should be finished"); |
STAssertNotNil(self.op3, @"op3 should be present"); |
STAssertFalse([self.op3 isExecuting], @"op3 shouldn't be executing"); |
STAssertFalse([self.op3 isCancelled], @"op3 shouldn't be cancelled"); |
STAssertTrue( [self.op3 isFinished], @"op3 should be finished"); |
STAssertEqualObjects([self.timerOp2.debugEventLog componentsJoinedByString:@"/"], @">start/-setState.executing/<start/>startOnRunLoopThread/-startOnRunLoopThread.start/<startOnRunLoopThread/>finishWithError/-finishWithError.noError/-setState.finished/<finishWithError", @"sequence error"); |
self.op1 = nil; |
self.op2 = nil; |
self.op3 = nil; |
} |
#pragma mark * Turnover Run Loop First |
// Tests main to run loop to thread to run loop turn over. |
- (void)testTurnoverRunLoopFirst |
{ |
NSDate * endDate; |
self.op1 = [self timerOperationWithDuration:0.2 name:@"op1"]; |
assert(self.op1 != nil); |
STAssertFalse([self.op1 isExecuting], @"shouldn't start executing"); |
STAssertFalse([self.op1 isCancelled], @"shouldn't start cancelled"); |
STAssertFalse([self.op1 isFinished], @"shouldn't start finished"); |
self.op2 = [[[DelayOperation alloc] initWithDuration:0.2] autorelease]; |
assert(self.op2 != nil); |
((DelayOperation *) self.op2).debugName = @"op2"; |
STAssertFalse([self.op2 isExecuting], @"shouldn't start executing"); |
STAssertFalse([self.op2 isCancelled], @"shouldn't start cancelled"); |
STAssertFalse([self.op2 isFinished], @"shouldn't start finished"); |
self.op3 = [self timerOperationWithDuration:0.2 name:@"op3"]; |
assert(self.op3 != nil); |
STAssertFalse([self.op3 isExecuting], @"shouldn't start executing"); |
STAssertFalse([self.op3 isCancelled], @"shouldn't start cancelled"); |
STAssertFalse([self.op3 isFinished], @"shouldn't start finished"); |
[self.queue addOperation:self.op1]; |
[self.queue addOperation:self.op2]; |
[self.queue addOperation:self.op3]; |
// STAssertFalse([self.op1 isExecuting], @"shouldn't start executing"); -- it may be executing at this point |
STAssertFalse([self.op1 isCancelled], @"shouldn't start cancelled"); |
STAssertFalse([self.op1 isFinished], @"shouldn't start finished"); |
STAssertFalse([self.op2 isExecuting], @"shouldn't start executing"); |
STAssertFalse([self.op2 isCancelled], @"shouldn't start cancelled"); |
STAssertFalse([self.op2 isFinished], @"shouldn't start finished"); |
STAssertFalse([self.op3 isExecuting], @"shouldn't start executing"); |
STAssertFalse([self.op3 isCancelled], @"shouldn't start cancelled"); |
STAssertFalse([self.op3 isFinished], @"shouldn't start finished"); |
[self performSelector:@selector(turnoverRunLoopFirstBeforeOp1Done) withObject:nil afterDelay:0.1]; |
[self performSelector:@selector(turnoverRunLoopFirstAfterOp1Done) withObject:nil afterDelay:0.3]; |
[self performSelector:@selector(turnoverRunLoopFirstAfterOp2Done) withObject:nil afterDelay:0.5]; |
[self performSelector:@selector(turnoverRunLoopFirstAfterOp3Done) withObject:nil afterDelay:0.7]; |
endDate = [NSDate dateWithTimeIntervalSinceNow:0.8]; |
while (self.op3 != nil) { |
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:endDate]; |
} |
} |
- (void)turnoverRunLoopFirstBeforeOp1Done |
{ |
// NSLog(@"turnoverRunLoopFirstBeforeOp1Done"); |
STAssertNotNil(self.op1, @"op1 should be present"); |
STAssertTrue( [self.op1 isExecuting], @"op1 should be executing"); |
STAssertFalse([self.op1 isCancelled], @"op1 shouldn't be cancelled"); |
STAssertFalse([self.op1 isFinished], @"op1 shouldn't be finished"); |
STAssertNotNil(self.op2, @"op2 should be present"); |
STAssertFalse([self.op2 isExecuting], @"op2 shouldn't be executing"); |
STAssertFalse([self.op2 isCancelled], @"op2 shouldn't be cancelled"); |
STAssertFalse([self.op2 isFinished], @"op2 shouldn't be finished"); |
STAssertNotNil(self.op3, @"op3 should be present"); |
STAssertFalse([self.op3 isExecuting], @"op3 shouldn't be executing"); |
STAssertFalse([self.op3 isCancelled], @"op3 shouldn't be cancelled"); |
STAssertFalse([self.op3 isFinished], @"op3 shouldn't be finished"); |
} |
- (void)turnoverRunLoopFirstAfterOp1Done |
{ |
// NSLog(@"turnoverRunLoopFirstAfterOp1Done"); |
STAssertNotNil(self.op1, @"op1 should be present"); |
STAssertFalse([self.op1 isExecuting], @"op1 should be executing"); |
STAssertFalse([self.op1 isCancelled], @"op1 shouldn't be cancelled"); |
STAssertTrue( [self.op1 isFinished], @"op1 should be finished"); |
STAssertNotNil(self.op2, @"op2 should be present"); |
STAssertTrue( [self.op2 isExecuting], @"op2 should be executing"); |
STAssertFalse([self.op2 isCancelled], @"op2 shouldn't be cancelled"); |
STAssertFalse([self.op2 isFinished], @"op2 shouldn't be finished"); |
STAssertNotNil(self.op3, @"op3 should be present"); |
STAssertFalse([self.op3 isExecuting], @"op3 shouldn't be executing"); |
STAssertFalse([self.op3 isCancelled], @"op3 shouldn't be cancelled"); |
STAssertFalse([self.op3 isFinished], @"op3 shouldn't be finished"); |
} |
- (void)turnoverRunLoopFirstAfterOp2Done |
{ |
// NSLog(@"turnoverRunLoopFirstAfterOp2Done"); |
STAssertNotNil(self.op1, @"op1 should be present"); |
STAssertFalse([self.op1 isExecuting], @"op1 should be executing"); |
STAssertFalse([self.op1 isCancelled], @"op1 shouldn't be cancelled"); |
STAssertTrue( [self.op1 isFinished], @"op1 should be finished"); |
STAssertNotNil(self.op2, @"op2 should be present"); |
STAssertFalse([self.op2 isExecuting], @"op2 shouldn't be executing"); |
STAssertFalse([self.op2 isCancelled], @"op2 shouldn't be cancelled"); |
STAssertTrue( [self.op2 isFinished], @"op2 should be finished"); |
STAssertNotNil(self.op3, @"op3 should be present"); |
STAssertTrue( [self.op3 isExecuting], @"op3 should be executing"); |
STAssertFalse([self.op3 isCancelled], @"op3 shouldn't be cancelled"); |
STAssertFalse([self.op3 isFinished], @"op3 shouldn't be finished"); |
} |
- (void)turnoverRunLoopFirstAfterOp3Done |
{ |
// NSLog(@"turnoverRunLoopFirstAfterOp3Done"); |
STAssertNotNil(self.op1, @"op1 should be present"); |
STAssertFalse([self.op1 isExecuting], @"op1 should be executing"); |
STAssertFalse([self.op1 isCancelled], @"op1 shouldn't be cancelled"); |
STAssertTrue( [self.op1 isFinished], @"op1 should be finished"); |
STAssertNotNil(self.op2, @"op2 should be present"); |
STAssertFalse([self.op2 isExecuting], @"op2 shouldn't be executing"); |
STAssertFalse([self.op2 isCancelled], @"op2 shouldn't be cancelled"); |
STAssertTrue( [self.op2 isFinished], @"op2 should be finished"); |
STAssertNotNil(self.op3, @"op3 should be present"); |
STAssertFalse([self.op3 isExecuting], @"op3 shouldn't be executing"); |
STAssertFalse([self.op3 isCancelled], @"op3 shouldn't be cancelled"); |
STAssertTrue( [self.op3 isFinished], @"op3 should be finished"); |
STAssertEqualObjects([self.timerOp1.debugEventLog componentsJoinedByString:@"/"], @">start/-setState.executing/<start/>startOnRunLoopThread/-startOnRunLoopThread.start/<startOnRunLoopThread/>finishWithError/-finishWithError.noError/-setState.finished/<finishWithError", @"sequence error"); |
STAssertEqualObjects([self.timerOp3.debugEventLog componentsJoinedByString:@"/"], @">start/-setState.executing/<start/>startOnRunLoopThread/-startOnRunLoopThread.start/<startOnRunLoopThread/>finishWithError/-finishWithError.noError/-setState.finished/<finishWithError", @"sequence error"); |
self.op1 = nil; |
self.op2 = nil; |
self.op3 = nil; |
} |
#pragma mark * Turnover Width |
// Tests that multiple operations execute concurrent on the queue. |
- (void)testTurnoverWidth |
{ |
NSDate * endDate; |
[self.queue setMaxConcurrentOperationCount:2]; |
self.op1 = [self timerOperationWithDuration:0.2 name:@"op1"]; |
assert(self.op1 != nil); |
STAssertFalse([self.op1 isExecuting], @"shouldn't start executing"); |
STAssertFalse([self.op1 isCancelled], @"shouldn't start cancelled"); |
STAssertFalse([self.op1 isFinished], @"shouldn't start finished"); |
self.op2 = [self timerOperationWithDuration:0.2 name:@"op2"]; |
assert(self.op2 != nil); |
STAssertFalse([self.op2 isExecuting], @"shouldn't start executing"); |
STAssertFalse([self.op2 isCancelled], @"shouldn't start cancelled"); |
STAssertFalse([self.op2 isFinished], @"shouldn't start finished"); |
self.op3 = [self timerOperationWithDuration:0.2 name:@"op3"]; |
assert(self.op3 != nil); |
STAssertFalse([self.op3 isExecuting], @"shouldn't start executing"); |
STAssertFalse([self.op3 isCancelled], @"shouldn't start cancelled"); |
STAssertFalse([self.op3 isFinished], @"shouldn't start finished"); |
[self.queue addOperation:self.op1]; |
[self.queue addOperation:self.op2]; |
[self.queue addOperation:self.op3]; |
// STAssertFalse([self.op1 isExecuting], @"shouldn't start executing"); -- it may be executing at this point |
STAssertFalse([self.op1 isCancelled], @"shouldn't start cancelled"); |
STAssertFalse([self.op1 isFinished], @"shouldn't start finished"); |
// STAssertFalse([self.op2 isExecuting], @"shouldn't start executing"); -- it may be executing at this point |
STAssertFalse([self.op2 isCancelled], @"shouldn't start cancelled"); |
STAssertFalse([self.op2 isFinished], @"shouldn't start finished"); |
STAssertFalse([self.op3 isExecuting], @"shouldn't start executing"); |
STAssertFalse([self.op3 isCancelled], @"shouldn't start cancelled"); |
STAssertFalse([self.op3 isFinished], @"shouldn't start finished"); |
[self performSelector:@selector(turnoverWidthBeforeOp1And2Done) withObject:nil afterDelay:0.1]; |
[self performSelector:@selector(turnoverWidthAfterOp1And2Done) withObject:nil afterDelay:0.3]; |
[self performSelector:@selector(turnoverWidthAfterOp3Done) withObject:nil afterDelay:0.5]; |
endDate = [NSDate dateWithTimeIntervalSinceNow:0.6]; |
while (self.op3 != nil) { |
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:endDate]; |
} |
[self.queue setMaxConcurrentOperationCount:1]; |
} |
- (void)turnoverWidthBeforeOp1And2Done |
{ |
STAssertNotNil(self.op1, @"op1 should be present"); |
STAssertTrue( [self.op1 isExecuting], @"op1 should be executing"); |
STAssertFalse([self.op1 isCancelled], @"op1 shouldn't be cancelled"); |
STAssertFalse([self.op1 isFinished], @"op1 shouldn't be finished"); |
STAssertNotNil(self.op2, @"op2 should be present"); |
STAssertTrue( [self.op2 isExecuting], @"op2 should be executing"); |
STAssertFalse([self.op2 isCancelled], @"op2 shouldn't be cancelled"); |
STAssertFalse([self.op2 isFinished], @"op2 shouldn't be finished"); |
STAssertNotNil(self.op3, @"op3 should be present"); |
STAssertFalse([self.op3 isExecuting], @"op3 shouldn't be executing"); |
STAssertFalse([self.op3 isCancelled], @"op3 shouldn't be cancelled"); |
STAssertFalse([self.op3 isFinished], @"op3 shouldn't be finished"); |
} |
- (void)turnoverWidthAfterOp1And2Done |
{ |
STAssertNotNil(self.op1, @"op1 should be present"); |
STAssertFalse([self.op1 isExecuting], @"op1 shouldn't be executing"); |
STAssertFalse([self.op1 isCancelled], @"op1 shouldn't be cancelled"); |
STAssertTrue( [self.op1 isFinished], @"op1 should be finished"); |
STAssertNotNil(self.op2, @"op2 should be present"); |
STAssertFalse([self.op2 isExecuting], @"op2 shouldn't be executing"); |
STAssertFalse([self.op2 isCancelled], @"op2 shouldn't be cancelled"); |
STAssertTrue( [self.op2 isFinished], @"op2 should be finished"); |
STAssertNotNil(self.op3, @"op3 should be present"); |
STAssertTrue( [self.op3 isExecuting], @"op3 shouldn be executing"); |
STAssertFalse([self.op3 isCancelled], @"op3 shouldn't be cancelled"); |
STAssertFalse([self.op3 isFinished], @"op3 shouldn't be finished"); |
} |
- (void)turnoverWidthAfterOp3Done |
{ |
STAssertNotNil(self.op1, @"op1 should be present"); |
STAssertFalse([self.op1 isExecuting], @"op1 should be executing"); |
STAssertFalse([self.op1 isCancelled], @"op1 shouldn't be cancelled"); |
STAssertTrue( [self.op1 isFinished], @"op1 should be finished"); |
STAssertNotNil(self.op2, @"op2 should be present"); |
STAssertFalse([self.op2 isExecuting], @"op2 shouldn't be executing"); |
STAssertFalse([self.op2 isCancelled], @"op2 shouldn't be cancelled"); |
STAssertTrue( [self.op2 isFinished], @"op2 should be finished"); |
STAssertNotNil(self.op3, @"op3 should be present"); |
STAssertFalse([self.op3 isExecuting], @"op3 shouldn't be executing"); |
STAssertFalse([self.op3 isCancelled], @"op3 shouldn't be cancelled"); |
STAssertTrue( [self.op3 isFinished], @"op3 should be finished"); |
STAssertEqualObjects([self.timerOp1.debugEventLog componentsJoinedByString:@"/"], @">start/-setState.executing/<start/>startOnRunLoopThread/-startOnRunLoopThread.start/<startOnRunLoopThread/>finishWithError/-finishWithError.noError/-setState.finished/<finishWithError", @"sequence error"); |
STAssertEqualObjects([self.timerOp2.debugEventLog componentsJoinedByString:@"/"], @">start/-setState.executing/<start/>startOnRunLoopThread/-startOnRunLoopThread.start/<startOnRunLoopThread/>finishWithError/-finishWithError.noError/-setState.finished/<finishWithError", @"sequence error"); |
STAssertEqualObjects([self.timerOp3.debugEventLog componentsJoinedByString:@"/"], @">start/-setState.executing/<start/>startOnRunLoopThread/-startOnRunLoopThread.start/<startOnRunLoopThread/>finishWithError/-finishWithError.noError/-setState.finished/<finishWithError", @"sequence error"); |
self.op1 = nil; |
self.op2 = nil; |
self.op3 = nil; |
} |
#pragma mark * Turnover Cancel Middle |
// Tests that one operation will start the next operation. |
- (void)testTurnoverCancelMiddle |
{ |
NSDate * endDate; |
self.op1 = [self timerOperationWithDuration:0.2 name:@"op1"]; |
assert(self.op1 != nil); |
STAssertFalse([self.op1 isExecuting], @"shouldn't start executing"); |
STAssertFalse([self.op1 isCancelled], @"shouldn't start cancelled"); |
STAssertFalse([self.op1 isFinished], @"shouldn't start finished"); |
self.op2 = [self timerOperationWithDuration:0.2 name:@"op2"]; |
assert(self.op2 != nil); |
STAssertFalse([self.op2 isExecuting], @"shouldn't start executing"); |
STAssertFalse([self.op2 isCancelled], @"shouldn't start cancelled"); |
STAssertFalse([self.op2 isFinished], @"shouldn't start finished"); |
self.op3 = [self timerOperationWithDuration:0.2 name:@"op3"]; |
assert(self.op3 != nil); |
STAssertFalse([self.op3 isExecuting], @"shouldn't start executing"); |
STAssertFalse([self.op3 isCancelled], @"shouldn't start cancelled"); |
STAssertFalse([self.op3 isFinished], @"shouldn't start finished"); |
[self.queue addOperation:self.op1]; |
[self.queue addOperation:self.op2]; |
[self.queue addOperation:self.op3]; |
// STAssertFalse([self.op1 isExecuting], @"shouldn't start executing"); -- it may be executing at this point |
STAssertFalse([self.op1 isCancelled], @"shouldn't start cancelled"); |
STAssertFalse([self.op1 isFinished], @"shouldn't start finished"); |
STAssertFalse([self.op2 isExecuting], @"shouldn't start executing"); |
STAssertFalse([self.op2 isCancelled], @"shouldn't start cancelled"); |
STAssertFalse([self.op2 isFinished], @"shouldn't start finished"); |
STAssertFalse([self.op3 isExecuting], @"shouldn't start executing"); |
STAssertFalse([self.op3 isCancelled], @"shouldn't start cancelled"); |
STAssertFalse([self.op3 isFinished], @"shouldn't start finished"); |
[self performSelector:@selector(turnoverCancelMiddleBeforeOp1Done) withObject:nil afterDelay:0.1]; |
[self performSelector:@selector(turnoverCancelMiddleAfterOp2Done) withObject:nil afterDelay:0.3]; |
[self performSelector:@selector(turnoverCancelMiddleAfterOp3Done) withObject:nil afterDelay:0.5]; |
endDate = [NSDate dateWithTimeIntervalSinceNow:0.6]; |
while (self.op3 != nil) { |
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:endDate]; |
} |
} |
// +op1 -op2 +op3 |
// 0.0 0.2 0.2 0.2 0.2 0.4 |
// ^ ^ ^ |
- (void)turnoverCancelMiddleBeforeOp1Done |
{ |
// NSLog(@"turnoverCancelMiddleBeforeOp1Done"); |
STAssertNotNil(self.op1, @"op1 should be present"); |
STAssertTrue( [self.op1 isExecuting], @"op1 should be executing"); |
STAssertFalse([self.op1 isCancelled], @"op1 shouldn't be cancelled"); |
STAssertFalse([self.op1 isFinished], @"op1 shouldn't be finished"); |
STAssertNotNil(self.op2, @"op2 should be present"); |
STAssertFalse([self.op2 isExecuting], @"op2 shouldn't be executing"); |
STAssertFalse([self.op2 isCancelled], @"op2 shouldn't be cancelled"); |
STAssertFalse([self.op2 isFinished], @"op2 shouldn't be finished"); |
STAssertNotNil(self.op3, @"op3 should be present"); |
STAssertFalse([self.op3 isExecuting], @"op3 shouldn't be executing"); |
STAssertFalse([self.op3 isCancelled], @"op3 shouldn't be cancelled"); |
STAssertFalse([self.op3 isFinished], @"op3 shouldn't be finished"); |
[self.op2 cancel]; |
} |
- (void)turnoverCancelMiddleAfterOp2Done |
{ |
// NSLog(@"turnoverCancelMiddleAfterOp2Done"); |
STAssertNotNil(self.op1, @"op1 should be present"); |
STAssertFalse([self.op1 isExecuting], @"op1 should be executing"); |
STAssertFalse([self.op1 isCancelled], @"op1 shouldn't be cancelled"); |
STAssertTrue( [self.op1 isFinished], @"op1 should be finished"); |
STAssertNotNil(self.op2, @"op2 should be present"); |
STAssertFalse([self.op2 isExecuting], @"op2 shouldn't be executing"); |
STAssertTrue( [self.op2 isCancelled], @"op2 should be cancelled"); |
STAssertTrue( [self.op2 isFinished], @"op2 should be finished"); |
STAssertNotNil(self.op3, @"op3 should be present"); |
STAssertTrue( [self.op3 isExecuting], @"op3 should be executing"); |
STAssertFalse([self.op3 isCancelled], @"op3 shouldn't be cancelled"); |
STAssertFalse([self.op3 isFinished], @"op3 shouldn't be finished"); |
} |
- (void)turnoverCancelMiddleAfterOp3Done |
{ |
// NSLog(@"turnoverCancelMiddleAfterOp3Done"); |
STAssertNotNil(self.op1, @"op1 should be present"); |
STAssertFalse([self.op1 isExecuting], @"op1 should be executing"); |
STAssertFalse([self.op1 isCancelled], @"op1 shouldn't be cancelled"); |
STAssertTrue( [self.op1 isFinished], @"op1 should be finished"); |
STAssertNotNil(self.op2, @"op2 should be present"); |
STAssertFalse([self.op2 isExecuting], @"op2 shouldn't be executing"); |
STAssertTrue( [self.op2 isCancelled], @"op2 should be cancelled"); |
STAssertTrue( [self.op2 isFinished], @"op2 should be finished"); |
STAssertNotNil(self.op3, @"op3 should be present"); |
STAssertFalse([self.op3 isExecuting], @"op3 shouldn't be executing"); |
STAssertFalse([self.op3 isCancelled], @"op3 shouldn't be cancelled"); |
STAssertTrue( [self.op3 isFinished], @"op3 should be finished"); |
STAssertEqualObjects([self.timerOp1.debugEventLog componentsJoinedByString:@"/"], @">start/-setState.executing/<start/>startOnRunLoopThread/-startOnRunLoopThread.start/<startOnRunLoopThread/>finishWithError/-finishWithError.noError/-setState.finished/<finishWithError", @"sequence error"); |
STAssertEqualObjects([self.timerOp2.debugEventLog componentsJoinedByString:@"/"], @">cancel/-cancel.winner/<cancel/>start/-setState.executing/<start/>startOnRunLoopThread/-startOnRunLoopThread.cancelled/>finishWithError/-finishWithError.error/-setState.finished/<finishWithError/<startOnRunLoopThread", @"sequence error"); |
STAssertEqualObjects([self.timerOp3.debugEventLog componentsJoinedByString:@"/"], @">start/-setState.executing/<start/>startOnRunLoopThread/-startOnRunLoopThread.start/<startOnRunLoopThread/>finishWithError/-finishWithError.noError/-setState.finished/<finishWithError", @"sequence error"); |
self.op1 = nil; |
self.op2 = nil; |
self.op3 = nil; |
} |
#pragma mark * Delayed Cancel |
// Tests the much-delayed cancel case |
- (void)testDelayedCancel |
{ |
NSDate * endDate; |
// 0.0 0.05 0.1 0.15 0.2 |
// start cancel finish cancel all done |
// begins effective |
// but bounces |
self.op1 = [self timerOperationWithDuration:0.1 name:@"op1"]; |
assert(self.op1 != nil); |
STAssertFalse([self.op1 isExecuting], @"shouldn't start executing"); |
STAssertFalse([self.op1 isCancelled], @"shouldn't start cancelled"); |
STAssertFalse([self.op1 isFinished], @"shouldn't start finished"); |
self.timerOp1.debugSecondaryThreadCancelDelay = 0.1; |
[self.queue addOperation:self.op1]; |
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t) (0.05 * NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){ |
assert( ! [NSThread isMainThread] ); |
STAssertNotNil(self.op1, @"op1 shouldn't be already done"); |
STAssertTrue( [self.op1 isExecuting], @"should be executing"); |
STAssertFalse([self.op1 isCancelled], @"shouldn't be cancelled"); |
STAssertFalse([self.op1 isFinished], @"shouldn't be finished"); |
[self.op1 cancel]; |
STAssertTrue([self.op1 isCancelled], @"shouldn't be cancelled"); |
}); |
[self performSelector:@selector(delayedCancelBeforeOp1Cancelled) withObject:nil afterDelay:0.02]; |
[self performSelector:@selector(delayedCancelAfterOp1Cancelled) withObject:nil afterDelay:0.07]; |
[self performSelector:@selector(delayedCancelAfterOp1Done) withObject:nil afterDelay:0.12]; |
[self performSelector:@selector(delayedCancelAfterAllDone) withObject:nil afterDelay:0.20]; |
endDate = [NSDate dateWithTimeIntervalSinceNow:0.5]; |
while (self.op1 != nil) { |
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:endDate]; |
} |
} |
- (void)delayedCancelBeforeOp1Cancelled |
{ |
STAssertNotNil(self.op1, @"op1 shouldn't be already done"); |
STAssertTrue( [self.op1 isExecuting], @"should be executing"); |
STAssertFalse([self.op1 isCancelled], @"shouldn't be cancelled"); |
STAssertFalse([self.op1 isFinished], @"shouldn't be finished"); |
} |
- (void)delayedCancelAfterOp1Cancelled |
{ |
STAssertNotNil(self.op1, @"op1 shouldn't be already done"); |
STAssertTrue( [self.op1 isExecuting], @"should be executing"); |
STAssertTrue( [self.op1 isCancelled], @"should be cancelled"); |
STAssertFalse([self.op1 isFinished], @"shouldn't be finished"); |
} |
- (void)delayedCancelAfterOp1Done |
{ |
STAssertNotNil(self.op1, @"op1 shouldn't be already done"); |
STAssertFalse([self.op1 isExecuting], @"shouldn't be executing"); |
STAssertTrue( [self.op1 isCancelled], @"should be cancelled"); |
STAssertTrue( [self.op1 isFinished], @"should be finished"); |
} |
- (void)delayedCancelAfterAllDone |
{ |
STAssertEqualObjects([self.timerOp1.debugEventLog componentsJoinedByString:@"/"], @">start/-setState.executing/<start/>startOnRunLoopThread/-startOnRunLoopThread.start/<startOnRunLoopThread/>cancel/-cancel.winner/-cancel.delay/>finishWithError/-finishWithError.noError/-setState.finished/<finishWithError/-cancel.schedule/<cancel/>cancelOnRunLoopThread/-cancelOnRunLoopThread.bounce/<cancelOnRunLoopThread", @"sequence error"); |
self.op1 = nil; |
} |
#pragma mark * Stress Test |
enum { |
kTestStressLogEnabled = NO |
}; |
- (void)testStress |
{ |
NSDate * endDate; |
NSUInteger cancelIndex; |
TimerOperation * timerOp; |
NSUInteger opCount; |
[self.queue setMaxConcurrentOperationCount:5]; |
assert(self.operations == nil); |
self.operations = [NSMutableArray array]; |
assert(self.operations != nil); |
opCount = 666; |
endDate = [NSDate dateWithTimeIntervalSinceNow:5.0]; |
while ( [NSDate timeIntervalSinceReferenceDate] < [endDate timeIntervalSinceReferenceDate] ) { |
NSAutoreleasePool * pool; |
pool = [[NSAutoreleasePool alloc] init]; |
assert(pool != nil); |
// in in ten iterations, cancel a random operation |
if ([self.operations count] != 0) { |
if ((arc4random() % 10) == 0) { |
cancelIndex = arc4random() % [self.operations count]; |
assert(cancelIndex < [self.operations count]); |
timerOp = (TimerOperation *) [self.operations objectAtIndex:cancelIndex]; |
assert([timerOp isKindOfClass:[TimerOperation class]]); |
[timerOp cancel]; |
} |
} |
// start operations until we hit our limit |
while ( [self.operations count] < 20 ) { |
timerOp = [self timerOperationWithDuration:((NSTimeInterval) (arc4random() % 100)) / 1000.0 name:[NSString stringWithFormat:@"op%zu", (size_t) opCount]]; |
opCount += 1; |
[timerOp addObserver:self forKeyPath:@"isFinished" options:0 context:&self->_operations]; |
if (kTestStressLogEnabled) { |
NSLog(@" started %@ for %.3f", timerOp.debugName, timerOp.duration); |
} |
[self.operations addObject:timerOp]; |
[self.queue addOperation:timerOp]; |
} |
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.01]]; |
[pool drain]; |
} |
while ([self.operations count] != 0) { |
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.01]]; |
} |
assert([self.operations count] == 0); |
self.operations = nil; |
[self.queue setMaxConcurrentOperationCount:1]; |
} |
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context |
{ |
if (context == &self->_operations) { |
TimerOperation * timerOp; |
timerOp = (TimerOperation *) object; |
assert([timerOp isKindOfClass:[TimerOperation class]]); |
[timerOp removeObserver:self forKeyPath:@"isFinished"]; |
[self performSelectorOnMainThread:@selector(nixOperation:) withObject:timerOp waitUntilDone:NO]; |
} else { |
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; |
} |
} |
- (void)nixOperation:(TimerOperation *)timerOp |
{ |
assert([timerOp isKindOfClass:[TimerOperation class]]); |
if (kTestStressLogEnabled) { |
if ([timerOp isCancelled]) { |
NSLog(@"cancelled %@", timerOp.debugName); |
} else { |
NSLog(@" done %@", timerOp.debugName); |
} |
} |
[self.operations removeObject:timerOp]; |
} |
@end |
Copyright © 2013 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2013-03-05