RACChannelExamples.m 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. //
  2. // RACChannelExamples.m
  3. // ReactiveCocoa
  4. //
  5. // Created by Uri Baghin on 30/12/2012.
  6. // Copyright (c) 2012 GitHub, Inc. All rights reserved.
  7. //
  8. #import <Quick/Quick.h>
  9. #import <Nimble/Nimble.h>
  10. #import "RACChannelExamples.h"
  11. #import "NSObject+RACDeallocating.h"
  12. #import "NSObject+RACPropertySubscribing.h"
  13. #import "RACChannel.h"
  14. #import "RACCompoundDisposable.h"
  15. #import "RACDisposable.h"
  16. #import "RACSignal+Operations.h"
  17. NSString * const RACChannelExamples = @"RACChannelExamples";
  18. NSString * const RACChannelExampleCreateBlock = @"RACChannelExampleCreateBlock";
  19. NSString * const RACViewChannelExamples = @"RACViewChannelExamples";
  20. NSString * const RACViewChannelExampleCreateViewBlock = @"RACViewChannelExampleCreateViewBlock";
  21. NSString * const RACViewChannelExampleCreateTerminalBlock = @"RACViewChannelExampleCreateTerminalBlock";
  22. NSString * const RACViewChannelExampleKeyPath = @"RACViewChannelExampleKeyPath";
  23. NSString * const RACViewChannelExampleSetViewValueBlock = @"RACViewChannelExampleSetViewValueBlock";
  24. QuickConfigurationBegin(RACChannelExampleGroups)
  25. + (void)configure:(Configuration *)configuration {
  26. sharedExamples(RACChannelExamples, ^(QCKDSLSharedExampleContext exampleContext) {
  27. __block RACChannel * (^getChannel)(void);
  28. __block RACChannel *channel;
  29. id value1 = @"test value 1";
  30. id value2 = @"test value 2";
  31. id value3 = @"test value 3";
  32. NSArray *values = @[ value1, value2, value3 ];
  33. qck_beforeEach(^{
  34. getChannel = exampleContext()[RACChannelExampleCreateBlock];
  35. channel = getChannel();
  36. });
  37. qck_it(@"should not send any leadingTerminal value on subscription", ^{
  38. __block id receivedValue = nil;
  39. [channel.followingTerminal sendNext:value1];
  40. [channel.leadingTerminal subscribeNext:^(id x) {
  41. receivedValue = x;
  42. }];
  43. expect(receivedValue).to(beNil());
  44. [channel.followingTerminal sendNext:value2];
  45. expect(receivedValue).to(equal(value2));
  46. });
  47. qck_it(@"should send the latest followingTerminal value on subscription", ^{
  48. __block id receivedValue = nil;
  49. [channel.leadingTerminal sendNext:value1];
  50. [[channel.followingTerminal take:1] subscribeNext:^(id x) {
  51. receivedValue = x;
  52. }];
  53. expect(receivedValue).to(equal(value1));
  54. [channel.leadingTerminal sendNext:value2];
  55. [[channel.followingTerminal take:1] subscribeNext:^(id x) {
  56. receivedValue = x;
  57. }];
  58. expect(receivedValue).to(equal(value2));
  59. });
  60. qck_it(@"should send leadingTerminal values as they change", ^{
  61. NSMutableArray *receivedValues = [NSMutableArray array];
  62. [channel.leadingTerminal subscribeNext:^(id x) {
  63. [receivedValues addObject:x];
  64. }];
  65. [channel.followingTerminal sendNext:value1];
  66. [channel.followingTerminal sendNext:value2];
  67. [channel.followingTerminal sendNext:value3];
  68. expect(receivedValues).to(equal(values));
  69. });
  70. qck_it(@"should send followingTerminal values as they change", ^{
  71. [channel.leadingTerminal sendNext:value1];
  72. NSMutableArray *receivedValues = [NSMutableArray array];
  73. [channel.followingTerminal subscribeNext:^(id x) {
  74. [receivedValues addObject:x];
  75. }];
  76. [channel.leadingTerminal sendNext:value2];
  77. [channel.leadingTerminal sendNext:value3];
  78. expect(receivedValues).to(equal(values));
  79. });
  80. qck_it(@"should complete both signals when the leadingTerminal is completed", ^{
  81. __block BOOL completedLeft = NO;
  82. [channel.leadingTerminal subscribeCompleted:^{
  83. completedLeft = YES;
  84. }];
  85. __block BOOL completedRight = NO;
  86. [channel.followingTerminal subscribeCompleted:^{
  87. completedRight = YES;
  88. }];
  89. [channel.leadingTerminal sendCompleted];
  90. expect(@(completedLeft)).to(beTruthy());
  91. expect(@(completedRight)).to(beTruthy());
  92. });
  93. qck_it(@"should complete both signals when the followingTerminal is completed", ^{
  94. __block BOOL completedLeft = NO;
  95. [channel.leadingTerminal subscribeCompleted:^{
  96. completedLeft = YES;
  97. }];
  98. __block BOOL completedRight = NO;
  99. [channel.followingTerminal subscribeCompleted:^{
  100. completedRight = YES;
  101. }];
  102. [channel.followingTerminal sendCompleted];
  103. expect(@(completedLeft)).to(beTruthy());
  104. expect(@(completedRight)).to(beTruthy());
  105. });
  106. qck_it(@"should replay completion to new subscribers", ^{
  107. [channel.leadingTerminal sendCompleted];
  108. __block BOOL completedLeft = NO;
  109. [channel.leadingTerminal subscribeCompleted:^{
  110. completedLeft = YES;
  111. }];
  112. __block BOOL completedRight = NO;
  113. [channel.followingTerminal subscribeCompleted:^{
  114. completedRight = YES;
  115. }];
  116. expect(@(completedLeft)).to(beTruthy());
  117. expect(@(completedRight)).to(beTruthy());
  118. });
  119. });
  120. sharedExamples(RACViewChannelExamples, ^(QCKDSLSharedExampleContext exampleContext) {
  121. __block NSString *keyPath;
  122. __block NSObject * (^getView)(void);
  123. __block RACChannelTerminal * (^getTerminal)(NSObject *);
  124. __block void (^setViewValue)(NSObject *view, NSNumber *value);
  125. __block NSObject *testView;
  126. __block RACChannelTerminal *endpoint;
  127. qck_beforeEach(^{
  128. keyPath = exampleContext()[RACViewChannelExampleKeyPath];
  129. getTerminal = exampleContext()[RACViewChannelExampleCreateTerminalBlock];
  130. getView = exampleContext()[RACViewChannelExampleCreateViewBlock];
  131. setViewValue = exampleContext()[RACViewChannelExampleSetViewValueBlock];
  132. testView = getView();
  133. endpoint = getTerminal(testView);
  134. });
  135. qck_it(@"should not send changes made by the channel itself", ^{
  136. __block BOOL receivedNext = NO;
  137. [endpoint subscribeNext:^(id x) {
  138. receivedNext = YES;
  139. }];
  140. expect(@(receivedNext)).to(beFalsy());
  141. [endpoint sendNext:@0.1];
  142. expect(@(receivedNext)).to(beFalsy());
  143. [endpoint sendNext:@0.2];
  144. expect(@(receivedNext)).to(beFalsy());
  145. [endpoint sendCompleted];
  146. expect(@(receivedNext)).to(beFalsy());
  147. });
  148. qck_it(@"should not send progammatic changes made to the view", ^{
  149. __block BOOL receivedNext = NO;
  150. [endpoint subscribeNext:^(id x) {
  151. receivedNext = YES;
  152. }];
  153. expect(@(receivedNext)).to(beFalsy());
  154. [testView setValue:@0.1 forKeyPath:keyPath];
  155. expect(@(receivedNext)).to(beFalsy());
  156. [testView setValue:@0.2 forKeyPath:keyPath];
  157. expect(@(receivedNext)).to(beFalsy());
  158. });
  159. qck_it(@"should not have a starting value", ^{
  160. __block BOOL receivedNext = NO;
  161. [endpoint subscribeNext:^(id x) {
  162. receivedNext = YES;
  163. }];
  164. expect(@(receivedNext)).to(beFalsy());
  165. });
  166. qck_it(@"should send view changes", ^{
  167. __block NSString *received;
  168. [endpoint subscribeNext:^(id x) {
  169. received = x;
  170. }];
  171. setViewValue(testView, @0.1);
  172. expect(received).to(equal(@0.1));
  173. setViewValue(testView, @0.2);
  174. expect(received).to(equal(@0.2));
  175. });
  176. qck_it(@"should set values on the view", ^{
  177. [endpoint sendNext:@0.1];
  178. expect([testView valueForKeyPath:keyPath]).to(equal(@0.1));
  179. [endpoint sendNext:@0.2];
  180. expect([testView valueForKeyPath:keyPath]).to(equal(@0.2));
  181. });
  182. qck_it(@"should not echo changes back to the channel", ^{
  183. __block NSUInteger receivedCount = 0;
  184. [endpoint subscribeNext:^(id _) {
  185. receivedCount++;
  186. }];
  187. expect(@(receivedCount)).to(equal(@0));
  188. [endpoint sendNext:@0.1];
  189. expect(@(receivedCount)).to(equal(@0));
  190. setViewValue(testView, @0.2);
  191. expect(@(receivedCount)).to(equal(@1));
  192. });
  193. qck_it(@"should complete when the view deallocates", ^{
  194. __block BOOL deallocated = NO;
  195. __block BOOL completed = NO;
  196. @autoreleasepool {
  197. NSObject *view __attribute__((objc_precise_lifetime)) = getView();
  198. [view.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{
  199. deallocated = YES;
  200. }]];
  201. RACChannelTerminal *terminal = getTerminal(view);
  202. [terminal subscribeCompleted:^{
  203. completed = YES;
  204. }];
  205. expect(@(deallocated)).to(beFalsy());
  206. expect(@(completed)).to(beFalsy());
  207. }
  208. expect(@(deallocated)).to(beTruthy());
  209. expect(@(completed)).to(beTruthy());
  210. });
  211. qck_it(@"should deallocate after the view deallocates", ^{
  212. __block BOOL viewDeallocated = NO;
  213. __block BOOL terminalDeallocated = NO;
  214. @autoreleasepool {
  215. NSObject *view __attribute__((objc_precise_lifetime)) = getView();
  216. [view.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{
  217. viewDeallocated = YES;
  218. }]];
  219. RACChannelTerminal *terminal = getTerminal(view);
  220. [terminal.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{
  221. terminalDeallocated = YES;
  222. }]];
  223. expect(@(viewDeallocated)).to(beFalsy());
  224. expect(@(terminalDeallocated)).to(beFalsy());
  225. }
  226. expect(@(viewDeallocated)).to(beTruthy());
  227. expect(@(terminalDeallocated)).toEventually(beTruthy());
  228. });
  229. });
  230. }
  231. QuickConfigurationEnd