Skip to content
Snippets Groups Projects
Commit 29f61b20 authored by Oliver Wiese's avatar Oliver Wiese
Browse files

add more properties and tests

parent cd6566e2
Branches
Tags
No related merge requests found
Showing
with 500 additions and 123 deletions
...@@ -69,6 +69,8 @@ ...@@ -69,6 +69,8 @@
472F39901E252470009260FB /* CNMailAddressesExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 472F398F1E252470009260FB /* CNMailAddressesExtension.swift */; }; 472F39901E252470009260FB /* CNMailAddressesExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 472F398F1E252470009260FB /* CNMailAddressesExtension.swift */; };
4733B1CE25262CDB00AB5600 /* PersistentDataProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4733B1CD25262CDB00AB5600 /* PersistentDataProtocol.swift */; }; 4733B1CE25262CDB00AB5600 /* PersistentDataProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4733B1CD25262CDB00AB5600 /* PersistentDataProtocol.swift */; };
4733B1E52527196100AB5600 /* PersistentDataProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4733B1E42527196100AB5600 /* PersistentDataProvider.swift */; }; 4733B1E52527196100AB5600 /* PersistentDataProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4733B1E42527196100AB5600 /* PersistentDataProvider.swift */; };
4733B202252B142C00AB5600 /* Properties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4733B201252B142B00AB5600 /* Properties.swift */; };
4733B206252B16D100AB5600 /* FolderRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4733B205252B16D100AB5600 /* FolderRecord.swift */; };
47358D92244A5AEA000116D7 /* SelectableTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47358D91244A5AEA000116D7 /* SelectableTextView.swift */; }; 47358D92244A5AEA000116D7 /* SelectableTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47358D91244A5AEA000116D7 /* SelectableTextView.swift */; };
474054982244D7A9007CF83B /* MailServerConfigurationTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 474054972244D7A9007CF83B /* MailServerConfigurationTest.swift */; }; 474054982244D7A9007CF83B /* MailServerConfigurationTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 474054972244D7A9007CF83B /* MailServerConfigurationTest.swift */; };
474994022261E4E6000F8DA5 /* SimpleSendIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 474994012261E4E6000F8DA5 /* SimpleSendIcon.swift */; }; 474994022261E4E6000F8DA5 /* SimpleSendIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 474994012261E4E6000F8DA5 /* SimpleSendIcon.swift */; };
...@@ -414,6 +416,8 @@ ...@@ -414,6 +416,8 @@
472F398F1E252470009260FB /* CNMailAddressesExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CNMailAddressesExtension.swift; sourceTree = "<group>"; }; 472F398F1E252470009260FB /* CNMailAddressesExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CNMailAddressesExtension.swift; sourceTree = "<group>"; };
4733B1CD25262CDB00AB5600 /* PersistentDataProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersistentDataProtocol.swift; sourceTree = "<group>"; }; 4733B1CD25262CDB00AB5600 /* PersistentDataProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersistentDataProtocol.swift; sourceTree = "<group>"; };
4733B1E42527196100AB5600 /* PersistentDataProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersistentDataProvider.swift; sourceTree = "<group>"; }; 4733B1E42527196100AB5600 /* PersistentDataProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersistentDataProvider.swift; sourceTree = "<group>"; };
4733B201252B142B00AB5600 /* Properties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Properties.swift; sourceTree = "<group>"; };
4733B205252B16D100AB5600 /* FolderRecord.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FolderRecord.swift; sourceTree = "<group>"; };
47358D91244A5AEA000116D7 /* SelectableTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectableTextView.swift; sourceTree = "<group>"; }; 47358D91244A5AEA000116D7 /* SelectableTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectableTextView.swift; sourceTree = "<group>"; };
474054972244D7A9007CF83B /* MailServerConfigurationTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MailServerConfigurationTest.swift; sourceTree = "<group>"; }; 474054972244D7A9007CF83B /* MailServerConfigurationTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MailServerConfigurationTest.swift; sourceTree = "<group>"; };
474994012261E4E6000F8DA5 /* SimpleSendIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleSendIcon.swift; sourceTree = "<group>"; }; 474994012261E4E6000F8DA5 /* SimpleSendIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleSendIcon.swift; sourceTree = "<group>"; };
...@@ -1390,6 +1394,8 @@ ...@@ -1390,6 +1394,8 @@
47FAE3482524FB58005A1BCB /* AddressRecord.swift */, 47FAE3482524FB58005A1BCB /* AddressRecord.swift */,
4733B1CD25262CDB00AB5600 /* PersistentDataProtocol.swift */, 4733B1CD25262CDB00AB5600 /* PersistentDataProtocol.swift */,
4733B1E42527196100AB5600 /* PersistentDataProvider.swift */, 4733B1E42527196100AB5600 /* PersistentDataProvider.swift */,
4733B201252B142B00AB5600 /* Properties.swift */,
4733B205252B16D100AB5600 /* FolderRecord.swift */,
); );
path = persistentData; path = persistentData;
sourceTree = "<group>"; sourceTree = "<group>";
...@@ -2404,6 +2410,7 @@ ...@@ -2404,6 +2410,7 @@
A1EB05841D956867008659C1 /* TableViewDataDelegate.swift in Sources */, A1EB05841D956867008659C1 /* TableViewDataDelegate.swift in Sources */,
8428A85E1F436A05007649A5 /* CircleView.swift in Sources */, 8428A85E1F436A05007649A5 /* CircleView.swift in Sources */,
A182182C21E5072200918A29 /* IntroDescriptionViewController.swift in Sources */, A182182C21E5072200918A29 /* IntroDescriptionViewController.swift in Sources */,
4733B202252B142C00AB5600 /* Properties.swift in Sources */,
47FAE3492524FB58005A1BCB /* AddressRecord.swift in Sources */, 47FAE3492524FB58005A1BCB /* AddressRecord.swift in Sources */,
4775D7AA243F0E260052F2CC /* SimulatorData.swift in Sources */, 4775D7AA243F0E260052F2CC /* SimulatorData.swift in Sources */,
F1C7AC821FED6473007629DB /* AboutViewController.swift in Sources */, F1C7AC821FED6473007629DB /* AboutViewController.swift in Sources */,
...@@ -2449,6 +2456,7 @@ ...@@ -2449,6 +2456,7 @@
F12060821DA552FC00F6EF37 /* MailHandlerDelegator.swift in Sources */, F12060821DA552FC00F6EF37 /* MailHandlerDelegator.swift in Sources */,
47C822622438A81C005BCE73 /* MapView.swift in Sources */, 47C822622438A81C005BCE73 /* MapView.swift in Sources */,
474994022261E4E6000F8DA5 /* SimpleSendIcon.swift in Sources */, 474994022261E4E6000F8DA5 /* SimpleSendIcon.swift in Sources */,
4733B206252B16D100AB5600 /* FolderRecord.swift in Sources */,
0ECEA0E8240E7081007DC71E /* SearchHelper.swift in Sources */, 0ECEA0E8240E7081007DC71E /* SearchHelper.swift in Sources */,
A12F91D821F3A99800AB0589 /* NSLayoutConstraintExtension.swift in Sources */, A12F91D821F3A99800AB0589 /* NSLayoutConstraintExtension.swift in Sources */,
71DFE5BA240679E80042019C /* HeaderExtractionValues.swift in Sources */, 71DFE5BA240679E80042019C /* HeaderExtractionValues.swift in Sources */,
......
...@@ -139,6 +139,7 @@ class IncomingMail { ...@@ -139,6 +139,7 @@ class IncomingMail {
private var rec: [MCOAddress] = [] private var rec: [MCOAddress] = []
private var cc: [MCOAddress] = [] private var cc: [MCOAddress] = []
private var bcc: [MCOAddress] = []
private var from: MCOAddress? private var from: MCOAddress?
private var fromKeyIds: [String] { private var fromKeyIds: [String] {
get{ get{
...@@ -264,6 +265,23 @@ class IncomingMail { ...@@ -264,6 +265,23 @@ class IncomingMail {
} }
} }
func export() -> MailProperties {
let to = rec.map{$0.export()}
let ccProperties = cc.map{$0.export()}
let bccProperties = bcc.map{$0.export()}
let folder = FolderProperties(delimiter: nil, icon: nil, uidValidity: nil, lastUpdate: nil, maxUID: nil, minUID: nil, path: self.folderPath)
let from = self.from?.export() ?? nil
let sigState = self.cryptoObj?.signatureState.rawValue ?? 0
let encState = self.cryptoObj?.encryptionState.rawValue ?? 0
let f = Int16(self.flags.rawValue)
var m = MailProperties(messageID: self.msgID, subject: subject, date: date, flags: f, from: from, folder: folder, body: body, signatureState: sigState, encryptionState: encState)
m.to = to
m.cc = ccProperties
m.bcc = bccProperties
return m
}
func store(keyRecord: KeyRecord?) -> PersistentMail? { func store(keyRecord: KeyRecord?) -> PersistentMail? {
let sk = secretKeys.first //TODO FIX: may import more secret keys? let sk = secretKeys.first //TODO FIX: may import more secret keys?
let mail = DataHandler.handler.createMail(uID, sender: from, receivers: rec, cc: cc, time: date, received: true, subject: subject, body: body, readableAttachments: readableAttachments, flags: flags, record: keyRecord, autocrypt: autocrypt, decryptedData: cryptoObj, folderPath: folderPath, secretKey: sk, references: references, mailagent: userAgent, messageID: msgID, encryptedBody: encryptedBody, storeEncrypted: storeEncrypted, attachedSignature: attachedSignature) let mail = DataHandler.handler.createMail(uID, sender: from, receivers: rec, cc: cc, time: date, received: true, subject: subject, body: body, readableAttachments: readableAttachments, flags: flags, record: keyRecord, autocrypt: autocrypt, decryptedData: cryptoObj, folderPath: folderPath, secretKey: sk, references: references, mailagent: userAgent, messageID: msgID, encryptedBody: encryptedBody, storeEncrypted: storeEncrypted, attachedSignature: attachedSignature)
...@@ -642,6 +660,11 @@ class IncomingMail { ...@@ -642,6 +660,11 @@ class IncomingMail {
cc.append(r as! MCOAddress) cc.append(r as! MCOAddress)
} }
} }
if let bccs = header.bcc {
for a in bccs {
bcc.append(a as! MCOAddress)
}
}
if let _ = header.extraHeaderValue(forName: Autocrypt.AUTOCRYPTHEADER){ if let _ = header.extraHeaderValue(forName: Autocrypt.AUTOCRYPTHEADER){
let autocrypt = Autocrypt(header: header) let autocrypt = Autocrypt(header: header)
......
...@@ -6,31 +6,13 @@ ...@@ -6,31 +6,13 @@
// Copyright © 2020 fu-berlin. All rights reserved. // Copyright © 2020 fu-berlin. All rights reserved.
// //
extension AddressRecord: PersistentDataProtocol { extension AddressRecord {
typealias T = AddressProperties
static var entityName = "AddressRecord" static var entityName = "AddressRecord"
func update(with addressProperties: AddressProperties){ func update(with addressProperties: AddressProperties){
email = addressProperties.email email = addressProperties.email
if let name = addressProperties.name {
self.displayname = name
} }
} }
struct AddressProperties: DataPropertyProtocol {
var entityName = "AddressRecord"
func update(m: Any) -> Bool {
if let m = m as? AddressRecord {
m.update(with: self)
return true
}
return false
}
let email: String
var dictionary: [String: Any] {
var dic = [String: Any]()
dic["email"] = email
return dic
}
} }
...@@ -5,27 +5,63 @@ ...@@ -5,27 +5,63 @@
<attribute name="id" attributeType="String"/> <attribute name="id" attributeType="String"/>
</entity> </entity>
<entity name="AddressRecord" representedClassName="AddressRecord" syncable="YES" codeGenerationType="class"> <entity name="AddressRecord" representedClassName="AddressRecord" syncable="YES" codeGenerationType="class">
<attribute name="displayname" optional="YES" attributeType="String"/>
<attribute name="email" attributeType="String"/> <attribute name="email" attributeType="String"/>
<relationship name="inFromField" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="MailRecord" inverseName="fromAddress" inverseEntity="MailRecord"/> <relationship name="inBCCField" toMany="YES" deletionRule="Nullify" destinationEntity="MailRecord" inverseName="bccAddresses" inverseEntity="MailRecord"/>
<relationship name="inCCField" toMany="YES" deletionRule="Nullify" destinationEntity="MailRecord" inverseName="ccAddresses" inverseEntity="MailRecord"/>
<relationship name="inFromField" toMany="YES" deletionRule="Nullify" destinationEntity="MailRecord" inverseName="fromAddress" inverseEntity="MailRecord"/>
<relationship name="inToField" toMany="YES" deletionRule="Nullify" destinationEntity="MailRecord" inverseName="toAddresses" inverseEntity="MailRecord"/>
<uniquenessConstraints> <uniquenessConstraints>
<uniquenessConstraint> <uniquenessConstraint>
<constraint value="email"/> <constraint value="email"/>
</uniquenessConstraint> </uniquenessConstraint>
</uniquenessConstraints> </uniquenessConstraints>
</entity> </entity>
<entity name="AttachmentRecord" representedClassName="AttachmentRecord" syncable="YES" codeGenerationType="class">
<attribute name="contentID" optional="YES" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="data" optional="YES" attributeType="Binary"/>
<attribute name="mimeType" optional="YES" attributeType="String"/>
<attribute name="name" optional="YES" attributeType="String"/>
<attribute name="type" optional="YES" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/>
<relationship name="isPartOfMail" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="MailRecord" inverseName="includedAttachments" inverseEntity="MailRecord"/>
</entity>
<entity name="FolderRecord" representedClassName="FolderRecord" syncable="YES" codeGenerationType="class">
<attribute name="delimiter" optional="YES" attributeType="String"/>
<attribute name="icon" optional="YES" attributeType="String"/>
<attribute name="lastUpdate" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="maxUID" optional="YES" attributeType="Decimal" defaultValueString="0.0"/>
<attribute name="minUID" optional="YES" attributeType="Decimal" defaultValueString="0.0"/>
<attribute name="path" attributeType="String"/>
<attribute name="uidValidity" optional="YES" attributeType="Decimal" defaultValueString="0.0"/>
<relationship name="childrenFolder" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="FolderRecord" inverseName="partentFolder" inverseEntity="FolderRecord"/>
<relationship name="mailsInFolder" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="MailRecord" inverseName="inFolder" inverseEntity="MailRecord"/>
<relationship name="partentFolder" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="FolderRecord" inverseName="childrenFolder" inverseEntity="FolderRecord"/>
<uniquenessConstraints>
<uniquenessConstraint>
<constraint value="path"/>
</uniquenessConstraint>
</uniquenessConstraints>
</entity>
<entity name="MailRecord" representedClassName="MailRecord" syncable="YES" codeGenerationType="class"> <entity name="MailRecord" representedClassName="MailRecord" syncable="YES" codeGenerationType="class">
<attribute name="body" attributeType="String"/> <attribute name="body" attributeType="String"/>
<attribute name="date" attributeType="Date" usesScalarValueType="NO"/> <attribute name="date" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="encryptionState" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/> <attribute name="encryptionStateInt" attributeType="Integer 16" minValueString="0" maxValueString="3" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="flag" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/> <attribute name="flag" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="messageID" attributeType="String"/> <attribute name="messageID" attributeType="String"/>
<attribute name="signatureState" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/> <attribute name="signatureStateInt" attributeType="Integer 16" minValueString="-1" maxValueString="2" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="subject" attributeType="String"/> <attribute name="subject" attributeType="String"/>
<attribute name="xMailer" optional="YES" attributeType="String"/> <attribute name="xMailer" optional="YES" attributeType="String"/>
<relationship name="bccAddresses" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="AddressRecord"/> <relationship name="attachedAutocryptPublicKey" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="PublicKeyRecord" inverseName="sendWithAutocryptHeader" inverseEntity="PublicKeyRecord"/>
<relationship name="ccAddresses" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="AddressRecord"/> <relationship name="attachedPublicKeys" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="PublicKeyRecord" inverseName="sendWithMail" inverseEntity="PublicKeyRecord"/>
<relationship name="attachedSecretKey" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="SecretKeyRecord" inverseName="sendWithMail" inverseEntity="SecretKeyRecord"/>
<relationship name="bccAddresses" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="AddressRecord" inverseName="inBCCField" inverseEntity="AddressRecord"/>
<relationship name="ccAddresses" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="AddressRecord" inverseName="inCCField" inverseEntity="AddressRecord"/>
<relationship name="decryptionKey" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="SecretKeyRecord" inverseName="decryptedMails" inverseEntity="SecretKeyRecord"/>
<relationship name="fromAddress" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="AddressRecord" inverseName="inFromField" inverseEntity="AddressRecord"/> <relationship name="fromAddress" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="AddressRecord" inverseName="inFromField" inverseEntity="AddressRecord"/>
<relationship name="toAddresses" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="AddressRecord"/> <relationship name="includedAttachments" optional="YES" toMany="YES" deletionRule="Cascade" destinationEntity="AttachmentRecord" inverseName="isPartOfMail" inverseEntity="AttachmentRecord"/>
<relationship name="inFolder" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="FolderRecord" inverseName="mailsInFolder" inverseEntity="FolderRecord"/>
<relationship name="signatureKey" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="PublicKeyRecord" inverseName="signedMails" inverseEntity="PublicKeyRecord"/>
<relationship name="toAddresses" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="AddressRecord" inverseName="inToField" inverseEntity="AddressRecord"/>
<uniquenessConstraints> <uniquenessConstraints>
<uniquenessConstraint> <uniquenessConstraint>
<constraint value="messageID"/> <constraint value="messageID"/>
...@@ -38,17 +74,23 @@ ...@@ -38,17 +74,23 @@
<attribute name="lastSeenSignedMail" optional="YES" attributeType="Date" usesScalarValueType="NO"/> <attribute name="lastSeenSignedMail" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="origin" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/> <attribute name="origin" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="preferEncryption" attributeType="Integer 16" usesScalarValueType="YES"/> <attribute name="preferEncryption" attributeType="Integer 16" usesScalarValueType="YES"/>
<relationship name="sendWithAutocryptHeader" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="MailRecord" inverseName="attachedAutocryptPublicKey" inverseEntity="MailRecord"/>
<relationship name="sendWithMail" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="MailRecord" inverseName="attachedPublicKeys" inverseEntity="MailRecord"/>
<relationship name="signedMails" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="MailRecord" inverseName="signatureKey" inverseEntity="MailRecord"/>
</entity> </entity>
<entity name="SecretKeyRecord" representedClassName="SecretKeyRecord" parentEntity="AbstractKeyRecord" syncable="YES" codeGenerationType="class"> <entity name="SecretKeyRecord" representedClassName="SecretKeyRecord" parentEntity="AbstractKeyRecord" syncable="YES" codeGenerationType="class">
<attribute name="exported" attributeType="Boolean" usesScalarValueType="YES"/> <attribute name="exported" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="importedDate" optional="YES" attributeType="Date" usesScalarValueType="NO"/> <attribute name="importedDate" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<relationship name="decryptedMails" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="MailRecord" inverseName="decryptionKey" inverseEntity="MailRecord"/>
<relationship name="sendWithMail" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="MailRecord" inverseName="attachedSecretKey" inverseEntity="MailRecord"/>
</entity> </entity>
<fetchRequest name="FetchAddressesRequest" entity="AddressRecord" fetchLimit="200" fetchBatchSize="200"/>
<elements> <elements>
<element name="AddressRecord" positionX="-36" positionY="27" width="128" height="73"/>
<element name="MailRecord" positionX="-54" positionY="-9" width="128" height="223"/>
<element name="AbstractKeyRecord" positionX="-27" positionY="54" width="128" height="28"/> <element name="AbstractKeyRecord" positionX="-27" positionY="54" width="128" height="28"/>
<element name="SecretKeyRecord" positionX="-9" positionY="63" width="128" height="28"/> <element name="AddressRecord" positionX="-36" positionY="27" width="128" height="133"/>
<element name="PublicKeyRecord" positionX="9" positionY="63" width="128" height="28"/> <element name="FolderRecord" positionX="27" positionY="135" width="128" height="193"/>
<element name="MailRecord" positionX="-54" positionY="-9" width="128" height="328"/>
<element name="PublicKeyRecord" positionX="9" positionY="63" width="128" height="163"/>
<element name="SecretKeyRecord" positionX="-9" positionY="63" width="128" height="103"/>
<element name="AttachmentRecord" positionX="0" positionY="144" width="128" height="133"/>
</elements> </elements>
</model> </model>
\ No newline at end of file
//
// FolderRecord.swift
// enzevalos_iphone
//
// Created by Oliver Wiese on 05.10.20.
// Copyright © 2020 fu-berlin. All rights reserved.
//
extension FolderRecord {
static let entityName = "FolderRecord"
func update(properties: FolderProperties) {
if let delimiter = properties.delimiter {
self.delimiter = delimiter
}
if let icon = icon {
self.icon = icon
}
if let uidValidity = properties.uidValidity {
self.uidValidity = uidValidity
}
if let lastUpdate = properties.lastUpdate {
self.lastUpdate = lastUpdate
}
if let maxUID = properties.maxUID {
self.maxUID = maxUID
}
if let minUID = properties.minUID {
self.minUID = minUID
}
path = properties.path
}
}
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
/** /**
Managed object subclass extension for the mail entity. Managed object subclass extension for the mail entity.
*/ */
extension MailRecord: PersistentDataProtocol { extension MailRecord {
static let entityName = "MailRecord" static let entityName = "MailRecord"
func update(with mailProperties: MailProperties) { func update(with mailProperties: MailProperties) {
...@@ -18,62 +18,22 @@ extension MailRecord: PersistentDataProtocol { ...@@ -18,62 +18,22 @@ extension MailRecord: PersistentDataProtocol {
date = mailProperties.date date = mailProperties.date
flag = mailProperties.flags flag = mailProperties.flags
subject = mailProperties.subject subject = mailProperties.subject
xMailer = mailProperties.xMailer
// Content // Content
body = mailProperties.body body = mailProperties.body
// Security // Security
signatureState = mailProperties.signatureState signatureStateInt = mailProperties.signatureState
encryptionState = mailProperties.encryptionState encryptionStateInt = mailProperties.encryptionState
} }
func update(mail: IncomingMail) { var signatureState: SignatureState {
return SignatureState.init(rawValue: signatureStateInt) ?? .NoSignature
} }
}
/**
A struct encapsulating the properties of a E-Mail.
TODO: Folder, routing information, gmailMessageID, gmailThreadID, ThreadID, signatureKey, decryptionKey, attachments, autocrypt, xMailer
What about attached keys (public, secret keys)
*/
struct MailProperties: DataPropertyProtocol {
var entityName = "MailRecord"
// Header properties
let messageID: String
let subject: String
let date: Date
let flags: Int16
let from: AddressProperties
let to: [AddressProperties]
let cc: [AddressProperties]
let bcc: [AddressProperties]
// Content properties var encryptionState: EncryptionState {
var body: String = "" return EncryptionState.init(rawValue: encryptionStateInt) ?? .NoEncryption
// Security properties
let signatureState: Int16
let encryptionState: Int16
var dictionary: [String: Any] {
var dic = [String: Any]()
dic["messageID"] = messageID
dic["subject"] = subject
return dic
}
func update(m: Any) -> Bool {
if let m = m as? MailRecord {
m.update(with: self)
return true
}
return false
} }
} }
...@@ -6,18 +6,6 @@ ...@@ -6,18 +6,6 @@
// Copyright © 2020 fu-berlin. All rights reserved. // Copyright © 2020 fu-berlin. All rights reserved.
// //
protocol PersistentDataProtocol {
associatedtype T
func update(with properties: T)
}
protocol DataPropertyProtocol {
var entityName: String { get }
var dictionary: [String: Any] { get }
func update(m: Any) -> Bool
}
...@@ -167,15 +167,23 @@ class PersitentDataProvider { ...@@ -167,15 +167,23 @@ class PersitentDataProvider {
// Create a managed object on the private queue context. // Create a managed object on the private queue context.
let mail = NSEntityDescription.insertNewObject(forEntityName: MailRecord.entityName, into: taskContext) as! MailRecord let mail = NSEntityDescription.insertNewObject(forEntityName: MailRecord.entityName, into: taskContext) as! MailRecord
mail.update(with: m) mail.update(with: m)
let from = NSEntityDescription.insertNewObject(forEntityName: AddressRecord.entityName, into: taskContext) as! AddressRecord
from.update(with: m.from)
// add relationships // add relationships
// From
if let sender = m.from {
let from = NSEntityDescription.insertNewObject(forEntityName: AddressRecord.entityName, into: taskContext) as! AddressRecord
from.update(with: sender)
mail.fromAddress = from mail.fromAddress = from
}
// To, CC, BCC // To, CC, BCC
importManyAddresses(addrs: m.to, taskContext: taskContext, addTo: mail.addToToAddresses) importManyAddresses(addrs: m.to, taskContext: taskContext, addTo: mail.addToToAddresses)
importManyAddresses(addrs: m.cc, taskContext: taskContext, addTo: mail.addToCcAddresses) importManyAddresses(addrs: m.cc, taskContext: taskContext, addTo: mail.addToCcAddresses)
importManyAddresses(addrs: m.bcc, taskContext: taskContext, addTo: mail.addToBccAddresses) importManyAddresses(addrs: m.bcc, taskContext: taskContext, addTo: mail.addToBccAddresses)
// Add to folder
let folder = NSEntityDescription.insertNewObject(forEntityName: FolderRecord.entityName, into: taskContext) as! FolderRecord
folder.update(properties: m.folder)
mail.inFolder = folder
} }
private func importManyAddresses(addrs: [AddressProperties], taskContext: NSManagedObjectContext, addTo: (AddressRecord) -> () ) { private func importManyAddresses(addrs: [AddressProperties], taskContext: NSManagedObjectContext, addTo: (AddressRecord) -> () ) {
...@@ -194,12 +202,11 @@ class PersitentDataProvider { ...@@ -194,12 +202,11 @@ class PersitentDataProvider {
func deleteAll(completionHandler: @escaping (Error?) -> Void) { func deleteAll(completionHandler: @escaping (Error?) -> Void) {
let taskContext = newTaskContext() let taskContext = newTaskContext()
taskContext.perform { taskContext.perform {
for name in [AddressRecord.entityName, MailRecord.entityName] { for name in [AddressRecord.entityName, MailRecord.entityName, FolderRecord.entityName] {
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: name) let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: name)
let batchDeleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest) let batchDeleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
batchDeleteRequest.resultType = .resultTypeCount batchDeleteRequest.resultType = .resultTypeCount
// Execute the batch insert
guard let batchDeleteResult = try? taskContext.execute(batchDeleteRequest) as? NSBatchDeleteResult, guard let batchDeleteResult = try? taskContext.execute(batchDeleteRequest) as? NSBatchDeleteResult,
batchDeleteResult.result != nil else { batchDeleteResult.result != nil else {
completionHandler(PersistentDataError.batchDeleteError) completionHandler(PersistentDataError.batchDeleteError)
...@@ -231,10 +238,25 @@ class PersitentDataProvider { ...@@ -231,10 +238,25 @@ class PersitentDataProvider {
return controller return controller
}() }()
lazy var fetchedFolderResultsControler: NSFetchedResultsController<FolderRecord> = {
let fetchRequest = NSFetchRequest<FolderRecord>(entityName: FolderRecord.entityName)
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "path", ascending: false)]
let controller = NSFetchedResultsController(fetchRequest: fetchRequest,
managedObjectContext: persistentContainer.viewContext,
sectionNameKeyPath: nil, cacheName: nil)
// Perform the fetch.
do {
try controller.performFetch()
} catch {
fatalError("Unresolved error \(error)")
}
return controller
} ()
lazy var fetchedMailResultsController: NSFetchedResultsController<MailRecord> = { lazy var fetchedMailResultsController: NSFetchedResultsController<MailRecord> = {
// Create a fetch request for the Quake entity sorted by time. // Create a fetch request for the email entity sorted by time.
let fetchRequest = NSFetchRequest<MailRecord>(entityName: MailRecord.entityName) let fetchRequest = NSFetchRequest<MailRecord>(entityName: MailRecord.entityName)
// Create a fetched results controller and set its fetch request, context, and delegate. // Create a fetched results controller and set its fetch request, context, and delegate.
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "messageID", ascending: false)] fetchRequest.sortDescriptors = [NSSortDescriptor(key: "messageID", ascending: false)]
......
//
// Properties.swift
// enzevalos_iphone
//
// Created by Oliver Wiese on 05.10.20.
// Copyright © 2020 fu-berlin. All rights reserved.
//
protocol DataPropertyProtocol {
var entityName: String { get }
func update(m: Any) -> Bool
}
/**
A struct encapsulating the properties of a E-Mail.
TODO: Folder, routing information, gmailMessageID, gmailThreadID, ThreadID, signatureKey, decryptionKey, attachments, autocrypt, xMailer
What about attached keys (public, secret keys)
*/
struct MailProperties: DataPropertyProtocol {
let entityName = "MailRecord"
// Header properties
let messageID: String
let subject: String
let date: Date
let flags: Int16
let from: AddressProperties?
var to: [AddressProperties] = []
var cc: [AddressProperties] = []
var bcc: [AddressProperties] = []
let xMailer: String? = nil
let folder: FolderProperties
// Content properties
var body: String = ""
// Security properties
let signatureState: Int16
let encryptionState: Int16
func update(m: Any) -> Bool {
if let m = m as? MailRecord {
m.update(with: self)
return true
}
return false
}
}
struct AddressProperties: DataPropertyProtocol {
let entityName = "AddressRecord"
let email: String
var name: String? = nil
func update(m: Any) -> Bool {
if let m = m as? AddressRecord {
m.update(with: self)
return true
}
return false
}
}
struct FolderProperties: DataPropertyProtocol{
let entityName = "FolderRecord"
var delimiter: String?
var icon: String?
var uidValidity: NSDecimalNumber?
var lastUpdate: Date?
var maxUID: NSDecimalNumber?
var minUID: NSDecimalNumber?
let path: String
func update(m: Any) -> Bool {
if let folder = m as? FolderRecord {
folder.update(properties: self)
return true
}
return false
}
}
extension MCOAddress {
func export() -> AddressProperties {
return AddressProperties(email: self.mailbox)
}
}
...@@ -12,23 +12,76 @@ import XCTest ...@@ -12,23 +12,76 @@ import XCTest
class CoreAddressTest: XCTestCase { class CoreAddressTest: XCTestCase {
var provider = PersitentDataProvider() var provider = PersitentDataProvider()
private func deleteAll() {
provider = PersitentDataProvider()
let deleteExpectation = expectation(description: "Delete all data!")
provider.deleteAll(completionHandler: {error in
if let error = error {
XCTFail("Error while importing addresses! \(error)")
}
deleteExpectation.fulfill()
})
wait(for: [deleteExpectation], timeout: TimeInterval(20))
provider.reset()
let frc = provider.fetchAddressResultController
XCTAssertEqual(frc.fetchedObjects?.count ?? 0, 0)
provider = PersitentDataProvider()
}
override func setUpWithError() throws { override func setUpWithError() throws {
provider.deleteAll(completionHandler: {_ in }) deleteAll()
} }
override func tearDownWithError() throws { override func tearDownWithError() throws {
provider.deleteAll(completionHandler: {_ in }) deleteAll()
}
func testSimpleCreateAddress() throws {
var addr1 = AddressProperties(email: "vic@example.com")
addr1.name = "vic"
let importExpectation = expectation(description: "Import new addresses!")
print("Import data!")
provider.importData(from: [addr1], completionHandler: {error in
if let error = error {
XCTFail("Error while importing addresses! \(error)")
}
importExpectation.fulfill()
})
wait(for: [importExpectation], timeout: TimeInterval(20))
provider.reset()
let frc = provider.fetchAddressResultController
XCTAssertEqual(frc.fetchedObjects?.count ?? 0, 1, "Missing addresses! \(frc.fetchedObjects?.count ?? 0)")
if let objects = frc.fetchedObjects {
for obj in objects {
XCTAssertEqual(obj.inFromField?.count, 0)
XCTAssertEqual(obj.email, "vic@example.com")
XCTAssertEqual(obj.displayname, "vic")
}
} else {
XCTFail("No addresses!")
}
} }
func testCreateAddress() throws { func testCreateAddress() throws {
let n = 1 let n = 1
let addr1 = AddressProperties(email: "vic@example.com") var addr1 = AddressProperties(email: "vic@example.com")
addr1.name = "vic"
let addr2 = AddressProperties(email: "vic@example.com") let addr2 = AddressProperties(email: "vic@example.com")
let importExpectation = expectation(description: "Import new addresses!") var importExpectation = expectation(description: "Import new addresses!")
let addresses = [addr1, addr2]
provider.importData(from: addresses, completionHandler: {error in provider.importData(from: [addr1], completionHandler: {error in
if let error = error {
XCTFail("Error while importing addresses! \(error)")
}
importExpectation.fulfill()
})
wait(for: [importExpectation], timeout: TimeInterval(20))
importExpectation = expectation(description: "Import new addresses!")
provider.importData(from: [addr2], completionHandler: {error in
if let error = error { if let error = error {
XCTFail("Error while importing addresses! \(error)") XCTFail("Error while importing addresses! \(error)")
} }
...@@ -37,12 +90,52 @@ class CoreAddressTest: XCTestCase { ...@@ -37,12 +90,52 @@ class CoreAddressTest: XCTestCase {
wait(for: [importExpectation], timeout: TimeInterval(20)) wait(for: [importExpectation], timeout: TimeInterval(20))
provider.reset() provider.reset()
let frc = provider.fetchAddressResultController let frc = provider.fetchAddressResultController
XCTAssertEqual(frc.fetchedObjects?.count ?? 0, n, "Missing message! \(frc.fetchedObjects?.count ?? 0)") XCTAssertEqual(frc.fetchedObjects?.count ?? 0, n, "Missing addresses! \(frc.fetchedObjects?.count ?? 0)")
if let objects = frc.fetchedObjects { if let objects = frc.fetchedObjects {
for obj in objects { for obj in objects {
print("#from mails: \(obj.inFromField?.count ?? -1)") XCTAssertEqual(obj.inFromField?.count, 0)
XCTAssertEqual(obj.email, "vic@example.com")
XCTAssertEqual(obj.displayname, nil)
}
} }
} }
func testCreateAddress2() throws {
let n = 1
let addr1 = AddressProperties(email: "vic@example.com")
var addr2 = AddressProperties(email: "vic@example.com")
addr2.name = "vic"
var importExpectation = expectation(description: "Import new addresses!")
provider.importData(from: [addr1], completionHandler: {error in
if let error = error {
XCTFail("Error while importing addresses! \(error)")
}
importExpectation.fulfill()
})
wait(for: [importExpectation], timeout: TimeInterval(20))
importExpectation = expectation(description: "Import new addresses!")
provider.importData(from: [addr2], completionHandler: {error in
if let error = error {
XCTFail("Error while importing addresses! \(error)")
}
importExpectation.fulfill()
})
wait(for: [importExpectation], timeout: TimeInterval(20))
provider.reset()
let frc = provider.fetchAddressResultController
XCTAssertEqual(frc.fetchedObjects?.count ?? 0, n, "Missing addresses! \(frc.fetchedObjects?.count ?? 0)")
if let objects = frc.fetchedObjects {
for obj in objects {
XCTAssertEqual(obj.inFromField?.count, 0)
XCTAssertEqual(obj.email, "vic@example.com")
XCTAssertEqual(obj.displayname, "vic")
}
}
} }
} }
...@@ -13,12 +13,29 @@ class CoreMailTest: XCTestCase { ...@@ -13,12 +13,29 @@ class CoreMailTest: XCTestCase {
var provider = PersitentDataProvider() var provider = PersitentDataProvider()
private func deleteAll() {
provider = PersitentDataProvider()
let deleteExpectation = expectation(description: "Delete all data!")
provider.deleteAll(completionHandler: {error in
if let error = error {
XCTFail("Error while importing addresses! \(error)")
}
deleteExpectation.fulfill()
})
wait(for: [deleteExpectation], timeout: TimeInterval(20))
provider.reset()
let frc = provider.fetchedMailResultsController
XCTAssertEqual(frc.fetchedObjects?.count ?? 0, 0)
provider = PersitentDataProvider()
}
override func setUpWithError() throws { override func setUpWithError() throws {
provider.deleteAll(completionHandler: {_ in }) deleteAll()
} }
override func tearDownWithError() throws { override func tearDownWithError() throws {
provider.deleteAll(completionHandler: {_ in }) deleteAll()
} }
/** /**
...@@ -27,10 +44,12 @@ class CoreMailTest: XCTestCase { ...@@ -27,10 +44,12 @@ class CoreMailTest: XCTestCase {
func testImportMail(){ func testImportMail(){
let addr = "vic@example.com" let addr = "vic@example.com"
let addr1 = AddressProperties(email: addr) let addr1 = AddressProperties(email: addr)
let folder = FolderProperties(delimiter: nil, icon: nil, uidValidity: nil, lastUpdate: nil, maxUID: nil, minUID: nil, path: "Testfolder")
let importExpectation = expectation(description: "Import new msg!") let importExpectation = expectation(description: "Import new msg!")
let m1 = MailProperties(messageID: "1", subject: "MSG1", date: Date(), flags: 0, from: addr1, body: "THIS IS MY SECOND MSG1", signatureState: 0, encryptionState: 0) let m1 = MailProperties(messageID: "1", subject: "MSG1", date: Date(), flags: 0, from: addr1, folder: folder, 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) let m2 = MailProperties(messageID: "2", subject: "MSG2", date: Date(), flags: 0, from: addr1, folder: folder, signatureState: 0, encryptionState: 0)
provider.importMails(from: [m1,m2], completionHandler: {error in provider.importMails(from: [m1,m2], completionHandler: {error in
if let error = error { if let error = error {
...@@ -60,8 +79,10 @@ class CoreMailTest: XCTestCase { ...@@ -60,8 +79,10 @@ class CoreMailTest: XCTestCase {
func testDuplicateMails() { func testDuplicateMails() {
let addr1 = AddressProperties(email: "vic@example.com") let addr1 = AddressProperties(email: "vic@example.com")
let m1 = MailProperties(messageID: "1", subject: "MSG1", date: Date(), flags: 0, from: addr1, body: "THIS IS MY MSG1" , signatureState: 0, encryptionState: 0) let folder = FolderProperties(delimiter: nil, icon: nil, uidValidity: nil, lastUpdate: nil, maxUID: nil, minUID: nil, path: "Testfolder")
let m2 = MailProperties(messageID: "1", subject: "Second MSG1", date: Date(), flags: 0, from: addr1, body: "THIS IS MY SECOND MSG1" , signatureState: 0, encryptionState: 0)
let m1 = MailProperties(messageID: "1", subject: "MSG1", date: Date(), flags: 0, from: addr1, folder: folder, signatureState: 0, encryptionState: 0)
let m2 = MailProperties(messageID: "1", subject: "Second MSG1", date: Date(), flags: 0, from: addr1, folder: folder, signatureState: 0, encryptionState: 0)
provider.reset() provider.reset()
let frc = provider.fetchedMailResultsController let frc = provider.fetchedMailResultsController
...@@ -81,9 +102,49 @@ class CoreMailTest: XCTestCase { ...@@ -81,9 +102,49 @@ class CoreMailTest: XCTestCase {
XCTFail("Could not fetch! \(error)") XCTFail("Could not fetch! \(error)")
} }
XCTAssertEqual(frc.fetchedObjects?.count ?? 0, 1, "Missing message! \(frc.fetchedObjects?.count ?? 0)") XCTAssertEqual(frc.fetchedObjects?.count ?? 0, 1, "Missing message! \(frc.fetchedObjects?.count ?? 0)")
if let obj = frc.fetchedObjects?.first { if let obj = frc.fetchedObjects?.first, let subject = obj.subject {
XCTAssertEqual(obj.body, "THIS IS MY SECOND MSG1","We updated the message...") XCTAssert(subject == "Second MSG1" || subject == "MSG1", "Wired subject: \(subject)")
XCTAssertEqual(obj.subject, "Second MSG1", "We updated the message...") } else {
XCTFail("No messages!")
}
}
func testDuplicateMails2() {
let addr1 = AddressProperties(email: "vic@example.com")
let folder = FolderProperties(delimiter: nil, icon: nil, uidValidity: nil, lastUpdate: nil, maxUID: nil, minUID: nil, path: "Testfolder")
let m1 = MailProperties(messageID: "1", subject: "MSG1", date: Date(), flags: 0, from: addr1, folder: folder, signatureState: 0, encryptionState: 0)
let m2 = MailProperties(messageID: "1", subject: "Second MSG1", date: Date(), flags: 0, from: addr1, folder: folder, signatureState: 0, encryptionState: 0)
provider.reset()
let frc = provider.fetchedMailResultsController
XCTAssertEqual(frc.fetchedObjects?.count ?? 0, 0, "Too much messages! \(frc.fetchedObjects?.count ?? 0)")
var importExpectation = expectation(description: "Import new data!")
provider.importMails(from: [m1], completionHandler: {error in
if let error = error {
XCTFail("Error while importing messages! \(error)")
}
importExpectation.fulfill()
})
wait(for: [importExpectation], timeout: TimeInterval(20))
importExpectation = expectation(description: "Import new data!")
provider.importMails(from: [m2], completionHandler: {error in
if let error = error {
XCTFail("Error while importing messages! \(error)")
}
importExpectation.fulfill()
})
wait(for: [importExpectation], timeout: TimeInterval(20))
provider.reset()
do {
try frc.performFetch()
} catch {
XCTFail("Could not fetch! \(error)")
}
XCTAssertEqual(frc.fetchedObjects?.count ?? 0, 1, "Missing message! \(frc.fetchedObjects?.count ?? 0)")
if let obj = frc.fetchedObjects?.first, let subject = obj.subject {
XCTAssertEqual(subject, "Second MSG1", "We updated the message...")
} else { } else {
XCTFail("No messages!") XCTFail("No messages!")
} }
...@@ -91,23 +152,25 @@ class CoreMailTest: XCTestCase { ...@@ -91,23 +152,25 @@ class CoreMailTest: XCTestCase {
} }
/**
Tests to import multiple Mails in one Fetch
*/
func testImportMails() { func testImportMails() {
let n = 100 let n = 1000
let addr1 = AddressProperties(email: "vic@example.com") let addr1 = AddressProperties(email: "vic@example.com")
let addr2 = AddressProperties(email: "alex@example.com") let addr2 = AddressProperties(email: "alex@example.com")
let addrs = [addr1, addr2] let addrs = [addr1, addr2]
let folder = FolderProperties(delimiter: nil, icon: nil, uidValidity: nil, lastUpdate: nil, maxUID: nil, minUID: nil, path: "Testfolder")
var msgs = [MailProperties]() var msgs = [MailProperties]()
for i in 1...n { for i in 1...n {
let a = addrs[i%addrs.count] 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) let m = MailProperties(messageID: "\(i)", subject: "MSG\(i)", date: Date(), flags: 0, from: a, folder: folder, signatureState: 0, encryptionState: 0)
msgs.append(m) msgs.append(m)
} }
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.reset() provider.reset()
let frc = provider.fetchedMailResultsController let frc = provider.fetchedMailResultsController
XCTAssertEqual(frc.fetchedObjects?.count ?? 0, 0, "Too much messages! \(frc.fetchedObjects?.count ?? 0)") XCTAssertEqual(frc.fetchedObjects?.count ?? 0, 0, "Too much messages! \(frc.fetchedObjects?.count ?? 0)")
...@@ -126,5 +189,69 @@ class CoreMailTest: XCTestCase { ...@@ -126,5 +189,69 @@ class CoreMailTest: XCTestCase {
XCTFail("Could not fetch! \(error)") XCTFail("Could not fetch! \(error)")
} }
XCTAssertEqual(frc.fetchedObjects?.count ?? 0, n, "Missing message! \(frc.fetchedObjects?.count ?? 0)") XCTAssertEqual(frc.fetchedObjects?.count ?? 0, n, "Missing message! \(frc.fetchedObjects?.count ?? 0)")
if let folders = provider.fetchedFolderResultsControler.fetchedObjects {
XCTAssert(folders.count == 1, "We have only one folder! folders: \(folders.count)")
if let f = folders.first {
XCTAssertEqual(f.path, "Testfolder")
XCTAssertEqual(f.mailsInFolder?.count, n)
}
} else{
XCTFail("No folders!")
}
}
func testImportMoreMails() {
let n = 100
let m = 10
var k = 1
let addr1 = AddressProperties(email: "vic@example.com")
let addr2 = AddressProperties(email: "alex@example.com")
let addrs = [addr1, addr2]
let folder = FolderProperties(delimiter: nil, icon: nil, uidValidity: nil, lastUpdate: nil, maxUID: nil, minUID: nil, path: "Testfolder")
for j in 1...m {
var msgs = [MailProperties]()
for i in 1...n {
let a = addrs[i%addrs.count]
let msg = MailProperties(messageID: "\(k)", subject: "MSG\(k)", date: Date(), flags: 0, from: a, folder: folder, signatureState: 0, encryptionState: 0)
k = k + 1
msgs.append(msg)
}
provider.reset()
let frc = provider.fetchedMailResultsController
XCTAssertEqual(frc.fetchedObjects?.count ?? 0, (j-1)*n, "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()
})
wait(for: [importExpectation], timeout: TimeInterval(20))
provider.reset()
do {
try frc.performFetch()
} catch {
XCTFail("Could not fetch! \(error)")
}
XCTAssertEqual(frc.fetchedObjects?.count ?? 0, j*n, "Missing message! \(frc.fetchedObjects?.count ?? 0)")
}
if let folders = provider.fetchedFolderResultsControler.fetchedObjects {
XCTAssert(folders.count == 1, "We have only one folder! folders: \(folders.count)")
if let f = folders.first {
XCTAssertEqual(f.path, "Testfolder")
XCTAssertEqual(f.mailsInFolder?.count, m*n)
}
else{
XCTFail("No folders!")
}
} else{
XCTFail("No folders!")
}
} }
} }
// MARK: - Mocks generated from file: enzevalos_iphone/AuthenticationModel.swift at 2020-10-02 11:51:02 +0000 // MARK: - Mocks generated from file: enzevalos_iphone/AuthenticationModel.swift at 2020-10-05 15:19:11 +0000
// //
// AuthenticationModel.swift // AuthenticationModel.swift
...@@ -654,7 +654,7 @@ import Foundation ...@@ -654,7 +654,7 @@ import Foundation
} }
// MARK: - Mocks generated from file: enzevalos_iphone/AuthenticationViewModel.swift at 2020-10-02 11:51:02 +0000 // MARK: - Mocks generated from file: enzevalos_iphone/AuthenticationViewModel.swift at 2020-10-05 15:19:11 +0000
// //
// AuthenticationViewModel.swift // AuthenticationViewModel.swift
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment