Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Tests and implements futures for handling completion and cancellation…

… of asynchronous tasks.
  • Loading branch information...
commit 04284339237bda67bdbdd5c2d34ba0022859b8e4 1 parent 518b0fe
@robrix authored
View
18 RXFutures/RXFuture.h
@@ -4,6 +4,22 @@
#import <Foundation/Foundation.h>
-@interface RXFuture : NSObject
+@interface RXFuture : NSObject {
+@private
+ BOOL completed;
+ BOOL cancelled;
+ NSMutableSet *completionHandlers;
+ NSMutableSet *cancellationHandlers;
+ dispatch_queue_t queue;
+}
+
+-(void)onComplete:(void(^)())block;
+-(void)onCancel:(void(^)())block;
+
+-(void)cancel;
+-(void)complete;
+
+@property (nonatomic, readonly, assign, getter=isCancelled) BOOL cancelled;
+@property (nonatomic, readonly, assign, getter=isCompleted) BOOL completed;
@end
View
58 RXFutures/RXFuture.m
@@ -4,6 +4,64 @@
#import "RXFuture.h"
+@interface RXFuture ()
+
+@property (nonatomic, readwrite, assign, getter=isCancelled) BOOL cancelled;
+@property (nonatomic, readwrite, assign, getter=isCompleted) BOOL completed;
+
+@end
+
@implementation RXFuture
+@synthesize cancelled, completed;
+
+-(id)init {
+ if((self = [super init])) {
+ completionHandlers = [NSMutableSet new];
+ cancellationHandlers = [NSMutableSet new];
+ queue = dispatch_queue_create("com.monochromeindustries.RXFuture", 0);
+ }
+ return self;
+}
+
+-(void)dealloc {
+ dispatch_release(queue);
+}
+
+
+-(void)onComplete:(void(^)())block {
+ dispatch_async(queue, ^{
+ [completionHandlers addObject:block];
+ });
+}
+
+-(void)onCancel:(void(^)())block {
+ dispatch_async(queue, ^{
+ [cancellationHandlers addObject:block];
+ });
+}
+
+
+-(void)cancel {
+ dispatch_async(queue, ^{
+ if(!cancelled && !completed) {
+ self.cancelled = YES;
+ for(void (^block)() in cancellationHandlers) {
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), block);
+ }
+ }
+ });
+}
+
+-(void)complete {
+ dispatch_async(queue, ^{
+ if(!cancelled && !completed) {
+ self.completed = YES;
+ for(void (^block)() in completionHandlers) {
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), block);
+ }
+ }
+ });
+}
+
@end
View
117 RXFuturesTests/RXFutureTests.m
@@ -7,21 +7,124 @@
#import "RXSynchronously.h"
@interface RXFutureTests : SenTestCase
+
+@property (nonatomic, strong) RXFuture *future;
+@property (nonatomic, strong) NSMutableSet *actions;
+
@end
-@implementation RXFutureTests
+@implementation RXFutureTests {
+ dispatch_queue_t queue;
+}
--(void)testCanBeCancelled {
- RXFuture *future = [RXFuture new];
-
- RXSynchronously(^(RXSynchronousCompletionBlock didCancel) {
- [future cancelWithCompletionHandler:^{
- didCancel();
+@synthesize future, actions;
+
+
+-(void)setUp {
+ self.future = [RXFuture new];
+ self.actions = [NSMutableSet new];
+ queue = dispatch_queue_create("RXFutureTests", 0);
+}
+
+-(void)tearDown {
+ self.future = nil;
+ self.actions = nil;
+ dispatch_release(queue);
+}
+
+
+-(void)testCallsCancellationHandlersAfterCancelling {
+ RXSynchronously(^(RXSynchronousCompletionBlock done) {
+ [future onCancel:^{
+ RXAssert(future.isCancelled);
+ done();
+ }];
+ [future cancel];
+ });
+}
+
+-(void)testCallsCompletionHandlersAfterCompleting {
+ RXSynchronously(^(RXSynchronousCompletionBlock done) {
+ [future onComplete:^{
+ RXAssert(future.isCompleted);
+ done();
}];
+ [future complete];
+ });
+}
+
+-(void)testCancellationPrecludesCompletion {
+ RXSynchronously(^(RXSynchronousCompletionBlock done) {
+ [future onComplete:done];
+ [future onCancel:done];
+ [future cancel];
+ [future complete];
});
RXAssert(future.isCancelled);
+ RXAssertFalse(future.isCompleted);
+}
+
+-(void)testCompletionPrecludesCancellation {
+ RXSynchronously(^(RXSynchronousCompletionBlock done) {
+ [future onComplete:done];
+ [future onCancel:done];
+ [future complete];
+ [future cancel];
+ });
+
+ RXAssertFalse(future.isCancelled);
+ RXAssert(future.isCompleted);
+}
+
+
+-(void)addAction:(NSString *)action {
+ dispatch_async(queue, ^{
+ [actions addObject:action];
+ });
+}
+
+
+-(void)testCallsCancellationHandlersOnCancellation {
+ [future onCancel:^{ [self addAction:@"a"]; }];
+ [future onCancel:^{ [self addAction:@"b"]; }];
+ RXSynchronously(^(RXSynchronousCompletionBlock done) {
+ [future onCancel:done];
+ [future cancel];
+ });
+ RXAssertEquals(actions, ([NSSet setWithObjects:@"a", @"b", nil]));
+}
+
+-(void)testDoesNotCallCancellationHandlersOnCompletion {
+ [future onCancel:^{ [self addAction:@"a"]; }];
+ [future onCancel:^{ [self addAction:@"b"]; }];
+ RXSynchronously(^(RXSynchronousCompletionBlock done) {
+ [future onComplete:done];
+ [future complete];
+ });
+ RXAssertEquals(actions, [NSSet set]);
+}
+
+
+-(void)testCallsCompletionHandlersOnCompletion {
+ [future onComplete:^{ [self addAction:@"a"]; }];
+ [future onComplete:^{ [self addAction:@"b"]; }];
+ RXSynchronously(^(RXSynchronousCompletionBlock done) {
+ [future onComplete:done];
+ [future complete];
+ });
+ RXAssertEquals(actions, ([NSSet setWithObjects:@"a", @"b", nil]));
+}
+
+-(void)testDoesNotCallCompletionHandlersOnCancellation {
+ [future onComplete:^{ [self addAction:@"a"]; }];
+ [future onComplete:^{ [self addAction:@"b"]; }];
+ RXSynchronously(^(RXSynchronousCompletionBlock done) {
+ [future onCancel:done];
+ [future cancel];
+ });
+ RXAssertEquals(actions, [NSSet set]);
}
@end
Please sign in to comment.
Something went wrong with that request. Please try again.