importing unit tests

This commit is contained in:
John Rommel Estropia
2016-06-12 20:34:13 +09:00
parent 8e5c7ec9b2
commit 76a2bc1da2
15 changed files with 1603 additions and 404 deletions

View File

@@ -8,7 +8,6 @@
/* Begin PBXBuildFile section */
2F03A53619C5C6DA005002A5 /* CoreStore.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F03A53519C5C6DA005002A5 /* CoreStore.h */; settings = {ATTRIBUTES = (Public, ); }; };
2F03A54019C5C6DA005002A5 /* CoreStoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F03A53F19C5C6DA005002A5 /* CoreStoreTests.swift */; };
2F03A54D19C5C872005002A5 /* CoreData.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2F03A54C19C5C872005002A5 /* CoreData.framework */; };
2F291E2719C6D3CF007AF63F /* CoreStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F291E2619C6D3CF007AF63F /* CoreStore.swift */; };
82BA18931C4BBCBA00A0916E /* CoreStore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 82BA18891C4BBCBA00A0916E /* CoreStore.framework */; };
@@ -66,7 +65,6 @@
82BA18D61C4BBD7100A0916E /* NSManagedObjectContext+Transaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F331AFF85470064E85B /* NSManagedObjectContext+Transaction.swift */; };
82BA18D71C4BBD7100A0916E /* NSManagedObjectModel+Setup.swift in Sources */ = {isa = PBXBuildFile; fileRef = B51BE0691B47FC4B0069F532 /* NSManagedObjectModel+Setup.swift */; };
82BA18D81C4BBD7100A0916E /* WeakObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F2D1AFF849C0064E85B /* WeakObject.swift */; };
82BA18D91C4BBD9700A0916E /* CoreStoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F03A53F19C5C6DA005002A5 /* CoreStoreTests.swift */; };
82BA18DC1C4BBD9C00A0916E /* Model.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = B5D372821A39CD6900F583D9 /* Model.xcdatamodeld */; };
82BA18DD1C4BBE1400A0916E /* NSFetchedResultsController+Convenience.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5202CF91C04688100DED140 /* NSFetchedResultsController+Convenience.swift */; };
82BA18DF1C4BBE2600A0916E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 82BA18DE1C4BBE2600A0916E /* Foundation.framework */; };
@@ -99,6 +97,12 @@
B51FE5AF1CD4D00300E54258 /* CoreStore+CustomDebugStringConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = B51FE5AA1CD4D00300E54258 /* CoreStore+CustomDebugStringConvertible.swift */; };
B5202CFA1C04688100DED140 /* NSFetchedResultsController+Convenience.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5202CF91C04688100DED140 /* NSFetchedResultsController+Convenience.swift */; };
B5202CFD1C046E8400DED140 /* NSFetchedResultsController+Convenience.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5202CF91C04688100DED140 /* NSFetchedResultsController+Convenience.swift */; };
B5220E081D0C5F8D009BC71E /* ObjectObserverTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5220E071D0C5F8D009BC71E /* ObjectObserverTests.swift */; };
B5220E091D0C5F8D009BC71E /* ObjectObserverTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5220E071D0C5F8D009BC71E /* ObjectObserverTests.swift */; };
B5220E0A1D0C5F8D009BC71E /* ObjectObserverTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5220E071D0C5F8D009BC71E /* ObjectObserverTests.swift */; };
B5220E0C1D0D0D19009BC71E /* ImportTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5220E0B1D0D0D19009BC71E /* ImportTests.swift */; };
B5220E0D1D0D0D19009BC71E /* ImportTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5220E0B1D0D0D19009BC71E /* ImportTests.swift */; };
B5220E0E1D0D0D19009BC71E /* ImportTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5220E0B1D0D0D19009BC71E /* ImportTests.swift */; };
B525576C1CFAF18F00E51965 /* IntoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B525576B1CFAF18F00E51965 /* IntoTests.swift */; };
B525576D1CFAF18F00E51965 /* IntoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B525576B1CFAF18F00E51965 /* IntoTests.swift */; };
B525576E1CFAF18F00E51965 /* IntoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B525576B1CFAF18F00E51965 /* IntoTests.swift */; };
@@ -181,7 +185,6 @@
B52DD1C91BE1F94600949AFE /* NSManagedObjectContext+Transaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F331AFF85470064E85B /* NSManagedObjectContext+Transaction.swift */; };
B52DD1CA1BE1F94600949AFE /* NSManagedObjectModel+Setup.swift in Sources */ = {isa = PBXBuildFile; fileRef = B51BE0691B47FC4B0069F532 /* NSManagedObjectModel+Setup.swift */; };
B52DD1CB1BE1F94600949AFE /* WeakObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F2D1AFF849C0064E85B /* WeakObject.swift */; };
B52DD1CC1BE1F94D00949AFE /* CoreStoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F03A53F19C5C6DA005002A5 /* CoreStoreTests.swift */; };
B53FB9FE1CAB2D2F00F0D40A /* CSMigrationResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = B53FB9FD1CAB2D2F00F0D40A /* CSMigrationResult.swift */; };
B53FB9FF1CAB2D2F00F0D40A /* CSMigrationResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = B53FB9FD1CAB2D2F00F0D40A /* CSMigrationResult.swift */; };
B53FBA001CAB2D2F00F0D40A /* CSMigrationResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = B53FB9FD1CAB2D2F00F0D40A /* CSMigrationResult.swift */; };
@@ -660,7 +663,6 @@
2F03A53519C5C6DA005002A5 /* CoreStore.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CoreStore.h; sourceTree = "<group>"; };
2F03A53B19C5C6DA005002A5 /* CoreStoreTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CoreStoreTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
2F03A53E19C5C6DA005002A5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
2F03A53F19C5C6DA005002A5 /* CoreStoreTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = CoreStoreTests.swift; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
2F03A54C19C5C872005002A5 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; };
2F291E2619C6D3CF007AF63F /* CoreStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = CoreStore.swift; sourceTree = "<group>"; };
82BA18891C4BBCBA00A0916E /* CoreStore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CoreStore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -676,6 +678,8 @@
B51BE0691B47FC4B0069F532 /* NSManagedObjectModel+Setup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSManagedObjectModel+Setup.swift"; sourceTree = "<group>"; };
B51FE5AA1CD4D00300E54258 /* CoreStore+CustomDebugStringConvertible.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CoreStore+CustomDebugStringConvertible.swift"; sourceTree = "<group>"; };
B5202CF91C04688100DED140 /* NSFetchedResultsController+Convenience.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSFetchedResultsController+Convenience.swift"; sourceTree = "<group>"; };
B5220E071D0C5F8D009BC71E /* ObjectObserverTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ObjectObserverTests.swift; sourceTree = "<group>"; };
B5220E0B1D0D0D19009BC71E /* ImportTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImportTests.swift; sourceTree = "<group>"; };
B525576B1CFAF18F00E51965 /* IntoTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IntoTests.swift; sourceTree = "<group>"; };
B525576F1D02561A00E51965 /* SelectTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectTests.swift; sourceTree = "<group>"; };
B52557731D02791400E51965 /* WhereTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WhereTests.swift; sourceTree = "<group>"; };
@@ -954,13 +958,14 @@
B5489F4A1CF5F743008B4978 /* BaseTests */,
B5DBE2DD1C9939E100B5CEFA /* BridgingTests.h */,
B5DBE2DE1C9939E100B5CEFA /* BridgingTests.m */,
2F03A53F19C5C6DA005002A5 /* CoreStoreTests.swift */,
B5519A3F1CA1B17B002BEF78 /* ErrorTests.swift */,
B52557871D02DE8100E51965 /* FetchTests.swift */,
B5489F4F1CF603D5008B4978 /* FromTests.swift */,
B525577B1D0291FE00E51965 /* GroupByTests.swift */,
B5220E0B1D0D0D19009BC71E /* ImportTests.swift */,
B525576B1CFAF18F00E51965 /* IntoTests.swift */,
B5DC47C51C93D22900FA3BF3 /* MigrationChainTests.swift */,
B5220E071D0C5F8D009BC71E /* ObjectObserverTests.swift */,
B52557771D02826E00E51965 /* OrderByTests.swift */,
B57D27C11D0BC20100539C58 /* QueryTests.swift */,
B52557831D02A07400E51965 /* SectionByTests.swift */,
@@ -1764,13 +1769,14 @@
B5519A401CA1B17B002BEF78 /* ErrorTests.swift in Sources */,
B525577C1D0291FE00E51965 /* GroupByTests.swift in Sources */,
B52557741D02791400E51965 /* WhereTests.swift in Sources */,
2F03A54019C5C6DA005002A5 /* CoreStoreTests.swift in Sources */,
B5DC47C61C93D22900FA3BF3 /* MigrationChainTests.swift in Sources */,
B525576C1CFAF18F00E51965 /* IntoTests.swift in Sources */,
B5220E0C1D0D0D19009BC71E /* ImportTests.swift in Sources */,
B5D372841A39CD6900F583D9 /* Model.xcdatamodeld in Sources */,
B52557881D02DE8100E51965 /* FetchTests.swift in Sources */,
B5489F501CF603D5008B4978 /* FromTests.swift in Sources */,
B52557781D02826E00E51965 /* OrderByTests.swift in Sources */,
B5220E081D0C5F8D009BC71E /* ObjectObserverTests.swift in Sources */,
B5489F421CF5EEBC008B4978 /* TestEntity2.swift in Sources */,
B52557701D02561A00E51965 /* SelectTests.swift in Sources */,
B5489F461CF5F017008B4978 /* TransactionTests.swift in Sources */,
@@ -1911,16 +1917,17 @@
B52557751D02791400E51965 /* WhereTests.swift in Sources */,
B5DC47C71C93D22900FA3BF3 /* MigrationChainTests.swift in Sources */,
B5DBE2E01C9939E100B5CEFA /* BridgingTests.m in Sources */,
B5220E0D1D0D0D19009BC71E /* ImportTests.swift in Sources */,
B525576D1CFAF18F00E51965 /* IntoTests.swift in Sources */,
B580857B1CDF808D004C2EEB /* SetupTests.swift in Sources */,
B52557891D02DE8100E51965 /* FetchTests.swift in Sources */,
B5489F511CF603D5008B4978 /* FromTests.swift in Sources */,
B5220E091D0C5F8D009BC71E /* ObjectObserverTests.swift in Sources */,
B52557791D02826E00E51965 /* OrderByTests.swift in Sources */,
B5489F431CF5EEBC008B4978 /* TestEntity2.swift in Sources */,
B52557711D02561A00E51965 /* SelectTests.swift in Sources */,
B5489F471CF5F017008B4978 /* TransactionTests.swift in Sources */,
B52557811D029D2500E51965 /* TweakTests.swift in Sources */,
82BA18D91C4BBD9700A0916E /* CoreStoreTests.swift in Sources */,
B5489F4D1CF5F743008B4978 /* BaseTestCase.swift in Sources */,
82BA18DC1C4BBD9C00A0916E /* Model.xcdatamodeld in Sources */,
B57D27BF1D0BBE8200539C58 /* BaseTestDataTestCase.swift in Sources */,
@@ -2037,16 +2044,17 @@
B52557761D02791400E51965 /* WhereTests.swift in Sources */,
B5DC47C81C93D22900FA3BF3 /* MigrationChainTests.swift in Sources */,
B5DBE2E11C9939E100B5CEFA /* BridgingTests.m in Sources */,
B5220E0E1D0D0D19009BC71E /* ImportTests.swift in Sources */,
B525576E1CFAF18F00E51965 /* IntoTests.swift in Sources */,
B580857C1CDF808F004C2EEB /* SetupTests.swift in Sources */,
B525578A1D02DE8100E51965 /* FetchTests.swift in Sources */,
B5489F521CF603D5008B4978 /* FromTests.swift in Sources */,
B5220E0A1D0C5F8D009BC71E /* ObjectObserverTests.swift in Sources */,
B525577A1D02826E00E51965 /* OrderByTests.swift in Sources */,
B5489F441CF5EEBC008B4978 /* TestEntity2.swift in Sources */,
B52557721D02561A00E51965 /* SelectTests.swift in Sources */,
B5489F481CF5F017008B4978 /* TransactionTests.swift in Sources */,
B52557821D029D2500E51965 /* TweakTests.swift in Sources */,
B52DD1CC1BE1F94D00949AFE /* CoreStoreTests.swift in Sources */,
B5489F4E1CF5F743008B4978 /* BaseTestCase.swift in Sources */,
B5598BCC1BE2093D0092EFCE /* Model.xcdatamodeld in Sources */,
B57D27C01D0BBE8200539C58 /* BaseTestDataTestCase.swift in Sources */,

View File

@@ -70,7 +70,7 @@ class BaseTestCase: XCTestCase {
CoreStore.logger = TestLogger(self.prepareLoggerExpectations(expectations))
defer {
self.waitForExpectationsWithTimeout(0, handler: nil)
self.checkExpectationsImmediately()
CoreStore.logger = TestLogger([:])
}
return closure()
@@ -93,6 +93,17 @@ class BaseTestCase: XCTestCase {
return testExpectations
}
@nonobjc
func checkExpectationsImmediately() {
self.waitForExpectationsWithTimeout(0, handler: nil)
}
@nonobjc
func waitAndCheckExpectations() {
self.waitForExpectationsWithTimeout(10, handler: nil)
}
// MARK: XCTestCase
@@ -165,10 +176,9 @@ class TestLogger: CoreStoreLogger {
self.fulfill(.AssertionFailure)
}
@noreturn func fatalError(message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
func abort(message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
self.fulfill(.FatalError)
Swift.fatalError()
}

View File

@@ -1,364 +0,0 @@
//
// CoreStoreTests.swift
// CoreStoreTests
//
// Copyright © 2014 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import XCTest
@testable
import CoreStore
class CoreStoreTests: XCTestCase {
override func setUp() {
super.setUp()
self.deleteStores()
}
override func tearDown() {
self.deleteStores()
super.tearDown()
}
func testExample() {
let stack = DataStack(
modelName: "Model",
bundle: NSBundle(forClass: self.dynamicType)
)
CoreStore.defaultStack = stack
XCTAssert(CoreStore.defaultStack === stack, "CoreStore.defaultStack === stack")
do {
try stack.addStorageAndWait(
SQLiteStore(
fileName: "ConfigStore1.sqlite",
configuration: "Config1",
localStorageOptions: .RecreateStoreOnModelMismatch
)
)
}
catch let error as NSError {
XCTFail(error.description)
}
do {
try stack.addStorageAndWait(
SQLiteStore(
fileName: "ConfigStore2.sqlite",
configuration: "Config2",
localStorageOptions: .RecreateStoreOnModelMismatch
)
)
}
catch let error as NSError {
XCTFail(error.description)
}
let unsafeTransaction = CoreStore.beginUnsafe()
let createExpectation = self.expectationWithDescription("Entity creation")
CoreStore.beginAsynchronous { (transaction) -> Void in
let obj1 = transaction.create(Into(TestEntity1))
obj1.testEntityID = 1
obj1.testString = "lololol"
obj1.testNumber = 42
obj1.testDate = NSDate()
let count = transaction.queryValue(
From<TestEntity1>(),
Select<Int>(.Count("testNumber"))
)
XCTAssertTrue(count == 0, "count == 0 (actual: \(count))") // counts only objects in store
let obj2 = transaction.create(Into<TestEntity2>())
obj2.testEntityID = 2
obj2.testString = "hahaha"
obj2.testNumber = 100
obj2.testDate = NSDate()
let obj3 = transaction.create(Into<TestEntity2>("Config2"))
obj3.testEntityID = 3
obj3.testString = "hahaha"
obj3.testNumber = 90
obj3.testDate = NSDate()
let obj4 = transaction.create(Into(TestEntity2.self, "Config2"))
obj4.testEntityID = 5
obj4.testString = "hohoho"
obj4.testNumber = 80
obj4.testDate = NSDate()
transaction.beginSynchronous { (transaction) -> Void in
let obj4 = transaction.create(Into<TestEntity2>())
obj4.testEntityID = 4
obj4.testString = "hehehehe"
obj4.testNumber = 80
obj4.testDate = NSDate()
let objs4test = transaction.fetchOne(
From<TestEntity2>("Config2"),
Where("testEntityID", isEqualTo: 4),
Tweak { (fetchRequest) -> Void in
fetchRequest.includesPendingChanges = true
}
)
XCTAssertNotNil(objs4test, "objs4test != nil")
let objs5test = transaction.fetchOne(
From(TestEntity2),
Where("testEntityID", isEqualTo: 4),
Tweak { (fetchRequest) -> Void in
fetchRequest.includesPendingChanges = false
}
)
XCTAssertNil(objs5test, "objs5test == nil")
// Dont commit1
}
transaction.commit { (result) -> Void in
let objs4test = CoreStore.fetchOne(
From(TestEntity2),
Where("testEntityID", isEqualTo: 4),
Tweak { (fetchRequest) -> Void in
fetchRequest.includesPendingChanges = false
}
)
XCTAssertNil(objs4test, "objs4test == nil")
let objs5test = unsafeTransaction.fetchCount(From(TestEntity2))
XCTAssertTrue(objs5test == 3, "objs5test == 3")
XCTAssertTrue(NSThread.isMainThread(), "NSThread.isMainThread()")
switch result {
case .Success(let hasChanges):
XCTAssertTrue(hasChanges, "hasChanges == true")
createExpectation.fulfill()
case .Failure(let error):
XCTFail("\(error)")
}
}
}
let queryExpectation = self.expectationWithDescription("Query creation")
CoreStore.beginAsynchronous { (transaction) -> Void in
let obj1 = transaction.fetchOne(From(TestEntity1))
XCTAssertNotNil(obj1, "obj1 != nil")
var orderBy = OrderBy(.Ascending("testEntityID"))
orderBy += OrderBy(.Descending("testString"))
let objs2 = transaction.fetchAll(
From(TestEntity2),
Where("testNumber", isEqualTo: 100) || Where("%K == %@", "testNumber", 90),
orderBy,
Tweak { (fetchRequest) -> Void in
fetchRequest.includesPendingChanges = true
}
)
XCTAssertNotNil(objs2, "objs2 != nil")
XCTAssertTrue(objs2?.count == 2, "objs2?.count == 2")
transaction.commit { (result) -> Void in
let counts = CoreStore.queryAttributes(
From(TestEntity2),
Select("testString", .Count("testString", As: "count")),
GroupBy("testString")
)
XCTAssertTrue(NSThread.isMainThread(), "NSThread.isMainThread()")
switch result {
case .Success(let hasChanges):
XCTAssertFalse(hasChanges, "hasChanges == false")
queryExpectation.fulfill()
case .Failure(let error):
XCTFail("\(error)")
}
}
}
self.waitForExpectationsWithTimeout(100, handler: nil)
let max1 = CoreStore.queryValue(
From(TestEntity2),
Select<Int>(.Maximum("testNumber"))
)
XCTAssertTrue(max1 == 100, "max == 100 (actual: \(max1))")
let max2 = CoreStore.queryValue(
From(TestEntity2),
Select<NSNumber>(.Maximum("testNumber")),
Where("%K > %@", "testEntityID", 2)
)
XCTAssertTrue(max2 == 90, "max == 90 (actual: \(max2))")
CoreStore.beginSynchronous { (transaction) -> Void in
let numberOfDeletedObjects1 = transaction.deleteAll(From(TestEntity1))
XCTAssertTrue(numberOfDeletedObjects1 == 1, "numberOfDeletedObjects1 == 1 (actual: \(numberOfDeletedObjects1))")
let numberOfDeletedObjects2 = transaction.deleteAll(
From(TestEntity2),
Where("%K > %@", "testEntityID", 2)
)
XCTAssertTrue(numberOfDeletedObjects2 == 2, "numberOfDeletedObjects2 == 2 (actual: \(numberOfDeletedObjects2))")
transaction.commitAndWait()
}
CoreStore.beginSynchronous({ (transaction) -> Void in
if let obj = CoreStore.fetchOne(From(TestEntity2)) {
let oldID = obj.testEntityID
obj.testEntityID = 0
obj.testEntityID = oldID
}
transaction.commitAndWait()
})
let objs1 = CoreStore.fetchAll(From(TestEntity1))
XCTAssertNotNil(objs1, "objs1 != nil")
XCTAssertTrue(objs1?.count == 0, "objs1?.count == 0")
let objs2 = CoreStore.fetchAll(From(TestEntity2))
XCTAssertNotNil(objs2, "objs2 != nil")
XCTAssertTrue(objs2?.count == 1, "objs2?.count == 1")
let unsafeExpectation = self.expectationWithDescription("Query creation")
let obj5 = unsafeTransaction.create(Into<TestEntity1>("Config1"))
obj5.testEntityID = 5
obj5.testString = "hihihi"
obj5.testNumber = 70
obj5.testDate = NSDate()
XCTAssert(unsafeTransaction === obj5.unsafeDataTransaction, "unsafeTransaction === obj5.unsafeDataTransaction")
unsafeTransaction.commit { (result) -> Void in
XCTAssertTrue(NSThread.isMainThread(), "NSThread.isMainThread()")
switch result {
case .Success(let hasChanges):
XCTAssertTrue(hasChanges, "hasChanges == true")
CoreStore.beginSynchronous { (transaction) -> Void in
let obj5Copy1 = transaction.edit(obj5)
XCTAssertTrue(obj5.objectID == obj5Copy1?.objectID, "obj5.objectID == obj5Copy1?.objectID")
XCTAssertFalse(obj5 == obj5Copy1, "obj5 == obj5Copy1")
XCTAssertNil(obj5Copy1?.unsafeDataTransaction)
let obj5Copy2 = transaction.edit(Into(TestEntity1), obj5.objectID)
XCTAssertTrue(obj5.objectID == obj5Copy2?.objectID, "obj5.objectID == obj5Copy2?.objectID")
XCTAssertFalse(obj5 == obj5Copy2, "obj5 == obj5Copy2")
}
let count: Int? = CoreStore.queryValue(
From(TestEntity1),
Select(.Count("testNumber"))
)
XCTAssertTrue(count == 1, "count == 1 (actual: \(count))")
let obj6 = unsafeTransaction.create(Into<TestEntity1>())
obj6.testEntityID = 6
obj6.testString = "huehuehue"
obj6.testNumber = 130
obj6.testDate = NSDate()
XCTAssert(unsafeTransaction === obj6.unsafeDataTransaction, "unsafeTransaction === obj6.unsafeDataTransaction")
unsafeTransaction.commit { (result) -> Void in
XCTAssertTrue(NSThread.isMainThread(), "NSThread.isMainThread()")
switch result {
case .Success(let hasChanges):
XCTAssertTrue(hasChanges, "hasChanges == true")
let count = CoreStore.queryValue(
From(TestEntity1),
Select<Int>(.Count("testNumber"))
)
XCTAssertTrue(count == 2, "count == 2 (actual: \(count))")
CoreStore.beginSynchronous { (transaction) -> Void in
let obj6 = transaction.edit(obj6)
let obj5 = transaction.edit(obj5)
transaction.delete(obj5, obj6)
transaction.commitAndWait()
}
let count2 = CoreStore.queryValue(
From(TestEntity1),
Select<Int>(.Count("testNumber"))
)
XCTAssertTrue(count2 == 0, "count == 0 (actual: \(count2))")
unsafeExpectation.fulfill()
case .Failure(let error):
XCTFail("\(error)")
}
}
case .Failure(let error):
XCTFail("\(error)")
}
}
self.waitForExpectationsWithTimeout(100, handler: nil)
}
private func deleteStores() {
do {
try NSFileManager.defaultManager().removeItemAtURL(SQLiteStore.defaultRootDirectory)
}
catch _ { }
}
}

View File

@@ -24,6 +24,7 @@
//
import XCTest
import GCDKit
@testable
import CoreStore
@@ -33,6 +34,195 @@ import CoreStore
final class FetchTests: BaseTestDataTestCase {
@objc
dynamic func test_ThatDataStacksAndTransactions_CanFetchOneExisting() {
let configurations: [String?] = ["Config1"]
self.prepareStack(configurations: configurations) { (stack) in
self.prepareTestDataForStack(stack, configurations: configurations)
let from = From(TestEntity1)
let fetchClauses: [FetchClause] = [
OrderBy(.Ascending("testEntityID"))
]
let object = stack.fetchOne(from, fetchClauses)!
do {
let existing = stack.fetchExisting(object)
XCTAssertNotNil(existing)
XCTAssertEqual(existing!.objectID, object.objectID)
XCTAssertEqual(existing!.managedObjectContext, stack.mainContext)
}
do {
let transaction = stack.beginUnsafe()
let existing1 = transaction.fetchExisting(object)
XCTAssertNotNil(existing1)
XCTAssertEqual(existing1!.objectID, object.objectID)
XCTAssertEqual(existing1!.managedObjectContext, transaction.context)
let existing2 = stack.fetchExisting(existing1!)
XCTAssertNotNil(existing2)
XCTAssertEqual(existing2!.objectID, object.objectID)
XCTAssertEqual(existing2!.managedObjectContext, stack.mainContext)
}
do {
let fetchExpectation = self.expectationWithDescription("fetch")
var existing1: TestEntity1?
stack.beginSynchronous { (transaction) in
existing1 = transaction.fetchExisting(object)
XCTAssertNotNil(existing1)
XCTAssertEqual(existing1!.objectID, object.objectID)
XCTAssertEqual(existing1!.managedObjectContext, transaction.context)
fetchExpectation.fulfill()
}
let existing2 = stack.fetchExisting(existing1!)
XCTAssertNotNil(existing2)
XCTAssertEqual(existing2!.objectID, object.objectID)
XCTAssertEqual(existing2!.managedObjectContext, stack.mainContext)
}
do {
let fetchExpectation = self.expectationWithDescription("fetch")
stack.beginAsynchronous { (transaction) in
let existing1 = transaction.fetchExisting(object)
XCTAssertNotNil(existing1)
XCTAssertEqual(existing1!.objectID, object.objectID)
XCTAssertEqual(existing1!.managedObjectContext, transaction.context)
GCDQueue.Main.async {
let existing2 = stack.fetchExisting(existing1!)
XCTAssertNotNil(existing2)
XCTAssertEqual(existing2!.objectID, object.objectID)
XCTAssertEqual(existing2!.managedObjectContext, stack.mainContext)
fetchExpectation.fulfill()
}
}
}
}
self.waitAndCheckExpectations()
}
@objc
dynamic func test_ThatDataStacksAndTransactions_CanFetchAllExisting() {
let configurations: [String?] = ["Config1"]
self.prepareStack(configurations: configurations) { (stack) in
self.prepareTestDataForStack(stack, configurations: configurations)
let from = From(TestEntity1)
let fetchClauses: [FetchClause] = [
OrderBy(.Ascending("testEntityID"))
]
let objects = stack.fetchAll(from, fetchClauses)!
do {
let existing = stack.fetchExisting(objects)
XCTAssertEqual(
existing.map { $0.objectID },
objects.map { $0.objectID }
)
for object in existing {
XCTAssertEqual(object.managedObjectContext, stack.mainContext)
}
}
do {
let transaction = stack.beginUnsafe()
let existing1 = transaction.fetchExisting(objects)
XCTAssertEqual(
existing1.map { $0.objectID },
objects.map { $0.objectID }
)
for object in existing1 {
XCTAssertEqual(object.managedObjectContext, transaction.context)
}
let existing2 = stack.fetchExisting(existing1)
XCTAssertEqual(
existing2.map { $0.objectID },
objects.map { $0.objectID }
)
for object in existing2 {
XCTAssertEqual(object.managedObjectContext, stack.mainContext)
}
}
do {
let fetchExpectation = self.expectationWithDescription("fetch")
var existing1 = [TestEntity1]()
stack.beginSynchronous { (transaction) in
existing1 = transaction.fetchExisting(objects)
XCTAssertEqual(
existing1.map { $0.objectID },
objects.map { $0.objectID }
)
for object in existing1 {
XCTAssertEqual(object.managedObjectContext, transaction.context)
}
fetchExpectation.fulfill()
}
let existing2 = stack.fetchExisting(existing1)
XCTAssertEqual(
existing2.map { $0.objectID },
objects.map { $0.objectID }
)
for object in existing2 {
XCTAssertEqual(object.managedObjectContext, stack.mainContext)
}
}
do {
let fetchExpectation = self.expectationWithDescription("fetch")
stack.beginAsynchronous { (transaction) in
let existing1 = transaction.fetchExisting(objects)
XCTAssertEqual(
existing1.map { $0.objectID },
objects.map { $0.objectID }
)
for object in existing1 {
XCTAssertEqual(object.managedObjectContext, transaction.context)
}
GCDQueue.Main.async {
let existing2 = stack.fetchExisting(existing1)
XCTAssertEqual(
existing2.map { $0.objectID },
objects.map { $0.objectID }
)
for object in existing2 {
XCTAssertEqual(object.managedObjectContext, stack.mainContext)
}
fetchExpectation.fulfill()
}
}
}
}
self.waitAndCheckExpectations()
}
@objc
dynamic func test_ThatDataStacks_CanFetchOneFromDefaultConfiguration() {

View File

@@ -0,0 +1,983 @@
//
// ImportTests.swift
// CoreStore
//
// Copyright © 2016 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import XCTest
@testable
import CoreStore
// MARK: - ImportTests
class ImportTests: BaseTestDataTestCase {
@objc
dynamic func test_ThatImportObject_CanSkipImport() {
self.prepareStack { (stack) in
stack.beginSynchronous { (transaction) in
do {
let object = try transaction.importObject(
Into(TestEntity1),
source: [
"testBoolean": NSNumber(bool: true),
"testNumber": NSNumber(integer: 1),
"testDecimal": NSDecimalNumber(string: "1"),
"testString": "nil:TestEntity1:1",
"testData": ("nil:TestEntity1:1" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!,
"testDate": self.dateFormatter.dateFromString("2000-01-01T00:00:00Z")!,
"skip_insert": ""
]
)
XCTAssertNil(object)
XCTAssertEqual(transaction.fetchCount(From(TestEntity1)), 0)
}
catch {
XCTFail()
}
}
}
}
@objc
dynamic func test_ThatImportObject_CanThrowError() {
self.prepareStack { (stack) in
stack.beginSynchronous { (transaction) in
let errorExpectation = self.expectationWithDescription("error")
do {
let _ = try transaction.importObject(
Into(TestEntity1),
source: [
"testBoolean": NSNumber(bool: true),
"testNumber": NSNumber(integer: 1),
"testDecimal": NSDecimalNumber(string: "1"),
"testString": "nil:TestEntity1:1",
"testData": ("nil:TestEntity1:1" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!,
"testDate": self.dateFormatter.dateFromString("2000-01-01T00:00:00Z")!,
"throw_on_insert": ""
]
)
XCTFail()
}
catch _ as TestInsertError {
errorExpectation.fulfill()
XCTAssertEqual(transaction.fetchCount(From(TestEntity1)), 1)
let object = transaction.fetchOne(From(TestEntity1))
XCTAssertNotNil(object)
XCTAssertNil(object?.testEntityID)
XCTAssertNil(object?.testBoolean)
XCTAssertNil(object?.testNumber)
XCTAssertNil(object?.testDecimal)
XCTAssertNil(object?.testString)
XCTAssertNil(object?.testData)
XCTAssertNil(object?.testDate)
}
catch {
XCTFail()
}
self.checkExpectationsImmediately()
transaction.context.reset()
}
}
}
@objc
dynamic func test_ThatImportObject_CanImportCorrectly() {
self.prepareStack { (stack) in
stack.beginSynchronous { (transaction) in
do {
let object = try transaction.importObject(
Into(TestEntity1),
source: [
"testBoolean": NSNumber(bool: true),
"testNumber": NSNumber(integer: 1),
"testDecimal": NSDecimalNumber(string: "1"),
"testString": "nil:TestEntity1:1",
"testData": ("nil:TestEntity1:1" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!,
"testDate": self.dateFormatter.dateFromString("2000-01-01T00:00:00Z")!
]
)
XCTAssertNotNil(object)
XCTAssertEqual(transaction.fetchCount(From(TestEntity1)), 1)
XCTAssertNil(object?.testEntityID)
XCTAssertEqual(object?.testBoolean, NSNumber(bool: true))
XCTAssertEqual(object?.testNumber, NSNumber(integer: 1))
XCTAssertEqual(object?.testDecimal, NSDecimalNumber(string: "1"))
XCTAssertEqual(object?.testString, "nil:TestEntity1:1")
XCTAssertEqual(object?.testData, ("nil:TestEntity1:1" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!)
XCTAssertEqual(object?.testDate, self.dateFormatter.dateFromString("2000-01-01T00:00:00Z")!)
try transaction.importObject(
object!,
source: [
"testBoolean": NSNumber(bool: false),
"testNumber": NSNumber(integer: 2),
"testDecimal": NSDecimalNumber(string: "2"),
"testString": "nil:TestEntity1:2",
"testData": ("nil:TestEntity1:2" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!,
"testDate": self.dateFormatter.dateFromString("2000-01-02T00:00:00Z")!
]
)
XCTAssertEqual(transaction.fetchCount(From(TestEntity1)), 1)
XCTAssertNil(object?.testEntityID)
XCTAssertEqual(object?.testBoolean, NSNumber(bool: false))
XCTAssertEqual(object?.testNumber, NSNumber(integer: 2))
XCTAssertEqual(object?.testDecimal, NSDecimalNumber(string: "2"))
XCTAssertEqual(object?.testString, "nil:TestEntity1:2")
XCTAssertEqual(object?.testData, ("nil:TestEntity1:2" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!)
XCTAssertEqual(object?.testDate, self.dateFormatter.dateFromString("2000-01-02T00:00:00Z")!)
}
catch {
XCTFail()
}
transaction.context.reset()
}
}
}
@objc
dynamic func test_ThatImportObjects_CanSkipImport() {
self.prepareStack { (stack) in
stack.beginSynchronous { (transaction) in
do {
let sourceArray: [TestEntity1.ImportSource] = [
[
"testBoolean": NSNumber(bool: true),
"testNumber": NSNumber(integer: 1),
"testDecimal": NSDecimalNumber(string: "1"),
"testString": "nil:TestEntity1:1",
"testData": ("nil:TestEntity1:1" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!,
"testDate": self.dateFormatter.dateFromString("2000-01-01T00:00:00Z")!,
"skip_insert": ""
],
[
"testBoolean": NSNumber(bool: false),
"testNumber": NSNumber(integer: 2),
"testDecimal": NSDecimalNumber(string: "2"),
"testString": "nil:TestEntity1:2",
"testData": ("nil:TestEntity1:2" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!,
"testDate": self.dateFormatter.dateFromString("2000-01-02T00:00:00Z")!
]
]
let objects = try transaction.importObjects(
Into(TestEntity1),
sourceArray: sourceArray
)
XCTAssertEqual(objects.count, 1)
XCTAssertEqual(transaction.fetchCount(From(TestEntity1)), 1)
let object = objects[0]
let dictionary = sourceArray[1]
XCTAssertNil(object.testEntityID)
XCTAssertEqual(object.testBoolean, dictionary["testBoolean"] as? NSNumber)
XCTAssertEqual(object.testNumber, dictionary["testNumber"] as? NSNumber)
XCTAssertEqual(object.testDecimal, dictionary["testDecimal"] as? NSDecimalNumber)
XCTAssertEqual(object.testString, dictionary["testString"] as? String)
XCTAssertEqual(object.testData, dictionary["testData"] as? NSData)
XCTAssertEqual(object.testDate, dictionary["testDate"] as? NSDate)
}
catch {
XCTFail()
}
transaction.context.reset()
}
}
}
@objc
dynamic func test_ThatImportObjects_CanThrowError() {
self.prepareStack { (stack) in
stack.beginSynchronous { (transaction) in
let errorExpectation = self.expectationWithDescription("error")
do {
let sourceArray: [TestEntity1.ImportSource] = [
[
"testBoolean": NSNumber(bool: true),
"testNumber": NSNumber(integer: 1),
"testDecimal": NSDecimalNumber(string: "1"),
"testString": "nil:TestEntity1:1",
"testData": ("nil:TestEntity1:1" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!,
"testDate": self.dateFormatter.dateFromString("2000-01-01T00:00:00Z")!,
"throw_on_insert": ""
],
[
"testBoolean": NSNumber(bool: false),
"testNumber": NSNumber(integer: 2),
"testDecimal": NSDecimalNumber(string: "2"),
"testString": "nil:TestEntity1:2",
"testData": ("nil:TestEntity1:2" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!,
"testDate": self.dateFormatter.dateFromString("2000-01-02T00:00:00Z")!
]
]
let _ = try transaction.importObjects(
Into(TestEntity1),
sourceArray: sourceArray
)
XCTFail()
}
catch _ as TestInsertError {
errorExpectation.fulfill()
XCTAssertEqual(transaction.fetchCount(From(TestEntity1)), 1)
let object = transaction.fetchOne(From(TestEntity1))
XCTAssertNotNil(object)
XCTAssertNil(object?.testEntityID)
XCTAssertNil(object?.testBoolean)
XCTAssertNil(object?.testNumber)
XCTAssertNil(object?.testDecimal)
XCTAssertNil(object?.testString)
XCTAssertNil(object?.testData)
XCTAssertNil(object?.testDate)
}
catch {
XCTFail()
}
self.checkExpectationsImmediately()
transaction.context.reset()
}
}
}
@objc
dynamic func test_ThatImportObjects_CanImportCorrectly() {
self.prepareStack { (stack) in
stack.beginSynchronous { (transaction) in
do {
let sourceArray: [TestEntity1.ImportSource] = [
[
"testBoolean": NSNumber(bool: true),
"testNumber": NSNumber(integer: 1),
"testDecimal": NSDecimalNumber(string: "1"),
"testString": "nil:TestEntity1:1",
"testData": ("nil:TestEntity1:1" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!,
"testDate": self.dateFormatter.dateFromString("2000-01-01T00:00:00Z")!
],
[
"testBoolean": NSNumber(bool: false),
"testNumber": NSNumber(integer: 2),
"testDecimal": NSDecimalNumber(string: "2"),
"testString": "nil:TestEntity1:2",
"testData": ("nil:TestEntity1:2" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!,
"testDate": self.dateFormatter.dateFromString("2000-01-02T00:00:00Z")!
]
]
let objects = try transaction.importObjects(
Into(TestEntity1),
sourceArray: sourceArray
)
XCTAssertEqual(objects.count, sourceArray.count)
XCTAssertEqual(transaction.fetchCount(From(TestEntity1)), 2)
for i in 0 ..< sourceArray.count {
let object = objects[i]
let dictionary = sourceArray[i]
XCTAssertNil(object.testEntityID)
XCTAssertEqual(object.testBoolean, dictionary["testBoolean"] as? NSNumber)
XCTAssertEqual(object.testNumber, dictionary["testNumber"] as? NSNumber)
XCTAssertEqual(object.testDecimal, dictionary["testDecimal"] as? NSDecimalNumber)
XCTAssertEqual(object.testString, dictionary["testString"] as? String)
XCTAssertEqual(object.testData, dictionary["testData"] as? NSData)
XCTAssertEqual(object.testDate, dictionary["testDate"] as? NSDate)
}
}
catch {
XCTFail()
}
transaction.context.reset()
}
}
}
@objc
dynamic func test_ThatImportUniqueObject_CanSkipImport() {
self.prepareStack { (stack) in
self.prepareTestDataForStack(stack, configurations: [nil])
stack.beginSynchronous { (transaction) in
do {
let object = try transaction.importUniqueObject(
Into(TestEntity1),
source: [
"testEntityID": NSNumber(integer: 106),
"testBoolean": NSNumber(bool: true),
"testNumber": NSNumber(integer: 6),
"testDecimal": NSDecimalNumber(string: "6"),
"testString": "nil:TestEntity1:6",
"testData": ("nil:TestEntity1:6" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!,
"testDate": self.dateFormatter.dateFromString("2000-01-06T00:00:00Z")!,
"skip_insert": ""
]
)
XCTAssertNil(object)
XCTAssertEqual(transaction.fetchCount(From(TestEntity1)), 5)
}
catch {
XCTFail()
}
do {
let object = try transaction.importUniqueObject(
Into(TestEntity1),
source: [
"testEntityID": NSNumber(integer: 105),
"testBoolean": NSNumber(bool: false),
"testNumber": NSNumber(integer: 6),
"testDecimal": NSDecimalNumber(string: "6"),
"testString": "nil:TestEntity1:6",
"testData": ("nil:TestEntity1:6" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!,
"testDate": self.dateFormatter.dateFromString("2000-01-06T00:00:00Z")!,
"skip_update": ""
]
)
XCTAssertNil(object)
XCTAssertEqual(transaction.fetchCount(From(TestEntity1)), 5)
let existingObjects = transaction.fetchAll(From(TestEntity1), Where("testEntityID", isEqualTo: 105))
XCTAssertNotNil(existingObjects)
XCTAssertEqual(existingObjects?.count, 1)
let existingObject = existingObjects?[0]
XCTAssertEqual(existingObject?.testEntityID, NSNumber(integer: 105))
XCTAssertEqual(existingObject?.testBoolean, NSNumber(bool: true))
XCTAssertEqual(existingObject?.testNumber, NSNumber(integer: 5))
XCTAssertEqual(existingObject?.testDecimal, NSDecimalNumber(string: "5"))
XCTAssertEqual(existingObject?.testString, "nil:TestEntity1:5")
XCTAssertEqual(existingObject?.testData, ("nil:TestEntity1:5" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!)
XCTAssertEqual(existingObject?.testDate, self.dateFormatter.dateFromString("2000-01-05T00:00:00Z")!)
}
catch {
XCTFail()
}
}
}
}
@objc
dynamic func test_ThatImportUniqueObject_CanThrowError() {
self.prepareStack { (stack) in
self.prepareTestDataForStack(stack, configurations: [nil])
stack.beginSynchronous { (transaction) in
do {
let errorExpectation = self.expectationWithDescription("error")
do {
let _ = try transaction.importUniqueObject(
Into(TestEntity1),
source: [
"testEntityID": NSNumber(integer: 106),
"testBoolean": NSNumber(bool: true),
"testNumber": NSNumber(integer: 6),
"testDecimal": NSDecimalNumber(string: "6"),
"testString": "nil:TestEntity1:6",
"testData": ("nil:TestEntity1:6" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!,
"testDate": self.dateFormatter.dateFromString("2000-01-06T00:00:00Z")!,
"throw_on_insert": ""
]
)
XCTFail()
}
catch _ as TestInsertError {
errorExpectation.fulfill()
XCTAssertEqual(transaction.fetchCount(From(TestEntity1)), 6)
let object = transaction.fetchOne(From(TestEntity1), Where("testEntityID", isEqualTo: 106))
XCTAssertNotNil(object)
XCTAssertEqual(object?.testEntityID, NSNumber(integer: 106))
XCTAssertNil(object?.testBoolean)
XCTAssertNil(object?.testNumber)
XCTAssertNil(object?.testDecimal)
XCTAssertNil(object?.testString)
XCTAssertNil(object?.testData)
XCTAssertNil(object?.testDate)
}
catch {
XCTFail()
}
self.checkExpectationsImmediately()
}
do {
let errorExpectation = self.expectationWithDescription("error")
do {
let _ = try transaction.importUniqueObject(
Into(TestEntity1),
source: [
"testEntityID": NSNumber(integer: 105),
"testBoolean": NSNumber(bool: false),
"testNumber": NSNumber(integer: 6),
"testDecimal": NSDecimalNumber(string: "6"),
"testString": "nil:TestEntity1:6",
"testData": ("nil:TestEntity1:6" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!,
"testDate": self.dateFormatter.dateFromString("2000-01-06T00:00:00Z")!,
"throw_on_update": ""
]
)
XCTFail()
}
catch _ as TestUpdateError {
errorExpectation.fulfill()
XCTAssertEqual(transaction.fetchCount(From(TestEntity1)), 6)
let existingObjects = transaction.fetchAll(From(TestEntity1), Where("testEntityID", isEqualTo: 105))
XCTAssertNotNil(existingObjects)
XCTAssertEqual(existingObjects?.count, 1)
let existingObject = existingObjects?[0]
XCTAssertNotNil(existingObject)
XCTAssertEqual(existingObject?.testEntityID, NSNumber(integer: 105))
XCTAssertEqual(existingObject?.testBoolean, NSNumber(bool: true))
XCTAssertEqual(existingObject?.testNumber, NSNumber(integer: 5))
XCTAssertEqual(existingObject?.testDecimal, NSDecimalNumber(string: "5"))
XCTAssertEqual(existingObject?.testString, "nil:TestEntity1:5")
XCTAssertEqual(existingObject?.testData, ("nil:TestEntity1:5" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!)
XCTAssertEqual(existingObject?.testDate, self.dateFormatter.dateFromString("2000-01-05T00:00:00Z")!)
}
catch {
XCTFail()
}
self.checkExpectationsImmediately()
}
transaction.context.reset()
}
}
}
@objc
dynamic func test_ThatImportUniqueObject_CanImportCorrectly() {
self.prepareStack { (stack) in
self.prepareTestDataForStack(stack, configurations: [nil])
stack.beginSynchronous { (transaction) in
do {
let object = try transaction.importUniqueObject(
Into(TestEntity1),
source: [
"testEntityID": NSNumber(integer: 106),
"testBoolean": NSNumber(bool: true),
"testNumber": NSNumber(integer: 6),
"testDecimal": NSDecimalNumber(string: "6"),
"testString": "nil:TestEntity1:6",
"testData": ("nil:TestEntity1:6" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!,
"testDate": self.dateFormatter.dateFromString("2000-01-06T00:00:00Z")!
]
)
XCTAssertNotNil(object)
XCTAssertEqual(transaction.fetchCount(From(TestEntity1)), 6)
XCTAssertEqual(object?.testEntityID, NSNumber(integer: 106))
XCTAssertEqual(object?.testBoolean, NSNumber(bool: true))
XCTAssertEqual(object?.testNumber, NSNumber(integer: 6))
XCTAssertEqual(object?.testDecimal, NSDecimalNumber(string: "6"))
XCTAssertEqual(object?.testString, "nil:TestEntity1:6")
XCTAssertEqual(object?.testData, ("nil:TestEntity1:6" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!)
XCTAssertEqual(object?.testDate, self.dateFormatter.dateFromString("2000-01-06T00:00:00Z")!)
}
catch {
XCTFail()
}
do {
let object = try transaction.importUniqueObject(
Into(TestEntity1),
source: [
"testEntityID": NSNumber(integer: 106),
"testBoolean": NSNumber(bool: false),
"testNumber": NSNumber(integer: 7),
"testDecimal": NSDecimalNumber(string: "7"),
"testString": "nil:TestEntity1:7",
"testData": ("nil:TestEntity1:7" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!,
"testDate": self.dateFormatter.dateFromString("2000-01-07T00:00:00Z")!,
]
)
XCTAssertNotNil(object)
XCTAssertEqual(transaction.fetchCount(From(TestEntity1)), 6)
XCTAssertEqual(object?.testEntityID, NSNumber(integer: 106))
XCTAssertEqual(object?.testBoolean, NSNumber(bool: false))
XCTAssertEqual(object?.testNumber, NSNumber(integer: 7))
XCTAssertEqual(object?.testDecimal, NSDecimalNumber(string: "7"))
XCTAssertEqual(object?.testString, "nil:TestEntity1:7")
XCTAssertEqual(object?.testData, ("nil:TestEntity1:7" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!)
XCTAssertEqual(object?.testDate, self.dateFormatter.dateFromString("2000-01-07T00:00:00Z")!)
let existingObjects = transaction.fetchAll(From(TestEntity1), Where("testEntityID", isEqualTo: 106))
XCTAssertNotNil(existingObjects)
XCTAssertEqual(existingObjects?.count, 1)
let existingObject = existingObjects?[0]
XCTAssertEqual(existingObject, object)
}
catch {
XCTFail()
}
transaction.context.reset()
}
}
}
@objc
dynamic func test_ThatImportUniqueObjects_CanSkipImport() {
self.prepareStack { (stack) in
self.prepareTestDataForStack(stack, configurations: [nil])
stack.beginSynchronous { (transaction) in
do {
let sourceArray: [TestEntity1.ImportSource] = [
[
"testEntityID": NSNumber(integer: 106),
"testBoolean": NSNumber(bool: true),
"testNumber": NSNumber(integer: 6),
"testDecimal": NSDecimalNumber(string: "6"),
"testString": "nil:TestEntity1:6",
"testData": ("nil:TestEntity1:6" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!,
"testDate": self.dateFormatter.dateFromString("2000-01-06T00:00:00Z")!,
"skip_insert": ""
],
[
"testEntityID": NSNumber(integer: 107),
"testBoolean": NSNumber(bool: false),
"testNumber": NSNumber(integer: 7),
"testDecimal": NSDecimalNumber(string: "7"),
"testString": "nil:TestEntity1:7",
"testData": ("nil:TestEntity1:7" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!,
"testDate": self.dateFormatter.dateFromString("2000-01-07T00:00:00Z")!
]
]
let objects = try transaction.importUniqueObjects(
Into(TestEntity1),
sourceArray: sourceArray
)
XCTAssertEqual(objects.count, 1)
XCTAssertEqual(transaction.fetchCount(From(TestEntity1)), 6)
let object = objects[0]
let dictionary = sourceArray[1]
XCTAssertEqual(object.testEntityID, dictionary["testEntityID"] as? NSNumber)
XCTAssertEqual(object.testBoolean, dictionary["testBoolean"] as? NSNumber)
XCTAssertEqual(object.testNumber, dictionary["testNumber"] as? NSNumber)
XCTAssertEqual(object.testDecimal, dictionary["testDecimal"] as? NSDecimalNumber)
XCTAssertEqual(object.testString, dictionary["testString"] as? String)
XCTAssertEqual(object.testData, dictionary["testData"] as? NSData)
XCTAssertEqual(object.testDate, dictionary["testDate"] as? NSDate)
}
catch {
XCTFail()
}
transaction.context.reset()
}
}
}
@objc
dynamic func test_ThatImportUniqueObjects_CanThrowError() {
self.prepareStack { (stack) in
self.prepareTestDataForStack(stack, configurations: [nil])
stack.beginSynchronous { (transaction) in
let errorExpectation = self.expectationWithDescription("error")
do {
let sourceArray: [TestEntity1.ImportSource] = [
[
"testEntityID": NSNumber(integer: 106),
"testBoolean": NSNumber(bool: true),
"testNumber": NSNumber(integer: 6),
"testDecimal": NSDecimalNumber(string: "6"),
"testString": "nil:TestEntity1:6",
"testData": ("nil:TestEntity1:6" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!,
"testDate": self.dateFormatter.dateFromString("2000-01-06T00:00:00Z")!,
"throw_on_id": ""
],
[
"testEntityID": NSNumber(integer: 107),
"testBoolean": NSNumber(bool: false),
"testNumber": NSNumber(integer: 7),
"testDecimal": NSDecimalNumber(string: "7"),
"testString": "nil:TestEntity1:7",
"testData": ("nil:TestEntity1:7" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!,
"testDate": self.dateFormatter.dateFromString("2000-01-07T00:00:00Z")!
]
]
let _ = try transaction.importUniqueObjects(
Into(TestEntity1),
sourceArray: sourceArray
)
XCTFail()
}
catch _ as TestIDError {
errorExpectation.fulfill()
XCTAssertEqual(transaction.fetchCount(From(TestEntity1)), 5)
XCTAssertNil(transaction.fetchOne(From(TestEntity1), Where("testEntityID", isEqualTo: 106)))
XCTAssertNil(transaction.fetchOne(From(TestEntity1), Where("testEntityID", isEqualTo: 107)))
}
catch {
XCTFail()
}
self.checkExpectationsImmediately()
transaction.context.reset()
}
stack.beginSynchronous { (transaction) in
let errorExpectation = self.expectationWithDescription("error")
do {
let sourceArray: [TestEntity1.ImportSource] = [
[
"testEntityID": NSNumber(integer: 106),
"testBoolean": NSNumber(bool: true),
"testNumber": NSNumber(integer: 6),
"testDecimal": NSDecimalNumber(string: "6"),
"testString": "nil:TestEntity1:6",
"testData": ("nil:TestEntity1:6" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!,
"testDate": self.dateFormatter.dateFromString("2000-01-06T00:00:00Z")!,
"throw_on_insert": ""
],
[
"testEntityID": NSNumber(integer: 107),
"testBoolean": NSNumber(bool: false),
"testNumber": NSNumber(integer: 7),
"testDecimal": NSDecimalNumber(string: "7"),
"testString": "nil:TestEntity1:7",
"testData": ("nil:TestEntity1:7" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!,
"testDate": self.dateFormatter.dateFromString("2000-01-07T00:00:00Z")!
]
]
let _ = try transaction.importUniqueObjects(
Into(TestEntity1),
sourceArray: sourceArray
)
XCTFail()
}
catch _ as TestInsertError {
errorExpectation.fulfill()
XCTAssertEqual(transaction.fetchCount(From(TestEntity1)), 7)
let object = transaction.fetchOne(From(TestEntity1), Where("testEntityID", isEqualTo: 106))
XCTAssertNotNil(object)
XCTAssertEqual(object?.testEntityID, NSNumber(integer: 106))
XCTAssertNil(object?.testBoolean)
XCTAssertNil(object?.testNumber)
XCTAssertNil(object?.testDecimal)
XCTAssertNil(object?.testString)
XCTAssertNil(object?.testData)
XCTAssertNil(object?.testDate)
}
catch {
XCTFail()
}
self.checkExpectationsImmediately()
transaction.context.reset()
}
stack.beginSynchronous { (transaction) in
let errorExpectation = self.expectationWithDescription("error")
do {
let sourceArray: [TestEntity1.ImportSource] = [
[
"testEntityID": NSNumber(integer: 105),
"testBoolean": NSNumber(bool: false),
"testNumber": NSNumber(integer: 6),
"testDecimal": NSDecimalNumber(string: "6"),
"testString": "nil:TestEntity1:6",
"testData": ("nil:TestEntity1:6" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!,
"testDate": self.dateFormatter.dateFromString("2000-01-06T00:00:00Z")!,
"throw_on_update": ""
]
]
let _ = try transaction.importUniqueObjects(
Into(TestEntity1),
sourceArray: sourceArray
)
XCTFail()
}
catch _ as TestUpdateError {
errorExpectation.fulfill()
XCTAssertEqual(transaction.fetchCount(From(TestEntity1)), 5)
let object = transaction.fetchOne(From(TestEntity1), Where("testEntityID", isEqualTo: 105))
XCTAssertNotNil(object)
XCTAssertEqual(object?.testEntityID, NSNumber(integer: 105))
XCTAssertEqual(object?.testBoolean, NSNumber(bool: true))
XCTAssertEqual(object?.testNumber, NSNumber(integer: 5))
XCTAssertEqual(object?.testDecimal, NSDecimalNumber(string: "5"))
XCTAssertEqual(object?.testString, "nil:TestEntity1:5")
XCTAssertEqual(object?.testData, ("nil:TestEntity1:5" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!)
XCTAssertEqual(object?.testDate, self.dateFormatter.dateFromString("2000-01-05T00:00:00Z")!)
let existingObjects = transaction.fetchAll(From(TestEntity1), Where("testEntityID", isEqualTo: 105))
XCTAssertNotNil(existingObjects)
XCTAssertEqual(existingObjects?.count, 1)
let existingObject = existingObjects?[0]
XCTAssertEqual(existingObject, object)
}
catch {
XCTFail()
}
self.checkExpectationsImmediately()
transaction.context.reset()
}
}
}
@objc
dynamic func test_ThatImportUniqueObjects_CanImportCorrectly() {
self.prepareStack { (stack) in
self.prepareTestDataForStack(stack, configurations: [nil])
stack.beginSynchronous { (transaction) in
do {
let sourceArray: [TestEntity1.ImportSource] = [
[
"testEntityID": NSNumber(integer: 105),
"testBoolean": NSNumber(bool: false),
"testNumber": NSNumber(integer: 15),
"testDecimal": NSDecimalNumber(string: "15"),
"testString": "nil:TestEntity1:15",
"testData": ("nil:TestEntity1:15" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!,
"testDate": self.dateFormatter.dateFromString("2000-01-15T00:00:00Z")!
],
[
"testEntityID": NSNumber(integer: 106),
"testBoolean": NSNumber(bool: false),
"testNumber": NSNumber(integer: 6),
"testDecimal": NSDecimalNumber(string: "6"),
"testString": "nil:TestEntity1:6",
"testData": ("nil:TestEntity1:6" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!,
"testDate": self.dateFormatter.dateFromString("2000-01-06T00:00:00Z")!
]
]
let objects = try transaction.importUniqueObjects(
Into(TestEntity1),
sourceArray: sourceArray
)
XCTAssertEqual(objects.count, sourceArray.count)
XCTAssertEqual(transaction.fetchCount(From(TestEntity1)), 6)
for i in 0 ..< sourceArray.count {
let object = objects[i]
let dictionary = sourceArray[i]
XCTAssertEqual(object.testEntityID, dictionary["testEntityID"] as? NSNumber)
XCTAssertEqual(object.testBoolean, dictionary["testBoolean"] as? NSNumber)
XCTAssertEqual(object.testNumber, dictionary["testNumber"] as? NSNumber)
XCTAssertEqual(object.testDecimal, dictionary["testDecimal"] as? NSDecimalNumber)
XCTAssertEqual(object.testString, dictionary["testString"] as? String)
XCTAssertEqual(object.testData, dictionary["testData"] as? NSData)
XCTAssertEqual(object.testDate, dictionary["testDate"] as? NSDate)
}
let existingObjects = transaction.fetchAll(From(TestEntity1), Where("testEntityID", isEqualTo: 105))
XCTAssertNotNil(existingObjects)
XCTAssertEqual(existingObjects?.count, 1)
let existingObject = existingObjects?[0]
XCTAssertEqual(existingObject, objects[0])
}
catch {
XCTFail()
}
transaction.context.reset()
}
}
}
}
// MARK: - TestInsertError
private struct TestInsertError: ErrorType {}
// MARK: - TestUpdateError
private struct TestUpdateError: ErrorType {}
// MARK: - TestIDError
private struct TestIDError: ErrorType {}
// MARK: - TestEntity1
extension TestEntity1: ImportableUniqueObject {
// MARK: ImportableObject
typealias ImportSource = [String: AnyObject]
static func shouldInsertFromImportSource(source: [String: AnyObject], inTransaction transaction: BaseDataTransaction) -> Bool {
return source["skip_insert"] == nil
}
func didInsertFromImportSource(source: [String: AnyObject], inTransaction transaction: BaseDataTransaction) throws {
if let _ = source["throw_on_insert"] {
throw TestInsertError()
}
self.testBoolean = source["testBoolean"] as? NSNumber
self.testNumber = source["testNumber"] as? NSNumber
self.testDecimal = source["testDecimal"] as? NSDecimalNumber
self.testString = source["testString"] as? String
self.testData = source["testData"] as? NSData
self.testDate = source["testDate"] as? NSDate
self.testNil = nil
}
// MARK: ImportableUniqueObject
typealias UniqueIDType = NSNumber
static var uniqueIDKeyPath: String {
return "testEntityID"
}
var uniqueIDValue: NSNumber {
get {
guard let ID = self.testEntityID else {
XCTFail()
return 0
}
return ID
}
set {
self.testEntityID = newValue
}
}
static func shouldUpdateFromImportSource(source: [String: AnyObject], inTransaction transaction: BaseDataTransaction) -> Bool {
return source["skip_update"] == nil
}
static func uniqueIDFromImportSource(source: [String: AnyObject], inTransaction transaction: BaseDataTransaction) throws -> NSNumber? {
if let _ = source["throw_on_id"] {
throw TestIDError()
}
return source["testEntityID"] as? NSNumber
}
func updateFromImportSource(source: [String: AnyObject], inTransaction transaction: BaseDataTransaction) throws {
if let _ = source["throw_on_update"] {
throw TestUpdateError()
}
self.testBoolean = source["testBoolean"] as? NSNumber
self.testNumber = source["testNumber"] as? NSNumber
self.testDecimal = source["testDecimal"] as? NSDecimalNumber
self.testString = source["testString"] as? String
self.testData = source["testData"] as? NSData
self.testDate = source["testDate"] as? NSDate
self.testNil = nil
}
}

View File

@@ -4,20 +4,20 @@
<attribute name="testBoolean" optional="YES" attributeType="Boolean" syncable="YES"/>
<attribute name="testData" optional="YES" attributeType="Binary" syncable="YES"/>
<attribute name="testDate" optional="YES" attributeType="Date" syncable="YES"/>
<attribute name="testDecimal" optional="YES" attributeType="Decimal" defaultValueString="0.0" syncable="YES"/>
<attribute name="testEntityID" attributeType="Integer 64" syncable="YES"/>
<attribute name="testDecimal" optional="YES" attributeType="Decimal" syncable="YES"/>
<attribute name="testEntityID" optional="YES" attributeType="Integer 64" syncable="YES"/>
<attribute name="testNil" optional="YES" attributeType="String" syncable="YES"/>
<attribute name="testNumber" optional="YES" attributeType="Integer 32" defaultValueString="0" syncable="YES"/>
<attribute name="testNumber" optional="YES" attributeType="Integer 32" syncable="YES"/>
<attribute name="testString" optional="YES" attributeType="String" syncable="YES"/>
</entity>
<entity name="TestEntity2" representedClassName="CoreStoreTests.TestEntity2" syncable="YES">
<attribute name="testBoolean" optional="YES" attributeType="Boolean" syncable="YES"/>
<attribute name="testData" optional="YES" attributeType="Binary" syncable="YES"/>
<attribute name="testDate" optional="YES" attributeType="Date" syncable="YES"/>
<attribute name="testDecimal" optional="YES" attributeType="Decimal" defaultValueString="0.0" syncable="YES"/>
<attribute name="testEntityID" attributeType="Integer 64" syncable="YES"/>
<attribute name="testDecimal" optional="YES" attributeType="Decimal" syncable="YES"/>
<attribute name="testEntityID" optional="YES" attributeType="Integer 64" syncable="YES"/>
<attribute name="testNil" optional="YES" attributeType="String" syncable="YES"/>
<attribute name="testNumber" optional="YES" attributeType="Integer 32" defaultValueString="0" syncable="YES"/>
<attribute name="testNumber" optional="YES" attributeType="Integer 32" syncable="YES"/>
<attribute name="testString" optional="YES" attributeType="String" syncable="YES"/>
</entity>
<configuration name="Config1">

View File

@@ -0,0 +1,37 @@
//
// ObjectObserverTests.swift
// CoreStore
//
// Copyright © 2016 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import XCTest
@testable
import CoreStore
// MARK: - ObjectObserverTests
class ObjectObserverTests: BaseTestDataTestCase {
}

View File

@@ -24,11 +24,10 @@
//
import XCTest
import GCDKit
@testable
import CoreStore
@testable
import GCDKit
//MARK: - TransactionTests
@@ -62,7 +61,7 @@ final class TransactionTests: BaseTestCase {
XCTFail()
}
}
self.waitForExpectationsWithTimeout(0, handler: nil)
self.checkExpectationsImmediately()
XCTAssertEqual(stack.fetchCount(From(TestEntity1)), 1)
@@ -97,7 +96,7 @@ final class TransactionTests: BaseTestCase {
XCTFail()
}
}
self.waitForExpectationsWithTimeout(0, handler: nil)
self.checkExpectationsImmediately()
XCTAssertEqual(stack.fetchCount(From(TestEntity1)), 1)
@@ -126,7 +125,7 @@ final class TransactionTests: BaseTestCase {
XCTFail()
}
}
self.waitForExpectationsWithTimeout(0, handler: nil)
self.checkExpectationsImmediately()
XCTAssertEqual(stack.fetchCount(From(TestEntity1)), 0)
@@ -136,6 +135,107 @@ final class TransactionTests: BaseTestCase {
}
}
@objc
dynamic func test_ThatSynchronousTransactions_CanPerformCRUDsInCorrectConfiguration() {
self.prepareStack(configurations: [nil, "Config1"]) { (stack) in
let testDate = NSDate()
do {
let createExpectation = self.expectationWithDescription("create")
stack.beginSynchronous { (transaction) in
let object = transaction.create(Into<TestEntity1>("Config1"))
object.testEntityID = NSNumber(integer: 1)
object.testString = "string1"
object.testNumber = 100
object.testDate = testDate
switch transaction.commitAndWait() {
case .Success(let hasChanges):
XCTAssertTrue(hasChanges)
createExpectation.fulfill()
default:
XCTFail()
}
}
self.checkExpectationsImmediately()
XCTAssertEqual(stack.fetchCount(From<TestEntity1>("Config1")), 1)
XCTAssertEqual(stack.fetchCount(From<TestEntity1>(nil)), 0)
let object = stack.fetchOne(From<TestEntity1>("Config1"))
XCTAssertNotNil(object)
XCTAssertEqual(object?.testEntityID, NSNumber(integer: 1))
XCTAssertEqual(object?.testString, "string1")
XCTAssertEqual(object?.testNumber, 100)
XCTAssertEqual(object?.testDate, testDate)
}
do {
let updateExpectation = self.expectationWithDescription("update")
stack.beginSynchronous { (transaction) in
guard let object = transaction.fetchOne(From<TestEntity1>("Config1")) else {
XCTFail()
return
}
object.testString = "string1_edit"
object.testNumber = 200
object.testDate = NSDate.distantFuture()
switch transaction.commitAndWait() {
case .Success(let hasChanges):
XCTAssertTrue(hasChanges)
updateExpectation.fulfill()
default:
XCTFail()
}
}
self.checkExpectationsImmediately()
XCTAssertEqual(stack.fetchCount(From<TestEntity1>("Config1")), 1)
XCTAssertEqual(stack.fetchCount(From<TestEntity1>(nil)), 0)
let object = stack.fetchOne(From<TestEntity1>("Config1"))
XCTAssertNotNil(object)
XCTAssertEqual(object?.testEntityID, NSNumber(integer: 1))
XCTAssertEqual(object?.testString, "string1_edit")
XCTAssertEqual(object?.testNumber, 200)
XCTAssertEqual(object?.testDate, NSDate.distantFuture())
}
do {
let deleteExpectation = self.expectationWithDescription("delete")
stack.beginSynchronous { (transaction) in
let object = transaction.fetchOne(From<TestEntity1>("Config1"))
transaction.delete(object)
switch transaction.commitAndWait() {
case .Success(let hasChanges):
XCTAssertTrue(hasChanges)
deleteExpectation.fulfill()
default:
XCTFail()
}
}
self.checkExpectationsImmediately()
XCTAssertEqual(stack.fetchCount(From<TestEntity1>("Config1")), 0)
XCTAssertEqual(stack.fetchCount(From<TestEntity1>(nil)), 0)
}
}
}
@objc
dynamic func test_ThatSynchronousTransactions_CanDiscardUncommittedChanges() {
@@ -156,7 +256,7 @@ final class TransactionTests: BaseTestCase {
createDiscardExpectation.fulfill()
self.expectLogger(loggerExpectations)
}
self.waitForExpectationsWithTimeout(0, handler: nil)
self.checkExpectationsImmediately()
XCTAssertEqual(stack.fetchCount(From(TestEntity1)), 0)
@@ -184,7 +284,7 @@ final class TransactionTests: BaseTestCase {
XCTFail()
}
}
self.waitForExpectationsWithTimeout(0, handler: nil)
self.checkExpectationsImmediately()
}
do {
@@ -204,7 +304,7 @@ final class TransactionTests: BaseTestCase {
updateDiscardExpectation.fulfill()
self.expectLogger(loggerExpectations)
}
self.waitForExpectationsWithTimeout(0, handler: nil)
self.checkExpectationsImmediately()
XCTAssertEqual(stack.fetchCount(From(TestEntity1)), 1)
@@ -231,7 +331,7 @@ final class TransactionTests: BaseTestCase {
deleteDiscardExpectation.fulfill()
self.expectLogger(loggerExpectations)
}
self.waitForExpectationsWithTimeout(0, handler: nil)
self.checkExpectationsImmediately()
XCTAssertEqual(stack.fetchCount(From(TestEntity1)), 1)
@@ -350,7 +450,116 @@ final class TransactionTests: BaseTestCase {
}
}
}
self.waitForExpectationsWithTimeout(NSTimeInterval(Int8.max), handler: nil)
self.waitAndCheckExpectations()
}
@objc
dynamic func test_ThatAsynchronousTransactions_CanPerformCRUDsInCorrectConfiguration() {
self.prepareStack(configurations: [nil, "Config1"]) { (stack) in
let testDate = NSDate()
do {
let createExpectation = self.expectationWithDescription("create")
stack.beginAsynchronous { (transaction) in
let object = transaction.create(Into<TestEntity1>("Config1"))
object.testEntityID = NSNumber(integer: 1)
object.testString = "string1"
object.testNumber = 100
object.testDate = testDate
transaction.commit { (result) in
switch result {
case .Success(let hasChanges):
XCTAssertTrue(hasChanges)
XCTAssertEqual(stack.fetchCount(From<TestEntity1>("Config1")), 1)
XCTAssertEqual(stack.fetchCount(From<TestEntity1>(nil)), 0)
let object = stack.fetchOne(From<TestEntity1>("Config1"))
XCTAssertNotNil(object)
XCTAssertEqual(object?.testEntityID, NSNumber(integer: 1))
XCTAssertEqual(object?.testString, "string1")
XCTAssertEqual(object?.testNumber, 100)
XCTAssertEqual(object?.testDate, testDate)
createExpectation.fulfill()
default:
XCTFail()
}
}
}
}
do {
let updateExpectation = self.expectationWithDescription("update")
stack.beginAsynchronous { (transaction) in
guard let object = transaction.fetchOne(From<TestEntity1>("Config1")) else {
XCTFail()
return
}
object.testString = "string1_edit"
object.testNumber = 200
object.testDate = NSDate.distantFuture()
transaction.commit { (result) in
switch result {
case .Success(let hasChanges):
XCTAssertTrue(hasChanges)
XCTAssertEqual(stack.fetchCount(From<TestEntity1>("Config1")), 1)
XCTAssertEqual(stack.fetchCount(From<TestEntity1>(nil)), 0)
let object = stack.fetchOne(From<TestEntity1>("Config1"))
XCTAssertNotNil(object)
XCTAssertEqual(object?.testEntityID, NSNumber(integer: 1))
XCTAssertEqual(object?.testString, "string1_edit")
XCTAssertEqual(object?.testNumber, 200)
XCTAssertEqual(object?.testDate, NSDate.distantFuture())
updateExpectation.fulfill()
default:
XCTFail()
}
}
}
}
do {
let deleteExpectation = self.expectationWithDescription("delete")
stack.beginAsynchronous { (transaction) in
let object = transaction.fetchOne(From<TestEntity1>("Config1"))
transaction.delete(object)
transaction.commit { (result) in
switch result {
case .Success(let hasChanges):
XCTAssertTrue(hasChanges)
XCTAssertEqual(stack.fetchCount(From<TestEntity1>("Config1")), 0)
XCTAssertEqual(stack.fetchCount(From<TestEntity1>(nil)), 0)
deleteExpectation.fulfill()
default:
XCTFail()
}
}
}
}
}
self.waitAndCheckExpectations()
}
@objc
@@ -458,7 +667,7 @@ final class TransactionTests: BaseTestCase {
}
}
}
self.waitForExpectationsWithTimeout(NSTimeInterval(Int8.max), handler: nil)
self.waitAndCheckExpectations()
}
@objc
@@ -542,6 +751,89 @@ final class TransactionTests: BaseTestCase {
}
}
@objc
dynamic func test_ThatUnsafeTransactions_CanPerformCRUDsInCorrectConfiguration() {
self.prepareStack(configurations: [nil, "Config1"]) { (stack) in
let transaction = stack.beginUnsafe()
let testDate = NSDate()
do {
let object = transaction.create(Into<TestEntity1>("Config1"))
object.testEntityID = NSNumber(integer: 1)
object.testString = "string1"
object.testNumber = 100
object.testDate = testDate
switch transaction.commitAndWait() {
case .Success(let hasChanges):
XCTAssertTrue(hasChanges)
XCTAssertEqual(stack.fetchCount(From<TestEntity1>("Config1")), 1)
XCTAssertEqual(stack.fetchCount(From<TestEntity1>(nil)), 0)
let object = stack.fetchOne(From<TestEntity1>("Config1"))
XCTAssertNotNil(object)
XCTAssertEqual(object?.testEntityID, NSNumber(integer: 1))
XCTAssertEqual(object?.testString, "string1")
XCTAssertEqual(object?.testNumber, 100)
XCTAssertEqual(object?.testDate, testDate)
default:
XCTFail()
}
}
do {
guard let object = transaction.fetchOne(From<TestEntity1>("Config1")) else {
XCTFail()
return
}
object.testString = "string1_edit"
object.testNumber = 200
object.testDate = NSDate.distantFuture()
switch transaction.commitAndWait() {
case .Success(let hasChanges):
XCTAssertTrue(hasChanges)
XCTAssertEqual(stack.fetchCount(From<TestEntity1>("Config1")), 1)
XCTAssertEqual(stack.fetchCount(From<TestEntity1>(nil)), 0)
let object = stack.fetchOne(From<TestEntity1>("Config1"))
XCTAssertNotNil(object)
XCTAssertEqual(object?.testEntityID, NSNumber(integer: 1))
XCTAssertEqual(object?.testString, "string1_edit")
XCTAssertEqual(object?.testNumber, 200)
XCTAssertEqual(object?.testDate, NSDate.distantFuture())
default:
XCTFail()
}
}
do {
let object = transaction.fetchOne(From<TestEntity1>("Config1"))
transaction.delete(object)
switch transaction.commitAndWait() {
case .Success(let hasChanges):
XCTAssertTrue(hasChanges)
XCTAssertEqual(stack.fetchCount(From<TestEntity1>("Config1")), 0)
XCTAssertEqual(stack.fetchCount(From<TestEntity1>(nil)), 0)
default:
XCTFail()
}
}
}
}
@objc
dynamic func test_ThatUnsafeTransactions_CanRollbackChanges() {

View File

@@ -208,7 +208,7 @@ public extension BaseDataTransaction {
mapping = try cs_autoreleasepool { try preProcess(mapping: mapping) }
var objects = Dictionary<T.UniqueIDType, T>()
for object in self.fetchAll(From(T), Where(T.uniqueIDKeyPath, isMemberOf: mapping.keys)) ?? [] {
for object in self.fetchAll(From(T), Where(T.uniqueIDKeyPath, isMemberOf: sortedIDs)) ?? [] {
try cs_autoreleasepool {

View File

@@ -67,7 +67,7 @@ internal final class CoreStoreFetchedResultsController: NSFetchedResultsControll
guard let from = (fetchRequest.entity.flatMap { $0.managedObjectClassName }).flatMap(NSClassFromString).flatMap(From.init) else {
fatalError("Attempted to create an \(cs_typeName(NSFetchedResultsController)) without a \(cs_typeName(From)) clause or an \(cs_typeName(NSEntityDescription)).")
CoreStore.abort("Attempted to create an \(cs_typeName(NSFetchedResultsController)) without a \(cs_typeName(From)) clause or an \(cs_typeName(NSEntityDescription)).")
}
self.reapplyAffectedStores = { fetchRequest, context in

View File

@@ -38,7 +38,7 @@ internal extension NSManagedObjectModel {
guard let modelFilePath = bundle.pathForResource(modelName, ofType: "momd") else {
fatalError("Could not find \"\(modelName).momd\" from the bundle. \(bundle)")
CoreStore.abort("Could not find \"\(modelName).momd\" from the bundle. \(bundle)")
}
let modelFileURL = NSURL(fileURLWithPath: modelFilePath)
@@ -47,7 +47,7 @@ internal extension NSManagedObjectModel {
guard let versionInfo = NSDictionary(contentsOfURL: versionInfoPlistURL),
let versionHashes = versionInfo["NSManagedObjectModel_VersionHashes"] as? [String: AnyObject] else {
fatalError("Could not load \(cs_typeName(NSManagedObjectModel)) metadata from path \"\(versionInfoPlistURL)\".")
CoreStore.abort("Could not load \(cs_typeName(NSManagedObjectModel)) metadata from path \"\(versionInfoPlistURL)\".")
}
let modelVersions = Set(versionHashes.keys)
@@ -77,7 +77,7 @@ internal extension NSManagedObjectModel {
}
else {
fatalError("No model files were found in URL \"\(modelFileURL)\".")
CoreStore.abort("No model files were found in URL \"\(modelFileURL)\".")
}
var modelVersionFileURL: NSURL?
@@ -106,7 +106,7 @@ internal extension NSManagedObjectModel {
return rootModel
}
fatalError("Could not create an \(cs_typeName(NSManagedObjectModel)) from the model at URL \"\(modelFileURL)\".")
CoreStore.abort("Could not create an \(cs_typeName(NSManagedObjectModel)) from the model at URL \"\(modelFileURL)\".")
}
@nonobjc

View File

@@ -70,4 +70,16 @@ public extension CoreStore {
functionName: functionName
)
}
@noreturn
internal static func abort(message: String, fileName: StaticString = #file, lineNumber: Int = #line, functionName: StaticString = #function) {
self.logger.abort(
message,
fileName: fileName,
lineNumber: lineNumber,
functionName: functionName
)
Swift.fatalError(message, file: fileName, line: UInt(lineNumber))
}
}

View File

@@ -80,6 +80,17 @@ public protocol CoreStoreLogger {
*/
func assert(@autoclosure condition: () -> Bool, @autoclosure message: () -> String, fileName: StaticString, lineNumber: Int, functionName: StaticString)
/**
Handles fatal errors made throughout the `CoreStore` framework. The app wil terminate after this method is called.
- Important: Implementers may guarantee that the function doesn't return, either by calling another `@noreturn` function such as `fatalError()` or `abort()`, or by raising an exception. If the implementation does not terminate the app, CoreStore will call an internal `fatalError()` to do so.
- parameter message: the fatal error message
- parameter fileName: the source file name
- parameter lineNumber: the source line number
- parameter functionName: the source function name
*/
func abort(message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString)
// MARK: Deprecated
@@ -100,4 +111,9 @@ extension CoreStoreLogger {
self.log(error: error.bridgeToSwift, message: message, fileName: fileName, lineNumber: lineNumber, functionName: functionName)
}
public func abort(message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
Swift.fatalError(message, file: fileName, line: UInt(lineNumber))
}
}

View File

@@ -111,7 +111,22 @@ public final class DefaultLogger: CoreStoreLogger {
return
}
Swift.print("❗ [CoreStore: Assertion Failure] \((fileName.stringValue as NSString).lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ \(message())\n")
Swift.fatalError()
Swift.fatalError(file: fileName, line: UInt(lineNumber))
#endif
}
/**
Handles fatal errors made throughout the `CoreStore` framework.
- Important: This method should be marked `@noreturn` and implementers should guarantee that the function doesn't, either by calling another `@noreturn` function such as `fatalError()` or `abort()`, or by raising an exception.
- parameter message: the fatal error message
- parameter fileName: the source file name
- parameter lineNumber: the source line number
- parameter functionName: the source function name
*/
public func abort(message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
Swift.print("❗ [CoreStore: Fatal Error] \((fileName.stringValue as NSString).lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ \(message)\n")
Swift.fatalError(file: fileName, line: UInt(lineNumber))
}
}

View File

@@ -76,10 +76,10 @@ public /*abstract*/ class BaseDataTransaction {
return object
case (nil, true):
fatalError("Attempted to create an entity of type \(cs_typeName(entityClass)) with ambiguous destination persistent store, but the configuration name was not specified.")
CoreStore.abort("Attempted to create an entity of type \(cs_typeName(entityClass)) with ambiguous destination persistent store, but the configuration name was not specified.")
default:
fatalError("Attempted to create an entity of type \(cs_typeName(entityClass)), but a destination persistent store containing the entity type could not be found.")
CoreStore.abort("Attempted to create an entity of type \(cs_typeName(entityClass)), but a destination persistent store containing the entity type could not be found.")
}
}
else {
@@ -97,16 +97,16 @@ public /*abstract*/ class BaseDataTransaction {
return object
case (nil, true):
fatalError("Attempted to create an entity of type \(cs_typeName(entityClass)) with ambiguous destination persistent store, but the configuration name was not specified.")
CoreStore.abort("Attempted to create an entity of type \(cs_typeName(entityClass)) with ambiguous destination persistent store, but the configuration name was not specified.")
default:
if let configuration = into.configuration {
fatalError("Attempted to create an entity of type \(cs_typeName(entityClass)) into the configuration \"\(configuration)\", which it doesn't belong to.")
CoreStore.abort("Attempted to create an entity of type \(cs_typeName(entityClass)) into the configuration \"\(configuration)\", which it doesn't belong to.")
}
else {
fatalError("Attempted to create an entity of type \(cs_typeName(entityClass)) into the default configuration, which it doesn't belong to.")
CoreStore.abort("Attempted to create an entity of type \(cs_typeName(entityClass)) into the default configuration, which it doesn't belong to.")
}
}
}