FEventTester.m 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  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 "FEventTester.h"
  17. #import <FirebaseDatabase/FIRDatabaseReference.h>
  18. #import "FTupleBoolBlock.h"
  19. #import "FTupleEventTypeString.h"
  20. #import "FTestHelpers.h"
  21. #import "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. {
  32. self = [super init];
  33. if (self) {
  34. self.seenFirebaseLocations = [[NSMutableDictionary alloc] init];
  35. self.initializationEvents = 0;
  36. self.lookingFor = [[NSMutableArray alloc] init];
  37. self.actualPathsAndEvents = [[NSMutableArray alloc] init];
  38. self.from = elsewhere;
  39. self.callbacksCalled = 0;
  40. }
  41. return self;
  42. }
  43. - (void) addLookingFor:(NSArray *)l {
  44. // expect them in the order they're given to us
  45. [self.lookingFor addObjectsFromArray:l];
  46. // see notes on ordering of listens in init.spec.js
  47. NSArray* toListen = [l sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
  48. FTupleEventTypeString* a = obj1;
  49. FTupleEventTypeString* b = obj2;
  50. NSUInteger lenA = [a.firebase description].length;
  51. NSUInteger lenB = [b.firebase description].length;
  52. if (lenA < lenB) {
  53. return NSOrderedAscending;
  54. } else if (lenA == lenB) {
  55. return NSOrderedSame;
  56. } else {
  57. return NSOrderedDescending;
  58. }
  59. }];
  60. for(FTupleEventTypeString* fevts in toListen) {
  61. if(! [self.seenFirebaseLocations objectForKey:[fevts.firebase description]]) {
  62. fevts.vvcallback = [self listenOnPath:fevts.firebase];
  63. fevts.initialized = NO;
  64. [self.seenFirebaseLocations setObject:fevts forKey:[fevts.firebase description]];
  65. }
  66. }
  67. }
  68. - (void) unregister {
  69. for(FTupleEventTypeString* fevts in self.lookingFor) {
  70. if (fevts.vvcallback) {
  71. fevts.vvcallback();
  72. }
  73. }
  74. [self.lookingFor removeAllObjects];
  75. }
  76. - (fbt_void_void) listenOnPath:(FIRDatabaseReference *)path {
  77. FIRDatabaseHandle removedHandle = [path observeEventType:FIRDataEventTypeChildRemoved withBlock:[self makeEventCallback:FIRDataEventTypeChildRemoved]];
  78. FIRDatabaseHandle addedHandle = [path observeEventType:FIRDataEventTypeChildAdded withBlock:[self makeEventCallback:FIRDataEventTypeChildAdded]];
  79. FIRDatabaseHandle movedHandle = [path observeEventType:FIRDataEventTypeChildMoved withBlock:[self makeEventCallback:FIRDataEventTypeChildMoved]];
  80. FIRDatabaseHandle changedHandle = [path observeEventType:FIRDataEventTypeChildChanged withBlock:[self makeEventCallback:FIRDataEventTypeChildChanged]];
  81. FIRDatabaseHandle valueHandle = [path observeEventType:FIRDataEventTypeValue withBlock:[self makeEventCallback:FIRDataEventTypeValue]];
  82. fbt_void_void cb = ^() {
  83. [path removeObserverWithHandle:removedHandle];
  84. [path removeObserverWithHandle:addedHandle];
  85. [path removeObserverWithHandle:movedHandle];
  86. [path removeObserverWithHandle:changedHandle];
  87. [path removeObserverWithHandle:valueHandle];
  88. };
  89. return [cb copy];
  90. }
  91. - (void) wait {
  92. [self waitUntil:^BOOL{
  93. return self.actualPathsAndEvents.count >= self.lookingFor.count;
  94. } timeout:kFirebaseTestTimeout];
  95. for (int i = 0; i < self.lookingFor.count; ++i) {
  96. FTupleEventTypeString* target = [self.lookingFor objectAtIndex:i];
  97. FTupleEventTypeString* recvd = [self.actualPathsAndEvents objectAtIndex:i];
  98. XCTAssertTrue([target isEqualTo:recvd], @"Expected %@ to match %@", target, recvd);
  99. }
  100. if (self.actualPathsAndEvents.count > self.lookingFor.count) {
  101. NSLog(@"Too many events: %@", self.actualPathsAndEvents);
  102. XCTFail(@"Received too many events");
  103. }
  104. }
  105. - (void) waitForInitialization {
  106. [self waitUntil:^BOOL{
  107. for (FTupleEventTypeString* evt in [self.seenFirebaseLocations allValues]) {
  108. if (!evt.initialized) {
  109. return NO;
  110. }
  111. }
  112. // splice out all of the initialization events
  113. NSRange theRange;
  114. theRange.location = 0;
  115. theRange.length = self.initializationEvents;
  116. [self.actualPathsAndEvents removeObjectsInRange:theRange];
  117. return YES;
  118. } timeout:kFirebaseTestTimeout];
  119. }
  120. - (fbt_void_datasnapshot) makeEventCallback:(FIRDataEventType)type {
  121. fbt_void_datasnapshot cb = ^(FIRDataSnapshot * snap) {
  122. FIRDatabaseReference * ref = snap.ref;
  123. NSString* name = nil;
  124. if (type != FIRDataEventTypeValue) {
  125. ref = ref.parent;
  126. name = snap.key;
  127. }
  128. FTupleEventTypeString* evt = [[FTupleEventTypeString alloc] initWithFirebase:ref withEvent:type withString:name];
  129. [self.actualPathsAndEvents addObject:evt];
  130. NSLog(@"Adding event: %@ (%@)", evt, [snap value]);
  131. FTupleEventTypeString* targetEvt = [self.seenFirebaseLocations objectForKey:[ref description]];
  132. if (targetEvt && !targetEvt.initialized) {
  133. self.initializationEvents++;
  134. if (type == FIRDataEventTypeValue) {
  135. targetEvt.initialized = YES;
  136. }
  137. }
  138. };
  139. return [cb copy];
  140. }
  141. - (void) failWithException:(NSException *) anException {
  142. //TODO: FIX
  143. @throw anException;
  144. }
  145. @end