| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618 |
- /*
- * 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 "Firestore/Source/Core/FSTView.h"
- #import <XCTest/XCTest.h>
- #import "Firestore/Source/API/FIRFirestore+Internal.h"
- #import "Firestore/Source/Core/FSTQuery.h"
- #import "Firestore/Source/Core/FSTViewSnapshot.h"
- #import "Firestore/Source/Model/FSTDocument.h"
- #import "Firestore/Source/Model/FSTDocumentKey.h"
- #import "Firestore/Source/Model/FSTDocumentSet.h"
- #import "Firestore/Source/Model/FSTFieldValue.h"
- #import "Firestore/Source/Model/FSTPath.h"
- #import "Firestore/Source/Remote/FSTRemoteEvent.h"
- #import "Firestore/Example/Tests/Util/FSTHelpers.h"
- NS_ASSUME_NONNULL_BEGIN
- @interface FSTViewTests : XCTestCase
- @end
- @implementation FSTViewTests
- /** Returns a new empty query to use for testing. */
- - (FSTQuery *)queryForMessages {
- return [FSTQuery
- queryWithPath:[FSTResourcePath pathWithSegments:@[ @"rooms", @"eros", @"messages" ]]];
- }
- - (void)testAddsDocumentsBasedOnQuery {
- FSTQuery *query = [self queryForMessages];
- FSTView *view = [[FSTView alloc] initWithQuery:query remoteDocuments:[FSTDocumentKeySet keySet]];
- FSTDocument *doc1 = FSTTestDoc(@"rooms/eros/messages/1", 0, @{@"text" : @"msg1"}, NO);
- FSTDocument *doc2 = FSTTestDoc(@"rooms/eros/messages/2", 0, @{@"text" : @"msg2"}, NO);
- FSTDocument *doc3 = FSTTestDoc(@"rooms/other/messages/1", 0, @{@"text" : @"msg3"}, NO);
- FSTViewSnapshot *_Nullable snapshot =
- FSTTestApplyChanges(view, @[ doc1, doc2, doc3 ],
- [FSTTargetChange changeWithDocuments:@[ doc1, doc2, doc3 ]
- currentStatusUpdate:FSTCurrentStatusUpdateMarkCurrent]);
- XCTAssertEqual(snapshot.query, query);
- XCTAssertEqualObjects(snapshot.documents.arrayValue, (@[ doc1, doc2 ]));
- XCTAssertEqualObjects(
- snapshot.documentChanges, (@[
- [FSTDocumentViewChange changeWithDocument:doc1 type:FSTDocumentViewChangeTypeAdded],
- [FSTDocumentViewChange changeWithDocument:doc2 type:FSTDocumentViewChangeTypeAdded]
- ]));
- XCTAssertFalse(snapshot.isFromCache);
- XCTAssertFalse(snapshot.hasPendingWrites);
- XCTAssertTrue(snapshot.syncStateChanged);
- }
- - (void)testRemovesDocuments {
- FSTQuery *query = [self queryForMessages];
- FSTView *view = [[FSTView alloc] initWithQuery:query remoteDocuments:[FSTDocumentKeySet keySet]];
- FSTDocument *doc1 = FSTTestDoc(@"rooms/eros/messages/1", 0, @{@"text" : @"msg1"}, NO);
- FSTDocument *doc2 = FSTTestDoc(@"rooms/eros/messages/2", 0, @{@"text" : @"msg2"}, NO);
- FSTDocument *doc3 = FSTTestDoc(@"rooms/eros/messages/3", 0, @{@"text" : @"msg3"}, NO);
- // initial state
- FSTTestApplyChanges(view, @[ doc1, doc2 ], nil);
- // delete doc2, add doc3
- FSTViewSnapshot *snapshot =
- FSTTestApplyChanges(view, @[ FSTTestDeletedDoc(@"rooms/eros/messages/2", 0), doc3 ],
- [FSTTargetChange changeWithDocuments:@[ doc1, doc3 ]
- currentStatusUpdate:FSTCurrentStatusUpdateMarkCurrent]);
- XCTAssertEqual(snapshot.query, query);
- XCTAssertEqualObjects(snapshot.documents.arrayValue, (@[ doc1, doc3 ]));
- XCTAssertEqualObjects(
- snapshot.documentChanges, (@[
- [FSTDocumentViewChange changeWithDocument:doc2 type:FSTDocumentViewChangeTypeRemoved],
- [FSTDocumentViewChange changeWithDocument:doc3 type:FSTDocumentViewChangeTypeAdded]
- ]));
- XCTAssertFalse(snapshot.isFromCache);
- XCTAssertTrue(snapshot.syncStateChanged);
- }
- - (void)testReturnsNilIfThereAreNoChanges {
- FSTQuery *query = [self queryForMessages];
- FSTView *view = [[FSTView alloc] initWithQuery:query remoteDocuments:[FSTDocumentKeySet keySet]];
- FSTDocument *doc1 = FSTTestDoc(@"rooms/eros/messages/1", 0, @{@"text" : @"msg1"}, NO);
- FSTDocument *doc2 = FSTTestDoc(@"rooms/eros/messages/2", 0, @{@"text" : @"msg2"}, NO);
- // initial state
- FSTTestApplyChanges(view, @[ doc1, doc2 ], nil);
- // reapply same docs, no changes
- FSTViewSnapshot *snapshot = FSTTestApplyChanges(view, @[ doc1, doc2 ], nil);
- XCTAssertNil(snapshot);
- }
- - (void)testDoesNotReturnNilForFirstChanges {
- FSTQuery *query = [self queryForMessages];
- FSTView *view = [[FSTView alloc] initWithQuery:query remoteDocuments:[FSTDocumentKeySet keySet]];
- FSTViewSnapshot *snapshot = FSTTestApplyChanges(view, @[], nil);
- XCTAssertNotNil(snapshot);
- }
- - (void)testFiltersDocumentsBasedOnQueryWithFilter {
- FSTQuery *query = [self queryForMessages];
- FSTRelationFilter *filter =
- [FSTRelationFilter filterWithField:FSTTestFieldPath(@"sort")
- filterOperator:FSTRelationFilterOperatorLessThanOrEqual
- value:[FSTDoubleValue doubleValue:2]];
- query = [query queryByAddingFilter:filter];
- FSTView *view = [[FSTView alloc] initWithQuery:query remoteDocuments:[FSTDocumentKeySet keySet]];
- FSTDocument *doc1 = FSTTestDoc(@"rooms/eros/messages/1", 0, @{ @"sort" : @1 }, NO);
- FSTDocument *doc2 = FSTTestDoc(@"rooms/eros/messages/2", 0, @{ @"sort" : @2 }, NO);
- FSTDocument *doc3 = FSTTestDoc(@"rooms/eros/messages/3", 0, @{ @"sort" : @3 }, NO);
- FSTDocument *doc4 = FSTTestDoc(@"rooms/eros/messages/4", 0, @{}, NO); // no sort, no match
- FSTDocument *doc5 = FSTTestDoc(@"rooms/eros/messages/5", 0, @{ @"sort" : @1 }, NO);
- FSTViewSnapshot *snapshot = FSTTestApplyChanges(view, @[ doc1, doc2, doc3, doc4, doc5 ], nil);
- XCTAssertEqual(snapshot.query, query);
- XCTAssertEqualObjects(snapshot.documents.arrayValue, (@[ doc1, doc5, doc2 ]));
- XCTAssertEqualObjects(
- snapshot.documentChanges, (@[
- [FSTDocumentViewChange changeWithDocument:doc1 type:FSTDocumentViewChangeTypeAdded],
- [FSTDocumentViewChange changeWithDocument:doc5 type:FSTDocumentViewChangeTypeAdded],
- [FSTDocumentViewChange changeWithDocument:doc2 type:FSTDocumentViewChangeTypeAdded]
- ]));
- XCTAssertTrue(snapshot.isFromCache);
- XCTAssertTrue(snapshot.syncStateChanged);
- }
- - (void)testUpdatesDocumentsBasedOnQueryWithFilter {
- FSTQuery *query = [self queryForMessages];
- FSTRelationFilter *filter =
- [FSTRelationFilter filterWithField:FSTTestFieldPath(@"sort")
- filterOperator:FSTRelationFilterOperatorLessThanOrEqual
- value:[FSTDoubleValue doubleValue:2]];
- query = [query queryByAddingFilter:filter];
- FSTView *view = [[FSTView alloc] initWithQuery:query remoteDocuments:[FSTDocumentKeySet keySet]];
- FSTDocument *doc1 = FSTTestDoc(@"rooms/eros/messages/1", 0, @{ @"sort" : @1 }, NO);
- FSTDocument *doc2 = FSTTestDoc(@"rooms/eros/messages/2", 0, @{ @"sort" : @3 }, NO);
- FSTDocument *doc3 = FSTTestDoc(@"rooms/eros/messages/3", 0, @{ @"sort" : @2 }, NO);
- FSTDocument *doc4 = FSTTestDoc(@"rooms/eros/messages/4", 0, @{}, NO);
- FSTViewSnapshot *snapshot = FSTTestApplyChanges(view, @[ doc1, doc2, doc3, doc4 ], nil);
- XCTAssertEqual(snapshot.query, query);
- XCTAssertEqualObjects(snapshot.documents.arrayValue, (@[ doc1, doc3 ]));
- FSTDocument *newDoc2 = FSTTestDoc(@"rooms/eros/messages/2", 1, @{ @"sort" : @2 }, NO);
- FSTDocument *newDoc3 = FSTTestDoc(@"rooms/eros/messages/3", 1, @{ @"sort" : @3 }, NO);
- FSTDocument *newDoc4 = FSTTestDoc(@"rooms/eros/messages/4", 1, @{ @"sort" : @0 }, NO);
- snapshot = FSTTestApplyChanges(view, @[ newDoc2, newDoc3, newDoc4 ], nil);
- XCTAssertEqual(snapshot.query, query);
- XCTAssertEqualObjects(snapshot.documents.arrayValue, (@[ newDoc4, doc1, newDoc2 ]));
- XCTAssertEqualObjects(
- snapshot.documentChanges, (@[
- [FSTDocumentViewChange changeWithDocument:doc3 type:FSTDocumentViewChangeTypeRemoved],
- [FSTDocumentViewChange changeWithDocument:newDoc4 type:FSTDocumentViewChangeTypeAdded],
- [FSTDocumentViewChange changeWithDocument:newDoc2 type:FSTDocumentViewChangeTypeAdded]
- ]));
- XCTAssertTrue(snapshot.isFromCache);
- XCTAssertFalse(snapshot.syncStateChanged);
- }
- - (void)testRemovesDocumentsForQueryWithLimit {
- FSTQuery *query = [self queryForMessages];
- query = [query queryBySettingLimit:2];
- FSTView *view = [[FSTView alloc] initWithQuery:query remoteDocuments:[FSTDocumentKeySet keySet]];
- FSTDocument *doc1 = FSTTestDoc(@"rooms/eros/messages/1", 0, @{@"text" : @"msg1"}, NO);
- FSTDocument *doc2 = FSTTestDoc(@"rooms/eros/messages/2", 0, @{@"text" : @"msg2"}, NO);
- FSTDocument *doc3 = FSTTestDoc(@"rooms/eros/messages/3", 0, @{@"text" : @"msg3"}, NO);
- // initial state
- FSTTestApplyChanges(view, @[ doc1, doc3 ], nil);
- // add doc2, which should push out doc3
- FSTViewSnapshot *snapshot =
- FSTTestApplyChanges(view, @[ doc2 ],
- [FSTTargetChange changeWithDocuments:@[ doc1, doc2, doc3 ]
- currentStatusUpdate:FSTCurrentStatusUpdateMarkCurrent]);
- XCTAssertEqual(snapshot.query, query);
- XCTAssertEqualObjects(snapshot.documents.arrayValue, (@[ doc1, doc2 ]));
- XCTAssertEqualObjects(
- snapshot.documentChanges, (@[
- [FSTDocumentViewChange changeWithDocument:doc3 type:FSTDocumentViewChangeTypeRemoved],
- [FSTDocumentViewChange changeWithDocument:doc2 type:FSTDocumentViewChangeTypeAdded]
- ]));
- XCTAssertFalse(snapshot.isFromCache);
- XCTAssertTrue(snapshot.syncStateChanged);
- }
- - (void)testDoesntReportChangesForDocumentBeyondLimitOfQuery {
- FSTQuery *query = [self queryForMessages];
- query =
- [query queryByAddingSortOrder:[FSTSortOrder sortOrderWithFieldPath:FSTTestFieldPath(@"num")
- ascending:YES]];
- query = [query queryBySettingLimit:2];
- FSTView *view = [[FSTView alloc] initWithQuery:query remoteDocuments:[FSTDocumentKeySet keySet]];
- FSTDocument *doc1 = FSTTestDoc(@"rooms/eros/messages/1", 0, @{ @"num" : @1 }, NO);
- FSTDocument *doc2 = FSTTestDoc(@"rooms/eros/messages/2", 0, @{ @"num" : @2 }, NO);
- FSTDocument *doc3 = FSTTestDoc(@"rooms/eros/messages/3", 0, @{ @"num" : @3 }, NO);
- FSTDocument *doc4 = FSTTestDoc(@"rooms/eros/messages/4", 0, @{ @"num" : @4 }, NO);
- // initial state
- FSTTestApplyChanges(view, @[ doc1, doc2 ], nil);
- // change doc2 to 5, and add doc3 and doc4.
- // doc2 will be modified + removed = removed
- // doc3 will be added
- // doc4 will be added + removed = nothing
- doc2 = FSTTestDoc(@"rooms/eros/messages/2", 1, @{ @"num" : @5 }, NO);
- FSTViewDocumentChanges *viewDocChanges =
- [view computeChangesWithDocuments:FSTTestDocUpdates(@[ doc2, doc3, doc4 ])];
- XCTAssertTrue(viewDocChanges.needsRefill);
- // Verify that all the docs still match.
- viewDocChanges = [view computeChangesWithDocuments:FSTTestDocUpdates(@[ doc1, doc2, doc3, doc4 ])
- previousChanges:viewDocChanges];
- FSTViewSnapshot *snapshot =
- [view applyChangesToDocuments:viewDocChanges
- targetChange:[FSTTargetChange
- changeWithDocuments:@[ doc1, doc2, doc3, doc4 ]
- currentStatusUpdate:FSTCurrentStatusUpdateMarkCurrent]]
- .snapshot;
- XCTAssertEqual(snapshot.query, query);
- XCTAssertEqualObjects(snapshot.documents.arrayValue, (@[ doc1, doc3 ]));
- XCTAssertEqualObjects(
- snapshot.documentChanges, (@[
- [FSTDocumentViewChange changeWithDocument:doc2 type:FSTDocumentViewChangeTypeRemoved],
- [FSTDocumentViewChange changeWithDocument:doc3 type:FSTDocumentViewChangeTypeAdded]
- ]));
- XCTAssertFalse(snapshot.isFromCache);
- XCTAssertTrue(snapshot.syncStateChanged);
- }
- - (void)testKeepsTrackOfLimboDocuments {
- FSTQuery *query = [self queryForMessages];
- FSTView *view = [[FSTView alloc] initWithQuery:query remoteDocuments:[FSTDocumentKeySet keySet]];
- FSTDocument *doc1 = FSTTestDoc(@"rooms/eros/messages/0", 0, @{}, NO);
- FSTDocument *doc2 = FSTTestDoc(@"rooms/eros/messages/1", 0, @{}, NO);
- FSTDocument *doc3 = FSTTestDoc(@"rooms/eros/messages/2", 0, @{}, NO);
- FSTViewChange *change = [view
- applyChangesToDocuments:[view computeChangesWithDocuments:FSTTestDocUpdates(@[ doc1 ])]];
- XCTAssertEqualObjects(change.limboChanges, @[]);
- change =
- [view applyChangesToDocuments:[view computeChangesWithDocuments:FSTTestDocUpdates(@[])]
- targetChange:[FSTTargetChange
- changeWithDocuments:@[]
- currentStatusUpdate:FSTCurrentStatusUpdateMarkCurrent]];
- XCTAssertEqualObjects(
- change.limboChanges,
- @[ [FSTLimboDocumentChange changeWithType:FSTLimboDocumentChangeTypeAdded key:doc1.key] ]);
- change = [view
- applyChangesToDocuments:[view computeChangesWithDocuments:FSTTestDocUpdates(@[])]
- targetChange:[FSTTargetChange changeWithDocuments:@[ doc1 ]
- currentStatusUpdate:FSTCurrentStatusUpdateNone]];
- XCTAssertEqualObjects(
- change.limboChanges,
- @[ [FSTLimboDocumentChange changeWithType:FSTLimboDocumentChangeTypeRemoved key:doc1.key] ]);
- change = [view
- applyChangesToDocuments:[view computeChangesWithDocuments:FSTTestDocUpdates(@[ doc2 ])]
- targetChange:[FSTTargetChange changeWithDocuments:@[ doc2 ]
- currentStatusUpdate:FSTCurrentStatusUpdateNone]];
- XCTAssertEqualObjects(change.limboChanges, @[]);
- change = [view
- applyChangesToDocuments:[view computeChangesWithDocuments:FSTTestDocUpdates(@[ doc3 ])]];
- XCTAssertEqualObjects(
- change.limboChanges,
- @[ [FSTLimboDocumentChange changeWithType:FSTLimboDocumentChangeTypeAdded key:doc3.key] ]);
- change = [view applyChangesToDocuments:[view computeChangesWithDocuments:FSTTestDocUpdates(@[
- FSTTestDeletedDoc(@"rooms/eros/messages/2",
- 1)
- ])]]; // remove
- XCTAssertEqualObjects(
- change.limboChanges,
- @[ [FSTLimboDocumentChange changeWithType:FSTLimboDocumentChangeTypeRemoved key:doc3.key] ]);
- }
- - (void)testResumingQueryCreatesNoLimbos {
- FSTQuery *query = [self queryForMessages];
- FSTDocument *doc1 = FSTTestDoc(@"rooms/eros/messages/0", 0, @{}, NO);
- FSTDocument *doc2 = FSTTestDoc(@"rooms/eros/messages/1", 0, @{}, NO);
- // Unlike other cases, here the view is initialized with a set of previously synced documents
- // which happens when listening to a previously listened-to query.
- FSTView *view = [[FSTView alloc] initWithQuery:query
- remoteDocuments:FSTTestDocKeySet(@[ doc1.key, doc2.key ])];
- FSTTargetChange *markCurrent =
- [FSTTargetChange changeWithDocuments:@[]
- currentStatusUpdate:FSTCurrentStatusUpdateMarkCurrent];
- FSTViewDocumentChanges *changes = [view computeChangesWithDocuments:FSTTestDocUpdates(@[])];
- FSTViewChange *change = [view applyChangesToDocuments:changes targetChange:markCurrent];
- XCTAssertEqualObjects(change.limboChanges, @[]);
- }
- - (void)assertDocSet:(FSTDocumentSet *)docSet containsDocs:(NSArray<FSTDocument *> *)docs {
- XCTAssertEqual(docs.count, docSet.count);
- for (FSTDocument *doc in docs) {
- XCTAssertTrue([docSet containsKey:doc.key]);
- }
- }
- - (void)testReturnsNeedsRefillOnDeleteInLimitQuery {
- FSTQuery *query = [[self queryForMessages] queryBySettingLimit:2];
- FSTDocument *doc1 = FSTTestDoc(@"rooms/eros/messages/0", 0, @{}, NO);
- FSTDocument *doc2 = FSTTestDoc(@"rooms/eros/messages/1", 0, @{}, NO);
- FSTView *view = [[FSTView alloc] initWithQuery:query remoteDocuments:[FSTDocumentKeySet keySet]];
- // Start with a full view.
- FSTViewDocumentChanges *changes =
- [view computeChangesWithDocuments:FSTTestDocUpdates(@[ doc1, doc2 ])];
- [self assertDocSet:changes.documentSet containsDocs:@[ doc1, doc2 ]];
- XCTAssertFalse(changes.needsRefill);
- XCTAssertEqual(2, [changes.changeSet changes].count);
- [view applyChangesToDocuments:changes];
- // Remove one of the docs.
- changes = [view computeChangesWithDocuments:FSTTestDocUpdates(@[ FSTTestDeletedDoc(
- @"rooms/eros/messages/0", 0) ])];
- [self assertDocSet:changes.documentSet containsDocs:@[ doc2 ]];
- XCTAssertTrue(changes.needsRefill);
- XCTAssertEqual(1, [changes.changeSet changes].count);
- // Refill it with just the one doc remaining.
- changes = [view computeChangesWithDocuments:FSTTestDocUpdates(@[ doc2 ]) previousChanges:changes];
- [self assertDocSet:changes.documentSet containsDocs:@[ doc2 ]];
- XCTAssertFalse(changes.needsRefill);
- XCTAssertEqual(1, [changes.changeSet changes].count);
- [view applyChangesToDocuments:changes];
- }
- - (void)testReturnsNeedsRefillOnReorderInLimitQuery {
- FSTQuery *query = [self queryForMessages];
- query =
- [query queryByAddingSortOrder:[FSTSortOrder sortOrderWithFieldPath:FSTTestFieldPath(@"order")
- ascending:YES]];
- query = [query queryBySettingLimit:2];
- FSTDocument *doc1 = FSTTestDoc(@"rooms/eros/messages/0", 0, @{ @"order" : @1 }, NO);
- FSTDocument *doc2 = FSTTestDoc(@"rooms/eros/messages/1", 0, @{ @"order" : @2 }, NO);
- FSTDocument *doc3 = FSTTestDoc(@"rooms/eros/messages/2", 0, @{ @"order" : @3 }, NO);
- FSTView *view = [[FSTView alloc] initWithQuery:query remoteDocuments:[FSTDocumentKeySet keySet]];
- // Start with a full view.
- FSTViewDocumentChanges *changes =
- [view computeChangesWithDocuments:FSTTestDocUpdates(@[ doc1, doc2, doc3 ])];
- [self assertDocSet:changes.documentSet containsDocs:@[ doc1, doc2 ]];
- XCTAssertFalse(changes.needsRefill);
- XCTAssertEqual(2, [changes.changeSet changes].count);
- [view applyChangesToDocuments:changes];
- // Move one of the docs.
- doc2 = FSTTestDoc(@"rooms/eros/messages/1", 1, @{ @"order" : @2000 }, NO);
- changes = [view computeChangesWithDocuments:FSTTestDocUpdates(@[ doc2 ])];
- [self assertDocSet:changes.documentSet containsDocs:@[ doc1, doc2 ]];
- XCTAssertTrue(changes.needsRefill);
- XCTAssertEqual(1, [changes.changeSet changes].count);
- // Refill it with all three current docs.
- changes = [view computeChangesWithDocuments:FSTTestDocUpdates(@[ doc1, doc2, doc3 ])
- previousChanges:changes];
- [self assertDocSet:changes.documentSet containsDocs:@[ doc1, doc3 ]];
- XCTAssertFalse(changes.needsRefill);
- XCTAssertEqual(2, [changes.changeSet changes].count);
- [view applyChangesToDocuments:changes];
- }
- - (void)testDoesntNeedRefillOnReorderWithinLimit {
- FSTQuery *query = [self queryForMessages];
- query =
- [query queryByAddingSortOrder:[FSTSortOrder sortOrderWithFieldPath:FSTTestFieldPath(@"order")
- ascending:YES]];
- query = [query queryBySettingLimit:3];
- FSTDocument *doc1 = FSTTestDoc(@"rooms/eros/messages/0", 0, @{ @"order" : @1 }, NO);
- FSTDocument *doc2 = FSTTestDoc(@"rooms/eros/messages/1", 0, @{ @"order" : @2 }, NO);
- FSTDocument *doc3 = FSTTestDoc(@"rooms/eros/messages/2", 0, @{ @"order" : @3 }, NO);
- FSTDocument *doc4 = FSTTestDoc(@"rooms/eros/messages/3", 0, @{ @"order" : @4 }, NO);
- FSTDocument *doc5 = FSTTestDoc(@"rooms/eros/messages/4", 0, @{ @"order" : @5 }, NO);
- FSTView *view = [[FSTView alloc] initWithQuery:query remoteDocuments:[FSTDocumentKeySet keySet]];
- // Start with a full view.
- FSTViewDocumentChanges *changes =
- [view computeChangesWithDocuments:FSTTestDocUpdates(@[ doc1, doc2, doc3, doc4, doc5 ])];
- [self assertDocSet:changes.documentSet containsDocs:@[ doc1, doc2, doc3 ]];
- XCTAssertFalse(changes.needsRefill);
- XCTAssertEqual(3, [changes.changeSet changes].count);
- [view applyChangesToDocuments:changes];
- // Move one of the docs.
- doc1 = FSTTestDoc(@"rooms/eros/messages/0", 1, @{ @"order" : @3 }, NO);
- changes = [view computeChangesWithDocuments:FSTTestDocUpdates(@[ doc1 ])];
- [self assertDocSet:changes.documentSet containsDocs:@[ doc2, doc3, doc1 ]];
- XCTAssertFalse(changes.needsRefill);
- XCTAssertEqual(1, [changes.changeSet changes].count);
- [view applyChangesToDocuments:changes];
- }
- - (void)testDoesntNeedRefillOnReorderAfterLimitQuery {
- FSTQuery *query = [self queryForMessages];
- query =
- [query queryByAddingSortOrder:[FSTSortOrder sortOrderWithFieldPath:FSTTestFieldPath(@"order")
- ascending:YES]];
- query = [query queryBySettingLimit:3];
- FSTDocument *doc1 = FSTTestDoc(@"rooms/eros/messages/0", 0, @{ @"order" : @1 }, NO);
- FSTDocument *doc2 = FSTTestDoc(@"rooms/eros/messages/1", 0, @{ @"order" : @2 }, NO);
- FSTDocument *doc3 = FSTTestDoc(@"rooms/eros/messages/2", 0, @{ @"order" : @3 }, NO);
- FSTDocument *doc4 = FSTTestDoc(@"rooms/eros/messages/3", 0, @{ @"order" : @4 }, NO);
- FSTDocument *doc5 = FSTTestDoc(@"rooms/eros/messages/4", 0, @{ @"order" : @5 }, NO);
- FSTView *view = [[FSTView alloc] initWithQuery:query remoteDocuments:[FSTDocumentKeySet keySet]];
- // Start with a full view.
- FSTViewDocumentChanges *changes =
- [view computeChangesWithDocuments:FSTTestDocUpdates(@[ doc1, doc2, doc3, doc4, doc5 ])];
- [self assertDocSet:changes.documentSet containsDocs:@[ doc1, doc2, doc3 ]];
- XCTAssertFalse(changes.needsRefill);
- XCTAssertEqual(3, [changes.changeSet changes].count);
- [view applyChangesToDocuments:changes];
- // Move one of the docs.
- doc4 = FSTTestDoc(@"rooms/eros/messages/3", 1, @{ @"order" : @6 }, NO);
- changes = [view computeChangesWithDocuments:FSTTestDocUpdates(@[ doc4 ])];
- [self assertDocSet:changes.documentSet containsDocs:@[ doc1, doc2, doc3 ]];
- XCTAssertFalse(changes.needsRefill);
- XCTAssertEqual(0, [changes.changeSet changes].count);
- [view applyChangesToDocuments:changes];
- }
- - (void)testDoesntNeedRefillForAdditionAfterTheLimit {
- FSTQuery *query = [[self queryForMessages] queryBySettingLimit:2];
- FSTDocument *doc1 = FSTTestDoc(@"rooms/eros/messages/0", 0, @{}, NO);
- FSTDocument *doc2 = FSTTestDoc(@"rooms/eros/messages/1", 0, @{}, NO);
- FSTView *view = [[FSTView alloc] initWithQuery:query remoteDocuments:[FSTDocumentKeySet keySet]];
- // Start with a full view.
- FSTViewDocumentChanges *changes =
- [view computeChangesWithDocuments:FSTTestDocUpdates(@[ doc1, doc2 ])];
- [self assertDocSet:changes.documentSet containsDocs:@[ doc1, doc2 ]];
- XCTAssertFalse(changes.needsRefill);
- XCTAssertEqual(2, [changes.changeSet changes].count);
- [view applyChangesToDocuments:changes];
- // Add a doc that is past the limit.
- FSTDocument *doc3 = FSTTestDoc(@"rooms/eros/messages/2", 1, @{}, NO);
- changes = [view computeChangesWithDocuments:FSTTestDocUpdates(@[ doc3 ])];
- [self assertDocSet:changes.documentSet containsDocs:@[ doc1, doc2 ]];
- XCTAssertFalse(changes.needsRefill);
- XCTAssertEqual(0, [changes.changeSet changes].count);
- [view applyChangesToDocuments:changes];
- }
- - (void)testDoesntNeedRefillForDeletionsWhenNotNearTheLimit {
- FSTQuery *query = [[self queryForMessages] queryBySettingLimit:20];
- FSTDocument *doc1 = FSTTestDoc(@"rooms/eros/messages/0", 0, @{}, NO);
- FSTDocument *doc2 = FSTTestDoc(@"rooms/eros/messages/1", 0, @{}, NO);
- FSTView *view = [[FSTView alloc] initWithQuery:query remoteDocuments:[FSTDocumentKeySet keySet]];
- FSTViewDocumentChanges *changes =
- [view computeChangesWithDocuments:FSTTestDocUpdates(@[ doc1, doc2 ])];
- [self assertDocSet:changes.documentSet containsDocs:@[ doc1, doc2 ]];
- XCTAssertFalse(changes.needsRefill);
- XCTAssertEqual(2, [changes.changeSet changes].count);
- [view applyChangesToDocuments:changes];
- // Remove one of the docs.
- changes = [view computeChangesWithDocuments:FSTTestDocUpdates(@[ FSTTestDeletedDoc(
- @"rooms/eros/messages/1", 0) ])];
- [self assertDocSet:changes.documentSet containsDocs:@[ doc1 ]];
- XCTAssertFalse(changes.needsRefill);
- XCTAssertEqual(1, [changes.changeSet changes].count);
- [view applyChangesToDocuments:changes];
- }
- - (void)testHandlesApplyingIrrelevantDocs {
- FSTQuery *query = [[self queryForMessages] queryBySettingLimit:2];
- FSTDocument *doc1 = FSTTestDoc(@"rooms/eros/messages/0", 0, @{}, NO);
- FSTDocument *doc2 = FSTTestDoc(@"rooms/eros/messages/1", 0, @{}, NO);
- FSTView *view = [[FSTView alloc] initWithQuery:query remoteDocuments:[FSTDocumentKeySet keySet]];
- // Start with a full view.
- FSTViewDocumentChanges *changes =
- [view computeChangesWithDocuments:FSTTestDocUpdates(@[ doc1, doc2 ])];
- [self assertDocSet:changes.documentSet containsDocs:@[ doc1, doc2 ]];
- XCTAssertFalse(changes.needsRefill);
- XCTAssertEqual(2, [changes.changeSet changes].count);
- [view applyChangesToDocuments:changes];
- // Remove a doc that isn't even in the results.
- changes = [view computeChangesWithDocuments:FSTTestDocUpdates(@[ FSTTestDeletedDoc(
- @"rooms/eros/messages/2", 0) ])];
- [self assertDocSet:changes.documentSet containsDocs:@[ doc1, doc2 ]];
- XCTAssertFalse(changes.needsRefill);
- XCTAssertEqual(0, [changes.changeSet changes].count);
- [view applyChangesToDocuments:changes];
- }
- - (void)testComputesMutatedKeys {
- FSTQuery *query = [self queryForMessages];
- FSTDocument *doc1 = FSTTestDoc(@"rooms/eros/messages/0", 0, @{}, NO);
- FSTDocument *doc2 = FSTTestDoc(@"rooms/eros/messages/1", 0, @{}, NO);
- FSTView *view = [[FSTView alloc] initWithQuery:query remoteDocuments:[FSTDocumentKeySet keySet]];
- // Start with a full view.
- FSTViewDocumentChanges *changes =
- [view computeChangesWithDocuments:FSTTestDocUpdates(@[ doc1, doc2 ])];
- [view applyChangesToDocuments:changes];
- XCTAssertEqualObjects(changes.mutatedKeys, FSTTestDocKeySet(@[]));
- FSTDocument *doc3 = FSTTestDoc(@"rooms/eros/messages/2", 0, @{}, YES);
- changes = [view computeChangesWithDocuments:FSTTestDocUpdates(@[ doc3 ])];
- XCTAssertEqualObjects(changes.mutatedKeys, FSTTestDocKeySet(@[ doc3.key ]));
- }
- - (void)testRemovesKeysFromMutatedKeysWhenNewDocHasNoLocalChanges {
- FSTQuery *query = [self queryForMessages];
- FSTDocument *doc1 = FSTTestDoc(@"rooms/eros/messages/0", 0, @{}, NO);
- FSTDocument *doc2 = FSTTestDoc(@"rooms/eros/messages/1", 0, @{}, YES);
- FSTView *view = [[FSTView alloc] initWithQuery:query remoteDocuments:[FSTDocumentKeySet keySet]];
- // Start with a full view.
- FSTViewDocumentChanges *changes =
- [view computeChangesWithDocuments:FSTTestDocUpdates(@[ doc1, doc2 ])];
- [view applyChangesToDocuments:changes];
- XCTAssertEqualObjects(changes.mutatedKeys, FSTTestDocKeySet(@[ doc2.key ]));
- FSTDocument *doc2Prime = FSTTestDoc(@"rooms/eros/messages/1", 0, @{}, NO);
- changes = [view computeChangesWithDocuments:FSTTestDocUpdates(@[ doc2Prime ])];
- [view applyChangesToDocuments:changes];
- XCTAssertEqualObjects(changes.mutatedKeys, FSTTestDocKeySet(@[]));
- }
- - (void)testRemembersLocalMutationsFromPreviousSnapshot {
- FSTQuery *query = [self queryForMessages];
- FSTDocument *doc1 = FSTTestDoc(@"rooms/eros/messages/0", 0, @{}, NO);
- FSTDocument *doc2 = FSTTestDoc(@"rooms/eros/messages/1", 0, @{}, YES);
- FSTView *view = [[FSTView alloc] initWithQuery:query remoteDocuments:[FSTDocumentKeySet keySet]];
- // Start with a full view.
- FSTViewDocumentChanges *changes =
- [view computeChangesWithDocuments:FSTTestDocUpdates(@[ doc1, doc2 ])];
- [view applyChangesToDocuments:changes];
- XCTAssertEqualObjects(changes.mutatedKeys, FSTTestDocKeySet(@[ doc2.key ]));
- FSTDocument *doc3 = FSTTestDoc(@"rooms/eros/messages/2", 0, @{}, NO);
- changes = [view computeChangesWithDocuments:FSTTestDocUpdates(@[ doc3 ])];
- [view applyChangesToDocuments:changes];
- XCTAssertEqualObjects(changes.mutatedKeys, FSTTestDocKeySet(@[ doc2.key ]));
- }
- - (void)testRemembersLocalMutationsFromPreviousCallToComputeChangesWithDocuments {
- FSTQuery *query = [self queryForMessages];
- FSTDocument *doc1 = FSTTestDoc(@"rooms/eros/messages/0", 0, @{}, NO);
- FSTDocument *doc2 = FSTTestDoc(@"rooms/eros/messages/1", 0, @{}, YES);
- FSTView *view = [[FSTView alloc] initWithQuery:query remoteDocuments:[FSTDocumentKeySet keySet]];
- // Start with a full view.
- FSTViewDocumentChanges *changes =
- [view computeChangesWithDocuments:FSTTestDocUpdates(@[ doc1, doc2 ])];
- XCTAssertEqualObjects(changes.mutatedKeys, FSTTestDocKeySet(@[ doc2.key ]));
- FSTDocument *doc3 = FSTTestDoc(@"rooms/eros/messages/2", 0, @{}, NO);
- changes = [view computeChangesWithDocuments:FSTTestDocUpdates(@[ doc3 ]) previousChanges:changes];
- XCTAssertEqualObjects(changes.mutatedKeys, FSTTestDocKeySet(@[ doc2.key ]));
- }
- @end
- NS_ASSUME_NONNULL_END
|