mirror of
https://github.com/zhigang1992/RestKit.git
synced 2026-04-29 05:05:34 +08:00
Updated mapping test API for 0.20
* Reimplemented connection tests to work with `RKConnectionDescription`. Introduced new `RKConnectionTestExpectation` class * Slimmed down API by removing proxy methods on `RKMappingTest` * Eliminated `verifiesOnExpect` behavior in favor of using `evaluateExpectation:` * Ensured compatibility with RKKiwiMatchers
This commit is contained in:
83
Code/Testing/RKConnectionTestExpectation.h
Normal file
83
Code/Testing/RKConnectionTestExpectation.h
Normal file
@@ -0,0 +1,83 @@
|
||||
//
|
||||
// RKConnectionTestExpectation.h
|
||||
// RestKit
|
||||
//
|
||||
// Created by Blake Watters on 12/8/12.
|
||||
// Copyright (c) 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 <Foundation/Foundation.h>
|
||||
|
||||
/**
|
||||
An `RKConnectionTestExpectation` object defines an expectation that a Core Data relationship is connected during the execution of a `RKMappingTest`. These expectation are used to unit test a connection specified via an `RKConnectionDescription` object.
|
||||
|
||||
@see `RKMappingTest`
|
||||
@see `RKConnectionDescription`
|
||||
*/
|
||||
@interface RKConnectionTestExpectation : NSObject
|
||||
|
||||
///----------------------------
|
||||
/// @name Creating Expectations
|
||||
///----------------------------
|
||||
|
||||
/**
|
||||
Creates and returns a connection expectation for the specified relationship name, attributes dictionary, and value.
|
||||
|
||||
@param relationshipName The name of the relationship expected to be connected.
|
||||
@param attributes A dictionary specifying the attributes that are expected to be used to establish the connection.
|
||||
@param value The value that is expected to be set for the relationship when the connection is established.
|
||||
@return A newly constructed connection expectation, initialized with the given relationship name, attributes dictionary, and expected value.
|
||||
*/
|
||||
+ (id)expectationWithRelationshipName:(NSString *)relationshipName attributes:(NSDictionary *)attributes value:(id)value;
|
||||
|
||||
/**
|
||||
Initializes the receiver with the given relationship name, attributes dictionary, and value.
|
||||
|
||||
@param relationshipName The name of the relationship expected to be connected.
|
||||
@param attributes A dictionary specifying the attributes that are expected to be used to establish the connection.
|
||||
@param value The value that is expected to be set for the relationship when the connection is established.
|
||||
@return The receiver, initialized with the given relationship name, attributes dictionary, and expected value.
|
||||
*/
|
||||
- (id)initWithRelationshipName:(NSString *)relationshipName attributes:(NSDictionary *)attributes value:(id)value;
|
||||
|
||||
///------------------------------------
|
||||
/// @name Accessing Expectation Details
|
||||
///------------------------------------
|
||||
|
||||
/**
|
||||
The name of the relationship that is expected to be connected. Cannot be `nil`.
|
||||
*/
|
||||
@property (nonatomic, copy, readonly) NSString *relationshipName;
|
||||
|
||||
/**
|
||||
The dictionary of attributes that are expected to be used when the connection is established. May be `nil`.
|
||||
*/
|
||||
@property (nonatomic, copy, readonly) NSDictionary *attributes;
|
||||
|
||||
/**
|
||||
The value that is expected to be set for the relationship when connected. May be `nil`.
|
||||
|
||||
A value of `nil` indicates that expectation does not specify an exact value for the connection, only that it was set during the execution of the test. A value of `[NSNull null]` indicates that the connection is expected to be connected to a nil value.
|
||||
*/
|
||||
@property (nonatomic, strong, readonly) id value;
|
||||
|
||||
/**
|
||||
Returns a string summary of the connection that is expected to be established.
|
||||
|
||||
@return A string describing the expected connection.
|
||||
*/
|
||||
- (NSString *)summary;
|
||||
|
||||
@end
|
||||
66
Code/Testing/RKConnectionTestExpectation.m
Normal file
66
Code/Testing/RKConnectionTestExpectation.m
Normal file
@@ -0,0 +1,66 @@
|
||||
//
|
||||
// RKConnectionTestExpectation.m
|
||||
// RestKit
|
||||
//
|
||||
// Created by Blake Watters on 12/8/12.
|
||||
// Copyright (c) 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 <CoreData/CoreData.h>
|
||||
#import "RKConnectionTestExpectation.h"
|
||||
#import "RKObjectUtilities.h"
|
||||
|
||||
@interface RKConnectionTestExpectation ()
|
||||
@property (nonatomic, copy, readwrite) NSString *relationshipName;
|
||||
@property (nonatomic, copy, readwrite) NSDictionary *attributes;
|
||||
@property (nonatomic, strong, readwrite) id value;
|
||||
@end
|
||||
|
||||
@implementation RKConnectionTestExpectation
|
||||
|
||||
+ (id)expectationWithRelationshipName:(NSString *)relationshipName attributes:(NSDictionary *)attributes value:(id)value
|
||||
{
|
||||
return [[self alloc] initWithRelationshipName:relationshipName attributes:attributes value:value];
|
||||
}
|
||||
|
||||
- (id)initWithRelationshipName:(NSString *)relationshipName attributes:(NSDictionary *)attributes value:(id)value
|
||||
{
|
||||
NSParameterAssert(relationshipName);
|
||||
NSAssert(value == nil ||
|
||||
[value isKindOfClass:[NSManagedObject class]] ||
|
||||
RKObjectIsCollectionContainingOnlyManagedObjects(value), @"Can only expect a connection to `nil`, a `NSManagedObject`, or a collection of `NSManagedObject` objects");
|
||||
self = [self init];
|
||||
if (self) {
|
||||
self.relationshipName = relationshipName;
|
||||
self.attributes = attributes;
|
||||
self.value = value;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSString *)summary
|
||||
{
|
||||
return [NSString stringWithFormat:@"connect relationship '%@'", self.relationshipName];
|
||||
}
|
||||
|
||||
- (NSString *)description
|
||||
{
|
||||
NSMutableString *description = [[self summary] mutableCopy];
|
||||
if (self.attributes) [description appendFormat:@" using attributes %@", self.attributes];
|
||||
if (self.value) [description appendFormat:@" to value %@", self.value];
|
||||
return description;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -21,7 +21,7 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <CoreData/CoreData.h>
|
||||
#import "RKMappingOperation.h"
|
||||
#import "RKMappingTestExpectation.h"
|
||||
#import "RKPropertyMappingTestExpectation.h"
|
||||
|
||||
@protocol RKMappingOperationDataSource, RKManagedObjectCaching;
|
||||
|
||||
@@ -45,10 +45,28 @@ extern NSString * const RKMappingTestVerificationFailureException;
|
||||
enum {
|
||||
RKMappingTestUnsatisfiedExpectationError, // An expected mapping event did not occur
|
||||
RKMappingTestEvaluationBlockError, // An evaluation block returned `NO` when evaluating a mapping event
|
||||
RKMappingTestValueInequalityError, // A mapped value was not equal to the expected value
|
||||
RKMappingTestValueInequalityError, // A value was not equal to the expected value
|
||||
RKMappingTestMappingMismatchError, // A mapping occurred using an unexpected `RKObjectMapping` object
|
||||
};
|
||||
|
||||
/**
|
||||
@define RKMappingTestExpectationTestCondition
|
||||
@abstract Tests a condition and returns `NO` and error if it is not true.
|
||||
@discussion This is a useful macro when constructing mapping test evaluation blocks. It will test a condition and return `NO` as well as construct an error. This is meant to be used **only** within the body of a `RKMappingTestExpectationEvaluationBlock` object.
|
||||
@param condition The condition to test.
|
||||
@param errorCode An error code in the RKMappingTestErrorDomain indicating the nature of the failure.
|
||||
@param error The NSError object to put the error string into. May be nil, but should usually be the error parameter from the expectation evaluation block.
|
||||
@param ... A string describing the error.
|
||||
*/
|
||||
#define RKMappingTestCondition(condition, errorCode, error, ...) ({ \
|
||||
if (!(condition)) { \
|
||||
if (error) { \
|
||||
*error = [NSError errorWithDomain:RKMappingTestErrorDomain code:errorCode userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:__VA_ARGS__], NSLocalizedDescriptionKey, nil]]; \
|
||||
} \
|
||||
return NO; \
|
||||
} \
|
||||
})
|
||||
|
||||
/**
|
||||
The `RKMappingTestEvent` object for the mapping event which failed to satify the expectation.
|
||||
*/
|
||||
@@ -89,59 +107,29 @@ extern NSString * const RKMappingTestExpectationErrorKey;
|
||||
*/
|
||||
- (id)initWithMapping:(RKMapping *)mapping sourceObject:(id)sourceObject destinationObject:(id)destinationObject;
|
||||
|
||||
///---------------------------
|
||||
/// @name Setting Expectations
|
||||
///---------------------------
|
||||
|
||||
/**
|
||||
Creates and adds an expectation that a key path on the source object will be mapped to a new key path on the destination object.
|
||||
|
||||
@param sourceKeyPath A key path on the sourceObject that should be mapped from.
|
||||
@param destinationKeyPath A key path on the destinationObject that should be mapped to.
|
||||
@see `RKMappingTestExpectation`
|
||||
*/
|
||||
- (void)expectMappingFromKeyPath:(NSString *)sourceKeyPath toKeyPath:(NSString *)destinationKeyPath;
|
||||
|
||||
/**
|
||||
Creates and adds an expectation that a key path on the source object will be mapped to a new key path on the destination object with a given value.
|
||||
|
||||
@param sourceKeyPath A key path on the sourceObject that should be mapped from.
|
||||
@param destinationKeyPath A key path on the destinationObject that should be mapped from.
|
||||
@param value A value that is expected to be assigned to destinationKeyPath on the destinationObject.
|
||||
@see `RKMappingTestExpectation`
|
||||
*/
|
||||
- (void)expectMappingFromKeyPath:(NSString *)sourceKeyPath toKeyPath:(NSString *)destinationKeyPath withValue:(id)value;
|
||||
|
||||
/**
|
||||
Creates and adds an expectation that a key path on the source object will be mapped to a new key path on the destination object with a value that passes a given test block.
|
||||
|
||||
@param sourceKeyPath A key path on the sourceObject that should be mapped from.
|
||||
@param destinationKeyPath A key path on the destinationObject that should be mapped to.
|
||||
@param evaluationBlock A block with which to evaluate the success of the mapping.
|
||||
@see `RKMappingTestExpectation`
|
||||
*/
|
||||
- (void)expectMappingFromKeyPath:(NSString *)sourceKeyPath toKeyPath:(NSString *)destinationKeyPath passingTest:(RKMappingTestExpectationEvaluationBlock)evaluationBlock;
|
||||
|
||||
/**
|
||||
Creates and adds an expectation that a key path on the source object will be mapped to a new key path on the destination object using the given object mapping.
|
||||
|
||||
@param sourceKeyPath A key path on the sourceObject that should be mapped from.
|
||||
@param destinationKeyPath A key path on the destinationObject that should be mapped to.
|
||||
@param mapping An object mapping that should be used for mapping the source key path.
|
||||
@see `RKMappingTestExpectation`
|
||||
*/
|
||||
- (void)expectMappingFromKeyPath:(NSString *)sourceKeyPath toKeyPath:(NSString *)destinationKeyPath usingMapping:(RKMapping *)mapping;
|
||||
///----------------------------
|
||||
/// @name Managing Expectations
|
||||
///----------------------------
|
||||
|
||||
/**
|
||||
Adds an expectation to the receiver to be evaluated during verification.
|
||||
|
||||
If the receiver has been configured with `verifiesOnExpect = YES`, the mapping operation is performed immediately and the expectation is evaluated.
|
||||
|
||||
@param expectation An expectation object to evaluate during test verification.
|
||||
@param expectation An expectation object to evaluate during test verification. Must be an instance of `RKPropertyMappingTestExpectation` or `RKConnectionTestExpectation`.
|
||||
@see `RKMappingTestExpectation`
|
||||
@see `verifiesOnExpect`
|
||||
*/
|
||||
- (void)addExpectation:(RKMappingTestExpectation *)expectation;
|
||||
- (void)addExpectation:(id)expectation;
|
||||
|
||||
/**
|
||||
Evaluates the given expectation against the mapping test and returns a Boolean value indicating if the expectation is met by the receiver.
|
||||
|
||||
Invocation of this method will implicitly invoke `performMapping` if the mapping has not yet been performed.
|
||||
|
||||
@param expectation The expectation to evaluate against the receiver. Must be an intance of either `RKPropertyMappingTestExpectation` or `RKConnectionTestExpectation`.
|
||||
@param error A pointer to an `NSError` object to be set describing the failure in the event that the expectation is not met.
|
||||
@return `YES` if the expectation is met, else `NO`.
|
||||
*/
|
||||
- (BOOL)evaluateExpectation:(id)expectation error:(NSError **)error;
|
||||
|
||||
///------------------------
|
||||
/// @name Verifying Results
|
||||
@@ -170,17 +158,6 @@ extern NSString * const RKMappingTestExpectationErrorKey;
|
||||
*/
|
||||
- (BOOL)evaluate;
|
||||
|
||||
/**
|
||||
Evaluates the given expectation against the mapping test and returns a Boolean value indicating if the expectation is met by the receiver.
|
||||
|
||||
Invocation of this method will implicitly invoke `performMapping` if the mapping has not yet been performed.
|
||||
|
||||
@param expectation The expectation to evaluate against the receiver.
|
||||
@param error A pointer to an `NSError` object to be set describing the failure in the event that the expectation is not met.
|
||||
@return `YES` if the expectation is met, else `NO`.
|
||||
*/
|
||||
- (BOOL)evaluateExpectation:(RKMappingTestExpectation *)expectation error:(NSError **)error;
|
||||
|
||||
///-------------------------
|
||||
/// @name Test Configuration
|
||||
///-------------------------
|
||||
@@ -218,13 +195,6 @@ extern NSString * const RKMappingTestExpectationErrorKey;
|
||||
*/
|
||||
@property (nonatomic, strong, readonly) id destinationObject;
|
||||
|
||||
/**
|
||||
A Boolean value that determines if expectations should be verified immediately when added to the receiver.
|
||||
|
||||
**Default**: `NO`
|
||||
*/
|
||||
@property (nonatomic, assign) BOOL verifiesOnExpect;
|
||||
|
||||
///----------------------------
|
||||
/// @name Core Data Integration
|
||||
///----------------------------
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
#import "RKLog.h"
|
||||
|
||||
// Core Data
|
||||
#import "RKConnectionDescription.h"
|
||||
#import "RKConnectionTestExpectation.h"
|
||||
#import "RKFetchRequestManagedObjectCache.h"
|
||||
#import "RKManagedObjectMappingOperationDataSource.h"
|
||||
|
||||
@@ -122,7 +124,7 @@ NSString * const RKMappingTestVerificationFailureException = @"RKMappingTestVeri
|
||||
|
||||
// Method Definitions for old compilers
|
||||
- (void)performMapping;
|
||||
- (void)verifyExpectation:(RKMappingTestExpectation *)expectation;
|
||||
- (void)verifyExpectation:(RKPropertyMappingTestExpectation *)expectation;
|
||||
|
||||
@end
|
||||
|
||||
@@ -145,55 +147,43 @@ NSString * const RKMappingTestVerificationFailureException = @"RKMappingTestVeri
|
||||
self.mapping = mapping;
|
||||
self.expectations = [NSMutableArray new];
|
||||
self.events = [NSMutableArray new];
|
||||
self.verifiesOnExpect = NO;
|
||||
self.performedMapping = NO;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)addExpectation:(RKMappingTestExpectation *)expectation
|
||||
- (void)addExpectation:(id)expectation
|
||||
{
|
||||
[self.expectations addObject:expectation];
|
||||
|
||||
if (self.verifiesOnExpect) {
|
||||
[self performMapping];
|
||||
[self verifyExpectation:expectation];
|
||||
NSParameterAssert(expectation);
|
||||
if (![expectation isKindOfClass:[RKPropertyMappingTestExpectation class]] && ![expectation isKindOfClass:[RKConnectionTestExpectation class]]) {
|
||||
[NSException raise:NSInvalidArgumentException
|
||||
format:@"Invalid expectation: expected an object of type `%@` or `%@`, but instead got a `%@`",
|
||||
[RKPropertyMappingTestExpectation class], [RKConnectionTestExpectation class], expectation];
|
||||
}
|
||||
[self.expectations addObject:expectation];
|
||||
}
|
||||
|
||||
- (void)expectMappingFromKeyPath:(NSString *)sourceKeyPath toKeyPath:(NSString *)destinationKeyPath
|
||||
{
|
||||
[self addExpectation:[RKMappingTestExpectation expectationWithSourceKeyPath:sourceKeyPath destinationKeyPath:destinationKeyPath]];
|
||||
}
|
||||
|
||||
- (void)expectMappingFromKeyPath:(NSString *)sourceKeyPath toKeyPath:(NSString *)destinationKeyPath withValue:(id)value
|
||||
{
|
||||
[self addExpectation:[RKMappingTestExpectation expectationWithSourceKeyPath:sourceKeyPath destinationKeyPath:destinationKeyPath value:value]];
|
||||
}
|
||||
|
||||
- (void)expectMappingFromKeyPath:(NSString *)sourceKeyPath toKeyPath:(NSString *)destinationKeyPath passingTest:(RKMappingTestExpectationEvaluationBlock)evaluationBlock
|
||||
{
|
||||
[self addExpectation:[RKMappingTestExpectation expectationWithSourceKeyPath:sourceKeyPath destinationKeyPath:destinationKeyPath evaluationBlock:evaluationBlock]];
|
||||
}
|
||||
|
||||
- (void)expectMappingFromKeyPath:(NSString *)sourceKeyPath toKeyPath:(NSString *)destinationKeyPath usingMapping:(RKMapping *)mapping
|
||||
{
|
||||
[self addExpectation:[RKMappingTestExpectation expectationWithSourceKeyPath:sourceKeyPath destinationKeyPath:destinationKeyPath mapping:mapping]];
|
||||
}
|
||||
|
||||
- (RKMappingTestEvent *)eventMatchingKeyPathsForExpectation:(RKMappingTestExpectation *)expectation
|
||||
- (RKMappingTestEvent *)eventMatchingExpectation:(id)expectation
|
||||
{
|
||||
for (RKMappingTestEvent *event in [self.events copy]) {
|
||||
if ([event.sourceKeyPath isEqualToString:expectation.sourceKeyPath] && [event.destinationKeyPath isEqualToString:expectation.destinationKeyPath]) {
|
||||
return event;
|
||||
if ([expectation isKindOfClass:[RKPropertyMappingTestExpectation class]]) {
|
||||
RKPropertyMappingTestExpectation *propertyExpectation = (RKPropertyMappingTestExpectation *) expectation;
|
||||
if ([event.sourceKeyPath isEqualToString:propertyExpectation.sourceKeyPath] && [event.destinationKeyPath isEqualToString:propertyExpectation.destinationKeyPath]) {
|
||||
return event;
|
||||
}
|
||||
} else if ([expectation isKindOfClass:[RKConnectionTestExpectation class]]) {
|
||||
RKConnectionTestExpectation *connectionExpectation = (RKConnectionTestExpectation *) expectation;
|
||||
if ([[event.connection.relationship name] isEqualToString:connectionExpectation.relationshipName]) {
|
||||
return event;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSError *)errorForExpectation:(RKMappingTestExpectation *)expectation
|
||||
- (NSError *)errorForExpectation:(RKPropertyMappingTestExpectation *)expectation
|
||||
withCode:(NSInteger)errorCode
|
||||
userInfo:(NSDictionary *)userInfo
|
||||
description:(NSString *)description
|
||||
@@ -205,90 +195,123 @@ NSString * const RKMappingTestVerificationFailureException = @"RKMappingTestVeri
|
||||
return [NSError errorWithDomain:RKMappingTestErrorDomain code:errorCode userInfo:fullUserInfo];
|
||||
}
|
||||
|
||||
- (BOOL)event:(RKMappingTestEvent *)event satisfiesExpectation:(RKMappingTestExpectation *)expectation error:(NSError **)error
|
||||
- (BOOL)event:(RKMappingTestEvent *)event satisfiesExpectation:(id)expectation error:(NSError **)error
|
||||
{
|
||||
BOOL success;
|
||||
|
||||
NSDictionary *userInfo = @{ RKMappingTestEventErrorKey : event,
|
||||
RKMappingTestExpectationErrorKey : expectation };
|
||||
if (expectation.evaluationBlock) {
|
||||
// Let the expectation block evaluate the match
|
||||
NSError *blockError = nil;
|
||||
success = expectation.evaluationBlock(expectation, event.propertyMapping, event.value, &blockError);
|
||||
|
||||
if (! success) {
|
||||
if (blockError) {
|
||||
// If the block has given us an error, use the reason
|
||||
NSMutableDictionary *mutableUserInfo = [userInfo mutableCopy];
|
||||
[mutableUserInfo setValue:blockError forKey:NSUnderlyingErrorKey];
|
||||
NSString *reason = [NSString stringWithFormat:@"expected to %@ with value %@ '%@', but it did not",
|
||||
expectation, [event.value class], event.value];
|
||||
*error = [self errorForExpectation:expectation
|
||||
withCode:RKMappingTestEvaluationBlockError
|
||||
userInfo:mutableUserInfo
|
||||
description:[blockError localizedDescription]
|
||||
reason:reason];
|
||||
|
||||
*error = blockError;
|
||||
} else {
|
||||
NSString *description = [NSString stringWithFormat:@"evaluation block returned `NO` for %@ value '%@'", [event.value class], event.value];
|
||||
NSString *reason = [NSString stringWithFormat:@"expected to %@ with value %@ '%@', but it did not",
|
||||
expectation, [event.value class], event.value];
|
||||
*error = [self errorForExpectation:expectation
|
||||
withCode:RKMappingTestEvaluationBlockError
|
||||
userInfo:userInfo
|
||||
description:description
|
||||
reason:reason];
|
||||
}
|
||||
}
|
||||
} else if (expectation.value) {
|
||||
// Use RestKit comparison magic to match values
|
||||
success = RKObjectIsEqualToObject(event.value, expectation.value);
|
||||
|
||||
if (! success) {
|
||||
NSString *description = [NSString stringWithFormat:@"mapped to unexpected %@ value '%@'", [event.value class], event.value];
|
||||
NSString *reason = [NSString stringWithFormat:@"expected to %@, but instead got %@ '%@'",
|
||||
expectation, [event.value class], event.value];
|
||||
if (error) *error = [self errorForExpectation:expectation
|
||||
withCode:RKMappingTestEvaluationBlockError
|
||||
userInfo:userInfo
|
||||
description:description
|
||||
reason:reason];
|
||||
}
|
||||
} else if (expectation.mapping) {
|
||||
if ([event.propertyMapping isKindOfClass:[RKRelationshipMapping class]]) {
|
||||
// Check the mapping that was used to map the relationship
|
||||
RKMapping *relationshipMapping = [(RKRelationshipMapping *)event.propertyMapping mapping];
|
||||
success = [relationshipMapping isEqualToMapping:expectation.mapping];
|
||||
|
||||
if ([expectation isKindOfClass:[RKPropertyMappingTestExpectation class]]) {
|
||||
RKPropertyMappingTestExpectation *propertyExpectation = (RKPropertyMappingTestExpectation *)expectation;
|
||||
if (propertyExpectation.evaluationBlock) {
|
||||
// Let the expectation block evaluate the match
|
||||
NSError *blockError = nil;
|
||||
success = propertyExpectation.evaluationBlock(expectation, event.propertyMapping, event.value, &blockError);
|
||||
|
||||
if (! success) {
|
||||
NSString *description = [NSString stringWithFormat:@"mapped using unexpected mapping: %@", relationshipMapping];
|
||||
NSString *reason = [NSString stringWithFormat:@"expected to %@, but was instead mapped using: %@",
|
||||
expectation, relationshipMapping];
|
||||
if (blockError) {
|
||||
// If the block has given us an error, use the reason
|
||||
NSMutableDictionary *mutableUserInfo = [userInfo mutableCopy];
|
||||
[mutableUserInfo setValue:blockError forKey:NSUnderlyingErrorKey];
|
||||
NSString *reason = [NSString stringWithFormat:@"expected to %@ with value %@ '%@', but it did not",
|
||||
expectation, [event.value class], event.value];
|
||||
*error = [self errorForExpectation:expectation
|
||||
withCode:RKMappingTestEvaluationBlockError
|
||||
userInfo:mutableUserInfo
|
||||
description:[blockError localizedDescription]
|
||||
reason:reason];
|
||||
|
||||
*error = blockError;
|
||||
} else {
|
||||
NSString *description = [NSString stringWithFormat:@"evaluation block returned `NO` for %@ value '%@'", [event.value class], event.value];
|
||||
NSString *reason = [NSString stringWithFormat:@"expected to %@ with value %@ '%@', but it did not",
|
||||
expectation, [event.value class], event.value];
|
||||
*error = [self errorForExpectation:expectation
|
||||
withCode:RKMappingTestEvaluationBlockError
|
||||
userInfo:userInfo
|
||||
description:description
|
||||
reason:reason];
|
||||
}
|
||||
}
|
||||
} else if (propertyExpectation.value) {
|
||||
// Use RestKit comparison magic to match values
|
||||
success = RKObjectIsEqualToObject(event.value, propertyExpectation.value);
|
||||
|
||||
if (! success) {
|
||||
NSString *description = [NSString stringWithFormat:@"mapped to unexpected %@ value '%@'", [event.value class], event.value];
|
||||
NSString *reason = [NSString stringWithFormat:@"expected to %@, but instead got %@ '%@'",
|
||||
expectation, [event.value class], event.value];
|
||||
if (error) *error = [self errorForExpectation:expectation
|
||||
withCode:RKMappingTestEvaluationBlockError
|
||||
userInfo:userInfo
|
||||
description:description
|
||||
reason:reason];
|
||||
}
|
||||
} else if (propertyExpectation.mapping) {
|
||||
if ([event.propertyMapping isKindOfClass:[RKRelationshipMapping class]]) {
|
||||
// Check the mapping that was used to map the relationship
|
||||
RKMapping *relationshipMapping = [(RKRelationshipMapping *)event.propertyMapping mapping];
|
||||
success = [relationshipMapping isEqualToMapping:propertyExpectation.mapping];
|
||||
|
||||
if (! success) {
|
||||
NSString *description = [NSString stringWithFormat:@"mapped using unexpected mapping: %@", relationshipMapping];
|
||||
NSString *reason = [NSString stringWithFormat:@"expected to %@, but was instead mapped using: %@",
|
||||
expectation, relationshipMapping];
|
||||
if (error) *error = [self errorForExpectation:expectation
|
||||
withCode:RKMappingTestValueInequalityError
|
||||
userInfo:userInfo
|
||||
description:description
|
||||
reason:reason];
|
||||
}
|
||||
} else {
|
||||
NSString *description = [NSString stringWithFormat:@"expected a property mapping of type `RKRelationshipMapping` but instead got a `%@`", [propertyExpectation.mapping class]];
|
||||
NSString *reason = [NSString stringWithFormat:@"expected to %@, but instead of a `RKRelationshipMapping` got a `%@`",
|
||||
expectation, [propertyExpectation.mapping class]];
|
||||
if (error) *error = [self errorForExpectation:expectation
|
||||
withCode:RKMappingTestMappingMismatchError
|
||||
userInfo:userInfo
|
||||
description:description
|
||||
reason:reason];
|
||||
|
||||
// Error message here that a relationship was not mapped!!!
|
||||
return NO;
|
||||
}
|
||||
} else {
|
||||
NSString *description = [NSString stringWithFormat:@"expected a property mapping of type `RKRelationshipMapping` but instead got a `%@`", [expectation.mapping class]];
|
||||
NSString *reason = [NSString stringWithFormat:@"expected to %@, but instead of a `RKRelationshipMapping` got a `%@`",
|
||||
expectation, [expectation.mapping class]];
|
||||
if (error) *error = [self errorForExpectation:expectation
|
||||
withCode:RKMappingTestEvaluationBlockError
|
||||
userInfo:userInfo
|
||||
description:description
|
||||
reason:reason];
|
||||
|
||||
// Error message here that a relationship was not mapped!!!
|
||||
return NO;
|
||||
// We only wanted to know that a mapping occured between the keyPaths
|
||||
success = YES;
|
||||
}
|
||||
} else {
|
||||
// We only wanted to know that a mapping occured between the keyPaths
|
||||
success = YES;
|
||||
} else if ([expectation isKindOfClass:[RKConnectionTestExpectation class]]) {
|
||||
RKConnectionTestExpectation *connectionExpectation = (RKConnectionTestExpectation *)expectation;
|
||||
RKConnectionDescription *connection = event.connection;
|
||||
id expectedValue = connectionExpectation.value;
|
||||
id connectedValue = event.value;
|
||||
|
||||
// Check that the connection attributes match
|
||||
if (connectionExpectation.attributes) {
|
||||
RKMappingTestCondition([connectionExpectation.attributes isEqualToDictionary:event.connection.attributes], RKMappingTestValueInequalityError, error, @"established connection using unexpected attributes: %@", event.connection.attributes);
|
||||
}
|
||||
|
||||
// Wrong objects
|
||||
if (expectedValue) {
|
||||
RKMappingTestCondition(connectedValue, RKMappingTestValueInequalityError, error, @"unexpectedly connected to nil object set (%@)", connectedValue);
|
||||
|
||||
if ([connectedValue isKindOfClass:[NSManagedObject class]] && [connectionExpectation.value isKindOfClass:[NSManagedObject class]]) {
|
||||
// Do a managed object ID comparison
|
||||
RKMappingTestCondition([[connectedValue objectID] isEqual:[expectedValue objectID]], RKMappingTestValueInequalityError, error, @"connected to unexpected managed object: %@", connectedValue);
|
||||
} else {
|
||||
// If we are connecting to a collection of managed objects, do a comparison of object IDs
|
||||
if (RKObjectIsCollectionContainingOnlyManagedObjects(connectedValue) && RKObjectIsCollectionContainingOnlyManagedObjects(expectedValue)) {
|
||||
RKMappingTestCondition(RKObjectIsEqualToObject([connectedValue valueForKeyPath:@"objectID"], [expectedValue valueForKeyPath:@"objectID"]), RKMappingTestValueInequalityError, error, @"connected to unexpected %@ value '%@'", [connectedValue class], connectedValue);
|
||||
} else {
|
||||
RKMappingTestCondition(RKObjectIsEqualToObject(connectedValue, expectedValue), RKMappingTestValueInequalityError, error, @"connected to unexpected %@ value '%@'", [connectedValue class], connectedValue);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
RKMappingTestCondition(connectedValue == nil, RKMappingTestValueInequalityError, error, @"unexpectedly connected to non-nil object set (%@)", connectedValue);
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
@@ -342,9 +365,9 @@ NSString * const RKMappingTestVerificationFailureException = @"RKMappingTestVeri
|
||||
}
|
||||
}
|
||||
|
||||
- (void)verifyExpectation:(RKMappingTestExpectation *)expectation
|
||||
- (void)verifyExpectation:(RKPropertyMappingTestExpectation *)expectation
|
||||
{
|
||||
RKMappingTestEvent *event = [self eventMatchingKeyPathsForExpectation:expectation];
|
||||
RKMappingTestEvent *event = [self eventMatchingExpectation:expectation];
|
||||
if (event) {
|
||||
// Found a matching event, check if it satisfies the expectation
|
||||
NSError *error = nil;
|
||||
@@ -359,7 +382,7 @@ NSString * const RKMappingTestVerificationFailureException = @"RKMappingTestVeri
|
||||
} else {
|
||||
// No match
|
||||
[NSException raise:NSInternalInconsistencyException format:@"%@: expectation not satisfied: %@, but did not.",
|
||||
[self description], [expectation mappingDescription]];
|
||||
[self description], [expectation summary]];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -367,7 +390,7 @@ NSString * const RKMappingTestVerificationFailureException = @"RKMappingTestVeri
|
||||
{
|
||||
[self performMapping];
|
||||
|
||||
for (RKMappingTestExpectation *expectation in self.expectations) {
|
||||
for (RKPropertyMappingTestExpectation *expectation in self.expectations) {
|
||||
[self verifyExpectation:expectation];
|
||||
}
|
||||
}
|
||||
@@ -378,18 +401,20 @@ NSString * const RKMappingTestVerificationFailureException = @"RKMappingTestVeri
|
||||
{
|
||||
[self performMapping];
|
||||
|
||||
for (RKMappingTestExpectation *expectation in self.expectations) {
|
||||
for (RKPropertyMappingTestExpectation *expectation in self.expectations) {
|
||||
if (! [self evaluateExpectation:expectation error:nil]) return NO;
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)evaluateExpectation:(RKMappingTestExpectation *)expectation error:(NSError **)error
|
||||
- (BOOL)evaluateExpectation:(id)expectation error:(NSError **)error
|
||||
{
|
||||
NSParameterAssert(expectation);
|
||||
NSAssert([expectation isKindOfClass:[RKPropertyMappingTestExpectation class]] || [expectation isKindOfClass:[RKConnectionTestExpectation class]], @"Must be an instance of `RKPropertyMappingTestExpectation` or `RKConnectionTestExpectation`");
|
||||
[self performMapping];
|
||||
|
||||
RKMappingTestEvent *event = [self eventMatchingKeyPathsForExpectation:expectation];
|
||||
RKMappingTestEvent *event = [self eventMatchingExpectation:expectation];
|
||||
if (event) {
|
||||
if (! [self event:event satisfiesExpectation:expectation error:error]) {
|
||||
return NO;
|
||||
@@ -398,8 +423,8 @@ NSString * const RKMappingTestVerificationFailureException = @"RKMappingTestVeri
|
||||
if (error) {
|
||||
NSDictionary *userInfo = @{
|
||||
RKMappingTestExpectationErrorKey : expectation,
|
||||
NSLocalizedDescriptionKey : [NSString stringWithFormat:@"expected to %@, but did not.", [expectation mappingDescription]],
|
||||
NSLocalizedFailureReasonErrorKey : [NSString stringWithFormat:@"%@: %@, but did not.", [self description], [expectation mappingDescription]]
|
||||
NSLocalizedDescriptionKey : [NSString stringWithFormat:@"expected to %@, but did not.", [expectation summary]],
|
||||
NSLocalizedFailureReasonErrorKey : [NSString stringWithFormat:@"%@: %@, but did not.", [self description], [expectation summary]]
|
||||
};
|
||||
*error = [NSError errorWithDomain:RKMappingTestErrorDomain code:RKMappingTestUnsatisfiedExpectationError userInfo:userInfo];
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// RKMappingTestExpectation.h
|
||||
// RKPropertyMappingTestExpectation.h
|
||||
// RestKit
|
||||
//
|
||||
// Created by Blake Watters on 2/17/12.
|
||||
@@ -18,7 +18,7 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
@class RKMapping, RKPropertyMapping, RKMappingTestExpectation;
|
||||
@class RKMapping, RKPropertyMapping, RKPropertyMappingTestExpectation;
|
||||
|
||||
/**
|
||||
@typedef RKMappingTestExpectationEvaluationBlock
|
||||
@@ -28,35 +28,18 @@
|
||||
@param mappedValue The value that was mapped.
|
||||
@param error A pointer to an error object that is to be set in the event that the expectation evaluates negatively. If left to `nil`, a generic error will be generated.
|
||||
*/
|
||||
typedef BOOL (^RKMappingTestExpectationEvaluationBlock)(RKMappingTestExpectation *expectation, RKPropertyMapping *mapping, id mappedValue, NSError **error);
|
||||
|
||||
/**
|
||||
@define RKMappingTestExpectationTestCondition
|
||||
@abstract Tests a condition and returns `NO` and error if it is not true.
|
||||
@discussion This is a useful macro when constructing mapping test evaluation blocks. It will test a condition and return `NO` as well as construct an error. This is meant to be used **only** within the body of a `RKMappingTestExpectationEvaluationBlock` object.
|
||||
@param condition The condition to test.
|
||||
@param error The NSError object to put the error string into. May be nil, but should usually be the error parameter from the expectation evaluation block.
|
||||
@param ... A string describing the error.
|
||||
*/
|
||||
#define RKMappingTestExpectationTestCondition(condition, error, ...) ({ \
|
||||
if (!(condition)) { \
|
||||
if (error) { \
|
||||
*error = [NSError errorWithDomain:RKMappingTestErrorDomain code:RKMappingTestEvaluationBlockError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:__VA_ARGS__], NSLocalizedDescriptionKey, nil]]; \
|
||||
} \
|
||||
return NO; \
|
||||
} \
|
||||
})
|
||||
typedef BOOL (^RKMappingTestExpectationEvaluationBlock)(RKPropertyMappingTestExpectation *expectation, RKPropertyMapping *mapping, id mappedValue, NSError **error);
|
||||
|
||||
/**
|
||||
An `RKMappingTestExpectation` object defines an expected mapping event that should occur during the execution of a `RKMappingTest`.
|
||||
|
||||
@see `RKMappingTest`
|
||||
*/
|
||||
@interface RKMappingTestExpectation : NSObject
|
||||
@interface RKPropertyMappingTestExpectation : NSObject
|
||||
|
||||
///-----------------------------------------------------------------------------
|
||||
///----------------------------
|
||||
/// @name Creating Expectations
|
||||
///-----------------------------------------------------------------------------
|
||||
///----------------------------
|
||||
|
||||
/**
|
||||
Creates and returns a new expectation specifying that a key path in a source object should be mapped to another key path on a destination object. The value mapped is not evaluated.
|
||||
@@ -65,7 +48,7 @@ return NO; \
|
||||
@param destinationKeyPath A key path on the destination object that should be mapped onto.
|
||||
@return An expectation specifying that sourceKeyPath should be mapped to destinationKeyPath.
|
||||
*/
|
||||
+ (RKMappingTestExpectation *)expectationWithSourceKeyPath:(NSString *)sourceKeyPath destinationKeyPath:(NSString *)destinationKeyPath;
|
||||
+ (RKPropertyMappingTestExpectation *)expectationWithSourceKeyPath:(NSString *)sourceKeyPath destinationKeyPath:(NSString *)destinationKeyPath;
|
||||
|
||||
/**
|
||||
Creates and returns a new expectation specifying that a key path in a source object should be mapped to another key path on a destination object with a given value.
|
||||
@@ -75,7 +58,7 @@ return NO; \
|
||||
@param value The value that is expected to be assigned to the destination object at destinationKeyPath.
|
||||
@return An expectation specifying that sourceKeyPath should be mapped to destinationKeyPath with value.
|
||||
*/
|
||||
+ (RKMappingTestExpectation *)expectationWithSourceKeyPath:(NSString *)sourceKeyPath destinationKeyPath:(NSString *)destinationKeyPath value:(id)value;
|
||||
+ (RKPropertyMappingTestExpectation *)expectationWithSourceKeyPath:(NSString *)sourceKeyPath destinationKeyPath:(NSString *)destinationKeyPath value:(id)value;
|
||||
|
||||
/**
|
||||
Creates and returns a new expectation specifying that a key path in a source object should be mapped to another key path on a destinaton object and that the attribute mapping and value should evaluate to true with a given block.
|
||||
@@ -85,7 +68,7 @@ return NO; \
|
||||
@param evaluationBlock A block with which to evaluate the success of the mapping.
|
||||
@return An expectation specifying that sourceKeyPath should be mapped to destinationKeyPath with value.
|
||||
*/
|
||||
+ (RKMappingTestExpectation *)expectationWithSourceKeyPath:(NSString *)sourceKeyPath destinationKeyPath:(NSString *)destinationKeyPath evaluationBlock:(RKMappingTestExpectationEvaluationBlock)evaluationBlock;
|
||||
+ (RKPropertyMappingTestExpectation *)expectationWithSourceKeyPath:(NSString *)sourceKeyPath destinationKeyPath:(NSString *)destinationKeyPath evaluationBlock:(RKMappingTestExpectationEvaluationBlock)evaluationBlock;
|
||||
|
||||
/**
|
||||
Creates and returns a new expectation specifying that a key path in a source object should be mapped to another key path on a destinaton object using a specific object mapping for the relationship.
|
||||
@@ -95,11 +78,11 @@ return NO; \
|
||||
@param mapping An object mapping that is expected to be used for mapping the nested relationship.
|
||||
@return An expectation specifying that sourceKeyPath should be mapped to destinationKeyPath using a specific object mapping.
|
||||
*/
|
||||
+ (RKMappingTestExpectation *)expectationWithSourceKeyPath:(NSString *)sourceKeyPath destinationKeyPath:(NSString *)destinationKeyPath mapping:(RKMapping *)mapping;
|
||||
+ (RKPropertyMappingTestExpectation *)expectationWithSourceKeyPath:(NSString *)sourceKeyPath destinationKeyPath:(NSString *)destinationKeyPath mapping:(RKMapping *)mapping;
|
||||
|
||||
///-----------------------------------------------------------------------------
|
||||
///-------------------------
|
||||
/// @name Expectation Values
|
||||
///-----------------------------------------------------------------------------
|
||||
///-------------------------
|
||||
|
||||
/**
|
||||
Returns a keyPath on the source object that a value should be mapped from.
|
||||
@@ -133,6 +116,6 @@ return NO; \
|
||||
|
||||
@return A string describing the expected sourceKeyPath to destinationKeyPath mapping.
|
||||
*/
|
||||
- (NSString *)mappingDescription;
|
||||
- (NSString *)summary;
|
||||
|
||||
@end
|
||||
@@ -18,10 +18,10 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#import "RKMappingTestExpectation.h"
|
||||
#import "RKPropertyMappingTestExpectation.h"
|
||||
#import "RKPropertyMapping.h"
|
||||
|
||||
@interface RKMappingTestExpectation ()
|
||||
@interface RKPropertyMappingTestExpectation ()
|
||||
@property (nonatomic, copy, readwrite) NSString *sourceKeyPath;
|
||||
@property (nonatomic, copy, readwrite) NSString *destinationKeyPath;
|
||||
@property (nonatomic, strong, readwrite) id value;
|
||||
@@ -29,20 +29,20 @@
|
||||
@property (nonatomic, strong, readwrite) RKMapping *mapping;
|
||||
@end
|
||||
|
||||
@implementation RKMappingTestExpectation
|
||||
@implementation RKPropertyMappingTestExpectation
|
||||
|
||||
+ (RKMappingTestExpectation *)expectationWithSourceKeyPath:(NSString *)sourceKeyPath destinationKeyPath:(NSString *)destinationKeyPath
|
||||
+ (RKPropertyMappingTestExpectation *)expectationWithSourceKeyPath:(NSString *)sourceKeyPath destinationKeyPath:(NSString *)destinationKeyPath
|
||||
{
|
||||
RKMappingTestExpectation *expectation = [self new];
|
||||
RKPropertyMappingTestExpectation *expectation = [self new];
|
||||
expectation.sourceKeyPath = sourceKeyPath;
|
||||
expectation.destinationKeyPath = destinationKeyPath;
|
||||
|
||||
return expectation;
|
||||
}
|
||||
|
||||
+ (RKMappingTestExpectation *)expectationWithSourceKeyPath:(NSString *)sourceKeyPath destinationKeyPath:(NSString *)destinationKeyPath value:(id)value
|
||||
+ (RKPropertyMappingTestExpectation *)expectationWithSourceKeyPath:(NSString *)sourceKeyPath destinationKeyPath:(NSString *)destinationKeyPath value:(id)value
|
||||
{
|
||||
RKMappingTestExpectation *expectation = [self new];
|
||||
RKPropertyMappingTestExpectation *expectation = [self new];
|
||||
expectation.sourceKeyPath = sourceKeyPath;
|
||||
expectation.destinationKeyPath = destinationKeyPath;
|
||||
expectation.value = value;
|
||||
@@ -50,9 +50,9 @@
|
||||
return expectation;
|
||||
}
|
||||
|
||||
+ (RKMappingTestExpectation *)expectationWithSourceKeyPath:(NSString *)sourceKeyPath destinationKeyPath:(NSString *)destinationKeyPath evaluationBlock:(RKMappingTestExpectationEvaluationBlock)evaluationBlock
|
||||
+ (RKPropertyMappingTestExpectation *)expectationWithSourceKeyPath:(NSString *)sourceKeyPath destinationKeyPath:(NSString *)destinationKeyPath evaluationBlock:(RKMappingTestExpectationEvaluationBlock)evaluationBlock
|
||||
{
|
||||
RKMappingTestExpectation *expectation = [self new];
|
||||
RKPropertyMappingTestExpectation *expectation = [self new];
|
||||
expectation.sourceKeyPath = sourceKeyPath;
|
||||
expectation.destinationKeyPath = destinationKeyPath;
|
||||
expectation.evaluationBlock = evaluationBlock;
|
||||
@@ -60,9 +60,9 @@
|
||||
return expectation;
|
||||
}
|
||||
|
||||
+ (RKMappingTestExpectation *)expectationWithSourceKeyPath:(NSString *)sourceKeyPath destinationKeyPath:(NSString *)destinationKeyPath mapping:(RKMapping *)mapping
|
||||
+ (RKPropertyMappingTestExpectation *)expectationWithSourceKeyPath:(NSString *)sourceKeyPath destinationKeyPath:(NSString *)destinationKeyPath mapping:(RKMapping *)mapping
|
||||
{
|
||||
RKMappingTestExpectation *expectation = [self new];
|
||||
RKPropertyMappingTestExpectation *expectation = [self new];
|
||||
expectation.sourceKeyPath = sourceKeyPath;
|
||||
expectation.destinationKeyPath = destinationKeyPath;
|
||||
expectation.mapping = mapping;
|
||||
@@ -70,7 +70,7 @@
|
||||
return expectation;
|
||||
}
|
||||
|
||||
- (NSString *)mappingDescription
|
||||
- (NSString *)summary
|
||||
{
|
||||
return [NSString stringWithFormat:@"map '%@' to '%@'", self.sourceKeyPath, self.destinationKeyPath];
|
||||
}
|
||||
@@ -88,7 +88,7 @@
|
||||
self.sourceKeyPath, self.destinationKeyPath, self.mapping];
|
||||
}
|
||||
|
||||
return [self mappingDescription];
|
||||
return [self summary];
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in New Issue
Block a user