| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411 |
- //
- // NSObjectRACLifting.m
- // ReactiveCocoa
- //
- // Created by Josh Abernathy on 10/2/12.
- // Copyright (c) 2012 GitHub, Inc. All rights reserved.
- //
- #import <Quick/Quick.h>
- #import <Nimble/Nimble.h>
- #import "RACTestObject.h"
- #import "NSObject+RACLifting.h"
- #import "NSObject+RACDeallocating.h"
- #import "NSObject+RACPropertySubscribing.h"
- #import "RACCompoundDisposable.h"
- #import "RACDisposable.h"
- #import "RACSubject.h"
- #import "RACTuple.h"
- #import "RACUnit.h"
- QuickSpecBegin(NSObjectRACLiftingSpec)
- qck_describe(@"-rac_liftSelector:withSignals:", ^{
- __block RACTestObject *object;
- qck_beforeEach(^{
- object = [[RACTestObject alloc] init];
- });
- qck_it(@"should call the selector with the value of the signal", ^{
- RACSubject *subject = [RACSubject subject];
- [object rac_liftSelector:@selector(setObjectValue:) withSignals:subject, nil];
- expect(object.objectValue).to(beNil());
- [subject sendNext:@1];
- expect(object.objectValue).to(equal(@1));
- [subject sendNext:@42];
- expect(object.objectValue).to(equal(@42));
- });
- });
- qck_describe(@"-rac_liftSelector:withSignalsFromArray:", ^{
- __block RACTestObject *object;
- qck_beforeEach(^{
- object = [[RACTestObject alloc] init];
- });
- qck_it(@"should call the selector with the value of the signal", ^{
- RACSubject *subject = [RACSubject subject];
- [object rac_liftSelector:@selector(setObjectValue:) withSignalsFromArray:@[ subject ]];
- expect(object.objectValue).to(beNil());
- [subject sendNext:@1];
- expect(object.objectValue).to(equal(@1));
- [subject sendNext:@42];
- expect(object.objectValue).to(equal(@42));
- });
- qck_it(@"should call the selector with the value of the signal unboxed", ^{
- RACSubject *subject = [RACSubject subject];
- [object rac_liftSelector:@selector(setIntegerValue:) withSignalsFromArray:@[ subject ]];
- expect(@(object.integerValue)).to(equal(@0));
- [subject sendNext:@1];
- expect(@(object.integerValue)).to(equal(@1));
- [subject sendNext:@42];
- expect(@(object.integerValue)).to(equal(@42));
- });
- qck_it(@"should work with multiple arguments", ^{
- RACSubject *objectValueSubject = [RACSubject subject];
- RACSubject *integerValueSubject = [RACSubject subject];
- [object rac_liftSelector:@selector(setObjectValue:andIntegerValue:) withSignalsFromArray:@[ objectValueSubject, integerValueSubject ]];
- expect(@(object.hasInvokedSetObjectValueAndIntegerValue)).to(beFalsy());
- expect(object.objectValue).to(beNil());
- expect(@(object.integerValue)).to(equal(@0));
- [objectValueSubject sendNext:@1];
- expect(@(object.hasInvokedSetObjectValueAndIntegerValue)).to(beFalsy());
- expect(object.objectValue).to(beNil());
- expect(@(object.integerValue)).to(equal(@0));
- [integerValueSubject sendNext:@42];
- expect(@(object.hasInvokedSetObjectValueAndIntegerValue)).to(beTruthy());
- expect(object.objectValue).to(equal(@1));
- expect(@(object.integerValue)).to(equal(@42));
- });
- qck_it(@"should work with signals that immediately start with a value", ^{
- RACSubject *subject = [RACSubject subject];
- [object rac_liftSelector:@selector(setObjectValue:) withSignalsFromArray:@[ [subject startWith:@42] ]];
- expect(object.objectValue).to(equal(@42));
- [subject sendNext:@1];
- expect(object.objectValue).to(equal(@1));
- });
- qck_it(@"should work with signals that send nil", ^{
- RACSubject *subject = [RACSubject subject];
- [object rac_liftSelector:@selector(setObjectValue:) withSignalsFromArray:@[ subject ]];
- [subject sendNext:nil];
- expect(object.objectValue).to(beNil());
- [subject sendNext:RACTupleNil.tupleNil];
- expect(object.objectValue).to(beNil());
- });
- qck_it(@"should work with integers", ^{
- RACSubject *subject = [RACSubject subject];
- [object rac_liftSelector:@selector(setIntegerValue:) withSignalsFromArray:@[ subject ]];
- expect(@(object.integerValue)).to(equal(@0));
- [subject sendNext:@1];
- expect(@(object.integerValue)).to(equal(@1));
- });
- qck_it(@"should convert between numeric types", ^{
- RACSubject *subject = [RACSubject subject];
- [object rac_liftSelector:@selector(setIntegerValue:) withSignalsFromArray:@[ subject ]];
- expect(@(object.integerValue)).to(equal(@0));
- [subject sendNext:@1.0];
- expect(@(object.integerValue)).to(equal(@1));
- });
- qck_it(@"should work with class objects", ^{
- RACSubject *subject = [RACSubject subject];
- [object rac_liftSelector:@selector(setObjectValue:) withSignalsFromArray:@[ subject ]];
- expect(object.objectValue).to(beNil());
- [subject sendNext:self.class];
- expect(object.objectValue).to(equal(self.class));
- });
- qck_it(@"should work for char pointer", ^{
- RACSubject *subject = [RACSubject subject];
- [object rac_liftSelector:@selector(setCharPointerValue:) withSignalsFromArray:@[ subject ]];
- expect(@((size_t)object.charPointerValue)).to(equal(@0));
- NSString *string = @"blah blah blah";
- [subject sendNext:string];
- expect(@(object.charPointerValue)).to(equal(string));
- });
- qck_it(@"should work for const char pointer", ^{
- RACSubject *subject = [RACSubject subject];
- [object rac_liftSelector:@selector(setConstCharPointerValue:) withSignalsFromArray:@[ subject ]];
- expect(@((size_t)object.constCharPointerValue)).to(equal(@0));
- NSString *string = @"blah blah blah";
- [subject sendNext:string];
- expect(@(object.constCharPointerValue)).to(equal(string));
- });
- qck_it(@"should work for CGRect", ^{
- RACSubject *subject = [RACSubject subject];
- [object rac_liftSelector:@selector(setRectValue:) withSignalsFromArray:@[ subject ]];
- expect(@(CGRectEqualToRect(object.rectValue, CGRectZero))).to(beTruthy());
- CGRect value = CGRectMake(10, 20, 30, 40);
- [subject sendNext:[NSValue valueWithBytes:&value objCType:@encode(CGRect)]];
- expect(@(CGRectEqualToRect(object.rectValue, value))).to(beTruthy());
- });
- qck_it(@"should work for CGSize", ^{
- RACSubject *subject = [RACSubject subject];
- [object rac_liftSelector:@selector(setSizeValue:) withSignalsFromArray:@[ subject ]];
- expect(@(CGSizeEqualToSize(object.sizeValue, CGSizeZero))).to(beTruthy());
- CGSize value = CGSizeMake(10, 20);
- [subject sendNext:[NSValue valueWithBytes:&value objCType:@encode(CGSize)]];
- expect(@(CGSizeEqualToSize(object.sizeValue, value))).to(beTruthy());
- });
- qck_it(@"should work for CGPoint", ^{
- RACSubject *subject = [RACSubject subject];
- [object rac_liftSelector:@selector(setPointValue:) withSignalsFromArray:@[ subject ]];
- expect(@(CGPointEqualToPoint(object.pointValue, CGPointZero))).to(beTruthy());
- CGPoint value = CGPointMake(10, 20);
- [subject sendNext:[NSValue valueWithBytes:&value objCType:@encode(CGPoint)]];
- expect(@(CGPointEqualToPoint(object.pointValue, value))).to(beTruthy());
- });
- qck_it(@"should work for NSRange", ^{
- RACSubject *subject = [RACSubject subject];
- [object rac_liftSelector:@selector(setRangeValue:) withSignalsFromArray:@[ subject ]];
- expect(@(NSEqualRanges(object.rangeValue, NSMakeRange(0, 0)))).to(beTruthy());
- NSRange value = NSMakeRange(10, 20);
- [subject sendNext:[NSValue valueWithRange:value]];
- expect(@(NSEqualRanges(object.rangeValue, value))).to(beTruthy());
- });
- qck_it(@"should work for _Bool", ^{
- RACSubject *subject = [RACSubject subject];
- [object rac_liftSelector:@selector(setC99BoolValue:) withSignalsFromArray:@[ subject ]];
- expect(@(object.c99BoolValue)).to(beFalsy());
- _Bool value = true;
- [subject sendNext:@(value)];
- expect(@(object.c99BoolValue)).to(beTruthy());
- });
- qck_it(@"should work for primitive pointers", ^{
- RACSubject *subject = [RACSubject subject];
- [object rac_liftSelector:@selector(write5ToIntPointer:) withSignalsFromArray:@[ subject ]];
- int value = 0;
- int *valuePointer = &value;
- expect(@(value)).to(equal(@0));
- [subject sendNext:[NSValue valueWithPointer:valuePointer]];
- expect(@(value)).to(equal(@5));
- });
- qck_it(@"should work for custom structs", ^{
- RACSubject *subject = [RACSubject subject];
- [object rac_liftSelector:@selector(setStructValue:) withSignalsFromArray:@[ subject ]];
- expect(@(object.structValue.integerField)).to(equal(@0));
- expect(@(object.structValue.doubleField)).to(equal(@0.0));
- RACTestStruct value = (RACTestStruct){7, 1.23};
- [subject sendNext:[NSValue valueWithBytes:&value objCType:@encode(typeof(value))]];
- expect(@(object.structValue.integerField)).to(equal(@(value.integerField)));
- expect(@(object.structValue.doubleField)).to(equal(@(value.doubleField)));
- });
- qck_it(@"should send the latest value of the signal as the right argument", ^{
- RACSubject *subject = [RACSubject subject];
- [object rac_liftSelector:@selector(setObjectValue:andIntegerValue:) withSignalsFromArray:@[ [RACSignal return:@"object"], subject ]];
- [subject sendNext:@1];
- expect(object.objectValue).to(equal(@"object"));
- expect(@(object.integerValue)).to(equal(@1));
- });
- qck_describe(@"the returned signal", ^{
- qck_it(@"should send the return value of the method invocation", ^{
- RACSubject *objectSubject = [RACSubject subject];
- RACSubject *integerSubject = [RACSubject subject];
- RACSignal *signal = [object rac_liftSelector:@selector(combineObjectValue:andIntegerValue:) withSignalsFromArray:@[ objectSubject, integerSubject ]];
- __block NSString *result;
- [signal subscribeNext:^(id x) {
- result = x;
- }];
- [objectSubject sendNext:@"Magic number"];
- expect(result).to(beNil());
- [integerSubject sendNext:@42];
- expect(result).to(equal(@"Magic number: 42"));
- });
- qck_it(@"should send RACUnit.defaultUnit for void-returning methods", ^{
- RACSubject *subject = [RACSubject subject];
- RACSignal *signal = [object rac_liftSelector:@selector(setObjectValue:) withSignalsFromArray:@[ subject ]];
- __block id result;
- [signal subscribeNext:^(id x) {
- result = x;
- }];
- [subject sendNext:@1];
- expect(result).to(equal(RACUnit.defaultUnit));
- });
- qck_it(@"should support integer returning methods", ^{
- RACSubject *subject = [RACSubject subject];
- RACSignal *signal = [object rac_liftSelector:@selector(doubleInteger:) withSignalsFromArray:@[ subject ]];
- __block id result;
- [signal subscribeNext:^(id x) {
- result = x;
- }];
- [subject sendNext:@1];
- expect(result).to(equal(@2));
- });
- qck_it(@"should support char * returning methods", ^{
- RACSubject *subject = [RACSubject subject];
- RACSignal *signal = [object rac_liftSelector:@selector(doubleString:) withSignalsFromArray:@[ subject ]];
- __block id result;
- [signal subscribeNext:^(id x) {
- result = x;
- }];
- [subject sendNext:@"test"];
- expect(result).to(equal(@"testtest"));
- });
- qck_it(@"should support const char * returning methods", ^{
- RACSubject *subject = [RACSubject subject];
- RACSignal *signal = [object rac_liftSelector:@selector(doubleConstString:) withSignalsFromArray:@[ subject ]];
- __block id result;
- [signal subscribeNext:^(id x) {
- result = x;
- }];
- [subject sendNext:@"test"];
- expect(result).to(equal(@"testtest"));
- });
- qck_it(@"should support struct returning methods", ^{
- RACSubject *subject = [RACSubject subject];
- RACSignal *signal = [object rac_liftSelector:@selector(doubleStruct:) withSignalsFromArray:@[ subject ]];
- __block NSValue *boxedResult;
- [signal subscribeNext:^(id x) {
- boxedResult = x;
- }];
- RACTestStruct value = {4, 12.3};
- NSValue *boxedValue = [NSValue valueWithBytes:&value objCType:@encode(typeof(value))];
- [subject sendNext:boxedValue];
- RACTestStruct result = {0, 0.0};
- [boxedResult getValue:&result];
- expect(@(result.integerField)).to(equal(@8));
- expect(@(result.doubleField)).to(equal(@24.6));
- });
- qck_it(@"should support block arguments and returns", ^{
- RACSubject *subject = [RACSubject subject];
- RACSignal *signal = [object rac_liftSelector:@selector(wrapBlock:) withSignalsFromArray:@[ subject ]];
- __block BOOL blockInvoked = NO;
- dispatch_block_t testBlock = ^{
- blockInvoked = YES;
- };
- __block dispatch_block_t result;
- [signal subscribeNext:^(id x) {
- result = x;
- }];
- [subject sendNext:testBlock];
- expect(result).notTo(beNil());
- result();
- expect(@(blockInvoked)).to(beTruthy());
- });
- qck_it(@"should replay the last value", ^{
- RACSubject *objectSubject = [RACSubject subject];
- RACSubject *integerSubject = [RACSubject subject];
- RACSignal *signal = [object rac_liftSelector:@selector(combineObjectValue:andIntegerValue:) withSignalsFromArray:@[ objectSubject, integerSubject ]];
- [objectSubject sendNext:@"Magic number"];
- [integerSubject sendNext:@42];
- [integerSubject sendNext:@43];
- __block NSString *result;
- [signal subscribeNext:^(id x) {
- result = x;
- }];
- expect(result).to(equal(@"Magic number: 43"));
- });
- });
- qck_it(@"shouldn't strongly capture the receiver", ^{
- __block BOOL dealloced = NO;
- @autoreleasepool {
- RACTestObject *testObject __attribute__((objc_precise_lifetime)) = [[RACTestObject alloc] init];
- [testObject.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{
- dealloced = YES;
- }]];
- RACSubject *subject = [RACSubject subject];
- [testObject rac_liftSelector:@selector(setObjectValue:) withSignalsFromArray:@[ subject ]];
- [subject sendNext:@1];
- }
- expect(@(dealloced)).to(beTruthy());
- });
- });
- QuickSpecEnd
|