blob: 8a1725de25d3a041491a1846744274c084133a47 [file] [log] [blame]
//
// RACSubscriberSpec.m
// ReactiveCocoa
//
// Created by Justin Spahr-Summers on 2012-11-27.
// Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import "RACSubscriberExamples.h"
#import "RACSubscriber.h"
#import "RACSubscriber+Private.h"
#import <libkern/OSAtomic.h>
SpecBegin(RACSubscriber)
__block RACSubscriber *subscriber;
__block NSMutableArray *values;
__block volatile BOOL finished;
__block volatile int32_t nextsAfterFinished;
__block BOOL success;
__block NSError *error;
beforeEach(^{
values = [NSMutableArray array];
finished = NO;
nextsAfterFinished = 0;
success = YES;
error = nil;
subscriber = [RACSubscriber subscriberWithNext:^(id value) {
if (finished) OSAtomicIncrement32Barrier(&nextsAfterFinished);
[values addObject:value];
} error:^(NSError *e) {
error = e;
success = NO;
} completed:^{
success = YES;
}];
});
itShouldBehaveLike(RACSubscriberExamples, ^{
return @{
RACSubscriberExampleSubscriber: subscriber,
RACSubscriberExampleValuesReceivedBlock: [^{ return [values copy]; } copy],
RACSubscriberExampleErrorReceivedBlock: [^{ return error; } copy],
RACSubscriberExampleSuccessBlock: [^{ return success; } copy]
};
});
describe(@"finishing", ^{
__block void (^sendValues)(void);
__block BOOL expectedSuccess;
__block dispatch_group_t dispatchGroup;
__block dispatch_queue_t concurrentQueue;
beforeEach(^{
dispatchGroup = dispatch_group_create();
expect(dispatchGroup).notTo.beNil();
concurrentQueue = dispatch_queue_create("com.github.ReactiveCocoa.RACSubscriberSpec", DISPATCH_QUEUE_CONCURRENT);
expect(concurrentQueue).notTo.beNil();
dispatch_suspend(concurrentQueue);
sendValues = [^{
for (NSUInteger i = 0; i < 15; i++) {
dispatch_group_async(dispatchGroup, concurrentQueue, ^{
[subscriber sendNext:@(i)];
});
}
} copy];
sendValues();
});
afterEach(^{
sendValues();
dispatch_resume(concurrentQueue);
// Time out after one second.
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC));
expect(dispatch_group_wait(dispatchGroup, time)).to.equal(0);
dispatch_release(dispatchGroup);
dispatchGroup = NULL;
dispatch_release(concurrentQueue);
concurrentQueue = NULL;
expect(nextsAfterFinished).to.equal(0);
if (expectedSuccess) {
expect(success).to.beTruthy();
expect(error).to.beNil();
} else {
expect(success).to.beFalsy();
}
});
it(@"should never invoke next after sending completed", ^{
expectedSuccess = YES;
dispatch_group_async(dispatchGroup, concurrentQueue, ^{
[subscriber sendCompleted];
finished = YES;
OSMemoryBarrier();
});
});
it(@"should never invoke next after sending error", ^{
expectedSuccess = NO;
dispatch_group_async(dispatchGroup, concurrentQueue, ^{
[subscriber sendError:nil];
finished = YES;
OSMemoryBarrier();
});
});
});
SpecEnd