diff --git a/enzevalos_iphone.xcodeproj/project.pbxproj b/enzevalos_iphone.xcodeproj/project.pbxproj index 76608a6953980cdf9e3ac94f65ca47618e57b292..eab0b94251b234be77ea28f9dc60b95a473aeefa 100644 --- a/enzevalos_iphone.xcodeproj/project.pbxproj +++ b/enzevalos_iphone.xcodeproj/project.pbxproj @@ -196,7 +196,6 @@ 47F867E02052B47C00AA832F /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 47F867DF2052B47C00AA832F /* Security.framework */; }; 47F867E22052B48E00AA832F /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 47F867E12052B48E00AA832F /* libz.tbd */; }; 47F867E42052B49800AA832F /* libbz2.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 47F867E32052B49800AA832F /* libbz2.tbd */; }; - 47FAE3072524AA4B005A1BCB /* DataProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47FAE3062524AA4B005A1BCB /* DataProvider.swift */; }; 47FAE30E2524AA97005A1BCB /* DataModel.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 47FAE30C2524AA97005A1BCB /* DataModel.xcdatamodeld */; }; 47FAE3122524BFDB005A1BCB /* PersistentDataError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47FAE3112524BFDB005A1BCB /* PersistentDataError.swift */; }; 47FAE31C2524C07B005A1BCB /* MailRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47FAE31B2524C07B005A1BCB /* MailRecord.swift */; }; @@ -656,7 +655,6 @@ 47F867DF2052B47C00AA832F /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; 47F867E12052B48E00AA832F /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; }; 47F867E32052B49800AA832F /* libbz2.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libbz2.tbd; path = usr/lib/libbz2.tbd; sourceTree = SDKROOT; }; - 47FAE3062524AA4B005A1BCB /* DataProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataProvider.swift; sourceTree = "<group>"; }; 47FAE30D2524AA97005A1BCB /* DataModel.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = DataModel.xcdatamodel; sourceTree = "<group>"; }; 47FAE3112524BFDB005A1BCB /* PersistentDataError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersistentDataError.swift; sourceTree = "<group>"; }; 47FAE31B2524C07B005A1BCB /* MailRecord.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MailRecord.swift; sourceTree = "<group>"; }; @@ -1386,7 +1384,6 @@ 47FAE3052524AA30005A1BCB /* persistentData */ = { isa = PBXGroup; children = ( - 47FAE3062524AA4B005A1BCB /* DataProvider.swift */, 47FAE30C2524AA97005A1BCB /* DataModel.xcdatamodeld */, 47FAE3112524BFDB005A1BCB /* PersistentDataError.swift */, 47FAE31B2524C07B005A1BCB /* MailRecord.swift */, @@ -2397,7 +2394,6 @@ 475B00421F7BB6D6006CDD41 /* PersistentKey+CoreDataClass.swift in Sources */, A10DAA5721F37600005D8BBB /* IntroInfoButton.swift in Sources */, 47A2A57223599D180013883D /* FeedbackButtonHelper.swift in Sources */, - 47FAE3072524AA4B005A1BCB /* DataProvider.swift in Sources */, 476406842416AA9100C7D426 /* TestOpenSSL.swift in Sources */, 3EC35F2420037651008BDF95 /* InvitationHelper.swift in Sources */, A1B49E6421E55ECD00ED86FC /* IntroPageViewController.swift in Sources */, diff --git a/enzevalos_iphone/persistentData/AddressRecord.swift b/enzevalos_iphone/persistentData/AddressRecord.swift index 94014c86906cb2abe0f1679f7d9acbe07ac1a60a..377943683f96db7eb6e4e11b81e19ea510c558bb 100644 --- a/enzevalos_iphone/persistentData/AddressRecord.swift +++ b/enzevalos_iphone/persistentData/AddressRecord.swift @@ -16,7 +16,7 @@ extension AddressRecord: PersistentDataProtocol { } struct AddressProperties: DataPropertyProtocol { - var entityName = "CoreAddress" + var entityName = "AddressRecord" func update(m: Any) -> Bool { if let m = m as? AddressRecord { diff --git a/enzevalos_iphone/persistentData/DataModel.xcdatamodeld/DataModel.xcdatamodel/contents b/enzevalos_iphone/persistentData/DataModel.xcdatamodeld/DataModel.xcdatamodel/contents index cbb02cc1dece0e630f2092c6beb9dee038369565..560e2d56be0729fe2398a2f128e2045b557d4d7c 100644 --- a/enzevalos_iphone/persistentData/DataModel.xcdatamodeld/DataModel.xcdatamodel/contents +++ b/enzevalos_iphone/persistentData/DataModel.xcdatamodeld/DataModel.xcdatamodel/contents @@ -25,7 +25,7 @@ <relationship name="bccAddresses" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="AddressRecord"/> <relationship name="ccAddresses" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="AddressRecord"/> <relationship name="fromAddress" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="AddressRecord" inverseName="inFromField" inverseEntity="AddressRecord"/> - <relationship name="toAddresses" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="AddressRecord"/> + <relationship name="toAddresses" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="AddressRecord"/> <uniquenessConstraints> <uniquenessConstraint> <constraint value="messageID"/> diff --git a/enzevalos_iphone/persistentData/DataProvider.swift b/enzevalos_iphone/persistentData/DataProvider.swift deleted file mode 100644 index ef886b0936b809d7506c3a852e0db6c2a21aa521..0000000000000000000000000000000000000000 --- a/enzevalos_iphone/persistentData/DataProvider.swift +++ /dev/null @@ -1,305 +0,0 @@ -// -// DataProvider.swift -// enzevalos_iphone -// -// Created by Oliver Wiese on 30.09.20. -// Copyright © 2020 fu-berlin. All rights reserved. -// - -import CoreData - -/* - One Entity needs a name, type, a struct with dict and a update function with the struct... - */ - -public class DataProvider { - - // MARK: - Core Data - - /** - A persistent container to set up the Core Data stack. - */ - lazy var persistentContainer: NSPersistentContainer = { - let container = NSPersistentContainer(name: "DataModel") - - // Enable remote notifications - guard let description = container.persistentStoreDescriptions.first else { - fatalError("Failed to retrieve a persistent store description.") - } - description.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey) - - container.loadPersistentStores { storeDesription, error in - guard error == nil else { - fatalError("Unresolved error \(error!)") - } - } - - // This sample refreshes UI by refetching data, so doesn't need to merge the changes. - container.viewContext.automaticallyMergesChangesFromParent = false - container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy - container.viewContext.undoManager = nil - container.viewContext.shouldDeleteInaccessibleFaults = true - - // Observe Core Data remote change notifications. - NotificationCenter.default.addObserver( - self, selector: #selector(type(of: self).storeRemoteChange(_:)), - name: .NSPersistentStoreRemoteChange, object: nil) - return container - }() - - /** - Creates and configures a private queue context. - */ - private func newTaskContext() -> NSManagedObjectContext { - // Create a private queue context. - let taskContext = persistentContainer.newBackgroundContext() - taskContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy - // Set unused undoManager to nil for macOS (it is nil by default on iOS) - // to reduce resource requirements. - taskContext.undoManager = nil - return taskContext - } - - func importMails(from emails: [MailProperties], completionHandler: @escaping (Error?) -> Void, withBIR: Bool = true){ - importData(from: emails, completionHandler: completionHandler, withBIR: withBIR) - } - - - - func importData(from data: [DataPropertyProtocol], completionHandler: @escaping (Error?) -> Void, withBIR: Bool = true) { - guard !data.isEmpty else { - completionHandler(nil) - return - } - var performError: Error? = nil - - DispatchQueue.global(qos: .background).async { - do { - if withBIR { - try self.importDataUsingBIR(from: data) - } - else { - try self.importDataBeforeBIR(from: data) - } - } catch { - performError = error - } - DispatchQueue.main.asyncAfter(deadline: .now(), execute: { - completionHandler(performError) - }) - - } - } - - - /** - Uses NSBatchInsertRequest (BIR) to import a list of emails into the Core Data store on a private queue. - NSBatchInsertRequest is available since iOS 13 and macOS 10.15. - */ - private func importDataUsingBIR(from data: [DataPropertyProtocol]) throws { - var performError: Error? - - let taskContext = self.newTaskContext() - taskContext.performAndWait { - if let batchInsert = self.newBatchInsertRequest(with: data) { - batchInsert.resultType = .statusOnly - if let batchInsertResult = try? taskContext.execute(batchInsert) as? NSBatchInsertResult, - let success = batchInsertResult.result as? Bool, success { - return - } - } - performError = PersistentDataError.batchInsertError - } - if let error = performError { - throw error - } - } - - private func newBatchInsertRequest(with data: [DataPropertyProtocol]) -> NSBatchInsertRequest? { - guard data.count > 0 else { - return nil - } - let name = data.first!.entityName - let batchInsert: NSBatchInsertRequest - var index = 0 - let total = data.count - batchInsert = NSBatchInsertRequest(entityName: name, dictionaryHandler: { dictionary in - guard index < total else { return true } - dictionary.addEntries(from: data[index].dictionary) - index += 1 - return false - }) - return batchInsert - } - - /** - Imports a JSON dictionary into the Core Data store on a private queue, - processing the record in batches to avoid a high memory footprint. - */ - private func importDataBeforeBIR(from data: [DataPropertyProtocol]) throws { - guard !data.isEmpty else { return } - - // Process records in batches to avoid a high memory footprint. - let batchSize = 256 - let count = data.count - - // Determine the total number of batches. - var numBatches = count / batchSize - numBatches += count % batchSize > 0 ? 1 : 0 - - for batchNumber in 0 ..< numBatches { - // Determine the range for this batch. - let batchStart = batchNumber * batchSize - let batchEnd = batchStart + min(batchSize, count - batchNumber * batchSize) - let range = batchStart..<batchEnd - - // Create a batch for this range from the decoded JSON. - // Stop importing if any batch is unsuccessful. - try importOneBatch(Array(data[range])) - } - } - - /** - Imports one batch of quakes, creating managed objects from the new data, - and saving them to the persistent store, on a private queue. After saving, - resets the context to clean up the cache and lower the memory footprint. - - NSManagedObjectContext.performAndWait doesn't rethrow so this function - catches throws within the closure and uses a return value to indicate - whether the import is successful. - */ - private func importOneBatch(_ data: [DataPropertyProtocol]) throws { - guard data.count > 0 else { - throw PersistentDataError.creationError - } - - let name = data.first!.entityName - - let taskContext = newTaskContext() - var performError: Error? - - taskContext.performAndWait { - // Create a new record for each quake in the batch. - for m in data { - // Create a managed object on the private queue context. - let item = NSEntityDescription.insertNewObject(forEntityName: name, into: taskContext) - if !m.update(m: item) { - performError = PersistentDataError.creationError - return - } - } - - // Save all insertions and deletions from the context to the store. - if taskContext.hasChanges { - do { - try taskContext.save() - } catch { - performError = error - return - } - // Reset the taskContext to free the cache and lower the memory footprint. - taskContext.reset() - } - } - - if let error = performError { - throw error - } - } - - /** - Deletes all the records in the Core Data store. - */ - func deleteAll(completionHandler: @escaping (Error?) -> Void) { - let taskContext = newTaskContext() - taskContext.perform { - for name in [AddressRecord.entityName, MailRecord.entityName] { - let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: name) - let batchDeleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest) - batchDeleteRequest.resultType = .resultTypeCount - - // Execute the batch insert - guard let batchDeleteResult = try? taskContext.execute(batchDeleteRequest) as? NSBatchDeleteResult, - batchDeleteResult.result != nil else { - completionHandler(PersistentDataError.batchDeleteError) - return - } - } - completionHandler(nil) - } - } - - // MARK: - NSFetchedResultsController - - lazy var fetchAddressResultController: NSFetchedResultsController<AddressRecord> = { - let freq = NSFetchRequest<AddressRecord>(entityName: AddressRecord.entityName) - freq.sortDescriptors = [NSSortDescriptor(key: "email", ascending: false)] - - let controller = NSFetchedResultsController(fetchRequest: freq, managedObjectContext: persistentContainer.viewContext, sectionNameKeyPath: nil, cacheName: nil) - do { - try controller.performFetch() - } catch { - fatalError("Unresolved error \(error)") - } - return controller - }() - - /** - A fetched results controller delegate to give consumers a chance to update - the user interface when content changes. - */ - weak var fetchedResultsControllerDelegate: NSFetchedResultsControllerDelegate? - - /** - A fetched results controller to fetch EMail records sorted by time. - */ - lazy var fetchedResultsController: NSFetchedResultsController<MailRecord> = { - - // Create a fetch request for the Quake entity sorted by time. - let fetchRequest = NSFetchRequest<MailRecord>(entityName: MailRecord.entityName) - // Create a fetched results controller and set its fetch request, context, and delegate. - fetchRequest.sortDescriptors = [NSSortDescriptor(key: "messageID", ascending: false)] - fetchRequest.propertiesToFetch = ["messageID", "subject"] - let controller = NSFetchedResultsController(fetchRequest: fetchRequest, - managedObjectContext: persistentContainer.viewContext, - sectionNameKeyPath: nil, cacheName: nil) - controller.delegate = fetchedResultsControllerDelegate - - // Perform the fetch. - do { - try controller.performFetch() - } catch { - fatalError("Unresolved error \(error)") - } - return controller - }() - - /** - Resets viewContext and refetches the data from the store. - */ - func resetAndRefetch() { - reset() - do { - try fetchedResultsController.performFetch() - } catch { - fatalError("Unresolved error \(error)") - } - } - - func reset(){ - persistentContainer.viewContext.reset() - } - - // MARK: - NSPersistentStoreRemoteChange handler - - /** - Handles remote store change notifications (.NSPersistentStoreRemoteChange). - storeRemoteChange runs on the queue where the changes were made. - */ - @objc - func storeRemoteChange(_ notification: Notification) { - //print("\(#function): Got a persistent store remote change notification!") - } -} - - diff --git a/enzevalos_iphone/persistentData/MailRecord.swift b/enzevalos_iphone/persistentData/MailRecord.swift index a5a4cc60a8aaac83200c192b8606f085b3411072..326b950f1aa510f2d964e8d2cfc254bb394a91f2 100644 --- a/enzevalos_iphone/persistentData/MailRecord.swift +++ b/enzevalos_iphone/persistentData/MailRecord.swift @@ -13,8 +13,19 @@ extension MailRecord: PersistentDataProtocol { static let entityName = "MailRecord" func update(with mailProperties: MailProperties) { + // Header messageID = mailProperties.messageID + date = mailProperties.date + flag = mailProperties.flags subject = mailProperties.subject + + + // Content + body = mailProperties.body + + // Security + signatureState = mailProperties.signatureState + encryptionState = mailProperties.encryptionState } func update(mail: IncomingMail) { @@ -29,7 +40,7 @@ extension MailRecord: PersistentDataProtocol { */ struct MailProperties: DataPropertyProtocol { - var entityName = "CoreMail" + var entityName = "MailRecord" // Header properties @@ -38,6 +49,9 @@ struct MailProperties: DataPropertyProtocol { let date: Date let flags: Int16 let from: AddressProperties + let to: [AddressProperties] + let cc: [AddressProperties] + let bcc: [AddressProperties] // Content properties var body: String = "" diff --git a/enzevalos_iphone/persistentData/PersistentDataProvider.swift b/enzevalos_iphone/persistentData/PersistentDataProvider.swift index f474936db4de88c70cc11de5b64afdd4b30c83c0..7576196d81c5e578aea9005482c909e3ee8bb37d 100644 --- a/enzevalos_iphone/persistentData/PersistentDataProvider.swift +++ b/enzevalos_iphone/persistentData/PersistentDataProvider.swift @@ -8,6 +8,22 @@ import CoreData +/* + TODO: + * add all poperties in: + + Mail + + Key + + Address + * Add Folder + * How to handle key rcord? + * add fetch requests: + * Find use cases + + mails in Folder -> Inbox/Folder View + + mails per Address/Key -> Contact View + + Addresses per Key -> Contact View + + all folders -> Folder Overview + + find specific mail -> Detail view + */ class PersitentDataProvider { // MARK: - Core Data @@ -55,9 +71,13 @@ class PersitentDataProvider { return taskContext } - func importMails(from mails: [MailProperties], completionHandler: @escaping (Error?) -> Void) { - guard !mails.isEmpty else { + importData(from: mails, completionHandler: completionHandler) + } + + + func importData(from data: [DataPropertyProtocol], completionHandler: @escaping (Error?) -> Void) { + guard !data.isEmpty else { completionHandler(nil) return } @@ -66,11 +86,11 @@ class PersitentDataProvider { DispatchQueue.global(qos: .background).async { // Process records in batches to avoid a high memory footprint. let batchSize = 30 - let count = mails.count + let count = data.count if count < batchSize { do { - try self.importOneBatch(mails) + try self.importOneBatch(data) } catch { performError = error } @@ -88,7 +108,7 @@ class PersitentDataProvider { // Create a batch for this range from the decoded JSON. // Stop importing if any batch is unsuccessful. do { - try self.importOneBatch(Array(mails[range])) + try self.importOneBatch(Array(data[range])) } catch { performError = error } @@ -102,8 +122,8 @@ class PersitentDataProvider { } } - private func importOneBatch(_ mails: [MailProperties]) throws { - guard mails.count > 0 else { + private func importOneBatch(_ data: [DataPropertyProtocol]) throws { + guard data.count > 0 else { throw PersistentDataError.creationError } @@ -112,8 +132,17 @@ class PersitentDataProvider { taskContext.performAndWait { // Create a new record for each mail in the batch. - for m in mails { - importOneMail(m: m, taskContext: taskContext) + for d in data { + if let m = d as? MailProperties { + importOneMail(m: m, taskContext: taskContext) + } else { + // Create a managed object on the private queue context. + let item = NSEntityDescription.insertNewObject(forEntityName: d.entityName, into: taskContext) + if !d.update(m: item) { + performError = PersistentDataError.creationError + return + } + } } // Save all insertions and deletions from the context to the store. @@ -136,16 +165,29 @@ class PersitentDataProvider { private func importOneMail(m: MailProperties, taskContext: NSManagedObjectContext) { // Create a managed object on the private queue context. + let mail = NSEntityDescription.insertNewObject(forEntityName: MailRecord.entityName, into: taskContext) as! MailRecord + mail.update(with: m) + let from = NSEntityDescription.insertNewObject(forEntityName: AddressRecord.entityName, into: taskContext) as! AddressRecord from.update(with: m.from) - - let mail = NSEntityDescription.insertNewObject(forEntityName: MailRecord.entityName, into: taskContext) as! MailRecord + // add relationships mail.fromAddress = from - mail.messageID = m.messageID - - // add relationship -> Update? + // To, CC, BCC + importManyAddresses(addrs: m.to, taskContext: taskContext, addTo: mail.addToToAddresses) + importManyAddresses(addrs: m.cc, taskContext: taskContext, addTo: mail.addToCcAddresses) + importManyAddresses(addrs: m.bcc, taskContext: taskContext, addTo: mail.addToBccAddresses) + } + + private func importManyAddresses(addrs: [AddressProperties], taskContext: NSManagedObjectContext, addTo: (AddressRecord) -> () ) { + for addr in addrs { + let record = NSEntityDescription.insertNewObject(forEntityName: AddressRecord.entityName, into: taskContext) as! AddressRecord + record.update(with: addr) + addTo(record) + } } + + /** Deletes all the records in the Core Data store. */ diff --git a/enzevalos_iphoneTests/CoreAddressTest.swift b/enzevalos_iphoneTests/CoreAddressTest.swift index 4cffb4a1bde92f93a66c8673b455fa58852d8d60..f0daa68a41287f26b558a4fee97788581daa793a 100644 --- a/enzevalos_iphoneTests/CoreAddressTest.swift +++ b/enzevalos_iphoneTests/CoreAddressTest.swift @@ -10,7 +10,7 @@ import XCTest @testable import enzevalos_iphone class CoreAddressTest: XCTestCase { - var provider = DataProvider() + var provider = PersitentDataProvider() override func setUpWithError() throws { provider.deleteAll(completionHandler: {_ in }) @@ -33,7 +33,7 @@ class CoreAddressTest: XCTestCase { XCTFail("Error while importing addresses! \(error)") } importExpectation.fulfill() - }) + }) wait(for: [importExpectation], timeout: TimeInterval(20)) provider.reset() let frc = provider.fetchAddressResultController diff --git a/enzevalos_iphoneTests/CoreMailTest.swift b/enzevalos_iphoneTests/CoreMailTest.swift index f721f083c1ecfeac42f0eabfeb58a84d9993ae39..e198cd51eaff3fa61b43691097aad212e26cd395 100644 --- a/enzevalos_iphoneTests/CoreMailTest.swift +++ b/enzevalos_iphoneTests/CoreMailTest.swift @@ -11,8 +11,7 @@ import XCTest @testable import enzevalos_iphone class CoreMailTest: XCTestCase { - var provider = DataProvider() - var p2 = PersitentDataProvider() + var provider = PersitentDataProvider() override func setUpWithError() throws { provider.deleteAll(completionHandler: {_ in }) @@ -22,6 +21,9 @@ class CoreMailTest: XCTestCase { provider.deleteAll(completionHandler: {_ in }) } + /** + We test if two mails from the same sender is added to the sender as inFromMails. + */ func testImportMail(){ let addr = "vic@example.com" let addr1 = AddressProperties(email: addr) @@ -30,14 +32,14 @@ class CoreMailTest: XCTestCase { let m1 = MailProperties(messageID: "1", subject: "MSG1", date: Date(), flags: 0, from: addr1, body: "THIS IS MY SECOND MSG1", signatureState: 0, encryptionState: 0) let m2 = MailProperties(messageID: "2", subject: "MSG2", date: Date(), flags: 0, from: addr1, body: "THIS IS MY SECOND MSG1", signatureState: 0, encryptionState: 0) - p2.importMails(from: [m1,m2], completionHandler: {error in + provider.importMails(from: [m1,m2], completionHandler: {error in if let error = error { XCTFail("Error while importing messages! \(error)") } importExpectation.fulfill()}) wait(for: [importExpectation], timeout: TimeInterval(20)) - self.provider.resetAndRefetch() - if let mails = provider.fetchedResultsController.fetchedObjects { + self.provider.reset() + if let mails = provider.fetchedMailResultsController.fetchedObjects { for m in mails { XCTAssertEqual(m.fromAddress?.email ?? "", addr, "Wrong email from address: \(m.fromAddress?.email ?? "-1")") } @@ -54,73 +56,75 @@ class CoreMailTest: XCTestCase { } else { XCTFail("No addresses...") } - - } - func testImportOneMail() { + func testDuplicateMails() { let addr1 = AddressProperties(email: "vic@example.com") - let importExpectation = expectation(description: "Import new addresses!") - let addresses = [addr1] + let m1 = MailProperties(messageID: "1", subject: "MSG1", date: Date(), flags: 0, from: addr1, body: "THIS IS MY MSG1" , signatureState: 0, encryptionState: 0) + let m2 = MailProperties(messageID: "1", subject: "Second MSG1", date: Date(), flags: 0, from: addr1, body: "THIS IS MY SECOND MSG1" , signatureState: 0, encryptionState: 0) - provider.importData(from: addresses, completionHandler: {error in + provider.reset() + let frc = provider.fetchedMailResultsController + XCTAssertEqual(frc.fetchedObjects?.count ?? 0, 0, "Too much messages! \(frc.fetchedObjects?.count ?? 0)") + let importExpectation = expectation(description: "Import new data!") + provider.importMails(from: [m1,m2], completionHandler: {error in if let error = error { - XCTFail("Error while importing addresses! \(error)") + XCTFail("Error while importing messages! \(error)") } - let m = MailProperties(messageID: "1", subject: "MSG1", date: Date(), flags: 0, from: addr1, body: "THIS IS MY SECOND MSG1", signatureState: 0, encryptionState: 0) - self.provider.importMails(from: [m], completionHandler: {error in - if let error = error { - XCTFail("Error while importing messages! \(error)") - } - importExpectation.fulfill() - }, withBIR: true) - + importExpectation.fulfill() }) wait(for: [importExpectation], timeout: TimeInterval(20)) - self.provider.resetAndRefetch() - if let mails = provider.fetchedResultsController.fetchedObjects { - for m in mails { - print(m.messageID, m.subject, m.fromAddress?.email) - } + provider.reset() + do { + try frc.performFetch() + } catch { + XCTFail("Could not fetch! \(error)") } - else { - XCTFail("No mails...") + XCTAssertEqual(frc.fetchedObjects?.count ?? 0, 1, "Missing message! \(frc.fetchedObjects?.count ?? 0)") + if let obj = frc.fetchedObjects?.first { + XCTAssertEqual(obj.body, "THIS IS MY SECOND MSG1","We updated the message...") + XCTAssertEqual(obj.subject, "Second MSG1", "We updated the message...") + } else { + XCTFail("No messages!") } } -/* - func testImport(withBIR: Bool) { + + + func testImportMails() { let n = 100 + let addr1 = AddressProperties(email: "vic@example.com") + let addr2 = AddressProperties(email: "alex@example.com") + let addrs = [addr1, addr2] + var msgs = [MailProperties]() for i in 1...n { - let m = MailProperties(messageID: "\(i)", subject: "MSG\(i)", date: Date(), flags: 0, body: "THIS IS MSG\(i)", signatureState: 0, encryptionState: 0) + let a = addrs[i%addrs.count] + let m = MailProperties(messageID: "\(i)", subject: "MSG\(i)", date: Date(), flags: 0, from: a, body: "THIS IS MSG\(i)", signatureState: 0, encryptionState: 0) msgs.append(m) } - let m = MailProperties(messageID: "1", subject: "MSG1", date: Date(), flags: 0, body: "THIS IS MY SECOND MSG1", signatureState: 0, encryptionState: 0) + let m = MailProperties(messageID: "1", subject: "Second MSG1", date: Date(), flags: 0, from: addr1, body: "THIS IS MY SECOND MSG1" , signatureState: 0, encryptionState: 0) + msgs.append(m) - provider.resetAndRefetch() - XCTAssertEqual(provider.fetchedResultsController.fetchedObjects?.count ?? 0, 0, "Too much messages! \(provider.fetchedResultsController.fetchedObjects?.count ?? 0)") + provider.reset() + let frc = provider.fetchedMailResultsController + XCTAssertEqual(frc.fetchedObjects?.count ?? 0, 0, "Too much messages! \(frc.fetchedObjects?.count ?? 0)") let importExpectation = expectation(description: "Import new data!") provider.importMails(from: msgs, completionHandler: {error in if let error = error { XCTFail("Error while importing messages! \(error)") } importExpectation.fulfill() - }, withBIR: withBIR) + }) wait(for: [importExpectation], timeout: TimeInterval(20)) - provider.resetAndRefetch() - XCTAssertEqual(provider.fetchedResultsController.fetchedObjects?.count ?? 0, n, "Missing message! \(provider.fetchedResultsController.fetchedObjects?.count ?? 0)") - } - - - func testImportWithBIR() { - testImport(withBIR: true) - } - - func testImportBeforeBIR() { - testImport(withBIR: false) + provider.reset() + do { + try frc.performFetch() + } catch { + XCTFail("Could not fetch! \(error)") + } + XCTAssertEqual(frc.fetchedObjects?.count ?? 0, n, "Missing message! \(frc.fetchedObjects?.count ?? 0)") } -*/ } diff --git a/enzevalos_iphoneTests/GeneratedMocks.swift b/enzevalos_iphoneTests/GeneratedMocks.swift index 20fda625749c80505919b8abe49ee279ea10ba6c..56ce0e296ffb22209e99def1367237630662624c 100644 --- a/enzevalos_iphoneTests/GeneratedMocks.swift +++ b/enzevalos_iphoneTests/GeneratedMocks.swift @@ -1,4 +1,4 @@ -// MARK: - Mocks generated from file: enzevalos_iphone/AuthenticationModel.swift at 2020-10-02 10:21:42 +0000 +// MARK: - Mocks generated from file: enzevalos_iphone/AuthenticationModel.swift at 2020-10-02 11:51:02 +0000 // // AuthenticationModel.swift @@ -654,7 +654,7 @@ import Foundation } -// MARK: - Mocks generated from file: enzevalos_iphone/AuthenticationViewModel.swift at 2020-10-02 10:21:42 +0000 +// MARK: - Mocks generated from file: enzevalos_iphone/AuthenticationViewModel.swift at 2020-10-02 11:51:02 +0000 // // AuthenticationViewModel.swift