Files
RestKit/Tests/Logic/Network/RKManagedObjectRequestOperationTest.m

1171 lines
82 KiB
Objective-C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// RKManagedObjectRequestOperationTest.m
// RestKit
//
// Created by Blake Watters on 10/17/12.
// Copyright (c) 2012 RestKit. All rights reserved.
//
#import "RKTestEnvironment.h"
#import "RKManagedObjectRequestOperation.h"
#import "RKEntityMapping.h"
#import "RKHuman.h"
#import "RKTestUser.h"
#import "RKMappingErrors.h"
#import "RKMappableObject.h"
#import "RKPost.h"
@interface RKManagedObjectRequestOperation ()
- (NSSet *)localObjectsFromFetchRequestsMatchingRequestURL:(NSError **)error;
@end
NSSet *RKSetByRemovingSubkeypathsFromSet(NSSet *setOfKeyPaths);
@interface RKTestDelegateManagedObjectRequestOperation : RKManagedObjectRequestOperation
@end
@implementation RKTestDelegateManagedObjectRequestOperation
- (void)mapperWillStartMapping:(RKMapperOperation *)mapper
{
// For stubbing
}
@end
@interface RKTestListOfLists : NSObject
@property (nonatomic, strong) NSArray *listOfLists;
@end
@implementation RKTestListOfLists
@end
@interface RKManagedObjectRequestOperationTest : RKTestCase
@end
@implementation RKManagedObjectRequestOperationTest
- (void)setUp
{
[RKTestFactory setUp];
}
- (void)tearDown
{
[RKTestFactory tearDown];
}
- (void)testThatInitializationWithRequestDefaultsToSavingToPersistentStore
{
RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:@"http://restkit.org"]];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"/whatever" relativeToURL:manager.baseURL]];
RKManagedObjectRequestOperation *operation = [[RKManagedObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[]];
expect(operation.savesToPersistentStore).to.equal(YES);
}
- (void)testThatInitializationWithRequestOperationDefaultsToSavingToPersistentStore
{
RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:@"http://restkit.org"]];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"/whatever" relativeToURL:manager.baseURL]];
RKHTTPRequestOperation *requestOperation = [[RKHTTPRequestOperation alloc] initWithRequest:request];
RKManagedObjectRequestOperation *operation = [[RKManagedObjectRequestOperation alloc] initWithHTTPRequestOperation:requestOperation responseDescriptors:@[]];
expect(operation.savesToPersistentStore).to.equal(YES);
}
- (void)testFetchRequestBlocksAreInvokedWithARelativeURL
{
NSURL *baseURL = [NSURL URLWithString:@"http://restkit.org/api/v1/"];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"categories/1234" relativeToURL:baseURL]];
NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:request.URL statusCode:200 HTTPVersion:@"1.1" headerFields:@{}];
RKObjectMapping *mapping = [RKObjectMapping requestMapping];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:mapping pathPattern:@"categories/:categoryID" keyPath:nil statusCodes:[NSIndexSet indexSetWithIndex:200]];
responseDescriptor.baseURL = baseURL;
id mockRequestOperation = [OCMockObject niceMockForClass:[RKHTTPRequestOperation class]];
[[[mockRequestOperation stub] andReturn:request] request];
[[[mockRequestOperation stub] andReturn:response] response];
RKManagedObjectRequestOperation *operation = [[RKManagedObjectRequestOperation alloc] initWithHTTPRequestOperation:mockRequestOperation responseDescriptors:@[ responseDescriptor ]];
__block NSURL *blockURL = nil;
RKFetchRequestBlock fetchRequesBlock = ^NSFetchRequest *(NSURL *URL) {
blockURL = URL;
return nil;
};
operation.fetchRequestBlocks = @[fetchRequesBlock];
NSError *error;
[operation localObjectsFromFetchRequestsMatchingRequestURL:&error];
expect(blockURL).notTo.beNil();
expect([blockURL.baseURL absoluteString]).to.equal(@"http://restkit.org/api/v1/");
expect(blockURL.relativePath).to.equal(@"categories/1234");
}
- (void)testFetchRequestBlocksDoNotCrash
{
RKLogConfigureByName("RestKit/Network/CoreData", RKLogLevelTrace);
NSURL *baseURL = [NSURL URLWithString:@"http://restkit.org/api/v1/"];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"categories/1234" relativeToURL:baseURL]];
NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:request.URL statusCode:200 HTTPVersion:@"1.1" headerFields:@{}];
RKObjectMapping *mapping = [RKObjectMapping requestMapping];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:mapping pathPattern:@"categories/:categoryID" keyPath:nil statusCodes:[NSIndexSet indexSetWithIndex:200]];
responseDescriptor.baseURL = baseURL;
id mockRequestOperation = [OCMockObject niceMockForClass:[RKHTTPRequestOperation class]];
[[[mockRequestOperation stub] andReturn:request] request];
[[[mockRequestOperation stub] andReturn:response] response];
RKManagedObjectRequestOperation *operation = [[RKManagedObjectRequestOperation alloc] initWithHTTPRequestOperation:mockRequestOperation responseDescriptors:@[ responseDescriptor ]];
RKFetchRequestBlock fetchRequesBlock = ^NSFetchRequest *(NSURL *URL) {
return [NSFetchRequest fetchRequestWithEntityName:@"RKHuman"];
};
operation.fetchRequestBlocks = @[fetchRequesBlock];
NSError *error;
[operation localObjectsFromFetchRequestsMatchingRequestURL:&error];
}
- (void)testThatFetchRequestBlocksInvokedWithRelativeURLAreInAgreementWithPathPattern
{
NSURL *baseURL = [NSURL URLWithString:@"http://restkit.org/api/v1/"];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"library/" relativeToURL:baseURL]];
NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:request.URL statusCode:200 HTTPVersion:@"1.1" headerFields:@{}];
expect([request.URL absoluteString]).to.equal(@"http://restkit.org/api/v1/library/");
RKObjectMapping *mapping = [RKObjectMapping requestMapping];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:mapping pathPattern:@"library/" keyPath:nil statusCodes:[NSIndexSet indexSetWithIndex:200]];
responseDescriptor.baseURL = baseURL;
id mockRequestOperation = [OCMockObject niceMockForClass:[RKHTTPRequestOperation class]];
[[[mockRequestOperation stub] andReturn:request] request];
[[[mockRequestOperation stub] andReturn:response] response];
RKManagedObjectRequestOperation *operation = [[RKManagedObjectRequestOperation alloc] initWithHTTPRequestOperation:mockRequestOperation responseDescriptors:@[ responseDescriptor ]];
__block NSURL *blockURL = nil;
RKFetchRequestBlock fetchRequesBlock = ^NSFetchRequest *(NSURL *URL) {
blockURL = URL;
return nil;
};
operation.fetchRequestBlocks = @[fetchRequesBlock];
NSError *error;
[operation localObjectsFromFetchRequestsMatchingRequestURL:&error];
expect(blockURL).notTo.beNil();
expect([blockURL absoluteString]).to.equal(@"http://restkit.org/api/v1/library/");
expect([blockURL.baseURL absoluteString]).to.equal(@"http://restkit.org/api/v1/");
expect(blockURL.relativePath).to.equal(@"library");
expect(blockURL.relativeString).to.equal(@"library/");
}
- (void)testThatMappingResultContainsObjectsFetchedFromManagedObjectContextTheOperationWasInitializedWith
{
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"/JSON/humans/all.json" relativeToURL:[RKTestFactory baseURL]]];
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
RKEntityMapping *humanMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore];
[humanMapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:@"name" toKeyPath:@"name"]];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:humanMapping pathPattern:nil keyPath:@"human" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
RKManagedObjectRequestOperation *managedObjectRequestOperation = [[RKManagedObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[responseDescriptor]];
managedObjectRequestOperation.managedObjectContext = managedObjectStore.mainQueueManagedObjectContext;
[managedObjectRequestOperation start];
[managedObjectRequestOperation waitUntilFinished];
expect(managedObjectRequestOperation.mappingResult).notTo.beNil();
NSArray *managedObjectContexts = [[managedObjectRequestOperation.mappingResult array] valueForKeyPath:@"@distinctUnionOfObjects.managedObjectContext"];
expect([managedObjectContexts count]).to.equal(1);
expect(managedObjectContexts).to.equal([NSArray arrayWithObject:managedObjectStore.mainQueueManagedObjectContext]);
}
// 304 'Not Modified'
- (void)testThatManagedObjectsAreFetchedWhenHandlingAResponseThatCanSkipMapping
{
RKFetchRequestBlock fetchRequestBlock = ^(NSURL *URL){
return [NSFetchRequest fetchRequestWithEntityName:@"Human"];
};
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
RKHuman *human = [NSEntityDescription insertNewObjectForEntityForName:@"Human" inManagedObjectContext:managedObjectStore.mainQueueManagedObjectContext];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"/humans/1" relativeToURL:[RKTestFactory baseURL]]];
// Store a cache entry indicating that the response has been previously mapped
NSData *responseData = [@"{}" dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *headers = @{ @"Etag": @"\"2cdd0a2b329541d81e82ab20aff6281b\"", @"Content-Type": @"application/json" };
NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:[request URL] statusCode:200 HTTPVersion:@"1.1" headerFields:headers];
NSAssert(response, @"Failed to build cached response");
NSCachedURLResponse *cachedResponse = [[NSCachedURLResponse alloc] initWithResponse:response data:responseData userInfo:@{RKResponseHasBeenMappedCacheUserInfoKey: @YES} storagePolicy:NSURLCacheStorageAllowed];
[[NSURLCache sharedURLCache] storeCachedResponse:cachedResponse forRequest:request];
RKEntityMapping *humanMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore];
[humanMapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:@"name" toKeyPath:@"name"]];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:humanMapping pathPattern:nil keyPath:@"human" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
RKManagedObjectRequestOperation *managedObjectRequestOperation = [[RKManagedObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[responseDescriptor]];
managedObjectRequestOperation.fetchRequestBlocks = @[fetchRequestBlock];
managedObjectRequestOperation.managedObjectContext = managedObjectStore.mainQueueManagedObjectContext;
[managedObjectRequestOperation start];
[managedObjectRequestOperation waitUntilFinished];
expect(managedObjectRequestOperation.mappingResult).notTo.beNil();
NSArray *mappedObjects = [managedObjectRequestOperation.mappingResult array];
expect(mappedObjects).to.haveCountOf(1);
expect([mappedObjects[0] objectID]).to.equal([human objectID]);
}
- (void)testThatCachedNotModifiedResponseIsNotUsedWhenMappingFailedToComplete
{
[[NSURLCache sharedURLCache] removeAllCachedResponses];
RKFetchRequestBlock fetchRequestBlock = ^(NSURL *URL){
return [NSFetchRequest fetchRequestWithEntityName:@"Human"];
};
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"/coredata/etag" relativeToURL:[RKTestFactory baseURL]]];
RKEntityMapping *humanMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore];
[humanMapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:@"name" toKeyPath:@"name"]];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:humanMapping pathPattern:nil keyPath:@"human" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
RKManagedObjectRequestOperation *initialManagedObjectRequestOperation = [[RKManagedObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[responseDescriptor]];
initialManagedObjectRequestOperation.fetchRequestBlocks = @[fetchRequestBlock];
initialManagedObjectRequestOperation.managedObjectContext = managedObjectStore.persistentStoreManagedObjectContext;
initialManagedObjectRequestOperation.managedObjectCache = managedObjectStore.managedObjectCache;
// Send our first request in order to generate a cache entry, ensuring mapping is suspended and thus no objects are created in the store
NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init];
[[RKObjectRequestOperation responseMappingQueue] setSuspended:YES];
[operationQueue addOperation:initialManagedObjectRequestOperation];
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]];
[initialManagedObjectRequestOperation cancel];
expect(initialManagedObjectRequestOperation.isCancelled).to.beTruthy();
expect([[NSURLCache sharedURLCache] cachedResponseForRequest:request]).toNot.beNil();
expect(initialManagedObjectRequestOperation.mappingResult).to.beNil();
// Now setup and send our second request
[[RKObjectRequestOperation responseMappingQueue] setSuspended:NO];
RKManagedObjectRequestOperation *secondManagedObjectRequestOperation = [[RKManagedObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[responseDescriptor]];
secondManagedObjectRequestOperation.fetchRequestBlocks = @[fetchRequestBlock];
secondManagedObjectRequestOperation.managedObjectContext = managedObjectStore.persistentStoreManagedObjectContext;
secondManagedObjectRequestOperation.managedObjectCache = managedObjectStore.managedObjectCache;
[operationQueue addOperation:secondManagedObjectRequestOperation];
[operationQueue waitUntilAllOperationsAreFinished];
expect(secondManagedObjectRequestOperation.mappingResult).notTo.beNil();
NSArray *mappedObjects = [secondManagedObjectRequestOperation.mappingResult array];
expect(mappedObjects).to.haveCountOf(2);
}
- (void)testThatInvalidObjectFailingManagedObjectContextSaveFailsOperation
{
// NOTE: The model defines a maximum length of 15 for the 'name' attribute
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
RKHuman *human = [RKTestFactory insertManagedObjectForEntityForName:@"Human" inManagedObjectContext:nil withProperties:nil];
human.name = @"This Is An Invalid Name Because It Exceeds Fifteen Characters";
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"/JSON/humans/all.json" relativeToURL:[RKTestFactory baseURL]]];
RKEntityMapping *humanMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore];
[humanMapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:@"name" toKeyPath:@"name"]];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:humanMapping pathPattern:nil keyPath:@"human" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
RKManagedObjectRequestOperation *managedObjectRequestOperation = [[RKManagedObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[responseDescriptor]];
managedObjectRequestOperation.managedObjectContext = managedObjectStore.mainQueueManagedObjectContext;
[managedObjectRequestOperation start];
[managedObjectRequestOperation waitUntilFinished];
expect(managedObjectRequestOperation.error).notTo.beNil();
expect(managedObjectRequestOperation.mappingResult).to.beNil();
#if __IPHONE_OS_VERSION_MIN_REQUIRED
expect([managedObjectRequestOperation.error localizedDescription]).to.equal(@"The operation couldnt be completed. (Cocoa error 1660.)");
#else
expect([managedObjectRequestOperation.error localizedDescription]).to.equal(@"name is too long.");
#endif
}
#pragma mark - Deletion Response Tests
// 204 application/json
- (void)testDeletionOfObjectWith204ResponseTriggersObjectDeletion
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
RKHuman *human = [RKTestFactory insertManagedObjectForEntityForName:@"Human" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext withProperties:nil];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"/humans/204" relativeToURL:[RKTestFactory baseURL]]];
request.HTTPMethod = @"DELETE";
RKManagedObjectRequestOperation *managedObjectRequestOperation = [[RKManagedObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[]];
managedObjectRequestOperation.managedObjectContext = managedObjectStore.persistentStoreManagedObjectContext;
managedObjectRequestOperation.targetObject = human;
[managedObjectRequestOperation start];
[managedObjectRequestOperation waitUntilFinished];
expect(managedObjectRequestOperation.error).to.beNil();
expect([human hasBeenDeleted]).to.equal(YES);
}
// 200 application/json ""
- (void)testDeletionOfObjectWithZeroLengthResponseTriggersObjectDeletion
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
RKHuman *human = [RKTestFactory insertManagedObjectForEntityForName:@"Human" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext withProperties:nil];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"/humans/empty" relativeToURL:[RKTestFactory baseURL]]];
request.HTTPMethod = @"DELETE";
RKManagedObjectRequestOperation *managedObjectRequestOperation = [[RKManagedObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[]];
managedObjectRequestOperation.managedObjectContext = managedObjectStore.persistentStoreManagedObjectContext;
managedObjectRequestOperation.targetObject = human;
[managedObjectRequestOperation start];
[managedObjectRequestOperation waitUntilFinished];
expect(managedObjectRequestOperation.error).to.beNil();
expect([human hasBeenDeleted]).to.equal(YES);
}
// 200 application/json "{}"
- (void)testDeletionOfObjectWithEmptyDictionaryResponseTriggersObjectDeletion
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
RKHuman *human = [RKTestFactory insertManagedObjectForEntityForName:@"Human" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext withProperties:nil];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"/humans/1" relativeToURL:[RKTestFactory baseURL]]];
request.HTTPMethod = @"DELETE";
RKManagedObjectRequestOperation *managedObjectRequestOperation = [[RKManagedObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[]];
managedObjectRequestOperation.managedObjectContext = managedObjectStore.persistentStoreManagedObjectContext;
managedObjectRequestOperation.targetObject = human;
[managedObjectRequestOperation start];
expect(managedObjectRequestOperation.error).to.beNil();
expect([human hasBeenDeleted]).to.equal(YES);
}
// 200 application/json { "human": { "status": "OK" } }
- (void)testDeletionOfObjectWithUnmappedResponseBody
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
RKHuman *human = [RKTestFactory insertManagedObjectForEntityForName:@"Human" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext withProperties:nil];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"/humans/success" relativeToURL:[RKTestFactory baseURL]]];
request.HTTPMethod = @"DELETE";
RKManagedObjectRequestOperation *managedObjectRequestOperation = [[RKManagedObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[]];
managedObjectRequestOperation.managedObjectContext = managedObjectStore.persistentStoreManagedObjectContext;
managedObjectRequestOperation.targetObject = human;
[managedObjectRequestOperation start];
expect(managedObjectRequestOperation.error).to.beNil();
expect([human hasBeenDeleted]).to.equal(YES);
}
// 200 application/json { "human": { "status": "OK" } }
- (void)testDeletionOfObjectWithResponseDescriptorMappingResponseByURL
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
RKEntityMapping *entityMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore];
[entityMapping addAttributeMappingsFromDictionary:@{ @"human.status" : @"name" }];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:entityMapping pathPattern:@"/humans/success" keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
RKHuman *human = [RKTestFactory insertManagedObjectForEntityForName:@"Human" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext withProperties:nil];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"/humans/success" relativeToURL:[RKTestFactory baseURL]]];
request.HTTPMethod = @"DELETE";
RKManagedObjectRequestOperation *managedObjectRequestOperation = [[RKManagedObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[ responseDescriptor ]];
managedObjectRequestOperation.managedObjectContext = managedObjectStore.persistentStoreManagedObjectContext;
managedObjectRequestOperation.targetObject = human;
[managedObjectRequestOperation start];
expect(managedObjectRequestOperation.error).to.beNil();
expect([human hasBeenDeleted]).to.equal(YES);
}
// 200 application/json { "human": { "status": "OK" } }
- (void)testDeletionOfObjectWithResponseDescriptorMappingResponseByKeyPath
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
RKEntityMapping *entityMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore];
[entityMapping addAttributeMappingsFromDictionary:@{ @"status" : @"name" }];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:entityMapping pathPattern:nil keyPath:@"human" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
RKHuman *human = [RKTestFactory insertManagedObjectForEntityForName:@"Human" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext withProperties:nil];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"/humans/success" relativeToURL:[RKTestFactory baseURL]]];
request.HTTPMethod = @"DELETE";
RKManagedObjectRequestOperation *managedObjectRequestOperation = [[RKManagedObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[ responseDescriptor ]];
managedObjectRequestOperation.managedObjectContext = managedObjectStore.persistentStoreManagedObjectContext;
managedObjectRequestOperation.targetObject = human;
[managedObjectRequestOperation start];
expect(managedObjectRequestOperation.error).to.beNil();
expect([human hasBeenDeleted]).to.equal(YES);
}
- (void)testThatDeletionOfObjectThatHasAlreadyBeenDeletedFromCoreDataDoesNotRaiseException
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
RKHuman *human = [RKTestFactory insertManagedObjectForEntityForName:@"Human" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext withProperties:nil];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"/humans/success" relativeToURL:[RKTestFactory baseURL]]];
request.HTTPMethod = @"DELETE";
[managedObjectStore.persistentStoreManagedObjectContext saveToPersistentStore:nil];
RKManagedObjectRequestOperation *managedObjectRequestOperation = [[RKManagedObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[]];
managedObjectRequestOperation.managedObjectContext = managedObjectStore.persistentStoreManagedObjectContext;
managedObjectRequestOperation.targetObject = human;
[managedObjectRequestOperation start];
[managedObjectRequestOperation waitUntilFinished];
expect(managedObjectRequestOperation.error).to.beNil();
expect([human hasBeenDeleted]).to.equal(YES);
}
- (void)testThatManagedObjectMappedAsTheRelationshipOfNonManagedObjectsAreRefetchedFromTheParentContext
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
RKObjectMapping *userMapping = [RKObjectMapping mappingForClass:[RKTestUser class]];
RKEntityMapping *entityMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore];
[entityMapping addAttributeMappingsFromArray:@[ @"name" ]];
[userMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"favorite_cat" toKeyPath:@"friends" withMapping:entityMapping]];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:userMapping 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 ]];
managedObjectRequestOperation.managedObjectContext = managedObjectStore.persistentStoreManagedObjectContext;
[managedObjectRequestOperation start];
expect(managedObjectRequestOperation.error).to.beNil();
expect([managedObjectRequestOperation.mappingResult array]).to.haveCountOf(1);
RKTestUser *testUser = [managedObjectRequestOperation.mappingResult firstObject];
expect([[testUser.friends lastObject] managedObjectContext]).to.equal(managedObjectStore.persistentStoreManagedObjectContext);
}
- (void)testThatManagedObjectMappedAsTheRelationshipOfNonManagedObjectsWithADynamicMappingAreRefetchedFromTheParentContext
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
RKObjectMapping *userMapping = [RKObjectMapping mappingForClass:[RKTestUser class]];
RKEntityMapping *entityMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore];
[entityMapping addAttributeMappingsFromArray:@[ @"name" ]];
[userMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"favorite_cat" toKeyPath:@"friends" withMapping:entityMapping]];
RKDynamicMapping *dynamicMapping = [RKDynamicMapping new];
[dynamicMapping addMatcher:[RKObjectMappingMatcher matcherWithKeyPath:@"name" expectedValue:@"Blake Watters" objectMapping:userMapping]];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:dynamicMapping 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 ]];
managedObjectRequestOperation.managedObjectContext = managedObjectStore.persistentStoreManagedObjectContext;
[managedObjectRequestOperation start];
expect(managedObjectRequestOperation.error).to.beNil();
expect([managedObjectRequestOperation.mappingResult array]).to.haveCountOf(1);
RKTestUser *testUser = [managedObjectRequestOperation.mappingResult firstObject];
expect([[testUser.friends lastObject] managedObjectContext]).to.equal(managedObjectStore.persistentStoreManagedObjectContext);
}
- (void)testThatManagedObjectMappedFromRootKeyPathAreRefetchedFromTheParentContext
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
RKEntityMapping *entityMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore];
[entityMapping addAttributeMappingsFromDictionary:@{ @"human.name": @"name" }];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:entityMapping pathPattern:nil keyPath:nil 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 ]];
managedObjectRequestOperation.managedObjectContext = managedObjectStore.persistentStoreManagedObjectContext;
[managedObjectRequestOperation start];
expect(managedObjectRequestOperation.error).to.beNil();
expect([managedObjectRequestOperation.mappingResult array]).to.haveCountOf(1);
NSManagedObject *managedObject = [managedObjectRequestOperation.mappingResult firstObject];
expect([managedObject managedObjectContext]).to.equal(managedObjectStore.persistentStoreManagedObjectContext);
}
- (void)testThatManagedObjectMappedToNSSetRelationshipOfNonManagedObjectsAreRefetchedFromTheParentContext
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
RKObjectMapping *userMapping = [RKObjectMapping mappingForClass:[RKTestUser class]];
RKEntityMapping *entityMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore];
[entityMapping addAttributeMappingsFromArray:@[ @"name" ]];
[userMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"favorite_cat" toKeyPath:@"friendsSet" withMapping:entityMapping]];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:userMapping 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 ]];
managedObjectRequestOperation.managedObjectContext = managedObjectStore.persistentStoreManagedObjectContext;
[managedObjectRequestOperation start];
expect(managedObjectRequestOperation.error).to.beNil();
expect([managedObjectRequestOperation.mappingResult array]).to.haveCountOf(1);
RKTestUser *testUser = [managedObjectRequestOperation.mappingResult firstObject];
expect([[testUser.friendsSet anyObject] managedObjectContext]).to.equal(managedObjectStore.persistentStoreManagedObjectContext);
}
- (void)testThatManagedObjectMappedToNSOrderedSetRelationshipOfNonManagedObjectsAreRefetchedFromTheParentContext
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
RKObjectMapping *userMapping = [RKObjectMapping mappingForClass:[RKTestUser class]];
RKEntityMapping *entityMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore];
[entityMapping addAttributeMappingsFromArray:@[ @"name" ]];
[userMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"favorite_cat" toKeyPath:@"friendsOrderedSet" withMapping:entityMapping]];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:userMapping 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 ]];
managedObjectRequestOperation.managedObjectContext = managedObjectStore.persistentStoreManagedObjectContext;
[managedObjectRequestOperation start];
expect(managedObjectRequestOperation.error).to.beNil();
expect([managedObjectRequestOperation.mappingResult array]).to.haveCountOf(1);
RKTestUser *testUser = [managedObjectRequestOperation.mappingResult firstObject];
expect([[testUser.friendsOrderedSet firstObject] managedObjectContext]).to.equal(managedObjectStore.persistentStoreManagedObjectContext);
}
- (void)testMappingRespectsTargetObjectWhenMappingNonManagedThatIncludesChildManagedObject
{
RKTestUser *testUser = [RKTestUser new];
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
RKObjectMapping *userMapping = [RKObjectMapping mappingForClass:[RKTestUser class]];
RKEntityMapping *entityMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore];
[entityMapping addAttributeMappingsFromArray:@[ @"name" ]];
[userMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"favorite_cat" toKeyPath:@"friendsOrderedSet" withMapping:entityMapping]];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:userMapping 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 ]];
managedObjectRequestOperation.targetObject = testUser;
managedObjectRequestOperation.managedObjectContext = managedObjectStore.persistentStoreManagedObjectContext;
[managedObjectRequestOperation start];
expect(managedObjectRequestOperation.error).to.beNil();
expect([managedObjectRequestOperation.mappingResult array]).to.haveCountOf(1);
RKTestUser *mappedTestUser = [managedObjectRequestOperation.mappingResult firstObject];
expect(mappedTestUser).to.equal(testUser);
}
- (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];
RKHuman *orphanedHuman = [NSEntityDescription insertNewObjectForEntityForName:@"Human" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
RKObjectMapping *userMapping = [RKObjectMapping mappingForClass:[RKTestUser class]];
RKEntityMapping *entityMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore];
[entityMapping addAttributeMappingsFromArray:@[ @"name" ]];
[userMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"favorite_cat" toKeyPath:@"friends" withMapping:entityMapping]];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:userMapping 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)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:@"Title" forKey:@"title"];
[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"];
[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);
}
- (void)testPathVisitationDoesNotRecurseInfinitelyForSelfReferentialMappings
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
RKHuman *orphanedHuman = [NSEntityDescription insertNewObjectForEntityForName:@"Human" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
RKEntityMapping *entityMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore];
[entityMapping addAttributeMappingsFromArray:@[ @"name" ]];
[entityMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"friends" toKeyPath:@"friends" withMapping:entityMapping]];
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;
RKFetchRequestManagedObjectCache *managedObjectCache = [RKFetchRequestManagedObjectCache new];
managedObjectRequestOperation.managedObjectCache = managedObjectCache;
[managedObjectRequestOperation start];
expect(managedObjectRequestOperation.error).to.beNil();
expect([managedObjectRequestOperation.mappingResult array]).to.haveCountOf(1);
expect(orphanedHuman.managedObjectContext).to.beNil();
}
- (void)testDeletionOfObjectsMappedFindsObjectsMappedBySelfReferentialMappings
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
RKEntityMapping *entityMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore];
entityMapping.identificationAttributes = @[ @"railsID" ];
[entityMapping addAttributeMappingsFromDictionary:@{ @"name": @"name", @"id": @"railsID" }];
[entityMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"friends" toKeyPath:@"friends" withMapping:entityMapping]];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:entityMapping pathPattern:nil keyPath:nil statusCodes:[NSIndexSet indexSetWithIndex:200]];
// Create Blake, Sarah, Colin, Monkey & Orphan
NSManagedObjectContext *context = managedObjectStore.persistentStoreManagedObjectContext;
NSUInteger count = [context countForEntityForName:@"Human" predicate:nil error:nil];
expect(count).to.equal(0);
RKHuman *blake = [RKTestFactory insertManagedObjectForEntityForName:@"Human" inManagedObjectContext:context withProperties:@{ @"railsID": @(1), @"name": @"Blake" }];
RKHuman *sarah = [RKTestFactory insertManagedObjectForEntityForName:@"Human" inManagedObjectContext:context withProperties:@{ @"railsID": @(2), @"name": @"Sarah" }];
RKHuman *monkey = [RKTestFactory insertManagedObjectForEntityForName:@"Human" inManagedObjectContext:context withProperties:@{ @"railsID": @(3), @"name": @"Monkey" }];
RKHuman *colin = [RKTestFactory insertManagedObjectForEntityForName:@"Human" inManagedObjectContext:context withProperties:@{ @"railsID": @(4), @"name": @"Colin" }];
RKHuman *orphan = [RKTestFactory insertManagedObjectForEntityForName:@"Human" inManagedObjectContext:context withProperties:@{ @"railsID": @(5), @"name": @"Orphan" }];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"/JSON/humans/self_referential.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;
RKFetchRequestManagedObjectCache *managedObjectCache = [RKFetchRequestManagedObjectCache new];
managedObjectRequestOperation.managedObjectCache = managedObjectCache;
[managedObjectRequestOperation start];
expect(managedObjectRequestOperation.error).to.beNil();
expect([managedObjectRequestOperation.mappingResult array]).to.haveCountOf(1);
// Verify that orphan was deleted
count = [context countForEntityForName:@"Human" predicate:nil error:nil];
expect(count).to.equal(4);
expect(blake.managedObjectContext).notTo.beNil();
expect(sarah.managedObjectContext).notTo.beNil();
expect(monkey.managedObjectContext).notTo.beNil();
expect(colin.managedObjectContext).notTo.beNil();
expect(orphan.managedObjectContext).to.beNil();
}
- (void)testDeletionOfObjectsMappedFindsObjectsMappedByNestedSelfReferentialMappings
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
RKEntityMapping *houseMapping = [RKEntityMapping mappingForEntityForName:@"House" inManagedObjectStore:managedObjectStore];
[houseMapping addAttributeMappingsFromDictionary:@{ @"houseID": @"railsID" }];
[houseMapping addAttributeMappingsFromArray:@[ @"city", @"state" ]];
houseMapping.identificationAttributes = @[ @"railsID" ];
RKEntityMapping *humanMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore];
humanMapping.identificationAttributes = @[ @"railsID" ];
[humanMapping addAttributeMappingsFromDictionary:@{ @"name": @"name", @"humanID": @"railsID" }];
[humanMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"roommates" toKeyPath:@"friends" withMapping:humanMapping]];
[humanMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"landlord" toKeyPath:@"landlord" withMapping:humanMapping]];
[houseMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"owner" toKeyPath:@"owner" withMapping:humanMapping]];
[houseMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"occupants" toKeyPath:@"occupants" withMapping:humanMapping]];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:houseMapping pathPattern:nil keyPath:@"houses" statusCodes:[NSIndexSet indexSetWithIndex:200]];
// Create Blake, Sarah, Colin, Monkey & Orphan
NSManagedObjectContext *context = managedObjectStore.persistentStoreManagedObjectContext;
RKHuman *orphan = [RKTestFactory insertManagedObjectForEntityForName:@"Human" inManagedObjectContext:context withProperties:@{ @"railsID": @(5), @"name": @"Orphan" }];
RKHuman *edward = [RKTestFactory insertManagedObjectForEntityForName:@"Human" inManagedObjectContext:context withProperties:@{ @"railsID": @(4), @"name": @"Edward" }];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"/JSON/humans/nested_self_referential.json" relativeToURL:[RKTestFactory baseURL]]];
RKManagedObjectRequestOperation *managedObjectRequestOperation = [[RKManagedObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[ responseDescriptor ]];
RKFetchRequestBlock humanFetchRequestBlock = ^NSFetchRequest * (NSURL *URL) {
return [NSFetchRequest fetchRequestWithEntityName:@"Human"];
};
RKFetchRequestBlock houseFetchRequestBlock = ^NSFetchRequest * (NSURL *URL) {
return [NSFetchRequest fetchRequestWithEntityName:@"House"];
};
managedObjectRequestOperation.fetchRequestBlocks = @[ humanFetchRequestBlock, houseFetchRequestBlock ];
managedObjectRequestOperation.managedObjectContext = managedObjectStore.persistentStoreManagedObjectContext;
managedObjectRequestOperation.deletesOrphanedObjects = YES;
RKFetchRequestManagedObjectCache *managedObjectCache = [RKFetchRequestManagedObjectCache new];
managedObjectRequestOperation.managedObjectCache = managedObjectCache;
[managedObjectRequestOperation start];
expect(managedObjectRequestOperation.error).to.beNil();
expect([managedObjectRequestOperation.mappingResult array]).to.haveCountOf(1);
NSUInteger count = [context countForEntityForName:@"Human" predicate:nil error:nil];
expect(count).to.equal(4);
count = [context countForEntityForName:@"House" predicate:nil error:nil];
expect(count).to.equal(1);
expect(edward.managedObjectContext).notTo.beNil();
expect(orphan.managedObjectContext).to.beNil();
}
- (void)testDeletionOfOrphanedObjectsMappedWithCyclicRelationshipThatIsNotSelfReferential
{
NSManagedObjectModel *managedObjectModel = [NSManagedObjectModel new];
NSEntityDescription *listEntity = [NSEntityDescription new];
[listEntity setName:@"List"];
NSAttributeDescription *listNameAttribute = [NSAttributeDescription new];
[listNameAttribute setName:@"name"];
[listNameAttribute setAttributeType:NSStringAttributeType];
NSEntityDescription *authorEntity = [NSEntityDescription new];
[authorEntity setName:@"Author"];
NSAttributeDescription *authorNameAttribute = [NSAttributeDescription new];
[authorNameAttribute setName:@"name"];
[authorNameAttribute setAttributeType:NSStringAttributeType];
[authorEntity setProperties:@[ authorNameAttribute ]];
NSEntityDescription *entryEntity = [NSEntityDescription new];
[entryEntity setName:@"Entry"];
NSAttributeDescription *entryNameAttribute = [NSAttributeDescription new];
[entryNameAttribute setName:@"name"];
[entryNameAttribute setAttributeType:NSStringAttributeType];
NSAttributeDescription *entryValueAttribute = [NSAttributeDescription new];
[entryValueAttribute setName:@"value"];
[entryValueAttribute setAttributeType:NSStringAttributeType];
// Create relationships
NSRelationshipDescription *listHasOneAuthorRelationship = [NSRelationshipDescription new];
[listHasOneAuthorRelationship setName:@"author"];
[listHasOneAuthorRelationship setDestinationEntity:authorEntity];
[listHasOneAuthorRelationship setMaxCount:1]; // To One
NSRelationshipDescription *authorHasManyListsRelationship = [NSRelationshipDescription new];
[authorHasManyListsRelationship setName:@"lists"];
[authorHasManyListsRelationship setDestinationEntity:listEntity];
[authorHasManyListsRelationship setMaxCount:0]; // To Many
[authorHasManyListsRelationship setInverseRelationship:listHasOneAuthorRelationship];
[listHasOneAuthorRelationship setInverseRelationship:authorHasManyListsRelationship];
NSRelationshipDescription *listHasManyValuesRelationship = [NSRelationshipDescription new];
[listHasManyValuesRelationship setName:@"entries"];
[listHasManyValuesRelationship setDestinationEntity:entryEntity];
[listHasManyValuesRelationship setMaxCount:0]; // To Many
NSRelationshipDescription *entryBelongsToListRelationship = [NSRelationshipDescription new];
[entryBelongsToListRelationship setName:@"list"];
[entryBelongsToListRelationship setDestinationEntity:listEntity];
[entryBelongsToListRelationship setMaxCount:1]; // To One
[entryBelongsToListRelationship setInverseRelationship:listHasManyValuesRelationship];
[listHasManyValuesRelationship setInverseRelationship:entryBelongsToListRelationship];
NSRelationshipDescription *entryRelatesToOtherListRelationship = [NSRelationshipDescription new];
[entryRelatesToOtherListRelationship setName:@"relatedList"];
[entryRelatesToOtherListRelationship setDestinationEntity:listEntity];
[entryRelatesToOtherListRelationship setMaxCount:1]; // To One
[entryRelatesToOtherListRelationship setInverseRelationship:listHasManyValuesRelationship];
// Set the properties
[authorEntity setProperties:@[ authorNameAttribute, authorHasManyListsRelationship ]];
[listEntity setProperties:@[ listNameAttribute, listHasOneAuthorRelationship, listHasManyValuesRelationship ]];
[entryEntity setProperties:@[ entryNameAttribute, entryValueAttribute, entryBelongsToListRelationship, entryRelatesToOtherListRelationship ]];
[managedObjectModel setEntities:@[ listEntity, authorEntity, entryEntity ]];
// Configure a Core Data stack for this model
NSError *error = nil;
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel];
[managedObjectStore createPersistentStoreCoordinator];
[managedObjectStore addInMemoryPersistentStore:&error];
[managedObjectStore createManagedObjectContexts];
// Create mappings
RKEntityMapping *listMapping = [[RKEntityMapping alloc] initWithEntity:listEntity];
listMapping.identificationAttributes = @[ @"name" ];
[listMapping addAttributeMappingsFromArray:@[ @"name" ]];
RKEntityMapping *authorMapping = [[RKEntityMapping alloc] initWithEntity:authorEntity];
authorMapping.identificationAttributes = @[ @"name" ];
[authorMapping addAttributeMappingsFromArray:@[ @"name" ]];
RKEntityMapping *entryMapping = [[RKEntityMapping alloc] initWithEntity:entryEntity];
entryMapping.identificationAttributes = @[ @"name" ];
[entryMapping addAttributeMappingsFromArray:@[ @"name" ]];
// NOTE: This cyclic mapping should trigger an explosion...
[entryMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"list"
toKeyPath:@"list"
withMapping:listMapping]];
[entryMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"relatedList"
toKeyPath:@"relatedList"
withMapping:listMapping]];
[listMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"author"
toKeyPath:@"author"
withMapping:authorMapping]];
RKRelationshipMapping *entriesRelationship = [RKRelationshipMapping relationshipMappingFromKeyPath:@"entries"
toKeyPath:@"entries"
withMapping:entryMapping];
entriesRelationship.assignmentPolicy = RKUnionAssignmentPolicy;
[listMapping addPropertyMapping:entriesRelationship];
RKObjectMapping *listsOfListsMapping = [RKObjectMapping mappingForClass:[RKTestListOfLists class]];
[listsOfListsMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"lists" toKeyPath:@"listOfLists" withMapping:listMapping]];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:listsOfListsMapping
pathPattern:nil
keyPath:nil
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
// Create an orphaned Author and List
NSManagedObject *orphanedAuthor = [[NSManagedObject alloc] initWithEntity:authorEntity insertIntoManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
[orphanedAuthor setValue:@"Orphaned Author" forKey:@"name"];
NSManagedObject *orphanedList = [[NSManagedObject alloc] initWithEntity:listEntity insertIntoManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
[orphanedList setValue:@"Orphaned List" forKey:@"name"];
// Create an existing List and Entry to be Unioned onto the result set
NSManagedObject *existingList = [[NSManagedObject alloc] initWithEntity:listEntity insertIntoManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
[existingList setValue:@"Second List" forKey:@"name"];
NSManagedObject *existingEntry = [[NSManagedObject alloc] initWithEntity:entryEntity insertIntoManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
[existingEntry setValue:@"Existing Entry" forKey:@"name"];
[existingList setValue:[NSSet setWithObject:existingEntry] forKey:@"entries"];
BOOL success = [managedObjectStore.persistentStoreManagedObjectContext saveToPersistentStore:&error];
expect(success).to.equal(YES);
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"/JSON/lists.json" relativeToURL:[RKTestFactory baseURL]]];
RKManagedObjectRequestOperation *managedObjectRequestOperation = [[RKManagedObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[ responseDescriptor ]];
RKFetchRequestBlock listFetchRequestBlock = ^NSFetchRequest * (NSURL *URL) {
return [NSFetchRequest fetchRequestWithEntityName:@"List"];
};
RKFetchRequestBlock authorFetchRequestBlock = ^NSFetchRequest * (NSURL *URL) {
return [NSFetchRequest fetchRequestWithEntityName:@"Author"];
};
RKFetchRequestBlock entryFetchRequestBlock = ^NSFetchRequest * (NSURL *URL) {
return [NSFetchRequest fetchRequestWithEntityName:@"Entry"];
};
managedObjectRequestOperation.fetchRequestBlocks = @[ listFetchRequestBlock, authorFetchRequestBlock, entryFetchRequestBlock ];
managedObjectRequestOperation.managedObjectContext = managedObjectStore.persistentStoreManagedObjectContext;
managedObjectRequestOperation.deletesOrphanedObjects = YES;
RKFetchRequestManagedObjectCache *managedObjectCache = [RKFetchRequestManagedObjectCache new];
managedObjectRequestOperation.managedObjectCache = managedObjectCache;
[managedObjectRequestOperation start];
expect(managedObjectRequestOperation.error).to.beNil();
expect([managedObjectRequestOperation.mappingResult array]).to.haveCountOf(1);
NSManagedObjectContext *managedObjectContext = managedObjectStore.persistentStoreManagedObjectContext;
NSUInteger count = [managedObjectContext countForEntityForName:@"List" predicate:nil error:nil];
expect(count).to.equal(3);
count = [managedObjectContext countForEntityForName:@"Entry" predicate:nil error:nil];
expect(count).to.equal(4);
count = [managedObjectContext countForEntityForName:@"Author" predicate:nil error:nil];
expect(count).to.equal(2);
// Orphans get deleted
expect(orphanedAuthor.managedObjectContext).to.beNil();
expect(orphanedList.managedObjectContext).to.beNil();
// Objects in the results do not
expect(existingList.managedObjectContext).notTo.beNil();
expect(existingEntry.managedObjectContext).notTo.beNil();
}
- (void)testMappingWithDynamicMappingContainingIncompatibleEntityMappingsAtSameKeyPath
{
RKDynamicMapping *dynamicMapping = [RKDynamicMapping new];
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
RKEntityMapping *humanMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore];
humanMapping.identificationAttributes = @[ @"railsID" ];
[humanMapping addAttributeMappingsFromDictionary:@{ @"name": @"name", @"humanID": @"railsID" }];
[humanMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"roommates" toKeyPath:@"friends" withMapping:humanMapping]];
RKEntityMapping *childMapping = [RKEntityMapping mappingForEntityForName:@"Child" inManagedObjectStore:managedObjectStore];
RKEntityMapping *parentMapping = [RKEntityMapping mappingForEntityForName:@"Parent" inManagedObjectStore:managedObjectStore];
parentMapping.identificationAttributes = @[ @"railsID" ];
[parentMapping addAttributeMappingsFromDictionary:@{ @"name": @"name", @"humanID": @"railsID" }];
[parentMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"children" toKeyPath:@"children" withMapping:childMapping]];
[dynamicMapping addMatcher:[RKObjectMappingMatcher matcherWithKeyPath:@"invalid" expectedValue:@"whatever" objectMapping:parentMapping]];
[dynamicMapping addMatcher:[RKObjectMappingMatcher matcherWithKeyPath:@"name" expectedValue:@"Blake" objectMapping:humanMapping]];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:dynamicMapping pathPattern:nil keyPath:nil statusCodes:[NSIndexSet indexSetWithIndex:200]];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"/JSON/humans/self_referential.json" relativeToURL:[RKTestFactory baseURL]]];
RKManagedObjectRequestOperation *managedObjectRequestOperation = [[RKManagedObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[ responseDescriptor ]];
RKFetchRequestBlock humanFetchRequestBlock = ^NSFetchRequest * (NSURL *URL) {
return [NSFetchRequest fetchRequestWithEntityName:@"Human"];
};
RKFetchRequestBlock parentFetchRequestBlock = ^NSFetchRequest * (NSURL *URL) {
return [NSFetchRequest fetchRequestWithEntityName:@"Parent"];
};
RKFetchRequestBlock childFetchRequestBlock = ^NSFetchRequest * (NSURL *URL) {
return [NSFetchRequest fetchRequestWithEntityName:@"Child"];
};
managedObjectRequestOperation.fetchRequestBlocks = @[ humanFetchRequestBlock, parentFetchRequestBlock, childFetchRequestBlock ];
managedObjectRequestOperation.managedObjectContext = managedObjectStore.persistentStoreManagedObjectContext;
managedObjectRequestOperation.deletesOrphanedObjects = YES;
RKFetchRequestManagedObjectCache *managedObjectCache = [RKFetchRequestManagedObjectCache new];
managedObjectRequestOperation.managedObjectCache = managedObjectCache;
[managedObjectRequestOperation start];
expect(managedObjectRequestOperation.error).to.beNil();
expect([managedObjectRequestOperation.mappingResult array]).to.haveCountOf(1);
}
- (void)testThatMappingObjectsWithTheSameIdentificationAttributesAcrossTwoObjectRequestOperationConcurrentlyDoesNotCreateDuplicateObjects
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
RKInMemoryManagedObjectCache *inMemoryCache = [[RKInMemoryManagedObjectCache alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
managedObjectStore.managedObjectCache = inMemoryCache;
RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore];
mapping.identificationAttributes = @[ @"railsID" ];
[mapping addAttributeMappingsFromArray:@[ @"name" ]];
[mapping addAttributeMappingsFromDictionary:@{ @"id": @"railsID" }];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:mapping pathPattern:nil keyPath:@"human" statusCodes:nil];
NSURL *URL = [NSURL URLWithString:@"humans/1" relativeToURL:[RKTestFactory baseURL]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
RKManagedObjectRequestOperation *firstOperation = [[RKManagedObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[ responseDescriptor ]];
firstOperation.managedObjectContext = managedObjectStore.persistentStoreManagedObjectContext;
firstOperation.managedObjectCache = inMemoryCache;
RKManagedObjectRequestOperation *secondOperation = [[RKManagedObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[ responseDescriptor ]];
secondOperation.managedObjectContext = managedObjectStore.persistentStoreManagedObjectContext;
secondOperation.managedObjectCache = inMemoryCache;
NSOperationQueue *operationQueue = [NSOperationQueue new];
[operationQueue setMaxConcurrentOperationCount:2];
[operationQueue setSuspended:YES];
[operationQueue addOperation:firstOperation];
[operationQueue addOperation:secondOperation];
// Start both operations
[operationQueue setSuspended:NO];
[operationQueue waitUntilAllOperationsAreFinished];
// Now pull the count back from the parent context
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Human"];
fetchRequest.predicate = [NSPredicate predicateWithFormat:@"railsID == 1"];
NSArray *fetchedObjects = [managedObjectStore.persistentStoreManagedObjectContext executeFetchRequest:fetchRequest error:nil];
expect(fetchedObjects).to.haveCountOf(1);
}
- (void)testManagedObjectRequestOperationCompletesAndIgnoresInvalidObjects
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
RKEntityMapping *postMapping = [RKEntityMapping mappingForEntityForName:@"Post" inManagedObjectStore:managedObjectStore];
[postMapping addAttributeMappingsFromArray:@[ @"title", @"body" ]];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:postMapping pathPattern:nil keyPath:@"posts" statusCodes:[NSIndexSet indexSetWithIndex:200]];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"/posts_with_invalid.json" relativeToURL:[RKTestFactory baseURL]]];
RKManagedObjectRequestOperation *managedObjectRequestOperation = [[RKManagedObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[ responseDescriptor ]];
managedObjectRequestOperation.managedObjectContext = managedObjectStore.persistentStoreManagedObjectContext;
[managedObjectRequestOperation start];
expect(managedObjectRequestOperation.error).to.beNil();
expect([managedObjectRequestOperation.mappingResult array]).to.haveCountOf(1);
}
- (void)testThatSuccessfulCompletionSavesManagedObjectIfTargetObjectIsUnsavedEvenIfNoMappingWasPerformed
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
RKHuman *human = [RKTestFactory insertManagedObjectForEntityForName:@"Human" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext withProperties:nil];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"/204" relativeToURL:[RKTestFactory baseURL]]];
request.HTTPMethod = @"POST";
RKManagedObjectRequestOperation *managedObjectRequestOperation = [[RKManagedObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[]];
managedObjectRequestOperation.managedObjectContext = managedObjectStore.persistentStoreManagedObjectContext;
managedObjectRequestOperation.targetObject = human;
[managedObjectRequestOperation start];
[managedObjectRequestOperation waitUntilFinished];
expect(managedObjectRequestOperation.error).to.beNil();
[managedObjectStore.persistentStoreManagedObjectContext performBlockAndWait:^{
expect([human isNew]).to.equal(NO);
}];
}
- (void)testThatMapperOperationDelegateIsPassedThroughToUnderlyingMapperOperation
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
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]]];
RKTestDelegateManagedObjectRequestOperation *managedObjectRequestOperation = [[RKTestDelegateManagedObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[ responseDescriptor ]];
id mockOperation = [OCMockObject partialMockForObject:managedObjectRequestOperation];
[[mockOperation expect] mapperWillStartMapping:OCMOCK_ANY];
managedObjectRequestOperation.managedObjectContext = managedObjectStore.persistentStoreManagedObjectContext;
[managedObjectRequestOperation start];
expect([managedObjectRequestOperation isFinished]).will.beTruthy();
[mockOperation verify];
}
- (void)testThatRefetchingOfNestedNonManagedAndManagedObjectsWorksWithHasOneRelations
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
RKObjectMapping *itemMapping = [RKObjectMapping mappingForClass:[RKMappableObject class]];
RKObjectMapping *userMapping = [RKObjectMapping mappingForClass:[RKTestUser class]];
RKEntityMapping *entityMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore];
[entityMapping addAttributeMappingsFromArray:@[ @"name" ]];
[userMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"favorite_cat" toKeyPath:@"bestFriend" withMapping:entityMapping]];
[itemMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"items.human" toKeyPath:@"hasMany" withMapping:userMapping]];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:itemMapping pathPattern:nil keyPath:@"result" statusCodes:[NSIndexSet indexSetWithIndex:200]];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"/JSON/humans/has_many_with_to_one_relationship.json" relativeToURL:[RKTestFactory baseURL]]];
RKManagedObjectRequestOperation *managedObjectRequestOperation = [[RKManagedObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[ responseDescriptor ]];
managedObjectRequestOperation.managedObjectContext = managedObjectStore.persistentStoreManagedObjectContext;
[managedObjectRequestOperation start];
expect(managedObjectRequestOperation.error).to.beNil();
RKMappableObject *result = [managedObjectRequestOperation.mappingResult.array lastObject];
RKTestUser *user = (RKTestUser *)result.hasMany.anyObject;
NSLog(@"Examining result = %@, with result.hasMany = %@, user = %@ and user.bestFriend(%@) = %@", result, result.hasMany, user, [user.bestFriend class], user.bestFriend);
expect(user.bestFriend).to.beInstanceOf([RKHuman class]);
expect([user.bestFriend managedObjectContext]).to.equal(managedObjectStore.persistentStoreManagedObjectContext);
}
- (void)testThatAnEmptyResultHasTheProperManagedObjectContext
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
RKEntityMapping *entityMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore];
[entityMapping addAttributeMappingsFromArray:@[ @"name" ]];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:entityMapping pathPattern:nil keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"/JSON/humans/empty_human.json" relativeToURL:[RKTestFactory baseURL]]];
RKManagedObjectRequestOperation *managedObjectRequestOperation = [[RKManagedObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[ responseDescriptor ]];
managedObjectRequestOperation.managedObjectContext = managedObjectStore.persistentStoreManagedObjectContext;
[managedObjectRequestOperation start];
expect(managedObjectRequestOperation.error).to.beNil();
RKHuman *result = [managedObjectRequestOperation.mappingResult.array lastObject];
expect(managedObjectRequestOperation.managedObjectContext).to.equal(result.managedObjectContext);
}
- (void)testMappingMetadataConfiguredOnTheOperation
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
RKEntityMapping *entityMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore];
[entityMapping addAttributeMappingsFromDictionary:@{ @"@metadata.nickName": @"nickName" }];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:entityMapping pathPattern:nil keyPath:@"human" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"/humans/1" relativeToURL:[RKTestFactory baseURL]]];
RKManagedObjectRequestOperation *managedObjectRequestOperation = [[RKManagedObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[ responseDescriptor ]];
managedObjectRequestOperation.managedObjectContext = managedObjectStore.persistentStoreManagedObjectContext;
managedObjectRequestOperation.mappingMetadata = @{ @"nickName": @"Big Sleezy" };
[managedObjectRequestOperation start];
expect(managedObjectRequestOperation.error).to.beNil();
expect(managedObjectRequestOperation.mappingResult).notTo.beNil();
RKHuman *human = [managedObjectRequestOperation.mappingResult firstObject];
expect(human.nickName).to.equal(@"Big Sleezy");
}
- (void)testCopyingOperation
{
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
RKEntityMapping *entityMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore];
[entityMapping addAttributeMappingsFromDictionary:@{ @"@metadata.nickName": @"nickName" }];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:entityMapping pathPattern:nil keyPath:@"human" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"/humans/1" relativeToURL:[RKTestFactory baseURL]]];
RKManagedObjectRequestOperation *managedObjectRequestOperation = [[RKManagedObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[ responseDescriptor ]];
managedObjectRequestOperation.managedObjectContext = managedObjectStore.persistentStoreManagedObjectContext;
RKManagedObjectRequestOperation *copiedOperation = [managedObjectRequestOperation copy];
copiedOperation.mappingMetadata = @{ @"nickName": @"Big Sleezy" };
[copiedOperation start];
expect(copiedOperation.error).to.beNil();
expect(copiedOperation.mappingResult).notTo.beNil();
RKHuman *human = [copiedOperation.mappingResult firstObject];
expect(human.nickName).to.equal(@"Big Sleezy");
}
@end