// // RKObjectMappingTest.m // RestKit // // Created by Blake Watters on 6/8/12. // Copyright (c) 2012 RestKit. All rights reserved. // #import "RKTestEnvironment.h" #import "RKTestUser.h" #import "RKObjectMappingOperationDataSource.h" @interface RKObjectMappingTest : RKTestCase @end @implementation RKObjectMappingTest - (void)tearDown { [RKObjectMapping setDefaultSourceToDestinationKeyTransformationBlock:nil]; } - (void)testThatTwoMappingsWithTheSameAttributeMappingsButDifferentObjectClassesAreNotConsideredEqual { RKObjectMapping *mapping1 = [RKObjectMapping mappingForClass:[NSString class]]; RKObjectMapping *mapping2 = [RKObjectMapping mappingForClass:[NSNumber class]]; assertThatBool([mapping1 isEqualToMapping:mapping2], is(equalToBool(NO))); } - (void)testThatTwoMappingsForNilObjectClassAreConsideredEqual { RKObjectMapping *mapping1 = [RKObjectMapping mappingForClass:nil]; RKObjectMapping *mapping2 = [RKObjectMapping mappingForClass:nil]; assertThatBool([mapping1 isEqualToMapping:mapping2], is(equalToBool(YES))); } - (void)testThatTwoMappingsAreNotConsideredEqualIfOneHasNilObjectClass { RKObjectMapping *mapping1 = [RKObjectMapping mappingForClass:nil]; RKObjectMapping *mapping2 = [RKObjectMapping mappingForClass:[NSString class]]; assertThatBool([mapping1 isEqualToMapping:mapping2], is(equalToBool(NO))); } - (void)testThatRelationshipMappingsWithTheSameObjectClassAndNoAttributesAreConsideredEqual { RKObjectMapping *mapping1 = [RKObjectMapping mappingForClass:[NSString class]]; RKObjectMapping *mapping2 = [RKObjectMapping mappingForClass:[NSString class]]; assertThatBool([mapping1 isEqualToMapping:mapping2], is(equalToBool(YES))); } - (void)testThatTwoMappingsForTheSameObjectClassContainingIdenticalAttributeMappingsAreConsideredEqual { RKObjectMapping *mapping1 = [RKObjectMapping mappingForClass:[NSString class]]; [mapping1 addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:@"this" toKeyPath:@"that"]]; RKObjectMapping *mapping2 = [RKObjectMapping mappingForClass:[NSString class]]; [mapping2 addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:@"this" toKeyPath:@"that"]]; assertThatBool([mapping1 isEqualToMapping:mapping2], is(equalToBool(YES))); } - (void)testThatTwoMappingsForTheSameObjectClassContainingDifferingAttributeMappingsAreNotConsideredEqual { RKObjectMapping *mapping1 = [RKObjectMapping mappingForClass:[NSString class]]; [mapping1 addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:@"this" toKeyPath:@"that"]]; RKObjectMapping *mapping2 = [RKObjectMapping mappingForClass:[NSString class]]; [mapping2 addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:@"different" toKeyPath:@"that"]]; assertThatBool([mapping1 isEqualToMapping:mapping2], is(equalToBool(NO))); } - (void)testThatTwoMappingsWithEqualRelationshipMappingsAreConsideredEqual { RKObjectMapping *relationshipMapping1 = [RKObjectMapping mappingForClass:[NSSet class]]; RKObjectMapping *relationshipMapping2 = [RKObjectMapping mappingForClass:[NSSet class]]; RKObjectMapping *mapping1 = [RKObjectMapping mappingForClass:[NSString class]]; [mapping1 addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"this" toKeyPath:@"that" withMapping:relationshipMapping1]];; RKObjectMapping *mapping2 = [RKObjectMapping mappingForClass:[NSString class]]; [mapping2 addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"this" toKeyPath:@"that" withMapping:relationshipMapping2]];; assertThatBool([mapping1 isEqualToMapping:mapping2], is(equalToBool(YES))); } - (void)testThatTwoMappingsWithDifferingRelationshipMappingClassesAreNotConsideredEqual { RKObjectMapping *relationshipMapping1 = [RKObjectMapping mappingForClass:[NSSet class]]; RKObjectMapping *relationshipMapping2 = [RKObjectMapping mappingForClass:[NSNumber class]]; RKObjectMapping *mapping1 = [RKObjectMapping mappingForClass:[NSString class]]; [mapping1 addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"this" toKeyPath:@"that" withMapping:relationshipMapping1]];; RKObjectMapping *mapping2 = [RKObjectMapping mappingForClass:[NSString class]]; [mapping2 addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"this" toKeyPath:@"that" withMapping:relationshipMapping2]];; assertThatBool([mapping1 isEqualToMapping:mapping2], is(equalToBool(NO))); } - (void)testThatTwoMappingsWithDifferingRelationshipMappingKeyPathsAreNotConsideredEqual { RKObjectMapping *relationshipMapping1 = [RKObjectMapping mappingForClass:[NSSet class]]; RKObjectMapping *relationshipMapping2 = [RKObjectMapping mappingForClass:[NSSet class]]; RKObjectMapping *mapping1 = [RKObjectMapping mappingForClass:[NSString class]]; [mapping1 addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"this" toKeyPath:@"that" withMapping:relationshipMapping1]];; RKObjectMapping *mapping2 = [RKObjectMapping mappingForClass:[NSString class]]; [mapping2 addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"this" toKeyPath:@"different" withMapping:relationshipMapping2]];; assertThatBool([mapping1 isEqualToMapping:mapping2], is(equalToBool(NO))); } - (void)testThatAddingAPropertyMappingThatExistsInAnotherMappingTriggersException { RKObjectMapping *firstMapping = [RKObjectMapping mappingForClass:[NSMutableDictionary class]]; RKAttributeMapping *attributeMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"this" toKeyPath:@"that"]; [firstMapping addPropertyMapping:attributeMapping]; RKObjectMapping *secondMapping = [RKObjectMapping mappingForClass:[NSMutableDictionary class]]; NSException *exception = nil; @try { [secondMapping addPropertyMapping:attributeMapping]; } @catch (NSException *caughtException) { exception = caughtException; } @finally { expect(exception).notTo.beNil(); expect(exception.reason).to.equal(@"Cannot add a property mapping object that has already been added to another `RKObjectMapping` object. You probably want to obtain a copy of the mapping: `[propertyMapping copy]`"); } } - (void)testThatAddingAnArrayOfPropertyMappingsThatExistInAnotherMappingTriggersException { RKObjectMapping *firstMapping = [RKObjectMapping mappingForClass:[NSMutableDictionary class]]; RKAttributeMapping *attributeMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"this" toKeyPath:@"that"]; [firstMapping addPropertyMapping:attributeMapping]; RKObjectMapping *secondMapping = [RKObjectMapping mappingForClass:[NSMutableDictionary class]]; NSException *exception = nil; @try { [secondMapping addPropertyMappingsFromArray:@[attributeMapping]]; } @catch (NSException *caughtException) { exception = caughtException; } @finally { expect(exception).notTo.beNil(); expect(exception.reason).to.equal(@"One or more of the property mappings in the given array has already been added to another `RKObjectMapping` object. You probably want to obtain a copy of the array of mappings: `[[NSArray alloc] initWithArray:arrayOfPropertyMappings copyItems:YES]`"); } } - (void)testThatAddingAnArrayOfAttributeMappingsThatExistInAnotherMappingTriggersException { RKObjectMapping *firstMapping = [RKObjectMapping mappingForClass:[NSMutableDictionary class]]; RKAttributeMapping *attributeMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"this" toKeyPath:@"that"]; [firstMapping addPropertyMapping:attributeMapping]; RKObjectMapping *secondMapping = [RKObjectMapping mappingForClass:[NSMutableDictionary class]]; NSException *exception = nil; @try { [secondMapping addAttributeMappingsFromArray:@[attributeMapping, @"stringValue"]]; } @catch (NSException *caughtException) { exception = caughtException; } @finally { expect(exception).notTo.beNil(); expect(exception.reason).to.equal(@"One or more of the property mappings in the given array has already been added to another `RKObjectMapping` object. You probably want to obtain a copy of the array of mappings: `[[NSArray alloc] initWithArray:arrayOfPropertyMappings copyItems:YES]`"); } } #pragma mark - Key Transformations - (void)testPropertyNameTransformationBlockForAttributes { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[NSMutableDictionary class]]; [mapping setSourceToDestinationKeyTransformationBlock:^NSString *(RKObjectMapping *mapping, NSString *sourceKey) { return [sourceKey uppercaseString]; }]; [mapping addAttributeMappingsFromArray:@[ @"name", @"rank" ]]; NSArray *expectedNames = @[ @"NAME", @"RANK" ]; expect([mapping.propertyMappingsByDestinationKeyPath allKeys]).to.equal(expectedNames); } - (void)testPropertyNameTransformationBlockForRelationships { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[NSMutableDictionary class]]; [mapping setSourceToDestinationKeyTransformationBlock:^NSString *(RKObjectMapping *mapping, NSString *sourceKey) { return [sourceKey uppercaseString]; }]; RKObjectMapping *relatedMapping = [RKObjectMapping mappingForClass:[NSMutableDictionary class]]; [mapping addRelationshipMappingWithSourceKeyPath:@"something" mapping:relatedMapping]; RKRelationshipMapping *relationshipMapping = [mapping propertyMappingsByDestinationKeyPath][@"SOMETHING"]; expect(relationshipMapping).notTo.beNil(); expect(relationshipMapping.sourceKeyPath).to.equal(@"something"); expect(relationshipMapping.destinationKeyPath).to.equal(@"SOMETHING"); } - (void)testTransformationOfAttributeKeyPaths { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[NSMutableDictionary class]]; [mapping setSourceToDestinationKeyTransformationBlock:^NSString *(RKObjectMapping *mapping, NSString *sourceKey) { return [sourceKey capitalizedString]; }]; [mapping addAttributeMappingsFromArray:@[ @"user.comments" ]]; NSArray *expectedNames = @[ @"User.Comments" ]; expect([mapping.propertyMappingsByDestinationKeyPath allKeys]).to.equal(expectedNames); } - (void)testDefaultSourceToDestinationKeyTransformationBlock { [RKObjectMapping setDefaultSourceToDestinationKeyTransformationBlock:^NSString *(RKObjectMapping *mapping, NSString *sourceKey) { return [sourceKey capitalizedString]; }]; RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[NSMutableDictionary class]]; [mapping addAttributeMappingsFromArray:@[ @"user.comments" ]]; NSArray *expectedNames = @[ @"User.Comments" ]; expect([mapping.propertyMappingsByDestinationKeyPath allKeys]).to.equal(expectedNames); } - (void)testBreakageOfRecursiveInverseCyclicGraphs { RKObjectMapping *parentMapping = [RKObjectMapping mappingForClass:[NSObject class]]; [parentMapping addAttributeMappingsFromDictionary:@{ @"first_name": @"firstName", @"last_name": @"lastName" }]; RKObjectMapping *childMapping = [RKObjectMapping mappingForClass:[NSObject class]]; [childMapping addAttributeMappingsFromDictionary:@{ @"first_name": @"firstName", @"last_name": @"lastName" }]; [parentMapping addRelationshipMappingWithSourceKeyPath:@"children" mapping:childMapping]; [childMapping addRelationshipMappingWithSourceKeyPath:@"parents" mapping:parentMapping]; RKObjectMapping *inverseMapping = [parentMapping inverseMapping]; expect([inverseMapping propertyMappingsBySourceKeyPath][@"firstName"]).notTo.beNil(); expect([inverseMapping propertyMappingsBySourceKeyPath][@"lastName"]).notTo.beNil(); expect([inverseMapping propertyMappingsBySourceKeyPath][@"children"]).notTo.beNil(); } - (void)testInverseMappingWithNilDestinationKeyPathForAttributeMapping { // Map @"Blake" to RKTestUser with name = @"Blake" RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestUser class]]; [mapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:nil toKeyPath:@"name"]]; RKObjectMapping *inverseMapping = [mapping inverseMapping]; RKTestUser *user = [RKTestUser new]; user.name = @"Blake"; NSMutableDictionary *dictionary = [NSMutableDictionary dictionary]; RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:user destinationObject:dictionary mapping:inverseMapping]; RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; operation.dataSource = dataSource; [operation start]; expect(operation.destinationObject).to.equal(@{ @"Blake": @{} }); } @end