FIRDatabaseTests.m 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741
  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 Firestore;
  17. #import <XCTest/XCTest.h>
  18. #import "FSTIntegrationTestCase.h"
  19. @interface FIRDatabaseTests : FSTIntegrationTestCase
  20. @end
  21. @implementation FIRDatabaseTests
  22. - (void)testCanUpdateAnExistingDocument {
  23. FIRDocumentReference *doc = [self.db documentWithPath:@"rooms/eros"];
  24. NSDictionary<NSString *, id> *initialData =
  25. @{ @"desc" : @"Description",
  26. @"owner" : @{@"name" : @"Jonny", @"email" : @"abc@xyz.com"} };
  27. NSDictionary<NSString *, id> *updateData =
  28. @{@"desc" : @"NewDescription", @"owner.email" : @"new@xyz.com"};
  29. NSDictionary<NSString *, id> *finalData =
  30. @{ @"desc" : @"NewDescription",
  31. @"owner" : @{@"name" : @"Jonny", @"email" : @"new@xyz.com"} };
  32. [self writeDocumentRef:doc data:initialData];
  33. XCTestExpectation *updateCompletion = [self expectationWithDescription:@"updateData"];
  34. [doc updateData:updateData
  35. completion:^(NSError *_Nullable error) {
  36. XCTAssertNil(error);
  37. [updateCompletion fulfill];
  38. }];
  39. [self awaitExpectations];
  40. FIRDocumentSnapshot *result = [self readDocumentForRef:doc];
  41. XCTAssertTrue(result.exists);
  42. XCTAssertEqualObjects(result.data, finalData);
  43. }
  44. - (void)testCanDeleteAFieldWithAnUpdate {
  45. FIRDocumentReference *doc = [self.db documentWithPath:@"rooms/eros"];
  46. NSDictionary<NSString *, id> *initialData =
  47. @{ @"desc" : @"Description",
  48. @"owner" : @{@"name" : @"Jonny", @"email" : @"abc@xyz.com"} };
  49. NSDictionary<NSString *, id> *updateData =
  50. @{@"owner.email" : [FIRFieldValue fieldValueForDelete]};
  51. NSDictionary<NSString *, id> *finalData =
  52. @{ @"desc" : @"Description",
  53. @"owner" : @{@"name" : @"Jonny"} };
  54. [self writeDocumentRef:doc data:initialData];
  55. [self updateDocumentRef:doc data:updateData];
  56. FIRDocumentSnapshot *result = [self readDocumentForRef:doc];
  57. XCTAssertTrue(result.exists);
  58. XCTAssertEqualObjects(result.data, finalData);
  59. }
  60. - (void)testDeleteDocument {
  61. FIRDocumentReference *doc = [self.db documentWithPath:@"rooms/eros"];
  62. NSDictionary<NSString *, id> *data = @{@"value" : @"foo"};
  63. [self writeDocumentRef:doc data:data];
  64. FIRDocumentSnapshot *result = [self readDocumentForRef:doc];
  65. XCTAssertEqualObjects(result.data, data);
  66. [self deleteDocumentRef:doc];
  67. result = [self readDocumentForRef:doc];
  68. XCTAssertFalse(result.exists);
  69. }
  70. - (void)testCannotUpdateNonexistentDocument {
  71. FIRDocumentReference *doc = [[self.db collectionWithPath:@"rooms"] documentWithAutoID];
  72. XCTestExpectation *setCompletion = [self expectationWithDescription:@"setData"];
  73. [doc updateData:@{@"owner" : @"abc"}
  74. completion:^(NSError *_Nullable error) {
  75. XCTAssertNotNil(error);
  76. XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain);
  77. XCTAssertEqual(error.code, FIRFirestoreErrorCodeNotFound);
  78. [setCompletion fulfill];
  79. }];
  80. [self awaitExpectations];
  81. FIRDocumentSnapshot *result = [self readDocumentForRef:doc];
  82. XCTAssertFalse(result.exists);
  83. }
  84. - (void)testCanOverwriteDataAnExistingDocumentUsingSet {
  85. FIRDocumentReference *doc = [[self.db collectionWithPath:@"rooms"] documentWithAutoID];
  86. NSDictionary<NSString *, id> *initialData =
  87. @{ @"desc" : @"Description",
  88. @"owner" : @{@"name" : @"Jonny", @"email" : @"abc@xyz.com"} };
  89. NSDictionary<NSString *, id> *udpateData = @{@"desc" : @"NewDescription"};
  90. [self writeDocumentRef:doc data:initialData];
  91. [self writeDocumentRef:doc data:udpateData];
  92. FIRDocumentSnapshot *document = [self readDocumentForRef:doc];
  93. XCTAssertEqualObjects(document.data, udpateData);
  94. }
  95. - (void)testCanMergeDataWithAnExistingDocumentUsingSet {
  96. FIRDocumentReference *doc = [[self.db collectionWithPath:@"rooms"] documentWithAutoID];
  97. NSDictionary<NSString *, id> *initialData = @{
  98. @"desc" : @"Description",
  99. @"owner.data" : @{@"name" : @"Jonny", @"email" : @"abc@xyz.com"}
  100. };
  101. NSDictionary<NSString *, id> *updateData =
  102. @{ @"updated" : @YES,
  103. @"owner.data" : @{@"name" : @"Sebastian"} };
  104. NSDictionary<NSString *, id> *finalData = @{
  105. @"desc" : @"Description",
  106. @"updated" : @YES,
  107. @"owner.data" : @{@"name" : @"Sebastian", @"email" : @"abc@xyz.com"}
  108. };
  109. [self writeDocumentRef:doc data:initialData];
  110. XCTestExpectation *completed =
  111. [self expectationWithDescription:@"testCanMergeDataWithAnExistingDocumentUsingSet"];
  112. [doc setData:updateData
  113. options:[FIRSetOptions merge]
  114. completion:^(NSError *error) {
  115. XCTAssertNil(error);
  116. [completed fulfill];
  117. }];
  118. [self awaitExpectations];
  119. FIRDocumentSnapshot *document = [self readDocumentForRef:doc];
  120. XCTAssertEqualObjects(document.data, finalData);
  121. }
  122. - (void)testMergeReplacesArrays {
  123. FIRDocumentReference *doc = [[self.db collectionWithPath:@"rooms"] documentWithAutoID];
  124. NSDictionary<NSString *, id> *initialData = @{
  125. @"untouched" : @YES,
  126. @"data" : @"old",
  127. @"topLevel" : @[ @"old", @"old" ],
  128. @"mapInArray" : @[ @{@"data" : @"old"} ]
  129. };
  130. NSDictionary<NSString *, id> *updateData =
  131. @{ @"data" : @"new",
  132. @"topLevel" : @[ @"new" ],
  133. @"mapInArray" : @[ @{@"data" : @"new"} ] };
  134. NSDictionary<NSString *, id> *finalData = @{
  135. @"untouched" : @YES,
  136. @"data" : @"new",
  137. @"topLevel" : @[ @"new" ],
  138. @"mapInArray" : @[ @{@"data" : @"new"} ]
  139. };
  140. [self writeDocumentRef:doc data:initialData];
  141. XCTestExpectation *completed =
  142. [self expectationWithDescription:@"testCanMergeDataWithAnExistingDocumentUsingSet"];
  143. [doc setData:updateData
  144. options:[FIRSetOptions merge]
  145. completion:^(NSError *error) {
  146. XCTAssertNil(error);
  147. [completed fulfill];
  148. }];
  149. [self awaitExpectations];
  150. FIRDocumentSnapshot *document = [self readDocumentForRef:doc];
  151. XCTAssertEqualObjects(document.data, finalData);
  152. }
  153. - (void)testAddingToACollectionYieldsTheCorrectDocumentReference {
  154. FIRCollectionReference *coll = [self.db collectionWithPath:@"collection"];
  155. FIRDocumentReference *ref = [coll addDocumentWithData:@{ @"foo" : @1 }];
  156. XCTestExpectation *getCompletion = [self expectationWithDescription:@"getData"];
  157. [ref getDocumentWithCompletion:^(FIRDocumentSnapshot *_Nullable document,
  158. NSError *_Nullable error) {
  159. XCTAssertNil(error);
  160. XCTAssertEqualObjects(document.data, (@{ @"foo" : @1 }));
  161. [getCompletion fulfill];
  162. }];
  163. [self awaitExpectations];
  164. }
  165. - (void)testListenCanBeCalledMultipleTimes {
  166. FIRCollectionReference *coll = [self.db collectionWithPath:@"collection"];
  167. FIRDocumentReference *doc = [coll documentWithAutoID];
  168. XCTestExpectation *completed = [self expectationWithDescription:@"multiple addSnapshotListeners"];
  169. __block NSDictionary<NSString *, id> *resultingData;
  170. // Shut the compiler up about strong references to doc.
  171. FIRDocumentReference *__weak weakDoc = doc;
  172. [doc setData:@{@"foo" : @"bar"}
  173. completion:^(NSError *error1) {
  174. XCTAssertNil(error1);
  175. FIRDocumentReference *strongDoc = weakDoc;
  176. [strongDoc addSnapshotListener:^(FIRDocumentSnapshot *snapshot2, NSError *error2) {
  177. XCTAssertNil(error2);
  178. FIRDocumentReference *strongDoc2 = weakDoc;
  179. [strongDoc2 addSnapshotListener:^(FIRDocumentSnapshot *snapshot3, NSError *error3) {
  180. XCTAssertNil(error3);
  181. resultingData = snapshot3.data;
  182. [completed fulfill];
  183. }];
  184. }];
  185. }];
  186. [self awaitExpectations];
  187. XCTAssertEqualObjects(resultingData, @{@"foo" : @"bar"});
  188. }
  189. - (void)testDocumentSnapshotEvents_nonExistent {
  190. FIRDocumentReference *docRef = [[self.db collectionWithPath:@"rooms"] documentWithAutoID];
  191. XCTestExpectation *snapshotCompletion = [self expectationWithDescription:@"snapshot"];
  192. __block int callbacks = 0;
  193. id<FIRListenerRegistration> listenerRegistration =
  194. [docRef addSnapshotListener:^(FIRDocumentSnapshot *_Nullable doc, NSError *error) {
  195. callbacks++;
  196. if (callbacks == 1) {
  197. XCTAssertNotNil(doc);
  198. XCTAssertFalse(doc.exists);
  199. [snapshotCompletion fulfill];
  200. } else if (callbacks == 2) {
  201. XCTFail("Should not have received this callback");
  202. }
  203. }];
  204. [self awaitExpectations];
  205. [listenerRegistration remove];
  206. }
  207. - (void)testDocumentSnapshotEvents_forAdd {
  208. FIRDocumentReference *docRef = [[self.db collectionWithPath:@"rooms"] documentWithAutoID];
  209. XCTestExpectation *emptyCompletion = [self expectationWithDescription:@"empty snapshot"];
  210. __block XCTestExpectation *dataCompletion;
  211. __block int callbacks = 0;
  212. id<FIRListenerRegistration> listenerRegistration =
  213. [docRef addSnapshotListener:^(FIRDocumentSnapshot *_Nullable doc, NSError *error) {
  214. callbacks++;
  215. if (callbacks == 1) {
  216. XCTAssertNotNil(doc);
  217. XCTAssertFalse(doc.exists);
  218. [emptyCompletion fulfill];
  219. } else if (callbacks == 2) {
  220. XCTAssertEqualObjects(doc.data, (@{ @"a" : @1 }));
  221. XCTAssertEqual(doc.metadata.hasPendingWrites, YES);
  222. [dataCompletion fulfill];
  223. } else if (callbacks == 3) {
  224. XCTFail("Should not have received this callback");
  225. }
  226. }];
  227. [self awaitExpectations];
  228. dataCompletion = [self expectationWithDescription:@"data snapshot"];
  229. [docRef setData:@{ @"a" : @1 }];
  230. [self awaitExpectations];
  231. [listenerRegistration remove];
  232. }
  233. - (void)testDocumentSnapshotEvents_forAddIncludingMetadata {
  234. FIRDocumentReference *docRef = [[self.db collectionWithPath:@"rooms"] documentWithAutoID];
  235. XCTestExpectation *emptyCompletion = [self expectationWithDescription:@"empty snapshot"];
  236. __block XCTestExpectation *dataCompletion;
  237. __block int callbacks = 0;
  238. FIRDocumentListenOptions *options =
  239. [[FIRDocumentListenOptions options] includeMetadataChanges:YES];
  240. id<FIRListenerRegistration> listenerRegistration =
  241. [docRef addSnapshotListenerWithOptions:options
  242. listener:^(FIRDocumentSnapshot *_Nullable doc, NSError *error) {
  243. callbacks++;
  244. if (callbacks == 1) {
  245. XCTAssertNotNil(doc);
  246. XCTAssertFalse(doc.exists);
  247. [emptyCompletion fulfill];
  248. } else if (callbacks == 2) {
  249. XCTAssertEqualObjects(doc.data, (@{ @"a" : @1 }));
  250. XCTAssertEqual(doc.metadata.hasPendingWrites, YES);
  251. } else if (callbacks == 3) {
  252. XCTAssertEqualObjects(doc.data, (@{ @"a" : @1 }));
  253. XCTAssertEqual(doc.metadata.hasPendingWrites, NO);
  254. [dataCompletion fulfill];
  255. } else if (callbacks == 4) {
  256. XCTFail("Should not have received this callback");
  257. }
  258. }];
  259. [self awaitExpectations];
  260. dataCompletion = [self expectationWithDescription:@"data snapshot"];
  261. [docRef setData:@{ @"a" : @1 }];
  262. [self awaitExpectations];
  263. [listenerRegistration remove];
  264. }
  265. - (void)testDocumentSnapshotEvents_forChange {
  266. FIRDocumentReference *docRef = [[self.db collectionWithPath:@"rooms"] documentWithAutoID];
  267. NSDictionary<NSString *, id> *initialData = @{ @"a" : @1 };
  268. NSDictionary<NSString *, id> *changedData = @{ @"b" : @2 };
  269. [self writeDocumentRef:docRef data:initialData];
  270. XCTestExpectation *initialCompletion = [self expectationWithDescription:@"initial data"];
  271. __block XCTestExpectation *changeCompletion;
  272. __block int callbacks = 0;
  273. id<FIRListenerRegistration> listenerRegistration =
  274. [docRef addSnapshotListener:^(FIRDocumentSnapshot *_Nullable doc, NSError *error) {
  275. callbacks++;
  276. if (callbacks == 1) {
  277. XCTAssertEqualObjects(doc.data, initialData);
  278. XCTAssertEqual(doc.metadata.hasPendingWrites, NO);
  279. [initialCompletion fulfill];
  280. } else if (callbacks == 2) {
  281. XCTAssertEqualObjects(doc.data, changedData);
  282. XCTAssertEqual(doc.metadata.hasPendingWrites, YES);
  283. [changeCompletion fulfill];
  284. } else if (callbacks == 3) {
  285. XCTFail("Should not have received this callback");
  286. }
  287. }];
  288. [self awaitExpectations];
  289. changeCompletion = [self expectationWithDescription:@"listen for changed data"];
  290. [docRef setData:changedData];
  291. [self awaitExpectations];
  292. [listenerRegistration remove];
  293. }
  294. - (void)testDocumentSnapshotEvents_forChangeIncludingMetadata {
  295. FIRDocumentReference *docRef = [[self.db collectionWithPath:@"rooms"] documentWithAutoID];
  296. NSDictionary<NSString *, id> *initialData = @{ @"a" : @1 };
  297. NSDictionary<NSString *, id> *changedData = @{ @"b" : @2 };
  298. [self writeDocumentRef:docRef data:initialData];
  299. XCTestExpectation *initialCompletion = [self expectationWithDescription:@"initial data"];
  300. __block XCTestExpectation *changeCompletion;
  301. __block int callbacks = 0;
  302. FIRDocumentListenOptions *options =
  303. [[FIRDocumentListenOptions options] includeMetadataChanges:YES];
  304. id<FIRListenerRegistration> listenerRegistration =
  305. [docRef addSnapshotListenerWithOptions:options
  306. listener:^(FIRDocumentSnapshot *_Nullable doc, NSError *error) {
  307. callbacks++;
  308. if (callbacks == 1) {
  309. XCTAssertEqualObjects(doc.data, initialData);
  310. XCTAssertEqual(doc.metadata.hasPendingWrites, NO);
  311. XCTAssertEqual(doc.metadata.isFromCache, YES);
  312. } else if (callbacks == 2) {
  313. XCTAssertEqualObjects(doc.data, initialData);
  314. XCTAssertEqual(doc.metadata.hasPendingWrites, NO);
  315. XCTAssertEqual(doc.metadata.isFromCache, NO);
  316. [initialCompletion fulfill];
  317. } else if (callbacks == 3) {
  318. XCTAssertEqualObjects(doc.data, changedData);
  319. XCTAssertEqual(doc.metadata.hasPendingWrites, YES);
  320. XCTAssertEqual(doc.metadata.isFromCache, NO);
  321. } else if (callbacks == 4) {
  322. XCTAssertEqualObjects(doc.data, changedData);
  323. XCTAssertEqual(doc.metadata.hasPendingWrites, NO);
  324. XCTAssertEqual(doc.metadata.isFromCache, NO);
  325. [changeCompletion fulfill];
  326. } else if (callbacks == 5) {
  327. XCTFail("Should not have received this callback");
  328. }
  329. }];
  330. [self awaitExpectations];
  331. changeCompletion = [self expectationWithDescription:@"listen for changed data"];
  332. [docRef setData:changedData];
  333. [self awaitExpectations];
  334. [listenerRegistration remove];
  335. }
  336. - (void)testDocumentSnapshotEvents_forDelete {
  337. FIRDocumentReference *docRef = [[self.db collectionWithPath:@"rooms"] documentWithAutoID];
  338. NSDictionary<NSString *, id> *initialData = @{ @"a" : @1 };
  339. [self writeDocumentRef:docRef data:initialData];
  340. XCTestExpectation *initialCompletion = [self expectationWithDescription:@"initial data"];
  341. __block XCTestExpectation *changeCompletion;
  342. __block int callbacks = 0;
  343. id<FIRListenerRegistration> listenerRegistration =
  344. [docRef addSnapshotListener:^(FIRDocumentSnapshot *_Nullable doc, NSError *error) {
  345. callbacks++;
  346. if (callbacks == 1) {
  347. XCTAssertEqualObjects(doc.data, initialData);
  348. XCTAssertEqual(doc.metadata.hasPendingWrites, NO);
  349. XCTAssertEqual(doc.metadata.isFromCache, YES);
  350. [initialCompletion fulfill];
  351. } else if (callbacks == 2) {
  352. XCTAssertFalse(doc.exists);
  353. [changeCompletion fulfill];
  354. } else if (callbacks == 3) {
  355. XCTFail("Should not have received this callback");
  356. }
  357. }];
  358. [self awaitExpectations];
  359. changeCompletion = [self expectationWithDescription:@"listen for changed data"];
  360. [docRef deleteDocument];
  361. [self awaitExpectations];
  362. [listenerRegistration remove];
  363. }
  364. - (void)testDocumentSnapshotEvents_forDeleteIncludingMetadata {
  365. FIRDocumentReference *docRef = [[self.db collectionWithPath:@"rooms"] documentWithAutoID];
  366. NSDictionary<NSString *, id> *initialData = @{ @"a" : @1 };
  367. [self writeDocumentRef:docRef data:initialData];
  368. FIRDocumentListenOptions *options =
  369. [[FIRDocumentListenOptions options] includeMetadataChanges:YES];
  370. XCTestExpectation *initialCompletion = [self expectationWithDescription:@"initial data"];
  371. __block XCTestExpectation *changeCompletion;
  372. __block int callbacks = 0;
  373. id<FIRListenerRegistration> listenerRegistration =
  374. [docRef addSnapshotListenerWithOptions:options
  375. listener:^(FIRDocumentSnapshot *_Nullable doc, NSError *error) {
  376. callbacks++;
  377. if (callbacks == 1) {
  378. XCTAssertEqualObjects(doc.data, initialData);
  379. XCTAssertEqual(doc.metadata.hasPendingWrites, NO);
  380. XCTAssertEqual(doc.metadata.isFromCache, YES);
  381. } else if (callbacks == 2) {
  382. XCTAssertEqualObjects(doc.data, initialData);
  383. XCTAssertEqual(doc.metadata.hasPendingWrites, NO);
  384. XCTAssertEqual(doc.metadata.isFromCache, NO);
  385. [initialCompletion fulfill];
  386. } else if (callbacks == 3) {
  387. XCTAssertFalse(doc.exists);
  388. XCTAssertEqual(doc.metadata.hasPendingWrites, NO);
  389. XCTAssertEqual(doc.metadata.isFromCache, NO);
  390. [changeCompletion fulfill];
  391. } else if (callbacks == 4) {
  392. XCTFail("Should not have received this callback");
  393. }
  394. }];
  395. [self awaitExpectations];
  396. changeCompletion = [self expectationWithDescription:@"listen for changed data"];
  397. [docRef deleteDocument];
  398. [self awaitExpectations];
  399. [listenerRegistration remove];
  400. }
  401. - (void)testQuerySnapshotEvents_forAdd {
  402. FIRCollectionReference *roomsRef = [self collectionRef];
  403. FIRDocumentReference *docRef = [roomsRef documentWithAutoID];
  404. NSDictionary<NSString *, id> *newData = @{ @"a" : @1 };
  405. XCTestExpectation *emptyCompletion = [self expectationWithDescription:@"empty snapshot"];
  406. __block XCTestExpectation *changeCompletion;
  407. __block int callbacks = 0;
  408. id<FIRListenerRegistration> listenerRegistration =
  409. [roomsRef addSnapshotListener:^(FIRQuerySnapshot *_Nullable docSet, NSError *error) {
  410. callbacks++;
  411. if (callbacks == 1) {
  412. XCTAssertEqual(docSet.count, 0);
  413. [emptyCompletion fulfill];
  414. } else if (callbacks == 2) {
  415. XCTAssertEqual(docSet.count, 1);
  416. XCTAssertEqualObjects(docSet.documents[0].data, newData);
  417. XCTAssertEqual(docSet.documents[0].metadata.hasPendingWrites, YES);
  418. [changeCompletion fulfill];
  419. } else if (callbacks == 3) {
  420. XCTFail("Should not have received a third callback");
  421. }
  422. }];
  423. [self awaitExpectations];
  424. changeCompletion = [self expectationWithDescription:@"changed snapshot"];
  425. [docRef setData:newData];
  426. [self awaitExpectations];
  427. [listenerRegistration remove];
  428. }
  429. - (void)testQuerySnapshotEvents_forChange {
  430. FIRCollectionReference *roomsRef = [self collectionRef];
  431. FIRDocumentReference *docRef = [roomsRef documentWithAutoID];
  432. NSDictionary<NSString *, id> *initialData = @{ @"a" : @1 };
  433. NSDictionary<NSString *, id> *changedData = @{ @"b" : @2 };
  434. [self writeDocumentRef:docRef data:initialData];
  435. XCTestExpectation *initialCompletion = [self expectationWithDescription:@"initial data"];
  436. __block XCTestExpectation *changeCompletion;
  437. __block int callbacks = 0;
  438. id<FIRListenerRegistration> listenerRegistration =
  439. [roomsRef addSnapshotListener:^(FIRQuerySnapshot *_Nullable docSet, NSError *error) {
  440. callbacks++;
  441. if (callbacks == 1) {
  442. XCTAssertEqual(docSet.count, 1);
  443. XCTAssertEqualObjects(docSet.documents[0].data, initialData);
  444. XCTAssertEqual(docSet.documents[0].metadata.hasPendingWrites, NO);
  445. [initialCompletion fulfill];
  446. } else if (callbacks == 2) {
  447. XCTAssertEqual(docSet.count, 1);
  448. XCTAssertEqualObjects(docSet.documents[0].data, changedData);
  449. XCTAssertEqual(docSet.documents[0].metadata.hasPendingWrites, YES);
  450. [changeCompletion fulfill];
  451. } else if (callbacks == 3) {
  452. XCTFail("Should not have received a third callback");
  453. }
  454. }];
  455. [self awaitExpectations];
  456. changeCompletion = [self expectationWithDescription:@"listen for changed data"];
  457. [docRef setData:changedData];
  458. [self awaitExpectations];
  459. [listenerRegistration remove];
  460. }
  461. - (void)testQuerySnapshotEvents_forDelete {
  462. FIRCollectionReference *roomsRef = [self collectionRef];
  463. FIRDocumentReference *docRef = [roomsRef documentWithAutoID];
  464. NSDictionary<NSString *, id> *initialData = @{ @"a" : @1 };
  465. [self writeDocumentRef:docRef data:initialData];
  466. XCTestExpectation *initialCompletion = [self expectationWithDescription:@"initial data"];
  467. __block XCTestExpectation *changeCompletion;
  468. __block int callbacks = 0;
  469. id<FIRListenerRegistration> listenerRegistration =
  470. [roomsRef addSnapshotListener:^(FIRQuerySnapshot *_Nullable docSet, NSError *error) {
  471. callbacks++;
  472. if (callbacks == 1) {
  473. XCTAssertEqual(docSet.count, 1);
  474. XCTAssertEqualObjects(docSet.documents[0].data, initialData);
  475. XCTAssertEqual(docSet.documents[0].metadata.hasPendingWrites, NO);
  476. [initialCompletion fulfill];
  477. } else if (callbacks == 2) {
  478. XCTAssertEqual(docSet.count, 0);
  479. [changeCompletion fulfill];
  480. } else if (callbacks == 4) {
  481. XCTFail("Should not have received a third callback");
  482. }
  483. }];
  484. [self awaitExpectations];
  485. changeCompletion = [self expectationWithDescription:@"listen for changed data"];
  486. [docRef deleteDocument];
  487. [self awaitExpectations];
  488. [listenerRegistration remove];
  489. }
  490. - (void)testExposesFirestoreOnDocumentReferences {
  491. FIRDocumentReference *doc = [self.db documentWithPath:@"foo/bar"];
  492. XCTAssertEqual(doc.firestore, self.db);
  493. }
  494. - (void)testExposesFirestoreOnQueries {
  495. FIRQuery *q = [[self.db collectionWithPath:@"foo"] queryLimitedTo:5];
  496. XCTAssertEqual(q.firestore, self.db);
  497. }
  498. - (void)testCanTraverseCollectionsAndDocuments {
  499. NSString *expected = @"a/b/c/d";
  500. // doc path from root Firestore.
  501. XCTAssertEqualObjects([self.db documentWithPath:@"a/b/c/d"].path, expected);
  502. // collection path from root Firestore.
  503. XCTAssertEqualObjects([[self.db collectionWithPath:@"a/b/c"] documentWithPath:@"d"].path,
  504. expected);
  505. // doc path from CollectionReference.
  506. XCTAssertEqualObjects([[self.db collectionWithPath:@"a"] documentWithPath:@"b/c/d"].path,
  507. expected);
  508. // collection path from DocumentReference.
  509. XCTAssertEqualObjects([[self.db documentWithPath:@"a/b"] collectionWithPath:@"c/d/e"].path,
  510. @"a/b/c/d/e");
  511. }
  512. - (void)testCanTraverseCollectionAndDocumentParents {
  513. FIRCollectionReference *collection = [self.db collectionWithPath:@"a/b/c"];
  514. XCTAssertEqualObjects(collection.path, @"a/b/c");
  515. FIRDocumentReference *doc = collection.parent;
  516. XCTAssertEqualObjects(doc.path, @"a/b");
  517. collection = doc.parent;
  518. XCTAssertEqualObjects(collection.path, @"a");
  519. FIRDocumentReference *nilDoc = collection.parent;
  520. XCTAssertNil(nilDoc);
  521. }
  522. - (void)testUpdateFieldsWithDots {
  523. FIRDocumentReference *doc = [self documentRef];
  524. [self writeDocumentRef:doc data:@{@"a.b" : @"old", @"c.d" : @"old"}];
  525. [self updateDocumentRef:doc data:@{ [[FIRFieldPath alloc] initWithFields:@[ @"a.b" ]] : @"new" }];
  526. XCTestExpectation *expectation = [self expectationWithDescription:@"testUpdateFieldsWithDots"];
  527. [doc getDocumentWithCompletion:^(FIRDocumentSnapshot *snapshot, NSError *error) {
  528. XCTAssertNil(error);
  529. XCTAssertEqualObjects(snapshot.data, (@{@"a.b" : @"new", @"c.d" : @"old"}));
  530. [expectation fulfill];
  531. }];
  532. [self awaitExpectations];
  533. }
  534. - (void)testUpdateNestedFields {
  535. FIRDocumentReference *doc = [self documentRef];
  536. [self writeDocumentRef:doc
  537. data:@{
  538. @"a" : @{@"b" : @"old"},
  539. @"c" : @{@"d" : @"old"},
  540. @"e" : @{@"f" : @"old"}
  541. }];
  542. [self updateDocumentRef:doc
  543. data:@{
  544. @"a.b" : @"new",
  545. [[FIRFieldPath alloc] initWithFields:@[ @"c", @"d" ]] : @"new"
  546. }];
  547. XCTestExpectation *expectation = [self expectationWithDescription:@"testUpdateNestedFields"];
  548. [doc getDocumentWithCompletion:^(FIRDocumentSnapshot *snapshot, NSError *error) {
  549. XCTAssertNil(error);
  550. XCTAssertEqualObjects(snapshot.data, (@{
  551. @"a" : @{@"b" : @"new"},
  552. @"c" : @{@"d" : @"new"},
  553. @"e" : @{@"f" : @"old"}
  554. }));
  555. [expectation fulfill];
  556. }];
  557. [self awaitExpectations];
  558. }
  559. - (void)testCollectionID {
  560. XCTAssertEqualObjects([self.db collectionWithPath:@"foo"].collectionID, @"foo");
  561. XCTAssertEqualObjects([self.db collectionWithPath:@"foo/bar/baz"].collectionID, @"baz");
  562. }
  563. - (void)testDocumentID {
  564. XCTAssertEqualObjects([self.db documentWithPath:@"foo/bar"].documentID, @"bar");
  565. XCTAssertEqualObjects([self.db documentWithPath:@"foo/bar/baz/qux"].documentID, @"qux");
  566. }
  567. @end