Files
RestKit/Tests/Logic/ObjectMapping/RKObjectLoaderTest.m
2012-04-17 12:41:26 -04:00

768 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:[RKObjectAttributeMapping 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:[RKObjectAttributeMapping 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 routeClass:[RKTestComplexUser class] toResourcePath:@"/204"];
[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 routeClass:[RKTestComplexUser class] toResourcePath:@"/notNestedUser"];
[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 routeClass:[RKTestComplexUser class] toResourcePath:@"/noMIME"];
[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 routeClass:[RKTestComplexUser class] toResourcePath:@"/notNestedUser"];
[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 routeClass:[RKTestComplexUser class] toResourcePath:@"/notNestedUser"];
[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 routeClass:[RKTestComplexUser class] toResourcePath:@"/notNestedUser"];
[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
dispatch_suspend(objectManager.mappingQueue);
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