All deprecated and non-deprecated methods have tests to ensure their function

This commit is contained in:
Tony Arnold
2012-12-14 12:18:34 +11:00
parent 2c66056016
commit c2fa8c4859
6 changed files with 726 additions and 195 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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