Files
RestKit/Tests/Logic/CoreData/RKInMemoryEntityCacheTest.m
Blake Watters a545c3942b Integrated primaryKey extension to NSEntityDescription and refactored cache strategy
classes to eliminate issues with duplicated objects. closes #611, #612, #613, #618

* NSEntityDescription is now aware of the primaryKeyAttribute. Can be configured via
Interface Builder within Xcode or programatically.
* Added findByPrimaryKey: interface to the Core Data extensions.
* Relaxed dependencies on RKManagedObjectMapping across the system now that primaryKey is
available without a reference to the mapping.
2012-04-03 23:39:42 -04:00

297 lines
15 KiB
Objective-C

//
// RKInMemoryEntityCacheTest.m
// RestKit
//
// Created by Jeff Arena on 1/25/12.
// Copyright (c) 2012 RestKit. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#import "RKTestEnvironment.h"
#import "RKHuman.h"
@interface RKInMemoryEntityCache ()
@property(nonatomic, retain) NSMutableDictionary *entityCache;
- (BOOL)shouldCoerceAttributeToString:(NSString *)attribute forEntity:(NSEntityDescription *)entity;
- (NSManagedObject *)objectWithID:(NSManagedObjectID *)objectID inContext:(NSManagedObjectContext *)managedObjectContext;
@end
@interface RKInMemoryEntityCacheTest : RKTestCase
@end
@implementation RKInMemoryEntityCacheTest
- (void)testInitializationWithManagedObjectContext
{
RKManagedObjectStore *objectStore = [RKTestFactory managedObjectStore];
RKInMemoryEntityCache *cache = [[RKInMemoryEntityCache alloc] initWithManagedObjectContext:objectStore.primaryManagedObjectContext];
assertThat(cache.managedObjectContext, is(equalTo(objectStore.primaryManagedObjectContext)));
}
- (void)testShouldCoercePrimaryKeysToStringsForLookup {
RKManagedObjectStore* objectStore = [RKTestFactory managedObjectStore];
RKHuman* human = [RKHuman createEntity];
human.railsID = [NSNumber numberWithInt:1234];
[objectStore save:nil];
RKInMemoryEntityCache *entityCache = [[[RKInMemoryEntityCache alloc] init] autorelease];
assertThatBool([entityCache shouldCoerceAttributeToString:@"railsID" forEntity:human.entity], is(equalToBool(YES)));
}
- (void)testShouldCacheAllObjectsForEntityWhenAccessingEntityCache {
RKManagedObjectStore* objectStore = [RKTestFactory managedObjectStore];
RKHuman* human = [RKHuman createEntity];
human.railsID = [NSNumber numberWithInt:1234];
[objectStore save:nil];
RKInMemoryEntityCache *entityCache = [[[RKInMemoryEntityCache alloc] init] autorelease];
NSMutableDictionary *humanCache = [entityCache cachedObjectsForEntity:human.entity
byAttribute:@"railsID"
inContext:objectStore.primaryManagedObjectContext];
assertThatInteger([humanCache count], is(equalToInt(1)));
}
- (void)testShouldCacheAllObjectsForEntityWhenAsked {
RKManagedObjectStore* objectStore = [RKTestFactory managedObjectStore];
RKHuman* human = [RKHuman createEntity];
human.railsID = [NSNumber numberWithInt:1234];
[objectStore save:nil];
RKInMemoryEntityCache *entityCache = [[[RKInMemoryEntityCache alloc] init] autorelease];
[entityCache cacheObjectsForEntity:human.entity byAttribute:@"railsID" inContext:objectStore.primaryManagedObjectContext];
NSMutableDictionary *humanCache = [entityCache cachedObjectsForEntity:human.entity
byAttribute:@"railsID"
inContext:objectStore.primaryManagedObjectContext];
assertThatInteger([humanCache count], is(equalToInt(1)));
}
- (void)testShouldRetrieveObjectsProperlyFromTheEntityCache {
RKManagedObjectStore* objectStore = [RKTestFactory managedObjectStore];
RKHuman* human = [RKHuman createEntity];
human.railsID = [NSNumber numberWithInt:1234];
[objectStore save:nil];
RKInMemoryEntityCache *entityCache = [[[RKInMemoryEntityCache alloc] init] autorelease];
NSManagedObject *cachedInstance = [entityCache cachedObjectForEntity:human.entity
withAttribute:@"railsID"
value:[NSNumber numberWithInt:1234]
inContext:objectStore.primaryManagedObjectContext];
assertThat(cachedInstance, is(equalTo(human)));
}
- (void)testShouldCacheAnIndividualObjectWhenAsked {
RKManagedObjectStore* objectStore = [RKTestFactory managedObjectStore];
RKHuman* human = [RKHuman createEntity];
human.railsID = [NSNumber numberWithInt:1234];
[objectStore save:nil];
RKInMemoryEntityCache *entityCache = [[[RKInMemoryEntityCache alloc] init] autorelease];
NSMutableDictionary *humanCache = [entityCache cachedObjectsForEntity:human.entity
byAttribute:@"railsID"
inContext:objectStore.primaryManagedObjectContext];
assertThatInteger([humanCache count], is(equalToInt(1)));
RKHuman* newHuman = [RKHuman createEntity];
newHuman.railsID = [NSNumber numberWithInt:5678];
[entityCache cacheObject:newHuman byAttribute:@"railsID" inContext:objectStore.primaryManagedObjectContext];
[entityCache cacheObjectsForEntity:human.entity byAttribute:@"railsID" inContext:objectStore.primaryManagedObjectContext];
humanCache = [entityCache cachedObjectsForEntity:human.entity
byAttribute:@"railsID"
inContext:objectStore.primaryManagedObjectContext];
assertThatInteger([humanCache count], is(equalToInt(2)));
}
- (void)testShouldCacheAnIndividualObjectByPrimaryKeyValueWhenAsked {
RKManagedObjectStore* objectStore = [RKTestFactory managedObjectStore];
RKHuman* human = [RKHuman createEntity];
human.railsID = [NSNumber numberWithInt:1234];
[objectStore save:nil];
RKInMemoryEntityCache *entityCache = [[[RKInMemoryEntityCache alloc] init] autorelease];
NSMutableDictionary *humanCache = [entityCache cachedObjectsForEntity:human.entity
byAttribute:@"railsID"
inContext:objectStore.primaryManagedObjectContext];
assertThatInteger([humanCache count], is(equalToInt(1)));
RKHuman* newHuman = [RKHuman createEntity];
newHuman.railsID = [NSNumber numberWithInt:5678];
[objectStore save:nil];
[entityCache cacheObject:newHuman.entity
byAttribute:@"railsID"
value:[NSNumber numberWithInt:5678]
inContext:objectStore.primaryManagedObjectContext];
[entityCache cacheObjectsForEntity:human.entity byAttribute:@"railsID" inContext:objectStore.primaryManagedObjectContext];
humanCache = [entityCache cachedObjectsForEntity:human.entity byAttribute:@"railsID" inContext:objectStore.primaryManagedObjectContext];
assertThatInteger([humanCache count], is(equalToInt(2)));
}
- (void)testShouldExpireACacheEntryForAnObjectWhenAsked {
RKManagedObjectStore* objectStore = [RKTestFactory managedObjectStore];
RKHuman* human = [RKHuman createEntity];
human.railsID = [NSNumber numberWithInt:1234];
[objectStore save:nil];
RKInMemoryEntityCache *entityCache = [[[RKInMemoryEntityCache alloc] init] autorelease];
NSMutableDictionary *humanCache = [entityCache cachedObjectsForEntity:human.entity
byAttribute:@"railsID"
inContext:objectStore.primaryManagedObjectContext];
assertThatInteger([humanCache count], is(equalToInt(1)));
[entityCache expireCacheEntryForObject:human byAttribute:@"railsID" inContext:objectStore.primaryManagedObjectContext];
assertThatInteger([entityCache.entityCache count], is(equalToInt(0)));
}
- (void)testShouldExpireEntityCacheWhenAsked {
RKManagedObjectStore* objectStore = [RKTestFactory managedObjectStore];
RKHuman* human = [RKHuman createEntity];
human.railsID = [NSNumber numberWithInt:1234];
[objectStore save:nil];
RKInMemoryEntityCache *entityCache = [[[RKInMemoryEntityCache alloc] init] autorelease];
NSMutableDictionary *humanCache = [entityCache cachedObjectsForEntity:human.entity
byAttribute:@"railsID"
inContext:objectStore.primaryManagedObjectContext];
assertThatInteger([humanCache count], is(equalToInt(1)));
[entityCache expireCacheEntriesForEntity:human.entity];
assertThatInteger([entityCache.entityCache count], is(equalToInt(0)));
}
#if TARGET_OS_IPHONE
- (void)testShouldExpireEntityCacheInResponseToMemoryWarning {
RKManagedObjectStore* objectStore = [RKTestFactory managedObjectStore];
RKHuman* human = [RKHuman createEntity];
human.railsID = [NSNumber numberWithInt:1234];
[objectStore save:nil];
RKInMemoryEntityCache *entityCache = [[[RKInMemoryEntityCache alloc] init] autorelease];
NSMutableDictionary *humanCache = [entityCache cachedObjectsForEntity:human.entity
byAttribute:@"railsID"
inContext:objectStore.primaryManagedObjectContext];
assertThatInteger([humanCache count], is(equalToInt(1)));
[[NSNotificationCenter defaultCenter] postNotificationName:UIApplicationDidReceiveMemoryWarningNotification object:nil];
assertThatInteger([entityCache.entityCache count], is(equalToInt(0)));
}
#endif
- (void)testShouldAddInstancesOfInsertedObjectsToCache {
RKManagedObjectStore* objectStore = [RKTestFactory managedObjectStore];
RKHuman* human = [RKHuman createEntity];
human.railsID = [NSNumber numberWithInt:1234];
[objectStore save:nil];
RKInMemoryEntityCache *entityCache = [[[RKInMemoryEntityCache alloc] init] autorelease];
NSMutableDictionary *humanCache = [entityCache cachedObjectsForEntity:human.entity
byAttribute:@"railsID"
inContext:objectStore.primaryManagedObjectContext];
assertThatInteger([humanCache count], is(equalToInt(1)));
RKHuman* newHuman = [RKHuman createEntity];
newHuman.railsID = [NSNumber numberWithInt:5678];
[objectStore save:nil];
humanCache = [entityCache cachedObjectsForEntity:human.entity
byAttribute:@"railsID"
inContext:objectStore.primaryManagedObjectContext];
assertThatInteger([humanCache count], is(equalToInt(2)));
}
- (void)testShouldRemoveInstancesOfDeletedObjectsToCache {
RKManagedObjectStore* objectStore = [RKTestFactory managedObjectStore];
RKHuman* humanOne = [RKHuman createEntity];
humanOne.railsID = [NSNumber numberWithInt:1234];
RKHuman* humanTwo = [RKHuman createEntity];
humanTwo.railsID = [NSNumber numberWithInt:5678];
[objectStore save:nil];
RKInMemoryEntityCache *entityCache = [[[RKInMemoryEntityCache alloc] init] autorelease];
NSMutableDictionary *humanCache = [entityCache cachedObjectsForEntity:humanOne.entity
byAttribute:@"railsID"
inContext:objectStore.primaryManagedObjectContext];
assertThatInteger([humanCache count], is(equalToInt(2)));
[humanTwo deleteEntity];
[objectStore save:nil];
humanCache = [entityCache cachedObjectsForEntity:humanOne.entity
byAttribute:@"railsID"
inContext:objectStore.primaryManagedObjectContext];
assertThatInteger([humanCache count], is(equalToInt(1)));
}
- (void)testThatDeletionOfObjectsDoesNotPermitCreationOfDuplicates {
RKManagedObjectStore* objectStore = [RKTestFactory managedObjectStore];
RKHuman* humanOne = [RKHuman createEntity];
humanOne.railsID = [NSNumber numberWithInt:1234];
RKHuman* humanTwo = [RKHuman createEntity];
humanTwo.railsID = [NSNumber numberWithInt:5678];
[objectStore save:nil];
RKInMemoryEntityCache *entityCache = [[[RKInMemoryEntityCache alloc] init] autorelease];
NSMutableDictionary *humanCache = [entityCache cachedObjectsForEntity:humanOne.entity
byAttribute:@"railsID"
inContext:objectStore.primaryManagedObjectContext];
assertThatInteger([humanCache count], is(equalToInt(2)));
[humanTwo deleteEntity];
[objectStore save:nil];
RKHuman *existingReference = (RKHuman *)[entityCache cachedObjectForEntity:[RKHuman entity] withAttribute:@"railsID" value:[NSNumber numberWithInt:1234] inContext:objectStore.primaryManagedObjectContext];
assertThat(existingReference, is(notNilValue()));
assertThat(existingReference, is(equalTo(humanOne)));
}
- (void)testThatRepeatedInvocationsOfLoadObjectDoesNotDuplicateObjects {
RKManagedObjectStore *objectStore = [RKTestFactory managedObjectStore];
objectStore.cacheStrategy = [RKInMemoryManagedObjectCache new];
RKObjectManager *objectManager = [RKTestFactory objectManager];
objectManager.objectStore = objectStore;
RKManagedObjectMapping *humanMapping = [RKManagedObjectMapping mappingForClass:[RKHuman class] inManagedObjectStore:objectStore];
humanMapping.primaryKeyAttribute = @"name";
[humanMapping mapKeyPath:@"id" toAttribute:@"railsID"];
[humanMapping mapAttributes:@"name", nil];
[objectManager.mappingProvider setObjectMapping:humanMapping forKeyPath:@"human"];
for (NSUInteger i = 0; i < 5; i++) {
RKTestResponseLoader *responseLoader = [RKTestResponseLoader responseLoader];
[objectManager loadObjectsAtResourcePath:@"/JSON/ArrayOfHumans.json" delegate:responseLoader];
[responseLoader waitForResponse];
for (RKHuman *object in [RKHuman allObjects]) {
if ([object.railsID intValue] == 201) {
[objectStore.managedObjectContextForCurrentThread deleteObject:object];
[objectStore.managedObjectContextForCurrentThread save:nil];
}
}
[objectStore save:nil];
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.2]];
}
NSUInteger count = [RKHuman count:nil];
assertThatInt(count, is(equalToInt(1)));
NSArray *humans = [RKHuman allObjects];
[humans makeObjectsPerformSelector:@selector(railsID)];
}
@end