BoltsTests/TaskTests.m (613 lines of code) (raw):
/*
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
@import XCTest;
#import <Bolts/Bolts.h>
@interface TaskTests : XCTestCase
@end
@implementation TaskTests
- (void)testBasicOnSuccess {
[[[BFTask taskWithResult:@"foo"] continueWithSuccessBlock:^id(BFTask *t) {
XCTAssertEqualObjects(@"foo", t.result);
return nil;
}] waitUntilFinished];
}
- (void)testBasicOnSuccessWithExecutor {
__block BOOL completed = NO;
BFTask *task = [[BFTask taskWithDelay:100] continueWithExecutor:[BFExecutor immediateExecutor]
withSuccessBlock:^id _Nullable(BFTask * _Nonnull _) {
completed = YES;
return nil;
}];
[task waitUntilFinished];
XCTAssertTrue(completed);
XCTAssertTrue(task.completed);
XCTAssertFalse(task.faulted);
XCTAssertFalse(task.cancelled);
XCTAssertNil(task.result);
}
- (void)testBasicOnSuccessWithToken {
BFCancellationTokenSource *cts = [BFCancellationTokenSource cancellationTokenSource];
BFTask *task = [BFTask taskWithDelay:100];
task = [task continueWithSuccessBlock:^id(BFTask *t) {
XCTFail(@"Success block should not be triggered");
return nil;
} cancellationToken:cts.token];
[cts cancel];
[task waitUntilFinished];
XCTAssertTrue(task.cancelled);
}
- (void)testBasicOnSuccessWithExecutorToken {
BFCancellationTokenSource *cts = [BFCancellationTokenSource cancellationTokenSource];
BFTask *task = [BFTask taskWithDelay:100];
task = [task continueWithExecutor:[BFExecutor immediateExecutor]
successBlock:^id(BFTask *t) {
XCTFail(@"Success block should not be triggered");
return nil;
}
cancellationToken:cts.token];
[cts cancel];
[task waitUntilFinished];
XCTAssertTrue(task.cancelled);
}
- (void)testBasicOnSuccessWithCancelledToken {
BFCancellationTokenSource *cts = [BFCancellationTokenSource cancellationTokenSource];
BFTask *task = [BFTask taskWithResult:nil];
[cts cancel];
task = [task continueWithExecutor:[BFExecutor immediateExecutor]
successBlock:^id(BFTask *t) {
XCTFail(@"Success block should not be triggered");
return nil;
}
cancellationToken:cts.token];
XCTAssertTrue(task.isCancelled);
}
- (void)testBasicContinueWithError {
NSError *originalError = [NSError errorWithDomain:@"Bolts" code:22 userInfo:nil];
[[[BFTask taskWithError:originalError] continueWithBlock:^id(BFTask *t) {
XCTAssertNotNil(t.error, @"Task should have failed.");
XCTAssertEqual((NSInteger)22, t.error.code);
return nil;
}] waitUntilFinished];
}
- (void)testBasicContinueWithToken {
BFCancellationTokenSource *cts = [BFCancellationTokenSource cancellationTokenSource];
BFTask *task = [BFTask taskWithDelay:100];
task = [task continueWithExecutor:[BFExecutor immediateExecutor]
block:^id(BFTask *t) {
XCTFail(@"Continuation block should not be triggered");
return nil;
}
cancellationToken:cts.token];
[cts cancel];
[task waitUntilFinished];
XCTAssertTrue(task.isCancelled);
}
- (void)testBasicContinueWithCancelledToken {
BFCancellationTokenSource *cts = [BFCancellationTokenSource cancellationTokenSource];
BFTask *task = [BFTask taskWithResult:nil];
[cts cancel];
task = [task continueWithExecutor:[BFExecutor immediateExecutor]
block:^id(BFTask *t) {
XCTFail(@"Continuation block should not be triggered");
return nil;
}
cancellationToken:cts.token];
XCTAssertTrue(task.isCancelled);
}
- (void)testFinishLaterWithSuccess {
BFTaskCompletionSource *tcs = [BFTaskCompletionSource taskCompletionSource];
BFTask *task = [tcs.task continueWithBlock:^id(BFTask *t) {
XCTAssertEqualObjects(@"bar", t.result);
return nil;
}];
[[BFTask taskWithDelay:0] continueWithBlock:^id(BFTask *t) {
tcs.result = @"bar";
return nil;
}];
[task waitUntilFinished];
}
- (void)testFinishLaterWithError {
BFTaskCompletionSource *tcs = [BFTaskCompletionSource taskCompletionSource];
BFTask *task = [tcs.task continueWithBlock:^id(BFTask *t) {
XCTAssertNotNil(t.error);
XCTAssertEqual((NSInteger)23, t.error.code);
return nil;
}];
[[BFTask taskWithDelay:0] continueWithBlock:^id(BFTask *t) {
tcs.error = [NSError errorWithDomain:@"Bolts" code:23 userInfo:nil];
return nil;
}];
[task waitUntilFinished];
}
- (void)testTransformConstantToConstant {
BFTaskCompletionSource *tcs = [BFTaskCompletionSource taskCompletionSource];
BFTask *task = [[tcs.task continueWithBlock:^id(BFTask *t) {
XCTAssertEqualObjects(@"foo", t.result);
return @"bar";
}] continueWithBlock:^id(BFTask *t) {
XCTAssertEqualObjects(@"bar", t.result);
return nil;
}];
[[BFTask taskWithDelay:0] continueWithBlock:^id(BFTask *t) {
tcs.result = @"foo";
return nil;
}];
[task waitUntilFinished];
}
- (void)testTransformErrorToConstant {
BFTaskCompletionSource *tcs = [BFTaskCompletionSource taskCompletionSource];
BFTask *task = [[tcs.task continueWithBlock:^id(BFTask *t) {
XCTAssertNotNil(t.error);
XCTAssertEqual((NSInteger)23, t.error.code);
return @"bar";
}] continueWithBlock:^id(BFTask *t) {
XCTAssertEqualObjects(@"bar", t.result);
return nil;
}];
[[BFTask taskWithDelay:0] continueWithBlock:^id(BFTask *t) {
tcs.error = [NSError errorWithDomain:@"Bolts" code:23 userInfo:nil];
return nil;
}];
[task waitUntilFinished];
}
- (void)testReturnSuccessfulTaskFromContinuation {
BFTaskCompletionSource *tcs = [BFTaskCompletionSource taskCompletionSource];
BFTask *task = [[tcs.task continueWithBlock:^id(BFTask *t) {
XCTAssertEqualObjects(@"foo", t.result);
return [BFTask taskWithResult:@"bar"];
}] continueWithBlock:^id(BFTask *t) {
XCTAssertEqualObjects(@"bar", t.result);
return nil;
}];
[[BFTask taskWithDelay:0] continueWithBlock:^id(BFTask *t) {
tcs.result = @"foo";
return nil;
}];
[task waitUntilFinished];
}
- (void)testReturnSuccessfulTaskFromContinuationAfterError {
BFTaskCompletionSource *tcs = [BFTaskCompletionSource taskCompletionSource];
BFTask *task = [[tcs.task continueWithBlock:^id(BFTask *t) {
XCTAssertNotNil(t.error);
XCTAssertEqual((NSInteger)23, t.error.code);
return [BFTask taskWithResult:@"bar"];
}] continueWithBlock:^id(BFTask *t) {
XCTAssertEqualObjects(@"bar", t.result);
return nil;
}];
[[BFTask taskWithDelay:0] continueWithBlock:^id(BFTask *t) {
tcs.error = [NSError errorWithDomain:@"Bolts" code:23 userInfo:nil];
return nil;
}];
[task waitUntilFinished];
}
- (void)testReturnErrorTaskFromContinuation {
BFTaskCompletionSource *tcs = [BFTaskCompletionSource taskCompletionSource];
BFTask *task = [[tcs.task continueWithBlock:^id(BFTask *t) {
XCTAssertEqualObjects(@"foo", t.result);
NSError *originalError = [NSError errorWithDomain:@"Bolts" code:24 userInfo:nil];
return [BFTask taskWithError:originalError];
}] continueWithBlock:^id(BFTask *t) {
XCTAssertNotNil(t.error);
XCTAssertEqual((NSInteger)24, t.error.code);
return nil;
}];
[[BFTask taskWithDelay:0] continueWithBlock:^id(BFTask *t) {
tcs.result = @"foo";
return nil;
}];
[task waitUntilFinished];
}
- (void)testReturnErrorTaskFromContinuationAfterError {
BFTaskCompletionSource *tcs = [BFTaskCompletionSource taskCompletionSource];
BFTask *task = [[tcs.task continueWithBlock:^id(BFTask *t) {
XCTAssertNotNil(t.error);
XCTAssertEqual((NSInteger)23, t.error.code);
NSError *originalError = [NSError errorWithDomain:@"Bolts" code:24 userInfo:nil];
return [BFTask taskWithError:originalError];
}] continueWithBlock:^id(BFTask *t) {
XCTAssertNotNil(t.error);
XCTAssertEqual((NSInteger)24, t.error.code);
return nil;
}];
[[BFTask taskWithDelay:0] continueWithBlock:^id(BFTask *t) {
tcs.error = [NSError errorWithDomain:@"Bolts" code:23 userInfo:nil];
return nil;
}];
[task waitUntilFinished];
}
- (void)testPassOnError {
NSError *originalError = [NSError errorWithDomain:@"Bolts" code:30 userInfo:nil];
[[[[[[[[BFTask taskWithError:originalError] continueWithSuccessBlock:^id(BFTask *t) {
XCTFail(@"This callback should be skipped.");
return nil;
}] continueWithSuccessBlock:^id(BFTask *t) {
XCTFail(@"This callback should be skipped.");
return nil;
}] continueWithBlock:^id(BFTask *t) {
XCTAssertNotNil(t.error);
XCTAssertEqual((NSInteger)30, t.error.code);
NSError *newError = [NSError errorWithDomain:@"Bolts" code:31 userInfo:nil];
return [BFTask taskWithError:newError];
}] continueWithSuccessBlock:^id(BFTask *t) {
XCTFail(@"This callback should be skipped.");
return nil;
}] continueWithBlock:^id(BFTask *t) {
XCTAssertNotNil(t.error);
XCTAssertEqual((NSInteger)31, t.error.code);
return [BFTask taskWithResult:@"okay"];
}] continueWithSuccessBlock:^id(BFTask *t) {
XCTAssertEqualObjects(@"okay", t.result);
return nil;
}] waitUntilFinished];
}
- (void)testCancellation {
BFTaskCompletionSource *tcs = [BFTaskCompletionSource taskCompletionSource];
BFTask *task = [[BFTask taskWithDelay:100] continueWithBlock:^id(BFTask *t) {
return tcs.task;
}];
[tcs cancel];
[task waitUntilFinished];
XCTAssertTrue(task.isCancelled);
}
- (void)testTaskForCompletionOfAllTasksSuccess {
NSMutableArray *tasks = [NSMutableArray array];
const int kTaskCount = 20;
for (int i = 0; i < kTaskCount; ++i) {
double sleepTimeInMs = rand() % 100;
[tasks addObject:[[BFTask taskWithDelay:(int)sleepTimeInMs] continueWithBlock:^id(BFTask *t) {
return @(i);
}]];
}
[[[BFTask taskForCompletionOfAllTasks:tasks] continueWithBlock:^id(BFTask *t) {
XCTAssertNil(t.error);
XCTAssertFalse(t.isCancelled);
for (int i = 0; i < kTaskCount; ++i) {
XCTAssertEqual(i, [((BFTask *)[tasks objectAtIndex:i]).result intValue]);
}
return nil;
}] waitUntilFinished];
}
- (void)testTaskForCompletionOfAllTasksOneError {
NSMutableArray *tasks = [NSMutableArray array];
const int kTaskCount = 20;
for (int i = 0; i < kTaskCount; ++i) {
double sleepTimeInMs = rand() % 100;
[tasks addObject:[[BFTask taskWithDelay:(int)sleepTimeInMs] continueWithBlock:^id(BFTask *t) {
if (i == 10) {
return [BFTask taskWithError:[NSError errorWithDomain:@"BoltsTests"
code:35
userInfo:nil]];
}
return @(i);
}]];
}
[[[BFTask taskForCompletionOfAllTasks:tasks] continueWithBlock:^id(BFTask *t) {
XCTAssertNotNil(t.error);
XCTAssertFalse(t.isCancelled);
XCTAssertEqualObjects(@"BoltsTests", t.error.domain);
XCTAssertEqual(35, (int)t.error.code);
for (int i = 0; i < kTaskCount; ++i) {
if (i == 10) {
XCTAssertNotNil(((BFTask *)[tasks objectAtIndex:i]).error);
} else {
XCTAssertEqual(i, [((BFTask *)[tasks objectAtIndex:i]).result intValue]);
}
}
return nil;
}] waitUntilFinished];
}
- (void)testTaskForCompletionOfAllTasksTwoErrors {
NSMutableArray *tasks = [NSMutableArray array];
const int kTaskCount = 20;
for (int i = 0; i < kTaskCount; ++i) {
double sleepTimeInMs = rand() % 100;
[tasks addObject:[[BFTask taskWithDelay:(int)sleepTimeInMs] continueWithBlock:^id(BFTask *t) {
if (i == 10 || i == 11) {
return [BFTask taskWithError:[NSError errorWithDomain:@"BoltsTests"
code:35
userInfo:nil]];
}
return @(i);
}]];
}
[[[BFTask taskForCompletionOfAllTasks:tasks] continueWithBlock:^id(BFTask *t) {
XCTAssertNotNil(t.error);
XCTAssertFalse(t.isCancelled);
XCTAssertEqualObjects(@"bolts", t.error.domain);
XCTAssertEqual(kBFMultipleErrorsError, t.error.code);
NSArray *errors = [t.error.userInfo objectForKey:BFTaskMultipleErrorsUserInfoKey];
XCTAssertEqualObjects(@"BoltsTests", [[errors objectAtIndex:0] domain]);
XCTAssertEqual(35, (int)[[errors objectAtIndex:0] code]);
XCTAssertEqualObjects(@"BoltsTests", [[errors objectAtIndex:1] domain]);
XCTAssertEqual(35, (int)[[errors objectAtIndex:1] code]);
for (int i = 0; i < kTaskCount; ++i) {
if (i == 10 || i == 11) {
XCTAssertNotNil(((BFTask *)[tasks objectAtIndex:i]).error);
} else {
XCTAssertEqual(i, [((BFTask *)[tasks objectAtIndex:i]).result intValue]);
}
}
return nil;
}] waitUntilFinished];
}
- (void)testTaskForCompletionOfAllTasksCancelled {
NSMutableArray *tasks = [NSMutableArray array];
const int kTaskCount = 20;
for (int i = 0; i < kTaskCount; ++i) {
double sleepTimeInMs = rand() % 100;
[tasks addObject:[[BFTask taskWithDelay:(int)sleepTimeInMs] continueWithBlock:^id(BFTask *t) {
if (i == 10) {
return [BFTask cancelledTask];
}
return @(i);
}]];
}
[[[BFTask taskForCompletionOfAllTasks:tasks] continueWithBlock:^id(BFTask *t) {
XCTAssertNil(t.error);
XCTAssertTrue(t.isCancelled);
for (int i = 0; i < kTaskCount; ++i) {
if (i == 10) {
XCTAssertTrue(((BFTask *)[tasks objectAtIndex:i]).isCancelled);
} else {
XCTAssertEqual(i, [((BFTask *)[tasks objectAtIndex:i]).result intValue]);
}
}
return nil;
}] waitUntilFinished];
}
- (void)testTaskForCompletionOfAllTasksNoTasksImmediateCompletion {
NSMutableArray *tasks = [NSMutableArray array];
BFTask *task = [BFTask taskForCompletionOfAllTasks:tasks];
XCTAssertTrue(task.completed);
XCTAssertFalse(task.cancelled);
XCTAssertFalse(task.faulted);
}
- (void)testTaskForCompletionOfAllTasksWithResultsSuccess {
NSMutableArray *tasks = [NSMutableArray array];
const int kTaskCount = 20;
for (int i = 0; i < kTaskCount; ++i) {
double sleepTimeInMs = i * 10;
int result = i + 1;
[tasks addObject:[[BFTask taskWithDelay:(int)sleepTimeInMs] continueWithBlock:^id(BFTask *__unused t) {
return @(result);
}]];
}
[[[BFTask taskForCompletionOfAllTasksWithResults:tasks] continueWithBlock:^id(BFTask *t) {
XCTAssertFalse(t.cancelled);
XCTAssertFalse(t.faulted);
NSArray *results = t.result;
for (int i = 0; i < kTaskCount; ++i) {
NSNumber *individualResult = [results objectAtIndex:i];
XCTAssertEqual([individualResult intValue], [((BFTask *)[tasks objectAtIndex:i]).result intValue]);
}
return nil;
}] waitUntilFinished];
}
- (void)testTaskForCompletionOfAllTasksErrorCancelledSuccess {
BFTask *errorTask = [BFTask taskWithError:[NSError new]];
BFTask *cancelledTask = [BFTask cancelledTask];
BFTask *successfulTask = [BFTask taskWithResult:[NSNumber numberWithInt:2]];
BFTask *allTasks = [BFTask taskForCompletionOfAllTasks:@[ successfulTask, cancelledTask, errorTask ]];
XCTAssertTrue(allTasks.faulted, @"Task should be faulted");
}
- (void)testTaskForCompletionOfAllTasksExceptionErrorCancelledSuccess {
BFTask *errorTask = [BFTask taskWithError:[NSError new]];
BFTask *cancelledTask = [BFTask cancelledTask];
BFTask *successfulTask = [BFTask taskWithResult:[NSNumber numberWithInt:2]];
BFTask *allTasks = [BFTask taskForCompletionOfAllTasks:@[ successfulTask, cancelledTask, errorTask ]];
XCTAssertTrue(allTasks.faulted, @"Task should be faulted");
XCTAssertNotNil(allTasks.error, @"Task should have error");
}
- (void)testTaskForCompletionOfAllTasksErrorCancelled {
BFTask *errorTask = [BFTask taskWithError:[NSError new]];
BFTask *cancelledTask = [BFTask cancelledTask];
BFTask *allTasks = [BFTask taskForCompletionOfAllTasks:@[ cancelledTask, errorTask ]];
XCTAssertTrue(allTasks.faulted, @"Task should be faulted");
}
- (void)testTaskForCompletionOfAllTasksSuccessCancelled {
BFTask *cancelledTask = [BFTask cancelledTask];
BFTask *successfulTask = [BFTask taskWithResult:[NSNumber numberWithInt:2]];
BFTask *allTasks = [BFTask taskForCompletionOfAllTasks:@[ successfulTask, cancelledTask ]];
XCTAssertTrue(allTasks.cancelled, @"Task should be cancelled");
}
- (void)testTaskForCompletionOfAllTasksSuccessError {
BFTask *errorTask = [BFTask taskWithError:[NSError new]];
BFTask *successfulTask = [BFTask taskWithResult:[NSNumber numberWithInt:2]];
BFTask *allTasks = [BFTask taskForCompletionOfAllTasks:@[ successfulTask, errorTask ]];
XCTAssertTrue(allTasks.faulted, @"Task should be faulted");
}
- (void)testTaskForCompletionOfAllTasksWithResultsNoTasksImmediateCompletion {
NSMutableArray *tasks = [NSMutableArray array];
BFTask *task = [BFTask taskForCompletionOfAllTasksWithResults:tasks];
XCTAssertTrue(task.completed);
XCTAssertFalse(task.cancelled);
XCTAssertFalse(task.faulted);
XCTAssertTrue(task.result != nil);
}
- (void)testTasksForTaskForCompletionOfAnyTasksWithSuccess {
BFTask *task = [BFTask taskForCompletionOfAnyTask:@[[BFTask taskWithDelay:20], [BFTask taskWithResult:@"success"]]];
[task waitUntilFinished];
XCTAssertEqualObjects(@"success", task.result);
}
- (void)testTasksForTaskForCompletionOfAnyTasksWithRacing {
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
BFExecutor *executor = [BFExecutor executorWithDispatchQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)];
BFTask *first = [BFTask taskFromExecutor:executor withBlock:^id _Nullable {
return @"first";
}];
BFTask *second = [BFTask taskFromExecutor:executor withBlock:^id _Nullable {
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
return @"second";
}];
BFTask *task = [BFTask taskForCompletionOfAnyTask:@[first, second]];
[task waitUntilFinished];
dispatch_semaphore_signal(semaphore);
XCTAssertEqualObjects(@"first", task.result);
}
- (void)testTasksForTaskForCompletionOfAnyTasksWithErrorAndSuccess {
NSError *error = [NSError errorWithDomain:@"BoltsTests"
code:35
userInfo:nil];
BFTask *task = [BFTask taskForCompletionOfAnyTask:@[[BFTask taskWithError:error], [BFTask taskWithResult:@"success"]]];
[task waitUntilFinished];
XCTAssertEqualObjects(@"success", task.result);
XCTAssertNil(task.error);
}
- (void)testTasksForTaskForCompletionOfAnyTasksWithError {
NSError *error = [NSError errorWithDomain:@"BoltsTests"
code:35
userInfo:nil];
BFTask *task = [BFTask taskForCompletionOfAnyTask:@[[BFTask taskWithError:error]]];
[task waitUntilFinished];
XCTAssertEqualObjects(error, task.error);
XCTAssertNotNil(task.error);
}
- (void)testTasksForTaskForCompletionOfAnyTasksWithNilArray {
BFTask *task = [BFTask taskForCompletionOfAnyTask:nil];
[task waitUntilFinished];
XCTAssertNil(task.result);
XCTAssertNil(task.error);
}
- (void)testTasksForTaskForCompletionOfAnyTasksAllErrors {
NSError *error = [NSError errorWithDomain:@"BoltsTests"
code:35
userInfo:nil];
BFTask *task = [BFTask taskForCompletionOfAnyTask:@[[BFTask taskWithError:error], [BFTask taskWithError:error]]];
[task waitUntilFinished];
XCTAssertNil(task.result);
XCTAssertNotNil(task.error);
XCTAssertNotNil(task.error.userInfo);
XCTAssertEqualObjects(@"bolts", task.error.domain);
XCTAssertTrue([task.error.userInfo[@"errors"] isKindOfClass:[NSArray class]]);
XCTAssertEqual(2, [task.error.userInfo[@"errors"] count]);
}
- (void)testWaitUntilFinished {
BFTask *task = [[BFTask taskWithDelay:50] continueWithBlock:^id(BFTask *t) {
return @"foo";
}];
[task waitUntilFinished];
XCTAssertEqualObjects(@"foo", task.result);
}
- (void)testDelayWithToken {
BFCancellationTokenSource *cts = [BFCancellationTokenSource cancellationTokenSource];
BFTask *task = [BFTask taskWithDelay:100 cancellationToken:cts.token];
[cts cancel];
[task waitUntilFinished];
XCTAssertTrue(task.cancelled, @"Task should be cancelled immediately");
}
- (void)testDelayWithCancelledToken {
BFCancellationTokenSource *cts = [BFCancellationTokenSource cancellationTokenSource];
[cts cancel];
BFTask *task = [BFTask taskWithDelay:100 cancellationToken:cts.token];
XCTAssertTrue(task.cancelled, @"Task should be cancelled immediately");
}
- (void)testTaskFromExecutor {
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0L);
BFExecutor *queueExecutor = [BFExecutor executorWithDispatchQueue:queue];
BFTask *task = [BFTask taskFromExecutor:queueExecutor withBlock:^id() {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
XCTAssertEqual(queue, dispatch_get_current_queue());
#pragma clang diagnostic pop
return @"foo";
}];
[task waitUntilFinished];
XCTAssertEqual(@"foo", task.result);
}
- (void)testDescription {
BFTask *task = [BFTask taskWithResult:nil];
NSString *expected = [NSString stringWithFormat:@"<BFTask: %p; completed = YES; cancelled = NO; faulted = NO; result = (null)>", task];
NSString *description = task.description;
XCTAssertTrue([expected isEqualToString:description]);
}
- (void)testReturnTaskFromContinuationWithCancellation {
BFCancellationTokenSource *cts = [BFCancellationTokenSource cancellationTokenSource];
XCTestExpectation *expectation = [self expectationWithDescription:@"task"];
[[[BFTask taskWithDelay:1] continueWithBlock:^id(BFTask *t) {
[cts cancel];
return [BFTask taskWithDelay:10];
} cancellationToken:cts.token] continueWithBlock:^id(BFTask *t) {
XCTAssertTrue(t.cancelled);
[expectation fulfill];
return nil;
}];
[self waitForExpectationsWithTimeout:10.0 handler:nil];
}
- (void)testSetResult {
BFTaskCompletionSource *taskCompletionSource = [BFTaskCompletionSource taskCompletionSource];
taskCompletionSource.result = @"a";
XCTAssertThrowsSpecificNamed([taskCompletionSource setResult:@"b"], NSException, NSInternalInconsistencyException);
XCTAssertTrue(taskCompletionSource.task.completed);
XCTAssertEqualObjects(taskCompletionSource.task.result, @"a");
}
- (void)testTrySetResult {
BFTaskCompletionSource *taskCompletionSource = [BFTaskCompletionSource taskCompletionSource];
[taskCompletionSource trySetResult:@"a"];
[taskCompletionSource trySetResult:@"b"];
XCTAssertTrue(taskCompletionSource.task.completed);
XCTAssertEqualObjects(taskCompletionSource.task.result, @"a");
}
- (void)testSetError {
BFTaskCompletionSource *taskCompletionSource = [BFTaskCompletionSource taskCompletionSource];
NSError *error = [NSError errorWithDomain:@"TestDomain" code:100500 userInfo:nil];
taskCompletionSource.error = error;
XCTAssertThrowsSpecificNamed([taskCompletionSource setError:error], NSException, NSInternalInconsistencyException);
XCTAssertTrue(taskCompletionSource.task.completed);
XCTAssertTrue(taskCompletionSource.task.faulted);
XCTAssertEqualObjects(taskCompletionSource.task.error, error);
}
- (void)testTrySetError {
BFTaskCompletionSource *taskCompletionSource = [BFTaskCompletionSource taskCompletionSource];
NSError *error = [NSError errorWithDomain:@"TestDomain" code:100500 userInfo:nil];
[taskCompletionSource trySetError:error];
[taskCompletionSource trySetError:error];
XCTAssertTrue(taskCompletionSource.task.completed);
XCTAssertTrue(taskCompletionSource.task.faulted);
XCTAssertEqualObjects(taskCompletionSource.task.error, error);
}
- (void)testSetCancelled {
BFTaskCompletionSource *taskCompletionSource = [BFTaskCompletionSource taskCompletionSource];
[taskCompletionSource cancel];
XCTAssertThrowsSpecificNamed([taskCompletionSource cancel], NSException, NSInternalInconsistencyException);
XCTAssertTrue(taskCompletionSource.task.completed);
XCTAssertTrue(taskCompletionSource.task.cancelled);
}
- (void)testTrySetCancelled {
BFTaskCompletionSource *taskCompletionSource = [BFTaskCompletionSource taskCompletionSource];
[taskCompletionSource trySetCancelled];
[taskCompletionSource trySetCancelled];
XCTAssertTrue(taskCompletionSource.task.completed);
XCTAssertTrue(taskCompletionSource.task.cancelled);
}
- (void)testMultipleWaitUntilFinished {
BFTask *task = [[BFTask taskWithDelay:50] continueWithBlock:^id(BFTask *t) {
return @"foo";
}];
[task waitUntilFinished];
XCTestExpectation *expectation = [self expectationWithDescription:NSStringFromSelector(_cmd)];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[task waitUntilFinished];
[expectation fulfill];
});
[self waitForExpectationsWithTimeout:10.0 handler:nil];
}
- (void)testMultipleThreadsWaitUntilFinished {
BFTask *task = [[BFTask taskWithDelay:500] continueWithBlock:^id(BFTask *t) {
return @"foo";
}];
dispatch_queue_t queue = dispatch_queue_create("com.bolts.tests.wait", DISPATCH_QUEUE_CONCURRENT);
dispatch_group_t group = dispatch_group_create();
XCTestExpectation *expectation = [self expectationWithDescription:NSStringFromSelector(_cmd)];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_group_async(group, queue, ^{
[task waitUntilFinished];
});
dispatch_group_async(group, queue, ^{
[task waitUntilFinished];
});
[task waitUntilFinished];
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
[expectation fulfill];
});
[self waitForExpectationsWithTimeout:10.0 handler:nil];
}
@end