FIRFieldsTests.mm 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. /*
  2. * Copyright 2017 Google LLC
  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/FIRTimestamp.h>
  17. #import <FirebaseFirestore/FirebaseFirestore.h>
  18. #import <XCTest/XCTest.h>
  19. #import "Firestore/Example/Tests/Util/FSTIntegrationTestCase.h"
  20. NS_ASSUME_NONNULL_BEGIN
  21. @interface FIRFieldsTests : FSTIntegrationTestCase
  22. @end
  23. NSDictionary<NSString *, id> *testDataWithTimestamps(FIRTimestamp *timestamp) {
  24. return @{@"timestamp" : timestamp, @"nested" : @{@"timestamp2" : timestamp}};
  25. }
  26. @implementation FIRFieldsTests
  27. - (NSDictionary<NSString *, id> *)testNestedDataNumbered:(int)number {
  28. return @{
  29. @"name" : [NSString stringWithFormat:@"room %d", number],
  30. @"metadata" : @{
  31. @"createdAt" : @(number),
  32. @"deep" : @{@"field" : [NSString stringWithFormat:@"deep-field-%d", number]}
  33. }
  34. };
  35. }
  36. - (void)testNestedFieldsCanBeWrittenWithSet {
  37. NSDictionary<NSString *, id> *testData = [self testNestedDataNumbered:1];
  38. FIRDocumentReference *doc = [self documentRef];
  39. [self writeDocumentRef:doc data:testData];
  40. FIRDocumentSnapshot *result = [self readDocumentForRef:doc];
  41. XCTAssertEqualObjects(result.data, testData);
  42. }
  43. - (void)testNestedFieldsCanBeReadDirectly {
  44. NSDictionary<NSString *, id> *testData = [self testNestedDataNumbered:1];
  45. FIRDocumentReference *doc = [self documentRef];
  46. [self writeDocumentRef:doc data:testData];
  47. FIRDocumentSnapshot *result = [self readDocumentForRef:doc];
  48. XCTAssertEqualObjects(result[@"name"], testData[@"name"]);
  49. XCTAssertEqualObjects(result[@"metadata"], testData[@"metadata"]);
  50. XCTAssertEqualObjects(result[@"metadata.deep.field"], testData[@"metadata"][@"deep"][@"field"]);
  51. XCTAssertNil(result[@"metadata.nofield"]);
  52. XCTAssertNil(result[@"nometadata.nofield"]);
  53. }
  54. - (void)testNestedFieldsCanBeUpdated {
  55. NSDictionary<NSString *, id> *testData = [self testNestedDataNumbered:1];
  56. FIRDocumentReference *doc = [self documentRef];
  57. [self writeDocumentRef:doc data:testData];
  58. [self updateDocumentRef:doc data:@{@"metadata.deep.field" : @100, @"metadata.added" : @200}];
  59. FIRDocumentSnapshot *result = [self readDocumentForRef:doc];
  60. XCTAssertEqualObjects(
  61. result.data, (@{
  62. @"name" : @"room 1",
  63. @"metadata" : @{@"createdAt" : @1, @"deep" : @{@"field" : @100}, @"added" : @200}
  64. }));
  65. }
  66. - (void)testNestedFieldsCanBeUsedInQueryFilters {
  67. NSDictionary<NSString *, NSDictionary<NSString *, id> *> *testDocs = @{
  68. @"1" : [self testNestedDataNumbered:300],
  69. @"2" : [self testNestedDataNumbered:100],
  70. @"3" : [self testNestedDataNumbered:200]
  71. };
  72. // inequality adds implicit sort on field
  73. NSArray<NSDictionary<NSString *, id> *> *expected =
  74. @[ [self testNestedDataNumbered:200], [self testNestedDataNumbered:300] ];
  75. FIRCollectionReference *coll = [self collectionRefWithDocuments:testDocs];
  76. FIRQuery *q = [coll queryWhereField:@"metadata.createdAt" isGreaterThanOrEqualTo:@200];
  77. FIRQuerySnapshot *results = [self readDocumentSetForRef:q];
  78. XCTAssertEqualObjects(FIRQuerySnapshotGetData(results), (expected));
  79. }
  80. - (void)testNestedFieldsCanBeUsedInOrderBy {
  81. NSDictionary<NSString *, NSDictionary<NSString *, id> *> *testDocs = @{
  82. @"1" : [self testNestedDataNumbered:300],
  83. @"2" : [self testNestedDataNumbered:100],
  84. @"3" : [self testNestedDataNumbered:200]
  85. };
  86. FIRCollectionReference *coll = [self collectionRefWithDocuments:testDocs];
  87. XCTestExpectation *queryCompletion = [self expectationWithDescription:@"query"];
  88. FIRQuery *q = [coll queryOrderedByField:@"metadata.createdAt"];
  89. [q getDocumentsWithCompletion:^(FIRQuerySnapshot *results, NSError *error) {
  90. XCTAssertNil(error);
  91. XCTAssertEqualObjects(FIRQuerySnapshotGetData(results), (@[
  92. [self testNestedDataNumbered:100], [self testNestedDataNumbered:200],
  93. [self testNestedDataNumbered:300]
  94. ]));
  95. [queryCompletion fulfill];
  96. }];
  97. [self awaitExpectations];
  98. }
  99. /**
  100. * Creates test data with special characters in field names. Datastore currently prohibits mixing
  101. * nested data with special characters so tests that use this data must be separate.
  102. */
  103. - (NSDictionary<NSString *, id> *)testDottedDataNumbered:(int)number {
  104. return @{
  105. @"a" : [NSString stringWithFormat:@"field %d", number],
  106. @"b.dot" : @(number),
  107. @"c\\slash" : @(number)
  108. };
  109. }
  110. - (void)testFieldsWithSpecialCharsCanBeWrittenWithSet {
  111. NSDictionary<NSString *, id> *testData = [self testDottedDataNumbered:1];
  112. FIRDocumentReference *doc = [self documentRef];
  113. [self writeDocumentRef:doc data:testData];
  114. FIRDocumentSnapshot *result = [self readDocumentForRef:doc];
  115. XCTAssertEqualObjects(result.data, testData);
  116. }
  117. - (void)testFieldsWithSpecialCharsCanBeReadDirectly {
  118. NSDictionary<NSString *, id> *testData = [self testDottedDataNumbered:1];
  119. FIRDocumentReference *doc = [self documentRef];
  120. [self writeDocumentRef:doc data:testData];
  121. FIRDocumentSnapshot *result = [self readDocumentForRef:doc];
  122. XCTAssertEqualObjects(result[@"a"], testData[@"a"]);
  123. XCTAssertEqualObjects(result[[[FIRFieldPath alloc] initWithFields:@[ @"b.dot" ]]],
  124. testData[@"b.dot"]);
  125. XCTAssertEqualObjects(result[@"c\\slash"], testData[@"c\\slash"]);
  126. }
  127. - (void)testFieldsWithSpecialCharsCanBeUpdated {
  128. NSDictionary<NSString *, id> *testData = [self testDottedDataNumbered:1];
  129. FIRDocumentReference *doc = [self documentRef];
  130. [self writeDocumentRef:doc data:testData];
  131. [self updateDocumentRef:doc
  132. data:@{
  133. (id)[[FIRFieldPath alloc] initWithFields:@[ @"b.dot" ]] : @100,
  134. (id) @"c\\slash" : @200
  135. }];
  136. FIRDocumentSnapshot *result = [self readDocumentForRef:doc];
  137. XCTAssertEqualObjects(result.data, (@{@"a" : @"field 1", @"b.dot" : @100, @"c\\slash" : @200}));
  138. }
  139. - (void)testFieldsWithSpecialCharsCanBeUsedInQueryFilters {
  140. NSDictionary<NSString *, NSDictionary<NSString *, id> *> *testDocs = @{
  141. @"1" : [self testDottedDataNumbered:300],
  142. @"2" : [self testDottedDataNumbered:100],
  143. @"3" : [self testDottedDataNumbered:200]
  144. };
  145. // inequality adds implicit sort on field
  146. NSArray<NSDictionary<NSString *, id> *> *expected =
  147. @[ [self testDottedDataNumbered:200], [self testDottedDataNumbered:300] ];
  148. FIRCollectionReference *coll = [self collectionRefWithDocuments:testDocs];
  149. XCTestExpectation *queryCompletion = [self expectationWithDescription:@"query"];
  150. FIRQuery *q = [coll queryWhereFieldPath:[[FIRFieldPath alloc] initWithFields:@[ @"b.dot" ]]
  151. isGreaterThanOrEqualTo:@200];
  152. [q getDocumentsWithCompletion:^(FIRQuerySnapshot *results, NSError *error) {
  153. XCTAssertNil(error);
  154. XCTAssertEqualObjects(FIRQuerySnapshotGetData(results), expected);
  155. [queryCompletion fulfill];
  156. }];
  157. [self awaitExpectations];
  158. }
  159. - (void)testFieldsWithSpecialCharsCanBeUsedInOrderBy {
  160. NSDictionary<NSString *, NSDictionary<NSString *, id> *> *testDocs = @{
  161. @"1" : [self testDottedDataNumbered:300],
  162. @"2" : [self testDottedDataNumbered:100],
  163. @"3" : [self testDottedDataNumbered:200]
  164. };
  165. NSArray<NSDictionary<NSString *, id> *> *expected = @[
  166. [self testDottedDataNumbered:100], [self testDottedDataNumbered:200],
  167. [self testDottedDataNumbered:300]
  168. ];
  169. FIRCollectionReference *coll = [self collectionRefWithDocuments:testDocs];
  170. FIRQuery *q = [coll queryOrderedByFieldPath:[[FIRFieldPath alloc] initWithFields:@[ @"b.dot" ]]];
  171. XCTestExpectation *queryDot = [self expectationWithDescription:@"query dot"];
  172. [q getDocumentsWithCompletion:^(FIRQuerySnapshot *results, NSError *error) {
  173. XCTAssertNil(error);
  174. XCTAssertEqualObjects(FIRQuerySnapshotGetData(results), expected);
  175. [queryDot fulfill];
  176. }];
  177. [self awaitExpectations];
  178. XCTestExpectation *querySlash = [self expectationWithDescription:@"query slash"];
  179. q = [coll queryOrderedByField:@"c\\slash"];
  180. [q getDocumentsWithCompletion:^(FIRQuerySnapshot *results, NSError *error) {
  181. XCTAssertNil(error);
  182. XCTAssertEqualObjects(FIRQuerySnapshotGetData(results), expected);
  183. [querySlash fulfill];
  184. }];
  185. [self awaitExpectations];
  186. }
  187. - (FIRDocumentSnapshot *)snapshotWithTimestamps:(FIRTimestamp *)timestamp {
  188. FIRDocumentReference *doc = [self documentRef];
  189. NSDictionary<NSString *, id> *data =
  190. @{@"timestamp" : timestamp, @"nested" : @{@"timestamp2" : timestamp}};
  191. [self writeDocumentRef:doc data:data];
  192. return [self readDocumentForRef:doc];
  193. }
  194. - (void)testTimestampsAreTruncated {
  195. FIRTimestamp *originalTimestamp = [FIRTimestamp timestampWithSeconds:100 nanoseconds:123456789];
  196. FIRDocumentReference *doc = [self documentRef];
  197. [self writeDocumentRef:doc data:testDataWithTimestamps(originalTimestamp)];
  198. FIRDocumentSnapshot *snapshot = [self readDocumentForRef:doc];
  199. NSDictionary<NSString *, id> *data = [snapshot data];
  200. // Timestamp are currently truncated to microseconds after being written to the database.
  201. FIRTimestamp *truncatedTimestamp =
  202. [FIRTimestamp timestampWithSeconds:originalTimestamp.seconds
  203. nanoseconds:originalTimestamp.nanoseconds / 1000 * 1000];
  204. FIRTimestamp *timestampFromSnapshot = snapshot[@"timestamp"];
  205. FIRTimestamp *timestampFromData = data[@"timestamp"];
  206. XCTAssertEqualObjects(truncatedTimestamp, timestampFromData);
  207. XCTAssertEqualObjects(timestampFromSnapshot, timestampFromData);
  208. timestampFromSnapshot = snapshot[@"nested.timestamp2"];
  209. timestampFromData = data[@"nested"][@"timestamp2"];
  210. XCTAssertEqualObjects(truncatedTimestamp, timestampFromData);
  211. XCTAssertEqualObjects(timestampFromSnapshot, timestampFromData);
  212. }
  213. @end
  214. NS_ASSUME_NONNULL_END