Skip to content

Commit b9d97ad

Browse files
committed
add sorted array test
1 parent aca3de8 commit b9d97ad

File tree

6 files changed

+214
-16
lines changed

6 files changed

+214
-16
lines changed

FirebaseDatabaseUI/FUISortedArray.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,14 @@ NS_ASSUME_NONNULL_BEGIN
2222

2323
@interface FUISortedArray : NSObject <FUICollection>
2424

25+
/**
26+
* A copy of the snapshots currently in the array.
27+
*/
2528
@property (nonatomic, readonly, copy) NSArray<FIRDataSnapshot *> *items;
2629

30+
/**
31+
* The delegate that should receive events from the sorted array.
32+
*/
2733
@property (nonatomic, weak, readwrite, nullable) id<FUICollectionDelegate> delegate;
2834

2935
- (instancetype)init NS_UNAVAILABLE;
@@ -35,7 +41,7 @@ NS_ASSUME_NONNULL_BEGIN
3541
* @param sortDescriptor The closure used by the array to sort its contents. This
3642
* block must always return consistent results or the array may raise a fatal error.
3743
*/
38-
- (instancetype)initWithQuery:(id<FIRDataObservable>)query
44+
- (instancetype)initWithQuery:(id<FUIDataObservable>)query
3945
delegate:(nullable id<FUICollectionDelegate>)delegate
4046
sortDescriptor:(NSComparisonResult (^)(FIRDataSnapshot *left,
4147
FIRDataSnapshot *right))sortDescriptor NS_DESIGNATED_INITIALIZER;

FirebaseDatabaseUI/FUISortedArray.m

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ - (instancetype)initWithQuery:(FIRDatabaseQuery *)query
5050
FIRDataSnapshot *))sortDescriptor {
5151
self = [super init];
5252
if (self != nil) {
53+
_contents = [NSMutableArray array];
5354
_delegate = delegate;
5455
_query = query;
5556
_sortDescriptor = sortDescriptor;
@@ -67,7 +68,14 @@ - (void)observeQuery {
6768
FIRDatabaseHandle handle;
6869
handle = [self.query observeEventType:FIRDataEventTypeChildAdded
6970
andPreviousSiblingKeyWithBlock:^(FIRDataSnapshot *snapshot, NSString *previousChildKey) {
70-
[self insertSnapshot:snapshot];
71+
NSInteger index = [self insertSnapshot:snapshot];
72+
if ([self.delegate respondsToSelector:@selector(array:didAddObject:atIndex:)]) {
73+
[self.delegate array:self didAddObject:snapshot atIndex:index];
74+
}
75+
} withCancelBlock:^(NSError *error) {
76+
if ([self.delegate respondsToSelector:@selector(array:queryCancelledWithError:)]) {
77+
[self.delegate array:self queryCancelledWithError:error];
78+
}
7179
}];
7280
[_handles addObject:@(handle)];
7381

@@ -88,6 +96,10 @@ - (void)observeQuery {
8896
if ([self.delegate respondsToSelector:@selector(array:didAddObject:atIndex:)]) {
8997
[self.delegate array:self didAddObject:snapshot atIndex:newIndex];
9098
}
99+
} withCancelBlock:^(NSError *error) {
100+
if ([self.delegate respondsToSelector:@selector(array:queryCancelledWithError:)]) {
101+
[self.delegate array:self queryCancelledWithError:error];
102+
}
91103
}];
92104
[_handles addObject:@(handle)];
93105

@@ -141,7 +153,7 @@ - (NSArray *)items {
141153
}
142154

143155
- (NSUInteger)count {
144-
return self.items.count;
156+
return self.contents.count;
145157
}
146158

147159
- (void)invalidate {
@@ -189,7 +201,8 @@ - (NSInteger)insertSnapshot:(FIRDataSnapshot *)snapshot {
189201
continue;
190202
} else if (left == NSOrderedAscending && right == NSOrderedDescending) {
191203
// look right
192-
index = ((self.contents.count - index) / 2) + index;
204+
index = ((self.contents.count - index) / 2) + index + 1;
205+
continue;
193206
} else if (left == NSOrderedDescending && right == NSOrderedDescending) {
194207
// bad state (array is not sorted to begin with)
195208
NSAssert(NO, @"FUISortedArray %@'s sort descriptor returned inconsistent results!", self);

FirebaseDatabaseUITests/FUIDatabaseTestUtils.h

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,9 @@ NS_ASSUME_NONNULL_BEGIN
7272

7373
- (void)removeAllObservers;
7474

75-
// Sends an event to the observable's observers.
75+
// Sends an event to the observable's observers. This could be more
76+
// robust--currently it depends on the tester knowing what the "correct"
77+
// previousKey is supposed to be.
7678
- (void)sendEvent:(FIRDataEventType)event
7779
withObject:(nullable FUIFakeSnapshot *)object
7880
previousKey:(nullable NSString *)string
@@ -90,11 +92,11 @@ NS_ASSUME_NONNULL_BEGIN
9092
@end
9193

9294
@interface FUIArrayTestDelegate : NSObject <FUICollectionDelegate>
93-
@property (nonatomic, copy) void (^queryCancelled)(FUIArray *array, NSError *error);
94-
@property (nonatomic, copy) void (^didAddObject)(FUIArray *array, id object, NSUInteger index);
95-
@property (nonatomic, copy) void (^didChangeObject)(FUIArray *array, id object, NSUInteger index);
96-
@property (nonatomic, copy) void (^didRemoveObject)(FUIArray *array, id object, NSUInteger index);
97-
@property (nonatomic, copy) void (^didMoveObject)(FUIArray *array, id object, NSUInteger fromIndex, NSUInteger toIndex);
95+
@property (nonatomic, copy) void (^queryCancelled)(id<FUICollection> array, NSError *error);
96+
@property (nonatomic, copy) void (^didAddObject)(id<FUICollection> array, id object, NSUInteger index);
97+
@property (nonatomic, copy) void (^didChangeObject)(id<FUICollection> array, id object, NSUInteger index);
98+
@property (nonatomic, copy) void (^didRemoveObject)(id<FUICollection> array, id object, NSUInteger index);
99+
@property (nonatomic, copy) void (^didMoveObject)(id<FUICollection> array, id object, NSUInteger fromIndex, NSUInteger toIndex);
98100
@end
99101

100102
@interface FUIIndexArrayTestDelegate : NSObject <FUIIndexArrayDelegate>

FirebaseDatabaseUITests/FUIDatabaseTestUtils.m

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,7 @@ - (BOOL)isEqual:(id)object {
4949
}
5050

5151
- (NSString *)description {
52-
return [NSString stringWithFormat:@"%@, key: %@, value: %@",
53-
[super description], self.key, self.value];
52+
return [NSString stringWithFormat:@"<FUIFakeSnapshot: %p key = %@, value = %@>", self, self.key, self.value];
5453
}
5554
@end
5655

@@ -219,25 +218,25 @@ - (void)populateWithCount:(NSUInteger)count {
219218

220219
@implementation FUIArrayTestDelegate
221220

222-
- (void)array:(FUIArray *)array didAddObject:(id)object atIndex:(NSUInteger)index {
221+
- (void)array:(id<FUICollection>)array didAddObject:(id)object atIndex:(NSUInteger)index {
223222
if (self.didAddObject != NULL) {
224223
self.didAddObject(array, object, index);
225224
}
226225
}
227226

228-
- (void)array:(FUIArray *)array didChangeObject:(id)object atIndex:(NSUInteger)index {
227+
- (void)array:(id<FUICollection>)array didChangeObject:(id)object atIndex:(NSUInteger)index {
229228
if (self.didChangeObject != NULL) {
230229
self.didChangeObject(array, object, index);
231230
}
232231
}
233232

234-
- (void)array:(FUIArray *)array didRemoveObject:(id)object atIndex:(NSUInteger)index {
233+
- (void)array:(id<FUICollection>)array didRemoveObject:(id)object atIndex:(NSUInteger)index {
235234
if (self.didRemoveObject != NULL) {
236235
self.didRemoveObject(array, object, index);
237236
}
238237
}
239238

240-
- (void)array:(FUIArray *)array didMoveObject:(id)object
239+
- (void)array:(id<FUICollection>)array didMoveObject:(id)object
241240
fromIndex:(NSUInteger)fromIndex toIndex:(NSUInteger)toIndex {
242241
if (self.didMoveObject != NULL) {
243242
self.didMoveObject(array, object, fromIndex, toIndex);
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
//
2+
// Copyright (c) 2016 Google Inc.
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
//
16+
17+
@import XCTest;
18+
@import FirebaseDatabaseUI;
19+
20+
#import "FUISortedArray.h"
21+
22+
#import "FUIDatabaseTestUtils.h"
23+
24+
@interface FUISortedArrayTest : XCTestCase
25+
26+
@property (nonatomic, nullable) FUIArrayTestDelegate *arrayDelegate;
27+
@property (nonatomic, nullable) FUITestObservable *observable;
28+
@property (nonatomic, nullable) FUISortedArray *array;
29+
@property (nonatomic, nullable) FUIFakeSnapshot *snap;
30+
31+
@end
32+
33+
@implementation FUISortedArrayTest
34+
35+
- (void)setUp {
36+
[super setUp];
37+
self.arrayDelegate = [[FUIArrayTestDelegate alloc] init];
38+
self.snap = [[FUIFakeSnapshot alloc] init];
39+
self.observable = [[FUITestObservable alloc] init];
40+
self.array = [[FUISortedArray alloc] initWithQuery:self.observable
41+
delegate:self.arrayDelegate
42+
sortDescriptor:^NSComparisonResult(FIRDataSnapshot *left,
43+
FIRDataSnapshot *right) {
44+
return [left.key compare:right.key];
45+
}];
46+
[self.array observeQuery];
47+
}
48+
49+
- (void)tearDown {
50+
[super tearDown];
51+
}
52+
53+
- (void)testArrayCanBeInitialized {
54+
XCTAssertNotNil(self.array, @"expected array to not be nil when initialized");
55+
}
56+
57+
- (void)testItSortsItselfOnMiddleInsert {
58+
[self.observable populateWithCount:10];
59+
60+
// Test delegate
61+
__block BOOL delegateWasCalled = NO;
62+
__block BOOL expectedParametersWereCorrect = NO;
63+
self.arrayDelegate.didAddObject = ^(FUISortedArray *array, id object, NSUInteger index) {
64+
// Xcode complains about retain cycles if an XCTAssert is placed in here.
65+
delegateWasCalled = YES;
66+
expectedParametersWereCorrect = (array == self.array &&
67+
object == self.snap &&
68+
// index should be 2 since "11" comes before "2" alphabetically.
69+
index == 2);
70+
};
71+
72+
// Test insert
73+
self.snap.key = @"11";
74+
[self.observable sendEvent:FIRDataEventTypeChildAdded
75+
withObject:self.snap
76+
previousKey:@"0" // insert after "0" should be ignored to maintain sort
77+
error:nil];
78+
// Array expectations
79+
XCTAssert(self.array.count == 11, @"expected empty array to contain one item after insert");
80+
81+
// Delegate expectations
82+
XCTAssert(delegateWasCalled, @"expected delegate to receive callback for insertion");
83+
XCTAssert(expectedParametersWereCorrect, @"unexpected parameter in delegate callback");
84+
}
85+
86+
- (void)testItSortsItselfOnBeginningInsert {
87+
[self.observable populateWithCount:10];
88+
89+
// Test delegate
90+
__block BOOL delegateWasCalled = NO;
91+
__block BOOL expectedParametersWereCorrect = NO;
92+
self.arrayDelegate.didAddObject = ^(FUISortedArray *array, id object, NSUInteger index) {
93+
// Xcode complains about retain cycles if an XCTAssert is placed in here.
94+
delegateWasCalled = YES;
95+
expectedParametersWereCorrect = (array == self.array &&
96+
object == self.snap &&
97+
// index should be 0 since "+" comes before "0" alphabetically.
98+
index == 0);
99+
};
100+
101+
// Test insert
102+
self.snap.key = @"+";
103+
[self.observable sendEvent:FIRDataEventTypeChildAdded
104+
withObject:self.snap
105+
previousKey:@"0" // insert after "0" should be ignored to maintain sort
106+
error:nil];
107+
// Array expectations
108+
XCTAssert(self.array.count == 11, @"expected empty array to contain one item after insert");
109+
110+
// Delegate expectations
111+
XCTAssert(delegateWasCalled, @"expected delegate to receive callback for insertion");
112+
XCTAssert(expectedParametersWereCorrect, @"unexpected parameter in delegate callback");
113+
}
114+
115+
- (void)testItSortsItselfOnEndInsert {
116+
[self.observable populateWithCount:10];
117+
118+
// Test delegate
119+
__block BOOL delegateWasCalled = NO;
120+
__block BOOL expectedParametersWereCorrect = NO;
121+
self.arrayDelegate.didAddObject = ^(FUISortedArray *array, id object, NSUInteger index) {
122+
// Xcode complains about retain cycles if an XCTAssert is placed in here.
123+
delegateWasCalled = YES;
124+
expectedParametersWereCorrect = (array == self.array &&
125+
object == self.snap &&
126+
// index should be 10 since "a" comes after "9" alphabetically.
127+
index == 10);
128+
};
129+
130+
// Test insert
131+
self.snap.key = @"a";
132+
[self.observable sendEvent:FIRDataEventTypeChildAdded
133+
withObject:self.snap
134+
previousKey:@"0" // insert after "0" should be ignored to maintain sort
135+
error:nil];
136+
// Array expectations
137+
XCTAssert(self.array.count == 11, @"expected empty array to contain one item after insert");
138+
139+
// Delegate expectations
140+
XCTAssert(delegateWasCalled, @"expected delegate to receive callback for insertion");
141+
XCTAssert(expectedParametersWereCorrect, @"unexpected parameter in delegate callback");
142+
}
143+
144+
- (void)testEmptyArrayUpdatesCountOnInsert {
145+
// Test delegate
146+
__block BOOL delegateWasCalled = NO;
147+
__block BOOL expectedParametersWereCorrect = NO;
148+
self.arrayDelegate.didAddObject = ^(FUISortedArray *array, id object, NSUInteger index) {
149+
// Xcode complains about retain cycles if an XCTAssert is placed in here.
150+
delegateWasCalled = YES;
151+
expectedParametersWereCorrect = (array == self.array &&
152+
object == self.snap &&
153+
index == 0);
154+
};
155+
156+
// Test insert
157+
self.snap.key = @"snapshot";
158+
[self.observable sendEvent:FIRDataEventTypeChildAdded
159+
withObject:self.snap
160+
previousKey:nil
161+
error:nil];
162+
// Array expectations
163+
XCTAssert(self.array.count == 1, @"expected empty array to contain one item after insert");
164+
165+
// Delegate expectations
166+
XCTAssert(delegateWasCalled, @"expected delegate to receive callback for insertion");
167+
XCTAssert(expectedParametersWereCorrect, @"unexpected parameter in delegate callback");
168+
}
169+
170+
@end

FirebaseUI.xcodeproj/project.pbxproj

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
8D2A84AA1D678B2B0058DF04 /* FirebaseUI.h in Headers */ = {isa = PBXBuildFile; fileRef = 8D2A84A91D678B2B0058DF04 /* FirebaseUI.h */; settings = {ATTRIBUTES = (Public, ); }; };
1313
8D3A120E1DC2B122007558BA /* FUISortedArray.h in Headers */ = {isa = PBXBuildFile; fileRef = 8D3A120C1DC2B122007558BA /* FUISortedArray.h */; };
1414
8D3A120F1DC2B122007558BA /* FUISortedArray.m in Sources */ = {isa = PBXBuildFile; fileRef = 8D3A120D1DC2B122007558BA /* FUISortedArray.m */; };
15+
8D60505F1DCA8EB8005D8635 /* FUISortedArrayTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8D60505E1DCA8EB8005D8635 /* FUISortedArrayTest.m */; };
1516
8D78AF061D9D8CB000CFA9C5 /* UIImageView+FirebaseStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = 8D7AD9B61D9317FB006866B9 /* UIImageView+FirebaseStorage.m */; };
1617
8D7AD9B71D9317FB006866B9 /* UIImageView+FirebaseStorage.h in Headers */ = {isa = PBXBuildFile; fileRef = 8D7AD9B51D9317FB006866B9 /* UIImageView+FirebaseStorage.h */; settings = {ATTRIBUTES = (Public, ); }; };
1718
8D7AD9B81D9317FB006866B9 /* UIImageView+FirebaseStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = 8D7AD9B61D9317FB006866B9 /* UIImageView+FirebaseStorage.m */; };
@@ -354,6 +355,7 @@
354355
8D2A84AB1D678B2B0058DF04 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
355356
8D3A120C1DC2B122007558BA /* FUISortedArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FUISortedArray.h; sourceTree = "<group>"; };
356357
8D3A120D1DC2B122007558BA /* FUISortedArray.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FUISortedArray.m; sourceTree = "<group>"; };
358+
8D60505E1DCA8EB8005D8635 /* FUISortedArrayTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FUISortedArrayTest.m; sourceTree = "<group>"; };
357359
8D7AD9B51D9317FB006866B9 /* UIImageView+FirebaseStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImageView+FirebaseStorage.h"; sourceTree = "<group>"; };
358360
8D7AD9B61D9317FB006866B9 /* UIImageView+FirebaseStorage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImageView+FirebaseStorage.m"; sourceTree = "<group>"; };
359361
8D9084201D93168800333CC8 /* libStorage.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libStorage.a; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -869,6 +871,7 @@
869871
8D1E107B1DAEB97300AEFCA0 /* FUIIndexTableViewDataSourceTest.m */,
870872
8D01FC7A1DAEC2FF00BD7848 /* FUIIndexCollectionViewDataSourceTest.m */,
871873
8DA941E91D67951B00CD3685 /* FUIArrayTest.m */,
874+
8D60505E1DCA8EB8005D8635 /* FUISortedArrayTest.m */,
872875
8DA941EC1D67951B00CD3685 /* FUICollectionViewDataSourceTest.m */,
873876
8DA941ED1D67951B00CD3685 /* FUITableViewDataSourceTest.m */,
874877
);
@@ -1918,6 +1921,11 @@
19181921
8D01FC7B1DAEC2FF00BD7848 /* FUIIndexCollectionViewDataSourceTest.m in Sources */,
19191922
8D1E107C1DAEB97300AEFCA0 /* FUIIndexTableViewDataSourceTest.m in Sources */,
19201923
8D924C611DA6F69100C4DA48 /* FUIIndexArrayTest.m in Sources */,
1924+
8D9B1BF71DD105BE003D1F47 /* FUIArrayTest.m in Sources */,
1925+
8D9B1BF31DD105AC003D1F47 /* FUIDatabaseTestUtils.m in Sources */,
1926+
8D9B1BF81DD105C1003D1F47 /* FUICollectionViewDataSourceTest.m in Sources */,
1927+
8D9B1BF91DD105C5003D1F47 /* FUITableViewDataSourceTest.m in Sources */,
1928+
8D60505F1DCA8EB8005D8635 /* FUISortedArrayTest.m in Sources */,
19211929
);
19221930
runOnlyForDeploymentPostprocessing = 0;
19231931
};

0 commit comments

Comments
 (0)