/* * 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 #import #import "Firestore/Example/Tests/Util/FSTIntegrationTestCase.h" @interface FIRCursorTests : FSTIntegrationTestCase @end @implementation FIRCursorTests - (void)testCanPageThroughItems { FIRCollectionReference *testCollection = [self collectionRefWithDocuments:@{ @"a" : @{@"v" : @"a"}, @"b" : @{@"v" : @"b"}, @"c" : @{@"v" : @"c"}, @"d" : @{@"v" : @"d"}, @"e" : @{@"v" : @"e"}, @"f" : @{@"v" : @"f"} }]; FIRQuerySnapshot *snapshot = [self readDocumentSetForRef:[testCollection queryLimitedTo:2]]; XCTAssertEqualObjects(FIRQuerySnapshotGetData(snapshot), (@[ @{@"v" : @"a"}, @{@"v" : @"b"} ])); FIRDocumentSnapshot *lastDoc = snapshot.documents.lastObject; snapshot = [self readDocumentSetForRef:[[testCollection queryLimitedTo:3] queryStartingAfterDocument:lastDoc]]; XCTAssertEqualObjects(FIRQuerySnapshotGetData(snapshot), (@[ @{@"v" : @"c"}, @{@"v" : @"d"}, @{@"v" : @"e"} ])); lastDoc = snapshot.documents.lastObject; snapshot = [self readDocumentSetForRef:[[testCollection queryLimitedTo:1] queryStartingAfterDocument:lastDoc]]; XCTAssertEqualObjects(FIRQuerySnapshotGetData(snapshot), @[ @{@"v" : @"f"} ]); lastDoc = snapshot.documents.lastObject; snapshot = [self readDocumentSetForRef:[[testCollection queryLimitedTo:3] queryStartingAfterDocument:lastDoc]]; XCTAssertEqualObjects(FIRQuerySnapshotGetData(snapshot), @[]); } - (void)testCanBeCreatedFromDocuments { FIRCollectionReference *testCollection = [self collectionRefWithDocuments:@{ @"a" : @{@"v" : @"a", @"sort" : @1.0}, @"b" : @{@"v" : @"b", @"sort" : @2.0}, @"c" : @{@"v" : @"c", @"sort" : @2.0}, @"d" : @{@"v" : @"d", @"sort" : @2.0}, @"e" : @{@"v" : @"e", @"sort" : @0.0}, @"f" : @{@"v" : @"f", @"nosort" : @1.0} // should not show up }]; FIRQuery *query = [testCollection queryOrderedByField:@"sort"]; FIRDocumentSnapshot *snapshot = [self readDocumentForRef:[testCollection documentWithPath:@"c"]]; XCTAssertTrue(snapshot.exists); FIRQuerySnapshot *querySnapshot = [self readDocumentSetForRef:[query queryStartingAtDocument:snapshot]]; XCTAssertEqualObjects(FIRQuerySnapshotGetData(querySnapshot), (@[ @{ @"v" : @"c", @"sort" : @2.0 }, @{ @"v" : @"d", @"sort" : @2.0 } ])); querySnapshot = [self readDocumentSetForRef:[query queryEndingBeforeDocument:snapshot]]; XCTAssertEqualObjects(FIRQuerySnapshotGetData(querySnapshot), (@[ @{ @"v" : @"e", @"sort" : @0.0 }, @{ @"v" : @"a", @"sort" : @1.0 }, @{ @"v" : @"b", @"sort" : @2.0 } ])); } - (void)testCanBeCreatedFromValues { FIRCollectionReference *testCollection = [self collectionRefWithDocuments:@{ @"a" : @{@"v" : @"a", @"sort" : @1.0}, @"b" : @{@"v" : @"b", @"sort" : @2.0}, @"c" : @{@"v" : @"c", @"sort" : @2.0}, @"d" : @{@"v" : @"d", @"sort" : @2.0}, @"e" : @{@"v" : @"e", @"sort" : @0.0}, @"f" : @{@"v" : @"f", @"nosort" : @1.0} // should not show up }]; FIRQuery *query = [testCollection queryOrderedByField:@"sort"]; FIRQuerySnapshot *querySnapshot = [self readDocumentSetForRef:[query queryStartingAtValues:@[ @2.0 ]]]; XCTAssertEqualObjects(FIRQuerySnapshotGetData(querySnapshot), (@[ @{ @"v" : @"b", @"sort" : @2.0 }, @{ @"v" : @"c", @"sort" : @2.0 }, @{ @"v" : @"d", @"sort" : @2.0 } ])); querySnapshot = [self readDocumentSetForRef:[query queryEndingBeforeValues:@[ @2.0 ]]]; XCTAssertEqualObjects(FIRQuerySnapshotGetData(querySnapshot), (@[ @{ @"v" : @"e", @"sort" : @0.0 }, @{ @"v" : @"a", @"sort" : @1.0 } ])); } - (void)testCanBeCreatedUsingDocumentId { NSDictionary *testDocs = @{ @"a" : @{@"k" : @"a"}, @"b" : @{@"k" : @"b"}, @"c" : @{@"k" : @"c"}, @"d" : @{@"k" : @"d"}, @"e" : @{@"k" : @"e"} }; FIRCollectionReference *writer = [[[[self firestore] collectionWithPath:@"parent-collection"] documentWithAutoID] collectionWithPath:@"sub-collection"]; [self writeAllDocuments:testDocs toCollection:writer]; FIRCollectionReference *reader = [[self firestore] collectionWithPath:writer.path]; FIRQuerySnapshot *querySnapshot = [self readDocumentSetForRef:[[[reader queryOrderedByFieldPath:[FIRFieldPath documentID]] queryStartingAtValues:@[ @"b" ]] queryEndingBeforeValues:@[ @"d" ]]]; XCTAssertEqualObjects(FIRQuerySnapshotGetData(querySnapshot), (@[ @{@"k" : @"b"}, @{@"k" : @"c"} ])); } - (void)testCanBeUsedWithReferenceValues { FIRFirestore *db = [self firestore]; FIRCollectionReference *testCollection = [self collectionRefWithDocuments:@{ @"a" : @{@"k" : @"1a", @"ref" : [db documentWithPath:@"1/a"]}, @"b" : @{@"k" : @"1b", @"ref" : [db documentWithPath:@"1/b"]}, @"c" : @{@"k" : @"2a", @"ref" : [db documentWithPath:@"2/a"]}, @"d" : @{@"k" : @"2b", @"ref" : [db documentWithPath:@"2/b"]}, @"e" : @{@"k" : @"3a", @"ref" : [db documentWithPath:@"3/a"]}, }]; FIRQuery *query = [testCollection queryOrderedByField:@"ref"]; FIRQuerySnapshot *querySnapshot = [self readDocumentSetForRef:[[query queryStartingAfterValues:@[ [db documentWithPath:@"1/a"] ]] queryEndingAtValues:@[ [db documentWithPath:@"2/b"] ]]]; NSMutableArray *actual = [NSMutableArray array]; [querySnapshot.documents enumerateObjectsUsingBlock:^(FIRDocumentSnapshot *_Nonnull doc, NSUInteger idx, BOOL *_Nonnull stop) { [actual addObject:doc.data[@"k"]]; }]; XCTAssertEqualObjects(actual, (@[ @"1b", @"2a", @"2b" ])); } - (void)testCanBeUsedInDescendingQueries { FIRCollectionReference *testCollection = [self collectionRefWithDocuments:@{ @"a" : @{@"v" : @"a", @"sort" : @1.0}, @"b" : @{@"v" : @"b", @"sort" : @2.0}, @"c" : @{@"v" : @"c", @"sort" : @2.0}, @"d" : @{@"v" : @"d", @"sort" : @3.0}, @"e" : @{@"v" : @"e", @"sort" : @0.0}, @"f" : @{@"v" : @"f", @"nosort" : @1.0} // should not show up }]; FIRQuery *query = [[testCollection queryOrderedByField:@"sort" descending:YES] queryOrderedByFieldPath:[FIRFieldPath documentID] descending:YES]; FIRQuerySnapshot *snapshot = [self readDocumentSetForRef:[query queryStartingAtValues:@[ @2.0 ]]]; XCTAssertEqualObjects(FIRQuerySnapshotGetData(snapshot), (@[ @{ @"v" : @"c", @"sort" : @2.0 }, @{ @"v" : @"b", @"sort" : @2.0 }, @{ @"v" : @"a", @"sort" : @1.0 }, @{ @"v" : @"e", @"sort" : @0.0 } ])); snapshot = [self readDocumentSetForRef:[query queryEndingBeforeValues:@[ @2.0 ]]]; XCTAssertEqualObjects(FIRQuerySnapshotGetData(snapshot), (@[ @{ @"v" : @"d", @"sort" : @3.0 } ])); } FIRTimestamp *TimestampWithMicros(int64_t seconds, int32_t micros) { // Firestore only supports microsecond resolution, so use a microsecond as a minimum value for // nanoseconds. return [FIRTimestamp timestampWithSeconds:seconds nanoseconds:micros * 1000]; } - (void)testTimestampsCanBePassedToQueriesAsLimits { FIRCollectionReference *testCollection = [self collectionRefWithDocuments:@{ @"a" : @{@"timestamp" : TimestampWithMicros(100, 2)}, @"b" : @{@"timestamp" : TimestampWithMicros(100, 5)}, @"c" : @{@"timestamp" : TimestampWithMicros(100, 3)}, @"d" : @{@"timestamp" : TimestampWithMicros(100, 1)}, // Number of microseconds deliberately repeated. @"e" : @{@"timestamp" : TimestampWithMicros(100, 5)}, @"f" : @{@"timestamp" : TimestampWithMicros(100, 4)}, }]; FIRQuery *query = [testCollection queryOrderedByField:@"timestamp"]; FIRQuerySnapshot *querySnapshot = [self readDocumentSetForRef:[[query queryStartingAfterValues:@[ TimestampWithMicros(100, 2) ]] queryEndingAtValues:@[ TimestampWithMicros(100, 5) ]]]; XCTAssertEqualObjects(FIRQuerySnapshotGetIDs(querySnapshot), (@[ @"c", @"f", @"b", @"e" ])); } - (void)testTimestampsCanBePassedToQueriesInWhereClause { FIRCollectionReference *testCollection = [self collectionRefWithDocuments:@{ @"a" : @{ @"timestamp" : TimestampWithMicros(100, 7), }, @"b" : @{ @"timestamp" : TimestampWithMicros(100, 4), }, @"c" : @{ @"timestamp" : TimestampWithMicros(100, 8), }, @"d" : @{ @"timestamp" : TimestampWithMicros(100, 5), }, @"e" : @{ @"timestamp" : TimestampWithMicros(100, 6), } }]; FIRQuerySnapshot *querySnapshot = [self readDocumentSetForRef:[[testCollection queryWhereField:@"timestamp" isGreaterThanOrEqualTo:TimestampWithMicros(100, 5)] queryWhereField:@"timestamp" isLessThan:TimestampWithMicros(100, 8)]]; XCTAssertEqualObjects(FIRQuerySnapshotGetIDs(querySnapshot), (@[ @"d", @"e", @"a" ])); } - (void)testTimestampsAreTruncatedToMicroseconds { FIRTimestamp *nanos = [FIRTimestamp timestampWithSeconds:0 nanoseconds:123456789]; FIRTimestamp *micros = [FIRTimestamp timestampWithSeconds:0 nanoseconds:123456000]; FIRTimestamp *millis = [FIRTimestamp timestampWithSeconds:0 nanoseconds:123000000]; FIRCollectionReference *testCollection = [self collectionRefWithDocuments:@{ @"a" : @{@"timestamp" : nanos}, }]; FIRQuerySnapshot *querySnapshot = [self readDocumentSetForRef:[testCollection queryWhereField:@"timestamp" isEqualTo:nanos]]; XCTAssertEqualObjects(FIRQuerySnapshotGetIDs(querySnapshot), (@[ @"a" ])); // Because Timestamp should have been truncated to microseconds, the microsecond timestamp // should be considered equal to the nanosecond one. querySnapshot = [self readDocumentSetForRef:[testCollection queryWhereField:@"timestamp" isEqualTo:micros]]; XCTAssertEqualObjects(FIRQuerySnapshotGetIDs(querySnapshot), (@[ @"a" ])); // The truncation is just to the microseconds, however, so the millisecond timestamp should be // treated as different and thus the query should return no results. querySnapshot = [self readDocumentSetForRef:[testCollection queryWhereField:@"timestamp" isEqualTo:millis]]; XCTAssertEqualObjects(FIRQuerySnapshotGetIDs(querySnapshot), (@[])); } @end