Spaces:
Sleeping
Sleeping
| var test = require("tap").test; | |
| var addrs = require("../lib/email-addresses"); | |
| test("simple one address function", function (t) { | |
| var fxn, result; | |
| fxn = addrs.parseOneAddress; | |
| result = fxn("ABC < a@b.c>") || {}; | |
| t.notOk(result.node, "has no ast information"); | |
| t.equal(result.address, "a@b.c", "full address, semantic only"); | |
| t.equal(result.name, "ABC", "display name"); | |
| t.equal(result.local, "a", "local part"); | |
| t.equal(result.domain, "b.c", "domain"); | |
| t.equal(fxn("bogus"), null, "bogus address > null"); | |
| t.equal(fxn("a@b.c, d@e.f"), null, "address list > null"); | |
| result = fxn("\"Françoise Lefèvre\"@example.com"); | |
| t.ok(result, "RFC 6532 (Unicode support) is enabled by default"); | |
| t.equal(result.parts.local.semantic, "Françoise Lefèvre"); | |
| result = fxn("First Last <first@last.com>"); | |
| t.equal(result.name, "First Last", | |
| "whitespace is not removed from display names without quotes"); | |
| result = fxn(" First Last <first@last.com>"); | |
| t.equal(result.name, "First Last", | |
| "whitespace in names is collapsed"); | |
| t.end(); | |
| }); | |
| test("address with @ in the name", function (t) { | |
| var fxn, result; | |
| fxn = addrs.parseOneAddress; | |
| result = fxn({input: "ABC@abc (comment) < a@b.c>", atInDisplayName: true }) || {}; | |
| t.equal(result.name, "ABC@abc", "display name"); | |
| t.end(); | |
| }); | |
| test("address with comma in the display name", function (t) { | |
| var fxn, result; | |
| fxn = addrs.parseOneAddress; | |
| result = fxn({input: "ABC, abc (comment) <a@b.c>", commaInDisplayName: true }) || {}; | |
| t.equal(result.name, "ABC, abc", "display name"); | |
| result = fxn({input: "ABC, abc (comment) <a@b.c>", commaInDisplayName: false }) || {}; | |
| t.equal(result.name, undefined); | |
| t.end(); | |
| }); | |
| test("address with comments", function (t) { | |
| var fxn, result; | |
| fxn = addrs.parseOneAddress; | |
| result = fxn("ABC (comment) < a@b.c>" ) || {}; | |
| t.equal(result.name, "ABC", "display name"); | |
| t.equal(result.comments, '(comment)'); | |
| t.end(); | |
| }); | |
| test("simple address list function", function (t) { | |
| var fxn, result; | |
| fxn = addrs.parseAddressList; | |
| result = fxn("\"A B C\" < a@b.c>, d@e") || [{}, {}]; | |
| t.notOk(result[0].node, "has no ast information"); | |
| t.equal(result[0].address, "a@b.c", "full address, semantic only"); | |
| t.equal(result[0].name, "A B C", "display name"); | |
| t.equal(result[0].local, "a", "local part"); | |
| t.equal(result[0].domain, "b.c", "domain"); | |
| t.notOk(result[1].node, "has no ast information"); | |
| t.equal(result[1].address, "d@e", "second address"); | |
| t.equal(result[1].name, null, "second display name"); | |
| t.equal(result[1].local, "d", "second local part"); | |
| t.equal(result[1].domain, "e", "second domain"); | |
| t.equal(fxn("bogus"), null, "bogus address > null"); | |
| t.equal(fxn("a@b.c").length, 1, "single address > ok"); | |
| result = fxn("\"Françoise Lefèvre\"@example.com"); | |
| t.ok(result, "RFC 6532 (Unicode support) is enabled by default"); | |
| t.end(); | |
| }); | |
| test("simple address list function with user-specified list separator", function (t) { | |
| var fxn, result; | |
| fxn = addrs.parseAddressList; | |
| result = fxn({ input: "\"A B C\" < a@b.c>; d@e", addressListSeparator: ";" }) || [{}, {}]; | |
| t.notOk(result[0].node, "has no ast information"); | |
| t.equal(result[0].address, "a@b.c", "full address, semantic only"); | |
| t.equal(result[0].name, "A B C", "display name"); | |
| t.equal(result[0].local, "a", "local part"); | |
| t.equal(result[0].domain, "b.c", "domain"); | |
| t.notOk(result[1].node, "has no ast information"); | |
| t.equal(result[1].address, "d@e", "second address"); | |
| t.equal(result[1].name, null, "second display name"); | |
| t.equal(result[1].local, "d", "second local part"); | |
| t.equal(result[1].domain, "e", "second domain"); | |
| t.end(); | |
| }); | |
| test("rfc5322 parser", function (t) { | |
| var fxn, result; | |
| fxn = addrs; | |
| result = fxn("\"A B C\" < a@b.c>, d@e") || {}; | |
| t.ok(result.ast, "has an ast"); | |
| t.ok(result.addresses.length, "has the addresses"); | |
| result = result.addresses; | |
| t.ok(result[0].node, "has link to node in ast"); | |
| t.equal(result[0].address, "a@b.c", "full address, semantic only"); | |
| t.equal(result[0].name, "A B C", "display name"); | |
| t.equal(result[0].local, "a", "local part"); | |
| t.equal(result[0].domain, "b.c", "domain"); | |
| t.ok(result[1].node, "has link to node in ast"); | |
| t.equal(result[1].address, "d@e", "second address"); | |
| t.equal(result[1].name, null, "second display name"); | |
| t.equal(result[1].local, "d", "second local part"); | |
| t.equal(result[1].domain, "e", "second domain"); | |
| t.equal(fxn("bogus"), null, "bogus address > null"); | |
| t.equal(fxn("a@b bogus"), null, "not all input is an email list > null"); | |
| result = fxn({ input: "a@b bogus", partial: true }); | |
| t.ok(result, "can obtain partial results if at beginning of string"); | |
| result = fxn("\"Françoise Lefèvre\"@example.com"); | |
| t.notOk(result, "extended ascii characters are invalid according to RFC 5322"); | |
| result = fxn({ input: "\"Françoise Lefèvre\"@example.com", rfc6532: true }); | |
| t.ok(result, "but extended ascii is allowed starting with RFC 6532"); | |
| t.end(); | |
| }); | |
| test("display-name semantic interpretation", function (t) { | |
| var fxn, result; | |
| fxn = addrs.parseOneAddress; | |
| function check(s, comment, expected) { | |
| t.equal(fxn(s).name, expected || "First Last", comment); | |
| } | |
| check( | |
| "First<foo@bar.com>", | |
| "single basic name is ok", | |
| "First"); | |
| check( | |
| "First Last<foo@bar.com>", | |
| "no extra whitespace is ok"); | |
| check( | |
| " First Last <foo@bar.com>", | |
| "single whitespace at beginning and end is removed"); | |
| check( | |
| "First Last<foo@bar.com>", | |
| "whitespace in the middle is collapsed"); | |
| check( | |
| " First Last <foo@bar.com>", | |
| "extra whitespace everywhere is collapsed"); | |
| check( | |
| " First Middle Last <foo@bar.com>", | |
| "extra whitespace everywhere is collapsed, with more than 2 names", | |
| "First Middle Last"); | |
| check( | |
| "\tFirst \t Last\t<foo@bar.com>", | |
| "extra whitespace everywhere is collapsed with a mix of tabs and spaces"); | |
| check( | |
| "\"First Last\"<foo@bar.com>", | |
| "surrounding quotes are not semantic"); | |
| check( | |
| " \t \"First Last\" <foo@bar.com>", | |
| "surrounding quotes are not semantic and whitespace is collapsed"); | |
| check( | |
| " \t \"First \\\"The\t\tNickname\\\" Last\" <foo@bar.com>", | |
| "surrounding quotes are not semantic, but inner quotes are, and whitespace is collapsed", | |
| "First \"The Nickname\" Last"); | |
| t.end(); | |
| }); | |
| test("address semantic interpretation", function (t) { | |
| var fxn, result; | |
| fxn = addrs.parseOneAddress; | |
| function check(s, comment, expected) { | |
| t.equal(fxn(s).address, expected || "foo@bar.com", comment); | |
| } | |
| check( | |
| "foo@bar.com", | |
| "plain address is ok"); | |
| check( | |
| " foo@bar.com ", | |
| "plain address with whitespace at beginning and end"); | |
| check( | |
| "foo @bar.com", | |
| "plain address with whitespace left of @ sign"); | |
| check( | |
| "foo@ bar.com", | |
| "plain address with whitespace right of @ sign"); | |
| // Technically, we should also be able to handle removing CFWS in | |
| // a dot-atom (or more importantly, obs-domain), but I don't think anyone cares. | |
| check( | |
| "\t foo\t\t@ \t bar.com \t ", | |
| "plain address with whitespace everywhere"); | |
| check( | |
| "Bob <\t foo\t\t@ \t bar.com \t >", | |
| "angle-addr with whitespace everywhere"); | |
| check( | |
| "\"foo\"@bar.com", | |
| "plain address with quoted-string local-part"); | |
| check( | |
| "\"foo baz\"@bar.com", | |
| "plain address with quoted-string local-part including spaces" + | |
| " (Note: This is a confusing situation for 'semantic' local-parts, and" + | |
| " in this case we don't return a valid address. Don't use this. Just" + | |
| " take the raw tokens used for the address if you always want it to be equivalent.)", | |
| "foo baz@bar.com"); | |
| t.end(); | |
| }); | |
| test("unicode support", function (t) { | |
| var fxn, result; | |
| fxn = addrs.parseOneAddress; | |
| result = fxn("\"Françoise Lefèvre\"@example.com"); | |
| t.ok(result, "extended ascii characters are allowed"); | |
| result = fxn("杨孝宇 <xiaoyu@example.com>"); | |
| t.ok(result, "unicode support includes chinese characters (display-name, no quoted string)"); | |
| result = fxn("\"杨孝宇\" <xiaoyu@example.com>"); | |
| t.ok(result, "unicode support includes chinese characters (display-name, quoted-string)"); | |
| t.end(); | |
| }); | |
| test("rejectTLD option", function (t) { | |
| var fxn, result; | |
| fxn = addrs.parseOneAddress; | |
| result = fxn({ input: "foo@bar.com", rejectTLD: false }); | |
| t.ok(result, "a simple address is ok (rejectTLD false)"); | |
| result = fxn({ input: "foo@bar.com", rejectTLD: true }); | |
| t.ok(result, "a simple address is ok (rejectTLD true)"); | |
| result = fxn({ input: "\"Foo Bar\" <foo@bar.com>", rejectTLD: false }); | |
| t.ok(result, "a more complicated address is ok (rejectTLD false)"); | |
| result = fxn({ input: "\"Foo Bar\" <foo@bar.com>", rejectTLD: true }); | |
| t.ok(result, "a more complicated address is ok (rejectTLD true)"); | |
| result = fxn({ input: "foo@bar", rejectTLD: false }); | |
| t.ok(result, "an address with a TLD for its domain is allowed by rfc 5322"); | |
| result = fxn({ input: "foo@bar", rejectTLD: true }); | |
| t.notOk(result, "an address with a TLD for its domain is rejected when the option is set"); | |
| result = fxn({ input: "\"Foo Bar\" <foo@bar>", rejectTLD: false }); | |
| t.ok(result, "a more complicated address with a TLD for its domain is allowed by rfc 5322"); | |
| result = fxn({ input: "\"Foo Bar\" <foo@bar>", rejectTLD: true }); | |
| t.notOk(result, "a more complicated address with a TLD for its domain is rejected when the option is set"); | |
| result = fxn({ input: "jack@", rejectTLD: true }); | |
| t.notOk(result, "no domain is ok with rejectTLD set"); | |
| t.end(); | |
| }); | |
| test("dots in unquoted display-names", function (t) { | |
| var fxn, result; | |
| fxn = addrs.parseOneAddress; | |
| result = fxn("H.P. Lovecraft <foo@bar.net>"); | |
| t.ok(result, "dots in the middle of an unquoted display-name with spaces (obs-phrase production)"); | |
| result = fxn("Hmm Yes Info. <foo@bar.net>"); | |
| t.ok(result, "dots to end an unquoted display-name (obs-phrase production)"); | |
| result = fxn("bar.net <foo@bar.net>"); | |
| t.ok(result, "dots in the middle of an unquoted display-name without spaces (obs-phrase production)"); | |
| result = fxn({ input: "H.P. Lovecraft <foo@bar.net>", strict: true }); | |
| t.notOk(result, "dots without using 'obsolete' productions"); | |
| result = fxn({ input: "Hmm Yes Info. <foo@bar.net>", strict: true }); | |
| t.notOk(result, "dots without using 'obsolete' productions"); | |
| result = fxn({ input: "bar.net <foo@bar.net>", strict: true }); | |
| t.notOk(result, "dots without using 'obsolete' productions"); | |
| t.end(); | |
| }); | |
| test("rfc6854 - from", function (t) { | |
| var fxn, result; | |
| fxn = addrs.parseFrom; | |
| result = fxn("Managing Partners:ben@example.com,carol@example.com;"); | |
| t.ok(result, "Parse group for From:"); | |
| t.equal(result[0].name, "Managing Partners", "Extract group name"); | |
| t.equal(result[0].addresses.length, 2, "Extract group addresses"); | |
| t.equal(result[0].addresses[0].address, "ben@example.com", "Group address 1"); | |
| t.equal(result[0].addresses[1].address, "carol@example.com", "Group address 1") | |
| result = fxn("Managing Partners:ben@example.com,carol@example.com;, \"Foo\" <foo@example.com>"); | |
| t.ok(result, "Group and mailbox"); | |
| t.equal(result[0].name, "Managing Partners", "Extract group name"); | |
| t.equal(result[1].name, "Foo", "Second address name"); | |
| t.equal(result[1].local, "foo", "Second address local"); | |
| t.equal(result[1].domain, "example.com", "Second address domain"); | |
| t.end(); | |
| }); | |
| test("rfc6854 - sender", function (t) { | |
| var fxn, result; | |
| fxn = addrs.parseSender; | |
| result = fxn("Managing Partners:ben@example.com,carol@example.com;"); | |
| t.ok(result, "Parse group for Sender:"); | |
| t.equal(result.length, undefined, "Result is not an array"); | |
| t.equal(result.name, "Managing Partners", "Result has name"); | |
| t.equal(result.local, undefined, "Result has no local part"); | |
| t.equal(result.addresses.length, 2, "Result has two addresses"); | |
| t.equal(result.addresses[0].address, "ben@example.com", "Result first address match"); | |
| t.equal(result.addresses[1].address, "carol@example.com", "Result first address match"); | |
| t.end(); | |
| }); | |
| test("rfc6854 - reply-to", function (t) { | |
| var fxn, result; | |
| fxn = addrs.parseReplyTo; | |
| result = fxn("Managing Partners:ben@example.com,carol@example.com;"); | |
| t.ok(result, "Parse group for Reply-To:"); | |
| t.equal(result[0].name, "Managing Partners", "Extract group name"); | |
| t.equal(result[0].addresses.length, 2, "Extract group addresses"); | |
| t.equal(result[0].addresses[0].address, "ben@example.com", "Group address 1"); | |
| t.equal(result[0].addresses[1].address, "carol@example.com", "Group address 1") | |
| result = fxn("Managing Partners:ben@example.com,carol@example.com;, \"Foo\" <foo@example.com>"); | |
| t.ok(result, "Group and mailbox"); | |
| t.equal(result[0].name, "Managing Partners", "Extract group name"); | |
| t.equal(result[1].name, "Foo", "Second address name"); | |
| t.equal(result[1].local, "foo", "Second address local"); | |
| t.equal(result[1].domain, "example.com", "Second address domain"); | |
| result = fxn("Managing Partners:ben@example.com,carol@example.com;, \"Foo\" <foo@example.com>, Group2:alice@example.com;"); | |
| t.ok(result, "Group, mailbox, group"); | |
| t.equal(result[0].name, "Managing Partners", "First: group name"); | |
| t.equal(result[0].addresses[0].address, "ben@example.com"); | |
| t.equal(result[0].addresses[1].address, "carol@example.com"); | |
| t.equal(result[1].name, "Foo", "Second: address name"); | |
| t.equal(result[2].name, "Group2", "Third: group name"); | |
| t.end(); | |
| }); | |
| test("whitespace in domain", function (t) { | |
| var fxn, result; | |
| fxn = addrs.parseOneAddress; | |
| result = fxn('":sysmail"@ Some-Group. Some-Org'); | |
| t.ok(result, "spaces in domain parses ok"); | |
| t.equal(result.domain, "Some-Group.Some-Org", "domain parsing strips whitespace"); | |
| t.end(); | |
| }) | |