From 4f35e4e3991133ccab588f9bb21feba0a6be97e2 Mon Sep 17 00:00:00 2001 From: Tony Arnold Date: Wed, 28 Nov 2012 08:12:51 +1100 Subject: [PATCH 01/10] Implement new save methods --- .../NSManagedObjectContext+MagicalSaves.h | 37 ++- .../NSManagedObjectContext+MagicalSaves.m | 219 ++++++++++++------ MagicalRecord/Core/MagicalRecord+Actions.h | 25 +- MagicalRecord/Core/MagicalRecord+Actions.m | 131 ++++++++--- 4 files changed, 288 insertions(+), 124 deletions(-) diff --git a/MagicalRecord/Categories/NSManagedObjectContext/NSManagedObjectContext+MagicalSaves.h b/MagicalRecord/Categories/NSManagedObjectContext/NSManagedObjectContext+MagicalSaves.h index 5c15ef6..4815c6c 100644 --- a/MagicalRecord/Categories/NSManagedObjectContext/NSManagedObjectContext+MagicalSaves.h +++ b/MagicalRecord/Categories/NSManagedObjectContext/NSManagedObjectContext+MagicalSaves.h @@ -8,17 +8,38 @@ #import +typedef NS_OPTIONS(NSUInteger, MRSaveContextOptions) { + MRSaveParentContexts = 1, + MRSaveSynchronously = 2 +}; + +typedef void (^MRSaveCompletionHandler)(BOOL success, NSError *error); + @interface NSManagedObjectContext (MagicalSaves) -- (void) MR_save; -- (void) MR_saveWithErrorCallback:(void(^)(NSError *))errorCallback; +// Asynchronous saving +- (void) MR_saveOnlySelfWithCompletion:(MRSaveCompletionHandler)completion; +- (void) MR_saveToPersistentStoreWithCompletion:(MRSaveCompletionHandler)completion; -- (void) MR_saveInBackgroundCompletion:(void (^)(void))completion; -- (void) MR_saveInBackgroundErrorHandler:(void (^)(NSError *))errorCallback; -- (void) MR_saveInBackgroundErrorHandler:(void (^)(NSError *))errorCallback completion:(void (^)(void))completion; +// Synchronous saving +- (void) MR_saveOnlySelfAndWait; +- (void) MR_saveToPersistentStoreAndWait; -- (void) MR_saveNestedContexts; -- (void) MR_saveNestedContextsErrorHandler:(void (^)(NSError *))errorCallback; -- (void) MR_saveNestedContextsErrorHandler:(void (^)(NSError *))errorCallback completion:(void (^)(void))completion; +// Save with options +- (void) MR_saveWithOptions:(MRSaveContextOptions)mask completion:(MRSaveCompletionHandler)completion; + +/* DEPRECATION NOTICE: + * The following methods are deprecated, but remain in place for backwards compatibility until the next major version (3.x) + */ +- (void) MR_save __attribute__((deprecated)); +- (void) MR_saveWithErrorCallback:(void(^)(NSError *))errorCallback __attribute__((deprecated)); + +- (void) MR_saveInBackgroundCompletion:(void (^)(void))completion __attribute__((deprecated)); +- (void) MR_saveInBackgroundErrorHandler:(void (^)(NSError *))errorCallback __attribute__((deprecated)); +- (void) MR_saveInBackgroundErrorHandler:(void (^)(NSError *))errorCallback completion:(void (^)(void))completion __attribute__((deprecated)); + +- (void) MR_saveNestedContexts __attribute__((deprecated)); +- (void) MR_saveNestedContextsErrorHandler:(void (^)(NSError *))errorCallback __attribute__((deprecated)); +- (void) MR_saveNestedContextsErrorHandler:(void (^)(NSError *))errorCallback completion:(void (^)(void))completion __attribute__((deprecated)); @end diff --git a/MagicalRecord/Categories/NSManagedObjectContext/NSManagedObjectContext+MagicalSaves.m b/MagicalRecord/Categories/NSManagedObjectContext/NSManagedObjectContext+MagicalSaves.m index aec15ad..62a6992 100644 --- a/MagicalRecord/Categories/NSManagedObjectContext/NSManagedObjectContext+MagicalSaves.m +++ b/MagicalRecord/Categories/NSManagedObjectContext/NSManagedObjectContext+MagicalSaves.m @@ -11,115 +11,180 @@ #import "NSManagedObjectContext+MagicalRecord.h" #import "MagicalRecord.h" -@interface NSManagedObjectContext (InternalMagicalSaves) - -- (void) MR_saveWithErrorCallback:(void(^)(NSError *))errorCallback; - -@end - - @implementation NSManagedObjectContext (MagicalSaves) -- (void) MR_saveWithErrorCallback:(void(^)(NSError *))errorCallback; +- (void)MR_saveOnlySelfWithCompletion:(MRSaveCompletionHandler)completion; { - if (![self hasChanges]) - { - MRLog(@"NO CHANGES IN CONTEXT %@ - NOT SAVING", [self MR_description]); + [self MR_saveWithOptions:0 completion:completion]; +} + +- (void)MR_saveOnlySelfAndWait; +{ + [self MR_saveWithOptions:MRSaveSynchronously completion:nil]; +} + +- (void) MR_saveToPersistentStoreWithCompletion:(MRSaveCompletionHandler)completion; +{ + [self MR_saveWithOptions:MRSaveParentContexts completion:completion]; +} + +- (void) MR_saveToPersistentStoreAndWait; +{ + [self MR_saveWithOptions:MRSaveParentContexts | MRSaveSynchronously completion:nil]; +} + +- (void)MR_saveWithOptions:(MRSaveContextOptions)mask completion:(MRSaveCompletionHandler)completion; +{ + BOOL syncSave = ((mask & MRSaveSynchronously) == MRSaveSynchronously); + BOOL saveParentContexts = ((mask & MRSaveParentContexts) == MRSaveParentContexts); + + if (![self hasChanges]) { + MRLog(@"NO CHANGES IN ** %@ ** CONTEXT - NOT SAVING", [self MR_workingName]); + + if (completion) + { + completion(NO, nil); + } + return; } - - MRLog(@"-> Saving %@", [self MR_description]); - - __block NSError *error = nil; - __block BOOL saved = NO; - @try - { - [self performBlockAndWait:^{ - saved = [self save:&error]; - }]; - } - @catch (NSException *exception) - { - MRLog(@"Unable to perform save: %@", (id)[exception userInfo] ?: (id)[exception reason]); - } - @finally - { - if (!saved) + + MRLog(@"→ Saving %@", [self MR_description]); + + id saveBlock = ^{ + NSError *error = nil; + BOOL saved = NO; + + @try { - if (errorCallback) - { - errorCallback(error); - } - else - { + saved = [self save:&error]; + } + @catch(NSException *exception) + { + MRLog(@"Unable to perform save: %@", (id)[exception userInfo] ? : (id)[exception reason]); + } + + @finally + { + if (!saved) { [MagicalRecord handleErrors:error]; + + if (completion) { + completion(saved, error); + } + } else { + // If we're the default context, save to disk too (the user expects it to persist) + if (self == [[self class] MR_defaultContext]) { + [[[self class] MR_rootSavingContext] MR_saveWithOptions:MRSaveSynchronously completion:completion]; + } + // If we're saving parent contexts, do so + else if ((YES == saveParentContexts) && [self parentContext]) { + [[self parentContext] MR_saveWithOptions:MRSaveSynchronously | MRSaveParentContexts completion:completion]; + } + // If we are not the default context (And therefore need to save the root context, do the completion action if one was specified + else { + MRLog(@"→ Finished saving: %@", [self MR_description]); + if (completion) { + completion(saved, error); + } + } } } + }; + + if (YES == syncSave) { + [self performBlockAndWait:saveBlock]; + } else { + [self performBlock:saveBlock]; } } -- (void) MR_saveNestedContexts; +#pragma mark - Deprecated methods +// These methods will be removed in MagicalRecord 3.0 + +- (void)MR_saveNestedContexts; { - [self MR_saveNestedContextsErrorHandler:nil]; + [self MR_saveToPersistentStoreWithCompletion:nil]; } -- (void) MR_saveNestedContextsErrorHandler:(void (^)(NSError *))errorCallback; +- (void)MR_saveNestedContextsErrorHandler:(void (^)(NSError *))errorCallback; { - [self MR_saveNestedContextsErrorHandler:nil completion:nil]; + [self MR_saveToPersistentStoreWithCompletion:^(BOOL success, NSError *error) { + if (!success) { + if (errorCallback) { + errorCallback(error); + } + } + }]; } -- (void) MR_saveNestedContextsErrorHandler:(void (^)(NSError *))errorCallback completion:(void (^)(void))completion; +- (void)MR_saveNestedContextsErrorHandler:(void (^)(NSError *))errorCallback completion:(void (^)(void))completion; { - [self performBlock:^{ - [self MR_saveWithErrorCallback:errorCallback]; - if (self.parentContext) { - [[self parentContext] performBlock:^{ - [[self parentContext] MR_saveNestedContextsErrorHandler:errorCallback completion:completion]; - }]; - } else { + [self MR_saveToPersistentStoreWithCompletion:^(BOOL success, NSError *error) { + if (success) { if (completion) { - dispatch_async(dispatch_get_main_queue(), ^{ - completion(); - }); + completion(); + } + } else { + if (errorCallback) { + errorCallback(error); } } }]; } -- (void) MR_save; +- (void)MR_save; { - [self MR_saveWithErrorCallback:nil]; + [self MR_saveToPersistentStoreAndWait]; } -- (void) MR_saveInBackgroundCompletion:(void (^)(void))completion; -{ - [self MR_saveInBackgroundErrorHandler:nil completion:completion]; -} +- (void)MR_saveWithErrorCallback:(void (^)(NSError *))errorCallback __attribute__((deprecated)); -- (void) MR_saveInBackgroundErrorHandler:(void (^)(NSError *))errorCallback; { - [self MR_saveInBackgroundErrorHandler:errorCallback completion:nil]; -} - -- (void) MR_saveInBackgroundErrorHandler:(void (^)(NSError *))errorCallback completion:(void (^)(void))completion; -{ - [self performBlock:^{ - // Save the context - [self MR_saveWithErrorCallback:errorCallback]; - - // If we're the default context, save to disk too (the user expects it to persist) - if (self == [[self class] MR_defaultContext]) - { - [[[self class] MR_rootSavingContext] MR_saveInBackgroundErrorHandler:errorCallback completion:completion]; - } - else - { - // If we are not the default context (And therefore need to save the root context, do the completion action if one was specified - if (completion) - { - dispatch_async(dispatch_get_main_queue(), completion); + [self MR_saveWithOptions:MRSaveSynchronously completion:^(BOOL success, NSError *error) { + if (!success) { + if (errorCallback) { + errorCallback(error); } } }]; } + +- (void)MR_saveInBackgroundCompletion:(void (^)(void))completion; +{ + [self MR_saveOnlySelfWithCompletion:^(BOOL success, NSError *error) { + if (success) { + if (completion) { + completion(); + } + } + }]; +} + +- (void)MR_saveInBackgroundErrorHandler:(void (^)(NSError *))errorCallback; +{ + [self MR_saveOnlySelfWithCompletion:^(BOOL success, NSError *error) { + if (!success) { + if (errorCallback) { + errorCallback(error); + } + } + }]; +} + +- (void)MR_saveInBackgroundErrorHandler:(void (^)(NSError *))errorCallback completion:(void (^)(void))completion; +{ + [self MR_saveOnlySelfWithCompletion:^(BOOL success, NSError *error) { + if (success) { + if (completion) { + completion(); + } + } else { + if (errorCallback) { + errorCallback(error); + } + } + }]; +} + @end diff --git a/MagicalRecord/Core/MagicalRecord+Actions.h b/MagicalRecord/Core/MagicalRecord+Actions.h index 4b2d60a..0bce647 100644 --- a/MagicalRecord/Core/MagicalRecord+Actions.h +++ b/MagicalRecord/Core/MagicalRecord+Actions.h @@ -7,21 +7,38 @@ #import #import "NSManagedObjectContext+MagicalRecord.h" +#import "NSManagedObjectContext+MagicalSaves.h" @interface MagicalRecord (Actions) -/* For saving on the current thread as the caller, only with a seperate context. Useful when you're managing your own threads/queues and need a serial call to create or change data +/* For all background saving operations. These calls will be sent to a different thread/queue. */ + (void) saveWithBlock:(void(^)(NSManagedObjectContext *localContext))block; ++ (void) saveWithBlock:(void(^)(NSManagedObjectContext *localContext))block completion:(MRSaveCompletionHandler)completion; + +/* For saving on the current thread as the caller, only with a seperate context. Useful when you're managing your own threads/queues and need a serial call to create or change data + */ ++ (void) saveWithBlockAndWait:(void(^)(NSManagedObjectContext *localContext))block; + +/* + If you want to reuse the context on the current thread, use these methods. + */ ++ (void) saveUsingCurrentContextWithBlock:(void (^)(NSManagedObjectContext *localContext))block completion:(MRSaveCompletionHandler)completion; ++ (void) saveUsingCurrentContextWithBlockAndWait:(void (^)(NSManagedObjectContext *localContext))block; + + +/* DEPRECATION NOTICE: + * The following methods are deprecated, but remain in place for backwards compatibility until the next major version (3.x) + */ /* For all background saving operations. These calls will be sent to a different thread/queue. */ -+ (void) saveInBackgroundWithBlock:(void(^)(NSManagedObjectContext *localContext))block; -+ (void) saveInBackgroundWithBlock:(void(^)(NSManagedObjectContext *localContext))block completion:(void(^)(void))callback; ++ (void) saveInBackgroundWithBlock:(void(^)(NSManagedObjectContext *localContext))block __attribute__((deprecated)); ++ (void) saveInBackgroundWithBlock:(void(^)(NSManagedObjectContext *localContext))block completion:(void(^)(void))completion __attribute__((deprecated)); /* If you want to reuse the context on the current thread, use this method. */ -+ (void) saveInBackgroundUsingCurrentContextWithBlock:(void (^)(NSManagedObjectContext *))block completion:(void (^)(void))completion errorHandler:(void (^)(NSError *))errorHandler; ++ (void) saveInBackgroundUsingCurrentContextWithBlock:(void (^)(NSManagedObjectContext *localContext))block completion:(void (^)(void))completion errorHandler:(void (^)(NSError *))errorHandler __attribute__((deprecated)); @end diff --git a/MagicalRecord/Core/MagicalRecord+Actions.m b/MagicalRecord/Core/MagicalRecord+Actions.m index 2e56bbb..d886c27 100644 --- a/MagicalRecord/Core/MagicalRecord+Actions.m +++ b/MagicalRecord/Core/MagicalRecord+Actions.m @@ -8,63 +8,124 @@ #import "CoreData+MagicalRecord.h" #import "NSManagedObjectContext+MagicalRecord.h" + @implementation MagicalRecord (Actions) -+ (void) saveInBackgroundUsingContext:(NSManagedObjectContext *)localContext block:(void (^)(NSManagedObjectContext *))block completion:(void(^)(void))completion errorHandler:(void(^)(NSError *))errorHandler; +#pragma mark - Asynchronous saving + ++ (void) saveWithBlock:(void(^)(NSManagedObjectContext *localContext))block; { - [localContext performBlock: ^{ - block(localContext); - - [localContext MR_saveNestedContextsErrorHandler:errorHandler completion:completion]; + [self saveWithBlock:block completion:nil]; +} + ++ (void) saveWithBlock:(void(^)(NSManagedObjectContext *localContext))block completion:(MRSaveCompletionHandler)completion; +{ + NSManagedObjectContext *mainContext = [NSManagedObjectContext MR_defaultContext]; + NSManagedObjectContext *localContext = [NSManagedObjectContext MR_contextWithParent:mainContext]; + + [localContext performBlock:^{ + if (block) { + block(localContext); + } + + [localContext MR_saveWithOptions:MRSaveParentContexts|MRSaveSynchronously completion:completion]; }]; } -+ (void) saveInBackgroundWithBlock:(void (^)(NSManagedObjectContext *))block completion:(void (^)(void))completion errorHandler:(void (^)(NSError *))errorHandler; -{ - NSManagedObjectContext *mainContext = [NSManagedObjectContext MR_defaultContext]; - NSManagedObjectContext *localContext = [NSManagedObjectContext MR_contextWithParent:mainContext]; - - [self saveInBackgroundUsingContext:localContext block:block completion:completion errorHandler:errorHandler]; -} - -+ (void) saveInBackgroundUsingCurrentContextWithBlock:(void (^)(NSManagedObjectContext *))block completion:(void (^)(void))completion errorHandler:(void (^)(NSError *))errorHandler; ++ (void) saveUsingCurrentContextWithBlock:(void (^)(NSManagedObjectContext *localContext))block completion:(MRSaveCompletionHandler)completion; { NSManagedObjectContext *localContext = [NSManagedObjectContext MR_contextForCurrentThread]; - - [self saveInBackgroundUsingContext:localContext block:block completion:completion errorHandler:errorHandler]; + + [localContext performBlock:^{ + if (block) { + block(localContext); + } + + [localContext MR_saveWithOptions:MRSaveParentContexts|MRSaveSynchronously completion:completion]; + }]; } - -+ (void) saveWithBlock:(void (^)(NSManagedObjectContext *localContext))block completion:(void (^)(void))completion errorHandler:(void (^)(NSError *))errorHandler; + + +#pragma mark - Synchronous saving + ++ (void) saveWithBlockAndWait:(void(^)(NSManagedObjectContext *localContext))block; { NSManagedObjectContext *mainContext = [NSManagedObjectContext MR_defaultContext]; NSManagedObjectContext *localContext = [NSManagedObjectContext MR_contextWithParent:mainContext]; - block(localContext); - - if ([localContext hasChanges]) - { - [localContext MR_saveWithErrorCallback:errorHandler]; - } - - if (completion) - { - dispatch_async(dispatch_get_main_queue(), completion); - } + [localContext performBlockAndWait:^{ + if (block) { + block(localContext); + } + + [localContext MR_saveWithOptions:MRSaveParentContexts|MRSaveSynchronously completion:nil]; + }]; } -+ (void) saveWithBlock:(void(^)(NSManagedObjectContext *localContext))block -{ - [self saveWithBlock:block completion:nil errorHandler:nil]; ++ (void) saveUsingCurrentContextWithBlockAndWait:(void (^)(NSManagedObjectContext *localContext))block; +{ + NSManagedObjectContext *localContext = [NSManagedObjectContext MR_contextForCurrentThread]; + + [localContext performBlockAndWait:^{ + if (block) { + block(localContext); + } + + [localContext MR_saveWithOptions:MRSaveParentContexts|MRSaveSynchronously completion:nil]; + }]; } + +#pragma mark - Deprecated methods + + (void) saveInBackgroundWithBlock:(void(^)(NSManagedObjectContext *localContext))block { - [self saveInBackgroundWithBlock:block completion:nil errorHandler:nil]; + [[self class] saveWithBlock:block completion:nil]; } -+ (void) saveInBackgroundWithBlock:(void(^)(NSManagedObjectContext *localContext))block completion:(void(^)(void))callback ++ (void) saveInBackgroundWithBlock:(void(^)(NSManagedObjectContext *localContext))block completion:(void(^)(void))completion { - [self saveInBackgroundWithBlock:block completion:callback errorHandler:nil]; + NSManagedObjectContext *mainContext = [NSManagedObjectContext MR_defaultContext]; + NSManagedObjectContext *localContext = [NSManagedObjectContext MR_contextWithParent:mainContext]; + + [localContext performBlock:^{ + if (block) + { + block(localContext); + } + + [localContext MR_saveToPersistentStoreAndWait]; + + if (completion) + { + completion(); + } + }]; +} + ++ (void) saveInBackgroundUsingCurrentContextWithBlock:(void (^)(NSManagedObjectContext *localContext))block completion:(void (^)(void))completion errorHandler:(void (^)(NSError *))errorHandler; +{ + NSManagedObjectContext *localContext = [NSManagedObjectContext MR_contextForCurrentThread]; + + [localContext performBlock:^{ + if (block) { + block(localContext); + } + + [localContext MR_saveToPersistentStoreWithCompletion:^(BOOL success, NSError *error) { + + if (success) { + if (completion) { + completion(); + } + } + else { + if (errorHandler) { + errorHandler(error); + } + } + }]; + }]; } @end From c763d4ad9126ca37d03a1077a4e2b84aa2668923 Mon Sep 17 00:00:00 2001 From: Tony Arnold Date: Thu, 13 Dec 2012 10:02:29 +1100 Subject: [PATCH 02/10] Update existing save tests to reflect save changes. Also begin adding tests for deprecated methods to ensure consistent behaviour in unmodified code. --- ...appedEntitiesUsingListOfPrimaryKeysTests.m | 4 +- ...MappedEntitiesUsingMappedPrimaryKeyTests.m | 2 +- ...yRelatedToMappedEntityUsingDefaultsTests.m | 4 +- ...ToMappedEntityUsingMappedPrimaryKeyTests.m | 6 +- ...pedEntityWithNestedMappedAttributesTests.m | 2 +- ...ToMappedEntityWithSecondaryMappingsTests.m | 2 +- .../ImportSingleRelatedEntityTests.m | 4 +- .../NSManagedObjectContextHelperTests.m | 2 +- .../Unit Tests/NSManagedObjectHelperTests.m | 4 +- Project Files/Unit Tests/SaveTests.m | 179 +++++++++++++++--- 10 files changed, 163 insertions(+), 46 deletions(-) diff --git a/Project Files/Unit Tests/Fixtures/ImportSingleEntityRelatedToManyMappedEntitiesUsingListOfPrimaryKeysTests.m b/Project Files/Unit Tests/Fixtures/ImportSingleEntityRelatedToManyMappedEntitiesUsingListOfPrimaryKeysTests.m index 02bfe56..5c1f43f 100644 --- a/Project Files/Unit Tests/Fixtures/ImportSingleEntityRelatedToManyMappedEntitiesUsingListOfPrimaryKeysTests.m +++ b/Project Files/Unit Tests/Fixtures/ImportSingleEntityRelatedToManyMappedEntitiesUsingListOfPrimaryKeysTests.m @@ -38,13 +38,13 @@ entity.testPrimaryKeyValue = 84; [entity addMappedEntitiesObject:related]; - [context MR_save]; + [context MR_saveSelfAndParentContextsAndWait]; } - (void) testDataImportUsingListOfPrimaryKeyIDs { SingleEntityRelatedToManyMappedEntitiesUsingMappedPrimaryKey *testEntity = [[self testEntityClass] MR_importFromObject:self.testEntityData]; - [[NSManagedObjectContext MR_defaultContext] MR_save]; + [[NSManagedObjectContext MR_defaultContext] MR_saveSelfAndParentContextsAndWait]; assertThat([SingleEntityRelatedToManyMappedEntitiesUsingMappedPrimaryKey numberOfEntities], is(equalToInteger(1))); assertThat([MappedEntity numberOfEntities], is(equalToInteger(10))); diff --git a/Project Files/Unit Tests/ImportSingleEntityRelatedToManyMappedEntitiesUsingMappedPrimaryKeyTests.m b/Project Files/Unit Tests/ImportSingleEntityRelatedToManyMappedEntitiesUsingMappedPrimaryKeyTests.m index c82713d..f5f34a1 100644 --- a/Project Files/Unit Tests/ImportSingleEntityRelatedToManyMappedEntitiesUsingMappedPrimaryKeyTests.m +++ b/Project Files/Unit Tests/ImportSingleEntityRelatedToManyMappedEntitiesUsingMappedPrimaryKeyTests.m @@ -23,7 +23,7 @@ - (void) testImportData { SingleEntityRelatedToManyMappedEntitiesUsingMappedPrimaryKey *entity = [[self testEntityClass] MR_importFromObject:self.testEntityData]; - [[NSManagedObjectContext MR_defaultContext] MR_save]; + [[NSManagedObjectContext MR_defaultContext] MR_saveSelfAndParentContextsAndWait]; assertThat(entity, is(notNilValue())); assertThat(entity.mappedEntities, hasCountOf(4)); diff --git a/Project Files/Unit Tests/ImportSingleEntityRelatedToMappedEntityUsingDefaultsTests.m b/Project Files/Unit Tests/ImportSingleEntityRelatedToMappedEntityUsingDefaultsTests.m index 760518e..7533bcd 100644 --- a/Project Files/Unit Tests/ImportSingleEntityRelatedToMappedEntityUsingDefaultsTests.m +++ b/Project Files/Unit Tests/ImportSingleEntityRelatedToMappedEntityUsingDefaultsTests.m @@ -32,14 +32,14 @@ SingleEntityRelatedToMappedEntityUsingDefaults *entity = [SingleEntityRelatedToMappedEntityUsingDefaults createInContext:context]; entity.singleEntityRelatedToMappedEntityUsingDefaultsIDValue = 24; - [context MR_save]; + [context MR_saveSelfAndParentContextsAndWait]; } - (void) testImportMappedEntityViaToOneRelationship { SingleEntityRelatedToMappedEntityUsingDefaults *entity = [[self testEntityClass] MR_importFromObject:self.testEntityData]; - [[NSManagedObjectContext MR_defaultContext] MR_save]; + [[NSManagedObjectContext MR_defaultContext] MR_saveSelfAndParentContextsAndWait]; id testRelatedEntity = entity.mappedEntity; diff --git a/Project Files/Unit Tests/ImportSingleEntityRelatedToMappedEntityUsingMappedPrimaryKeyTests.m b/Project Files/Unit Tests/ImportSingleEntityRelatedToMappedEntityUsingMappedPrimaryKeyTests.m index d416cdc..5a8c358 100644 --- a/Project Files/Unit Tests/ImportSingleEntityRelatedToMappedEntityUsingMappedPrimaryKeyTests.m +++ b/Project Files/Unit Tests/ImportSingleEntityRelatedToMappedEntityUsingMappedPrimaryKeyTests.m @@ -24,7 +24,7 @@ testMappedEntity.testMappedEntityIDValue = 42; testMappedEntity.sampleAttribute = @"This attribute created as part of the test case setup"; - [context MR_save]; + [context MR_saveSelfAndParentContextsAndWait]; } - (Class) testEntityClass @@ -35,7 +35,7 @@ - (void) testImportMappedEntityRelatedViaToOneRelationship { SingleEntityRelatedToMappedEntityUsingMappedPrimaryKey *entity = [[self testEntityClass] MR_importFromObject:self.testEntityData]; - [[NSManagedObjectContext MR_defaultContext] MR_save]; + [[NSManagedObjectContext MR_defaultContext] MR_saveSelfAndParentContextsAndWait]; id testRelatedEntity = entity.mappedEntity; @@ -72,7 +72,7 @@ - (void) testImportMappedEntityUsingPrimaryRelationshipKey { SingleEntityRelatedToMappedEntityUsingMappedPrimaryKey *entity = [[self testEntityClass] MR_importFromObject:self.testEntityData]; - [[NSManagedObjectContext MR_defaultContext] MR_save]; + [[NSManagedObjectContext MR_defaultContext] MR_saveSelfAndParentContextsAndWait]; id testRelatedEntity = entity.mappedEntity; diff --git a/Project Files/Unit Tests/ImportSingleEntityRelatedToMappedEntityWithNestedMappedAttributesTests.m b/Project Files/Unit Tests/ImportSingleEntityRelatedToMappedEntityWithNestedMappedAttributesTests.m index 63e88aa..0925874 100644 --- a/Project Files/Unit Tests/ImportSingleEntityRelatedToMappedEntityWithNestedMappedAttributesTests.m +++ b/Project Files/Unit Tests/ImportSingleEntityRelatedToMappedEntityWithNestedMappedAttributesTests.m @@ -25,7 +25,7 @@ - (void) testDataImport { SingleEntityRelatedToMappedEntityWithNestedMappedAttributes *entity = [[self testEntityClass] MR_importFromObject:self.testEntityData]; - [[NSManagedObjectContext MR_defaultContext] MR_save]; + [[NSManagedObjectContext MR_defaultContext] MR_saveSelfAndParentContextsAndWait]; assertThat(entity.mappedEntity, is(notNilValue())); assertThat(entity.mappedEntity.mappedEntityID, is(equalToInteger(42))); diff --git a/Project Files/Unit Tests/ImportSingleEntityRelatedToMappedEntityWithSecondaryMappingsTests.m b/Project Files/Unit Tests/ImportSingleEntityRelatedToMappedEntityWithSecondaryMappingsTests.m index 466c287..5b7a232 100644 --- a/Project Files/Unit Tests/ImportSingleEntityRelatedToMappedEntityWithSecondaryMappingsTests.m +++ b/Project Files/Unit Tests/ImportSingleEntityRelatedToMappedEntityWithSecondaryMappingsTests.m @@ -23,7 +23,7 @@ - (void) testImportMappedAttributeUsingSecondaryMappedKeyName { SingleEntityRelatedToMappedEntityWithSecondaryMappings *entity = [[self testEntityClass] MR_importFromObject:self.testEntityData]; - [[NSManagedObjectContext MR_defaultContext] MR_save]; + [[NSManagedObjectContext MR_defaultContext] MR_saveSelfAndParentContextsAndWait]; assertThat(entity, is(notNilValue())); assertThat([entity secondaryMappedAttribute], containsString(@"sample json file")); diff --git a/Project Files/Unit Tests/ImportSingleRelatedEntityTests.m b/Project Files/Unit Tests/ImportSingleRelatedEntityTests.m index acc747c..903fe04 100644 --- a/Project Files/Unit Tests/ImportSingleRelatedEntityTests.m +++ b/Project Files/Unit Tests/ImportSingleRelatedEntityTests.m @@ -30,14 +30,14 @@ testMappedEntity.testMappedEntityIDValue = 42; testMappedEntity.sampleAttribute = @"This attribute created as part of the test case setup"; - [context MR_save]; + [context MR_saveSelfAndParentContextsAndWait]; } - (void) setUp { [super setUp]; self.singleTestEntity = [SingleRelatedEntity MR_importFromObject:self.testEntityData]; - [[NSManagedObjectContext MR_defaultContext] MR_save]; + [[NSManagedObjectContext MR_defaultContext] MR_saveSelfAndParentContextsAndWait]; } - (void) testImportAnEntityRelatedToAbstractEntityViaToOneRelationshop diff --git a/Project Files/Unit Tests/NSManagedObjectContextHelperTests.m b/Project Files/Unit Tests/NSManagedObjectContextHelperTests.m index f2ac884..0f53a64 100644 --- a/Project Files/Unit Tests/NSManagedObjectContextHelperTests.m +++ b/Project Files/Unit Tests/NSManagedObjectContextHelperTests.m @@ -40,7 +40,7 @@ NSManagedObjectContext *context = [NSManagedObjectContext MR_defaultContext]; SingleEntityWithNoRelationships *entity = [SingleEntityWithNoRelationships MR_createInContext:context]; assertThatBool([[entity objectID] isTemporaryID], equalToBool(YES)); - [context MR_save]; + [context MR_saveOnlySelfAndWait]; assertThatBool([[entity objectID] isTemporaryID], equalToBool(NO)); } diff --git a/Project Files/Unit Tests/NSManagedObjectHelperTests.m b/Project Files/Unit Tests/NSManagedObjectHelperTests.m index e440799..7697bfd 100644 --- a/Project Files/Unit Tests/NSManagedObjectHelperTests.m +++ b/Project Files/Unit Tests/NSManagedObjectHelperTests.m @@ -80,7 +80,7 @@ - (void) testCanDeleteEntityInstance { id testEntity = [SingleRelatedEntity createEntity]; - [[NSManagedObjectContext MR_defaultContext] MR_save]; + [[NSManagedObjectContext MR_defaultContext] MR_saveSelfAndParentContextsAndWait]; assertThatBool([testEntity isDeleted], is(equalToBool(NO))); @@ -100,7 +100,7 @@ testEntity.mappedStringAttribute = [NSString stringWithFormat:@"%d", i / 5]; } - [[NSManagedObjectContext MR_defaultContext] MR_save]; + [[NSManagedObjectContext MR_defaultContext] MR_saveOnlySelfAndWait]; } - (void) testCanSearchForNumberOfAllEntities diff --git a/Project Files/Unit Tests/SaveTests.m b/Project Files/Unit Tests/SaveTests.m index c010006..b457101 100644 --- a/Project Files/Unit Tests/SaveTests.m +++ b/Project Files/Unit Tests/SaveTests.m @@ -16,7 +16,6 @@ - (void) setUpClass { [NSManagedObjectModel MR_setDefaultManagedObjectModel:[NSManagedObjectModel MR_managedObjectModelNamed:@"TestModel.momd"]]; - } - (void) setUp @@ -30,56 +29,174 @@ [MagicalRecord cleanUp]; } -- (void)testBackgroundSaveCallsCompletionHandler +- (void)testAsynchronousSaveCallsCompletionHandler { - __block BOOL didSave = NO; - [MagicalRecord saveInBackgroundWithBlock:^(NSManagedObjectContext *localContext) { - [SingleEntityWithNoRelationships MR_createInContext:localContext]; - } completion:^{ - didSave = YES; - }]; - - expect(didSave).will.beTruthy(); -} + __block BOOL completionHandlerCalled = NO; -- (void)testBackgroundSavesActuallySave -{ - __block NSManagedObjectID *objectId; - __block NSManagedObject *fetchedObject; dispatch_group_t group = dispatch_group_create(); - dispatch_group_enter(group); - [MagicalRecord saveInBackgroundWithBlock:^(NSManagedObjectContext *localContext) { - NSManagedObject *inserted = [SingleEntityWithNoRelationships MR_createInContext:localContext]; - expect([inserted hasChanges]).to.beTruthy(); - [localContext obtainPermanentIDsForObjects:@[inserted] error:nil]; - objectId = inserted.objectID; - } completion:^{ - fetchedObject = [[NSManagedObjectContext MR_rootSavingContext] objectWithID:objectId]; + dispatch_group_enter(group); + + [MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) { + expect(localContext).toNot.beNil(); + [SingleEntityWithNoRelationships MR_createInContext:localContext]; + } completion:^(BOOL success, NSError *error) { + // Ignore the success state — we only care that this block is executed + completionHandlerCalled = YES; dispatch_group_leave(group); - }]; - + dispatch_group_wait(group, DISPATCH_TIME_FOREVER); - expect(fetchedObject).toNot.beNil(); - expect([fetchedObject hasChanges]).to.beFalsy(); + expect(completionHandlerCalled).will.beTruthy(); } -- (void)testCurrentThreadSavesActuallySave +- (void)testAsynchronousSavesActuallySave { - __block NSManagedObjectID *objectId; - __block NSManagedObject *fetchedObject; + __block BOOL saveSuccessState = NO; + __block NSManagedObjectID *objectId; + __block NSManagedObject *fetchedObject; + + dispatch_group_t group = dispatch_group_create(); + + dispatch_group_enter(group); + [MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) { NSManagedObject *inserted = [SingleEntityWithNoRelationships MR_createInContext:localContext]; expect([inserted hasChanges]).to.beTruthy(); [localContext obtainPermanentIDsForObjects:@[inserted] error:nil]; objectId = inserted.objectID; + } completion:^(BOOL success, NSError *error) { + saveSuccessState = success; + fetchedObject = [[NSManagedObjectContext MR_rootSavingContext] objectWithID:objectId]; + dispatch_group_leave(group); }]; - fetchedObject = [[NSManagedObjectContext MR_rootSavingContext] objectWithID:objectId]; + dispatch_group_wait(group, DISPATCH_TIME_FOREVER); + expect(saveSuccessState).to.beTruthy(); + expect(fetchedObject).toNot.beNil(); + expect([fetchedObject hasChanges]).to.beFalsy(); +} + +- (void)testSynchronousSavesActuallySave +{ + __block NSManagedObjectID *objectId; + __block NSManagedObject *fetchedObject; + + [MagicalRecord saveWithBlockAndWait:^(NSManagedObjectContext *localContext) { + NSManagedObject *inserted = [SingleEntityWithNoRelationships MR_createInContext:localContext]; + expect([inserted hasChanges]).to.beTruthy(); + [localContext obtainPermanentIDsForObjects:@[inserted] error:nil]; + objectId = inserted.objectID; + }]; + + fetchedObject = [[NSManagedObjectContext MR_rootSavingContext] objectWithID:objectId]; expect(fetchedObject).toNot.beNil(); expect([fetchedObject hasChanges]).to.beFalsy(); } +- (void)testCurrentThreadContextAsynchronousSavesActuallySave +{ + __block NSManagedObjectID *objectId; + __block NSManagedObject *fetchedObject; + + dispatch_group_t group = dispatch_group_create(); + + dispatch_group_enter(group); + + [MagicalRecord saveUsingCurrentContextWithBlock:^(NSManagedObjectContext *localContext) { + NSManagedObject *inserted = [SingleEntityWithNoRelationships MR_createInContext:localContext]; + expect([inserted hasChanges]).to.beTruthy(); + [localContext obtainPermanentIDsForObjects:@[inserted] error:nil]; + objectId = inserted.objectID; + } completion:^(BOOL success, NSError *error) { + expect(success).to.beTruthy(); + dispatch_group_leave(group); + }]; + + dispatch_group_wait(group, DISPATCH_TIME_FOREVER); + fetchedObject = [[NSManagedObjectContext MR_rootSavingContext] objectWithID:objectId]; + expect(fetchedObject).toNot.beNil(); + expect([fetchedObject hasChanges]).to.beFalsy(); +} + +- (void)testCurrentThreadContextSynchronousSavesActuallySave +{ + __block NSManagedObjectID *objectId; + __block NSManagedObject *fetchedObject; + + [MagicalRecord saveUsingCurrentContextWithBlockAndWait:^(NSManagedObjectContext *localContext) { + NSManagedObject *inserted = [SingleEntityWithNoRelationships MR_createInContext:localContext]; + expect([inserted hasChanges]).to.beTruthy(); + [localContext obtainPermanentIDsForObjects:@[inserted] error:nil]; + objectId = inserted.objectID; + }]; + + fetchedObject = [[NSManagedObjectContext MR_rootSavingContext] objectWithID:objectId]; + expect(fetchedObject).toNot.beNil(); + expect([fetchedObject hasChanges]).to.beFalsy(); +} + +#pragma mark - Test deprecated methods still work as expected + +- (void)testDeprecatedSimpleSynchronousSaveActuallySaves +{ + NSManagedObjectContext *managedObjectContext = [NSManagedObjectContext MR_defaultContext]; + NSManagedObject *inserted = [SingleEntityWithNoRelationships MR_createEntity]; + + expect([inserted hasChanges]).to.beTruthy(); + [managedObjectContext obtainPermanentIDsForObjects:@[inserted] error:nil]; + NSManagedObjectID *objectId = inserted.objectID; + + [managedObjectContext MR_save]; + + NSManagedObject *fetchedObject = [[NSManagedObjectContext MR_rootSavingContext] objectWithID:objectId]; + expect(fetchedObject).toNot.beNil(); + expect([fetchedObject hasChanges]).to.beFalsy(); +} + +- (void)testDeprecatedBackgroundSaveCallsCompletionHandler +{ + __block BOOL didSave = NO; + + dispatch_group_t group = dispatch_group_create(); + + dispatch_group_enter(group); + + [MagicalRecord saveInBackgroundWithBlock:^(NSManagedObjectContext *localContext) { + expect(localContext).toNot.beNil(); + [SingleEntityWithNoRelationships MR_createInContext:localContext]; + } completion:^{ + didSave = YES; + dispatch_group_leave(group); + }]; + + dispatch_group_wait(group, DISPATCH_TIME_FOREVER); + expect(didSave).will.beTruthy(); +} + +- (void)testDeprecatedBackgroundSavesActuallySave +{ + __block NSManagedObjectID *objectId; + __block NSManagedObject *fetchedObject; + + dispatch_group_t group = dispatch_group_create(); + + dispatch_group_enter(group); + + [MagicalRecord saveInBackgroundWithBlock:^(NSManagedObjectContext *localContext) { + NSManagedObject *inserted = [SingleEntityWithNoRelationships MR_createInContext:localContext]; + expect([inserted hasChanges]).to.beTruthy(); + [localContext obtainPermanentIDsForObjects:@[inserted] error:nil]; + objectId = inserted.objectID; + } completion:^{ + fetchedObject = [[NSManagedObjectContext MR_rootSavingContext] objectWithID:objectId]; + dispatch_group_leave(group); + }]; + + dispatch_group_wait(group, DISPATCH_TIME_FOREVER); + expect(fetchedObject).toNot.beNil(); + expect([fetchedObject hasChanges]).to.beFalsy(); +} + @end From af84aff8f1fa78b16ac80649538b71c4f65b3dfa Mon Sep 17 00:00:00 2001 From: Tony Arnold Date: Thu, 13 Dec 2012 10:03:45 +1100 Subject: [PATCH 03/10] Fix compilation problems under latest Xcode. --- .../Magical Record.xcodeproj/project.pbxproj | 115 ++++++++---------- .../xcschemes/Mac App Unit Tests.xcscheme | 2 +- .../xcschemes/iOS App Unit Tests.xcscheme | 2 +- 3 files changed, 55 insertions(+), 64 deletions(-) diff --git a/Project Files/Magical Record.xcodeproj/project.pbxproj b/Project Files/Magical Record.xcodeproj/project.pbxproj index f308dc8..0d279cd 100644 --- a/Project Files/Magical Record.xcodeproj/project.pbxproj +++ b/Project Files/Magical Record.xcodeproj/project.pbxproj @@ -7,64 +7,69 @@ objects = { /* Begin PBXBuildFile section */ - 4B7116FD15F8EE4600B64426 /* EXPBackwardCompatibility.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116C215F8EE4600B64426 /* EXPBackwardCompatibility.m */; }; + 4B7116FD15F8EE4600B64426 /* EXPBackwardCompatibility.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116C215F8EE4600B64426 /* EXPBackwardCompatibility.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 4B7116FE15F8EE4600B64426 /* EXPBackwardCompatibility.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116C215F8EE4600B64426 /* EXPBackwardCompatibility.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; - 4B7116FF15F8EE4600B64426 /* EXPBlockDefinedMatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116C415F8EE4600B64426 /* EXPBlockDefinedMatcher.m */; }; + 4B7116FF15F8EE4600B64426 /* EXPBlockDefinedMatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116C415F8EE4600B64426 /* EXPBlockDefinedMatcher.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 4B71170015F8EE4600B64426 /* EXPBlockDefinedMatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116C415F8EE4600B64426 /* EXPBlockDefinedMatcher.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; - 4B71170115F8EE4600B64426 /* EXPDoubleTuple.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116C715F8EE4600B64426 /* EXPDoubleTuple.m */; }; + 4B71170115F8EE4600B64426 /* EXPDoubleTuple.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116C715F8EE4600B64426 /* EXPDoubleTuple.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 4B71170215F8EE4600B64426 /* EXPDoubleTuple.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116C715F8EE4600B64426 /* EXPDoubleTuple.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; - 4B71170315F8EE4600B64426 /* Expecta.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116CA15F8EE4600B64426 /* Expecta.m */; }; + 4B71170315F8EE4600B64426 /* Expecta.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116CA15F8EE4600B64426 /* Expecta.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 4B71170415F8EE4600B64426 /* Expecta.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116CA15F8EE4600B64426 /* Expecta.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; - 4B71170515F8EE4600B64426 /* ExpectaSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116CC15F8EE4600B64426 /* ExpectaSupport.m */; }; + 4B71170515F8EE4600B64426 /* ExpectaSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116CC15F8EE4600B64426 /* ExpectaSupport.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 4B71170615F8EE4600B64426 /* ExpectaSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116CC15F8EE4600B64426 /* ExpectaSupport.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; - 4B71170715F8EE4600B64426 /* EXPExpect.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116CE15F8EE4600B64426 /* EXPExpect.m */; }; + 4B71170715F8EE4600B64426 /* EXPExpect.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116CE15F8EE4600B64426 /* EXPExpect.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 4B71170815F8EE4600B64426 /* EXPExpect.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116CE15F8EE4600B64426 /* EXPExpect.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; - 4B71170915F8EE4600B64426 /* EXPFloatTuple.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116D015F8EE4600B64426 /* EXPFloatTuple.m */; }; + 4B71170915F8EE4600B64426 /* EXPFloatTuple.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116D015F8EE4600B64426 /* EXPFloatTuple.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 4B71170A15F8EE4600B64426 /* EXPFloatTuple.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116D015F8EE4600B64426 /* EXPFloatTuple.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; - 4B71170B15F8EE4600B64426 /* EXPUnsupportedObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116D315F8EE4600B64426 /* EXPUnsupportedObject.m */; }; + 4B71170B15F8EE4600B64426 /* EXPUnsupportedObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116D315F8EE4600B64426 /* EXPUnsupportedObject.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 4B71170C15F8EE4600B64426 /* EXPUnsupportedObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116D315F8EE4600B64426 /* EXPUnsupportedObject.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; - 4B71170D15F8EE4600B64426 /* EXPMatcherHelpers.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116D615F8EE4600B64426 /* EXPMatcherHelpers.m */; }; + 4B71170D15F8EE4600B64426 /* EXPMatcherHelpers.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116D615F8EE4600B64426 /* EXPMatcherHelpers.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 4B71170E15F8EE4600B64426 /* EXPMatcherHelpers.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116D615F8EE4600B64426 /* EXPMatcherHelpers.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; - 4B71170F15F8EE4600B64426 /* EXPMatchers+beCloseTo.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116D815F8EE4600B64426 /* EXPMatchers+beCloseTo.m */; }; + 4B71170F15F8EE4600B64426 /* EXPMatchers+beCloseTo.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116D815F8EE4600B64426 /* EXPMatchers+beCloseTo.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 4B71171015F8EE4600B64426 /* EXPMatchers+beCloseTo.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116D815F8EE4600B64426 /* EXPMatchers+beCloseTo.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; - 4B71171115F8EE4600B64426 /* EXPMatchers+beFalsy.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116DA15F8EE4600B64426 /* EXPMatchers+beFalsy.m */; }; + 4B71171115F8EE4600B64426 /* EXPMatchers+beFalsy.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116DA15F8EE4600B64426 /* EXPMatchers+beFalsy.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 4B71171215F8EE4600B64426 /* EXPMatchers+beFalsy.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116DA15F8EE4600B64426 /* EXPMatchers+beFalsy.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; - 4B71171315F8EE4600B64426 /* EXPMatchers+beGreaterThan.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116DC15F8EE4600B64426 /* EXPMatchers+beGreaterThan.m */; }; + 4B71171315F8EE4600B64426 /* EXPMatchers+beGreaterThan.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116DC15F8EE4600B64426 /* EXPMatchers+beGreaterThan.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 4B71171415F8EE4600B64426 /* EXPMatchers+beGreaterThan.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116DC15F8EE4600B64426 /* EXPMatchers+beGreaterThan.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; - 4B71171515F8EE4600B64426 /* EXPMatchers+beGreaterThanOrEqualTo.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116DE15F8EE4600B64426 /* EXPMatchers+beGreaterThanOrEqualTo.m */; }; + 4B71171515F8EE4600B64426 /* EXPMatchers+beGreaterThanOrEqualTo.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116DE15F8EE4600B64426 /* EXPMatchers+beGreaterThanOrEqualTo.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 4B71171615F8EE4600B64426 /* EXPMatchers+beGreaterThanOrEqualTo.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116DE15F8EE4600B64426 /* EXPMatchers+beGreaterThanOrEqualTo.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; - 4B71171715F8EE4600B64426 /* EXPMatchers+beIdenticalTo.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116E015F8EE4600B64426 /* EXPMatchers+beIdenticalTo.m */; }; + 4B71171715F8EE4600B64426 /* EXPMatchers+beIdenticalTo.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116E015F8EE4600B64426 /* EXPMatchers+beIdenticalTo.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 4B71171815F8EE4600B64426 /* EXPMatchers+beIdenticalTo.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116E015F8EE4600B64426 /* EXPMatchers+beIdenticalTo.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; - 4B71171915F8EE4600B64426 /* EXPMatchers+beInstanceOf.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116E215F8EE4600B64426 /* EXPMatchers+beInstanceOf.m */; }; + 4B71171915F8EE4600B64426 /* EXPMatchers+beInstanceOf.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116E215F8EE4600B64426 /* EXPMatchers+beInstanceOf.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 4B71171A15F8EE4600B64426 /* EXPMatchers+beInstanceOf.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116E215F8EE4600B64426 /* EXPMatchers+beInstanceOf.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; - 4B71171B15F8EE4600B64426 /* EXPMatchers+beInTheRangeOf.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116E415F8EE4600B64426 /* EXPMatchers+beInTheRangeOf.m */; }; + 4B71171B15F8EE4600B64426 /* EXPMatchers+beInTheRangeOf.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116E415F8EE4600B64426 /* EXPMatchers+beInTheRangeOf.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 4B71171C15F8EE4600B64426 /* EXPMatchers+beInTheRangeOf.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116E415F8EE4600B64426 /* EXPMatchers+beInTheRangeOf.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; - 4B71171D15F8EE4600B64426 /* EXPMatchers+beKindOf.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116E615F8EE4600B64426 /* EXPMatchers+beKindOf.m */; }; + 4B71171D15F8EE4600B64426 /* EXPMatchers+beKindOf.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116E615F8EE4600B64426 /* EXPMatchers+beKindOf.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 4B71171E15F8EE4600B64426 /* EXPMatchers+beKindOf.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116E615F8EE4600B64426 /* EXPMatchers+beKindOf.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; - 4B71171F15F8EE4600B64426 /* EXPMatchers+beLessThan.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116E815F8EE4600B64426 /* EXPMatchers+beLessThan.m */; }; + 4B71171F15F8EE4600B64426 /* EXPMatchers+beLessThan.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116E815F8EE4600B64426 /* EXPMatchers+beLessThan.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 4B71172015F8EE4600B64426 /* EXPMatchers+beLessThan.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116E815F8EE4600B64426 /* EXPMatchers+beLessThan.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; - 4B71172115F8EE4600B64426 /* EXPMatchers+beLessThanOrEqualTo.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116EA15F8EE4600B64426 /* EXPMatchers+beLessThanOrEqualTo.m */; }; + 4B71172115F8EE4600B64426 /* EXPMatchers+beLessThanOrEqualTo.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116EA15F8EE4600B64426 /* EXPMatchers+beLessThanOrEqualTo.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 4B71172215F8EE4600B64426 /* EXPMatchers+beLessThanOrEqualTo.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116EA15F8EE4600B64426 /* EXPMatchers+beLessThanOrEqualTo.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; - 4B71172315F8EE4600B64426 /* EXPMatchers+beNil.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116EC15F8EE4600B64426 /* EXPMatchers+beNil.m */; }; + 4B71172315F8EE4600B64426 /* EXPMatchers+beNil.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116EC15F8EE4600B64426 /* EXPMatchers+beNil.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 4B71172415F8EE4600B64426 /* EXPMatchers+beNil.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116EC15F8EE4600B64426 /* EXPMatchers+beNil.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; - 4B71172515F8EE4600B64426 /* EXPMatchers+beSubclassOf.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116EE15F8EE4600B64426 /* EXPMatchers+beSubclassOf.m */; }; + 4B71172515F8EE4600B64426 /* EXPMatchers+beSubclassOf.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116EE15F8EE4600B64426 /* EXPMatchers+beSubclassOf.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 4B71172615F8EE4600B64426 /* EXPMatchers+beSubclassOf.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116EE15F8EE4600B64426 /* EXPMatchers+beSubclassOf.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; - 4B71172715F8EE4600B64426 /* EXPMatchers+beTruthy.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116F015F8EE4600B64426 /* EXPMatchers+beTruthy.m */; }; + 4B71172715F8EE4600B64426 /* EXPMatchers+beTruthy.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116F015F8EE4600B64426 /* EXPMatchers+beTruthy.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 4B71172815F8EE4600B64426 /* EXPMatchers+beTruthy.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116F015F8EE4600B64426 /* EXPMatchers+beTruthy.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; - 4B71172915F8EE4600B64426 /* EXPMatchers+contain.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116F215F8EE4600B64426 /* EXPMatchers+contain.m */; }; + 4B71172915F8EE4600B64426 /* EXPMatchers+contain.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116F215F8EE4600B64426 /* EXPMatchers+contain.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 4B71172A15F8EE4600B64426 /* EXPMatchers+contain.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116F215F8EE4600B64426 /* EXPMatchers+contain.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; - 4B71172B15F8EE4600B64426 /* EXPMatchers+equal.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116F415F8EE4600B64426 /* EXPMatchers+equal.m */; }; + 4B71172B15F8EE4600B64426 /* EXPMatchers+equal.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116F415F8EE4600B64426 /* EXPMatchers+equal.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 4B71172C15F8EE4600B64426 /* EXPMatchers+equal.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116F415F8EE4600B64426 /* EXPMatchers+equal.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; - 4B71172D15F8EE4600B64426 /* EXPMatchers+haveCountOf.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116F615F8EE4600B64426 /* EXPMatchers+haveCountOf.m */; }; + 4B71172D15F8EE4600B64426 /* EXPMatchers+haveCountOf.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116F615F8EE4600B64426 /* EXPMatchers+haveCountOf.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 4B71172E15F8EE4600B64426 /* EXPMatchers+haveCountOf.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116F615F8EE4600B64426 /* EXPMatchers+haveCountOf.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; - 4B71172F15F8EE4600B64426 /* EXPMatchers+raise.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116F815F8EE4600B64426 /* EXPMatchers+raise.m */; }; + 4B71172F15F8EE4600B64426 /* EXPMatchers+raise.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116F815F8EE4600B64426 /* EXPMatchers+raise.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 4B71173015F8EE4600B64426 /* EXPMatchers+raise.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116F815F8EE4600B64426 /* EXPMatchers+raise.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; - 4B71173115F8EE4600B64426 /* NSValue+Expecta.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116FC15F8EE4600B64426 /* NSValue+Expecta.m */; }; + 4B71173115F8EE4600B64426 /* NSValue+Expecta.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116FC15F8EE4600B64426 /* NSValue+Expecta.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 4B71173215F8EE4600B64426 /* NSValue+Expecta.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116FC15F8EE4600B64426 /* NSValue+Expecta.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 4B71173315F9149900B64426 /* SaveTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116BC15F8ED5A00B64426 /* SaveTests.m */; }; 4B71173415F914A400B64426 /* SaveTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116BC15F8ED5A00B64426 /* SaveTests.m */; }; 4B93EA49160ECF1D00FB5676 /* TestModel.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 4B93EA47160ECF1D00FB5676 /* TestModel.xcdatamodeld */; }; 4B93EA4A160ECF1D00FB5676 /* TestModel.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 4B93EA47160ECF1D00FB5676 /* TestModel.xcdatamodeld */; }; + 900E1CC11676E246005FFF1C /* GHUnit.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = C7D2DC22155AFDF500B3A468 /* GHUnit.framework */; }; + 900E1CC21676E246005FFF1C /* OCHamcrest.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = C7D2DC23155AFDF500B3A468 /* OCHamcrest.framework */; }; + 900E1CC31676E246005FFF1C /* OCMock.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = C7D2DC24155AFDF500B3A468 /* OCMock.framework */; }; + 900E1CC81676E27E005FFF1C /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 900E1CC41676E25E005FFF1C /* CoreGraphics.framework */; }; + 900E1CC91676E488005FFF1C /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 900E1CC61676E275005FFF1C /* UIKit.framework */; }; C70B6E7113D0F62500709450 /* NSPersisentStoreHelperTests.m in Sources */ = {isa = PBXBuildFile; fileRef = C70B6E7013D0F62500709450 /* NSPersisentStoreHelperTests.m */; }; C70B6E7413D0F64000709450 /* NSPersistentStoreCoordinatorHelperTests.m in Sources */ = {isa = PBXBuildFile; fileRef = C70B6E7313D0F64000709450 /* NSPersistentStoreCoordinatorHelperTests.m */; }; C70B6E7713D0F66000709450 /* NSManagedObjectModelHelperTests.m in Sources */ = {isa = PBXBuildFile; fileRef = C70B6E7613D0F66000709450 /* NSManagedObjectModelHelperTests.m */; }; @@ -104,8 +109,6 @@ C76AF7FC13DBEB5500CE2E05 /* ImportSingleRelatedEntityTests.m in Sources */ = {isa = PBXBuildFile; fileRef = C76AF7FA13DBEB5500CE2E05 /* ImportSingleRelatedEntityTests.m */; }; C76AF82A13DBEE5A00CE2E05 /* SingleRelatedEntity.json in Resources */ = {isa = PBXBuildFile; fileRef = C76AF82913DBEE5A00CE2E05 /* SingleRelatedEntity.json */; }; C76AF82B13DBEE5A00CE2E05 /* SingleRelatedEntity.json in Resources */ = {isa = PBXBuildFile; fileRef = C76AF82913DBEE5A00CE2E05 /* SingleRelatedEntity.json */; }; - C76D3EF715718EBC00B2D163 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C76D3EF615718EBC00B2D163 /* UIKit.framework */; }; - C76D3EF915718EC800B2D163 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C76D3EF815718EC800B2D163 /* CoreGraphics.framework */; }; C77E5F9B13D0CA0A00298F87 /* CoreData.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C721C7E213D0C3A00097AB6F /* CoreData.framework */; }; C77E5FA813D0CBDE00298F87 /* MagicalRecordTests.m in Sources */ = {isa = PBXBuildFile; fileRef = C77E5FA713D0CBDE00298F87 /* MagicalRecordTests.m */; }; C77E5FB313D0D1D100298F87 /* SingleEntityWithNoRelationships.plist in Resources */ = {isa = PBXBuildFile; fileRef = C77E5FB213D0D1D100298F87 /* SingleEntityWithNoRelationships.plist */; }; @@ -231,7 +234,6 @@ C7DD7307150F832B00216827 /* MagicalRecord.m in Sources */ = {isa = PBXBuildFile; fileRef = C7DD72D2150F832A00216827 /* MagicalRecord.m */; }; C7DD7308150F832B00216827 /* MagicalRecord.m in Sources */ = {isa = PBXBuildFile; fileRef = C7DD72D2150F832A00216827 /* MagicalRecord.m */; }; C7E736DF1402FE64005657C9 /* SingleEntityWithNoRelationships.json in Resources */ = {isa = PBXBuildFile; fileRef = C7E736DE1402FE64005657C9 /* SingleEntityWithNoRelationships.json */; }; - C7F5EEB2148DC76700964607 /* (null) in Sources */ = {isa = PBXBuildFile; }; FD73E54614AC4AC700922CA4 /* MagicalDataImportTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = C7913B9C13FAFC13007E09CC /* MagicalDataImportTestCase.m */; }; /* End PBXBuildFile section */ @@ -249,26 +251,6 @@ /* End PBXBuildRule section */ /* Begin PBXCopyFilesBuildPhase section */ - C753897513DB6310002B2F57 /* Copy GHUnit into App Bundle */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - ); - name = "Copy GHUnit into App Bundle"; - runOnlyForDeploymentPostprocessing = 0; - }; - C76AF7F313DBC33100CE2E05 /* Copy OCHamcrest into App Bundle */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 16; - files = ( - ); - name = "Copy OCHamcrest into App Bundle"; - runOnlyForDeploymentPostprocessing = 0; - }; C7E37A7B14157BE600CE9BF5 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -278,13 +260,17 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - FD73E54714AC4D5200922CA4 /* CopyFiles */ = { + FD73E54714AC4D5200922CA4 /* Copy Frameworks */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; dstSubfolderSpec = 10; files = ( + 900E1CC11676E246005FFF1C /* GHUnit.framework in Copy Frameworks */, + 900E1CC21676E246005FFF1C /* OCHamcrest.framework in Copy Frameworks */, + 900E1CC31676E246005FFF1C /* OCMock.framework in Copy Frameworks */, ); + name = "Copy Frameworks"; runOnlyForDeploymentPostprocessing = 0; }; /* End PBXCopyFilesBuildPhase section */ @@ -352,6 +338,8 @@ 4B7116FB15F8EE4600B64426 /* NSValue+Expecta.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSValue+Expecta.h"; sourceTree = ""; }; 4B7116FC15F8EE4600B64426 /* NSValue+Expecta.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSValue+Expecta.m"; sourceTree = ""; }; 4B93EA48160ECF1D00FB5676 /* TestModel.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = TestModel.xcdatamodel; sourceTree = ""; }; + 900E1CC41676E25E005FFF1C /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.1.sdk/System/Library/Frameworks/CoreGraphics.framework; sourceTree = DEVELOPER_DIR; }; + 900E1CC61676E275005FFF1C /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.1.sdk/System/Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; }; C70B6E6F13D0F62500709450 /* NSPersisentStoreHelperTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NSPersisentStoreHelperTests.h; path = "Unit Tests/NSPersisentStoreHelperTests.h"; sourceTree = ""; }; C70B6E7013D0F62500709450 /* NSPersisentStoreHelperTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NSPersisentStoreHelperTests.m; path = "Unit Tests/NSPersisentStoreHelperTests.m"; sourceTree = ""; }; C70B6E7213D0F64000709450 /* NSPersistentStoreCoordinatorHelperTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NSPersistentStoreCoordinatorHelperTests.h; path = "Unit Tests/NSPersistentStoreCoordinatorHelperTests.h"; sourceTree = ""; }; @@ -389,8 +377,6 @@ C763783113E10BEC0009A6CA /* GHUnitIOSTestMain.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GHUnitIOSTestMain.m; sourceTree = ""; }; C76AF7FA13DBEB5500CE2E05 /* ImportSingleRelatedEntityTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ImportSingleRelatedEntityTests.m; path = "Unit Tests/ImportSingleRelatedEntityTests.m"; sourceTree = ""; }; C76AF82913DBEE5A00CE2E05 /* SingleRelatedEntity.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = SingleRelatedEntity.json; path = "Unit Tests/Fixtures/SingleRelatedEntity.json"; sourceTree = ""; }; - C76D3EF615718EBC00B2D163 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk/System/Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; }; - C76D3EF815718EC800B2D163 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk/System/Library/Frameworks/CoreGraphics.framework; sourceTree = DEVELOPER_DIR; }; C77E5FA613D0CBDE00298F87 /* MagicalRecordTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MagicalRecordTests.h; path = "Unit Tests/MagicalRecordTests.h"; sourceTree = ""; }; C77E5FA713D0CBDE00298F87 /* MagicalRecordTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MagicalRecordTests.m; path = "Unit Tests/MagicalRecordTests.m"; sourceTree = ""; }; C77E5FB213D0D1D100298F87 /* SingleEntityWithNoRelationships.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = SingleEntityWithNoRelationships.plist; path = "Unit Tests/Fixtures/SingleEntityWithNoRelationships.plist"; sourceTree = ""; }; @@ -535,8 +521,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - C76D3EF915718EC800B2D163 /* CoreGraphics.framework in Frameworks */, - C76D3EF715718EBC00B2D163 /* UIKit.framework in Frameworks */, + 900E1CC91676E488005FFF1C /* UIKit.framework in Frameworks */, + 900E1CC81676E27E005FFF1C /* CoreGraphics.framework in Frameworks */, C721C82513D0C4660097AB6F /* Foundation.framework in Frameworks */, C77E5F9B13D0CA0A00298F87 /* CoreData.framework in Frameworks */, C74F8E611555E39D0008B054 /* OCHamcrestIOS.framework in Frameworks */, @@ -700,8 +686,8 @@ C721C82E13D0C6390097AB6F /* Frameworks */ = { isa = PBXGroup; children = ( - C76D3EF815718EC800B2D163 /* CoreGraphics.framework */, - C76D3EF615718EBC00B2D163 /* UIKit.framework */, + 900E1CC61676E275005FFF1C /* UIKit.framework */, + 900E1CC41676E25E005FFF1C /* CoreGraphics.framework */, C7D2DC29155AFE6D00B3A468 /* GHUnitIOS.framework */, C74F8E551555E39D0008B054 /* OCHamcrestIOS.framework */, C74F8E561555E39D0008B054 /* OCMockLibrary */, @@ -1018,9 +1004,7 @@ C721C7D813D0C3A00097AB6F /* Sources */, C721C7D913D0C3A00097AB6F /* Frameworks */, C721C7DA13D0C3A00097AB6F /* Resources */, - C753897513DB6310002B2F57 /* Copy GHUnit into App Bundle */, - C76AF7F313DBC33100CE2E05 /* Copy OCHamcrest into App Bundle */, - FD73E54714AC4D5200922CA4 /* CopyFiles */, + FD73E54714AC4D5200922CA4 /* Copy Frameworks */, ); buildRules = ( ); @@ -1058,7 +1042,7 @@ C721C7A213D0A3750097AB6F /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0450; + LastUpgradeCheck = 0460; ORGANIZATIONNAME = "Magical Panda Software LLC"; }; buildConfigurationList = C721C7A513D0A3750097AB6F /* Build configuration list for PBXProject "Magical Record" */; @@ -1181,7 +1165,6 @@ C76AF7EB13DBC08F00CE2E05 /* NSManagedObjectContextHelperTests.m in Sources */, C76AF7EC13DBC08F00CE2E05 /* NSManagedObjectHelperTests.m in Sources */, C76AF7FB13DBEB5500CE2E05 /* ImportSingleRelatedEntityTests.m in Sources */, - C7F5EEB2148DC76700964607 /* (null) in Sources */, C78990211506937E0016F493 /* MappedEntity.m in Sources */, C7899022150693D50016F493 /* _SingleEntityRelatedToMappedEntityWithSecondaryMappings.m in Sources */, C7899023150693D50016F493 /* _AbstractRelatedEntity.m in Sources */, @@ -1405,19 +1388,23 @@ buildSettings = { CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; GCC_TREAT_WARNINGS_AS_ERRORS = NO; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; GCC_WARN_ABOUT_MISSING_NEWLINE = YES; GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; GCC_WARN_SHADOW = YES; GCC_WARN_SIGN_COMPARE = YES; GCC_WARN_STRICT_SELECTOR_MATCH = YES; GCC_WARN_UNDECLARED_SELECTOR = NO; + GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_LABEL = YES; + GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 4.3; MACOSX_DEPLOYMENT_TARGET = 10.7; SDKROOT = ""; @@ -1429,19 +1416,23 @@ buildSettings = { CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; GCC_TREAT_WARNINGS_AS_ERRORS = NO; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; GCC_WARN_ABOUT_MISSING_NEWLINE = YES; GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; GCC_WARN_SHADOW = YES; GCC_WARN_SIGN_COMPARE = YES; GCC_WARN_STRICT_SELECTOR_MATCH = YES; GCC_WARN_UNDECLARED_SELECTOR = NO; + GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_LABEL = YES; + GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 4.3; MACOSX_DEPLOYMENT_TARGET = 10.7; SDKROOT = ""; diff --git a/Project Files/Magical Record.xcodeproj/xcshareddata/xcschemes/Mac App Unit Tests.xcscheme b/Project Files/Magical Record.xcodeproj/xcshareddata/xcschemes/Mac App Unit Tests.xcscheme index 1e83068..59032b7 100644 --- a/Project Files/Magical Record.xcodeproj/xcshareddata/xcschemes/Mac App Unit Tests.xcscheme +++ b/Project Files/Magical Record.xcodeproj/xcshareddata/xcschemes/Mac App Unit Tests.xcscheme @@ -1,6 +1,6 @@ Date: Thu, 13 Dec 2012 13:55:36 +1100 Subject: [PATCH 04/10] Update gitignore and remove user specific xcuserdata --- .gitignore | 30 ++++++------- .../WorkspaceSettings.xcsettings | 22 ---------- .../xcschemes/xcschememanagement.plist | 42 ------------------- 3 files changed, 13 insertions(+), 81 deletions(-) delete mode 100644 Project Files/Magical Record.xcodeproj/project.xcworkspace/xcuserdata/saul.xcuserdatad/WorkspaceSettings.xcsettings delete mode 100644 Project Files/Magical Record.xcodeproj/xcuserdata/saul.xcuserdatad/xcschemes/xcschememanagement.plist diff --git a/.gitignore b/.gitignore index 642b180..c8f953d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,23 +1,19 @@ +# Finder .DS_Store -*.swp -*~.nib - -build/ +# Xcode +build/* *.pbxuser -*.perspective -*.perspectivev3 - -.hg -.hgtags - +!default.pbxuser *.mode1v3 +!default.mode1v3 *.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +*.xcworkspace +!default.xcworkspace +xcuserdata +profile +*.moved-aside -UserInterfaceState.xcuserstate -/Magical Record.xcodeproj/project.xcworkspace/xcuserdata/saul.xcuserdatad/UserInterfaceState.xcuserstate -/Magical Record.xcodeproj/xcuserdata/saul.xcuserdatad/xcdebugger/Breakpoints.xcbkptlist -/Magical Record.xcodeproj/xcuserdata/gfurman.xcuserdatad -Project Files/Magical Record.xcodeproj/xcuserdata -Project Files/MagicalRecord.xcodeproj/xcuserdata/saul.xcuserdatad/xcdebugger/Breakpoints.xcbkptlist -Project Files/MagicalRecord.xcodeproj/xcuserdata/saul.xcuserdatad/xcschemes/iOS Test Runner.xcscheme diff --git a/Project Files/Magical Record.xcodeproj/project.xcworkspace/xcuserdata/saul.xcuserdatad/WorkspaceSettings.xcsettings b/Project Files/Magical Record.xcodeproj/project.xcworkspace/xcuserdata/saul.xcuserdatad/WorkspaceSettings.xcsettings deleted file mode 100644 index 714aa1c..0000000 --- a/Project Files/Magical Record.xcodeproj/project.xcworkspace/xcuserdata/saul.xcuserdatad/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,22 +0,0 @@ - - - - - IDEWorkspaceUserSettings_BuildLocationStyle - 0 - IDEWorkspaceUserSettings_BuildSubfolderNameStyle - 0 - IDEWorkspaceUserSettings_DerivedDataLocationStyle - 0 - IDEWorkspaceUserSettings_HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges - - IDEWorkspaceUserSettings_IssueFilterStyle - 0 - IDEWorkspaceUserSettings_LiveSourceIssuesEnabled - - IDEWorkspaceUserSettings_SnapshotAutomaticallyBeforeSignificantChanges - - IDEWorkspaceUserSettings_SnapshotLocationStyle - 0 - - diff --git a/Project Files/Magical Record.xcodeproj/xcuserdata/saul.xcuserdatad/xcschemes/xcschememanagement.plist b/Project Files/Magical Record.xcodeproj/xcuserdata/saul.xcuserdatad/xcschemes/xcschememanagement.plist deleted file mode 100644 index c6c227e..0000000 --- a/Project Files/Magical Record.xcodeproj/xcuserdata/saul.xcuserdatad/xcschemes/xcschememanagement.plist +++ /dev/null @@ -1,42 +0,0 @@ - - - - - SchemeUserState - - Mac App Unit Tests.xcscheme_^#shared#^_ - - orderHint - 1 - - iOS App Unit Tests.xcscheme_^#shared#^_ - - orderHint - 0 - - - SuppressBuildableAutocreation - - C721C7AF13D0A3AF0097AB6F - - primary - - - C721C7DB13D0C3A00097AB6F - - primary - - - C721C7FC13D0C3CD0097AB6F - - primary - - - C738F55613F1CC0200CD5F2C - - primary - - - - - From 55af799d60fff099430faf0aca4567e049640081 Mon Sep 17 00:00:00 2001 From: Tony Arnold Date: Sun, 16 Dec 2012 18:39:05 +1100 Subject: [PATCH 05/10] Add Kiwi for saner asynchronous testing and remove existing GHUnit tests for save methods --- .gitmodules | 3 + .../Mac Unit Tests/Mac Unit Tests-Info.plist | 22 + .../Mac Unit Tests/Mac Unit Tests-Prefix.pch | 7 + .../MagicalRecord+ActionsSpec.m | 31 ++ .../NSManagedObjectContext+MagicalSavesSpec.m | 31 ++ .../Magical Record.xcodeproj/project.pbxproj | 432 +++++++++++++++++- .../xcschemes/Mac Unit Tests.xcscheme | 69 +++ Project Files/Third Party/Kiwi | 1 + Project Files/Unit Tests/SaveTests.h | 13 - 9 files changed, 588 insertions(+), 21 deletions(-) create mode 100644 .gitmodules create mode 100644 Project Files/Mac Unit Tests/Mac Unit Tests-Info.plist create mode 100644 Project Files/Mac Unit Tests/Mac Unit Tests-Prefix.pch create mode 100644 Project Files/Mac Unit Tests/MagicalRecord+ActionsSpec.m create mode 100644 Project Files/Mac Unit Tests/NSManagedObjectContext+MagicalSavesSpec.m create mode 100644 Project Files/Magical Record.xcodeproj/xcshareddata/xcschemes/Mac Unit Tests.xcscheme create mode 160000 Project Files/Third Party/Kiwi delete mode 100644 Project Files/Unit Tests/SaveTests.h diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..39df517 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "Project Files/Third Party/Kiwi"] + path = Project Files/Third Party/Kiwi + url = git://github.com/allending/Kiwi.git diff --git a/Project Files/Mac Unit Tests/Mac Unit Tests-Info.plist b/Project Files/Mac Unit Tests/Mac Unit Tests-Info.plist new file mode 100644 index 0000000..4eced61 --- /dev/null +++ b/Project Files/Mac Unit Tests/Mac Unit Tests-Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + com.magicalpanda.${PRODUCT_NAME:rfc1034identifier} + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/Project Files/Mac Unit Tests/Mac Unit Tests-Prefix.pch b/Project Files/Mac Unit Tests/Mac Unit Tests-Prefix.pch new file mode 100644 index 0000000..ebb8d47 --- /dev/null +++ b/Project Files/Mac Unit Tests/Mac Unit Tests-Prefix.pch @@ -0,0 +1,7 @@ +// +// Prefix header for all source files of the 'Mac Unit Tests' target in the 'Mac Unit Tests' project +// + +#ifdef __OBJC__ + #import +#endif diff --git a/Project Files/Mac Unit Tests/MagicalRecord+ActionsSpec.m b/Project Files/Mac Unit Tests/MagicalRecord+ActionsSpec.m new file mode 100644 index 0000000..2e078ce --- /dev/null +++ b/Project Files/Mac Unit Tests/MagicalRecord+ActionsSpec.m @@ -0,0 +1,31 @@ +#import "Kiwi.h" + +// Project +#import "MagicalRecord_Actions.h" + +SPEC_BEGIN(MagicalRecord_ActionsSpec) + +describe(@"MagicalRecord_Actions", ^{ + beforeAll(^{ + // Occurs once + }); + + afterAll(^{ + // Occurs once + }); + + beforeEach(^{ + // Occurs before each enclosed "it" block + }); + + afterEach(^{ + // Occurs after each enclosed "it" block + }); + + it(@"should really test something", ^{ + // Test something + pending(@" — sadly, you've only just created this spec, so it's currently unimplemented", nil); + }); +}); + +SPEC_END diff --git a/Project Files/Mac Unit Tests/NSManagedObjectContext+MagicalSavesSpec.m b/Project Files/Mac Unit Tests/NSManagedObjectContext+MagicalSavesSpec.m new file mode 100644 index 0000000..2e52668 --- /dev/null +++ b/Project Files/Mac Unit Tests/NSManagedObjectContext+MagicalSavesSpec.m @@ -0,0 +1,31 @@ +#import "Kiwi.h" + +// Project +#import "NSManagedObjectContext_MagicalSaves.h" + +SPEC_BEGIN(NSManagedObjectContext_MagicalSavesSpec) + +describe(@"NSManagedObjectContext_MagicalSaves", ^{ + beforeAll(^{ + // Occurs once + }); + + afterAll(^{ + // Occurs once + }); + + beforeEach(^{ + // Occurs before each enclosed "it" block + }); + + afterEach(^{ + // Occurs after each enclosed "it" block + }); + + it(@"should really test something", ^{ + // Test something + pending(@" — sadly, you've only just created this spec, so it's currently unimplemented", nil); + }); +}); + +SPEC_END diff --git a/Project Files/Magical Record.xcodeproj/project.pbxproj b/Project Files/Magical Record.xcodeproj/project.pbxproj index 0d279cd..55c25d3 100644 --- a/Project Files/Magical Record.xcodeproj/project.pbxproj +++ b/Project Files/Magical Record.xcodeproj/project.pbxproj @@ -61,8 +61,6 @@ 4B71173015F8EE4600B64426 /* EXPMatchers+raise.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116F815F8EE4600B64426 /* EXPMatchers+raise.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 4B71173115F8EE4600B64426 /* NSValue+Expecta.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116FC15F8EE4600B64426 /* NSValue+Expecta.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 4B71173215F8EE4600B64426 /* NSValue+Expecta.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116FC15F8EE4600B64426 /* NSValue+Expecta.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; - 4B71173315F9149900B64426 /* SaveTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116BC15F8ED5A00B64426 /* SaveTests.m */; }; - 4B71173415F914A400B64426 /* SaveTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7116BC15F8ED5A00B64426 /* SaveTests.m */; }; 4B93EA49160ECF1D00FB5676 /* TestModel.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 4B93EA47160ECF1D00FB5676 /* TestModel.xcdatamodeld */; }; 4B93EA4A160ECF1D00FB5676 /* TestModel.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 4B93EA47160ECF1D00FB5676 /* TestModel.xcdatamodeld */; }; 900E1CC11676E246005FFF1C /* GHUnit.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = C7D2DC22155AFDF500B3A468 /* GHUnit.framework */; }; @@ -70,6 +68,71 @@ 900E1CC31676E246005FFF1C /* OCMock.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = C7D2DC24155AFDF500B3A468 /* OCMock.framework */; }; 900E1CC81676E27E005FFF1C /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 900E1CC41676E25E005FFF1C /* CoreGraphics.framework */; }; 900E1CC91676E488005FFF1C /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 900E1CC61676E275005FFF1C /* UIKit.framework */; }; + 90DD2047167AA4630033BA25 /* SenTestingKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 90DD2045167AA45B0033BA25 /* SenTestingKit.framework */; }; + 90DD204A167AA46D0033BA25 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 90DD2048167AA4670033BA25 /* Cocoa.framework */; }; + 90DD204B167AA46F0033BA25 /* libKiwi-OSX.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 90DD203E167AA44D0033BA25 /* libKiwi-OSX.a */; }; + 90DD204E167AA4E10033BA25 /* MagicalRecord+ActionsSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 90DD204D167AA4E10033BA25 /* MagicalRecord+ActionsSpec.m */; }; + 90DD2054167AA6C80033BA25 /* MappedEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = C784348E13F0FEE000463CEE /* MappedEntity.m */; }; + 90DD2055167AA6C80033BA25 /* AbstractRelatedEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = C7BD888313DBFA6200274567 /* AbstractRelatedEntity.m */; }; + 90DD2056167AA6C80033BA25 /* ConcreteRelatedEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = C7BD888513DBFA6200274567 /* ConcreteRelatedEntity.m */; }; + 90DD2057167AA6C80033BA25 /* DifferentClassNameMapping.m in Sources */ = {isa = PBXBuildFile; fileRef = C7BD888713DBFA6200274567 /* DifferentClassNameMapping.m */; }; + 90DD2058167AA6C80033BA25 /* SingleEntityWithNoRelationships.m in Sources */ = {isa = PBXBuildFile; fileRef = C7BD888913DBFA6200274567 /* SingleEntityWithNoRelationships.m */; }; + 90DD2059167AA6C80033BA25 /* SingleRelatedEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = C7BD888B13DBFA6200274567 /* SingleRelatedEntity.m */; }; + 90DD205A167AA6C80033BA25 /* SingleEntityRelatedToMappedEntityWithSecondaryMappings.m in Sources */ = {isa = PBXBuildFile; fileRef = C78F8FD913FDC3F400549DD8 /* SingleEntityRelatedToMappedEntityWithSecondaryMappings.m */; }; + 90DD205B167AA6C80033BA25 /* SingleEntityRelatedToMappedEntityUsingDefaults.m in Sources */ = {isa = PBXBuildFile; fileRef = C7C9A38713F4524B002C5B0C /* SingleEntityRelatedToMappedEntityUsingDefaults.m */; }; + 90DD205C167AA6C80033BA25 /* SingleEntityRelatedToMappedEntityUsingMappedPrimaryKey.m in Sources */ = {isa = PBXBuildFile; fileRef = C7C9A38913F4524B002C5B0C /* SingleEntityRelatedToMappedEntityUsingMappedPrimaryKey.m */; }; + 90DD205D167AA6C80033BA25 /* SingleEntityRelatedToManyMappedEntitiesUsingMappedPrimaryKey.m in Sources */ = {isa = PBXBuildFile; fileRef = C7913B9813FAEDF8007E09CC /* SingleEntityRelatedToManyMappedEntitiesUsingMappedPrimaryKey.m */; }; + 90DD205E167AA6C80033BA25 /* SingleEntityRelatedToMappedEntityWithNestedMappedAttributes.m in Sources */ = {isa = PBXBuildFile; fileRef = C7913BA813FB1D2A007E09CC /* SingleEntityRelatedToMappedEntityWithNestedMappedAttributes.m */; }; + 90DD205F167AA6CC0033BA25 /* TestModel.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 4B93EA47160ECF1D00FB5676 /* TestModel.xcdatamodeld */; }; + 90DD2060167AA6D80033BA25 /* _SingleEntityRelatedToMappedEntityWithSecondaryMappings.m in Sources */ = {isa = PBXBuildFile; fileRef = C78F8FDC13FDC3FD00549DD8 /* _SingleEntityRelatedToMappedEntityWithSecondaryMappings.m */; }; + 90DD2061167AA6D80033BA25 /* _AbstractRelatedEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = C7BD887913DBFA6200274567 /* _AbstractRelatedEntity.m */; }; + 90DD2062167AA6D80033BA25 /* _ConcreteRelatedEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = C7BD887B13DBFA6200274567 /* _ConcreteRelatedEntity.m */; }; + 90DD2063167AA6D80033BA25 /* _DifferentClassNameMapping.m in Sources */ = {isa = PBXBuildFile; fileRef = C7BD887D13DBFA6200274567 /* _DifferentClassNameMapping.m */; }; + 90DD2064167AA6D80033BA25 /* _SingleEntityWithNoRelationships.m in Sources */ = {isa = PBXBuildFile; fileRef = C7BD887F13DBFA6200274567 /* _SingleEntityWithNoRelationships.m */; }; + 90DD2065167AA6D80033BA25 /* _SingleEntityRelatedToManyMappedEntitiesUsingMappedPrimaryKey.m in Sources */ = {isa = PBXBuildFile; fileRef = C7913B9413FAEDE9007E09CC /* _SingleEntityRelatedToManyMappedEntitiesUsingMappedPrimaryKey.m */; }; + 90DD2066167AA6D80033BA25 /* _SingleRelatedEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = C7BD888113DBFA6200274567 /* _SingleRelatedEntity.m */; }; + 90DD2067167AA6D80033BA25 /* _MappedEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = C784348C13F0FEE000463CEE /* _MappedEntity.m */; }; + 90DD2068167AA6D80033BA25 /* _SingleEntityRelatedToMappedEntityUsingDefaults.m in Sources */ = {isa = PBXBuildFile; fileRef = C7C9A38113F45240002C5B0C /* _SingleEntityRelatedToMappedEntityUsingDefaults.m */; }; + 90DD2069167AA6D80033BA25 /* _SingleEntityRelatedToMappedEntityUsingMappedPrimaryKey.m in Sources */ = {isa = PBXBuildFile; fileRef = C7C9A38313F45240002C5B0C /* _SingleEntityRelatedToMappedEntityUsingMappedPrimaryKey.m */; }; + 90DD206A167AA6D80033BA25 /* _SingleEntityRelatedToMappedEntityWithNestedMappedAttributes.m in Sources */ = {isa = PBXBuildFile; fileRef = C7913BA513FB1D17007E09CC /* _SingleEntityRelatedToMappedEntityWithNestedMappedAttributes.m */; }; + 90DD206B167AA6DF0033BA25 /* SingleEntityWithNoRelationships.plist in Resources */ = {isa = PBXBuildFile; fileRef = C77E5FB213D0D1D100298F87 /* SingleEntityWithNoRelationships.plist */; }; + 90DD206C167AA6DF0033BA25 /* SingleEntityWithNoRelationships.json in Resources */ = {isa = PBXBuildFile; fileRef = C7E736DE1402FE64005657C9 /* SingleEntityWithNoRelationships.json */; }; + 90DD206D167AA6DF0033BA25 /* SampleJSONDataForImport.json in Resources */ = {isa = PBXBuildFile; fileRef = C77E5FB413D0D1EC00298F87 /* SampleJSONDataForImport.json */; }; + 90DD206E167AA6DF0033BA25 /* SingleRelatedEntity.json in Resources */ = {isa = PBXBuildFile; fileRef = C76AF82913DBEE5A00CE2E05 /* SingleRelatedEntity.json */; }; + 90DD206F167AA6DF0033BA25 /* SingleEntityRelatedToMappedEntityUsingMappedPrimaryKey.json in Resources */ = {isa = PBXBuildFile; fileRef = C7C9A37C13F44B08002C5B0C /* SingleEntityRelatedToMappedEntityUsingMappedPrimaryKey.json */; }; + 90DD2070167AA6DF0033BA25 /* SingleEntityRelatedToMappedEntityUsingDefaults.json in Resources */ = {isa = PBXBuildFile; fileRef = C7C9A37E13F44B29002C5B0C /* SingleEntityRelatedToMappedEntityUsingDefaults.json */; }; + 90DD2071167AA6DF0033BA25 /* SingleEntityRelatedToManyMappedEntitiesUsingMappedPrimaryKey.json in Resources */ = {isa = PBXBuildFile; fileRef = C7B7379913FAE5D500EE4940 /* SingleEntityRelatedToManyMappedEntitiesUsingMappedPrimaryKey.json */; }; + 90DD2072167AA6DF0033BA25 /* SingleEntityRelatedToMappedEntityWithNestedMappedAttributes.json in Resources */ = {isa = PBXBuildFile; fileRef = C7913BAE13FB1E11007E09CC /* SingleEntityRelatedToMappedEntityWithNestedMappedAttributes.json */; }; + 90DD2073167AA6DF0033BA25 /* SingleEntityRelatedToMappedEntityWithSecondaryMappings.json in Resources */ = {isa = PBXBuildFile; fileRef = C78F8FD213FDC2B600549DD8 /* SingleEntityRelatedToMappedEntityWithSecondaryMappings.json */; }; + 90DD2074167AA6DF0033BA25 /* SingleEntityRelatedToManyMappedEntitiesUsingListOfPrimaryKeys.json in Resources */ = {isa = PBXBuildFile; fileRef = C7381275141037E80054EEF0 /* SingleEntityRelatedToManyMappedEntitiesUsingListOfPrimaryKeys.json */; }; + 90DD2076167AA7050033BA25 /* MagicalRecord.m in Sources */ = {isa = PBXBuildFile; fileRef = C7DD72D2150F832A00216827 /* MagicalRecord.m */; }; + 90DD2077167AA7050033BA25 /* MagicalRecord+Actions.m in Sources */ = {isa = PBXBuildFile; fileRef = C7DD72C6150F832A00216827 /* MagicalRecord+Actions.m */; }; + 90DD2078167AA7050033BA25 /* MagicalRecord+ErrorHandling.m in Sources */ = {isa = PBXBuildFile; fileRef = C7DD72C8150F832A00216827 /* MagicalRecord+ErrorHandling.m */; }; + 90DD2079167AA7050033BA25 /* MagicalRecord+iCloud.m in Sources */ = {isa = PBXBuildFile; fileRef = C7DD72CA150F832A00216827 /* MagicalRecord+iCloud.m */; }; + 90DD207A167AA7050033BA25 /* MagicalRecord+Options.m in Sources */ = {isa = PBXBuildFile; fileRef = C7DD72CC150F832A00216827 /* MagicalRecord+Options.m */; }; + 90DD207B167AA7050033BA25 /* MagicalRecord+Setup.m in Sources */ = {isa = PBXBuildFile; fileRef = C7DD72CE150F832A00216827 /* MagicalRecord+Setup.m */; }; + 90DD207C167AA7050033BA25 /* MagicalRecord+ShorthandSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = C7DD72D0150F832A00216827 /* MagicalRecord+ShorthandSupport.m */; }; + 90DD207D167AA7080033BA25 /* NSManagedObjectModel+MagicalRecord.m in Sources */ = {isa = PBXBuildFile; fileRef = C7DD72BF150F832A00216827 /* NSManagedObjectModel+MagicalRecord.m */; }; + 90DD207E167AA7080033BA25 /* NSPersistentStore+MagicalRecord.m in Sources */ = {isa = PBXBuildFile; fileRef = C7DD72C1150F832A00216827 /* NSPersistentStore+MagicalRecord.m */; }; + 90DD207F167AA7080033BA25 /* NSPersistentStoreCoordinator+MagicalRecord.m in Sources */ = {isa = PBXBuildFile; fileRef = C7DD72C3150F832A00216827 /* NSPersistentStoreCoordinator+MagicalRecord.m */; }; + 90DD2080167AA70E0033BA25 /* MagicalImportFunctions.m in Sources */ = {isa = PBXBuildFile; fileRef = C7DD729D150F832A00216827 /* MagicalImportFunctions.m */; }; + 90DD2081167AA70E0033BA25 /* NSEntityDescription+MagicalDataImport.m in Sources */ = {isa = PBXBuildFile; fileRef = C7DD72A1150F832A00216827 /* NSEntityDescription+MagicalDataImport.m */; }; + 90DD2082167AA70E0033BA25 /* NSAttributeDescription+MagicalDataImport.m in Sources */ = {isa = PBXBuildFile; fileRef = C7DD729F150F832A00216827 /* NSAttributeDescription+MagicalDataImport.m */; }; + 90DD2083167AA70E0033BA25 /* NSRelationshipDescription+MagicalDataImport.m in Sources */ = {isa = PBXBuildFile; fileRef = C7DD72A7150F832A00216827 /* NSRelationshipDescription+MagicalDataImport.m */; }; + 90DD2084167AA70E0033BA25 /* NSNumber+MagicalDataImport.m in Sources */ = {isa = PBXBuildFile; fileRef = C7DD72A3150F832A00216827 /* NSNumber+MagicalDataImport.m */; }; + 90DD2085167AA70E0033BA25 /* NSObject+MagicalDataImport.m in Sources */ = {isa = PBXBuildFile; fileRef = C7DD72A5150F832A00216827 /* NSObject+MagicalDataImport.m */; }; + 90DD2086167AA70E0033BA25 /* NSString+MagicalDataImport.m in Sources */ = {isa = PBXBuildFile; fileRef = C7DD72A9150F832A00216827 /* NSString+MagicalDataImport.m */; }; + 90DD2087167AA7130033BA25 /* NSManagedObject+MagicalAggregation.m in Sources */ = {isa = PBXBuildFile; fileRef = C7DD72AC150F832A00216827 /* NSManagedObject+MagicalAggregation.m */; }; + 90DD2088167AA7130033BA25 /* NSManagedObject+MagicalDataImport.m in Sources */ = {isa = PBXBuildFile; fileRef = C7DD72AE150F832A00216827 /* NSManagedObject+MagicalDataImport.m */; }; + 90DD2089167AA7130033BA25 /* NSManagedObject+MagicalFinders.m in Sources */ = {isa = PBXBuildFile; fileRef = C7DD72B0150F832A00216827 /* NSManagedObject+MagicalFinders.m */; }; + 90DD208A167AA7130033BA25 /* NSManagedObject+MagicalRecord.m in Sources */ = {isa = PBXBuildFile; fileRef = C7DD72B2150F832A00216827 /* NSManagedObject+MagicalRecord.m */; }; + 90DD208B167AA7130033BA25 /* NSManagedObject+MagicalRequests.m in Sources */ = {isa = PBXBuildFile; fileRef = C7DD72B4150F832A00216827 /* NSManagedObject+MagicalRequests.m */; }; + 90DD208C167AA7180033BA25 /* NSManagedObjectContext+MagicalObserving.m in Sources */ = {isa = PBXBuildFile; fileRef = C7DD72B7150F832A00216827 /* NSManagedObjectContext+MagicalObserving.m */; }; + 90DD208D167AA7180033BA25 /* NSManagedObjectContext+MagicalRecord.m in Sources */ = {isa = PBXBuildFile; fileRef = C7DD72B9150F832A00216827 /* NSManagedObjectContext+MagicalRecord.m */; }; + 90DD208E167AA7180033BA25 /* NSManagedObjectContext+MagicalSaves.m in Sources */ = {isa = PBXBuildFile; fileRef = C7DD72BB150F832A00216827 /* NSManagedObjectContext+MagicalSaves.m */; }; + 90DD208F167AA7180033BA25 /* NSManagedObjectContext+MagicalThreading.m in Sources */ = {isa = PBXBuildFile; fileRef = C7DD72BD150F832A00216827 /* NSManagedObjectContext+MagicalThreading.m */; }; + 90DD2090167AA7590033BA25 /* generateShorthandFile.rb in Resources */ = {isa = PBXBuildFile; fileRef = C75C7D69147220D300D0C2FE /* generateShorthandFile.rb */; }; + 90DD2093167AAEFA0033BA25 /* NSManagedObjectContext+MagicalSavesSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 90DD2092167AAEFA0033BA25 /* NSManagedObjectContext+MagicalSavesSpec.m */; }; C70B6E7113D0F62500709450 /* NSPersisentStoreHelperTests.m in Sources */ = {isa = PBXBuildFile; fileRef = C70B6E7013D0F62500709450 /* NSPersisentStoreHelperTests.m */; }; C70B6E7413D0F64000709450 /* NSPersistentStoreCoordinatorHelperTests.m in Sources */ = {isa = PBXBuildFile; fileRef = C70B6E7313D0F64000709450 /* NSPersistentStoreCoordinatorHelperTests.m */; }; C70B6E7713D0F66000709450 /* NSManagedObjectModelHelperTests.m in Sources */ = {isa = PBXBuildFile; fileRef = C70B6E7613D0F66000709450 /* NSManagedObjectModelHelperTests.m */; }; @@ -250,6 +313,44 @@ }; /* End PBXBuildRule section */ +/* Begin PBXContainerItemProxy section */ + 90DD203B167AA44D0033BA25 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 90DD2033167AA44D0033BA25 /* Kiwi.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = F5015B9F11583A77002E9A98; + remoteInfo = Kiwi; + }; + 90DD203D167AA44D0033BA25 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 90DD2033167AA44D0033BA25 /* Kiwi.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 832C83C7157263B300F160D5; + remoteInfo = "Kiwi-OSX"; + }; + 90DD203F167AA44D0033BA25 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 90DD2033167AA44D0033BA25 /* Kiwi.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = F5015C9E11584017002E9A98; + remoteInfo = KiwiTests; + }; + 90DD2041167AA44D0033BA25 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 90DD2033167AA44D0033BA25 /* Kiwi.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = A3B16542139967B800E9CC6E; + remoteInfo = KiwiExamples; + }; + 90DD2043167AA4530033BA25 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 90DD2033167AA44D0033BA25 /* Kiwi.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = 832C8323157263B300F160D5; + remoteInfo = "Kiwi-OSX"; + }; +/* End PBXContainerItemProxy section */ + /* Begin PBXCopyFilesBuildPhase section */ C7E37A7B14157BE600CE9BF5 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; @@ -276,8 +377,6 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 4B7116BB15F8ED5A00B64426 /* SaveTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SaveTests.h; path = "Unit Tests/SaveTests.h"; sourceTree = ""; }; - 4B7116BC15F8ED5A00B64426 /* SaveTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SaveTests.m; path = "Unit Tests/SaveTests.m"; sourceTree = ""; }; 4B7116C115F8EE4600B64426 /* EXPBackwardCompatibility.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EXPBackwardCompatibility.h; sourceTree = ""; }; 4B7116C215F8EE4600B64426 /* EXPBackwardCompatibility.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EXPBackwardCompatibility.m; sourceTree = ""; }; 4B7116C315F8EE4600B64426 /* EXPBlockDefinedMatcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EXPBlockDefinedMatcher.h; sourceTree = ""; }; @@ -340,6 +439,19 @@ 4B93EA48160ECF1D00FB5676 /* TestModel.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = TestModel.xcdatamodel; sourceTree = ""; }; 900E1CC41676E25E005FFF1C /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.1.sdk/System/Library/Frameworks/CoreGraphics.framework; sourceTree = DEVELOPER_DIR; }; 900E1CC61676E275005FFF1C /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.1.sdk/System/Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; }; + 90DD201D167AA4350033BA25 /* Mac Unit Tests.octest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Mac Unit Tests.octest"; sourceTree = BUILT_PRODUCTS_DIR; }; + 90DD201E167AA4350033BA25 /* SenTestingKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SenTestingKit.framework; path = Library/Frameworks/SenTestingKit.framework; sourceTree = DEVELOPER_DIR; }; + 90DD2020167AA4350033BA25 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = Library/Frameworks/Cocoa.framework; sourceTree = DEVELOPER_DIR; }; + 90DD2023167AA4350033BA25 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; + 90DD2024167AA4350033BA25 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; + 90DD2025167AA4350033BA25 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 90DD2028167AA4350033BA25 /* Mac Unit Tests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Mac Unit Tests-Info.plist"; sourceTree = ""; }; + 90DD202F167AA4350033BA25 /* Mac Unit Tests-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Mac Unit Tests-Prefix.pch"; sourceTree = ""; }; + 90DD2033167AA44D0033BA25 /* Kiwi.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Kiwi.xcodeproj; path = "Third Party/Kiwi/Kiwi.xcodeproj"; sourceTree = ""; }; + 90DD2045167AA45B0033BA25 /* SenTestingKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SenTestingKit.framework; path = Library/Frameworks/SenTestingKit.framework; sourceTree = DEVELOPER_DIR; }; + 90DD2048167AA4670033BA25 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.sdk/System/Library/Frameworks/Cocoa.framework; sourceTree = DEVELOPER_DIR; }; + 90DD204D167AA4E10033BA25 /* MagicalRecord+ActionsSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MagicalRecord+ActionsSpec.m"; sourceTree = ""; }; + 90DD2092167AAEFA0033BA25 /* NSManagedObjectContext+MagicalSavesSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSManagedObjectContext+MagicalSavesSpec.m"; sourceTree = ""; }; C70B6E6F13D0F62500709450 /* NSPersisentStoreHelperTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NSPersisentStoreHelperTests.h; path = "Unit Tests/NSPersisentStoreHelperTests.h"; sourceTree = ""; }; C70B6E7013D0F62500709450 /* NSPersisentStoreHelperTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NSPersisentStoreHelperTests.m; path = "Unit Tests/NSPersisentStoreHelperTests.m"; sourceTree = ""; }; C70B6E7213D0F64000709450 /* NSPersistentStoreCoordinatorHelperTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NSPersistentStoreCoordinatorHelperTests.h; path = "Unit Tests/NSPersistentStoreCoordinatorHelperTests.h"; sourceTree = ""; }; @@ -505,6 +617,16 @@ /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + 90DD2019167AA4350033BA25 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 90DD204A167AA46D0033BA25 /* Cocoa.framework in Frameworks */, + 90DD2047167AA4630033BA25 /* SenTestingKit.framework in Frameworks */, + 90DD204B167AA46F0033BA25 /* libKiwi-OSX.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; C721C7D913D0C3A00097AB6F /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -609,6 +731,48 @@ path = matchers; sourceTree = ""; }; + 90DD2022167AA4350033BA25 /* Other Frameworks */ = { + isa = PBXGroup; + children = ( + 90DD2023167AA4350033BA25 /* AppKit.framework */, + 90DD2024167AA4350033BA25 /* CoreData.framework */, + 90DD2025167AA4350033BA25 /* Foundation.framework */, + ); + name = "Other Frameworks"; + sourceTree = ""; + }; + 90DD2026167AA4350033BA25 /* Mac Unit Tests */ = { + isa = PBXGroup; + children = ( + 90DD2027167AA4350033BA25 /* Supporting Files */, + 90DD204D167AA4E10033BA25 /* MagicalRecord+ActionsSpec.m */, + 90DD2092167AAEFA0033BA25 /* NSManagedObjectContext+MagicalSavesSpec.m */, + ); + path = "Mac Unit Tests"; + sourceTree = ""; + }; + 90DD2027167AA4350033BA25 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 90DD2048167AA4670033BA25 /* Cocoa.framework */, + 90DD2045167AA45B0033BA25 /* SenTestingKit.framework */, + 90DD2028167AA4350033BA25 /* Mac Unit Tests-Info.plist */, + 90DD202F167AA4350033BA25 /* Mac Unit Tests-Prefix.pch */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 90DD2034167AA44D0033BA25 /* Products */ = { + isa = PBXGroup; + children = ( + 90DD203C167AA44D0033BA25 /* libKiwi.a */, + 90DD203E167AA44D0033BA25 /* libKiwi-OSX.a */, + 90DD2040167AA44D0033BA25 /* KiwiTests.octest */, + 90DD2042167AA44D0033BA25 /* KiwiExamples.octest */, + ); + name = Products; + sourceTree = ""; + }; C721C7A013D0A3750097AB6F = { isa = PBXGroup; children = ( @@ -618,6 +782,7 @@ C721C7E413D0C3A00097AB6F /* Mac App Unit Tests */, C721C80213D0C3CD0097AB6F /* iOS App Unit Tests */, C7C9A37013F43D3E002C5B0C /* Third Party */, + 90DD2026167AA4350033BA25 /* Mac Unit Tests */, C721C7B313D0A3AF0097AB6F /* Frameworks */, C721C7B113D0A3AF0097AB6F /* Products */, ); @@ -628,6 +793,7 @@ children = ( C721C7DC13D0C3A00097AB6F /* Mac App Unit Tests.app */, C721C7FD13D0C3CD0097AB6F /* iOS App Unit Tests.app */, + 90DD201D167AA4350033BA25 /* Mac Unit Tests.octest */, ); name = Products; sourceTree = ""; @@ -637,6 +803,9 @@ children = ( C721C7E313D0C3A00097AB6F /* Foundation.framework */, C721C7E213D0C3A00097AB6F /* CoreData.framework */, + 90DD201E167AA4350033BA25 /* SenTestingKit.framework */, + 90DD2020167AA4350033BA25 /* Cocoa.framework */, + 90DD2022167AA4350033BA25 /* Other Frameworks */, ); name = Frameworks; sourceTree = ""; @@ -863,6 +1032,7 @@ C7C9A37013F43D3E002C5B0C /* Third Party */ = { isa = PBXGroup; children = ( + 90DD2033167AA44D0033BA25 /* Kiwi.xcodeproj */, 4B7116C015F8EE4600B64426 /* expecta */, C7C9A37113F43D93002C5B0C /* JSONKit.h */, C7C9A37213F43D93002C5B0C /* JSONKit.m */, @@ -987,8 +1157,6 @@ C70B6E7913D0F68400709450 /* NSManagedObjectContextHelperTests.m */, C70B6E7B13D0F69A00709450 /* NSManagedObjectHelperTests.h */, C70B6E7C13D0F69A00709450 /* NSManagedObjectHelperTests.m */, - 4B7116BB15F8ED5A00B64426 /* SaveTests.h */, - 4B7116BC15F8ED5A00B64426 /* SaveTests.m */, ); name = "Core Tests"; sourceTree = ""; @@ -996,6 +1164,26 @@ /* End PBXGroup section */ /* Begin PBXNativeTarget section */ + 90DD201C167AA4350033BA25 /* Mac Unit Tests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 90DD2032167AA4350033BA25 /* Build configuration list for PBXNativeTarget "Mac Unit Tests" */; + buildPhases = ( + 90DD2091167AA7700033BA25 /* Update Generated Core Data Entities */, + 90DD2018167AA4350033BA25 /* Sources */, + 90DD2019167AA4350033BA25 /* Frameworks */, + 90DD201A167AA4350033BA25 /* Resources */, + 90DD201B167AA4350033BA25 /* Run Unit Tests */, + ); + buildRules = ( + ); + dependencies = ( + 90DD2044167AA4530033BA25 /* PBXTargetDependency */, + ); + name = "Mac Unit Tests"; + productName = "Mac Unit Tests"; + productReference = 90DD201D167AA4350033BA25 /* Mac Unit Tests.octest */; + productType = "com.apple.product-type.bundle"; + }; C721C7DB13D0C3A00097AB6F /* Mac App Unit Tests */ = { isa = PBXNativeTarget; buildConfigurationList = C721C7F613D0C3A00097AB6F /* Build configuration list for PBXNativeTarget "Mac App Unit Tests" */; @@ -1055,15 +1243,71 @@ mainGroup = C721C7A013D0A3750097AB6F; productRefGroup = C721C7B113D0A3AF0097AB6F /* Products */; projectDirPath = ""; + projectReferences = ( + { + ProductGroup = 90DD2034167AA44D0033BA25 /* Products */; + ProjectRef = 90DD2033167AA44D0033BA25 /* Kiwi.xcodeproj */; + }, + ); projectRoot = ""; targets = ( C721C7DB13D0C3A00097AB6F /* Mac App Unit Tests */, C721C7FC13D0C3CD0097AB6F /* iOS App Unit Tests */, + 90DD201C167AA4350033BA25 /* Mac Unit Tests */, ); }; /* End PBXProject section */ +/* Begin PBXReferenceProxy section */ + 90DD203C167AA44D0033BA25 /* libKiwi.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libKiwi.a; + remoteRef = 90DD203B167AA44D0033BA25 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 90DD203E167AA44D0033BA25 /* libKiwi-OSX.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = "libKiwi-OSX.a"; + remoteRef = 90DD203D167AA44D0033BA25 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 90DD2040167AA44D0033BA25 /* KiwiTests.octest */ = { + isa = PBXReferenceProxy; + fileType = wrapper.cfbundle; + path = KiwiTests.octest; + remoteRef = 90DD203F167AA44D0033BA25 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 90DD2042167AA44D0033BA25 /* KiwiExamples.octest */ = { + isa = PBXReferenceProxy; + fileType = wrapper.cfbundle; + path = KiwiExamples.octest; + remoteRef = 90DD2041167AA44D0033BA25 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; +/* End PBXReferenceProxy section */ + /* Begin PBXResourcesBuildPhase section */ + 90DD201A167AA4350033BA25 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 90DD2090167AA7590033BA25 /* generateShorthandFile.rb in Resources */, + 90DD206B167AA6DF0033BA25 /* SingleEntityWithNoRelationships.plist in Resources */, + 90DD206C167AA6DF0033BA25 /* SingleEntityWithNoRelationships.json in Resources */, + 90DD206D167AA6DF0033BA25 /* SampleJSONDataForImport.json in Resources */, + 90DD206E167AA6DF0033BA25 /* SingleRelatedEntity.json in Resources */, + 90DD206F167AA6DF0033BA25 /* SingleEntityRelatedToMappedEntityUsingMappedPrimaryKey.json in Resources */, + 90DD2070167AA6DF0033BA25 /* SingleEntityRelatedToMappedEntityUsingDefaults.json in Resources */, + 90DD2071167AA6DF0033BA25 /* SingleEntityRelatedToManyMappedEntitiesUsingMappedPrimaryKey.json in Resources */, + 90DD2072167AA6DF0033BA25 /* SingleEntityRelatedToMappedEntityWithNestedMappedAttributes.json in Resources */, + 90DD2073167AA6DF0033BA25 /* SingleEntityRelatedToMappedEntityWithSecondaryMappings.json in Resources */, + 90DD2074167AA6DF0033BA25 /* SingleEntityRelatedToManyMappedEntitiesUsingListOfPrimaryKeys.json in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; C721C7DA13D0C3A00097AB6F /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -1105,6 +1349,34 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + 90DD201B167AA4350033BA25 /* Run Unit Tests */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Unit Tests"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "# Run the unit tests in this test bundle.\n\"${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests\"\n"; + }; + 90DD2091167AA7700033BA25 /* Update Generated Core Data Entities */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Update Generated Core Data Entities"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "#cd \"Unit Tests/Fixtures/Mac\" && mogenerator -m TestModel.xcdatamodeld/TestModel.xcdatamodel -O TestEntities"; + }; C76AF7F613DBD47400CE2E05 /* Update Generated Core Data Entities */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -1150,6 +1422,64 @@ /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + 90DD2018167AA4350033BA25 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 90DD204E167AA4E10033BA25 /* MagicalRecord+ActionsSpec.m in Sources */, + 90DD2054167AA6C80033BA25 /* MappedEntity.m in Sources */, + 90DD2055167AA6C80033BA25 /* AbstractRelatedEntity.m in Sources */, + 90DD2056167AA6C80033BA25 /* ConcreteRelatedEntity.m in Sources */, + 90DD2057167AA6C80033BA25 /* DifferentClassNameMapping.m in Sources */, + 90DD2058167AA6C80033BA25 /* SingleEntityWithNoRelationships.m in Sources */, + 90DD2059167AA6C80033BA25 /* SingleRelatedEntity.m in Sources */, + 90DD205A167AA6C80033BA25 /* SingleEntityRelatedToMappedEntityWithSecondaryMappings.m in Sources */, + 90DD205B167AA6C80033BA25 /* SingleEntityRelatedToMappedEntityUsingDefaults.m in Sources */, + 90DD205C167AA6C80033BA25 /* SingleEntityRelatedToMappedEntityUsingMappedPrimaryKey.m in Sources */, + 90DD205D167AA6C80033BA25 /* SingleEntityRelatedToManyMappedEntitiesUsingMappedPrimaryKey.m in Sources */, + 90DD205E167AA6C80033BA25 /* SingleEntityRelatedToMappedEntityWithNestedMappedAttributes.m in Sources */, + 90DD205F167AA6CC0033BA25 /* TestModel.xcdatamodeld in Sources */, + 90DD2060167AA6D80033BA25 /* _SingleEntityRelatedToMappedEntityWithSecondaryMappings.m in Sources */, + 90DD2061167AA6D80033BA25 /* _AbstractRelatedEntity.m in Sources */, + 90DD2062167AA6D80033BA25 /* _ConcreteRelatedEntity.m in Sources */, + 90DD2063167AA6D80033BA25 /* _DifferentClassNameMapping.m in Sources */, + 90DD2064167AA6D80033BA25 /* _SingleEntityWithNoRelationships.m in Sources */, + 90DD2065167AA6D80033BA25 /* _SingleEntityRelatedToManyMappedEntitiesUsingMappedPrimaryKey.m in Sources */, + 90DD2066167AA6D80033BA25 /* _SingleRelatedEntity.m in Sources */, + 90DD2067167AA6D80033BA25 /* _MappedEntity.m in Sources */, + 90DD2068167AA6D80033BA25 /* _SingleEntityRelatedToMappedEntityUsingDefaults.m in Sources */, + 90DD2069167AA6D80033BA25 /* _SingleEntityRelatedToMappedEntityUsingMappedPrimaryKey.m in Sources */, + 90DD206A167AA6D80033BA25 /* _SingleEntityRelatedToMappedEntityWithNestedMappedAttributes.m in Sources */, + 90DD2076167AA7050033BA25 /* MagicalRecord.m in Sources */, + 90DD2077167AA7050033BA25 /* MagicalRecord+Actions.m in Sources */, + 90DD2078167AA7050033BA25 /* MagicalRecord+ErrorHandling.m in Sources */, + 90DD2079167AA7050033BA25 /* MagicalRecord+iCloud.m in Sources */, + 90DD207A167AA7050033BA25 /* MagicalRecord+Options.m in Sources */, + 90DD207B167AA7050033BA25 /* MagicalRecord+Setup.m in Sources */, + 90DD207C167AA7050033BA25 /* MagicalRecord+ShorthandSupport.m in Sources */, + 90DD207D167AA7080033BA25 /* NSManagedObjectModel+MagicalRecord.m in Sources */, + 90DD207E167AA7080033BA25 /* NSPersistentStore+MagicalRecord.m in Sources */, + 90DD207F167AA7080033BA25 /* NSPersistentStoreCoordinator+MagicalRecord.m in Sources */, + 90DD2080167AA70E0033BA25 /* MagicalImportFunctions.m in Sources */, + 90DD2081167AA70E0033BA25 /* NSEntityDescription+MagicalDataImport.m in Sources */, + 90DD2082167AA70E0033BA25 /* NSAttributeDescription+MagicalDataImport.m in Sources */, + 90DD2083167AA70E0033BA25 /* NSRelationshipDescription+MagicalDataImport.m in Sources */, + 90DD2084167AA70E0033BA25 /* NSNumber+MagicalDataImport.m in Sources */, + 90DD2085167AA70E0033BA25 /* NSObject+MagicalDataImport.m in Sources */, + 90DD2086167AA70E0033BA25 /* NSString+MagicalDataImport.m in Sources */, + 90DD2087167AA7130033BA25 /* NSManagedObject+MagicalAggregation.m in Sources */, + 90DD2088167AA7130033BA25 /* NSManagedObject+MagicalDataImport.m in Sources */, + 90DD2089167AA7130033BA25 /* NSManagedObject+MagicalFinders.m in Sources */, + 90DD208A167AA7130033BA25 /* NSManagedObject+MagicalRecord.m in Sources */, + 90DD208B167AA7130033BA25 /* NSManagedObject+MagicalRequests.m in Sources */, + 90DD208C167AA7180033BA25 /* NSManagedObjectContext+MagicalObserving.m in Sources */, + 90DD208D167AA7180033BA25 /* NSManagedObjectContext+MagicalRecord.m in Sources */, + 90DD208E167AA7180033BA25 /* NSManagedObjectContext+MagicalSaves.m in Sources */, + 90DD208F167AA7180033BA25 /* NSManagedObjectContext+MagicalThreading.m in Sources */, + 90DD2093167AAEFA0033BA25 /* NSManagedObjectContext+MagicalSavesSpec.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; C721C7D813D0C3A00097AB6F /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -1246,7 +1576,6 @@ 4B71172D15F8EE4600B64426 /* EXPMatchers+haveCountOf.m in Sources */, 4B71172F15F8EE4600B64426 /* EXPMatchers+raise.m in Sources */, 4B71173115F8EE4600B64426 /* NSValue+Expecta.m in Sources */, - 4B71173415F914A400B64426 /* SaveTests.m in Sources */, 4B93EA49160ECF1D00FB5676 /* TestModel.xcdatamodeld in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1348,13 +1677,20 @@ 4B71172E15F8EE4600B64426 /* EXPMatchers+haveCountOf.m in Sources */, 4B71173015F8EE4600B64426 /* EXPMatchers+raise.m in Sources */, 4B71173215F8EE4600B64426 /* NSValue+Expecta.m in Sources */, - 4B71173315F9149900B64426 /* SaveTests.m in Sources */, 4B93EA4A160ECF1D00FB5676 /* TestModel.xcdatamodeld in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ +/* Begin PBXTargetDependency section */ + 90DD2044167AA4530033BA25 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "Kiwi-OSX"; + targetProxy = 90DD2043167AA4530033BA25 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + /* Begin PBXVariantGroup section */ C721C7E713D0C3A00097AB6F /* InfoPlist.strings */ = { isa = PBXVariantGroup; @@ -1383,6 +1719,77 @@ /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ + 90DD2030167AA4350033BA25 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(ARCHS_STANDARD_64_BIT)"; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + FRAMEWORK_SEARCH_PATHS = "\"$(DEVELOPER_LIBRARY_DIR)/Frameworks\""; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "Mac Unit Tests/Mac Unit Tests-Prefix.pch"; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + HEADER_SEARCH_PATHS = ( + "\"$(SRCROOT)/Third Party/Kiwi/Kiwi\"", + ); + INFOPLIST_FILE = "Mac Unit Tests/Mac Unit Tests-Info.plist"; + MACOSX_DEPLOYMENT_TARGET = 10.8; + ONLY_ACTIVE_ARCH = YES; + OTHER_LDFLAGS = "-all_load"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + WRAPPER_EXTENSION = octest; + }; + name = Debug; + }; + 90DD2031167AA4350033BA25 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(ARCHS_STANDARD_64_BIT)"; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + FRAMEWORK_SEARCH_PATHS = "\"$(DEVELOPER_LIBRARY_DIR)/Frameworks\""; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "Mac Unit Tests/Mac Unit Tests-Prefix.pch"; + HEADER_SEARCH_PATHS = ( + "\"$(SRCROOT)/Third Party/Kiwi/Kiwi\"", + ); + INFOPLIST_FILE = "Mac Unit Tests/Mac Unit Tests-Info.plist"; + MACOSX_DEPLOYMENT_TARGET = 10.8; + OTHER_LDFLAGS = "-all_load"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + WRAPPER_EXTENSION = octest; + }; + name = Release; + }; C721C7A713D0A3750097AB6F /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -1650,6 +2057,15 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 90DD2032167AA4350033BA25 /* Build configuration list for PBXNativeTarget "Mac Unit Tests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 90DD2030167AA4350033BA25 /* Debug */, + 90DD2031167AA4350033BA25 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; C721C7A513D0A3750097AB6F /* Build configuration list for PBXProject "Magical Record" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/Project Files/Magical Record.xcodeproj/xcshareddata/xcschemes/Mac Unit Tests.xcscheme b/Project Files/Magical Record.xcodeproj/xcshareddata/xcschemes/Mac Unit Tests.xcscheme new file mode 100644 index 0000000..1056a80 --- /dev/null +++ b/Project Files/Magical Record.xcodeproj/xcshareddata/xcschemes/Mac Unit Tests.xcscheme @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Project Files/Third Party/Kiwi b/Project Files/Third Party/Kiwi new file mode 160000 index 0000000..879a1b9 --- /dev/null +++ b/Project Files/Third Party/Kiwi @@ -0,0 +1 @@ +Subproject commit 879a1b931fe1e612e0060f8a38fcb23dba880425 diff --git a/Project Files/Unit Tests/SaveTests.h b/Project Files/Unit Tests/SaveTests.h deleted file mode 100644 index 9738b33..0000000 --- a/Project Files/Unit Tests/SaveTests.h +++ /dev/null @@ -1,13 +0,0 @@ -// -// SaveTests.h -// Magical Record -// -// Created by Stephen J Vanterpool on 9/6/12. -// Copyright (c) 2012 Magical Panda Software LLC. All rights reserved. -// - - - -@interface SaveTests : GHTestCase - -@end From a28d4210ac89f45e37b3d9ea9854c37f97519945 Mon Sep 17 00:00:00 2001 From: Tony Arnold Date: Fri, 14 Dec 2012 12:03:59 +1100 Subject: [PATCH 06/10] Flesh out tests for MagicalRecord+Actions and the NSManagedObjectContext+MagicalSaves category --- MagicalRecord/Core/MagicalRecord+Actions.h | 4 +- MagicalRecord/Core/MagicalRecord+Actions.m | 4 +- .../Mac Unit Tests/Mac Unit Tests-Prefix.pch | 4 + .../MagicalRecord+ActionsSpec.m | 204 ++++++++++++++++-- .../NSManagedObjectContext+MagicalSavesSpec.m | 81 +++++-- 5 files changed, 261 insertions(+), 36 deletions(-) diff --git a/MagicalRecord/Core/MagicalRecord+Actions.h b/MagicalRecord/Core/MagicalRecord+Actions.h index 0bce647..7926ac3 100644 --- a/MagicalRecord/Core/MagicalRecord+Actions.h +++ b/MagicalRecord/Core/MagicalRecord+Actions.h @@ -23,8 +23,8 @@ /* If you want to reuse the context on the current thread, use these methods. */ -+ (void) saveUsingCurrentContextWithBlock:(void (^)(NSManagedObjectContext *localContext))block completion:(MRSaveCompletionHandler)completion; -+ (void) saveUsingCurrentContextWithBlockAndWait:(void (^)(NSManagedObjectContext *localContext))block; ++ (void) saveUsingCurrentThreadContextWithBlock:(void (^)(NSManagedObjectContext *localContext))block completion:(MRSaveCompletionHandler)completion; ++ (void) saveUsingCurrentThreadContextWithBlockAndWait:(void (^)(NSManagedObjectContext *localContext))block; /* DEPRECATION NOTICE: diff --git a/MagicalRecord/Core/MagicalRecord+Actions.m b/MagicalRecord/Core/MagicalRecord+Actions.m index d886c27..97020e8 100644 --- a/MagicalRecord/Core/MagicalRecord+Actions.m +++ b/MagicalRecord/Core/MagicalRecord+Actions.m @@ -32,7 +32,7 @@ }]; } -+ (void) saveUsingCurrentContextWithBlock:(void (^)(NSManagedObjectContext *localContext))block completion:(MRSaveCompletionHandler)completion; ++ (void) saveUsingCurrentThreadContextWithBlock:(void (^)(NSManagedObjectContext *localContext))block completion:(MRSaveCompletionHandler)completion; { NSManagedObjectContext *localContext = [NSManagedObjectContext MR_contextForCurrentThread]; @@ -62,7 +62,7 @@ }]; } -+ (void) saveUsingCurrentContextWithBlockAndWait:(void (^)(NSManagedObjectContext *localContext))block; ++ (void) saveUsingCurrentThreadContextWithBlockAndWait:(void (^)(NSManagedObjectContext *localContext))block; { NSManagedObjectContext *localContext = [NSManagedObjectContext MR_contextForCurrentThread]; diff --git a/Project Files/Mac Unit Tests/Mac Unit Tests-Prefix.pch b/Project Files/Mac Unit Tests/Mac Unit Tests-Prefix.pch index ebb8d47..427c4ab 100644 --- a/Project Files/Mac Unit Tests/Mac Unit Tests-Prefix.pch +++ b/Project Files/Mac Unit Tests/Mac Unit Tests-Prefix.pch @@ -4,4 +4,8 @@ #ifdef __OBJC__ #import + #import + + #define MR_SHORTHAND + #import "CoreData+MagicalRecord.h" #endif diff --git a/Project Files/Mac Unit Tests/MagicalRecord+ActionsSpec.m b/Project Files/Mac Unit Tests/MagicalRecord+ActionsSpec.m index 2e078ce..4ab5596 100644 --- a/Project Files/Mac Unit Tests/MagicalRecord+ActionsSpec.m +++ b/Project Files/Mac Unit Tests/MagicalRecord+ActionsSpec.m @@ -1,31 +1,205 @@ #import "Kiwi.h" // Project -#import "MagicalRecord_Actions.h" +#import "SingleEntityWithNoRelationships.h" -SPEC_BEGIN(MagicalRecord_ActionsSpec) +SPEC_BEGIN(MagicalRecordActionsSpec) -describe(@"MagicalRecord_Actions", ^{ - beforeAll(^{ - // Occurs once - }); - - afterAll(^{ - // Occurs once - }); - +describe(@"MagicalRecord", ^{ beforeEach(^{ // Occurs before each enclosed "it" block + [MagicalRecord setDefaultModelFromClass:[self class]]; + [MagicalRecord setupCoreDataStackWithInMemoryStore]; }); afterEach(^{ // Occurs after each enclosed "it" block + [MagicalRecord cleanUp]; }); - - it(@"should really test something", ^{ - // Test something - pending(@" — sadly, you've only just created this spec, so it's currently unimplemented", nil); + + context(@"synchronous save action", ^{ + it(@"should save", ^{ + __block NSManagedObjectID *objectId; + __block NSManagedObject *fetchedObject; + + [MagicalRecord saveWithBlockAndWait:^(NSManagedObjectContext *localContext) { + NSManagedObject *inserted = [SingleEntityWithNoRelationships MR_createInContext:localContext]; + + [[@([inserted hasChanges]) should] beTrue]; + + [localContext obtainPermanentIDsForObjects:@[inserted] error:nil]; + objectId = [inserted objectID]; + }]; + + [[objectId should] beNonNil]; + + fetchedObject = [[NSManagedObjectContext MR_rootSavingContext] objectWithID:objectId]; + + [[fetchedObject should] beNonNil]; + [[@([fetchedObject hasChanges]) should] beFalse]; + }); + }); + + context(@"asynchronous save action", ^{ + it(@"should call completion block", ^{ + __block BOOL completionBlockCalled = NO; + + [MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) { + [SingleEntityWithNoRelationships MR_createInContext:localContext]; + } completion:^(BOOL success, NSError *error) { + // Ignore the success state — we only care that this block is executed + completionBlockCalled = YES; + }]; + + [[expectFutureValue(@(completionBlockCalled)) shouldEventually] beTrue]; + }); + + it(@"should save", ^{ + __block BOOL saveSuccessState = NO; + __block NSManagedObjectID *objectId; + __block NSManagedObject *fetchedObject; + + [MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) { + NSManagedObject *inserted = [SingleEntityWithNoRelationships MR_createInContext:localContext]; + + [[@([inserted hasChanges]) should] beTrue]; + + [localContext obtainPermanentIDsForObjects:@[inserted] error:nil]; + objectId = [inserted objectID]; + } completion:^(BOOL success, NSError *error) { + saveSuccessState = success; + fetchedObject = [[NSManagedObjectContext MR_rootSavingContext] objectWithID:objectId]; + }]; + + [[expectFutureValue(@(saveSuccessState)) shouldEventually] beTrue]; + [[expectFutureValue(fetchedObject) shouldEventually] beNonNil]; + [[expectFutureValue(@([fetchedObject hasChanges])) shouldEventually] beFalse]; + }); + }); + + context(@"current thread save action", ^{ + context(@"running synchronously", ^{ + it(@"should save", ^{ + __block NSManagedObjectID *objectId; + + [MagicalRecord saveUsingCurrentThreadContextWithBlockAndWait:^(NSManagedObjectContext *localContext) { + NSManagedObject *inserted = [SingleEntityWithNoRelationships MR_createInContext:localContext]; + + [[@([inserted hasChanges]) should] beTrue]; + + [localContext obtainPermanentIDsForObjects:@[inserted] error:nil]; + objectId = [inserted objectID]; + }]; + + [[objectId should] beNonNil]; + + NSManagedObject *fetchedObject = [[NSManagedObjectContext MR_rootSavingContext] objectWithID:objectId]; + + [[fetchedObject should] beNonNil]; + [[@([fetchedObject hasChanges]) should] beFalse]; + }); + }); + + context(@"running asynchronously", ^{ + it(@"should call completion block", ^{ + __block BOOL completionBlockCalled = NO; + + [MagicalRecord saveUsingCurrentThreadContextWithBlock:^(NSManagedObjectContext *localContext) { + [SingleEntityWithNoRelationships MR_createInContext:localContext]; + } completion:^(BOOL success, NSError *error) { + // Ignore the success state — we only care that this block is executed + completionBlockCalled = YES; + }]; + + [[expectFutureValue(@(completionBlockCalled)) shouldEventually] beTrue]; + }); + + it(@"should save", ^{ + __block NSManagedObjectID *objectId; + + [MagicalRecord saveUsingCurrentThreadContextWithBlock:^(NSManagedObjectContext *localContext) { + NSManagedObject *inserted = [SingleEntityWithNoRelationships MR_createInContext:localContext]; + + [[@([inserted hasChanges]) should] beTrue]; + + [localContext obtainPermanentIDsForObjects:@[inserted] error:nil]; + objectId = [inserted objectID]; + } completion:^(BOOL success, NSError *error) { + [[@(success) should] beTrue]; + }]; + + [[expectFutureValue(objectId) shouldEventually] beNonNil]; + + NSManagedObject *fetchedObject = [[NSManagedObjectContext MR_rootSavingContext] objectWithID:objectId]; + + [[expectFutureValue(fetchedObject) shouldEventually] beNonNil]; + [[expectFutureValue(@([fetchedObject hasChanges])) shouldEventually] beFalse]; + }); + }); }); + + context(@"deprecated method", ^{ + context(@"simple save", ^{ + it(@"should save", ^{ + NSManagedObjectContext *managedObjectContext = [NSManagedObjectContext MR_defaultContext]; + NSManagedObject *inserted = [SingleEntityWithNoRelationships MR_createEntity]; + + [[@([inserted hasChanges]) should] beTrue]; + + [managedObjectContext obtainPermanentIDsForObjects:@[inserted] error:nil]; + NSManagedObjectID *objectId = [inserted objectID]; + + [[objectId should] beNonNil]; + + [[[managedObjectContext should] receive] MR_save]; + [managedObjectContext MR_save]; + + NSManagedObject *fetchedObject = [[NSManagedObjectContext MR_rootSavingContext] objectWithID:objectId]; + + [[fetchedObject should] beNonNil]; + [[@([fetchedObject hasChanges]) should] beFalse]; + }); + }); + + context(@"background save action", ^{ + it(@"should call completion block", ^{ + __block BOOL completionBlockCalled = NO; + + [MagicalRecord saveInBackgroundWithBlock:^(NSManagedObjectContext *localContext) { + [SingleEntityWithNoRelationships MR_createInContext:localContext]; + } completion:^{ + // Ignore the success state — we only care that this block is executed + completionBlockCalled = YES; + }]; + + [[expectFutureValue(@(completionBlockCalled)) shouldEventually] beTrue]; + }); + + it(@"should save", ^{ + __block BOOL saveSuccessState = NO; + __block NSManagedObjectID *objectId; + __block NSManagedObject *fetchedObject; + + [MagicalRecord saveInBackgroundWithBlock:^(NSManagedObjectContext *localContext) { + NSManagedObject *inserted = [SingleEntityWithNoRelationships MR_createInContext:localContext]; + + [[@([inserted hasChanges]) should] beTrue]; + + [localContext obtainPermanentIDsForObjects:@[inserted] error:nil]; + objectId = [inserted objectID]; + } completion:^{ + [[objectId should] beNonNil]; + + fetchedObject = [[NSManagedObjectContext MR_rootSavingContext] objectWithID:objectId]; + }]; + + [[expectFutureValue(objectId) shouldEventually] beNonNil]; + [[expectFutureValue(fetchedObject) shouldEventually] beNonNil]; + [[expectFutureValue(@([fetchedObject hasChanges])) shouldEventually] beFalse]; + }); + + }); + }); }); SPEC_END diff --git a/Project Files/Mac Unit Tests/NSManagedObjectContext+MagicalSavesSpec.m b/Project Files/Mac Unit Tests/NSManagedObjectContext+MagicalSavesSpec.m index 2e52668..fed5ef3 100644 --- a/Project Files/Mac Unit Tests/NSManagedObjectContext+MagicalSavesSpec.m +++ b/Project Files/Mac Unit Tests/NSManagedObjectContext+MagicalSavesSpec.m @@ -1,31 +1,78 @@ #import "Kiwi.h" // Project -#import "NSManagedObjectContext_MagicalSaves.h" +#import "SingleEntityWithNoRelationships.h" -SPEC_BEGIN(NSManagedObjectContext_MagicalSavesSpec) +SPEC_BEGIN(NSManagedObjectContextMagicalSavesSpec) -describe(@"NSManagedObjectContext_MagicalSaves", ^{ - beforeAll(^{ - // Occurs once - }); - - afterAll(^{ - // Occurs once - }); - +describe(@"NSManagedObjectContext+MagicalSaves", ^{ beforeEach(^{ // Occurs before each enclosed "it" block + [MagicalRecord setDefaultModelFromClass:[self class]]; + [MagicalRecord setupCoreDataStackWithInMemoryStore]; }); - + afterEach(^{ // Occurs after each enclosed "it" block + [MagicalRecord cleanUp]; }); - - it(@"should really test something", ^{ - // Test something - pending(@" — sadly, you've only just created this spec, so it's currently unimplemented", nil); - }); + + context(@"saving synchronously", ^{ + it(@"should save", ^{ + NSManagedObjectContext *managedObjectContext = [NSManagedObjectContext MR_contextWithParent:[NSManagedObjectContext MR_defaultContext]]; + NSManagedObject *inserted = [SingleEntityWithNoRelationships MR_createInContext:managedObjectContext]; + + [[@([inserted hasChanges]) should] beTrue]; + + [managedObjectContext obtainPermanentIDsForObjects:@[inserted] error:nil]; + NSManagedObjectID *objectId = inserted.objectID; + + [managedObjectContext MR_saveToPersistentStoreAndWait]; + + NSManagedObject *fetchedObject = [[NSManagedObjectContext MR_rootSavingContext] objectWithID:objectId]; + + [[fetchedObject should] beNonNil]; + [[@([fetchedObject hasChanges]) should] beFalse]; + }); + + }); + + context(@"saving asynchronously", ^{ + it(@"should call completion block", ^{ + __block BOOL completionBlockCalled = NO; + + NSManagedObjectContext *managedObjectContext = [NSManagedObjectContext MR_contextForCurrentThread]; + + [SingleEntityWithNoRelationships MR_createInContext:managedObjectContext]; + + [managedObjectContext MR_saveToPersistentStoreWithCompletion:^(BOOL success, NSError *error) { + completionBlockCalled = YES; + }]; + + [[expectFutureValue(@(completionBlockCalled)) shouldEventually] beTrue]; + }); + + it(@"should save", ^{ + __block NSManagedObjectID *objectId; + NSManagedObjectContext *managedObjectContext = [NSManagedObjectContext MR_contextWithParent:[NSManagedObjectContext MR_defaultContext]]; + NSManagedObject *inserted = [SingleEntityWithNoRelationships MR_createInContext:managedObjectContext]; + + [[@([inserted hasChanges]) should] beTrue]; + + [managedObjectContext MR_saveToPersistentStoreWithCompletion:^(BOOL success, NSError *error) { + [managedObjectContext obtainPermanentIDsForObjects:@[inserted] error:nil]; + objectId = inserted.objectID; + }]; + + [[expectFutureValue(objectId) shouldEventually] beNonNil]; + + NSManagedObject *fetchedObject = [[NSManagedObjectContext MR_rootSavingContext] objectWithID:objectId]; + + [[expectFutureValue(fetchedObject) shouldEventually] beNonNil]; + [[expectFutureValue(@([fetchedObject hasChanges])) shouldEventually] beFalse]; + }); + }); + }); SPEC_END From 2c660560162832017736c4d00b9b11564e4b4c73 Mon Sep 17 00:00:00 2001 From: Tony Arnold Date: Fri, 14 Dec 2012 12:09:35 +1100 Subject: [PATCH 07/10] The deprecated saveWithBlock: method should do it's work on the current thread --- MagicalRecord/Core/MagicalRecord+Actions.m | 2 +- .../MagicalRecord+ActionsSpec.m | 27 +++++++++++++++++-- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/MagicalRecord/Core/MagicalRecord+Actions.m b/MagicalRecord/Core/MagicalRecord+Actions.m index 97020e8..c4f7bf9 100644 --- a/MagicalRecord/Core/MagicalRecord+Actions.m +++ b/MagicalRecord/Core/MagicalRecord+Actions.m @@ -15,7 +15,7 @@ + (void) saveWithBlock:(void(^)(NSManagedObjectContext *localContext))block; { - [self saveWithBlock:block completion:nil]; + [self saveWithBlockAndWait:block]; } + (void) saveWithBlock:(void(^)(NSManagedObjectContext *localContext))block completion:(MRSaveCompletionHandler)completion; diff --git a/Project Files/Mac Unit Tests/MagicalRecord+ActionsSpec.m b/Project Files/Mac Unit Tests/MagicalRecord+ActionsSpec.m index 4ab5596..219231e 100644 --- a/Project Files/Mac Unit Tests/MagicalRecord+ActionsSpec.m +++ b/Project Files/Mac Unit Tests/MagicalRecord+ActionsSpec.m @@ -161,6 +161,29 @@ describe(@"MagicalRecord", ^{ }); }); + context(@"save action", ^{ + it(@"should save", ^{ + __block NSManagedObjectID *objectId; + + [MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) { + NSManagedObject *inserted = [SingleEntityWithNoRelationships MR_createInContext:localContext]; + + [[@([inserted hasChanges]) should] beTrue]; + + [localContext obtainPermanentIDsForObjects:@[inserted] error:nil]; + objectId = [inserted objectID]; + }]; + + [[objectId should] beNonNil]; + + NSManagedObject *fetchedObject = [[NSManagedObjectContext MR_rootSavingContext] objectWithID:objectId]; + + [[objectId should] beNonNil]; + [[fetchedObject should] beNonNil]; + [[@([fetchedObject hasChanges]) should] beFalse]; + }); + }); + context(@"background save action", ^{ it(@"should call completion block", ^{ __block BOOL completionBlockCalled = NO; @@ -176,7 +199,6 @@ describe(@"MagicalRecord", ^{ }); it(@"should save", ^{ - __block BOOL saveSuccessState = NO; __block NSManagedObjectID *objectId; __block NSManagedObject *fetchedObject; @@ -197,8 +219,9 @@ describe(@"MagicalRecord", ^{ [[expectFutureValue(fetchedObject) shouldEventually] beNonNil]; [[expectFutureValue(@([fetchedObject hasChanges])) shouldEventually] beFalse]; }); - }); + + }); }); From c2fa8c48591a759b4ebf0f3f00746262cd1f66c6 Mon Sep 17 00:00:00 2001 From: Tony Arnold Date: Fri, 14 Dec 2012 12:18:34 +1100 Subject: [PATCH 08/10] All deprecated and non-deprecated methods have tests to ensure their function --- .../NSManagedObjectContext+MagicalSaves.h | 10 +- .../NSManagedObjectContext+MagicalSaves.m | 76 +-- MagicalRecord/Core/MagicalRecord+Actions.h | 2 +- MagicalRecord/Core/MagicalRecord+Actions.m | 8 +- .../MagicalRecord+ActionsSpec.m | 261 +++++--- .../NSManagedObjectContext+MagicalSavesSpec.m | 564 ++++++++++++++++-- 6 files changed, 726 insertions(+), 195 deletions(-) diff --git a/MagicalRecord/Categories/NSManagedObjectContext/NSManagedObjectContext+MagicalSaves.h b/MagicalRecord/Categories/NSManagedObjectContext/NSManagedObjectContext+MagicalSaves.h index 4815c6c..6b75c11 100644 --- a/MagicalRecord/Categories/NSManagedObjectContext/NSManagedObjectContext+MagicalSaves.h +++ b/MagicalRecord/Categories/NSManagedObjectContext/NSManagedObjectContext+MagicalSaves.h @@ -32,14 +32,14 @@ typedef void (^MRSaveCompletionHandler)(BOOL success, NSError *error); * The following methods are deprecated, but remain in place for backwards compatibility until the next major version (3.x) */ - (void) MR_save __attribute__((deprecated)); -- (void) MR_saveWithErrorCallback:(void(^)(NSError *))errorCallback __attribute__((deprecated)); +- (void) MR_saveWithErrorCallback:(void(^)(NSError *error))errorCallback __attribute__((deprecated)); - (void) MR_saveInBackgroundCompletion:(void (^)(void))completion __attribute__((deprecated)); -- (void) MR_saveInBackgroundErrorHandler:(void (^)(NSError *))errorCallback __attribute__((deprecated)); -- (void) MR_saveInBackgroundErrorHandler:(void (^)(NSError *))errorCallback completion:(void (^)(void))completion __attribute__((deprecated)); +- (void) MR_saveInBackgroundErrorHandler:(void (^)(NSError *error))errorCallback __attribute__((deprecated)); +- (void) MR_saveInBackgroundErrorHandler:(void (^)(NSError *error))errorCallback completion:(void (^)(void))completion __attribute__((deprecated)); - (void) MR_saveNestedContexts __attribute__((deprecated)); -- (void) MR_saveNestedContextsErrorHandler:(void (^)(NSError *))errorCallback __attribute__((deprecated)); -- (void) MR_saveNestedContextsErrorHandler:(void (^)(NSError *))errorCallback completion:(void (^)(void))completion __attribute__((deprecated)); +- (void) MR_saveNestedContextsErrorHandler:(void (^)(NSError *error))errorCallback __attribute__((deprecated)); +- (void) MR_saveNestedContextsErrorHandler:(void (^)(NSError *error))errorCallback completion:(void (^)(void))completion __attribute__((deprecated)); @end diff --git a/MagicalRecord/Categories/NSManagedObjectContext/NSManagedObjectContext+MagicalSaves.m b/MagicalRecord/Categories/NSManagedObjectContext/NSManagedObjectContext+MagicalSaves.m index 62a6992..c7ea37a 100644 --- a/MagicalRecord/Categories/NSManagedObjectContext/NSManagedObjectContext+MagicalSaves.m +++ b/MagicalRecord/Categories/NSManagedObjectContext/NSManagedObjectContext+MagicalSaves.m @@ -50,6 +50,8 @@ } MRLog(@"→ Saving %@", [self MR_description]); + MRLog(@"→ Save Parents? %@", @(saveParentContexts)); + MRLog(@"→ Save Synchronously? %@", @(syncSave)); id saveBlock = ^{ NSError *error = nil; @@ -102,46 +104,17 @@ #pragma mark - Deprecated methods // These methods will be removed in MagicalRecord 3.0 -- (void)MR_saveNestedContexts; -{ - [self MR_saveToPersistentStoreWithCompletion:nil]; -} - -- (void)MR_saveNestedContextsErrorHandler:(void (^)(NSError *))errorCallback; -{ - [self MR_saveToPersistentStoreWithCompletion:^(BOOL success, NSError *error) { - if (!success) { - if (errorCallback) { - errorCallback(error); - } - } - }]; -} - -- (void)MR_saveNestedContextsErrorHandler:(void (^)(NSError *))errorCallback completion:(void (^)(void))completion; -{ - [self MR_saveToPersistentStoreWithCompletion:^(BOOL success, NSError *error) { - if (success) { - if (completion) { - completion(); - } - } else { - if (errorCallback) { - errorCallback(error); - } - } - }]; -} +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-implementations" - (void)MR_save; { [self MR_saveToPersistentStoreAndWait]; } -- (void)MR_saveWithErrorCallback:(void (^)(NSError *))errorCallback __attribute__((deprecated)); - +- (void)MR_saveWithErrorCallback:(void (^)(NSError *error))errorCallback; { - [self MR_saveWithOptions:MRSaveSynchronously completion:^(BOOL success, NSError *error) { + [self MR_saveWithOptions:MRSaveSynchronously|MRSaveParentContexts completion:^(BOOL success, NSError *error) { if (!success) { if (errorCallback) { errorCallback(error); @@ -161,7 +134,7 @@ }]; } -- (void)MR_saveInBackgroundErrorHandler:(void (^)(NSError *))errorCallback; +- (void)MR_saveInBackgroundErrorHandler:(void (^)(NSError *error))errorCallback; { [self MR_saveOnlySelfWithCompletion:^(BOOL success, NSError *error) { if (!success) { @@ -172,7 +145,7 @@ }]; } -- (void)MR_saveInBackgroundErrorHandler:(void (^)(NSError *))errorCallback completion:(void (^)(void))completion; +- (void)MR_saveInBackgroundErrorHandler:(void (^)(NSError *error))errorCallback completion:(void (^)(void))completion; { [self MR_saveOnlySelfWithCompletion:^(BOOL success, NSError *error) { if (success) { @@ -187,4 +160,37 @@ }]; } +- (void)MR_saveNestedContexts; +{ + [self MR_saveToPersistentStoreWithCompletion:nil]; +} + +- (void)MR_saveNestedContextsErrorHandler:(void (^)(NSError *error))errorCallback; +{ + [self MR_saveToPersistentStoreWithCompletion:^(BOOL success, NSError *error) { + if (!success) { + if (errorCallback) { + errorCallback(error); + } + } + }]; +} + +- (void)MR_saveNestedContextsErrorHandler:(void (^)(NSError *error))errorCallback completion:(void (^)(void))completion; +{ + [self MR_saveToPersistentStoreWithCompletion:^(BOOL success, NSError *error) { + if (success) { + if (completion) { + completion(); + } + } else { + if (errorCallback) { + errorCallback(error); + } + } + }]; +} + +#pragma clang diagnostic pop // ignored "-Wdeprecated-implementations" + @end diff --git a/MagicalRecord/Core/MagicalRecord+Actions.h b/MagicalRecord/Core/MagicalRecord+Actions.h index 7926ac3..c11759d 100644 --- a/MagicalRecord/Core/MagicalRecord+Actions.h +++ b/MagicalRecord/Core/MagicalRecord+Actions.h @@ -39,6 +39,6 @@ /* If you want to reuse the context on the current thread, use this method. */ -+ (void) saveInBackgroundUsingCurrentContextWithBlock:(void (^)(NSManagedObjectContext *localContext))block completion:(void (^)(void))completion errorHandler:(void (^)(NSError *))errorHandler __attribute__((deprecated)); ++ (void) saveInBackgroundUsingCurrentContextWithBlock:(void (^)(NSManagedObjectContext *localContext))block completion:(void (^)(void))completion errorHandler:(void (^)(NSError *error))errorHandler __attribute__((deprecated)); @end diff --git a/MagicalRecord/Core/MagicalRecord+Actions.m b/MagicalRecord/Core/MagicalRecord+Actions.m index c4f7bf9..2e2d4d2 100644 --- a/MagicalRecord/Core/MagicalRecord+Actions.m +++ b/MagicalRecord/Core/MagicalRecord+Actions.m @@ -78,6 +78,9 @@ #pragma mark - Deprecated methods +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-implementations" + + (void) saveInBackgroundWithBlock:(void(^)(NSManagedObjectContext *localContext))block { [[self class] saveWithBlock:block completion:nil]; @@ -103,7 +106,7 @@ }]; } -+ (void) saveInBackgroundUsingCurrentContextWithBlock:(void (^)(NSManagedObjectContext *localContext))block completion:(void (^)(void))completion errorHandler:(void (^)(NSError *))errorHandler; ++ (void) saveInBackgroundUsingCurrentContextWithBlock:(void (^)(NSManagedObjectContext *localContext))block completion:(void (^)(void))completion errorHandler:(void (^)(NSError *error))errorHandler; { NSManagedObjectContext *localContext = [NSManagedObjectContext MR_contextForCurrentThread]; @@ -113,7 +116,6 @@ } [localContext MR_saveToPersistentStoreWithCompletion:^(BOOL success, NSError *error) { - if (success) { if (completion) { completion(); @@ -128,4 +130,6 @@ }]; } +#pragma clang diagnostic pop // ignored "-Wdeprecated-implementations" + @end diff --git a/Project Files/Mac Unit Tests/MagicalRecord+ActionsSpec.m b/Project Files/Mac Unit Tests/MagicalRecord+ActionsSpec.m index 219231e..17eaea4 100644 --- a/Project Files/Mac Unit Tests/MagicalRecord+ActionsSpec.m +++ b/Project Files/Mac Unit Tests/MagicalRecord+ActionsSpec.m @@ -16,213 +16,288 @@ describe(@"MagicalRecord", ^{ // Occurs after each enclosed "it" block [MagicalRecord cleanUp]; }); - + context(@"synchronous save action", ^{ it(@"should save", ^{ __block NSManagedObjectID *objectId; - __block NSManagedObject *fetchedObject; - + [MagicalRecord saveWithBlockAndWait:^(NSManagedObjectContext *localContext) { NSManagedObject *inserted = [SingleEntityWithNoRelationships MR_createInContext:localContext]; - + [[@([inserted hasChanges]) should] beTrue]; - + [localContext obtainPermanentIDsForObjects:@[inserted] error:nil]; objectId = [inserted objectID]; }]; - + [[objectId should] beNonNil]; - - fetchedObject = [[NSManagedObjectContext MR_rootSavingContext] objectWithID:objectId]; - + + NSManagedObject *fetchedObject = [[NSManagedObjectContext MR_rootSavingContext] objectRegisteredForID:objectId]; + [[fetchedObject should] beNonNil]; [[@([fetchedObject hasChanges]) should] beFalse]; }); }); - + context(@"asynchronous save action", ^{ it(@"should call completion block", ^{ __block BOOL completionBlockCalled = NO; - + [MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) { [SingleEntityWithNoRelationships MR_createInContext:localContext]; } completion:^(BOOL success, NSError *error) { // Ignore the success state — we only care that this block is executed completionBlockCalled = YES; }]; - + [[expectFutureValue(@(completionBlockCalled)) shouldEventually] beTrue]; }); - + it(@"should save", ^{ __block BOOL saveSuccessState = NO; __block NSManagedObjectID *objectId; __block NSManagedObject *fetchedObject; - + [MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) { NSManagedObject *inserted = [SingleEntityWithNoRelationships MR_createInContext:localContext]; - + [[@([inserted hasChanges]) should] beTrue]; - + [localContext obtainPermanentIDsForObjects:@[inserted] error:nil]; objectId = [inserted objectID]; } completion:^(BOOL success, NSError *error) { saveSuccessState = success; - fetchedObject = [[NSManagedObjectContext MR_rootSavingContext] objectWithID:objectId]; + fetchedObject = [[NSManagedObjectContext MR_rootSavingContext] objectRegisteredForID:objectId]; }]; - + [[expectFutureValue(@(saveSuccessState)) shouldEventually] beTrue]; [[expectFutureValue(fetchedObject) shouldEventually] beNonNil]; [[expectFutureValue(@([fetchedObject hasChanges])) shouldEventually] beFalse]; }); }); - + context(@"current thread save action", ^{ context(@"running synchronously", ^{ it(@"should save", ^{ __block NSManagedObjectID *objectId; - + [MagicalRecord saveUsingCurrentThreadContextWithBlockAndWait:^(NSManagedObjectContext *localContext) { NSManagedObject *inserted = [SingleEntityWithNoRelationships MR_createInContext:localContext]; - + [[@([inserted hasChanges]) should] beTrue]; - + [localContext obtainPermanentIDsForObjects:@[inserted] error:nil]; objectId = [inserted objectID]; }]; - + [[objectId should] beNonNil]; - - NSManagedObject *fetchedObject = [[NSManagedObjectContext MR_rootSavingContext] objectWithID:objectId]; - + + NSManagedObject *fetchedObject = [[NSManagedObjectContext MR_rootSavingContext] objectRegisteredForID:objectId]; + [[fetchedObject should] beNonNil]; [[@([fetchedObject hasChanges]) should] beFalse]; }); }); - + context(@"running asynchronously", ^{ it(@"should call completion block", ^{ __block BOOL completionBlockCalled = NO; - + [MagicalRecord saveUsingCurrentThreadContextWithBlock:^(NSManagedObjectContext *localContext) { [SingleEntityWithNoRelationships MR_createInContext:localContext]; } completion:^(BOOL success, NSError *error) { // Ignore the success state — we only care that this block is executed completionBlockCalled = YES; }]; - + [[expectFutureValue(@(completionBlockCalled)) shouldEventually] beTrue]; }); - + it(@"should save", ^{ + __block BOOL saveSuccessState = NO; + __block NSError *saveError; __block NSManagedObjectID *objectId; - + [MagicalRecord saveUsingCurrentThreadContextWithBlock:^(NSManagedObjectContext *localContext) { NSManagedObject *inserted = [SingleEntityWithNoRelationships MR_createInContext:localContext]; - + [[@([inserted hasChanges]) should] beTrue]; - + [localContext obtainPermanentIDsForObjects:@[inserted] error:nil]; objectId = [inserted objectID]; } completion:^(BOOL success, NSError *error) { - [[@(success) should] beTrue]; + saveSuccessState = success; + saveError = error; }]; + [[expectFutureValue(@(saveSuccessState)) shouldEventually] beTrue]; + [[expectFutureValue(saveError) shouldEventually] beNil]; [[expectFutureValue(objectId) shouldEventually] beNonNil]; - - NSManagedObject *fetchedObject = [[NSManagedObjectContext MR_rootSavingContext] objectWithID:objectId]; - + + NSManagedObject *fetchedObject = [[NSManagedObjectContext MR_rootSavingContext] objectRegisteredForID:objectId]; + [[expectFutureValue(fetchedObject) shouldEventually] beNonNil]; [[expectFutureValue(@([fetchedObject hasChanges])) shouldEventually] beFalse]; }); }); }); - - context(@"deprecated method", ^{ - context(@"simple save", ^{ - it(@"should save", ^{ - NSManagedObjectContext *managedObjectContext = [NSManagedObjectContext MR_defaultContext]; - NSManagedObject *inserted = [SingleEntityWithNoRelationships MR_createEntity]; - - [[@([inserted hasChanges]) should] beTrue]; - - [managedObjectContext obtainPermanentIDsForObjects:@[inserted] error:nil]; - NSManagedObjectID *objectId = [inserted objectID]; - - [[objectId should] beNonNil]; - - [[[managedObjectContext should] receive] MR_save]; - [managedObjectContext MR_save]; - - NSManagedObject *fetchedObject = [[NSManagedObjectContext MR_rootSavingContext] objectWithID:objectId]; - - [[fetchedObject should] beNonNil]; - [[@([fetchedObject hasChanges]) should] beFalse]; - }); - }); - - context(@"save action", ^{ + + + // We're testing for deprecated method function — ignore the warnings +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + + context(@"deprecated method", ^{ + context(@"saveWithBlock:", ^{ it(@"should save", ^{ __block NSManagedObjectID *objectId; - + [MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) { NSManagedObject *inserted = [SingleEntityWithNoRelationships MR_createInContext:localContext]; - + [[@([inserted hasChanges]) should] beTrue]; - + [localContext obtainPermanentIDsForObjects:@[inserted] error:nil]; objectId = [inserted objectID]; }]; - + [[objectId should] beNonNil]; - - NSManagedObject *fetchedObject = [[NSManagedObjectContext MR_rootSavingContext] objectWithID:objectId]; + + NSManagedObject *fetchedObject = [[NSManagedObjectContext MR_rootSavingContext] objectRegisteredForID:objectId]; [[objectId should] beNonNil]; [[fetchedObject should] beNonNil]; [[@([fetchedObject hasChanges]) should] beFalse]; }); }); - - context(@"background save action", ^{ - it(@"should call completion block", ^{ - __block BOOL completionBlockCalled = NO; - - [MagicalRecord saveInBackgroundWithBlock:^(NSManagedObjectContext *localContext) { - [SingleEntityWithNoRelationships MR_createInContext:localContext]; - } completion:^{ - // Ignore the success state — we only care that this block is executed - completionBlockCalled = YES; - }]; - - [[expectFutureValue(@(completionBlockCalled)) shouldEventually] beTrue]; - }); - + + context(@"saveInBackgroundWithBlock:", ^{ it(@"should save", ^{ __block NSManagedObjectID *objectId; - __block NSManagedObject *fetchedObject; - + [MagicalRecord saveInBackgroundWithBlock:^(NSManagedObjectContext *localContext) { NSManagedObject *inserted = [SingleEntityWithNoRelationships MR_createInContext:localContext]; - + [[@([inserted hasChanges]) should] beTrue]; - + [localContext obtainPermanentIDsForObjects:@[inserted] error:nil]; objectId = [inserted objectID]; - } completion:^{ - [[objectId should] beNonNil]; - - fetchedObject = [[NSManagedObjectContext MR_rootSavingContext] objectWithID:objectId]; }]; - + + [[expectFutureValue(objectId) shouldEventually] beNonNil]; + + NSManagedObject *fetchedObject = [[NSManagedObjectContext MR_rootSavingContext] objectRegisteredForID:objectId]; + [[expectFutureValue(objectId) shouldEventually] beNonNil]; [[expectFutureValue(fetchedObject) shouldEventually] beNonNil]; [[expectFutureValue(@([fetchedObject hasChanges])) shouldEventually] beFalse]; }); }); - + context(@"saveInBackgroundWithBlock:completion:", ^{ + it(@"should call completion block", ^{ + __block BOOL completionBlockCalled = NO; + + [MagicalRecord saveInBackgroundWithBlock:^(NSManagedObjectContext *localContext) { + [SingleEntityWithNoRelationships MR_createInContext:localContext]; + } completion:^{ + completionBlockCalled = YES; + }]; + + [[expectFutureValue(@(completionBlockCalled)) shouldEventually] beTrue]; + }); + + it(@"should save", ^{ + __block NSManagedObjectID *objectId; + __block NSManagedObject *fetchedObject; + + [MagicalRecord saveInBackgroundWithBlock:^(NSManagedObjectContext *localContext) { + NSManagedObject *inserted = [SingleEntityWithNoRelationships MR_createInContext:localContext]; + + [[@([inserted hasChanges])should] beTrue]; + + [localContext obtainPermanentIDsForObjects:@[inserted] error:nil]; + objectId = [inserted objectID]; + } completion:^{ + [[objectId should] beNonNil]; + + fetchedObject = [[NSManagedObjectContext MR_rootSavingContext] objectRegisteredForID:objectId]; + }]; + + [[expectFutureValue(objectId) shouldEventually] beNonNil]; + [[expectFutureValue(fetchedObject) shouldEventually] beNonNil]; + [[expectFutureValue(@([fetchedObject hasChanges])) shouldEventually] beFalse]; + }); + }); + + context(@"saveInBackgroundUsingCurrentContextWithBlock:completion:errorHandler:", ^{ + + context(@"should call", ^{ + __block BOOL completionBlockCalled = NO; + __block BOOL errorBlockCalled = NO; + + afterEach(^{ + completionBlockCalled = NO; + errorBlockCalled = NO; + }); + + it(@"completion block", ^{ + [MagicalRecord saveInBackgroundUsingCurrentContextWithBlock:^(NSManagedObjectContext *localContext) { + [SingleEntityWithNoRelationships MR_createInContext:localContext]; + } completion:^{ + completionBlockCalled = YES; + } errorHandler:^(NSError *error) { + errorBlockCalled = YES; + }]; + + [[expectFutureValue(@(completionBlockCalled)) shouldEventually] beTrue]; + [[expectFutureValue(@(errorBlockCalled)) shouldEventually] beFalse]; + }); + + it(@"error handler when there is an error", ^{ + [MagicalRecord saveInBackgroundUsingCurrentContextWithBlock:^(NSManagedObjectContext *localContext) { + // Don't make any changes so that an error is triggered + } completion:^{ + completionBlockCalled = YES; + } errorHandler:^(NSError *error) { + errorBlockCalled = YES; + }]; + + [[expectFutureValue(@(completionBlockCalled)) shouldEventually] beFalse]; + [[expectFutureValue(@(errorBlockCalled)) shouldEventually] beTrue]; + }); + }); + + it(@"should save", ^{ + __block NSError *saveError; + __block NSManagedObjectID *objectId; + __block NSManagedObject *fetchedObject; + + [MagicalRecord saveInBackgroundUsingCurrentContextWithBlock:^(NSManagedObjectContext *localContext) { + NSManagedObject *inserted = [SingleEntityWithNoRelationships MR_createInContext:localContext]; + + [[@([inserted hasChanges])should] beTrue]; + + [localContext obtainPermanentIDsForObjects:@[inserted] error:nil]; + objectId = [inserted objectID]; + } completion:^{ + [[objectId should] beNonNil]; + + fetchedObject = [[NSManagedObjectContext MR_rootSavingContext] objectRegisteredForID:objectId]; + } errorHandler:^(NSError *error) { + saveError = error; + }]; + + [[expectFutureValue(objectId) shouldEventually] beNonNil]; + [[expectFutureValue(saveError) shouldEventually] beNil]; + [[expectFutureValue(fetchedObject) shouldEventually] beNonNil]; + [[expectFutureValue(@([fetchedObject hasChanges])) shouldEventually] beFalse]; + }); + }); }); + +#pragma clang diagnostic pop // ignored "-Wdeprecated-declarations" + }); SPEC_END diff --git a/Project Files/Mac Unit Tests/NSManagedObjectContext+MagicalSavesSpec.m b/Project Files/Mac Unit Tests/NSManagedObjectContext+MagicalSavesSpec.m index fed5ef3..fee20f9 100644 --- a/Project Files/Mac Unit Tests/NSManagedObjectContext+MagicalSavesSpec.m +++ b/Project Files/Mac Unit Tests/NSManagedObjectContext+MagicalSavesSpec.m @@ -6,73 +6,519 @@ SPEC_BEGIN(NSManagedObjectContextMagicalSavesSpec) describe(@"NSManagedObjectContext+MagicalSaves", ^{ - beforeEach(^{ - // Occurs before each enclosed "it" block + beforeEach (^{ + // Occurs before each enclosed "it" block [MagicalRecord setDefaultModelFromClass:[self class]]; [MagicalRecord setupCoreDataStackWithInMemoryStore]; - }); - - afterEach(^{ - // Occurs after each enclosed "it" block + }); + + afterEach (^{ + // Occurs after each enclosed "it" block [MagicalRecord cleanUp]; - }); - - context(@"saving synchronously", ^{ - it(@"should save", ^{ - NSManagedObjectContext *managedObjectContext = [NSManagedObjectContext MR_contextWithParent:[NSManagedObjectContext MR_defaultContext]]; - NSManagedObject *inserted = [SingleEntityWithNoRelationships MR_createInContext:managedObjectContext]; - - [[@([inserted hasChanges]) should] beTrue]; - - [managedObjectContext obtainPermanentIDsForObjects:@[inserted] error:nil]; - NSManagedObjectID *objectId = inserted.objectID; - - [managedObjectContext MR_saveToPersistentStoreAndWait]; - - NSManagedObject *fetchedObject = [[NSManagedObjectContext MR_rootSavingContext] objectWithID:objectId]; - - [[fetchedObject should] beNonNil]; - [[@([fetchedObject hasChanges]) should] beFalse]; - }); - }); - - context(@"saving asynchronously", ^{ - it(@"should call completion block", ^{ - __block BOOL completionBlockCalled = NO; - - NSManagedObjectContext *managedObjectContext = [NSManagedObjectContext MR_contextForCurrentThread]; - - [SingleEntityWithNoRelationships MR_createInContext:managedObjectContext]; - - [managedObjectContext MR_saveToPersistentStoreWithCompletion:^(BOOL success, NSError *error) { - completionBlockCalled = YES; - }]; - - [[expectFutureValue(@(completionBlockCalled)) shouldEventually] beTrue]; + + context(@"be able to save to self only", ^{ + __block NSManagedObjectContext *managedObjectContext; + + beforeEach (^{ + managedObjectContext = [NSManagedObjectContext MR_context]; }); - - it(@"should save", ^{ - __block NSManagedObjectID *objectId; - NSManagedObjectContext *managedObjectContext = [NSManagedObjectContext MR_contextWithParent:[NSManagedObjectContext MR_defaultContext]]; - NSManagedObject *inserted = [SingleEntityWithNoRelationships MR_createInContext:managedObjectContext]; - - [[@([inserted hasChanges]) should] beTrue]; - - [managedObjectContext MR_saveToPersistentStoreWithCompletion:^(BOOL success, NSError *error) { + + afterEach (^{ + [managedObjectContext reset]; + managedObjectContext = nil; + }); + + context(@"synchronously", ^{ + it(@"should save", ^{ + NSManagedObject *inserted = [SingleEntityWithNoRelationships MR_createInContext:managedObjectContext]; + + [[@([inserted hasChanges]) should] beTrue]; + [managedObjectContext obtainPermanentIDsForObjects:@[inserted] error:nil]; - objectId = inserted.objectID; - }]; - - [[expectFutureValue(objectId) shouldEventually] beNonNil]; - - NSManagedObject *fetchedObject = [[NSManagedObjectContext MR_rootSavingContext] objectWithID:objectId]; - - [[expectFutureValue(fetchedObject) shouldEventually] beNonNil]; - [[expectFutureValue(@([fetchedObject hasChanges])) shouldEventually] beFalse]; + NSManagedObjectID *objectId = [inserted objectID]; + + [managedObjectContext MR_saveOnlySelfAndWait]; + + NSManagedObject *rootFetchedObject = [[NSManagedObjectContext MR_rootSavingContext] objectRegisteredForID:objectId]; + + [rootFetchedObject shouldBeNil]; + [[@([rootFetchedObject hasChanges]) should] beFalse]; + + rootFetchedObject = [managedObjectContext objectRegisteredForID:objectId]; + + [rootFetchedObject shouldNotBeNil]; + [[@([rootFetchedObject hasChanges]) should] beFalse]; + }); + }); + + context(@"asynchronously", ^{ + it(@"should call completion block", ^{ + __block BOOL completionBlockCalled = NO; + + [SingleEntityWithNoRelationships MR_createInContext:managedObjectContext]; + + [managedObjectContext MR_saveOnlySelfWithCompletion:^(BOOL success, NSError *error) { + completionBlockCalled = YES; + }]; + + [[expectFutureValue(@(completionBlockCalled)) shouldEventually] beTrue]; + }); + + it(@"should save", ^{ + __block NSManagedObjectID *objectId; + NSManagedObject *inserted = [SingleEntityWithNoRelationships MR_createInContext:managedObjectContext]; + + [[@([inserted hasChanges]) should] beTrue]; + + [managedObjectContext MR_saveOnlySelfWithCompletion:^(BOOL success, NSError *error) { + [managedObjectContext obtainPermanentIDsForObjects:@[inserted] error:nil]; + objectId = [inserted objectID]; + }]; + + [[expectFutureValue(objectId) shouldEventually] beNonNil]; + + NSManagedObject *fetchedObject = [[NSManagedObjectContext MR_rootSavingContext] objectRegisteredForID:objectId]; + + [[expectFutureValue(fetchedObject) shouldEventually] beNil]; + [[expectFutureValue(@([fetchedObject hasChanges])) shouldEventually] beFalse]; + + fetchedObject = [managedObjectContext objectRegisteredForID:objectId]; + + [[expectFutureValue(fetchedObject) shouldEventually] beNonNil]; + [[expectFutureValue(@([fetchedObject hasChanges])) shouldEventually] beFalse]; + }); }); }); - + + context(@"be able to save to the persistent store", ^{ + __block NSManagedObjectContext *managedObjectContext; + + beforeEach (^{ + managedObjectContext = [NSManagedObjectContext MR_context]; + }); + + afterEach (^{ + [managedObjectContext reset]; + managedObjectContext = nil; + }); + + context(@"synchronously", ^{ + it(@"and should save", ^{ + NSManagedObject *inserted = [SingleEntityWithNoRelationships MR_createInContext:managedObjectContext]; + + [[@([managedObjectContext hasChanges]) should] beTrue]; + [[@([inserted hasChanges]) should] beTrue]; + + [managedObjectContext obtainPermanentIDsForObjects:@[inserted] error:nil]; + NSManagedObjectID *objectId = [inserted objectID]; + + [managedObjectContext MR_saveToPersistentStoreAndWait]; + + NSManagedObject *fetchedObject = [[NSManagedObjectContext MR_rootSavingContext] objectRegisteredForID:objectId]; + + [fetchedObject shouldNotBeNil]; + [[@([fetchedObject hasChanges]) should] beFalse]; + }); + }); + + context(@"asynchronously", ^{ + it(@"and should call completion block", ^{ + __block BOOL completionBlockCalled = NO; + + [SingleEntityWithNoRelationships MR_createInContext:managedObjectContext]; + + [[@([managedObjectContext hasChanges]) should] beTrue]; + + [managedObjectContext MR_saveToPersistentStoreWithCompletion:^(BOOL success, NSError *error) { + completionBlockCalled = YES; + }]; + + [[expectFutureValue(@(completionBlockCalled)) shouldEventually] beTrue]; + }); + + it(@"and should save", ^{ + __block NSManagedObjectID *objectId; + + NSManagedObject *inserted = [SingleEntityWithNoRelationships MR_createInContext:managedObjectContext]; + + [[@([managedObjectContext hasChanges]) should] beTrue]; + [[@([inserted hasChanges]) should] beTrue]; + + [managedObjectContext MR_saveToPersistentStoreWithCompletion:^(BOOL success, NSError *error) { + [managedObjectContext obtainPermanentIDsForObjects:@[inserted] error:nil]; + objectId = [inserted objectID]; + }]; + + [[expectFutureValue(objectId) shouldEventually] beNonNil]; + + NSManagedObject *fetchedObject = [[NSManagedObjectContext MR_rootSavingContext] objectRegisteredForID:objectId]; + + [[expectFutureValue(fetchedObject) shouldEventually] beNonNil]; + [[expectFutureValue(@([fetchedObject hasChanges])) shouldEventually] beFalse]; + }); + }); + }); + + context(@"be able to save with options", ^{ + __block NSManagedObjectContext *managedObjectContext; + __block NSManagedObjectID *permanentObjectID; + __block NSManagedObject *insertedObject; + + beforeEach (^{ + managedObjectContext = [NSManagedObjectContext MR_context]; + insertedObject = [SingleEntityWithNoRelationships MR_createInContext:managedObjectContext]; + [managedObjectContext obtainPermanentIDsForObjects:@[insertedObject] error:nil]; + }); + + afterEach (^{ + [managedObjectContext reset]; + + permanentObjectID = nil; + insertedObject = nil; + managedObjectContext = nil; + }); + + context(@"synchronously", ^{ + beforeEach(^{ + permanentObjectID = [insertedObject objectID]; + [permanentObjectID shouldNotBeNil]; + }); + + specify (^{ + [[@([managedObjectContext hasChanges]) should] beTrue]; + [[@([insertedObject hasChanges]) should] beTrue]; + }); + + it(@"to self only", ^{ + [managedObjectContext MR_saveWithOptions:MRSaveSynchronously completion:^(BOOL success, NSError *error) { + [[@(success) should] beTrue]; + [error shouldBeNil]; + }]; + + NSManagedObject *fetchedObject = [[NSManagedObjectContext MR_rootSavingContext] objectRegisteredForID:permanentObjectID]; + [fetchedObject shouldBeNil]; + [[@([fetchedObject hasChanges]) should] beFalse]; + }); + + it(@"to persistent store", ^{ + [managedObjectContext MR_saveWithOptions:MRSaveSynchronously | MRSaveParentContexts completion:^(BOOL success, NSError *error) { + [[@(success) should] beTrue]; + [error shouldBeNil]; + }]; + + NSManagedObject *fetchedObject = [[NSManagedObjectContext MR_rootSavingContext] objectRegisteredForID:permanentObjectID]; + [fetchedObject shouldNotBeNil]; + [[@([fetchedObject hasChanges]) should] beFalse]; + }); + }); + + context(@"asynchronously", ^{ + it(@"to self only", ^{ + [managedObjectContext MR_saveWithOptions:0 completion:^(BOOL success, NSError *error) { + [[@(success) should] beTrue]; + [error shouldBeNil]; + + [managedObjectContext obtainPermanentIDsForObjects:@[insertedObject] error:nil]; + permanentObjectID = [insertedObject objectID]; + }]; + + [[expectFutureValue(permanentObjectID) shouldEventually] beNonNil]; + + NSManagedObject *fetchedObject = [[NSManagedObjectContext MR_rootSavingContext] objectRegisteredForID:permanentObjectID]; + [[expectFutureValue(fetchedObject) shouldEventually] beNil]; + [[@([fetchedObject hasChanges]) should] beFalse]; + }); + + it(@"to persistent store", ^{ + [managedObjectContext MR_saveWithOptions:MRSaveParentContexts completion:^(BOOL success, NSError *error) { + [[@(success) should] beTrue]; + [error shouldBeNil]; + + [managedObjectContext obtainPermanentIDsForObjects:@[insertedObject] error:nil]; + permanentObjectID = [insertedObject objectID]; + }]; + + [[expectFutureValue(permanentObjectID) shouldEventually] beNonNil]; + + NSManagedObject *fetchedObject = [[NSManagedObjectContext MR_rootSavingContext] objectRegisteredForID:permanentObjectID]; + [[expectFutureValue(fetchedObject) shouldEventually] beNonNil]; + [[@([fetchedObject hasChanges]) should] beFalse]; + }); + }); + }); + + // We're testing for deprecated method function — ignore the warnings +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + + context(@"deprecated method", ^{ + __block NSManagedObjectContext *managedObjectContext; + + beforeEach (^{ + managedObjectContext = [NSManagedObjectContext MR_contextWithParent:[NSManagedObjectContext MR_defaultContext]]; + }); + + afterEach (^{ + [managedObjectContext reset]; + managedObjectContext = nil; + }); + + context(@"MR_save", ^{ + it(@"should save", ^{ + NSManagedObject *inserted = [SingleEntityWithNoRelationships MR_createInContext:managedObjectContext]; + + [[@([inserted hasChanges]) should] beTrue]; + + [managedObjectContext obtainPermanentIDsForObjects:@[inserted] error:nil]; + NSManagedObjectID *objectId = [inserted objectID]; + + [managedObjectContext MR_save]; + + NSManagedObject *fetchedObject = [[NSManagedObjectContext MR_rootSavingContext] objectRegisteredForID:objectId]; + + [fetchedObject shouldNotBeNil]; + [[@([fetchedObject hasChanges]) should] beFalse]; + }); + }); + + context(@"MR_saveWithErrorCallback", ^{ + it(@"should call error handler on errors", ^{ + __block BOOL errorHandlerCalled = NO; + + [managedObjectContext MR_saveWithErrorCallback:^(NSError *error) { + errorHandlerCalled = YES; + }]; + + [[@(errorHandlerCalled) should] beTrue]; + }); + + it(@"should save", ^{ + NSManagedObject *inserted = [SingleEntityWithNoRelationships MR_createInContext:managedObjectContext]; + + [[@([inserted hasChanges]) should] beTrue]; + + [managedObjectContext obtainPermanentIDsForObjects:@[inserted] error:nil]; + NSManagedObjectID *objectId = [inserted objectID]; + + __block BOOL errorHandlerCalled = NO; + __block NSError *saveError; + + [managedObjectContext MR_saveWithErrorCallback:^(NSError *error) { + saveError = error; + errorHandlerCalled = YES; + }]; + + [saveError shouldBeNil]; + [[@(errorHandlerCalled) should] beFalse]; + + NSManagedObject *fetchedObject = [[NSManagedObjectContext MR_rootSavingContext] objectRegisteredForID:objectId]; + + [fetchedObject shouldNotBeNil]; + [[@([fetchedObject hasChanges]) should] beFalse]; + }); + }); + + context(@"MR_saveInBackgroundErrorHandler", ^{ + it(@"should call error handler on errors", ^{ + __block BOOL errorHandlerCalled = NO; + + [managedObjectContext MR_saveInBackgroundErrorHandler:^(NSError *error) { + errorHandlerCalled = YES; + }]; + + [[expectFutureValue(@(errorHandlerCalled)) shouldEventually] beTrue]; + }); + + it(@"should save to self, and be present in parent context", ^{ + NSManagedObject *inserted = [SingleEntityWithNoRelationships MR_createInContext:managedObjectContext]; + + [[@([inserted hasChanges]) should] beTrue]; + + [managedObjectContext obtainPermanentIDsForObjects:@[inserted] error:nil]; + NSManagedObjectID *objectId = [inserted objectID]; + + __block BOOL errorHandlerCalled = NO; + __block NSError *saveError; + + [managedObjectContext MR_saveInBackgroundErrorHandler:^(NSError *error) { + saveError = error; + errorHandlerCalled = YES; + }]; + + [[expectFutureValue(@([inserted hasChanges])) shouldEventually] beFalse]; + + // There should be no errors + [[expectFutureValue(saveError) shouldEventually] beNil]; + [[expectFutureValue(@(errorHandlerCalled)) shouldEventually] beFalse]; + + // Retrieve the object from the root saving context, and check that it's valid + NSManagedObject *fetchedObject = [[NSManagedObjectContext MR_rootSavingContext] objectRegisteredForID:objectId]; + + [[expectFutureValue(fetchedObject) shouldEventually] beNil]; + [[expectFutureValue(@([fetchedObject hasChanges])) shouldEventually] beFalse]; + + // Check that the object has been passed up to the parent context, but that the fetched object has unsaved changes + fetchedObject = [[managedObjectContext parentContext] objectRegisteredForID:objectId]; + + [[expectFutureValue(fetchedObject) shouldEventually] beNonNil]; + [[expectFutureValue(@([fetchedObject hasChanges])) shouldEventually] beTrue]; + }); + }); + + context(@"MR_saveInBackgroundErrorHandler", ^{ + it(@"should call completion block", ^{ + __block BOOL completionBlockCalled = NO; + __block BOOL errorHandlerCalled = NO; + + [SingleEntityWithNoRelationships MR_createInContext:managedObjectContext]; + + [managedObjectContext MR_saveInBackgroundErrorHandler:^(NSError *error) { + errorHandlerCalled = YES; + } completion:^{ + completionBlockCalled = YES; + }]; + + [[expectFutureValue(@(errorHandlerCalled)) shouldEventually] beFalse]; + [[expectFutureValue(@(completionBlockCalled)) shouldEventually] beTrue]; + }); + + it(@"should call error handler on errors", ^{ + __block BOOL completionBlockCalled = NO; + __block BOOL errorHandlerCalled = NO; + + [managedObjectContext MR_saveInBackgroundErrorHandler:^(NSError *error) { + errorHandlerCalled = YES; + } completion:^{ + completionBlockCalled = YES; + }]; + + [[expectFutureValue(@(errorHandlerCalled)) shouldEventually] beTrue]; + [[expectFutureValue(@(completionBlockCalled)) shouldEventually] beFalse]; + }); + + it(@"should save to self, and be present in parent context", ^{ + NSManagedObject *inserted = [SingleEntityWithNoRelationships MR_createInContext:managedObjectContext]; + + [[@([inserted hasChanges]) should] beTrue]; + + [managedObjectContext obtainPermanentIDsForObjects:@[inserted] error:nil]; + NSManagedObjectID *objectId = [inserted objectID]; + + __block BOOL errorHandlerCalled = NO; + __block NSError *saveError; + + [managedObjectContext MR_saveInBackgroundErrorHandler:^(NSError *error) { + saveError = error; + errorHandlerCalled = YES; + }]; + + [[expectFutureValue(@([inserted hasChanges])) shouldEventually] beFalse]; + + // There should be no errors + [[expectFutureValue(saveError) shouldEventually] beNil]; + [[expectFutureValue(@(errorHandlerCalled)) shouldEventually] beFalse]; + + // Retrieve the object from the root saving context, and check that it's valid + NSManagedObject *fetchedObject = [[NSManagedObjectContext MR_rootSavingContext] objectRegisteredForID:objectId]; + + [[expectFutureValue(fetchedObject) shouldEventually] beNil]; + [[expectFutureValue(@([fetchedObject hasChanges])) shouldEventually] beFalse]; + + // Check that the object has been passed up to the parent context, but that the fetched object has unsaved changes + fetchedObject = [[managedObjectContext parentContext] objectRegisteredForID:objectId]; + + [[expectFutureValue(fetchedObject) shouldEventually] beNonNil]; + [[expectFutureValue(@([fetchedObject hasChanges])) shouldEventually] beTrue]; + }); + }); + + context(@"MR_saveNestedContextsErrorHandler", ^{ + it(@"should call error handler on errors", ^{ + __block BOOL errorHandlerCalled = NO; + + [managedObjectContext MR_saveNestedContextsErrorHandler:^(NSError *error) { + errorHandlerCalled = YES; + }]; + + [[@(errorHandlerCalled) should] beTrue]; + }); + + it(@"should save", ^{ + NSManagedObject *inserted = [SingleEntityWithNoRelationships MR_createInContext:managedObjectContext]; + + [[@([inserted hasChanges]) should] beTrue]; + + [managedObjectContext obtainPermanentIDsForObjects:@[inserted] error:nil]; + NSManagedObjectID *objectId = [inserted objectID]; + + __block BOOL errorHandlerCalled = NO; + __block NSError *saveError; + + [managedObjectContext MR_saveNestedContextsErrorHandler:^(NSError *error) { + saveError = error; + errorHandlerCalled = YES; + }]; + + [[expectFutureValue(saveError) shouldEventually] beNil]; + [[expectFutureValue(@(errorHandlerCalled)) shouldEventually] beFalse]; + + NSManagedObject *fetchedObject = [[NSManagedObjectContext MR_rootSavingContext] objectRegisteredForID:objectId]; + + [[expectFutureValue(fetchedObject) shouldEventually] beNonNil]; + [[expectFutureValue(@([fetchedObject hasChanges])) shouldEventually] beFalse]; + }); + }); + + context(@"MR_saveInBackgroundErrorHandler", ^{ + it(@"should call error handler on errors", ^{ + __block BOOL errorHandlerCalled = NO; + + [managedObjectContext MR_saveInBackgroundErrorHandler:^(NSError *error) { + errorHandlerCalled = YES; + }]; + + [[expectFutureValue(@(errorHandlerCalled)) shouldEventually] beTrue]; + }); + + it(@"should save to self, and be present in parent context", ^{ + NSManagedObject *inserted = [SingleEntityWithNoRelationships MR_createInContext:managedObjectContext]; + + [[@([inserted hasChanges]) should] beTrue]; + + [managedObjectContext obtainPermanentIDsForObjects:@[inserted] error:nil]; + NSManagedObjectID *objectId = [inserted objectID]; + + __block BOOL errorHandlerCalled = NO; + __block NSError *saveError; + + [managedObjectContext MR_saveInBackgroundErrorHandler:^(NSError *error) { + saveError = error; + errorHandlerCalled = YES; + }]; + + [[expectFutureValue(@([inserted hasChanges])) shouldEventually] beFalse]; + + // There should be no errors + [[expectFutureValue(saveError) shouldEventually] beNil]; + [[expectFutureValue(@(errorHandlerCalled)) shouldEventually] beFalse]; + + // Retrieve the object from the root saving context, and check that it's valid + NSManagedObject *fetchedObject = [[NSManagedObjectContext MR_rootSavingContext] objectRegisteredForID:objectId]; + + [[expectFutureValue(fetchedObject) shouldEventually] beNil]; + [[expectFutureValue(@([fetchedObject hasChanges])) shouldEventually] beFalse]; + + // Check that the object has been passed up to the parent context, but that the fetched object has unsaved changes + fetchedObject = [[managedObjectContext parentContext] objectRegisteredForID:objectId]; + + [[expectFutureValue(fetchedObject) shouldEventually] beNonNil]; + [[expectFutureValue(@([fetchedObject hasChanges])) shouldEventually] beTrue]; + }); + }); + }); + +#pragma clang diagnostic pop // ignored "-Wdeprecated-declarations" }); SPEC_END From 4316422da767438f583a17f7baa1bfe9e886fcf9 Mon Sep 17 00:00:00 2001 From: Tony Arnold Date: Fri, 14 Dec 2012 20:49:09 +1100 Subject: [PATCH 09/10] Update README with details of the changes in this branch --- README.md | 50 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 29cbad6..8aac037 100644 --- a/README.md +++ b/README.md @@ -24,14 +24,58 @@ MagicalRecord was inspired by the ease of Ruby on Rails' Active Record fetching. MagicalRecord Platform Requirements: -* iOS5.0 and newer, or Mac OS 10.7 and newer +* iOS5.x or newer, or Mac OS 10.7 and newer * ARC An iOS4 compatible version is available for use. Reference [tag 1.8.3](https://github.com/magicalpanda/MagicalRecord/tree/1.8.3). -## Updating to 2.0 +## Updating to 2.1 + +MagicalRecord 2.1 is considered a major update since there are class and API changes that may affect existing uses of MagicalRecord in your code. + +### Changes to saving + +The APIs for saving have been revised to behave more consistently overall, and also to follow naming patterns present in Core Data. Extensive work has gone into adding automated tests that ensure the save methods (both new and deprecated) continue to work as expected through future updates. + +`MR_save` has been temporarily restored to it's original state of running synchronously on the current thread, and saving to the persistent store. However, the __`MR_save` method is marked as deprecated and will be removed in the next major release of MagicalRecord (version 3.0)__. You should use `MR_saveToPersistentStoreAndWait` if you want the same behaviour in future versions of the library. + +### New Methods +The following methods have been added: + +#### NSManagedObjectContext+MagicalSaves +- `- (void) MR_saveOnlySelfWithCompletion:(MRSaveCompletionHandler)completion;` +- `- (void) MR_saveToPersistentStoreWithCompletion:(MRSaveCompletionHandler)completion;` +- `- (void) MR_saveOnlySelfAndWait;` +- `- (void) MR_saveToPersistentStoreAndWait;` +- `- (void) MR_saveWithOptions:(MRSaveContextOptions)mask completion:(MRSaveCompletionHandler)completion;` + +#### __MagicalRecord+Actions__ +- `+ (void) saveWithBlock:(void(^)(NSManagedObjectContext *localContext))block;` +- `+ (void) saveWithBlock:(void(^)(NSManagedObjectContext *localContext))block completion:(MRSaveCompletionHandler)completion;` +- `+ (void) saveWithBlockAndWait:(void(^)(NSManagedObjectContext *localContext))block;` +- `+ (void) saveUsingCurrentThreadContextWithBlock:(void (^)(NSManagedObjectContext *localContext))block completion:(MRSaveCompletionHandler)completion;` +- `+ (void) saveUsingCurrentThreadContextWithBlockAndWait:(void (^)(NSManagedObjectContext *localContext))block;` + +### Deprecations + +The following methods have been deprecated in favour of newer alternatives, and will be removed in MagicalRecord 3.0: + +#### NSManagedObjectContext+MagicalSaves +- `- (void) MR_save;` +- `- (void) MR_saveWithErrorCallback:(void(^)(NSError *error))errorCallback;` +- `- (void) MR_saveInBackgroundCompletion:(void (^)(void))completion;` +- `- (void) MR_saveInBackgroundErrorHandler:(void (^)(NSError *error))errorCallback;` +- `- (void) MR_saveInBackgroundErrorHandler:(void (^)(NSError *error))errorCallback completion:(void (^)(void))completion;` +- `- (void) MR_saveNestedContexts;` +- `- (void) MR_saveNestedContextsErrorHandler:(void (^)(NSError *error))errorCallback;` +- `- (void) MR_saveNestedContextsErrorHandler:(void (^)(NSError *error))errorCallback completion:(void (^)(void))completion;` + +### MagicalRecord+Actions +- `+ (void) saveWithBlock:(void(^)(NSManagedObjectContext *localContext))block;` +- `+ (void) saveInBackgroundWithBlock:(void(^)(NSManagedObjectContext *localContext))block;` +- `+ (void) saveInBackgroundWithBlock:(void(^)(NSManagedObjectContext *localContext))block completion:(void(^)(void))completion;` +- `+ (void) saveInBackgroundUsingCurrentContextWithBlock:(void (^)(NSManagedObjectContext *localContext))block completion:(void (^)(void))completion errorHandler:(void (^)(NSError *error))errorHandler;` -MagicalRecord 2.0 is considered a major update since there were some class and API refactorings that will effect previous installations of MagicalRecord in your code. The most straight forward change is that *MagicalRecordHelpers* and *MRCoreDataAction* have both been replaced with a single class, *MagicalRecord*. ## ARC Support From 1af12010963cdb9208e0de425ce6e7daf04a226c Mon Sep 17 00:00:00 2001 From: Tony Arnold Date: Sat, 15 Dec 2012 12:32:42 +1100 Subject: [PATCH 10/10] Update shorthand methods and import the magical saves category so that MRSaveCompletionHandler resolves --- MagicalRecord/Core/MagicalRecordShorthand.h | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/MagicalRecord/Core/MagicalRecordShorthand.h b/MagicalRecord/Core/MagicalRecordShorthand.h index dd9efeb..ccac6fe 100644 --- a/MagicalRecord/Core/MagicalRecordShorthand.h +++ b/MagicalRecord/Core/MagicalRecordShorthand.h @@ -131,14 +131,21 @@ + (void) cleanUp; - (NSString *) description; @end +#import "NSManagedObjectContext+MagicalSaves.h" @interface NSManagedObjectContext (MagicalSavesShortHand) -- (void) save; -- (void) saveErrorHandler:(void (^)(NSError *))errorCallback; -- (void) saveInBackgroundCompletion:(void (^)(void))completion; -- (void) saveInBackgroundErrorHandler:(void (^)(NSError *))errorCallback; -- (void) saveInBackgroundErrorHandler:(void (^)(NSError *))errorCallback completion:(void (^)(void))completion; -- (void) saveNestedContexts; -- (void) saveNestedContextsErrorHandler:(void (^)(NSError *))errorCallback; +- (void) saveOnlySelfWithCompletion:(MRSaveCompletionHandler)completion; +- (void) saveToPersistentStoreWithCompletion:(MRSaveCompletionHandler)completion; +- (void) saveOnlySelfAndWait; +- (void) saveToPersistentStoreAndWait; +- (void) saveWithOptions:(MRSaveContextOptions)mask completion:(MRSaveCompletionHandler)completion; +- (void) save __attribute__((deprecated)); +- (void) saveWithErrorCallback:(void(^)(NSError *error))errorCallback __attribute__((deprecated)); +- (void) saveInBackgroundCompletion:(void (^)(void))completion __attribute__((deprecated)); +- (void) saveInBackgroundErrorHandler:(void (^)(NSError *error))errorCallback __attribute__((deprecated)); +- (void) saveInBackgroundErrorHandler:(void (^)(NSError *error))errorCallback completion:(void (^)(void))completion __attribute__((deprecated)); +- (void) saveNestedContexts __attribute__((deprecated)); +- (void) saveNestedContextsErrorHandler:(void (^)(NSError *error))errorCallback __attribute__((deprecated)); +- (void) saveNestedContextsErrorHandler:(void (^)(NSError *error))errorCallback completion:(void (^)(void))completion __attribute__((deprecated)); @end @interface NSManagedObjectContext (MagicalThreadingShortHand) + (NSManagedObjectContext *) contextForCurrentThread;