| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306 |
- /*
- * Copyright 2017 Google
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- #import <FirebaseFirestore/FIRTimestamp.h>
- #import <FirebaseFirestore/FirebaseFirestore.h>
- #import <XCTest/XCTest.h>
- #import "Firestore/core/src/firebase/firestore/util/warnings.h"
- #import "Firestore/Example/Tests/Util/FSTIntegrationTestCase.h"
- @interface FIRFieldsTests : FSTIntegrationTestCase
- @end
- NSDictionary<NSString *, id> *testDataWithTimestamps(FIRTimestamp *timestamp) {
- return @{@"timestamp" : timestamp, @"nested" : @{@"timestamp2" : timestamp}};
- }
- @implementation FIRFieldsTests
- - (NSDictionary<NSString *, id> *)testNestedDataNumbered:(int)number {
- return @{
- @"name" : [NSString stringWithFormat:@"room %d", number],
- @"metadata" : @{
- @"createdAt" : @(number),
- @"deep" : @{@"field" : [NSString stringWithFormat:@"deep-field-%d", number]}
- }
- };
- }
- - (void)testNestedFieldsCanBeWrittenWithSet {
- NSDictionary<NSString *, id> *testData = [self testNestedDataNumbered:1];
- FIRDocumentReference *doc = [self documentRef];
- [self writeDocumentRef:doc data:testData];
- FIRDocumentSnapshot *result = [self readDocumentForRef:doc];
- XCTAssertEqualObjects(result.data, testData);
- }
- - (void)testNestedFieldsCanBeReadDirectly {
- NSDictionary<NSString *, id> *testData = [self testNestedDataNumbered:1];
- FIRDocumentReference *doc = [self documentRef];
- [self writeDocumentRef:doc data:testData];
- FIRDocumentSnapshot *result = [self readDocumentForRef:doc];
- XCTAssertEqualObjects(result[@"name"], testData[@"name"]);
- XCTAssertEqualObjects(result[@"metadata"], testData[@"metadata"]);
- XCTAssertEqualObjects(result[@"metadata.deep.field"], testData[@"metadata"][@"deep"][@"field"]);
- XCTAssertNil(result[@"metadata.nofield"]);
- XCTAssertNil(result[@"nometadata.nofield"]);
- }
- - (void)testNestedFieldsCanBeUpdated {
- NSDictionary<NSString *, id> *testData = [self testNestedDataNumbered:1];
- FIRDocumentReference *doc = [self documentRef];
- [self writeDocumentRef:doc data:testData];
- [self updateDocumentRef:doc data:@{@"metadata.deep.field" : @100, @"metadata.added" : @200}];
- FIRDocumentSnapshot *result = [self readDocumentForRef:doc];
- XCTAssertEqualObjects(
- result.data, (@{
- @"name" : @"room 1",
- @"metadata" : @{@"createdAt" : @1, @"deep" : @{@"field" : @100}, @"added" : @200}
- }));
- }
- - (void)testNestedFieldsCanBeUsedInQueryFilters {
- NSDictionary<NSString *, NSDictionary<NSString *, id> *> *testDocs = @{
- @"1" : [self testNestedDataNumbered:300],
- @"2" : [self testNestedDataNumbered:100],
- @"3" : [self testNestedDataNumbered:200]
- };
- // inequality adds implicit sort on field
- NSArray<NSDictionary<NSString *, id> *> *expected =
- @[ [self testNestedDataNumbered:200], [self testNestedDataNumbered:300] ];
- FIRCollectionReference *coll = [self collectionRefWithDocuments:testDocs];
- FIRQuery *q = [coll queryWhereField:@"metadata.createdAt" isGreaterThanOrEqualTo:@200];
- FIRQuerySnapshot *results = [self readDocumentSetForRef:q];
- XCTAssertEqualObjects(FIRQuerySnapshotGetData(results), (expected));
- }
- - (void)testNestedFieldsCanBeUsedInOrderBy {
- NSDictionary<NSString *, NSDictionary<NSString *, id> *> *testDocs = @{
- @"1" : [self testNestedDataNumbered:300],
- @"2" : [self testNestedDataNumbered:100],
- @"3" : [self testNestedDataNumbered:200]
- };
- FIRCollectionReference *coll = [self collectionRefWithDocuments:testDocs];
- XCTestExpectation *queryCompletion = [self expectationWithDescription:@"query"];
- FIRQuery *q = [coll queryOrderedByField:@"metadata.createdAt"];
- [q getDocumentsWithCompletion:^(FIRQuerySnapshot *results, NSError *error) {
- XCTAssertNil(error);
- XCTAssertEqualObjects(FIRQuerySnapshotGetData(results), (@[
- [self testNestedDataNumbered:100], [self testNestedDataNumbered:200],
- [self testNestedDataNumbered:300]
- ]));
- [queryCompletion fulfill];
- }];
- [self awaitExpectations];
- }
- /**
- * Creates test data with special characters in field names. Datastore currently prohibits mixing
- * nested data with special characters so tests that use this data must be separate.
- */
- - (NSDictionary<NSString *, id> *)testDottedDataNumbered:(int)number {
- return @{
- @"a" : [NSString stringWithFormat:@"field %d", number],
- @"b.dot" : @(number),
- @"c\\slash" : @(number)
- };
- }
- - (void)testFieldsWithSpecialCharsCanBeWrittenWithSet {
- NSDictionary<NSString *, id> *testData = [self testDottedDataNumbered:1];
- FIRDocumentReference *doc = [self documentRef];
- [self writeDocumentRef:doc data:testData];
- FIRDocumentSnapshot *result = [self readDocumentForRef:doc];
- XCTAssertEqualObjects(result.data, testData);
- }
- - (void)testFieldsWithSpecialCharsCanBeReadDirectly {
- NSDictionary<NSString *, id> *testData = [self testDottedDataNumbered:1];
- FIRDocumentReference *doc = [self documentRef];
- [self writeDocumentRef:doc data:testData];
- FIRDocumentSnapshot *result = [self readDocumentForRef:doc];
- XCTAssertEqualObjects(result[@"a"], testData[@"a"]);
- XCTAssertEqualObjects(result[[[FIRFieldPath alloc] initWithFields:@[ @"b.dot" ]]],
- testData[@"b.dot"]);
- XCTAssertEqualObjects(result[@"c\\slash"], testData[@"c\\slash"]);
- }
- - (void)testFieldsWithSpecialCharsCanBeUpdated {
- NSDictionary<NSString *, id> *testData = [self testDottedDataNumbered:1];
- FIRDocumentReference *doc = [self documentRef];
- [self writeDocumentRef:doc data:testData];
- [self updateDocumentRef:doc
- data:@{
- (id)[[FIRFieldPath alloc] initWithFields:@[ @"b.dot" ]] : @100,
- (id) @"c\\slash" : @200
- }];
- FIRDocumentSnapshot *result = [self readDocumentForRef:doc];
- XCTAssertEqualObjects(result.data, (@{@"a" : @"field 1", @"b.dot" : @100, @"c\\slash" : @200}));
- }
- - (void)testFieldsWithSpecialCharsCanBeUsedInQueryFilters {
- NSDictionary<NSString *, NSDictionary<NSString *, id> *> *testDocs = @{
- @"1" : [self testDottedDataNumbered:300],
- @"2" : [self testDottedDataNumbered:100],
- @"3" : [self testDottedDataNumbered:200]
- };
- // inequality adds implicit sort on field
- NSArray<NSDictionary<NSString *, id> *> *expected =
- @[ [self testDottedDataNumbered:200], [self testDottedDataNumbered:300] ];
- FIRCollectionReference *coll = [self collectionRefWithDocuments:testDocs];
- XCTestExpectation *queryCompletion = [self expectationWithDescription:@"query"];
- FIRQuery *q = [coll queryWhereFieldPath:[[FIRFieldPath alloc] initWithFields:@[ @"b.dot" ]]
- isGreaterThanOrEqualTo:@200];
- [q getDocumentsWithCompletion:^(FIRQuerySnapshot *results, NSError *error) {
- XCTAssertNil(error);
- XCTAssertEqualObjects(FIRQuerySnapshotGetData(results), expected);
- [queryCompletion fulfill];
- }];
- [self awaitExpectations];
- }
- - (void)testFieldsWithSpecialCharsCanBeUsedInOrderBy {
- NSDictionary<NSString *, NSDictionary<NSString *, id> *> *testDocs = @{
- @"1" : [self testDottedDataNumbered:300],
- @"2" : [self testDottedDataNumbered:100],
- @"3" : [self testDottedDataNumbered:200]
- };
- NSArray<NSDictionary<NSString *, id> *> *expected = @[
- [self testDottedDataNumbered:100], [self testDottedDataNumbered:200],
- [self testDottedDataNumbered:300]
- ];
- FIRCollectionReference *coll = [self collectionRefWithDocuments:testDocs];
- FIRQuery *q = [coll queryOrderedByFieldPath:[[FIRFieldPath alloc] initWithFields:@[ @"b.dot" ]]];
- XCTestExpectation *queryDot = [self expectationWithDescription:@"query dot"];
- [q getDocumentsWithCompletion:^(FIRQuerySnapshot *results, NSError *error) {
- XCTAssertNil(error);
- XCTAssertEqualObjects(FIRQuerySnapshotGetData(results), expected);
- [queryDot fulfill];
- }];
- [self awaitExpectations];
- XCTestExpectation *querySlash = [self expectationWithDescription:@"query slash"];
- q = [coll queryOrderedByField:@"c\\slash"];
- [q getDocumentsWithCompletion:^(FIRQuerySnapshot *results, NSError *error) {
- XCTAssertNil(error);
- XCTAssertEqualObjects(FIRQuerySnapshotGetData(results), expected);
- [querySlash fulfill];
- }];
- [self awaitExpectations];
- }
- - (FIRDocumentSnapshot *)snapshotWithTimestamps:(FIRTimestamp *)timestamp {
- FIRDocumentReference *doc = [self documentRef];
- NSDictionary<NSString *, id> *data =
- @{@"timestamp" : timestamp, @"nested" : @{@"timestamp2" : timestamp}};
- [self writeDocumentRef:doc data:data];
- return [self readDocumentForRef:doc];
- }
- - (void)testTimestampsInSnapshots {
- FIRTimestamp *originalTimestamp = [FIRTimestamp timestampWithSeconds:100 nanoseconds:123456789];
- FIRDocumentReference *doc = [self documentRef];
- [self writeDocumentRef:doc data:testDataWithTimestamps(originalTimestamp)];
- FIRDocumentSnapshot *snapshot = [self readDocumentForRef:doc];
- NSDictionary<NSString *, id> *data = [snapshot data];
- // Timestamp are currently truncated to microseconds after being written to the database.
- FIRTimestamp *truncatedTimestamp =
- [FIRTimestamp timestampWithSeconds:originalTimestamp.seconds
- nanoseconds:originalTimestamp.nanoseconds / 1000 * 1000];
- FIRTimestamp *timestampFromSnapshot = snapshot[@"timestamp"];
- FIRTimestamp *timestampFromData = data[@"timestamp"];
- XCTAssertEqualObjects(truncatedTimestamp, timestampFromData);
- XCTAssertEqualObjects(timestampFromSnapshot, timestampFromData);
- timestampFromSnapshot = snapshot[@"nested.timestamp2"];
- timestampFromData = data[@"nested"][@"timestamp2"];
- XCTAssertEqualObjects(truncatedTimestamp, timestampFromData);
- XCTAssertEqualObjects(timestampFromSnapshot, timestampFromData);
- }
- @end
- @interface FIRTimestampsInSnapshotsLegacyBehaviorTests : FSTIntegrationTestCase
- @end
- @implementation FIRTimestampsInSnapshotsLegacyBehaviorTests
- - (void)setUp {
- [super setUp];
- // Settings can only be redefined before client is initialized, so this has to happen in setUp.
- FIRFirestoreSettings *settings = self.db.settings;
- SUPPRESS_DEPRECATED_DECLARATIONS_BEGIN()
- settings.timestampsInSnapshotsEnabled = NO;
- SUPPRESS_END()
- self.db.settings = settings;
- }
- - (void)testLegacyBehaviorForTimestampFields {
- NSDate *originalDate = [NSDate date];
- FIRDocumentReference *doc = [self documentRef];
- [self writeDocumentRef:doc
- data:testDataWithTimestamps([FIRTimestamp timestampWithDate:originalDate])];
- FIRDocumentSnapshot *snapshot = [self readDocumentForRef:doc];
- NSDictionary<NSString *, id> *data = [snapshot data];
- double microsecond = 0.000001;
- NSDate *timestampFromSnapshot = snapshot[@"timestamp"];
- NSDate *timestampFromData = data[@"timestamp"];
- XCTAssertEqualObjects(timestampFromSnapshot, timestampFromData);
- XCTAssertEqualWithAccuracy([timestampFromSnapshot timeIntervalSince1970],
- [originalDate timeIntervalSince1970], microsecond);
- timestampFromSnapshot = snapshot[@"nested.timestamp2"];
- timestampFromData = data[@"nested"][@"timestamp2"];
- XCTAssertEqualObjects(timestampFromSnapshot, timestampFromData);
- XCTAssertEqualWithAccuracy([timestampFromSnapshot timeIntervalSince1970],
- [originalDate timeIntervalSince1970], microsecond);
- }
- - (void)testLegacyBehaviorForServerTimestampFields {
- FIRDocumentReference *doc = [self documentRef];
- [self writeDocumentRef:doc data:@{@"when" : [FIRFieldValue fieldValueForServerTimestamp]}];
- FIRDocumentSnapshot *snapshot = [self readDocumentForRef:doc];
- XCTAssertTrue([snapshot[@"when"] isKindOfClass:[NSDate class]]);
- XCTAssertTrue([snapshot.data[@"when"] isKindOfClass:[NSDate class]]);
- }
- @end
|