3231 lines
108 KiB
Objective-C
3231 lines
108 KiB
Objective-C
#import <XCTest/XCTest.h>
|
|
|
|
#import "YapDatabase.h"
|
|
#import "YapDatabaseView.h"
|
|
#import "YapDatabaseAutoView.h"
|
|
|
|
#import <CocoaLumberjack/CocoaLumberjack.h>
|
|
#import <CocoaLumberjack/DDTTYLogger.h>
|
|
|
|
@interface TestYapDatabaseView : XCTestCase
|
|
@end
|
|
|
|
@implementation TestYapDatabaseView
|
|
|
|
- (NSString *)databasePath:(NSString *)suffix
|
|
{
|
|
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
|
|
NSString *baseDir = ([paths count] > 0) ? [paths objectAtIndex:0] : NSTemporaryDirectory();
|
|
|
|
NSString *databaseName = [NSString stringWithFormat:@"%@-%@.sqlite", THIS_FILE, suffix];
|
|
|
|
return [baseDir stringByAppendingPathComponent:databaseName];
|
|
}
|
|
|
|
- (void)setUp
|
|
{
|
|
[super setUp];
|
|
[DDLog removeAllLoggers];
|
|
[DDLog addLogger:[DDTTYLogger sharedInstance]];
|
|
}
|
|
|
|
- (void)tearDown
|
|
{
|
|
[DDLog flushLog];
|
|
[super tearDown];
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
#pragma mark -
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
- (void)test_persistent
|
|
{
|
|
NSString *databasePath = [self databasePath:NSStringFromSelector(_cmd)];
|
|
|
|
YapDatabaseViewOptions *options = [[YapDatabaseViewOptions alloc] init];
|
|
options.isPersistent = YES;
|
|
|
|
[self _test_withPath:databasePath options:options];
|
|
}
|
|
|
|
- (void)test_nonPersistent
|
|
{
|
|
NSString *databasePath = [self databasePath:NSStringFromSelector(_cmd)];
|
|
|
|
YapDatabaseViewOptions *options = [[YapDatabaseViewOptions alloc] init];
|
|
options.isPersistent = NO;
|
|
|
|
[self _test_withPath:databasePath options:options];
|
|
}
|
|
|
|
- (void)_test_withPath:(NSString *)databasePath options:(YapDatabaseViewOptions *)options
|
|
{
|
|
[[NSFileManager defaultManager] removeItemAtPath:databasePath error:NULL];
|
|
YapDatabase *database = [[YapDatabase alloc] initWithPath:databasePath];
|
|
|
|
XCTAssertNotNil(database, @"Oops");
|
|
|
|
YapDatabaseConnection *connection1 = [database newConnection];
|
|
YapDatabaseConnection *connection2 = [database newConnection];
|
|
|
|
YapDatabaseViewGrouping *grouping = [YapDatabaseViewGrouping withKeyBlock:
|
|
^NSString *(YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key){
|
|
|
|
if ([key isEqualToString:@"keyX"]) // Exclude keyX from view
|
|
return nil;
|
|
else
|
|
return @"";
|
|
}];
|
|
|
|
YapDatabaseViewSorting *sorting = [YapDatabaseViewSorting withObjectBlock:
|
|
^(YapDatabaseReadTransaction *transaction, NSString *group,
|
|
NSString *collection1, NSString *key1, id obj1,
|
|
NSString *collection2, NSString *key2, id obj2)
|
|
{
|
|
__unsafe_unretained NSString *object1 = (NSString *)obj1;
|
|
__unsafe_unretained NSString *object2 = (NSString *)obj2;
|
|
|
|
return [object1 compare:object2 options:NSNumericSearch];
|
|
}];
|
|
|
|
NSString *initialVersionTag = @"1";
|
|
|
|
YapDatabaseAutoView *databaseView =
|
|
[[YapDatabaseAutoView alloc] initWithGrouping:grouping
|
|
sorting:sorting
|
|
versionTag:initialVersionTag
|
|
options:options];
|
|
|
|
BOOL registerResult = [database registerExtension:databaseView withName:@"order"];
|
|
|
|
XCTAssertTrue(registerResult, @"Failure registering extension");
|
|
|
|
[connection1 readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
NSString *versionTag = [[transaction ext:@"order"] versionTag];
|
|
|
|
XCTAssert([versionTag isEqualToString:initialVersionTag], @"Bad versionTag");
|
|
}];
|
|
|
|
NSString *key0 = @"key0";
|
|
NSString *key1 = @"key1";
|
|
NSString *key2 = @"key2";
|
|
NSString *key3 = @"key3";
|
|
NSString *key4 = @"key4";
|
|
NSString *keyX = @"keyX";
|
|
|
|
id object0 = @"object0"; // index 0
|
|
id object1 = @"object1"; // index 1
|
|
id object2 = @"object2"; // index 2
|
|
id object3 = @"object3"; // index 3
|
|
id object4 = @"object4"; // index 4
|
|
id objectX = @"objectX"; // ------- excluded from group
|
|
|
|
id object1B = @"object5"; // moves key1 from index1 to index4
|
|
|
|
__block NSUInteger keysCount = 0;
|
|
|
|
[connection1 readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction){
|
|
|
|
XCTAssertNil([transaction ext:@"non-existent-view"], @"Expected nil");
|
|
XCTAssertNotNil([transaction ext:@"order"], @"Expected non-nil view transaction");
|
|
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfGroups] == 0, @"Expected zero group count");
|
|
XCTAssertTrue([[[transaction ext:@"order"] allGroups] count] == 0, @"Expected empty array");
|
|
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfItemsInGroup:@""] == 0, @"Expected zero");
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfItemsInAllGroups] == 0, @"Expected zero");
|
|
|
|
XCTAssertNil([[transaction ext:@"order"] groupForKey:key0 inCollection:nil], @"Expected nil");
|
|
|
|
NSString *group = nil;
|
|
NSUInteger index = 0;
|
|
|
|
BOOL result = [[transaction ext:@"order"] getGroup:&group index:&index forKey:key0 inCollection:nil];
|
|
|
|
XCTAssertFalse(result, @"Expected NO");
|
|
XCTAssertNil(group, @"Expected group to be set to nil");
|
|
XCTAssertTrue(index == 0, @"Expected index to be set to zero");
|
|
}];
|
|
|
|
[connection2 readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction){
|
|
|
|
// Test inserting a single object
|
|
|
|
[transaction setObject:object0 forKey:key0 inCollection:nil]; keysCount++;
|
|
|
|
// Read it back
|
|
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfGroups] == 1, @"Wrong group count");
|
|
XCTAssertTrue([[[transaction ext:@"order"] allGroups] count] == 1, @"Wrong array count");
|
|
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfItemsInGroup:@""] == keysCount, @"Wrong count");
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfItemsInAllGroups] == keysCount, @"Wrong count");
|
|
|
|
NSString *group = nil;
|
|
NSUInteger index = NSNotFound;
|
|
|
|
group = [[transaction ext:@"order"] groupForKey:key0 inCollection:nil];
|
|
|
|
XCTAssertTrue([group isEqualToString:@""], @"Wrong group");
|
|
|
|
id fetchedKey0;
|
|
id fetchedCollection0;
|
|
|
|
[[transaction ext:@"order"] getKey:&fetchedKey0 collection:&fetchedCollection0 atIndex:0 inGroup:@""];
|
|
|
|
XCTAssertTrue([fetchedKey0 isEqualToString:key0], @"Expected match");
|
|
XCTAssertTrue([fetchedCollection0 isEqualToString:@""], @"Expected match");
|
|
|
|
id fetchedObject0 = [[transaction ext:@"order"] objectAtIndex:0 inGroup:@""];
|
|
|
|
XCTAssertTrue([fetchedObject0 isEqualToString:object0], @"Expected match");
|
|
|
|
BOOL result = [[transaction ext:@"order"] getGroup:&group index:&index forKey:key0 inCollection:nil];
|
|
|
|
XCTAssertTrue(result, @"Expected YES");
|
|
XCTAssertNotNil(group, @"Expected group to be set");
|
|
XCTAssertTrue(index == 0, @"Expected index to be set");
|
|
}];
|
|
|
|
[connection1 readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction){
|
|
|
|
// Test reading data back on separate connection
|
|
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfGroups] == 1, @"Wrong group count");
|
|
XCTAssertTrue([[[transaction ext:@"order"] allGroups] count] == 1, @"Wrong array count");
|
|
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfItemsInGroup:@""] == keysCount, @"Wrong count");
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfItemsInAllGroups] == keysCount, @"Wrong count");
|
|
|
|
NSString *group = nil;
|
|
NSUInteger index = NSNotFound;
|
|
|
|
group = [[transaction ext:@"order"] groupForKey:key0 inCollection:nil];
|
|
|
|
XCTAssertTrue([group isEqualToString:@""], @"Wrong group");
|
|
|
|
id fetchedKey0;
|
|
id fetchedCollection0;
|
|
|
|
[[transaction ext:@"order"] getKey:&fetchedKey0 collection:&fetchedCollection0 atIndex:0 inGroup:@""];
|
|
|
|
XCTAssertTrue([fetchedKey0 isEqualToString:key0],
|
|
@"Expected match: fetched(%@) vs expected(%@)", fetchedKey0, key0);
|
|
|
|
XCTAssertTrue([fetchedCollection0 isEqualToString:@""],
|
|
@"Expected match: fetched(%@) expected(%@)", fetchedCollection0, @"");
|
|
|
|
id fetchedObject0 = [[transaction ext:@"order"] objectAtIndex:0 inGroup:@""];
|
|
|
|
XCTAssertTrue([fetchedObject0 isEqualToString:object0],
|
|
@"Expected match: fetchedObject0(%@) vs object0(%@)", fetchedObject0, object0);
|
|
|
|
BOOL result = [[transaction ext:@"order"] getGroup:&group index:&index forKey:key0 inCollection:nil];
|
|
|
|
XCTAssertTrue(result, @"Expected YES");
|
|
XCTAssertNotNil(group, @"Expected group to be set");
|
|
XCTAssertTrue(index == 0, @"Expected index to be set to zero");
|
|
}];
|
|
|
|
[connection2 readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction){
|
|
|
|
// Test inserting more objects
|
|
|
|
[transaction setObject:object1 forKey:key1 inCollection:nil]; keysCount++; // Included
|
|
[transaction setObject:object2 forKey:key2 inCollection:nil]; keysCount++; // Included
|
|
[transaction setObject:object3 forKey:key3 inCollection:nil]; keysCount++; // Included
|
|
[transaction setObject:object4 forKey:key4 inCollection:nil]; keysCount++; // Included
|
|
[transaction setObject:objectX forKey:keyX inCollection:nil]; // Excluded !
|
|
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfGroups] == 1, @"Wrong group count");
|
|
XCTAssertTrue([[[transaction ext:@"order"] allGroups] count] == 1, @"Wrong array count");
|
|
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfItemsInGroup:@""] == keysCount, @"Wrong count");
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfItemsInAllGroups] == keysCount, @"Wrong count");
|
|
|
|
NSArray *keys = @[ key0, key1, key2, key3, key4 ];
|
|
|
|
NSUInteger index = 0;
|
|
for (NSString *key in keys)
|
|
{
|
|
NSString *fetchedCollection;
|
|
NSString *fetchedKey;
|
|
|
|
[[transaction ext:@"order"] getKey:&fetchedKey collection:&fetchedCollection atIndex:index inGroup:@""];
|
|
|
|
XCTAssertTrue([fetchedKey isEqualToString:key],
|
|
@"Non-matching keys(%@ vs %@) at index %d", fetchedKey, key, (int)index);
|
|
|
|
XCTAssertTrue([fetchedCollection isEqualToString:@""],
|
|
@"Non-matching collections(%@ vs %@) at index %d", fetchedCollection, @"", (int)index);
|
|
|
|
index++;
|
|
}
|
|
|
|
for (NSString *key in keys)
|
|
{
|
|
NSString *fetchedGroup = [[transaction ext:@"order"] groupForKey:key inCollection:nil];
|
|
|
|
XCTAssertTrue([fetchedGroup isEqualToString:@""], @"Wrong group(%@) for key(%@)", fetchedGroup, key);
|
|
}
|
|
|
|
index = 0;
|
|
for (NSString *key in keys)
|
|
{
|
|
NSString *fetchedGroup = nil;
|
|
NSUInteger fetchedIndex = NSNotFound;
|
|
|
|
BOOL result = [[transaction ext:@"order"] getGroup:&fetchedGroup
|
|
index:&fetchedIndex
|
|
forKey:key
|
|
inCollection:nil];
|
|
|
|
XCTAssertTrue(result, @"Wrong result for key(%@) at index(%d)", key, (int)index);
|
|
|
|
XCTAssertTrue([fetchedGroup isEqualToString:@""],
|
|
@"Wrong group(%@) for key(%@) at index(%d)", fetchedGroup, key, (int)index);
|
|
|
|
XCTAssertTrue(fetchedIndex == index,
|
|
@"Wrong index(%d) for key(%@) at index(%d)", (int)fetchedIndex, key, (int)index);
|
|
|
|
index++;
|
|
}
|
|
}];
|
|
|
|
[connection1 readWithBlock:^(YapDatabaseReadTransaction *transaction){
|
|
|
|
// Test a read-only transaction.
|
|
// Test reading multiple inserted objects from a separate connection.
|
|
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfGroups] == 1, @"Wrong group count");
|
|
XCTAssertTrue([[[transaction ext:@"order"] allGroups] count] == 1, @"Wrong array count");
|
|
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfItemsInGroup:@""] == keysCount, @"Wrong count");
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfItemsInAllGroups] == keysCount, @"Wrong count");
|
|
|
|
NSArray *keys = @[ key0, key1, key2, key3, key4 ];
|
|
|
|
NSUInteger index = 0;
|
|
for (NSString *key in keys)
|
|
{
|
|
NSString *fetchedKey;
|
|
NSString *fetchedCollection;
|
|
|
|
[[transaction ext:@"order"] getKey:&fetchedKey collection:&fetchedCollection atIndex:index inGroup:@""];
|
|
|
|
XCTAssertTrue([fetchedKey isEqualToString:key],
|
|
@"Non-matching keys(%@ vs %@) at index %d", fetchedKey, key, (int)index);
|
|
|
|
XCTAssertTrue([fetchedCollection isEqualToString:@""],
|
|
@"Non-matching collections(%@ vs %@) at index %d", fetchedCollection, @"", (int)index);
|
|
|
|
index++;
|
|
}
|
|
|
|
for (NSString *key in keys)
|
|
{
|
|
NSString *fetchedGroup = [[transaction ext:@"order"] groupForKey:key inCollection:nil];
|
|
|
|
XCTAssertTrue([fetchedGroup isEqualToString:@""], @"Wrong group(%@) for key(%@)", fetchedGroup, key);
|
|
}
|
|
|
|
index = 0;
|
|
for (NSString *key in keys)
|
|
{
|
|
NSString *fetchedGroup = nil;
|
|
NSUInteger fetchedIndex = NSNotFound;
|
|
|
|
BOOL result =
|
|
[[transaction ext:@"order"] getGroup:&fetchedGroup index:&fetchedIndex forKey:key inCollection:nil];
|
|
|
|
XCTAssertTrue(result, @"Wrong result for key(%@) at index(%d)", key, (int)index);
|
|
|
|
XCTAssertTrue([fetchedGroup isEqualToString:@""],
|
|
@"Wrong group(%@) for key(%@) at index(%d)", fetchedGroup, key, (int)index);
|
|
|
|
XCTAssertTrue(fetchedIndex == index,
|
|
@"Wrong index(%d) for key(%@) at index(%d)", (int)fetchedIndex, key, (int)index);
|
|
|
|
index++;
|
|
}
|
|
}];
|
|
|
|
[connection2 readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction){
|
|
|
|
// Test updating the metadata of our object.
|
|
//
|
|
// This should invoke our grouping block (to determine if the group changed).
|
|
// However, once it determines the group hasn't changed,
|
|
// it should abort as the sorting block only takes the object into account.
|
|
|
|
[transaction replaceMetadata:@"some-metadata" forKey:key0 inCollection:nil];
|
|
}];
|
|
|
|
[connection1 readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction){
|
|
|
|
// Test updating the object (in such a manner that changes its position within the view)
|
|
//
|
|
// key0 should move from index0 to index4
|
|
|
|
NSString *fetchedKey = nil;
|
|
NSString *fetchedCollection = nil;
|
|
|
|
[[transaction ext:@"order"] getKey:&fetchedKey collection:&fetchedCollection atIndex:1 inGroup:@""];
|
|
|
|
XCTAssertTrue([fetchedKey isEqualToString:key1], @"Oops");
|
|
XCTAssertTrue([fetchedCollection isEqualToString:@""], @"Oops");
|
|
|
|
[transaction setObject:object1B forKey:key1 inCollection:nil];
|
|
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfGroups] == 1, @"Wrong group count");
|
|
XCTAssertTrue([[[transaction ext:@"order"] allGroups] count] == 1, @"Wrong array count");
|
|
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfItemsInGroup:@""] == keysCount, @"Wrong count");
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfItemsInAllGroups] == keysCount, @"Wrong count");
|
|
|
|
NSArray *keys = @[ key0, key2, key3, key4, key1 ]; // <-- Updated order (key1 moved to end)
|
|
|
|
NSUInteger index = 0;
|
|
for (NSString *key in keys)
|
|
{
|
|
[[transaction ext:@"order"] getKey:&fetchedKey collection:&fetchedCollection atIndex:index inGroup:@""];
|
|
|
|
XCTAssertTrue([fetchedKey isEqualToString:key],
|
|
@"Non-matching keys(%@ vs %@) at index %d", fetchedKey, key, (int)index);
|
|
|
|
XCTAssertTrue([fetchedCollection isEqualToString:@""],
|
|
@"Non-matching collections(%@ vs %@) at index %d", fetchedCollection, @"", (int)index);
|
|
|
|
index++;
|
|
}
|
|
|
|
for (NSString *key in keys)
|
|
{
|
|
NSString *fetchedGroup = [[transaction ext:@"order"] groupForKey:key inCollection:nil];
|
|
|
|
XCTAssertTrue([fetchedGroup isEqualToString:@""], @"Wrong group(%@) for key(%@)", fetchedGroup, key);
|
|
}
|
|
|
|
index = 0;
|
|
for (NSString *key in keys)
|
|
{
|
|
NSString *fetchedGroup = nil;
|
|
NSUInteger fetchedIndex = NSNotFound;
|
|
|
|
BOOL result =
|
|
[[transaction ext:@"order"] getGroup:&fetchedGroup index:&fetchedIndex forKey:key inCollection:nil];
|
|
|
|
XCTAssertTrue(result, @"Wrong result for key(%@) at index(%d)", key, (int)index);
|
|
|
|
XCTAssertTrue([fetchedGroup isEqualToString:@""],
|
|
@"Wrong group(%@) for key(%@) at index(%d)", fetchedGroup, key, (int)index);
|
|
|
|
XCTAssertTrue(fetchedIndex == index,
|
|
@"Wrong index(%d) for key(%@) at index(%d)", (int)fetchedIndex, key, (int)index);
|
|
|
|
index++;
|
|
}
|
|
}];
|
|
|
|
[connection2 readWithBlock:^(YapDatabaseReadTransaction *transaction){
|
|
|
|
// Test read-only block.
|
|
// Test reading back updated index.
|
|
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfGroups] == 1, @"Wrong group count");
|
|
XCTAssertTrue([[[transaction ext:@"order"] allGroups] count] == 1, @"Wrong array count");
|
|
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfItemsInGroup:@""] == keysCount, @"Wrong count");
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfItemsInAllGroups] == keysCount, @"Wrong count");
|
|
|
|
NSArray *keys = @[ key0, key2, key3, key4, key1 ]; // <-- Updated order (key1 moved to end)
|
|
|
|
NSUInteger index = 0;
|
|
for (NSString *key in keys)
|
|
{
|
|
NSString *fetchedKey;
|
|
NSString *fetchedCollection;
|
|
|
|
[[transaction ext:@"order"] getKey:&fetchedKey collection:&fetchedCollection atIndex:index inGroup:@""];
|
|
|
|
XCTAssertTrue([fetchedKey isEqualToString:key],
|
|
@"Non-matching keys(%@ vs %@) at index %d", fetchedKey, key, (int)index);
|
|
|
|
XCTAssertTrue([fetchedCollection isEqualToString:@""],
|
|
@"Non-matching collections(%@ vs %@) at index %d", fetchedCollection, @"", (int)index);
|
|
|
|
index++;
|
|
}
|
|
|
|
for (NSString *key in keys)
|
|
{
|
|
NSString *fetchedGroup = [[transaction ext:@"order"] groupForKey:key inCollection:nil];
|
|
|
|
XCTAssertTrue([fetchedGroup isEqualToString:@""], @"Wrong group(%@) for key(%@)", fetchedGroup, key);
|
|
}
|
|
|
|
index = 0;
|
|
for (NSString *key in keys)
|
|
{
|
|
NSString *fetchedGroup = nil;
|
|
NSUInteger fetchedIndex = NSNotFound;
|
|
|
|
BOOL result =
|
|
[[transaction ext:@"order"] getGroup:&fetchedGroup index:&fetchedIndex forKey:key inCollection:nil];
|
|
|
|
XCTAssertTrue(result, @"Wrong result for key(%@) at index(%d)", key, (int)index);
|
|
|
|
XCTAssertTrue([fetchedGroup isEqualToString:@""],
|
|
@"Wrong group(%@) for key(%@) at index(%d)", fetchedGroup, key, (int)index);
|
|
|
|
XCTAssertTrue(fetchedIndex == index,
|
|
@"Wrong index(%d) for key(%@) at index(%d)", (int)fetchedIndex, key, (int)index);
|
|
|
|
index++;
|
|
}
|
|
}];
|
|
|
|
[connection1 readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction){
|
|
|
|
// Test removing a single key
|
|
|
|
[transaction removeObjectForKey:key1 inCollection:nil]; keysCount--;
|
|
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfGroups] == 1, @"Wrong group count");
|
|
XCTAssertTrue([[[transaction ext:@"order"] allGroups] count] == 1, @"Wrong array count");
|
|
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfItemsInGroup:@""] == keysCount, @"Wrong count");
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfItemsInAllGroups] == keysCount, @"Wrong count");
|
|
|
|
NSArray *keys = @[ key0, key2, key3, key4, ]; // <-- Updated order (key1 removed)
|
|
|
|
NSUInteger index = 0;
|
|
for (NSString *key in keys)
|
|
{
|
|
NSString *fetchedKey;
|
|
NSString *fetchedCollection;
|
|
|
|
[[transaction ext:@"order"] getKey:&fetchedKey collection:&fetchedCollection atIndex:index inGroup:@""];
|
|
|
|
XCTAssertTrue([fetchedKey isEqualToString:key],
|
|
@"Non-matching keys(%@ vs %@) at index %d", fetchedKey, key, (int)index);
|
|
|
|
XCTAssertTrue([fetchedCollection isEqualToString:@""],
|
|
@"Non-matching collections(%@ vs %@) at index %d", fetchedCollection, @"", (int)index);
|
|
|
|
index++;
|
|
}
|
|
|
|
for (NSString *key in keys)
|
|
{
|
|
NSString *fetchedGroup = [[transaction ext:@"order"] groupForKey:key inCollection:nil];
|
|
|
|
XCTAssertTrue([fetchedGroup isEqualToString:@""], @"Wrong group(%@) for key(%@)", fetchedGroup, key);
|
|
}
|
|
|
|
index = 0;
|
|
for (NSString *key in keys)
|
|
{
|
|
NSString *fetchedGroup = nil;
|
|
NSUInteger fetchedIndex = NSNotFound;
|
|
|
|
BOOL result =
|
|
[[transaction ext:@"order"] getGroup:&fetchedGroup index:&fetchedIndex forKey:key inCollection:nil];
|
|
|
|
XCTAssertTrue(result, @"Wrong result for key(%@) at index(%d)", key, (int)index);
|
|
|
|
XCTAssertTrue([fetchedGroup isEqualToString:@""],
|
|
@"Wrong group(%@) for key(%@) at index(%d)", fetchedGroup, key, (int)index);
|
|
|
|
XCTAssertTrue(fetchedIndex == index,
|
|
@"Wrong index(%d) for key(%@) at index(%d)", (int)fetchedIndex, key, (int)index);
|
|
|
|
index++;
|
|
}
|
|
}];
|
|
|
|
[connection2 readWithBlock:^(YapDatabaseReadTransaction *transaction){
|
|
|
|
// Test read-only block.
|
|
// Test reading back updated index.
|
|
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfGroups] == 1, @"Wrong group count");
|
|
XCTAssertTrue([[[transaction ext:@"order"] allGroups] count] == 1, @"Wrong array count");
|
|
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfItemsInGroup:@""] == keysCount, @"Wrong count");
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfItemsInAllGroups] == keysCount, @"Wrong count");
|
|
|
|
NSArray *keys = @[ key0, key2, key3, key4, ]; // <-- Updated order (key1 removed)
|
|
|
|
NSUInteger index = 0;
|
|
for (NSString *key in keys)
|
|
{
|
|
NSString *fetchedKey;
|
|
NSString *fetchedCollection;
|
|
|
|
[[transaction ext:@"order"] getKey:&fetchedKey collection:&fetchedCollection atIndex:index inGroup:@""];
|
|
|
|
XCTAssertTrue([fetchedKey isEqualToString:key],
|
|
@"Non-matching keys(%@ vs %@) at index %d", fetchedKey, key, (int)index);
|
|
|
|
XCTAssertTrue([fetchedCollection isEqualToString:@""],
|
|
@"Non-matching collections(%@ vs %@) at index %d", fetchedCollection, @"", (int)index);
|
|
|
|
index++;
|
|
}
|
|
|
|
for (NSString *key in keys)
|
|
{
|
|
NSString *fetchedGroup = [[transaction ext:@"order"] groupForKey:key inCollection:nil];
|
|
|
|
XCTAssertTrue([fetchedGroup isEqualToString:@""], @"Wrong group(%@) for key(%@)", fetchedGroup, key);
|
|
}
|
|
|
|
index = 0;
|
|
for (NSString *key in keys)
|
|
{
|
|
NSString *fetchedGroup = nil;
|
|
NSUInteger fetchedIndex = NSNotFound;
|
|
|
|
BOOL result =
|
|
[[transaction ext:@"order"] getGroup:&fetchedGroup index:&fetchedIndex forKey:key inCollection:nil];
|
|
|
|
XCTAssertTrue(result, @"Wrong result for key(%@) at index(%d)", key, (int)index);
|
|
|
|
XCTAssertTrue([fetchedGroup isEqualToString:@""],
|
|
@"Wrong group(%@) for key(%@) at index(%d)", fetchedGroup, key, (int)index);
|
|
|
|
XCTAssertTrue(fetchedIndex == index,
|
|
@"Wrong index(%d) for key(%@) at index(%d)", (int)fetchedIndex, key, (int)index);
|
|
|
|
index++;
|
|
}
|
|
}];
|
|
|
|
[connection1 readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction){
|
|
|
|
// Test remove multiple objects
|
|
|
|
[transaction removeObjectsForKeys:@[ key2, key3 ] inCollection:nil]; keysCount -= 2;
|
|
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfGroups] == 1, @"Wrong group count");
|
|
XCTAssertTrue([[[transaction ext:@"order"] allGroups] count] == 1, @"Wrong array count");
|
|
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfItemsInGroup:@""] == keysCount, @"Wrong count");
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfItemsInAllGroups] == keysCount, @"Wrong count");
|
|
|
|
NSArray *keys = @[ key0, key4, ]; // <-- Updated order (key2 & key3 removed)
|
|
|
|
NSUInteger index = 0;
|
|
for (NSString *key in keys)
|
|
{
|
|
NSString *fetchedKey;
|
|
NSString *fetchedCollection;
|
|
|
|
[[transaction ext:@"order"] getKey:&fetchedKey collection:&fetchedCollection atIndex:index inGroup:@""];
|
|
|
|
XCTAssertTrue([fetchedKey isEqualToString:key],
|
|
@"Non-matching keys(%@ vs %@) at index %d", fetchedKey, key, (int)index);
|
|
|
|
XCTAssertTrue([fetchedCollection isEqualToString:@""],
|
|
@"Non-matching collections(%@ vs %@) at index %d", fetchedCollection, @"", (int)index);
|
|
|
|
index++;
|
|
}
|
|
|
|
for (NSString *key in keys)
|
|
{
|
|
NSString *fetchedGroup = [[transaction ext:@"order"] groupForKey:key inCollection:nil];
|
|
|
|
XCTAssertTrue([fetchedGroup isEqualToString:@""], @"Wrong group(%@) for key(%@)", fetchedGroup, key);
|
|
}
|
|
|
|
index = 0;
|
|
for (NSString *key in keys)
|
|
{
|
|
NSString *fetchedGroup = nil;
|
|
NSUInteger fetchedIndex = NSNotFound;
|
|
|
|
BOOL result =
|
|
[[transaction ext:@"order"] getGroup:&fetchedGroup index:&fetchedIndex forKey:key inCollection:nil];
|
|
|
|
XCTAssertTrue(result, @"Wrong result for key(%@) at index(%d)", key, (int)index);
|
|
|
|
XCTAssertTrue([fetchedGroup isEqualToString:@""],
|
|
@"Wrong group(%@) for key(%@) at index(%d)", fetchedGroup, key, (int)index);
|
|
|
|
XCTAssertTrue(fetchedIndex == index,
|
|
@"Wrong index(%d) for key(%@) at index(%d)", (int)fetchedIndex, key, (int)index);
|
|
|
|
index++;
|
|
}
|
|
}];
|
|
|
|
[connection2 readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction){
|
|
|
|
// Read the changes back on another connection
|
|
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfGroups] == 1, @"Wrong group count");
|
|
XCTAssertTrue([[[transaction ext:@"order"] allGroups] count] == 1, @"Wrong array count");
|
|
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfItemsInGroup:@""] == keysCount, @"Wrong count");
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfItemsInAllGroups] == keysCount, @"Wrong count");
|
|
|
|
NSArray *keys = @[ key0, key4, ]; // <-- Updated order (key2 & key3 removed)
|
|
|
|
NSUInteger index = 0;
|
|
for (NSString *key in keys)
|
|
{
|
|
NSString *fetchedKey;
|
|
NSString *fetchedCollection;
|
|
|
|
[[transaction ext:@"order"] getKey:&fetchedKey collection:&fetchedCollection atIndex:index inGroup:@""];
|
|
|
|
XCTAssertTrue([fetchedKey isEqualToString:key],
|
|
@"Non-matching keys(%@ vs %@) at index %d", fetchedKey, key, (int)index);
|
|
|
|
XCTAssertTrue([fetchedCollection isEqualToString:@""],
|
|
@"Non-matching collections(%@ vs %@) at index %d", fetchedCollection, @"", (int)index);
|
|
|
|
index++;
|
|
}
|
|
|
|
for (NSString *key in keys)
|
|
{
|
|
NSString *fetchedGroup = [[transaction ext:@"order"] groupForKey:key inCollection:nil];
|
|
|
|
XCTAssertTrue([fetchedGroup isEqualToString:@""], @"Wrong group(%@) for key(%@)", fetchedGroup, key);
|
|
}
|
|
|
|
index = 0;
|
|
for (NSString *key in keys)
|
|
{
|
|
NSString *fetchedGroup = nil;
|
|
NSUInteger fetchedIndex = NSNotFound;
|
|
|
|
BOOL result =
|
|
[[transaction ext:@"order"] getGroup:&fetchedGroup index:&fetchedIndex forKey:key inCollection:nil];
|
|
|
|
XCTAssertTrue(result, @"Wrong result for key(%@) at index(%d)", key, (int)index);
|
|
|
|
XCTAssertTrue([fetchedGroup isEqualToString:@""],
|
|
@"Wrong group(%@) for key(%@) at index(%d)", fetchedGroup, key, (int)index);
|
|
|
|
XCTAssertTrue(fetchedIndex == index,
|
|
@"Wrong index(%d) for key(%@) at index(%d)", (int)fetchedIndex, key, (int)index);
|
|
|
|
index++;
|
|
}
|
|
}];
|
|
|
|
[connection1 readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction){
|
|
|
|
// Test remove all objects
|
|
|
|
[transaction removeAllObjectsInAllCollections]; keysCount = 0;
|
|
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfGroups] == 0, @"Wrong group count");
|
|
XCTAssertTrue([[[transaction ext:@"order"] allGroups] count] == 0, @"Wrong array count");
|
|
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfItemsInGroup:@""] == keysCount, @"Wrong count");
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfItemsInAllGroups] == keysCount, @"Wrong count");
|
|
}];
|
|
|
|
[connection2 readWithBlock:^(YapDatabaseReadTransaction *transaction){
|
|
|
|
// Read changes from other connection
|
|
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfGroups] == 0, @"Wrong group count");
|
|
XCTAssertTrue([[[transaction ext:@"order"] allGroups] count] == 0, @"Wrong array count");
|
|
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfItemsInGroup:@""] == keysCount, @"Wrong count");
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfItemsInAllGroups] == keysCount, @"Wrong count");
|
|
}];
|
|
|
|
[connection1 readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction){
|
|
|
|
// Add all the objects back (in random order)
|
|
|
|
[transaction setObject:object2 forKey:key2 inCollection:nil]; keysCount++; // Included
|
|
[transaction setObject:object1 forKey:key1 inCollection:nil]; keysCount++; // Included
|
|
[transaction setObject:object3 forKey:key3 inCollection:nil]; keysCount++; // Included
|
|
[transaction setObject:objectX forKey:keyX inCollection:nil]; // Excluded !
|
|
[transaction setObject:object0 forKey:key0 inCollection:nil]; keysCount++; // Included
|
|
[transaction setObject:object4 forKey:key4 inCollection:nil]; keysCount++; // Included
|
|
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfGroups] == 1, @"Wrong group count");
|
|
XCTAssertTrue([[[transaction ext:@"order"] allGroups] count] == 1, @"Wrong array count");
|
|
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfItemsInGroup:@""] == keysCount, @"Wrong count");
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfItemsInAllGroups] == keysCount, @"Wrong count");
|
|
|
|
NSArray *keys = @[ key0, key1, key2, key3, key4 ];
|
|
|
|
NSUInteger index = 0;
|
|
for (NSString *key in keys)
|
|
{
|
|
NSString *fetchedKey;
|
|
NSString *fetchedCollection;
|
|
|
|
[[transaction ext:@"order"] getKey:&fetchedKey collection:&fetchedCollection atIndex:index inGroup:@""];
|
|
|
|
XCTAssertTrue([fetchedKey isEqualToString:key],
|
|
@"Non-matching keys(%@ vs %@) at index %d", fetchedKey, key, (int)index);
|
|
|
|
XCTAssertTrue([fetchedCollection isEqualToString:@""],
|
|
@"Non-matching collections(%@ vs %@) at index %d", fetchedCollection, @"", (int)index);
|
|
|
|
index++;
|
|
}
|
|
|
|
for (NSString *key in keys)
|
|
{
|
|
NSString *fetchedGroup = [[transaction ext:@"order"] groupForKey:key inCollection:nil];
|
|
|
|
XCTAssertTrue([fetchedGroup isEqualToString:@""], @"Wrong group(%@) for key(%@)", fetchedGroup, key);
|
|
}
|
|
|
|
index = 0;
|
|
for (NSString *key in keys)
|
|
{
|
|
NSString *fetchedGroup = nil;
|
|
NSUInteger fetchedIndex = NSNotFound;
|
|
|
|
BOOL result =
|
|
[[transaction ext:@"order"] getGroup:&fetchedGroup index:&fetchedIndex forKey:key inCollection:nil];
|
|
|
|
XCTAssertTrue(result, @"Wrong result for key(%@) at index(%d)", key, (int)index);
|
|
|
|
XCTAssertTrue([fetchedGroup isEqualToString:@""],
|
|
@"Wrong group(%@) for key(%@) at index(%d)", fetchedGroup, key, (int)index);
|
|
|
|
XCTAssertTrue(fetchedIndex == index,
|
|
@"Wrong index(%d) for key(%@) at index(%d)", (int)fetchedIndex, key, (int)index);
|
|
|
|
index++;
|
|
}
|
|
}];
|
|
|
|
[connection2 readWithBlock:^(YapDatabaseReadTransaction *transaction){
|
|
|
|
// Read the changes
|
|
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfGroups] == 1, @"Wrong group count");
|
|
XCTAssertTrue([[[transaction ext:@"order"] allGroups] count] == 1, @"Wrong array count");
|
|
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfItemsInGroup:@""] == keysCount, @"Wrong count");
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfItemsInAllGroups] == keysCount, @"Wrong count");
|
|
|
|
NSArray *keys = @[ key0, key1, key2, key3, key4 ]; // <-- Updated order (key1 moved to end)
|
|
|
|
NSUInteger index = 0;
|
|
for (NSString *key in keys)
|
|
{
|
|
NSString *fetchedKey;
|
|
NSString *fetchedCollection;
|
|
|
|
[[transaction ext:@"order"] getKey:&fetchedKey collection:&fetchedCollection atIndex:index inGroup:@""];
|
|
|
|
XCTAssertTrue([fetchedKey isEqualToString:key],
|
|
@"Non-matching keys(%@ vs %@) at index %d", fetchedKey, key, (int)index);
|
|
|
|
XCTAssertTrue([fetchedCollection isEqualToString:@""],
|
|
@"Non-matching collections(%@ vs %@) at index %d", fetchedCollection, @"", (int)index);
|
|
|
|
index++;
|
|
}
|
|
|
|
for (NSString *key in keys)
|
|
{
|
|
NSString *fetchedGroup = [[transaction ext:@"order"] groupForKey:key inCollection:nil];
|
|
|
|
XCTAssertTrue([fetchedGroup isEqualToString:@""], @"Wrong group(%@) for key(%@)", fetchedGroup, key);
|
|
}
|
|
|
|
index = 0;
|
|
for (NSString *key in keys)
|
|
{
|
|
NSString *fetchedGroup = nil;
|
|
NSUInteger fetchedIndex = NSNotFound;
|
|
|
|
BOOL result =
|
|
[[transaction ext:@"order"] getGroup:&fetchedGroup index:&fetchedIndex forKey:key inCollection:nil];
|
|
|
|
XCTAssertTrue(result, @"Wrong result for key(%@) at index(%d)", key, (int)index);
|
|
|
|
XCTAssertTrue([fetchedGroup isEqualToString:@""],
|
|
@"Wrong group(%@) for key(%@) at index(%d)", fetchedGroup, key, (int)index);
|
|
|
|
XCTAssertTrue(fetchedIndex == index,
|
|
@"Wrong index(%d) for key(%@) at index(%d)", (int)fetchedIndex, key, (int)index);
|
|
|
|
index++;
|
|
}
|
|
}];
|
|
|
|
[connection2 readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction){
|
|
|
|
// Again on connection 2
|
|
// Remove all the keys, and then add a few back
|
|
|
|
[transaction removeAllObjectsInCollection:nil]; keysCount = 0;
|
|
|
|
[transaction setObject:object1 forKey:key1 inCollection:nil]; keysCount++; // Included
|
|
[transaction setObject:object0 forKey:key0 inCollection:nil]; keysCount++; // Included
|
|
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfGroups] == 1, @"Wrong group count");
|
|
XCTAssertTrue([[[transaction ext:@"order"] allGroups] count] == 1, @"Wrong array count");
|
|
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfItemsInGroup:@""] == keysCount, @"Wrong count");
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfItemsInAllGroups] == keysCount, @"Wrong count");
|
|
|
|
NSArray *keys = @[ key0, key1 ];
|
|
|
|
NSUInteger index = 0;
|
|
for (NSString *key in keys)
|
|
{
|
|
NSString *fetchedKey;
|
|
NSString *fetchedCollection;
|
|
|
|
[[transaction ext:@"order"] getKey:&fetchedKey collection:&fetchedCollection atIndex:index inGroup:@""];
|
|
|
|
XCTAssertTrue([fetchedKey isEqualToString:key],
|
|
@"Non-matching keys(%@ vs %@) at index %d", fetchedKey, key, (int)index);
|
|
|
|
XCTAssertTrue([fetchedCollection isEqualToString:@""],
|
|
@"Non-matching collections(%@ vs %@) at index %d", fetchedCollection, @"", (int)index);
|
|
|
|
index++;
|
|
}
|
|
|
|
for (NSString *key in keys)
|
|
{
|
|
NSString *fetchedGroup = [[transaction ext:@"order"] groupForKey:key inCollection:nil];
|
|
|
|
XCTAssertTrue([fetchedGroup isEqualToString:@""], @"Wrong group(%@) for key(%@)", fetchedGroup, key);
|
|
}
|
|
|
|
index = 0;
|
|
for (NSString *key in keys)
|
|
{
|
|
NSString *fetchedGroup = nil;
|
|
NSUInteger fetchedIndex = NSNotFound;
|
|
|
|
BOOL result =
|
|
[[transaction ext:@"order"] getGroup:&fetchedGroup index:&fetchedIndex forKey:key inCollection:nil];
|
|
|
|
XCTAssertTrue(result, @"Wrong result for key(%@) at index(%d)", key, (int)index);
|
|
|
|
XCTAssertTrue([fetchedGroup isEqualToString:@""],
|
|
@"Wrong group(%@) for key(%@) at index(%d)", fetchedGroup, key, (int)index);
|
|
|
|
XCTAssertTrue(fetchedIndex == index,
|
|
@"Wrong index(%d) for key(%@) at index(%d)", (int)fetchedIndex, key, (int)index);
|
|
|
|
index++;
|
|
}
|
|
}];
|
|
|
|
[connection1 readWithBlock:^(YapDatabaseReadTransaction *transaction){
|
|
|
|
// Read the changes
|
|
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfGroups] == 1, @"Wrong group count");
|
|
XCTAssertTrue([[[transaction ext:@"order"] allGroups] count] == 1, @"Wrong array count");
|
|
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfItemsInGroup:@""] == keysCount, @"Wrong count");
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfItemsInAllGroups] == keysCount, @"Wrong count");
|
|
|
|
NSArray *keys = @[ key0, key1 ];
|
|
|
|
NSUInteger index = 0;
|
|
for (NSString *key in keys)
|
|
{
|
|
NSString *fetchedKey;
|
|
NSString *fetchedCollection;
|
|
|
|
[[transaction ext:@"order"] getKey:&fetchedKey collection:&fetchedCollection atIndex:index inGroup:@""];
|
|
|
|
XCTAssertTrue([fetchedKey isEqualToString:key],
|
|
@"Non-matching keys(%@ vs %@) at index %d", fetchedKey, key, (int)index);
|
|
|
|
XCTAssertTrue([fetchedCollection isEqualToString:@""],
|
|
@"Non-matching collections(%@ vs %@) at index %d", fetchedCollection, @"", (int)index);
|
|
|
|
index++;
|
|
}
|
|
|
|
for (NSString *key in keys)
|
|
{
|
|
NSString *fetchedGroup = [[transaction ext:@"order"] groupForKey:key inCollection:nil];
|
|
|
|
XCTAssertTrue([fetchedGroup isEqualToString:@""], @"Wrong group(%@) for key(%@)", fetchedGroup, key);
|
|
}
|
|
|
|
index = 0;
|
|
for (NSString *key in keys)
|
|
{
|
|
NSString *fetchedGroup = nil;
|
|
NSUInteger fetchedIndex = NSNotFound;
|
|
|
|
BOOL result =
|
|
[[transaction ext:@"order"] getGroup:&fetchedGroup index:&fetchedIndex forKey:key inCollection:nil];
|
|
|
|
XCTAssertTrue(result, @"Wrong result for key(%@) at index(%d)", key, (int)index);
|
|
|
|
XCTAssertTrue([fetchedGroup isEqualToString:@""],
|
|
@"Wrong group(%@) for key(%@) at index(%d)", fetchedGroup, key, (int)index);
|
|
|
|
XCTAssertTrue(fetchedIndex == index,
|
|
@"Wrong index(%d) for key(%@) at index(%d)", (int)fetchedIndex, key, (int)index);
|
|
|
|
index++;
|
|
}
|
|
}];
|
|
|
|
[connection2 readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction){
|
|
|
|
// Add all the keys back. Some are already included.
|
|
|
|
[transaction setObject:object0 forKey:key0 inCollection:nil]; // Already included
|
|
[transaction setObject:object1 forKey:key1 inCollection:nil]; // Already included
|
|
[transaction setObject:object2 forKey:key2 inCollection:nil]; keysCount++; // Included
|
|
[transaction setObject:object3 forKey:key3 inCollection:nil]; keysCount++; // Included
|
|
[transaction setObject:object4 forKey:key4 inCollection:nil]; keysCount++; // Included
|
|
[transaction setObject:objectX forKey:keyX inCollection:nil]; // Excluded !
|
|
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfGroups] == 1, @"Wrong group count");
|
|
XCTAssertTrue([[[transaction ext:@"order"] allGroups] count] == 1, @"Wrong array count");
|
|
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfItemsInGroup:@""] == keysCount, @"Wrong count");
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfItemsInAllGroups] == keysCount, @"Wrong count");
|
|
|
|
NSArray *keys = @[ key0, key1, key2, key3, key4 ];
|
|
|
|
NSUInteger index = 0;
|
|
for (NSString *key in keys)
|
|
{
|
|
NSString *fetchedKey;
|
|
NSString *fetchedCollection;
|
|
|
|
[[transaction ext:@"order"] getKey:&fetchedKey collection:&fetchedCollection atIndex:index inGroup:@""];
|
|
|
|
XCTAssertTrue([fetchedKey isEqualToString:key],
|
|
@"Non-matching keys(%@ vs %@) at index %d", fetchedKey, key, (int)index);
|
|
|
|
XCTAssertTrue([fetchedCollection isEqualToString:@""],
|
|
@"Non-matching collections(%@ vs %@) at index %d", fetchedCollection, @"", (int)index);
|
|
|
|
index++;
|
|
}
|
|
|
|
for (NSString *key in keys)
|
|
{
|
|
NSString *fetchedGroup = [[transaction ext:@"order"] groupForKey:key inCollection:nil];
|
|
|
|
XCTAssertTrue([fetchedGroup isEqualToString:@""], @"Wrong group(%@) for key(%@)", fetchedGroup, key);
|
|
}
|
|
|
|
index = 0;
|
|
for (NSString *key in keys)
|
|
{
|
|
NSString *fetchedGroup = nil;
|
|
NSUInteger fetchedIndex = NSNotFound;
|
|
|
|
BOOL result =
|
|
[[transaction ext:@"order"] getGroup:&fetchedGroup index:&fetchedIndex forKey:key inCollection:nil];
|
|
|
|
XCTAssertTrue(result, @"Wrong result for key(%@) at index(%d)", key, (int)index);
|
|
|
|
XCTAssertTrue([fetchedGroup isEqualToString:@""],
|
|
@"Wrong group(%@) for key(%@) at index(%d)", fetchedGroup, key, (int)index);
|
|
|
|
XCTAssertTrue(fetchedIndex == index,
|
|
@"Wrong index(%d) for key(%@) at index(%d)", (int)fetchedIndex, key, (int)index);
|
|
|
|
index++;
|
|
}
|
|
}];
|
|
|
|
[connection1 readWithBlock:^(YapDatabaseReadTransaction *transaction){
|
|
|
|
// Read the changes
|
|
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfGroups] == 1, @"Wrong group count");
|
|
XCTAssertTrue([[[transaction ext:@"order"] allGroups] count] == 1, @"Wrong array count");
|
|
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfItemsInGroup:@""] == keysCount, @"Wrong count");
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfItemsInAllGroups] == keysCount, @"Wrong count");
|
|
|
|
NSArray *keys = @[ key0, key1, key2, key3, key4 ];
|
|
|
|
NSUInteger index = 0;
|
|
for (NSString *key in keys)
|
|
{
|
|
NSString *fetchedKey;
|
|
NSString *fetchedCollection;
|
|
|
|
[[transaction ext:@"order"] getKey:&fetchedKey collection:&fetchedCollection atIndex:index inGroup:@""];
|
|
|
|
XCTAssertTrue([fetchedKey isEqualToString:key],
|
|
@"Non-matching keys(%@ vs %@) at index %d", fetchedKey, key, (int)index);
|
|
|
|
XCTAssertTrue([fetchedCollection isEqualToString:@""],
|
|
@"Non-matching collections(%@ vs %@) at index %d", fetchedCollection, @"", (int)index);
|
|
|
|
index++;
|
|
}
|
|
|
|
for (NSString *key in keys)
|
|
{
|
|
NSString *fetchedGroup = [[transaction ext:@"order"] groupForKey:key inCollection:nil];
|
|
|
|
XCTAssertTrue([fetchedGroup isEqualToString:@""], @"Wrong group(%@) for key(%@)", fetchedGroup, key);
|
|
}
|
|
|
|
index = 0;
|
|
for (NSString *key in keys)
|
|
{
|
|
NSString *fetchedGroup = nil;
|
|
NSUInteger fetchedIndex = NSNotFound;
|
|
|
|
BOOL result =
|
|
[[transaction ext:@"order"] getGroup:&fetchedGroup index:&fetchedIndex forKey:key inCollection:nil];
|
|
|
|
XCTAssertTrue(result, @"Wrong result for key(%@) at index(%d)", key, (int)index);
|
|
|
|
XCTAssertTrue([fetchedGroup isEqualToString:@""],
|
|
@"Wrong group(%@) for key(%@) at index(%d)", fetchedGroup, key, (int)index);
|
|
|
|
XCTAssertTrue(fetchedIndex == index,
|
|
@"Wrong index(%d) for key(%@) at index(%d)", (int)fetchedIndex, key, (int)index);
|
|
|
|
index++;
|
|
}
|
|
}];
|
|
|
|
[connection2 readWithBlock:^(YapDatabaseReadTransaction *transaction){
|
|
|
|
// Test enumeration
|
|
|
|
__block NSUInteger correctIndex;
|
|
|
|
NSArray *keys = @[ key0, key1, key2, key3, key4 ];
|
|
|
|
// Basic enumeration
|
|
|
|
correctIndex = 0;
|
|
[[transaction ext:@"order"] enumerateKeysInGroup:@""
|
|
usingBlock:^(NSString *collection, NSString *key, NSUInteger index, BOOL *stop) {
|
|
|
|
XCTAssertTrue(index == correctIndex,
|
|
@"Index mismatch: %lu vs %lu", (unsigned long)index, (unsigned long)correctIndex);
|
|
correctIndex++;
|
|
|
|
NSString *correctKey = [keys objectAtIndex:index];
|
|
XCTAssertTrue([key isEqual:correctKey],
|
|
@"Enumeration mismatch: (%@) vs (%@) at index %lu", key, correctKey, (unsigned long)index);
|
|
}];
|
|
|
|
// Enumerate with options: forwards
|
|
|
|
correctIndex = 0;
|
|
[[transaction ext:@"order"] enumerateKeysInGroup:@""
|
|
withOptions:0
|
|
usingBlock:^(NSString *collection, NSString *key, NSUInteger index, BOOL *stop) {
|
|
|
|
XCTAssertTrue(index == correctIndex,
|
|
@"Index mismatch: %lu vs %lu", (unsigned long)index, (unsigned long)correctIndex);
|
|
correctIndex++;
|
|
|
|
NSString *correctKey = [keys objectAtIndex:index];
|
|
XCTAssertTrue([key isEqual:correctKey],
|
|
@"Enumeration mismatch: (%@) vs (%@) at index %lu", key, correctKey, (unsigned long)index);
|
|
}];
|
|
|
|
// Enumerate with options: backwards
|
|
|
|
correctIndex = 4;
|
|
[[transaction ext:@"order"] enumerateKeysInGroup:@""
|
|
withOptions:NSEnumerationReverse
|
|
usingBlock:^(NSString *collection, NSString *key, NSUInteger index, BOOL *stop) {
|
|
|
|
XCTAssertTrue(index == correctIndex,
|
|
@"Index mismatch: %lu vs %lu", (unsigned long)index, (unsigned long)correctIndex);
|
|
correctIndex--;
|
|
|
|
NSString *correctKey = [keys objectAtIndex:index];
|
|
XCTAssertTrue([key isEqual:correctKey],
|
|
@"Enumeration mismatch: (%@) vs (%@) at index %lu", key, correctKey, (unsigned long)index);
|
|
}];
|
|
|
|
// Enumerate with options & range: forwards, full range
|
|
|
|
correctIndex = 0;
|
|
[[transaction ext:@"order"] enumerateKeysInGroup:@""
|
|
withOptions:0
|
|
range:NSMakeRange(0, 5)
|
|
usingBlock:^(NSString *collection, NSString *key, NSUInteger index, BOOL *stop) {
|
|
|
|
XCTAssertTrue(index == correctIndex,
|
|
@"Index mismatch: %lu vs %lu", (unsigned long)index, (unsigned long)correctIndex);
|
|
correctIndex++;
|
|
|
|
NSString *correctKey = [keys objectAtIndex:index];
|
|
XCTAssertTrue([key isEqual:correctKey],
|
|
@"Enumeration mismatch: (%@) vs (%@) at index %lu", key, correctKey, (unsigned long)index);
|
|
}];
|
|
|
|
// Enumerate with options & range: backwards, full range
|
|
|
|
correctIndex = 4;
|
|
[[transaction ext:@"order"] enumerateKeysInGroup:@""
|
|
withOptions:NSEnumerationReverse
|
|
range:NSMakeRange(0, 5)
|
|
usingBlock:^(NSString *collection, NSString *key, NSUInteger index, BOOL *stop) {
|
|
|
|
XCTAssertTrue(index == correctIndex,
|
|
@"Index mismatch: %lu vs %lu", (unsigned long)index, (unsigned long)correctIndex);
|
|
correctIndex--;
|
|
|
|
NSString *correctKey = [keys objectAtIndex:index];
|
|
XCTAssertTrue([key isEqual:correctKey],
|
|
@"Enumeration mismatch: (%@) vs (%@) at index %lu", key, correctKey, (unsigned long)index);
|
|
}];
|
|
|
|
// Enumerate with options & range: forwards, subset range
|
|
|
|
correctIndex = 1;
|
|
[[transaction ext:@"order"] enumerateKeysInGroup:@""
|
|
withOptions:0
|
|
range:NSMakeRange(1, 3)
|
|
usingBlock:^(NSString *collection, NSString *key, NSUInteger index, BOOL *stop) {
|
|
|
|
XCTAssertTrue(index == correctIndex,
|
|
@"Index mismatch: %lu vs %lu", (unsigned long)index, (unsigned long)correctIndex);
|
|
correctIndex++;
|
|
|
|
NSString *correctKey = [keys objectAtIndex:index];
|
|
XCTAssertTrue([key isEqual:correctKey],
|
|
@"Enumeration mismatch: (%@) vs (%@) at index %lu", key, correctKey, (unsigned long)index);
|
|
}];
|
|
|
|
// Enumerate with options & range: backwards, subset range
|
|
|
|
correctIndex = 3;
|
|
[[transaction ext:@"order"] enumerateKeysInGroup:@""
|
|
withOptions:NSEnumerationReverse
|
|
range:NSMakeRange(1, 3)
|
|
usingBlock:^(NSString *collection, NSString *key, NSUInteger index, BOOL *stop) {
|
|
|
|
XCTAssertTrue(index == correctIndex,
|
|
@"Index mismatch: %lu vs %lu", (unsigned long)index, (unsigned long)correctIndex);
|
|
correctIndex--;
|
|
|
|
NSString *correctKey = [keys objectAtIndex:index];
|
|
XCTAssertTrue([key isEqual:correctKey],
|
|
@"Enumeration mismatch: (%@) vs (%@) at index %lu", key, correctKey, (unsigned long)index);
|
|
}];
|
|
}];
|
|
|
|
connection1 = nil;
|
|
connection2 = nil;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
#pragma mark -
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
- (void)testMultiPage_persistent
|
|
{
|
|
NSString *databasePath = [self databasePath:NSStringFromSelector(_cmd)];
|
|
|
|
YapDatabaseViewOptions *options = [[YapDatabaseViewOptions alloc] init];
|
|
options.isPersistent = YES;
|
|
|
|
[self _testMultiPage_withPath:databasePath options:options];
|
|
}
|
|
|
|
- (void)testMultiPage_nonPersistent
|
|
{
|
|
NSString *databasePath = [self databasePath:NSStringFromSelector(_cmd)];
|
|
|
|
YapDatabaseViewOptions *options = [[YapDatabaseViewOptions alloc] init];
|
|
options.isPersistent = NO;
|
|
|
|
[self _testMultiPage_withPath:databasePath options:options];
|
|
}
|
|
|
|
- (void)_testMultiPage_withPath:(NSString *)databasePath options:(YapDatabaseViewOptions *)options
|
|
{
|
|
//
|
|
// These tests include enough keys to ensure that the view has to deal with multiple pages.
|
|
// By default, there are 50 keys in a page.
|
|
|
|
[[NSFileManager defaultManager] removeItemAtPath:databasePath error:NULL];
|
|
YapDatabase *database = [[YapDatabase alloc] initWithPath:databasePath];
|
|
|
|
XCTAssertNotNil(database, @"Oops");
|
|
|
|
YapDatabaseConnection *connection1 = [database newConnection];
|
|
YapDatabaseConnection *connection2 = [database newConnection];
|
|
|
|
YapDatabaseViewGrouping *grouping = [YapDatabaseViewGrouping withKeyBlock:
|
|
^NSString *(YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key)
|
|
{
|
|
return @"";
|
|
}];
|
|
|
|
YapDatabaseViewSorting *sorting = [YapDatabaseViewSorting withObjectBlock:
|
|
^(YapDatabaseReadTransaction *transaction, NSString *group, NSString *collection1, NSString *key1, id obj1,
|
|
NSString *collection2, NSString *key2, id obj2)
|
|
{
|
|
NSString *object1 = (NSString *)obj1;
|
|
NSString *object2 = (NSString *)obj2;
|
|
|
|
return [object1 compare:object2 options:NSNumericSearch];
|
|
}];
|
|
|
|
YapDatabaseAutoView *databaseView =
|
|
[[YapDatabaseAutoView alloc] initWithGrouping:grouping
|
|
sorting:sorting
|
|
versionTag:@"1"
|
|
options:options];
|
|
|
|
BOOL registerResult = [database registerExtension:databaseView withName:@"order"];
|
|
|
|
XCTAssertTrue(registerResult, @"Failure registering extension");
|
|
|
|
//
|
|
// Test adding a bunch of keys
|
|
//
|
|
|
|
[connection1 readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
|
|
|
// Add 3 pages of keys to the view
|
|
//
|
|
// page0 = [key0 - key49]
|
|
// page1 = [key50 - key99]
|
|
// page2 = [key100 - key149]
|
|
|
|
for (int i = 0; i < 150; i++)
|
|
{
|
|
NSString *key = [NSString stringWithFormat:@"key%d", i];
|
|
NSString *obj = [NSString stringWithFormat:@"object%d", i];
|
|
|
|
[transaction setObject:obj forKey:key inCollection:nil];
|
|
}
|
|
}];
|
|
|
|
[connection1 readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
for (int i = 0; i < 150; i++)
|
|
{
|
|
NSString *expectedKey = [NSString stringWithFormat:@"key%d", i];
|
|
|
|
NSString *fetchedKey = [[transaction ext:@"order"] keyAtIndex:i inGroup:@""];
|
|
|
|
XCTAssertTrue([expectedKey isEqualToString:fetchedKey],
|
|
@"Key mismatch: expected(%@) fetched(%@)", expectedKey, fetchedKey);
|
|
}
|
|
}];
|
|
|
|
[connection2 readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
for (int i = 0; i < 150; i++)
|
|
{
|
|
NSString *expectedKey = [NSString stringWithFormat:@"key%d", i];
|
|
|
|
NSString *fetchedKey = [[transaction ext:@"order"] keyAtIndex:i inGroup:@""];
|
|
|
|
XCTAssertTrue([expectedKey isEqualToString:fetchedKey],
|
|
@"Key mismatch: expected(%@) fetched(%@)", expectedKey, fetchedKey);
|
|
}
|
|
}];
|
|
|
|
[[database newConnection] readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
for (int i = 0; i < 150; i++)
|
|
{
|
|
NSString *expectedKey = [NSString stringWithFormat:@"key%d", i];
|
|
|
|
NSString *fetchedKey = [[transaction ext:@"order"] keyAtIndex:i inGroup:@""];
|
|
|
|
XCTAssertTrue([expectedKey isEqualToString:fetchedKey],
|
|
@"Key mismatch: expected(%@) fetched(%@)", expectedKey, fetchedKey);
|
|
}
|
|
}];
|
|
|
|
//
|
|
// Test removing an entire page of keys from the middle
|
|
//
|
|
|
|
[connection1 readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
|
|
|
// Drop middle of the 3 pages
|
|
//
|
|
// page0 = [key0 - key49]
|
|
// page1 = [key50 - key99] <-- Drop
|
|
// page2 = [key100 - key149]
|
|
|
|
for (int i = 50; i < 100; i++)
|
|
{
|
|
NSString *key = [NSString stringWithFormat:@"key%d", i];
|
|
|
|
[transaction removeObjectForKey:key inCollection:nil];
|
|
}
|
|
}];
|
|
|
|
[connection1 readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
for (int i = 0; i < 100; i++)
|
|
{
|
|
NSString *expectedKey;
|
|
|
|
if (i < 50)
|
|
expectedKey = [NSString stringWithFormat:@"key%d", i];
|
|
else
|
|
expectedKey = [NSString stringWithFormat:@"key%d", (i+50)];
|
|
|
|
NSString *fetchedKey = [[transaction ext:@"order"] keyAtIndex:i inGroup:@""];
|
|
|
|
XCTAssertTrue([expectedKey isEqualToString:fetchedKey],
|
|
@"Key mismatch: expected(%@) fetched(%@)", expectedKey, fetchedKey);
|
|
}
|
|
}];
|
|
|
|
[connection2 readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
for (int i = 0; i < 100; i++)
|
|
{
|
|
NSString *expectedKey;
|
|
|
|
if (i < 50)
|
|
expectedKey = [NSString stringWithFormat:@"key%d", i];
|
|
else
|
|
expectedKey = [NSString stringWithFormat:@"key%d", (i+50)];
|
|
|
|
NSString *fetchedKey = [[transaction ext:@"order"] keyAtIndex:i inGroup:@""];
|
|
|
|
XCTAssertTrue([expectedKey isEqualToString:fetchedKey],
|
|
@"Key mismatch: expected(%@) fetched(%@)", expectedKey, fetchedKey);
|
|
}
|
|
}];
|
|
|
|
[[database newConnection] readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
for (int i = 0; i < 100; i++)
|
|
{
|
|
NSString *expectedKey;
|
|
|
|
if (i < 50)
|
|
expectedKey = [NSString stringWithFormat:@"key%d", i];
|
|
else
|
|
expectedKey = [NSString stringWithFormat:@"key%d", (i+50)];
|
|
|
|
NSString *fetchedKey = [[transaction ext:@"order"] keyAtIndex:i inGroup:@""];
|
|
|
|
XCTAssertTrue([expectedKey isEqualToString:fetchedKey],
|
|
@"Key mismatch: expected(%@) fetched(%@)", expectedKey, fetchedKey);
|
|
}
|
|
}];
|
|
|
|
//
|
|
// Test adding an entire page in the middle
|
|
//
|
|
|
|
[connection1 readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
|
|
|
// Re-add middle page
|
|
//
|
|
// page0 = [key0 - key49]
|
|
// page1 = [key50 - key99] <-- Re-add
|
|
// page2 = [key100 - key149]
|
|
|
|
for (int i = 50; i < 100; i++)
|
|
{
|
|
NSString *key = [NSString stringWithFormat:@"key%d", i];
|
|
NSString *obj = [NSString stringWithFormat:@"object%d", i];
|
|
|
|
[transaction setObject:obj forKey:key inCollection:nil];
|
|
}
|
|
}];
|
|
|
|
[connection1 readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
for (int i = 0; i < 150; i++)
|
|
{
|
|
NSString *expectedKey = [NSString stringWithFormat:@"key%d", i];
|
|
|
|
NSString *fetchedKey = [[transaction ext:@"order"] keyAtIndex:i inGroup:@""];
|
|
|
|
XCTAssertTrue([expectedKey isEqualToString:fetchedKey],
|
|
@"Key mismatch: expected(%@) fetched(%@)", expectedKey, fetchedKey);
|
|
}
|
|
}];
|
|
|
|
[connection2 readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
for (int i = 0; i < 150; i++)
|
|
{
|
|
NSString *expectedKey = [NSString stringWithFormat:@"key%d", i];
|
|
|
|
NSString *fetchedKey = [[transaction ext:@"order"] keyAtIndex:i inGroup:@""];
|
|
|
|
XCTAssertTrue([expectedKey isEqualToString:fetchedKey],
|
|
@"Key mismatch: expected(%@) fetched(%@)", expectedKey, fetchedKey);
|
|
}
|
|
}];
|
|
|
|
[[database newConnection] readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
for (int i = 0; i < 150; i++)
|
|
{
|
|
NSString *expectedKey = [NSString stringWithFormat:@"key%d", i];
|
|
|
|
NSString *fetchedKey = [[transaction ext:@"order"] keyAtIndex:i inGroup:@""];
|
|
|
|
XCTAssertTrue([expectedKey isEqualToString:fetchedKey],
|
|
@"Key mismatch: expected(%@) fetched(%@)", expectedKey, fetchedKey);
|
|
}
|
|
}];
|
|
|
|
//
|
|
// Test removing keys from multiple pages
|
|
//
|
|
|
|
[connection1 readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
|
|
|
// Remove every 5th item
|
|
|
|
for (int i = 5; i < 150; i += 5)
|
|
{
|
|
NSString *key = [NSString stringWithFormat:@"key%d", i];
|
|
|
|
[transaction removeObjectForKey:key inCollection:nil];
|
|
}
|
|
}];
|
|
|
|
[connection1 readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
for (int i = 0; i < 150; i++)
|
|
{
|
|
if ((i % 5) == 0){
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
NSString *expectedKey = [NSString stringWithFormat:@"key%d", i];
|
|
|
|
int index = i - (i / 5);
|
|
|
|
NSString *fetchedKey = [[transaction ext:@"order"] keyAtIndex:index inGroup:@""];
|
|
|
|
XCTAssertTrue([expectedKey isEqualToString:fetchedKey],
|
|
@"Key mismatch: expected(%@) fetched(%@)", expectedKey, fetchedKey);
|
|
}
|
|
}
|
|
}];
|
|
|
|
[connection2 readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
for (int i = 0; i < 150; i++)
|
|
{
|
|
if ((i % 5) == 0){
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
NSString *expectedKey = [NSString stringWithFormat:@"key%d", i];
|
|
|
|
int index = i - (i / 5);
|
|
|
|
NSString *fetchedKey = [[transaction ext:@"order"] keyAtIndex:index inGroup:@""];
|
|
|
|
XCTAssertTrue([expectedKey isEqualToString:fetchedKey],
|
|
@"Key mismatch: expected(%@) fetched(%@)", expectedKey, fetchedKey);
|
|
}
|
|
}
|
|
}];
|
|
|
|
[[database newConnection] readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
for (int i = 0; i < 150; i++)
|
|
{
|
|
if ((i % 5) == 0){
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
NSString *expectedKey = [NSString stringWithFormat:@"key%d", i];
|
|
|
|
int index = i - (i / 5);
|
|
|
|
NSString *fetchedKey = [[transaction ext:@"order"] keyAtIndex:index inGroup:@""];
|
|
|
|
XCTAssertTrue([expectedKey isEqualToString:fetchedKey],
|
|
@"Key mismatch: expected(%@) fetched(%@)", expectedKey, fetchedKey);
|
|
}
|
|
}
|
|
}];
|
|
|
|
//
|
|
// Test removing all keys
|
|
//
|
|
|
|
[connection1 readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
|
|
|
[transaction removeAllObjectsInAllCollections];
|
|
}];
|
|
|
|
[connection1 readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
NSUInteger count = [[transaction ext:@"order"] numberOfItemsInGroup:@""];
|
|
|
|
XCTAssertTrue(count == 0, @"Wrong count. Expected zero, got %lu", (unsigned long)count);
|
|
}];
|
|
|
|
[connection2 readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
NSUInteger count = [[transaction ext:@"order"] numberOfItemsInGroup:@""];
|
|
|
|
XCTAssertTrue(count == 0, @"Wrong count. Expected zero, got %lu", (unsigned long)count);
|
|
}];
|
|
|
|
[[database newConnection] readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
NSUInteger count = [[transaction ext:@"order"] numberOfItemsInGroup:@""];
|
|
|
|
XCTAssertTrue(count == 0, @"Wrong count. Expected zero, got %lu", (unsigned long)count);
|
|
}];
|
|
|
|
//
|
|
// Test adding a bunch of keys (again)
|
|
//
|
|
|
|
[connection1 readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
|
|
|
// Add 3 pages of keys to the view
|
|
//
|
|
// page0 = [key0 - key49]
|
|
// page1 = [key50 - key99]
|
|
// page2 = [key100 - key149]
|
|
|
|
for (int i = 0; i < 150; i++)
|
|
{
|
|
NSString *key = [NSString stringWithFormat:@"key%d", i];
|
|
NSString *obj = [NSString stringWithFormat:@"object%d", i];
|
|
|
|
[transaction setObject:obj forKey:key inCollection:nil];
|
|
}
|
|
}];
|
|
|
|
[connection1 readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
for (int i = 0; i < 150; i++)
|
|
{
|
|
NSString *expectedKey = [NSString stringWithFormat:@"key%d", i];
|
|
|
|
NSString *fetchedKey = [[transaction ext:@"order"] keyAtIndex:i inGroup:@""];
|
|
|
|
XCTAssertTrue([expectedKey isEqualToString:fetchedKey],
|
|
@"Key mismatch: expected(%@) fetched(%@)", expectedKey, fetchedKey);
|
|
}
|
|
}];
|
|
|
|
[connection2 readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
for (int i = 0; i < 150; i++)
|
|
{
|
|
NSString *expectedKey = [NSString stringWithFormat:@"key%d", i];
|
|
|
|
NSString *fetchedKey = [[transaction ext:@"order"] keyAtIndex:i inGroup:@""];
|
|
|
|
XCTAssertTrue([expectedKey isEqualToString:fetchedKey],
|
|
@"Key mismatch: expected(%@) fetched(%@)", expectedKey, fetchedKey);
|
|
}
|
|
}];
|
|
|
|
[[database newConnection] readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
for (int i = 0; i < 150; i++)
|
|
{
|
|
NSString *expectedKey = [NSString stringWithFormat:@"key%d", i];
|
|
|
|
NSString *fetchedKey = [[transaction ext:@"order"] keyAtIndex:i inGroup:@""];
|
|
|
|
XCTAssertTrue([expectedKey isEqualToString:fetchedKey],
|
|
@"Key mismatch: expected(%@) fetched(%@)", expectedKey, fetchedKey);
|
|
}
|
|
}];
|
|
|
|
//
|
|
// Test removing keys from multiple pages (this time as a single instruction)
|
|
//
|
|
|
|
[connection1 readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
|
|
|
// Remove every 5th item
|
|
|
|
NSMutableArray *keysToRemove = [NSMutableArray array];
|
|
|
|
for (int i = 5; i < 150; i += 5)
|
|
{
|
|
NSString *key = [NSString stringWithFormat:@"key%d", i];
|
|
|
|
[keysToRemove addObject:key];
|
|
}
|
|
|
|
[transaction removeObjectsForKeys:keysToRemove inCollection:nil];
|
|
}];
|
|
|
|
[connection1 readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
for (int i = 0; i < 150; i++)
|
|
{
|
|
if ((i % 5) == 0){
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
NSString *expectedKey = [NSString stringWithFormat:@"key%d", i];
|
|
|
|
int index = i - (i / 5);
|
|
|
|
NSString *fetchedKey = [[transaction ext:@"order"] keyAtIndex:index inGroup:@""];
|
|
|
|
XCTAssertTrue([expectedKey isEqualToString:fetchedKey],
|
|
@"Key mismatch: expected(%@) fetched(%@)", expectedKey, fetchedKey);
|
|
}
|
|
}
|
|
}];
|
|
|
|
[connection2 readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
for (int i = 0; i < 150; i++)
|
|
{
|
|
if ((i % 5) == 0){
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
NSString *expectedKey = [NSString stringWithFormat:@"key%d", i];
|
|
|
|
int index = i - (i / 5);
|
|
|
|
NSString *fetchedKey = [[transaction ext:@"order"] keyAtIndex:index inGroup:@""];
|
|
|
|
XCTAssertTrue([expectedKey isEqualToString:fetchedKey],
|
|
@"Key mismatch: expected(%@) fetched(%@)", expectedKey, fetchedKey);
|
|
}
|
|
}
|
|
}];
|
|
|
|
[[database newConnection] readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
for (int i = 0; i < 150; i++)
|
|
{
|
|
if ((i % 5) == 0){
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
NSString *expectedKey = [NSString stringWithFormat:@"key%d", i];
|
|
|
|
int index = i - (i / 5);
|
|
|
|
NSString *fetchedKey = [[transaction ext:@"order"] keyAtIndex:index inGroup:@""];
|
|
|
|
XCTAssertTrue([expectedKey isEqualToString:fetchedKey],
|
|
@"Key mismatch: expected(%@) fetched(%@)", expectedKey, fetchedKey);
|
|
}
|
|
}
|
|
}];
|
|
|
|
//
|
|
// Clear the database, and add a bunch of keys (again)
|
|
//
|
|
|
|
[connection1 readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
|
|
|
[transaction removeAllObjectsInAllCollections];
|
|
|
|
// Add 2 pages of keys to the view
|
|
//
|
|
// page0 = [key0 - key49]
|
|
// page1 = [key100 - key149]
|
|
|
|
for (int i = 0; i < 50; i++)
|
|
{
|
|
NSString *key = [NSString stringWithFormat:@"key%d", i];
|
|
NSString *obj = [NSString stringWithFormat:@"object%d", i];
|
|
|
|
[transaction setObject:obj forKey:key inCollection:nil];
|
|
}
|
|
|
|
for (int i = 100; i < 150; i++)
|
|
{
|
|
NSString *key = [NSString stringWithFormat:@"key%d", i];
|
|
NSString *obj = [NSString stringWithFormat:@"object%d", i];
|
|
|
|
[transaction setObject:obj forKey:key inCollection:nil];
|
|
}
|
|
}];
|
|
|
|
[connection1 readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
|
|
|
// Add [key50 - key59]
|
|
//
|
|
// Should originally add to page1, and then get moved to page0
|
|
|
|
for (int i = 50; i < 60; i++)
|
|
{
|
|
NSString *key = [NSString stringWithFormat:@"key%d", i];
|
|
NSString *obj = [NSString stringWithFormat:@"object%d", i];
|
|
|
|
[transaction setObject:obj forKey:key inCollection:nil];
|
|
}
|
|
|
|
// Remove [key40 - key49]
|
|
//
|
|
// This should make room for [key50 - key59] to move from page1 to page0
|
|
|
|
for (int i = 40; i < 50; i++)
|
|
{
|
|
NSString *key = [NSString stringWithFormat:@"key%d", i];
|
|
|
|
[transaction removeObjectForKey:key inCollection:nil];
|
|
}
|
|
|
|
// This test is designed to hit the codePath:
|
|
//
|
|
// YapDatabaseViewTransaction:
|
|
// - splitOversizedPage
|
|
// - "Move objects from beginning of page to end of previous page"
|
|
}];
|
|
|
|
[connection1 readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
NSUInteger index = 0;
|
|
|
|
for (int i = 0; i < 40; i++)
|
|
{
|
|
NSString *expectedKey = [NSString stringWithFormat:@"key%d", i];
|
|
|
|
NSString *fetchedKey = [[transaction ext:@"order"] keyAtIndex:index inGroup:@""];
|
|
|
|
XCTAssertTrue([expectedKey isEqualToString:fetchedKey],
|
|
@"Key mismatch: expected(%@) fetched(%@)", expectedKey, fetchedKey);
|
|
|
|
index++;
|
|
}
|
|
|
|
for (int i = 50; i < 60; i++)
|
|
{
|
|
NSString *expectedKey = [NSString stringWithFormat:@"key%d", i];
|
|
|
|
NSString *fetchedKey = [[transaction ext:@"order"] keyAtIndex:index inGroup:@""];
|
|
|
|
XCTAssertTrue([expectedKey isEqualToString:fetchedKey],
|
|
@"Key mismatch: expected(%@) fetched(%@)", expectedKey, fetchedKey);
|
|
|
|
index++;
|
|
}
|
|
|
|
for (int i = 100; i < 150; i++)
|
|
{
|
|
NSString *expectedKey = [NSString stringWithFormat:@"key%d", i];
|
|
|
|
NSString *fetchedKey = [[transaction ext:@"order"] keyAtIndex:index inGroup:@""];
|
|
|
|
XCTAssertTrue([expectedKey isEqualToString:fetchedKey],
|
|
@"Key mismatch: expected(%@) fetched(%@)", expectedKey, fetchedKey);
|
|
|
|
index++;
|
|
}
|
|
}];
|
|
|
|
//
|
|
// Clear the database, and add a bunch of keys (again)
|
|
//
|
|
|
|
[connection1 readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
|
|
|
[transaction removeAllObjectsInAllCollections];
|
|
|
|
// Add 2 pages of keys to the view
|
|
//
|
|
// page0 = [key50 - key99]
|
|
// page1 = [key100 - key149]
|
|
|
|
for (int i = 50; i < 150; i++)
|
|
{
|
|
NSString *key = [NSString stringWithFormat:@"key%d", i];
|
|
NSString *obj = [NSString stringWithFormat:@"object%d", i];
|
|
|
|
[transaction setObject:obj forKey:key inCollection:nil];
|
|
}
|
|
}];
|
|
|
|
[connection1 readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
|
|
|
// Add [key0 - key9]
|
|
//
|
|
// Should add to page0
|
|
|
|
for (int i = 0; i < 10; i++)
|
|
{
|
|
NSString *key = [NSString stringWithFormat:@"key%d", i];
|
|
NSString *obj = [NSString stringWithFormat:@"object%d", i];
|
|
|
|
[transaction setObject:obj forKey:key inCollection:nil];
|
|
}
|
|
|
|
// Remove [key100 - key109]
|
|
//
|
|
// This should make room for [key90 - key99] to move from page0 to page1
|
|
|
|
for (int i = 100; i < 110; i++)
|
|
{
|
|
NSString *key = [NSString stringWithFormat:@"key%d", i];
|
|
|
|
[transaction removeObjectForKey:key inCollection:nil];
|
|
}
|
|
|
|
// This test is designed to hit the codePath:
|
|
//
|
|
// YapDatabaseViewTransaction:
|
|
// - splitOversizedPage
|
|
// - "Move objects from end of page to beginning of next page"
|
|
}];
|
|
|
|
[connection1 readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
NSUInteger index = 0;
|
|
|
|
for (int i = 0; i < 10; i++)
|
|
{
|
|
NSString *expectedKey = [NSString stringWithFormat:@"key%d", i];
|
|
|
|
NSString *fetchedKey = [[transaction ext:@"order"] keyAtIndex:index inGroup:@""];
|
|
|
|
XCTAssertTrue([expectedKey isEqualToString:fetchedKey],
|
|
@"Key mismatch: expected(%@) fetched(%@)", expectedKey, fetchedKey);
|
|
|
|
index++;
|
|
}
|
|
|
|
for (int i = 50; i < 100; i++)
|
|
{
|
|
NSString *expectedKey = [NSString stringWithFormat:@"key%d", i];
|
|
|
|
NSString *fetchedKey = [[transaction ext:@"order"] keyAtIndex:index inGroup:@""];
|
|
|
|
XCTAssertTrue([expectedKey isEqualToString:fetchedKey],
|
|
@"Key mismatch: expected(%@) fetched(%@)", expectedKey, fetchedKey);
|
|
|
|
index++;
|
|
}
|
|
|
|
for (int i = 110; i < 150; i++)
|
|
{
|
|
NSString *expectedKey = [NSString stringWithFormat:@"key%d", i];
|
|
|
|
NSString *fetchedKey = [[transaction ext:@"order"] keyAtIndex:index inGroup:@""];
|
|
|
|
XCTAssertTrue([expectedKey isEqualToString:fetchedKey],
|
|
@"Key mismatch: expected(%@) fetched(%@)", expectedKey, fetchedKey);
|
|
|
|
index++;
|
|
}
|
|
}];
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
#pragma mark -
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
- (void)testViewPopulation_persistent
|
|
{
|
|
NSString *databasePath = [self databasePath:NSStringFromSelector(_cmd)];
|
|
|
|
YapDatabaseViewOptions *options = [[YapDatabaseViewOptions alloc] init];
|
|
options.isPersistent = YES;
|
|
|
|
[self _testViewPopulation_withPath:databasePath options:options];
|
|
}
|
|
|
|
- (void)testViewPopulation_nonPersistent
|
|
{
|
|
NSString *databasePath = [self databasePath:NSStringFromSelector(_cmd)];
|
|
|
|
YapDatabaseViewOptions *options = [[YapDatabaseViewOptions alloc] init];
|
|
options.isPersistent = NO;
|
|
|
|
[self _testViewPopulation_withPath:databasePath options:options];
|
|
}
|
|
|
|
- (void)_testViewPopulation_withPath:(NSString *)databasePath options:(YapDatabaseViewOptions *)options
|
|
{
|
|
[[NSFileManager defaultManager] removeItemAtPath:databasePath error:NULL];
|
|
YapDatabase *database = [[YapDatabase alloc] initWithPath:databasePath];
|
|
|
|
XCTAssertNotNil(database, @"Oops");
|
|
|
|
YapDatabaseConnection *connection1 = [database newConnection];
|
|
YapDatabaseConnection *connection2 = [database newConnection];
|
|
|
|
YapDatabaseViewGrouping *grouping = [YapDatabaseViewGrouping withKeyBlock:
|
|
^NSString *(YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key)
|
|
{
|
|
return @"";
|
|
}];
|
|
|
|
YapDatabaseViewSorting *sorting = [YapDatabaseViewSorting withObjectBlock:
|
|
^(YapDatabaseReadTransaction *transaction, NSString *group,
|
|
NSString *collection1, NSString *key1, id obj1,
|
|
NSString *collection2, NSString *key2, id obj2)
|
|
{
|
|
__unsafe_unretained NSString *object1 = (NSString *)obj1;
|
|
__unsafe_unretained NSString *object2 = (NSString *)obj2;
|
|
|
|
return [object1 compare:object2 options:NSNumericSearch];
|
|
}];
|
|
|
|
YapDatabaseAutoView *databaseView =
|
|
[[YapDatabaseAutoView alloc] initWithGrouping:grouping
|
|
sorting:sorting
|
|
versionTag:@"1"
|
|
options:options];
|
|
|
|
// Without registering the view,
|
|
// add a bunch of keys to the database.
|
|
|
|
[connection1 readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
|
|
|
for (int i = 0; i < 150; i++)
|
|
{
|
|
NSString *key = [NSString stringWithFormat:@"key%d", i];
|
|
NSString *obj = [NSString stringWithFormat:@"object%d", i];
|
|
|
|
[transaction setObject:obj forKey:key inCollection:nil];
|
|
}
|
|
}];
|
|
|
|
// And NOW register the view
|
|
|
|
BOOL registerResult = [database registerExtension:databaseView withName:@"order"];
|
|
|
|
XCTAssertTrue(registerResult, @"Failure registering extension");
|
|
|
|
// Make sure both connections can see the view now
|
|
|
|
[connection1 readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
for (int i = 0; i < 150; i++)
|
|
{
|
|
NSString *expectedKey = [NSString stringWithFormat:@"key%d", i];
|
|
|
|
NSString *fetchedKey = [[transaction ext:@"order"] keyAtIndex:i inGroup:@""];
|
|
|
|
XCTAssertTrue([expectedKey isEqualToString:fetchedKey],
|
|
@"Key mismatch: expected(%@) fetched(%@)", expectedKey, fetchedKey);
|
|
}
|
|
}];
|
|
|
|
[connection2 readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
for (int i = 0; i < 150; i++)
|
|
{
|
|
NSString *expectedKey = [NSString stringWithFormat:@"key%d", i];
|
|
|
|
NSString *fetchedKey = [[transaction ext:@"order"] keyAtIndex:i inGroup:@""];
|
|
|
|
XCTAssertTrue([expectedKey isEqualToString:fetchedKey],
|
|
@"Key mismatch: expected(%@) fetched(%@)", expectedKey, fetchedKey);
|
|
}
|
|
}];
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
#pragma mark -
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
- (void)testViewPopulation_skipInitialViewPopulation_persistent
|
|
{
|
|
NSString *databasePath = [self databasePath:NSStringFromSelector(_cmd)];
|
|
|
|
YapDatabaseViewOptions *options = [[YapDatabaseViewOptions alloc] init];
|
|
options.isPersistent = YES;
|
|
options.skipInitialViewPopulation = YES;
|
|
|
|
[self _testViewPopulation_skipInitialViewPopulation_withPath:databasePath options:options];
|
|
}
|
|
|
|
- (void)testViewPopulation_skipInitialViewPopulation_nonPersistent
|
|
{
|
|
NSString *databasePath = [self databasePath:NSStringFromSelector(_cmd)];
|
|
|
|
YapDatabaseViewOptions *options = [[YapDatabaseViewOptions alloc] init];
|
|
options.isPersistent = NO;
|
|
options.skipInitialViewPopulation = YES;
|
|
|
|
[self _testViewPopulation_skipInitialViewPopulation_withPath:databasePath options:options];
|
|
}
|
|
|
|
- (void)testViewPopulation_notSkipInitialViewPopulation_persistent
|
|
{
|
|
NSString *databasePath = [self databasePath:NSStringFromSelector(_cmd)];
|
|
|
|
YapDatabaseViewOptions *options = [[YapDatabaseViewOptions alloc] init];
|
|
options.isPersistent = YES;
|
|
options.skipInitialViewPopulation = NO;
|
|
|
|
[self _testViewPopulation_skipInitialViewPopulation_withPath:databasePath options:options];
|
|
}
|
|
|
|
- (void)testViewPopulation_notSkipInitialViewPopulation_nonPersistent
|
|
{
|
|
NSString *databasePath = [self databasePath:NSStringFromSelector(_cmd)];
|
|
|
|
YapDatabaseViewOptions *options = [[YapDatabaseViewOptions alloc] init];
|
|
options.isPersistent = NO;
|
|
options.skipInitialViewPopulation = NO;
|
|
|
|
[self _testViewPopulation_skipInitialViewPopulation_withPath:databasePath options:options];
|
|
}
|
|
|
|
- (void)_testViewPopulation_skipInitialViewPopulation_withPath:(NSString *)databasePath options:(YapDatabaseViewOptions *)options
|
|
{
|
|
[[NSFileManager defaultManager] removeItemAtPath:databasePath error:NULL];
|
|
YapDatabase *database = [[YapDatabase alloc] initWithPath:databasePath];
|
|
|
|
XCTAssertNotNil(database, @"Oops");
|
|
|
|
YapDatabaseConnection *connection1 = [database newConnection];
|
|
YapDatabaseConnection *connection2 = [database newConnection];
|
|
|
|
YapDatabaseViewGrouping *grouping = [YapDatabaseViewGrouping withKeyBlock:
|
|
^NSString *(YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key)
|
|
{
|
|
return @"";
|
|
}];
|
|
|
|
YapDatabaseViewSorting *sorting = [YapDatabaseViewSorting withObjectBlock:
|
|
^(YapDatabaseReadTransaction *transaction, NSString *group,
|
|
NSString *collection1, NSString *key1, id obj1,
|
|
NSString *collection2, NSString *key2, id obj2)
|
|
{
|
|
__unsafe_unretained NSString *object1 = (NSString *)obj1;
|
|
__unsafe_unretained NSString *object2 = (NSString *)obj2;
|
|
|
|
return [object1 compare:object2 options:NSNumericSearch];
|
|
}];
|
|
|
|
YapDatabaseAutoView *databaseView =
|
|
[[YapDatabaseAutoView alloc] initWithGrouping:grouping
|
|
sorting:sorting
|
|
versionTag:@"1"
|
|
options:options];
|
|
|
|
// Without registering the view,
|
|
// add a bunch of keys to the database.
|
|
|
|
[connection1 readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
|
|
|
for (int i = 0; i < 150; i++)
|
|
{
|
|
NSString *key = [NSString stringWithFormat:@"key%d", i];
|
|
NSString *obj = [NSString stringWithFormat:@"object%d", i];
|
|
|
|
[transaction setObject:obj forKey:key inCollection:nil];
|
|
}
|
|
}];
|
|
|
|
// And NOW register the view
|
|
|
|
BOOL registerResult = [database registerExtension:databaseView withName:@"order"];
|
|
|
|
XCTAssertTrue(registerResult, @"Failure registering extension");
|
|
|
|
// Make sure both connections can see the view now
|
|
|
|
[connection1 readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
NSUInteger orderCount = [[transaction ext:@"order"] numberOfItemsInGroup:@""];
|
|
if (options.skipInitialViewPopulation) {
|
|
XCTAssertTrue(orderCount == 0, @"Bad count in view. Expected 0, got %d", (int)orderCount);
|
|
} else {
|
|
XCTAssertTrue(orderCount == 150, @"Bad count in view. Expected 0, got %d", (int)orderCount);
|
|
}
|
|
}];
|
|
|
|
[connection2 readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
NSUInteger orderCount = [[transaction ext:@"order"] numberOfItemsInGroup:@""];
|
|
if (options.skipInitialViewPopulation) {
|
|
XCTAssertTrue(orderCount == 0, @"Bad count in view. Expected 0, got %d", (int)orderCount);
|
|
} else {
|
|
XCTAssertTrue(orderCount == 150, @"Bad count in view. Expected 0, got %d", (int)orderCount);
|
|
}
|
|
}];
|
|
|
|
connection1 = nil;
|
|
connection2 = nil;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
#pragma mark -
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
- (void)testMutationDuringEnumerationProtection_persistent
|
|
{
|
|
NSString *databasePath = [self databasePath:NSStringFromSelector(_cmd)];
|
|
|
|
YapDatabaseViewOptions *options = [[YapDatabaseViewOptions alloc] init];
|
|
options.isPersistent = YES;
|
|
|
|
[self _testMutationDuringEnumerationProtection_withPath:databasePath options:options];
|
|
}
|
|
|
|
- (void)testMutationDuringEnumerationProtection_nonPersistent
|
|
{
|
|
NSString *databasePath = [self databasePath:NSStringFromSelector(_cmd)];
|
|
|
|
YapDatabaseViewOptions *options = [[YapDatabaseViewOptions alloc] init];
|
|
options.isPersistent = NO;
|
|
|
|
[self _testMutationDuringEnumerationProtection_withPath:databasePath options:options];
|
|
}
|
|
|
|
- (void)_testMutationDuringEnumerationProtection_withPath:(NSString *)databasePath
|
|
options:(YapDatabaseViewOptions *)options
|
|
{
|
|
[[NSFileManager defaultManager] removeItemAtPath:databasePath error:NULL];
|
|
YapDatabase *database = [[YapDatabase alloc] initWithPath:databasePath];
|
|
|
|
XCTAssertNotNil(database, @"Oops");
|
|
|
|
YapDatabaseConnection *connection = [database newConnection];
|
|
|
|
YapDatabaseViewGrouping *grouping = [YapDatabaseViewGrouping withKeyBlock:
|
|
^NSString *(YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key)
|
|
{
|
|
if ([key hasPrefix:@"key"])
|
|
return @"default-group";
|
|
else
|
|
return @"different-group";
|
|
}];
|
|
|
|
YapDatabaseViewSorting *sorting = [YapDatabaseViewSorting withObjectBlock:
|
|
^(YapDatabaseReadTransaction *transaction, NSString *group,
|
|
NSString *collection1, NSString *key1, id obj1,
|
|
NSString *collection2, NSString *key2, id obj2)
|
|
{
|
|
__unsafe_unretained NSString *object1 = (NSString *)obj1;
|
|
__unsafe_unretained NSString *object2 = (NSString *)obj2;
|
|
|
|
return [object1 compare:object2 options:NSNumericSearch];
|
|
}];
|
|
|
|
YapDatabaseAutoView *databaseView =
|
|
[[YapDatabaseAutoView alloc] initWithGrouping:grouping
|
|
sorting:sorting
|
|
versionTag:@"1"
|
|
options:options];
|
|
|
|
BOOL registerResult = [database registerExtension:databaseView withName:@"order"];
|
|
|
|
XCTAssertTrue(registerResult, @"Failure registering extension");
|
|
|
|
// Add a bunch of keys to the database.
|
|
|
|
[connection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
|
|
|
for (int i = 0; i < 100; i++)
|
|
{
|
|
NSString *key = [NSString stringWithFormat:@"key-%d", i];
|
|
NSString *obj = [NSString stringWithFormat:@"obj-%d", i];
|
|
|
|
[transaction setObject:obj forKey:key inCollection:nil];
|
|
}
|
|
}];
|
|
|
|
[connection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
|
|
|
// enumerateKeysInGroup:usingBlock:
|
|
|
|
__block int i = 200;
|
|
__block int j = 0;
|
|
__block int k = 0;
|
|
|
|
dispatch_block_t exceptionBlock1A = ^{
|
|
|
|
[[transaction ext:@"order"]
|
|
enumerateKeysInGroup:@"default-group"
|
|
usingBlock:^(NSString *collection, NSString *key, NSUInteger index, BOOL *stop) {
|
|
|
|
[transaction setObject:[NSString stringWithFormat:@"obj-%d", i]
|
|
forKey:[NSString stringWithFormat:@"key-%d", i]
|
|
inCollection:nil];
|
|
i++;
|
|
// Missing stop; Will cause exception.
|
|
}];
|
|
};
|
|
dispatch_block_t exceptionBlock1B = ^{
|
|
|
|
[[transaction ext:@"order"]
|
|
enumerateKeysInGroup:@"default-group"
|
|
usingBlock:^(NSString *collection, NSString *key, NSUInteger index, BOOL *stop) {
|
|
|
|
[transaction removeObjectForKey:[NSString stringWithFormat:@"key-%d", j] inCollection:nil];
|
|
j++;
|
|
// Missing stop; Will cause exception.
|
|
}];
|
|
};
|
|
dispatch_block_t noExceptionBlock1A = ^{
|
|
|
|
[[transaction ext:@"order"]
|
|
enumerateKeysInGroup:@"default-group"
|
|
usingBlock:^(NSString *collection, NSString *key, NSUInteger index, BOOL *stop) {
|
|
|
|
[transaction setObject:[NSString stringWithFormat:@"obj-%d", i]
|
|
forKey:[NSString stringWithFormat:@"key-%d", i]
|
|
inCollection:nil];
|
|
i++;
|
|
*stop = YES;
|
|
}];
|
|
};
|
|
dispatch_block_t noExceptionBlock1B = ^{
|
|
|
|
[[transaction ext:@"order"]
|
|
enumerateKeysInGroup:@"default-group"
|
|
usingBlock:^(NSString *collection, NSString *key, NSUInteger index, BOOL *stop) {
|
|
|
|
[transaction removeObjectForKey:[NSString stringWithFormat:@"key-%d", j] inCollection:nil];
|
|
j++;
|
|
*stop = YES;
|
|
}];
|
|
};
|
|
dispatch_block_t noExceptionBlock1C = ^{
|
|
|
|
[[transaction ext:@"order"]
|
|
enumerateKeysInGroup:@"default-group"
|
|
usingBlock:^(NSString *collection, NSString *key, NSUInteger index, BOOL *stop) {
|
|
|
|
[transaction setObject:[NSString stringWithFormat:@"diff-obj-%d", k]
|
|
forKey:[NSString stringWithFormat:@"diff-key-%d", k]
|
|
inCollection:nil];
|
|
k++;
|
|
// No stop; Shouldn't affect default-group.
|
|
}];
|
|
};
|
|
|
|
XCTAssertThrows(exceptionBlock1A(), @"Should throw exception");
|
|
XCTAssertThrows(exceptionBlock1B(), @"Should throw exception");
|
|
XCTAssertNoThrow(noExceptionBlock1A(), @"Should NOT throw exception. Proper use of stop.");
|
|
XCTAssertNoThrow(noExceptionBlock1B(), @"Should NOT throw exception. Proper use of stop.");
|
|
XCTAssertNoThrow(noExceptionBlock1C(), @"Should NOT throw exception. Mutating different group.");
|
|
|
|
// enumerateKeysInGroup:withOptions:usingBlock:
|
|
|
|
dispatch_block_t exceptionBlock2A = ^{
|
|
|
|
[[transaction ext:@"order"]
|
|
enumerateKeysInGroup:@"default-group"
|
|
withOptions:NSEnumerationReverse
|
|
usingBlock:^(NSString *collection, NSString *key, NSUInteger index, BOOL *stop) {
|
|
|
|
[transaction setObject:[NSString stringWithFormat:@"obj-%d", i]
|
|
forKey:[NSString stringWithFormat:@"key-%d", i]
|
|
inCollection:nil];
|
|
i++;
|
|
// Missing stop; Will cause exception.
|
|
}];
|
|
};
|
|
dispatch_block_t exceptionBlock2B = ^{
|
|
|
|
[[transaction ext:@"order"]
|
|
enumerateKeysInGroup:@"default-group"
|
|
withOptions:NSEnumerationReverse
|
|
usingBlock:^(NSString *collection, NSString *key, NSUInteger index, BOOL *stop) {
|
|
|
|
[transaction removeObjectForKey:[NSString stringWithFormat:@"key-%d", j] inCollection:nil];
|
|
j++;
|
|
// Missing stop; Will cause exception.
|
|
}];
|
|
};
|
|
dispatch_block_t noExceptionBlock2A = ^{
|
|
|
|
[[transaction ext:@"order"]
|
|
enumerateKeysInGroup:@"default-group"
|
|
withOptions:NSEnumerationReverse
|
|
usingBlock:^(NSString *collection, NSString *key, NSUInteger index, BOOL *stop) {
|
|
|
|
[transaction setObject:[NSString stringWithFormat:@"obj-%d", i]
|
|
forKey:[NSString stringWithFormat:@"key-%d", i]
|
|
inCollection:nil];
|
|
i++;
|
|
*stop = YES;
|
|
}];
|
|
};
|
|
dispatch_block_t noExceptionBlock2B = ^{
|
|
|
|
[[transaction ext:@"order"]
|
|
enumerateKeysInGroup:@"default-group"
|
|
withOptions:NSEnumerationReverse
|
|
usingBlock:^(NSString *collection, NSString *key, NSUInteger index, BOOL *stop) {
|
|
|
|
[transaction removeObjectForKey:[NSString stringWithFormat:@"key-%d", j] inCollection:nil];
|
|
j++;
|
|
*stop = YES;
|
|
}];
|
|
};
|
|
dispatch_block_t noExceptionBlock2C = ^{
|
|
|
|
[[transaction ext:@"order"]
|
|
enumerateKeysInGroup:@"default-group"
|
|
withOptions:NSEnumerationReverse
|
|
usingBlock:^(NSString *collection, NSString *key, NSUInteger index, BOOL *stop) {
|
|
|
|
[transaction setObject:[NSString stringWithFormat:@"diff-obj-%d", k]
|
|
forKey:[NSString stringWithFormat:@"diff-key-%d", k]
|
|
inCollection:nil];
|
|
k++;
|
|
// No stop; Shouldn't affect default-group.
|
|
}];
|
|
};
|
|
|
|
XCTAssertThrows(exceptionBlock2A(), @"Should throw exception");
|
|
XCTAssertThrows(exceptionBlock2B(), @"Should throw exception");
|
|
XCTAssertNoThrow(noExceptionBlock2A(), @"Should NOT throw exception. Proper use of stop.");
|
|
XCTAssertNoThrow(noExceptionBlock2B(), @"Should NOT throw exception. Proper use of stop.");
|
|
XCTAssertNoThrow(noExceptionBlock2C(), @"Should NOT throw exception. Mutating different group.");
|
|
|
|
// enumerateKeysInGroup:withOptions:range:usingBlock:
|
|
|
|
dispatch_block_t exceptionBlock3A = ^{
|
|
|
|
[[transaction ext:@"order"]
|
|
enumerateKeysInGroup:@"default-group"
|
|
withOptions:0
|
|
range:NSMakeRange(0, 10)
|
|
usingBlock:^(NSString *collection, NSString *key, NSUInteger index, BOOL *stop) {
|
|
|
|
[transaction setObject:[NSString stringWithFormat:@"obj-%d", i]
|
|
forKey:[NSString stringWithFormat:@"key-%d", i]
|
|
inCollection:nil];
|
|
i++;
|
|
// Missing stop; Will cause exception.
|
|
}];
|
|
};
|
|
dispatch_block_t exceptionBlock3B = ^{
|
|
|
|
[[transaction ext:@"order"]
|
|
enumerateKeysInGroup:@"default-group"
|
|
withOptions:0
|
|
range:NSMakeRange(0, 10)
|
|
usingBlock:^(NSString *collection, NSString *key, NSUInteger index, BOOL *stop) {
|
|
|
|
[transaction removeObjectForKey:[NSString stringWithFormat:@"key-%d", j] inCollection:nil];
|
|
j++;
|
|
// Missing stop; Will cause exception.
|
|
}];
|
|
};
|
|
dispatch_block_t noExceptionBlock3A = ^{
|
|
|
|
[[transaction ext:@"order"]
|
|
enumerateKeysInGroup:@"default-group"
|
|
withOptions:0
|
|
range:NSMakeRange(0, 10)
|
|
usingBlock:^(NSString *collection, NSString *key, NSUInteger index, BOOL *stop) {
|
|
|
|
[transaction setObject:[NSString stringWithFormat:@"obj-%d", i]
|
|
forKey:[NSString stringWithFormat:@"key-%d", i]
|
|
inCollection:nil];
|
|
i++;
|
|
*stop = YES;
|
|
}];
|
|
};
|
|
dispatch_block_t noExceptionBlock3B = ^{
|
|
|
|
[[transaction ext:@"order"]
|
|
enumerateKeysInGroup:@"default-group"
|
|
withOptions:0
|
|
range:NSMakeRange(0, 10)
|
|
usingBlock:^(NSString *collection, NSString *key, NSUInteger index, BOOL *stop) {
|
|
|
|
[transaction removeObjectForKey:[NSString stringWithFormat:@"key-%d", j] inCollection:nil];
|
|
j++;
|
|
*stop = YES;
|
|
}];
|
|
};
|
|
dispatch_block_t noExceptionBlock3C = ^{
|
|
|
|
[[transaction ext:@"order"]
|
|
enumerateKeysInGroup:@"default-group"
|
|
withOptions:0
|
|
range:NSMakeRange(0, 10)
|
|
usingBlock:^(NSString *collection, NSString *key, NSUInteger index, BOOL *stop) {
|
|
|
|
[transaction setObject:[NSString stringWithFormat:@"diff-obj-%d", k]
|
|
forKey:[NSString stringWithFormat:@"diff-key-%d", k]
|
|
inCollection:nil];
|
|
k++;
|
|
// No stop; Shouldn't affect default-group.
|
|
}];
|
|
};
|
|
|
|
XCTAssertThrows(exceptionBlock3A(), @"Should throw exception");
|
|
XCTAssertThrows(exceptionBlock3B(), @"Should throw exception");
|
|
XCTAssertNoThrow(noExceptionBlock3A(), @"Should NOT throw exception. Proper use of stop.");
|
|
XCTAssertNoThrow(noExceptionBlock3B(), @"Should NOT throw exception. Proper use of stop.");
|
|
XCTAssertNoThrow(noExceptionBlock3C(), @"Should NOT throw exception. Mutating different group.");
|
|
}];
|
|
|
|
[connection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
|
|
|
// Test removeAll
|
|
|
|
for (int i = 0; i < 100; i++)
|
|
{
|
|
NSString *key = [NSString stringWithFormat:@"key-%d", i];
|
|
NSString *obj = [NSString stringWithFormat:@"obj-%d", i];
|
|
|
|
[transaction setObject:obj forKey:key inCollection:nil];
|
|
}
|
|
|
|
dispatch_block_t exceptionBlock1 = ^{
|
|
|
|
[[transaction ext:@"order"]
|
|
enumerateKeysInGroup:@"default-group"
|
|
usingBlock:^(NSString *collection, NSString *key, NSUInteger index, BOOL *stop) {
|
|
|
|
[transaction removeAllObjectsInAllCollections];
|
|
// Missing stop; Will cause exception.
|
|
}];
|
|
};
|
|
|
|
XCTAssertThrows(exceptionBlock1(), @"Should throw exception");
|
|
|
|
for (int i = 0; i < 100; i++)
|
|
{
|
|
NSString *key = [NSString stringWithFormat:@"key-%d", i];
|
|
NSString *obj = [NSString stringWithFormat:@"obj-%d", i];
|
|
|
|
[transaction setObject:obj forKey:key inCollection:nil];
|
|
}
|
|
|
|
dispatch_block_t noExceptionBlock1 = ^{
|
|
|
|
[[transaction ext:@"order"]
|
|
enumerateKeysInGroup:@"default-group"
|
|
usingBlock:^(NSString *collection, NSString *key, NSUInteger index, BOOL *stop) {
|
|
|
|
[transaction removeAllObjectsInAllCollections];
|
|
*stop = YES;
|
|
}];
|
|
};
|
|
|
|
XCTAssertNoThrow(noExceptionBlock1(), @"Should NOT throw exception. Proper use of stop.");
|
|
}];
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
#pragma mark -
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
- (void)testDropView_persistent
|
|
{
|
|
NSString *databasePath = [self databasePath:NSStringFromSelector(_cmd)];
|
|
|
|
YapDatabaseViewOptions *options = [[YapDatabaseViewOptions alloc] init];
|
|
options.isPersistent = YES;
|
|
|
|
[self _testDropView_withPath:databasePath options:options];
|
|
}
|
|
|
|
- (void)testDropView_nonPersistent
|
|
{
|
|
NSString *databasePath = [self databasePath:NSStringFromSelector(_cmd)];
|
|
|
|
YapDatabaseViewOptions *options = [[YapDatabaseViewOptions alloc] init];
|
|
options.isPersistent = NO;
|
|
|
|
[self _testDropView_withPath:databasePath options:options];
|
|
}
|
|
|
|
- (void)_testDropView_withPath:(NSString *)databasePath options:(YapDatabaseViewOptions *)options
|
|
{
|
|
[[NSFileManager defaultManager] removeItemAtPath:databasePath error:NULL];
|
|
YapDatabase *database = [[YapDatabase alloc] initWithPath:databasePath];
|
|
|
|
XCTAssertNotNil(database, @"Oops");
|
|
|
|
YapDatabaseConnection *connection = [database newConnection];
|
|
|
|
YapDatabaseViewGrouping *grouping = [YapDatabaseViewGrouping withKeyBlock:
|
|
^NSString *(YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key)
|
|
{
|
|
return @"";
|
|
}];
|
|
|
|
YapDatabaseViewSorting *sorting = [YapDatabaseViewSorting withObjectBlock:
|
|
^(YapDatabaseReadTransaction *transaction, NSString *group,
|
|
NSString *collection1, NSString *key1, id obj1,
|
|
NSString *collection2, NSString *key2, id obj2)
|
|
{
|
|
__unsafe_unretained NSString *object1 = (NSString *)obj1;
|
|
__unsafe_unretained NSString *object2 = (NSString *)obj2;
|
|
|
|
return [object1 compare:object2 options:NSNumericSearch];
|
|
}];
|
|
|
|
YapDatabaseAutoView *databaseView =
|
|
[[YapDatabaseAutoView alloc] initWithGrouping:grouping
|
|
sorting:sorting
|
|
versionTag:@"1"
|
|
options:options];
|
|
|
|
BOOL registerResult = [database registerExtension:databaseView withName:@"order"];
|
|
|
|
XCTAssertTrue(registerResult, @"Failure registering extension");
|
|
|
|
// Add a bunch of keys to the database & to the view
|
|
|
|
NSUInteger count = 100;
|
|
|
|
[connection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
|
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
NSString *key = [NSString stringWithFormat:@"key-%d", i];
|
|
NSString *obj = [NSString stringWithFormat:@"obj-%d", i];
|
|
|
|
[transaction setObject:obj forKey:key inCollection:nil];
|
|
}
|
|
}];
|
|
|
|
// Make sure the view is populated
|
|
|
|
[connection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfItemsInGroup:@""] == count, @"View count is wrong");
|
|
}];
|
|
|
|
// Now drop the view
|
|
|
|
[database unregisterExtensionWithName:@"order"];
|
|
|
|
// Now make sure it's gone
|
|
|
|
[connection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
XCTAssertNil([transaction ext:@"order"], @"Expected nil extension");
|
|
}];
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
#pragma mark -
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
- (void)testFind_persistent
|
|
{
|
|
NSString *databasePath = [self databasePath:NSStringFromSelector(_cmd)];
|
|
|
|
YapDatabaseViewOptions *options = [[YapDatabaseViewOptions alloc] init];
|
|
options.isPersistent = YES;
|
|
|
|
[self _testFind_withPath:databasePath options:options];
|
|
}
|
|
|
|
- (void)testFind_nonPersistent
|
|
{
|
|
NSString *databasePath = [self databasePath:NSStringFromSelector(_cmd)];
|
|
|
|
YapDatabaseViewOptions *options = [[YapDatabaseViewOptions alloc] init];
|
|
options.isPersistent = NO;
|
|
|
|
[self _testFind_withPath:databasePath options:options];
|
|
}
|
|
|
|
- (void)_testFind_withPath:(NSString *)databasePath options:(YapDatabaseViewOptions *)options
|
|
{
|
|
[[NSFileManager defaultManager] removeItemAtPath:databasePath error:NULL];
|
|
YapDatabase *database = [[YapDatabase alloc] initWithPath:databasePath];
|
|
|
|
XCTAssertNotNil(database, @"Oops");
|
|
|
|
YapDatabaseConnection *connection = [database newConnection];
|
|
|
|
YapDatabaseViewGrouping *grouping = [YapDatabaseViewGrouping withKeyBlock:
|
|
^NSString *(YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key)
|
|
{
|
|
return @"";
|
|
}];
|
|
|
|
YapDatabaseViewSorting *sorting = [YapDatabaseViewSorting withObjectBlock:
|
|
^(YapDatabaseReadTransaction *transaction, NSString *group,
|
|
NSString *collection1, NSString *key1, id obj1,
|
|
NSString *collection2, NSString *key2, id obj2)
|
|
{
|
|
__unsafe_unretained NSNumber *number1 = (NSNumber *)obj1;
|
|
__unsafe_unretained NSNumber *number2 = (NSNumber *)obj2;
|
|
|
|
return [number1 compare:number2];
|
|
}];
|
|
|
|
YapDatabaseAutoView *databaseView =
|
|
[[YapDatabaseAutoView alloc] initWithGrouping:grouping
|
|
sorting:sorting
|
|
versionTag:@"1"
|
|
options:options];
|
|
|
|
BOOL registerResult = [database registerExtension:databaseView withName:@"order"];
|
|
|
|
XCTAssertTrue(registerResult, @"Failure registering extension");
|
|
|
|
// Add a bunch of values to the database & to the view
|
|
|
|
NSUInteger count = 100;
|
|
|
|
[connection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
|
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
NSString *key = [NSString stringWithFormat:@"key-%d", i];
|
|
NSNumber *num = [NSNumber numberWithInt:i];
|
|
|
|
[transaction setObject:num forKey:key inCollection:nil];
|
|
}
|
|
}];
|
|
|
|
// Make sure the view is populated
|
|
|
|
[connection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfItemsInGroup:@""] == count, @"View count is wrong");
|
|
}];
|
|
|
|
// Now test finding different ranges
|
|
|
|
[connection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
int min = 0;
|
|
int max = 5;
|
|
|
|
YapDatabaseViewFind *find = [YapDatabaseViewFind withObjectBlock:
|
|
^(NSString *collection, NSString *key, id object)
|
|
{
|
|
int value = [(NSNumber *)object intValue];
|
|
|
|
if (value < min)
|
|
return NSOrderedAscending;
|
|
if (value >= max)
|
|
return NSOrderedDescending;
|
|
|
|
return NSOrderedSame;
|
|
}];
|
|
|
|
NSRange range = [[transaction ext:@"order"] findRangeInGroup:@"" using:find];
|
|
|
|
NSUInteger location = (max > min) ? min : NSNotFound;
|
|
NSUInteger length = (max > min) ? (max - min) : 0;
|
|
|
|
XCTAssertTrue(range.location == location, @"Bad range location: %d", (int)range.location);
|
|
XCTAssertTrue(range.length == length, @"Bad range length: %d", (int)range.length);
|
|
}];
|
|
|
|
[connection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
int min = 11;
|
|
int max = 54;
|
|
|
|
YapDatabaseViewFind *find = [YapDatabaseViewFind withObjectBlock:
|
|
^(NSString *collection, NSString *key, id object)
|
|
{
|
|
int value = [(NSNumber *)object intValue];
|
|
|
|
if (value < min)
|
|
return NSOrderedAscending;
|
|
if (value >= max)
|
|
return NSOrderedDescending;
|
|
|
|
return NSOrderedSame;
|
|
}];
|
|
|
|
NSRange range = [[transaction ext:@"order"] findRangeInGroup:@"" using:find];
|
|
|
|
NSUInteger location = (max > min) ? min : NSNotFound;
|
|
NSUInteger length = (max > min) ? (max - min) : 0;
|
|
|
|
XCTAssertTrue(range.location == location, @"Bad range location: %d", (int)range.location);
|
|
XCTAssertTrue(range.length == length, @"Bad range length: %d", (int)range.length);
|
|
}];
|
|
|
|
[connection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
int min = 50;
|
|
int max = 100;
|
|
|
|
YapDatabaseViewFind *find = [YapDatabaseViewFind withObjectBlock:
|
|
^(NSString *collection, NSString *key, id object)
|
|
{
|
|
int value = [(NSNumber *)object intValue];
|
|
|
|
if (value < min)
|
|
return NSOrderedAscending;
|
|
if (value >= max)
|
|
return NSOrderedDescending;
|
|
|
|
return NSOrderedSame;
|
|
}];
|
|
|
|
NSRange range = [[transaction ext:@"order"] findRangeInGroup:@"" using:find];
|
|
|
|
NSUInteger location = (max > min) ? min : NSNotFound;
|
|
NSUInteger length = (max > min) ? (max - min) : 0;
|
|
|
|
XCTAssertTrue(range.location == location, @"Bad range location: %d", (int)range.location);
|
|
XCTAssertTrue(range.length == length, @"Bad range length: %d", (int)range.length);
|
|
}];
|
|
|
|
[connection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
int min = 40;
|
|
int max = 40;
|
|
|
|
YapDatabaseViewFind *find = [YapDatabaseViewFind withObjectBlock:
|
|
^(NSString *collection, NSString *key, id object)
|
|
{
|
|
int value = [(NSNumber *)object intValue];
|
|
|
|
if (value < min)
|
|
return NSOrderedAscending;
|
|
if (value >= max)
|
|
return NSOrderedDescending;
|
|
|
|
return NSOrderedSame;
|
|
}];
|
|
|
|
NSRange range = [[transaction ext:@"order"] findRangeInGroup:@"" using:find];
|
|
|
|
NSUInteger location = (max > min) ? min : NSNotFound;
|
|
NSUInteger length = (max > min) ? (max - min) : 0;
|
|
|
|
XCTAssertTrue(range.location == location, @"Bad range location: %d", (int)range.location);
|
|
XCTAssertTrue(range.length == length, @"Bad range length: %d", (int)range.length);
|
|
}];
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
#pragma mark -
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
- (void)testChangeBlocks_persistent
|
|
{
|
|
NSString *databasePath = [self databasePath:NSStringFromSelector(_cmd)];
|
|
|
|
YapDatabaseViewOptions *options = [[YapDatabaseViewOptions alloc] init];
|
|
options.isPersistent = YES;
|
|
|
|
[self _testChangeBlocks_withPath:databasePath options:options];
|
|
}
|
|
|
|
- (void)testChangeBlocks_nonPersistent
|
|
{
|
|
NSString *databasePath = [self databasePath:NSStringFromSelector(_cmd)];
|
|
|
|
YapDatabaseViewOptions *options = [[YapDatabaseViewOptions alloc] init];
|
|
options.isPersistent = NO;
|
|
|
|
[self _testChangeBlocks_withPath:databasePath options:options];
|
|
}
|
|
|
|
- (void)_testChangeBlocks_withPath:(NSString *)databasePath options:(YapDatabaseViewOptions *)options
|
|
{
|
|
[[NSFileManager defaultManager] removeItemAtPath:databasePath error:NULL];
|
|
YapDatabase *database = [[YapDatabase alloc] initWithPath:databasePath];
|
|
|
|
XCTAssertNotNil(database, @"Oops");
|
|
|
|
YapDatabaseConnection *connection1 = [database newConnection];
|
|
YapDatabaseConnection *connection2 = [database newConnection];
|
|
|
|
YapDatabaseViewGrouping *grouping = [YapDatabaseViewGrouping withObjectBlock:
|
|
^NSString *(YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key, id obj)
|
|
{
|
|
__unsafe_unretained NSNumber *number = (NSNumber *)obj;
|
|
|
|
if ([number intValue] % 2 == 0)
|
|
return @"";
|
|
else
|
|
return nil;
|
|
}];
|
|
|
|
YapDatabaseViewSorting *sorting = [YapDatabaseViewSorting withObjectBlock:
|
|
^(YapDatabaseReadTransaction *transaction, NSString *group,
|
|
NSString *collection1, NSString *key1, id obj1,
|
|
NSString *collection2, NSString *key2, id obj2)
|
|
{
|
|
__unsafe_unretained NSNumber *number1 = (NSNumber *)obj1;
|
|
__unsafe_unretained NSNumber *number2 = (NSNumber *)obj2;
|
|
|
|
return [number1 compare:number2];
|
|
}];
|
|
|
|
YapDatabaseAutoView *databaseView =
|
|
[[YapDatabaseAutoView alloc] initWithGrouping:grouping
|
|
sorting:sorting
|
|
versionTag:@"1"
|
|
options:options];
|
|
|
|
BOOL registerResult = [database registerExtension:databaseView withName:@"order"];
|
|
|
|
XCTAssertTrue(registerResult, @"Failure registering extension");
|
|
|
|
// Add a bunch of values to the database & to the view
|
|
|
|
NSUInteger count = 10;
|
|
|
|
[connection1 readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
|
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
NSString *key = [NSString stringWithFormat:@"key-%d", i];
|
|
NSNumber *num = [NSNumber numberWithInt:i];
|
|
|
|
[transaction setObject:num forKey:key inCollection:nil];
|
|
}
|
|
}];
|
|
|
|
// Make sure the view is populated
|
|
|
|
[connection1 readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
XCTAssertTrue([[transaction ext:@"order"] numberOfItemsInGroup:@""] == 5, @"View count is wrong");
|
|
}];
|
|
|
|
// Now change the groupingBlock
|
|
|
|
YapDatabaseViewMappings *mappings = [YapDatabaseViewMappings mappingsWithGroups:@[ @"" ] view:@"order"];
|
|
|
|
[connection2 beginLongLivedReadTransaction];
|
|
[connection2 readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
[mappings updateWithTransaction:transaction];
|
|
}];
|
|
|
|
YapDatabaseViewGrouping *newGrouping = [YapDatabaseViewGrouping withObjectBlock:
|
|
^NSString *(YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key, id obj)
|
|
{
|
|
__unsafe_unretained NSNumber *number = (NSNumber *)obj;
|
|
|
|
if ([number intValue] % 2 == 0)
|
|
return @"";
|
|
else
|
|
return @""; // <<-- Allow odd numbers now too
|
|
}];
|
|
|
|
[connection1 readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
|
|
|
[[transaction ext:@"order"] setGrouping:newGrouping
|
|
sorting:sorting
|
|
versionTag:@"2"];
|
|
}];
|
|
|
|
NSArray *notifications =[connection2 beginLongLivedReadTransaction];
|
|
|
|
NSArray *sectionChanges = nil;
|
|
NSArray *rowChanges = nil;
|
|
|
|
[[connection2 ext:@"order"] getSectionChanges:§ionChanges
|
|
rowChanges:&rowChanges
|
|
forNotifications:notifications
|
|
withMappings:mappings];
|
|
|
|
XCTAssertTrue([sectionChanges count] == 0, @"Bad count");
|
|
XCTAssertTrue([rowChanges count] == 10, @"Bad count");
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
#pragma mark -
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
- (void)testInsertAndDelete_persistent
|
|
{
|
|
NSString *databasePath = [self databasePath:NSStringFromSelector(_cmd)];
|
|
|
|
YapDatabaseViewOptions *options = [[YapDatabaseViewOptions alloc] init];
|
|
options.isPersistent = YES;
|
|
|
|
[self _testInsertAndDelete_withPath:databasePath options:options];
|
|
}
|
|
|
|
- (void)testInsertAndDelete_nonPersistent
|
|
{
|
|
NSString *databasePath = [self databasePath:NSStringFromSelector(_cmd)];
|
|
|
|
YapDatabaseViewOptions *options = [[YapDatabaseViewOptions alloc] init];
|
|
options.isPersistent = NO;
|
|
|
|
[self _testInsertAndDelete_withPath:databasePath options:options];
|
|
}
|
|
|
|
- (void)_testInsertAndDelete_withPath:(NSString *)databasePath options:(YapDatabaseViewOptions *)options
|
|
{
|
|
[[NSFileManager defaultManager] removeItemAtPath:databasePath error:NULL];
|
|
YapDatabase *database = [[YapDatabase alloc] initWithPath:databasePath];
|
|
|
|
XCTAssertNotNil(database, @"Oops");
|
|
|
|
YapDatabaseConnection *connection1 = [database newConnection];
|
|
YapDatabaseConnection *connection2 = [database newConnection];
|
|
|
|
YapDatabaseViewGrouping *grouping = [YapDatabaseViewGrouping withObjectBlock:
|
|
^NSString *(YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key, id obj)
|
|
{
|
|
return @"";
|
|
}];
|
|
|
|
YapDatabaseViewSorting *sorting = [YapDatabaseViewSorting withObjectBlock:
|
|
^(YapDatabaseReadTransaction *transaction, NSString *group,
|
|
NSString *collection1, NSString *key1, id obj1,
|
|
NSString *collection2, NSString *key2, id obj2)
|
|
{
|
|
__unsafe_unretained NSNumber *number1 = (NSNumber *)obj1;
|
|
__unsafe_unretained NSNumber *number2 = (NSNumber *)obj2;
|
|
|
|
return [number1 compare:number2];
|
|
}];
|
|
|
|
YapDatabaseAutoView *databaseView =
|
|
[[YapDatabaseAutoView alloc] initWithGrouping:grouping
|
|
sorting:sorting
|
|
versionTag:@"1"
|
|
options:options];
|
|
|
|
BOOL registerResult = [database registerExtension:databaseView withName:@"order"];
|
|
|
|
XCTAssertTrue(registerResult, @"Failure registering extension");
|
|
|
|
[connection1 readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
|
|
|
NSString *key = @"someKey";
|
|
NSString *value = @"someValue";
|
|
|
|
[transaction setObject:value forKey:key inCollection:nil];
|
|
|
|
[transaction removeObjectForKey:key inCollection:nil];
|
|
|
|
XCTAssert([[transaction ext:@"order"] numberOfItemsInGroup:@""] == 0, @"Oops");
|
|
}];
|
|
|
|
[connection1 readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
XCTAssert([[transaction ext:@"order"] numberOfItemsInGroup:@""] == 0, @"Oops");
|
|
}];
|
|
|
|
[connection2 readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
XCTAssert([[transaction ext:@"order"] numberOfItemsInGroup:@""] == 0, @"Oops");
|
|
}];
|
|
|
|
[connection1 readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
|
|
|
NSUInteger count = 10;
|
|
|
|
NSMutableArray *keys = [NSMutableArray arrayWithCapacity:count];
|
|
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
NSString *key = [NSString stringWithFormat:@"key-%d", i];
|
|
NSNumber *num = [NSNumber numberWithInt:i];
|
|
|
|
[transaction setObject:num forKey:key inCollection:nil];
|
|
[keys addObject:key];
|
|
}
|
|
|
|
[transaction removeObjectsForKeys:keys inCollection:nil];
|
|
|
|
XCTAssert([[transaction ext:@"order"] numberOfItemsInGroup:@""] == 0, @"Oops");
|
|
}];
|
|
|
|
[connection1 readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
XCTAssert([[transaction ext:@"order"] numberOfItemsInGroup:@""] == 0, @"Oops");
|
|
}];
|
|
|
|
[connection2 readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
XCTAssert([[transaction ext:@"order"] numberOfItemsInGroup:@""] == 0, @"Oops");
|
|
}];
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
#pragma mark -
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
- (void)testDoubleDelete_persistent
|
|
{
|
|
NSString *databasePath = [self databasePath:NSStringFromSelector(_cmd)];
|
|
|
|
YapDatabaseViewOptions *options = [[YapDatabaseViewOptions alloc] init];
|
|
options.isPersistent = YES;
|
|
|
|
[self _testDoubleDelete_withPath:databasePath options:options];
|
|
}
|
|
|
|
- (void)testDoubleDelete_nonPersistent
|
|
{
|
|
NSString *databasePath = [self databasePath:NSStringFromSelector(_cmd)];
|
|
|
|
YapDatabaseViewOptions *options = [[YapDatabaseViewOptions alloc] init];
|
|
options.isPersistent = NO;
|
|
|
|
[self _testDoubleDelete_withPath:databasePath options:options];
|
|
}
|
|
|
|
- (void)_testDoubleDelete_withPath:(NSString *)databasePath options:(YapDatabaseViewOptions *)options
|
|
{
|
|
[[NSFileManager defaultManager] removeItemAtPath:databasePath error:NULL];
|
|
YapDatabase *database = [[YapDatabase alloc] initWithPath:databasePath];
|
|
|
|
XCTAssertNotNil(database, @"Oops");
|
|
|
|
YapDatabaseConnection *connection1 = [database newConnection];
|
|
YapDatabaseConnection *connection2 = [database newConnection];
|
|
|
|
YapDatabaseViewGrouping *grouping = [YapDatabaseViewGrouping withObjectBlock:
|
|
^NSString *(YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key, id obj)
|
|
{
|
|
if ([obj isKindOfClass:[NSString class]])
|
|
return @"";
|
|
else
|
|
return nil;
|
|
}];
|
|
|
|
YapDatabaseViewSorting *sorting = [YapDatabaseViewSorting withObjectBlock:
|
|
^(YapDatabaseReadTransaction *transaction, NSString *group,
|
|
NSString *collection1, NSString *key1, id obj1,
|
|
NSString *collection2, NSString *key2, id obj2)
|
|
{
|
|
__unsafe_unretained NSNumber *number1 = (NSNumber *)obj1;
|
|
__unsafe_unretained NSNumber *number2 = (NSNumber *)obj2;
|
|
|
|
return [number1 compare:number2];
|
|
}];
|
|
|
|
YapDatabaseAutoView *databaseView =
|
|
[[YapDatabaseAutoView alloc] initWithGrouping:grouping
|
|
sorting:sorting
|
|
versionTag:@"1"
|
|
options:options];
|
|
|
|
BOOL registerResult = [database registerExtension:databaseView withName:@"order"];
|
|
|
|
XCTAssertTrue(registerResult, @"Failure registering extension");
|
|
|
|
NSUInteger count = 10;
|
|
NSMutableArray *keys = [NSMutableArray arrayWithCapacity:count];
|
|
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
[keys addObject:[NSString stringWithFormat:@"key-%d", i]];
|
|
}
|
|
|
|
[connection1 readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
|
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
[transaction setObject:@"someValue" forKey:keys[i] inCollection:nil];
|
|
}
|
|
}];
|
|
|
|
// Test #1
|
|
|
|
[connection1 readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
|
|
|
[transaction removeObjectForKey:keys[0] inCollection:nil]; // remove 1
|
|
[transaction removeObjectForKey:keys[0] inCollection:nil]; // remove it again
|
|
|
|
XCTAssert([[transaction ext:@"order"] numberOfItemsInGroup:@""] == (count - 1), @"Oops");
|
|
}];
|
|
|
|
[connection1 readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
XCTAssert([[transaction ext:@"order"] numberOfItemsInGroup:@""] == (count - 1), @"Oops");
|
|
}];
|
|
|
|
[connection2 readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
XCTAssert([[transaction ext:@"order"] numberOfItemsInGroup:@""] == (count - 1), @"Oops");
|
|
}];
|
|
|
|
// Test #2
|
|
|
|
[connection1 readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
|
|
|
[transaction setObject:@(0) forKey:keys[1] inCollection:nil]; // remove from view
|
|
[transaction removeObjectForKey:keys[1] inCollection:nil]; // and then remove from database
|
|
|
|
XCTAssert([[transaction ext:@"order"] numberOfItemsInGroup:@""] == (count - 2), @"Oops");
|
|
}];
|
|
|
|
[connection1 readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
XCTAssert([[transaction ext:@"order"] numberOfItemsInGroup:@""] == (count - 2), @"Oops");
|
|
}];
|
|
|
|
[connection2 readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
XCTAssert([[transaction ext:@"order"] numberOfItemsInGroup:@""] == (count - 2), @"Oops");
|
|
}];
|
|
|
|
// Test #3
|
|
|
|
[connection1 readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
|
|
|
NSArray *keysToRemove = @[ keys[2], keys[3], keys[4] ];
|
|
|
|
[transaction setObject:@(0) forKey:keys[2] inCollection:nil]; // remove from view
|
|
[transaction removeObjectsForKeys:keysToRemove inCollection:nil]; // and then remove from database
|
|
|
|
XCTAssert([[transaction ext:@"order"] numberOfItemsInGroup:@""] == (count - 5), @"Oops");
|
|
}];
|
|
|
|
[connection1 readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
XCTAssert([[transaction ext:@"order"] numberOfItemsInGroup:@""] == (count - 5), @"Oops");
|
|
}];
|
|
|
|
[connection2 readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
XCTAssert([[transaction ext:@"order"] numberOfItemsInGroup:@""] == (count - 5), @"Oops");
|
|
}];
|
|
|
|
// Test #4
|
|
|
|
[connection1 readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
|
|
|
[transaction removeObjectForKey:keys[5] inCollection:nil]; // remove single item
|
|
[transaction removeObjectsForKeys:keys inCollection:nil]; // and then remove all
|
|
|
|
XCTAssert([[transaction ext:@"order"] numberOfItemsInGroup:@""] == 0, @"Oops");
|
|
}];
|
|
|
|
[connection1 readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
XCTAssert([[transaction ext:@"order"] numberOfItemsInGroup:@""] == 0, @"Oops");
|
|
}];
|
|
|
|
[connection2 readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
XCTAssert([[transaction ext:@"order"] numberOfItemsInGroup:@""] == 0, @"Oops");
|
|
}];
|
|
}
|
|
|
|
@end
|