UNPKG

12.8 kBJavaScriptView Raw
1
2var test = require("tap").test;
3
4var addrs = require("../lib/email-addresses");
5
6
7test("simple one address function", function (t) {
8 var fxn, result;
9 fxn = addrs.parseOneAddress;
10
11 result = fxn("ABC < a@b.c>") || {};
12 t.notOk(result.node, "has no ast information");
13 t.equal(result.address, "a@b.c", "full address, semantic only");
14 t.equal(result.name, "ABC", "display name");
15 t.equal(result.local, "a", "local part");
16 t.equal(result.domain, "b.c", "domain");
17
18 t.equal(fxn("bogus"), null, "bogus address > null");
19 t.equal(fxn("a@b.c, d@e.f"), null, "address list > null");
20
21 result = fxn("\"Françoise Lefèvre\"@example.com");
22 t.ok(result, "RFC 6532 (Unicode support) is enabled by default");
23 t.equal(result.parts.local.semantic, "Françoise Lefèvre");
24
25 result = fxn("First Last <first@last.com>");
26 t.equal(result.name, "First Last",
27 "whitespace is not removed from display names without quotes");
28
29 result = fxn(" First Last <first@last.com>");
30 t.equal(result.name, "First Last",
31 "whitespace in names is collapsed");
32
33 t.end();
34});
35
36test("simple address list function", function (t) {
37 var fxn, result;
38 fxn = addrs.parseAddressList;
39
40 result = fxn("\"A B C\" < a@b.c>, d@e") || [{}, {}];
41 t.notOk(result[0].node, "has no ast information");
42 t.equal(result[0].address, "a@b.c", "full address, semantic only");
43 t.equal(result[0].name, "A B C", "display name");
44 t.equal(result[0].local, "a", "local part");
45 t.equal(result[0].domain, "b.c", "domain");
46
47 t.notOk(result[1].node, "has no ast information");
48 t.equal(result[1].address, "d@e", "second address");
49 t.equal(result[1].name, null, "second display name");
50 t.equal(result[1].local, "d", "second local part");
51 t.equal(result[1].domain, "e", "second domain");
52
53 t.equal(fxn("bogus"), null, "bogus address > null");
54 t.equal(fxn("a@b.c").length, 1, "single address > ok");
55
56 result = fxn("\"Françoise Lefèvre\"@example.com");
57 t.ok(result, "RFC 6532 (Unicode support) is enabled by default");
58
59 t.end();
60});
61
62test("rfc5322 parser", function (t) {
63 var fxn, result;
64 fxn = addrs;
65
66 result = fxn("\"A B C\" < a@b.c>, d@e") || {};
67 t.ok(result.ast, "has an ast");
68 t.ok(result.addresses.length, "has the addresses");
69
70 result = result.addresses;
71 t.ok(result[0].node, "has link to node in ast");
72 t.equal(result[0].address, "a@b.c", "full address, semantic only");
73 t.equal(result[0].name, "A B C", "display name");
74 t.equal(result[0].local, "a", "local part");
75 t.equal(result[0].domain, "b.c", "domain");
76
77 t.ok(result[1].node, "has link to node in ast");
78 t.equal(result[1].address, "d@e", "second address");
79 t.equal(result[1].name, null, "second display name");
80 t.equal(result[1].local, "d", "second local part");
81 t.equal(result[1].domain, "e", "second domain");
82
83 t.equal(fxn("bogus"), null, "bogus address > null");
84 t.equal(fxn("a@b bogus"), null, "not all input is an email list > null");
85
86 result = fxn({ input: "a@b bogus", partial: true });
87 t.ok(result, "can obtain partial results if at beginning of string");
88
89 result = fxn("\"Françoise Lefèvre\"@example.com");
90 t.notOk(result, "extended ascii characters are invalid according to RFC 5322");
91
92 result = fxn({ input: "\"Françoise Lefèvre\"@example.com", rfc6532: true });
93 t.ok(result, "but extended ascii is allowed starting with RFC 6532");
94
95 t.end();
96});
97
98test("display-name semantic interpretation", function (t) {
99 var fxn, result;
100 fxn = addrs.parseOneAddress;
101
102 function check(s, comment, expected) {
103 t.equal(fxn(s).name, expected || "First Last", comment);
104 }
105
106 check(
107 "First<foo@bar.com>",
108 "single basic name is ok",
109 "First");
110
111 check(
112 "First Last<foo@bar.com>",
113 "no extra whitespace is ok");
114
115 check(
116 " First Last <foo@bar.com>",
117 "single whitespace at beginning and end is removed");
118
119 check(
120 "First Last<foo@bar.com>",
121 "whitespace in the middle is collapsed");
122
123 check(
124 " First Last <foo@bar.com>",
125 "extra whitespace everywhere is collapsed");
126
127 check(
128 " First Middle Last <foo@bar.com>",
129 "extra whitespace everywhere is collapsed, with more than 2 names",
130 "First Middle Last");
131
132 check(
133 "\tFirst \t Last\t<foo@bar.com>",
134 "extra whitespace everywhere is collapsed with a mix of tabs and spaces");
135
136 check(
137 "\"First Last\"<foo@bar.com>",
138 "surrounding quotes are not semantic");
139
140 check(
141 " \t \"First Last\" <foo@bar.com>",
142 "surrounding quotes are not semantic and whitespace is collapsed");
143
144 check(
145 " \t \"First \\\"The\t\tNickname\\\" Last\" <foo@bar.com>",
146 "surrounding quotes are not semantic, but inner quotes are, and whitespace is collapsed",
147 "First \"The Nickname\" Last");
148
149 t.end();
150});
151
152test("address semantic interpretation", function (t) {
153 var fxn, result;
154 fxn = addrs.parseOneAddress;
155
156 function check(s, comment, expected) {
157 t.equal(fxn(s).address, expected || "foo@bar.com", comment);
158 }
159
160 check(
161 "foo@bar.com",
162 "plain address is ok");
163
164 check(
165 " foo@bar.com ",
166 "plain address with whitespace at beginning and end");
167
168 check(
169 "foo @bar.com",
170 "plain address with whitespace left of @ sign");
171
172 check(
173 "foo@ bar.com",
174 "plain address with whitespace right of @ sign");
175
176 // Technically, we should also be able to handle removing CFWS in
177 // a dot-atom (or more importantly, obs-domain), but I don't think anyone cares.
178
179 check(
180 "\t foo\t\t@ \t bar.com \t ",
181 "plain address with whitespace everywhere");
182
183 check(
184 "Bob <\t foo\t\t@ \t bar.com \t >",
185 "angle-addr with whitespace everywhere");
186
187 check(
188 "\"foo\"@bar.com",
189 "plain address with quoted-string local-part");
190
191 check(
192 "\"foo baz\"@bar.com",
193 "plain address with quoted-string local-part including spaces" +
194 " (Note: This is a confusing situation for 'semantic' local-parts, and" +
195 " in this case we don't return a valid address. Don't use this. Just" +
196 " take the raw tokens used for the address if you always want it to be equivalent.)",
197 "foo baz@bar.com");
198
199 t.end();
200});
201
202test("unicode support", function (t) {
203 var fxn, result;
204 fxn = addrs.parseOneAddress;
205
206 result = fxn("\"Françoise Lefèvre\"@example.com");
207 t.ok(result, "extended ascii characters are allowed");
208
209 result = fxn("杨孝宇 <xiaoyu@example.com>");
210 t.ok(result, "unicode support includes chinese characters (display-name, no quoted string)");
211
212 result = fxn("\"杨孝宇\" <xiaoyu@example.com>");
213 t.ok(result, "unicode support includes chinese characters (display-name, quoted-string)");
214
215 t.end();
216});
217
218test("rejectTLD option", function (t) {
219 var fxn, result;
220 fxn = addrs.parseOneAddress;
221
222 result = fxn({ input: "foo@bar.com", rejectTLD: false });
223 t.ok(result, "a simple address is ok (rejectTLD false)");
224
225 result = fxn({ input: "foo@bar.com", rejectTLD: true });
226 t.ok(result, "a simple address is ok (rejectTLD true)");
227
228 result = fxn({ input: "\"Foo Bar\" <foo@bar.com>", rejectTLD: false });
229 t.ok(result, "a more complicated address is ok (rejectTLD false)");
230
231 result = fxn({ input: "\"Foo Bar\" <foo@bar.com>", rejectTLD: true });
232 t.ok(result, "a more complicated address is ok (rejectTLD true)");
233
234 result = fxn({ input: "foo@bar", rejectTLD: false });
235 t.ok(result, "an address with a TLD for its domain is allowed by rfc 5322");
236
237 result = fxn({ input: "foo@bar", rejectTLD: true });
238 t.notOk(result, "an address with a TLD for its domain is rejected when the option is set");
239
240 result = fxn({ input: "\"Foo Bar\" <foo@bar>", rejectTLD: false });
241 t.ok(result, "a more complicated address with a TLD for its domain is allowed by rfc 5322");
242
243 result = fxn({ input: "\"Foo Bar\" <foo@bar>", rejectTLD: true });
244 t.notOk(result, "a more complicated address with a TLD for its domain is rejected when the option is set");
245
246 result = fxn({ input: "jack@", rejectTLD: true });
247 t.notOk(result, "no domain is ok with rejectTLD set");
248
249 t.end();
250});
251
252test("dots in unquoted display-names", function (t) {
253 var fxn, result;
254 fxn = addrs.parseOneAddress;
255
256 result = fxn("H.P. Lovecraft <foo@bar.net>");
257 t.ok(result, "dots in the middle of an unquoted display-name with spaces (obs-phrase production)");
258
259 result = fxn("Hmm Yes Info. <foo@bar.net>");
260 t.ok(result, "dots to end an unquoted display-name (obs-phrase production)");
261
262 result = fxn("bar.net <foo@bar.net>");
263 t.ok(result, "dots in the middle of an unquoted display-name without spaces (obs-phrase production)");
264
265 result = fxn({ input: "H.P. Lovecraft <foo@bar.net>", strict: true });
266 t.notOk(result, "dots without using 'obsolete' productions");
267
268 result = fxn({ input: "Hmm Yes Info. <foo@bar.net>", strict: true });
269 t.notOk(result, "dots without using 'obsolete' productions");
270
271 result = fxn({ input: "bar.net <foo@bar.net>", strict: true });
272 t.notOk(result, "dots without using 'obsolete' productions");
273
274 t.end();
275});
276
277test("rfc6854 - from", function (t) {
278 var fxn, result;
279 fxn = addrs.parseFrom;
280
281 result = fxn("Managing Partners:ben@example.com,carol@example.com;");
282 t.ok(result, "Parse group for From:");
283 t.equal(result[0].name, "Managing Partners", "Extract group name");
284 t.equal(result[0].addresses.length, 2, "Extract group addresses");
285 t.equal(result[0].addresses[0].address, "ben@example.com", "Group address 1");
286 t.equal(result[0].addresses[1].address, "carol@example.com", "Group address 1")
287
288 result = fxn("Managing Partners:ben@example.com,carol@example.com;, \"Foo\" <foo@example.com>");
289 t.ok(result, "Group and mailbox");
290 t.equal(result[0].name, "Managing Partners", "Extract group name");
291 t.equal(result[1].name, "Foo", "Second address name");
292 t.equal(result[1].local, "foo", "Second address local");
293 t.equal(result[1].domain, "example.com", "Second address domain");
294
295 t.end();
296});
297
298test("rfc6854 - sender", function (t) {
299 var fxn, result;
300 fxn = addrs.parseSender;
301
302 result = fxn("Managing Partners:ben@example.com,carol@example.com;");
303 t.ok(result, "Parse group for Sender:");
304 t.equal(result.length, undefined, "Result is not an array");
305 t.equal(result.name, "Managing Partners", "Result has name");
306 t.equal(result.local, undefined, "Result has no local part");
307 t.equal(result.addresses.length, 2, "Result has two addresses");
308 t.equal(result.addresses[0].address, "ben@example.com", "Result first address match");
309 t.equal(result.addresses[1].address, "carol@example.com", "Result first address match");
310
311 t.end();
312});
313
314test("rfc6854 - reply-to", function (t) {
315 var fxn, result;
316 fxn = addrs.parseReplyTo;
317
318 result = fxn("Managing Partners:ben@example.com,carol@example.com;");
319 t.ok(result, "Parse group for Reply-To:");
320 t.equal(result[0].name, "Managing Partners", "Extract group name");
321 t.equal(result[0].addresses.length, 2, "Extract group addresses");
322 t.equal(result[0].addresses[0].address, "ben@example.com", "Group address 1");
323 t.equal(result[0].addresses[1].address, "carol@example.com", "Group address 1")
324
325 result = fxn("Managing Partners:ben@example.com,carol@example.com;, \"Foo\" <foo@example.com>");
326 t.ok(result, "Group and mailbox");
327 t.equal(result[0].name, "Managing Partners", "Extract group name");
328 t.equal(result[1].name, "Foo", "Second address name");
329 t.equal(result[1].local, "foo", "Second address local");
330 t.equal(result[1].domain, "example.com", "Second address domain");
331
332 result = fxn("Managing Partners:ben@example.com,carol@example.com;, \"Foo\" <foo@example.com>, Group2:alice@example.com;");
333 t.ok(result, "Group, mailbox, group");
334 t.equal(result[0].name, "Managing Partners", "First: group name");
335 t.equal(result[0].addresses[0].address, "ben@example.com");
336 t.equal(result[0].addresses[1].address, "carol@example.com");
337 t.equal(result[1].name, "Foo", "Second: address name");
338 t.equal(result[2].name, "Group2", "Third: group name");
339
340 t.end();
341});
342
343test("whitespace in domain", function (t) {
344 var fxn, result;
345 fxn = addrs.parseOneAddress;
346
347 result = fxn('":sysmail"@ Some-Group. Some-Org');
348 t.ok(result, "spaces in domain parses ok");
349 t.equal(result.domain, "Some-Group.Some-Org", "domain parsing strips whitespace");
350
351 t.end();
352})