FIRFieldsTests.mm 9.5 KB

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