Add test coverage and fixes for RKMappingTest. closes #1086

This commit is contained in:
Blake Watters
2013-01-03 18:19:50 -05:00
parent bf63a77bc1
commit 9005bd573c
15 changed files with 295 additions and 11 deletions

View File

@@ -603,7 +603,6 @@ static BOOL RKObjectContainsValueForKeyPaths(id representation, NSArray *keyPath
{
NSAssert(self.dataSource, @"Cannot perform relationship mapping without a data source");
NSMutableArray *mappingsApplied = [NSMutableArray array];
id destinationObject = nil;
for (RKRelationshipMapping *relationshipMapping in [self relationshipMappings]) {
if ([self isCancelled]) return NO;
@@ -702,7 +701,8 @@ static BOOL RKObjectContainsValueForKeyPaths(id representation, NSArray *keyPath
// Notify the delegate
if ([self.delegate respondsToSelector:@selector(mappingOperation:didSetValue:forKeyPath:usingMapping:)]) {
[self.delegate mappingOperation:self didSetValue:destinationObject forKeyPath:relationshipMapping.destinationKeyPath usingMapping:relationshipMapping];
id setValue = [self.destinationObject valueForKeyPath:relationshipMapping.destinationKeyPath];
[self.delegate mappingOperation:self didSetValue:setValue forKeyPath:relationshipMapping.destinationKeyPath usingMapping:relationshipMapping];
}
// Fail out if a validation error has occurred

View File

@@ -376,7 +376,7 @@
/**
Returns the preferred date formatter to use when generating NSString representations from NSDate attributes. This type of transformation occurs when RestKit is mapping local objects into JSON or form encoded serializations that do not have a native time construct.
Defaults to an instance of the `RKISO8601DateFormatter` configured with the UTC time-zone. The format string is equal to "YYYY-MM-DDThh:mm:ssTZD"
Defaults to an instance of the `RKISO8601DateFormatter` configured with the UTC time-zone. The format string is equal to "yyyy-MM-DDThh:mm:ssTZD"
For details about the ISO-8601 format, see http://www.w3.org/TR/NOTE-datetime

View File

@@ -13,4 +13,5 @@
#import <SystemConfiguration/SystemConfiguration.h>
#import <CoreServices/CoreServices.h>
#endif
#import <CoreData/CoreData.h>
#endif

View File

@@ -11,3 +11,7 @@
#import "RKTestFactory.h"
#import "RKTestHelpers.h"
#import "RKMappingTest.h"
#ifdef _COREDATADEFINES_H
#import "RKConnectionTestExpectation.h"
#endif

View File

@@ -18,6 +18,8 @@
// limitations under the License.
//
#ifdef _COREDATADEFINES_H
#import <Foundation/Foundation.h>
/**
@@ -81,3 +83,5 @@
- (NSString *)summary;
@end
#endif

View File

@@ -18,7 +18,8 @@
// limitations under the License.
//
#import <CoreData/CoreData.h>
#ifdef _COREDATADEFINES_H
#import "RKConnectionTestExpectation.h"
#import "RKObjectUtilities.h"
@@ -64,3 +65,5 @@
}
@end
#endif

View File

@@ -19,7 +19,6 @@
//
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#import "RKMappingOperation.h"
#import "RKPropertyMappingTestExpectation.h"
@@ -195,6 +194,8 @@ extern NSString * const RKMappingTestExpectationErrorKey;
*/
@property (nonatomic, strong, readonly) id destinationObject;
#ifdef _COREDATADEFINES_H
///----------------------------
/// @name Core Data Integration
///----------------------------
@@ -213,4 +214,6 @@ extern NSString * const RKMappingTestExpectationErrorKey;
*/
@property (nonatomic, strong) id<RKManagedObjectCaching> managedObjectCache;
#endif // _COREDATADEFINES_H
@end

View File

@@ -242,7 +242,7 @@ NSString * const RKMappingTestVerificationFailureException = @"RKMappingTestVeri
NSString *reason = [NSString stringWithFormat:@"expected to %@, but instead got %@ '%@'",
expectation, [event.value class], event.value];
if (error) *error = [self errorForExpectation:expectation
withCode:RKMappingTestEvaluationBlockError
withCode:RKMappingTestValueInequalityError
userInfo:userInfo
description:description
reason:reason];
@@ -258,7 +258,7 @@ NSString * const RKMappingTestVerificationFailureException = @"RKMappingTestVeri
NSString *reason = [NSString stringWithFormat:@"expected to %@, but was instead mapped using: %@",
expectation, relationshipMapping];
if (error) *error = [self errorForExpectation:expectation
withCode:RKMappingTestValueInequalityError
withCode:RKMappingTestMappingMismatchError
userInfo:userInfo
description:description
reason:reason];
@@ -319,6 +319,7 @@ NSString * const RKMappingTestVerificationFailureException = @"RKMappingTestVeri
// If we have been given an explicit data source, use it
if (self.mappingOperationDataSource) return self.mappingOperationDataSource;
#ifdef _COREDATADEFINES_H
if ([self.mapping isKindOfClass:[RKEntityMapping class]]) {
NSAssert(self.managedObjectContext, @"Cannot test an `RKEntityMapping` with a nil managed object context.");
id<RKManagedObjectCaching> managedObjectCache = self.managedObjectCache ?: [RKFetchRequestManagedObjectCache new];
@@ -332,6 +333,9 @@ NSString * const RKMappingTestVerificationFailureException = @"RKMappingTestVeri
} else {
return [RKObjectMappingOperationDataSource new];
}
#else
return [RKObjectMappingOperationDataSource new];
#endif
}
- (void)performMapping
@@ -350,7 +354,8 @@ NSString * const RKMappingTestVerificationFailureException = @"RKMappingTestVeri
}
// Let the connection operations execute to completion
if ([mappingOperation.dataSource isKindOfClass:[RKManagedObjectMappingOperationDataSource class]]) {
Class managedObjectMappingOperationDataSourceClass = NSClassFromString(@"RKManagedObjectMappingOperationDataSource");
if ([mappingOperation.dataSource isKindOfClass:managedObjectMappingOperationDataSourceClass]) {
NSOperationQueue *operationQueue = [(RKManagedObjectMappingOperationDataSource *)mappingOperation.dataSource operationQueue];
if (! [operationQueue isEqual:[NSOperationQueue mainQueue]]) {
[operationQueue waitUntilAllOperationsAreFinished];
@@ -410,7 +415,8 @@ NSString * const RKMappingTestVerificationFailureException = @"RKMappingTestVeri
- (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`");
Class connectionTestExpectation = NSClassFromString(@"RKConnectionTestExpectation");
NSAssert([expectation isKindOfClass:[RKPropertyMappingTestExpectation class]] || (connectionTestExpectation && [expectation isKindOfClass:connectionTestExpectation]), @"Must be an instance of `RKPropertyMappingTestExpectation` or `RKConnectionTestExpectation`");
[self performMapping];
RKMappingTestEvent *event = [self eventMatchingExpectation:expectation];

View File

@@ -223,6 +223,8 @@ operation.managedObjectCache = managedObjectStore.managedObjectCache;
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(@"Failed with error: %@", [error localizedDescription]);
}];
NSOperationQueue *operationQueue = [NSOperationQueue new];
[operationQueue addOperation:operation];
```
### Map a Client Error Response to an NSError

View File

@@ -497,6 +497,8 @@
25B408271491CDDC00F21111 /* RKPathUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 25B408241491CDDB00F21111 /* RKPathUtilities.h */; settings = {ATTRIBUTES = (Public, ); }; };
25B408281491CDDC00F21111 /* RKPathUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 25B408251491CDDB00F21111 /* RKPathUtilities.m */; };
25B408291491CDDC00F21111 /* RKPathUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 25B408251491CDDB00F21111 /* RKPathUtilities.m */; };
25B639CC16961EFA0065EB7B /* RKMappingTestTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 25B639CB16961EFA0065EB7B /* RKMappingTestTest.m */; };
25B639CD16961EFA0065EB7B /* RKMappingTestTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 25B639CB16961EFA0065EB7B /* RKMappingTestTest.m */; };
25B6E95514CF795D00B1E881 /* RKErrors.h in Headers */ = {isa = PBXBuildFile; fileRef = 25B6E95414CF795D00B1E881 /* RKErrors.h */; settings = {ATTRIBUTES = (Public, ); }; };
25B6E95614CF795D00B1E881 /* RKErrors.h in Headers */ = {isa = PBXBuildFile; fileRef = 25B6E95414CF795D00B1E881 /* RKErrors.h */; settings = {ATTRIBUTES = (Public, ); }; };
25B6E95814CF7A1C00B1E881 /* RKErrors.m in Sources */ = {isa = PBXBuildFile; fileRef = 25B6E95714CF7A1C00B1E881 /* RKErrors.m */; };
@@ -893,6 +895,7 @@
25AFF8F015B4CF1F0051877F /* RKMappingErrors.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = RKMappingErrors.h; sourceTree = "<group>"; };
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>"; };
25B639CB16961EFA0065EB7B /* RKMappingTestTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKMappingTestTest.m; sourceTree = "<group>"; };
25B6E95414CF795D00B1E881 /* RKErrors.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RKErrors.h; sourceTree = "<group>"; };
25B6E95714CF7A1C00B1E881 /* RKErrors.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKErrors.m; sourceTree = "<group>"; };
25B6E95A14CF7E3C00B1E881 /* RKObjectMappingMatcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RKObjectMappingMatcher.h; sourceTree = "<group>"; };
@@ -1292,6 +1295,7 @@
2516101B1456F2330060A5C5 /* ObjectMapping */,
251610511456F2330060A5C5 /* Support */,
25104F9B15C33E3A00829135 /* Search */,
25B639C816961EC70065EB7B /* Testing */,
251610471456F2330060A5C5 /* Server */,
);
path = Tests;
@@ -1561,6 +1565,15 @@
name = Testing;
sourceTree = "<group>";
};
25B639C816961EC70065EB7B /* Testing */ = {
isa = PBXGroup;
children = (
25B639CB16961EFA0065EB7B /* RKMappingTestTest.m */,
);
name = Testing;
path = Logic/Testing;
sourceTree = "<group>";
};
25BCB31715ED57D500EE84DD /* AFNetworking */ = {
isa = PBXGroup;
children = (
@@ -2358,6 +2371,7 @@
2536D1FD167270F100DF9BB0 /* RKRouterTest.m in Sources */,
2551338F167838590017E4B6 /* RKHTTPRequestOperationTest.m in Sources */,
255133CF167AC7600017E4B6 /* RKManagedObjectRequestOperationTest.m in Sources */,
25B639CC16961EFA0065EB7B /* RKMappingTestTest.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -2508,6 +2522,7 @@
2543A25E1664FD3200821D5B /* RKResponseDescriptorTest.m in Sources */,
2536D1FE167270F100DF9BB0 /* RKRouterTest.m in Sources */,
25513390167838590017E4B6 /* RKHTTPRequestOperationTest.m in Sources */,
25B639CD16961EFA0065EB7B /* RKMappingTestTest.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@@ -1 +1,12 @@
{"human":{"name":"Blake Watters","id":null,"age":28,"favorite_cat":{"name": "Asia"}}}
{
"human": {
"name": "Blake Watters",
"id": null,
"age": 28,
"favorite_cat_id": 1234,
"favorite_cat": {
"name": "Asia",
"id": 1234
}
}
}

View File

@@ -26,5 +26,8 @@
"id": 7,
"name": "Rachit Shukla"
}
]
],
"created_at": "2011-02-02 07:53:08",
"latitude": 12345,
"longitude": 56789
}

View File

@@ -0,0 +1,224 @@
//
// RKMappingTestTest.m
// RestKit
//
// Created by Blake Watters on 1/3/13.
// Copyright (c) 2013 RestKit. All rights reserved.
//
#import "RKTestEnvironment.h"
#import "RKMappingTest.h"
#import "RKTestUser.h"
#import "RKHuman.h"
#import "RKCat.h"
@interface RKMappingTestTest : SenTestCase
@property (nonatomic, strong) id objectRepresentation;
@property (nonatomic, strong) RKMappingTest *mappingTest;
@end
@implementation RKMappingTestTest
- (void)setUp
{
self.objectRepresentation = [RKTestFixture parsedObjectWithContentsOfFixture:@"user.json"];
RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]];
[mapping addAttributeMappingsFromDictionary:@{
@"id": @"userID",
@"name": @"name",
@"birthdate": @"birthDate",
@"created_at": @"createdAt"
}];
RKObjectMapping *addressMapping = [RKObjectMapping mappingForClass:[RKTestAddress class]];
[addressMapping addAttributeMappingsFromDictionary:@{ @"id": @"addressID"}];
[addressMapping addAttributeMappingsFromArray:@[ @"city", @"state", @"country" ]];
[mapping addRelationshipMappingWithSourceKeyPath:@"address" mapping:addressMapping];
RKObjectMapping *coordinateMapping = [RKObjectMapping mappingForClass:[RKTestCoordinate class]];
[coordinateMapping addAttributeMappingsFromArray:@[ @"latitude", @"longitude" ]];
[mapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:nil toKeyPath:@"coordinate" withMapping:coordinateMapping]];
self.mappingTest = [[RKMappingTest alloc] initWithMapping:mapping sourceObject:self.objectRepresentation destinationObject:nil];
}
- (void)testMappingTestForAttribute
{
[self.mappingTest addExpectation:[RKPropertyMappingTestExpectation expectationWithSourceKeyPath:@"name"
destinationKeyPath:@"name"
value:@"Blake Watters"]];
expect([self.mappingTest evaluate]).to.equal(YES);
}
- (void)testMappingTestFailureForAttribute
{
[self.mappingTest addExpectation:[RKPropertyMappingTestExpectation expectationWithSourceKeyPath:@"name"
destinationKeyPath:@"name"
value:@"Invalid"]];
expect([self.mappingTest evaluate]).to.equal(NO);
}
- (void)testMappingTestForAttributeWithBlock
{
[self.mappingTest addExpectation:[RKPropertyMappingTestExpectation expectationWithSourceKeyPath:@"name" destinationKeyPath:@"name" evaluationBlock:^BOOL(RKPropertyMappingTestExpectation *expectation, RKPropertyMapping *mapping, id mappedValue, NSError *__autoreleasing *error) {
return [mappedValue isEqualToString:@"Blake Watters"];
}]];
expect([self.mappingTest evaluate]).to.equal(YES);
}
- (void)testMappingTestForRelationship
{
RKTestCoordinate *coordinate = [RKTestCoordinate new];
coordinate.latitude = 12345;
coordinate.longitude = 56789;
[self.mappingTest addExpectation:[RKPropertyMappingTestExpectation expectationWithSourceKeyPath:nil
destinationKeyPath:@"coordinate"
value:coordinate]];
expect([self.mappingTest evaluate]).to.equal(NO);
}
- (void)testMappingTestForRelationshipWithBlock
{
[self.mappingTest addExpectation:[RKPropertyMappingTestExpectation expectationWithSourceKeyPath:@"address" destinationKeyPath:@"address" evaluationBlock:^BOOL(RKPropertyMappingTestExpectation *expectation, RKPropertyMapping *mapping, id mappedValue, NSError *__autoreleasing *error) {
RKTestAddress *address = (RKTestAddress *)mappedValue;
return [address.addressID isEqualToNumber:@(1234)] && [address.city isEqualToString:@"Carrboro"] && [address.state isEqualToString:@"North Carolina"] && [address.country isEqualToString:@"USA"];
return YES;
}]];
expect([self.mappingTest evaluate]).to.equal(YES);
}
- (void)testEvaluateExpectationReturnsUnsatisfiedExpectationErrorForUnmappedKeyPath
{
NSError *error = nil;
BOOL success = [self.mappingTest evaluateExpectation:[RKPropertyMappingTestExpectation expectationWithSourceKeyPath:@"nonexistant"
destinationKeyPath:@"name"
value:@"Invalid"] error:&error];
expect(success).to.equal(NO);
expect(error).notTo.beNil();
expect(error.code).to.equal(RKMappingTestUnsatisfiedExpectationError);
expect([error localizedDescription]).to.equal(@"expected to map 'nonexistant' to 'name', but did not.");
}
- (void)testEvaluateExpectationReturnsValueInequalityErrorErrorForValueMismatch
{
NSError *error = nil;
BOOL success = [self.mappingTest evaluateExpectation:[RKPropertyMappingTestExpectation expectationWithSourceKeyPath:@"name"
destinationKeyPath:@"name"
value:@"Incorrect"] error:&error];
expect(success).to.equal(NO);
expect(error).notTo.beNil();
expect(error.code).to.equal(RKMappingTestValueInequalityError);
expect([error localizedDescription]).to.equal(@"mapped to unexpected __NSCFString value 'Blake Watters'");
}
- (void)testEvaluateExpectationReturnsEvaluationBlockErrorForBlockFailure
{
NSError *error = nil;
BOOL success = [self.mappingTest evaluateExpectation:[RKPropertyMappingTestExpectation expectationWithSourceKeyPath:@"address" destinationKeyPath:@"address" evaluationBlock:^BOOL(RKPropertyMappingTestExpectation *expectation, RKPropertyMapping *mapping, id mappedValue, NSError *__autoreleasing *error) {
return NO;
}] error:&error];
expect(success).to.equal(NO);
expect(error).notTo.beNil();
expect(error.code).to.equal(RKMappingTestEvaluationBlockError);
assertThat([error localizedDescription], startsWith(@"evaluation block returned `NO` for RKTestAddress value '<RKTestAddress:"));
}
- (void)testEvaluateExpectationReturnsMappingMismatchErrorForMismatchedMapping
{
NSError *error = nil;
RKDynamicMapping *dynamicMapping = [RKDynamicMapping new];
BOOL success = [self.mappingTest evaluateExpectation:[RKPropertyMappingTestExpectation expectationWithSourceKeyPath:@"address" destinationKeyPath:@"address" mapping:dynamicMapping] error:&error];
expect(success).to.equal(NO);
expect(error).notTo.beNil();
expect(error.code).to.equal(RKMappingTestMappingMismatchError);
assertThat([error localizedDescription], startsWith(@"mapped using unexpected mapping: <RKObjectMapping"));
}
- (void)testVerifyWithFailureRaisesException
{
NSException *caughtException = nil;
@try {
[self.mappingTest addExpectation:[RKPropertyMappingTestExpectation expectationWithSourceKeyPath:@"name"
destinationKeyPath:@"name"
value:@"Invalid"]];
[self.mappingTest verify];
}
@catch (NSException *exception) {
caughtException = exception;
}
expect(caughtException).notTo.beNil();
expect([caughtException name]).to.equal(RKMappingTestVerificationFailureException);
expect([caughtException reason]).to.equal(@"mapped to unexpected __NSCFString value 'Blake Watters'");
}
@end
@interface RKMappingTestCoreDataIntegrationTest : RKTestCase
@property (nonatomic, strong) id objectRepresentation;
@property (nonatomic, strong) RKManagedObjectStore *managedObjectStore;
@property (nonatomic, strong) RKMappingTest *mappingTest;
@property (nonatomic, strong) RKEntityMapping *entityMapping;
@property (nonatomic, strong) RKCat *asia;
@end
@implementation RKMappingTestCoreDataIntegrationTest
- (void)setUp
{
[RKTestFactory setUp];
self.objectRepresentation = [RKTestFixture parsedObjectWithContentsOfFixture:@"with_to_one_relationship.json"];
self.managedObjectStore = [RKTestFactory managedObjectStore];
self.entityMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:self.managedObjectStore];
[self.entityMapping addAttributeMappingsFromDictionary:@{
@"name": @"name",
@"age": @"age",
@"favorite_cat_id": @"favoriteCatID"
}];
self.mappingTest = [[RKMappingTest alloc] initWithMapping:self.entityMapping sourceObject:self.objectRepresentation destinationObject:nil];
self.mappingTest.rootKeyPath = @"human";
RKFetchRequestManagedObjectCache *managedObjectCache = [RKFetchRequestManagedObjectCache new];
RKManagedObjectMappingOperationDataSource *dataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:self.managedObjectStore.persistentStoreManagedObjectContext cache:managedObjectCache];
dataSource.operationQueue = [NSOperationQueue new];
self.mappingTest.mappingOperationDataSource = dataSource;
self.mappingTest.managedObjectContext = self.managedObjectStore.persistentStoreManagedObjectContext;
self.mappingTest.managedObjectCache = managedObjectCache;
self.asia = [NSEntityDescription insertNewObjectForEntityForName:@"Cat" inManagedObjectContext:self.mappingTest.managedObjectContext];
self.asia.name = @"Asia";
self.asia.railsID = @(1234);
}
- (void)tearDown
{
[RKTestFactory tearDown];
}
- (void)testMappingTestForCoreDataAttribute
{
[self.mappingTest addExpectation:[RKPropertyMappingTestExpectation expectationWithSourceKeyPath:@"name"
destinationKeyPath:@"name"
value:@"Blake Watters"]];
expect([self.mappingTest evaluate]).to.equal(YES);
}
- (void)testMappingTestForCoreDataRelationship
{
RKEntityMapping *catMapping = [RKEntityMapping mappingForEntityForName:@"Cat" inManagedObjectStore:self.managedObjectStore];
catMapping.identificationAttributes = @[ @"name" ];
[catMapping addAttributeMappingsFromDictionary:@{ @"id": @"railsID" }];
[catMapping addAttributeMappingsFromArray:@[ @"name" ]];
[self.entityMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"favorite_cat" toKeyPath:@"favoriteCat" withMapping:catMapping]];
[self.mappingTest addExpectation:[RKPropertyMappingTestExpectation expectationWithSourceKeyPath:@"favorite_cat"
destinationKeyPath:@"favoriteCat"
value:self.asia]];
expect([self.mappingTest evaluate]).to.equal(YES);
}
- (void)testMappingTestForCoreDataRelationshipConnection
{
[self.entityMapping addConnectionForRelationship:@"favoriteCat" connectedBy:@{ @"favoriteCatID": @"railsID" }];
[self.mappingTest addExpectation:[RKConnectionTestExpectation expectationWithRelationshipName:@"favoriteCat" attributes:@{ @"favoriteCatID": @"railsID" } value:self.asia]];
expect([self.mappingTest evaluate]).to.equal(YES);
}
@end

View File

@@ -36,6 +36,7 @@
@property (nonatomic, strong) NSData *data;
@property (nonatomic, strong) RKTestCoordinate *coordinate;
@property (nonatomic, assign) NSInteger age;
@property (nonatomic, strong) NSDate *createdAt;
+ (RKTestUser *)user;

View File

@@ -10,6 +10,13 @@
#import "RKLog.h"
@implementation RKTestCoordinate
- (BOOL)isEqual:(id)object
{
if (! [object isKindOfClass:[RKTestCoordinate class]]) return NO;
return [object latitude] == self.latitude && [object longitude] == self.longitude;
}
@end
@implementation RKTestUser