blob: b043beb97c0b782ce0ad4fec6b2afd5e32397797 [file] [log] [blame] [edit]
//
// RACMulticastConnectionSpec.m
// ReactiveCocoa
//
// Created by Josh Abernathy on 10/8/12.
// Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import "RACMulticastConnection.h"
#import "RACDisposable.h"
#import "RACSignal+Operations.h"
#import "RACSubscriber.h"
#import "RACReplaySubject.h"
#import "RACScheduler.h"
#import <libkern/OSAtomic.h>
SpecBegin(RACMulticastConnection)
__block NSUInteger subscriptionCount = 0;
__block RACMulticastConnection *connection;
__block BOOL disposed = NO;
beforeEach(^{
subscriptionCount = 0;
disposed = NO;
connection = [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {
subscriptionCount++;
return [RACDisposable disposableWithBlock:^{
disposed = YES;
}];
}] publish];
expect(subscriptionCount).to.equal(0);
});
describe(@"-connect", ^{
it(@"should subscribe to the underlying signal", ^{
[connection connect];
expect(subscriptionCount).to.equal(1);
});
it(@"should return the same disposable for each invocation", ^{
RACDisposable *d1 = [connection connect];
RACDisposable *d2 = [connection connect];
expect(d1).to.equal(d2);
expect(subscriptionCount).to.equal(1);
});
it(@"shouldn't reconnect after disposal", ^{
RACDisposable *disposable1 = [connection connect];
expect(subscriptionCount).to.equal(1);
[disposable1 dispose];
RACDisposable *disposable2 = [connection connect];
expect(subscriptionCount).to.equal(1);
expect(disposable1).to.equal(disposable2);
});
it(@"shouldn't race when connecting", ^{
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
RACMulticastConnection *connection = [[RACSignal
defer:^ id {
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
return nil;
}]
publish];
__block RACDisposable *disposable;
[RACScheduler.scheduler schedule:^{
disposable = [connection connect];
dispatch_semaphore_signal(semaphore);
}];
expect([connection connect]).notTo.beNil();
dispatch_semaphore_signal(semaphore);
expect(disposable).willNot.beNil();
dispatch_release(semaphore);
});
});
describe(@"-autoconnect", ^{
__block RACSignal *autoconnectedSignal;
beforeEach(^{
autoconnectedSignal = [connection autoconnect];
});
it(@"should subscribe to the multicasted signal on the first subscription", ^{
expect(subscriptionCount).to.equal(0);
[autoconnectedSignal subscribeNext:^(id x) {}];
expect(subscriptionCount).to.equal(1);
[autoconnectedSignal subscribeNext:^(id x) {}];
expect(subscriptionCount).to.equal(1);
});
it(@"should dispose of the multicasted subscription when the signal has no subscribers", ^{
RACDisposable *disposable = [autoconnectedSignal subscribeNext:^(id x) {}];
expect(disposed).to.beFalsy();
[disposable dispose];
expect(disposed).to.beTruthy();
});
it(@"shouldn't reconnect after disposal", ^{
RACDisposable *disposable = [autoconnectedSignal subscribeNext:^(id x) {}];
expect(subscriptionCount).to.equal(1);
[disposable dispose];
disposable = [autoconnectedSignal subscribeNext:^(id x) {}];
expect(subscriptionCount).to.equal(1);
[disposable dispose];
});
it(@"should replay values after disposal when multicasted to a replay subject", ^{
RACSubject *subject = [RACSubject subject];
RACSignal *signal = [[subject multicast:[RACReplaySubject subject]] autoconnect];
NSMutableArray *results1 = [NSMutableArray array];
RACDisposable *disposable = [signal subscribeNext:^(id x) {
[results1 addObject:x];
}];
[subject sendNext:@1];
[subject sendNext:@2];
expect(results1).to.equal((@[ @1, @2 ]));
[disposable dispose];
NSMutableArray *results2 = [NSMutableArray array];
[signal subscribeNext:^(id x) {
[results2 addObject:x];
}];
expect(results2).will.equal((@[ @1, @2 ]));
});
});
SpecEnd