Files
RestKit/Tests/Logic/CoreData/RKManagedObjectMappingOperationTest.m

367 lines
20 KiB
Objective-C

//
// RKManagedObjectMappingOperationTest.m
// RestKit
//
// Created by Blake Watters on 5/31/11.
// Copyright 2011 Two Toasters
//
// 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 "RKTestEnvironment.h"
#import "RKManagedObjectMapping.h"
#import "RKManagedObjectMappingOperation.h"
#import "RKCat.h"
#import "RKHuman.h"
#import "RKChild.h"
#import "RKParent.h"
@interface RKManagedObjectMappingOperationTest : RKTestCase {
}
@end
@implementation RKManagedObjectMappingOperationTest
- (void)testShouldOverloadInitializationOfRKObjectMappingOperationToReturnInstancesOfRKManagedObjectMappingOperationWhenAppropriate {
RKManagedObjectStore *store = [RKTestFactory managedObjectStore];
RKManagedObjectMapping* managedMapping = [RKManagedObjectMapping mappingForClass:[RKHuman class] inManagedObjectStore:store];
NSDictionary* sourceObject = [NSDictionary dictionary];
RKHuman* human = [RKHuman createEntity];
RKObjectMappingOperation* operation = [RKObjectMappingOperation mappingOperationFromObject:sourceObject toObject:human withMapping:managedMapping];
assertThat(operation, is(instanceOf([RKManagedObjectMappingOperation class])));
}
- (void)testShouldOverloadInitializationOfRKObjectMappingOperationButReturnUnmanagedMappingOperationWhenAppropriate {
RKObjectMapping* vanillaMapping = [RKObjectMapping mappingForClass:[NSMutableDictionary class]];
NSDictionary* sourceObject = [NSDictionary dictionary];
NSMutableDictionary* destinationObject = [NSMutableDictionary dictionary];
RKObjectMappingOperation* operation = [RKObjectMappingOperation mappingOperationFromObject:sourceObject toObject:destinationObject withMapping:vanillaMapping];
assertThat(operation, is(instanceOf([RKObjectMappingOperation class])));
}
- (void)testShouldConnectRelationshipsByPrimaryKey {
RKManagedObjectStore* objectStore = [RKTestFactory managedObjectStore];
RKManagedObjectMapping* catMapping = [RKManagedObjectMapping mappingForClass:[RKCat class] inManagedObjectStore:objectStore];
catMapping.primaryKeyAttribute = @"railsID";
[catMapping mapAttributes:@"name", nil];
RKManagedObjectMapping* humanMapping = [RKManagedObjectMapping mappingForClass:[RKHuman class] inManagedObjectStore:objectStore];
humanMapping.primaryKeyAttribute = @"railsID";
[humanMapping mapAttributes:@"name", @"favoriteCatID", nil];
[humanMapping hasOne:@"favoriteCat" withMapping:catMapping];
[humanMapping connectRelationship:@"favoriteCat" withObjectForPrimaryKeyAttribute:@"favoriteCatID"];
// Create a cat to connect
RKCat* cat = [RKCat object];
cat.name = @"Asia";
cat.railsID = [NSNumber numberWithInt:31337];
[objectStore save:nil];
NSDictionary* mappableData = [NSDictionary dictionaryWithKeysAndObjects:@"name", @"Blake", @"favoriteCatID", [NSNumber numberWithInt:31337], nil];
RKHuman* human = [RKHuman object];
RKManagedObjectMappingOperation* operation = [[RKManagedObjectMappingOperation alloc] initWithSourceObject:mappableData destinationObject:human mapping:humanMapping];
NSError* error = nil;
BOOL success = [operation performMapping:&error];
assertThatBool(success, is(equalToBool(YES)));
assertThat(human.favoriteCat, isNot(nilValue()));
assertThat(human.favoriteCat.name, is(equalTo(@"Asia")));
}
- (void)testConnectRelationshipsDoesNotLeakMemory {
RKManagedObjectStore* objectStore = [RKTestFactory managedObjectStore];
RKManagedObjectMapping* catMapping = [RKManagedObjectMapping mappingForClass:[RKCat class] inManagedObjectStore:objectStore];
catMapping.primaryKeyAttribute = @"railsID";
[catMapping mapAttributes:@"name", nil];
RKManagedObjectMapping* humanMapping = [RKManagedObjectMapping mappingForClass:[RKHuman class] inManagedObjectStore:objectStore];
humanMapping.primaryKeyAttribute = @"railsID";
[humanMapping mapAttributes:@"name", @"favoriteCatID", nil];
[humanMapping hasOne:@"favoriteCat" withMapping:catMapping];
[humanMapping connectRelationship:@"favoriteCat" withObjectForPrimaryKeyAttribute:@"favoriteCatID"];
// Create a cat to connect
RKCat* cat = [RKCat object];
cat.name = @"Asia";
cat.railsID = [NSNumber numberWithInt:31337];
[objectStore save:nil];
NSDictionary* mappableData = [NSDictionary dictionaryWithKeysAndObjects:@"name", @"Blake", @"favoriteCatID", [NSNumber numberWithInt:31337], nil];
RKHuman* human = [RKHuman object];
RKManagedObjectMappingOperation* operation = [[RKManagedObjectMappingOperation alloc] initWithSourceObject:mappableData destinationObject:human mapping:humanMapping];
operation.queue = [RKMappingOperationQueue new];
NSError* error = nil;
[operation performMapping:&error];
assertThatInteger([operation retainCount], is(equalToInteger(1)));
}
- (void)testConnectionOfHasManyRelationshipsByPrimaryKey {
RKManagedObjectStore* objectStore = [RKTestFactory managedObjectStore];
RKManagedObjectMapping* catMapping = [RKManagedObjectMapping mappingForClass:[RKCat class] inManagedObjectStore:objectStore];
catMapping.primaryKeyAttribute = @"railsID";
[catMapping mapAttributes:@"name", nil];
RKManagedObjectMapping* humanMapping = [RKManagedObjectMapping mappingForClass:[RKHuman class] inManagedObjectStore:objectStore];
humanMapping.primaryKeyAttribute = @"railsID";
[humanMapping mapAttributes:@"name", @"favoriteCatID", nil];
[humanMapping hasOne:@"favoriteCat" withMapping:catMapping];
[humanMapping connectRelationship:@"favoriteCat" withObjectForPrimaryKeyAttribute:@"favoriteCatID"];
// Create a cat to connect
RKCat* cat = [RKCat object];
cat.name = @"Asia";
cat.railsID = [NSNumber numberWithInt:31337];
[objectStore save:nil];
NSDictionary* mappableData = [NSDictionary dictionaryWithKeysAndObjects:@"name", @"Blake", @"favoriteCatID", [NSNumber numberWithInt:31337], nil];
RKHuman* human = [RKHuman object];
RKManagedObjectMappingOperation* operation = [[RKManagedObjectMappingOperation alloc] initWithSourceObject:mappableData destinationObject:human mapping:humanMapping];
NSError* error = nil;
BOOL success = [operation performMapping:&error];
assertThatBool(success, is(equalToBool(YES)));
assertThat(human.favoriteCat, isNot(nilValue()));
assertThat(human.favoriteCat.name, is(equalTo(@"Asia")));
}
- (void)testShouldConnectRelationshipsByPrimaryKeyWithDifferentSourceAndDestinationKeyPaths {
RKManagedObjectStore* objectStore = [RKTestFactory managedObjectStore];
RKManagedObjectMapping* catMapping = [RKManagedObjectMapping mappingForClass:[RKCat class] inManagedObjectStore:objectStore];
catMapping.primaryKeyAttribute = @"railsID";
[catMapping mapAttributes:@"name", nil];
RKManagedObjectMapping* humanMapping = [RKManagedObjectMapping mappingForClass:[RKHuman class] inManagedObjectStore:objectStore];
humanMapping.primaryKeyAttribute = @"railsID";
[humanMapping mapAttributes:@"name", @"favoriteCatID", @"catIDs", nil];
[humanMapping mapRelationship:@"cats" withMapping:catMapping];
[humanMapping connectRelationship:@"cats" withObjectForPrimaryKeyAttribute:@"catIDs"];
// Create a couple of cats to connect
RKCat* asia = [RKCat object];
asia.name = @"Asia";
asia.railsID = [NSNumber numberWithInt:31337];
RKCat* roy = [RKCat object];
roy.name = @"Reginald Royford Williams III";
roy.railsID = [NSNumber numberWithInt:31338];
[objectStore save:nil];
NSArray *catIDs = [NSArray arrayWithObjects:[NSNumber numberWithInt:31337], [NSNumber numberWithInt:31338], nil];
NSDictionary* mappableData = [NSDictionary dictionaryWithKeysAndObjects:@"name", @"Blake", @"catIDs", catIDs, nil];
RKHuman* human = [RKHuman object];
RKManagedObjectMappingOperation* operation = [[RKManagedObjectMappingOperation alloc] initWithSourceObject:mappableData destinationObject:human mapping:humanMapping];
NSError* error = nil;
BOOL success = [operation performMapping:&error];
assertThatBool(success, is(equalToBool(YES)));
assertThat(human.cats, isNot(nilValue()));
assertThat([human.cats valueForKeyPath:@"name"], containsInAnyOrder(@"Asia", @"Reginald Royford Williams III", nil));
}
- (void)testShouldLoadNestedHasManyRelationship {
RKManagedObjectStore* objectStore = [RKTestFactory managedObjectStore];
RKManagedObjectMapping* catMapping = [RKManagedObjectMapping mappingForClass:[RKCat class] inManagedObjectStore:objectStore];
catMapping.primaryKeyAttribute = @"railsID";
[catMapping mapAttributes:@"name", nil];
RKManagedObjectMapping* humanMapping = [RKManagedObjectMapping mappingForClass:[RKHuman class] inManagedObjectStore:objectStore];
humanMapping.primaryKeyAttribute = @"railsID";
[humanMapping mapAttributes:@"name", @"favoriteCatID", nil];
[humanMapping hasMany:@"cats" withMapping:catMapping];
NSArray* catsData = [NSArray arrayWithObject:[NSDictionary dictionaryWithObject:@"Asia" forKey:@"name"]];
NSDictionary* mappableData = [NSDictionary dictionaryWithKeysAndObjects:@"name", @"Blake", @"favoriteCatID", [NSNumber numberWithInt:31337], @"cats", catsData, nil];
RKHuman* human = [RKHuman object];
RKManagedObjectMappingOperation* operation = [[RKManagedObjectMappingOperation alloc] initWithSourceObject:mappableData destinationObject:human mapping:humanMapping];
NSError* error = nil;
BOOL success = [operation performMapping:&error];
assertThatBool(success, is(equalToBool(YES)));
}
- (void)testShouldLoadOrderedHasManyRelationship {
RKManagedObjectStore* objectStore = [RKTestFactory managedObjectStore];
RKManagedObjectMapping* catMapping = [RKManagedObjectMapping mappingForClass:[RKCat class] inManagedObjectStore:objectStore];
catMapping.primaryKeyAttribute = @"railsID";
[catMapping mapAttributes:@"name", nil];
RKManagedObjectMapping* humanMapping = [RKManagedObjectMapping mappingForClass:[RKHuman class] inManagedObjectStore:objectStore];
humanMapping.primaryKeyAttribute = @"railsID";
[humanMapping mapAttributes:@"name", @"favoriteCatID", nil];
[humanMapping mapKeyPath:@"cats" toRelationship:@"catsInOrderByAge" withMapping:catMapping];
NSArray* catsData = [NSArray arrayWithObject:[NSDictionary dictionaryWithObject:@"Asia" forKey:@"name"]];
NSDictionary* mappableData = [NSDictionary dictionaryWithKeysAndObjects:@"name", @"Blake", @"favoriteCatID", [NSNumber numberWithInt:31337], @"cats", catsData, nil];
RKHuman* human = [RKHuman object];
RKManagedObjectMappingOperation* operation = [[RKManagedObjectMappingOperation alloc] initWithSourceObject:mappableData destinationObject:human mapping:humanMapping];
NSError* error = nil;
BOOL success = [operation performMapping:&error];
assertThatBool(success, is(equalToBool(YES)));
assertThat([human catsInOrderByAge], isNot(empty()));
}
- (void)testShouldMapNullToAHasManyRelationship {
RKManagedObjectStore *objectStore = [RKTestFactory managedObjectStore];
RKManagedObjectMapping* catMapping = [RKManagedObjectMapping mappingForClass:[RKCat class] inManagedObjectStore:objectStore];
[catMapping mapAttributes:@"name", nil];
RKManagedObjectMapping* humanMapping = [RKManagedObjectMapping mappingForClass:[RKHuman class] inManagedObjectStore:objectStore];
[humanMapping mapAttributes:@"name", @"favoriteCatID", nil];
[humanMapping hasMany:@"cats" withMapping:catMapping];
NSDictionary* mappableData = [NSDictionary dictionaryWithKeysAndObjects:@"name", @"Blake", @"cats", [NSNull null], nil];
RKHuman* human = [RKHuman object];
RKManagedObjectMappingOperation* operation = [[RKManagedObjectMappingOperation alloc] initWithSourceObject:mappableData destinationObject:human mapping:humanMapping];
NSError* error = nil;
BOOL success = [operation performMapping:&error];
assertThatBool(success, is(equalToBool(YES)));
assertThat(human.cats, is(empty()));
}
- (void)testShouldLoadNestedHasManyRelationshipWithoutABackingClass {
RKManagedObjectStore* objectStore = [RKTestFactory managedObjectStore];
RKManagedObjectMapping* cloudMapping = [RKManagedObjectMapping mappingForEntityWithName:@"RKCloud" inManagedObjectStore:objectStore];
[cloudMapping mapAttributes:@"name", nil];
RKManagedObjectMapping* stormMapping = [RKManagedObjectMapping mappingForEntityWithName:@"RKStorm" inManagedObjectStore:objectStore];
[stormMapping mapAttributes:@"name", @"favoriteCatID", nil];
[stormMapping hasMany:@"clouds" withMapping:cloudMapping];
NSArray* cloudsData = [NSArray arrayWithObject:[NSDictionary dictionaryWithObject:@"Nimbus" forKey:@"name"]];
NSDictionary* mappableData = [NSDictionary dictionaryWithKeysAndObjects:@"name", @"Hurricane", @"clouds", cloudsData, nil];
NSEntityDescription* entity = [NSEntityDescription entityForName:@"RKStorm" inManagedObjectContext:objectStore.primaryManagedObjectContext];
NSManagedObject* storm = [[NSManagedObject alloc] initWithEntity:entity insertIntoManagedObjectContext:objectStore.primaryManagedObjectContext];
RKManagedObjectMappingOperation* operation = [[RKManagedObjectMappingOperation alloc] initWithSourceObject:mappableData destinationObject:storm mapping:stormMapping];
NSError* error = nil;
BOOL success = [operation performMapping:&error];
assertThatBool(success, is(equalToBool(YES)));
}
- (void)testShouldDynamicallyConnectRelationshipsByPrimaryKeyWhenMatchingSucceeds {
RKManagedObjectStore* objectStore = [RKTestFactory managedObjectStore];
RKManagedObjectMapping* catMapping = [RKManagedObjectMapping mappingForClass:[RKCat class] inManagedObjectStore:objectStore];
catMapping.primaryKeyAttribute = @"railsID";
[catMapping mapAttributes:@"name", nil];
RKManagedObjectMapping* humanMapping = [RKManagedObjectMapping mappingForClass:[RKHuman class] inManagedObjectStore:objectStore];
humanMapping.primaryKeyAttribute = @"railsID";
[humanMapping mapAttributes:@"name", @"favoriteCatID", nil];
[humanMapping hasOne:@"favoriteCat" withMapping:catMapping];
[humanMapping connectRelationship:@"favoriteCat" withObjectForPrimaryKeyAttribute:@"favoriteCatID" whenValueOfKeyPath:@"name" isEqualTo:@"Blake"];
// Create a cat to connect
RKCat* cat = [RKCat object];
cat.name = @"Asia";
cat.railsID = [NSNumber numberWithInt:31337];
[objectStore save:nil];
NSDictionary* mappableData = [NSDictionary dictionaryWithKeysAndObjects:@"name", @"Blake", @"favoriteCatID", [NSNumber numberWithInt:31337], nil];
RKHuman* human = [RKHuman object];
RKManagedObjectMappingOperation* operation = [[RKManagedObjectMappingOperation alloc] initWithSourceObject:mappableData destinationObject:human mapping:humanMapping];
NSError* error = nil;
BOOL success = [operation performMapping:&error];
assertThatBool(success, is(equalToBool(YES)));
assertThat(human.favoriteCat, isNot(nilValue()));
assertThat(human.favoriteCat.name, is(equalTo(@"Asia")));
}
- (void)testShouldNotDynamicallyConnectRelationshipsByPrimaryKeyWhenMatchingFails {
RKManagedObjectStore* objectStore = [RKTestFactory managedObjectStore];
RKManagedObjectMapping* catMapping = [RKManagedObjectMapping mappingForClass:[RKCat class] inManagedObjectStore:objectStore];
catMapping.primaryKeyAttribute = @"railsID";
[catMapping mapAttributes:@"name", nil];
RKManagedObjectMapping* humanMapping = [RKManagedObjectMapping mappingForClass:[RKHuman class] inManagedObjectStore:objectStore];
humanMapping.primaryKeyAttribute = @"railsID";
[humanMapping mapAttributes:@"name", @"favoriteCatID", nil];
[humanMapping hasOne:@"favoriteCat" withMapping:catMapping];
[humanMapping connectRelationship:@"favoriteCat" withObjectForPrimaryKeyAttribute:@"favoriteCatID" whenValueOfKeyPath:@"name" isEqualTo:@"Jeff"];
// Create a cat to connect
RKCat* cat = [RKCat object];
cat.name = @"Asia";
cat.railsID = [NSNumber numberWithInt:31337];
[objectStore save:nil];
NSDictionary* mappableData = [NSDictionary dictionaryWithKeysAndObjects:@"name", @"Blake", @"favoriteCatID", [NSNumber numberWithInt:31337], nil];
RKHuman* human = [RKHuman object];
RKManagedObjectMappingOperation* operation = [[RKManagedObjectMappingOperation alloc] initWithSourceObject:mappableData destinationObject:human mapping:humanMapping];
NSError* error = nil;
BOOL success = [operation performMapping:&error];
assertThatBool(success, is(equalToBool(YES)));
assertThat(human.favoriteCat, is(nilValue()));
}
- (void)testShouldConnectManyToManyRelationships {
RKManagedObjectStore *store = [RKTestFactory managedObjectStore];
RKManagedObjectMapping* childMapping = [RKManagedObjectMapping mappingForClass:[RKChild class] inManagedObjectStore:store];
childMapping.primaryKeyAttribute = @"railsID";
[childMapping mapAttributes:@"name", nil];
RKManagedObjectMapping* parentMapping = [RKManagedObjectMapping mappingForClass:[RKParent class] inManagedObjectStore:store];
parentMapping.primaryKeyAttribute = @"railsID";
[parentMapping mapAttributes:@"name", @"age", nil];
[parentMapping hasMany:@"children" withMapping:childMapping];
NSArray* childMappableData = [NSArray arrayWithObjects:[NSDictionary dictionaryWithKeysAndObjects:@"name", @"Maya", nil],
[NSDictionary dictionaryWithKeysAndObjects:@"name", @"Brady", nil], nil];
NSDictionary* parentMappableData = [NSDictionary dictionaryWithKeysAndObjects:@"name", @"Win",
@"age", [NSNumber numberWithInt:34],
@"children", childMappableData, nil];
RKParent* parent = [RKParent object];
RKManagedObjectMappingOperation* operation = [[RKManagedObjectMappingOperation alloc] initWithSourceObject:parentMappableData destinationObject:parent mapping:parentMapping];
NSError* error = nil;
BOOL success = [operation performMapping:&error];
assertThatBool(success, is(equalToBool(YES)));
assertThat(parent.children, isNot(nilValue()));
assertThatUnsignedInteger([parent.children count], is(equalToInt(2)));
assertThat([[parent.children anyObject] parents], isNot(nilValue()));
assertThatBool([[[parent.children anyObject] parents] containsObject:parent], is(equalToBool(YES)));
assertThatUnsignedInteger([[[parent.children anyObject] parents] count], is(equalToInt(1)));
}
- (void)testShouldConnectRelationshipsByPrimaryKeyRegardlessOfOrder {
RKManagedObjectStore *store = [RKTestFactory managedObjectStore];
RKManagedObjectMapping* parentMapping = [RKManagedObjectMapping mappingForClass:[RKParent class] inManagedObjectStore:store];
[parentMapping mapAttributes:@"parentID", nil];
parentMapping.primaryKeyAttribute = @"parentID";
RKManagedObjectMapping* childMapping = [RKManagedObjectMapping mappingForClass:[RKChild class] inManagedObjectStore:store];
[childMapping mapAttributes:@"fatherID", nil];
[childMapping mapRelationship:@"father" withMapping:parentMapping];
[childMapping connectRelationship:@"father" withObjectForPrimaryKeyAttribute:@"fatherID"];
RKObjectMappingProvider *mappingProvider = [RKObjectMappingProvider new];
// NOTE: This may be fragile. Reverse order seems to trigger them to be mapped parent first. NSDictionary
// keys are not guaranteed to return in any particular order
[mappingProvider setMapping:parentMapping forKeyPath:@"parents"];
[mappingProvider setMapping:childMapping forKeyPath:@"children"];
NSDictionary *JSON = [RKTestFixture parsedObjectWithContentsOfFixture:@"ConnectingParents.json"];
RKObjectMapper *mapper = [RKObjectMapper mapperWithObject:JSON mappingProvider:mappingProvider];
RKObjectMappingResult *result = [mapper performMapping];
NSArray *children = [[result asDictionary] valueForKey:@"children"];
assertThat(children, hasCountOf(1));
RKChild *child = [children lastObject];
assertThat(child.father, is(notNilValue()));
}
@end