mirror of
https://github.com/firebase/firebase-ios-sdk
synced 2026-11-10 22:45:59 +05:45
* Move all Firestore files to Objective-C++
* Update project file references
* Don't use module imports from Objective-C++
* Use extern "C" for C-accessible globals
* Work around more stringent type checking in Objective-C++
* NSMutableDictionary ivars aren't implicitly casted to NSDictionary
* FSTMaybeDocument callback can't be passed a function that accepts
FSTDocument
* NSComparisonResult can't be multiplied by -1 without casting
* Add a #include <inttypes.h> where needed
* Avoid using C++ keywords as variables
* Remove #if __cplusplus guards
619 lines
28 KiB
Plaintext
619 lines
28 KiB
Plaintext
/*
|
|
* 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
|