RACSubscriberSpec.m 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. //
  2. // RACSubscriberSpec.m
  3. // ReactiveCocoa
  4. //
  5. // Created by Justin Spahr-Summers on 2012-11-27.
  6. // Copyright (c) 2012 GitHub, Inc. All rights reserved.
  7. //
  8. #import <Quick/Quick.h>
  9. #import <Nimble/Nimble.h>
  10. #import "RACSubscriberExamples.h"
  11. #import "RACSubscriber.h"
  12. #import "RACSubscriber+Private.h"
  13. #import <libkern/OSAtomic.h>
  14. QuickSpecBegin(RACSubscriberSpec)
  15. __block RACSubscriber *subscriber;
  16. __block NSMutableArray *values;
  17. __block volatile BOOL finished;
  18. __block volatile int32_t nextsAfterFinished;
  19. __block BOOL success;
  20. __block NSError *error;
  21. qck_beforeEach(^{
  22. values = [NSMutableArray array];
  23. finished = NO;
  24. nextsAfterFinished = 0;
  25. success = YES;
  26. error = nil;
  27. subscriber = [RACSubscriber subscriberWithNext:^(id value) {
  28. if (finished) OSAtomicIncrement32Barrier(&nextsAfterFinished);
  29. [values addObject:value];
  30. } error:^(NSError *e) {
  31. error = e;
  32. success = NO;
  33. } completed:^{
  34. success = YES;
  35. }];
  36. });
  37. qck_itBehavesLike(RACSubscriberExamples, ^{
  38. return @{
  39. RACSubscriberExampleSubscriber: subscriber,
  40. RACSubscriberExampleValuesReceivedBlock: [^{ return [values copy]; } copy],
  41. RACSubscriberExampleErrorReceivedBlock: [^{ return error; } copy],
  42. RACSubscriberExampleSuccessBlock: [^{ return success; } copy]
  43. };
  44. });
  45. qck_describe(@"finishing", ^{
  46. __block void (^sendValues)(void);
  47. __block BOOL expectedSuccess;
  48. __block dispatch_group_t dispatchGroup;
  49. __block dispatch_queue_t concurrentQueue;
  50. qck_beforeEach(^{
  51. dispatchGroup = dispatch_group_create();
  52. expect(dispatchGroup).notTo(beNil());
  53. concurrentQueue = dispatch_queue_create("org.reactivecocoa.ReactiveCocoa.RACSubscriberSpec", DISPATCH_QUEUE_CONCURRENT);
  54. expect(concurrentQueue).notTo(beNil());
  55. dispatch_suspend(concurrentQueue);
  56. sendValues = [^{
  57. for (NSUInteger i = 0; i < 15; i++) {
  58. dispatch_group_async(dispatchGroup, concurrentQueue, ^{
  59. [subscriber sendNext:@(i)];
  60. });
  61. }
  62. } copy];
  63. sendValues();
  64. });
  65. qck_afterEach(^{
  66. sendValues();
  67. dispatch_resume(concurrentQueue);
  68. // Time out after one second.
  69. dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC));
  70. expect(@(dispatch_group_wait(dispatchGroup, time))).to(equal(@0));
  71. dispatchGroup = NULL;
  72. concurrentQueue = NULL;
  73. expect(@(nextsAfterFinished)).to(equal(@0));
  74. if (expectedSuccess) {
  75. expect(@(success)).to(beTruthy());
  76. expect(error).to(beNil());
  77. } else {
  78. expect(@(success)).to(beFalsy());
  79. }
  80. });
  81. qck_it(@"should never invoke next after sending completed", ^{
  82. expectedSuccess = YES;
  83. dispatch_group_async(dispatchGroup, concurrentQueue, ^{
  84. [subscriber sendCompleted];
  85. finished = YES;
  86. OSMemoryBarrier();
  87. });
  88. });
  89. qck_it(@"should never invoke next after sending error", ^{
  90. expectedSuccess = NO;
  91. dispatch_group_async(dispatchGroup, concurrentQueue, ^{
  92. [subscriber sendError:nil];
  93. finished = YES;
  94. OSMemoryBarrier();
  95. });
  96. });
  97. });
  98. QuickSpecEnd