Files
firebase-ios-sdk/Example/Database/Tests/Integration/FOrderByTests.m
T
Paul Beusterien ddbfd4cc66 Add travis trailing whitespace check (#116)
* Add travis trailing whitespace check

* Remove trailing white space
2017-06-30 13:47:37 -04:00

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