AliyunOSSiOSTests/OSSTaskTests.m (708 lines of code) (raw):

// // OSSTaskTests.m // AliyunOSSiOSTests // // Created by 怀叙 on 2017/11/15. // Copyright © 2017年 zhouzhuo. All rights reserved. // #import <XCTest/XCTest.h> #import <AliyunOSSiOS/AliyunOSSiOS.h> @interface OSSTaskTests : XCTestCase @end @implementation OSSTaskTests - (void)testBasicOnSuccess { [[[OSSTask taskWithResult:@"foo"] continueWithSuccessBlock:^id(OSSTask *t) { XCTAssertEqualObjects(@"foo", t.result); return nil; }] waitUntilFinished]; } - (void)testBasicOnSuccessWithExecutor { __block BOOL completed = NO; OSSTask *task = [[OSSTask taskWithDelay:100] continueWithExecutor:[OSSExecutor immediateExecutor] withSuccessBlock:^id _Nullable(OSSTask * _Nonnull _) { completed = YES; return nil; }]; [task waitUntilFinished]; XCTAssertTrue(completed); XCTAssertTrue(task.completed); XCTAssertFalse(task.faulted); XCTAssertFalse(task.cancelled); XCTAssertNil(task.result); } - (void)testBasicOnSuccessWithToken { OSSCancellationTokenSource *cts = [OSSCancellationTokenSource cancellationTokenSource]; OSSTask *task = [OSSTask taskWithDelay:100]; task = [task continueWithSuccessBlock:^id(OSSTask *t) { XCTFail(@"Success block should not be triggered"); return nil; } cancellationToken:cts.token]; [cts cancel]; [task waitUntilFinished]; XCTAssertTrue(task.cancelled); } - (void)testBasicOnSuccessWithExecutorToken { OSSCancellationTokenSource *cts = [OSSCancellationTokenSource cancellationTokenSource]; OSSTask *task = [OSSTask taskWithDelay:100]; task = [task continueWithExecutor:[OSSExecutor immediateExecutor] successBlock:^id(OSSTask *t) { XCTFail(@"Success block should not be triggered"); return nil; } cancellationToken:cts.token]; [cts cancel]; [task waitUntilFinished]; XCTAssertTrue(task.cancelled); } - (void)testBasicOnSuccessWithCancelledToken { OSSCancellationTokenSource *cts = [OSSCancellationTokenSource cancellationTokenSource]; OSSTask *task = [OSSTask taskWithResult:nil]; [cts cancel]; task = [task continueWithExecutor:[OSSExecutor immediateExecutor] successBlock:^id(OSSTask *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]; [[[OSSTask taskWithError:originalError] continueWithBlock:^id(OSSTask *t) { XCTAssertNotNil(t.error, @"Task should have failed."); XCTAssertEqual((NSInteger)22, t.error.code); return nil; }] waitUntilFinished]; } - (void)testBasicContinueWithToken { OSSCancellationTokenSource *cts = [OSSCancellationTokenSource cancellationTokenSource]; OSSTask *task = [OSSTask taskWithDelay:100]; task = [task continueWithExecutor:[OSSExecutor immediateExecutor] block:^id(OSSTask *t) { XCTFail(@"Continuation block should not be triggered"); return nil; } cancellationToken:cts.token]; [cts cancel]; [task waitUntilFinished]; XCTAssertTrue(task.isCancelled); } - (void)testBasicContinueWithCancelledToken { OSSCancellationTokenSource *cts = [OSSCancellationTokenSource cancellationTokenSource]; OSSTask *task = [OSSTask taskWithResult:nil]; [cts cancel]; task = [task continueWithExecutor:[OSSExecutor immediateExecutor] block:^id(OSSTask *t) { XCTFail(@"Continuation block should not be triggered"); return nil; } cancellationToken:cts.token]; XCTAssertTrue(task.isCancelled); } - (void)testFinishLaterWithSuccess { OSSTaskCompletionSource *tcs = [OSSTaskCompletionSource taskCompletionSource]; OSSTask *task = [tcs.task continueWithBlock:^id(OSSTask *t) { XCTAssertEqualObjects(@"bar", t.result); return nil; }]; [[OSSTask taskWithDelay:0] continueWithBlock:^id(OSSTask *t) { tcs.result = @"bar"; return nil; }]; [task waitUntilFinished]; } - (void)testFinishLaterWithError { OSSTaskCompletionSource *tcs = [OSSTaskCompletionSource taskCompletionSource]; OSSTask *task = [tcs.task continueWithBlock:^id(OSSTask *t) { XCTAssertNotNil(t.error); XCTAssertEqual((NSInteger)23, t.error.code); return nil; }]; [[OSSTask taskWithDelay:0] continueWithBlock:^id(OSSTask *t) { tcs.error = [NSError errorWithDomain:@"Bolts" code:23 userInfo:nil]; return nil; }]; [task waitUntilFinished]; } - (void)testTransformConstantToConstant { OSSTaskCompletionSource *tcs = [OSSTaskCompletionSource taskCompletionSource]; OSSTask *task = [[tcs.task continueWithBlock:^id(OSSTask *t) { XCTAssertEqualObjects(@"foo", t.result); return @"bar"; }] continueWithBlock:^id(OSSTask *t) { XCTAssertEqualObjects(@"bar", t.result); return nil; }]; [[OSSTask taskWithDelay:0] continueWithBlock:^id(OSSTask *t) { tcs.result = @"foo"; return nil; }]; [task waitUntilFinished]; } - (void)testTransformErrorToConstant { OSSTaskCompletionSource *tcs = [OSSTaskCompletionSource taskCompletionSource]; OSSTask *task = [[tcs.task continueWithBlock:^id(OSSTask *t) { XCTAssertNotNil(t.error); XCTAssertEqual((NSInteger)23, t.error.code); return @"bar"; }] continueWithBlock:^id(OSSTask *t) { XCTAssertEqualObjects(@"bar", t.result); return nil; }]; [[OSSTask taskWithDelay:0] continueWithBlock:^id(OSSTask *t) { tcs.error = [NSError errorWithDomain:@"Bolts" code:23 userInfo:nil]; return nil; }]; [task waitUntilFinished]; } - (void)testReturnSuccessfulTaskFromContinuation { OSSTaskCompletionSource *tcs = [OSSTaskCompletionSource taskCompletionSource]; OSSTask *task = [[tcs.task continueWithBlock:^id(OSSTask *t) { XCTAssertEqualObjects(@"foo", t.result); return [OSSTask taskWithResult:@"bar"]; }] continueWithBlock:^id(OSSTask *t) { XCTAssertEqualObjects(@"bar", t.result); return nil; }]; [[OSSTask taskWithDelay:0] continueWithBlock:^id(OSSTask *t) { tcs.result = @"foo"; return nil; }]; [task waitUntilFinished]; } - (void)testReturnSuccessfulTaskFromContinuationAfterError { OSSTaskCompletionSource *tcs = [OSSTaskCompletionSource taskCompletionSource]; OSSTask *task = [[tcs.task continueWithBlock:^id(OSSTask *t) { XCTAssertNotNil(t.error); XCTAssertEqual((NSInteger)23, t.error.code); return [OSSTask taskWithResult:@"bar"]; }] continueWithBlock:^id(OSSTask *t) { XCTAssertEqualObjects(@"bar", t.result); return nil; }]; [[OSSTask taskWithDelay:0] continueWithBlock:^id(OSSTask *t) { tcs.error = [NSError errorWithDomain:@"Bolts" code:23 userInfo:nil]; return nil; }]; [task waitUntilFinished]; } - (void)testReturnErrorTaskFromContinuation { OSSTaskCompletionSource *tcs = [OSSTaskCompletionSource taskCompletionSource]; OSSTask *task = [[tcs.task continueWithBlock:^id(OSSTask *t) { XCTAssertEqualObjects(@"foo", t.result); NSError *originalError = [NSError errorWithDomain:@"Bolts" code:24 userInfo:nil]; return [OSSTask taskWithError:originalError]; }] continueWithBlock:^id(OSSTask *t) { XCTAssertNotNil(t.error); XCTAssertEqual((NSInteger)24, t.error.code); return nil; }]; [[OSSTask taskWithDelay:0] continueWithBlock:^id(OSSTask *t) { tcs.result = @"foo"; return nil; }]; [task waitUntilFinished]; } - (void)testReturnErrorTaskFromContinuationAfterError { OSSTaskCompletionSource *tcs = [OSSTaskCompletionSource taskCompletionSource]; OSSTask *task = [[tcs.task continueWithBlock:^id(OSSTask *t) { XCTAssertNotNil(t.error); XCTAssertEqual((NSInteger)23, t.error.code); NSError *originalError = [NSError errorWithDomain:@"Bolts" code:24 userInfo:nil]; return [OSSTask taskWithError:originalError]; }] continueWithBlock:^id(OSSTask *t) { XCTAssertNotNil(t.error); XCTAssertEqual((NSInteger)24, t.error.code); return nil; }]; [[OSSTask taskWithDelay:0] continueWithBlock:^id(OSSTask *t) { tcs.error = [NSError errorWithDomain:@"Bolts" code:23 userInfo:nil]; return nil; }]; [task waitUntilFinished]; } - (void)testReturnErrorTaskFromContinuationWithException { OSSTaskCompletionSource *tcs = [OSSTaskCompletionSource taskCompletionSource]; OSSTask *task = [[tcs.task continueWithBlock:^id(OSSTask *t) { XCTAssertEqualObjects(@"foo", t.result); NSArray *arr = @[]; [arr objectAtIndex:1]; NSError *originalError = [NSError errorWithDomain:@"Bolts" code:24 userInfo:nil]; return [OSSTask taskWithError:originalError]; }] continueWithBlock:^id(OSSTask *t) { XCTAssertNotNil(t.error); XCTAssertEqual(OSSClientErrorCodeExcpetionCatched, t.error.code); return nil; }]; [[OSSTask taskWithDelay:0] continueWithBlock:^id(OSSTask *t) { tcs.result = @"foo"; return nil; }]; [task waitUntilFinished]; } - (void)testPassOnError { NSError *originalError = [NSError errorWithDomain:@"Bolts" code:30 userInfo:nil]; [[[[[[[[OSSTask taskWithError:originalError] continueWithSuccessBlock:^id(OSSTask *t) { XCTFail(@"This callback should be skipped."); return nil; }] continueWithSuccessBlock:^id(OSSTask *t) { XCTFail(@"This callback should be skipped."); return nil; }] continueWithBlock:^id(OSSTask *t) { XCTAssertNotNil(t.error); XCTAssertEqual((NSInteger)30, t.error.code); NSError *newError = [NSError errorWithDomain:@"Bolts" code:31 userInfo:nil]; return [OSSTask taskWithError:newError]; }] continueWithSuccessBlock:^id(OSSTask *t) { XCTFail(@"This callback should be skipped."); return nil; }] continueWithBlock:^id(OSSTask *t) { XCTAssertNotNil(t.error); XCTAssertEqual((NSInteger)31, t.error.code); return [OSSTask taskWithResult:@"okay"]; }] continueWithSuccessBlock:^id(OSSTask *t) { XCTAssertEqualObjects(@"okay", t.result); return nil; }] waitUntilFinished]; } - (void)testCancellation { OSSTaskCompletionSource *tcs = [OSSTaskCompletionSource taskCompletionSource]; OSSTask *task = [[OSSTask taskWithDelay:100] continueWithBlock:^id(OSSTask *t) { return tcs.task; }]; [tcs cancel]; [task waitUntilFinished]; XCTAssertTrue(task.isCancelled); } - (void)testCompleteWithSuccess { OSSResult *putResult = [OSSPutObjectResult new]; OSSTaskCompletionSource *tcs = [OSSTaskCompletionSource taskCompletionSource]; OSSTask *task = [tcs.task completed:^(BOOL isSuccess, NSError * _Nullable error, OSSResult * _Nullable result) { XCTAssertTrue(isSuccess); XCTAssertNotNil(result); XCTAssertEqual(result, putResult); }]; [[OSSTask taskWithDelay:0] continueWithBlock:^id(OSSTask *t) { tcs.result = putResult; return nil; }]; [task waitUntilFinished]; } - (void)testCompleteWithError { OSSTaskCompletionSource *tcs = [OSSTaskCompletionSource taskCompletionSource]; OSSTask *task = [tcs.task completed:^(BOOL isSuccess, NSError * _Nullable error, OSSResult * _Nullable result) { XCTAssertFalse(isSuccess); XCTAssertNotNil(error); XCTAssertEqual(error.domain, @"Bolts"); XCTAssertEqual(error.code, 33); }]; [[OSSTask taskWithDelay:0] continueWithBlock:^id(OSSTask *t) { tcs.error = [NSError errorWithDomain:@"Bolts" code:33 userInfo:nil]; return nil; }]; [task waitUntilFinished]; } - (void)testCompleteWithException { OSSTaskCompletionSource *tcs = [OSSTaskCompletionSource taskCompletionSource]; OSSTask *task = [tcs.task completed:^(BOOL isSuccess, NSError * _Nullable error, OSSResult * _Nullable result) { XCTAssertFalse(isSuccess); XCTAssertNotNil(error); XCTAssertEqual(error.domain, OSSClientErrorDomain); XCTAssertEqual(error.code, OSSClientErrorCodeExcpetionCatched); }]; [[OSSTask taskWithDelay:0] continueWithBlock:^id(OSSTask *t) { tcs.exception = [NSException exceptionWithName:NSInvalidArgumentException reason:@"test" userInfo:nil]; return nil; }]; [task waitUntilFinished]; } - (void)testCompleteWithCancel { OSSTaskCompletionSource *tcs = [OSSTaskCompletionSource taskCompletionSource]; OSSTask *task = [tcs.task completed:^(BOOL isSuccess, NSError * _Nullable error, OSSResult * _Nullable result) { XCTAssertFalse(isSuccess); XCTAssertNotNil(error); XCTAssertEqual(error.domain, OSSClientErrorDomain); XCTAssertEqual(error.code, OSSClientErrorCodeTaskCancelled); }]; [[OSSTask taskWithDelay:0] continueWithBlock:^id(OSSTask *t) { [tcs cancel]; return nil; }]; [task waitUntilFinished]; } - (void)testTaskForCompletionOfAllTasksSuccess { NSMutableArray *tasks = [NSMutableArray array]; const int kTaskCount = 20; for (int i = 0; i < kTaskCount; ++i) { double sleepTimeInMs = rand() % 100; [tasks addObject:[[OSSTask taskWithDelay:(int)sleepTimeInMs] continueWithBlock:^id(OSSTask *t) { return @(i); }]]; } [[[OSSTask taskForCompletionOfAllTasks:tasks] continueWithBlock:^id(OSSTask *t) { XCTAssertNil(t.error); XCTAssertFalse(t.isCancelled); for (int i = 0; i < kTaskCount; ++i) { XCTAssertEqual(i, [((OSSTask *)[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:[[OSSTask taskWithDelay:(int)sleepTimeInMs] continueWithBlock:^id(OSSTask *t) { if (i == 10) { return [OSSTask taskWithError:[NSError errorWithDomain:@"BoltsTests" code:35 userInfo:nil]]; } return @(i); }]]; } [[[OSSTask taskForCompletionOfAllTasks:tasks] continueWithBlock:^id(OSSTask *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(((OSSTask *)[tasks objectAtIndex:i]).error); } else { XCTAssertEqual(i, [((OSSTask *)[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:[[OSSTask taskWithDelay:(int)sleepTimeInMs] continueWithBlock:^id(OSSTask *t) { if (i == 10 || i == 11) { return [OSSTask taskWithError:[NSError errorWithDomain:@"BoltsTests" code:35 userInfo:nil]]; } return @(i); }]]; } [[[OSSTask taskForCompletionOfAllTasks:tasks] continueWithBlock:^id(OSSTask *t) { XCTAssertNotNil(t.error); XCTAssertFalse(t.isCancelled); XCTAssertEqualObjects(@"bolts", t.error.domain); XCTAssertEqual(kOSSMultipleErrorsError, t.error.code); NSArray *errors = [t.error.userInfo objectForKey:OSSTaskMultipleErrorsUserInfoKey]; 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(((OSSTask *)[tasks objectAtIndex:i]).error); } else { XCTAssertEqual(i, [((OSSTask *)[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:[[OSSTask taskWithDelay:(int)sleepTimeInMs] continueWithBlock:^id(OSSTask *t) { if (i == 10) { return [OSSTask cancelledTask]; } return @(i); }]]; } [[[OSSTask taskForCompletionOfAllTasks:tasks] continueWithBlock:^id(OSSTask *t) { XCTAssertNil(t.error); XCTAssertTrue(t.isCancelled); for (int i = 0; i < kTaskCount; ++i) { if (i == 10) { XCTAssertTrue(((OSSTask *)[tasks objectAtIndex:i]).isCancelled); } else { XCTAssertEqual(i, [((OSSTask *)[tasks objectAtIndex:i]).result intValue]); } } return nil; }] waitUntilFinished]; } - (void)testTaskForCompletionOfAllTasksNoTasksImmediateCompletion { NSMutableArray *tasks = [NSMutableArray array]; OSSTask *task = [OSSTask 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:[[OSSTask taskWithDelay:(int)sleepTimeInMs] continueWithBlock:^id(OSSTask *__unused t) { return @(result); }]]; } [[[OSSTask taskForCompletionOfAllTasksWithResults:tasks] continueWithBlock:^id(OSSTask *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], [((OSSTask *)[tasks objectAtIndex:i]).result intValue]); } return nil; }] waitUntilFinished]; } - (void)testTaskForCompletionOfAllTasksErrorCancelledSuccess { OSSTask *errorTask = [OSSTask taskWithError:[NSError new]]; OSSTask *cancelledTask = [OSSTask cancelledTask]; OSSTask *successfulTask = [OSSTask taskWithResult:[NSNumber numberWithInt:2]]; OSSTask *allTasks = [OSSTask taskForCompletionOfAllTasks:@[ successfulTask, cancelledTask, errorTask ]]; XCTAssertTrue(allTasks.faulted, @"Task should be faulted"); } - (void)testTaskForCompletionOfAllTasksExceptionErrorCancelledSuccess { OSSTask *errorTask = [OSSTask taskWithError:[NSError new]]; OSSTask *cancelledTask = [OSSTask cancelledTask]; OSSTask *successfulTask = [OSSTask taskWithResult:[NSNumber numberWithInt:2]]; OSSTask *allTasks = [OSSTask taskForCompletionOfAllTasks:@[ successfulTask, cancelledTask, errorTask ]]; XCTAssertTrue(allTasks.faulted, @"Task should be faulted"); XCTAssertNotNil(allTasks.error, @"Task should have error"); } - (void)testTaskForCompletionOfAllTasksErrorCancelled { OSSTask *errorTask = [OSSTask taskWithError:[NSError new]]; OSSTask *cancelledTask = [OSSTask cancelledTask]; OSSTask *allTasks = [OSSTask taskForCompletionOfAllTasks:@[ cancelledTask, errorTask ]]; XCTAssertTrue(allTasks.faulted, @"Task should be faulted"); } - (void)testTaskForCompletionOfAllTasksSuccessCancelled { OSSTask *cancelledTask = [OSSTask cancelledTask]; OSSTask *successfulTask = [OSSTask taskWithResult:[NSNumber numberWithInt:2]]; OSSTask *allTasks = [OSSTask taskForCompletionOfAllTasks:@[ successfulTask, cancelledTask ]]; XCTAssertTrue(allTasks.cancelled, @"Task should be cancelled"); } - (void)testTaskForCompletionOfAllTasksSuccessError { OSSTask *errorTask = [OSSTask taskWithError:[NSError new]]; OSSTask *successfulTask = [OSSTask taskWithResult:[NSNumber numberWithInt:2]]; OSSTask *allTasks = [OSSTask taskForCompletionOfAllTasks:@[ successfulTask, errorTask ]]; XCTAssertTrue(allTasks.faulted, @"Task should be faulted"); } - (void)testTaskForCompletionOfAllTasksWithResultsNoTasksImmediateCompletion { NSMutableArray *tasks = [NSMutableArray array]; OSSTask *task = [OSSTask taskForCompletionOfAllTasksWithResults:tasks]; XCTAssertTrue(task.completed); XCTAssertFalse(task.cancelled); XCTAssertFalse(task.faulted); XCTAssertTrue(task.result != nil); } - (void)testTasksForTaskForCompletionOfAnyTasksWithSuccess { OSSTask *task = [OSSTask taskForCompletionOfAnyTask:@[[OSSTask taskWithDelay:20], [OSSTask taskWithResult:@"success"]]]; [task waitUntilFinished]; XCTAssertEqualObjects(@"success", task.result); } - (void)testTasksForTaskForCompletionOfAnyTasksWithRacing { dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); OSSExecutor *executor = [OSSExecutor executorWithDispatchQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)]; OSSTask *first = [OSSTask taskFromExecutor:executor withBlock:^id _Nullable { return @"first"; }]; OSSTask *second = [OSSTask taskFromExecutor:executor withBlock:^id _Nullable { dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); return @"second"; }]; OSSTask *task = [OSSTask taskForCompletionOfAnyTask:@[first, second]]; [task waitUntilFinished]; dispatch_semaphore_signal(semaphore); XCTAssertEqualObjects(@"first", task.result); } - (void)testTasksForTaskForCompletionOfAnyTasksWithErrorAndSuccess { NSError *error = [NSError errorWithDomain:@"BoltsTests" code:35 userInfo:nil]; OSSTask *task = [OSSTask taskForCompletionOfAnyTask:@[[OSSTask taskWithError:error], [OSSTask taskWithResult:@"success"]]]; [task waitUntilFinished]; XCTAssertEqualObjects(@"success", task.result); XCTAssertNil(task.error); } - (void)testTasksForTaskForCompletionOfAnyTasksWithError { NSError *error = [NSError errorWithDomain:@"BoltsTests" code:35 userInfo:nil]; OSSTask *task = [OSSTask taskForCompletionOfAnyTask:@[[OSSTask taskWithError:error]]]; [task waitUntilFinished]; XCTAssertEqualObjects(error, task.error); XCTAssertNotNil(task.error); } - (void)testTasksForTaskForCompletionOfAnyTasksWithNilArray { OSSTask *task = [OSSTask taskForCompletionOfAnyTask:nil]; [task waitUntilFinished]; XCTAssertNil(task.result); XCTAssertNil(task.error); } - (void)testTasksForTaskForCompletionOfAnyTasksAllErrors { NSError *error = [NSError errorWithDomain:@"BoltsTests" code:35 userInfo:nil]; OSSTask *task = [OSSTask taskForCompletionOfAnyTask:@[[OSSTask taskWithError:error], [OSSTask 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 { OSSTask *task = [[OSSTask taskWithDelay:50] continueWithBlock:^id(OSSTask *t) { return @"foo"; }]; [task waitUntilFinished]; XCTAssertEqualObjects(@"foo", task.result); } - (void)testDelayWithToken { OSSCancellationTokenSource *cts = [OSSCancellationTokenSource cancellationTokenSource]; OSSTask *task = [OSSTask taskWithDelay:100 cancellationToken:cts.token]; [cts cancel]; [task waitUntilFinished]; XCTAssertTrue(task.cancelled, @"Task should be cancelled immediately"); } - (void)testDelayWithCancelledToken { OSSCancellationTokenSource *cts = [OSSCancellationTokenSource cancellationTokenSource]; [cts cancel]; OSSTask *task = [OSSTask 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); OSSExecutor *queueExecutor = [OSSExecutor executorWithDispatchQueue:queue]; OSSTask *task = [OSSTask 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 { OSSTask *task = [OSSTask taskWithResult:nil]; NSString *expected = [NSString stringWithFormat:@"<OSSTask: %p; completed = YES; cancelled = NO; faulted = NO; result = (null)>", task]; NSString *description = task.description; XCTAssertTrue([expected isEqualToString:description]); } - (void)testReturnTaskFromContinuationWithCancellation { OSSCancellationTokenSource *cts = [OSSCancellationTokenSource cancellationTokenSource]; XCTestExpectation *expectation = [self expectationWithDescription:@"task"]; [[[OSSTask taskWithDelay:1] continueWithBlock:^id(OSSTask *t) { [cts cancel]; return [OSSTask taskWithDelay:10]; } cancellationToken:cts.token] continueWithBlock:^id(OSSTask *t) { XCTAssertTrue(t.cancelled); [expectation fulfill]; return nil; }]; [self waitForExpectationsWithTimeout:10.0 handler:nil]; } - (void)testSetResult { OSSTaskCompletionSource *taskCompletionSource = [OSSTaskCompletionSource taskCompletionSource]; taskCompletionSource.result = @"a"; XCTAssertThrowsSpecificNamed([taskCompletionSource setResult:@"b"], NSException, NSInternalInconsistencyException); XCTAssertTrue(taskCompletionSource.task.completed); XCTAssertEqualObjects(taskCompletionSource.task.result, @"a"); } - (void)testTrySetResult { OSSTaskCompletionSource *taskCompletionSource = [OSSTaskCompletionSource taskCompletionSource]; [taskCompletionSource trySetResult:@"a"]; [taskCompletionSource trySetResult:@"b"]; XCTAssertTrue(taskCompletionSource.task.completed); XCTAssertEqualObjects(taskCompletionSource.task.result, @"a"); } - (void)testSetError { OSSTaskCompletionSource *taskCompletionSource = [OSSTaskCompletionSource 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 { OSSTaskCompletionSource *taskCompletionSource = [OSSTaskCompletionSource 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)testSetException { OSSTaskCompletionSource *taskCompletionSource = [OSSTaskCompletionSource taskCompletionSource]; NSException *exception = [NSException exceptionWithName:@"testExceptionName" reason:@"testExceptionReason" userInfo:nil]; taskCompletionSource.exception = exception; XCTAssertThrowsSpecificNamed([taskCompletionSource setException:exception], NSException, NSInternalInconsistencyException); XCTAssertTrue(taskCompletionSource.task.completed); XCTAssertTrue(taskCompletionSource.task.faulted); XCTAssertEqualObjects(taskCompletionSource.task.exception, exception); } - (void)testTrySetException { OSSTaskCompletionSource *taskCompletionSource = [OSSTaskCompletionSource taskCompletionSource]; NSException *exception = [NSException exceptionWithName:@"testExceptionName" reason:@"testExceptionReason" userInfo:nil]; [taskCompletionSource trySetException:exception]; [taskCompletionSource trySetException:exception]; XCTAssertTrue(taskCompletionSource.task.completed); XCTAssertTrue(taskCompletionSource.task.faulted); XCTAssertEqualObjects(taskCompletionSource.task.exception, exception); } - (void)testSetCancelled { OSSTaskCompletionSource *taskCompletionSource = [OSSTaskCompletionSource taskCompletionSource]; [taskCompletionSource cancel]; XCTAssertThrowsSpecificNamed([taskCompletionSource cancel], NSException, NSInternalInconsistencyException); XCTAssertTrue(taskCompletionSource.task.completed); XCTAssertTrue(taskCompletionSource.task.cancelled); } - (void)testTrySetCancelled { OSSTaskCompletionSource *taskCompletionSource = [OSSTaskCompletionSource taskCompletionSource]; [taskCompletionSource trySetCancelled]; [taskCompletionSource trySetCancelled]; XCTAssertTrue(taskCompletionSource.task.completed); XCTAssertTrue(taskCompletionSource.task.cancelled); } - (void)testMultipleWaitUntilFinished { OSSTask *task = [[OSSTask taskWithDelay:50] continueWithBlock:^id(OSSTask *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 { OSSTask *task = [[OSSTask taskWithDelay:500] continueWithBlock:^id(OSSTask *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