mirror of
https://github.com/zhigang1992/RestKit.git
synced 2026-04-23 12:27:52 +08:00
Expand test coverage on managed object deletion cases and fix bugs. closes #358
This commit is contained in:
@@ -69,22 +69,18 @@
|
||||
- (void)visitMapping:(RKMapping *)mapping atKeyPath:(NSString *)keyPath
|
||||
{
|
||||
id actualKeyPath = keyPath ?: [NSNull null];
|
||||
if ([self.keyPaths containsObject:actualKeyPath]) return;
|
||||
|
||||
if ([mapping isKindOfClass:[RKEntityMapping class]]) {
|
||||
[self.mutableKeyPaths addObject:actualKeyPath];
|
||||
} else {
|
||||
if ([mapping isKindOfClass:[RKDynamicMapping class]]) {
|
||||
RKDynamicMapping *dynamicMapping = (RKDynamicMapping *)mapping;
|
||||
for (RKMapping *nestedMapping in dynamicMapping.objectMappings) {
|
||||
[self visitMapping:nestedMapping atKeyPath:keyPath];
|
||||
}
|
||||
} else if ([mapping isKindOfClass:[RKObjectMapping class]]) {
|
||||
RKObjectMapping *objectMapping = (RKObjectMapping *)mapping;
|
||||
for (RKRelationshipMapping *relationshipMapping in objectMapping.relationshipMappings) {
|
||||
NSString *nestedKeyPath = keyPath ? [@[ keyPath, relationshipMapping.destinationKeyPath ] componentsJoinedByString:@"."] : relationshipMapping.destinationKeyPath;
|
||||
[self visitMapping:relationshipMapping.mapping atKeyPath:nestedKeyPath];
|
||||
}
|
||||
if ([self.keyPaths containsObject:actualKeyPath]) return;
|
||||
if ([mapping isKindOfClass:[RKEntityMapping class]]) [self.mutableKeyPaths addObject:actualKeyPath];
|
||||
if ([mapping isKindOfClass:[RKDynamicMapping class]]) {
|
||||
RKDynamicMapping *dynamicMapping = (RKDynamicMapping *)mapping;
|
||||
for (RKMapping *nestedMapping in dynamicMapping.objectMappings) {
|
||||
[self visitMapping:nestedMapping atKeyPath:keyPath];
|
||||
}
|
||||
} else if ([mapping isKindOfClass:[RKObjectMapping class]]) {
|
||||
RKObjectMapping *objectMapping = (RKObjectMapping *)mapping;
|
||||
for (RKRelationshipMapping *relationshipMapping in objectMapping.relationshipMappings) {
|
||||
NSString *nestedKeyPath = keyPath ? [@[ keyPath, relationshipMapping.destinationKeyPath ] componentsJoinedByString:@"."] : relationshipMapping.destinationKeyPath;
|
||||
[self visitMapping:relationshipMapping.mapping atKeyPath:nestedKeyPath];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -102,6 +98,28 @@ NSArray *RKArrayOfFetchRequestFromBlocksWithURL(NSArray *fetchRequestBlocks, NSU
|
||||
return fetchRequests;
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the set of keys containing the outermost nesting keypath for all children.
|
||||
For example, given a set containing: 'this', 'this.that', 'another.one.test', 'another.two.test', 'another.one.test.nested'
|
||||
would return: 'this, 'another.one', 'another.two'
|
||||
*/
|
||||
NSSet *RKSetByRemovingSubkeypathsFromSet(NSSet *setOfKeyPaths);
|
||||
NSSet *RKSetByRemovingSubkeypathsFromSet(NSSet *setOfKeyPaths)
|
||||
{
|
||||
return [setOfKeyPaths objectsPassingTest:^BOOL(NSString *keyPath, BOOL *stop) {
|
||||
if ([keyPath isEqual:[NSNull null]]) return YES; // Special case the root key path
|
||||
NSArray *keyPathComponents = [keyPath componentsSeparatedByString:@"."];
|
||||
NSMutableSet *parentKeyPaths = [NSMutableSet set];
|
||||
for (NSUInteger index = 0; index < [keyPathComponents count] - 1; index++) {
|
||||
[parentKeyPaths addObject:[[keyPathComponents subarrayWithRange:NSMakeRange(0, index + 1)] componentsJoinedByString:@"."]];
|
||||
}
|
||||
for (NSString *parentKeyPath in parentKeyPaths) {
|
||||
if ([setOfKeyPaths containsObject:parentKeyPath]) return NO;
|
||||
}
|
||||
return YES;
|
||||
}];
|
||||
}
|
||||
|
||||
// When we map the root object, it is returned under the key `[NSNull null]`
|
||||
static id RKMappedValueForKeyPathInDictionary(NSString *keyPath, NSDictionary *dictionary)
|
||||
{
|
||||
@@ -110,17 +128,33 @@ static id RKMappedValueForKeyPathInDictionary(NSString *keyPath, NSDictionary *d
|
||||
|
||||
static void RKSetMappedValueForKeyPathInDictionary(id value, NSString *keyPath, NSMutableDictionary *dictionary)
|
||||
{
|
||||
NSCParameterAssert(value);
|
||||
NSCParameterAssert(keyPath);
|
||||
NSCParameterAssert(dictionary);
|
||||
[keyPath isEqual:[NSNull null]] ? [dictionary setObject:value forKey:keyPath] : [dictionary setValue:value forKeyPath:keyPath];
|
||||
}
|
||||
|
||||
// Precondition: Must be called from within the correct context
|
||||
static NSManagedObject *RKRefetchManagedObjectInContext(NSManagedObject *managedObject, NSManagedObjectContext *managedObjectContext)
|
||||
{
|
||||
NSManagedObjectID *managedObjectID = [managedObject objectID];
|
||||
if (! [managedObject managedObjectContext]) return nil; // Object has been deleted
|
||||
if ([managedObjectID isTemporaryID]) {
|
||||
RKLogWarning(@"Unable to refetch managed object %@: the object has a temporary managed object ID.", managedObject);
|
||||
return managedObject;
|
||||
}
|
||||
NSError *error = nil;
|
||||
NSManagedObject *refetchedObject = [managedObjectContext existingObjectWithID:managedObjectID error:&error];
|
||||
NSCAssert(refetchedObject, @"Failed to find existing object with ID %@ in context %@: %@", managedObjectID, managedObjectContext, error);
|
||||
return refetchedObject;
|
||||
}
|
||||
|
||||
// Finds the key paths for all entity mappings in the graph whose parent objects are not other managed objects
|
||||
static NSDictionary *RKDictionaryFromDictionaryWithManagedObjectsAtKeyPathsRefetchedInContext(NSDictionary *dictionaryOfManagedObjects, NSSet *keyPaths, NSManagedObjectContext *managedObjectContext)
|
||||
{
|
||||
if (! [dictionaryOfManagedObjects count]) return dictionaryOfManagedObjects;
|
||||
NSMutableDictionary *newDictionary = [dictionaryOfManagedObjects mutableCopy];
|
||||
[managedObjectContext performBlockAndWait:^{
|
||||
__block NSError *error = nil;
|
||||
|
||||
for (NSString *keyPath in keyPaths) {
|
||||
id value = RKMappedValueForKeyPathInDictionary(keyPath, dictionaryOfManagedObjects);
|
||||
if (! value) {
|
||||
@@ -129,51 +163,31 @@ static NSDictionary *RKDictionaryFromDictionaryWithManagedObjectsAtKeyPathsRefet
|
||||
BOOL isMutable = [value isKindOfClass:[NSMutableArray class]];
|
||||
NSMutableArray *newValue = [[NSMutableArray alloc] initWithCapacity:[value count]];
|
||||
for (__strong id object in value) {
|
||||
if ([object isKindOfClass:[NSManagedObject class]]) {
|
||||
if (![object managedObjectContext]) continue; // Object was deleted
|
||||
object = [managedObjectContext existingObjectWithID:[object objectID] error:&error];
|
||||
NSCAssert(object, @"Failed to find existing object with ID %@ in context %@: %@", [object objectID], managedObjectContext, error);
|
||||
}
|
||||
|
||||
[newValue addObject:object];
|
||||
if ([object isKindOfClass:[NSManagedObject class]]) object = RKRefetchManagedObjectInContext(object, managedObjectContext);
|
||||
if (object) [newValue addObject:object];
|
||||
}
|
||||
value = (isMutable) ? newValue : [newValue copy];
|
||||
} else if ([value isKindOfClass:[NSSet class]]) {
|
||||
BOOL isMutable = [value isKindOfClass:[NSMutableSet class]];
|
||||
NSMutableSet *newValue = [[NSMutableSet alloc] initWithCapacity:[value count]];
|
||||
for (__strong id object in value) {
|
||||
if ([object isKindOfClass:[NSManagedObject class]]) {
|
||||
if (![object managedObjectContext]) continue; // Object was deleted
|
||||
object = [managedObjectContext existingObjectWithID:[object objectID] error:&error];
|
||||
NSCAssert(object, @"Failed to find existing object with ID %@ in context %@: %@", [object objectID], managedObjectContext, error);
|
||||
}
|
||||
|
||||
[newValue addObject:object];
|
||||
if ([object isKindOfClass:[NSManagedObject class]]) object = RKRefetchManagedObjectInContext(object, managedObjectContext);
|
||||
if (object) [newValue addObject:object];
|
||||
}
|
||||
value = (isMutable) ? newValue : [newValue copy];
|
||||
} else if ([value isKindOfClass:[NSOrderedSet class]]) {
|
||||
BOOL isMutable = [value isKindOfClass:[NSMutableOrderedSet class]];
|
||||
NSMutableOrderedSet *newValue = [NSMutableOrderedSet orderedSet];
|
||||
[(NSOrderedSet *)value enumerateObjectsUsingBlock:^(id object, NSUInteger index, BOOL *stop) {
|
||||
if ([object isKindOfClass:[NSManagedObject class]]) {
|
||||
if ([object managedObjectContext]) {
|
||||
object = [managedObjectContext existingObjectWithID:[object objectID] error:&error];
|
||||
NSCAssert(object, @"Failed to find existing object with ID %@ in context %@: %@", [object objectID], managedObjectContext, error);
|
||||
} else {
|
||||
// Object was deleted
|
||||
object = nil;
|
||||
}
|
||||
}
|
||||
|
||||
if ([object isKindOfClass:[NSManagedObject class]]) object = RKRefetchManagedObjectInContext(object, managedObjectContext);
|
||||
if (object) [newValue setObject:object atIndex:index];
|
||||
}];
|
||||
value = (isMutable) ? newValue : [newValue copy];
|
||||
} else if ([value isKindOfClass:[NSManagedObject class]]) {
|
||||
// Object becomes nil if deleted
|
||||
value = [value managedObjectContext] ? [managedObjectContext existingObjectWithID:[value objectID] error:&error] : nil;
|
||||
value = RKRefetchManagedObjectInContext(value, managedObjectContext);
|
||||
}
|
||||
|
||||
RKSetMappedValueForKeyPathInDictionary(value, keyPath, newDictionary);
|
||||
if (value) RKSetMappedValueForKeyPathInDictionary(value, keyPath, newDictionary);
|
||||
}
|
||||
}];
|
||||
|
||||
@@ -482,7 +496,8 @@ static NSURL *RKRelativeURLFromURLAndResponseDescriptors(NSURL *URL, NSArray *re
|
||||
|
||||
// Refetch all managed objects nested at key paths within the results dictionary before returning
|
||||
if (self.mappingResult) {
|
||||
NSDictionary *resultsDictionaryFromOriginalContext = RKDictionaryFromDictionaryWithManagedObjectsAtKeyPathsRefetchedInContext([self.mappingResult dictionary], managedObjectMappingResultKeyPaths, self.managedObjectContext);
|
||||
NSSet *nonNestedKeyPaths = RKSetByRemovingSubkeypathsFromSet(managedObjectMappingResultKeyPaths);
|
||||
NSDictionary *resultsDictionaryFromOriginalContext = RKDictionaryFromDictionaryWithManagedObjectsAtKeyPathsRefetchedInContext([self.mappingResult dictionary], nonNestedKeyPaths, self.managedObjectContext);
|
||||
self.mappingResult = [[RKMappingResult alloc] initWithDictionary:resultsDictionaryFromOriginalContext];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
@interface RKManagedObjectRequestOperation ()
|
||||
- (NSSet *)localObjectsFromFetchRequestsMatchingRequestURL:(NSError **)error;
|
||||
@end
|
||||
NSSet *RKSetByRemovingSubkeypathsFromSet(NSSet *setOfKeyPaths);
|
||||
|
||||
@interface RKManagedObjectRequestOperationTest : RKTestCase
|
||||
|
||||
@@ -367,6 +368,27 @@
|
||||
expect([[testUser.friendsOrderedSet firstObject] managedObjectContext]).to.equal(managedObjectStore.persistentStoreManagedObjectContext);
|
||||
}
|
||||
|
||||
- (void)testDeletionOfOrphanedManagedObjects
|
||||
{
|
||||
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
|
||||
RKHuman *orphanedHuman = [NSEntityDescription insertNewObjectForEntityForName:@"Human" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
|
||||
RKEntityMapping *entityMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore];
|
||||
[entityMapping addAttributeMappingsFromArray:@[ @"name" ]];
|
||||
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:entityMapping pathPattern:nil keyPath:@"human" statusCodes:[NSIndexSet indexSetWithIndex:200]];
|
||||
|
||||
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"/JSON/humans/with_to_one_relationship.json" relativeToURL:[RKTestFactory baseURL]]];
|
||||
RKManagedObjectRequestOperation *managedObjectRequestOperation = [[RKManagedObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[ responseDescriptor ]];
|
||||
RKFetchRequestBlock fetchRequestBlock = ^NSFetchRequest * (NSURL *URL) {
|
||||
return [NSFetchRequest fetchRequestWithEntityName:@"Human"];
|
||||
};
|
||||
managedObjectRequestOperation.fetchRequestBlocks = @[ fetchRequestBlock ];
|
||||
managedObjectRequestOperation.managedObjectContext = managedObjectStore.persistentStoreManagedObjectContext;
|
||||
[managedObjectRequestOperation start];
|
||||
expect(managedObjectRequestOperation.error).to.beNil();
|
||||
expect([managedObjectRequestOperation.mappingResult array]).to.haveCountOf(1);
|
||||
expect(orphanedHuman.managedObjectContext).to.beNil();
|
||||
}
|
||||
|
||||
- (void)testDeletionOfOrphanedObjectsMappedOnRelationships
|
||||
{
|
||||
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
|
||||
@@ -390,6 +412,131 @@
|
||||
expect(orphanedHuman.managedObjectContext).to.beNil();
|
||||
}
|
||||
|
||||
// TODO: test deletion of nested objects
|
||||
- (void)testDeletionOfOrphanedTagsOfPosts
|
||||
{
|
||||
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
|
||||
NSManagedObject *orphanedTag = [NSEntityDescription insertNewObjectForEntityForName:@"Tag" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
|
||||
[orphanedTag setValue:@"orphaned" forKey:@"name"];
|
||||
RKEntityMapping *postMapping = [RKEntityMapping mappingForEntityForName:@"Post" inManagedObjectStore:managedObjectStore];
|
||||
[postMapping addAttributeMappingsFromArray:@[ @"title", @"body" ]];
|
||||
RKEntityMapping *tagMapping = [RKEntityMapping mappingForEntityForName:@"Tag" inManagedObjectStore:managedObjectStore];
|
||||
[tagMapping addAttributeMappingsFromArray:@[ @"name" ]];
|
||||
[postMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"tags" toKeyPath:@"tags" withMapping:tagMapping]];
|
||||
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:postMapping pathPattern:nil keyPath:@"posts" statusCodes:[NSIndexSet indexSetWithIndex:200]];
|
||||
|
||||
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"/posts.json" relativeToURL:[RKTestFactory baseURL]]];
|
||||
RKManagedObjectRequestOperation *managedObjectRequestOperation = [[RKManagedObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[ responseDescriptor ]];
|
||||
RKFetchRequestBlock fetchRequestBlock = ^NSFetchRequest * (NSURL *URL) {
|
||||
return [NSFetchRequest fetchRequestWithEntityName:@"Tag"];
|
||||
};
|
||||
managedObjectRequestOperation.fetchRequestBlocks = @[ fetchRequestBlock ];
|
||||
managedObjectRequestOperation.managedObjectContext = managedObjectStore.persistentStoreManagedObjectContext;
|
||||
[managedObjectRequestOperation start];
|
||||
expect(managedObjectRequestOperation.error).to.beNil();
|
||||
expect([managedObjectRequestOperation.mappingResult array]).to.haveCountOf(1);
|
||||
expect(orphanedTag.managedObjectContext).to.beNil();
|
||||
|
||||
// Create 3 tags. Update the post entity so it only points to 2 tags. Tag should be deleted.
|
||||
// Create 3 tags. Create another post pointing to one of the tags. Update the post entity so it only points to 2 tags. Tag should be deleted.
|
||||
}
|
||||
|
||||
- (void)testThatDeletionOfOrphanedObjectsCanBeSuppressedByPredicate
|
||||
{
|
||||
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
|
||||
NSManagedObject *tagOnDiferentObject = [NSEntityDescription insertNewObjectForEntityForName:@"Tag" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
|
||||
[tagOnDiferentObject setValue:@"orphaned" forKey:@"name"];
|
||||
|
||||
NSManagedObject *otherPost = [NSEntityDescription insertNewObjectForEntityForName:@"Post" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
|
||||
[otherPost setValue:[NSSet setWithObject:tagOnDiferentObject] forKey:@"tags"];
|
||||
|
||||
RKEntityMapping *postMapping = [RKEntityMapping mappingForEntityForName:@"Post" inManagedObjectStore:managedObjectStore];
|
||||
[postMapping addAttributeMappingsFromArray:@[ @"title", @"body" ]];
|
||||
RKEntityMapping *tagMapping = [RKEntityMapping mappingForEntityForName:@"Tag" inManagedObjectStore:managedObjectStore];
|
||||
[tagMapping addAttributeMappingsFromArray:@[ @"name" ]];
|
||||
[postMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"tags" toKeyPath:@"tags" withMapping:tagMapping]];
|
||||
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:postMapping pathPattern:nil keyPath:@"posts" statusCodes:[NSIndexSet indexSetWithIndex:200]];
|
||||
|
||||
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"/posts.json" relativeToURL:[RKTestFactory baseURL]]];
|
||||
RKManagedObjectRequestOperation *managedObjectRequestOperation = [[RKManagedObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[ responseDescriptor ]];
|
||||
RKFetchRequestBlock fetchRequestBlock = ^NSFetchRequest * (NSURL *URL) {
|
||||
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Tag"];
|
||||
fetchRequest.predicate = [NSPredicate predicateWithFormat:@"posts.@count == 0"];
|
||||
return fetchRequest;
|
||||
};
|
||||
managedObjectRequestOperation.fetchRequestBlocks = @[ fetchRequestBlock ];
|
||||
managedObjectRequestOperation.managedObjectContext = managedObjectStore.persistentStoreManagedObjectContext;
|
||||
[managedObjectRequestOperation start];
|
||||
expect(managedObjectRequestOperation.error).to.beNil();
|
||||
expect([managedObjectRequestOperation.mappingResult array]).to.haveCountOf(1);
|
||||
expect(tagOnDiferentObject.managedObjectContext).notTo.beNil();
|
||||
}
|
||||
|
||||
- (void)testThatObjectsOrphanedByRequestOperationAreDeletedAppropriately
|
||||
{
|
||||
// create tags: development, restkit, orphaned
|
||||
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
|
||||
__block NSManagedObject *post = nil;
|
||||
__block NSManagedObject *orphanedTag;
|
||||
__block NSManagedObject *anotherTag;
|
||||
[managedObjectStore.persistentStoreManagedObjectContext performBlockAndWait:^{
|
||||
NSManagedObject *developmentTag = [NSEntityDescription insertNewObjectForEntityForName:@"Tag" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
|
||||
[developmentTag setValue:@"development" forKey:@"name"];
|
||||
NSManagedObject *restkitTag = [NSEntityDescription insertNewObjectForEntityForName:@"Tag" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
|
||||
[restkitTag setValue:@"restkit" forKey:@"name"];
|
||||
orphanedTag = [NSEntityDescription insertNewObjectForEntityForName:@"Tag" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
|
||||
[orphanedTag setValue:@"orphaned" forKey:@"name"];
|
||||
|
||||
post = [NSEntityDescription insertNewObjectForEntityForName:@"Post" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
|
||||
[post setValue:@"Post Title" forKey:@"title"];
|
||||
[post setValue:[NSSet setWithObjects:developmentTag, restkitTag, orphanedTag, nil] forKey:@"tags"];
|
||||
|
||||
anotherTag = [NSEntityDescription insertNewObjectForEntityForName:@"Tag" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
|
||||
[anotherTag setValue:@"another" forKey:@"name"];
|
||||
NSManagedObject *anotherPost = [NSEntityDescription insertNewObjectForEntityForName:@"Post" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
|
||||
[anotherPost setValue:@"Another Post" forKey:@"title"];
|
||||
[anotherPost setValue:[NSSet setWithObject:anotherTag] forKey:@"tags"];
|
||||
|
||||
BOOL success = [managedObjectStore.persistentStoreManagedObjectContext save:nil];
|
||||
}];
|
||||
|
||||
RKEntityMapping *postMapping = [RKEntityMapping mappingForEntityForName:@"Post" inManagedObjectStore:managedObjectStore];
|
||||
postMapping.identificationAttributes = @[ @"title" ];
|
||||
[postMapping addAttributeMappingsFromArray:@[ @"title", @"body" ]];
|
||||
RKEntityMapping *tagMapping = [RKEntityMapping mappingForEntityForName:@"Tag" inManagedObjectStore:managedObjectStore];
|
||||
tagMapping.identificationAttributes = @[ @"name" ];
|
||||
[tagMapping addAttributeMappingsFromArray:@[ @"name" ]];
|
||||
[postMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"tags" toKeyPath:@"tags" withMapping:tagMapping]];
|
||||
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:postMapping pathPattern:nil keyPath:@"posts" statusCodes:[NSIndexSet indexSetWithIndex:200]];
|
||||
|
||||
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"/posts.json" relativeToURL:[RKTestFactory baseURL]]];
|
||||
RKManagedObjectRequestOperation *managedObjectRequestOperation = [[RKManagedObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[ responseDescriptor ]];
|
||||
RKFetchRequestManagedObjectCache *managedObjectCache = [RKFetchRequestManagedObjectCache new];
|
||||
managedObjectRequestOperation.managedObjectCache = managedObjectCache;
|
||||
RKFetchRequestBlock fetchRequestBlock = ^NSFetchRequest * (NSURL *URL) {
|
||||
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Tag"];
|
||||
fetchRequest.predicate = [NSPredicate predicateWithFormat:@"posts.@count == 0"];
|
||||
return fetchRequest;
|
||||
};
|
||||
managedObjectRequestOperation.fetchRequestBlocks = @[ fetchRequestBlock ];
|
||||
managedObjectRequestOperation.managedObjectContext = managedObjectStore.persistentStoreManagedObjectContext;
|
||||
[managedObjectRequestOperation start];
|
||||
expect(managedObjectRequestOperation.error).to.beNil();
|
||||
expect([managedObjectRequestOperation.mappingResult array]).to.haveCountOf(1);
|
||||
|
||||
NSSet *tagNames = [post valueForKeyPath:@"tags.name"];
|
||||
NSSet *expectedTagNames = [NSSet setWithObjects:@"development", @"restkit", nil ];
|
||||
expect(tagNames).to.equal(expectedTagNames);
|
||||
|
||||
expect([orphanedTag hasBeenDeleted]).to.equal(YES);
|
||||
expect([anotherTag hasBeenDeleted]).to.equal(NO);
|
||||
}
|
||||
|
||||
- (void)testPruningOfSubkeypathsFromSet
|
||||
{
|
||||
NSSet *keyPaths = [NSSet setWithObjects:@"posts", @"posts.tags", @"another", @"something.else.entirely", @"another.this.that", @"somewhere.out.there", @"some.posts", nil];
|
||||
NSSet *prunedSet = RKSetByRemovingSubkeypathsFromSet(keyPaths);
|
||||
NSSet *expectedSet = [NSSet setWithObjects:@"posts", @"another", @"something.else.entirely", @"somewhere.out.there", @"some.posts", nil];
|
||||
expect(prunedSet).to.equal(expectedSet);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -98,7 +98,7 @@ class RestKitTestServer < Sinatra::Base
|
||||
delete '/humans/success' do
|
||||
status 200
|
||||
content_type 'application/json'
|
||||
{:humans => {:status => 'OK'}}.to_json
|
||||
{:human => {:status => 'OK'}}.to_json
|
||||
end
|
||||
|
||||
post '/echo_params' do
|
||||
@@ -299,6 +299,11 @@ class RestKitTestServer < Sinatra::Base
|
||||
content_type 'application/json'
|
||||
render_fixture('/JSON/ComplexNestedUser.json', :status => 200)
|
||||
end
|
||||
|
||||
get '/posts.json' do
|
||||
content_type 'application/json'
|
||||
{ :posts => [{:title => 'Post Title', :body => 'Some body.', :tags => [{ :name => 'development' }, { :name => 'restkit' }] }] }.to_json
|
||||
end
|
||||
|
||||
# start the server if ruby file executed directly
|
||||
run! if app_file == $0
|
||||
|
||||
Reference in New Issue
Block a user