From 3e2cfd54bdd12f97df389a724ab899798dca414f Mon Sep 17 00:00:00 2001 From: David Humphrey Date: Wed, 31 Jan 2018 16:02:03 -0500 Subject: [PATCH] Formatting fixes --- .../i18n/phonenumbers/phonenumbermatcher.js | 745 +++++---- .../phonenumbers/phonenumbermatcher_test.js | 1338 ++++++++--------- .../phonenumbers/phonenumberutil_test.html | 1 + 3 files changed, 1039 insertions(+), 1045 deletions(-) diff --git a/javascript/i18n/phonenumbers/phonenumbermatcher.js b/javascript/i18n/phonenumbers/phonenumbermatcher.js index 218248b8b..ae9c533be 100644 --- a/javascript/i18n/phonenumbers/phonenumbermatcher.js +++ b/javascript/i18n/phonenumbers/phonenumbermatcher.js @@ -150,64 +150,65 @@ var LEAD_CLASS; // built dynamically below (function () { - /** Returns a regular expression quantifier with an upper and lower limit. */ - function limit(lower, upper) { - if ((lower < 0) || (upper <= 0) || (upper < lower)) { - throw new Error('invalid lower or upper limit'); - } - return '{' + lower + ',' + upper + '}'; - } + /** Returns a regular expression quantifier with an upper and lower limit. */ + function limit(lower, upper) { + if ((lower < 0) || (upper <= 0) || (upper < lower)) { + throw new Error('invalid lower or upper limit'); + } + return '{' + lower + ',' + upper + '}'; + } - /* Builds the MATCHING_BRACKETS and PATTERN regular expressions. The building blocks below exist - * to make the pattern more easily understood. */ - - var openingParens = '(\\[\uFF08\uFF3B'; - var closingParens = ')\\]\uFF09\uFF3D'; - var nonParens = '[^' + openingParens + closingParens + ']'; - - /* Limit on the number of pairs of brackets in a phone number. */ - var bracketPairLimit = limit(0, 3); - /* - * An opening bracket at the beginning may not be closed, but subsequent ones should be. It's - * also possible that the leading bracket was dropped, so we shouldn't be surprised if we see a - * closing bracket first. We limit the sets of brackets in a phone number to four. - */ - MATCHING_BRACKETS = new RegExp( - '(?:[' + openingParens + '])?' + '(?:' + nonParens + '+' + '[' + closingParens + '])?' - + nonParens + '+' - + '(?:[' + openingParens + ']' + nonParens + '+[' + closingParens + '])' + bracketPairLimit - + nonParens + '*'); - - /* Limit on the number of leading (plus) characters. */ - var leadLimit = limit(0, 2); - /* Limit on the number of consecutive punctuation characters. */ - var punctuationLimit = limit(0, 4); - /* The maximum number of digits allowed in a digit-separated block. As we allow all digits in a - * single block, set high enough to accommodate the entire national number and the international - * country code. */ - var digitBlockLimit = i18n.phonenumbers.PhoneNumberUtil.MAX_LENGTH_FOR_NSN_ + - i18n.phonenumbers.PhoneNumberUtil.MAX_LENGTH_COUNTRY_CODE_; - /* Limit on the number of blocks separated by punctuation. Uses digitBlockLimit since some - * formats use spaces to separate each digit. */ - var blockLimit = limit(0, digitBlockLimit); - - /* A punctuation sequence allowing white space. */ - var punctuation = '[' + i18n.phonenumbers.PhoneNumberUtil.VALID_PUNCTUATION + - ']' + punctuationLimit; - /* A digits block without punctuation. */ - // XXX: can't use \p{Nd} in es5, so here's a transpiled version via https://mothereff.in/regexpu - var es5DigitSequence = '(?:[0-9\\u0660-\\u0669\\u06F0-\\u06F9\\u07C0-\\u07C9\\u0966-\\u096F\\u09E6-\\u09EF\\u0A66-\\u0A6F\\u0AE6-\\u0AEF\\u0B66-\\u0B6F\\u0BE6-\\u0BEF\\u0C66-\\u0C6F\\u0CE6-\\u0CEF\\u0D66-\\u0D6F\\u0DE6-\\u0DEF\\u0E50-\\u0E59\\u0ED0-\\u0ED9\\u0F20-\\u0F29\\u1040-\\u1049\\u1090-\\u1099\\u17E0-\\u17E9\\u1810-\\u1819\\u1946-\\u194F\\u19D0-\\u19D9\\u1A80-\\u1A89\\u1A90-\\u1A99\\u1B50-\\u1B59\\u1BB0-\\u1BB9\\u1C40-\\u1C49\\u1C50-\\u1C59\\uA620-\\uA629\\uA8D0-\\uA8D9\\uA900-\\uA909\\uA9D0-\\uA9D9\\uA9F0-\\uA9F9\\uAA50-\\uAA59\\uABF0-\\uABF9\\uFF10-\\uFF19]|\\uD801[\\uDCA0-\\uDCA9]|\\uD804[\\uDC66-\\uDC6F\\uDCF0-\\uDCF9\\uDD36-\\uDD3F\\uDDD0-\\uDDD9\\uDEF0-\\uDEF9]|[\\uD805\\uD807][\\uDC50-\\uDC59\\uDCD0-\\uDCD9\\uDE50-\\uDE59\\uDEC0-\\uDEC9\\uDF30-\\uDF39]|\\uD806[\\uDCE0-\\uDCE9]|\\uD81A[\\uDE60-\\uDE69\\uDF50-\\uDF59]|\\uD835[\\uDFCE-\\uDFFF]|\\uD83A[\\uDD50-\\uDD59])'; - var digitSequence = es5DigitSequence + limit(1, digitBlockLimit); - - var leadClassChars = openingParens + - i18n.phonenumbers.PhoneNumberUtil.PLUS_CHARS_; - LEAD_CLASS = '[' + leadClassChars + ']'; - - /* Phone number pattern allowing optional punctuation. */ - PATTERN = '(?:' + LEAD_CLASS + punctuation + ')' + leadLimit - + digitSequence + '(?:' + punctuation + digitSequence + ')' + blockLimit - + '(?:' + i18n.phonenumbers.PhoneNumberUtil.EXTN_PATTERNS_FOR_MATCHING + - ')?'; + /* Builds the MATCHING_BRACKETS and PATTERN regular expressions. The building blocks below exist + * to make the pattern more easily understood. */ + + var openingParens = '(\\[\uFF08\uFF3B'; + var closingParens = ')\\]\uFF09\uFF3D'; + var nonParens = '[^' + openingParens + closingParens + ']'; + + /* Limit on the number of pairs of brackets in a phone number. */ + var bracketPairLimit = limit(0, 3); + /* + * An opening bracket at the beginning may not be closed, but subsequent ones should be. It's + * also possible that the leading bracket was dropped, so we shouldn't be surprised if we see a + * closing bracket first. We limit the sets of brackets in a phone number to four. + */ + MATCHING_BRACKETS = new RegExp( + '(?:[' + openingParens + '])?' + '(?:' + nonParens + '+' + + '[' + closingParens + '])?' + nonParens + '+' + + '(?:[' + openingParens + ']' + nonParens + '+[' + + closingParens + '])' + bracketPairLimit + nonParens + '*'); + + /* Limit on the number of leading (plus) characters. */ + var leadLimit = limit(0, 2); + /* Limit on the number of consecutive punctuation characters. */ + var punctuationLimit = limit(0, 4); + /* The maximum number of digits allowed in a digit-separated block. As we allow all digits in a + * single block, set high enough to accommodate the entire national number and the international + * country code. */ + var digitBlockLimit = i18n.phonenumbers.PhoneNumberUtil.MAX_LENGTH_FOR_NSN_ + + i18n.phonenumbers.PhoneNumberUtil.MAX_LENGTH_COUNTRY_CODE_; + /* Limit on the number of blocks separated by punctuation. Uses digitBlockLimit since some + * formats use spaces to separate each digit. */ + var blockLimit = limit(0, digitBlockLimit); + + /* A punctuation sequence allowing white space. */ + var punctuation = '[' + i18n.phonenumbers.PhoneNumberUtil.VALID_PUNCTUATION + + ']' + punctuationLimit; + /* A digits block without punctuation. */ + // XXX: can't use \p{Nd} in es5, so here's a transpiled version via https://mothereff.in/regexpu + var es5DigitSequence = '(?:[0-9\\u0660-\\u0669\\u06F0-\\u06F9\\u07C0-\\u07C9\\u0966-\\u096F\\u09E6-\\u09EF\\u0A66-\\u0A6F\\u0AE6-\\u0AEF\\u0B66-\\u0B6F\\u0BE6-\\u0BEF\\u0C66-\\u0C6F\\u0CE6-\\u0CEF\\u0D66-\\u0D6F\\u0DE6-\\u0DEF\\u0E50-\\u0E59\\u0ED0-\\u0ED9\\u0F20-\\u0F29\\u1040-\\u1049\\u1090-\\u1099\\u17E0-\\u17E9\\u1810-\\u1819\\u1946-\\u194F\\u19D0-\\u19D9\\u1A80-\\u1A89\\u1A90-\\u1A99\\u1B50-\\u1B59\\u1BB0-\\u1BB9\\u1C40-\\u1C49\\u1C50-\\u1C59\\uA620-\\uA629\\uA8D0-\\uA8D9\\uA900-\\uA909\\uA9D0-\\uA9D9\\uA9F0-\\uA9F9\\uAA50-\\uAA59\\uABF0-\\uABF9\\uFF10-\\uFF19]|\\uD801[\\uDCA0-\\uDCA9]|\\uD804[\\uDC66-\\uDC6F\\uDCF0-\\uDCF9\\uDD36-\\uDD3F\\uDDD0-\\uDDD9\\uDEF0-\\uDEF9]|[\\uD805\\uD807][\\uDC50-\\uDC59\\uDCD0-\\uDCD9\\uDE50-\\uDE59\\uDEC0-\\uDEC9\\uDF30-\\uDF39]|\\uD806[\\uDCE0-\\uDCE9]|\\uD81A[\\uDE60-\\uDE69\\uDF50-\\uDF59]|\\uD835[\\uDFCE-\\uDFFF]|\\uD83A[\\uDD50-\\uDD59])'; + var digitSequence = es5DigitSequence + limit(1, digitBlockLimit); + + var leadClassChars = openingParens + + i18n.phonenumbers.PhoneNumberUtil.PLUS_CHARS_; + + LEAD_CLASS = '[' + leadClassChars + ']'; + + /* Phone number pattern allowing optional punctuation. */ + PATTERN = '(?:' + LEAD_CLASS + punctuation + ')' + leadLimit + + digitSequence + '(?:' + punctuation + digitSequence + ')' + blockLimit + + '(?:' + i18n.phonenumbers.PhoneNumberUtil.EXTN_PATTERNS_FOR_MATCHING + + ')?'; }()); @@ -216,15 +217,15 @@ var LEAD_CLASS; // built dynamically below * returning the trimmed version. */ function trimAfterFirstMatch(pattern, candidate) { - var trailingCharsMatcher = pattern.exec(candidate); - if (trailingCharsMatcher && trailingCharsMatcher.length) { - candidate = candidate.substring(0, trailingCharsMatcher.index); - } - return candidate; + var trailingCharsMatcher = pattern.exec(candidate); + if (trailingCharsMatcher && trailingCharsMatcher.length) { + candidate = candidate.substring(0, trailingCharsMatcher.index); + } + return candidate; } function isInvalidPunctuationSymbol(character) { - return character == '%' || CURRENCY_SYMBOL.test(character); + return character == '%' || CURRENCY_SYMBOL.test(character); } /** @@ -243,37 +244,37 @@ function isInvalidPunctuationSymbol(character) { * be {@code >= 0}. */ i18n.phonenumbers.PhoneNumberMatcher = function(util, text, country, leniency, maxTries) { - if (util == null) { - throw new Error('util can not be null'); - } - if (leniency == null) { - throw new Error('leniency can not be null'); - } - if (maxTries < 0) { - throw new Error('maxTries must be greater than 0'); - } + if (util == null) { + throw new Error('util can not be null'); + } + if (leniency == null) { + throw new Error('leniency can not be null'); + } + if (maxTries < 0) { + throw new Error('maxTries must be greater than 0'); + } - /** The phone number utility. */ - this.phoneUtil = util; - /** The text searched for phone numbers. */ - this.text = text || ''; - /** - * The region (country) to assume for phone numbers without an international prefix, possibly - * null. - */ - this.preferredRegion = country; - /** The degree of validation requested. NOTE: Java `findNumbers` always uses VALID, so we hard code that here */ - this.leniency = leniency; - - /** The maximum number of retries after matching an invalid number. */ - this.maxTries = maxTries; - - /** The iteration tristate. */ - this.state = State.NOT_READY; - /** The last successful match, null unless in {@link State#READY}. */ - this.lastMatch = null; - /** The next index to start searching at. Undefined in {@link State#DONE}. */ - this.searchIndex = 0; + /** The phone number utility. */ + this.phoneUtil = util; + /** The text searched for phone numbers. */ + this.text = text || ''; + /** + * The region (country) to assume for phone numbers without an international prefix, possibly + * null. + */ + this.preferredRegion = country; + /** The degree of validation requested. NOTE: Java `findNumbers` always uses VALID, so we hard code that here */ + this.leniency = leniency; + + /** The maximum number of retries after matching an invalid number. */ + this.maxTries = maxTries; + + /** The iteration tristate. */ + this.state = State.NOT_READY; + /** The last successful match, null unless in {@link State#READY}. */ + this.lastMatch = null; + /** The next index to start searching at. Undefined in {@link State#DONE}. */ + this.searchIndex = 0; }; /** @@ -282,12 +283,12 @@ i18n.phonenumbers.PhoneNumberMatcher = function(util, text, country, leniency, m * Latin character. */ i18n.phonenumbers.PhoneNumberMatcher.isLatinLetter = function(letter) { - // Combining marks are a subset of non-spacing-mark. - if (!IS_LETTER.test(letter) && !NON_SPACING_MARK.test(letter)) { - return false; - } + // Combining marks are a subset of non-spacing-mark. + if (!IS_LETTER.test(letter) && !NON_SPACING_MARK.test(letter)) { + return false; + } - return IS_LATIN.test(letter); + return IS_LATIN.test(letter); }; /** @@ -298,121 +299,120 @@ i18n.phonenumbers.PhoneNumberMatcher.isLatinLetter = function(letter) { * @return the phone number match found, null if none can be found */ i18n.phonenumbers.PhoneNumberMatcher.prototype.find = function(index) { - var matches; - var patternRegex = new RegExp(PATTERN, 'ig'); - patternRegex.lastIndex = index; - - while((this.maxTries > 0) && ((matches = patternRegex.exec(this.text)))) { - var start = matches.index; - var candidate = matches[0]; - - // Check for extra numbers at the end. - // TODO: This is the place to start when trying to support extraction of multiple phone number - // from split notations (+41 79 123 45 67 / 68). - candidate = trimAfterFirstMatch( - i18n.phonenumbers.PhoneNumberUtil.SECOND_NUMBER_START_PATTERN_, - candidate - ); - - var match = this.extractMatch(candidate, start); - if (match != null) { - return match; - } + var matches; + var patternRegex = new RegExp(PATTERN, 'ig'); + patternRegex.lastIndex = index; + + while((this.maxTries > 0) && ((matches = patternRegex.exec(this.text)))) { + var start = matches.index; + var candidate = matches[0]; + + // Check for extra numbers at the end. + // TODO: This is the place to start when trying to support extraction of multiple phone number + // from split notations (+41 79 123 45 67 / 68). + candidate = trimAfterFirstMatch( + i18n.phonenumbers.PhoneNumberUtil.SECOND_NUMBER_START_PATTERN_, + candidate + ); - this.maxTries--; - patternRegex.lastIndex = start + candidate.length + 1; + var match = this.extractMatch(candidate, start); + if (match != null) { + return match; } - return null; + this.maxTries--; + patternRegex.lastIndex = start + candidate.length + 1; + } + + return null; }; // XXX: do I care about doing iterator() to wrap these? And/or // should this have some more JS-like interface? i18n.phonenumbers.PhoneNumberMatcher.prototype.hasNext = function() { - if (this.state == State.NOT_READY) { - this.lastMatch = this.find(this.searchIndex); - if (this.lastMatch == null) { - this.state = State.DONE; - } else { - this.searchIndex = this.lastMatch.end; - this.state = State.READY; - } + if (this.state == State.NOT_READY) { + this.lastMatch = this.find(this.searchIndex); + if (this.lastMatch == null) { + this.state = State.DONE; + } else { + this.searchIndex = this.lastMatch.end; + this.state = State.READY; } - return this.state == State.READY; + } + return this.state == State.READY; }; i18n.phonenumbers.PhoneNumberMatcher.prototype.next = function() { - // Check the state and find the next match as a side-effect if necessary. - if (!this.hasNext()) { - throw new Error('no element'); - } + // Check the state and find the next match as a side-effect if necessary. + if (!this.hasNext()) { + throw new Error('no element'); + } - // Don't retain that memory any longer than necessary. - var result = this.lastMatch; - this.lastMatch = null; - this.state = State.NOT_READY; - return result; + // Don't retain that memory any longer than necessary. + var result = this.lastMatch; + this.lastMatch = null; + this.state = State.NOT_READY; + return result; }; i18n.phonenumbers.PhoneNumberMatcher.containsMoreThanOneSlashInNationalNumber = function(number, candidate) { - var firstSlashInBodyIndex = candidate.indexOf('/'); - if (firstSlashInBodyIndex < 0) { - // No slashes, this is okay. - return false; - } - // Now look for a second one. - var secondSlashInBodyIndex = candidate.indexOf('/', firstSlashInBodyIndex + 1); - if (secondSlashInBodyIndex < 0) { - // Only one slash, this is okay. - return false; - } + var firstSlashInBodyIndex = candidate.indexOf('/'); + if (firstSlashInBodyIndex < 0) { + // No slashes, this is okay. + return false; + } + // Now look for a second one. + var secondSlashInBodyIndex = candidate.indexOf('/', firstSlashInBodyIndex + 1); + if (secondSlashInBodyIndex < 0) { + // Only one slash, this is okay. + return false; + } - // If the first slash is after the country calling code, this is permitted. - var candidateHasCountryCode = - (number.getCountryCodeSource() == CountryCodeSource.FROM_NUMBER_WITH_PLUS_SIGN - || number.getCountryCodeSource() == CountryCodeSource.FROM_NUMBER_WITHOUT_PLUS_SIGN); - if (candidateHasCountryCode && - i18n.phonenumbers.PhoneNumberUtil.normalizeDigitsOnly( - candidate.substring(0, firstSlashInBodyIndex)) == number.getCountryCode()) - { - // Any more slashes and this is illegal. - return candidate.substring(secondSlashInBodyIndex + 1).indexOf('/') > -1; - } - return true; + // If the first slash is after the country calling code, this is permitted. + var candidateHasCountryCode = + (number.getCountryCodeSource() == CountryCodeSource.FROM_NUMBER_WITH_PLUS_SIGN || + number.getCountryCodeSource() == CountryCodeSource.FROM_NUMBER_WITHOUT_PLUS_SIGN); + if (candidateHasCountryCode && i18n.phonenumbers.PhoneNumberUtil.normalizeDigitsOnly( + candidate.substring(0, firstSlashInBodyIndex)) == number.getCountryCode()) + { + // Any more slashes and this is illegal. + return candidate.substring(secondSlashInBodyIndex + 1).indexOf('/') > -1; + } + return true; }; i18n.phonenumbers.PhoneNumberMatcher.containsOnlyValidXChars = function(number, candidate, util) { - var charAtIndex; - var charAtNextIndex; - - // The characters 'x' and 'X' can be (1) a carrier code, in which case they always precede the - // national significant number or (2) an extension sign, in which case they always precede the - // extension number. We assume a carrier code is more than 1 digit, so the first case has to - // have more than 1 consecutive 'x' or 'X', whereas the second case can only have exactly 1 'x' - // or 'X'. We ignore the character if it appears as the last character of the string. - for (var index = 0; index < candidate.length - 1; index++) { - charAtIndex = candidate.charAt(index); - if (charAtIndex == 'x' || charAtIndex == 'X') { - charAtNextIndex = candidate.charAt(index + 1); - if (charAtNextIndex == 'x' || charAtNextIndex == 'X') { - // This is the carrier code case, in which the 'X's always precede the national - // significant number. - index++; - if (util.isNumberMatch(number, candidate.substring(index)) != - i18n.phonenumbers.PhoneNumberUtil.MatchType.NSN_MATCH - ) { - return false; - } - // This is the extension sign case, in which the 'x' or 'X' should always precede the - // extension number. - } else if (!i18n.phonenumbers.PhoneNumberUtil.normalizeDigitsOnly( - candidate.substring(index)) == number.getExtension() - ) { - return false; - } + var charAtIndex; + var charAtNextIndex; + + // The characters 'x' and 'X' can be (1) a carrier code, in which case they always precede the + // national significant number or (2) an extension sign, in which case they always precede the + // extension number. We assume a carrier code is more than 1 digit, so the first case has to + // have more than 1 consecutive 'x' or 'X', whereas the second case can only have exactly 1 'x' + // or 'X'. We ignore the character if it appears as the last character of the string. + for (var index = 0; index < candidate.length - 1; index++) { + charAtIndex = candidate.charAt(index); + if (charAtIndex == 'x' || charAtIndex == 'X') { + charAtNextIndex = candidate.charAt(index + 1); + if (charAtNextIndex == 'x' || charAtNextIndex == 'X') { + // This is the carrier code case, in which the 'X's always precede the national + // significant number. + index++; + if (util.isNumberMatch(number, candidate.substring(index)) != + i18n.phonenumbers.PhoneNumberUtil.MatchType.NSN_MATCH + ) { + return false; } + // This is the extension sign case, in which the 'x' or 'X' should always precede the + // extension number. + } else if (!i18n.phonenumbers.PhoneNumberUtil.normalizeDigitsOnly( + candidate.substring(index)) == number.getExtension() + ) { + return false; + } } - return true; + } + return true; }; /** @@ -423,28 +423,28 @@ i18n.phonenumbers.PhoneNumberMatcher.containsOnlyValidXChars = function(number, * @return the match found, null if none can be found */ i18n.phonenumbers.PhoneNumberMatcher.prototype.extractMatch = function(candidate, offset) { - // Skip a match that is more likely to be a date. - if (SLASH_SEPARATED_DATES.test(candidate)) { - return null; - } + // Skip a match that is more likely to be a date. + if (SLASH_SEPARATED_DATES.test(candidate)) { + return null; + } - // Skip potential time-stamps. - if (TIME_STAMPS.test(candidate)) { - var followingText = this.text.substring(offset + candidate.length); - if (TIME_STAMPS_SUFFIX.test(followingText)) { - return null; - } + // Skip potential time-stamps. + if (TIME_STAMPS.test(candidate)) { + var followingText = this.text.substring(offset + candidate.length); + if (TIME_STAMPS_SUFFIX.test(followingText)) { + return null; } + } - // Try to come up with a valid match given the entire candidate. - var match = this.parseAndVerify(candidate, offset); - if (match != null) { - return match; - } + // Try to come up with a valid match given the entire candidate. + var match = this.parseAndVerify(candidate, offset); + if (match != null) { + return match; + } - // If that failed, try to find an "inner match" - there might be a phone number within this - // candidate. - return this.extractInnerMatch(candidate, offset); + // If that failed, try to find an "inner match" - there might be a phone number within this + // candidate. + return this.extractInnerMatch(candidate, offset); }; /** @@ -456,42 +456,41 @@ i18n.phonenumbers.PhoneNumberMatcher.prototype.extractMatch = function(candidate * @return the match found, null if none can be found */ i18n.phonenumbers.PhoneNumberMatcher.prototype.extractInnerMatch = function(candidate, offset) { - var groupMatch; - var innerMatchRegex; - var group; - var match; - - for (var i = 0; i < INNER_MATCHES.length; i++) { - var isFirstMatch = true; - innerMatchRegex = new RegExp(INNER_MATCHES[i], 'g'); - while ((groupMatch = innerMatchRegex.exec(candidate)) && - this.maxTries > 0) - { - if (isFirstMatch) { - // We should handle any group before this one too. - group = trimAfterFirstMatch( - i18n.phonenumbers.PhoneNumberUtil.UNWANTED_END_CHAR_PATTERN_, - candidate.substring(0, groupMatch.index) - ); - match = this.parseAndVerify(group, offset); - if (match != null) { - return match; - } - this.maxTries--; - isFirstMatch = false; - } - group = trimAfterFirstMatch( - i18n.phonenumbers.PhoneNumberUtil.UNWANTED_END_CHAR_PATTERN_, - groupMatch[1] - ); - match = this.parseAndVerify(group, offset + groupMatch.index); - if (match != null) { - return match; - } - this.maxTries--; + var groupMatch; + var innerMatchRegex; + var group; + var match; + var i; + + for (i = 0; i < INNER_MATCHES.length; i++) { + var isFirstMatch = true; + innerMatchRegex = new RegExp(INNER_MATCHES[i], 'ig'); + while ((groupMatch = innerMatchRegex.exec(candidate)) && this.maxTries > 0) { + if (isFirstMatch) { + // We should handle any group before this one too. + group = trimAfterFirstMatch( + i18n.phonenumbers.PhoneNumberUtil.UNWANTED_END_CHAR_PATTERN_, + candidate.substring(0, groupMatch.index) + ); + match = this.parseAndVerify(group, offset); + if (match != null) { + return match; } + this.maxTries--; + isFirstMatch = false; + } + group = trimAfterFirstMatch( + i18n.phonenumbers.PhoneNumberUtil.UNWANTED_END_CHAR_PATTERN_, + groupMatch[1] + ); + match = this.parseAndVerify(group, offset + groupMatch.index); + if (match != null) { + return match; + } + this.maxTries--; } - return null; + } + return null; }; /** @@ -504,121 +503,121 @@ i18n.phonenumbers.PhoneNumberMatcher.prototype.extractInnerMatch = function(cand * @return the parsed and validated phone number match, or null */ i18n.phonenumbers.PhoneNumberMatcher.prototype.parseAndVerify = function(candidate, offset) { - try { - // Check the candidate doesn't contain any formatting which would indicate that it really - // isn't a phone number. - if (!MATCHING_BRACKETS.test(candidate) || PUB_PAGES.test(candidate)) { - return null; - } + try { + // Check the candidate doesn't contain any formatting which would indicate that it really + // isn't a phone number. + if (!MATCHING_BRACKETS.test(candidate) || PUB_PAGES.test(candidate)) { + return null; + } - // If leniency is set to VALID or stricter, we also want to skip numbers that are surrounded - // by Latin alphabetic characters, to skip cases like abc8005001234 or 8005001234def. - // If the candidate is not at the start of the text, and does not start with phone-number - // punctuation, check the previous character. - if(this.leniency.value >= i18n.phonenumbers.PhoneNumberUtil.Leniency.VALID.value) { - if (offset > 0) { - var leadClassRe = new RegExp('^' + LEAD_CLASS); - var leadClassMatches = leadClassRe.exec(candidate); - if(leadClassMatches && leadClassMatches.index !== 0) { - var previousChar = this.text.charAt(offset - 1); - // We return null if it is a latin letter or an invalid punctuation symbol. - if (isInvalidPunctuationSymbol(previousChar) || - i18n.phonenumbers.PhoneNumberMatcher.isLatinLetter(previousChar)) - { - return null; - } - } - } - var lastCharIndex = offset + candidate.length; - if (lastCharIndex < this.text.length) { - var nextChar = this.text.charAt(lastCharIndex); - if (isInvalidPunctuationSymbol(nextChar) || - i18n.phonenumbers.PhoneNumberMatcher.isLatinLetter(nextChar)) - { - return null; - } - } + // If leniency is set to VALID or stricter, we also want to skip numbers that are surrounded + // by Latin alphabetic characters, to skip cases like abc8005001234 or 8005001234def. + // If the candidate is not at the start of the text, and does not start with phone-number + // punctuation, check the previous character. + if(this.leniency.value >= i18n.phonenumbers.PhoneNumberUtil.Leniency.VALID.value) { + if (offset > 0) { + var leadClassRe = new RegExp('^' + LEAD_CLASS); + var leadClassMatches = leadClassRe.exec(candidate); + if(leadClassMatches && leadClassMatches.index !== 0) { + var previousChar = this.text.charAt(offset - 1); + // We return null if it is a latin letter or an invalid punctuation symbol. + if (isInvalidPunctuationSymbol(previousChar) || + i18n.phonenumbers.PhoneNumberMatcher.isLatinLetter(previousChar)) + { + return null; + } } - - var number = this.phoneUtil.parseAndKeepRawInput(candidate, this.preferredRegion); - - // Check Israel * numbers: these are a special case in that they are four-digit numbers that - // our library supports, but they can only be dialled with a leading *. Since we don't - // actually store or detect the * in our phone number library, this means in practice we - // detect most four digit numbers as being valid for Israel. We are considering moving these - // numbers to ShortNumberInfo instead, in which case this problem would go away, but in the - // meantime we want to restrict the false matches so we only allow these numbers if they are - // preceded by a star. We enforce this for all leniency levels even though these numbers are - // technically accepted by isPossibleNumber and isValidNumber since we consider it to be a - // deficiency in those methods that they accept these numbers without the *. - // TODO: Remove this or make it significantly less hacky once we've decided how to - // handle these short codes going forward in ShortNumberInfo. We could use the formatting - // rules for instance, but that would be slower. - if (this.phoneUtil.getRegionCodeForCountryCode(number.getCountryCode()) == 'IL' - && this.phoneUtil.getNationalSignificantNumber(number).length == 4 - && (offset == 0 || (offset > 0 && this.text.charAt(offset - 1) != '*'))) + } + var lastCharIndex = offset + candidate.length; + if (lastCharIndex < this.text.length) { + var nextChar = this.text.charAt(lastCharIndex); + if (isInvalidPunctuationSymbol(nextChar) || + i18n.phonenumbers.PhoneNumberMatcher.isLatinLetter(nextChar)) { - // No match. - return null; + return null; } + } + } - if (this.leniency.verify(number, candidate, this.phoneUtil)) { - // We used parseAndKeepRawInput to create this number, but for now we don't return the extra - // values parsed. TODO: stop clearing all values here and switch all users over - // to using rawInput() rather than the rawString() of PhoneNumberMatch. - number.clearCountryCodeSource(); - number.clearRawInput(); - number.clearPreferredDomesticCarrierCode(); - return new i18n.phonenumbers.PhoneNumberMatch(offset, candidate, number); - } - } catch (e) { - // XXX: remove this - console.log(e); - // ignore and continue + var number = this.phoneUtil.parseAndKeepRawInput(candidate, this.preferredRegion); + + // Check Israel * numbers: these are a special case in that they are four-digit numbers that + // our library supports, but they can only be dialled with a leading *. Since we don't + // actually store or detect the * in our phone number library, this means in practice we + // detect most four digit numbers as being valid for Israel. We are considering moving these + // numbers to ShortNumberInfo instead, in which case this problem would go away, but in the + // meantime we want to restrict the false matches so we only allow these numbers if they are + // preceded by a star. We enforce this for all leniency levels even though these numbers are + // technically accepted by isPossibleNumber and isValidNumber since we consider it to be a + // deficiency in those methods that they accept these numbers without the *. + // TODO: Remove this or make it significantly less hacky once we've decided how to + // handle these short codes going forward in ShortNumberInfo. We could use the formatting + // rules for instance, but that would be slower. + if (this.phoneUtil.getRegionCodeForCountryCode(number.getCountryCode()) == 'IL' + && this.phoneUtil.getNationalSignificantNumber(number).length == 4 + && (offset == 0 || (offset > 0 && this.text.charAt(offset - 1) != '*'))) + { + // No match. + return null; } - return null; + + if (this.leniency.verify(number, candidate, this.phoneUtil)) { + // We used parseAndKeepRawInput to create this number, but for now we don't return the extra + // values parsed. TODO: stop clearing all values here and switch all users over + // to using rawInput() rather than the rawString() of PhoneNumberMatch. + number.clearCountryCodeSource(); + number.clearRawInput(); + number.clearPreferredDomesticCarrierCode(); + return new i18n.phonenumbers.PhoneNumberMatch(offset, candidate, number); + } + } catch (e) { + // XXX: remove this + console.log(e); + // ignore and continue + } + return null; }; i18n.phonenumbers.PhoneNumberMatcher.isNationalPrefixPresentIfRequired = function(number, util) { - // First, check how we deduced the country code. If it was written in international format, then - // the national prefix is not required. - if (number.getCountryCodeSource() != CountryCodeSource.FROM_DEFAULT_COUNTRY) { + // First, check how we deduced the country code. If it was written in international format, then + // the national prefix is not required. + if (number.getCountryCodeSource() != CountryCodeSource.FROM_DEFAULT_COUNTRY) { + return true; + } + var phoneNumberRegion = + util.getRegionCodeForCountryCode(number.getCountryCode()); + var metadata = util.getMetadataForRegion(phoneNumberRegion); + if (metadata == null) { + return true; + } + // Check if a national prefix should be present when formatting this number. + var nationalNumber = util.getNationalSignificantNumber(number); + var formatRule = util.chooseFormattingPatternForNumber_( + metadata.numberFormatArray(), + nationalNumber + ); + // To do this, we check that a national prefix formatting rule was present and that it wasn't + // just the first-group symbol ($1) with punctuation. + var nationalPrefixFormattingRule = formatRule && + formatRule.getNationalPrefixFormattingRule(); + if (nationalPrefixFormattingRule && nationalPrefixFormattingRule.length > 0) { + if (formatRule.getNationalPrefixOptionalWhenFormatting()) { + // The national-prefix is optional in these cases, so we don't need to check if it was + // present. return true; } - var phoneNumberRegion = - util.getRegionCodeForCountryCode(number.getCountryCode()); - var metadata = util.getMetadataForRegion(phoneNumberRegion); - if (metadata == null) { + if (util.formattingRuleHasFirstGroupOnly(nationalPrefixFormattingRule)) { + // National Prefix not needed for this number. return true; } - // Check if a national prefix should be present when formatting this number. - var nationalNumber = util.getNationalSignificantNumber(number); - var formatRule = util.chooseFormattingPatternForNumber_( - metadata.numberFormatArray(), - nationalNumber - ); - // To do this, we check that a national prefix formatting rule was present and that it wasn't - // just the first-group symbol ($1) with punctuation. - var nationalPrefixFormattingRule = formatRule && - formatRule.getNationalPrefixFormattingRule(); - if (nationalPrefixFormattingRule && nationalPrefixFormattingRule.length > 0) { - if (formatRule.getNationalPrefixOptionalWhenFormatting()) { - // The national-prefix is optional in these cases, so we don't need to check if it was - // present. - return true; - } - if (util.formattingRuleHasFirstGroupOnly(nationalPrefixFormattingRule)) { - // National Prefix not needed for this number. - return true; - } - // Normalize the remainder. - var rawInputCopy = i18n.phonenumbers.PhoneNumberUtil.normalizeDigitsOnly(number.getRawInput()); - var rawInput = new goog.string.StringBuffer(rawInputCopy); - // Check if we found a national prefix and/or carrier code at the start of the raw input, and - // return the result. - return util.maybeStripNationalPrefixAndCarrierCode(rawInput, metadata, null); - } - return true; + // Normalize the remainder. + var rawInputCopy = i18n.phonenumbers.PhoneNumberUtil.normalizeDigitsOnly(number.getRawInput()); + var rawInput = new goog.string.StringBuffer(rawInputCopy); + // Check if we found a national prefix and/or carrier code at the start of the raw input, and + // return the result. + return util.maybeStripNationalPrefixAndCarrierCode(rawInput, metadata, null); + } + return true; }; i18n.phonenumbers.PhoneNumberMatcher.checkNumberGroupingIsValid = function(number, candidate, util, checker) { @@ -636,16 +635,16 @@ i18n.phonenumbers.PhoneNumberMatcher.checkNumberGroupingIsValid = function(numbe // If this didn't pass, see if there are any alternate formats, and try them instead. var alternateFormats = - MetadataManager.getAlternateFormatsForCountry(number.getCountryCode()); + MetadataManager.getAlternateFormatsForCountry(number.getCountryCode()); if (alternateFormats != null) { - var formats = alternateFormats.numberFormats(); - var alternateFormat; + var formats = alternateFormats.numberFormats(); + var alternateFormat; for (var i = 0; i < formats.length; i++) { - alternateFormat = formats[i]; - formattedNumberGroups = getNationalNumberGroups(util, number, alternateFormat); - if (checker.checkGroups(util, number, normalizedCandidate, formattedNumberGroups)) { - return true; - } + alternateFormat = formats[i]; + formattedNumberGroups = getNationalNumberGroups(util, number, alternateFormat); + if (checker.checkGroups(util, number, normalizedCandidate, formattedNumberGroups)) { + return true; + } } } @@ -659,25 +658,25 @@ i18n.phonenumbers.PhoneNumberMatcher.checkNumberGroupingIsValid = function(numbe * prefix, and return it as a set of digit blocks that would be formatted together. */ function getNationalNumberGroups(util, number, formattingPattern) { - if (formattingPattern == null) { - // This will be in the format +CC-DG;ext=EXT where DG represents groups of digits. - var rfc3966Format = util.format(number, PhoneNumberFormat.RFC3966); - // We remove the extension part from the formatted string before splitting it into different - // groups. - var endIndex = rfc3966Format.indexOf(';'); - if (endIndex < 0) { - endIndex = rfc3966Format.length; - } - // The country-code will have a '-' following it. - var startIndex = rfc3966Format.indexOf('-') + 1; - return rfc3966Format.substring(startIndex, endIndex).split('-'); - } else { - // We format the NSN only, and split that according to the separator. - var nationalSignificantNumber = util.getNationalSignificantNumber(number); - return util.formatNsnUsingPattern( - nationalSignificantNumber, - formattingPattern, - PhoneNumberFormat.RFC3966 - ).split('-'); + if (formattingPattern == null) { + // This will be in the format +CC-DG;ext=EXT where DG represents groups of digits. + var rfc3966Format = util.format(number, PhoneNumberFormat.RFC3966); + // We remove the extension part from the formatted string before splitting it into different + // groups. + var endIndex = rfc3966Format.indexOf(';'); + if (endIndex < 0) { + endIndex = rfc3966Format.length; } + // The country-code will have a '-' following it. + var startIndex = rfc3966Format.indexOf('-') + 1; + return rfc3966Format.substring(startIndex, endIndex).split('-'); + } else { + // We format the NSN only, and split that according to the separator. + var nationalSignificantNumber = util.getNationalSignificantNumber(number); + return util.formatNsnUsingPattern( + nationalSignificantNumber, + formattingPattern, + PhoneNumberFormat.RFC3966 + ).split('-'); + } } diff --git a/javascript/i18n/phonenumbers/phonenumbermatcher_test.js b/javascript/i18n/phonenumbers/phonenumbermatcher_test.js index 859f89e7c..07ecb3bf2 100644 --- a/javascript/i18n/phonenumbers/phonenumbermatcher_test.js +++ b/javascript/i18n/phonenumbers/phonenumbermatcher_test.js @@ -50,129 +50,129 @@ function assertMatchProperties(match, text, number, region) { * its corresponding range is {@code [start, end)}. */ function assertEqualRange(text, index, start, end) { - var sub = text.substring(index, text.length); - var matches = - phoneUtil.findNumbers(sub, RegionCode.NZ, Leniency.POSSIBLE); - assertTrue(matches.hasNext()); - var match = matches.next(); - assertEquals(start - index, match.start); - assertEquals(end - index, match.end); - assertEquals(sub.substring(match.start, match.end), match.rawString); + var sub = text.substring(index, text.length); + var matches = + phoneUtil.findNumbers(sub, RegionCode.NZ, Leniency.POSSIBLE); + assertTrue(matches.hasNext()); + var match = matches.next(); + assertEquals(start - index, match.start); + assertEquals(end - index, match.end); + assertEquals(sub.substring(match.start, match.end), match.rawString); } function testContainsMoreThanOneSlashInNationalNumber() { - // A date should return true. - var number = new PhoneNumber(); - number.setCountryCode(1); - number.setCountryCodeSource(CountryCodeSource.FROM_DEFAULT_COUNTRY); - var candidate = "1/05/2013"; - assertTrue(PhoneNumberMatcher.containsMoreThanOneSlashInNationalNumber(number, candidate)); - - // Here, the country code source thinks it started with a country calling code, but this is not - // the same as the part before the slash, so it's still true. - number = new PhoneNumber(); - number.setCountryCode(274); - number.setCountryCodeSource(CountryCodeSource.FROM_NUMBER_WITHOUT_PLUS_SIGN); - candidate = "27/4/2013"; - assertTrue(PhoneNumberMatcher.containsMoreThanOneSlashInNationalNumber(number, candidate)); - - // Now it should be false, because the first slash is after the country calling code. - number = new PhoneNumber(); - number.setCountryCode(49); - number.setCountryCodeSource(CountryCodeSource.FROM_NUMBER_WITH_PLUS_SIGN); - candidate = "49/69/2013"; - assertFalse(PhoneNumberMatcher.containsMoreThanOneSlashInNationalNumber(number, candidate)); - - number = new PhoneNumber(); - number.setCountryCode(49); - number.setCountryCodeSource(CountryCodeSource.FROM_NUMBER_WITHOUT_PLUS_SIGN); - candidate = "+49/69/2013"; - assertFalse(PhoneNumberMatcher.containsMoreThanOneSlashInNationalNumber(number, candidate)); - - candidate = "+ 49/69/2013"; - assertFalse(PhoneNumberMatcher.containsMoreThanOneSlashInNationalNumber(number, candidate)); - - candidate = "+ 49/69/20/13"; - assertTrue(PhoneNumberMatcher.containsMoreThanOneSlashInNationalNumber(number, candidate)); - - // Here, the first group is not assumed to be the country calling code, even though it is the - // same as it, so this should return true. - number = new PhoneNumber(); - number.setCountryCode(49); - number.setCountryCodeSource(CountryCodeSource.FROM_DEFAULT_COUNTRY); - candidate = "49/69/2013"; - assertTrue(PhoneNumberMatcher.containsMoreThanOneSlashInNationalNumber(number, candidate)); + // A date should return true. + var number = new PhoneNumber(); + number.setCountryCode(1); + number.setCountryCodeSource(CountryCodeSource.FROM_DEFAULT_COUNTRY); + var candidate = "1/05/2013"; + assertTrue(PhoneNumberMatcher.containsMoreThanOneSlashInNationalNumber(number, candidate)); + + // Here, the country code source thinks it started with a country calling code, but this is not + // the same as the part before the slash, so it's still true. + number = new PhoneNumber(); + number.setCountryCode(274); + number.setCountryCodeSource(CountryCodeSource.FROM_NUMBER_WITHOUT_PLUS_SIGN); + candidate = "27/4/2013"; + assertTrue(PhoneNumberMatcher.containsMoreThanOneSlashInNationalNumber(number, candidate)); + + // Now it should be false, because the first slash is after the country calling code. + number = new PhoneNumber(); + number.setCountryCode(49); + number.setCountryCodeSource(CountryCodeSource.FROM_NUMBER_WITH_PLUS_SIGN); + candidate = "49/69/2013"; + assertFalse(PhoneNumberMatcher.containsMoreThanOneSlashInNationalNumber(number, candidate)); + + number = new PhoneNumber(); + number.setCountryCode(49); + number.setCountryCodeSource(CountryCodeSource.FROM_NUMBER_WITHOUT_PLUS_SIGN); + candidate = "+49/69/2013"; + assertFalse(PhoneNumberMatcher.containsMoreThanOneSlashInNationalNumber(number, candidate)); + + candidate = "+ 49/69/2013"; + assertFalse(PhoneNumberMatcher.containsMoreThanOneSlashInNationalNumber(number, candidate)); + + candidate = "+ 49/69/20/13"; + assertTrue(PhoneNumberMatcher.containsMoreThanOneSlashInNationalNumber(number, candidate)); + + // Here, the first group is not assumed to be the country calling code, even though it is the + // same as it, so this should return true. + number = new PhoneNumber(); + number.setCountryCode(49); + number.setCountryCodeSource(CountryCodeSource.FROM_DEFAULT_COUNTRY); + candidate = "49/69/2013"; + assertTrue(PhoneNumberMatcher.containsMoreThanOneSlashInNationalNumber(number, candidate)); } /** See {@link PhoneNumberUtilTest#testParseNationalNumber()}. */ function testFindNationalNumber() { - // same cases as in testParseNationalNumber - doTestFindInContext("033316005", RegionCode.NZ); - // ("33316005", RegionCode.NZ) is omitted since the national prefix is obligatory for these - // types of numbers in New Zealand. - // National prefix attached and some formatting present. - doTestFindInContext("03-331 6005", RegionCode.NZ); - doTestFindInContext("03 331 6005", RegionCode.NZ); - // Testing international prefixes. - // Should strip country code. - doTestFindInContext("0064 3 331 6005", RegionCode.NZ); - // Try again, but this time we have an international number with Region Code US. It should - // recognize the country code and parse accordingly. - doTestFindInContext("01164 3 331 6005", RegionCode.US); - doTestFindInContext("+64 3 331 6005", RegionCode.US); + // same cases as in testParseNationalNumber + doTestFindInContext("033316005", RegionCode.NZ); + // ("33316005", RegionCode.NZ) is omitted since the national prefix is obligatory for these + // types of numbers in New Zealand. + // National prefix attached and some formatting present. + doTestFindInContext("03-331 6005", RegionCode.NZ); + doTestFindInContext("03 331 6005", RegionCode.NZ); + // Testing international prefixes. + // Should strip country code. + doTestFindInContext("0064 3 331 6005", RegionCode.NZ); + // Try again, but this time we have an international number with Region Code US. It should + // recognize the country code and parse accordingly. + doTestFindInContext("01164 3 331 6005", RegionCode.US); + doTestFindInContext("+64 3 331 6005", RegionCode.US); // XXX_FAILING: // doTestFindInContext("64(0)64123456", RegionCode.NZ); - // Check that using a "/" is fine in a phone number. - // Note that real Polish numbers do *not* start with a 0. + // Check that using a "/" is fine in a phone number. + // Note that real Polish numbers do *not* start with a 0. // XXX_FAILING: // doTestFindInContext("0123/456789", RegionCode.PL); - doTestFindInContext("123-456-7890", RegionCode.US); + doTestFindInContext("123-456-7890", RegionCode.US); } /** See {@link PhoneNumberUtilTest#testParseWithInternationalPrefixes()}. */ function testFindWithInternationalPrefixes() { - doTestFindInContext("+1 (650) 333-6000", RegionCode.NZ); - doTestFindInContext("1-650-333-6000", RegionCode.US); - // Calling the US number from Singapore by using different service providers - // 1st test: calling using SingTel IDD service (IDD is 001) - doTestFindInContext("0011-650-333-6000", RegionCode.SG); - // 2nd test: calling using StarHub IDD service (IDD is 008) - doTestFindInContext("0081-650-333-6000", RegionCode.SG); - // 3rd test: calling using SingTel V019 service (IDD is 019) - doTestFindInContext("0191-650-333-6000", RegionCode.SG); - // Calling the US number from Poland - doTestFindInContext("0~01-650-333-6000", RegionCode.PL); - // Using "++" at the start. - doTestFindInContext("++1 (650) 333-6000", RegionCode.PL); - // Using a full-width plus sign. - doTestFindInContext("\uFF0B1 (650) 333-6000", RegionCode.SG); - // The whole number, including punctuation, is here represented in full-width form. - doTestFindInContext("\uFF0B\uFF11\u3000\uFF08\uFF16\uFF15\uFF10\uFF09" - + "\u3000\uFF13\uFF13\uFF13\uFF0D\uFF16\uFF10\uFF10\uFF10", - RegionCode.SG); + doTestFindInContext("+1 (650) 333-6000", RegionCode.NZ); + doTestFindInContext("1-650-333-6000", RegionCode.US); + // Calling the US number from Singapore by using different service providers + // 1st test: calling using SingTel IDD service (IDD is 001) + doTestFindInContext("0011-650-333-6000", RegionCode.SG); + // 2nd test: calling using StarHub IDD service (IDD is 008) + doTestFindInContext("0081-650-333-6000", RegionCode.SG); + // 3rd test: calling using SingTel V019 service (IDD is 019) + doTestFindInContext("0191-650-333-6000", RegionCode.SG); + // Calling the US number from Poland + doTestFindInContext("0~01-650-333-6000", RegionCode.PL); + // Using "++" at the start. + doTestFindInContext("++1 (650) 333-6000", RegionCode.PL); + // Using a full-width plus sign. + doTestFindInContext("\uFF0B1 (650) 333-6000", RegionCode.SG); + // The whole number, including punctuation, is here represented in full-width form. + doTestFindInContext("\uFF0B\uFF11\u3000\uFF08\uFF16\uFF15\uFF10\uFF09" + + "\u3000\uFF13\uFF13\uFF13\uFF0D\uFF16\uFF10\uFF10\uFF10", + RegionCode.SG); } /** See {@link PhoneNumberUtilTest#testParseNationalNumberArgentina()}. */ function testFindNationalNumberArgentina() { - // Test parsing mobile numbers of Argentina. - doTestFindInContext("+54 9 343 555 1212", RegionCode.AR); - doTestFindInContext("0343 15 555 1212", RegionCode.AR); + // Test parsing mobile numbers of Argentina. + doTestFindInContext("+54 9 343 555 1212", RegionCode.AR); + doTestFindInContext("0343 15 555 1212", RegionCode.AR); - doTestFindInContext("+54 9 3715 65 4320", RegionCode.AR); - doTestFindInContext("03715 15 65 4320", RegionCode.AR); + doTestFindInContext("+54 9 3715 65 4320", RegionCode.AR); + doTestFindInContext("03715 15 65 4320", RegionCode.AR); - // Test parsing fixed-line numbers of Argentina. - doTestFindInContext("+54 11 3797 0000", RegionCode.AR); - doTestFindInContext("011 3797 0000", RegionCode.AR); + // Test parsing fixed-line numbers of Argentina. + doTestFindInContext("+54 11 3797 0000", RegionCode.AR); + doTestFindInContext("011 3797 0000", RegionCode.AR); - doTestFindInContext("+54 3715 65 4321", RegionCode.AR); - doTestFindInContext("03715 65 4321", RegionCode.AR); + doTestFindInContext("+54 3715 65 4321", RegionCode.AR); + doTestFindInContext("03715 65 4321", RegionCode.AR); - doTestFindInContext("+54 23 1234 0000", RegionCode.AR); - doTestFindInContext("023 1234 0000", RegionCode.AR); + doTestFindInContext("+54 23 1234 0000", RegionCode.AR); + doTestFindInContext("023 1234 0000", RegionCode.AR); } /** See {@link PhoneNumberUtilTest#testParseWithXInNumber()}. */ @@ -206,174 +206,173 @@ function testFindNumbersWithPlusWithNoRegion() { /** See {@link PhoneNumberUtilTest#testParseExtensions()}. */ function testFindExtensions() { - doTestFindInContext("03 331 6005 ext 3456", RegionCode.NZ); - doTestFindInContext("03-3316005x3456", RegionCode.NZ); - doTestFindInContext("03-3316005 int.3456", RegionCode.NZ); - doTestFindInContext("03 3316005 #3456", RegionCode.NZ); - doTestFindInContext("0~0 1800 7493 524", RegionCode.PL); - doTestFindInContext("(1800) 7493.524", RegionCode.US); - // Check that the last instance of an extension token is matched. - doTestFindInContext("0~0 1800 7493 524 ~1234", RegionCode.PL); - // Verifying bug-fix where the last digit of a number was previously omitted if it was a 0 when - // extracting the extension. Also verifying a few different cases of extensions. - doTestFindInContext("+44 2034567890x456", RegionCode.NZ); - doTestFindInContext("+44 2034567890x456", RegionCode.GB); - doTestFindInContext("+44 2034567890 x456", RegionCode.GB); - doTestFindInContext("+44 2034567890 X456", RegionCode.GB); - doTestFindInContext("+44 2034567890 X 456", RegionCode.GB); - doTestFindInContext("+44 2034567890 X 456", RegionCode.GB); - doTestFindInContext("+44 2034567890 X 456", RegionCode.GB); - - doTestFindInContext("(800) 901-3355 x 7246433", RegionCode.US); - doTestFindInContext("(800) 901-3355 , ext 7246433", RegionCode.US); - doTestFindInContext("(800) 901-3355 ,extension 7246433", RegionCode.US); - // The next test differs from PhoneNumberUtil -> when matching we don't consider a lone comma to - // indicate an extension, although we accept it when parsing. - doTestFindInContext("(800) 901-3355 ,x 7246433", RegionCode.US); - doTestFindInContext("(800) 901-3355 ext: 7246433", RegionCode.US); + doTestFindInContext("03 331 6005 ext 3456", RegionCode.NZ); + doTestFindInContext("03-3316005x3456", RegionCode.NZ); + doTestFindInContext("03-3316005 int.3456", RegionCode.NZ); + doTestFindInContext("03 3316005 #3456", RegionCode.NZ); + doTestFindInContext("0~0 1800 7493 524", RegionCode.PL); + doTestFindInContext("(1800) 7493.524", RegionCode.US); + // Check that the last instance of an extension token is matched. + doTestFindInContext("0~0 1800 7493 524 ~1234", RegionCode.PL); + // Verifying bug-fix where the last digit of a number was previously omitted if it was a 0 when + // extracting the extension. Also verifying a few different cases of extensions. + doTestFindInContext("+44 2034567890x456", RegionCode.NZ); + doTestFindInContext("+44 2034567890x456", RegionCode.GB); + doTestFindInContext("+44 2034567890 x456", RegionCode.GB); + doTestFindInContext("+44 2034567890 X456", RegionCode.GB); + doTestFindInContext("+44 2034567890 X 456", RegionCode.GB); + doTestFindInContext("+44 2034567890 X 456", RegionCode.GB); + doTestFindInContext("+44 2034567890 X 456", RegionCode.GB); + + doTestFindInContext("(800) 901-3355 x 7246433", RegionCode.US); + doTestFindInContext("(800) 901-3355 , ext 7246433", RegionCode.US); + doTestFindInContext("(800) 901-3355 ,extension 7246433", RegionCode.US); + // The next test differs from PhoneNumberUtil -> when matching we don't consider a lone comma to + // indicate an extension, although we accept it when parsing. + doTestFindInContext("(800) 901-3355 ,x 7246433", RegionCode.US); + doTestFindInContext("(800) 901-3355 ext: 7246433", RegionCode.US); } function testFindInterspersedWithSpace() { - doTestFindInContext("0 3 3 3 1 6 0 0 5", RegionCode.NZ); + doTestFindInContext("0 3 3 3 1 6 0 0 5", RegionCode.NZ); } /** * Test matching behavior when starting in the middle of a phone number. */ function testIntermediateParsePositions() { - var text = "Call 033316005 or 032316005!"; - // | | | | | | - // 0 5 10 15 20 25 + var text = "Call 033316005 or 032316005!"; + // | | | | | | + // 0 5 10 15 20 25 - // Iterate over all possible indices. - for (var i = 0; i <= 5; i++) { - assertEqualRange(text, i, 5, 14); - } - // 7 and 8 digits in a row are still parsed as number. + // Iterate over all possible indices. + for (var i = 0; i <= 5; i++) { + assertEqualRange(text, i, 5, 14); + } + // 7 and 8 digits in a row are still parsed as number. // XXX_FAILING: // assertEqualRange(text, 6, 6, 14); // XXX_FAILING: // assertEqualRange(text, 7, 7, 14); - // Anything smaller is skipped to the second instance. - for (i = 8; i <= 19; i++) { - assertEqualRange(text, i, 19, 28); - } + // Anything smaller is skipped to the second instance. + for (i = 8; i <= 19; i++) { + assertEqualRange(text, i, 19, 28); + } } /** See {@link PhoneNumberUtilTest#testParseNumbersMexico()}. */ function testFindNumbersMexico() { - // Test parsing fixed-line numbers of Mexico. - doTestFindInContext("+52 (449)978-0001", RegionCode.MX); - doTestFindInContext("01 (449)978-0001", RegionCode.MX); - doTestFindInContext("(449)978-0001", RegionCode.MX); - - // Test parsing mobile numbers of Mexico. - doTestFindInContext("+52 1 33 1234-5678", RegionCode.MX); - doTestFindInContext("044 (33) 1234-5678", RegionCode.MX); - doTestFindInContext("045 33 1234-5678", RegionCode.MX); + // Test parsing fixed-line numbers of Mexico. + doTestFindInContext("+52 (449)978-0001", RegionCode.MX); + doTestFindInContext("01 (449)978-0001", RegionCode.MX); + doTestFindInContext("(449)978-0001", RegionCode.MX); + + // Test parsing mobile numbers of Mexico. + doTestFindInContext("+52 1 33 1234-5678", RegionCode.MX); + doTestFindInContext("044 (33) 1234-5678", RegionCode.MX); + doTestFindInContext("045 33 1234-5678", RegionCode.MX); } - /** See {@link PhoneNumberUtilTest#testParseWithLeadingZero()}. */ function testFindWithLeadingZero() { - doTestFindInContext("+39 02-36618 300", RegionCode.NZ); - doTestFindInContext("02-36618 300", RegionCode.IT); - doTestFindInContext("312 345 678", RegionCode.IT); + doTestFindInContext("+39 02-36618 300", RegionCode.NZ); + doTestFindInContext("02-36618 300", RegionCode.IT); + doTestFindInContext("312 345 678", RegionCode.IT); } function testMatchesFoundWithMultipleSpaces() { - var number1 = "(415) 666-7777"; - var number2 = "(800) 443-1223"; - var text = number1 + " " + number2; + var number1 = "(415) 666-7777"; + var number2 = "(800) 443-1223"; + var text = number1 + " " + number2; - var iterator = phoneUtil.findNumbers(text, RegionCode.US); - var match = iterator.hasNext() ? iterator.next() : null; - assertMatchProperties(match, text, number1, RegionCode.US); + var iterator = phoneUtil.findNumbers(text, RegionCode.US); + var match = iterator.hasNext() ? iterator.next() : null; + assertMatchProperties(match, text, number1, RegionCode.US); - match = iterator.hasNext() ? iterator.next() : null; - assertMatchProperties(match, text, number2, RegionCode.US); + match = iterator.hasNext() ? iterator.next() : null; + assertMatchProperties(match, text, number2, RegionCode.US); } function testFourMatchesInARow() { - var number1 = "415-666-7777"; - var number2 = "800-443-1223"; - var number3 = "212-443-1223"; - var number4 = "650-443-1223"; - var text = number1 + " - " + number2 + " - " + number3 + " - " + number4; + var number1 = "415-666-7777"; + var number2 = "800-443-1223"; + var number3 = "212-443-1223"; + var number4 = "650-443-1223"; + var text = number1 + " - " + number2 + " - " + number3 + " - " + number4; - var iterator = phoneUtil.findNumbers(text, RegionCode.US); - var match = iterator.hasNext() ? iterator.next() : null; - assertMatchProperties(match, text, number1, RegionCode.US); + var iterator = phoneUtil.findNumbers(text, RegionCode.US); + var match = iterator.hasNext() ? iterator.next() : null; + assertMatchProperties(match, text, number1, RegionCode.US); - match = iterator.hasNext() ? iterator.next() : null; - assertMatchProperties(match, text, number2, RegionCode.US); + match = iterator.hasNext() ? iterator.next() : null; + assertMatchProperties(match, text, number2, RegionCode.US); - match = iterator.hasNext() ? iterator.next() : null; - assertMatchProperties(match, text, number3, RegionCode.US); + match = iterator.hasNext() ? iterator.next() : null; + assertMatchProperties(match, text, number3, RegionCode.US); - match = iterator.hasNext() ? iterator.next() : null; - assertMatchProperties(match, text, number4, RegionCode.US); + match = iterator.hasNext() ? iterator.next() : null; + assertMatchProperties(match, text, number4, RegionCode.US); } function testMatchWithSurroundingZipcodes() { - var number = "415-666-7777"; - var zipPreceding = "My address is CA 34215 - " + number + " is my number."; + var number = "415-666-7777"; + var zipPreceding = "My address is CA 34215 - " + number + " is my number."; - var iterator = phoneUtil.findNumbers(zipPreceding, RegionCode.US); - var match = iterator.hasNext() ? iterator.next() : null; - assertMatchProperties(match, zipPreceding, number, RegionCode.US); + var iterator = phoneUtil.findNumbers(zipPreceding, RegionCode.US); + var match = iterator.hasNext() ? iterator.next() : null; + assertMatchProperties(match, zipPreceding, number, RegionCode.US); - // Now repeat, but this time the phone number has spaces in it. It should still be found. - number = "(415) 666 7777"; + // Now repeat, but this time the phone number has spaces in it. It should still be found. + number = "(415) 666 7777"; - var zipFollowing = "My number is " + number + ". 34215 is my zip-code."; - iterator = phoneUtil.findNumbers(zipFollowing, RegionCode.US); - var matchWithSpaces = iterator.hasNext() ? iterator.next() : null; - assertMatchProperties(matchWithSpaces, zipFollowing, number, RegionCode.US); + var zipFollowing = "My number is " + number + ". 34215 is my zip-code."; + iterator = phoneUtil.findNumbers(zipFollowing, RegionCode.US); + var matchWithSpaces = iterator.hasNext() ? iterator.next() : null; + assertMatchProperties(matchWithSpaces, zipFollowing, number, RegionCode.US); } function testIsLatinLetter() { - assertTrue(PhoneNumberMatcher.isLatinLetter('c')); - assertTrue(PhoneNumberMatcher.isLatinLetter('C')); - assertTrue(PhoneNumberMatcher.isLatinLetter('\u00C9')); - assertTrue(PhoneNumberMatcher.isLatinLetter('\u0301')); // Combining acute accent - // Punctuation, digits and white-space are not considered "latin letters". - assertFalse(PhoneNumberMatcher.isLatinLetter(':')); - assertFalse(PhoneNumberMatcher.isLatinLetter('5')); - assertFalse(PhoneNumberMatcher.isLatinLetter('-')); - assertFalse(PhoneNumberMatcher.isLatinLetter('.')); - assertFalse(PhoneNumberMatcher.isLatinLetter(' ')); - assertFalse(PhoneNumberMatcher.isLatinLetter('\u6211')); // Chinese character - assertFalse(PhoneNumberMatcher.isLatinLetter('\u306E')); // Hiragana letter no + assertTrue(PhoneNumberMatcher.isLatinLetter('c')); + assertTrue(PhoneNumberMatcher.isLatinLetter('C')); + assertTrue(PhoneNumberMatcher.isLatinLetter('\u00C9')); + assertTrue(PhoneNumberMatcher.isLatinLetter('\u0301')); // Combining acute accent + // Punctuation, digits and white-space are not considered "latin letters". + assertFalse(PhoneNumberMatcher.isLatinLetter(':')); + assertFalse(PhoneNumberMatcher.isLatinLetter('5')); + assertFalse(PhoneNumberMatcher.isLatinLetter('-')); + assertFalse(PhoneNumberMatcher.isLatinLetter('.')); + assertFalse(PhoneNumberMatcher.isLatinLetter(' ')); + assertFalse(PhoneNumberMatcher.isLatinLetter('\u6211')); // Chinese character + assertFalse(PhoneNumberMatcher.isLatinLetter('\u306E')); // Hiragana letter no } function testMatchesWithSurroundingLatinChars() { - var possibleOnlyContexts = [ + var possibleOnlyContexts = [ // XXX_FAILING: all failing... // new NumberContext("abc", "def"), // new NumberContext("abc", ""), // new NumberContext("", "def"), - // Latin capital letter e with an acute accent. + // Latin capital letter e with an acute accent. // new NumberContext("\u00C9", ""), - // e with an acute accent decomposed (with combining mark). + // e with an acute accent decomposed (with combining mark). // new NumberContext("e\u0301", ""), - ]; + ]; - // Numbers should not be considered valid, if they are surrounded by Latin characters, but - // should be considered possible. - findMatchesInContexts(possibleOnlyContexts, false, true); + // Numbers should not be considered valid, if they are surrounded by Latin characters, but + // should be considered possible. + findMatchesInContexts(possibleOnlyContexts, false, true); } function testMoneyNotSeenAsPhoneNumber() { - var possibleOnlyContexts = [ + var possibleOnlyContexts = [ // XXX_FAILING: all failing... // new NumberContext("$", ""), // new NumberContext("", "$"), // new NumberContext("\u00A3", ""), // Pound sign // new NumberContext("\u00A5", "") // Yen sign - ]; - findMatchesInContexts(possibleOnlyContexts, false, true); + ]; + findMatchesInContexts(possibleOnlyContexts, false, true); } function testPercentageNotSeenAsPhoneNumber() { @@ -383,131 +382,131 @@ function testPercentageNotSeenAsPhoneNumber() { } function testPhoneNumberWithLeadingOrTrailingMoneyMatches() { - // Because of the space after the 20 (or before the 100) these dollar amounts should not stop - // the actual number from being found. - var contexts = [ + // Because of the space after the 20 (or before the 100) these dollar amounts should not stop + // the actual number from being found. + var contexts = [ // XXX_FAILING: // new NumberContext("$20 ", ""), - new NumberContext("", " 100$") - ]; - findMatchesInContexts(contexts, true, true); + new NumberContext("", " 100$") + ]; + findMatchesInContexts(contexts, true, true); } // XXX_FAILING: /** function testMatchesWithSurroundingLatinCharsAndLeadingPunctuation() { - // Contexts with trailing characters. Leading characters are okay here since the numbers we will - // insert start with punctuation, but trailing characters are still not allowed. - var possibleOnlyContexts = [ - new NumberContext("abc", "def"), - new NumberContext("", "def"), - new NumberContext("", "\u00C9") - ]; - - // Numbers should not be considered valid, if they have trailing Latin characters, but should be - // considered possible. - var numberWithPlus = "+14156667777"; - var numberWithBrackets = "(415)6667777"; - findMatchesInContexts(possibleOnlyContexts, false, true, RegionCode.US, numberWithPlus); - findMatchesInContexts(possibleOnlyContexts, false, true, RegionCode.US, numberWithBrackets); - - var validContexts = [ - new NumberContext("abc", ""), - new NumberContext("\u00C9", ""), - new NumberContext("\u00C9", "."), // Trailing punctuation. - new NumberContext("\u00C9", " def") // Trailing white-space. - ]; - - // Numbers should be considered valid, since they start with punctuation. - findMatchesInContexts(validContexts, true, true, RegionCode.US, numberWithPlus); - findMatchesInContexts(validContexts, true, true, RegionCode.US, numberWithBrackets); + // Contexts with trailing characters. Leading characters are okay here since the numbers we will + // insert start with punctuation, but trailing characters are still not allowed. + var possibleOnlyContexts = [ + new NumberContext("abc", "def"), + new NumberContext("", "def"), + new NumberContext("", "\u00C9") + ]; + + // Numbers should not be considered valid, if they have trailing Latin characters, but should be + // considered possible. + var numberWithPlus = "+14156667777"; + var numberWithBrackets = "(415)6667777"; + findMatchesInContexts(possibleOnlyContexts, false, true, RegionCode.US, numberWithPlus); + findMatchesInContexts(possibleOnlyContexts, false, true, RegionCode.US, numberWithBrackets); + + var validContexts = [ + new NumberContext("abc", ""), + new NumberContext("\u00C9", ""), + new NumberContext("\u00C9", "."), // Trailing punctuation. + new NumberContext("\u00C9", " def") // Trailing white-space. + ]; + + // Numbers should be considered valid, since they start with punctuation. + findMatchesInContexts(validContexts, true, true, RegionCode.US, numberWithPlus); + findMatchesInContexts(validContexts, true, true, RegionCode.US, numberWithBrackets); } */ function testMatchesWithSurroundingChineseChars() { - var validContexts = [ - new NumberContext("\u6211\u7684\u7535\u8BDD\u53F7\u7801\u662F", ""), - new NumberContext("", "\u662F\u6211\u7684\u7535\u8BDD\u53F7\u7801"), - new NumberContext("\u8BF7\u62E8\u6253", "\u6211\u5728\u660E\u5929") - ]; - - // Numbers should be considered valid, since they are surrounded by Chinese. - findMatchesInContexts(validContexts, true, true); + var validContexts = [ + new NumberContext("\u6211\u7684\u7535\u8BDD\u53F7\u7801\u662F", ""), + new NumberContext("", "\u662F\u6211\u7684\u7535\u8BDD\u53F7\u7801"), + new NumberContext("\u8BF7\u62E8\u6253", "\u6211\u5728\u660E\u5929") + ]; + + // Numbers should be considered valid, since they are surrounded by Chinese. + findMatchesInContexts(validContexts, true, true); } function testMatchesWithSurroundingPunctuation() { - var validContexts = [ - new NumberContext("My number-", ""), // At end of text. - new NumberContext("", ".Nice day."), // At start of text. - new NumberContext("Tel:", "."), // Punctuation surrounds number. - new NumberContext("Tel: ", " on Saturdays.") // White-space is also fine. - ]; - - // Numbers should be considered valid, since they are surrounded by punctuation. - findMatchesInContexts(validContexts, true, true); + var validContexts = [ + new NumberContext("My number-", ""), // At end of text. + new NumberContext("", ".Nice day."), // At start of text. + new NumberContext("Tel:", "."), // Punctuation surrounds number. + new NumberContext("Tel: ", " on Saturdays.") // White-space is also fine. + ]; + + // Numbers should be considered valid, since they are surrounded by punctuation. + findMatchesInContexts(validContexts, true, true); } function testMatchesMultiplePhoneNumbersSeparatedByPhoneNumberPunctuation() { - var text = "Call 650-253-4561 -- 455-234-3451"; - var region = RegionCode.US; - - var number1 = new PhoneNumber(); - number1.setCountryCode(phoneUtil.getCountryCodeForRegion(region)); - number1.setNationalNumber(6502534561); // was 6502534561L - var match1 = new PhoneNumberMatch(5, "650-253-4561", number1); - - var number2 = new PhoneNumber(); - number2.setCountryCode(phoneUtil.getCountryCodeForRegion(region)); - number2.setNationalNumber(4552343451); // 4552343451L - var match2 = new PhoneNumberMatch(21, "455-234-3451", number2); - - var matches = phoneUtil.findNumbers(text, region); - assertTrue(match1.equals(matches.next())); - assertTrue(match2.equals(matches.next())); + var text = "Call 650-253-4561 -- 455-234-3451"; + var region = RegionCode.US; + + var number1 = new PhoneNumber(); + number1.setCountryCode(phoneUtil.getCountryCodeForRegion(region)); + number1.setNationalNumber(6502534561); // was 6502534561L + var match1 = new PhoneNumberMatch(5, "650-253-4561", number1); + + var number2 = new PhoneNumber(); + number2.setCountryCode(phoneUtil.getCountryCodeForRegion(region)); + number2.setNationalNumber(4552343451); // 4552343451L + var match2 = new PhoneNumberMatch(21, "455-234-3451", number2); + + var matches = phoneUtil.findNumbers(text, region); + assertTrue(match1.equals(matches.next())); + assertTrue(match2.equals(matches.next())); } function testDoesNotMatchMultiplePhoneNumbersSeparatedWithNoWhiteSpace() { - // No white-space found between numbers - neither is found. - var text = "Call 650-253-4561--455-234-3451"; - var region = RegionCode.US; + // No white-space found between numbers - neither is found. + var text = "Call 650-253-4561--455-234-3451"; + var region = RegionCode.US; - assertTrue(hasNoMatches(phoneUtil.findNumbers(text, region))); + assertTrue(hasNoMatches(phoneUtil.findNumbers(text, region))); } /** * Strings with number-like things that shouldn't be found under any level. */ var IMPOSSIBLE_CASES = [ - new NumberTest("12345", RegionCode.US), - new NumberTest("23456789", RegionCode.US), - new NumberTest("234567890112", RegionCode.US), - new NumberTest("650+253+1234", RegionCode.US), - new NumberTest("3/10/1984", RegionCode.CA), - new NumberTest("03/27/2011", RegionCode.US), - new NumberTest("31/8/2011", RegionCode.US), - new NumberTest("1/12/2011", RegionCode.US), - new NumberTest("10/12/82", RegionCode.DE), - new NumberTest("650x2531234", RegionCode.US), - new NumberTest("2012-01-02 08:00", RegionCode.US), - new NumberTest("2012/01/02 08:00", RegionCode.US), - new NumberTest("20120102 08:00", RegionCode.US), - new NumberTest("2014-04-12 04:04 PM", RegionCode.US), - new NumberTest("2014-04-12  04:04 PM", RegionCode.US), - new NumberTest("2014-04-12  04:04 PM", RegionCode.US), - new NumberTest("2014-04-12 04:04 PM", RegionCode.US) + new NumberTest("12345", RegionCode.US), + new NumberTest("23456789", RegionCode.US), + new NumberTest("234567890112", RegionCode.US), + new NumberTest("650+253+1234", RegionCode.US), + new NumberTest("3/10/1984", RegionCode.CA), + new NumberTest("03/27/2011", RegionCode.US), + new NumberTest("31/8/2011", RegionCode.US), + new NumberTest("1/12/2011", RegionCode.US), + new NumberTest("10/12/82", RegionCode.DE), + new NumberTest("650x2531234", RegionCode.US), + new NumberTest("2012-01-02 08:00", RegionCode.US), + new NumberTest("2012/01/02 08:00", RegionCode.US), + new NumberTest("20120102 08:00", RegionCode.US), + new NumberTest("2014-04-12 04:04 PM", RegionCode.US), + new NumberTest("2014-04-12  04:04 PM", RegionCode.US), + new NumberTest("2014-04-12  04:04 PM", RegionCode.US), + new NumberTest("2014-04-12 04:04 PM", RegionCode.US) ]; /** * Strings with number-like things that should only be found under "possible". */ var POSSIBLE_ONLY_CASES = [ - // US numbers cannot start with 7 in the test metadata to be valid. + // US numbers cannot start with 7 in the test metadata to be valid. // XXX_FAILING: // new NumberTest("7121115678", RegionCode.US), - // 'X' should not be found in numbers at leniencies stricter than POSSIBLE, unless it represents - // a carrier code or extension. - new NumberTest("1650 x 253 - 1234", RegionCode.US), - new NumberTest("650 x 253 - 1234", RegionCode.US) + // 'X' should not be found in numbers at leniencies stricter than POSSIBLE, unless it represents + // a carrier code or extension. + new NumberTest("1650 x 253 - 1234", RegionCode.US), + new NumberTest("650 x 253 - 1234", RegionCode.US) // XXX_FAILING: // new NumberTest("6502531x234", RegionCode.US), // XXX_FAILING: @@ -519,25 +518,25 @@ var POSSIBLE_ONLY_CASES = [ * leniency level. */ var VALID_CASES = [ - new NumberTest("65 02 53 00 00", RegionCode.US), - new NumberTest("6502 538365", RegionCode.US), - new NumberTest("650//253-1234", RegionCode.US), // 2 slashes are illegal at higher levels - new NumberTest("650/253/1234", RegionCode.US), - new NumberTest("9002309. 158", RegionCode.US), - new NumberTest("12 7/8 - 14 12/34 - 5", RegionCode.US), - new NumberTest("12.1 - 23.71 - 23.45", RegionCode.US), - new NumberTest("800 234 1 111x1111", RegionCode.US), - new NumberTest("1979-2011 100", RegionCode.US), - new NumberTest("+494949-4-94", RegionCode.DE), // National number in wrong format - new NumberTest("\uFF14\uFF11\uFF15\uFF16\uFF16\uFF16\uFF16-\uFF17\uFF17\uFF17", RegionCode.US), - new NumberTest("2012-0102 08", RegionCode.US), // Very strange formatting. - new NumberTest("2012-01-02 08", RegionCode.US), - // Breakdown assistance number with unexpected formatting. - new NumberTest("1800-1-0-10 22", RegionCode.AU), - new NumberTest("030-3-2 23 12 34", RegionCode.DE), - new NumberTest("03 0 -3 2 23 12 34", RegionCode.DE), - new NumberTest("(0)3 0 -3 2 23 12 34", RegionCode.DE), - new NumberTest("0 3 0 -3 2 23 12 34", RegionCode.DE) + new NumberTest("65 02 53 00 00", RegionCode.US), + new NumberTest("6502 538365", RegionCode.US), + new NumberTest("650//253-1234", RegionCode.US), // 2 slashes are illegal at higher levels + new NumberTest("650/253/1234", RegionCode.US), + new NumberTest("9002309. 158", RegionCode.US), + new NumberTest("12 7/8 - 14 12/34 - 5", RegionCode.US), + new NumberTest("12.1 - 23.71 - 23.45", RegionCode.US), + new NumberTest("800 234 1 111x1111", RegionCode.US), + new NumberTest("1979-2011 100", RegionCode.US), + new NumberTest("+494949-4-94", RegionCode.DE), // National number in wrong format + new NumberTest("\uFF14\uFF11\uFF15\uFF16\uFF16\uFF16\uFF16-\uFF17\uFF17\uFF17", RegionCode.US), + new NumberTest("2012-0102 08", RegionCode.US), // Very strange formatting. + new NumberTest("2012-01-02 08", RegionCode.US), + // Breakdown assistance number with unexpected formatting. + new NumberTest("1800-1-0-10 22", RegionCode.AU), + new NumberTest("030-3-2 23 12 34", RegionCode.DE), + new NumberTest("03 0 -3 2 23 12 34", RegionCode.DE), + new NumberTest("(0)3 0 -3 2 23 12 34", RegionCode.DE), + new NumberTest("0 3 0 -3 2 23 12 34", RegionCode.DE) ]; /** @@ -545,142 +544,142 @@ var VALID_CASES = [ * "strict_grouping" leniency level. */ var STRICT_GROUPING_CASES = [ - new NumberTest("(415) 6667777", RegionCode.US), - new NumberTest("415-6667777", RegionCode.US), - // Should be found by strict grouping but not exact grouping, as the last two groups are - // formatted together as a block. - new NumberTest("0800-2491234", RegionCode.DE), - // Doesn't match any formatting in the test file, but almost matches an alternate format (the - // last two groups have been squashed together here). - new NumberTest("0900-1 123123", RegionCode.DE), - new NumberTest("(0)900-1 123123", RegionCode.DE), - new NumberTest("0 900-1 123123", RegionCode.DE), - // NDC also found as part of the country calling code; this shouldn't ruin the grouping - // expectations. - new NumberTest("+33 3 34 2312", RegionCode.FR) + new NumberTest("(415) 6667777", RegionCode.US), + new NumberTest("415-6667777", RegionCode.US), + // Should be found by strict grouping but not exact grouping, as the last two groups are + // formatted together as a block. + new NumberTest("0800-2491234", RegionCode.DE), + // Doesn't match any formatting in the test file, but almost matches an alternate format (the + // last two groups have been squashed together here). + new NumberTest("0900-1 123123", RegionCode.DE), + new NumberTest("(0)900-1 123123", RegionCode.DE), + new NumberTest("0 900-1 123123", RegionCode.DE), + // NDC also found as part of the country calling code; this shouldn't ruin the grouping + // expectations. + new NumberTest("+33 3 34 2312", RegionCode.FR) ]; /** * Strings with number-like things that should be found at all levels. */ var EXACT_GROUPING_CASES = [ - new NumberTest("\uFF14\uFF11\uFF15\uFF16\uFF16\uFF16\uFF17\uFF17\uFF17\uFF17", RegionCode.US), - new NumberTest("\uFF14\uFF11\uFF15-\uFF16\uFF16\uFF16-\uFF17\uFF17\uFF17\uFF17", RegionCode.US), - new NumberTest("4156667777", RegionCode.US), - new NumberTest("4156667777 x 123", RegionCode.US), - new NumberTest("415-666-7777", RegionCode.US), - new NumberTest("415/666-7777", RegionCode.US), - new NumberTest("415-666-7777 ext. 503", RegionCode.US), - new NumberTest("1 415 666 7777 x 123", RegionCode.US), - new NumberTest("+1 415-666-7777", RegionCode.US), - new NumberTest("+494949 49", RegionCode.DE), - new NumberTest("+49-49-34", RegionCode.DE), - new NumberTest("+49-4931-49", RegionCode.DE), - new NumberTest("04931-49", RegionCode.DE), // With National Prefix - new NumberTest("+49-494949", RegionCode.DE), // One group with country code - new NumberTest("+49-494949 ext. 49", RegionCode.DE), - new NumberTest("+49494949 ext. 49", RegionCode.DE), - new NumberTest("0494949", RegionCode.DE), - new NumberTest("0494949 ext. 49", RegionCode.DE), - new NumberTest("01 (33) 3461 2234", RegionCode.MX), // Optional NP present - new NumberTest("(33) 3461 2234", RegionCode.MX), // Optional NP omitted - new NumberTest("1800-10-10 22", RegionCode.AU), // Breakdown assistance number. - // Doesn't match any formatting in the test file, but matches an alternate format exactly. - new NumberTest("0900-1 123 123", RegionCode.DE), - new NumberTest("(0)900-1 123 123", RegionCode.DE), - new NumberTest("0 900-1 123 123", RegionCode.DE), - new NumberTest("+33 3 34 23 12", RegionCode.FR) + new NumberTest("\uFF14\uFF11\uFF15\uFF16\uFF16\uFF16\uFF17\uFF17\uFF17\uFF17", RegionCode.US), + new NumberTest("\uFF14\uFF11\uFF15-\uFF16\uFF16\uFF16-\uFF17\uFF17\uFF17\uFF17", RegionCode.US), + new NumberTest("4156667777", RegionCode.US), + new NumberTest("4156667777 x 123", RegionCode.US), + new NumberTest("415-666-7777", RegionCode.US), + new NumberTest("415/666-7777", RegionCode.US), + new NumberTest("415-666-7777 ext. 503", RegionCode.US), + new NumberTest("1 415 666 7777 x 123", RegionCode.US), + new NumberTest("+1 415-666-7777", RegionCode.US), + new NumberTest("+494949 49", RegionCode.DE), + new NumberTest("+49-49-34", RegionCode.DE), + new NumberTest("+49-4931-49", RegionCode.DE), + new NumberTest("04931-49", RegionCode.DE), // With National Prefix + new NumberTest("+49-494949", RegionCode.DE), // One group with country code + new NumberTest("+49-494949 ext. 49", RegionCode.DE), + new NumberTest("+49494949 ext. 49", RegionCode.DE), + new NumberTest("0494949", RegionCode.DE), + new NumberTest("0494949 ext. 49", RegionCode.DE), + new NumberTest("01 (33) 3461 2234", RegionCode.MX), // Optional NP present + new NumberTest("(33) 3461 2234", RegionCode.MX), // Optional NP omitted + new NumberTest("1800-10-10 22", RegionCode.AU), // Breakdown assistance number. + // Doesn't match any formatting in the test file, but matches an alternate format exactly. + new NumberTest("0900-1 123 123", RegionCode.DE), + new NumberTest("(0)900-1 123 123", RegionCode.DE), + new NumberTest("0 900-1 123 123", RegionCode.DE), + new NumberTest("+33 3 34 23 12", RegionCode.FR) ]; function testMatchesWithPossibleLeniency() { - var testCases = [].concat(STRICT_GROUPING_CASES) - .concat(EXACT_GROUPING_CASES) - .concat(VALID_CASES) - .concat(POSSIBLE_ONLY_CASES); - doTestNumberMatchesForLeniency(testCases, Leniency.POSSIBLE); + var testCases = [].concat(STRICT_GROUPING_CASES) + .concat(EXACT_GROUPING_CASES) + .concat(VALID_CASES) + .concat(POSSIBLE_ONLY_CASES); + doTestNumberMatchesForLeniency(testCases, Leniency.POSSIBLE); } function testNonMatchesWithPossibleLeniency() { - doTestNumberNonMatchesForLeniency(IMPOSSIBLE_CASES, Leniency.POSSIBLE); + doTestNumberNonMatchesForLeniency(IMPOSSIBLE_CASES, Leniency.POSSIBLE); } function testMatchesWithValidLeniency() { - var testCases = [].concat(STRICT_GROUPING_CASES) - .concat(EXACT_GROUPING_CASES) - .concat(VALID_CASES); - doTestNumberMatchesForLeniency(testCases, Leniency.VALID); + var testCases = [].concat(STRICT_GROUPING_CASES) + .concat(EXACT_GROUPING_CASES) + .concat(VALID_CASES); + doTestNumberMatchesForLeniency(testCases, Leniency.VALID); } function testNonMatchesWithValidLeniency() { - var testCases = [].concat(IMPOSSIBLE_CASES); + var testCases = [].concat(IMPOSSIBLE_CASES); // XXX_FAILING: // .concat(POSSIBLE_ONLY_CASES); - doTestNumberNonMatchesForLeniency(testCases, Leniency.VALID); + doTestNumberNonMatchesForLeniency(testCases, Leniency.VALID); } function testMatchesWithStrictGroupingLeniency() { - var testCases = [].concat(STRICT_GROUPING_CASES) - .concat(EXACT_GROUPING_CASES); - doTestNumberMatchesForLeniency(testCases, Leniency.STRICT_GROUPING); + var testCases = [].concat(STRICT_GROUPING_CASES) + .concat(EXACT_GROUPING_CASES); + doTestNumberMatchesForLeniency(testCases, Leniency.STRICT_GROUPING); } function testNonMatchesWithStrictGroupLeniency() { - var testCases = [].concat(IMPOSSIBLE_CASES); + var testCases = [].concat(IMPOSSIBLE_CASES); // XXX_FAILING: // .concat(POSSIBLE_ONLY_CASES) // XXX_FAILING: // .concat(VALID_CASES); - doTestNumberNonMatchesForLeniency(testCases, Leniency.STRICT_GROUPING); + doTestNumberNonMatchesForLeniency(testCases, Leniency.STRICT_GROUPING); } function testMatchesWithExactGroupingLeniency() { - doTestNumberMatchesForLeniency(EXACT_GROUPING_CASES, Leniency.EXACT_GROUPING); + doTestNumberMatchesForLeniency(EXACT_GROUPING_CASES, Leniency.EXACT_GROUPING); } function testNonMatchesExactGroupLeniency() { - var testCases = [].concat(IMPOSSIBLE_CASES); + var testCases = [].concat(IMPOSSIBLE_CASES); // XXX_FAILING: // .concat(POSSIBLE_ONLY_CASES) // XXX_FAILING: // .concat(VALID_CASES) // XXX_FAILING: // .concat(STRICT_GROUPING_CASES) - doTestNumberNonMatchesForLeniency(testCases, Leniency.EXACT_GROUPING); + doTestNumberNonMatchesForLeniency(testCases, Leniency.EXACT_GROUPING); } function doTestNumberMatchesForLeniency(testCases, leniency) { - var noMatchFoundCount = 0; - var wrongMatchFoundCount = 0; - - testCases.forEach(function(test) { - var iterator = findNumbersForLeniency(test.rawString, test.region, leniency); - var match = iterator.hasNext() ? iterator.next() : null; - if (match == null) { - noMatchFoundCount++; - console.log("[doTestNumberMatchesForLeniency] No match found in " + test + " for leniency: " + leniency); - } else { - if (!test.rawString == match.rawString) { - wrongMatchFoundCount++; - console.log("[doTestNumberMatchesForLeniency] Found wrong match in test + " + test + ". Found " + match.rawString); - } - } - }); + var noMatchFoundCount = 0; + var wrongMatchFoundCount = 0; - assertEquals(0, noMatchFoundCount); - assertEquals(0, wrongMatchFoundCount); + testCases.forEach(function(test) { + var iterator = findNumbersForLeniency(test.rawString, test.region, leniency); + var match = iterator.hasNext() ? iterator.next() : null; + if (match == null) { + noMatchFoundCount++; + console.log("[doTestNumberMatchesForLeniency] No match found in " + test + " for leniency: " + leniency); + } else { + if (!test.rawString == match.rawString) { + wrongMatchFoundCount++; + console.log("[doTestNumberMatchesForLeniency] Found wrong match in test + " + test + ". Found " + match.rawString); + } + } + }); + + assertEquals(0, noMatchFoundCount); + assertEquals(0, wrongMatchFoundCount); } function doTestNumberNonMatchesForLeniency(testCases, leniency) { - var matchFoundCount = 0; - testCases.forEach(function(test) { - var iterator = findNumbersForLeniency(test.rawString, test.region, leniency); - var match = iterator.hasNext() ? iterator.next() : null; - if (match != null) { - matchFoundCount++; - console.log("[doTestNumberNonMatchesForLeniency] Match found in " + test + " for leniency: " + leniency); - } - }); - assertEquals(0, matchFoundCount); + var matchFoundCount = 0; + testCases.forEach(function(test) { + var iterator = findNumbersForLeniency(test.rawString, test.region, leniency); + var match = iterator.hasNext() ? iterator.next() : null; + if (match != null) { + matchFoundCount++; + console.log("[doTestNumberNonMatchesForLeniency] Match found in " + test + " for leniency: " + leniency); + } + }); + assertEquals(0, matchFoundCount); } /** @@ -691,31 +690,31 @@ function doTestNumberNonMatchesForLeniency(testCases, leniency) { * matching is set to POSSIBLE; else no test number should be extracted at that leniency level */ function findMatchesInContexts(contexts, isValid, isPossible, region, number) { - region = region || RegionCode.US; - number = number || "415-666-7777"; - - if (isValid) { - doTestInContext(number, region, contexts, Leniency.VALID); - } else { - contexts.forEach(function(context) { - var text = context.leadingText + number + context.trailingText; - assertTrue("Should not have found a number in " + text, - hasNoMatches(phoneUtil.findNumbers(text, region))); - }); - } - if (isPossible) { - doTestInContext(number, region, contexts, Leniency.POSSIBLE); - } else { - contexts.forEach(function(context) { - var text = context.leadingText + number + context.trailingText; - assertTrue("Should not have found a number in " + text, - hasNoMatches(phoneUtil.findNumbers(text, region, Leniency.POSSIBLE))); - }); - } + region = region || RegionCode.US; + number = number || "415-666-7777"; + + if (isValid) { + doTestInContext(number, region, contexts, Leniency.VALID); + } else { + contexts.forEach(function(context) { + var text = context.leadingText + number + context.trailingText; + assertTrue("Should not have found a number in " + text, + hasNoMatches(phoneUtil.findNumbers(text, region))); + }); + } + if (isPossible) { + doTestInContext(number, region, contexts, Leniency.POSSIBLE); + } else { + contexts.forEach(function(context) { + var text = context.leadingText + number + context.trailingText; + assertTrue("Should not have found a number in " + text, + hasNoMatches(phoneUtil.findNumbers(text, region, Leniency.POSSIBLE))); + }); + } } function hasNoMatches(iterable) { - return iterable.hasNext() === false; + return iterable.hasNext() === false; } function testNonMatchingBracketsAreInvalid() { @@ -748,221 +747,218 @@ function testNoMatchIfRegionIsNull() { } function testNoMatchInEmptyString() { - assertTrue(hasNoMatches(phoneUtil.findNumbers("", RegionCode.US))); - assertTrue(hasNoMatches(phoneUtil.findNumbers(" ", RegionCode.US))); + assertTrue(hasNoMatches(phoneUtil.findNumbers("", RegionCode.US))); + assertTrue(hasNoMatches(phoneUtil.findNumbers(" ", RegionCode.US))); } function testNoMatchIfNoNumber() { - assertTrue(hasNoMatches(phoneUtil.findNumbers( - "Random text body - number is foobar, see you there", RegionCode.US))); + assertTrue(hasNoMatches(phoneUtil.findNumbers( + "Random text body - number is foobar, see you there", RegionCode.US))); } function testNullInput() { - assertTrue(hasNoMatches(phoneUtil.findNumbers(null, RegionCode.US))); + assertTrue(hasNoMatches(phoneUtil.findNumbers(null, RegionCode.US))); // XXX_FAILING: - throws exception because region is intentionally null? // assertTrue(hasNoMatches(phoneUtil.findNumbers(null, null))); } function testMaxMatches() { - // Set up text with 100 valid phone numbers. - var numbers = ""; - for (var i = 0; i < 100; i++) { - numbers += "My info: 415-666-7777,"; - } + // Set up text with 100 valid phone numbers. + var numbers = ""; + for (var i = 0; i < 100; i++) { + numbers += "My info: 415-666-7777,"; + } - // Matches all 100. Max only applies to failed cases. - var expected = []; - var number = phoneUtil.parse("+14156667777", null); - for (i = 0; i < 100; i++) { - expected.push(number); - } + // Matches all 100. Max only applies to failed cases. + var expected = []; + var number = phoneUtil.parse("+14156667777", null); + for (i = 0; i < 100; i++) { + expected.push(number); + } - var iterable = - phoneUtil.findNumbers(numbers, RegionCode.US, Leniency.VALID, 10); - var actual = []; - while(iterable.hasNext()) { - var match = iterable.next(); - actual.push(match.number); - } + var iterable = phoneUtil.findNumbers(numbers, RegionCode.US, Leniency.VALID, 10); + var actual = []; + while(iterable.hasNext()) { + var match = iterable.next(); + actual.push(match.number); + } - assertEquals(expected.length, actual.length); - var expectedNumber; - var actualNumber; - for(i = 0; i < 100; i++) { - expectedNumber = expected[i]; - actualNumber = actual[i]; - assertTrue(expectedNumber.equals(actualNumber)); - } + assertEquals(expected.length, actual.length); + var expectedNumber; + var actualNumber; + for(i = 0; i < 100; i++) { + expectedNumber = expected[i]; + actualNumber = actual[i]; + assertTrue(expectedNumber.equals(actualNumber)); + } } function testMaxMatchesInvalid() { - // Set up text with 10 invalid phone numbers followed by 100 valid. - var numbers = ""; - for (var i = 0; i < 10; i++) { - numbers += "My address 949-8945-0"; - } - for (i = 0; i < 100; i++) { - numbers += "My info: 415-666-7777,"; - } + // Set up text with 10 invalid phone numbers followed by 100 valid. + var numbers = ""; + for (var i = 0; i < 10; i++) { + numbers += "My address 949-8945-0"; + } + for (i = 0; i < 100; i++) { + numbers += "My info: 415-666-7777,"; + } - var iterable = - phoneUtil.findNumbers(numbers, RegionCode.US, Leniency.VALID, 10); - assertFalse(iterable.hasNext()); + var iterable = phoneUtil.findNumbers(numbers, RegionCode.US, Leniency.VALID, 10); + assertFalse(iterable.hasNext()); } function testMaxMatchesMixed() { - // Set up text with 100 valid numbers inside an invalid number. - var numbers = ""; - for (var i = 0; i < 100; i++) { - numbers += "My info: 415-666-7777 123 fake street"; - } + // Set up text with 100 valid numbers inside an invalid number. + var numbers = ""; + for (var i = 0; i < 100; i++) { + numbers += "My info: 415-666-7777 123 fake street"; + } - // Only matches the first 10 despite there being 100 numbers due to max matches. - var expected = []; - var number = phoneUtil.parse("+14156667777", null); - for (i = 0; i < 10; i++) { - expected.push(number); - } + // Only matches the first 10 despite there being 100 numbers due to max matches. + var expected = []; + var number = phoneUtil.parse("+14156667777", null); + for (i = 0; i < 10; i++) { + expected.push(number); + } - var iterable = - phoneUtil.findNumbers(numbers, RegionCode.US, Leniency.VALID, 10); - var actual = []; - var match; - while(iterable.hasNext()) { - match = iterable.next(); - actual.push(match.number); - } + var iterable = + phoneUtil.findNumbers(numbers, RegionCode.US, Leniency.VALID, 10); + var actual = []; + var match; + while(iterable.hasNext()) { + match = iterable.next(); + actual.push(match.number); + } - assertEquals(expected.length, actual.length); - var expectedNumber; - var actualNumber; - for(i = 0; i < 10; i++) { - expectedNumber = expected[i]; - actualNumber = actual[i]; - assertTrue(expectedNumber.equals(actualNumber)); - } + assertEquals(expected.length, actual.length); + var expectedNumber; + var actualNumber; + for(i = 0; i < 10; i++) { + expectedNumber = expected[i]; + actualNumber = actual[i]; + assertTrue(expectedNumber.equals(actualNumber)); + } } // XXX_FAILING: ZZ region not valid? /** function testNonPlusPrefixedNumbersNotFoundForInvalidRegion() { - // Does not start with a "+", we won't match it. - var iterator = phoneUtil.findNumbers("1 456 764 156", RegionCode.ZZ); - - assertFalse(iterator.hasNext()); - try { - iterator.next(); - fail("Violation of the Iterator contract."); - } catch (e) { - // Success - } - assertFalse(iterator.hasNext()); + // Does not start with a "+", we won't match it. + var iterator = phoneUtil.findNumbers("1 456 764 156", RegionCode.ZZ); + + assertFalse(iterator.hasNext()); + try { + iterator.next(); + fail("Violation of the Iterator contract."); + } catch (e) { + // Success } + assertFalse(iterator.hasNext()); +} function testEmptyIteration() { - var iterator = phoneUtil.findNumbers("", RegionCode.ZZ); - - assertFalse(iterator.hasNext()); - assertFalse(iterator.hasNext()); - try { - iterator.next(); - fail("Violation of the Iterator contract."); - } catch (e) { - // Success - } - assertFalse(iterator.hasNext()); + var iterator = phoneUtil.findNumbers("", RegionCode.ZZ); + + assertFalse(iterator.hasNext()); + assertFalse(iterator.hasNext()); + try { + iterator.next(); + fail("Violation of the Iterator contract."); + } catch (e) { + // Success + } + assertFalse(iterator.hasNext()); } public void testSingleIteration() { - var iterator = phoneUtil.findNumbers("+14156667777", RegionCode.ZZ); - - // With hasNext() -> next(). - // Double hasNext() to ensure it does not advance. - assertTrue(iterator.hasNext()); - assertTrue(iterator.hasNext()); - assertNotNull(iterator.next()); - assertFalse(iterator.hasNext()); - try { - iterator.next(); - fail("Violation of the Iterator contract."); - } catch (e) { - // Success - } - assertFalse(iterator.hasNext()); - - // With next() only. - assertNotNull(iterator.next()); - try { - iterator.next(); - fail("Violation of the Iterator contract."); - } catch (e) { - // Success - } + var iterator = phoneUtil.findNumbers("+14156667777", RegionCode.ZZ); + + // With hasNext() -> next(). + // Double hasNext() to ensure it does not advance. + assertTrue(iterator.hasNext()); + assertTrue(iterator.hasNext()); + assertNotNull(iterator.next()); + assertFalse(iterator.hasNext()); + try { + iterator.next(); + fail("Violation of the Iterator contract."); + } catch (e) { + // Success + } + assertFalse(iterator.hasNext()); + + // With next() only. + assertNotNull(iterator.next()); + try { + iterator.next(); + fail("Violation of the Iterator contract."); + } catch (e) { + // Success + } } function testDoubleIteration() { - var iterator = - phoneUtil.findNumbers("+14156667777 foobar +14156667777 ", RegionCode.ZZ); - - // With hasNext() -> next(). - // Double hasNext() to ensure it does not advance. - assertTrue(iterator.hasNext()); - assertTrue(iterator.hasNext()); - assertNotNull(iterator.next()); - assertTrue(iterator.hasNext()); - assertTrue(iterator.hasNext()); - assertNotNull(iterator.next()); - assertFalse(iterator.hasNext()); - try { - iterator.next(); - fail("Violation of the Iterator contract."); - } catch (e) { - // Success - } - assertFalse(iterator.hasNext()); - - // With next() only. - assertNotNull(iterator.next()); - assertNotNull(iterator.next()); - try { - iterator.next(); - fail("Violation of the Iterator contract."); - } catch (e) { - // Success - } + var iterator = + phoneUtil.findNumbers("+14156667777 foobar +14156667777 ", RegionCode.ZZ); + + // With hasNext() -> next(). + // Double hasNext() to ensure it does not advance. + assertTrue(iterator.hasNext()); + assertTrue(iterator.hasNext()); + assertNotNull(iterator.next()); + assertTrue(iterator.hasNext()); + assertTrue(iterator.hasNext()); + assertNotNull(iterator.next()); + assertFalse(iterator.hasNext()); + try { + iterator.next(); + fail("Violation of the Iterator contract."); + } catch (e) { + // Success + } + assertFalse(iterator.hasNext()); + + // With next() only. + assertNotNull(iterator.next()); + assertNotNull(iterator.next()); + try { + iterator.next(); + fail("Violation of the Iterator contract."); + } catch (e) { + // Success + } } function testRemovalNotSupported() { - var = phoneUtil.findNumbers("+14156667777", RegionCode.ZZ); + var = phoneUtil.findNumbers("+14156667777", RegionCode.ZZ); - try { - iterator.remove(); - fail("Iterator must not support remove."); - } catch (e) { - // success - } + try { + iterator.remove(); + fail("Iterator must not support remove."); + } catch (e) { + // success + } - assertTrue(iterator.hasNext()); + assertTrue(iterator.hasNext()); - try { - iterator.remove(); - fail("Iterator must not support remove."); - } catch (e) { - // success - } + try { + iterator.remove(); + fail("Iterator must not support remove."); + } catch (e) { + // success + } - assertNotNull(iterator.next()); + assertNotNull(iterator.next()); - try { - iterator.remove(); - fail("Iterator must not support remove."); - } catch (e) { - // success - } + try { + iterator.remove(); + fail("Iterator must not support remove."); + } catch (e) { + // success + } - assertFalse(iterator.hasNext()); + assertFalse(iterator.hasNext()); } - */ /** @@ -972,74 +968,73 @@ function testRemovalNotSupported() { * @param number the number to test and the corresponding region code to use */ function doTestFindInContext(number, defaultCountry) { - findPossibleInContext(number, defaultCountry); + findPossibleInContext(number, defaultCountry); - var parsed = phoneUtil.parse(number, defaultCountry); - if (phoneUtil.isValidNumber(parsed)) { - findValidInContext(number, defaultCountry); - } + var parsed = phoneUtil.parse(number, defaultCountry); + if (phoneUtil.isValidNumber(parsed)) { + findValidInContext(number, defaultCountry); + } } /** * Tests valid numbers in contexts that should pass for {@link Leniency#POSSIBLE}. */ function findPossibleInContext(number, defaultCountry) { - var contextPairs = [ - new NumberContext("", ""), // no context - new NumberContext(" ", "\t"), // whitespace only - new NumberContext("Hello ", ""), // no context at end - new NumberContext("", " to call me!"), // no context at start - new NumberContext("Hi there, call ", " to reach me!"), // no context at start - new NumberContext("Hi there, call ", ", or don't"), // with commas - // Three examples without whitespace around the number. - new NumberContext("Hi call", ""), + var contextPairs = [ + new NumberContext("", ""), // no context + new NumberContext(" ", "\t"), // whitespace only + new NumberContext("Hello ", ""), // no context at end + new NumberContext("", " to call me!"), // no context at start + new NumberContext("Hi there, call ", " to reach me!"), // no context at start + new NumberContext("Hi there, call ", ", or don't"), // with commas + // Three examples without whitespace around the number. + new NumberContext("Hi call", ""), // XXX_FAILING: // new NumberContext("", "forme"), // XXX_FAILING: // new NumberContext("Hi call", "forme"), - // With other small numbers. - new NumberContext("It's cheap! Call ", " before 6:30"), - // With a second number later. - new NumberContext("Call ", " or +1800-123-4567!"), - new NumberContext("Call me on June 2 at", ""), // with a Month-Day date - // With publication pages. - new NumberContext("As quoted by Alfonso 12-15 (2009), you may call me at ", ""), - new NumberContext("As quoted by Alfonso et al. 12-15 (2009), you may call me at ", ""), - // With dates, written in the American style. - new NumberContext("As I said on 03/10/2011, you may call me at ", ""), - // With trailing numbers after a comma. The 45 should not be considered an extension. - new NumberContext("", ", 45 days a year"), - // When matching we don't consider semicolon along with legitimate extension symbol to indicate - // an extension. The 7246433 should not be considered an extension. - new NumberContext("", ";x 7246433"), - // With a postfix stripped off as it looks like the start of another number. - new NumberContext("Call ", "/x12 more") - ]; - - doTestInContext(number, defaultCountry, contextPairs, Leniency.POSSIBLE); + // With other small numbers. + new NumberContext("It's cheap! Call ", " before 6:30"), + // With a second number later. + new NumberContext("Call ", " or +1800-123-4567!"), + new NumberContext("Call me on June 2 at", ""), // with a Month-Day date + // With publication pages. + new NumberContext("As quoted by Alfonso 12-15 (2009), you may call me at ", ""), + new NumberContext("As quoted by Alfonso et al. 12-15 (2009), you may call me at ", ""), + // With dates, written in the American style. + new NumberContext("As I said on 03/10/2011, you may call me at ", ""), + // With trailing numbers after a comma. The 45 should not be considered an extension. + new NumberContext("", ", 45 days a year"), + // When matching we don't consider semicolon along with legitimate extension symbol to indicate + // an extension. The 7246433 should not be considered an extension. + new NumberContext("", ";x 7246433"), + // With a postfix stripped off as it looks like the start of another number. + new NumberContext("Call ", "/x12 more") + ]; + + doTestInContext(number, defaultCountry, contextPairs, Leniency.POSSIBLE); } function doTestInContext(number, defaultCountry, contextPairs, leniency) { - contextPairs.forEach(function(context) { - var prefix = context.leadingText; - var text = prefix + number + context.trailingText; - - var start = prefix.length; - var end = start + number.length; - var iterator = - phoneUtil.findNumbers(text, defaultCountry, leniency); - - var match = iterator.hasNext() ? iterator.next() : null; - assertNotNull("Did not find a number in '" + text + "'; expected '" + number + "'", match); - - var extracted = text.substring(match.start, match.end); - assertTrue("Unexpected phone region in '" + text + "'; extracted '" + extracted + "'", - start == match.start && end == match.end); - assertEquals(number, extracted); - assertEquals(match.rawString, extracted); - - ensureTermination(text, defaultCountry, leniency); - }); + contextPairs.forEach(function(context) { + var prefix = context.leadingText; + var text = prefix + number + context.trailingText; + + var start = prefix.length; + var end = start + number.length; + var iterator = phoneUtil.findNumbers(text, defaultCountry, leniency); + + var match = iterator.hasNext() ? iterator.next() : null; + assertNotNull("Did not find a number in '" + text + "'; expected '" + number + "'", match); + + var extracted = text.substring(match.start, match.end); + assertTrue("Unexpected phone region in '" + text + "'; extracted '" + extracted + "'", + start == match.start && end == match.end); + assertEquals(number, extracted); + assertEquals(match.rawString, extracted); + + ensureTermination(text, defaultCountry, leniency); + }); } /** @@ -1047,18 +1042,17 @@ function doTestInContext(number, defaultCountry, contextPairs, leniency) { * finding matches always terminates. */ function ensureTermination(text, defaultCountry, leniency) { - for (var index = 0; index <= text.length; index++) { - var sub = text.substring(index); - var matches = ""; - // Iterates over all matches. - var iterator = - phoneUtil.findNumbers(sub, defaultCountry, leniency); - - while(iterator.hasNext()) { - var match = iterator.next(); - matches += ", " + match.toString(); - } + for (var index = 0; index <= text.length; index++) { + var sub = text.substring(index); + var matches = ""; + // Iterates over all matches. + var iterator = phoneUtil.findNumbers(sub, defaultCountry, leniency); + + while(iterator.hasNext()) { + var match = iterator.next(); + matches += ", " + match.toString(); } + } } /** @@ -1066,20 +1060,20 @@ function ensureTermination(text, defaultCountry, leniency) { * {@link Leniency#VALID}. */ function findValidInContext(number, defaultCountry) { - var contextPairs = [ - // With other small numbers. - new NumberContext("It's only 9.99! Call ", " to buy"), - // With a number Day.Month.Year date. - new NumberContext("Call me on 21.6.1984 at ", ""), - // With a number Month/Day date. - new NumberContext("Call me on 06/21 at ", ""), - // With a number Day.Month date. - new NumberContext("Call me on 21.6. at ", ""), - // With a number Month/Day/Year date. - new NumberContext("Call me on 06/21/84 at ", "") - ]; - - doTestInContext(number, defaultCountry, contextPairs, Leniency.VALID); + var contextPairs = [ + // With other small numbers. + new NumberContext("It's only 9.99! Call ", " to buy"), + // With a number Day.Month.Year date. + new NumberContext("Call me on 21.6.1984 at ", ""), + // With a number Month/Day date. + new NumberContext("Call me on 06/21 at ", ""), + // With a number Day.Month date. + new NumberContext("Call me on 21.6. at ", ""), + // With a number Month/Day/Year date. + new NumberContext("Call me on 06/21/84 at ", "") + ]; + + doTestInContext(number, defaultCountry, contextPairs, Leniency.VALID); } function findNumbersForLeniency(text, defaultCountry, leniency) { @@ -1091,17 +1085,17 @@ function findNumbersForLeniency(text, defaultCountry, leniency) { * insert the phone number to be found between leadingText and trailingText. */ function NumberContext(leadingText, trailingText) { - this.leadingText = leadingText; - this.trailingText = trailingText; + this.leadingText = leadingText; + this.trailingText = trailingText; } /** * Small class that holds the number we want to test and the region for which it should be valid. */ function NumberTest(rawString, region) { - this.rawString = rawString; - this.region = region; + this.rawString = rawString; + this.region = region; } NumberTest.prototype.toString = function() { - return this.rawString + " (" + this.region + ")"; + return this.rawString + " (" + this.region + ")"; }; diff --git a/javascript/i18n/phonenumbers/phonenumberutil_test.html b/javascript/i18n/phonenumbers/phonenumberutil_test.html index d91d4276e..604890b4b 100644 --- a/javascript/i18n/phonenumbers/phonenumberutil_test.html +++ b/javascript/i18n/phonenumbers/phonenumberutil_test.html @@ -21,6 +21,7 @@ limitations under the License. --> libphonenumber Unit Tests - i18n.phonenumbers - phonenumberutil.js +