FIRCursorTests.mm 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  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 <FirebaseFirestore/FirebaseFirestore.h>
  17. #import <XCTest/XCTest.h>
  18. #import "FirebaseCore/Sources/Public/FirebaseCore/FIRTimestamp.h"
  19. #import "Firestore/Example/Tests/Util/FSTIntegrationTestCase.h"
  20. @interface FIRCursorTests : FSTIntegrationTestCase
  21. @end
  22. @implementation FIRCursorTests
  23. - (void)testCanPageThroughItems {
  24. FIRCollectionReference *testCollection = [self collectionRefWithDocuments:@{
  25. @"a" : @{@"v" : @"a"},
  26. @"b" : @{@"v" : @"b"},
  27. @"c" : @{@"v" : @"c"},
  28. @"d" : @{@"v" : @"d"},
  29. @"e" : @{@"v" : @"e"},
  30. @"f" : @{@"v" : @"f"}
  31. }];
  32. FIRQuerySnapshot *snapshot = [self readDocumentSetForRef:[testCollection queryLimitedTo:2]];
  33. XCTAssertEqualObjects(FIRQuerySnapshotGetData(snapshot), (@[ @{@"v" : @"a"}, @{@"v" : @"b"} ]));
  34. FIRDocumentSnapshot *lastDoc = snapshot.documents.lastObject;
  35. snapshot = [self
  36. readDocumentSetForRef:[[testCollection queryLimitedTo:3] queryStartingAfterDocument:lastDoc]];
  37. XCTAssertEqualObjects(FIRQuerySnapshotGetData(snapshot),
  38. (@[ @{@"v" : @"c"}, @{@"v" : @"d"}, @{@"v" : @"e"} ]));
  39. lastDoc = snapshot.documents.lastObject;
  40. snapshot = [self
  41. readDocumentSetForRef:[[testCollection queryLimitedTo:1] queryStartingAfterDocument:lastDoc]];
  42. XCTAssertEqualObjects(FIRQuerySnapshotGetData(snapshot), @[ @{@"v" : @"f"} ]);
  43. lastDoc = snapshot.documents.lastObject;
  44. snapshot = [self
  45. readDocumentSetForRef:[[testCollection queryLimitedTo:3] queryStartingAfterDocument:lastDoc]];
  46. XCTAssertEqualObjects(FIRQuerySnapshotGetData(snapshot), @[]);
  47. }
  48. - (void)testCanBeCreatedFromDocuments {
  49. FIRCollectionReference *testCollection = [self collectionRefWithDocuments:@{
  50. @"a" : @{@"v" : @"a", @"sort" : @1.0},
  51. @"b" : @{@"v" : @"b", @"sort" : @2.0},
  52. @"c" : @{@"v" : @"c", @"sort" : @2.0},
  53. @"d" : @{@"v" : @"d", @"sort" : @2.0},
  54. @"e" : @{@"v" : @"e", @"sort" : @0.0},
  55. @"f" : @{@"v" : @"f", @"nosort" : @1.0} // should not show up
  56. }];
  57. FIRQuery *query = [testCollection queryOrderedByField:@"sort"];
  58. FIRDocumentSnapshot *snapshot = [self readDocumentForRef:[testCollection documentWithPath:@"c"]];
  59. XCTAssertTrue(snapshot.exists);
  60. FIRQuerySnapshot *querySnapshot =
  61. [self readDocumentSetForRef:[query queryStartingAtDocument:snapshot]];
  62. XCTAssertEqualObjects(FIRQuerySnapshotGetData(querySnapshot),
  63. (@[ @{@"v" : @"c", @"sort" : @2.0}, @{@"v" : @"d", @"sort" : @2.0} ]));
  64. querySnapshot = [self readDocumentSetForRef:[query queryEndingBeforeDocument:snapshot]];
  65. XCTAssertEqualObjects(FIRQuerySnapshotGetData(querySnapshot), (@[
  66. @{@"v" : @"e", @"sort" : @0.0}, @{@"v" : @"a", @"sort" : @1.0},
  67. @{@"v" : @"b", @"sort" : @2.0}
  68. ]));
  69. }
  70. - (void)testCanBeCreatedFromValues {
  71. FIRCollectionReference *testCollection = [self collectionRefWithDocuments:@{
  72. @"a" : @{@"v" : @"a", @"sort" : @1.0},
  73. @"b" : @{@"v" : @"b", @"sort" : @2.0},
  74. @"c" : @{@"v" : @"c", @"sort" : @2.0},
  75. @"d" : @{@"v" : @"d", @"sort" : @2.0},
  76. @"e" : @{@"v" : @"e", @"sort" : @0.0},
  77. @"f" : @{@"v" : @"f", @"nosort" : @1.0} // should not show up
  78. }];
  79. FIRQuery *query = [testCollection queryOrderedByField:@"sort"];
  80. FIRQuerySnapshot *querySnapshot =
  81. [self readDocumentSetForRef:[query queryStartingAtValues:@[ @2.0 ]]];
  82. XCTAssertEqualObjects(FIRQuerySnapshotGetData(querySnapshot), (@[
  83. @{@"v" : @"b", @"sort" : @2.0}, @{@"v" : @"c", @"sort" : @2.0},
  84. @{@"v" : @"d", @"sort" : @2.0}
  85. ]));
  86. querySnapshot = [self readDocumentSetForRef:[query queryEndingBeforeValues:@[ @2.0 ]]];
  87. XCTAssertEqualObjects(FIRQuerySnapshotGetData(querySnapshot),
  88. (@[ @{@"v" : @"e", @"sort" : @0.0}, @{@"v" : @"a", @"sort" : @1.0} ]));
  89. }
  90. - (void)testCanBeCreatedUsingDocumentId {
  91. NSDictionary *testDocs = @{
  92. @"a" : @{@"k" : @"a"},
  93. @"b" : @{@"k" : @"b"},
  94. @"c" : @{@"k" : @"c"},
  95. @"d" : @{@"k" : @"d"},
  96. @"e" : @{@"k" : @"e"}
  97. };
  98. FIRCollectionReference *writer = [[[[self firestore] collectionWithPath:@"parent-collection"]
  99. documentWithAutoID] collectionWithPath:@"sub-collection"];
  100. [self writeAllDocuments:testDocs toCollection:writer];
  101. FIRCollectionReference *reader = [[self firestore] collectionWithPath:writer.path];
  102. FIRQuerySnapshot *querySnapshot =
  103. [self readDocumentSetForRef:[[[reader queryOrderedByFieldPath:[FIRFieldPath documentID]]
  104. queryStartingAtValues:@[ @"b" ]]
  105. queryEndingBeforeValues:@[ @"d" ]]];
  106. XCTAssertEqualObjects(FIRQuerySnapshotGetData(querySnapshot),
  107. (@[ @{@"k" : @"b"}, @{@"k" : @"c"} ]));
  108. }
  109. - (void)testCanBeUsedWithReferenceValues {
  110. FIRFirestore *db = [self firestore];
  111. FIRCollectionReference *testCollection = [self collectionRefWithDocuments:@{
  112. @"a" : @{@"k" : @"1a", @"ref" : [db documentWithPath:@"1/a"]},
  113. @"b" : @{@"k" : @"1b", @"ref" : [db documentWithPath:@"1/b"]},
  114. @"c" : @{@"k" : @"2a", @"ref" : [db documentWithPath:@"2/a"]},
  115. @"d" : @{@"k" : @"2b", @"ref" : [db documentWithPath:@"2/b"]},
  116. @"e" : @{@"k" : @"3a", @"ref" : [db documentWithPath:@"3/a"]},
  117. }];
  118. FIRQuery *query = [testCollection queryOrderedByField:@"ref"];
  119. FIRQuerySnapshot *querySnapshot = [self
  120. readDocumentSetForRef:[[query queryStartingAfterValues:@[ [db documentWithPath:@"1/a"] ]]
  121. queryEndingAtValues:@[ [db documentWithPath:@"2/b"] ]]];
  122. NSMutableArray<NSString *> *actual = [NSMutableArray array];
  123. [querySnapshot.documents
  124. enumerateObjectsUsingBlock:^(FIRDocumentSnapshot *_Nonnull doc, NSUInteger, BOOL *) {
  125. [actual addObject:doc.data[@"k"]];
  126. }];
  127. XCTAssertEqualObjects(actual, (@[ @"1b", @"2a", @"2b" ]));
  128. }
  129. - (void)testCanBeUsedInDescendingQueries {
  130. FIRCollectionReference *testCollection = [self collectionRefWithDocuments:@{
  131. @"a" : @{@"v" : @"a", @"sort" : @1.0},
  132. @"b" : @{@"v" : @"b", @"sort" : @2.0},
  133. @"c" : @{@"v" : @"c", @"sort" : @2.0},
  134. @"d" : @{@"v" : @"d", @"sort" : @3.0},
  135. @"e" : @{@"v" : @"e", @"sort" : @0.0},
  136. @"f" : @{@"v" : @"f", @"nosort" : @1.0} // should not show up
  137. }];
  138. FIRQuery *query = [[testCollection queryOrderedByField:@"sort" descending:YES]
  139. queryOrderedByFieldPath:[FIRFieldPath documentID]
  140. descending:YES];
  141. FIRQuerySnapshot *snapshot = [self readDocumentSetForRef:[query queryStartingAtValues:@[ @2.0 ]]];
  142. XCTAssertEqualObjects(FIRQuerySnapshotGetData(snapshot), (@[
  143. @{@"v" : @"c", @"sort" : @2.0}, @{@"v" : @"b", @"sort" : @2.0},
  144. @{@"v" : @"a", @"sort" : @1.0}, @{@"v" : @"e", @"sort" : @0.0}
  145. ]));
  146. snapshot = [self readDocumentSetForRef:[query queryEndingBeforeValues:@[ @2.0 ]]];
  147. XCTAssertEqualObjects(FIRQuerySnapshotGetData(snapshot), (@[ @{@"v" : @"d", @"sort" : @3.0} ]));
  148. }
  149. FIRTimestamp *TimestampWithMicros(int64_t seconds, int32_t micros) {
  150. // Firestore only supports microsecond resolution, so use a microsecond as a minimum value for
  151. // nanoseconds.
  152. return [FIRTimestamp timestampWithSeconds:seconds nanoseconds:micros * 1000];
  153. }
  154. - (void)testTimestampsCanBePassedToQueriesAsLimits {
  155. FIRCollectionReference *testCollection = [self collectionRefWithDocuments:@{
  156. @"a" : @{@"timestamp" : TimestampWithMicros(100, 2)},
  157. @"b" : @{@"timestamp" : TimestampWithMicros(100, 5)},
  158. @"c" : @{@"timestamp" : TimestampWithMicros(100, 3)},
  159. @"d" : @{@"timestamp" : TimestampWithMicros(100, 1)},
  160. // Number of microseconds deliberately repeated.
  161. @"e" : @{@"timestamp" : TimestampWithMicros(100, 5)},
  162. @"f" : @{@"timestamp" : TimestampWithMicros(100, 4)},
  163. }];
  164. FIRQuery *query = [testCollection queryOrderedByField:@"timestamp"];
  165. FIRQuerySnapshot *querySnapshot =
  166. [self readDocumentSetForRef:[[query queryStartingAfterValues:@[ TimestampWithMicros(100, 2) ]]
  167. queryEndingAtValues:@[ TimestampWithMicros(100, 5) ]]];
  168. XCTAssertEqualObjects(FIRQuerySnapshotGetIDs(querySnapshot), (@[ @"c", @"f", @"b", @"e" ]));
  169. }
  170. - (void)testTimestampsCanBePassedToQueriesInWhereClause {
  171. FIRCollectionReference *testCollection = [self collectionRefWithDocuments:@{
  172. @"a" : @{
  173. @"timestamp" : TimestampWithMicros(100, 7),
  174. },
  175. @"b" : @{
  176. @"timestamp" : TimestampWithMicros(100, 4),
  177. },
  178. @"c" : @{
  179. @"timestamp" : TimestampWithMicros(100, 8),
  180. },
  181. @"d" : @{
  182. @"timestamp" : TimestampWithMicros(100, 5),
  183. },
  184. @"e" : @{
  185. @"timestamp" : TimestampWithMicros(100, 6),
  186. }
  187. }];
  188. FIRQuerySnapshot *querySnapshot =
  189. [self readDocumentSetForRef:[[testCollection queryWhereField:@"timestamp"
  190. isGreaterThanOrEqualTo:TimestampWithMicros(100, 5)]
  191. queryWhereField:@"timestamp"
  192. isLessThan:TimestampWithMicros(100, 8)]];
  193. XCTAssertEqualObjects(FIRQuerySnapshotGetIDs(querySnapshot), (@[ @"d", @"e", @"a" ]));
  194. }
  195. - (void)testTimestampsAreTruncatedToMicroseconds {
  196. FIRTimestamp *nanos = [FIRTimestamp timestampWithSeconds:0 nanoseconds:123456789];
  197. FIRTimestamp *micros = [FIRTimestamp timestampWithSeconds:0 nanoseconds:123456000];
  198. FIRTimestamp *millis = [FIRTimestamp timestampWithSeconds:0 nanoseconds:123000000];
  199. FIRCollectionReference *testCollection = [self collectionRefWithDocuments:@{
  200. @"a" : @{@"timestamp" : nanos},
  201. }];
  202. FIRQuerySnapshot *querySnapshot =
  203. [self readDocumentSetForRef:[testCollection queryWhereField:@"timestamp" isEqualTo:nanos]];
  204. XCTAssertEqualObjects(FIRQuerySnapshotGetIDs(querySnapshot), (@[ @"a" ]));
  205. // Because Timestamp should have been truncated to microseconds, the microsecond timestamp
  206. // should be considered equal to the nanosecond one.
  207. querySnapshot = [self readDocumentSetForRef:[testCollection queryWhereField:@"timestamp"
  208. isEqualTo:micros]];
  209. XCTAssertEqualObjects(FIRQuerySnapshotGetIDs(querySnapshot), (@[ @"a" ]));
  210. // The truncation is just to the microseconds, however, so the millisecond timestamp should be
  211. // treated as different and thus the query should return no results.
  212. querySnapshot = [self readDocumentSetForRef:[testCollection queryWhereField:@"timestamp"
  213. isEqualTo:millis]];
  214. XCTAssertEqualObjects(FIRQuerySnapshotGetIDs(querySnapshot), (@[]));
  215. }
  216. @end