FIRDatabaseQueryTests.m 99 KB

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