// // RKObjectMappingNextGenTest.m // RestKit // // Created by Blake Watters on 4/30/11. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import #import #import "RKTestEnvironment.h" #import "RKObjectMapping.h" #import "RKMappingOperation.h" #import "RKAttributeMapping.h" #import "RKRelationshipMapping.h" #import "RKLog.h" #import "RKMapperOperation.h" #import "RKMapperOperation_Private.h" #import "RKMappingErrors.h" #import "RKDynamicMappingModels.h" #import "RKTestAddress.h" #import "RKTestUser.h" #import "RKObjectMappingOperationDataSource.h" #import "RKManagedObjectMappingOperationDataSource.h" #import "RKDynamicMapping.h" #import "RKMIMETypeSerialization.h" // Managed Object Serialization Testific #import "RKHuman.h" #import "RKCat.h" @interface RKObjectMapping () + (void)resetDefaultDateFormatters; @end @interface RKExampleGroupWithUserArray : NSObject { NSString *_name; NSArray *_users; } @property (nonatomic, retain) NSString *name; @property (nonatomic, retain) NSArray *users; @end @implementation RKExampleGroupWithUserArray @synthesize name = _name; @synthesize users = _users; + (RKExampleGroupWithUserArray *)group { return [self new]; } // isEqual: is consulted by the mapping operation // to determine if assocation values should be set - (BOOL)isEqual:(id)object { if ([object isKindOfClass:[RKExampleGroupWithUserArray class]]) { return [[(RKExampleGroupWithUserArray *)object name] isEqualToString:self.name]; } else { return NO; } } @end @interface RKExampleGroupWithUserSet : NSObject { NSString *_name; NSSet *_users; } @property (nonatomic, retain) NSString *name; @property (nonatomic, retain) NSSet *users; @end @implementation RKExampleGroupWithUserSet @synthesize name = _name; @synthesize users = _users; + (RKExampleGroupWithUserSet *)group { return [self new]; } // isEqual: is consulted by the mapping operation // to determine if assocation values should be set - (BOOL)isEqual:(id)object { if ([object isKindOfClass:[RKExampleGroupWithUserSet class]]) { return [[(RKExampleGroupWithUserSet *)object name] isEqualToString:self.name]; } else { return NO; } } @end //////////////////////////////////////////////////////////////////////////////// #pragma mark - @interface RKObjectMappingNextGenTest : RKTestCase { } @end @implementation RKObjectMappingNextGenTest #pragma mark - RKObjectKeyPathMapping Tests - (void)testShouldDefineElementToPropertyMapping { RKAttributeMapping *elementMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"id" toKeyPath:@"userID"]; assertThat(elementMapping.sourceKeyPath, is(equalTo(@"id"))); assertThat(elementMapping.destinationKeyPath, is(equalTo(@"userID"))); } - (void)testShouldDescribeElementMappings { RKAttributeMapping *elementMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"id" toKeyPath:@"userID"]; assertThatBool([[elementMapping description] hasSuffix:@"id => userID>"], is(equalToBool(YES))); } #pragma mark - RKObjectMapping Tests - (void)testShouldDefineMappingFromAnElementToAProperty { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKAttributeMapping *idMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"id" toKeyPath:@"userID"]; [mapping addPropertyMapping:idMapping]; assertThat(mapping.propertyMappingsBySourceKeyPath[@"id"], is(sameInstance(idMapping))); } - (void)testShouldAddMappingsToAttributeMappings { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKAttributeMapping *idMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"id" toKeyPath:@"userID"]; [mapping addPropertyMapping:idMapping]; assertThatBool([mapping.propertyMappings containsObject:idMapping], is(equalToBool(YES))); assertThatBool([mapping.attributeMappings containsObject:idMapping], is(equalToBool(YES))); } - (void)testShouldAddMappingsToRelationshipMappings { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKRelationshipMapping *idMapping = [RKRelationshipMapping relationshipMappingFromKeyPath:@"id" toKeyPath:@"userID" withMapping:nil]; [mapping addPropertyMapping:idMapping]; assertThatBool([mapping.propertyMappings containsObject:idMapping], is(equalToBool(YES))); assertThatBool([mapping.relationshipMappings containsObject:idMapping], is(equalToBool(YES))); } - (void)testShouldGenerateAttributeMappings { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; assertThat(mapping.propertyMappingsBySourceKeyPath[@"name"], is(nilValue())); [mapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:@"name" toKeyPath:@"name"]]; assertThat(mapping.propertyMappingsBySourceKeyPath[@"name"], isNot(nilValue())); } - (void)testShouldGenerateRelationshipMappings { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKObjectMapping *anotherMapping = [RKObjectMapping mappingForClass:[NSDictionary class]]; assertThat(mapping.propertyMappingsBySourceKeyPath[@"another"], is(nilValue())); [mapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"another" toKeyPath:@"another" withMapping:anotherMapping]]; assertThat(mapping.propertyMappingsBySourceKeyPath[@"another"], isNot(nilValue())); } - (void)testShouldGenerateAnInverseMappings { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; [mapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:@"first_name" toKeyPath:@"firstName"]]; [mapping addAttributeMappingsFromArray:@[@"city", @"state", @"zip"]]; RKObjectMapping *otherMapping = [RKObjectMapping mappingForClass:[RKTestAddress class]]; [otherMapping addAttributeMappingsFromArray:@[@"street"]]; [mapping addRelationshipMappingWithSourceKeyPath:@"address" mapping:otherMapping]; RKObjectMapping *inverse = [mapping inverseMapping]; assertThat(inverse.objectClass, is(equalTo([NSMutableDictionary class]))); assertThat([inverse propertyMappingsBySourceKeyPath][@"firstName"], isNot(nilValue())); } - (void)testShouldLetYouRetrieveMappingsByAttribute { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKAttributeMapping *attributeMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"name" toKeyPath:@"nameAttribute"]; [mapping addPropertyMapping:attributeMapping]; assertThat(mapping.propertyMappingsByDestinationKeyPath[@"nameAttribute"], is(equalTo(attributeMapping))); } - (void)testShouldLetYouRetrieveMappingsByRelationship { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKRelationshipMapping *relationshipMapping = [RKRelationshipMapping relationshipMappingFromKeyPath:@"friend" toKeyPath:@"friendRelationship" withMapping:mapping]; [mapping addPropertyMapping:relationshipMapping]; assertThat(mapping.propertyMappingsByDestinationKeyPath[@"friendRelationship"], is(equalTo(relationshipMapping))); } #pragma mark - RKMapperOperation Tests // TODO: Move these into RKMapperOperationTest.m - (void)testShouldPerformBasicMapping { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKAttributeMapping *idMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"id" toKeyPath:@"userID"]; [mapping addPropertyMapping:idMapping]; RKAttributeMapping *nameMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"name" toKeyPath:@"name"]; [mapping addPropertyMapping:nameMapping]; RKMapperOperation *mapper = [RKMapperOperation new]; mapper.mappingOperationDataSource = [RKObjectMappingOperationDataSource new]; id userInfo = [RKTestFixture parsedObjectWithContentsOfFixture:@"user.json"]; RKTestUser *user = [RKTestUser user]; BOOL success = [mapper mapRepresentation:userInfo toObject:user atKeyPath:@"" usingMapping:mapping metadata:nil]; assertThatBool(success, is(equalToBool(YES))); assertThatInt([user.userID intValue], is(equalToInt(31337))); assertThat(user.name, is(equalTo(@"Blake Watters"))); } - (void)testShouldMapACollectionOfSimpleObjectDictionaries { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKAttributeMapping *idMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"id" toKeyPath:@"userID"]; [mapping addPropertyMapping:idMapping]; RKAttributeMapping *nameMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"name" toKeyPath:@"name"]; [mapping addPropertyMapping:nameMapping]; RKMapperOperation *mapper = [RKMapperOperation new]; mapper.mappingOperationDataSource = [RKObjectMappingOperationDataSource new]; id userInfo = [RKTestFixture parsedObjectWithContentsOfFixture:@"users.json"]; NSArray *users = [mapper mapRepresentations:userInfo atKeyPath:@"" usingMapping:mapping]; assertThatUnsignedInteger([users count], is(equalToInt(3))); RKTestUser *blake = [users objectAtIndex:0]; assertThat(blake.name, is(equalTo(@"Blake Watters"))); } - (void)testShouldDetermineTheObjectMappingByConsultingTheMappingProviderWhenThereIsATargetObject { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; NSMutableDictionary *mappingsDictionary = [NSMutableDictionary dictionary]; [mappingsDictionary setObject:mapping forKey:[NSNull null]]; id userInfo = [RKTestFixture parsedObjectWithContentsOfFixture:@"user.json"]; RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:userInfo mappingsDictionary:mappingsDictionary]; mapper.targetObject = [RKTestUser user]; [mapper start]; } - (void)testShouldAddAnErrorWhenTheKeyPathMappingAndObjectClassDoNotAgree { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; id userInfo = [RKTestFixture parsedObjectWithContentsOfFixture:@"user.json"]; RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:userInfo mappingsDictionary:@{[NSNull null] : mapping}]; NSDictionary *dictionary = [NSDictionary new]; mapper.targetObject = dictionary; [mapper start]; assertThat(mapper.error, is(notNilValue())); // TODO: Better check on the error type... } - (void)testShouldMapToATargetObject { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKAttributeMapping *idMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"id" toKeyPath:@"userID"]; [mapping addPropertyMapping:idMapping]; RKAttributeMapping *nameMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"name" toKeyPath:@"name"]; [mapping addPropertyMapping:nameMapping]; id userInfo = [RKTestFixture parsedObjectWithContentsOfFixture:@"user.json"]; RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:userInfo mappingsDictionary:@{[NSNull null] : mapping}]; RKTestUser *user = [RKTestUser user]; mapper.targetObject = user; [mapper start]; RKMappingResult *result = mapper.mappingResult; assertThat(result, isNot(nilValue())); assertThatBool([result firstObject] == user, is(equalToBool(YES))); assertThat(user.name, is(equalTo(@"Blake Watters"))); } - (void)testShouldCreateANewInstanceOfTheAppropriateDestinationObjectWhenThereIsNoTargetObject { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKAttributeMapping *nameMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"name" toKeyPath:@"name"]; [mapping addPropertyMapping:nameMapping]; id userInfo = [RKTestFixture parsedObjectWithContentsOfFixture:@"user.json"]; RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:userInfo mappingsDictionary:@{ [NSNull null]: mapping }]; [mapper start]; id mappingResult = [mapper.mappingResult firstObject]; assertThatBool([mappingResult isKindOfClass:[RKTestUser class]], is(equalToBool(YES))); } - (void)testShouldMapWithoutATargetMapping { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKAttributeMapping *idMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"id" toKeyPath:@"userID"]; [mapping addPropertyMapping:idMapping]; RKAttributeMapping *nameMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"name" toKeyPath:@"name"]; [mapping addPropertyMapping:nameMapping]; id userInfo = [RKTestFixture parsedObjectWithContentsOfFixture:@"user.json"]; RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:userInfo mappingsDictionary:@{ [NSNull null]: mapping }]; [mapper start]; RKTestUser *user = [mapper.mappingResult firstObject]; assertThat(user, is(notNilValue())); assertThatBool([user isKindOfClass:[RKTestUser class]], is(equalToBool(YES))); assertThat(user.name, is(equalTo(@"Blake Watters"))); } - (void)testShouldMapACollectionOfObjects { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKAttributeMapping *idMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"id" toKeyPath:@"userID"]; [mapping addPropertyMapping:idMapping]; RKAttributeMapping *nameMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"name" toKeyPath:@"name"]; [mapping addPropertyMapping:nameMapping]; id userInfo = [RKTestFixture parsedObjectWithContentsOfFixture:@"users.json"]; RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:userInfo mappingsDictionary:@{ [NSNull null]: mapping }]; [mapper start]; NSArray *users = [mapper.mappingResult array]; assertThatBool([users isKindOfClass:[NSArray class]], is(equalToBool(YES))); assertThatUnsignedInteger([users count], is(equalToInt(3))); RKTestUser *user = [users objectAtIndex:0]; assertThatBool([user isKindOfClass:[RKTestUser class]], is(equalToBool(YES))); assertThat(user.name, is(equalTo(@"Blake Watters"))); } - (void)testShouldMapACollectionOfObjectsWithDynamicKeys { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; mapping.forceCollectionMapping = YES; [mapping addAttributeMappingFromKeyOfRepresentationToAttribute:@"name"]; RKAttributeMapping *idMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"(name).id" toKeyPath:@"userID"]; [mapping addPropertyMapping:idMapping]; NSMutableDictionary *mappingsDictionary = [NSMutableDictionary dictionary]; [mappingsDictionary setObject:mapping forKey:@"users"]; id userInfo = [RKTestFixture parsedObjectWithContentsOfFixture:@"DynamicKeys.json"]; RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:userInfo mappingsDictionary:mappingsDictionary]; [mapper start]; NSArray *users = [mapper.mappingResult array]; assertThatBool([users isKindOfClass:[NSArray class]], is(equalToBool(YES))); assertThatUnsignedInteger([users count], is(equalToInt(2))); RKTestUser *user = [users objectAtIndex:0]; assertThatBool([user isKindOfClass:[RKTestUser class]], is(equalToBool(YES))); assertThat(user.name, is(equalTo(@"blake"))); user = [users objectAtIndex:1]; assertThatBool([user isKindOfClass:[RKTestUser class]], is(equalToBool(YES))); assertThat(user.name, is(equalTo(@"rachit"))); } - (void)testShouldMapACollectionOfObjectsWithDynamicKeysAndRelationships { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; mapping.forceCollectionMapping = YES; [mapping addAttributeMappingFromKeyOfRepresentationToAttribute:@"name"]; RKObjectMapping *addressMapping = [RKObjectMapping mappingForClass:[RKTestAddress class]]; [addressMapping addAttributeMappingsFromArray:@[@"city", @"state"]]; [mapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"(name).address" toKeyPath:@"address" withMapping:addressMapping]];; NSMutableDictionary *mappingsDictionary = [NSMutableDictionary dictionary]; [mappingsDictionary setObject:mapping forKey:@"users"]; id userInfo = [RKTestFixture parsedObjectWithContentsOfFixture:@"DynamicKeysWithRelationship.json"]; RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:userInfo mappingsDictionary:mappingsDictionary]; [mapper start]; RKMappingResult *result = mapper.mappingResult; NSArray *users = [result array]; assertThatBool([users isKindOfClass:[NSArray class]], is(equalToBool(YES))); assertThatUnsignedInteger([users count], is(equalToInt(2))); RKTestUser *user = [users objectAtIndex:0]; assertThatBool([user isKindOfClass:[RKTestUser class]], is(equalToBool(YES))); assertThat(user.name, is(equalTo(@"blake"))); user = [users objectAtIndex:1]; assertThatBool([user isKindOfClass:[RKTestUser class]], is(equalToBool(YES))); assertThat(user.name, is(equalTo(@"rachit"))); assertThat(user.address, isNot(nilValue())); assertThat(user.address.city, is(equalTo(@"New York"))); } - (void)testShouldMapANestedArrayOfObjectsWithDynamicKeysAndArrayRelationships { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKExampleGroupWithUserArray class]]; [mapping addAttributeMappingsFromArray:@[@"name"]]; RKObjectMapping *userMapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; userMapping.forceCollectionMapping = YES; [userMapping addAttributeMappingFromKeyOfRepresentationToAttribute:@"name"]; [mapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"users" toKeyPath:@"users" withMapping:userMapping]];; RKObjectMapping *addressMapping = [RKObjectMapping mappingForClass:[RKTestAddress class]]; [addressMapping addAttributeMappingsFromDictionary:@{ @"city": @"city", @"state": @"state", @"country": @"country", }]; [userMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"(name).address" toKeyPath:@"address" withMapping:addressMapping]];; NSMutableDictionary *mappingsDictionary = [NSMutableDictionary dictionary]; [mappingsDictionary setObject:mapping forKey:@"groups"]; id userInfo = [RKTestFixture parsedObjectWithContentsOfFixture:@"DynamicKeysWithNestedRelationship.json"]; RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:userInfo mappingsDictionary:mappingsDictionary]; [mapper start]; RKMappingResult *result = mapper.mappingResult; NSArray *groups = [result array]; assertThatBool([groups isKindOfClass:[NSArray class]], is(equalToBool(YES))); assertThatUnsignedInteger([groups count], is(equalToInt(2))); RKExampleGroupWithUserArray *group = [groups objectAtIndex:0]; assertThatBool([group isKindOfClass:[RKExampleGroupWithUserArray class]], is(equalToBool(YES))); assertThat(group.name, is(equalTo(@"restkit"))); NSArray *users = group.users; RKTestUser *user = [users objectAtIndex:0]; assertThatBool([user isKindOfClass:[RKTestUser class]], is(equalToBool(YES))); assertThat(user.name, is(equalTo(@"blake"))); user = [users objectAtIndex:1]; assertThatBool([user isKindOfClass:[RKTestUser class]], is(equalToBool(YES))); assertThat(user.name, is(equalTo(@"rachit"))); assertThat(user.address, isNot(nilValue())); assertThat(user.address.city, is(equalTo(@"New York"))); group = [groups objectAtIndex:1]; assertThatBool([group isKindOfClass:[RKExampleGroupWithUserArray class]], is(equalToBool(YES))); assertThat(group.name, is(equalTo(@"others"))); users = group.users; assertThatUnsignedInteger([users count], is(equalToInt(1))); user = [users objectAtIndex:0]; assertThatBool([user isKindOfClass:[RKTestUser class]], is(equalToBool(YES))); assertThat(user.name, is(equalTo(@"bjorn"))); assertThat(user.address, isNot(nilValue())); assertThat(user.address.city, is(equalTo(@"Gothenburg"))); assertThat(user.address.country, is(equalTo(@"Sweden"))); } - (void)testShouldMapANestedArrayOfObjectsWithDynamicKeysAndSetRelationships { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKExampleGroupWithUserSet class]]; [mapping addAttributeMappingsFromArray:@[@"name"]]; RKObjectMapping *userMapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; userMapping.forceCollectionMapping = YES; [userMapping addAttributeMappingFromKeyOfRepresentationToAttribute:@"name"]; [mapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"users" toKeyPath:@"users" withMapping:userMapping]];; RKObjectMapping *addressMapping = [RKObjectMapping mappingForClass:[RKTestAddress class]]; [addressMapping addAttributeMappingsFromDictionary:@{ @"city": @"city", @"state": @"state", @"country": @"country", }]; [userMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"(name).address" toKeyPath:@"address" withMapping:addressMapping]];; NSMutableDictionary *mappingsDictionary = [NSMutableDictionary dictionary]; [mappingsDictionary setObject:mapping forKey:@"groups"]; id userInfo = [RKTestFixture parsedObjectWithContentsOfFixture:@"DynamicKeysWithNestedRelationship.json"]; RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:userInfo mappingsDictionary:mappingsDictionary]; [mapper start]; RKMappingResult *result = mapper.mappingResult; NSArray *groups = [result array]; assertThatBool([groups isKindOfClass:[NSArray class]], is(equalToBool(YES))); assertThatUnsignedInteger([groups count], is(equalToInt(2))); RKExampleGroupWithUserSet *group = [groups objectAtIndex:0]; assertThatBool([group isKindOfClass:[RKExampleGroupWithUserSet class]], is(equalToBool(YES))); assertThat(group.name, is(equalTo(@"restkit"))); NSSortDescriptor *sortByName = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES]; NSArray *descriptors = [NSArray arrayWithObject:sortByName];; NSArray *users = [group.users sortedArrayUsingDescriptors:descriptors]; RKTestUser *user = [users objectAtIndex:0]; assertThatBool([user isKindOfClass:[RKTestUser class]], is(equalToBool(YES))); assertThat(user.name, is(equalTo(@"blake"))); user = [users objectAtIndex:1]; assertThatBool([user isKindOfClass:[RKTestUser class]], is(equalToBool(YES))); assertThat(user.name, is(equalTo(@"rachit"))); assertThat(user.address, isNot(nilValue())); assertThat(user.address.city, is(equalTo(@"New York"))); group = [groups objectAtIndex:1]; assertThatBool([group isKindOfClass:[RKExampleGroupWithUserSet class]], is(equalToBool(YES))); assertThat(group.name, is(equalTo(@"others"))); users = [group.users sortedArrayUsingDescriptors:descriptors]; assertThatUnsignedInteger([users count], is(equalToInt(1))); user = [users objectAtIndex:0]; assertThatBool([user isKindOfClass:[RKTestUser class]], is(equalToBool(YES))); assertThat(user.name, is(equalTo(@"bjorn"))); assertThat(user.address, isNot(nilValue())); assertThat(user.address.city, is(equalTo(@"Gothenburg"))); assertThat(user.address.country, is(equalTo(@"Sweden"))); } - (void)testShouldBeAbleToMapFromAUserObjectToADictionary { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[NSMutableDictionary class]]; RKAttributeMapping *idMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"userID" toKeyPath:@"id"]; [mapping addPropertyMapping:idMapping]; RKAttributeMapping *nameMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"name" toKeyPath:@"name"]; [mapping addPropertyMapping:nameMapping]; RKTestUser *user = [RKTestUser user]; user.name = @"Blake Watters"; user.userID = [NSNumber numberWithInt:123]; RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:user mappingsDictionary:@{ [NSNull null]: mapping }]; [mapper start]; RKMappingResult *result = mapper.mappingResult; NSDictionary *userInfo = [result firstObject]; assertThatBool([userInfo isKindOfClass:[NSDictionary class]], is(equalToBool(YES))); assertThat([userInfo valueForKey:@"name"], is(equalTo(@"Blake Watters"))); } - (void)testShouldMapRegisteredSubKeyPathsOfAnUnmappableDictionaryAndReturnTheResults { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKAttributeMapping *idMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"id" toKeyPath:@"userID"]; [mapping addPropertyMapping:idMapping]; RKAttributeMapping *nameMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"name" toKeyPath:@"name"]; [mapping addPropertyMapping:nameMapping]; NSMutableDictionary *mappingsDictionary = [NSMutableDictionary dictionary]; [mappingsDictionary setObject:mapping forKey:@"user"]; id userInfo = [RKTestFixture parsedObjectWithContentsOfFixture:@"nested_user.json"]; RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:userInfo mappingsDictionary:mappingsDictionary]; [mapper start]; NSDictionary *dictionary = [mapper.mappingResult dictionary]; assertThatBool([dictionary isKindOfClass:[NSDictionary class]], is(equalToBool(YES))); RKTestUser *user = [dictionary objectForKey:@"user"]; assertThat(user, isNot(nilValue())); assertThat(user.name, is(equalTo(@"Blake Watters"))); } #pragma mark Mapping Error States - (void)testShouldAddAnErrorWhenYouTryToMapAnArrayToATargetObject { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKAttributeMapping *idMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"id" toKeyPath:@"userID"]; [mapping addPropertyMapping:idMapping]; RKAttributeMapping *nameMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"name" toKeyPath:@"name"]; [mapping addPropertyMapping:nameMapping]; id userInfo = [RKTestFixture parsedObjectWithContentsOfFixture:@"users.json"]; RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:userInfo mappingsDictionary:@{ [NSNull null]: mapping }]; mapper.targetObject = [RKTestUser user]; [mapper start]; assertThatInteger(mapper.error.code, is(equalToInt(RKMappingErrorTypeMismatch))); } - (void)testShouldAddAnErrorWhenAttemptingToMapADictionaryWithoutAnObjectMapping { id userInfo = [RKTestFixture parsedObjectWithContentsOfFixture:@"user.json"]; RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:userInfo mappingsDictionary:@{}]; [mapper start]; assertThat([mapper.error localizedDescription], is(equalTo(@"No mappable object representations were found at the key paths searched."))); } - (void)testShouldAddAnErrorWhenAttemptingToMapACollectionWithoutAnObjectMapping { NSMutableDictionary *mappingsDictionary = [NSMutableDictionary dictionary]; id userInfo = [RKTestFixture parsedObjectWithContentsOfFixture:@"users.json"]; RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:userInfo mappingsDictionary:mappingsDictionary]; [mapper start]; assertThat([mapper.error localizedDescription], is(equalTo(@"No mappable object representations were found at the key paths searched."))); } - (void)testThatAnErrorIsSetWithAHelpfulDescriptionWhenNoKeyPathsMatchTheArrayOfObjectsRepresentationBeingMapped { RKObjectMapping *mapping1 = [RKObjectMapping mappingForClass:[NSMutableDictionary class]]; RKObjectMapping *mapping2 = [RKObjectMapping mappingForClass:[NSMutableDictionary class]]; NSDictionary *mappingsDictionary = @{ @"this": mapping1, @"that": mapping2 }; id userInfo = [RKTestFixture parsedObjectWithContentsOfFixture:@"users.json"]; RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:userInfo mappingsDictionary:mappingsDictionary]; [mapper start]; assertThat([mapper.error localizedDescription], is(equalTo(@"No mappable object representations were found at the key paths searched."))); assertThat([mapper.error localizedFailureReason], is(equalTo(@"The mapping operation was unable to find any nested object representations at the key paths searched: that, this\nThis likely indicates that you have misconfigured the key paths for your mappings."))); } - (void)testThatAnErrorIsSetWithAHelpfulDescriptionWhenNoKeyPathsMatchTheObjectRepresentationBeingMapped { RKObjectMapping *mapping1 = [RKObjectMapping mappingForClass:[NSMutableDictionary class]]; RKObjectMapping *mapping2 = [RKObjectMapping mappingForClass:[NSMutableDictionary class]]; NSDictionary *mappingsDictionary = @{ @"this": mapping1, @"that": mapping2 }; id userInfo = [RKTestFixture parsedObjectWithContentsOfFixture:@"RailsUser.json"]; RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:userInfo mappingsDictionary:mappingsDictionary]; [mapper start]; assertThat([mapper.error localizedDescription], is(equalTo(@"No mappable object representations were found at the key paths searched."))); assertThat([mapper.error localizedFailureReason], is(equalTo(@"The mapping operation was unable to find any nested object representations at the key paths searched: that, this\nThe representation inputted to the mapper was found to contain nested object representations at the following key paths: user\nThis likely indicates that you have misconfigured the key paths for your mappings."))); } #pragma mark RKMapperOperationDelegate Tests - (void)testShouldInformTheDelegateWhenMappingBegins { id mockDelegate = [OCMockObject niceMockForProtocol:@protocol(RKMapperOperationDelegate)]; RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; id userInfo = [RKTestFixture parsedObjectWithContentsOfFixture:@"users.json"]; RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:userInfo mappingsDictionary:@{ [NSNull null]: mapping }]; [[mockDelegate expect] mapperWillStartMapping:mapper]; mapper.delegate = mockDelegate; [mapper start]; [mockDelegate verify]; } - (void)testShouldInformTheDelegateWhenMappingEnds { id mockDelegate = [OCMockObject niceMockForProtocol:@protocol(RKMapperOperationDelegate)]; RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; id userInfo = [RKTestFixture parsedObjectWithContentsOfFixture:@"users.json"]; RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:userInfo mappingsDictionary:@{ [NSNull null]: mapping }]; [[mockDelegate stub] mapperWillStartMapping:mapper]; [[mockDelegate expect] mapperDidFinishMapping:mapper]; mapper.delegate = mockDelegate; [mapper start]; [mockDelegate verify]; } - (void)testShouldInformTheDelegateWhenCheckingForObjectMappingForKeyPathIsSuccessful { id mockDelegate = [OCMockObject niceMockForProtocol:@protocol(RKMapperOperationDelegate)]; RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; id userInfo = [RKTestFixture parsedObjectWithContentsOfFixture:@"user.json"]; RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:userInfo mappingsDictionary:@{ [NSNull null]: mapping }]; [[mockDelegate expect] mapper:mapper didFindRepresentationOrArrayOfRepresentations:OCMOCK_ANY atKeyPath:nil]; mapper.delegate = mockDelegate; [mapper start]; [mockDelegate verify]; } - (void)testShouldInformTheDelegateWhenCheckingForObjectMappingForKeyPathIsNotSuccessful { NSMutableDictionary *mappingsDictionary = [NSMutableDictionary dictionary]; RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; [mappingsDictionary setObject:mapping forKey:@"users"]; id userInfo = [RKTestFixture parsedObjectWithContentsOfFixture:@"user.json"]; RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:userInfo mappingsDictionary:mappingsDictionary]; id mockDelegate = [OCMockObject niceMockForProtocol:@protocol(RKMapperOperationDelegate)]; [[mockDelegate expect] mapper:mapper didNotFindRepresentationOrArrayOfRepresentationsAtKeyPath:@"users"]; mapper.delegate = mockDelegate; [mapper start]; [mockDelegate verify]; } - (void)testShouldNotifyTheDelegateWhenItDidMapAnObject { id mockDelegate = [OCMockObject niceMockForProtocol:@protocol(RKMapperOperationDelegate)]; RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKAttributeMapping *nameMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"name" toKeyPath:@"name"]; [mapping addPropertyMapping:nameMapping]; id userInfo = [RKTestFixture parsedObjectWithContentsOfFixture:@"user.json"]; RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:userInfo mappingsDictionary:@{ [NSNull null]: mapping }]; [[mockDelegate expect] mapper:mapper didFinishMappingOperation:OCMOCK_ANY forKeyPath:nil]; mapper.delegate = mockDelegate; [mapper start]; [mockDelegate verify]; } - (void)testMappingConstructsMappingInfoDictionaryWithAttributeInfo { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; [mapping addAttributeMappingsFromArray:@[ @"name" ]]; NSDictionary *representation = @{ @"name": @"Blake Watters" }; RKTestUser *user = [RKTestUser new]; RKMappingOperation *mappingOperation = [[RKMappingOperation alloc] initWithSourceObject:representation destinationObject:user mapping:mapping]; [mappingOperation start]; expect(mappingOperation.mappingInfo).notTo.beNil(); RKPropertyMapping *nameMapping = mappingOperation.mappingInfo[@"name"]; expect(nameMapping).to.equal([mapping propertyMappingsByDestinationKeyPath][@"name"]); } - (void)testMappingConstructsMappingInfoDictionaryWithMergedRelationshipInfo { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; [mapping addAttributeMappingsFromArray:@[ @"name" ]]; [mapping addRelationshipMappingWithSourceKeyPath:@"friends" mapping:mapping]; NSDictionary *representation = @{ @"name": @"Blake Watters", @"friends": @[ @{ @"name": @"Jeff Arena"} ] }; RKTestUser *user = [RKTestUser new]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; RKMappingOperation *mappingOperation = [[RKMappingOperation alloc] initWithSourceObject:representation destinationObject:user mapping:mapping]; mappingOperation.dataSource = dataSource; [mappingOperation start]; expect(mappingOperation.mappingInfo).notTo.beNil(); RKPropertyMapping *friendsMapping = mappingOperation.mappingInfo[@"friends"]; RKPropertyMapping *nameMapping = mappingOperation.mappingInfo[@"name"]; RKPropertyMapping *nestedNameMapping = mappingOperation.mappingInfo[@"friends.name"]; expect(nameMapping).to.equal([mapping propertyMappingsByDestinationKeyPath][@"name"]); expect(friendsMapping).to.equal([mapping propertyMappingsByDestinationKeyPath][@"friends"]); expect(nestedNameMapping).to.equal([mapping propertyMappingsByDestinationKeyPath][@"name"]); } - (void)testThatMappingHasManyDoesNotDuplicateRelationshipMappingInMappingInfo { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; [mapping addAttributeMappingsFromArray:@[ @"name" ]]; [mapping addRelationshipMappingWithSourceKeyPath:@"friends" mapping:mapping]; NSDictionary *representation = @{ @"name": @"Blake Watters", @"friends": @[ @{ @"name": @"Jeff Arena"}, @{ @"name": @"Dan Gellert" } ] }; RKTestUser *user = [RKTestUser new]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; RKMappingOperation *mappingOperation = [[RKMappingOperation alloc] initWithSourceObject:representation destinationObject:user mapping:mapping]; mappingOperation.dataSource = dataSource; [mappingOperation start]; expect(mappingOperation.mappingInfo).notTo.beNil(); RKPropertyMapping *friendsMapping = mappingOperation.mappingInfo[@"friends"]; expect(friendsMapping).to.equal([mapping propertyMappingsByDestinationKeyPath][@"friends"]); } - (void)testThatDynamicMappingCoalescesObjectClassesInMappingInfo { // use a dynamic mapping with 2 classes, should have an objectClass as an array containing both } - (void)testMapperOperationAggregatesMappingInfoFromChildOperations { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; [mapping addAttributeMappingsFromArray:@[ @"name" ]]; [mapping addRelationshipMappingWithSourceKeyPath:@"friends" mapping:mapping]; NSDictionary *representation = @{ @"name": @"Blake Watters", @"friends": @[ @{ @"name": @"Jeff Arena"}, @{ @"name": @"Dan Gellert" } ] }; RKTestUser *user = [RKTestUser new]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; RKMapperOperation *mapperOperation = [[RKMapperOperation alloc] initWithRepresentation:representation mappingsDictionary:@{ [NSNull null]: mapping }]; mapperOperation.targetObject = user; mapperOperation.mappingOperationDataSource = dataSource; [mapperOperation start]; expect(mapperOperation.mappingInfo).notTo.beNil(); RKPropertyMapping *friendsMapping = mapperOperation.mappingInfo[[NSNull null]][@"friends"]; expect(friendsMapping).to.equal([mapping propertyMappingsByDestinationKeyPath][@"friends"]); } - (BOOL)fakeValidateValue:(inout id *)ioValue forKeyPath:(NSString *)inKey error:(out NSError **)outError { *outError = [NSError errorWithDomain:RKErrorDomain code:1234 userInfo:nil]; return NO; } - (void)testShouldNotifyTheDelegateWhenItFailedToMapAnObject { id mockDelegate = [OCMockObject niceMockForProtocol:@protocol(RKMapperOperationDelegate)]; RKObjectMapping *mapping = [RKObjectMapping mappingForClass:NSClassFromString(@"OCPartialMockObject")]; [mapping addAttributeMappingsFromArray:@[@"name"]]; id userInfo = [RKTestFixture parsedObjectWithContentsOfFixture:@"user.json"]; RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:userInfo mappingsDictionary:@{ [NSNull null]: mapping }]; RKTestUser *exampleUser = [RKTestUser new]; id mockObject = [OCMockObject partialMockForObject:exampleUser]; [[[mockObject expect] andCall:@selector(fakeValidateValue:forKeyPath:error:) onObject:self] validateValue:(id __autoreleasing *)[OCMArg anyPointer] forKeyPath:OCMOCK_ANY error:(NSError * __autoreleasing *)[OCMArg anyPointer]]; mapper.targetObject = mockObject; [[mockDelegate expect] mapper:mapper didFailMappingOperation:OCMOCK_ANY forKeyPath:nil withError:OCMOCK_ANY]; mapper.delegate = mockDelegate; [mapper start]; [mockObject verify]; [mockDelegate verify]; } #pragma mark - RKObjectMappingOperationTests - (void)testShouldBeAbleToMapADictionaryToAUser { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[NSMutableDictionary class]]; RKAttributeMapping *idMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"id" toKeyPath:@"userID"]; [mapping addPropertyMapping:idMapping]; RKAttributeMapping *nameMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"name" toKeyPath:@"name"]; [mapping addPropertyMapping:nameMapping]; NSMutableDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:123], @"id", @"Blake Watters", @"name", nil]; RKTestUser *user = [RKTestUser user]; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:dictionary destinationObject:user mapping:mapping]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; operation.dataSource = dataSource; [operation start]; assertThat(user.name, is(equalTo(@"Blake Watters"))); assertThatInt([user.userID intValue], is(equalToInt(123))); } - (void)testShouldConsiderADictionaryContainingOnlyNullValuesForKeysMappable { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[NSMutableDictionary class]]; RKAttributeMapping *idMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"id" toKeyPath:@"userID"]; [mapping addPropertyMapping:idMapping]; RKAttributeMapping *nameMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"name" toKeyPath:@"name"]; [mapping addPropertyMapping:nameMapping]; NSDictionary *dictionary = @{ @"name": [NSNull null] }; RKTestUser *user = [RKTestUser user]; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:dictionary destinationObject:user mapping:mapping]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; operation.dataSource = dataSource; BOOL success = [operation performMapping:nil]; assertThatBool(success, is(equalToBool(YES))); assertThat(user.name, is(nilValue())); } - (void)testShouldBeAbleToMapAUserToADictionary { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[NSMutableDictionary class]]; RKAttributeMapping *idMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"userID" toKeyPath:@"id"]; [mapping addPropertyMapping:idMapping]; RKAttributeMapping *nameMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"name" toKeyPath:@"name"]; [mapping addPropertyMapping:nameMapping]; RKTestUser *user = [RKTestUser user]; user.name = @"Blake Watters"; user.userID = [NSNumber numberWithInt:123]; NSMutableDictionary *dictionary = [NSMutableDictionary dictionary]; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:user destinationObject:dictionary mapping:mapping]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; operation.dataSource = dataSource; BOOL success = [operation performMapping:nil]; assertThatBool(success, is(equalToBool(YES))); assertThat([dictionary valueForKey:@"name"], is(equalTo(@"Blake Watters"))); assertThatInt([[dictionary valueForKey:@"id"] intValue], is(equalToInt(123))); } - (void)testShouldReturnNoWithoutErrorWhenGivenASourceObjectThatContainsNoMappableKeys { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[NSMutableDictionary class]]; RKAttributeMapping *idMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"id" toKeyPath:@"userID"]; [mapping addPropertyMapping:idMapping]; RKAttributeMapping *nameMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"name" toKeyPath:@"name"]; [mapping addPropertyMapping:nameMapping]; NSMutableDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:@"blue", @"favorite_color", @"coffee", @"preferred_beverage", nil]; RKTestUser *user = [RKTestUser user]; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:dictionary destinationObject:user mapping:mapping]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; operation.dataSource = dataSource; NSError *error = nil; BOOL success = [operation performMapping:&error]; assertThatBool(success, is(equalToBool(NO))); assertThat(error, is(notNilValue())); assertThatInteger(operation.error.code, is(equalToInteger(RKMappingErrorUnmappableRepresentation))); } - (void)testShouldInformTheDelegateOfAnErrorWhenMappingFailsBecauseThereIsNoMappableContent { id mockDelegate = [OCMockObject niceMockForProtocol:@protocol(RKMappingOperationDelegate)]; RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[NSMutableDictionary class]]; RKAttributeMapping *idMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"id" toKeyPath:@"userID"]; [mapping addPropertyMapping:idMapping]; RKAttributeMapping *nameMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"name" toKeyPath:@"name"]; [mapping addPropertyMapping:nameMapping]; NSMutableDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:@"blue", @"favorite_color", @"coffee", @"preferred_beverage", nil]; RKTestUser *user = [RKTestUser user]; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:dictionary destinationObject:user mapping:mapping]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; operation.dataSource = dataSource; operation.delegate = mockDelegate; BOOL success = [operation performMapping:nil]; assertThatBool(success, is(equalToBool(NO))); [mockDelegate verify]; } - (void)testShouldSetTheErrorWhenMappingOperationFails { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[NSMutableDictionary class]]; RKAttributeMapping *idMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"id" toKeyPath:@"userID"]; [mapping addPropertyMapping:idMapping]; RKAttributeMapping *nameMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"name" toKeyPath:@"name"]; [mapping addPropertyMapping:nameMapping]; NSMutableDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:@"FAILURE", @"id", nil]; RKTestUser *user = [RKTestUser user]; id mockObject = [OCMockObject partialMockForObject:user]; [[[mockObject expect] andCall:@selector(fakeValidateValue:forKeyPath:error:) onObject:self] validateValue:(id __autoreleasing *)[OCMArg anyPointer] forKeyPath:OCMOCK_ANY error:(NSError * __autoreleasing *)[OCMArg anyPointer]]; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:dictionary destinationObject:mockObject mapping:mapping]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; operation.dataSource = dataSource; NSError *error = nil; [operation performMapping:&error]; assertThat(error, isNot(nilValue())); } #pragma mark - Attribute Mapping - (void)testShouldMapAStringToADateAttribute { [RKObjectMapping resetDefaultDateFormatters]; RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKAttributeMapping *birthDateMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"birthdate" toKeyPath:@"birthDate"]; [mapping addPropertyMapping:birthDateMapping]; NSDictionary *dictionary = [RKTestFixture parsedObjectWithContentsOfFixture:@"user.json"]; RKTestUser *user = [RKTestUser user]; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:dictionary destinationObject:user mapping:mapping]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; operation.dataSource = dataSource; NSError *error = nil; [operation performMapping:&error]; NSDateFormatter *dateFormatter = [NSDateFormatter new]; dateFormatter.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"UTC"]; [dateFormatter setDateFormat:@"MM/dd/yyyy"]; assertThat([dateFormatter stringFromDate:user.birthDate], is(equalTo(@"11/27/1982"))); } - (void)testShouldMapStringToURL { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKAttributeMapping *websiteMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"website" toKeyPath:@"website"]; [mapping addPropertyMapping:websiteMapping]; NSDictionary *dictionary = [RKTestFixture parsedObjectWithContentsOfFixture:@"user.json"]; RKTestUser *user = [RKTestUser user]; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:dictionary destinationObject:user mapping:mapping]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; operation.dataSource = dataSource; NSError *error = nil; [operation performMapping:&error]; assertThat(user.website, isNot(nilValue())); assertThatBool([user.website isKindOfClass:[NSURL class]], is(equalToBool(YES))); assertThat([user.website absoluteString], is(equalTo(@"http://restkit.org/"))); } - (void)testShouldMapAStringToANumberBool { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKAttributeMapping *websiteMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"is_developer" toKeyPath:@"isDeveloper"]; [mapping addPropertyMapping:websiteMapping]; NSDictionary *dictionary = [RKTestFixture parsedObjectWithContentsOfFixture:@"user.json"]; RKTestUser *user = [RKTestUser user]; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:dictionary destinationObject:user mapping:mapping]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; operation.dataSource = dataSource; NSError *error = nil; [operation performMapping:&error]; assertThatBool([[user isDeveloper] boolValue], is(equalToBool(YES))); } - (void)testShouldMapAShortTrueStringToANumberBool { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKAttributeMapping *websiteMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"is_developer" toKeyPath:@"isDeveloper"]; [mapping addPropertyMapping:websiteMapping]; NSDictionary *dictionary = [[RKTestFixture parsedObjectWithContentsOfFixture:@"user.json"] mutableCopy]; RKTestUser *user = [RKTestUser user]; [dictionary setValue:@"T" forKey:@"is_developer"]; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:dictionary destinationObject:user mapping:mapping]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; operation.dataSource = dataSource; NSError *error = nil; [operation performMapping:&error]; assertThatBool([[user isDeveloper] boolValue], is(equalToBool(YES))); } - (void)testShouldMapAShortFalseStringToANumberBool { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKAttributeMapping *websiteMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"is_developer" toKeyPath:@"isDeveloper"]; [mapping addPropertyMapping:websiteMapping]; NSDictionary *dictionary = [[RKTestFixture parsedObjectWithContentsOfFixture:@"user.json"] mutableCopy]; RKTestUser *user = [RKTestUser user]; [dictionary setValue:@"f" forKey:@"is_developer"]; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:dictionary destinationObject:user mapping:mapping]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; operation.dataSource = dataSource; NSError *error = nil; [operation performMapping:&error]; assertThatBool([[user isDeveloper] boolValue], is(equalToBool(NO))); } - (void)testShouldMapAYesStringToANumberBool { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKAttributeMapping *websiteMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"is_developer" toKeyPath:@"isDeveloper"]; [mapping addPropertyMapping:websiteMapping]; NSDictionary *dictionary = [[RKTestFixture parsedObjectWithContentsOfFixture:@"user.json"] mutableCopy]; RKTestUser *user = [RKTestUser user]; [dictionary setValue:@"yes" forKey:@"is_developer"]; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:dictionary destinationObject:user mapping:mapping]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; operation.dataSource = dataSource; NSError *error = nil; [operation performMapping:&error]; assertThatBool([[user isDeveloper] boolValue], is(equalToBool(YES))); } - (void)testShouldMapANoStringToANumberBool { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKAttributeMapping *websiteMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"is_developer" toKeyPath:@"isDeveloper"]; [mapping addPropertyMapping:websiteMapping]; NSDictionary *dictionary = [[RKTestFixture parsedObjectWithContentsOfFixture:@"user.json"] mutableCopy]; RKTestUser *user = [RKTestUser user]; [dictionary setValue:@"NO" forKey:@"is_developer"]; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:dictionary destinationObject:user mapping:mapping]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; operation.dataSource = dataSource; NSError *error = nil; [operation performMapping:&error]; assertThatBool([[user isDeveloper] boolValue], is(equalToBool(NO))); } - (void)testShouldMapAYCharacterStringToANumberBool { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKAttributeMapping *websiteMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"is_developer" toKeyPath:@"isDeveloper"]; [mapping addPropertyMapping:websiteMapping]; NSDictionary *dictionary = [[RKTestFixture parsedObjectWithContentsOfFixture:@"user.json"] mutableCopy]; RKTestUser *user = [RKTestUser user]; [dictionary setValue:@"y" forKey:@"is_developer"]; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:dictionary destinationObject:user mapping:mapping]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; operation.dataSource = dataSource; NSError *error = nil; [operation performMapping:&error]; assertThatBool([[user isDeveloper] boolValue], is(equalToBool(YES))); } - (void)testShouldMapANCharacterStringToANumberBool { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKAttributeMapping *websiteMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"is_developer" toKeyPath:@"isDeveloper"]; [mapping addPropertyMapping:websiteMapping]; NSDictionary *dictionary = [[RKTestFixture parsedObjectWithContentsOfFixture:@"user.json"] mutableCopy]; RKTestUser *user = [RKTestUser user]; [dictionary setValue:@"n" forKey:@"is_developer"]; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:dictionary destinationObject:user mapping:mapping]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; operation.dataSource = dataSource; NSError *error = nil; [operation performMapping:&error]; assertThatBool([[user isDeveloper] boolValue], is(equalToBool(NO))); } - (void)testShouldMapAStringToANumber { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKAttributeMapping *websiteMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"lucky_number" toKeyPath:@"luckyNumber"]; [mapping addPropertyMapping:websiteMapping]; NSDictionary *dictionary = [RKTestFixture parsedObjectWithContentsOfFixture:@"user.json"]; RKTestUser *user = [RKTestUser user]; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:dictionary destinationObject:user mapping:mapping]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; operation.dataSource = dataSource; NSError *error = nil; [operation performMapping:&error]; assertThatInt([user.luckyNumber intValue], is(equalToInt(187))); } - (void)testShouldMapAStringToADecimalNumber { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKAttributeMapping *websiteMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"weight" toKeyPath:@"weight"]; [mapping addPropertyMapping:websiteMapping]; NSDictionary *dictionary = [RKTestFixture parsedObjectWithContentsOfFixture:@"user.json"]; RKTestUser *user = [RKTestUser user]; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:dictionary destinationObject:user mapping:mapping]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; operation.dataSource = dataSource; NSError *error = nil; [operation performMapping:&error]; NSDecimalNumber *weight = user.weight; assertThatBool([weight isKindOfClass:[NSDecimalNumber class]], is(equalToBool(YES))); assertThatInteger([weight compare:[NSDecimalNumber decimalNumberWithString:@"131.3"]], is(equalToInt(NSOrderedSame))); } - (void)testShouldMapANumberToAString { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKAttributeMapping *websiteMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"lucky_number" toKeyPath:@"name"]; [mapping addPropertyMapping:websiteMapping]; NSDictionary *dictionary = [RKTestFixture parsedObjectWithContentsOfFixture:@"user.json"]; RKTestUser *user = [RKTestUser user]; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:dictionary destinationObject:user mapping:mapping]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; operation.dataSource = dataSource; NSError *error = nil; [operation performMapping:&error]; assertThat(user.name, is(equalTo(@"187"))); } - (void)testShouldMapANumberToANSDecimalNumber { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKAttributeMapping *websiteMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"lucky_number" toKeyPath:@"weight"]; [mapping addPropertyMapping:websiteMapping]; NSDictionary *dictionary = [RKTestFixture parsedObjectWithContentsOfFixture:@"user.json"]; RKTestUser *user = [RKTestUser user]; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:dictionary destinationObject:user mapping:mapping]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; operation.dataSource = dataSource; NSError *error = nil; [operation performMapping:&error]; NSDecimalNumber *weight = user.weight; assertThatBool([weight isKindOfClass:[NSDecimalNumber class]], is(equalToBool(YES))); assertThatInteger([weight compare:[NSDecimalNumber decimalNumberWithString:@"187"]], is(equalToInt(NSOrderedSame))); } - (void)testShouldMapANumberToADate { NSDateFormatter *dateFormatter = [NSDateFormatter new]; [dateFormatter setDateFormat:@"MM/dd/yyyy"]; NSDate *date = [dateFormatter dateFromString:@"11/27/1982"]; RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKAttributeMapping *birthDateMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"dateAsNumber" toKeyPath:@"birthDate"]; [mapping addPropertyMapping:birthDateMapping]; NSMutableDictionary *dictionary = [[RKTestFixture parsedObjectWithContentsOfFixture:@"user.json"] mutableCopy]; [dictionary setValue:[NSNumber numberWithInt:[date timeIntervalSince1970]] forKey:@"dateAsNumber"]; RKTestUser *user = [RKTestUser user]; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:dictionary destinationObject:user mapping:mapping]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; operation.dataSource = dataSource; NSError *error = nil; [operation performMapping:&error]; assertThat([dateFormatter stringFromDate:user.birthDate], is(equalTo(@"11/27/1982"))); } - (void)testShouldMapANestedKeyPathToAnAttribute { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKAttributeMapping *countryMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"address.country" toKeyPath:@"country"]; [mapping addPropertyMapping:countryMapping]; NSDictionary *dictionary = [RKTestFixture parsedObjectWithContentsOfFixture:@"user.json"]; RKTestUser *user = [RKTestUser user]; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:dictionary destinationObject:user mapping:mapping]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; operation.dataSource = dataSource; NSError *error = nil; [operation performMapping:&error]; assertThat(user.country, is(equalTo(@"USA"))); } - (void)testShouldMapANestedArrayOfStringsToAnAttribute { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKAttributeMapping *countryMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"interests" toKeyPath:@"interests"]; [mapping addPropertyMapping:countryMapping]; NSDictionary *dictionary = [RKTestFixture parsedObjectWithContentsOfFixture:@"user.json"]; RKTestUser *user = [RKTestUser user]; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:dictionary destinationObject:user mapping:mapping]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; operation.dataSource = dataSource; NSError *error = nil; [operation performMapping:&error]; NSArray *interests = [NSArray arrayWithObjects:@"Hacking", @"Running", nil]; assertThat(user.interests, is(equalTo(interests))); } - (void)testShouldMapANestedDictionaryToAnAttribute { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKAttributeMapping *countryMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"address" toKeyPath:@"addressDictionary"]; [mapping addPropertyMapping:countryMapping]; NSDictionary *dictionary = [RKTestFixture parsedObjectWithContentsOfFixture:@"user.json"]; RKTestUser *user = [RKTestUser user]; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:dictionary destinationObject:user mapping:mapping]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; operation.dataSource = dataSource; NSError *error = nil; [operation performMapping:&error]; NSDictionary *address = @{ @"city": @"Carrboro", @"state": @"North Carolina", @"id": [NSNumber numberWithInt:1234], @"country": @"USA"}; assertThat(user.addressDictionary, is(equalTo(address))); } - (void)testShouldNotSetAPropertyWhenTheValueIsTheSame { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKAttributeMapping *nameMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"name" toKeyPath:@"name"]; [mapping addPropertyMapping:nameMapping]; NSDictionary *dictionary = [RKTestFixture parsedObjectWithContentsOfFixture:@"user.json"]; RKTestUser *user = [RKTestUser user]; user.name = @"Blake Watters"; id mockUser = [OCMockObject partialMockForObject:user]; [(RKTestUser *)[mockUser reject] setName:OCMOCK_ANY]; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:dictionary destinationObject:user mapping:mapping]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; operation.dataSource = dataSource; NSError *error = nil; [operation performMapping:&error]; } - (void)testShouldNotSetTheDestinationPropertyWhenBothAreNil { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKAttributeMapping *nameMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"name" toKeyPath:@"name"]; [mapping addPropertyMapping:nameMapping]; NSMutableDictionary *dictionary = [[RKTestFixture parsedObjectWithContentsOfFixture:@"user.json"] mutableCopy]; [dictionary setValue:[NSNull null] forKey:@"name"]; RKTestUser *user = [RKTestUser user]; user.name = nil; id mockUser = [OCMockObject partialMockForObject:user]; [(RKTestUser *)[mockUser reject] setName:OCMOCK_ANY]; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:dictionary destinationObject:user mapping:mapping]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; operation.dataSource = dataSource; NSError *error = nil; [operation performMapping:&error]; } - (void)testShouldSetNilForNSNullValues { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKAttributeMapping *nameMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"name" toKeyPath:@"name"]; [mapping addPropertyMapping:nameMapping]; NSDictionary *dictionary = [[RKTestFixture parsedObjectWithContentsOfFixture:@"user.json"] mutableCopy]; [dictionary setValue:[NSNull null] forKey:@"name"]; RKTestUser *user = [RKTestUser user]; user.name = @"Blake Watters"; id mockUser = [OCMockObject partialMockForObject:user]; [(RKTestUser *)[mockUser expect] setName:nil]; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:dictionary destinationObject:user mapping:mapping]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; operation.dataSource = dataSource; NSError *error = nil; [operation performMapping:&error]; [mockUser verify]; } - (void)testDelegateIsInformedWhenANilValueIsMappedForNSNullWithExistingValue { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKAttributeMapping *nameMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"name" toKeyPath:@"name"]; [mapping addPropertyMapping:nameMapping]; NSDictionary *dictionary = [[RKTestFixture parsedObjectWithContentsOfFixture:@"user.json"] mutableCopy]; [dictionary setValue:[NSNull null] forKey:@"name"]; RKTestUser *user = [RKTestUser user]; user.name = @"Blake Watters"; id mockDelegate = [OCMockObject mockForProtocol:@protocol(RKMappingOperationDelegate)]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:dictionary destinationObject:user mapping:mapping]; operation.delegate = mockDelegate; NSError *error = nil; [[mockDelegate expect] mappingOperation:operation didFindValue:[NSNull null] forKeyPath:@"name" mapping:nameMapping]; [[mockDelegate expect] mappingOperation:operation didSetValue:nil forKeyPath:@"name" usingMapping:nameMapping]; operation.dataSource = dataSource; [operation performMapping:&error]; [mockDelegate verify]; } - (void)testDelegateIsInformedWhenUnchangedValueIsSkipped { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKAttributeMapping *nameMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"name" toKeyPath:@"name"]; [mapping addPropertyMapping:nameMapping]; NSDictionary *dictionary = [[RKTestFixture parsedObjectWithContentsOfFixture:@"user.json"] mutableCopy]; [dictionary setValue:@"Blake Watters" forKey:@"name"]; RKTestUser *user = [RKTestUser user]; user.name = @"Blake Watters"; id mockDelegate = [OCMockObject mockForProtocol:@protocol(RKMappingOperationDelegate)]; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:dictionary destinationObject:user mapping:mapping]; operation.delegate = mockDelegate; NSError *error = nil; [[mockDelegate expect] mappingOperation:operation didFindValue:@"Blake Watters" forKeyPath:@"name" mapping:nameMapping]; [[mockDelegate expect] mappingOperation:operation didNotSetUnchangedValue:@"Blake Watters" forKeyPath:@"name" usingMapping:nameMapping]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; operation.dataSource = dataSource; [operation performMapping:&error]; [mockDelegate verify]; } - (void)testShouldOptionallySetDefaultValueForAMissingKeyPath { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKAttributeMapping *nameMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"name" toKeyPath:@"name"]; [mapping addPropertyMapping:nameMapping]; NSMutableDictionary *dictionary = [[RKTestFixture parsedObjectWithContentsOfFixture:@"user.json"] mutableCopy]; [dictionary removeObjectForKey:@"name"]; RKTestUser *user = [RKTestUser user]; user.name = @"Blake Watters"; id mockUser = [OCMockObject partialMockForObject:user]; [(RKTestUser *)[mockUser expect] setName:nil]; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:dictionary destinationObject:user mapping:mapping]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; operation.dataSource = dataSource; id mockMapping = [OCMockObject partialMockForObject:mapping]; BOOL returnValue = YES; [[[mockMapping expect] andReturnValue:OCMOCK_VALUE(returnValue)] shouldSetDefaultValueForMissingAttributes]; NSError *error = nil; [operation performMapping:&error]; [mockUser verify]; } - (void)testShouldOptionallyIgnoreAMissingSourceKeyPath { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKAttributeMapping *nameMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"name" toKeyPath:@"name"]; [mapping addPropertyMapping:nameMapping]; NSMutableDictionary *dictionary = [[RKTestFixture parsedObjectWithContentsOfFixture:@"user.json"] mutableCopy]; [dictionary removeObjectForKey:@"name"]; RKTestUser *user = [RKTestUser user]; user.name = @"Blake Watters"; id mockUser = [OCMockObject partialMockForObject:user]; [(RKTestUser *)[mockUser reject] setName:nil]; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:dictionary destinationObject:user mapping:mapping]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; operation.dataSource = dataSource; id mockMapping = [OCMockObject partialMockForObject:mapping]; BOOL returnValue = NO; [[[mockMapping expect] andReturnValue:OCMOCK_VALUE(returnValue)] shouldSetDefaultValueForMissingAttributes]; NSError *error = nil; [operation performMapping:&error]; assertThat(user.name, is(equalTo(@"Blake Watters"))); } - (void)testMappingToAnNSDataAttributeUsingKeyedArchiver { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKAttributeMapping *attributeMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"arrayOfStrings" toKeyPath:@"data"]; [mapping addPropertyMapping:attributeMapping]; NSDictionary *dictionary = @{ @"arrayOfStrings": @[ @"one", @"two", @"three" ] }; RKTestUser *user = [RKTestUser user]; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:dictionary destinationObject:user mapping:mapping]; NSError *error = nil; BOOL success = [operation performMapping:&error]; expect(success).to.equal(YES); expect(user.data).notTo.beNil(); NSDictionary *decodedDictionary = [NSKeyedUnarchiver unarchiveObjectWithData:user.data]; NSArray *expectedValue = @[ @"one", @"two", @"three" ]; expect(decodedDictionary).to.equal(expectedValue); } - (void)testShouldMapNSDateDistantFutureDateStringToADate { [RKObjectMapping resetDefaultDateFormatters]; RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKAttributeMapping *birthDateMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"birthdate" toKeyPath:@"birthDate"]; [mapping addPropertyMapping:birthDateMapping]; NSMutableDictionary *dictionary = [[RKTestFixture parsedObjectWithContentsOfFixture:@"user.json"] mutableCopy]; [dictionary setObject:@"3001-01-01T00:00:00Z" forKey:@"birthdate"]; RKTestUser *user = [RKTestUser user]; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:dictionary destinationObject:user mapping:mapping]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; operation.dataSource = dataSource; NSError *error = nil; [operation performMapping:&error]; NSDateFormatter *dateFormatter = [NSDateFormatter new]; dateFormatter.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"UTC"]; [dateFormatter setDateFormat:@"MM/dd/yyyy"]; assertThat([dateFormatter stringFromDate:user.birthDate], is(equalTo(@"01/01/3001"))); } - (void)testMappingASingularValueToAnArray { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; [mapping addAttributeMappingsFromArray:@[ @"favoriteColors" ]]; NSDictionary *dictionary = @{ @"favoriteColors": @"Blue" }; RKTestUser *user = [RKTestUser user]; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:dictionary destinationObject:user mapping:mapping]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; operation.dataSource = dataSource; NSError *error = nil; [operation performMapping:&error]; assertThat(user.favoriteColors, is(equalTo(@[ @"Blue" ]))); } - (void)testMappingArrayToMutableArray { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; [mapping addAttributeMappingsFromDictionary:@{ @"favoriteColors": @"mutableFavoriteColors" }]; NSDictionary *dictionary = @{ @"favoriteColors": @[ @"Blue", @"Red" ] }; RKTestUser *user = [RKTestUser user]; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:dictionary destinationObject:user mapping:mapping]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; operation.dataSource = dataSource; NSError *error = nil; [operation performMapping:&error]; assertThat(user.mutableFavoriteColors, is(equalTo(@[ @"Blue", @"Red" ]))); assertThat(user.mutableFavoriteColors, is(instanceOf([NSMutableArray class]))); } - (void)testMappingASingularValueToASet { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; [mapping addAttributeMappingsFromArray:@[ @"friendsSet" ]]; NSDictionary *dictionary = @{ @"friendsSet": @"Jeff" }; RKTestUser *user = [RKTestUser user]; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:dictionary destinationObject:user mapping:mapping]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; operation.dataSource = dataSource; NSError *error = nil; [operation performMapping:&error]; assertThat(user.friendsSet, is(equalTo([NSSet setWithObject:@"Jeff" ]))); } - (void)testMappingASingularValueToAnOrderedSet { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; [mapping addAttributeMappingsFromArray:@[ @"friendsOrderedSet" ]]; NSDictionary *dictionary = @{ @"friendsOrderedSet": @"Jeff" }; RKTestUser *user = [RKTestUser user]; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:dictionary destinationObject:user mapping:mapping]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; operation.dataSource = dataSource; NSError *error = nil; [operation performMapping:&error]; assertThat(user.friendsOrderedSet, is(equalTo([NSOrderedSet orderedSetWithObject:@"Jeff" ]))); } - (void)testTypeTransformationAtKeyPath { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKAttributeMapping *websiteMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"this.that" toKeyPath:@"address.addressID"]; [mapping addPropertyMapping:websiteMapping]; NSDictionary *dictionary = @{ @"this": @{ @"that": @"12345" }}; RKTestUser *user = [RKTestUser user]; RKTestAddress *address = [RKTestAddress new]; user.address = address; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:dictionary destinationObject:user mapping:mapping]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; operation.dataSource = dataSource; NSError *error = nil; [operation performMapping:&error]; assertThat(user.address.addressID, is(instanceOf([NSNumber class]))); assertThat(user.address.addressID, is(equalTo(@(12345)))); } - (void)testThatAttributeMappingToAPrimitiveValueFromNullDoesNotCrash { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; [mapping addAttributeMappingsFromArray:@[ @"age" ]]; NSDictionary *dictionary = @{ @"age": [NSNull null] }; RKTestUser *user = [RKTestUser user]; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:dictionary destinationObject:user mapping:mapping]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; operation.dataSource = dataSource; NSError *error = nil; [operation performMapping:&error]; expect(user.age).to.equal(0); } - (void)testThatAttributeMappingToAPrimitiveValueFromUnexpectedObjectTypeDoesNotCrash { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; [mapping addAttributeMappingsFromArray:@[ @"age" ]]; NSDictionary *dictionary = @{ @"age": @{ @"wrong": @"data" }}; RKTestUser *user = [RKTestUser user]; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:dictionary destinationObject:user mapping:mapping]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; operation.dataSource = dataSource; NSError *error = nil; [operation performMapping:&error]; expect(user.age).to.equal(0); } - (void)testThatMappingNullValueToTransformablePropertyDoesNotGenerateWarning { RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore]; RKEntityMapping *humanMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore]; [humanMapping addAttributeMappingsFromArray:@[ @"catIDs" ]]; NSDictionary *dictionary = @{ @"catsIDs": [NSNull null] }; RKHuman *human = [NSEntityDescription insertNewObjectForEntityForName:@"Human" inManagedObjectContext:managedObjectStore.mainQueueManagedObjectContext]; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:dictionary destinationObject:human mapping:humanMapping]; RKManagedObjectMappingOperationDataSource *dataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.mainQueueManagedObjectContext cache:nil]; operation.dataSource = dataSource; NSError *error = nil; [operation performMapping:&error]; expect(human.catIDs).to.beNil(); } #pragma mark - Relationship Mapping - (void)testShouldMapANestedObject { RKObjectMapping *userMapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKAttributeMapping *nameMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"name" toKeyPath:@"name"]; [userMapping addPropertyMapping:nameMapping]; RKObjectMapping *addressMapping = [RKObjectMapping mappingForClass:[RKTestAddress class]]; RKAttributeMapping *cityMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"city" toKeyPath:@"city"]; [addressMapping addPropertyMapping:cityMapping]; RKRelationshipMapping *hasOneMapping = [RKRelationshipMapping relationshipMappingFromKeyPath:@"address" toKeyPath:@"address" withMapping:addressMapping]; [userMapping addPropertyMapping:hasOneMapping]; RKMapperOperation *mapper = [RKMapperOperation new]; mapper.mappingOperationDataSource = [RKObjectMappingOperationDataSource new]; id userInfo = [RKTestFixture parsedObjectWithContentsOfFixture:@"user.json"]; RKTestUser *user = [RKTestUser user]; BOOL success = [mapper mapRepresentation:userInfo toObject:user atKeyPath:@"" usingMapping:userMapping metadata:nil]; assertThatBool(success, is(equalToBool(YES))); assertThat(user.name, is(equalTo(@"Blake Watters"))); assertThat(user.address, isNot(nilValue())); } - (void)testShouldMapANestedObjectToCollection { RKObjectMapping *userMapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKAttributeMapping *nameMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"name" toKeyPath:@"name"]; [userMapping addPropertyMapping:nameMapping]; RKObjectMapping *addressMapping = [RKObjectMapping mappingForClass:[RKTestAddress class]]; RKAttributeMapping *cityMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"city" toKeyPath:@"city"]; [addressMapping addPropertyMapping:cityMapping]; RKRelationshipMapping *hasOneMapping = [RKRelationshipMapping relationshipMappingFromKeyPath:@"address" toKeyPath:@"friends" withMapping:addressMapping]; [userMapping addPropertyMapping:hasOneMapping]; RKMapperOperation *mapper = [RKMapperOperation new]; mapper.mappingOperationDataSource = [RKObjectMappingOperationDataSource new]; id userInfo = [RKTestFixture parsedObjectWithContentsOfFixture:@"user.json"]; RKTestUser *user = [RKTestUser user]; BOOL success = [mapper mapRepresentation:userInfo toObject:user atKeyPath:@"" usingMapping:userMapping metadata:nil]; assertThatBool(success, is(equalToBool(YES))); assertThat(user.name, is(equalTo(@"Blake Watters"))); assertThat(user.friends, isNot(nilValue())); assertThatUnsignedInteger([user.friends count], is(equalToInt(1))); } - (void)testShouldMapANestedObjectToOrderedSetCollection { RKObjectMapping *userMapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKAttributeMapping *nameMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"name" toKeyPath:@"name"]; [userMapping addPropertyMapping:nameMapping]; RKObjectMapping *addressMapping = [RKObjectMapping mappingForClass:[RKTestAddress class]]; RKAttributeMapping *cityMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"city" toKeyPath:@"city"]; [addressMapping addPropertyMapping:cityMapping]; RKRelationshipMapping *hasOneMapping = [RKRelationshipMapping relationshipMappingFromKeyPath:@"address" toKeyPath:@"friendsOrderedSet" withMapping:addressMapping]; [userMapping addPropertyMapping:hasOneMapping]; RKMapperOperation *mapper = [RKMapperOperation new]; mapper.mappingOperationDataSource = [RKObjectMappingOperationDataSource new]; id userInfo = [RKTestFixture parsedObjectWithContentsOfFixture:@"user.json"]; RKTestUser *user = [RKTestUser user]; BOOL success = [mapper mapRepresentation:userInfo toObject:user atKeyPath:@"" usingMapping:userMapping metadata:nil]; assertThatBool(success, is(equalToBool(YES))); assertThat(user.name, is(equalTo(@"Blake Watters"))); assertThat(user.friendsOrderedSet, isNot(nilValue())); assertThatUnsignedInteger([user.friendsOrderedSet count], is(equalToInt(1))); } - (void)testShouldMapANestedObjectCollection { RKObjectMapping *userMapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKAttributeMapping *nameMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"name" toKeyPath:@"name"]; [userMapping addPropertyMapping:nameMapping]; RKRelationshipMapping *hasManyMapping = [RKRelationshipMapping relationshipMappingFromKeyPath:@"friends" toKeyPath:@"friends" withMapping:userMapping]; [userMapping addPropertyMapping:hasManyMapping]; RKMapperOperation *mapper = [RKMapperOperation new]; mapper.mappingOperationDataSource = [RKObjectMappingOperationDataSource new]; id userInfo = [RKTestFixture parsedObjectWithContentsOfFixture:@"user.json"]; RKTestUser *user = [RKTestUser user]; BOOL success = [mapper mapRepresentation:userInfo toObject:user atKeyPath:@"" usingMapping:userMapping metadata:nil]; assertThatBool(success, is(equalToBool(YES))); assertThat(user.name, is(equalTo(@"Blake Watters"))); assertThat(user.friends, isNot(nilValue())); assertThatUnsignedInteger([user.friends count], is(equalToInt(2))); NSArray *names = [NSArray arrayWithObjects:@"Jeremy Ellison", @"Rachit Shukla", nil]; assertThat([user.friends valueForKey:@"name"], is(equalTo(names))); } - (void)testShouldMapANestedArrayIntoASet { RKObjectMapping *userMapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKAttributeMapping *nameMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"name" toKeyPath:@"name"]; [userMapping addPropertyMapping:nameMapping]; RKRelationshipMapping *hasManyMapping = [RKRelationshipMapping relationshipMappingFromKeyPath:@"friends" toKeyPath:@"friendsSet" withMapping:userMapping]; [userMapping addPropertyMapping:hasManyMapping]; RKMapperOperation *mapper = [RKMapperOperation new]; mapper.mappingOperationDataSource = [RKObjectMappingOperationDataSource new]; id userInfo = [RKTestFixture parsedObjectWithContentsOfFixture:@"user.json"]; RKTestUser *user = [RKTestUser user]; BOOL success = [mapper mapRepresentation:userInfo toObject:user atKeyPath:@"" usingMapping:userMapping metadata:nil]; assertThatBool(success, is(equalToBool(YES))); assertThat(user.name, is(equalTo(@"Blake Watters"))); assertThat(user.friendsSet, isNot(nilValue())); assertThatBool([user.friendsSet isKindOfClass:[NSSet class]], is(equalToBool(YES))); assertThatUnsignedInteger([user.friendsSet count], is(equalToInt(2))); NSSet *names = [NSSet setWithObjects:@"Jeremy Ellison", @"Rachit Shukla", nil]; assertThat([user.friendsSet valueForKey:@"name"], is(equalTo(names))); } - (void)testShouldMapANestedArrayIntoAnOrderedSet { RKObjectMapping *userMapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKAttributeMapping *nameMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"name" toKeyPath:@"name"]; [userMapping addPropertyMapping:nameMapping]; RKRelationshipMapping *hasManyMapping = [RKRelationshipMapping relationshipMappingFromKeyPath:@"friends" toKeyPath:@"friendsOrderedSet" withMapping:userMapping]; [userMapping addPropertyMapping:hasManyMapping]; RKMapperOperation *mapper = [RKMapperOperation new]; mapper.mappingOperationDataSource = [RKObjectMappingOperationDataSource new]; id userInfo = [RKTestFixture parsedObjectWithContentsOfFixture:@"user.json"]; RKTestUser *user = [RKTestUser user]; BOOL success = [mapper mapRepresentation:userInfo toObject:user atKeyPath:@"" usingMapping:userMapping metadata:nil]; assertThatBool(success, is(equalToBool(YES))); assertThat(user.name, is(equalTo(@"Blake Watters"))); assertThat(user.friendsOrderedSet, isNot(nilValue())); assertThatBool([user.friendsOrderedSet isKindOfClass:[NSOrderedSet class]], is(equalToBool(YES))); assertThatUnsignedInteger([user.friendsOrderedSet count], is(equalToInt(2))); NSOrderedSet *names = [NSOrderedSet orderedSetWithObjects:@"Jeremy Ellison", @"Rachit Shukla", nil]; assertThat([user.friendsOrderedSet valueForKey:@"name"], is(equalTo(names))); } - (void)testShouldNotSetThePropertyWhenTheNestedObjectIsIdentical { RKTestUser *user = [RKTestUser user]; RKTestAddress *address = [RKTestAddress address]; address.addressID = [NSNumber numberWithInt:1234]; user.address = address; id mockUser = [OCMockObject partialMockForObject:user]; [[mockUser reject] setAddress:OCMOCK_ANY]; RKObjectMapping *userMapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKAttributeMapping *nameMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"name" toKeyPath:@"name"]; [userMapping addPropertyMapping:nameMapping]; RKObjectMapping *addressMapping = [RKObjectMapping mappingForClass:[RKTestAddress class]]; RKAttributeMapping *idMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"id" toKeyPath:@"addressID"]; [addressMapping addPropertyMapping:idMapping]; RKRelationshipMapping *hasOneMapping = [RKRelationshipMapping relationshipMappingFromKeyPath:@"address" toKeyPath:@"address" withMapping:addressMapping]; [userMapping addPropertyMapping:hasOneMapping]; RKMapperOperation *mapper = [RKMapperOperation new]; mapper.mappingOperationDataSource = [RKObjectMappingOperationDataSource new]; id userInfo = [RKTestFixture parsedObjectWithContentsOfFixture:@"user.json"]; [mapper mapRepresentation:userInfo toObject:user atKeyPath:@"" usingMapping:userMapping metadata:nil]; } - (void)testSkippingOfIdenticalObjectsInformsDelegate { RKTestUser *user = [RKTestUser user]; RKTestAddress *address = [RKTestAddress address]; address.addressID = [NSNumber numberWithInt:1234]; user.address = address; id mockUser = [OCMockObject partialMockForObject:user]; [[mockUser reject] setAddress:OCMOCK_ANY]; RKObjectMapping *userMapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKAttributeMapping *nameMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"name" toKeyPath:@"name"]; [userMapping addPropertyMapping:nameMapping]; RKObjectMapping *addressMapping = [RKObjectMapping mappingForClass:[RKTestAddress class]]; RKAttributeMapping *idMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"id" toKeyPath:@"addressID"]; [addressMapping addPropertyMapping:idMapping]; RKRelationshipMapping *hasOneMapping = [RKRelationshipMapping relationshipMappingFromKeyPath:@"address" toKeyPath:@"address" withMapping:addressMapping]; [userMapping addPropertyMapping:hasOneMapping]; id userInfo = [RKTestFixture parsedObjectWithContentsOfFixture:@"user.json"]; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:userInfo destinationObject:user mapping:userMapping]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; operation.dataSource = dataSource; id mockDelegate = [OCMockObject niceMockForProtocol:@protocol(RKMappingOperationDelegate)]; [[mockDelegate expect] mappingOperation:operation didNotSetUnchangedValue:address forKeyPath:@"address" usingMapping:hasOneMapping]; operation.delegate = mockDelegate; [operation performMapping:nil]; [mockDelegate verify]; } - (void)testShouldNotSetThePropertyWhenTheNestedObjectCollectionIsIdentical { RKObjectMapping *userMapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKAttributeMapping *idMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"id" toKeyPath:@"userID"]; RKAttributeMapping *nameMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"name" toKeyPath:@"name"]; [userMapping addPropertyMapping:idMapping]; [userMapping addPropertyMapping:nameMapping]; RKRelationshipMapping *hasManyMapping = [RKRelationshipMapping relationshipMappingFromKeyPath:@"friends" toKeyPath:@"friends" withMapping:userMapping]; [userMapping addPropertyMapping:hasManyMapping]; RKMapperOperation *mapper = [RKMapperOperation new]; mapper.mappingOperationDataSource = [RKObjectMappingOperationDataSource new]; id userInfo = [RKTestFixture parsedObjectWithContentsOfFixture:@"user.json"]; RKTestUser *user = [RKTestUser user]; // Set the friends up RKTestUser *jeremy = [RKTestUser user]; jeremy.name = @"Jeremy Ellison"; jeremy.userID = [NSNumber numberWithInt:187]; RKTestUser *rachit = [RKTestUser user]; rachit.name = @"Rachit Shukla"; rachit.userID = [NSNumber numberWithInt:7]; user.friends = [NSArray arrayWithObjects:jeremy, rachit, nil]; id mockUser = [OCMockObject partialMockForObject:user]; [[mockUser reject] setFriends:OCMOCK_ANY]; [mapper mapRepresentation:userInfo toObject:mockUser atKeyPath:@"" usingMapping:userMapping metadata:nil]; [mockUser verify]; } - (void)testShouldOptionallyNilOutTheRelationshipIfItIsMissing { RKTestUser *user = [RKTestUser user]; RKTestAddress *address = [RKTestAddress address]; address.addressID = [NSNumber numberWithInt:1234]; user.address = address; id mockUser = [OCMockObject partialMockForObject:user]; [[mockUser expect] setAddress:nil]; RKObjectMapping *userMapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKAttributeMapping *nameMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"name" toKeyPath:@"name"]; [userMapping addPropertyMapping:nameMapping]; RKObjectMapping *addressMapping = [RKObjectMapping mappingForClass:[RKTestAddress class]]; RKAttributeMapping *idMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"id" toKeyPath:@"addressID"]; [addressMapping addPropertyMapping:idMapping]; RKRelationshipMapping *relationshipMapping = [RKRelationshipMapping relationshipMappingFromKeyPath:@"address" toKeyPath:@"address" withMapping:addressMapping]; [userMapping addPropertyMapping:relationshipMapping]; NSMutableDictionary *dictionary = [[RKTestFixture parsedObjectWithContentsOfFixture:@"user.json"] mutableCopy]; [dictionary removeObjectForKey:@"address"]; id mockMapping = [OCMockObject partialMockForObject:userMapping]; BOOL returnValue = YES; [[[mockMapping expect] andReturnValue:OCMOCK_VALUE(returnValue)] setNilForMissingRelationships]; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:dictionary destinationObject:mockUser mapping:mockMapping]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; operation.dataSource = dataSource; NSError *error = nil; [operation performMapping:&error]; [mockUser verify]; } - (void)testShouldNotNilOutTheRelationshipIfItIsMissingAndCurrentlyNilOnTheTargetObject { RKTestUser *user = [RKTestUser user]; user.address = nil; id mockUser = [OCMockObject partialMockForObject:user]; [[mockUser reject] setAddress:nil]; RKObjectMapping *userMapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKAttributeMapping *nameMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"name" toKeyPath:@"name"]; [userMapping addPropertyMapping:nameMapping]; RKObjectMapping *addressMapping = [RKObjectMapping mappingForClass:[RKTestAddress class]]; RKAttributeMapping *idMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"id" toKeyPath:@"addressID"]; [addressMapping addPropertyMapping:idMapping]; RKRelationshipMapping *relationshipMapping = [RKRelationshipMapping relationshipMappingFromKeyPath:@"address" toKeyPath:@"address" withMapping:addressMapping]; [userMapping addPropertyMapping:relationshipMapping]; NSMutableDictionary *dictionary = [[RKTestFixture parsedObjectWithContentsOfFixture:@"user.json"] mutableCopy]; [dictionary removeObjectForKey:@"address"]; id mockMapping = [OCMockObject partialMockForObject:userMapping]; BOOL returnValue = YES; [[[mockMapping expect] andReturnValue:OCMOCK_VALUE(returnValue)] setNilForMissingRelationships]; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:dictionary destinationObject:mockUser mapping:mockMapping]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; operation.dataSource = dataSource; NSError *error = nil; [operation performMapping:&error]; [mockUser verify]; } #pragma mark Assignment Policies - (void)testThatAttemptingToUnionOneToOneRelationshipGeneratesMappingError { RKTestUser *user = [RKTestUser new]; RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKObjectMapping *addressMapping = [RKObjectMapping mappingForClass:[RKTestAddress class]]; [mapping addAttributeMappingsFromArray:@[ @"name" ]]; RKRelationshipMapping *relationshipMapping = [RKRelationshipMapping relationshipMappingFromKeyPath:@"address" toKeyPath:@"address" withMapping:addressMapping]; relationshipMapping.assignmentPolicy = RKUnionAssignmentPolicy; [mapping addPropertyMapping:relationshipMapping]; NSDictionary *dictionary = @{ @"address": @{ @"city": @"NYC" } }; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:dictionary destinationObject:user mapping:mapping]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; operation.dataSource = dataSource; NSError *error = nil; [operation performMapping:&error]; expect(error).notTo.beNil(); expect(error.code).to.equal(RKMappingErrorInvalidAssignmentPolicy); expect([error localizedDescription]).to.equal(@"Invalid assignment policy: cannot union a one-to-one relationship."); } - (void)testUnionAssignmentPolicyWithSet { RKTestUser *user = [RKTestUser new]; RKTestUser *friend = [RKTestUser new]; friend.name = @"Jeff"; user.friendsSet = [NSSet setWithObject:friend]; RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; [mapping addAttributeMappingsFromArray:@[ @"name" ]]; RKRelationshipMapping *relationshipMapping = [RKRelationshipMapping relationshipMappingFromKeyPath:@"friendsSet" toKeyPath:@"friendsSet" withMapping:mapping]; relationshipMapping.assignmentPolicy = RKUnionAssignmentPolicy; [mapping addPropertyMapping:relationshipMapping]; NSDictionary *dictionary = @{ @"friendsSet": @[ @{ @"name": @"Zach" } ] }; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:dictionary destinationObject:user mapping:mapping]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; operation.dataSource = dataSource; NSError *error = nil; [operation performMapping:&error]; expect([user.friendsSet count]).to.equal(2); NSArray *names = [user.friendsSet valueForKey:@"name"]; assertThat(names, hasItems(@"Jeff", @"Zach", nil)); } - (void)testUnionAssignmentPolicyWithOrderedSet { RKTestUser *user = [RKTestUser new]; RKTestUser *friend = [RKTestUser new]; friend.name = @"Jeff"; user.friendsOrderedSet = [NSOrderedSet orderedSetWithObject:friend]; RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; [mapping addAttributeMappingsFromArray:@[ @"name" ]]; RKRelationshipMapping *relationshipMapping = [RKRelationshipMapping relationshipMappingFromKeyPath:@"friendsOrderedSet" toKeyPath:@"friendsOrderedSet" withMapping:mapping]; relationshipMapping.assignmentPolicy = RKUnionAssignmentPolicy; [mapping addPropertyMapping:relationshipMapping]; NSDictionary *dictionary = @{ @"friendsOrderedSet": @[ @{ @"name": @"Zach" } ] }; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:dictionary destinationObject:user mapping:mapping]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; operation.dataSource = dataSource; NSError *error = nil; [operation performMapping:&error]; expect([user.friendsOrderedSet count]).to.equal(2); NSArray *names = [user.friendsOrderedSet valueForKey:@"name"]; assertThat(names, hasItems(@"Jeff", @"Zach", nil)); } - (void)testUnionAssignmentPolicyWithArray { RKTestUser *user = [RKTestUser new]; RKTestUser *friend = [RKTestUser new]; friend.name = @"Jeff"; user.friends = [NSArray arrayWithObject:friend]; RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; [mapping addAttributeMappingsFromArray:@[ @"name" ]]; RKRelationshipMapping *relationshipMapping = [RKRelationshipMapping relationshipMappingFromKeyPath:@"friends" toKeyPath:@"friends" withMapping:mapping]; relationshipMapping.assignmentPolicy = RKUnionAssignmentPolicy; [mapping addPropertyMapping:relationshipMapping]; NSDictionary *dictionary = @{ @"friends": @[ @{ @"name": @"Zach" } ] }; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:dictionary destinationObject:user mapping:mapping]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; operation.dataSource = dataSource; NSError *error = nil; [operation performMapping:&error]; expect([user.friends count]).to.equal(2); NSArray *names = [user.friends valueForKey:@"name"]; assertThat(names, hasItems(@"Jeff", @"Zach", nil)); } - (void)testUnionAssignmentPolicyWithNilValue { RKTestUser *user = [RKTestUser new]; user.friends = nil; RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; [mapping addAttributeMappingsFromArray:@[ @"name" ]]; RKRelationshipMapping *relationshipMapping = [RKRelationshipMapping relationshipMappingFromKeyPath:@"friends" toKeyPath:@"friends" withMapping:mapping]; relationshipMapping.assignmentPolicy = RKUnionAssignmentPolicy; [mapping addPropertyMapping:relationshipMapping]; NSDictionary *dictionary = @{ @"friends": @[ @{ @"name": @"Zach" } ] }; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:dictionary destinationObject:user mapping:mapping]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; operation.dataSource = dataSource; NSError *error = nil; [operation performMapping:&error]; expect([user.friends count]).to.equal(1); NSArray *names = [user.friends valueForKey:@"name"]; assertThat(names, hasItems(@"Zach", nil)); } - (void)testReplacementPolicyForUnmanagedRelationship { RKTestUser *user = [RKTestUser new]; RKTestUser *friend = [RKTestUser new]; friend.name = @"Jeff"; user.friends = [NSArray arrayWithObject:friend]; RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; [mapping addAttributeMappingsFromArray:@[ @"name" ]]; RKRelationshipMapping *relationshipMapping = [RKRelationshipMapping relationshipMappingFromKeyPath:@"friends" toKeyPath:@"friends" withMapping:mapping]; relationshipMapping.assignmentPolicy = RKReplaceAssignmentPolicy; [mapping addPropertyMapping:relationshipMapping]; NSDictionary *dictionary = @{ @"friends": @[ @{ @"name": @"Zach" } ] }; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:dictionary destinationObject:user mapping:mapping]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; operation.dataSource = dataSource; NSError *error = nil; [operation performMapping:&error]; expect([user.friends count]).to.equal(1); NSArray *names = [user.friends valueForKey:@"name"]; assertThat(names, hasItems(@"Zach", nil)); } - (void)testReplacmentPolicyForToManyCoreDataRelationshipDeletesExistingValues { RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore]; RKHuman *human = [NSEntityDescription insertNewObjectForEntityForName:@"Human" inManagedObjectContext:managedObjectStore.mainQueueManagedObjectContext]; RKCat *existingCat = [NSEntityDescription insertNewObjectForEntityForName:@"Cat" inManagedObjectContext:managedObjectStore.mainQueueManagedObjectContext]; existingCat.name = @"Lola"; human.cats = [NSSet setWithObject:existingCat]; RKEntityMapping *entityMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore]; [entityMapping addAttributeMappingsFromArray:@[ @"name" ]]; RKEntityMapping *catMapping = [RKEntityMapping mappingForEntityForName:@"Cat" inManagedObjectStore:managedObjectStore]; [catMapping addAttributeMappingsFromArray:@[ @"name" ]]; catMapping.identificationAttributes = @[ @"name" ]; RKRelationshipMapping *relationshipMapping = [RKRelationshipMapping relationshipMappingFromKeyPath:@"cats" toKeyPath:@"cats" withMapping:catMapping]; relationshipMapping.assignmentPolicy = RKReplaceAssignmentPolicy; [entityMapping addPropertyMapping:relationshipMapping]; NSDictionary *dictionary = @{ @"name": @"Blake", @"cats": @[ @{ @"name": @"Roy" } ] }; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:dictionary destinationObject:human mapping:entityMapping]; RKManagedObjectMappingOperationDataSource *dataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.mainQueueManagedObjectContext cache:nil]; operation.dataSource = dataSource; NSError *error = nil; [operation performMapping:&error]; expect([human.cats count]).to.equal(1); NSArray *names = [human.cats valueForKey:@"name"]; assertThat(names, hasItems(@"Roy", nil)); expect([existingCat isDeleted]).to.equal(YES); } - (void)testReplacmentPolicyForToOneCoreDataRelationshipDeletesExistingValues { RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore]; RKHuman *human = [NSEntityDescription insertNewObjectForEntityForName:@"Human" inManagedObjectContext:managedObjectStore.mainQueueManagedObjectContext]; RKCat *existingCat = [NSEntityDescription insertNewObjectForEntityForName:@"Cat" inManagedObjectContext:managedObjectStore.mainQueueManagedObjectContext]; existingCat.name = @"Lola"; human.favoriteCat = existingCat; RKEntityMapping *entityMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore]; [entityMapping addAttributeMappingsFromArray:@[ @"name" ]]; RKEntityMapping *catMapping = [RKEntityMapping mappingForEntityForName:@"Cat" inManagedObjectStore:managedObjectStore]; [catMapping addAttributeMappingsFromArray:@[ @"name" ]]; catMapping.identificationAttributes = @[ @"name" ]; RKRelationshipMapping *relationshipMapping = [RKRelationshipMapping relationshipMappingFromKeyPath:@"favoriteCat" toKeyPath:@"favoriteCat" withMapping:catMapping]; relationshipMapping.assignmentPolicy = RKReplaceAssignmentPolicy; [entityMapping addPropertyMapping:relationshipMapping]; NSDictionary *dictionary = @{ @"name": @"Blake", @"favoriteCat": @{ @"name": @"Roy" } }; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:dictionary destinationObject:human mapping:entityMapping]; RKManagedObjectMappingOperationDataSource *dataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.mainQueueManagedObjectContext cache:nil]; operation.dataSource = dataSource; NSError *error = nil; [operation performMapping:&error]; expect(human.favoriteCat.name).to.equal(@"Roy"); expect([existingCat isDeleted]).to.equal(YES); } #pragma mark - RKDynamicMapping - (void)testShouldMapASingleObjectDynamically { RKObjectMapping *boyMapping = [RKObjectMapping mappingForClass:[Boy class]]; [boyMapping addAttributeMappingsFromArray:@[@"name"]]; RKObjectMapping *girlMapping = [RKObjectMapping mappingForClass:[Girl class]]; [girlMapping addAttributeMappingsFromArray:@[@"name"]]; RKDynamicMapping *dynamicMapping = [RKDynamicMapping new]; [dynamicMapping setObjectMappingForRepresentationBlock:^RKObjectMapping *(id representation) { if ([[representation valueForKey:@"type"] isEqualToString:@"Boy"]) { return boyMapping; } else if ([[representation valueForKey:@"type"] isEqualToString:@"Girl"]) { return girlMapping; } return nil; }]; NSMutableDictionary *mappingsDictionary = [NSMutableDictionary dictionary]; [mappingsDictionary setObject:dynamicMapping forKey:[NSNull null]]; id userInfo = [RKTestFixture parsedObjectWithContentsOfFixture:@"boy.json"]; RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:userInfo mappingsDictionary:mappingsDictionary]; [mapper start]; Boy *user = [mapper.mappingResult firstObject]; assertThat(user, is(instanceOf([Boy class]))); assertThat(user.name, is(equalTo(@"Blake Watters"))); } - (void)testShouldMapASingleObjectDynamicallyWithADeclarativeMatcher { RKObjectMapping *boyMapping = [RKObjectMapping mappingForClass:[Boy class]]; [boyMapping addAttributeMappingsFromArray:@[@"name"]]; RKObjectMapping *girlMapping = [RKObjectMapping mappingForClass:[Girl class]]; [girlMapping addAttributeMappingsFromArray:@[@"name"]]; RKDynamicMapping *dynamicMapping = [RKDynamicMapping new]; [dynamicMapping addMatcher:[RKObjectMappingMatcher matcherWithKeyPath:@"type" expectedValue:@"Boy" objectMapping:boyMapping]]; [dynamicMapping addMatcher:[RKObjectMappingMatcher matcherWithKeyPath:@"type" expectedValue:@"Girl" objectMapping:girlMapping]]; NSMutableDictionary *mappingsDictionary = [NSMutableDictionary dictionary]; [mappingsDictionary setObject:dynamicMapping forKey:[NSNull null]]; id userInfo = [RKTestFixture parsedObjectWithContentsOfFixture:@"boy.json"]; RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:userInfo mappingsDictionary:mappingsDictionary]; [mapper start]; Boy *user = [mapper.mappingResult firstObject]; assertThat(user, is(instanceOf([Boy class]))); assertThat(user.name, is(equalTo(@"Blake Watters"))); } - (void)testShouldACollectionOfObjectsDynamically { RKObjectMapping *boyMapping = [RKObjectMapping mappingForClass:[Boy class]]; [boyMapping addAttributeMappingsFromArray:@[@"name"]]; RKObjectMapping *girlMapping = [RKObjectMapping mappingForClass:[Girl class]]; [girlMapping addAttributeMappingsFromArray:@[@"name"]]; RKDynamicMapping *dynamicMapping = [RKDynamicMapping new]; [dynamicMapping addMatcher:[RKObjectMappingMatcher matcherWithKeyPath:@"type" expectedValue:@"Boy" objectMapping:boyMapping]]; [dynamicMapping addMatcher:[RKObjectMappingMatcher matcherWithKeyPath:@"type" expectedValue:@"Girl" objectMapping:girlMapping]]; NSMutableDictionary *mappingsDictionary = [NSMutableDictionary dictionary]; [mappingsDictionary setObject:dynamicMapping forKey:[NSNull null]]; id userInfo = [RKTestFixture parsedObjectWithContentsOfFixture:@"mixed.json"]; RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:userInfo mappingsDictionary:mappingsDictionary]; [mapper start]; NSArray *objects = [mapper.mappingResult array]; expect(objects).to.haveCountOf(2); expect(objects[0]).to.beInstanceOf([Boy class]); expect(objects[1]).to.beInstanceOf([Girl class]); Boy *boy = [objects objectAtIndex:0]; Girl *girl = [objects objectAtIndex:1]; expect(boy.name).to.equal(@"Blake Watters"); expect(girl.name).to.equal(@"Sarah"); } - (void)testShouldMapARelationshipDynamically { RKObjectMapping *boyMapping = [RKObjectMapping mappingForClass:[Boy class]]; [boyMapping addAttributeMappingsFromArray:@[@"name"]]; RKObjectMapping *girlMapping = [RKObjectMapping mappingForClass:[Girl class]]; [girlMapping addAttributeMappingsFromArray:@[@"name"]]; RKDynamicMapping *dynamicMapping = [RKDynamicMapping new]; [dynamicMapping addMatcher:[RKObjectMappingMatcher matcherWithKeyPath:@"type" expectedValue:@"Boy" objectMapping:boyMapping]]; [dynamicMapping addMatcher:[RKObjectMappingMatcher matcherWithKeyPath:@"type" expectedValue:@"Girl" objectMapping:girlMapping]]; [boyMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"friends" toKeyPath:@"friends" withMapping:dynamicMapping]];; NSMutableDictionary *mappingsDictionary = [NSMutableDictionary dictionary]; [mappingsDictionary setObject:dynamicMapping forKey:[NSNull null]]; id userInfo = [RKTestFixture parsedObjectWithContentsOfFixture:@"friends.json"]; RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:userInfo mappingsDictionary:mappingsDictionary]; [mapper start]; Boy *blake = [mapper.mappingResult firstObject]; NSArray *friends = blake.friends; assertThat(friends, hasCountOf(2)); assertThat([friends objectAtIndex:0], is(instanceOf([Boy class]))); assertThat([friends objectAtIndex:1], is(instanceOf([Girl class]))); Boy *boy = [friends objectAtIndex:0]; Girl *girl = [friends objectAtIndex:1]; assertThat(boy.name, is(equalTo(@"John Doe"))); assertThat(girl.name, is(equalTo(@"Jane Doe"))); } - (void)testShouldBeAbleToDeclineMappingAnObjectByReturningANilObjectMapping { RKObjectMapping *boyMapping = [RKObjectMapping mappingForClass:[Boy class]]; [boyMapping addAttributeMappingsFromArray:@[@"name"]]; RKObjectMapping *girlMapping = [RKObjectMapping mappingForClass:[Girl class]]; [girlMapping addAttributeMappingsFromArray:@[@"name"]]; RKDynamicMapping *dynamicMapping = [RKDynamicMapping new]; [dynamicMapping setObjectMappingForRepresentationBlock:^RKObjectMapping *(id representation) { if ([[representation valueForKey:@"type"] isEqualToString:@"Boy"]) { return boyMapping; } else if ([[representation valueForKey:@"type"] isEqualToString:@"Girl"]) { // NO GIRLS ALLOWED(*$!)(* return nil; } return nil; }]; NSMutableDictionary *mappingsDictionary = [NSMutableDictionary dictionary]; [mappingsDictionary setObject:dynamicMapping forKey:[NSNull null]]; id userInfo = [RKTestFixture parsedObjectWithContentsOfFixture:@"mixed.json"]; RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:userInfo mappingsDictionary:mappingsDictionary]; [mapper start]; NSArray *boys = [mapper.mappingResult array]; assertThat(boys, hasCountOf(1)); Boy *user = [boys objectAtIndex:0]; assertThat(user, is(instanceOf([Boy class]))); assertThat(user.name, is(equalTo(@"Blake Watters"))); } - (void)testShouldBeAbleToDeclineMappingObjectsInARelationshipByReturningANilObjectMapping { RKObjectMapping *boyMapping = [RKObjectMapping mappingForClass:[Boy class]]; [boyMapping addAttributeMappingsFromArray:@[@"name"]]; RKObjectMapping *girlMapping = [RKObjectMapping mappingForClass:[Girl class]]; [girlMapping addAttributeMappingsFromArray:@[@"name"]]; RKDynamicMapping *dynamicMapping = [RKDynamicMapping new]; [dynamicMapping setObjectMappingForRepresentationBlock:^RKObjectMapping *(id representation) { if ([[representation valueForKey:@"type"] isEqualToString:@"Boy"]) { return boyMapping; } else if ([[representation valueForKey:@"type"] isEqualToString:@"Girl"]) { // NO GIRLS ALLOWED(*$!)(* return nil; } return nil; }]; [boyMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"friends" toKeyPath:@"friends" withMapping:dynamicMapping]];; NSMutableDictionary *mappingsDictionary = [NSMutableDictionary dictionary]; [mappingsDictionary setObject:dynamicMapping forKey:[NSNull null]]; id userInfo = [RKTestFixture parsedObjectWithContentsOfFixture:@"friends.json"]; RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:userInfo mappingsDictionary:mappingsDictionary]; [mapper start]; Boy *blake = [mapper.mappingResult firstObject]; assertThat(blake, is(notNilValue())); assertThat(blake.name, is(equalTo(@"Blake Watters"))); assertThat(blake, is(instanceOf([Boy class]))); NSArray *friends = blake.friends; assertThat(friends, hasCountOf(1)); assertThat([friends objectAtIndex:0], is(instanceOf([Boy class]))); Boy *boy = [friends objectAtIndex:0]; assertThat(boy.name, is(equalTo(@"John Doe"))); } - (void)testShouldMapATargetObjectWithADynamicMapping { RKObjectMapping *boyMapping = [RKObjectMapping mappingForClass:[Boy class]]; [boyMapping addAttributeMappingsFromArray:@[@"name"]]; RKDynamicMapping *dynamicMapping = [RKDynamicMapping new]; [dynamicMapping setObjectMappingForRepresentationBlock:^RKObjectMapping *(id representation) { if ([[representation valueForKey:@"type"] isEqualToString:@"Boy"]) { return boyMapping; } return nil; }]; NSMutableDictionary *mappingsDictionary = [NSMutableDictionary dictionary]; [mappingsDictionary setObject:dynamicMapping forKey:[NSNull null]]; id userInfo = [RKTestFixture parsedObjectWithContentsOfFixture:@"boy.json"]; Boy *blake = [Boy new]; RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:userInfo mappingsDictionary:mappingsDictionary]; mapper.targetObject = blake; [mapper start]; Boy *user = [mapper.mappingResult firstObject]; assertThat(user, is(instanceOf([Boy class]))); assertThat(user.name, is(equalTo(@"Blake Watters"))); } - (void)testShouldFailWithAnErrorIfATargetObjectIsProvidedAndTheDynamicMappingReturnsNil { RKObjectMapping *boyMapping = [RKObjectMapping mappingForClass:[Boy class]]; [boyMapping addAttributeMappingsFromArray:@[@"name"]]; RKDynamicMapping *dynamicMapping = [RKDynamicMapping new]; [dynamicMapping setObjectMappingForRepresentationBlock:^RKObjectMapping *(id representation) { return nil; }]; NSMutableDictionary *mappingsDictionary = [NSMutableDictionary dictionary]; [mappingsDictionary setObject:dynamicMapping forKey:[NSNull null]]; id userInfo = [RKTestFixture parsedObjectWithContentsOfFixture:@"boy.json"]; Boy *blake = [Boy new]; RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:userInfo mappingsDictionary:mappingsDictionary]; mapper.targetObject = blake; [mapper start]; Boy *user = [mapper.mappingResult firstObject]; assertThat(user, is(nilValue())); assertThat(mapper.error, is(notNilValue())); } - (void)testShouldFailWithAnErrorIfATargetObjectIsProvidedAndTheDynamicMappingReturnsTheIncorrectType { RKObjectMapping *girlMapping = [RKObjectMapping mappingForClass:[Girl class]]; [girlMapping addAttributeMappingsFromArray:@[@"name"]]; RKDynamicMapping *dynamicMapping = [RKDynamicMapping new]; [dynamicMapping setObjectMappingForRepresentationBlock:^RKObjectMapping *(id representation) { if ([[representation valueForKey:@"type"] isEqualToString:@"Girl"]) { return girlMapping; } return nil; }]; NSMutableDictionary *mappingsDictionary = [NSMutableDictionary dictionary]; [mappingsDictionary setObject:dynamicMapping forKey:[NSNull null]]; id userInfo = [RKTestFixture parsedObjectWithContentsOfFixture:@"girl.json"]; Boy *blake = [Boy new]; RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:userInfo mappingsDictionary:mappingsDictionary]; mapper.targetObject = blake; [mapper start]; Boy *user = [mapper.mappingResult firstObject]; assertThat(user, is(nilValue())); assertThat(mapper.error, is(notNilValue())); } #pragma mark - Date and Time Formatting - (void)testShouldAutoConfigureDefaultDateFormatters { [RKObjectMapping resetDefaultDateFormatters]; NSArray *dateFormatters = [RKObjectMapping defaultDateFormatters]; expect(dateFormatters).to.haveCountOf(5); expect([dateFormatters[0] dateFormat]).to.equal(@"yyyy-MM-dd"); expect([dateFormatters[1] dateFormat]).to.equal(@"yyyy-MM-dd'T'HH:mm:ss'Z'"); expect([dateFormatters[2] dateFormat]).to.equal(@"MM/dd/yyyy"); NSTimeZone *UTCTimeZone = [NSTimeZone timeZoneWithAbbreviation:@"UTC"]; expect([[dateFormatters objectAtIndex:0] timeZone]).to.equal(UTCTimeZone); expect([[dateFormatters objectAtIndex:1] timeZone]).to.equal(UTCTimeZone); expect([[dateFormatters objectAtIndex:2] timeZone]).to.equal(UTCTimeZone); } - (void)testShouldLetYouSetTheDefaultDateFormatters { NSDateFormatter *dateFormatter = [NSDateFormatter new]; NSArray *dateFormatters = [NSArray arrayWithObject:dateFormatter]; [RKObjectMapping setDefaultDateFormatters:dateFormatters]; assertThat([RKObjectMapping defaultDateFormatters], is(equalTo(dateFormatters))); } - (void)testShouldLetYouAppendADateFormatterToTheList { [RKObjectMapping resetDefaultDateFormatters]; assertThat([RKObjectMapping defaultDateFormatters], hasCountOf(5)); NSDateFormatter *dateFormatter = [NSDateFormatter new]; [RKObjectMapping addDefaultDateFormatter:dateFormatter]; assertThat([RKObjectMapping defaultDateFormatters], hasCountOf(6)); } - (void)testShouldAllowNewlyAddedDateFormatterToRunFirst { [RKObjectMapping setDefaultDateFormatters:nil]; NSDateFormatter *newDateFormatter = [NSDateFormatter new]; [newDateFormatter setDateFormat:@"dd/MM/yyyy"]; [RKObjectMapping addDefaultDateFormatter:newDateFormatter]; RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKAttributeMapping *birthDateMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"favorite_date" toKeyPath:@"favoriteDate"]; [mapping addPropertyMapping:birthDateMapping]; NSDictionary *dictionary = [RKTestFixture parsedObjectWithContentsOfFixture:@"user.json"]; RKTestUser *user = [RKTestUser user]; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:dictionary destinationObject:user mapping:mapping]; NSError *error = nil; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; operation.dataSource = dataSource; [operation performMapping:&error]; NSDateFormatter *dateFormatter = [NSDateFormatter new]; [dateFormatter setDateFormat:@"MM/dd/yyyy"]; /* If RKObjectMappingOperation is using the date formatter set above, we're going to get a really wonky date, which is what we are testing for. */ assertThat([dateFormatter stringFromDate:user.favoriteDate], is(equalTo(@"01/03/2012"))); } - (void)testShouldLetYouConfigureANewDateFormatterFromAStringAndATimeZone { [RKObjectMapping resetDefaultDateFormatters]; assertThat([RKObjectMapping defaultDateFormatters], hasCountOf(5)); NSTimeZone *EDTTimeZone = [NSTimeZone timeZoneWithAbbreviation:@"EDT"]; [RKObjectMapping addDefaultDateFormatterForString:@"mm/dd/YYYY" inTimeZone:EDTTimeZone]; assertThat([RKObjectMapping defaultDateFormatters], hasCountOf(6)); NSDateFormatter *dateFormatter = [[RKObjectMapping defaultDateFormatters] objectAtIndex:0]; assertThat(dateFormatter.timeZone, is(equalTo(EDTTimeZone))); } - (void)testShouldReturnNilForEmptyDateValues { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKAttributeMapping *birthDateMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"birthdate" toKeyPath:@"birthDate"]; [mapping addPropertyMapping:birthDateMapping]; NSDictionary *dictionary = [RKTestFixture parsedObjectWithContentsOfFixture:@"user.json"]; NSMutableDictionary *mutableDictionary = [dictionary mutableCopy]; [mutableDictionary setValue:@"" forKey:@"birthdate"]; RKTestUser *user = [RKTestUser user]; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:mutableDictionary destinationObject:user mapping:mapping]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; operation.dataSource = dataSource; NSError *error = nil; [operation performMapping:&error]; assertThat(user.birthDate, is(equalTo(nil))); } - (void)testShouldConfigureANewDateFormatterInTheUTCTimeZoneIfPassedANilTimeZone { [RKObjectMapping resetDefaultDateFormatters]; assertThat([RKObjectMapping defaultDateFormatters], hasCountOf(5)); [RKObjectMapping addDefaultDateFormatterForString:@"mm/dd/YYYY" inTimeZone:nil]; assertThat([RKObjectMapping defaultDateFormatters], hasCountOf(6)); NSDateFormatter *dateFormatter = [[RKObjectMapping defaultDateFormatters] objectAtIndex:0]; NSTimeZone *UTCTimeZone = [NSTimeZone timeZoneWithAbbreviation:@"UTC"]; assertThat(dateFormatter.timeZone, is(equalTo(UTCTimeZone))); } - (void)testShouldEnsureRailsDatesAreParsedInUTCTimeZone { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; RKAttributeMapping *birthDateMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"birthdate" toKeyPath:@"birthDate"]; [mapping addPropertyMapping:birthDateMapping]; NSDictionary *dictionary = [RKTestFixture parsedObjectWithContentsOfFixture:@"user.json"]; NSMutableDictionary *mutableDictionary = [dictionary mutableCopy]; [mutableDictionary setValue:@"2012-03-01" forKey:@"birthdate"]; RKTestUser *user = [RKTestUser user]; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:mutableDictionary destinationObject:user mapping:mapping]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; operation.dataSource = dataSource; NSError *error = nil; [operation performMapping:&error]; NSDateComponents *components = [[NSDateComponents alloc] init]; components.year = 2012; components.month = 3; components.day = 1; components.timeZone = [NSTimeZone timeZoneWithName:@"UTC"]; NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; NSDate *date = [calendar dateFromComponents:components]; expect(user.birthDate).to.equal(date); } #pragma mark - Misc - (void)testUpdatingArrayOfExistingCats { RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore]; NSArray *array = [RKTestFixture parsedObjectWithContentsOfFixture:@"ArrayOfHumans.json"]; RKEntityMapping *humanMapping = [RKEntityMapping mappingForEntityForName:@"Human" inManagedObjectStore:managedObjectStore]; [humanMapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:@"id" toKeyPath:@"railsID"]]; humanMapping.identificationAttributes = @[ @"railsID" ]; NSMutableDictionary *mappingsDictionary = [NSMutableDictionary dictionary]; [mappingsDictionary setObject:humanMapping forKey:@"human"]; // Create instances that should match the fixture RKHuman *human1 = [NSEntityDescription insertNewObjectForEntityForName:@"Human" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext]; human1.railsID = [NSNumber numberWithInt:201]; RKHuman *human2 = [NSEntityDescription insertNewObjectForEntityForName:@"Human" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext]; human2.railsID = [NSNumber numberWithInt:202]; [managedObjectStore.persistentStoreManagedObjectContext save:nil]; RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:array mappingsDictionary:mappingsDictionary]; RKFetchRequestManagedObjectCache *managedObjectCache = [[RKFetchRequestManagedObjectCache alloc] init]; mapper.mappingOperationDataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext cache:managedObjectCache]; [mapper start]; RKMappingResult *result = mapper.mappingResult; assertThat(result, is(notNilValue())); NSArray *humans = [result array]; assertThat(humans, hasCountOf(2)); assertThat([humans objectAtIndex:0], is(equalTo(human1))); assertThat([humans objectAtIndex:1], is(equalTo(human2))); } - (void)testMappingMultipleKeyPathsAtRootOfObject { RKObjectMapping *mapping1 = [RKObjectMapping mappingForClass:[RKTestUser class]]; [mapping1 addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:@"prodId" toKeyPath:@"userID"]]; RKObjectMapping *mapping2 = [RKObjectMapping mappingForClass:[RKTestUser class]]; [mapping2 addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:@"catId" toKeyPath:@"userID"]]; NSDictionary *dictionary = [RKTestFixture parsedObjectWithContentsOfFixture:@"SameKeyDifferentTargetClasses.json"]; RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:dictionary mappingsDictionary:@{ @"products": mapping1, @"categories": mapping2 }]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; mapper.mappingOperationDataSource = dataSource; [mapper start]; expect(mapper.error).to.beNil(); expect(mapper.mappingResult).notTo.beNil(); expect([mapper.mappingResult array]).to.haveCountOf(4); } - (void)testAggregatingPropertyMappingUsingNilKeyPath { NSDictionary *objectRepresentation = @{ @"name": @"Blake", @"latitude": @(125.55), @"longitude": @(200.5) }; RKObjectMapping *userMapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; [userMapping addAttributeMappingsFromArray:@[ @"name" ]]; RKObjectMapping *coordinateMapping = [RKObjectMapping mappingForClass:[RKTestCoordinate class]]; [coordinateMapping addAttributeMappingsFromArray:@[ @"latitude", @"longitude" ]]; [userMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:nil toKeyPath:@"coordinate" withMapping:coordinateMapping]]; RKTestUser *user = [RKTestUser new]; RKMappingOperation *mappingOperation = [[RKMappingOperation alloc] initWithSourceObject:objectRepresentation destinationObject:user mapping:userMapping]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; mappingOperation.dataSource = dataSource; [mappingOperation start]; expect(mappingOperation.error).to.beNil(); expect(user.coordinate).notTo.beNil(); expect(user.coordinate.latitude).to.equal(125.55); expect(user.coordinate.longitude).to.equal(200.5); } - (void)testThatAggregatedRelationshipMappingsAreOnlyAppliedIfThereIsAtLeastOneValueInTheRepresentation { NSDictionary *objectRepresentation = @{ @"name": @"Blake" }; RKObjectMapping *userMapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; [userMapping addAttributeMappingsFromArray:@[ @"name" ]]; RKObjectMapping *coordinateMapping = [RKObjectMapping mappingForClass:[RKTestCoordinate class]]; [coordinateMapping addAttributeMappingsFromArray:@[ @"latitude", @"longitude" ]]; [userMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:nil toKeyPath:@"coordinate" withMapping:coordinateMapping]]; RKTestUser *user = [RKTestUser new]; RKMappingOperation *mappingOperation = [[RKMappingOperation alloc] initWithSourceObject:objectRepresentation destinationObject:user mapping:userMapping]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; mappingOperation.dataSource = dataSource; [mappingOperation start]; expect(mappingOperation.error).to.beNil(); expect(user.coordinate).to.beNil(); } #pragma mark - Metadata Mapping - (void)testMappingURLFromMetadata { NSDictionary *objectRepresentation = @{ @"name": @"Blake Watters" }; NSDictionary *metadata = @{ @"HTTP": @{ @"request": @{ @"URL": [NSURL URLWithString:@"http://restkit.org/"] } } }; RKObjectMapping *userMapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; [userMapping addAttributeMappingsFromDictionary:@{ @"name": @"name", @"@metadata.HTTP.request.URL": @"website" }]; RKTestUser *user = [RKTestUser new]; RKMappingOperation *mappingOperation = [[RKMappingOperation alloc] initWithSourceObject:objectRepresentation destinationObject:user mapping:userMapping]; mappingOperation.metadata = metadata; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; mappingOperation.dataSource = dataSource; [mappingOperation start]; expect(mappingOperation.error).to.beNil(); expect(user.name).to.equal(@"Blake Watters"); expect([user.website absoluteString]).to.equal(@"http://restkit.org/"); } - (void)testMappingHeadersFromMetadata { NSDictionary *objectRepresentation = @{ @"name": @"Blake Watters" }; NSDictionary *metadata = @{ @"HTTP": @{ @"request": @{ @"headers": @{ @"Content-Type": @"text/html; charset=UTF-8" } } } }; RKObjectMapping *userMapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; [userMapping addAttributeMappingsFromDictionary:@{ @"name": @"name", @"@metadata.HTTP.request.headers.Content-Type": @"emailAddress" }]; RKTestUser *user = [RKTestUser new]; RKMappingOperation *mappingOperation = [[RKMappingOperation alloc] initWithSourceObject:objectRepresentation destinationObject:user mapping:userMapping]; mappingOperation.metadata = metadata; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; mappingOperation.dataSource = dataSource; [mappingOperation start]; expect(mappingOperation.error).to.beNil(); expect(user.name).to.equal(@"Blake Watters"); expect(user.emailAddress).to.equal(@"text/html; charset=UTF-8"); } - (void)testMappingCollectionIndexFromRelationship { // Do same as above, but use the "friends" relationship NSDictionary *objectRepresentation = @{ @"name": @"Blake Watters", @"friends": @[ @{ @"name": @"Jeff Arena" } ] }; RKObjectMapping *userMapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; [userMapping addAttributeMappingsFromDictionary:@{ @"name": @"name", @"@metadata.mapping.collectionIndex": @"userID" }]; [userMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"friends" toKeyPath:@"friendsSet" withMapping:userMapping]]; RKTestUser *user = [RKTestUser new]; RKMappingOperation *mappingOperation = [[RKMappingOperation alloc] initWithSourceObject:objectRepresentation destinationObject:user mapping:userMapping]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; mappingOperation.dataSource = dataSource; [mappingOperation start]; expect(mappingOperation.error).to.beNil(); expect(user.name).to.equal(@"Blake Watters"); expect(user.friendsSet).to.haveCountOf(1); RKTestUser *jeff = [user.friendsSet anyObject]; expect(jeff.name).to.equal(@"Jeff Arena"); expect(jeff.userID).notTo.beNil(); expect(jeff.userID).to.equal(0); } - (void)testMappingCollectionIndexFromMapperOperation { NSArray *representations = @[ @{ @"name": @"Blake Watters" }, @{ @"name": @"Jeff Arena" }, @{ @"name": @"Dan Gellert" }, @{ @"name": @"Zachary Einzig" } ]; RKObjectMapping *userMapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; [userMapping addAttributeMappingsFromDictionary:@{ @"name": @"name", @"@metadata.mapping.collectionIndex": @"position" }]; RKMapperOperation *mapperOperation = [[RKMapperOperation alloc] initWithRepresentation:representations mappingsDictionary:@{ [NSNull null]: userMapping }]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; mapperOperation.mappingOperationDataSource = dataSource; NSError *error = nil; [mapperOperation execute:&error]; NSArray *users = [mapperOperation.mappingResult array]; expect(error).to.beNil(); expect(users).to.haveCountOf(4); NSArray *expectedUsers = @[ @"Blake Watters", @"Jeff Arena", @"Dan Gellert", @"Zachary Einzig" ]; [expectedUsers enumerateObjectsUsingBlock:^(NSString *name, NSUInteger index, BOOL *stop) { RKTestUser *user = [users objectAtIndex:index]; expect(user.name).to.equal(name); expect(user.position).to.equal(index); }]; } - (void)testMetadataIsMerged { NSArray *representations = @[ @{ @"name": @"Blake Watters" } ]; RKObjectMapping *userMapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; [userMapping addAttributeMappingsFromDictionary:@{ @"name": @"name", @"@metadata.mapping.collectionIndex": @"position", @"@metadata.mapping.country": @"country" }]; RKMapperOperation *mapperOperation = [[RKMapperOperation alloc] initWithRepresentation:representations mappingsDictionary:@{ [NSNull null]: userMapping }]; mapperOperation.metadata = @{ @"mapping": @{ @"country": @"United States of America" } }; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; mapperOperation.mappingOperationDataSource = dataSource; NSError *error = nil; [mapperOperation execute:&error]; RKTestUser *user = [mapperOperation.mappingResult firstObject]; expect(error).to.beNil(); expect(user.name).to.equal(@"Blake Watters"); expect(user.position).to.equal(0); expect(user.country).to.equal(@"United States of America"); } // RKResponseMapperOperation sets up Metadata for HTTP request/response // RKMapperOperation sets up mapping.rootKey, also collectionIndex for outer arrays @end