NSObjectRACPropertySubscribingSpec.m 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. //
  2. // NSObjectRACPropertySubscribingSpec.m
  3. // ReactiveCocoa
  4. //
  5. // Created by Josh Abernathy on 9/28/12.
  6. // Copyright (c) 2012 GitHub, Inc. All rights reserved.
  7. //
  8. #import <Quick/Quick.h>
  9. #import <Nimble/Nimble.h>
  10. #import "NSObjectRACPropertySubscribingExamples.h"
  11. #import "RACTestObject.h"
  12. #import "NSObject+RACPropertySubscribing.h"
  13. #import "RACDisposable.h"
  14. #import "RACSignal.h"
  15. QuickSpecBegin(NSObjectRACPropertySubscribingSpec)
  16. qck_describe(@"-rac_valuesForKeyPath:observer:", ^{
  17. id (^setupBlock)(id, id, id) = ^(RACTestObject *object, NSString *keyPath, id observer) {
  18. return [object rac_valuesForKeyPath:keyPath observer:observer];
  19. };
  20. qck_itBehavesLike(RACPropertySubscribingExamples, ^{
  21. return @{ RACPropertySubscribingExamplesSetupBlock: setupBlock };
  22. });
  23. });
  24. qck_describe(@"+rac_signalWithChangesFor:keyPath:options:observer:", ^{
  25. qck_describe(@"KVO options argument", ^{
  26. __block RACTestObject *object;
  27. __block id actual;
  28. __block RACSignal *(^objectValueSignal)(NSKeyValueObservingOptions);
  29. qck_beforeEach(^{
  30. object = [[RACTestObject alloc] init];
  31. objectValueSignal = ^(NSKeyValueObservingOptions options) {
  32. return [[object rac_valuesAndChangesForKeyPath:@keypath(object, objectValue) options:options observer:self] reduceEach:^(id value, NSDictionary *change) {
  33. return change;
  34. }];
  35. };
  36. });
  37. qck_it(@"sends a KVO dictionary", ^{
  38. [objectValueSignal(0) subscribeNext:^(NSDictionary *x) {
  39. actual = x;
  40. }];
  41. object.objectValue = @1;
  42. expect(actual).to(beAKindOf(NSDictionary.class));
  43. });
  44. qck_it(@"sends a kind key by default", ^{
  45. [objectValueSignal(0) subscribeNext:^(NSDictionary *x) {
  46. actual = x[NSKeyValueChangeKindKey];
  47. }];
  48. object.objectValue = @1;
  49. expect(actual).notTo(beNil());
  50. });
  51. qck_it(@"sends the newest changes with NSKeyValueObservingOptionNew", ^{
  52. [objectValueSignal(NSKeyValueObservingOptionNew) subscribeNext:^(NSDictionary *x) {
  53. actual = x[NSKeyValueChangeNewKey];
  54. }];
  55. object.objectValue = @1;
  56. expect(actual).to(equal(@1));
  57. object.objectValue = @2;
  58. expect(actual).to(equal(@2));
  59. });
  60. qck_it(@"sends an additional change value with NSKeyValueObservingOptionPrior", ^{
  61. NSMutableArray *values = [NSMutableArray new];
  62. NSArray *expected = @[ @(YES), @(NO) ];
  63. [objectValueSignal(NSKeyValueObservingOptionPrior) subscribeNext:^(NSDictionary *x) {
  64. BOOL isPrior = [x[NSKeyValueChangeNotificationIsPriorKey] boolValue];
  65. [values addObject:@(isPrior)];
  66. }];
  67. object.objectValue = @[ @1 ];
  68. expect(values).to(equal(expected));
  69. });
  70. qck_it(@"sends index changes when adding, inserting or removing a value from an observed object", ^{
  71. __block NSUInteger hasIndexesCount = 0;
  72. [objectValueSignal(0) subscribeNext:^(NSDictionary *x) {
  73. if (x[NSKeyValueChangeIndexesKey] != nil) {
  74. hasIndexesCount += 1;
  75. }
  76. }];
  77. object.objectValue = [NSMutableOrderedSet orderedSet];
  78. expect(@(hasIndexesCount)).to(equal(@0));
  79. NSMutableOrderedSet *objectValue = [object mutableOrderedSetValueForKey:@"objectValue"];
  80. [objectValue addObject:@1];
  81. expect(@(hasIndexesCount)).to(equal(@1));
  82. [objectValue replaceObjectAtIndex:0 withObject:@2];
  83. expect(@(hasIndexesCount)).to(equal(@2));
  84. [objectValue removeObject:@2];
  85. expect(@(hasIndexesCount)).to(equal(@3));
  86. });
  87. qck_it(@"sends the previous value with NSKeyValueObservingOptionOld", ^{
  88. [objectValueSignal(NSKeyValueObservingOptionOld) subscribeNext:^(NSDictionary *x) {
  89. actual = x[NSKeyValueChangeOldKey];
  90. }];
  91. object.objectValue = @1;
  92. expect(actual).to(equal(NSNull.null));
  93. object.objectValue = @2;
  94. expect(actual).to(equal(@1));
  95. });
  96. qck_it(@"sends the initial value with NSKeyValueObservingOptionInitial", ^{
  97. [objectValueSignal(NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew) subscribeNext:^(NSDictionary *x) {
  98. actual = x[NSKeyValueChangeNewKey];
  99. }];
  100. expect(actual).to(equal(NSNull.null));
  101. });
  102. });
  103. });
  104. qck_describe(@"-rac_valuesAndChangesForKeyPath:options:observer:", ^{
  105. qck_it(@"should complete immediately if the receiver or observer have deallocated", ^{
  106. RACSignal *signal;
  107. @autoreleasepool {
  108. RACTestObject *object __attribute__((objc_precise_lifetime)) = [[RACTestObject alloc] init];
  109. RACTestObject *observer __attribute__((objc_precise_lifetime)) = [[RACTestObject alloc] init];
  110. signal = [object rac_valuesAndChangesForKeyPath:@keypath(object, stringValue) options:0 observer:observer];
  111. }
  112. __block BOOL completed = NO;
  113. [signal subscribeCompleted:^{
  114. completed = YES;
  115. }];
  116. expect(@(completed)).to(beTruthy());
  117. });
  118. });
  119. QuickSpecEnd