test(fls): e-mail account files against Swift's reader
The Swift oracle reads the 43 account files Java read (--email-files, with TopologyRuntimeEmailStorage.decodeJavaServer and decodeJavaClient). The accounts the model takes match Swift's except where Swift checks names, hosts and addresses and fails the whole file on one it rejects, or reads the format otherwise (the first client line instead of the last, exactly nine fields, a required messages field). Every departure is named with its reason; Java's reading is right in each, none is a Java error Swift fixes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
[
|
||||
[
|
||||
"mail.gmx.de;mail.gmx.de;110;25;herbert;herbert1234;Schmidt;Herbert;herbert@gmx.de",
|
||||
{
|
||||
"email" : "herbert@gmx.de",
|
||||
"name" : "Herbert Schmidt",
|
||||
"password" : "herbert1234",
|
||||
"pop3Host" : "mail.gmx.de",
|
||||
"pop3Port" : 110,
|
||||
"smtpHost" : "mail.gmx.de",
|
||||
"smtpPort" : 25,
|
||||
"username" : "herbert"
|
||||
}
|
||||
],
|
||||
[
|
||||
"mail.gmx.de;mail.gmx.de;110;25;herbert;herbert1234;Schmidt;Herbert;herbert@gmx.de\\u000A",
|
||||
{
|
||||
"email" : "herbert@gmx.de",
|
||||
"name" : "Herbert Schmidt",
|
||||
"password" : "herbert1234",
|
||||
"pop3Host" : "mail.gmx.de",
|
||||
"pop3Port" : 110,
|
||||
"smtpHost" : "mail.gmx.de",
|
||||
"smtpPort" : 25,
|
||||
"username" : "herbert"
|
||||
}
|
||||
],
|
||||
[
|
||||
"a;a;110;25;first;p;L;F;first@x\\u000Ab;b;110;25;second;p;L;F;second@x\\u000A",
|
||||
{
|
||||
"email" : "first@x",
|
||||
"name" : "F L",
|
||||
"password" : "p",
|
||||
"pop3Host" : "a",
|
||||
"pop3Port" : 110,
|
||||
"smtpHost" : "a",
|
||||
"smtpPort" : 25,
|
||||
"username" : "first"
|
||||
}
|
||||
],
|
||||
[
|
||||
"a;a;110;25;first;p;L;F;first@x\\u000Abroken\\u000A",
|
||||
{
|
||||
"email" : "first@x",
|
||||
"name" : "F L",
|
||||
"password" : "p",
|
||||
"pop3Host" : "a",
|
||||
"pop3Port" : 110,
|
||||
"smtpHost" : "a",
|
||||
"smtpPort" : 25,
|
||||
"username" : "first"
|
||||
}
|
||||
],
|
||||
[
|
||||
"",
|
||||
"!invalidAccount(\"missing client account\")"
|
||||
],
|
||||
[
|
||||
"\\u000A",
|
||||
"!invalidAccount(\"missing client account\")"
|
||||
],
|
||||
[
|
||||
"\\u000A\\u000A\\u000A",
|
||||
"!invalidAccount(\"missing client account\")"
|
||||
],
|
||||
[
|
||||
"a;b;110;25;u;p;L;F;\\u000A",
|
||||
"!invalidAddress(\"\")"
|
||||
],
|
||||
[
|
||||
"a;b;110;25;u;p;L;F;u@x;extra\\u000A",
|
||||
"!invalidAccount(\"malformed client account\")"
|
||||
],
|
||||
[
|
||||
"a;b;110;25;u;p;L;F;u@x\\u000D\\u000A",
|
||||
{
|
||||
"email" : "u@x",
|
||||
"name" : "F L",
|
||||
"password" : "p",
|
||||
"pop3Host" : "a",
|
||||
"pop3Port" : 110,
|
||||
"smtpHost" : "b",
|
||||
"smtpPort" : 25,
|
||||
"username" : "u"
|
||||
}
|
||||
],
|
||||
[
|
||||
"a;;110;25;u;p;;;u@x\\u000A",
|
||||
"!invalidHost(\"\")"
|
||||
],
|
||||
[
|
||||
"a;b;110;25;u;p;L;F;u@x\\u000A\\u000A\\u000A",
|
||||
{
|
||||
"email" : "u@x",
|
||||
"name" : "F L",
|
||||
"password" : "p",
|
||||
"pop3Host" : "a",
|
||||
"pop3Port" : 110,
|
||||
"smtpHost" : "b",
|
||||
"smtpPort" : 25,
|
||||
"username" : "u"
|
||||
}
|
||||
],
|
||||
[
|
||||
"\\u000Aa;b;110;25;u;p;L;F;u@x",
|
||||
{
|
||||
"email" : "u@x",
|
||||
"name" : "F L",
|
||||
"password" : "p",
|
||||
"pop3Host" : "a",
|
||||
"pop3Port" : 110,
|
||||
"smtpHost" : "b",
|
||||
"smtpPort" : 25,
|
||||
"username" : "u"
|
||||
}
|
||||
],
|
||||
[
|
||||
" a ; b ;x;y; u ; p ; L ; F ; u@x \\u000A",
|
||||
"!invalidAccount(\"malformed client account\")"
|
||||
],
|
||||
[
|
||||
";;;;;;;;",
|
||||
"!invalidAccount(\"malformed client account\")"
|
||||
],
|
||||
[
|
||||
";;;;;;;;x",
|
||||
"!invalidAccount(\"malformed client account\")"
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,584 @@
|
||||
[
|
||||
[
|
||||
"bob;filius.de;bob;Nachname;Vorname;\\u000A",
|
||||
[
|
||||
{
|
||||
"mailbox" : [
|
||||
|
||||
],
|
||||
"name" : "Vorname Nachname",
|
||||
"password" : "bob",
|
||||
"username" : "bob"
|
||||
}
|
||||
]
|
||||
],
|
||||
[
|
||||
"bob;filius.de;bob;Nachname;Vorname;\\u000Aalice;filius.de;alice;A;B;\\u000A",
|
||||
[
|
||||
{
|
||||
"mailbox" : [
|
||||
|
||||
],
|
||||
"name" : "Vorname Nachname",
|
||||
"password" : "bob",
|
||||
"username" : "bob"
|
||||
},
|
||||
{
|
||||
"mailbox" : [
|
||||
|
||||
],
|
||||
"name" : "B A",
|
||||
"password" : "alice",
|
||||
"username" : "alice"
|
||||
}
|
||||
]
|
||||
],
|
||||
[
|
||||
"bob;filius.de;bob;Nachname;Vorname",
|
||||
"!invalidAccount(\"malformed server account\")"
|
||||
],
|
||||
[
|
||||
"bob;;bob;Nachname;Vorname;\\u000A",
|
||||
"!invalidDomain(\"\")"
|
||||
],
|
||||
[
|
||||
"bob;filius.de;bob;Nachname\\u000A",
|
||||
"!invalidAccount(\"malformed server account\")"
|
||||
],
|
||||
[
|
||||
"bob;filius.de;bob;Nachname;Vorname;\\u000Abroken\\u000A",
|
||||
"!invalidAccount(\"malformed server account\")"
|
||||
],
|
||||
[
|
||||
" bob ;filius.de; bob ;Nachname;Vorname;\\u000A",
|
||||
"!invalidAccount(\" bob \")"
|
||||
],
|
||||
[
|
||||
"bob;filius.de;bob;Nachname;Vorname\\u000D\\u000A",
|
||||
"!invalidAccount(\"malformed server account\")"
|
||||
],
|
||||
[
|
||||
"",
|
||||
[
|
||||
|
||||
]
|
||||
],
|
||||
[
|
||||
"\\u000A\\u000A",
|
||||
[
|
||||
|
||||
]
|
||||
],
|
||||
[
|
||||
"bob;filius.de;bob;Nachname;Vorname;#Alice <alice@senior.de>$bob@filius.de$$$$Hi Bob!$Hi BoB!|\\u000A",
|
||||
[
|
||||
{
|
||||
"mailbox" : [
|
||||
{
|
||||
"bcc" : [
|
||||
|
||||
],
|
||||
"body" : "Hi BoB!\n",
|
||||
"cc" : [
|
||||
|
||||
],
|
||||
"deliveryIdentity" : null,
|
||||
"from" : [
|
||||
"Alice",
|
||||
"alice@senior.de"
|
||||
],
|
||||
"id" : 1,
|
||||
"isMarkedForDeletion" : false,
|
||||
"isNew" : true,
|
||||
"isSent" : false,
|
||||
"receivedAtMilliseconds" : 1,
|
||||
"subject" : "Hi Bob!",
|
||||
"to" : [
|
||||
[
|
||||
null,
|
||||
"bob@filius.de"
|
||||
]
|
||||
]
|
||||
}
|
||||
],
|
||||
"name" : "Vorname Nachname",
|
||||
"password" : "bob",
|
||||
"username" : "bob"
|
||||
}
|
||||
]
|
||||
],
|
||||
[
|
||||
"bob;filius.de;bob;Nachname;Vorname;#Alice <alice@senior.de>$bob@filius.de$$$$Hi Bob!$Hi BoB!|#Alice <alice@senior.de>$bob@filius.de$$$$Hi Bob!$Hi BoB!|\\u000A",
|
||||
[
|
||||
{
|
||||
"mailbox" : [
|
||||
{
|
||||
"bcc" : [
|
||||
|
||||
],
|
||||
"body" : "Hi BoB!\n",
|
||||
"cc" : [
|
||||
|
||||
],
|
||||
"deliveryIdentity" : null,
|
||||
"from" : [
|
||||
"Alice",
|
||||
"alice@senior.de"
|
||||
],
|
||||
"id" : 1,
|
||||
"isMarkedForDeletion" : false,
|
||||
"isNew" : true,
|
||||
"isSent" : false,
|
||||
"receivedAtMilliseconds" : 1,
|
||||
"subject" : "Hi Bob!",
|
||||
"to" : [
|
||||
[
|
||||
null,
|
||||
"bob@filius.de"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"bcc" : [
|
||||
|
||||
],
|
||||
"body" : "Hi BoB!\n",
|
||||
"cc" : [
|
||||
|
||||
],
|
||||
"deliveryIdentity" : null,
|
||||
"from" : [
|
||||
"Alice",
|
||||
"alice@senior.de"
|
||||
],
|
||||
"id" : 2,
|
||||
"isMarkedForDeletion" : false,
|
||||
"isNew" : true,
|
||||
"isSent" : false,
|
||||
"receivedAtMilliseconds" : 2,
|
||||
"subject" : "Hi Bob!",
|
||||
"to" : [
|
||||
[
|
||||
null,
|
||||
"bob@filius.de"
|
||||
]
|
||||
]
|
||||
}
|
||||
],
|
||||
"name" : "Vorname Nachname",
|
||||
"password" : "bob",
|
||||
"username" : "bob"
|
||||
}
|
||||
]
|
||||
],
|
||||
[
|
||||
"bob;filius.de;bob;Nachname;Vorname;Alice <alice@senior.de>$bob@filius.de$$$$Hi$Text\\u000A",
|
||||
[
|
||||
{
|
||||
"mailbox" : [
|
||||
{
|
||||
"bcc" : [
|
||||
|
||||
],
|
||||
"body" : "Text",
|
||||
"cc" : [
|
||||
|
||||
],
|
||||
"deliveryIdentity" : null,
|
||||
"from" : [
|
||||
"Alice",
|
||||
"alice@senior.de"
|
||||
],
|
||||
"id" : 1,
|
||||
"isMarkedForDeletion" : false,
|
||||
"isNew" : true,
|
||||
"isSent" : false,
|
||||
"receivedAtMilliseconds" : 1,
|
||||
"subject" : "Hi",
|
||||
"to" : [
|
||||
[
|
||||
null,
|
||||
"bob@filius.de"
|
||||
]
|
||||
]
|
||||
}
|
||||
],
|
||||
"name" : "Vorname Nachname",
|
||||
"password" : "bob",
|
||||
"username" : "bob"
|
||||
}
|
||||
]
|
||||
],
|
||||
[
|
||||
"bob;filius.de;bob;Nachname;Vorname;#Alice <alice@senior.de>$bob@filius.de$$$$Hi$\\u000A",
|
||||
[
|
||||
{
|
||||
"mailbox" : [
|
||||
{
|
||||
"bcc" : [
|
||||
|
||||
],
|
||||
"body" : "",
|
||||
"cc" : [
|
||||
|
||||
],
|
||||
"deliveryIdentity" : null,
|
||||
"from" : [
|
||||
"Alice",
|
||||
"alice@senior.de"
|
||||
],
|
||||
"id" : 1,
|
||||
"isMarkedForDeletion" : false,
|
||||
"isNew" : true,
|
||||
"isSent" : false,
|
||||
"receivedAtMilliseconds" : 1,
|
||||
"subject" : "Hi",
|
||||
"to" : [
|
||||
[
|
||||
null,
|
||||
"bob@filius.de"
|
||||
]
|
||||
]
|
||||
}
|
||||
],
|
||||
"name" : "Vorname Nachname",
|
||||
"password" : "bob",
|
||||
"username" : "bob"
|
||||
}
|
||||
]
|
||||
],
|
||||
[
|
||||
"bob;filius.de;bob;Nachname;Vorname;#Alice <alice@senior.de>$bob@filius.de$$$$$\\u000A",
|
||||
[
|
||||
{
|
||||
"mailbox" : [
|
||||
{
|
||||
"bcc" : [
|
||||
|
||||
],
|
||||
"body" : "",
|
||||
"cc" : [
|
||||
|
||||
],
|
||||
"deliveryIdentity" : null,
|
||||
"from" : [
|
||||
"Alice",
|
||||
"alice@senior.de"
|
||||
],
|
||||
"id" : 1,
|
||||
"isMarkedForDeletion" : false,
|
||||
"isNew" : true,
|
||||
"isSent" : false,
|
||||
"receivedAtMilliseconds" : 1,
|
||||
"subject" : "",
|
||||
"to" : [
|
||||
[
|
||||
null,
|
||||
"bob@filius.de"
|
||||
]
|
||||
]
|
||||
}
|
||||
],
|
||||
"name" : "Vorname Nachname",
|
||||
"password" : "bob",
|
||||
"username" : "bob"
|
||||
}
|
||||
]
|
||||
],
|
||||
[
|
||||
"bob;filius.de;bob;Nachname;Vorname;#Alice <alice@senior.de>$bob@filius.de$$$$Hi $5$Text\\u000A",
|
||||
"!malformedMessage"
|
||||
],
|
||||
[
|
||||
"bob;filius.de;bob;Nachname;Vorname;#a@x$b@y$c@z$d@w$1234$Hi$Text\\u000A",
|
||||
[
|
||||
{
|
||||
"mailbox" : [
|
||||
{
|
||||
"bcc" : [
|
||||
[
|
||||
null,
|
||||
"d@w"
|
||||
]
|
||||
],
|
||||
"body" : "Text",
|
||||
"cc" : [
|
||||
[
|
||||
null,
|
||||
"c@z"
|
||||
]
|
||||
],
|
||||
"deliveryIdentity" : null,
|
||||
"from" : [
|
||||
null,
|
||||
"a@x"
|
||||
],
|
||||
"id" : 1,
|
||||
"isMarkedForDeletion" : false,
|
||||
"isNew" : true,
|
||||
"isSent" : false,
|
||||
"receivedAtMilliseconds" : 1234,
|
||||
"subject" : "Hi",
|
||||
"to" : [
|
||||
[
|
||||
null,
|
||||
"b@y"
|
||||
]
|
||||
]
|
||||
}
|
||||
],
|
||||
"name" : "Vorname Nachname",
|
||||
"password" : "bob",
|
||||
"username" : "bob"
|
||||
}
|
||||
]
|
||||
],
|
||||
[
|
||||
"bob;filius.de;bob;Nachname;Vorname;#a@x$b@y, ,c@z,$$$$Hi$Text\\u000A",
|
||||
"!malformedMessage"
|
||||
],
|
||||
[
|
||||
"bob;filius.de;bob;Nachname;Vorname;#Name <a@x$b@y$$$$Hi$Text\\u000A",
|
||||
"!malformedMessage"
|
||||
],
|
||||
[
|
||||
"bob;filius.de;bob;Nachname;Vorname;#<a@x>$Bob <b@y> , <c@z>$$$$Hi$Text\\u000A",
|
||||
[
|
||||
{
|
||||
"mailbox" : [
|
||||
{
|
||||
"bcc" : [
|
||||
|
||||
],
|
||||
"body" : "Text",
|
||||
"cc" : [
|
||||
|
||||
],
|
||||
"deliveryIdentity" : null,
|
||||
"from" : [
|
||||
null,
|
||||
"a@x"
|
||||
],
|
||||
"id" : 1,
|
||||
"isMarkedForDeletion" : false,
|
||||
"isNew" : true,
|
||||
"isSent" : false,
|
||||
"receivedAtMilliseconds" : 1,
|
||||
"subject" : "Hi",
|
||||
"to" : [
|
||||
[
|
||||
"Bob",
|
||||
"b@y"
|
||||
],
|
||||
[
|
||||
null,
|
||||
"c@z"
|
||||
]
|
||||
]
|
||||
}
|
||||
],
|
||||
"name" : "Vorname Nachname",
|
||||
"password" : "bob",
|
||||
"username" : "bob"
|
||||
}
|
||||
]
|
||||
],
|
||||
[
|
||||
"bob;filius.de;bob;Nachname;Vorname;#Only Name$b@y$$$$Hi$Text\\u000A",
|
||||
"!malformedMessage"
|
||||
],
|
||||
[
|
||||
"bob;filius.de;bob;Nachname;Vorname;#a@x$b@y$$$$Hi$l1||l2&&00124&&x&&00036&&y&&00059&&z&&00035&&w\\u000A",
|
||||
[
|
||||
{
|
||||
"mailbox" : [
|
||||
{
|
||||
"bcc" : [
|
||||
|
||||
],
|
||||
"body" : "l1\n\nl2|x$y;z#w",
|
||||
"cc" : [
|
||||
|
||||
],
|
||||
"deliveryIdentity" : null,
|
||||
"from" : [
|
||||
null,
|
||||
"a@x"
|
||||
],
|
||||
"id" : 1,
|
||||
"isMarkedForDeletion" : false,
|
||||
"isNew" : true,
|
||||
"isSent" : false,
|
||||
"receivedAtMilliseconds" : 1,
|
||||
"subject" : "Hi",
|
||||
"to" : [
|
||||
[
|
||||
null,
|
||||
"b@y"
|
||||
]
|
||||
]
|
||||
}
|
||||
],
|
||||
"name" : "Vorname Nachname",
|
||||
"password" : "bob",
|
||||
"username" : "bob"
|
||||
}
|
||||
]
|
||||
],
|
||||
[
|
||||
"bob;filius.de;bob;Nachname;Vorname;#a@x$b@y$$$$Hi$&&00124&&|\\u000A",
|
||||
[
|
||||
{
|
||||
"mailbox" : [
|
||||
{
|
||||
"bcc" : [
|
||||
|
||||
],
|
||||
"body" : "|\n",
|
||||
"cc" : [
|
||||
|
||||
],
|
||||
"deliveryIdentity" : null,
|
||||
"from" : [
|
||||
null,
|
||||
"a@x"
|
||||
],
|
||||
"id" : 1,
|
||||
"isMarkedForDeletion" : false,
|
||||
"isNew" : true,
|
||||
"isSent" : false,
|
||||
"receivedAtMilliseconds" : 1,
|
||||
"subject" : "Hi",
|
||||
"to" : [
|
||||
[
|
||||
null,
|
||||
"b@y"
|
||||
]
|
||||
]
|
||||
}
|
||||
],
|
||||
"name" : "Vorname Nachname",
|
||||
"password" : "bob",
|
||||
"username" : "bob"
|
||||
}
|
||||
]
|
||||
],
|
||||
[
|
||||
"bob;filius.de;bob;Nachname;Vorname;#a@x$b@y$$$$Hi$Text;extra\\u000A",
|
||||
[
|
||||
{
|
||||
"mailbox" : [
|
||||
{
|
||||
"bcc" : [
|
||||
|
||||
],
|
||||
"body" : "Text;extra",
|
||||
"cc" : [
|
||||
|
||||
],
|
||||
"deliveryIdentity" : null,
|
||||
"from" : [
|
||||
null,
|
||||
"a@x"
|
||||
],
|
||||
"id" : 1,
|
||||
"isMarkedForDeletion" : false,
|
||||
"isNew" : true,
|
||||
"isSent" : false,
|
||||
"receivedAtMilliseconds" : 1,
|
||||
"subject" : "Hi",
|
||||
"to" : [
|
||||
[
|
||||
null,
|
||||
"b@y"
|
||||
]
|
||||
]
|
||||
}
|
||||
],
|
||||
"name" : "Vorname Nachname",
|
||||
"password" : "bob",
|
||||
"username" : "bob"
|
||||
}
|
||||
]
|
||||
],
|
||||
[
|
||||
"bob;filius.de;bob;Nachname;Vorname;##a@x$b@y$$$$Hi$Text##\\u000A",
|
||||
[
|
||||
{
|
||||
"mailbox" : [
|
||||
{
|
||||
"bcc" : [
|
||||
|
||||
],
|
||||
"body" : "Text",
|
||||
"cc" : [
|
||||
|
||||
],
|
||||
"deliveryIdentity" : null,
|
||||
"from" : [
|
||||
null,
|
||||
"a@x"
|
||||
],
|
||||
"id" : 1,
|
||||
"isMarkedForDeletion" : false,
|
||||
"isNew" : true,
|
||||
"isSent" : false,
|
||||
"receivedAtMilliseconds" : 1,
|
||||
"subject" : "Hi",
|
||||
"to" : [
|
||||
[
|
||||
null,
|
||||
"b@y"
|
||||
]
|
||||
]
|
||||
}
|
||||
],
|
||||
"name" : "Vorname Nachname",
|
||||
"password" : "bob",
|
||||
"username" : "bob"
|
||||
}
|
||||
]
|
||||
],
|
||||
[
|
||||
"bob;filius.de;bob;Nachname;Vorname;#a@x$b@y$$$$Hi$Text\\u000D\\u000A",
|
||||
[
|
||||
{
|
||||
"mailbox" : [
|
||||
{
|
||||
"bcc" : [
|
||||
|
||||
],
|
||||
"body" : "Text",
|
||||
"cc" : [
|
||||
|
||||
],
|
||||
"deliveryIdentity" : null,
|
||||
"from" : [
|
||||
null,
|
||||
"a@x"
|
||||
],
|
||||
"id" : 1,
|
||||
"isMarkedForDeletion" : false,
|
||||
"isNew" : true,
|
||||
"isSent" : false,
|
||||
"receivedAtMilliseconds" : 1,
|
||||
"subject" : "Hi",
|
||||
"to" : [
|
||||
[
|
||||
null,
|
||||
"b@y"
|
||||
]
|
||||
]
|
||||
}
|
||||
],
|
||||
"name" : "Vorname Nachname",
|
||||
"password" : "bob",
|
||||
"username" : "bob"
|
||||
}
|
||||
]
|
||||
],
|
||||
[
|
||||
"bob;filius.de;bob;Nachname;Vorname;#\\u001Fa@x $b@y$$$$Hi$Text\\u000A",
|
||||
"!malformedMessage"
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,157 @@
|
||||
// The e-mail account files as the model takes them, against Swift's reader
|
||||
// (TopologyRuntimeEmailStorage.decodeJavaServer/decodeJavaClient,
|
||||
// email-*.swift.json, tools/swift-oracle --email-files) on the cases Java
|
||||
// read too (javaEmail.test.ts). Swift checks names, hosts and addresses and
|
||||
// fails the whole file on one it rejects, where Java reads it; each such
|
||||
// case is named with its reason and must really depart.
|
||||
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { dirname, join } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import type { EmailAddress, EmailMessage } from '@mdg-filius/core';
|
||||
import { emailClientConfiguration, emailServerConfiguration } from '../src/importEmail.js';
|
||||
import { readEmailClientFile, readEmailServerFile } from '../src/javaEmail.js';
|
||||
import type { FlsApplication } from '../src/index.js';
|
||||
|
||||
const here = dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
/** The cases file's escapes: a backslash, `u` and four hex digits for one UTF-16 unit. */
|
||||
function unescape(line: string): string {
|
||||
return line.replace(/\\u([0-9a-fA-F]{4})/g, (_, hex: string) => String.fromCharCode(Number.parseInt(hex, 16)));
|
||||
}
|
||||
|
||||
const fullName = (person: { firstName: string; lastName: string }) =>
|
||||
[person.firstName, person.lastName].filter((part) => part !== '').join(' ');
|
||||
|
||||
function swiftMessage(message: EmailMessage) {
|
||||
const address = (entry: EmailAddress) => [entry.name, entry.mailAddress];
|
||||
return {
|
||||
id: message.id,
|
||||
from: address(message.from),
|
||||
to: message.to.map(address),
|
||||
cc: message.cc.map(address),
|
||||
bcc: message.bcc.map(address),
|
||||
subject: message.subject,
|
||||
body: message.body,
|
||||
deliveryIdentity: null,
|
||||
receivedAtMilliseconds: message.receivedAtMilliseconds ?? null,
|
||||
isNew: message.isNew,
|
||||
isMarkedForDeletion: message.isMarkedForDeletion,
|
||||
isSent: message.isSent,
|
||||
};
|
||||
}
|
||||
|
||||
function serverAccounts(content: string) {
|
||||
const application = { fileAccounts: readEmailServerFile(content, () => {}), mailDomain: 'filius.de' } as FlsApplication;
|
||||
return emailServerConfiguration(application, () => {}).accounts.map((account) => ({
|
||||
username: account.username,
|
||||
password: account.password,
|
||||
name: fullName(account),
|
||||
mailbox: account.mailbox.map(swiftMessage),
|
||||
}));
|
||||
}
|
||||
|
||||
function clientAccount(content: string) {
|
||||
const application = { fileAccount: readEmailClientFile(content, () => {}) } as FlsApplication;
|
||||
const account = emailClientConfiguration(application, () => {}).account;
|
||||
if (account === null) return null;
|
||||
const { firstName, lastName, ...fields } = account;
|
||||
return { ...fields, name: fullName({ firstName, lastName }) };
|
||||
}
|
||||
|
||||
type Departures = { reason: string; lines: string[] }[];
|
||||
|
||||
/**
|
||||
* Swift's result where it means the same as ours: Swift numbers a mailbox's
|
||||
* messages as their received time (a Swift error named in
|
||||
* importProject.test.ts), and "no account" is an error to Swift.
|
||||
*/
|
||||
function comparable(expected: unknown): unknown {
|
||||
if (expected === '!invalidAccount("missing client account")') return null;
|
||||
if (!Array.isArray(expected)) return expected;
|
||||
return expected.map((account: { mailbox: { id: number; receivedAtMilliseconds: number | null }[] }) => ({
|
||||
...account,
|
||||
mailbox: account.mailbox.map((message) =>
|
||||
message.receivedAtMilliseconds === message.id ? { ...message, receivedAtMilliseconds: null } : message,
|
||||
),
|
||||
}));
|
||||
}
|
||||
|
||||
function compareWithSwift(kind: 'server' | 'client', departures: Departures, read: (content: string) => unknown) {
|
||||
const cases = JSON.parse(readFileSync(join(here, `email-${kind}.swift.json`), 'utf8')) as [string, unknown][];
|
||||
const lines = readFileSync(join(here, `email-${kind}.cases.txt`), 'ascii').split('\n').slice(0, -1);
|
||||
const byLine = new Map(departures.flatMap(({ reason, lines: named }) => named.map((line) => [line, reason] as const)));
|
||||
it('covers every line of the cases file and names only its lines', () => {
|
||||
expect(cases.map(([line]) => line)).toEqual(lines);
|
||||
expect([...byLine.keys()].filter((line) => !lines.includes(line))).toEqual([]);
|
||||
});
|
||||
for (const [line, expected] of cases) {
|
||||
const reason = byLine.get(line);
|
||||
it(reason === undefined ? JSON.stringify(line) : `${JSON.stringify(line)} (departs: ${reason})`, () => {
|
||||
if (reason === undefined) expect(read(unescape(line))).toEqual(comparable(expected));
|
||||
else expect(read(unescape(line))).not.toEqual(comparable(expected));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const SERVER_DEPARTURES: Departures = [
|
||||
{
|
||||
reason: 'a line without the messages field is an account, as in Java; Swift wants the sixth field and fails the file',
|
||||
lines: [String.raw`bob;filius.de;bob;Nachname;Vorname`, String.raw`bob;filius.de;bob;Nachname;Vorname\u000D\u000A`],
|
||||
},
|
||||
{
|
||||
reason: "the file's domain column is not used (Java takes the server's); Swift fails the file on an empty one",
|
||||
lines: [String.raw`bob;;bob;Nachname;Vorname;\u000A`],
|
||||
},
|
||||
{
|
||||
reason: 'a short line alone is left out; Swift fails the whole file',
|
||||
lines: [String.raw`bob;filius.de;bob;Nachname\u000A`, String.raw`bob;filius.de;bob;Nachname;Vorname;\u000Abroken\u000A`],
|
||||
},
|
||||
{
|
||||
reason: 'a user name stays as Java reads it; Swift rejects one with spaces and fails the file',
|
||||
lines: [String.raw` bob ;filius.de; bob ;Nachname;Vorname;\u000A`],
|
||||
},
|
||||
{
|
||||
reason: 'a message without seven fields alone is left out; Swift fails the whole file',
|
||||
lines: [String.raw`bob;filius.de;bob;Nachname;Vorname;#Alice <alice@senior.de>$bob@filius.de$$$$Hi $5$Text\u000A`],
|
||||
},
|
||||
{
|
||||
reason: "addresses as Java reads them (blank entries skipped, a name alone, Java's trim); Swift fails the file",
|
||||
lines: [
|
||||
String.raw`bob;filius.de;bob;Nachname;Vorname;#a@x$b@y, ,c@z,$$$$Hi$Text\u000A`,
|
||||
String.raw`bob;filius.de;bob;Nachname;Vorname;#Name <a@x$b@y$$$$Hi$Text\u000A`,
|
||||
String.raw`bob;filius.de;bob;Nachname;Vorname;#Only Name$b@y$$$$Hi$Text\u000A`,
|
||||
String.raw`bob;filius.de;bob;Nachname;Vorname;#\u001Fa@x $b@y$$$$Hi$Text\u000A`,
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const CLIENT_DEPARTURES: Departures = [
|
||||
{
|
||||
reason: 'the last complete line is the account, as in Java; Swift takes the first',
|
||||
lines: [String.raw`a;a;110;25;first;p;L;F;first@x\u000Ab;b;110;25;second;p;L;F;second@x\u000A`],
|
||||
},
|
||||
{
|
||||
reason: 'further fields are ignored, as in Java; Swift wants exactly nine',
|
||||
lines: [String.raw`a;b;110;25;u;p;L;F;u@x;extra\u000A`],
|
||||
},
|
||||
{
|
||||
reason: 'an account stays as Java reads it (a port that is no number is the default); Swift checks hosts, ports and the address and has none',
|
||||
lines: [
|
||||
String.raw`a;b;110;25;u;p;L;F;\u000A`,
|
||||
String.raw`a;;110;25;u;p;;;u@x\u000A`,
|
||||
String.raw` a ; b ;x;y; u ; p ; L ; F ; u@x \u000A`,
|
||||
String.raw`;;;;;;;;`,
|
||||
String.raw`;;;;;;;;x`,
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
describe('the server account file against Swift', () => {
|
||||
compareWithSwift('server', SERVER_DEPARTURES, serverAccounts);
|
||||
});
|
||||
|
||||
describe('the client account file against Swift', () => {
|
||||
compareWithSwift('client', CLIENT_DEPARTURES, clientAccount);
|
||||
});
|
||||
Reference in New Issue
Block a user