mirror of
https://github.com/firebase/firebase-ios-sdk
synced 2026-11-09 22:36:01 +05:45
672 lines
24 KiB
Objective-C
672 lines
24 KiB
Objective-C
/*
|
|
* 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 "FOrderByTests.h"
|
|
|
|
@interface FOrderByTests ()
|
|
@end
|
|
|
|
@implementation FOrderByTests
|
|
|
|
|
|
- (void) testCanDefineAndUseAnIndex {
|
|
__block FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
|
|
|
|
NSArray *users = @[
|
|
@{@"name": @"Andrew", @"nuggets": @35},
|
|
@{@"name": @"Rob", @"nuggets": @40},
|
|
@{@"name": @"Greg", @"nuggets": @38}
|
|
];
|
|
|
|
__block int setCount = 0;
|
|
[users enumerateObjectsUsingBlock:^(NSDictionary *user, NSUInteger idx, BOOL *stop) {
|
|
[[ref childByAutoId] setValue:user withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
|
|
setCount++;
|
|
}];
|
|
}];
|
|
|
|
[self waitUntil:^BOOL{
|
|
return setCount == users.count;
|
|
}];
|
|
|
|
__block NSMutableArray *byNuggets = [[NSMutableArray alloc] init];
|
|
[[ref queryOrderedByChild:@"nuggets"] observeEventType:FIRDataEventTypeChildAdded withBlock:^(FIRDataSnapshot *snapshot) {
|
|
NSDictionary *user = snapshot.value;
|
|
[byNuggets addObject:user[@"name"]];
|
|
}];
|
|
|
|
[self waitUntil:^BOOL{
|
|
return byNuggets.count == users.count;
|
|
}];
|
|
|
|
NSArray *expected = @[@"Andrew", @"Greg", @"Rob"];
|
|
XCTAssertEqualObjects(byNuggets, expected, @"Correct by-nugget ordering.");
|
|
}
|
|
|
|
- (void) testCanDefineAndUseDeepIndex {
|
|
__block FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
|
|
|
|
NSArray *users = @[
|
|
@{@"name": @"Andrew", @"deep": @{@"nuggets": @35}},
|
|
@{@"name": @"Rob", @"deep": @{@"nuggets": @40}},
|
|
@{@"name": @"Greg", @"deep": @{@"nuggets": @38}}
|
|
];
|
|
|
|
__block int setCount = 0;
|
|
[users enumerateObjectsUsingBlock:^(NSDictionary *user, NSUInteger idx, BOOL *stop) {
|
|
[[ref childByAutoId] setValue:user withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
|
|
setCount++;
|
|
}];
|
|
}];
|
|
|
|
[self waitUntil:^BOOL{
|
|
return setCount == users.count;
|
|
}];
|
|
|
|
__block NSMutableArray *byNuggets = [[NSMutableArray alloc] init];
|
|
[[ref queryOrderedByChild:@"deep/nuggets"] observeEventType:FIRDataEventTypeChildAdded withBlock:^(FIRDataSnapshot *snapshot) {
|
|
NSDictionary *user = snapshot.value;
|
|
[byNuggets addObject:user[@"name"]];
|
|
}];
|
|
|
|
[self waitUntil:^BOOL{
|
|
return byNuggets.count == users.count;
|
|
}];
|
|
|
|
NSArray *expected = @[@"Andrew", @"Greg", @"Rob"];
|
|
XCTAssertEqualObjects(byNuggets, expected, @"Correct by-nugget ordering.");
|
|
}
|
|
|
|
- (void) testCanUsaAFallbackThenDefineTheSpecifiedIndex {
|
|
FTupleFirebase *tuple = [FTestHelpers getRandomNodePair];
|
|
FIRDatabaseReference *reader = tuple.one, *writer = tuple.two;
|
|
|
|
NSDictionary *foo1 = @{
|
|
@"a" : @{@"order" : @2, @"foo" : @1},
|
|
@"b" : @{@"order" : @0},
|
|
@"c" : @{@"order" : @1, @"foo" : @NO},
|
|
@"d" : @{@"order" : @3, @"foo" : @"hello"}
|
|
};
|
|
|
|
NSDictionary *foo_e = @{@"order": @1.5, @"foo": @YES};
|
|
NSDictionary *foo_f = @{@"order": @4, @"foo": @{@"bar": @"baz"}};
|
|
|
|
[self waitForCompletionOf:writer setValue:foo1];
|
|
|
|
NSMutableArray *snaps = [[NSMutableArray alloc] init];
|
|
[[[reader queryOrderedByChild:@"order"] queryLimitedToLast:2] observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
|
|
[snaps addObject:snapshot.value];
|
|
}];
|
|
WAIT_FOR(snaps.count == 1);
|
|
|
|
NSDictionary *expected = @{
|
|
@"d": @{@"order": @3, @"foo": @"hello"},
|
|
@"a": @{@"order": @2, @"foo": @1}
|
|
};
|
|
XCTAssertEqualObjects(snaps[0], expected, @"Got correct result");
|
|
|
|
|
|
[self waitForCompletionOf:[writer child:@"e"] setValue:foo_e];
|
|
|
|
[self waitForRoundTrip:reader];
|
|
NSLog(@"snaps: %@", snaps);
|
|
NSLog(@"snaps.count: %ld", (unsigned long) snaps.count);
|
|
XCTAssertEqual(snaps.count, (NSUInteger)1, @"Should still have one event.");
|
|
|
|
[self waitForCompletionOf:[writer child:@"f"] setValue:foo_f];
|
|
|
|
[self waitForRoundTrip:reader];
|
|
XCTAssertEqual(snaps.count, (NSUInteger)2, @"Should have gotten another event.");
|
|
expected = @{
|
|
@"f": foo_f,
|
|
@"d": @{@"order": @3, @"foo": @"hello"}
|
|
};
|
|
XCTAssertEqualObjects(snaps[1], expected, @"Correct event.");
|
|
}
|
|
|
|
- (void) testSnapshotsAreIteratedInOrder {
|
|
FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
|
|
|
|
NSDictionary *initial = @{
|
|
@"alex": @{@"nuggets": @60},
|
|
@"rob": @{@"nuggets": @56},
|
|
@"vassili": @{@"nuggets": @55.5},
|
|
@"tony": @{@"nuggets": @52},
|
|
@"greg": @{@"nuggets": @52}
|
|
};
|
|
|
|
NSArray *expectedOrder = @[@"greg", @"tony", @"vassili", @"rob", @"alex"];
|
|
NSArray *expectedPrevNames = @[[NSNull null], @"greg", @"tony", @"vassili", @"rob"];
|
|
|
|
NSMutableArray *valueOrder = [[NSMutableArray alloc] init];
|
|
NSMutableArray *addedOrder = [[NSMutableArray alloc] init];
|
|
NSMutableArray *addedPrevNames = [[NSMutableArray alloc] init];
|
|
|
|
FIRDatabaseQuery *orderedRef = [ref queryOrderedByChild:@"nuggets"];
|
|
|
|
[orderedRef observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
|
|
for (FIRDataSnapshot *child in snapshot.children) {
|
|
[valueOrder addObject:child.key];
|
|
}
|
|
}];
|
|
|
|
[orderedRef observeEventType:FIRDataEventTypeChildAdded andPreviousSiblingKeyWithBlock:^(FIRDataSnapshot *snapshot, NSString *prevName) {
|
|
[addedOrder addObject:snapshot.key];
|
|
[addedPrevNames addObject:prevName ? prevName : [NSNull null]];
|
|
}];
|
|
|
|
[ref setValue:initial];
|
|
WAIT_FOR(addedOrder.count == expectedOrder.count && valueOrder.count == expectedOrder.count);
|
|
|
|
XCTAssertEqualObjects(addedOrder, expectedOrder, @"child_added events in correct order.");
|
|
XCTAssertEqualObjects(addedPrevNames, expectedPrevNames, @"Got correct prevnames for child_added events.");
|
|
XCTAssertEqualObjects(valueOrder, expectedOrder, @"enumerated snapshot children in correct order.");
|
|
}
|
|
|
|
- (void) testSnapshotsAreIteratedInOrderForValueIndex {
|
|
FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
|
|
|
|
NSDictionary *initial = @{
|
|
@"alex": @60,
|
|
@"rob": @56,
|
|
@"vassili": @55.5,
|
|
@"tony": @52,
|
|
@"greg": @52
|
|
};
|
|
|
|
NSArray *expectedOrder = @[@"greg", @"tony", @"vassili", @"rob", @"alex"];
|
|
NSArray *expectedPrevNames = @[[NSNull null], @"greg", @"tony", @"vassili", @"rob"];
|
|
|
|
NSMutableArray *valueOrder = [[NSMutableArray alloc] init];
|
|
NSMutableArray *addedOrder = [[NSMutableArray alloc] init];
|
|
NSMutableArray *addedPrevNames = [[NSMutableArray alloc] init];
|
|
|
|
FIRDatabaseQuery *orderedRef = [ref queryOrderedByValue];
|
|
|
|
[orderedRef observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
|
|
for (FIRDataSnapshot *child in snapshot.children) {
|
|
[valueOrder addObject:child.key];
|
|
}
|
|
}];
|
|
|
|
[orderedRef observeEventType:FIRDataEventTypeChildAdded andPreviousSiblingKeyWithBlock:^(FIRDataSnapshot *snapshot, NSString *prevName) {
|
|
[addedOrder addObject:snapshot.key];
|
|
[addedPrevNames addObject:prevName ? prevName : [NSNull null]];
|
|
}];
|
|
|
|
[ref setValue:initial];
|
|
WAIT_FOR(addedOrder.count == expectedOrder.count && valueOrder.count == expectedOrder.count);
|
|
|
|
XCTAssertEqualObjects(addedOrder, expectedOrder, @"child_added events in correct order.");
|
|
XCTAssertEqualObjects(addedPrevNames, expectedPrevNames, @"Got correct prevnames for child_added events.");
|
|
XCTAssertEqualObjects(valueOrder, expectedOrder, @"enumerated snapshot children in correct order.");
|
|
}
|
|
|
|
- (void) testFiresChildMovedEvents {
|
|
FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
|
|
|
|
NSDictionary *initial = @{
|
|
@"alex": @{@"nuggets": @60},
|
|
@"rob": @{@"nuggets": @56},
|
|
@"vassili": @{@"nuggets": @55.5},
|
|
@"tony": @{@"nuggets": @52},
|
|
@"greg": @{@"nuggets": @52}
|
|
};
|
|
|
|
FIRDatabaseQuery *orderedRef = [ref queryOrderedByChild:@"nuggets"];
|
|
|
|
__block BOOL moved = NO;
|
|
[orderedRef observeEventType:FIRDataEventTypeChildMoved andPreviousSiblingKeyWithBlock:^(FIRDataSnapshot *snapshot, NSString *prevName) {
|
|
moved = YES;
|
|
XCTAssertEqualObjects(snapshot.key, @"greg", @"");
|
|
XCTAssertEqualObjects(prevName, @"rob", @"");
|
|
XCTAssertEqualObjects(snapshot.value, @{@"nuggets" : @57}, @"");
|
|
}];
|
|
|
|
[ref setValue:initial];
|
|
[[ref child:@"greg/nuggets"] setValue:@57];
|
|
WAIT_FOR(moved);
|
|
}
|
|
|
|
- (void) testDefineMultipleIndexesAtALocation {
|
|
FTupleFirebase *tuple = [FTestHelpers getRandomNodePair];
|
|
FIRDatabaseReference *reader = tuple.one, *writer = tuple.two;
|
|
|
|
NSDictionary *foo1 = @{
|
|
@"a" : @{@"order" : @2, @"foo" : @2},
|
|
@"b" : @{@"order" : @0},
|
|
@"c" : @{@"order" : @1, @"foo" : @NO},
|
|
@"d" : @{@"order" : @3, @"foo" : @"hello"}
|
|
};
|
|
|
|
|
|
[self waitForCompletionOf:writer setValue:foo1];
|
|
|
|
FIRDatabaseQuery *fooOrder = [reader queryOrderedByChild:@"foo"];
|
|
FIRDatabaseQuery *orderOrder = [reader queryOrderedByChild:@"order"];
|
|
NSMutableArray *fooSnaps = [[NSMutableArray alloc] init];
|
|
NSMutableArray *orderSnaps = [[NSMutableArray alloc] init];
|
|
|
|
[[[fooOrder queryStartingAtValue:nil] queryEndingAtValue:@1] observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
|
|
[fooSnaps addObject:snapshot.value];
|
|
}];
|
|
|
|
[[orderOrder queryLimitedToLast:2] observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
|
|
[orderSnaps addObject:snapshot.value];
|
|
}];
|
|
|
|
WAIT_FOR(fooSnaps.count == 1 && orderSnaps.count == 1);
|
|
|
|
NSDictionary *expected = @{
|
|
@"b": @{@"order": @0},
|
|
@"c": @{@"order": @1, @"foo": @NO}
|
|
};
|
|
XCTAssertEqualObjects(fooSnaps[0], expected, @"");
|
|
|
|
expected = @{
|
|
@"d": @{@"order": @3, @"foo": @"hello"},
|
|
@"a": @{@"order": @2, @"foo": @2},
|
|
};
|
|
XCTAssertEqualObjects(orderSnaps[0], expected, @"");
|
|
|
|
[[writer child:@"a"] setValue:@{
|
|
@"order": @-1, @"foo": @1
|
|
}];
|
|
|
|
WAIT_FOR(fooSnaps.count == 2 && orderSnaps.count == 2);
|
|
|
|
expected = @{
|
|
@"a": @{@"order": @-1, @"foo": @1 },
|
|
@"b": @{@"order": @0},
|
|
@"c": @{@"order": @1, @"foo": @NO}
|
|
};
|
|
XCTAssertEqualObjects(fooSnaps[1], expected, @"");
|
|
|
|
expected = @{
|
|
@"d": @{@"order": @3, @"foo": @"hello"},
|
|
@"c": @{@"order": @1, @"foo": @NO}
|
|
};
|
|
XCTAssertEqualObjects(orderSnaps[1], expected, @"");
|
|
}
|
|
|
|
- (void) testCallbackRemovalWorks {
|
|
FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
|
|
|
|
__block int reads = 0;
|
|
FIRDatabaseHandle fooHandle, bazHandle;
|
|
fooHandle = [[ref queryOrderedByChild:@"foo"] observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
|
|
reads++;
|
|
}];
|
|
|
|
[[ref queryOrderedByChild:@"bar"] observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
|
|
reads++;
|
|
}];
|
|
|
|
bazHandle = [[ref queryOrderedByChild:@"baz"] observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
|
|
reads++;
|
|
}];
|
|
|
|
[ref observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
|
|
reads++;
|
|
}];
|
|
|
|
[self waitForCompletionOf:ref setValue:@1];
|
|
|
|
XCTAssertEqual(reads, 4, @"");
|
|
|
|
[ref removeObserverWithHandle:fooHandle];
|
|
[self waitForCompletionOf:ref setValue:@2];
|
|
XCTAssertEqual(reads, 7, @"");
|
|
|
|
// should be a no-op, resulting in 3 more reads.
|
|
[[ref queryOrderedByChild:@"foo"] removeObserverWithHandle:bazHandle];
|
|
[self waitForCompletionOf:ref setValue:@3];
|
|
XCTAssertEqual(reads, 10, @"");
|
|
|
|
[[ref queryOrderedByChild:@"bar"] removeAllObservers];
|
|
[self waitForCompletionOf:ref setValue:@4];
|
|
XCTAssertEqual(reads, 12, @"");
|
|
|
|
// Now, remove everything.
|
|
[ref removeAllObservers];
|
|
[self waitForCompletionOf:ref setValue:@5];
|
|
XCTAssertEqual(reads, 12, @"");
|
|
}
|
|
|
|
- (void) testChildAddedEventsAreInTheCorrectOrder {
|
|
FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
|
|
|
|
NSDictionary *initial = @{
|
|
@"a": @{@"value": @5},
|
|
@"c": @{@"value": @3}
|
|
};
|
|
|
|
NSMutableArray *added = [[NSMutableArray alloc] init];
|
|
[[ref queryOrderedByChild:@"value"] observeEventType:FIRDataEventTypeChildAdded withBlock:^(FIRDataSnapshot *snapshot) {
|
|
[added addObject:snapshot.key];
|
|
}];
|
|
[ref setValue:initial];
|
|
|
|
WAIT_FOR(added.count == 2);
|
|
NSArray *expected = @[@"c", @"a"];
|
|
XCTAssertEqualObjects(added, expected, @"");
|
|
|
|
[ref updateChildValues:@{
|
|
@"b": @{@"value": @4},
|
|
@"d": @{@"value": @2}
|
|
}];
|
|
|
|
WAIT_FOR(added.count == 4);
|
|
expected = @[@"c", @"a", @"d", @"b"];
|
|
XCTAssertEqualObjects(added, expected, @"");
|
|
}
|
|
|
|
- (void) testCanUseKeyIndex {
|
|
FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
|
|
|
|
NSDictionary *data = @{
|
|
@"a": @{ @".priority": @10, @".value": @"a" },
|
|
@"b": @{ @".priority": @5, @".value": @"b" },
|
|
@"c": @{ @".priority": @20, @".value": @"c" },
|
|
@"d": @{ @".priority": @7, @".value": @"d" },
|
|
@"e": @{ @".priority": @30, @".value": @"e" },
|
|
@"f": @{ @".priority": @8, @".value": @"f" }
|
|
};
|
|
|
|
[self waitForCompletionOf:ref setValue:data];
|
|
|
|
__block BOOL valueDone = NO;
|
|
[[[ref queryOrderedByKey] queryStartingAtValue:@"c"] observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
|
|
NSMutableArray *keys = [[NSMutableArray alloc] init];
|
|
for (FIRDataSnapshot *child in snapshot.children) {
|
|
[keys addObject:child.key];
|
|
}
|
|
NSArray *expected = @[@"c", @"d", @"e", @"f"];
|
|
XCTAssertEqualObjects(keys, expected, @"");
|
|
valueDone = YES;
|
|
}];
|
|
WAIT_FOR(valueDone);
|
|
|
|
NSMutableArray *keys = [[NSMutableArray alloc] init];
|
|
[[[ref queryOrderedByKey] queryLimitedToLast:5] observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
|
|
for (FIRDataSnapshot *child in snapshot.children) {
|
|
[keys addObject:child.key];
|
|
}
|
|
}];
|
|
|
|
WAIT_FOR(keys.count == 5);
|
|
NSArray *expected = @[@"b", @"c", @"d", @"e", @"f"];
|
|
XCTAssertEqualObjects(keys, expected, @"");
|
|
}
|
|
|
|
- (void) testQueriesWorkOnLeafNodes {
|
|
FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
|
|
|
|
[self waitForCompletionOf:ref setValue:@"leaf-node"];
|
|
|
|
__block BOOL valueDone = NO;
|
|
[[[ref queryOrderedByChild:@"foo"] queryLimitedToLast:1] observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
|
|
XCTAssertEqual(snapshot.value, [NSNull null]);
|
|
valueDone = YES;
|
|
}];
|
|
WAIT_FOR(valueDone);
|
|
}
|
|
|
|
- (void) testUpdatesForUnindexedQuery {
|
|
FTupleFirebase *refs = [FTestHelpers getRandomNodePair];
|
|
FIRDatabaseReference *reader = refs.one;
|
|
FIRDatabaseReference *writer = refs.two;
|
|
|
|
__block BOOL done = NO;
|
|
NSDictionary *value = @{ @"one": @{ @"index": @1, @"value": @"one" },
|
|
@"two": @{ @"index": @2, @"value": @"two" },
|
|
@"three": @{ @"index": @3, @"value": @"three" } };
|
|
[writer setValue:value withCompletionBlock:^(NSError *error, FIRDatabaseReference *ref) {
|
|
done = YES;
|
|
}];
|
|
WAIT_FOR(done);
|
|
|
|
done = NO;
|
|
|
|
NSMutableArray *snapshots = [NSMutableArray array];
|
|
|
|
[[[reader queryOrderedByChild:@"index"] queryLimitedToLast:2] observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
|
|
[snapshots addObject:snapshot.value];
|
|
done = YES;
|
|
}];
|
|
|
|
WAIT_FOR(done);
|
|
|
|
NSDictionary *expected = @{ @"two": @{ @"index": @2, @"value": @"two" },
|
|
@"three": @{ @"index": @3, @"value": @"three" } };
|
|
|
|
XCTAssertEqual(snapshots.count, (NSUInteger)1);
|
|
XCTAssertEqualObjects(snapshots[0], expected);
|
|
|
|
done = NO;
|
|
[[writer child:@"one/index"] setValue:@4];
|
|
|
|
WAIT_FOR(done);
|
|
|
|
expected = @{ @"one": @{ @"index": @4, @"value": @"one" },
|
|
@"three": @{ @"index": @3, @"value": @"three" } };
|
|
XCTAssertEqual(snapshots.count, (NSUInteger)2);
|
|
XCTAssertEqualObjects(snapshots[1], expected);
|
|
}
|
|
|
|
- (void) testServerRespectsKeyIndex {
|
|
FTupleFirebase *refs = [FTestHelpers getRandomNodePair];
|
|
FIRDatabaseReference *writer = refs.one;
|
|
FIRDatabaseReference *reader = refs.two;
|
|
|
|
NSDictionary *initial = @{
|
|
@"a": @1,
|
|
@"b": @2,
|
|
@"c": @3
|
|
};
|
|
|
|
// If the server doesn't respect the index, it will send down limited data, but with no offset, so the expected
|
|
// and actual data don't match
|
|
FIRDatabaseQuery *query = [[[reader queryOrderedByKey] queryStartingAtValue:@"b"] queryLimitedToFirst:2];
|
|
|
|
NSArray *expectedChildren = @[@"b", @"c"];
|
|
|
|
[self waitForCompletionOf:writer setValue:initial];
|
|
|
|
NSMutableArray *children = [[NSMutableArray alloc] init];
|
|
|
|
__block BOOL done = NO;
|
|
[query observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
|
|
for (FIRDataSnapshot *child in snapshot.children) {
|
|
[children addObject:child.key];
|
|
}
|
|
done = YES;
|
|
}];
|
|
|
|
WAIT_FOR(done);
|
|
|
|
XCTAssertEqualObjects(expectedChildren, children, @"Got correct children");
|
|
}
|
|
|
|
- (void) testServerRespectsValueIndex {
|
|
FTupleFirebase *refs = [FTestHelpers getRandomNodePair];
|
|
FIRDatabaseReference *writer = refs.one;
|
|
FIRDatabaseReference *reader = refs.two;
|
|
|
|
NSDictionary *initial = @{
|
|
@"a": @1,
|
|
@"c": @2,
|
|
@"b": @3
|
|
};
|
|
|
|
// If the server doesn't respect the index, it will send down limited data, but with no offset, so the expected
|
|
// and actual data don't match
|
|
FIRDatabaseQuery *query = [[[reader queryOrderedByValue] queryStartingAtValue:@2] queryLimitedToFirst:2];
|
|
|
|
NSArray *expectedChildren = @[@"c", @"b"];
|
|
|
|
[self waitForCompletionOf:writer setValue:initial];
|
|
|
|
NSMutableArray *children = [[NSMutableArray alloc] init];
|
|
|
|
__block BOOL done = NO;
|
|
[query observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
|
|
for (FIRDataSnapshot *child in snapshot.children) {
|
|
[children addObject:child.key];
|
|
}
|
|
done = YES;
|
|
}];
|
|
|
|
WAIT_FOR(done);
|
|
|
|
XCTAssertEqualObjects(expectedChildren, children, @"Got correct children");
|
|
}
|
|
|
|
- (void) testDeepUpdatesWorkWithQueries {
|
|
FTupleFirebase *refs = [FTestHelpers getRandomNodePair];
|
|
FIRDatabaseReference *writer = refs.one;
|
|
FIRDatabaseReference *reader = refs.two;
|
|
|
|
|
|
NSDictionary *initial = @{@"a": @{@"data": @"foo",
|
|
@"idx": @YES},
|
|
@"b": @{@"data": @"bar",
|
|
@"idx": @YES},
|
|
@"c": @{@"data": @"baz",
|
|
@"idx": @NO}};
|
|
[self waitForCompletionOf:writer setValue:initial];
|
|
|
|
FIRDatabaseQuery *query = [[reader queryOrderedByChild:@"idx"] queryEqualToValue:@YES];
|
|
|
|
NSDictionary* expected = @{@"a": @{@"data": @"foo",
|
|
@"idx": @YES},
|
|
@"b": @{@"data": @"bar",
|
|
@"idx": @YES}};
|
|
|
|
[self waitForExportValueOf:query toBe:expected];
|
|
|
|
NSDictionary *update = @{@"a/idx": @NO,
|
|
@"b/data": @"blah",
|
|
@"c/idx": @YES};
|
|
[self waitForCompletionOf:writer updateChildValues:update];
|
|
|
|
expected = @{@"b": @{@"data": @"blah",
|
|
@"idx": @YES},
|
|
@"c": @{@"data": @"baz",
|
|
@"idx": @YES}};
|
|
[self waitForExportValueOf:query toBe:expected];
|
|
}
|
|
|
|
- (void) testServerRespectsDeepIndex {
|
|
FTupleFirebase *refs = [FTestHelpers getRandomNodePair];
|
|
FIRDatabaseReference *writer = refs.one;
|
|
FIRDatabaseReference *reader = refs.two;
|
|
|
|
|
|
NSDictionary *initial = @{
|
|
@"a": @{@"deep":@{@"index":@1}},
|
|
@"c": @{@"deep":@{@"index":@2}},
|
|
@"b": @{@"deep":@{@"index":@3}}
|
|
};
|
|
|
|
// If the server doesn't respect the index, it will send down limited data, but with no offset, so the expected
|
|
// and actual data don't match
|
|
FIRDatabaseQuery *query = [[[reader queryOrderedByChild:@"deep/index"] queryStartingAtValue:@2] queryLimitedToFirst:2];
|
|
|
|
NSArray *expectedChildren = @[@"c", @"b"];
|
|
|
|
[self waitForCompletionOf:writer setValue:initial];
|
|
|
|
NSMutableArray *children = [[NSMutableArray alloc] init];
|
|
|
|
__block BOOL done = NO;
|
|
[query observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
|
|
for (FIRDataSnapshot *child in snapshot.children) {
|
|
[children addObject:child.key];
|
|
}
|
|
done = YES;
|
|
}];
|
|
|
|
WAIT_FOR(done);
|
|
|
|
XCTAssertEqualObjects(expectedChildren, children, @"Got correct children");
|
|
}
|
|
|
|
- (void) testStartAtEndAtWorksWithValueIndex {
|
|
FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
|
|
|
|
NSDictionary *initial = @{
|
|
@"alex": @60,
|
|
@"rob": @56,
|
|
@"vassili": @55.5,
|
|
@"tony": @52,
|
|
@"greg": @52
|
|
};
|
|
|
|
NSArray *expectedOrder = @[@"tony", @"vassili", @"rob"];
|
|
NSArray *expectedPrevNames = @[[NSNull null], @"tony", @"vassili"];
|
|
|
|
NSMutableArray *valueOrder = [[NSMutableArray alloc] init];
|
|
NSMutableArray *addedOrder = [[NSMutableArray alloc] init];
|
|
NSMutableArray *addedPrevNames = [[NSMutableArray alloc] init];
|
|
|
|
FIRDatabaseQuery *orderedRef = [[[ref queryOrderedByValue] queryStartingAtValue:@52 childKey:@"tony"] queryEndingAtValue:@59];
|
|
|
|
[orderedRef observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
|
|
for (FIRDataSnapshot *child in snapshot.children) {
|
|
[valueOrder addObject:child.key];
|
|
}
|
|
}];
|
|
|
|
[orderedRef observeEventType:FIRDataEventTypeChildAdded andPreviousSiblingKeyWithBlock:^(FIRDataSnapshot *snapshot, NSString *prevName) {
|
|
[addedOrder addObject:snapshot.key];
|
|
[addedPrevNames addObject:prevName ? prevName : [NSNull null]];
|
|
}];
|
|
|
|
[ref setValue:initial];
|
|
WAIT_FOR(addedOrder.count == expectedOrder.count && valueOrder.count == expectedOrder.count);
|
|
|
|
XCTAssertEqualObjects(addedOrder, expectedOrder, @"child_added events in correct order.");
|
|
XCTAssertEqualObjects(addedPrevNames, expectedPrevNames, @"Got correct prevnames for child_added events.");
|
|
XCTAssertEqualObjects(valueOrder, expectedOrder, @"enumerated snapshot children in correct order.");
|
|
}
|
|
|
|
- (void) testRemovingDefaultListenerRemovesNonDefaultListenWithLoadsAllData {
|
|
FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
|
|
|
|
NSDictionary *initialData = @{ @"key": @"value" };
|
|
[self waitForCompletionOf:ref setValue:initialData];
|
|
|
|
[[ref queryOrderedByKey] observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
|
|
}];
|
|
[ref observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
|
|
}];
|
|
|
|
// Should remove both listener and should remove the listen sent to the server
|
|
[ref removeAllObservers];
|
|
|
|
__block id result = nil;
|
|
// This used to crash because a listener for [ref queryOrderedByKey] existed already
|
|
[[ref queryOrderedByKey] observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
|
|
result = snapshot.value;
|
|
}];
|
|
|
|
WAIT_FOR(result);
|
|
XCTAssertEqualObjects(result, initialData);
|
|
}
|
|
|
|
@end
|