FEventTester.m 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. /*
  2. * Copyright 2017 Google
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #import "FirebaseDatabase/Tests/Helpers/FEventTester.h"
  17. #import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseReference.h"
  18. #import "FirebaseDatabase/Sources/Utilities/Tuples/FTupleBoolBlock.h"
  19. #import "FirebaseDatabase/Tests/Helpers/FTestHelpers.h"
  20. #import "FirebaseDatabase/Tests/Helpers/FTupleEventTypeString.h"
  21. #import "FirebaseDatabase/Tests/Helpers/SenTest+FWaiter.h"
  22. @implementation FEventTester
  23. @synthesize lookingFor;
  24. @synthesize callbacksCalled;
  25. @synthesize from;
  26. @synthesize errors;
  27. @synthesize seenFirebaseLocations;
  28. @synthesize initializationEvents;
  29. @synthesize actualPathsAndEvents;
  30. - (id)initFrom:(XCTestCase*)elsewhere {
  31. self = [super init];
  32. if (self) {
  33. self.seenFirebaseLocations = [[NSMutableDictionary alloc] init];
  34. self.initializationEvents = 0;
  35. self.lookingFor = [[NSMutableArray alloc] init];
  36. self.actualPathsAndEvents = [[NSMutableArray alloc] init];
  37. self.from = elsewhere;
  38. self.callbacksCalled = 0;
  39. }
  40. return self;
  41. }
  42. - (void)addLookingFor:(NSArray*)l {
  43. // expect them in the order they're given to us
  44. [self.lookingFor addObjectsFromArray:l];
  45. // see notes on ordering of listens in init.spec.js
  46. NSArray* toListen = [l sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
  47. FTupleEventTypeString* a = obj1;
  48. FTupleEventTypeString* b = obj2;
  49. NSUInteger lenA = [a.firebase description].length;
  50. NSUInteger lenB = [b.firebase description].length;
  51. if (lenA < lenB) {
  52. return NSOrderedAscending;
  53. } else if (lenA == lenB) {
  54. return NSOrderedSame;
  55. } else {
  56. return NSOrderedDescending;
  57. }
  58. }];
  59. for (FTupleEventTypeString* fevts in toListen) {
  60. if (![self.seenFirebaseLocations objectForKey:[fevts.firebase description]]) {
  61. fevts.vvcallback = [self listenOnPath:fevts.firebase];
  62. fevts.initialized = NO;
  63. [self.seenFirebaseLocations setObject:fevts forKey:[fevts.firebase description]];
  64. }
  65. }
  66. }
  67. - (void)unregister {
  68. for (FTupleEventTypeString* fevts in self.lookingFor) {
  69. if (fevts.vvcallback) {
  70. fevts.vvcallback();
  71. }
  72. }
  73. [self.lookingFor removeAllObjects];
  74. }
  75. - (fbt_void_void)listenOnPath:(FIRDatabaseReference*)path {
  76. FIRDatabaseHandle removedHandle =
  77. [path observeEventType:FIRDataEventTypeChildRemoved
  78. withBlock:[self makeEventCallback:FIRDataEventTypeChildRemoved]];
  79. FIRDatabaseHandle addedHandle =
  80. [path observeEventType:FIRDataEventTypeChildAdded
  81. withBlock:[self makeEventCallback:FIRDataEventTypeChildAdded]];
  82. FIRDatabaseHandle movedHandle =
  83. [path observeEventType:FIRDataEventTypeChildMoved
  84. withBlock:[self makeEventCallback:FIRDataEventTypeChildMoved]];
  85. FIRDatabaseHandle changedHandle =
  86. [path observeEventType:FIRDataEventTypeChildChanged
  87. withBlock:[self makeEventCallback:FIRDataEventTypeChildChanged]];
  88. FIRDatabaseHandle valueHandle =
  89. [path observeEventType:FIRDataEventTypeValue
  90. withBlock:[self makeEventCallback:FIRDataEventTypeValue]];
  91. fbt_void_void cb = ^() {
  92. [path removeObserverWithHandle:removedHandle];
  93. [path removeObserverWithHandle:addedHandle];
  94. [path removeObserverWithHandle:movedHandle];
  95. [path removeObserverWithHandle:changedHandle];
  96. [path removeObserverWithHandle:valueHandle];
  97. };
  98. return [cb copy];
  99. }
  100. - (void)wait {
  101. [self
  102. waitUntil:^BOOL {
  103. return self.actualPathsAndEvents.count >= self.lookingFor.count;
  104. }
  105. timeout:kFirebaseTestTimeout];
  106. for (int i = 0; i < self.lookingFor.count; ++i) {
  107. FTupleEventTypeString* target = [self.lookingFor objectAtIndex:i];
  108. FTupleEventTypeString* recvd = [self.actualPathsAndEvents objectAtIndex:i];
  109. XCTAssertTrue([target isEqualTo:recvd], @"Expected %@ to match %@", target, recvd);
  110. }
  111. if (self.actualPathsAndEvents.count > self.lookingFor.count) {
  112. NSLog(@"Too many events: %@", self.actualPathsAndEvents);
  113. XCTFail(@"Received too many events");
  114. }
  115. }
  116. - (void)waitForInitialization {
  117. [self
  118. waitUntil:^BOOL {
  119. for (FTupleEventTypeString* evt in [self.seenFirebaseLocations allValues]) {
  120. if (!evt.initialized) {
  121. return NO;
  122. }
  123. }
  124. // splice out all of the initialization events
  125. NSRange theRange;
  126. theRange.location = 0;
  127. theRange.length = self.initializationEvents;
  128. [self.actualPathsAndEvents removeObjectsInRange:theRange];
  129. return YES;
  130. }
  131. timeout:kFirebaseTestTimeout];
  132. }
  133. - (fbt_void_datasnapshot)makeEventCallback:(FIRDataEventType)type {
  134. fbt_void_datasnapshot cb = ^(FIRDataSnapshot* snap) {
  135. FIRDatabaseReference* ref = snap.ref;
  136. NSString* name = nil;
  137. if (type != FIRDataEventTypeValue) {
  138. ref = ref.parent;
  139. name = snap.key;
  140. }
  141. FTupleEventTypeString* evt = [[FTupleEventTypeString alloc] initWithFirebase:ref
  142. withEvent:type
  143. withString:name];
  144. [self.actualPathsAndEvents addObject:evt];
  145. NSLog(@"Adding event: %@ (%@)", evt, [snap value]);
  146. FTupleEventTypeString* targetEvt = [self.seenFirebaseLocations objectForKey:[ref description]];
  147. if (targetEvt && !targetEvt.initialized) {
  148. self.initializationEvents++;
  149. if (type == FIRDataEventTypeValue) {
  150. targetEvt.initialized = YES;
  151. }
  152. }
  153. };
  154. return [cb copy];
  155. }
  156. - (void)failWithException:(NSException*)anException {
  157. // TODO: FIX
  158. @throw anException;
  159. }
  160. @end