| // | |
| // NSObjectRACPropertySubscribingSpec.m | |
| // ReactiveCocoa | |
| // | |
| // Created by Josh Abernathy on 9/28/12. | |
| // Copyright (c) 2012 GitHub, Inc. All rights reserved. | |
| // | |
| #import "NSObjectRACPropertySubscribingExamples.h" | |
| #import "RACTestObject.h" | |
| #import "NSObject+RACPropertySubscribing.h" | |
| #import "RACDisposable.h" | |
| #import "RACSignal.h" | |
| SpecBegin(NSObjectRACPropertySubscribing) | |
| describe(@"-rac_valuesForKeyPath:observer:", ^{ | |
| id (^setupBlock)(id, id, id) = ^(RACTestObject *object, NSString *keyPath, id observer) { | |
| return [object rac_valuesForKeyPath:keyPath observer:observer]; | |
| }; | |
| itShouldBehaveLike(RACPropertySubscribingExamples, ^{ | |
| return @{ RACPropertySubscribingExamplesSetupBlock: setupBlock }; | |
| }); | |
| }); | |
| describe(@"+rac_signalWithChangesFor:keyPath:options:observer:", ^{ | |
| describe(@"KVO options argument", ^{ | |
| __block RACTestObject *object; | |
| __block id actual; | |
| __block RACSignal *(^objectValueSignal)(NSKeyValueObservingOptions); | |
| before(^{ | |
| object = [[RACTestObject alloc] init]; | |
| objectValueSignal = ^(NSKeyValueObservingOptions options) { | |
| return [[object rac_valuesAndChangesForKeyPath:@keypath(object, objectValue) options:options observer:self] reduceEach:^(id value, NSDictionary *change) { | |
| return change; | |
| }]; | |
| }; | |
| }); | |
| it(@"sends a KVO dictionary", ^{ | |
| [objectValueSignal(0) subscribeNext:^(NSDictionary *x) { | |
| actual = x; | |
| }]; | |
| object.objectValue = @1; | |
| expect(actual).to.beKindOf(NSDictionary.class); | |
| }); | |
| it(@"sends a kind key by default", ^{ | |
| [objectValueSignal(0) subscribeNext:^(NSDictionary *x) { | |
| actual = x[NSKeyValueChangeKindKey]; | |
| }]; | |
| object.objectValue = @1; | |
| expect(actual).notTo.beNil(); | |
| }); | |
| it(@"sends the newest changes with NSKeyValueObservingOptionNew", ^{ | |
| [objectValueSignal(NSKeyValueObservingOptionNew) subscribeNext:^(NSDictionary *x) { | |
| actual = x[NSKeyValueChangeNewKey]; | |
| }]; | |
| object.objectValue = @1; | |
| expect(actual).to.equal(@1); | |
| object.objectValue = @2; | |
| expect(actual).to.equal(@2); | |
| }); | |
| it(@"sends an additional change value with NSKeyValueObservingOptionPrior", ^{ | |
| NSMutableArray *values = [NSMutableArray new]; | |
| NSArray *expected = @[ @(YES), @(NO) ]; | |
| [objectValueSignal(NSKeyValueObservingOptionPrior) subscribeNext:^(NSDictionary *x) { | |
| BOOL isPrior = [x[NSKeyValueChangeNotificationIsPriorKey] boolValue]; | |
| [values addObject:@(isPrior)]; | |
| }]; | |
| object.objectValue = @[ @1 ]; | |
| expect(values).to.equal(expected); | |
| }); | |
| it(@"sends index changes when adding, inserting or removing a value from an observed object", ^{ | |
| __block NSUInteger hasIndexesCount = 0; | |
| [objectValueSignal(0) subscribeNext:^(NSDictionary *x) { | |
| if (x[NSKeyValueChangeIndexesKey] != nil) { | |
| hasIndexesCount += 1; | |
| } | |
| }]; | |
| object.objectValue = [NSMutableOrderedSet orderedSet]; | |
| expect(hasIndexesCount).to.equal(0); | |
| NSMutableOrderedSet *objectValue = [object mutableOrderedSetValueForKey:@"objectValue"]; | |
| [objectValue addObject:@1]; | |
| expect(hasIndexesCount).to.equal(1); | |
| [objectValue replaceObjectAtIndex:0 withObject:@2]; | |
| expect(hasIndexesCount).to.equal(2); | |
| [objectValue removeObject:@2]; | |
| expect(hasIndexesCount).to.equal(3); | |
| }); | |
| it(@"sends the previous value with NSKeyValueObservingOptionOld", ^{ | |
| [objectValueSignal(NSKeyValueObservingOptionOld) subscribeNext:^(NSDictionary *x) { | |
| actual = x[NSKeyValueChangeOldKey]; | |
| }]; | |
| object.objectValue = @1; | |
| expect(actual).to.equal(NSNull.null); | |
| object.objectValue = @2; | |
| expect(actual).to.equal(@1); | |
| }); | |
| it(@"sends the initial value with NSKeyValueObservingOptionInitial", ^{ | |
| [objectValueSignal(NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew) subscribeNext:^(NSDictionary *x) { | |
| actual = x[NSKeyValueChangeNewKey]; | |
| }]; | |
| expect(actual).to.equal(NSNull.null); | |
| }); | |
| }); | |
| }); | |
| describe(@"-rac_valuesAndChangesForKeyPath:options:observer:", ^{ | |
| it(@"should complete immediately if the receiver or observer have deallocated", ^{ | |
| RACSignal *signal; | |
| @autoreleasepool { | |
| RACTestObject *object __attribute__((objc_precise_lifetime)) = [[RACTestObject alloc] init]; | |
| RACTestObject *observer __attribute__((objc_precise_lifetime)) = [[RACTestObject alloc] init]; | |
| signal = [object rac_valuesAndChangesForKeyPath:@keypath(object, stringValue) options:0 observer:observer]; | |
| } | |
| __block BOOL completed = NO; | |
| [signal subscribeCompleted:^{ | |
| completed = YES; | |
| }]; | |
| expect(completed).to.beTruthy(); | |
| }); | |
| }); | |
| SpecEnd |