FIRDatabaseQueryTests.m 106 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059
  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 "FIRDatabaseQueryTests.h"
  17. #import "FIRDatabaseQuery_Private.h"
  18. #import "FQuerySpec.h"
  19. #import "FTestExpectations.h"
  20. @implementation FIRDatabaseQueryTests
  21. - (void)testCanCreateBasicQueries {
  22. // Just make sure none of these throw anything
  23. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  24. [ref queryLimitedToFirst:10];
  25. [ref queryLimitedToLast:10];
  26. [[ref queryOrderedByKey] queryStartingAtValue:@"foo"];
  27. [[ref queryOrderedByKey] queryEndingAtValue:@"foo"];
  28. [[ref queryOrderedByKey] queryEqualToValue:@"foo"];
  29. [[ref queryOrderedByChild:@"index"] queryStartingAtValue:@YES];
  30. [[ref queryOrderedByChild:@"index"] queryStartingAtValue:@1];
  31. [[ref queryOrderedByChild:@"index"] queryStartingAtValue:@"foo"];
  32. [[ref queryOrderedByChild:@"index"] queryStartingAtValue:nil];
  33. [[ref queryOrderedByChild:@"index"] queryEndingAtValue:@YES];
  34. [[ref queryOrderedByChild:@"index"] queryEndingAtValue:@1];
  35. [[ref queryOrderedByChild:@"index"] queryEndingAtValue:@"foo"];
  36. [[ref queryOrderedByChild:@"index"] queryEndingAtValue:nil];
  37. [[ref queryOrderedByChild:@"index"] queryEqualToValue:@YES];
  38. [[ref queryOrderedByChild:@"index"] queryEqualToValue:@1];
  39. [[ref queryOrderedByChild:@"index"] queryEqualToValue:@"foo"];
  40. [[ref queryOrderedByChild:@"index"] queryEqualToValue:nil];
  41. [[ref queryOrderedByPriority] queryStartingAtValue:@1];
  42. [[ref queryOrderedByPriority] queryStartingAtValue:@"foo"];
  43. [[ref queryOrderedByPriority] queryStartingAtValue:nil];
  44. [[ref queryOrderedByPriority] queryEndingAtValue:@1];
  45. [[ref queryOrderedByPriority] queryEndingAtValue:@"foo"];
  46. [[ref queryOrderedByPriority] queryEndingAtValue:nil];
  47. [[ref queryOrderedByPriority] queryEqualToValue:@1];
  48. [[ref queryOrderedByPriority] queryEqualToValue:@"foo"];
  49. [[ref queryOrderedByPriority] queryEqualToValue:nil];
  50. }
  51. - (void)testInvalidQueryParams {
  52. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  53. XCTAssertThrows([[ref queryLimitedToFirst:100] queryLimitedToFirst:100]);
  54. XCTAssertThrows([[ref queryLimitedToFirst:100] queryLimitedToLast:100]);
  55. XCTAssertThrows([[ref queryLimitedToLast:100] queryLimitedToFirst:100]);
  56. XCTAssertThrows([[ref queryLimitedToLast:100] queryLimitedToLast:100]);
  57. XCTAssertThrows([[ref queryOrderedByPriority] queryOrderedByPriority]);
  58. XCTAssertThrows([[ref queryOrderedByPriority] queryOrderedByKey]);
  59. XCTAssertThrows([[ref queryOrderedByPriority] queryOrderedByChild:@"foo"]);
  60. XCTAssertThrows([[ref queryOrderedByPriority] queryOrderedByValue]);
  61. XCTAssertThrows([[ref queryOrderedByKey] queryOrderedByPriority]);
  62. XCTAssertThrows([[ref queryOrderedByKey] queryOrderedByKey]);
  63. XCTAssertThrows([[ref queryOrderedByKey] queryOrderedByChild:@"foo"]);
  64. XCTAssertThrows([[ref queryOrderedByKey] queryOrderedByValue]);
  65. XCTAssertThrows([[ref queryOrderedByChild:@"foo"] queryOrderedByPriority]);
  66. XCTAssertThrows([[ref queryOrderedByChild:@"foo"] queryOrderedByKey]);
  67. XCTAssertThrows([[ref queryOrderedByChild:@"foo"] queryOrderedByChild:@"foo"]);
  68. XCTAssertThrows([[ref queryOrderedByChild:@"foo"] queryOrderedByValue]);
  69. XCTAssertThrows([[ref queryOrderedByValue] queryOrderedByPriority]);
  70. XCTAssertThrows([[ref queryOrderedByValue] queryOrderedByKey]);
  71. XCTAssertThrows([[ref queryOrderedByValue] queryOrderedByChild:@"foo"]);
  72. XCTAssertThrows([[ref queryOrderedByValue] queryOrderedByValue]);
  73. XCTAssertThrows([[ref queryStartingAtValue:@"foo"] queryStartingAtValue:@"foo"]);
  74. XCTAssertThrows([[ref queryStartingAtValue:@"foo"] queryEqualToValue:@"foo"]);
  75. XCTAssertThrows([[ref queryEndingAtValue:@"foo"] queryEndingAtValue:@"foo"]);
  76. XCTAssertThrows([[ref queryEndingAtValue:@"foo"] queryEqualToValue:@"foo"]);
  77. XCTAssertThrows([[ref queryEqualToValue:@"foo"] queryStartingAtValue:@"foo"]);
  78. XCTAssertThrows([[ref queryEqualToValue:@"foo"] queryEndingAtValue:@"foo"]);
  79. XCTAssertThrows([[ref queryEqualToValue:@"foo"] queryEqualToValue:@"foo"]);
  80. XCTAssertThrows([[ref queryOrderedByKey] queryStartingAtValue:@"foo" childKey:@"foo"]);
  81. XCTAssertThrows([[ref queryOrderedByKey] queryEndingAtValue:@"foo" childKey:@"foo"]);
  82. XCTAssertThrows([[ref queryOrderedByKey] queryEqualToValue:@"foo" childKey:@"foo"]);
  83. XCTAssertThrows([[ref queryOrderedByKey] queryStartingAtValue:@1 childKey:@"foo"]);
  84. XCTAssertThrows([[ref queryOrderedByKey] queryStartingAtValue:@YES]);
  85. XCTAssertThrows([[ref queryOrderedByKey] queryEndingAtValue:@1]);
  86. XCTAssertThrows([[ref queryOrderedByKey] queryEndingAtValue:@YES]);
  87. XCTAssertThrows([[ref queryOrderedByKey] queryStartingAtValue:nil]);
  88. XCTAssertThrows([[ref queryOrderedByKey] queryEndingAtValue:nil]);
  89. XCTAssertThrows([[ref queryOrderedByKey] queryEqualToValue:nil]);
  90. XCTAssertThrows([[ref queryStartingAtValue:@"foo" childKey:@"foo"] queryOrderedByKey]);
  91. XCTAssertThrows([[ref queryEndingAtValue:@"foo" childKey:@"foo"] queryOrderedByKey]);
  92. XCTAssertThrows([[ref queryEqualToValue:@"foo" childKey:@"foo"] queryOrderedByKey]);
  93. XCTAssertThrows([[ref queryStartingAtValue:@1] queryOrderedByKey]);
  94. XCTAssertThrows([[ref queryStartingAtValue:@YES] queryOrderedByKey]);
  95. XCTAssertThrows([[ref queryEndingAtValue:@1] queryOrderedByKey]);
  96. XCTAssertThrows([[ref queryEndingAtValue:@YES] queryOrderedByKey]);
  97. XCTAssertThrows([ref queryStartingAtValue:@[]]);
  98. XCTAssertThrows([ref queryStartingAtValue:@{}]);
  99. XCTAssertThrows([ref queryEndingAtValue:@[]]);
  100. XCTAssertThrows([ref queryEndingAtValue:@{}]);
  101. XCTAssertThrows([ref queryEqualToValue:@[]]);
  102. XCTAssertThrows([ref queryEqualToValue:@{}]);
  103. XCTAssertThrows([[ref queryOrderedByKey] queryOrderedByPriority],
  104. @"Cannot call orderBy multiple times");
  105. XCTAssertThrows([[ref queryOrderedByChild:@"foo"] queryOrderedByPriority],
  106. @"Cannot call orderBy multiple times");
  107. XCTAssertThrows([[ref queryOrderedByKey] queryOrderedByKey],
  108. @"Cannot call orderBy multiple times");
  109. XCTAssertThrows([[ref queryOrderedByChild:@"foo"] queryOrderedByKey],
  110. @"Cannot call orderBy multiple times");
  111. XCTAssertThrows([[ref queryOrderedByKey] queryOrderedByChild:@"foo"],
  112. @"Cannot call orderBy multiple times");
  113. XCTAssertThrows([[ref queryOrderedByChild:@"foo"] queryOrderedByChild:@"foo"],
  114. @"Cannot call orderBy multiple times");
  115. XCTAssertThrows([[ref queryOrderedByKey] queryStartingAtValue:@"a" childKey:@"b"],
  116. @"Cannot specify starting child name when ordering by key.");
  117. XCTAssertThrows([[ref queryOrderedByKey] queryEndingAtValue:@"a" childKey:@"b"],
  118. @"Cannot specify ending child name when ordering by key.");
  119. XCTAssertThrows([[ref queryOrderedByKey] queryEqualToValue:@"a" childKey:@"b"],
  120. @"Cannot specify equalTo child name when ordering by key.");
  121. XCTAssertThrows([[ref queryOrderedByPriority] queryStartingAtValue:@YES],
  122. @"Can't pass booleans as start/end when using priority index.");
  123. XCTAssertThrows([[ref queryOrderedByPriority] queryEndingAtValue:@NO],
  124. @"Can't pass booleans as start/end when using priority index.");
  125. XCTAssertThrows([[ref queryOrderedByPriority] queryEqualToValue:@YES],
  126. @"Can't pass booleans as start/end when using priority index.");
  127. }
  128. - (void)testLimitRanges {
  129. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  130. XCTAssertThrows([ref queryLimitedToLast:0], @"Can't pass zero as limit");
  131. XCTAssertThrows([ref queryLimitedToFirst:0], @"Can't pass zero as limit");
  132. XCTAssertThrows([ref queryLimitedToLast:0], @"Can't pass zero as limit");
  133. uint64_t MAX_ALLOWED_VALUE = (uint64_t)(1l << 31) - 1;
  134. [ref queryLimitedToFirst:(NSUInteger)MAX_ALLOWED_VALUE];
  135. [ref queryLimitedToLast:(NSUInteger)MAX_ALLOWED_VALUE];
  136. XCTAssertThrows([ref queryLimitedToFirst:(NSUInteger)(MAX_ALLOWED_VALUE + 1)],
  137. @"Can't pass limits that don't fit into 32 bit signed integer range");
  138. XCTAssertThrows([ref queryLimitedToLast:(NSUInteger)(MAX_ALLOWED_VALUE + 1)],
  139. @"Can't pass limits that don't fit into 32 bit signed integer range");
  140. }
  141. - (void)testInvalidKeys {
  142. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  143. NSArray* badKeys = @[
  144. @".test", @"test.", @"fo$o", @"[what", @"ever]", @"ha#sh", @"/thing", @"th/ing", @"thing/"
  145. ];
  146. for (NSString* badKey in badKeys) {
  147. XCTAssertThrows([[ref queryOrderedByPriority] queryStartingAtValue:nil childKey:badKey],
  148. @"Setting bad key");
  149. XCTAssertThrows([[ref queryOrderedByPriority] queryEndingAtValue:nil childKey:badKey],
  150. @"Setting bad key");
  151. }
  152. }
  153. - (void)testOffCanBeCalledOnDefault {
  154. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  155. __block BOOL called = NO;
  156. FIRDatabaseQuery* query = [ref queryLimitedToLast:5];
  157. [query observeEventType:FIRDataEventTypeValue
  158. withBlock:^(FIRDataSnapshot* snapshot) {
  159. if (called) {
  160. XCTFail(@"Should not be called twice");
  161. } else {
  162. called = YES;
  163. }
  164. }];
  165. [ref setValue:@{@"a" : @5, @"b" : @6}];
  166. [self waitUntil:^BOOL {
  167. return called;
  168. }];
  169. called = NO;
  170. [ref removeAllObservers];
  171. __block BOOL complete = NO;
  172. [ref setValue:@{@"a" : @6, @"b" : @7}
  173. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  174. complete = YES;
  175. }];
  176. [self waitUntil:^BOOL {
  177. return complete;
  178. }];
  179. XCTAssertFalse(called, @"Should not have been called again");
  180. }
  181. - (void)testOffCanBeCalledOnHandle {
  182. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  183. __block BOOL called = NO;
  184. FIRDatabaseQuery* query = [ref queryLimitedToLast:5];
  185. FIRDatabaseHandle handle = [query observeEventType:FIRDataEventTypeValue
  186. withBlock:^(FIRDataSnapshot* snapshot) {
  187. if (called) {
  188. XCTFail(@"Should not be called twice");
  189. } else {
  190. called = YES;
  191. }
  192. }];
  193. [ref setValue:@{@"a" : @5, @"b" : @6}];
  194. [self waitUntil:^BOOL {
  195. return called;
  196. }];
  197. called = NO;
  198. [ref removeObserverWithHandle:handle];
  199. __block BOOL complete = NO;
  200. [ref setValue:@{@"a" : @6, @"b" : @7}
  201. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  202. complete = YES;
  203. }];
  204. [self waitUntil:^BOOL {
  205. return complete;
  206. }];
  207. XCTAssertFalse(called, @"Should not have been called again");
  208. }
  209. - (void)testOffCanBeCalledOnSpecificQuery {
  210. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  211. __block BOOL called = NO;
  212. FIRDatabaseQuery* query = [ref queryLimitedToLast:5];
  213. FIRDatabaseHandle handle = [query observeEventType:FIRDataEventTypeValue
  214. withBlock:^(FIRDataSnapshot* snapshot) {
  215. if (called) {
  216. XCTFail(@"Should not be called twice");
  217. } else {
  218. called = YES;
  219. }
  220. }];
  221. [ref setValue:@{@"a" : @5, @"b" : @6}];
  222. [self waitUntil:^BOOL {
  223. return called;
  224. }];
  225. called = NO;
  226. [query removeObserverWithHandle:handle];
  227. __block BOOL complete = NO;
  228. [ref setValue:@{@"a" : @6, @"b" : @7}
  229. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  230. complete = YES;
  231. }];
  232. [self waitUntil:^BOOL {
  233. return complete;
  234. }];
  235. XCTAssertFalse(called, @"Should not have been called again");
  236. }
  237. - (void)testOffCanBeCalledOnMultipleQueries {
  238. FIRDatabaseQuery* query = [[FTestHelpers getRandomNode] queryLimitedToFirst:10];
  239. FIRDatabaseHandle handle1 = [query observeEventType:FIRDataEventTypeValue
  240. withBlock:^(FIRDataSnapshot* snapshot){
  241. }];
  242. FIRDatabaseHandle handle2 = [query observeEventType:FIRDataEventTypeValue
  243. withBlock:^(FIRDataSnapshot* snapshot){
  244. }];
  245. [query removeObserverWithHandle:handle1];
  246. [query removeObserverWithHandle:handle2];
  247. }
  248. - (void)testOffCanBeCalledWithoutHandle {
  249. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  250. __block BOOL called1 = NO;
  251. __block BOOL called2 = NO;
  252. FIRDatabaseQuery* query = [ref queryLimitedToLast:5];
  253. [ref observeEventType:FIRDataEventTypeValue
  254. withBlock:^(FIRDataSnapshot* snapshot) {
  255. called1 = YES;
  256. }];
  257. [query observeEventType:FIRDataEventTypeValue
  258. withBlock:^(FIRDataSnapshot* snapshot) {
  259. called2 = YES;
  260. }];
  261. [ref setValue:@{@"a" : @5, @"b" : @6}];
  262. [self waitUntil:^BOOL {
  263. return called1 && called2;
  264. }];
  265. called1 = NO;
  266. called2 = NO;
  267. [ref removeAllObservers];
  268. __block BOOL complete = NO;
  269. [ref setValue:@{@"a" : @6, @"b" : @7}
  270. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  271. complete = YES;
  272. }];
  273. [self waitUntil:^BOOL {
  274. return complete;
  275. }];
  276. XCTAssertFalse(called1 || called2, @"Should not have called either callback");
  277. }
  278. - (void)testEnsureOnly5ItemsAreKept {
  279. __block FIRDataSnapshot* snap = nil;
  280. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  281. FIRDatabaseQuery* query = [ref queryLimitedToLast:5];
  282. __block int count = 0;
  283. [query observeEventType:FIRDataEventTypeValue
  284. withBlock:^(FIRDataSnapshot* snapshot) {
  285. snap = snapshot;
  286. count++;
  287. }];
  288. [ref setValue:nil];
  289. for (int i = 0; i < 10; ++i) {
  290. [[ref childByAutoId] setValue:[NSNumber numberWithInt:i]];
  291. }
  292. [self waitUntil:^BOOL {
  293. // The initial set triggers the callback, so we need to wait for 11 events
  294. return count == 11;
  295. }];
  296. count = 5;
  297. for (FIRDataSnapshot* snapshot in snap.children) {
  298. NSNumber* num = [snapshot value];
  299. NSNumber* current = [NSNumber numberWithInt:count];
  300. XCTAssertTrue([num isEqualToNumber:current], @"Expect children in order");
  301. count++;
  302. }
  303. XCTAssertTrue(count == 10, @"Expected 5 children");
  304. }
  305. - (void)testOnlyLast5SentFromServer {
  306. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  307. __block int count = 0;
  308. [ref setValue:nil];
  309. for (int i = 0; i < 10; ++i) {
  310. [[ref childByAutoId] setValue:[NSNumber numberWithInt:i]
  311. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  312. count++;
  313. }];
  314. }
  315. [self waitUntil:^BOOL {
  316. return count == 10;
  317. }];
  318. FIRDatabaseQuery* query = [ref queryLimitedToLast:5];
  319. count = 5;
  320. [query observeEventType:FIRDataEventTypeValue
  321. withBlock:^(FIRDataSnapshot* snapshot) {
  322. for (FIRDataSnapshot* child in snapshot.children) {
  323. NSNumber* num = [child value];
  324. NSNumber* current = [NSNumber numberWithInt:count];
  325. XCTAssertTrue([num isEqualToNumber:current], @"Expect children to be in order");
  326. count++;
  327. }
  328. }];
  329. [self waitUntil:^BOOL {
  330. return count == 10;
  331. }];
  332. }
  333. - (void)testVariousLimits {
  334. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  335. FTestExpectations* expectations = [[FTestExpectations alloc] initFrom:self];
  336. [expectations addQuery:[ref queryLimitedToLast:1] withExpectation:@{@"c" : @3}];
  337. [expectations
  338. addQuery:[[[ref queryOrderedByPriority] queryEndingAtValue:nil] queryLimitedToLast:1]
  339. withExpectation:@{@"c" : @3}];
  340. [expectations
  341. addQuery:[[[ref queryOrderedByPriority] queryEndingAtValue:nil] queryLimitedToLast:2]
  342. withExpectation:@{@"b" : @2, @"c" : @3}];
  343. [expectations
  344. addQuery:[[[ref queryOrderedByPriority] queryEndingAtValue:nil] queryLimitedToLast:3]
  345. withExpectation:@{@"a" : @1, @"b" : @2, @"c" : @3}];
  346. [expectations
  347. addQuery:[[[ref queryOrderedByPriority] queryEndingAtValue:nil] queryLimitedToLast:4]
  348. withExpectation:@{@"a" : @1, @"b" : @2, @"c" : @3}];
  349. __block BOOL ready = NO;
  350. [ref setValue:@{@"a" : @1, @"b" : @2, @"c" : @3}
  351. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  352. ready = YES;
  353. }];
  354. [self waitUntil:^BOOL {
  355. return ready;
  356. }];
  357. [expectations validate];
  358. }
  359. - (void)testSetLimitsWithStartAt {
  360. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  361. FTestExpectations* expectations = [[FTestExpectations alloc] initFrom:self];
  362. [expectations addQuery:[[[ref queryOrderedByPriority] queryStartingAtValue:nil]
  363. queryLimitedToFirst:1]
  364. withExpectation:@{@"a" : @1}];
  365. [expectations addQuery:[[[ref queryOrderedByPriority] queryStartingAtValue:nil childKey:@"c"]
  366. queryLimitedToFirst:1]
  367. withExpectation:@{@"c" : @3}];
  368. [expectations addQuery:[[[ref queryOrderedByPriority] queryStartingAtValue:nil childKey:@"b"]
  369. queryLimitedToFirst:1]
  370. withExpectation:@{@"b" : @2}];
  371. [expectations addQuery:[[[ref queryOrderedByPriority] queryStartingAtValue:nil childKey:@"b"]
  372. queryLimitedToFirst:2]
  373. withExpectation:@{@"b" : @2, @"c" : @3}];
  374. [expectations addQuery:[[[ref queryOrderedByPriority] queryStartingAtValue:nil childKey:@"b"]
  375. queryLimitedToFirst:3]
  376. withExpectation:@{@"b" : @2, @"c" : @3}];
  377. __block BOOL ready = NO;
  378. [ref setValue:@{@"a" : @1, @"b" : @2, @"c" : @3}
  379. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  380. ready = YES;
  381. }];
  382. [self waitUntil:^BOOL {
  383. return ready;
  384. }];
  385. [expectations validate];
  386. }
  387. - (void)testLimitsAndStartAtWithServerData {
  388. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  389. __block BOOL ready = NO;
  390. [ref setValue:@{@"a" : @1, @"b" : @2, @"c" : @3}
  391. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  392. ready = YES;
  393. }];
  394. [self waitUntil:^BOOL {
  395. return ready;
  396. }];
  397. FTestExpectations* expectations = [[FTestExpectations alloc] initFrom:self];
  398. [expectations addQuery:[[[ref queryOrderedByPriority] queryStartingAtValue:nil]
  399. queryLimitedToFirst:1]
  400. withExpectation:@{@"a" : @1}];
  401. /*params = [[FQueryParams alloc] init];
  402. params = [params setStartPriority:nil andName:@"c"];
  403. params = [params limitTo:1];
  404. [expectations addQuery:[ref queryWithParams:params] withExpectation:@{@"c": @3}];
  405. params = [[FQueryParams alloc] init];
  406. params = [params setStartPriority:nil andName:@"b"];
  407. params = [params limitTo:1];
  408. [expectations addQuery:[ref queryWithParams:params] withExpectation:@{@"b": @2}];
  409. params = [[FQueryParams alloc] init];
  410. params = [params setStartPriority:nil andName:@"b"];
  411. params = [params limitTo:2];
  412. [expectations addQuery:[ref queryWithParams:params] withExpectation:@{@"b": @2, @"c": @3}];
  413. params = [[FQueryParams alloc] init];
  414. params = [params setStartPriority:nil andName:@"b"];
  415. params = [params limitTo:3];
  416. [expectations addQuery:[ref queryWithParams:params] withExpectation:@{@"b": @2, @"c": @3}];*/
  417. [self waitUntil:^BOOL {
  418. return expectations.isReady;
  419. }];
  420. [expectations validate];
  421. [ref removeAllObservers];
  422. }
  423. - (void)testChildEventsAreFiredWhenLimitIsHit {
  424. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  425. NSMutableArray* added = [[NSMutableArray alloc] init];
  426. NSMutableArray* removed = [[NSMutableArray alloc] init];
  427. [[ref queryLimitedToLast:2] observeEventType:FIRDataEventTypeChildAdded
  428. withBlock:^(FIRDataSnapshot* snapshot) {
  429. [added addObject:[snapshot key]];
  430. }];
  431. [[ref queryLimitedToLast:2] observeEventType:FIRDataEventTypeChildRemoved
  432. withBlock:^(FIRDataSnapshot* snapshot) {
  433. [removed addObject:[snapshot key]];
  434. }];
  435. __block BOOL ready = NO;
  436. [ref setValue:@{@"a" : @1, @"b" : @2, @"c" : @3}
  437. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  438. ready = YES;
  439. }];
  440. [self waitUntil:^BOOL {
  441. return ready;
  442. }];
  443. XCTAssertTrue([removed count] == 0, @"Nothing should be removed from our window");
  444. NSArray* expected = @[ @"b", @"c" ];
  445. XCTAssertTrue([added isEqualToArray:expected], @"Should have two items");
  446. [added removeAllObjects];
  447. ready = NO;
  448. [[ref child:@"d"] setValue:@4
  449. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  450. ready = YES;
  451. }];
  452. [self waitUntil:^BOOL {
  453. return ready;
  454. }];
  455. expected = @[ @"b" ];
  456. XCTAssertTrue([removed isEqualToArray:expected], @"Expected to remove b");
  457. expected = @[ @"d" ];
  458. XCTAssertTrue([added isEqualToArray:expected], @"Expected to add d");
  459. [ref removeAllObservers];
  460. }
  461. - (void)testChildEventsAreFiredWhenLimitIsHitWithServerData {
  462. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  463. __block BOOL ready = NO;
  464. [ref setValue:@{@"a" : @1, @"b" : @2, @"c" : @3}
  465. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  466. ready = YES;
  467. }];
  468. [self waitUntil:^BOOL {
  469. return ready;
  470. }];
  471. NSMutableArray* added = [[NSMutableArray alloc] init];
  472. NSMutableArray* removed = [[NSMutableArray alloc] init];
  473. FIRDatabaseQuery* query = [ref queryLimitedToLast:2];
  474. [query observeEventType:FIRDataEventTypeChildAdded
  475. withBlock:^(FIRDataSnapshot* snapshot) {
  476. [added addObject:[snapshot key]];
  477. }];
  478. [query observeEventType:FIRDataEventTypeChildRemoved
  479. withBlock:^(FIRDataSnapshot* snapshot) {
  480. [removed addObject:[snapshot key]];
  481. }];
  482. [self waitUntil:^BOOL {
  483. return [added count] == 2;
  484. }];
  485. XCTAssertTrue([removed count] == 0, @"Nothing should be removed from our window");
  486. NSArray* expected = @[ @"b", @"c" ];
  487. XCTAssertTrue([added isEqualToArray:expected], @"Should have two items");
  488. [added removeAllObjects];
  489. ready = NO;
  490. [[ref child:@"d"] setValue:@4
  491. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  492. ready = YES;
  493. }];
  494. [self waitUntil:^BOOL {
  495. return ready;
  496. }];
  497. expected = @[ @"b" ];
  498. XCTAssertTrue([removed isEqualToArray:expected], @"Expected to remove b");
  499. expected = @[ @"d" ];
  500. XCTAssertTrue([added isEqualToArray:expected], @"Expected to add d");
  501. [ref removeAllObservers];
  502. }
  503. - (void)testChildEventsAreFiredWhenLimitIsHitWithStart {
  504. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  505. FIRDatabaseQuery* query =
  506. [[[ref queryOrderedByPriority] queryStartingAtValue:nil childKey:@"a"] queryLimitedToFirst:2];
  507. NSMutableArray* added = [[NSMutableArray alloc] init];
  508. NSMutableArray* removed = [[NSMutableArray alloc] init];
  509. [query observeEventType:FIRDataEventTypeChildAdded
  510. withBlock:^(FIRDataSnapshot* snapshot) {
  511. [added addObject:[snapshot key]];
  512. }];
  513. [query observeEventType:FIRDataEventTypeChildRemoved
  514. withBlock:^(FIRDataSnapshot* snapshot) {
  515. [removed addObject:[snapshot key]];
  516. }];
  517. __block BOOL ready = NO;
  518. [ref setValue:@{@"a" : @1, @"b" : @2, @"c" : @3}
  519. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  520. ready = YES;
  521. }];
  522. [self waitUntil:^BOOL {
  523. return ready;
  524. }];
  525. XCTAssertTrue([removed count] == 0, @"Nothing should be removed from our window");
  526. NSArray* expected = @[ @"a", @"b" ];
  527. XCTAssertTrue([added isEqualToArray:expected], @"Should have two items");
  528. [added removeAllObjects];
  529. ready = NO;
  530. [[ref child:@"aa"] setValue:@4
  531. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  532. ready = YES;
  533. }];
  534. [self waitUntil:^BOOL {
  535. return ready;
  536. }];
  537. expected = @[ @"b" ];
  538. XCTAssertTrue([removed isEqualToArray:expected], @"Expected to remove b");
  539. expected = @[ @"aa" ];
  540. XCTAssertTrue([added isEqualToArray:expected], @"Expected to add aa");
  541. [ref removeAllObservers];
  542. }
  543. - (void)testChildEventsAreFiredWhenLimitIsHitWithStartAndServerData {
  544. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  545. __block BOOL ready = NO;
  546. [ref setValue:@{@"a" : @1, @"b" : @2, @"c" : @3}
  547. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  548. ready = YES;
  549. }];
  550. [self waitUntil:^BOOL {
  551. return ready;
  552. }];
  553. FIRDatabaseQuery* query =
  554. [[[ref queryOrderedByPriority] queryStartingAtValue:nil childKey:@"a"] queryLimitedToFirst:2];
  555. NSMutableArray* added = [[NSMutableArray alloc] init];
  556. NSMutableArray* removed = [[NSMutableArray alloc] init];
  557. [query observeEventType:FIRDataEventTypeChildAdded
  558. withBlock:^(FIRDataSnapshot* snapshot) {
  559. [added addObject:[snapshot key]];
  560. }];
  561. [query observeEventType:FIRDataEventTypeChildRemoved
  562. withBlock:^(FIRDataSnapshot* snapshot) {
  563. [removed addObject:[snapshot key]];
  564. }];
  565. [self waitUntil:^BOOL {
  566. return [added count] == 2;
  567. }];
  568. XCTAssertTrue([removed count] == 0, @"Nothing should be removed from our window");
  569. NSArray* expected = @[ @"a", @"b" ];
  570. XCTAssertTrue([added isEqualToArray:expected], @"Should have two items");
  571. [added removeAllObjects];
  572. ready = NO;
  573. [[ref child:@"aa"] setValue:@4
  574. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  575. ready = YES;
  576. }];
  577. [self waitUntil:^BOOL {
  578. return ready;
  579. }];
  580. expected = @[ @"b" ];
  581. XCTAssertTrue([removed isEqualToArray:expected], @"Expected to remove b");
  582. expected = @[ @"aa" ];
  583. XCTAssertTrue([added isEqualToArray:expected], @"Expected to add aa");
  584. [ref removeAllObservers];
  585. }
  586. - (void)testStartAndLimitWithIncompleteWindow {
  587. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  588. FIRDatabaseQuery* query =
  589. [[[ref queryOrderedByPriority] queryStartingAtValue:nil childKey:@"a"] queryLimitedToFirst:2];
  590. NSMutableArray* added = [[NSMutableArray alloc] init];
  591. NSMutableArray* removed = [[NSMutableArray alloc] init];
  592. [query observeEventType:FIRDataEventTypeChildAdded
  593. withBlock:^(FIRDataSnapshot* snapshot) {
  594. [added addObject:[snapshot key]];
  595. }];
  596. [query observeEventType:FIRDataEventTypeChildRemoved
  597. withBlock:^(FIRDataSnapshot* snapshot) {
  598. [removed addObject:[snapshot key]];
  599. }];
  600. __block BOOL ready = NO;
  601. [ref setValue:@{@"c" : @3}
  602. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  603. ready = YES;
  604. }];
  605. [self waitUntil:^BOOL {
  606. return ready && [added count] >= 1;
  607. }];
  608. XCTAssertTrue([removed count] == 0, @"Nothing should be removed from our window");
  609. NSArray* expected = @[ @"c" ];
  610. XCTAssertTrue([added isEqualToArray:expected], @"Should have one item");
  611. [added removeAllObjects];
  612. ready = NO;
  613. [[ref child:@"b"] setValue:@4
  614. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  615. ready = YES;
  616. }];
  617. [self waitUntil:^BOOL {
  618. return ready;
  619. }];
  620. XCTAssertTrue([removed count] == 0, @"Expected to remove nothing");
  621. expected = @[ @"b" ];
  622. XCTAssertTrue([added isEqualToArray:expected], @"Expected to add b");
  623. [ref removeAllObservers];
  624. }
  625. - (void)testStartAndLimitWithIncompleteWindowAndServerData {
  626. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  627. __block BOOL ready = NO;
  628. [ref setValue:@{@"c" : @3}
  629. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  630. ready = YES;
  631. }];
  632. [self waitUntil:^BOOL {
  633. return ready;
  634. }];
  635. FIRDatabaseQuery* query =
  636. [[[ref queryOrderedByPriority] queryStartingAtValue:nil childKey:@"a"] queryLimitedToFirst:2];
  637. NSMutableArray* added = [[NSMutableArray alloc] init];
  638. NSMutableArray* removed = [[NSMutableArray alloc] init];
  639. [query observeEventType:FIRDataEventTypeChildAdded
  640. withBlock:^(FIRDataSnapshot* snapshot) {
  641. [added addObject:[snapshot key]];
  642. }];
  643. [query observeEventType:FIRDataEventTypeChildRemoved
  644. withBlock:^(FIRDataSnapshot* snapshot) {
  645. [removed addObject:[snapshot key]];
  646. }];
  647. [self waitUntil:^BOOL {
  648. return [added count] == 1;
  649. }];
  650. XCTAssertTrue([removed count] == 0, @"Nothing should be removed from our window");
  651. NSArray* expected = @[ @"c" ];
  652. XCTAssertTrue([added isEqualToArray:expected], @"Should have one item");
  653. [added removeAllObjects];
  654. ready = NO;
  655. [[ref child:@"b"] setValue:@4
  656. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  657. ready = YES;
  658. }];
  659. [self waitUntil:^BOOL {
  660. return ready;
  661. }];
  662. XCTAssertTrue([removed count] == 0, @"Expected to remove nothing");
  663. expected = @[ @"b" ];
  664. XCTAssertTrue([added isEqualToArray:expected], @"Expected to add b");
  665. [ref removeAllObservers];
  666. }
  667. - (void)testChildEventsFiredWhenItemDeleted {
  668. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  669. FIRDatabaseQuery* query = [ref queryLimitedToLast:2];
  670. NSMutableArray* added = [[NSMutableArray alloc] init];
  671. NSMutableArray* removed = [[NSMutableArray alloc] init];
  672. [query observeEventType:FIRDataEventTypeChildAdded
  673. withBlock:^(FIRDataSnapshot* snapshot) {
  674. [added addObject:[snapshot key]];
  675. }];
  676. [query observeEventType:FIRDataEventTypeChildRemoved
  677. withBlock:^(FIRDataSnapshot* snapshot) {
  678. [removed addObject:[snapshot key]];
  679. }];
  680. __block BOOL ready = NO;
  681. [ref setValue:@{@"a" : @1, @"b" : @2, @"c" : @3}
  682. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  683. ready = YES;
  684. }];
  685. [self waitUntil:^BOOL {
  686. return ready && [added count] >= 1;
  687. }];
  688. XCTAssertTrue([removed count] == 0, @"Nothing should be removed from our window");
  689. NSArray* expected = @[ @"b", @"c" ];
  690. XCTAssertTrue([added isEqualToArray:expected], @"Should have one item");
  691. [added removeAllObjects];
  692. ready = NO;
  693. [[ref child:@"b"] removeValueWithCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  694. ready = YES;
  695. }];
  696. [self waitUntil:^BOOL {
  697. return ready;
  698. }];
  699. expected = @[ @"b" ];
  700. XCTAssertTrue([removed isEqualToArray:expected], @"Expected to remove b");
  701. expected = @[ @"a" ];
  702. XCTAssertTrue([added isEqualToArray:expected], @"Expected to add a");
  703. [ref removeAllObservers];
  704. }
  705. - (void)testChildEventsAreFiredWhenItemDeletedAtServer {
  706. FIRDatabaseReference* ref = [FTestHelpers getRandomNodeWithoutPersistence];
  707. __block BOOL ready = NO;
  708. [ref setValue:@{@"a" : @1, @"b" : @2, @"c" : @3}
  709. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  710. ready = YES;
  711. }];
  712. [self waitUntil:^BOOL {
  713. return ready;
  714. }];
  715. FIRDatabaseQuery* query = [ref queryLimitedToLast:2];
  716. NSMutableArray* added = [[NSMutableArray alloc] init];
  717. NSMutableArray* removed = [[NSMutableArray alloc] init];
  718. [query observeEventType:FIRDataEventTypeChildAdded
  719. withBlock:^(FIRDataSnapshot* snapshot) {
  720. [added addObject:[snapshot key]];
  721. }];
  722. [query observeEventType:FIRDataEventTypeChildRemoved
  723. withBlock:^(FIRDataSnapshot* snapshot) {
  724. [removed addObject:[snapshot key]];
  725. }];
  726. [self waitUntil:^BOOL {
  727. return [added count] == 2;
  728. }];
  729. XCTAssertTrue([removed count] == 0, @"Nothing should be removed from our window");
  730. NSArray* expected = @[ @"b", @"c" ];
  731. XCTAssertTrue([added isEqualToArray:expected], @"Should have two items");
  732. [added removeAllObjects];
  733. ready = NO;
  734. [[ref child:@"b"] removeValueWithCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  735. ready = YES;
  736. }];
  737. [self waitUntil:^BOOL {
  738. return ready;
  739. }];
  740. XCTAssertEqualObjects(removed, (@[ @"b" ]), @"Expected to remove b");
  741. XCTAssertEqualObjects(added, (@[ @"a" ]), @"Expected to add a");
  742. [ref removeAllObservers];
  743. }
  744. - (void)testRemoveFiredWhenItemDeleted {
  745. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  746. FIRDatabaseQuery* query = [ref queryLimitedToLast:2];
  747. NSMutableArray* added = [[NSMutableArray alloc] init];
  748. NSMutableArray* removed = [[NSMutableArray alloc] init];
  749. [query observeEventType:FIRDataEventTypeChildAdded
  750. withBlock:^(FIRDataSnapshot* snapshot) {
  751. [added addObject:[snapshot key]];
  752. }];
  753. [query observeEventType:FIRDataEventTypeChildRemoved
  754. withBlock:^(FIRDataSnapshot* snapshot) {
  755. [removed addObject:[snapshot key]];
  756. }];
  757. __block BOOL ready = NO;
  758. [ref setValue:@{@"b" : @2, @"c" : @3}
  759. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  760. ready = YES;
  761. }];
  762. [self waitUntil:^BOOL {
  763. return ready && [added count] >= 1;
  764. }];
  765. XCTAssertTrue([removed count] == 0, @"Nothing should be removed from our window");
  766. NSArray* expected = @[ @"b", @"c" ];
  767. XCTAssertTrue([added isEqualToArray:expected], @"Should have one item");
  768. [added removeAllObjects];
  769. ready = NO;
  770. [[ref child:@"b"] removeValueWithCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  771. ready = YES;
  772. }];
  773. [self waitUntil:^BOOL {
  774. return ready;
  775. }];
  776. expected = @[ @"b" ];
  777. XCTAssertTrue([removed isEqualToArray:expected], @"Expected to remove b");
  778. XCTAssertTrue([added count] == 0, @"Expected to add nothing");
  779. [ref removeAllObservers];
  780. }
  781. - (void)testRemoveFiredWhenItemDeletedAtServer {
  782. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  783. __block BOOL ready = NO;
  784. [ref setValue:@{@"b" : @2, @"c" : @3}
  785. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  786. ready = YES;
  787. }];
  788. [self waitUntil:^BOOL {
  789. return ready;
  790. }];
  791. FIRDatabaseQuery* query = [ref queryLimitedToLast:2];
  792. NSMutableArray* added = [[NSMutableArray alloc] init];
  793. NSMutableArray* removed = [[NSMutableArray alloc] init];
  794. [query observeEventType:FIRDataEventTypeChildAdded
  795. withBlock:^(FIRDataSnapshot* snapshot) {
  796. [added addObject:[snapshot key]];
  797. }];
  798. [query observeEventType:FIRDataEventTypeChildRemoved
  799. withBlock:^(FIRDataSnapshot* snapshot) {
  800. [removed addObject:[snapshot key]];
  801. }];
  802. [self waitUntil:^BOOL {
  803. return [added count] == 2;
  804. }];
  805. XCTAssertTrue([removed count] == 0, @"Nothing should be removed from our window");
  806. NSArray* expected = @[ @"b", @"c" ];
  807. XCTAssertTrue([added isEqualToArray:expected], @"Should have two items");
  808. [added removeAllObjects];
  809. ready = NO;
  810. [[ref child:@"b"] removeValueWithCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  811. ready = YES;
  812. }];
  813. [self waitUntil:^BOOL {
  814. return ready;
  815. }];
  816. expected = @[ @"b" ];
  817. XCTAssertTrue([removed isEqualToArray:expected], @"Expected to remove b");
  818. XCTAssertTrue([added count] == 0, @"Expected to add nothing");
  819. [ref removeAllObservers];
  820. }
  821. - (void)testStartAtPriorityAndEndAtPriorityWork {
  822. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  823. FTestExpectations* expectations = [[FTestExpectations alloc] initFrom:self];
  824. [expectations addQuery:[[[ref queryOrderedByPriority] queryStartingAtValue:@"w"]
  825. queryEndingAtValue:@"y"]
  826. withExpectation:@{@"b" : @2, @"c" : @3, @"d" : @4}];
  827. [expectations addQuery:[[[ref queryOrderedByPriority] queryStartingAtValue:@"w"]
  828. queryEndingAtValue:@"w"]
  829. withExpectation:@{@"d" : @4}];
  830. __block id nullSnap = @"dummy";
  831. [[[[ref queryOrderedByPriority] queryStartingAtValue:@"a"] queryEndingAtValue:@"c"]
  832. observeEventType:FIRDataEventTypeValue
  833. withBlock:^(FIRDataSnapshot* snapshot) {
  834. nullSnap = [snapshot value];
  835. }];
  836. [ref setValue:@{
  837. @"a" : @{@".value" : @1, @".priority" : @"z"},
  838. @"b" : @{@".value" : @2, @".priority" : @"y"},
  839. @"c" : @{@".value" : @3, @".priority" : @"x"},
  840. @"d" : @{@".value" : @4, @".priority" : @"w"}
  841. }];
  842. WAIT_FOR(expectations.isReady && [nullSnap isEqual:[NSNull null]]);
  843. [expectations validate];
  844. }
  845. - (void)testStartAtPriorityAndEndAtPriorityWorkWithServerData {
  846. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  847. __block BOOL ready = NO;
  848. [ref setValue:@{
  849. @"a" : @{@".value" : @1, @".priority" : @"z"},
  850. @"b" : @{@".value" : @2, @".priority" : @"y"},
  851. @"c" : @{@".value" : @3, @".priority" : @"x"},
  852. @"d" : @{@".value" : @4, @".priority" : @"w"}
  853. }
  854. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  855. ready = YES;
  856. }];
  857. WAIT_FOR(ready);
  858. FTestExpectations* expectations = [[FTestExpectations alloc] initFrom:self];
  859. [expectations addQuery:[[[ref queryOrderedByPriority] queryStartingAtValue:@"w"]
  860. queryEndingAtValue:@"y"]
  861. withExpectation:@{@"b" : @2, @"c" : @3, @"d" : @4}];
  862. [expectations addQuery:[[[ref queryOrderedByPriority] queryStartingAtValue:@"w"]
  863. queryEndingAtValue:@"w"]
  864. withExpectation:@{@"d" : @4}];
  865. __block id nullSnap = @"dummy";
  866. [[[[ref queryOrderedByPriority] queryStartingAtValue:@"a"] queryEndingAtValue:@"c"]
  867. observeEventType:FIRDataEventTypeValue
  868. withBlock:^(FIRDataSnapshot* snapshot) {
  869. nullSnap = [snapshot value];
  870. }];
  871. WAIT_FOR(expectations.isReady && [nullSnap isEqual:[NSNull null]]);
  872. [expectations validate];
  873. }
  874. - (void)testStartAtAndEndAtPriorityAndNameWork {
  875. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  876. FTestExpectations* expectations = [[FTestExpectations alloc] initFrom:self];
  877. FIRDatabaseQuery* query = [[[ref queryOrderedByPriority] queryStartingAtValue:@1 childKey:@"a"]
  878. queryEndingAtValue:@2
  879. childKey:@"d"];
  880. [expectations addQuery:query withExpectation:@{@"a" : @1, @"b" : @2, @"c" : @3, @"d" : @4}];
  881. query = [[[ref queryOrderedByPriority] queryStartingAtValue:@1
  882. childKey:@"b"] queryEndingAtValue:@2
  883. childKey:@"c"];
  884. [expectations addQuery:query withExpectation:@{@"b" : @2, @"c" : @3}];
  885. query = [[[ref queryOrderedByPriority] queryStartingAtValue:@1
  886. childKey:@"c"] queryEndingAtValue:@2];
  887. [expectations addQuery:query withExpectation:@{@"c" : @3, @"d" : @4}];
  888. [ref setValue:@{
  889. @"a" : @{@".value" : @1, @".priority" : @1},
  890. @"b" : @{@".value" : @2, @".priority" : @1},
  891. @"c" : @{@".value" : @3, @".priority" : @2},
  892. @"d" : @{@".value" : @4, @".priority" : @2}
  893. }];
  894. WAIT_FOR(expectations.isReady);
  895. [expectations validate];
  896. }
  897. - (void)testStartAtAndEndAtPriorityAndNameWorkWithServerData {
  898. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  899. __block BOOL ready = NO;
  900. [ref setValue:@{
  901. @"a" : @{@".value" : @1, @".priority" : @1},
  902. @"b" : @{@".value" : @2, @".priority" : @1},
  903. @"c" : @{@".value" : @3, @".priority" : @2},
  904. @"d" : @{@".value" : @4, @".priority" : @2}
  905. }
  906. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  907. ready = YES;
  908. }];
  909. WAIT_FOR(ready);
  910. FTestExpectations* expectations = [[FTestExpectations alloc] initFrom:self];
  911. FIRDatabaseQuery* query = [[[ref queryOrderedByPriority] queryStartingAtValue:@1 childKey:@"a"]
  912. queryEndingAtValue:@2
  913. childKey:@"d"];
  914. [expectations addQuery:query withExpectation:@{@"a" : @1, @"b" : @2, @"c" : @3, @"d" : @4}];
  915. query = [[[ref queryOrderedByPriority] queryStartingAtValue:@1
  916. childKey:@"b"] queryEndingAtValue:@2
  917. childKey:@"c"];
  918. [expectations addQuery:query withExpectation:@{@"b" : @2, @"c" : @3}];
  919. query = [[[ref queryOrderedByPriority] queryStartingAtValue:@1
  920. childKey:@"c"] queryEndingAtValue:@2];
  921. [expectations addQuery:query withExpectation:@{@"c" : @3, @"d" : @4}];
  922. WAIT_FOR(expectations.isReady);
  923. [expectations validate];
  924. }
  925. - (void)testStartAtAndEndAtPriorityAndNameWork2 {
  926. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  927. FTestExpectations* expectations = [[FTestExpectations alloc] initFrom:self];
  928. FIRDatabaseQuery* query = [[[ref queryOrderedByPriority] queryStartingAtValue:@1 childKey:@"c"]
  929. queryEndingAtValue:@2
  930. childKey:@"b"];
  931. [expectations addQuery:query withExpectation:@{@"a" : @1, @"b" : @2, @"c" : @3, @"d" : @4}];
  932. query = [[[ref queryOrderedByPriority] queryStartingAtValue:@1
  933. childKey:@"d"] queryEndingAtValue:@2
  934. childKey:@"a"];
  935. [expectations addQuery:query withExpectation:@{@"d" : @4, @"a" : @1}];
  936. query = [[[ref queryOrderedByPriority] queryStartingAtValue:@1
  937. childKey:@"e"] queryEndingAtValue:@2];
  938. [expectations addQuery:query withExpectation:@{@"a" : @1, @"b" : @2}];
  939. [ref setValue:@{
  940. @"c" : @{@".value" : @3, @".priority" : @1},
  941. @"d" : @{@".value" : @4, @".priority" : @1},
  942. @"a" : @{@".value" : @1, @".priority" : @2},
  943. @"b" : @{@".value" : @2, @".priority" : @2}
  944. }];
  945. WAIT_FOR(expectations.isReady);
  946. [expectations validate];
  947. }
  948. - (void)testStartAtAndEndAtPriorityAndNameWorkWithServerData2 {
  949. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  950. __block BOOL ready = NO;
  951. [ref setValue:@{
  952. @"c" : @{@".value" : @3, @".priority" : @1},
  953. @"d" : @{@".value" : @4, @".priority" : @1},
  954. @"a" : @{@".value" : @1, @".priority" : @2},
  955. @"b" : @{@".value" : @2, @".priority" : @2}
  956. }
  957. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  958. ready = YES;
  959. }];
  960. WAIT_FOR(ready);
  961. FTestExpectations* expectations = [[FTestExpectations alloc] initFrom:self];
  962. FIRDatabaseQuery* query = [[[ref queryOrderedByPriority] queryStartingAtValue:@1 childKey:@"c"]
  963. queryEndingAtValue:@2
  964. childKey:@"b"];
  965. [expectations addQuery:query withExpectation:@{@"a" : @1, @"b" : @2, @"c" : @3, @"d" : @4}];
  966. query = [[[ref queryOrderedByPriority] queryStartingAtValue:@1
  967. childKey:@"d"] queryEndingAtValue:@2
  968. childKey:@"a"];
  969. [expectations addQuery:query withExpectation:@{@"d" : @4, @"a" : @1}];
  970. query = [[[ref queryOrderedByPriority] queryStartingAtValue:@1
  971. childKey:@"e"] queryEndingAtValue:@2];
  972. [expectations addQuery:query withExpectation:@{@"a" : @1, @"b" : @2}];
  973. WAIT_FOR(expectations.isReady);
  974. [expectations validate];
  975. }
  976. - (void)testEqualToPriorityWorks {
  977. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  978. FTestExpectations* expectations = [[FTestExpectations alloc] initFrom:self];
  979. [expectations addQuery:[[ref queryOrderedByPriority] queryEqualToValue:@"w"]
  980. withExpectation:@{@"d" : @4}];
  981. __block id nullSnap = @"dummy";
  982. [[[ref queryOrderedByPriority] queryEqualToValue:@"c"]
  983. observeEventType:FIRDataEventTypeValue
  984. withBlock:^(FIRDataSnapshot* snapshot) {
  985. nullSnap = [snapshot value];
  986. }];
  987. [ref setValue:@{
  988. @"a" : @{@".value" : @1, @".priority" : @"z"},
  989. @"b" : @{@".value" : @2, @".priority" : @"y"},
  990. @"c" : @{@".value" : @3, @".priority" : @"x"},
  991. @"d" : @{@".value" : @4, @".priority" : @"w"}
  992. }];
  993. WAIT_FOR(expectations.isReady && [nullSnap isEqual:[NSNull null]]);
  994. [expectations validate];
  995. }
  996. - (void)testEqualToPriorityWorksWithServerData {
  997. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  998. __block BOOL ready = NO;
  999. [ref setValue:@{
  1000. @"a" : @{@".value" : @1, @".priority" : @"z"},
  1001. @"b" : @{@".value" : @2, @".priority" : @"y"},
  1002. @"c" : @{@".value" : @3, @".priority" : @"x"},
  1003. @"d" : @{@".value" : @4, @".priority" : @"w"}
  1004. }
  1005. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  1006. ready = YES;
  1007. }];
  1008. WAIT_FOR(ready);
  1009. FTestExpectations* expectations = [[FTestExpectations alloc] initFrom:self];
  1010. [expectations addQuery:[[ref queryOrderedByPriority] queryEqualToValue:@"w"]
  1011. withExpectation:@{@"d" : @4}];
  1012. __block id nullSnap = @"dummy";
  1013. [[[ref queryOrderedByPriority] queryEqualToValue:@"c"]
  1014. observeEventType:FIRDataEventTypeValue
  1015. withBlock:^(FIRDataSnapshot* snapshot) {
  1016. nullSnap = [snapshot value];
  1017. }];
  1018. WAIT_FOR(expectations.isReady && [nullSnap isEqual:[NSNull null]]);
  1019. [expectations validate];
  1020. }
  1021. - (void)testEqualToPriorityAndNameWorks {
  1022. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  1023. FTestExpectations* expectations = [[FTestExpectations alloc] initFrom:self];
  1024. FIRDatabaseQuery* query = [[ref queryOrderedByPriority] queryEqualToValue:@1 childKey:@"a"];
  1025. [expectations addQuery:query withExpectation:@{@"a" : @1}];
  1026. __block id nullSnap = @"dummy";
  1027. [[[ref queryOrderedByPriority] queryEqualToValue:@"1" childKey:@"z"]
  1028. observeEventType:FIRDataEventTypeValue
  1029. withBlock:^(FIRDataSnapshot* snapshot) {
  1030. nullSnap = [snapshot value];
  1031. }];
  1032. [ref setValue:@{
  1033. @"a" : @{@".value" : @1, @".priority" : @1},
  1034. @"b" : @{@".value" : @2, @".priority" : @1},
  1035. @"c" : @{@".value" : @3, @".priority" : @2},
  1036. @"d" : @{@".value" : @4, @".priority" : @2}
  1037. }];
  1038. WAIT_FOR(expectations.isReady && [nullSnap isEqual:[NSNull null]]);
  1039. [expectations validate];
  1040. }
  1041. - (void)testEqualToPriorityAndNameWorksWithServerData {
  1042. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  1043. __block BOOL ready = NO;
  1044. [ref setValue:@{
  1045. @"a" : @{@".value" : @1, @".priority" : @1},
  1046. @"b" : @{@".value" : @2, @".priority" : @1},
  1047. @"c" : @{@".value" : @3, @".priority" : @2},
  1048. @"d" : @{@".value" : @4, @".priority" : @2}
  1049. }
  1050. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  1051. ready = YES;
  1052. }];
  1053. WAIT_FOR(ready);
  1054. FTestExpectations* expectations = [[FTestExpectations alloc] initFrom:self];
  1055. FIRDatabaseQuery* query = [[ref queryOrderedByPriority] queryEqualToValue:@1 childKey:@"a"];
  1056. [expectations addQuery:query withExpectation:@{@"a" : @1}];
  1057. __block id nullSnap = @"dummy";
  1058. [[[ref queryOrderedByPriority] queryEqualToValue:@"1" childKey:@"z"]
  1059. observeEventType:FIRDataEventTypeValue
  1060. withBlock:^(FIRDataSnapshot* snapshot) {
  1061. nullSnap = [snapshot value];
  1062. }];
  1063. WAIT_FOR(expectations.isReady && [nullSnap isEqual:[NSNull null]]);
  1064. [expectations validate];
  1065. }
  1066. - (void)testPrevNameWorks {
  1067. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  1068. NSMutableArray* added = [[NSMutableArray alloc] init];
  1069. [[ref queryLimitedToLast:2] observeEventType:FIRDataEventTypeChildAdded
  1070. andPreviousSiblingKeyWithBlock:^(FIRDataSnapshot* snapshot, NSString* prevName) {
  1071. [added addObject:snapshot.key];
  1072. if (prevName) {
  1073. [added addObject:prevName];
  1074. } else {
  1075. [added addObject:@"null"];
  1076. }
  1077. }];
  1078. [[ref child:@"a"] setValue:@1];
  1079. [self waitUntil:^BOOL {
  1080. NSArray* expected = @[ @"a", @"null" ];
  1081. return [added isEqualToArray:expected];
  1082. }];
  1083. [added removeAllObjects];
  1084. [[ref child:@"c"] setValue:@3];
  1085. [self waitUntil:^BOOL {
  1086. NSArray* expected = @[ @"c", @"a" ];
  1087. return [added isEqualToArray:expected];
  1088. }];
  1089. [added removeAllObjects];
  1090. [[ref child:@"b"] setValue:@2];
  1091. [self waitUntil:^BOOL {
  1092. NSArray* expected = @[ @"b", @"null" ];
  1093. return [added isEqualToArray:expected];
  1094. }];
  1095. [added removeAllObjects];
  1096. [[ref child:@"d"] setValue:@3];
  1097. [self waitUntil:^BOOL {
  1098. NSArray* expected = @[ @"d", @"c" ];
  1099. return [added isEqualToArray:expected];
  1100. }];
  1101. }
  1102. // Dropping some of the server data tests here, around prevName. They don't really test anything
  1103. // new, and mostly don't even test server data
  1104. - (void)testPrevNameWorksWithMoves {
  1105. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  1106. NSMutableArray* moved = [[NSMutableArray alloc] init];
  1107. [[ref queryLimitedToLast:2] observeEventType:FIRDataEventTypeChildMoved
  1108. andPreviousSiblingKeyWithBlock:^(FIRDataSnapshot* snapshot, NSString* prevName) {
  1109. [moved addObject:snapshot.key];
  1110. if (prevName) {
  1111. [moved addObject:prevName];
  1112. } else {
  1113. [moved addObject:@"null"];
  1114. }
  1115. }];
  1116. [ref setValue:@{
  1117. @"a" : @{@".value" : @"a", @".priority" : @10},
  1118. @"b" : @{@".value" : @"b", @".priority" : @20},
  1119. @"c" : @{@".value" : @"c", @".priority" : @30},
  1120. @"d" : @{@".value" : @"d", @".priority" : @40}
  1121. }];
  1122. __block BOOL ready = NO;
  1123. [[ref child:@"c"] setPriority:@50
  1124. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  1125. ready = YES;
  1126. }];
  1127. [self waitUntil:^BOOL {
  1128. return ready;
  1129. }];
  1130. NSArray* expected = @[ @"c", @"d" ];
  1131. XCTAssertTrue([moved isEqualToArray:expected], @"Expected changed node and prevChild");
  1132. [moved removeAllObjects];
  1133. ready = NO;
  1134. [[ref child:@"c"] setPriority:@35
  1135. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  1136. ready = YES;
  1137. }];
  1138. [self waitUntil:^BOOL {
  1139. return ready;
  1140. }];
  1141. expected = @[ @"c", @"null" ];
  1142. XCTAssertTrue([moved isEqualToArray:expected], @"Expected changed node and prevChild");
  1143. [moved removeAllObjects];
  1144. ready = NO;
  1145. [[ref child:@"b"] setPriority:@33
  1146. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  1147. ready = YES;
  1148. }];
  1149. [self waitUntil:^BOOL {
  1150. return ready;
  1151. }];
  1152. expected = @[];
  1153. XCTAssertTrue([moved isEqualToArray:expected],
  1154. @"Expected changed node and prevChild to be empty");
  1155. }
  1156. - (void)testLocalEvents {
  1157. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  1158. NSMutableArray* events = [[NSMutableArray alloc] init];
  1159. [[ref queryLimitedToLast:2]
  1160. observeEventType:FIRDataEventTypeChildAdded
  1161. withBlock:^(FIRDataSnapshot* snapshot) {
  1162. NSString* eventString = [NSString stringWithFormat:@"%@ added", [snapshot value]];
  1163. [events addObject:eventString];
  1164. }];
  1165. [[ref queryLimitedToLast:2]
  1166. observeEventType:FIRDataEventTypeChildRemoved
  1167. withBlock:^(FIRDataSnapshot* snapshot) {
  1168. NSString* eventString = [NSString stringWithFormat:@"%@ removed", [snapshot value]];
  1169. [events addObject:eventString];
  1170. }];
  1171. __block BOOL ready = NO;
  1172. for (int i = 0; i < 5; ++i) {
  1173. [[ref childByAutoId] setValue:[NSNumber numberWithInt:i]
  1174. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  1175. if (i == 4) {
  1176. ready = YES;
  1177. }
  1178. }];
  1179. }
  1180. [self waitUntil:^BOOL {
  1181. return ready;
  1182. }];
  1183. NSArray* expected = @[
  1184. @"0 added", @"1 added", @"0 removed", @"2 added", @"1 removed", @"3 added", @"2 removed",
  1185. @"4 added"
  1186. ];
  1187. XCTAssertTrue([events isEqualToArray:expected], @"Expecting window to stay at two nodes");
  1188. }
  1189. - (void)testRemoteEvents {
  1190. FTupleFirebase* pair = [FTestHelpers getRandomNodePair];
  1191. FIRDatabaseReference* writer = pair.one;
  1192. FIRDatabaseReference* reader = pair.two;
  1193. NSMutableArray* events = [[NSMutableArray alloc] init];
  1194. [[reader queryLimitedToLast:2]
  1195. observeEventType:FIRDataEventTypeChildAdded
  1196. withBlock:^(FIRDataSnapshot* snapshot) {
  1197. NSString* eventString = [NSString stringWithFormat:@"%@ added", [snapshot value]];
  1198. [events addObject:eventString];
  1199. }];
  1200. [[reader queryLimitedToLast:2]
  1201. observeEventType:FIRDataEventTypeChildRemoved
  1202. withBlock:^(FIRDataSnapshot* snapshot) {
  1203. NSString* oldEventString = [NSString stringWithFormat:@"%@ added", [snapshot value]];
  1204. [events removeObject:oldEventString];
  1205. }];
  1206. for (int i = 0; i < 5; ++i) {
  1207. [[writer childByAutoId] setValue:[NSNumber numberWithInt:i]];
  1208. }
  1209. NSArray* expected = @[ @"3 added", @"4 added" ];
  1210. [self waitUntil:^BOOL {
  1211. return [events isEqualToArray:expected];
  1212. }];
  1213. }
  1214. - (void)testLimitOnEmptyNodeFiresValue {
  1215. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  1216. __block BOOL ready = NO;
  1217. [[ref queryLimitedToLast:1] observeEventType:FIRDataEventTypeValue
  1218. withBlock:^(FIRDataSnapshot* snapshot) {
  1219. ready = YES;
  1220. }];
  1221. [self waitUntil:^BOOL {
  1222. return ready;
  1223. }];
  1224. }
  1225. - (void)testFilteringToNullPriorities {
  1226. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  1227. // Note: cannot set nil in a dictionary, just leave out priority
  1228. [ref setValue:@{
  1229. @"a" : @0,
  1230. @"b" : @1,
  1231. @"c" : @{@".priority" : @2, @".value" : @2},
  1232. @"d" : @{@".priority" : @3, @".value" : @3},
  1233. @"e" : @{@".priority" : @"hi", @".value" : @4}
  1234. }];
  1235. __block BOOL ready = NO;
  1236. [[[[ref queryOrderedByPriority] queryStartingAtValue:nil] queryEndingAtValue:nil]
  1237. observeEventType:FIRDataEventTypeValue
  1238. withBlock:^(FIRDataSnapshot* snapshot) {
  1239. NSDictionary* expected = @{@"a" : @0, @"b" : @1};
  1240. NSDictionary* val = [snapshot value];
  1241. XCTAssertTrue([val isEqualToDictionary:expected],
  1242. @"Expected only null priority keys");
  1243. ready = YES;
  1244. }];
  1245. [self waitUntil:^BOOL {
  1246. return ready;
  1247. }];
  1248. }
  1249. - (void)testNullPrioritiesIncludedInEndAt {
  1250. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  1251. // Note: cannot set nil in a dictionary, just leave out priority
  1252. [ref setValue:@{
  1253. @"a" : @0,
  1254. @"b" : @1,
  1255. @"c" : @{@".priority" : @2, @".value" : @2},
  1256. @"d" : @{@".priority" : @3, @".value" : @3},
  1257. @"e" : @{@".priority" : @"hi", @".value" : @4}
  1258. }];
  1259. __block BOOL ready = NO;
  1260. [[[ref queryOrderedByPriority] queryEndingAtValue:@2]
  1261. observeEventType:FIRDataEventTypeValue
  1262. withBlock:^(FIRDataSnapshot* snapshot) {
  1263. NSDictionary* expected = @{@"a" : @0, @"b" : @1, @"c" : @2};
  1264. NSDictionary* val = [snapshot value];
  1265. XCTAssertTrue([val isEqualToDictionary:expected], @"Expected up to priority 2");
  1266. ready = YES;
  1267. }];
  1268. [self waitUntil:^BOOL {
  1269. return ready;
  1270. }];
  1271. }
  1272. - (NSSet*)dumpListensForRef:(FIRDatabaseReference*)ref {
  1273. NSMutableSet* dumpPieces = [[NSMutableSet alloc] init];
  1274. NSDictionary* listens = [ref.repo dumpListens];
  1275. FPath* nodePath = ref.path;
  1276. [listens enumerateKeysAndObjectsUsingBlock:^(FQuerySpec* spec, id obj, BOOL* stop) {
  1277. if ([nodePath contains:spec.path]) {
  1278. FPath* relative = [FPath relativePathFrom:nodePath to:spec.path];
  1279. [dumpPieces addObject:[[FQuerySpec alloc] initWithPath:relative params:spec.params]];
  1280. }
  1281. }];
  1282. return dumpPieces;
  1283. }
  1284. - (NSSet*)expectDefaultListenerAtPath:(FPath*)path {
  1285. return [self expectParams:[FQueryParams defaultInstance] atPath:path];
  1286. }
  1287. - (NSSet*)expectParamssetValue:(NSSet*)paramsSet atPath:(FPath*)path {
  1288. NSMutableSet* all = [NSMutableSet set];
  1289. [paramsSet enumerateObjectsUsingBlock:^(FQueryParams* params, BOOL* stop) {
  1290. [all addObject:[[FQuerySpec alloc] initWithPath:path params:params]];
  1291. }];
  1292. return all;
  1293. }
  1294. - (NSSet*)expectParams:(FQueryParams*)params atPath:(FPath*)path {
  1295. return [self expectParamssetValue:[NSSet setWithObject:params] atPath:path];
  1296. }
  1297. - (void)testDedupesListensOnChild {
  1298. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  1299. __block NSSet* listens = [self dumpListensForRef:ref];
  1300. XCTAssertTrue(listens.count == 0, @"No Listens yet");
  1301. [[ref child:@"a"] observeEventType:FIRDataEventTypeValue
  1302. withBlock:^(FIRDataSnapshot* snapshot){
  1303. }];
  1304. __block BOOL ready = NO;
  1305. dispatch_async([FIRDatabaseQuery sharedQueue], ^{
  1306. listens = [self dumpListensForRef:ref];
  1307. NSSet* expected = [NSSet setWithObject:[FQuerySpec defaultQueryAtPath:PATH(@"a")]];
  1308. XCTAssertTrue([expected isEqualToSet:listens], @"Expected child listener");
  1309. ready = YES;
  1310. });
  1311. [self waitUntil:^BOOL {
  1312. return ready;
  1313. }];
  1314. [ref observeEventType:FIRDataEventTypeValue
  1315. withBlock:^(FIRDataSnapshot* snapshot){
  1316. }];
  1317. ready = NO;
  1318. dispatch_async([FIRDatabaseQuery sharedQueue], ^{
  1319. listens = [self dumpListensForRef:ref];
  1320. NSSet* expected = [NSSet setWithObject:[FQuerySpec defaultQueryAtPath:PATH(@"")]];
  1321. XCTAssertTrue([expected isEqualToSet:listens], @"Expected parent listener");
  1322. ready = YES;
  1323. });
  1324. [self waitUntil:^BOOL {
  1325. return ready;
  1326. }];
  1327. [ref removeAllObservers];
  1328. ready = NO;
  1329. dispatch_async([FIRDatabaseQuery sharedQueue], ^{
  1330. listens = [self dumpListensForRef:ref];
  1331. NSSet* expected = [NSSet setWithObject:[FQuerySpec defaultQueryAtPath:PATH(@"a")]];
  1332. XCTAssertTrue([expected isEqualToSet:listens], @"Child listener should be back");
  1333. ready = YES;
  1334. });
  1335. [self waitUntil:^BOOL {
  1336. return ready;
  1337. }];
  1338. [[ref child:@"a"] removeAllObservers];
  1339. ready = NO;
  1340. dispatch_async([FIRDatabaseQuery sharedQueue], ^{
  1341. listens = [self dumpListensForRef:ref];
  1342. XCTAssertTrue(listens.count == 0, @"No more listeners");
  1343. ready = YES;
  1344. });
  1345. [self waitUntil:^BOOL {
  1346. return ready;
  1347. }];
  1348. }
  1349. - (void)testDedupeListensOnGrandchild {
  1350. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  1351. __block NSSet* listens;
  1352. __block BOOL ready = NO;
  1353. dispatch_async([FIRDatabaseQuery sharedQueue], ^{
  1354. listens = [self dumpListensForRef:ref];
  1355. XCTAssertTrue(listens.count == 0, @"No Listens yet");
  1356. ready = YES;
  1357. });
  1358. WAIT_FOR(ready);
  1359. [ref observeEventType:FIRDataEventTypeValue
  1360. withBlock:^(FIRDataSnapshot* snapshot){
  1361. }];
  1362. dispatch_async([FIRDatabaseQuery sharedQueue], ^{
  1363. listens = [self dumpListensForRef:ref];
  1364. NSSet* expected = [self expectDefaultListenerAtPath:[FPath empty]];
  1365. XCTAssertTrue([expected isEqualToSet:listens], @"Expected one listener");
  1366. ready = YES;
  1367. });
  1368. WAIT_FOR(ready);
  1369. [[ref child:@"a/aa"] observeEventType:FIRDataEventTypeValue
  1370. withBlock:^(FIRDataSnapshot* snapshot){
  1371. }];
  1372. ready = NO;
  1373. dispatch_async([FIRDatabaseQuery sharedQueue], ^{
  1374. listens = [self dumpListensForRef:ref];
  1375. NSSet* expected = [self expectDefaultListenerAtPath:[FPath empty]];
  1376. XCTAssertTrue([expected isEqualToSet:listens], @"Expected parent listener to override");
  1377. ready = YES;
  1378. });
  1379. WAIT_FOR(ready);
  1380. [ref removeAllObservers];
  1381. [[ref child:@"a/aa"] removeAllObservers];
  1382. ready = NO;
  1383. dispatch_async([FIRDatabaseQuery sharedQueue], ^{
  1384. listens = [self dumpListensForRef:ref];
  1385. XCTAssertTrue(listens.count == 0, @"No more listeners");
  1386. ready = YES;
  1387. });
  1388. WAIT_FOR(ready);
  1389. }
  1390. - (void)testListenOnGrandparentOfTwoChildren {
  1391. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  1392. __block NSSet* listens = [self dumpListensForRef:ref];
  1393. XCTAssertTrue(listens.count == 0, @"No Listens yet");
  1394. [[ref child:@"a/aa"] observeEventType:FIRDataEventTypeValue
  1395. withBlock:^(FIRDataSnapshot* snapshot){
  1396. }];
  1397. __block BOOL ready = NO;
  1398. dispatch_async([FIRDatabaseQuery sharedQueue], ^{
  1399. listens = [self dumpListensForRef:ref];
  1400. NSSet* expected = [self expectDefaultListenerAtPath:[FPath pathWithString:@"/a/aa"]];
  1401. XCTAssertTrue([expected isEqualToSet:listens], @"Expected grandchild");
  1402. ready = YES;
  1403. });
  1404. [self waitUntil:^BOOL {
  1405. return ready;
  1406. }];
  1407. [[ref child:@"a/bb"] observeEventType:FIRDataEventTypeValue
  1408. withBlock:^(FIRDataSnapshot* snapshot){
  1409. }];
  1410. ready = NO;
  1411. dispatch_async([FIRDatabaseQuery sharedQueue], ^{
  1412. listens = [self dumpListensForRef:ref];
  1413. NSSet* expecteda = [self expectDefaultListenerAtPath:[FPath pathWithString:@"/a/aa"]];
  1414. NSSet* expectedb = [self expectDefaultListenerAtPath:[FPath pathWithString:@"/a/bb"]];
  1415. NSMutableSet* expected = [NSMutableSet setWithSet:expecteda];
  1416. [expected unionSet:expectedb];
  1417. XCTAssertTrue([expected isEqualToSet:listens], @"Expected two grandchildren");
  1418. ready = YES;
  1419. });
  1420. [self waitUntil:^BOOL {
  1421. return ready;
  1422. }];
  1423. [ref observeEventType:FIRDataEventTypeValue
  1424. withBlock:^(FIRDataSnapshot* snapshot){
  1425. }];
  1426. ready = NO;
  1427. dispatch_async([FIRDatabaseQuery sharedQueue], ^{
  1428. listens = [self dumpListensForRef:ref];
  1429. NSSet* expected = [self expectDefaultListenerAtPath:[FPath empty]];
  1430. XCTAssertTrue([expected isEqualToSet:listens], @"Expected parent listener to override");
  1431. ready = YES;
  1432. });
  1433. [self waitUntil:^BOOL {
  1434. return ready;
  1435. }];
  1436. [ref removeAllObservers];
  1437. ready = NO;
  1438. dispatch_async([FIRDatabaseQuery sharedQueue], ^{
  1439. listens = [self dumpListensForRef:ref];
  1440. NSSet* expecteda = [self expectDefaultListenerAtPath:[FPath pathWithString:@"/a/aa"]];
  1441. NSSet* expectedb = [self expectDefaultListenerAtPath:[FPath pathWithString:@"/a/bb"]];
  1442. NSMutableSet* expected = [NSMutableSet setWithSet:expecteda];
  1443. [expected unionSet:expectedb];
  1444. XCTAssertTrue([expected isEqualToSet:listens], @"Expected grandchild listeners to return");
  1445. ready = YES;
  1446. });
  1447. [self waitUntil:^BOOL {
  1448. return ready;
  1449. }];
  1450. [[ref child:@"a/aa"] removeAllObservers];
  1451. ready = NO;
  1452. dispatch_async([FIRDatabaseQuery sharedQueue], ^{
  1453. listens = [self dumpListensForRef:ref];
  1454. NSSet* expected = [self expectDefaultListenerAtPath:[FPath pathWithString:@"/a/bb"]];
  1455. XCTAssertTrue([expected isEqualToSet:listens], @"Expected one listener");
  1456. ready = YES;
  1457. });
  1458. [self waitUntil:^BOOL {
  1459. return ready;
  1460. }];
  1461. [[ref child:@"a/bb"] removeAllObservers];
  1462. ready = NO;
  1463. dispatch_async([FIRDatabaseQuery sharedQueue], ^{
  1464. listens = [self dumpListensForRef:ref];
  1465. XCTAssertTrue(listens.count == 0, @"No more listeners");
  1466. ready = YES;
  1467. });
  1468. [self waitUntil:^BOOL {
  1469. return ready;
  1470. }];
  1471. }
  1472. - (void)testDedupingMultipleListenQueries {
  1473. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  1474. __block NSSet* listens = [self dumpListensForRef:ref];
  1475. XCTAssertTrue(listens.count == 0, @"No Listens yet");
  1476. __block BOOL ready = NO;
  1477. FIRDatabaseQuery* aLim1 = [[ref child:@"a"] queryLimitedToLast:1];
  1478. FIRDatabaseHandle handle1 = [aLim1 observeEventType:FIRDataEventTypeValue
  1479. withBlock:^(FIRDataSnapshot* snapshot){
  1480. }];
  1481. dispatch_async([FIRDatabaseQuery sharedQueue], ^{
  1482. listens = [self dumpListensForRef:ref];
  1483. FQueryParams* expectedParams = [[FQueryParams alloc] init];
  1484. expectedParams = [expectedParams limitTo:1];
  1485. NSSet* expected = [self expectParams:expectedParams atPath:[FPath pathWithString:@"/a"]];
  1486. XCTAssertTrue([expected isEqualToSet:listens], @"Single query");
  1487. ready = YES;
  1488. });
  1489. [self waitUntil:^BOOL {
  1490. return ready;
  1491. }];
  1492. ready = NO;
  1493. FIRDatabaseQuery* rootLim1 = [ref queryLimitedToLast:1];
  1494. FIRDatabaseHandle handle2 = [rootLim1 observeEventType:FIRDataEventTypeValue
  1495. withBlock:^(FIRDataSnapshot* snapshot){
  1496. }];
  1497. dispatch_async([FIRDatabaseQuery sharedQueue], ^{
  1498. listens = [self dumpListensForRef:ref];
  1499. FQueryParams* expectedParams = [[FQueryParams alloc] init];
  1500. expectedParams = [expectedParams limitTo:1];
  1501. NSSet* rootExpected = [self expectParams:expectedParams atPath:[FPath empty]];
  1502. NSSet* childExpected = [self expectParams:expectedParams atPath:[FPath pathWithString:@"/a"]];
  1503. NSMutableSet* expected = [NSMutableSet setWithSet:rootExpected];
  1504. [expected unionSet:childExpected];
  1505. XCTAssertTrue([expected isEqualToSet:listens], @"Two queries");
  1506. ready = YES;
  1507. });
  1508. [self waitUntil:^BOOL {
  1509. return ready;
  1510. }];
  1511. ready = NO;
  1512. FIRDatabaseQuery* aLim5 = [[ref child:@"a"] queryLimitedToLast:5];
  1513. FIRDatabaseHandle handle3 = [aLim5 observeEventType:FIRDataEventTypeValue
  1514. withBlock:^(FIRDataSnapshot* snapshot){
  1515. }];
  1516. dispatch_async([FIRDatabaseQuery sharedQueue], ^{
  1517. listens = [self dumpListensForRef:ref];
  1518. FQueryParams* expectedParams1 = [[FQueryParams alloc] init];
  1519. expectedParams1 = [expectedParams1 limitTo:1];
  1520. NSSet* rootExpected = [self expectParams:expectedParams1 atPath:[FPath empty]];
  1521. FQueryParams* expectedParams2 = [[FQueryParams alloc] init];
  1522. expectedParams2 = [expectedParams2 limitTo:5];
  1523. NSSet* childExpected =
  1524. [self expectParamssetValue:[NSSet setWithObjects:expectedParams1, expectedParams2, nil]
  1525. atPath:[FPath pathWithString:@"/a"]];
  1526. NSMutableSet* expected = [NSMutableSet setWithSet:childExpected];
  1527. [expected unionSet:rootExpected];
  1528. XCTAssertTrue([expected isEqualToSet:listens], @"Three queries");
  1529. ready = YES;
  1530. });
  1531. [self waitUntil:^BOOL {
  1532. return ready;
  1533. }];
  1534. [ref removeObserverWithHandle:handle2];
  1535. ready = NO;
  1536. dispatch_async([FIRDatabaseQuery sharedQueue], ^{
  1537. listens = [self dumpListensForRef:ref];
  1538. FQueryParams* expectedParams1 = [[FQueryParams alloc] init];
  1539. expectedParams1 = [expectedParams1 limitTo:1];
  1540. FQueryParams* expectedParams2 = [[FQueryParams alloc] init];
  1541. expectedParams2 = [expectedParams2 limitTo:5];
  1542. NSSet* expected =
  1543. [self expectParamssetValue:[NSSet setWithObjects:expectedParams1, expectedParams2, nil]
  1544. atPath:[FPath pathWithString:@"/a"]];
  1545. XCTAssertTrue([expected isEqualToSet:listens], @"Two queries");
  1546. ready = YES;
  1547. });
  1548. [self waitUntil:^BOOL {
  1549. return ready;
  1550. }];
  1551. [aLim1 removeObserverWithHandle:handle1];
  1552. [aLim5 removeObserverWithHandle:handle3];
  1553. ready = NO;
  1554. dispatch_async([FIRDatabaseQuery sharedQueue], ^{
  1555. listens = [self dumpListensForRef:ref];
  1556. XCTAssertTrue(listens.count == 0, @"No more listeners");
  1557. ready = YES;
  1558. });
  1559. [self waitUntil:^BOOL {
  1560. return ready;
  1561. }];
  1562. }
  1563. - (void)testListenOnParentOfQueriedChildren {
  1564. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  1565. __block NSSet* listens = [self dumpListensForRef:ref];
  1566. XCTAssertTrue(listens.count == 0, @"No Listens yet");
  1567. __block BOOL ready = NO;
  1568. FIRDatabaseQuery* aLim1 = [[ref child:@"a"] queryLimitedToLast:1];
  1569. FIRDatabaseHandle handle1 = [aLim1 observeEventType:FIRDataEventTypeValue
  1570. withBlock:^(FIRDataSnapshot* snapshot){
  1571. }];
  1572. dispatch_async([FIRDatabaseQuery sharedQueue], ^{
  1573. listens = [self dumpListensForRef:ref];
  1574. FQueryParams* expectedParams = [[FQueryParams alloc] init];
  1575. expectedParams = [expectedParams limitTo:1];
  1576. NSSet* expected = [self expectParams:expectedParams atPath:[FPath pathWithString:@"/a"]];
  1577. XCTAssertTrue([expected isEqualToSet:listens], @"Single query");
  1578. ready = YES;
  1579. });
  1580. [self waitUntil:^BOOL {
  1581. return ready;
  1582. }];
  1583. ready = NO;
  1584. FIRDatabaseQuery* bLim1 = [[ref child:@"b"] queryLimitedToLast:1];
  1585. FIRDatabaseHandle handle2 = [bLim1 observeEventType:FIRDataEventTypeValue
  1586. withBlock:^(FIRDataSnapshot* snapshot){
  1587. }];
  1588. dispatch_async([FIRDatabaseQuery sharedQueue], ^{
  1589. listens = [self dumpListensForRef:ref];
  1590. FQueryParams* expectedParams = [[FQueryParams alloc] init];
  1591. expectedParams = [expectedParams limitTo:1];
  1592. NSSet* expecteda = [self expectParams:expectedParams atPath:[FPath pathWithString:@"/a"]];
  1593. NSSet* expectedb = [self expectParams:expectedParams atPath:[FPath pathWithString:@"/b"]];
  1594. NSMutableSet* expected = [NSMutableSet setWithSet:expecteda];
  1595. [expected unionSet:expectedb];
  1596. XCTAssertTrue([expected isEqualToSet:listens], @"Two queries");
  1597. ready = YES;
  1598. });
  1599. [self waitUntil:^BOOL {
  1600. return ready;
  1601. }];
  1602. ready = NO;
  1603. FIRDatabaseHandle handle3 = [ref observeEventType:FIRDataEventTypeValue
  1604. withBlock:^(FIRDataSnapshot* snapshot){
  1605. }];
  1606. dispatch_async([FIRDatabaseQuery sharedQueue], ^{
  1607. listens = [self dumpListensForRef:ref];
  1608. NSSet* expected = [self expectDefaultListenerAtPath:[FPath empty]];
  1609. XCTAssertTrue([expected isEqualToSet:listens], @"Parent should override");
  1610. ready = YES;
  1611. });
  1612. [self waitUntil:^BOOL {
  1613. return ready;
  1614. }];
  1615. // remove in slightly random order
  1616. [aLim1 removeObserverWithHandle:handle1];
  1617. ready = NO;
  1618. dispatch_async([FIRDatabaseQuery sharedQueue], ^{
  1619. listens = [self dumpListensForRef:ref];
  1620. NSSet* expected = [self expectDefaultListenerAtPath:[FPath empty]];
  1621. XCTAssertTrue([expected isEqualToSet:listens], @"Parent should override");
  1622. ready = YES;
  1623. });
  1624. [self waitUntil:^BOOL {
  1625. return ready;
  1626. }];
  1627. [ref removeObserverWithHandle:handle3];
  1628. ready = NO;
  1629. dispatch_async([FIRDatabaseQuery sharedQueue], ^{
  1630. listens = [self dumpListensForRef:ref];
  1631. FQueryParams* expectedParams = [[FQueryParams alloc] init];
  1632. expectedParams = [expectedParams limitTo:1];
  1633. NSSet* expected = [self expectParams:expectedParams atPath:[FPath pathWithString:@"/b"]];
  1634. XCTAssertTrue([expected isEqualToSet:listens], @"Single query");
  1635. ready = YES;
  1636. });
  1637. [self waitUntil:^BOOL {
  1638. return ready;
  1639. }];
  1640. ready = NO;
  1641. [bLim1 removeObserverWithHandle:handle2];
  1642. dispatch_async([FIRDatabaseQuery sharedQueue], ^{
  1643. listens = [self dumpListensForRef:ref];
  1644. XCTAssertTrue(listens.count == 0, @"No more listeners");
  1645. ready = YES;
  1646. });
  1647. [self waitUntil:^BOOL {
  1648. return ready;
  1649. }];
  1650. }
  1651. - (void)testLimitWithMixOfNullAndNonNullPriorities {
  1652. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  1653. NSMutableArray* children = [[NSMutableArray alloc] init];
  1654. [[ref queryLimitedToLast:5] observeEventType:FIRDataEventTypeChildAdded
  1655. withBlock:^(FIRDataSnapshot* snapshot) {
  1656. [children addObject:[snapshot key]];
  1657. }];
  1658. __block BOOL ready = NO;
  1659. NSDictionary* toSet = @{
  1660. @"Vikrum" : @{@".priority" : @1000, @"score" : @1000, @"name" : @"Vikrum"},
  1661. @"Mike" : @{@".priority" : @500, @"score" : @500, @"name" : @"Mike"},
  1662. @"Andrew" : @{@".priority" : @50, @"score" : @50, @"name" : @"Andrew"},
  1663. @"James" : @{@".priority" : @7, @"score" : @7, @"name" : @"James"},
  1664. @"Sally" : @{@".priority" : @-7, @"score" : @-7, @"name" : @"Sally"},
  1665. @"Fred" : @{@"score" : @0, @"name" : @"Fred"}
  1666. };
  1667. [ref setValue:toSet
  1668. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  1669. ready = YES;
  1670. }];
  1671. [self waitUntil:^BOOL {
  1672. return ready;
  1673. }];
  1674. NSArray* expected = @[ @"Sally", @"James", @"Andrew", @"Mike", @"Vikrum" ];
  1675. XCTAssertTrue([children isEqualToArray:expected], @"Null priority should be left out");
  1676. }
  1677. - (void)testLimitWithMixOfNullAndNonNullPrioritiesOnServerData {
  1678. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  1679. __block BOOL ready = NO;
  1680. NSDictionary* toSet = @{
  1681. @"Vikrum" : @{@".priority" : @1000, @"score" : @1000, @"name" : @"Vikrum"},
  1682. @"Mike" : @{@".priority" : @500, @"score" : @500, @"name" : @"Mike"},
  1683. @"Andrew" : @{@".priority" : @50, @"score" : @50, @"name" : @"Andrew"},
  1684. @"James" : @{@".priority" : @7, @"score" : @7, @"name" : @"James"},
  1685. @"Sally" : @{@".priority" : @-7, @"score" : @-7, @"name" : @"Sally"},
  1686. @"Fred" : @{@"score" : @0, @"name" : @"Fred"}
  1687. };
  1688. [ref setValue:toSet
  1689. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  1690. ready = YES;
  1691. }];
  1692. [self waitUntil:^BOOL {
  1693. return ready;
  1694. }];
  1695. __block int count = 0;
  1696. NSMutableArray* children = [[NSMutableArray alloc] init];
  1697. [[ref queryLimitedToLast:5] observeEventType:FIRDataEventTypeChildAdded
  1698. withBlock:^(FIRDataSnapshot* snapshot) {
  1699. [children addObject:[snapshot key]];
  1700. count++;
  1701. }];
  1702. [self waitUntil:^BOOL {
  1703. return count == 5;
  1704. }];
  1705. NSArray* expected = @[ @"Sally", @"James", @"Andrew", @"Mike", @"Vikrum" ];
  1706. XCTAssertTrue([children isEqualToArray:expected], @"Null priority should be left out");
  1707. }
  1708. // Skipping context tests. Context is not implemented on iOS
  1709. /* DISABLING for now, since I'm not 100% sure what the right behavior is.
  1710. Perhaps a merge at /foo should shadow server updates at /foo instead of
  1711. just the modified children? Not sure.
  1712. - (void) testHandleUpdateThatDeletesEntireWindow {
  1713. Firebase* ref = [FTestHelpers getRandomNode];
  1714. NSMutableArray* snaps = [[NSMutableArray alloc] init];
  1715. [[ref queryLimitedToLast:2] observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot
  1716. *snapshot) { id val = [snapshot value]; if (val == nil) { [snaps addObject:[NSNull null]]; } else {
  1717. [snaps addObject:val];
  1718. }
  1719. }];
  1720. NSDictionary* toSet = @{
  1721. @"a": @{@".priority": @1, @".value": @1},
  1722. @"b": @{@".priority": @2, @".value": @2},
  1723. @"c": @{@".priority": @3, @".value": @3}
  1724. };
  1725. [ref setValue:toSet];
  1726. __block BOOL ready = NO;
  1727. toSet = @{@"b": [NSNull null], @"c": [NSNull null]};
  1728. [ref updateChildValues:toSet withCompletionBlock:^(NSError* err, Firebase* ref) {
  1729. ready = YES;
  1730. }];
  1731. [self waitUntil:^BOOL{
  1732. return ready;
  1733. }];
  1734. NSArray* expected = @[@{@"b": @2, @"c": @3}, [NSNull null], @{@"a": @1}];
  1735. STAssertTrue([snaps isEqualToArray:expected], @"Expected %@ to equal %@", snaps, expected);
  1736. }
  1737. */
  1738. - (void)testHandlesAnOutOfViewQueryOnAChild {
  1739. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  1740. __block NSDictionary* parent = nil;
  1741. [[ref queryLimitedToLast:1] observeEventType:FIRDataEventTypeValue
  1742. withBlock:^(FIRDataSnapshot* snapshot) {
  1743. parent = [snapshot value];
  1744. }];
  1745. __block NSNumber* child = nil;
  1746. [[ref child:@"a"] observeEventType:FIRDataEventTypeValue
  1747. withBlock:^(FIRDataSnapshot* snapshot) {
  1748. child = [snapshot value];
  1749. }];
  1750. __block BOOL ready = NO;
  1751. NSDictionary* toSet = @{@"a" : @1, @"b" : @2};
  1752. [ref setValue:toSet
  1753. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  1754. ready = YES;
  1755. }];
  1756. [self waitUntil:^BOOL {
  1757. return ready;
  1758. }];
  1759. NSDictionary* parentExpected = @{@"b" : @2};
  1760. NSNumber* childExpected = [NSNumber numberWithInt:1];
  1761. XCTAssertTrue([parent isEqualToDictionary:parentExpected], @"Expected last element");
  1762. XCTAssertTrue([child isEqualToNumber:childExpected], @"Expected value of a");
  1763. ready = NO;
  1764. [ref updateChildValues:@{@"c" : @3}
  1765. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  1766. ready = YES;
  1767. }];
  1768. [self waitUntil:^BOOL {
  1769. return ready;
  1770. }];
  1771. parentExpected = @{@"c" : @3};
  1772. XCTAssertTrue([parent isEqualToDictionary:parentExpected], @"Expected last element");
  1773. XCTAssertTrue([child isEqualToNumber:childExpected], @"Expected value of a");
  1774. }
  1775. - (void)testHandlesAChildQueryGoingOutOfViewOfTheParent {
  1776. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  1777. __block NSDictionary* parent = nil;
  1778. [[ref queryLimitedToLast:1] observeEventType:FIRDataEventTypeValue
  1779. withBlock:^(FIRDataSnapshot* snapshot) {
  1780. parent = [snapshot value];
  1781. }];
  1782. __block NSNumber* child = nil;
  1783. [[ref child:@"a"] observeEventType:FIRDataEventTypeValue
  1784. withBlock:^(FIRDataSnapshot* snapshot) {
  1785. child = [snapshot value];
  1786. }];
  1787. __block BOOL ready = NO;
  1788. NSDictionary* toSet = @{@"a" : @1};
  1789. [ref setValue:toSet
  1790. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  1791. ready = YES;
  1792. }];
  1793. WAIT_FOR(ready);
  1794. NSDictionary* parentExpected = @{@"a" : @1};
  1795. NSNumber* childExpected = [NSNumber numberWithInt:1];
  1796. XCTAssertTrue([parent isEqualToDictionary:parentExpected], @"Expected last element");
  1797. XCTAssertTrue([child isEqualToNumber:childExpected], @"Expected value of a");
  1798. ready = NO;
  1799. [[ref child:@"b"] setValue:@2
  1800. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  1801. ready = YES;
  1802. }];
  1803. WAIT_FOR(ready);
  1804. parentExpected = @{@"b" : @2};
  1805. XCTAssertTrue([parent isEqualToDictionary:parentExpected], @"Expected last element");
  1806. XCTAssertTrue([child isEqualToNumber:childExpected], @"Expected value of a");
  1807. ready = NO;
  1808. [[ref child:@"b"] removeValueWithCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  1809. ready = YES;
  1810. }];
  1811. [self waitUntil:^BOOL {
  1812. return ready;
  1813. }];
  1814. parentExpected = @{@"a" : @1};
  1815. XCTAssertTrue([parent isEqualToDictionary:parentExpected], @"Expected last element");
  1816. XCTAssertTrue([child isEqualToNumber:childExpected], @"Expected value of a");
  1817. }
  1818. - (void)testHandlesDivergingViews {
  1819. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  1820. __block NSDictionary* cVal = nil;
  1821. FIRDatabaseQuery* query =
  1822. [[[ref queryOrderedByPriority] queryEndingAtValue:nil childKey:@"c"] queryLimitedToLast:1];
  1823. [query observeEventType:FIRDataEventTypeValue
  1824. withBlock:^(FIRDataSnapshot* snapshot) {
  1825. cVal = [snapshot value];
  1826. }];
  1827. __block NSDictionary* dVal = nil;
  1828. query = [[[ref queryOrderedByPriority] queryEndingAtValue:nil
  1829. childKey:@"d"] queryLimitedToLast:1];
  1830. [query observeEventType:FIRDataEventTypeValue
  1831. withBlock:^(FIRDataSnapshot* snapshot) {
  1832. dVal = [snapshot value];
  1833. }];
  1834. __block BOOL ready = NO;
  1835. NSDictionary* toSet = @{@"a" : @1, @"b" : @2, @"c" : @3};
  1836. [ref setValue:toSet
  1837. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  1838. ready = YES;
  1839. }];
  1840. [self waitUntil:^BOOL {
  1841. return ready;
  1842. }];
  1843. NSDictionary* expected = @{@"c" : @3};
  1844. XCTAssertTrue([cVal isEqualToDictionary:expected], @"should be c");
  1845. XCTAssertTrue([dVal isEqualToDictionary:expected], @"should be c");
  1846. ready = NO;
  1847. [[ref child:@"d"] setValue:@4
  1848. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  1849. ready = YES;
  1850. }];
  1851. [self waitUntil:^BOOL {
  1852. return ready;
  1853. }];
  1854. XCTAssertTrue([cVal isEqualToDictionary:expected], @"should be c");
  1855. expected = @{@"d" : @4};
  1856. XCTAssertTrue([dVal isEqualToDictionary:expected], @"should be d");
  1857. }
  1858. - (void)testHandlesRemovingAQueriedElement {
  1859. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  1860. __block NSNumber* val = nil;
  1861. [[ref queryLimitedToLast:1] observeEventType:FIRDataEventTypeChildAdded
  1862. withBlock:^(FIRDataSnapshot* snapshot) {
  1863. id newVal = [snapshot value];
  1864. if (newVal != nil) {
  1865. val = [snapshot value];
  1866. }
  1867. }];
  1868. __block BOOL ready = NO;
  1869. [ref setValue:@{@"a" : @1, @"b" : @2}
  1870. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  1871. ready = YES;
  1872. }];
  1873. [self waitUntil:^BOOL {
  1874. return ready;
  1875. }];
  1876. XCTAssertTrue([val isEqualToNumber:@2], @"Expected last element in window");
  1877. ready = NO;
  1878. [[ref child:@"b"] removeValueWithCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  1879. ready = YES;
  1880. }];
  1881. [self waitUntil:^BOOL {
  1882. return ready;
  1883. }];
  1884. XCTAssertTrue([val isEqualToNumber:@1], @"Should now be the next element in the window");
  1885. }
  1886. - (void)testStartAtAndLimit1Works {
  1887. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  1888. __block NSNumber* val = nil;
  1889. FIRDatabaseQuery* query =
  1890. [[[ref queryOrderedByPriority] queryStartingAtValue:nil] queryLimitedToFirst:1];
  1891. [query observeEventType:FIRDataEventTypeChildAdded
  1892. withBlock:^(FIRDataSnapshot* snapshot) {
  1893. id newVal = [snapshot value];
  1894. if (newVal != nil) {
  1895. val = [snapshot value];
  1896. }
  1897. }];
  1898. __block BOOL ready = NO;
  1899. [ref setValue:@{@"a" : @1, @"b" : @2}
  1900. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  1901. ready = YES;
  1902. }];
  1903. [self waitUntil:^BOOL {
  1904. return ready;
  1905. }];
  1906. XCTAssertTrue([val isEqualToNumber:@1], @"Expected first element in window");
  1907. }
  1908. // See case 1664
  1909. - (void)testStartAtAndLimit1AndRemoveFirstChild {
  1910. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  1911. __block NSNumber* val = nil;
  1912. FIRDatabaseQuery* query =
  1913. [[[ref queryOrderedByPriority] queryStartingAtValue:nil] queryLimitedToFirst:1];
  1914. [query observeEventType:FIRDataEventTypeChildAdded
  1915. withBlock:^(FIRDataSnapshot* snapshot) {
  1916. id newVal = [snapshot value];
  1917. if (newVal != nil) {
  1918. val = [snapshot value];
  1919. }
  1920. }];
  1921. __block BOOL ready = NO;
  1922. [ref setValue:@{@"a" : @1, @"b" : @2}
  1923. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  1924. ready = YES;
  1925. }];
  1926. [self waitUntil:^BOOL {
  1927. return ready;
  1928. }];
  1929. XCTAssertTrue([val isEqualToNumber:@1], @"Expected first element in window");
  1930. ready = NO;
  1931. [[ref child:@"a"] removeValueWithCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  1932. ready = YES;
  1933. }];
  1934. [self waitUntil:^BOOL {
  1935. return ready;
  1936. }];
  1937. XCTAssertTrue([val isEqualToNumber:@2], @"Expected next element in window");
  1938. }
  1939. // See case 1169
  1940. - (void)testStartAtWithTwoArgumentsWorks {
  1941. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  1942. __block BOOL ready = NO;
  1943. NSMutableArray* children = [[NSMutableArray alloc] init];
  1944. NSDictionary* toSet = @{
  1945. @"Walker" : @{@"name" : @"Walker", @"score" : @20, @".priority" : @20},
  1946. @"Michael" : @{@"name" : @"Michael", @"score" : @100, @".priority" : @100}
  1947. };
  1948. [ref setValue:toSet
  1949. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  1950. ready = YES;
  1951. }];
  1952. [self waitUntil:^BOOL {
  1953. return ready;
  1954. }];
  1955. ready = NO;
  1956. FIRDatabaseQuery* query =
  1957. [[[ref queryOrderedByPriority] queryStartingAtValue:@20
  1958. childKey:@"Walker"] queryLimitedToFirst:2];
  1959. [query observeEventType:FIRDataEventTypeValue
  1960. withBlock:^(FIRDataSnapshot* snapshot) {
  1961. for (FIRDataSnapshot* child in snapshot.children) {
  1962. [children addObject:child.key];
  1963. }
  1964. ready = YES;
  1965. }];
  1966. [self waitUntil:^BOOL {
  1967. return ready;
  1968. }];
  1969. NSArray* expected = @[ @"Walker", @"Michael" ];
  1970. XCTAssertTrue([children isEqualToArray:expected], @"Expected both children");
  1971. }
  1972. - (void)testHandlesMultipleQueriesOnSameNode {
  1973. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  1974. __block BOOL ready = NO;
  1975. NSDictionary* toSet = @{@"a" : @1, @"b" : @2, @"c" : @3, @"d" : @4, @"e" : @5, @"f" : @6};
  1976. [ref setValue:toSet
  1977. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  1978. ready = YES;
  1979. }];
  1980. [self waitUntil:^BOOL {
  1981. return ready;
  1982. }];
  1983. ready = NO;
  1984. __block BOOL called = NO;
  1985. [[ref queryLimitedToLast:2]
  1986. observeEventType:FIRDataEventTypeValue
  1987. withBlock:^(FIRDataSnapshot* snapshot) {
  1988. // we got the initial data
  1989. XCTAssertFalse(called,
  1990. @"This should only get called once, we don't update data after this");
  1991. called = YES;
  1992. ready = YES;
  1993. }];
  1994. [self waitUntil:^BOOL {
  1995. return ready;
  1996. }];
  1997. ready = NO;
  1998. __block NSDictionary* snap = nil;
  1999. // now do nested once calls
  2000. [[ref queryLimitedToLast:1]
  2001. observeSingleEventOfType:FIRDataEventTypeValue
  2002. withBlock:^(FIRDataSnapshot* snapshot) {
  2003. [[ref queryLimitedToLast:1]
  2004. observeSingleEventOfType:FIRDataEventTypeValue
  2005. withBlock:^(FIRDataSnapshot* snapshot) {
  2006. snap = [snapshot value];
  2007. ready = YES;
  2008. }];
  2009. }];
  2010. [self waitUntil:^BOOL {
  2011. return ready;
  2012. }];
  2013. NSDictionary* expected = @{@"f" : @6};
  2014. XCTAssertTrue([snap isEqualToDictionary:expected], @"Expected the correct data");
  2015. }
  2016. - (void)testHandlesOnceCalledOnNodeWithDefaultListener {
  2017. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  2018. __block BOOL ready = NO;
  2019. NSDictionary* toSet = @{@"a" : @1, @"b" : @2, @"c" : @3, @"d" : @4, @"e" : @5, @"f" : @6};
  2020. [ref setValue:toSet
  2021. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  2022. ready = YES;
  2023. }];
  2024. [self waitUntil:^BOOL {
  2025. return ready;
  2026. }];
  2027. ready = NO;
  2028. [ref observeEventType:FIRDataEventTypeValue
  2029. withBlock:^(FIRDataSnapshot* snapshot) {
  2030. // we got the initial data
  2031. ready = YES;
  2032. }];
  2033. [self waitUntil:^BOOL {
  2034. return ready;
  2035. }];
  2036. ready = NO;
  2037. __block NSNumber* snap = nil;
  2038. [[ref queryLimitedToLast:1] observeSingleEventOfType:FIRDataEventTypeChildAdded
  2039. withBlock:^(FIRDataSnapshot* snapshot) {
  2040. snap = [snapshot value];
  2041. ready = YES;
  2042. }];
  2043. [self waitUntil:^BOOL {
  2044. return ready;
  2045. }];
  2046. XCTAssertTrue([snap isEqualToNumber:@6], @"Got once response");
  2047. }
  2048. - (void)testHandlesOnceCalledOnNodeWithDefaultListenerAndNonCompleteLimit {
  2049. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  2050. __block BOOL ready = NO;
  2051. NSDictionary* toSet = @{@"a" : @1, @"b" : @2, @"c" : @3};
  2052. [ref setValue:toSet
  2053. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  2054. ready = YES;
  2055. }];
  2056. [self waitUntil:^BOOL {
  2057. return ready;
  2058. }];
  2059. ready = NO;
  2060. // do first listen
  2061. [ref observeEventType:FIRDataEventTypeValue
  2062. withBlock:^(FIRDataSnapshot* snapshot) {
  2063. ready = YES;
  2064. }];
  2065. [self waitUntil:^BOOL {
  2066. return ready;
  2067. }];
  2068. ready = NO;
  2069. __block NSDictionary* snap = nil;
  2070. [[ref queryLimitedToLast:5] observeSingleEventOfType:FIRDataEventTypeValue
  2071. withBlock:^(FIRDataSnapshot* snapshot) {
  2072. snap = [snapshot value];
  2073. ready = YES;
  2074. }];
  2075. [self waitUntil:^BOOL {
  2076. return ready;
  2077. }];
  2078. NSDictionary* expected = @{@"a" : @1, @"b" : @2, @"c" : @3};
  2079. XCTAssertTrue([snap isEqualToDictionary:expected], @"Got once response");
  2080. }
  2081. - (void)testRemoveTriggersRemoteEvents {
  2082. FTupleFirebase* tuple = [FTestHelpers getRandomNodePair];
  2083. FIRDatabaseReference* writer = tuple.one;
  2084. FIRDatabaseReference* reader = tuple.two;
  2085. __block BOOL ready = NO;
  2086. NSDictionary* toSet = @{@"a" : @"a", @"b" : @"b", @"c" : @"c", @"d" : @"d", @"e" : @"e"};
  2087. [writer setValue:toSet
  2088. withCompletionBlock:^(NSError* err, FIRDatabaseReference* ref) {
  2089. ready = YES;
  2090. }];
  2091. [self waitUntil:^BOOL {
  2092. return ready;
  2093. }];
  2094. ready = NO;
  2095. __block int count = 0;
  2096. [[reader queryLimitedToLast:5]
  2097. observeEventType:FIRDataEventTypeValue
  2098. withBlock:^(FIRDataSnapshot* snapshot) {
  2099. count++;
  2100. if (count == 1) {
  2101. NSDictionary* val = [snapshot value];
  2102. NSDictionary* expected =
  2103. @{@"a" : @"a", @"b" : @"b", @"c" : @"c", @"d" : @"d", @"e" : @"e"};
  2104. XCTAssertTrue([val isEqualToDictionary:expected],
  2105. @"First callback, expect all the data");
  2106. [[writer child:@"c"] removeValue];
  2107. } else {
  2108. XCTAssertTrue(count == 2, @"Should only get called twice");
  2109. NSDictionary* val = [snapshot value];
  2110. NSDictionary* expected = @{@"a" : @"a", @"b" : @"b", @"d" : @"d", @"e" : @"e"};
  2111. XCTAssertTrue([val isEqualToDictionary:expected],
  2112. @"Second callback, expect all the remaining data");
  2113. ready = YES;
  2114. }
  2115. }];
  2116. [self waitUntil:^BOOL {
  2117. return ready;
  2118. }];
  2119. }
  2120. - (void)testEndingAtNameReturnsCorrectChildren {
  2121. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  2122. NSDictionary* toSet = @{
  2123. @"a" : @"a",
  2124. @"b" : @"b",
  2125. @"c" : @"c",
  2126. @"d" : @"d",
  2127. @"e" : @"e",
  2128. @"f" : @"f",
  2129. @"g" : @"g",
  2130. @"h" : @"h"
  2131. };
  2132. [self waitForCompletionOf:ref setValue:toSet];
  2133. __block NSDictionary* snap = nil;
  2134. __block BOOL done = NO;
  2135. FIRDatabaseQuery* query =
  2136. [[[ref queryOrderedByPriority] queryEndingAtValue:nil childKey:@"f"] queryLimitedToLast:5];
  2137. [query observeEventType:FIRDataEventTypeValue
  2138. withBlock:^(FIRDataSnapshot* snapshot) {
  2139. snap = [snapshot value];
  2140. done = YES;
  2141. }];
  2142. [self waitUntil:^BOOL {
  2143. return done;
  2144. }];
  2145. NSDictionary* expected = @{@"b" : @"b", @"c" : @"c", @"d" : @"d", @"e" : @"e", @"f" : @"f"};
  2146. XCTAssertTrue([snap isEqualToDictionary:expected], @"Expected 5 elements, ending at f");
  2147. }
  2148. - (void)testListenForChildAddedWithLimitEnsureEventsFireProperly {
  2149. FTupleFirebase* refs = [FTestHelpers getRandomNodePair];
  2150. FIRDatabaseReference* writer = refs.one;
  2151. FIRDatabaseReference* reader = refs.two;
  2152. __block BOOL done = NO;
  2153. NSDictionary* toSet =
  2154. @{@"a" : @1, @"b" : @"b", @"c" : @{@"deep" : @"path", @"of" : @{@"stuff" : @YES}}};
  2155. [writer setValue:toSet
  2156. withCompletionBlock:^(NSError* error, FIRDatabaseReference* ref) {
  2157. done = YES;
  2158. }];
  2159. WAIT_FOR(done);
  2160. __block int count = 0;
  2161. [[reader queryLimitedToLast:3]
  2162. observeEventType:FIRDataEventTypeChildAdded
  2163. withBlock:^(FIRDataSnapshot* snapshot) {
  2164. count++;
  2165. if (count == 1) {
  2166. XCTAssertTrue([snapshot.key isEqualToString:@"a"], @"Got first child");
  2167. XCTAssertTrue([snapshot.value isEqualToNumber:@1], @"Got correct value");
  2168. } else if (count == 2) {
  2169. XCTAssertTrue([snapshot.key isEqualToString:@"b"], @"Got second child");
  2170. XCTAssertTrue([snapshot.value isEqualToString:@"b"], @"got correct value");
  2171. } else if (count == 3) {
  2172. XCTAssertTrue([snapshot.key isEqualToString:@"c"], @"Got third child");
  2173. NSDictionary* expected = @{@"deep" : @"path", @"of" : @{@"stuff" : @YES}};
  2174. XCTAssertTrue([snapshot.value isEqualToDictionary:expected], @"Got deep object");
  2175. } else {
  2176. XCTFail(@"wrong event count");
  2177. }
  2178. }];
  2179. WAIT_FOR(count == 3);
  2180. }
  2181. #ifdef FLAKY_TEST
  2182. - (void)testListenForChildChangedWithLimitEnsureEventsFireProperly {
  2183. FTupleFirebase* refs = [FTestHelpers getRandomNodePair];
  2184. FIRDatabaseReference* writer = refs.one;
  2185. FIRDatabaseReference* reader = refs.two;
  2186. __block BOOL done = NO;
  2187. NSDictionary* toSet = @{@"a" : @"something", @"b" : @"we'll", @"c" : @"overwrite"};
  2188. [writer setValue:toSet
  2189. withCompletionBlock:^(NSError* error, FIRDatabaseReference* ref) {
  2190. done = YES;
  2191. }];
  2192. WAIT_FOR(done);
  2193. __block int count = 0;
  2194. [reader
  2195. observeEventType:FIRDataEventTypeChildChanged
  2196. withBlock:^(FIRDataSnapshot* snapshot) {
  2197. count++;
  2198. if (count == 1) {
  2199. XCTAssertTrue([snapshot.key isEqualToString:@"a"], @"Got first child");
  2200. XCTAssertTrue([snapshot.value isEqualToNumber:@1], @"Got correct value");
  2201. } else if (count == 2) {
  2202. XCTAssertTrue([snapshot.key isEqualToString:@"b"], @"Got second child");
  2203. XCTAssertTrue([snapshot.value isEqualToString:@"b"], @"got correct value");
  2204. } else if (count == 3) {
  2205. XCTAssertTrue([snapshot.key isEqualToString:@"c"], @"Got third child");
  2206. NSDictionary* expected = @{@"deep" : @"path", @"of" : @{@"stuff" : @YES}};
  2207. XCTAssertTrue([snapshot.value isEqualToDictionary:expected], @"Got deep object");
  2208. } else {
  2209. XCTFail(@"wrong event count");
  2210. }
  2211. }];
  2212. toSet = @{@"a" : @1, @"b" : @"b", @"c" : @{@"deep" : @"path", @"of" : @{@"stuff" : @YES}}};
  2213. [writer setValue:toSet];
  2214. WAIT_FOR(count == 3);
  2215. }
  2216. #endif
  2217. - (void)testListenForChildRemovedWithLimitEnsureEventsFireProperly {
  2218. FTupleFirebase* refs = [FTestHelpers getRandomNodePair];
  2219. FIRDatabaseReference* writer = refs.one;
  2220. FIRDatabaseReference* reader = refs.two;
  2221. __block BOOL done = NO;
  2222. NSDictionary* toSet =
  2223. @{@"a" : @1, @"b" : @"b", @"c" : @{@"deep" : @"path", @"of" : @{@"stuff" : @YES}}};
  2224. [writer setValue:toSet
  2225. withCompletionBlock:^(NSError* error, FIRDatabaseReference* ref) {
  2226. done = YES;
  2227. }];
  2228. WAIT_FOR(done);
  2229. __block int count = 0;
  2230. [reader
  2231. observeEventType:FIRDataEventTypeChildRemoved
  2232. withBlock:^(FIRDataSnapshot* snapshot) {
  2233. count++;
  2234. if (count == 1) {
  2235. XCTAssertTrue([snapshot.key isEqualToString:@"a"], @"Got first child");
  2236. XCTAssertTrue([snapshot.value isEqualToNumber:@1], @"Got correct value");
  2237. } else if (count == 2) {
  2238. XCTAssertTrue([snapshot.key isEqualToString:@"b"], @"Got second child");
  2239. XCTAssertTrue([snapshot.value isEqualToString:@"b"], @"got correct value");
  2240. } else if (count == 3) {
  2241. XCTAssertTrue([snapshot.key isEqualToString:@"c"], @"Got third child");
  2242. NSDictionary* expected = @{@"deep" : @"path", @"of" : @{@"stuff" : @YES}};
  2243. XCTAssertTrue([snapshot.value isEqualToDictionary:expected], @"Got deep object");
  2244. } else {
  2245. XCTFail(@"wrong event count");
  2246. }
  2247. }];
  2248. done = NO;
  2249. [reader observeEventType:FIRDataEventTypeValue
  2250. withBlock:^(FIRDataSnapshot* snapshot) {
  2251. // Load the data first
  2252. done = snapshot.value != [NSNull null] &&
  2253. [snapshot.value isEqualToDictionary:toSet];
  2254. }];
  2255. WAIT_FOR(done);
  2256. // Now do the removes
  2257. [[writer child:@"a"] removeValue];
  2258. [[writer child:@"b"] removeValue];
  2259. [[writer child:@"c"] removeValue];
  2260. WAIT_FOR(count == 3);
  2261. }
  2262. - (void)testQueriesBehaveProperlyAfterOnceCall {
  2263. FTupleFirebase* refs = [FTestHelpers getRandomNodePair];
  2264. FIRDatabaseReference* writer = refs.one;
  2265. FIRDatabaseReference* reader = refs.two;
  2266. __block BOOL done = NO;
  2267. NSDictionary* toSet = @{@"a" : @1, @"b" : @2, @"c" : @3, @"d" : @4};
  2268. [writer setValue:toSet
  2269. withCompletionBlock:^(NSError* error, FIRDatabaseReference* ref) {
  2270. done = YES;
  2271. }];
  2272. WAIT_FOR(done);
  2273. done = NO;
  2274. [reader observeSingleEventOfType:FIRDataEventTypeValue
  2275. withBlock:^(FIRDataSnapshot* snapshot) {
  2276. done = YES;
  2277. }];
  2278. WAIT_FOR(done);
  2279. // Ok, now do some queries
  2280. __block int startCount = 0;
  2281. __block int defaultCount = 0;
  2282. [[[reader queryOrderedByPriority] queryStartingAtValue:nil childKey:@"d"]
  2283. observeEventType:FIRDataEventTypeChildAdded
  2284. withBlock:^(FIRDataSnapshot* snapshot) {
  2285. startCount++;
  2286. }];
  2287. [reader observeEventType:FIRDataEventTypeChildAdded
  2288. withBlock:^(FIRDataSnapshot* snapshot) {
  2289. defaultCount++;
  2290. }];
  2291. [reader observeEventType:FIRDataEventTypeChildRemoved
  2292. withBlock:^(FIRDataSnapshot* snapshot) {
  2293. XCTFail(@"Should not remove any children");
  2294. }];
  2295. WAIT_FOR(startCount == 1 && defaultCount == 4);
  2296. }
  2297. - (void)testIntegerKeysBehaveNumerically1 {
  2298. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  2299. NSDictionary* toSet = @{
  2300. @"1" : @YES,
  2301. @"50" : @YES,
  2302. @"550" : @YES,
  2303. @"6" : @YES,
  2304. @"600" : @YES,
  2305. @"70" : @YES,
  2306. @"8" : @YES,
  2307. @"80" : @YES
  2308. };
  2309. __block BOOL done = NO;
  2310. [ref setValue:toSet
  2311. withCompletionBlock:^(NSError* error, FIRDatabaseReference* ref) {
  2312. [[[ref queryOrderedByPriority] queryStartingAtValue:nil childKey:@"80"]
  2313. observeSingleEventOfType:FIRDataEventTypeValue
  2314. withBlock:^(FIRDataSnapshot* snapshot) {
  2315. NSDictionary* expected = @{@"80" : @YES, @"550" : @YES, @"600" : @YES};
  2316. XCTAssertTrue([snapshot.value isEqualToDictionary:expected],
  2317. @"Got correct result.");
  2318. done = YES;
  2319. }];
  2320. }];
  2321. WAIT_FOR(done);
  2322. }
  2323. - (void)testIntegerKeysBehaveNumerically2 {
  2324. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  2325. NSDictionary* toSet = @{
  2326. @"1" : @YES,
  2327. @"50" : @YES,
  2328. @"550" : @YES,
  2329. @"6" : @YES,
  2330. @"600" : @YES,
  2331. @"70" : @YES,
  2332. @"8" : @YES,
  2333. @"80" : @YES
  2334. };
  2335. __block BOOL done = NO;
  2336. [ref setValue:toSet
  2337. withCompletionBlock:^(NSError* error, FIRDatabaseReference* ref) {
  2338. [[[ref queryOrderedByPriority] queryEndingAtValue:nil childKey:@"50"]
  2339. observeSingleEventOfType:FIRDataEventTypeValue
  2340. withBlock:^(FIRDataSnapshot* snapshot) {
  2341. NSDictionary* expected =
  2342. @{@"1" : @YES,
  2343. @"6" : @YES,
  2344. @"8" : @YES,
  2345. @"50" : @YES};
  2346. XCTAssertTrue([snapshot.value isEqualToDictionary:expected],
  2347. @"Got correct result.");
  2348. done = YES;
  2349. }];
  2350. }];
  2351. WAIT_FOR(done);
  2352. }
  2353. - (void)testIntegerKeysBehaveNumerically3 {
  2354. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  2355. NSDictionary* toSet = @{
  2356. @"1" : @YES,
  2357. @"50" : @YES,
  2358. @"550" : @YES,
  2359. @"6" : @YES,
  2360. @"600" : @YES,
  2361. @"70" : @YES,
  2362. @"8" : @YES,
  2363. @"80" : @YES
  2364. };
  2365. __block BOOL done = NO;
  2366. [ref setValue:toSet
  2367. withCompletionBlock:^(NSError* error, FIRDatabaseReference* ref) {
  2368. [[[[ref queryOrderedByPriority] queryStartingAtValue:nil
  2369. childKey:@"50"] queryEndingAtValue:nil
  2370. childKey:@"80"]
  2371. observeSingleEventOfType:FIRDataEventTypeValue
  2372. withBlock:^(FIRDataSnapshot* snapshot) {
  2373. NSDictionary* expected = @{@"50" : @YES, @"70" : @YES, @"80" : @YES};
  2374. XCTAssertTrue([snapshot.value isEqualToDictionary:expected],
  2375. @"Got correct result.");
  2376. done = YES;
  2377. }];
  2378. }];
  2379. WAIT_FOR(done);
  2380. }
  2381. - (void)testItemsPulledIntoLimitCorrectly {
  2382. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  2383. NSMutableArray* snaps = [[NSMutableArray alloc] init];
  2384. // Just so everything is cached locally.
  2385. [ref observeEventType:FIRDataEventTypeValue
  2386. withBlock:^(FIRDataSnapshot* snapshot){
  2387. }];
  2388. [[ref queryLimitedToLast:2] observeEventType:FIRDataEventTypeValue
  2389. withBlock:^(FIRDataSnapshot* snapshot) {
  2390. id val = [snapshot value];
  2391. [snaps addObject:val];
  2392. }];
  2393. [ref setValue:@{
  2394. @"a" : @{@".value" : @1, @".priority" : @1},
  2395. @"b" : @{@".value" : @2, @".priority" : @2},
  2396. @"c" : @{@".value" : @3, @".priority" : @3}
  2397. }];
  2398. __block BOOL ready = NO;
  2399. [[ref child:@"b"] setValue:[NSNull null]
  2400. withCompletionBlock:^(NSError* error, FIRDatabaseReference* ref) {
  2401. ready = YES;
  2402. }];
  2403. WAIT_FOR(ready);
  2404. NSArray* expected = @[ @{@"b" : @2, @"c" : @3}, @{@"a" : @1, @"c" : @3} ];
  2405. XCTAssertEqualObjects(snaps, expected, @"Incorrect snapshots.");
  2406. }
  2407. - (void)testChildChangedCausesChildRemovedEvent {
  2408. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  2409. [[ref child:@"l/a"] setValue:@"1" andPriority:@"a"];
  2410. [[ref child:@"l/b"] setValue:@"2" andPriority:@"b"];
  2411. FIRDatabaseQuery* query = [[[[ref child:@"l"] queryOrderedByPriority] queryStartingAtValue:@"b"]
  2412. queryEndingAtValue:@"d"];
  2413. __block BOOL removed = NO;
  2414. [query observeEventType:FIRDataEventTypeChildRemoved
  2415. withBlock:^(FIRDataSnapshot* snapshot) {
  2416. XCTAssertEqualObjects(snapshot.value, @"2", @"Incorrect snapshot");
  2417. removed = YES;
  2418. }];
  2419. [[ref child:@"l/b"] setValue:@"4" andPriority:@"a"];
  2420. WAIT_FOR(removed);
  2421. }
  2422. - (void)testQueryHasRef {
  2423. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  2424. FIRDatabaseQuery* query = [ref queryOrderedByKey];
  2425. XCTAssertEqualObjects([query.ref path], [ref path], @"Should have same path");
  2426. }
  2427. - (void)testQuerySnapshotChildrenRespectDefaultOrdering {
  2428. FTupleFirebase* pair = [FTestHelpers getRandomNodePair];
  2429. FIRDatabaseReference* writer = pair.one;
  2430. FIRDatabaseReference* reader = pair.two;
  2431. __block BOOL done = NO;
  2432. NSDictionary* list = @{
  2433. @"a" : @{
  2434. @"thisvaluefirst" : @{@".value" : @true, @".priority" : @1},
  2435. @"name" : @{@".value" : @"Michael", @".priority" : @2},
  2436. @"thisvaluelast" : @{@".value" : @true, @".priority" : @3},
  2437. },
  2438. @"b" : @{
  2439. @"thisvaluefirst" : @{@".value" : @true},
  2440. @"name" : @{@".value" : @"Rob", @".priority" : @2},
  2441. @"thisvaluelast" : @{@".value" : @true, @".priority" : @3},
  2442. },
  2443. @"c" : @{
  2444. @"thisvaluefirst" : @{@".value" : @true, @".priority" : @1},
  2445. @"name" : @{@".value" : @"Jonny", @".priority" : @2},
  2446. @"thisvaluelast" : @{@".value" : @true, @".priority" : @"somestring"},
  2447. }
  2448. };
  2449. [writer setValue:list
  2450. withCompletionBlock:^(NSError* error, FIRDatabaseReference* ref) {
  2451. done = YES;
  2452. }];
  2453. WAIT_FOR(done);
  2454. done = NO;
  2455. [[reader queryOrderedByChild:@"name"]
  2456. observeSingleEventOfType:FIRDataEventTypeValue
  2457. withBlock:^(FIRDataSnapshot* snapshot) {
  2458. NSArray* expectedKeys = @[ @"thisvaluefirst", @"name", @"thisvaluelast" ];
  2459. NSArray* expectedNames = @[ @"Jonny", @"Michael", @"Rob" ];
  2460. // Validate that snap.child() resets order to default for child snaps
  2461. NSMutableArray* orderedKeys = [[NSMutableArray alloc] init];
  2462. for (FIRDataSnapshot* childSnap in [snapshot childSnapshotForPath:@"b"]
  2463. .children) {
  2464. [orderedKeys addObject:childSnap.key];
  2465. }
  2466. XCTAssertEqualObjects(expectedKeys, orderedKeys,
  2467. @"Should have matching ordered lists of keys");
  2468. // Validate that snap.forEach() resets ordering to default for child snaps
  2469. NSMutableArray* orderedNames = [[NSMutableArray alloc] init];
  2470. for (FIRDataSnapshot* childSnap in snapshot.children) {
  2471. [orderedNames addObject:[childSnap childSnapshotForPath:@"name"].value];
  2472. [orderedKeys removeAllObjects];
  2473. for (FIRDataSnapshot* grandchildSnap in childSnap.children) {
  2474. [orderedKeys addObject:grandchildSnap.key];
  2475. }
  2476. XCTAssertEqualObjects(expectedKeys, orderedKeys,
  2477. @"Should have matching ordered lists of keys");
  2478. }
  2479. XCTAssertEqualObjects(expectedNames, orderedNames,
  2480. @"Should have matching ordered lists of names");
  2481. done = YES;
  2482. }];
  2483. WAIT_FOR(done);
  2484. }
  2485. - (void)testAddingListensForTheSamePathDoesNotCheckFail {
  2486. // This bug manifests itself if there's a hierarchy of query listener, default listener and
  2487. // one-time listener underneath. In Java implementation, during one-time listener registration,
  2488. // sync-tree traversal stopped as soon as it found a complete server cache (this is the case for
  2489. // not indexed query view). The problem is that the same traversal was looking for a ancestor
  2490. // default view, and the early exit prevented from finding the default listener above the one-time
  2491. // listener. Event removal code path wasn't removing the listener because it stopped as soon as it
  2492. // found the default view. This left the zombie one-time listener and check failed on the second
  2493. // attempt to create a listener for the same path (asana#61028598952586).
  2494. FIRDatabaseReference* ref = [FTestHelpers getRandomNode];
  2495. __block BOOL done = NO;
  2496. [[ref child:@"child"] setValue:@{@"name" : @"John"}];
  2497. [[[ref queryOrderedByChild:@"name"] queryEqualToValue:@"John"]
  2498. observeEventType:FIRDataEventTypeValue
  2499. withBlock:^(FIRDataSnapshot* snapshot) {
  2500. done = YES;
  2501. }];
  2502. WAIT_FOR(done);
  2503. done = NO;
  2504. [[[ref child:@"child"] child:@"favoriteToy"]
  2505. observeSingleEventOfType:FIRDataEventTypeValue
  2506. withBlock:^(FIRDataSnapshot* snapshot) {
  2507. done = YES;
  2508. }];
  2509. WAIT_FOR(done);
  2510. done = NO;
  2511. [[[ref child:@"child"] child:@"favoriteToy"]
  2512. observeSingleEventOfType:FIRDataEventTypeValue
  2513. withBlock:^(FIRDataSnapshot* snapshot) {
  2514. done = YES;
  2515. }];
  2516. WAIT_FOR(done);
  2517. }
  2518. @end