Expand test coverage and fix situations where requests would unexpectedly initialize incorrectly without error

* RKObjectParameterization now returns an empty dictionary if mapping produces an unmappable representation error (no mappable attributes/relationships found)
* Log errors if request construction results in an NSError and return nil
* Ensure errors are passed back up through object parameterization instead of just returning nil
* Reset the serialization MIME Type registry during RKTestFactory set up to ensure it is in a sane state
* Convert Hamcrest matchers to Expecta in the object mapper tests to fix infinite recursion on test failure (will need to completely phase out Hamcrest soon)
This commit is contained in:
Blake Watters
2012-10-05 19:16:55 -04:00
parent b9b34bf3dd
commit 877ce255b5
11 changed files with 111 additions and 52 deletions

View File

@@ -29,6 +29,7 @@
#import "RKLog.h"
#import "RKMIMETypeSerialization.h"
#import "RKPathMatcher.h"
#import "RKMappingErrors.h"
#if !__has_feature(objc_arc)
#error RestKit must be built with ARC.
@@ -215,6 +216,10 @@ static NSString *RKMIMETypeFromAFHTTPClientParameterEncoding(AFHTTPClientParamet
NSString *charset = (__bridge NSString *)CFStringConvertEncodingToIANACharSetName(CFStringConvertNSStringEncodingToEncoding(self.HTTPClient.stringEncoding));
[request setValue:[NSString stringWithFormat:@"%@; charset=%@", self.requestSerializationMIMEType, charset] forHTTPHeaderField:@"Content-Type"];
NSData *requestBody = [RKMIMETypeSerialization dataFromObject:parameters MIMEType:self.requestSerializationMIMEType error:&error];
if (! requestBody) {
RKLogError(@"Failed to generate request body from parameters: RKMIMETypeSerialization error: %@", error);
return nil;
}
[request setHTTPBody:requestBody];
}
}
@@ -253,6 +258,10 @@ static NSString *RKMIMETypeFromAFHTTPClientParameterEncoding(AFHTTPClientParamet
if ((method != RKRequestMethodGET && method != RKRequestMethodDELETE) && requestDescriptor) {
NSError *error = nil;
requestParameters = [[RKObjectParameterization parametersWithObject:object requestDescriptor:requestDescriptor error:&error] mutableCopy];
if (error) {
RKLogError(@"Object parameterization failed while building %@ request to '%@': %@", stringMethod, requestPath, error);
return nil;
}
if (parameters) {
requestParameters = RKDictionaryByMergingDictionaryWithDictionary(requestParameters, parameters);
}

View File

@@ -27,6 +27,7 @@
#import "RKObjectMapping.h"
#import "RKMappingOperation.h"
#import "RKMappingErrors.h"
// Set Logging Component
#undef RKLogComponent
@@ -48,8 +49,8 @@
+ (NSDictionary *)parametersWithObject:(id)object requestDescriptor:(RKRequestDescriptor *)requestDescriptor error:(NSError **)error
{
RKObjectParameterization *objectParameters = [[self alloc] initWithObject:object requestDescriptor:requestDescriptor];
return [objectParameters mapObjectToParameters:error];
RKObjectParameterization *parameterization = [[self alloc] initWithObject:object requestDescriptor:requestDescriptor];
return [parameterization mapObjectToParameters:error];
}
- (id)initWithObject:(id)object requestDescriptor:(RKRequestDescriptor *)requestDescriptor
@@ -84,6 +85,12 @@
operation.delegate = self;
[operation start];
if (operation.error) {
if (operation.error.code == RKMappingErrorUnmappableRepresentation) {
// If the mapped object is empty, return an empty dictionary and no error
return @{};
}
if (error) *error = operation.error;
return nil;
}

View File

@@ -22,11 +22,11 @@
typedef UInt32 RKMappingErrorCode;
enum {
RKMappingErrorNotFound = 1001, // No mapping found
RKMappingErrorTypeMismatch = 1002, // Target class and object mapping are in disagreement
RKMappingErrorUnmappableContent = 1003, // No mappable attributes or relationships were found
RKMappingErrorFromMappingResult = 1004, // The error was returned from the mapping result
RKMappingErrorValidationFailure = 1005 // Generic error code for use when constructing validation errors
RKMappingErrorNotFound = 1001, // No mapping found
RKMappingErrorTypeMismatch = 1002, // Target class and object mapping are in disagreement
RKMappingErrorUnmappableRepresentation = 1003, // No values were found at the key paths of any attribute or relationship mappings in the given representation
RKMappingErrorFromMappingResult = 1004, // The error was returned from the mapping result
RKMappingErrorValidationFailure = 1005 // Generic error code for use when constructing validation errors
};
extern NSString * const RKMappingErrorKeyPathErrorKey; // The key path the error is associated with

View File

@@ -604,8 +604,9 @@ NSDate *RKDateFromStringWithFormatters(NSString *dateString, NSArray *formatters
RKLogError(@"Failed mapping operation: %@", [self.error localizedDescription]);
} else {
// We did not find anything to do
RKLogDebug(@"Mapping operation did not find any mappable content");
self.error = [NSError errorWithDomain:RKErrorDomain code:RKMappingErrorUnmappableContent userInfo:nil];
RKLogDebug(@"Mapping operation did not find any mappable values for the attribute and relationship mappings in the given object representation");
NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: @"No mappable values found for any of the attributes or relationship mappings" };
self.error = [NSError errorWithDomain:RKErrorDomain code:RKMappingErrorUnmappableRepresentation userInfo:userInfo];
}
}

View File

@@ -23,6 +23,7 @@
#import "RKLog.h"
#import "RKObjectManager.h"
#import "RKPathUtilities.h"
#import "RKMIMETypeSerialization.h"
@interface RKTestFactory ()
@@ -38,6 +39,12 @@
@end
// Expose MIME Type singleton and initialization routine
@interface RKMIMETypeSerialization ()
+ (RKMIMETypeSerialization *)sharedSerialization;
- (void)addRegistrationsForKnownSerializations;
@end
static RKTestFactory *sharedFactory = nil;
@implementation RKTestFactory
@@ -234,6 +241,9 @@ static RKTestFactory *sharedFactory = nil;
[[RKTestFactory sharedFactory].sharedObjectsByFactoryName removeAllObjects];
[RKObjectManager setSharedManager:nil];
[RKManagedObjectStore setDefaultStore:nil];
// Restore the default MIME Type Serializations in case a test has manipulated the registry
[[RKMIMETypeSerialization sharedSerialization] addRegistrationsForKnownSerializations];
// Delete the store if it exists
NSString *path = [RKApplicationDataDirectory() stringByAppendingPathComponent:RKTestFactoryDefaultStoreFilename];

View File

@@ -644,7 +644,7 @@
25160D8E145650490060A5C5 /* RKObjectMapping.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKObjectMapping.m; sourceTree = "<group>"; };
25160D8F145650490060A5C5 /* RKMapping.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RKMapping.h; sourceTree = "<group>"; };
25160D90145650490060A5C5 /* RKMappingOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RKMappingOperation.h; sourceTree = "<group>"; };
25160D91145650490060A5C5 /* RKMappingOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKMappingOperation.m; sourceTree = "<group>"; };
25160D91145650490060A5C5 /* RKMappingOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = RKMappingOperation.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
25160D94145650490060A5C5 /* RKMappingResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RKMappingResult.h; sourceTree = "<group>"; };
25160D95145650490060A5C5 /* RKMappingResult.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKMappingResult.m; sourceTree = "<group>"; };
25160D96145650490060A5C5 /* RKPropertyInspector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RKPropertyInspector.h; sourceTree = "<group>"; };
@@ -742,8 +742,8 @@
2516101C1456F2330060A5C5 /* RKDynamicObjectMappingTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKDynamicObjectMappingTest.m; sourceTree = "<group>"; };
2516101E1456F2330060A5C5 /* RKObjectLoaderTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKObjectLoaderTest.m; sourceTree = "<group>"; };
2516101F1456F2330060A5C5 /* RKObjectManagerTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKObjectManagerTest.m; sourceTree = "<group>"; };
251610211456F2330060A5C5 /* RKObjectMappingNextGenTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKObjectMappingNextGenTest.m; sourceTree = "<group>"; };
251610221456F2330060A5C5 /* RKObjectMappingOperationTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKObjectMappingOperationTest.m; sourceTree = "<group>"; };
251610211456F2330060A5C5 /* RKObjectMappingNextGenTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = RKObjectMappingNextGenTest.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
251610221456F2330060A5C5 /* RKObjectMappingOperationTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = RKObjectMappingOperationTest.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
251610231456F2330060A5C5 /* RKObjectMappingProviderTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKObjectMappingProviderTest.m; sourceTree = "<group>"; };
251610241456F2330060A5C5 /* RKObjectMappingResultTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKObjectMappingResultTest.m; sourceTree = "<group>"; };
251610261456F2330060A5C5 /* RKObjectParameterizationTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKObjectParameterizationTest.m; sourceTree = "<group>"; };
@@ -858,7 +858,7 @@
25A763E415C7424500A9DF31 /* RKSearchIndexerTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKSearchIndexerTest.m; sourceTree = "<group>"; };
25AA23CF15AF291F006EF62D /* RKManagedObjectMappingOperationDataSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKManagedObjectMappingOperationDataSource.m; sourceTree = "<group>"; };
25AA23D315AF4F25006EF62D /* RKManagedObjectMappingOperationDataSourceTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKManagedObjectMappingOperationDataSourceTest.m; sourceTree = "<group>"; };
25AFF8F015B4CF1F0051877F /* RKMappingErrors.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RKMappingErrors.h; sourceTree = "<group>"; };
25AFF8F015B4CF1F0051877F /* RKMappingErrors.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = RKMappingErrors.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
25B408241491CDDB00F21111 /* RKPathUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RKPathUtilities.h; sourceTree = "<group>"; };
25B408251491CDDB00F21111 /* RKPathUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKPathUtilities.m; sourceTree = "<group>"; };
25B6E95414CF795D00B1E881 /* RKErrors.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RKErrors.h; sourceTree = "<group>"; };

View File

@@ -276,6 +276,20 @@ describe(@"matchesResponse:", ^{
[[@([responseDescriptor matchesResponse:response]) should] beYes];
});
});
context(@"then given the URL 'http://domain.com/domain/api/v1/recommendation?action=search&type=whatever'", ^{
beforeEach(^{
RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]];
responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:mapping pathPattern:@"/recommendation/" keyPath:nil statusCodes:[NSIndexSet indexSetWithIndex:200]];
responseDescriptor.baseURL = [NSURL URLWithString:@"http://domain.com/domain/api/v1/"];
});
it(@"returns YES", ^{
NSURL *URL = [NSURL URLWithString:@"http://domain.com/domain/api/v1/recommendation?action=search&type=whatever"];
NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:URL statusCode:200 HTTPVersion:@"1.1" headerFields:nil];
[[@([responseDescriptor matchesResponse:response]) should] beYes];
});
});
});
});
});

View File

@@ -137,22 +137,25 @@
// TODO: Move to Core Data specific spec file...
- (void)testShouldUpdateACoreDataBackedTargetObject
{
RKHuman *temporaryHuman = [[RKHuman alloc] initWithEntity:[NSEntityDescription entityForName:@"RKHuman" inManagedObjectContext:_objectManager.managedObjectStore.persistentStoreManagedObjectContext] insertIntoManagedObjectContext:_objectManager.managedObjectStore.persistentStoreManagedObjectContext];
NSManagedObjectContext *managedObjectContext = [[RKTestFactory managedObjectStore] persistentStoreManagedObjectContext];
RKHuman *temporaryHuman = [RKTestFactory insertManagedObjectForEntityForName:@"RKHuman" inManagedObjectContext:managedObjectContext withProperties:nil];
temporaryHuman.name = @"My Name";
RKManagedObjectRequestOperation *operation = [_objectManager appropriateObjectRequestOperationWithObject:temporaryHuman method:RKRequestMethodPOST path:nil parameters:nil];
[operation start];
[operation waitUntilFinished];
assertThat([operation.mappingResult array], isNot(empty()));
expect(operation.mappingResult).notTo.beNil();
expect([operation.mappingResult array]).notTo.beEmpty();
RKHuman *human = (RKHuman *)[[operation.mappingResult array] objectAtIndex:0];
assertThat(human.objectID, is(equalTo(temporaryHuman.objectID)));
assertThat(human.railsID, is(equalToInt(1)));
expect(human.objectID).to.equal(temporaryHuman.objectID);
expect(human.railsID).to.equal(1);
}
- (void)testShouldNotPersistTemporaryEntityToPersistentStoreOnError
{
RKHuman *temporaryHuman = [NSEntityDescription insertNewObjectForEntityForName:@"RKHuman" inManagedObjectContext:_objectManager.managedObjectStore.persistentStoreManagedObjectContext];
NSManagedObjectContext *managedObjectContext = [[RKTestFactory managedObjectStore] persistentStoreManagedObjectContext];
RKHuman *temporaryHuman = [RKTestFactory insertManagedObjectForEntityForName:@"RKHuman" inManagedObjectContext:managedObjectContext withProperties:nil];
temporaryHuman.name = @"My Name";
RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[NSMutableDictionary class]];
[mapping addAttributeMappingsFromArray:@[@"name"]];
@@ -161,29 +164,30 @@
[operation start];
[operation waitUntilFinished];
assertThatBool([temporaryHuman isNew], is(equalToBool(YES)));
expect([temporaryHuman isNew]).to.equal(YES);
}
- (void)testShouldNotDeleteACoreDataBackedTargetObjectOnErrorIfItWasAlreadySaved
- (void)testThatFailedObjectRequestOperationDoesNotSaveObjectToPersistentStore
{
RKHuman *temporaryHuman = [[RKHuman alloc] initWithEntity:[NSEntityDescription entityForName:@"RKHuman" inManagedObjectContext:_objectManager.managedObjectStore.persistentStoreManagedObjectContext] insertIntoManagedObjectContext:_objectManager.managedObjectStore.persistentStoreManagedObjectContext];
NSManagedObjectContext *managedObjectContext = [[RKTestFactory managedObjectStore] persistentStoreManagedObjectContext];
RKHuman *temporaryHuman = [RKTestFactory insertManagedObjectForEntityForName:@"RKHuman" inManagedObjectContext:managedObjectContext withProperties:nil];
temporaryHuman.name = @"My Name";
RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[NSMutableDictionary class]];
[mapping addAttributeMappingsFromArray:@[@"name"]];
// Save it to suppress deletion
[self.objectManager.managedObjectStore.persistentStoreManagedObjectContext save:nil];
expect([temporaryHuman isNew]).to.equal(YES);
RKManagedObjectRequestOperation *operation = [self.objectManager appropriateObjectRequestOperationWithObject:temporaryHuman method:RKRequestMethodPOST path:@"/humans/fail" parameters:nil];
[operation start];
[operation waitUntilFinished];
assertThat(temporaryHuman.managedObjectContext, is(equalTo(_objectManager.managedObjectStore.persistentStoreManagedObjectContext)));
expect([temporaryHuman isNew]).to.equal(YES);
}
- (void)testShouldDeleteACoreDataBackedTargetObjectOnSuccessfulDeleteReturning200
{
RKHuman *temporaryHuman = [[RKHuman alloc] initWithEntity:[NSEntityDescription entityForName:@"RKHuman" inManagedObjectContext:_objectManager.managedObjectStore.persistentStoreManagedObjectContext] insertIntoManagedObjectContext:_objectManager.managedObjectStore.persistentStoreManagedObjectContext];
NSManagedObjectContext *managedObjectContext = [[RKTestFactory managedObjectStore] persistentStoreManagedObjectContext];
RKHuman *temporaryHuman = [RKTestFactory insertManagedObjectForEntityForName:@"RKHuman" inManagedObjectContext:managedObjectContext withProperties:nil];
temporaryHuman.name = @"My Name";
temporaryHuman.railsID = @1;
RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[NSMutableDictionary class]];
@@ -199,13 +203,14 @@
NSError *error = nil;
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"RKHuman"];
NSArray *humans = [_objectManager.managedObjectStore.persistentStoreManagedObjectContext executeFetchRequest:fetchRequest error:&error];
assertThat(error, is(nilValue()));
assertThatInteger(humans.count, is(equalToInteger(0)));
expect(error).to.beNil();
expect(humans).to.haveCountOf(0);
}
- (void)testShouldDeleteACoreDataBackedTargetObjectOnSuccessfulDeleteReturning204
{
RKHuman *temporaryHuman = [[RKHuman alloc] initWithEntity:[NSEntityDescription entityForName:@"RKHuman" inManagedObjectContext:_objectManager.managedObjectStore.persistentStoreManagedObjectContext] insertIntoManagedObjectContext:_objectManager.managedObjectStore.persistentStoreManagedObjectContext];
NSManagedObjectContext *managedObjectContext = [[RKTestFactory managedObjectStore] persistentStoreManagedObjectContext];
RKHuman *temporaryHuman = [RKTestFactory insertManagedObjectForEntityForName:@"RKHuman" inManagedObjectContext:managedObjectContext withProperties:nil];
temporaryHuman.name = @"My Name";
temporaryHuman.railsID = @204;
RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[NSMutableDictionary class]];
@@ -221,8 +226,8 @@
NSError *error = nil;
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"RKHuman"];
NSArray *humans = [_objectManager.managedObjectStore.persistentStoreManagedObjectContext executeFetchRequest:fetchRequest error:&error];
assertThat(error, is(nilValue()));
assertThatInteger(humans.count, is(equalToInteger(0)));
expect(error).to.beNil();
expect(humans).to.haveCountOf(0);
}
- (void)testCancellationByExactMethodAndPath
@@ -231,7 +236,7 @@
RKObjectRequestOperation *operation = [[RKObjectRequestOperation alloc] initWithRequest:request responseDescriptors:self.objectManager.responseDescriptors];
[_objectManager enqueueObjectRequestOperation:operation];
[_objectManager cancelAllObjectRequestOperationsWithMethod:RKRequestMethodGET matchingPathPattern:@"/object_manager/cancel"];
assertThatBool([operation isCancelled], is(equalToBool(YES)));
expect([operation isCancelled]).to.equal(YES);
}
- (void)testCancellationByPathMatch
@@ -240,7 +245,7 @@
RKObjectRequestOperation *operation = [[RKObjectRequestOperation alloc] initWithRequest:request responseDescriptors:self.objectManager.responseDescriptors];
[_objectManager enqueueObjectRequestOperation:operation];
[_objectManager cancelAllObjectRequestOperationsWithMethod:RKRequestMethodGET matchingPathPattern:@"/object_manager/:objectID/cancel"];
assertThatBool([operation isCancelled], is(equalToBool(YES)));
expect([operation isCancelled]).to.equal(YES);
}
- (void)testCancellationFailsForMismatchedMethod
@@ -249,7 +254,7 @@
RKObjectRequestOperation *operation = [[RKObjectRequestOperation alloc] initWithRequest:request responseDescriptors:self.objectManager.responseDescriptors];
[_objectManager enqueueObjectRequestOperation:operation];
[_objectManager cancelAllObjectRequestOperationsWithMethod:RKRequestMethodPOST matchingPathPattern:@"/object_manager/cancel"];
assertThatBool([operation isCancelled], is(equalToBool(NO)));
expect([operation isCancelled]).to.equal(NO);
}
- (void)testCancellationFailsForMismatchedPath
@@ -258,12 +263,13 @@
RKObjectRequestOperation *operation = [[RKObjectRequestOperation alloc] initWithRequest:request responseDescriptors:self.objectManager.responseDescriptors];
[_objectManager enqueueObjectRequestOperation:operation];
[_objectManager cancelAllObjectRequestOperationsWithMethod:RKRequestMethodGET matchingPathPattern:@"/wrong"];
assertThatBool([operation isCancelled], is(equalToBool(NO)));
expect([operation isCancelled]).to.equal(NO);
}
- (void)testShouldProperlyFireABatchOfOperations
{
RKHuman *temporaryHuman = [NSEntityDescription insertNewObjectForEntityForName:@"RKHuman" inManagedObjectContext:_objectManager.managedObjectStore.persistentStoreManagedObjectContext];
NSManagedObjectContext *managedObjectContext = [[RKTestFactory managedObjectStore] persistentStoreManagedObjectContext];
RKHuman *temporaryHuman = [RKTestFactory insertManagedObjectForEntityForName:@"RKHuman" inManagedObjectContext:managedObjectContext withProperties:nil];
temporaryHuman.name = @"My Name";
RKManagedObjectRequestOperation *successfulGETOperation = [_objectManager appropriateObjectRequestOperationWithObject:temporaryHuman method:RKRequestMethodGET path:nil parameters:nil];
@@ -277,25 +283,26 @@
} completion:^(NSArray *operations) {
completionBlockOperationCount = operations.count;
}];
assertThat(_objectManager.operationQueue, is(notNilValue()));
expect(_objectManager.operationQueue).notTo.beNil();
[_objectManager.operationQueue waitUntilAllOperationsAreFinished];
// Spin the run loop to allow completion blocks to fire after operations have completed
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.01]];
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.02]];
assertThatInteger(progressCallbackCount, is(equalToInteger(3)));
assertThatInteger(completionBlockOperationCount, is(equalToInteger(3)));
expect(progressCallbackCount).to.equal(3);
expect(completionBlockOperationCount).to.equal(3);
}
- (void)testShouldProperlyFireABatchOfOperationsFromRoute
{
RKHuman *dan = [NSEntityDescription insertNewObjectForEntityForName:@"RKHuman" inManagedObjectContext:_objectManager.managedObjectStore.persistentStoreManagedObjectContext];
NSManagedObjectContext *managedObjectContext = [[RKTestFactory managedObjectStore] persistentStoreManagedObjectContext];
RKHuman *dan = [RKTestFactory insertManagedObjectForEntityForName:@"RKHuman" inManagedObjectContext:managedObjectContext withProperties:nil];
dan.name = @"Dan";
RKHuman *blake = [NSEntityDescription insertNewObjectForEntityForName:@"RKHuman" inManagedObjectContext:_objectManager.managedObjectStore.persistentStoreManagedObjectContext];
RKHuman *blake = [RKTestFactory insertManagedObjectForEntityForName:@"RKHuman" inManagedObjectContext:managedObjectContext withProperties:nil];
blake.name = @"Blake";
RKHuman *jeff = [NSEntityDescription insertNewObjectForEntityForName:@"RKHuman" inManagedObjectContext:_objectManager.managedObjectStore.persistentStoreManagedObjectContext];
RKHuman *jeff = [RKTestFactory insertManagedObjectForEntityForName:@"RKHuman" inManagedObjectContext:managedObjectContext withProperties:nil];
jeff.name = @"Jeff";
__block NSUInteger progressCallbackCount = 0;
@@ -305,19 +312,19 @@
} completion:^(NSArray *operations) {
completionBlockOperationCount = operations.count;
}];
assertThat(_objectManager.operationQueue, is(notNilValue()));
expect(_objectManager.operationQueue).notTo.beNil();
[_objectManager.operationQueue waitUntilAllOperationsAreFinished];
// Spin the run loop to allow completion blocks to fire after operations have completed
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.01]];
assertThatInteger(progressCallbackCount, is(equalToInteger(3)));
assertThatInteger(completionBlockOperationCount, is(equalToInteger(3)));
expect(progressCallbackCount).to.equal(3);
expect(completionBlockOperationCount).to.equal(3);
}
- (void)testThatObjectParametersAreNotSentDuringGetObject
{
RKHuman *temporaryHuman = [[RKHuman alloc] initWithEntity:[NSEntityDescription entityForName:@"RKHuman" inManagedObjectContext:_objectManager.managedObjectStore.persistentStoreManagedObjectContext] insertIntoManagedObjectContext:_objectManager.managedObjectStore.persistentStoreManagedObjectContext];
RKHuman *temporaryHuman = [RKTestFactory insertManagedObjectForEntityForName:@"RKHuman" inManagedObjectContext:nil withProperties:nil];
temporaryHuman.name = @"My Name";
temporaryHuman.railsID = @204;
RKManagedObjectRequestOperation *operation = [_objectManager appropriateObjectRequestOperationWithObject:temporaryHuman method:RKRequestMethodGET path:nil parameters:@{@"this": @"that"}];
@@ -326,13 +333,24 @@
- (void)testThatObjectParametersAreNotSentDuringDeleteObject
{
RKHuman *temporaryHuman = [[RKHuman alloc] initWithEntity:[NSEntityDescription entityForName:@"RKHuman" inManagedObjectContext:_objectManager.managedObjectStore.persistentStoreManagedObjectContext] insertIntoManagedObjectContext:_objectManager.managedObjectStore.persistentStoreManagedObjectContext];
RKHuman *temporaryHuman = [RKTestFactory insertManagedObjectForEntityForName:@"RKHuman" inManagedObjectContext:nil withProperties:nil];
temporaryHuman.name = @"My Name";
temporaryHuman.railsID = @204;
RKManagedObjectRequestOperation *operation = [_objectManager appropriateObjectRequestOperationWithObject:temporaryHuman method:RKRequestMethodDELETE path:nil parameters:@{@"this": @"that"}];
expect([operation.request.URL absoluteString]).to.equal(@"http://127.0.0.1:4567/humans/204?this=that");
}
- (void)testInitializationOfObjectRequestOperationProducesCorrectURLRequest
{
RKHuman *temporaryHuman = [RKTestFactory insertManagedObjectForEntityForName:@"RKHuman" inManagedObjectContext:nil withProperties:nil];
NSURLRequest *request = [_objectManager requestWithObject:temporaryHuman method:RKRequestMethodPATCH path:@"/the/path" parameters:@{@"key": @"value"}];
expect([request.URL absoluteString]).to.equal(@"http://127.0.0.1:4567/the/path");
expect(request.HTTPMethod).to.equal(@"PATCH");
expect(request.HTTPBody).notTo.beNil();
NSString *string = [[NSString alloc] initWithData:request.HTTPBody encoding:NSUTF8StringEncoding];
expect(string).to.equal(@"key=value");
}
// TODO: Move to Core Data specific spec file...
//- (void)testShouldLoadAHuman
//{

View File

@@ -793,7 +793,7 @@
BOOL success = [operation performMapping:&error];
assertThatBool(success, is(equalToBool(NO)));
assertThat(error, is(notNilValue()));
assertThatInteger(operation.error.code, is(equalToInteger(RKMappingErrorUnmappableContent)));
assertThatInteger(operation.error.code, is(equalToInteger(RKMappingErrorUnmappableRepresentation)));
}
- (void)testShouldInformTheDelegateOfAnErrorWhenMappingFailsBecauseThereIsNoMappableContent

View File

@@ -53,7 +53,7 @@
- (BOOL)validateBoolString:(id *)ioValue error:(NSError **)outError
{
if ([(NSObject *)*ioValue isKindOfClass:[NSString class]] && [(NSString *)*ioValue isEqualToString:@"FAIL"]) {
*outError = [NSError errorWithDomain:RKErrorDomain code:RKMappingErrorUnmappableContent userInfo:nil];
*outError = [NSError errorWithDomain:RKErrorDomain code:RKMappingErrorUnmappableRepresentation userInfo:nil];
return NO;
} else if ([(NSObject *)*ioValue isKindOfClass:[NSString class]] && [(NSString *)*ioValue isEqualToString:@"REJECT"]) {
return NO;

View File

@@ -177,7 +177,7 @@
assertThat(string, is(equalTo(@"{\"key2-form-name\":\"value2\",\"key1-form-name\":\"value1\"}")));
}
- (void)testShouldSetReturnNilIfItDoesNotFindAnythingToSerialize
- (void)testShouldSetReturnEmptyDictionaryIfItDoesNotFindAnythingToSerialize
{
NSDictionary *object = [NSDictionary dictionaryWithObjectsAndKeys:@"value1", @"key1", @"value2", @"key2", nil];
RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[NSDictionary class]];
@@ -186,8 +186,8 @@
NSError *error = nil;
RKRequestDescriptor *requestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:mapping objectClass:[NSDictionary class] rootKeyPath:nil];
NSDictionary *parameters = [RKObjectParameterization parametersWithObject:object requestDescriptor:requestDescriptor error:&error];
assertThat(parameters, is(nilValue()));
expect(error).to.beNil();
expect(parameters).to.equal(@{});
}
- (void)testShouldSerializeNestedObjectsContainingDatesToJSON