| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225 |
- //
- // NSObjectRACPropertySubscribingExamples.m
- // ReactiveCocoa
- //
- // Created by Josh Vera on 4/10/13.
- // Copyright (c) 2013 GitHub, Inc. All rights reserved.
- //
- #import <Quick/Quick.h>
- #import <Nimble/Nimble.h>
- #import "RACTestObject.h"
- #import "NSObjectRACPropertySubscribingExamples.h"
- #import <ReactiveCocoa/EXTScope.h>
- #import "NSObject+RACDeallocating.h"
- #import "NSObject+RACPropertySubscribing.h"
- #import "RACCompoundDisposable.h"
- #import "RACDisposable.h"
- #import "RACSignal.h"
- NSString * const RACPropertySubscribingExamples = @"RACPropertySubscribingExamples";
- NSString * const RACPropertySubscribingExamplesSetupBlock = @"RACPropertySubscribingExamplesSetupBlock";
- QuickConfigurationBegin(NSObjectRACPropertySubscribingExamples)
- + (void)configure:(Configuration *)configuration {
- sharedExamples(RACPropertySubscribingExamples, ^(QCKDSLSharedExampleContext exampleContext) {
- __block RACSignal *(^signalBlock)(RACTestObject *object, NSString *keyPath, id observer);
- qck_beforeEach(^{
- signalBlock = exampleContext()[RACPropertySubscribingExamplesSetupBlock];
- });
- qck_it(@"should send the current value once on subscription", ^{
- RACTestObject *object = [[RACTestObject alloc] init];
- RACSignal *signal = signalBlock(object, @keypath(object, objectValue), self);
- NSMutableArray *values = [NSMutableArray array];
- object.objectValue = @0;
- [signal subscribeNext:^(id x) {
- [values addObject:x];
- }];
- expect(values).to(equal((@[ @0 ])));
- });
- qck_it(@"should send the new value when it changes", ^{
- RACTestObject *object = [[RACTestObject alloc] init];
- RACSignal *signal = signalBlock(object, @keypath(object, objectValue), self);
- NSMutableArray *values = [NSMutableArray array];
- object.objectValue = @0;
- [signal subscribeNext:^(id x) {
- [values addObject:x];
- }];
- expect(values).to(equal((@[ @0 ])));
- object.objectValue = @1;
- expect(values).to(equal((@[ @0, @1 ])));
- });
- qck_it(@"should stop observing when disposed", ^{
- RACTestObject *object = [[RACTestObject alloc] init];
- RACSignal *signal = signalBlock(object, @keypath(object, objectValue), self);
- NSMutableArray *values = [NSMutableArray array];
- object.objectValue = @0;
- RACDisposable *disposable = [signal subscribeNext:^(id x) {
- [values addObject:x];
- }];
- object.objectValue = @1;
- NSArray *expected = @[ @0, @1 ];
- expect(values).to(equal(expected));
- [disposable dispose];
- object.objectValue = @2;
- expect(values).to(equal(expected));
- });
- qck_it(@"shouldn't send any more values after the observer is gone", ^{
- __block BOOL observerDealloced = NO;
- RACTestObject *object = [[RACTestObject alloc] init];
- NSMutableArray *values = [NSMutableArray array];
- @autoreleasepool {
- RACTestObject *observer __attribute__((objc_precise_lifetime)) = [[RACTestObject alloc] init];
- [observer.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{
- observerDealloced = YES;
- }]];
- RACSignal *signal = signalBlock(object, @keypath(object, objectValue), observer);
- object.objectValue = @1;
- [signal subscribeNext:^(id x) {
- [values addObject:x];
- }];
- }
- expect(@(observerDealloced)).to(beTruthy());
- NSArray *expected = @[ @1 ];
- expect(values).to(equal(expected));
- object.objectValue = @2;
- expect(values).to(equal(expected));
- });
- qck_it(@"shouldn't keep either object alive unnaturally long", ^{
- __block BOOL objectDealloced = NO;
- __block BOOL scopeObjectDealloced = NO;
- @autoreleasepool {
- RACTestObject *object __attribute__((objc_precise_lifetime)) = [[RACTestObject alloc] init];
- [object.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{
- objectDealloced = YES;
- }]];
- RACTestObject *scopeObject __attribute__((objc_precise_lifetime)) = [[RACTestObject alloc] init];
- [scopeObject.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{
- scopeObjectDealloced = YES;
- }]];
- RACSignal *signal = signalBlock(object, @keypath(object, objectValue), scopeObject);
- [signal subscribeNext:^(id _) {
- }];
- }
- expect(@(objectDealloced)).to(beTruthy());
- expect(@(scopeObjectDealloced)).to(beTruthy());
- });
- qck_it(@"shouldn't keep the signal alive past the lifetime of the object", ^{
- __block BOOL objectDealloced = NO;
- __block BOOL signalDealloced = NO;
- @autoreleasepool {
- RACTestObject *object __attribute__((objc_precise_lifetime)) = [[RACTestObject alloc] init];
- [object.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{
- objectDealloced = YES;
- }]];
- RACSignal *signal = [signalBlock(object, @keypath(object, objectValue), self) map:^(id value) {
- return value;
- }];
- [signal.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{
- signalDealloced = YES;
- }]];
- [signal subscribeNext:^(id _) {
- }];
- }
- expect(@(signalDealloced)).toEventually(beTruthy());
- expect(@(objectDealloced)).to(beTruthy());
- });
- qck_it(@"shouldn't crash when the value is changed on a different queue", ^{
- __block id value;
- @autoreleasepool {
- RACTestObject *object __attribute__((objc_precise_lifetime)) = [[RACTestObject alloc] init];
- RACSignal *signal = signalBlock(object, @keypath(object, objectValue), self);
- [signal subscribeNext:^(id x) {
- value = x;
- }];
- NSOperationQueue *queue = [[NSOperationQueue alloc] init];
- [queue addOperationWithBlock:^{
- object.objectValue = @1;
- }];
- [queue waitUntilAllOperationsAreFinished];
- }
- expect(value).toEventually(equal(@1));
- });
- qck_describe(@"mutating collections", ^{
- __block RACTestObject *object;
- __block NSMutableOrderedSet *lastValue;
- __block NSMutableOrderedSet *proxySet;
- qck_beforeEach(^{
- object = [[RACTestObject alloc] init];
- object.objectValue = [NSMutableOrderedSet orderedSetWithObject:@1];
- NSString *keyPath = @keypath(object, objectValue);
- [signalBlock(object, keyPath, self) subscribeNext:^(NSMutableOrderedSet *x) {
- lastValue = x;
- }];
- proxySet = [object mutableOrderedSetValueForKey:keyPath];
- });
- qck_it(@"sends the newest object when inserting values into an observed object", ^{
- NSMutableOrderedSet *expected = [NSMutableOrderedSet orderedSetWithObjects: @1, @2, nil];
- [proxySet addObject:@2];
- expect(lastValue).to(equal(expected));
- });
- qck_it(@"sends the newest object when removing values in an observed object", ^{
- NSMutableOrderedSet *expected = [NSMutableOrderedSet orderedSet];
- [proxySet removeAllObjects];
- expect(lastValue).to(equal(expected));
- });
- qck_it(@"sends the newest object when replacing values in an observed object", ^{
- NSMutableOrderedSet *expected = [NSMutableOrderedSet orderedSetWithObjects: @2, nil];
- [proxySet replaceObjectAtIndex:0 withObject:@2];
- expect(lastValue).to(equal(expected));
- });
- });
- });
- }
- QuickConfigurationEnd
|