Files
RestKit/Tests/Logic/ObjectMapping/RKObjectLoaderTest.m

809 lines
35 KiB
Objective-C

//
// RKObjectLoaderTest.m
// RestKit
//
// Created by Blake Watters on 4/27/11.
// Copyright (c) 2009-2012 RestKit. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#import "RKTestEnvironment.h"
#import "RKObjectMappingProvider.h"
#import "RKErrorMessage.h"
#import "RKJSONParserJSONKit.h"
// Models
#import "RKObjectLoaderTestResultModel.h"
@interface RKTestComplexUser : NSObject {
NSNumber *_userID;
NSString *_firstname;
NSString *_lastname;
NSString *_email;
NSString *_phone;
}
@property (nonatomic, retain) NSNumber *userID;
@property (nonatomic, retain) NSString *firstname;
@property (nonatomic, retain) NSString *lastname;
@property (nonatomic, retain) NSString *email;
@property (nonatomic, retain) NSString *phone;
@end
@implementation RKTestComplexUser
@synthesize userID = _userID;
@synthesize firstname = _firstname;
@synthesize lastname = _lastname;
@synthesize phone = _phone;
@synthesize email = _email;
- (void)willSendWithObjectLoader:(RKObjectLoader *)objectLoader
{
return;
}
@end
@interface RKTestResponseLoaderWithWillMapData : RKTestResponseLoader {
id _mappableData;
}
@property (nonatomic, readonly) id mappableData;
@end
@implementation RKTestResponseLoaderWithWillMapData
@synthesize mappableData = _mappableData;
- (void)dealloc
{
[_mappableData release];
[super dealloc];
}
- (void)objectLoader:(RKObjectLoader *)loader willMapData:(inout id *)mappableData
{
[*mappableData setValue:@"monkey!" forKey:@"newKey"];
_mappableData = [*mappableData retain];
}
@end
/////////////////////////////////////////////////////////////////////////////
@interface RKObjectLoaderTest : RKTestCase {
}
@end
@implementation RKObjectLoaderTest
- (void)setUp
{
[RKTestFactory setUp];
}
- (void)tearDown
{
[RKTestFactory tearDown];
}
- (RKObjectMappingProvider *)providerForComplexUser
{
RKObjectMappingProvider *provider = [[RKObjectMappingProvider new] autorelease];
RKObjectMapping *userMapping = [RKObjectMapping mappingForClass:[RKTestComplexUser class]];
[userMapping addAttributeMapping:[RKAttributeMapping mappingFromKeyPath:@"firstname" toKeyPath:@"firstname"]];
[provider setMapping:userMapping forKeyPath:@"data.STUser"];
return provider;
}
- (RKObjectMappingProvider *)errorMappingProvider
{
RKObjectMappingProvider *provider = [[RKObjectMappingProvider new] autorelease];
RKObjectMapping *errorMapping = [RKObjectMapping mappingForClass:[RKErrorMessage class]];
[errorMapping addAttributeMapping:[RKAttributeMapping mappingFromKeyPath:@"" toKeyPath:@"errorMessage"]];
errorMapping.rootKeyPath = @"errors";
provider.errorMapping = errorMapping;
return provider;
}
- (void)testShouldHandleTheErrorCaseAppropriately
{
RKObjectManager *objectManager = [RKTestFactory objectManager];
objectManager.mappingProvider = [self errorMappingProvider];
RKTestResponseLoader *responseLoader = [RKTestResponseLoader responseLoader];
RKObjectLoader *objectLoader = [objectManager loaderWithResourcePath:@"/errors.json"];
objectLoader.delegate = responseLoader;
objectLoader.method = RKRequestMethodGET;
[objectLoader sendAsynchronously];
[responseLoader waitForResponse];
assertThat(responseLoader.error, isNot(nilValue()));
assertThat([responseLoader.error localizedDescription], is(equalTo(@"error1, error2")));
NSArray *objects = [[responseLoader.error userInfo] objectForKey:RKObjectMapperErrorObjectsKey];
RKErrorMessage *error1 = [objects objectAtIndex:0];
RKErrorMessage *error2 = [objects lastObject];
assertThat(error1.errorMessage, is(equalTo(@"error1")));
assertThat(error2.errorMessage, is(equalTo(@"error2")));
}
- (void)testShouldNotCrashWhenLoadingAnErrorResponseWithAnUnmappableMIMEType
{
RKObjectManager *objectManager = [RKTestFactory objectManager];
RKTestResponseLoader *loader = [RKTestResponseLoader responseLoader];
[objectManager loadObjectsAtResourcePath:@"/404" delegate:loader];
[loader waitForResponse];
assertThatBool(loader.loadedUnexpectedResponse, is(equalToBool(YES)));
}
#pragma mark - Complex JSON
- (void)testShouldLoadAComplexUserObjectWithTargetObject
{
RKTestComplexUser *user = [[RKTestComplexUser new] autorelease];
RKObjectManager *objectManager = [RKObjectManager managerWithBaseURL:[RKTestFactory baseURL]];
RKTestResponseLoader *responseLoader = [RKTestResponseLoader responseLoader];
RKObjectLoader *objectLoader = [objectManager loaderWithResourcePath:@"/JSON/ComplexNestedUser.json"];
objectLoader.delegate = responseLoader;
NSString *authString = [NSString stringWithFormat:@"TRUEREST username=%@&password=%@&apikey=123456&class=iphone", @"username", @"password"];
[objectLoader.URLRequest addValue:authString forHTTPHeaderField:@"Authorization"];
objectLoader.method = RKRequestMethodGET;
objectLoader.targetObject = user;
objectLoader.mappingProvider = [self providerForComplexUser];
[objectLoader sendAsynchronously];
[responseLoader waitForResponse];
assertThat(user.firstname, is(equalTo(@"Diego")));
}
- (void)testShouldLoadAComplexUserObjectWithoutTargetObject
{
RKObjectManager *objectManager = [RKObjectManager managerWithBaseURL:[RKTestFactory baseURL]];
RKTestResponseLoader *responseLoader = [RKTestResponseLoader responseLoader];
RKObjectLoader *objectLoader = [objectManager loaderWithResourcePath:@"/JSON/ComplexNestedUser.json"];
objectLoader.delegate = responseLoader;
objectLoader.method = RKRequestMethodGET;
objectLoader.mappingProvider = [self providerForComplexUser];
[objectLoader sendAsynchronously];
[responseLoader waitForResponse];
assertThatUnsignedInteger([responseLoader.objects count], is(equalToInt(1)));
RKTestComplexUser *user = [responseLoader.objects lastObject];
assertThat(user.firstname, is(equalTo(@"Diego")));
}
- (void)testShouldLoadAComplexUserObjectUsingRegisteredKeyPath
{
RKObjectManager *objectManager = [RKObjectManager managerWithBaseURL:[RKTestFactory baseURL]];
RKTestResponseLoader *responseLoader = [RKTestResponseLoader responseLoader];
RKObjectLoader *objectLoader = [objectManager loaderWithResourcePath:@"/JSON/ComplexNestedUser.json"];
objectLoader.delegate = responseLoader;
objectLoader.method = RKRequestMethodGET;
objectLoader.mappingProvider = [self providerForComplexUser];
[objectLoader sendAsynchronously];
[responseLoader waitForResponse];
assertThatUnsignedInteger([responseLoader.objects count], is(equalToInt(1)));
RKTestComplexUser *user = [responseLoader.objects lastObject];
assertThat(user.firstname, is(equalTo(@"Diego")));
}
#pragma mark - willSendWithObjectLoader:
- (void)testShouldInvokeWillSendWithObjectLoaderOnSend
{
RKObjectManager *objectManager = [RKTestFactory objectManager];
RKTestComplexUser *user = [[RKTestComplexUser new] autorelease];
id mockObject = [OCMockObject partialMockForObject:user];
// Explicitly init so we don't get a managed object loader...
RKTestResponseLoader *responseLoader = [RKTestResponseLoader responseLoader];
RKObjectLoader *objectLoader = [[RKObjectLoader alloc] initWithURL:[objectManager.baseURL URLByAppendingResourcePath:@"/200"] mappingProvider:[self providerForComplexUser]];
objectLoader.configurationDelegate = objectManager;
objectLoader.sourceObject = mockObject;
objectLoader.delegate = responseLoader;
[[mockObject expect] willSendWithObjectLoader:objectLoader];
[objectLoader send];
[responseLoader waitForResponse];
[mockObject verify];
}
- (void)testShouldInvokeWillSendWithObjectLoaderOnSendAsynchronously
{
RKObjectManager *objectManager = [RKObjectManager managerWithBaseURL:[RKTestFactory baseURL]];
[objectManager setMappingProvider:[self providerForComplexUser]];
RKTestComplexUser *user = [[RKTestComplexUser new] autorelease];
id mockObject = [OCMockObject partialMockForObject:user];
// Explicitly init so we don't get a managed object loader...
RKTestResponseLoader *responseLoader = [RKTestResponseLoader responseLoader];
RKObjectLoader *objectLoader = [RKObjectLoader loaderWithURL:[objectManager.baseURL URLByAppendingResourcePath:@"/200"] mappingProvider:objectManager.mappingProvider];
objectLoader.delegate = responseLoader;
objectLoader.sourceObject = mockObject;
[[mockObject expect] willSendWithObjectLoader:objectLoader];
[objectLoader sendAsynchronously];
[responseLoader waitForResponse];
[mockObject verify];
}
- (void)testShouldInvokeWillSendWithObjectLoaderOnSendSynchronously
{
RKObjectManager *objectManager = [RKObjectManager managerWithBaseURL:[RKTestFactory baseURL]];
[objectManager setMappingProvider:[self providerForComplexUser]];
RKTestComplexUser *user = [[RKTestComplexUser new] autorelease];
id mockObject = [OCMockObject partialMockForObject:user];
// Explicitly init so we don't get a managed object loader...
RKObjectLoader *objectLoader = [RKObjectLoader loaderWithURL:[objectManager.baseURL URLByAppendingResourcePath:@"/200"] mappingProvider:objectManager.mappingProvider];
objectLoader.sourceObject = mockObject;
[[mockObject expect] willSendWithObjectLoader:objectLoader];
[objectLoader sendSynchronously];
[mockObject verify];
}
- (void)testShouldLoadResultsNestedAtAKeyPath
{
RKObjectManager *objectManager = [RKTestFactory objectManager];
RKObjectMapping *objectMapping = [RKObjectMapping mappingForClass:[RKObjectLoaderTestResultModel class]];
[objectMapping mapKeyPath:@"id" toAttribute:@"ID"];
[objectMapping mapKeyPath:@"ends_at" toAttribute:@"endsAt"];
[objectMapping mapKeyPath:@"photo_url" toAttribute:@"photoURL"];
[objectManager.mappingProvider setMapping:objectMapping forKeyPath:@"results"];
RKTestResponseLoader *loader = [RKTestResponseLoader responseLoader];
[objectManager loadObjectsAtResourcePath:@"/JSON/ArrayOfResults.json" delegate:loader];
[loader waitForResponse];
assertThat([loader objects], hasCountOf(2));
assertThat([[[loader objects] objectAtIndex:0] ID], is(equalToInt(226)));
assertThat([[[loader objects] objectAtIndex:0] photoURL], is(equalTo(@"1308262872.jpg")));
assertThat([[[loader objects] objectAtIndex:1] ID], is(equalToInt(235)));
assertThat([[[loader objects] objectAtIndex:1] photoURL], is(equalTo(@"1308634984.jpg")));
}
- (void)testShouldAllowMutationOfTheParsedDataInWillMapData
{
RKTestResponseLoaderWithWillMapData *loader = (RKTestResponseLoaderWithWillMapData *)[RKTestResponseLoaderWithWillMapData responseLoader];
RKObjectManager *manager = [RKTestFactory objectManager];
[manager loadObjectsAtResourcePath:@"/JSON/humans/1.json" delegate:loader];
[loader waitForResponse];
assertThat([loader.mappableData valueForKey:@"newKey"], is(equalTo(@"monkey!")));
}
- (void)testShouldAllowYouToPostAnObjectAndHandleAnEmpty204Response
{
RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestComplexUser class]];
[mapping mapAttributes:@"firstname", @"lastname", @"email", nil];
RKObjectMapping *serializationMapping = [mapping inverseMapping];
RKObjectManager *objectManager = [RKTestFactory objectManager];
[objectManager.router.routeSet addRoute:[RKRoute routeWithClass:[RKTestComplexUser class] resourcePathPattern:@"/204"method:RKRequestMethodAny]];
[objectManager.mappingProvider setSerializationMapping:serializationMapping forClass:[RKTestComplexUser class]];
RKTestComplexUser *user = [[RKTestComplexUser new] autorelease];
user.firstname = @"Blake";
user.lastname = @"Watters";
user.email = @"blake@restkit.org";
RKTestResponseLoader *responseLoader = [RKTestResponseLoader responseLoader];
RKObjectLoader *loader = [objectManager loaderForObject:user method:RKRequestMethodPOST];
loader.delegate = responseLoader;
loader.objectMapping = mapping;
[loader send];
[responseLoader waitForResponse];
assertThatBool([responseLoader wasSuccessful], is(equalToBool(YES)));
assertThat(user.email, is(equalTo(@"blake@restkit.org")));
}
- (void)testShouldAllowYouToPOSTAnObjectAndMapBackNonNestedContent
{
RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestComplexUser class]];
[mapping mapAttributes:@"firstname", @"lastname", @"email", nil];
RKObjectMapping *serializationMapping = [mapping inverseMapping];
RKObjectManager *objectManager = [RKTestFactory objectManager];
[objectManager.router.routeSet addRoute:[RKRoute routeWithClass:[RKTestComplexUser class] resourcePathPattern:@"/notNestedUser" method:RKRequestMethodAny]];
[objectManager.mappingProvider setSerializationMapping:serializationMapping forClass:[RKTestComplexUser class]];
RKTestComplexUser *user = [[RKTestComplexUser new] autorelease];
user.firstname = @"Blake";
user.lastname = @"Watters";
user.email = @"blake@restkit.org";
RKTestResponseLoader *responseLoader = [RKTestResponseLoader responseLoader];
RKObjectLoader *loader = [objectManager loaderForObject:user method:RKRequestMethodPOST];
loader.delegate = responseLoader;
loader.objectMapping = mapping;
[loader send];
[responseLoader waitForResponse];
assertThatBool([responseLoader wasSuccessful], is(equalToBool(YES)));
assertThat(user.email, is(equalTo(@"changed")));
}
- (void)testShouldMapContentWithoutAMIMEType
{
// TODO: Not sure that this is even worth it. Unable to get the Sinatra server to produce such a response
return;
RKLogConfigureByName("RestKit/Network", RKLogLevelTrace);
RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestComplexUser class]];
[mapping mapAttributes:@"firstname", @"lastname", @"email", nil];
RKObjectMapping *serializationMapping = [mapping inverseMapping];
RKObjectManager *objectManager = [RKTestFactory objectManager];
[[RKParserRegistry sharedRegistry] setParserClass:[RKJSONParserJSONKit class] forMIMEType:@"text/html"];
[objectManager.router.routeSet addRoute:[RKRoute routeWithClass:[RKTestComplexUser class] resourcePathPattern:@"/noMIME" method:RKRequestMethodAny]];
[objectManager.mappingProvider setSerializationMapping:serializationMapping forClass:[RKTestComplexUser class]];
RKTestComplexUser *user = [[RKTestComplexUser new] autorelease];
user.firstname = @"Blake";
user.lastname = @"Watters";
user.email = @"blake@restkit.org";
RKTestResponseLoader *responseLoader = [RKTestResponseLoader responseLoader];
RKObjectLoader *loader = [objectManager loaderForObject:user method:RKRequestMethodPOST];
loader.delegate = responseLoader;
loader.objectMapping = mapping;
[loader send];
[responseLoader waitForResponse];
assertThatBool([responseLoader wasSuccessful], is(equalToBool(YES)));
assertThat(user.email, is(equalTo(@"changed")));
}
- (void)testShouldAllowYouToPOSTAnObjectOfOneTypeAndGetBackAnother
{
RKObjectMapping *sourceMapping = [RKObjectMapping mappingForClass:[RKTestComplexUser class]];
[sourceMapping mapAttributes:@"firstname", @"lastname", @"email", nil];
RKObjectMapping *serializationMapping = [sourceMapping inverseMapping];
RKObjectMapping *targetMapping = [RKObjectMapping mappingForClass:[RKObjectLoaderTestResultModel class]];
[targetMapping mapAttributes:@"ID", nil];
RKObjectManager *objectManager = [RKTestFactory objectManager];
[objectManager.router.routeSet addRoute:[RKRoute routeWithClass:[RKTestComplexUser class] resourcePathPattern:@"/notNestedUser" method:RKRequestMethodAny]];
[objectManager.mappingProvider setSerializationMapping:serializationMapping forClass:[RKTestComplexUser class]];
RKTestComplexUser *user = [[RKTestComplexUser new] autorelease];
user.firstname = @"Blake";
user.lastname = @"Watters";
user.email = @"blake@restkit.org";
RKTestResponseLoader *responseLoader = [RKTestResponseLoader responseLoader];
RKObjectLoader *loader = [objectManager loaderForObject:user method:RKRequestMethodPOST];
loader.delegate = responseLoader;
loader.sourceObject = user;
loader.targetObject = nil;
loader.objectMapping = targetMapping;
[loader send];
[responseLoader waitForResponse];
assertThatBool([responseLoader wasSuccessful], is(equalToBool(YES)));
// Our original object should not have changed
assertThat(user.email, is(equalTo(@"blake@restkit.org")));
// And we should have a new one
RKObjectLoaderTestResultModel *newObject = [[responseLoader objects] lastObject];
assertThat(newObject, is(instanceOf([RKObjectLoaderTestResultModel class])));
assertThat(newObject.ID, is(equalToInt(31337)));
}
- (void)testShouldAllowYouToPOSTAnObjectOfOneTypeAndGetBackAnotherViaURLConfiguration
{
RKObjectMapping *sourceMapping = [RKObjectMapping mappingForClass:[RKTestComplexUser class]];
[sourceMapping mapAttributes:@"firstname", @"lastname", @"email", nil];
RKObjectMapping *serializationMapping = [sourceMapping inverseMapping];
RKObjectMapping *targetMapping = [RKObjectMapping mappingForClass:[RKObjectLoaderTestResultModel class]];
[targetMapping mapAttributes:@"ID", nil];
RKObjectManager *objectManager = [RKTestFactory objectManager];
[objectManager.router.routeSet addRoute:[RKRoute routeWithClass:[RKTestComplexUser class] resourcePathPattern:@"/notNestedUser" method:RKRequestMethodAny]];
[objectManager.mappingProvider setSerializationMapping:serializationMapping forClass:[RKTestComplexUser class]];
[objectManager.mappingProvider setObjectMapping:targetMapping forResourcePathPattern:@"/notNestedUser"];
RKTestComplexUser *user = [[RKTestComplexUser new] autorelease];
user.firstname = @"Blake";
user.lastname = @"Watters";
user.email = @"blake@restkit.org";
RKTestResponseLoader *responseLoader = [RKTestResponseLoader responseLoader];
RKObjectLoader *loader = [objectManager loaderForObject:user method:RKRequestMethodPOST];
loader.delegate = responseLoader;
loader.sourceObject = user;
loader.targetObject = nil;
[loader send];
[responseLoader waitForResponse];
assertThatBool([responseLoader wasSuccessful], is(equalToBool(YES)));
// Our original object should not have changed
assertThat(user.email, is(equalTo(@"blake@restkit.org")));
// And we should have a new one
RKObjectLoaderTestResultModel *newObject = [[responseLoader objects] lastObject];
assertThat(newObject, is(instanceOf([RKObjectLoaderTestResultModel class])));
assertThat(newObject.ID, is(equalToInt(31337)));
}
// TODO: Should live in a different file...
- (void)testShouldAllowYouToPOSTAnObjectAndMapBackNonNestedContentViapostObject
{
RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestComplexUser class]];
[mapping mapAttributes:@"firstname", @"lastname", @"email", nil];
RKObjectMapping *serializationMapping = [mapping inverseMapping];
RKObjectManager *objectManager = [RKTestFactory objectManager];
[objectManager.router.routeSet addRoute:[RKRoute routeWithClass:[RKTestComplexUser class] resourcePathPattern:@"/notNestedUser" method:RKRequestMethodAny]];
[objectManager.mappingProvider setSerializationMapping:serializationMapping forClass:[RKTestComplexUser class]];
RKTestComplexUser *user = [[RKTestComplexUser new] autorelease];
user.firstname = @"Blake";
user.lastname = @"Watters";
user.email = @"blake@restkit.org";
// NOTE: The postObject: should infer the target object from sourceObject and the mapping class
RKTestResponseLoader *responseLoader = [RKTestResponseLoader responseLoader];
[objectManager postObject:user usingBlock:^(RKObjectLoader *loader) {
loader.delegate = responseLoader;
loader.objectMapping = mapping;
}];
[responseLoader waitForResponse];
assertThatBool([responseLoader wasSuccessful], is(equalToBool(YES)));
assertThat(user.email, is(equalTo(@"changed")));
}
- (void)testShouldRespectTheRootKeyPathWhenConstructingATemporaryObjectMappingProvider
{
RKObjectMapping *userMapping = [RKObjectMapping mappingForClass:[RKTestComplexUser class]];
userMapping.rootKeyPath = @"data.STUser";
[userMapping mapAttributes:@"firstname", nil];
RKTestComplexUser *user = [[RKTestComplexUser new] autorelease];
RKObjectManager *objectManager = [RKObjectManager managerWithBaseURL:[RKTestFactory baseURL]];
RKTestResponseLoader *responseLoader = [RKTestResponseLoader responseLoader];
RKObjectLoader *objectLoader = [objectManager loaderWithResourcePath:@"/JSON/ComplexNestedUser.json"];
objectLoader.delegate = responseLoader;
objectLoader.objectMapping = userMapping;
objectLoader.method = RKRequestMethodGET;
objectLoader.targetObject = user;
[objectLoader sendAsynchronously];
[responseLoader waitForResponse];
assertThat(user.firstname, is(equalTo(@"Diego")));
}
- (void)testShouldDetermineObjectLoaderBasedOnResourcePathPatternWithExactMatch
{
RKObjectMapping *userMapping = [RKObjectMapping mappingForClass:[RKTestComplexUser class]];
userMapping.rootKeyPath = @"data.STUser";
[userMapping mapAttributes:@"firstname", nil];
RKTestComplexUser *user = [[RKTestComplexUser new] autorelease];
RKObjectManager *objectManager = [RKObjectManager managerWithBaseURL:[RKTestFactory baseURL]];
RKTestResponseLoader *responseLoader = [RKTestResponseLoader responseLoader];
RKObjectMappingProvider *mappingProvider = [RKObjectMappingProvider mappingProvider];
[mappingProvider setObjectMapping:userMapping forResourcePathPattern:@"/JSON/ComplexNestedUser.json"];
RKURL *URL = [objectManager.baseURL URLByAppendingResourcePath:@"/JSON/ComplexNestedUser.json"];
RKObjectLoader *objectLoader = [RKObjectLoader loaderWithURL:URL mappingProvider:mappingProvider];
objectLoader.delegate = responseLoader;
objectLoader.method = RKRequestMethodGET;
objectLoader.targetObject = user;
[objectLoader sendAsynchronously];
[responseLoader waitForResponse];
NSLog(@"Response: %@", responseLoader.objects);
assertThat(user.firstname, is(equalTo(@"Diego")));
}
- (void)testShouldDetermineObjectLoaderBasedOnResourcePathPatternWithPartialMatch
{
RKObjectMapping *userMapping = [RKObjectMapping mappingForClass:[RKTestComplexUser class]];
userMapping.rootKeyPath = @"data.STUser";
[userMapping mapAttributes:@"firstname", nil];
RKTestComplexUser *user = [[RKTestComplexUser new] autorelease];
RKObjectManager *objectManager = [RKObjectManager managerWithBaseURL:[RKTestFactory baseURL]];
RKTestResponseLoader *responseLoader = [RKTestResponseLoader responseLoader];
RKObjectMappingProvider *mappingProvider = [RKObjectMappingProvider mappingProvider];
[mappingProvider setObjectMapping:userMapping forResourcePathPattern:@"/JSON/:name\\.json"];
RKURL *URL = [objectManager.baseURL URLByAppendingResourcePath:@"/JSON/ComplexNestedUser.json"];
RKObjectLoader *objectLoader = [RKObjectLoader loaderWithURL:URL mappingProvider:mappingProvider];
objectLoader.delegate = responseLoader;
objectLoader.method = RKRequestMethodGET;
objectLoader.targetObject = user;
[objectLoader sendAsynchronously];
[responseLoader waitForResponse];
NSLog(@"Response: %@", responseLoader.objects);
assertThat(user.firstname, is(equalTo(@"Diego")));
}
- (void)testShouldReturnSuccessWhenTheStatusCodeIs200AndTheResponseBodyIsEmpty
{
RKObjectManager *objectManager = [RKTestFactory objectManager];
RKTestComplexUser *user = [[RKTestComplexUser new] autorelease];
user.firstname = @"Blake";
user.lastname = @"Watters";
user.email = @"blake@restkit.org";
RKObjectMapping *userMapping = [RKObjectMapping mappingForClass:[RKTestComplexUser class]];
userMapping.rootKeyPath = @"data.STUser";
[userMapping mapAttributes:@"firstname", nil];
RKTestResponseLoader *responseLoader = [RKTestResponseLoader responseLoader];
RKObjectLoader *objectLoader = [objectManager loaderWithResourcePath:@"/humans/1234"];
objectLoader.delegate = responseLoader;
objectLoader.method = RKRequestMethodDELETE;
objectLoader.objectMapping = userMapping;
objectLoader.targetObject = user;
[objectLoader send];
[responseLoader waitForResponse];
assertThatBool(responseLoader.wasSuccessful, is(equalToBool(YES)));
}
- (void)testShouldInvokeTheDelegateWithTheTargetObjectWhenTheStatusCodeIs200AndTheResponseBodyIsEmpty
{
RKObjectManager *objectManager = [RKTestFactory objectManager];
RKTestComplexUser *user = [[RKTestComplexUser new] autorelease];
user.firstname = @"Blake";
user.lastname = @"Watters";
user.email = @"blake@restkit.org";
RKObjectMapping *userMapping = [RKObjectMapping mappingForClass:[RKTestComplexUser class]];
userMapping.rootKeyPath = @"data.STUser";
[userMapping mapAttributes:@"firstname", nil];
RKTestResponseLoader *responseLoader = [RKTestResponseLoader responseLoader];
RKObjectLoader *objectLoader = [RKObjectLoader loaderWithURL:[objectManager.baseURL URLByAppendingResourcePath:@"/humans/1234"] mappingProvider:objectManager.mappingProvider];
objectLoader.delegate = responseLoader;
objectLoader.method = RKRequestMethodDELETE;
objectLoader.objectMapping = userMapping;
objectLoader.targetObject = user;
[objectLoader send];
[responseLoader waitForResponse];
assertThat(responseLoader.objects, hasItem(user));
}
- (void)testShouldConsiderTheLoadOfEmptyObjectsWithoutAnyMappableAttributesAsSuccess
{
RKObjectManager *objectManager = [RKTestFactory objectManager];
RKObjectMapping *userMapping = [RKObjectMapping mappingForClass:[RKTestComplexUser class]];
[userMapping mapAttributes:@"firstname", nil];
[objectManager.mappingProvider setMapping:userMapping forKeyPath:@"firstUser"];
[objectManager.mappingProvider setMapping:userMapping forKeyPath:@"secondUser"];
RKTestResponseLoader *responseLoader = [RKTestResponseLoader responseLoader];
[objectManager loadObjectsAtResourcePath:@"/users/empty" delegate:responseLoader];
[responseLoader waitForResponse];
assertThatBool(responseLoader.wasSuccessful, is(equalToBool(YES)));
}
- (void)testShouldInvokeTheDelegateOnSuccessIfTheResponseIsAnEmptyArray
{
RKObjectManager *objectManager = [RKTestFactory objectManager];
RKTestResponseLoader *responseLoader = [RKTestResponseLoader responseLoader];
responseLoader.timeout = 20;
[objectManager loadObjectsAtResourcePath:@"/empty/array" delegate:responseLoader];
[responseLoader waitForResponse];
assertThat(responseLoader.objects, isNot(nilValue()));
assertThatBool([responseLoader.objects isKindOfClass:[NSArray class]], is(equalToBool(YES)));
assertThat(responseLoader.objects, is(empty()));
}
- (void)testShouldInvokeTheDelegateOnSuccessIfTheResponseIsAnEmptyDictionary
{
RKObjectManager *objectManager = [RKTestFactory objectManager];
RKTestResponseLoader *responseLoader = [RKTestResponseLoader responseLoader];
responseLoader.timeout = 20;
[objectManager loadObjectsAtResourcePath:@"/empty/dictionary" delegate:responseLoader];
[responseLoader waitForResponse];
assertThat(responseLoader.objects, isNot(nilValue()));
assertThatBool([responseLoader.objects isKindOfClass:[NSArray class]], is(equalToBool(YES)));
assertThat(responseLoader.objects, is(empty()));
}
- (void)testShouldInvokeTheDelegateOnSuccessIfTheResponseIsAnEmptyString
{
RKObjectManager *objectManager = [RKTestFactory objectManager];
RKTestResponseLoader *responseLoader = [RKTestResponseLoader responseLoader];
responseLoader.timeout = 20;
[objectManager loadObjectsAtResourcePath:@"/empty/string" delegate:responseLoader];
[responseLoader waitForResponse];
assertThat(responseLoader.objects, isNot(nilValue()));
assertThatBool([responseLoader.objects isKindOfClass:[NSArray class]], is(equalToBool(YES)));
assertThat(responseLoader.objects, is(empty()));
}
- (void)testShouldNotBlockNetworkOperationsWhileAwaitingObjectMapping
{
RKObjectManager *objectManager = [RKTestFactory objectManager];
objectManager.requestCache.storagePolicy = RKRequestCacheStoragePolicyDisabled;
objectManager.client.requestQueue.concurrentRequestsLimit = 1;
RKObjectMapping *userMapping = [RKObjectMapping mappingForClass:[RKTestComplexUser class]];
userMapping.rootKeyPath = @"human";
[userMapping mapAttributes:@"name", @"id", nil];
// Suspend the Queue to block object mapping
[objectManager.mappingQueue setSuspended:YES];
RKTestResponseLoader *responseLoader = [RKTestResponseLoader responseLoader];
[objectManager.mappingProvider setObjectMapping:userMapping forResourcePathPattern:@"/humans/1"];
[objectManager loadObjectsAtResourcePath:@"/humans/1" delegate:nil];
[objectManager.client get:@"/empty/string" delegate:responseLoader];
[responseLoader waitForResponse];
// We should get a response is network is released even though object mapping didn't finish
assertThatBool(responseLoader.wasSuccessful, is(equalToBool(YES)));
}
#pragma mark - Block Tests
- (void)testInvocationOfDidLoadObjectBlock
{
RKObjectManager *objectManager = [RKObjectManager managerWithBaseURL:[RKTestFactory baseURL]];
RKTestResponseLoader *responseLoader = [RKTestResponseLoader responseLoader];
RKObjectLoader *objectLoader = [objectManager loaderWithResourcePath:@"/JSON/ComplexNestedUser.json"];
objectLoader.delegate = responseLoader;
objectLoader.method = RKRequestMethodGET;
objectLoader.mappingProvider = [self providerForComplexUser];
__block id expectedResult = nil;
objectLoader.onDidLoadObject = ^(id object) {
expectedResult = object;
};
[objectLoader sendAsynchronously];
[responseLoader waitForResponse];
assertThat(expectedResult, is(notNilValue()));
}
- (void)testInvocationOfDidLoadObjectBlockIsSingularObjectOfCorrectType
{
RKObjectManager *objectManager = [RKObjectManager managerWithBaseURL:[RKTestFactory baseURL]];
RKTestResponseLoader *responseLoader = [RKTestResponseLoader responseLoader];
RKObjectLoader *objectLoader = [objectManager loaderWithResourcePath:@"/JSON/ComplexNestedUser.json"];
objectLoader.delegate = responseLoader;
objectLoader.method = RKRequestMethodGET;
objectLoader.mappingProvider = [self providerForComplexUser];
__block id expectedResult = nil;
objectLoader.onDidLoadObject = ^(id object) {
expectedResult = object;
};
[objectLoader sendAsynchronously];
[responseLoader waitForResponse];
assertThat(expectedResult, is(instanceOf([RKTestComplexUser class])));
}
- (void)testInvocationOfDidLoadObjectsBlock
{
RKObjectManager *objectManager = [RKObjectManager managerWithBaseURL:[RKTestFactory baseURL]];
RKTestResponseLoader *responseLoader = [RKTestResponseLoader responseLoader];
RKObjectLoader *objectLoader = [objectManager loaderWithResourcePath:@"/JSON/ComplexNestedUser.json"];
objectLoader.delegate = responseLoader;
objectLoader.method = RKRequestMethodGET;
objectLoader.mappingProvider = [self providerForComplexUser];
__block id expectedResult = nil;
objectLoader.onDidLoadObjects = ^(NSArray *objects) {
expectedResult = objects;
};
[objectLoader sendAsynchronously];
[responseLoader waitForResponse];
assertThat(expectedResult, is(notNilValue()));
}
- (void)testInvocationOfDidLoadObjectsBlocksIsCollectionOfObjects
{
RKObjectManager *objectManager = [RKObjectManager managerWithBaseURL:[RKTestFactory baseURL]];
RKTestResponseLoader *responseLoader = [RKTestResponseLoader responseLoader];
RKObjectLoader *objectLoader = [objectManager loaderWithResourcePath:@"/JSON/ComplexNestedUser.json"];
objectLoader.delegate = responseLoader;
objectLoader.method = RKRequestMethodGET;
objectLoader.mappingProvider = [self providerForComplexUser];
__block id expectedResult = nil;
objectLoader.onDidLoadObjects = ^(NSArray *objects) {
expectedResult = [objects retain];
};
[objectLoader sendAsynchronously];
[responseLoader waitForResponse];
NSLog(@"The expectedResult = %@", expectedResult);
assertThat(expectedResult, is(instanceOf([NSArray class])));
assertThat(expectedResult, hasCountOf(1));
[expectedResult release];
}
- (void)testInvocationOfDidLoadObjectsDictionaryBlock
{
RKObjectManager *objectManager = [RKObjectManager managerWithBaseURL:[RKTestFactory baseURL]];
RKTestResponseLoader *responseLoader = [RKTestResponseLoader responseLoader];
RKObjectLoader *objectLoader = [objectManager loaderWithResourcePath:@"/JSON/ComplexNestedUser.json"];
objectLoader.delegate = responseLoader;
objectLoader.method = RKRequestMethodGET;
objectLoader.mappingProvider = [self providerForComplexUser];
__block id expectedResult = nil;
objectLoader.onDidLoadObjectsDictionary = ^(NSDictionary *dictionary) {
expectedResult = dictionary;
};
[objectLoader sendAsynchronously];
[responseLoader waitForResponse];
assertThat(expectedResult, is(notNilValue()));
}
- (void)testInvocationOfDidLoadObjectsDictionaryBlocksIsDictionaryOfObjects
{
RKObjectManager *objectManager = [RKObjectManager managerWithBaseURL:[RKTestFactory baseURL]];
RKTestResponseLoader *responseLoader = [RKTestResponseLoader responseLoader];
RKObjectLoader *objectLoader = [objectManager loaderWithResourcePath:@"/JSON/ComplexNestedUser.json"];
objectLoader.delegate = responseLoader;
objectLoader.method = RKRequestMethodGET;
objectLoader.mappingProvider = [self providerForComplexUser];
__block id expectedResult = nil;
objectLoader.onDidLoadObjectsDictionary = ^(NSDictionary *dictionary) {
expectedResult = dictionary;
};
[objectLoader sendAsynchronously];
[responseLoader waitForResponse];
assertThat(expectedResult, is(instanceOf([NSDictionary class])));
assertThat(expectedResult, hasCountOf(1));
}
// NOTE: Errors are fired in a number of contexts within the RKObjectLoader. We have centralized the cases into a private
// method and test that one case here. There should be better coverage for this.
- (void)testInvocationOfOnDidFailWithError
{
RKObjectLoader *loader = [RKObjectLoader loaderWithURL:nil mappingProvider:nil];
NSError *expectedError = [NSError errorWithDomain:@"Testing" code:1234 userInfo:nil];
__block NSError *blockError = nil;
loader.onDidFailWithError = ^(NSError *error) {
blockError = error;
};
[loader performSelector:@selector(informDelegateOfError:) withObject:expectedError];
assertThat(blockError, is(equalTo(expectedError)));
}
- (void)testShouldNotAssertDuringObjectMappingOnSynchronousRequest
{
RKObjectManager *objectManager = [RKTestFactory objectManager];
RKObjectMapping *userMapping = [RKObjectMapping mappingForClass:[RKTestComplexUser class]];
userMapping.rootKeyPath = @"data.STUser";
[userMapping mapAttributes:@"firstname", nil];
RKObjectLoader *objectLoader = [objectManager loaderWithResourcePath:@"/humans/1"];
objectLoader.objectMapping = userMapping;
[objectLoader sendSynchronously];
RKResponse *response = [objectLoader sendSynchronously];
assertThatInteger(response.statusCode, is(equalToInt(200)));
}
@end