/**
* @license
* Copyright The Closure Library Authors.
* SPDX-License-Identifier: Apache-2.0
*/
goog.module('goog.format.EmailAddressTest');
goog.setTestOnly();
const EmailAddress = goog.require('goog.format.EmailAddress');
const Format = goog.require('goog.i18n.bidi.Format');
const googArray = goog.require('goog.array');
const testSuite = goog.require('goog.testing.testSuite');
const LRM = Format.LRM;
const RLM = Format.RLM;
const LRE = Format.LRE;
const RLE = Format.RLE;
const PDF = Format.PDF;
function doIsValidTest(testFunc, valid, invalid) {
googArray.forEach(valid, (str) => {
assertTrue(`"${str}" should be valid.`, testFunc(str));
});
googArray.forEach(invalid, (str) => {
assertFalse(`"${str}" should be invalid.`, testFunc(str));
});
}
/**
* Asserts that parsing the inputString produces a list of email addresses
* containing the specified address strings, irrespective of their order.
* @param {string} inputString A raw address list.
* @param {Array<string>} expectedList The expected results.
* @param {string=} opt_message An assertion message.
* @return {string} the resulting email address objects.
* @suppress {checkTypes} suppression added to enable type checking
*/
function assertParsedList(inputString, expectedList, opt_message) {
const message = opt_message || 'Should parse address correctly';
const result = EmailAddress.parseList(inputString);
assertEquals(
'Should have correct # of addresses', expectedList.length, result.length);
for (let i = 0; i < expectedList.length; ++i) {
assertEquals(message, expectedList[i], result[i].getAddress());
}
return result;
}
testSuite({
testparseList() {
assertParsedList('', [], 'Failed to parse empty stringy');
assertParsedList(',,', [], 'Failed to parse string with commas only');
assertParsedList('<[email protected]>', ['[email protected]']);
assertParsedList(
'<[email protected]>,', ['[email protected]'],
'Failed to parse 1 address with trailing comma');
assertParsedList(
'<[email protected]>, ', ['[email protected]'],
'Failed to parse 1 address with trailing whitespace and comma');
assertParsedList(
',<[email protected]>', ['[email protected]'],
'Failed to parse 1 address with leading comma');
assertParsedList(
' ,<[email protected]>', ['[email protected]'],
'Failed to parse 1 address with leading whitespace and comma');
assertParsedList(
'<[email protected]>, <[email protected]>', ['[email protected]', '[email protected]'],
'Failed to parse 2 email addresses');
assertParsedList(
'<[email protected]>, <[email protected]>,', ['[email protected]', '[email protected]'],
'Failed to parse 2 email addresses and trailing comma');
assertParsedList(
'<[email protected]>, <[email protected]>, ',
['[email protected]', '[email protected]'],
'Failed to parse 2 email addresses, trailing comma and whitespace');
assertParsedList(
'John Doe <[email protected]>; Jane Doe <[email protected]>, ' +
'<[email protected]>',
['[email protected]', '[email protected]', '[email protected]'],
'Failed to parse addresses with semicolon separator');
},
testparseListOpenersAndClosers() {
assertParsedList(
'[email protected], "[email protected]", <[email protected]>, ' +
'([email protected]), [[email protected]]',
[
'[email protected]',
'"[email protected]"',
'[email protected]',
'([email protected])',
'[[email protected]]',
],
'Failed to handle all 5 opener/closer characters');
},
testparseListIdn() {
const idnaddr = 'mailtest@\u4F8B\u3048.\u30C6\u30B9\u30C8';
assertParsedList(idnaddr, [idnaddr]);
},
testparseListWithQuotedSpecialChars() {
const res = assertParsedList(
'a\\"b\\"c <[email protected]>,"g\\"h\\"i\\\\" <[email protected]>', ['[email protected]', '[email protected]']);
assertEquals('Wrong name 0', 'a"b"c', res[0].getName());
assertEquals('Wrong name 1', 'g"h"i\\', res[1].getName());
},
testparseListWithCommaInLocalPart() {
const res = assertParsedList(
'"Doe, John" <[email protected]>, <[email protected]>',
['[email protected]', '[email protected]']);
assertEquals('Doe, John', res[0].getName());
assertEquals('', res[1].getName());
},
testparseListWithWhitespaceSeparatedEmails() {
const res = assertParsedList(
'[email protected] <[email protected]> [email protected] "G H" <[email protected]> [email protected]',
['[email protected]', '[email protected]', '[email protected]', '[email protected]', '[email protected]']);
assertEquals('G H', res[3].getName());
},
testparseListSystemNewlines() {
// These Windows newlines can be inserted in IE8, or copied-and-pasted from
// bad data on a Mac, as seen in bug 11081852.
assertParsedList(
'[email protected]\r\[email protected]', ['[email protected]', '[email protected]'],
'Failed to parse Windows newlines');
assertParsedList(
'[email protected]\[email protected]', ['[email protected]', '[email protected]'],
'Failed to parse *nix newlines');
assertParsedList(
'[email protected]\n\[email protected]', ['[email protected]', '[email protected]'],
'Failed to parse obsolete newlines');
assertParsedList(
'[email protected]\[email protected]', ['[email protected]', '[email protected]'],
'Failed to parse pre-OS X Mac newlines');
},
testparseListBidiMarks() {
// These bidi marks can be copy pasted from an RTL formatted email
assertParsedList(
`ab ${LRE}${PDF}${RLM}<${LRE}[email protected]${PDF}${RLM}>` +
`${PDF}${RLM},[email protected]${PDF}${RLM} `,
['[email protected]', '[email protected]']);
assertParsedList(
`${PDF}ab ${RLE}${PDF}${LRM}<${RLE}[email protected]${PDF}${LRM}>` +
`${PDF}${LRM},[email protected]${PDF}${LRM} `,
['[email protected]', '[email protected]']);
},
testToString() {
const f = (str) => EmailAddress.parse(str).toString();
// No modification.
assertEquals('JOHN Doe <[email protected]>', f('JOHN Doe <[email protected]>'));
// Extra spaces.
assertEquals(
'JOHN Doe <[email protected]>', f(' JOHN Doe <[email protected]> '));
// No name.
assertEquals('[email protected]', f('<[email protected]>'));
assertEquals('[email protected]', f('[email protected]'));
// No address.
assertEquals('JOHN Doe', f('JOHN Doe <>'));
// Special chars in the name.
assertEquals(
'"JOHN, Doe" <[email protected]>', f('JOHN, Doe <[email protected]>'));
assertEquals(
'"JOHN(Johnny) Doe" <[email protected]>',
f('JOHN(Johnny) Doe <[email protected]>'));
assertEquals(
'"JOHN[Johnny] Doe" <[email protected]>',
f('JOHN[Johnny] Doe <[email protected]>'));
assertEquals(
'"JOHN@work Doe" <[email protected]>',
f('JOHN@work Doe <[email protected]>'));
assertEquals(
'"JOHN:theking Doe" <[email protected]>',
f('JOHN:theking Doe <[email protected]>'));
assertEquals(
'"JOHN\\\\ Doe" <[email protected]>', f('JOHN\\ Doe <[email protected]>'));
assertEquals(
'"JOHN.com Doe" <[email protected]>', f('JOHN.com Doe <[email protected]>'));
// Already quoted.
assertEquals(
'"JOHN, Doe" <[email protected]>', f('"JOHN, Doe" <[email protected]>'));
// Needless quotes.
assertEquals('JOHN Doe <[email protected]>', f('"JOHN Doe" <[email protected]>'));
// Not quoted-string, but has double quotes.
assertEquals(
'"JOHN, Doe" <[email protected]>', f('JOHN, "Doe" <[email protected]>'));
// No special characters other than quotes.
assertEquals('JOHN Doe <[email protected]>', f('JOHN "Doe" <[email protected]>'));
// Escaped quotes are also removed.
assertEquals(
'"JOHN, Doe" <[email protected]>', f('JOHN, \\"Doe\\" <[email protected]>'));
},
testIsValid() {
const valid = [
'[email protected]', '<[email protected]>', 'eric <[email protected]>', '"e" <[email protected]>',
'[email protected]', '[email protected]', '[email protected]', 'o\'[email protected]',
'[email protected]', '!/#$%&\'*+-=~|`{}?^[email protected]',
'[email protected]',
`blah blahson ${LRE}${PDF}${RLM}<${LRE}[email protected]${PDF}${RLM}>`
];
const invalid = [
'e',
'',
'e @c.com',
'a@b',
'foo.com',
'[email protected]',
'test@gma=il.com',
'aaa@gmail',
'has some [email protected]',
'has@three@[email protected]',
'@no-local-part.com',
'み.ん-あ@みんあ.みんあ',
'みんあ@test.com',
'test@test.みんあ',
'test@みんあ.com',
'fullwidthfullstop@sld' +
'\uff0e' +
'tld',
'ideographicfullstop@sld' +
'\u3002' +
'tld',
'halfwidthideographicfullstop@sld' +
'\uff61' +
'tld',
];
doIsValidTest(EmailAddress.isValidAddress, valid, invalid);
},
testIsValidLocalPart() {
const valid = [
'e',
'a.b+foo',
'o\'hara',
'user+someone',
'!/#$%&\'*+-=~|`{}?^_',
'confirm-bhk=modulo.org',
];
const invalid = [
'A@b@c',
'a"b(c)d,e:f;g<h>i[j\\k]l',
'just"not"right',
'this is"not\\allowed',
'this\\ still\"not\\\\allowed',
'has some spaces',
];
doIsValidTest(EmailAddress.isValidLocalPartSpec, valid, invalid);
},
testIsValidDomainPart() {
const valid =
['example.com', 'dept.example.org', 'long.domain.with.lots.of.dots'];
const invalid = [
'',
'@has.an.at.sign',
'..has.leading.dots',
'gma=il.com',
'DoesNotHaveADot',
'sld' +
'\uff0e' +
'tld',
'sld' +
'\u3002' +
'tld',
'sld' +
'\uff61' +
'tld',
];
doIsValidTest(EmailAddress.isValidDomainPartSpec, valid, invalid);
},
});