152699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia/*
2ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia * Copyright (C) 2011 The Libphonenumber Authors
352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia *
452699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia * Licensed under the Apache License, Version 2.0 (the "License");
552699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia * you may not use this file except in compliance with the License.
652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia * You may obtain a copy of the License at
752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia *
852699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia * http://www.apache.org/licenses/LICENSE-2.0
952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia *
1052699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia * Unless required by applicable law or agreed to in writing, software
1152699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia * distributed under the License is distributed on an "AS IS" BASIS,
1252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia * See the License for the specific language governing permissions and
1452699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia * limitations under the License.
1552699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia */
1652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
17a77faddfc3b3e4cca8f585c82d669054aec221f4Narayan Kamathpackage com.google.i18n.phonenumbers;
1852699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
19a77faddfc3b3e4cca8f585c82d669054aec221f4Narayan Kamathimport com.google.i18n.phonenumbers.PhoneNumberUtil.Leniency;
20a77faddfc3b3e4cca8f585c82d669054aec221f4Narayan Kamathimport com.google.i18n.phonenumbers.Phonenumber.PhoneNumber;
21a77faddfc3b3e4cca8f585c82d669054aec221f4Narayan Kamathimport com.google.i18n.phonenumbers.Phonenumber.PhoneNumber.CountryCodeSource;
2252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
2352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jiaimport java.util.ArrayList;
24f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jiaimport java.util.Arrays;
2552699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jiaimport java.util.Iterator;
2652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jiaimport java.util.List;
2752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jiaimport java.util.NoSuchElementException;
2852699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
2952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia/**
3052699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia * Tests for {@link PhoneNumberMatcher}. This only tests basic functionality based on test metadata.
3152699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia *
3252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia * @see PhoneNumberUtilTest {@link PhoneNumberUtilTest} for the origin of the test data
3352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia */
34b0e21c22b1ca6b9aeb1426924cdf42a221c3d416Shaopeng Jiapublic class PhoneNumberMatcherTest extends TestMetadataTestCase {
3552699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
36bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia  public void testContainsMoreThanOneSlashInNationalNumber() throws Exception {
37bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia    // A date should return true.
38bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia    PhoneNumber number = new PhoneNumber();
39bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia    number.setCountryCode(1);
40bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia    number.setCountryCodeSource(CountryCodeSource.FROM_DEFAULT_COUNTRY);
41bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia    String candidate = "1/05/2013";
42bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia    assertTrue(PhoneNumberMatcher.containsMoreThanOneSlashInNationalNumber(number, candidate));
43bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia
44bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia    // Here, the country code source thinks it started with a country calling code, but this is not
45bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia    // the same as the part before the slash, so it's still true.
46bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia    number = new PhoneNumber();
47bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia    number.setCountryCode(274);
48bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia    number.setCountryCodeSource(CountryCodeSource.FROM_NUMBER_WITHOUT_PLUS_SIGN);
49bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia    candidate = "27/4/2013";
50bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia    assertTrue(PhoneNumberMatcher.containsMoreThanOneSlashInNationalNumber(number, candidate));
51bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia
52bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia    // Now it should be false, because the first slash is after the country calling code.
53bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia    number = new PhoneNumber();
54bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia    number.setCountryCode(49);
55bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia    number.setCountryCodeSource(CountryCodeSource.FROM_NUMBER_WITH_PLUS_SIGN);
56bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia    candidate = "49/69/2013";
57bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia    assertFalse(PhoneNumberMatcher.containsMoreThanOneSlashInNationalNumber(number, candidate));
58bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia
59bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia    number = new PhoneNumber();
60bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia    number.setCountryCode(49);
61bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia    number.setCountryCodeSource(CountryCodeSource.FROM_NUMBER_WITHOUT_PLUS_SIGN);
62bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia    candidate = "+49/69/2013";
63bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia    assertFalse(PhoneNumberMatcher.containsMoreThanOneSlashInNationalNumber(number, candidate));
64bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia
65bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia    candidate = "+ 49/69/2013";
66bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia    assertFalse(PhoneNumberMatcher.containsMoreThanOneSlashInNationalNumber(number, candidate));
67bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia
68bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia    candidate = "+ 49/69/20/13";
69bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia    assertTrue(PhoneNumberMatcher.containsMoreThanOneSlashInNationalNumber(number, candidate));
70bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia
71bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia    // Here, the first group is not assumed to be the country calling code, even though it is the
72bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia    // same as it, so this should return true.
73bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia    number = new PhoneNumber();
74bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia    number.setCountryCode(49);
75bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia    number.setCountryCodeSource(CountryCodeSource.FROM_DEFAULT_COUNTRY);
76bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia    candidate = "49/69/2013";
77bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia    assertTrue(PhoneNumberMatcher.containsMoreThanOneSlashInNationalNumber(number, candidate));
78bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia  }
79bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia
8052699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  /** See {@link PhoneNumberUtilTest#testParseNationalNumber()}. */
8152699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  public void testFindNationalNumber() throws Exception {
8252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    // same cases as in testParseNationalNumber
83ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("033316005", RegionCode.NZ);
84a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia    // ("33316005", RegionCode.NZ) is omitted since the national prefix is obligatory for these
85a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia    // types of numbers in New Zealand.
8652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    // National prefix attached and some formatting present.
87ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("03-331 6005", RegionCode.NZ);
88ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("03 331 6005", RegionCode.NZ);
8952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    // Testing international prefixes.
9052699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    // Should strip country code.
91ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("0064 3 331 6005", RegionCode.NZ);
9252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    // Try again, but this time we have an international number with Region Code US. It should
9352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    // recognize the country code and parse accordingly.
94ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("01164 3 331 6005", RegionCode.US);
95ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("+64 3 331 6005", RegionCode.US);
9652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
97ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("64(0)64123456", RegionCode.NZ);
9852699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    // Check that using a "/" is fine in a phone number.
99b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia    // Note that real Polish numbers do *not* start with a 0.
100b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia    doTestFindInContext("0123/456789", RegionCode.PL);
101ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("123-456-7890", RegionCode.US);
10252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  }
10352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
10452699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  /** See {@link PhoneNumberUtilTest#testParseWithInternationalPrefixes()}. */
10552699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  public void testFindWithInternationalPrefixes() throws Exception {
106ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("+1 (650) 333-6000", RegionCode.NZ);
107ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("1-650-333-6000", RegionCode.US);
10852699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    // Calling the US number from Singapore by using different service providers
10952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    // 1st test: calling using SingTel IDD service (IDD is 001)
110ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("0011-650-333-6000", RegionCode.SG);
11152699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    // 2nd test: calling using StarHub IDD service (IDD is 008)
112ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("0081-650-333-6000", RegionCode.SG);
11352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    // 3rd test: calling using SingTel V019 service (IDD is 019)
114ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("0191-650-333-6000", RegionCode.SG);
11552699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    // Calling the US number from Poland
116ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("0~01-650-333-6000", RegionCode.PL);
11752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    // Using "++" at the start.
118ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("++1 (650) 333-6000", RegionCode.PL);
11952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    // Using a full-width plus sign.
120ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("\uFF0B1 (650) 333-6000", RegionCode.SG);
12152699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    // The whole number, including punctuation, is here represented in full-width form.
12252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    doTestFindInContext("\uFF0B\uFF11\u3000\uFF08\uFF16\uFF15\uFF10\uFF09" +
12352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia        "\u3000\uFF13\uFF13\uFF13\uFF0D\uFF16\uFF10\uFF10\uFF10",
124ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia        RegionCode.SG);
12552699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  }
12652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
12752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  /** See {@link PhoneNumberUtilTest#testParseWithLeadingZero()}. */
12852699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  public void testFindWithLeadingZero() throws Exception {
129ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("+39 02-36618 300", RegionCode.NZ);
130ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("02-36618 300", RegionCode.IT);
131ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("312 345 678", RegionCode.IT);
13252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  }
13352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
13452699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  /** See {@link PhoneNumberUtilTest#testParseNationalNumberArgentina()}. */
13552699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  public void testFindNationalNumberArgentina() throws Exception {
13652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    // Test parsing mobile numbers of Argentina.
137ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("+54 9 343 555 1212", RegionCode.AR);
138ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("0343 15 555 1212", RegionCode.AR);
13952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
140ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("+54 9 3715 65 4320", RegionCode.AR);
141ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("03715 15 65 4320", RegionCode.AR);
14252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
14352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    // Test parsing fixed-line numbers of Argentina.
144ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("+54 11 3797 0000", RegionCode.AR);
145ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("011 3797 0000", RegionCode.AR);
14652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
147ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("+54 3715 65 4321", RegionCode.AR);
148ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("03715 65 4321", RegionCode.AR);
14952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
150ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("+54 23 1234 0000", RegionCode.AR);
151ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("023 1234 0000", RegionCode.AR);
15252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  }
15352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
15452699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  /** See {@link PhoneNumberUtilTest#testParseWithXInNumber()}. */
15552699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  public void testFindWithXInNumber() throws Exception {
156ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("(0xx) 123456789", RegionCode.AR);
157f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    // A case where x denotes both carrier codes and extension symbol.
158ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("(0xx) 123456789 x 1234", RegionCode.AR);
15952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
16052699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    // This test is intentionally constructed such that the number of digit after xx is larger than
16152699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    // 7, so that the number won't be mistakenly treated as an extension, as we allow extensions up
16252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    // to 7 digits. This assumption is okay for now as all the countries where a carrier selection
16352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    // code is written in the form of xx have a national significant number of length larger than 7.
164ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("011xx5481429712", RegionCode.US);
16552699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  }
16652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
16752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  /** See {@link PhoneNumberUtilTest#testParseNumbersMexico()}. */
16852699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  public void testFindNumbersMexico() throws Exception {
16952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    // Test parsing fixed-line numbers of Mexico.
170ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("+52 (449)978-0001", RegionCode.MX);
171ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("01 (449)978-0001", RegionCode.MX);
172ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("(449)978-0001", RegionCode.MX);
17352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
17452699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    // Test parsing mobile numbers of Mexico.
175ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("+52 1 33 1234-5678", RegionCode.MX);
176ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("044 (33) 1234-5678", RegionCode.MX);
177ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("045 33 1234-5678", RegionCode.MX);
17852699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  }
17952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
18052699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  /** See {@link PhoneNumberUtilTest#testParseNumbersWithPlusWithNoRegion()}. */
18152699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  public void testFindNumbersWithPlusWithNoRegion() throws Exception {
182ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    // RegionCode.ZZ is allowed only if the number starts with a '+' - then the country code can be
18352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    // calculated.
184ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("+64 3 331 6005", RegionCode.ZZ);
18552699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    // Null is also allowed for the region code in these cases.
18652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    doTestFindInContext("+64 3 331 6005", null);
18752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  }
18852699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
18952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  /** See {@link PhoneNumberUtilTest#testParseExtensions()}. */
19052699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  public void testFindExtensions() throws Exception {
191ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("03 331 6005 ext 3456", RegionCode.NZ);
192ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("03-3316005x3456", RegionCode.NZ);
193ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("03-3316005 int.3456", RegionCode.NZ);
194ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("03 3316005 #3456", RegionCode.NZ);
195ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("0~0 1800 7493 524", RegionCode.PL);
196ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("(1800) 7493.524", RegionCode.US);
19752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    // Check that the last instance of an extension token is matched.
198ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("0~0 1800 7493 524 ~1234", RegionCode.PL);
19952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    // Verifying bug-fix where the last digit of a number was previously omitted if it was a 0 when
20052699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    // extracting the extension. Also verifying a few different cases of extensions.
201ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("+44 2034567890x456", RegionCode.NZ);
202ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("+44 2034567890x456", RegionCode.GB);
203ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("+44 2034567890 x456", RegionCode.GB);
204ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("+44 2034567890 X456", RegionCode.GB);
205ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("+44 2034567890 X 456", RegionCode.GB);
206ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("+44 2034567890 X  456", RegionCode.GB);
207ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("+44 2034567890  X 456", RegionCode.GB);
208ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia
209ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("(800) 901-3355 x 7246433", RegionCode.US);
210ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("(800) 901-3355 , ext 7246433", RegionCode.US);
211ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("(800) 901-3355 ,extension 7246433", RegionCode.US);
212f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    // The next test differs from PhoneNumberUtil -> when matching we don't consider a lone comma to
213f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    // indicate an extension, although we accept it when parsing.
214ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("(800) 901-3355 ,x 7246433", RegionCode.US);
215ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("(800) 901-3355 ext: 7246433", RegionCode.US);
21652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  }
21752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
21852699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  public void testFindInterspersedWithSpace() throws Exception {
219ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    doTestFindInContext("0 3   3 3 1   6 0 0 5", RegionCode.NZ);
22052699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  }
22152699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
22252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  /**
22352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia   * Test matching behavior when starting in the middle of a phone number.
22452699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia   */
22552699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  public void testIntermediateParsePositions() throws Exception {
22652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    String text = "Call 033316005  or 032316005!";
22752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    //             |    |    |    |    |    |
22852699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    //             0    5   10   15   20   25
22952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
23052699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    // Iterate over all possible indices.
23152699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    for (int i = 0; i <= 5; i++) {
23252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia      assertEqualRange(text, i, 5, 14);
23352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    }
23452699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    // 7 and 8 digits in a row are still parsed as number.
23552699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    assertEqualRange(text, 6, 6, 14);
23652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    assertEqualRange(text, 7, 7, 14);
23752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    // Anything smaller is skipped to the second instance.
23852699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    for (int i = 8; i <= 19; i++) {
23952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia      assertEqualRange(text, i, 19, 28);
24052699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    }
24152699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  }
24252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
243b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia  public void testFourMatchesInARow() throws Exception {
244b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia    String number1 = "415-666-7777";
245b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia    String number2 = "800-443-1223";
246b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia    String number3 = "212-443-1223";
247b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia    String number4 = "650-443-1223";
248b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia    String text = number1 + " - " + number2 + " - " + number3 + " - " + number4;
249b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia
250b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia    Iterator<PhoneNumberMatch> iterator =
251b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia        phoneUtil.findNumbers(text, RegionCode.US).iterator();
252b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia    PhoneNumberMatch match = iterator.hasNext() ? iterator.next() : null;
253b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia    assertMatchProperties(match, text, number1, RegionCode.US);
254b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia
255b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia    match = iterator.hasNext() ? iterator.next() : null;
256b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia    assertMatchProperties(match, text, number2, RegionCode.US);
257b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia
258b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia    match = iterator.hasNext() ? iterator.next() : null;
259b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia    assertMatchProperties(match, text, number3, RegionCode.US);
260b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia
261b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia    match = iterator.hasNext() ? iterator.next() : null;
262b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia    assertMatchProperties(match, text, number4, RegionCode.US);
263b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia  }
264b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia
265b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia  public void testMatchesFoundWithMultipleSpaces() throws Exception {
266b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia    String number1 = "(415) 666-7777";
267b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia    String number2 = "(800) 443-1223";
268b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia    String text = number1 + " " + number2;
269b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia
270b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia    Iterator<PhoneNumberMatch> iterator =
271b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia        phoneUtil.findNumbers(text, RegionCode.US).iterator();
272b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia    PhoneNumberMatch match = iterator.hasNext() ? iterator.next() : null;
273b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia    assertMatchProperties(match, text, number1, RegionCode.US);
274b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia
275b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia    match = iterator.hasNext() ? iterator.next() : null;
276b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia    assertMatchProperties(match, text, number2, RegionCode.US);
277b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia  }
278b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia
279372bff8dd464574d36737d47e495cad14346653cShaopeng Jia  public void testMatchWithSurroundingZipcodes() throws Exception {
280372bff8dd464574d36737d47e495cad14346653cShaopeng Jia    String number = "415-666-7777";
281f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    String zipPreceding = "My address is CA 34215 - " + number + " is my number.";
282372bff8dd464574d36737d47e495cad14346653cShaopeng Jia
283f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    Iterator<PhoneNumberMatch> iterator =
284ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia        phoneUtil.findNumbers(zipPreceding, RegionCode.US).iterator();
285372bff8dd464574d36737d47e495cad14346653cShaopeng Jia    PhoneNumberMatch match = iterator.hasNext() ? iterator.next() : null;
286b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia    assertMatchProperties(match, zipPreceding, number, RegionCode.US);
287372bff8dd464574d36737d47e495cad14346653cShaopeng Jia
288372bff8dd464574d36737d47e495cad14346653cShaopeng Jia    // Now repeat, but this time the phone number has spaces in it. It should still be found.
289372bff8dd464574d36737d47e495cad14346653cShaopeng Jia    number = "(415) 666 7777";
290372bff8dd464574d36737d47e495cad14346653cShaopeng Jia
291372bff8dd464574d36737d47e495cad14346653cShaopeng Jia    String zipFollowing = "My number is " + number + ". 34215 is my zip-code.";
292ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    iterator = phoneUtil.findNumbers(zipFollowing, RegionCode.US).iterator();
293372bff8dd464574d36737d47e495cad14346653cShaopeng Jia    PhoneNumberMatch matchWithSpaces = iterator.hasNext() ? iterator.next() : null;
294b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia    assertMatchProperties(matchWithSpaces, zipFollowing, number, RegionCode.US);
295372bff8dd464574d36737d47e495cad14346653cShaopeng Jia  }
296372bff8dd464574d36737d47e495cad14346653cShaopeng Jia
297d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia  public void testIsLatinLetter() throws Exception {
298d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia    assertTrue(PhoneNumberMatcher.isLatinLetter('c'));
299d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia    assertTrue(PhoneNumberMatcher.isLatinLetter('C'));
300d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia    assertTrue(PhoneNumberMatcher.isLatinLetter('\u00C9'));
301d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia    assertTrue(PhoneNumberMatcher.isLatinLetter('\u0301'));  // Combining acute accent
302d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia    // Punctuation, digits and white-space are not considered "latin letters".
303d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia    assertFalse(PhoneNumberMatcher.isLatinLetter(':'));
304d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia    assertFalse(PhoneNumberMatcher.isLatinLetter('5'));
305d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia    assertFalse(PhoneNumberMatcher.isLatinLetter('-'));
306d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia    assertFalse(PhoneNumberMatcher.isLatinLetter('.'));
307d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia    assertFalse(PhoneNumberMatcher.isLatinLetter(' '));
308d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia    assertFalse(PhoneNumberMatcher.isLatinLetter('\u6211'));  // Chinese character
309b210e301245cb5dc90aa3142f378632bd41cb172Shaopeng Jia    assertFalse(PhoneNumberMatcher.isLatinLetter('\u306E'));  // Hiragana letter no
310d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia  }
311d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia
312d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia  public void testMatchesWithSurroundingLatinChars() throws Exception {
313f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    ArrayList<NumberContext> possibleOnlyContexts = new ArrayList<NumberContext>();
314f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    possibleOnlyContexts.add(new NumberContext("abc", "def"));
315f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    possibleOnlyContexts.add(new NumberContext("abc", ""));
316f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    possibleOnlyContexts.add(new NumberContext("", "def"));
317f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    // Latin capital letter e with an acute accent.
318f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    possibleOnlyContexts.add(new NumberContext("\u00C9", ""));
319f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    // e with an acute accent decomposed (with combining mark).
320f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    possibleOnlyContexts.add(new NumberContext("e\u0301", ""));
321d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia
322d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia    // Numbers should not be considered valid, if they are surrounded by Latin characters, but
323d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia    // should be considered possible.
324f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    findMatchesInContexts(possibleOnlyContexts, false, true);
325f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia  }
326f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia
327f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia  public void testMoneyNotSeenAsPhoneNumber() throws Exception {
328f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    ArrayList<NumberContext> possibleOnlyContexts = new ArrayList<NumberContext>();
329f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    possibleOnlyContexts.add(new NumberContext("$", ""));
330f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    possibleOnlyContexts.add(new NumberContext("", "$"));
331f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    possibleOnlyContexts.add(new NumberContext("\u00A3", ""));  // Pound sign
332f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    possibleOnlyContexts.add(new NumberContext("\u00A5", ""));  // Yen sign
333f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    findMatchesInContexts(possibleOnlyContexts, false, true);
33496a7214cdabf08f53f5b1a560304601c9f65e0b9Shaopeng Jia  }
33596a7214cdabf08f53f5b1a560304601c9f65e0b9Shaopeng Jia
33696a7214cdabf08f53f5b1a560304601c9f65e0b9Shaopeng Jia  public void testPercentageNotSeenAsPhoneNumber() throws Exception {
33796a7214cdabf08f53f5b1a560304601c9f65e0b9Shaopeng Jia    ArrayList<NumberContext> possibleOnlyContexts = new ArrayList<NumberContext>();
33896a7214cdabf08f53f5b1a560304601c9f65e0b9Shaopeng Jia    possibleOnlyContexts.add(new NumberContext("", "%"));
33996a7214cdabf08f53f5b1a560304601c9f65e0b9Shaopeng Jia    // Numbers followed by % should be dropped.
34096a7214cdabf08f53f5b1a560304601c9f65e0b9Shaopeng Jia    findMatchesInContexts(possibleOnlyContexts, false, true);
341f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia  }
342f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia
343f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia  public void testPhoneNumberWithLeadingOrTrailingMoneyMatches() throws Exception {
344f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    // Because of the space after the 20 (or before the 100) these dollar amounts should not stop
345f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    // the actual number from being found.
346f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    ArrayList<NumberContext> contexts = new ArrayList<NumberContext>();
347f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    contexts.add(new NumberContext("$20 ", ""));
348f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    contexts.add(new NumberContext("", " 100$"));
349f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    findMatchesInContexts(contexts, true, true);
350d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia  }
351d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia
352d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia  public void testMatchesWithSurroundingLatinCharsAndLeadingPunctuation() throws Exception {
353d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia    // Contexts with trailing characters. Leading characters are okay here since the numbers we will
354d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia    // insert start with punctuation, but trailing characters are still not allowed.
355f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    ArrayList<NumberContext> possibleOnlyContexts = new ArrayList<NumberContext>();
356d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia    possibleOnlyContexts.add(new NumberContext("abc", "def"));
357d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia    possibleOnlyContexts.add(new NumberContext("", "def"));
358d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia    possibleOnlyContexts.add(new NumberContext("", "\u00C9"));
359d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia
360d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia    // Numbers should not be considered valid, if they have trailing Latin characters, but should be
361d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia    // considered possible.
362d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia    String numberWithPlus = "+14156667777";
363d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia    String numberWithBrackets = "(415)6667777";
364ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    findMatchesInContexts(possibleOnlyContexts, false, true, RegionCode.US, numberWithPlus);
365ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    findMatchesInContexts(possibleOnlyContexts, false, true, RegionCode.US, numberWithBrackets);
366d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia
367f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    ArrayList<NumberContext> validContexts = new ArrayList<NumberContext>();
368d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia    validContexts.add(new NumberContext("abc", ""));
369d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia    validContexts.add(new NumberContext("\u00C9", ""));
370d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia    validContexts.add(new NumberContext("\u00C9", "."));  // Trailing punctuation.
371d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia    validContexts.add(new NumberContext("\u00C9", " def"));  // Trailing white-space.
372d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia
373d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia    // Numbers should be considered valid, since they start with punctuation.
374ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    findMatchesInContexts(validContexts, true, true, RegionCode.US, numberWithPlus);
375ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    findMatchesInContexts(validContexts, true, true, RegionCode.US, numberWithBrackets);
376d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia  }
377d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia
378d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia  public void testMatchesWithSurroundingChineseChars() throws Exception {
379f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    ArrayList<NumberContext> validContexts = new ArrayList<NumberContext>();
380d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia    validContexts.add(new NumberContext("\u6211\u7684\u7535\u8BDD\u53F7\u7801\u662F", ""));
381d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia    validContexts.add(new NumberContext("", "\u662F\u6211\u7684\u7535\u8BDD\u53F7\u7801"));
382d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia    validContexts.add(new NumberContext("\u8BF7\u62E8\u6253", "\u6211\u5728\u660E\u5929"));
383d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia
384d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia    // Numbers should be considered valid, since they are surrounded by Chinese.
385d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia    findMatchesInContexts(validContexts, true, true);
386d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia  }
387d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia
388d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia  public void testMatchesWithSurroundingPunctuation() throws Exception {
389f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    ArrayList<NumberContext> validContexts = new ArrayList<NumberContext>();
390d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia    validContexts.add(new NumberContext("My number-", ""));  // At end of text.
391d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia    validContexts.add(new NumberContext("", ".Nice day."));  // At start of text.
392d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia    validContexts.add(new NumberContext("Tel:", "."));  // Punctuation surrounds number.
393d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia    validContexts.add(new NumberContext("Tel: ", " on Saturdays."));  // White-space is also fine.
394d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia
395d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia    // Numbers should be considered valid, since they are surrounded by punctuation.
396d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia    findMatchesInContexts(validContexts, true, true);
397d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia  }
398d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia
399f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia  public void testMatchesMultiplePhoneNumbersSeparatedByPhoneNumberPunctuation() throws Exception {
400f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    String text = "Call 650-253-4561 -- 455-234-3451";
401ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    String region = RegionCode.US;
402f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia
403f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    PhoneNumber number1 = new PhoneNumber();
404f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    number1.setCountryCode(phoneUtil.getCountryCodeForRegion(region));
405f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    number1.setNationalNumber(6502534561L);
406f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    PhoneNumberMatch match1 = new PhoneNumberMatch(5, "650-253-4561", number1);
407f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia
408f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    PhoneNumber number2 = new PhoneNumber();
409f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    number2.setCountryCode(phoneUtil.getCountryCodeForRegion(region));
410f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    number2.setNationalNumber(4552343451L);
411f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    PhoneNumberMatch match2 = new PhoneNumberMatch(21, "455-234-3451", number2);
412f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia
413f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    Iterator<PhoneNumberMatch> matches = phoneUtil.findNumbers(text, region).iterator();
414f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    assertEquals(match1, matches.next());
415f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    assertEquals(match2, matches.next());
416f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia  }
417f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia
418f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia  public void testDoesNotMatchMultiplePhoneNumbersSeparatedWithNoWhiteSpace() throws Exception {
419f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    // No white-space found between numbers - neither is found.
420f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    String text = "Call 650-253-4561--455-234-3451";
421ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    String region = RegionCode.US;
422f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia
423f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    assertTrue(hasNoMatches(phoneUtil.findNumbers(text, region)));
424f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia  }
425f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia
426f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia  /**
427f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia   * Strings with number-like things that shouldn't be found under any level.
428f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia   */
429f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia  private static final NumberTest[] IMPOSSIBLE_CASES = {
430ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    new NumberTest("12345", RegionCode.US),
431ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    new NumberTest("23456789", RegionCode.US),
432ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    new NumberTest("234567890112", RegionCode.US),
433ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    new NumberTest("650+253+1234", RegionCode.US),
434ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    new NumberTest("3/10/1984", RegionCode.CA),
435ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    new NumberTest("03/27/2011", RegionCode.US),
436ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    new NumberTest("31/8/2011", RegionCode.US),
437ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    new NumberTest("1/12/2011", RegionCode.US),
438ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    new NumberTest("10/12/82", RegionCode.DE),
439528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia    new NumberTest("650x2531234", RegionCode.US),
440cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia    new NumberTest("2012-01-02 08:00", RegionCode.US),
441cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia    new NumberTest("2012/01/02 08:00", RegionCode.US),
442cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia    new NumberTest("20120102 08:00", RegionCode.US),
4437a81979b0076f18b31b47b7df2beac29735f3a37Cecilia Roes    new NumberTest("2014-04-12 04:04 PM", RegionCode.US),
4447a81979b0076f18b31b47b7df2beac29735f3a37Cecilia Roes    new NumberTest("2014-04-12 &nbsp;04:04 PM", RegionCode.US),
4457a81979b0076f18b31b47b7df2beac29735f3a37Cecilia Roes    new NumberTest("2014-04-12 &nbsp;04:04 PM", RegionCode.US),
4467a81979b0076f18b31b47b7df2beac29735f3a37Cecilia Roes    new NumberTest("2014-04-12  04:04 PM", RegionCode.US),
447f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia  };
448f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia
449f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia  /**
450f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia   * Strings with number-like things that should only be found under "possible".
451f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia   */
452f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia  private static final NumberTest[] POSSIBLE_ONLY_CASES = {
453f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    // US numbers cannot start with 7 in the test metadata to be valid.
454ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    new NumberTest("7121115678", RegionCode.US),
455f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    // 'X' should not be found in numbers at leniencies stricter than POSSIBLE, unless it represents
456f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    // a carrier code or extension.
457ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    new NumberTest("1650 x 253 - 1234", RegionCode.US),
458ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    new NumberTest("650 x 253 - 1234", RegionCode.US),
459528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia    new NumberTest("6502531x234", RegionCode.US),
460a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia    new NumberTest("(20) 3346 1234", RegionCode.GB),  // Non-optional NP omitted
461f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia  };
462f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia
463f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia  /**
464f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia   * Strings with number-like things that should only be found up to and including the "valid"
465f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia   * leniency level.
466f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia   */
467f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia  private static final NumberTest[] VALID_CASES = {
468528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia    new NumberTest("65 02 53 00 00", RegionCode.US),
469ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    new NumberTest("6502 538365", RegionCode.US),
470ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    new NumberTest("650//253-1234", RegionCode.US),  // 2 slashes are illegal at higher levels
471ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    new NumberTest("650/253/1234", RegionCode.US),
472ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    new NumberTest("9002309. 158", RegionCode.US),
473528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia    new NumberTest("12 7/8 - 14 12/34 - 5", RegionCode.US),
474ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    new NumberTest("12.1 - 23.71 - 23.45", RegionCode.US),
475ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    new NumberTest("800 234 1 111x1111", RegionCode.US),
476528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia    new NumberTest("1979-2011 100", RegionCode.US),
477ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    new NumberTest("+494949-4-94", RegionCode.DE),  // National number in wrong format
478528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia    new NumberTest("\uFF14\uFF11\uFF15\uFF16\uFF16\uFF16\uFF16-\uFF17\uFF17\uFF17", RegionCode.US),
479cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia    new NumberTest("2012-0102 08", RegionCode.US),  // Very strange formatting.
480cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia    new NumberTest("2012-01-02 08", RegionCode.US),
4814b867acb917b73e699a596df94445c634c916519Shaopeng Jia    // Breakdown assistance number with unexpected formatting.
4824b867acb917b73e699a596df94445c634c916519Shaopeng Jia    new NumberTest("1800-1-0-10 22", RegionCode.AU),
4834b867acb917b73e699a596df94445c634c916519Shaopeng Jia    new NumberTest("030-3-2 23 12 34", RegionCode.DE),
4844b867acb917b73e699a596df94445c634c916519Shaopeng Jia    new NumberTest("03 0 -3 2 23 12 34", RegionCode.DE),
4854b867acb917b73e699a596df94445c634c916519Shaopeng Jia    new NumberTest("(0)3 0 -3 2 23 12 34", RegionCode.DE),
4864b867acb917b73e699a596df94445c634c916519Shaopeng Jia    new NumberTest("0 3 0 -3 2 23 12 34", RegionCode.DE),
487f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia  };
488f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia
489f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia  /**
490f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia   * Strings with number-like things that should only be found up to and including the
491f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia   * "strict_grouping" leniency level.
492f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia   */
493f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia  private static final NumberTest[] STRICT_GROUPING_CASES = {
494ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    new NumberTest("(415) 6667777", RegionCode.US),
495ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    new NumberTest("415-6667777", RegionCode.US),
496f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    // Should be found by strict grouping but not exact grouping, as the last two groups are
497f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    // formatted together as a block.
498a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia    new NumberTest("0800-2491234", RegionCode.DE),
4994b867acb917b73e699a596df94445c634c916519Shaopeng Jia    // Doesn't match any formatting in the test file, but almost matches an alternate format (the
5004b867acb917b73e699a596df94445c634c916519Shaopeng Jia    // last two groups have been squashed together here).
5014b867acb917b73e699a596df94445c634c916519Shaopeng Jia    new NumberTest("0900-1 123123", RegionCode.DE),
5024b867acb917b73e699a596df94445c634c916519Shaopeng Jia    new NumberTest("(0)900-1 123123", RegionCode.DE),
5034b867acb917b73e699a596df94445c634c916519Shaopeng Jia    new NumberTest("0 900-1 123123", RegionCode.DE),
504f9768eb3c8f303725fb4f899598481cbc4fb76a3Shaopeng Jia    // NDC also found as part of the country calling code; this shouldn't ruin the grouping
505f9768eb3c8f303725fb4f899598481cbc4fb76a3Shaopeng Jia    // expectations.
506f9768eb3c8f303725fb4f899598481cbc4fb76a3Shaopeng Jia    new NumberTest("+33 3 34 2312", RegionCode.FR),
507f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia  };
508f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia
509f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia  /**
510b210e301245cb5dc90aa3142f378632bd41cb172Shaopeng Jia   * Strings with number-like things that should be found at all levels.
511f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia   */
512f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia  private static final NumberTest[] EXACT_GROUPING_CASES = {
513ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    new NumberTest("\uFF14\uFF11\uFF15\uFF16\uFF16\uFF16\uFF17\uFF17\uFF17\uFF17", RegionCode.US),
514ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    new NumberTest("\uFF14\uFF11\uFF15-\uFF16\uFF16\uFF16-\uFF17\uFF17\uFF17\uFF17", RegionCode.US),
515ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    new NumberTest("4156667777", RegionCode.US),
516ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    new NumberTest("4156667777 x 123", RegionCode.US),
517ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    new NumberTest("415-666-7777", RegionCode.US),
518ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    new NumberTest("415/666-7777", RegionCode.US),
519ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    new NumberTest("415-666-7777 ext. 503", RegionCode.US),
520ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    new NumberTest("1 415 666 7777 x 123", RegionCode.US),
521ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    new NumberTest("+1 415-666-7777", RegionCode.US),
522ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    new NumberTest("+494949 49", RegionCode.DE),
523ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    new NumberTest("+49-49-34", RegionCode.DE),
524ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    new NumberTest("+49-4931-49", RegionCode.DE),
525ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    new NumberTest("04931-49", RegionCode.DE),  // With National Prefix
526ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    new NumberTest("+49-494949", RegionCode.DE),  // One group with country code
527ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    new NumberTest("+49-494949 ext. 49", RegionCode.DE),
528ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    new NumberTest("+49494949 ext. 49", RegionCode.DE),
529ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    new NumberTest("0494949", RegionCode.DE),
530ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    new NumberTest("0494949 ext. 49", RegionCode.DE),
531a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia    new NumberTest("01 (33) 3461 2234", RegionCode.MX),  // Optional NP present
532a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia    new NumberTest("(33) 3461 2234", RegionCode.MX),  // Optional NP omitted
5334b867acb917b73e699a596df94445c634c916519Shaopeng Jia    new NumberTest("1800-10-10 22", RegionCode.AU),  // Breakdown assistance number.
5344b867acb917b73e699a596df94445c634c916519Shaopeng Jia    // Doesn't match any formatting in the test file, but matches an alternate format exactly.
5354b867acb917b73e699a596df94445c634c916519Shaopeng Jia    new NumberTest("0900-1 123 123", RegionCode.DE),
5364b867acb917b73e699a596df94445c634c916519Shaopeng Jia    new NumberTest("(0)900-1 123 123", RegionCode.DE),
5374b867acb917b73e699a596df94445c634c916519Shaopeng Jia    new NumberTest("0 900-1 123 123", RegionCode.DE),
538f9768eb3c8f303725fb4f899598481cbc4fb76a3Shaopeng Jia    new NumberTest("+33 3 34 23 12", RegionCode.FR),
539f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia  };
540f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia
541528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia  public void testMatchesWithPossibleLeniency() throws Exception {
542528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia    List<NumberTest> testCases = new ArrayList<NumberTest>();
543528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia    testCases.addAll(Arrays.asList(STRICT_GROUPING_CASES));
544528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia    testCases.addAll(Arrays.asList(EXACT_GROUPING_CASES));
545528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia    testCases.addAll(Arrays.asList(VALID_CASES));
546528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia    testCases.addAll(Arrays.asList(POSSIBLE_ONLY_CASES));
547528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia    doTestNumberMatchesForLeniency(testCases, Leniency.POSSIBLE);
548528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia  }
549528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia
550528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia  public void testNonMatchesWithPossibleLeniency() throws Exception {
551528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia    List<NumberTest> testCases = new ArrayList<NumberTest>();
552528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia    testCases.addAll(Arrays.asList(IMPOSSIBLE_CASES));
553528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia    doTestNumberNonMatchesForLeniency(testCases, Leniency.POSSIBLE);
554528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia  }
555528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia
556528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia  public void testMatchesWithValidLeniency() throws Exception {
557528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia    List<NumberTest> testCases = new ArrayList<NumberTest>();
558528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia    testCases.addAll(Arrays.asList(STRICT_GROUPING_CASES));
559528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia    testCases.addAll(Arrays.asList(EXACT_GROUPING_CASES));
560528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia    testCases.addAll(Arrays.asList(VALID_CASES));
561528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia    doTestNumberMatchesForLeniency(testCases, Leniency.VALID);
562528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia  }
563528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia
564528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia  public void testNonMatchesWithValidLeniency() throws Exception {
565528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia    List<NumberTest> testCases = new ArrayList<NumberTest>();
566528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia    testCases.addAll(Arrays.asList(IMPOSSIBLE_CASES));
567528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia    testCases.addAll(Arrays.asList(POSSIBLE_ONLY_CASES));
568528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia    doTestNumberNonMatchesForLeniency(testCases, Leniency.VALID);
569528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia  }
570528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia
571f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia  public void testMatchesWithStrictGroupingLeniency() throws Exception {
572f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    List<NumberTest> testCases = new ArrayList<NumberTest>();
573f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    testCases.addAll(Arrays.asList(STRICT_GROUPING_CASES));
574f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    testCases.addAll(Arrays.asList(EXACT_GROUPING_CASES));
575f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    doTestNumberMatchesForLeniency(testCases, Leniency.STRICT_GROUPING);
576f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia  }
577f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia
578f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia  public void testNonMatchesWithStrictGroupLeniency() throws Exception {
579f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    List<NumberTest> testCases = new ArrayList<NumberTest>();
580ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    testCases.addAll(Arrays.asList(IMPOSSIBLE_CASES));
581f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    testCases.addAll(Arrays.asList(POSSIBLE_ONLY_CASES));
582f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    testCases.addAll(Arrays.asList(VALID_CASES));
583f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    doTestNumberNonMatchesForLeniency(testCases, Leniency.STRICT_GROUPING);
584f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia  }
585f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia
586f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia  public void testMatchesWithExactGroupingLeniency() throws Exception {
587f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    List<NumberTest> testCases = new ArrayList<NumberTest>();
588f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    testCases.addAll(Arrays.asList(EXACT_GROUPING_CASES));
589f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    doTestNumberMatchesForLeniency(testCases, Leniency.EXACT_GROUPING);
590f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia  }
591f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia
592f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia  public void testNonMatchesExactGroupLeniency() throws Exception {
593f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    List<NumberTest> testCases = new ArrayList<NumberTest>();
594ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    testCases.addAll(Arrays.asList(IMPOSSIBLE_CASES));
595f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    testCases.addAll(Arrays.asList(POSSIBLE_ONLY_CASES));
596f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    testCases.addAll(Arrays.asList(VALID_CASES));
597f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    testCases.addAll(Arrays.asList(STRICT_GROUPING_CASES));
598f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    doTestNumberNonMatchesForLeniency(testCases, Leniency.EXACT_GROUPING);
599f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia  }
600f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia
601bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia  private void doTestNumberMatchesForLeniency(List<NumberTest> testCases, Leniency leniency) {
602f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    int noMatchFoundCount = 0;
603f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    int wrongMatchFoundCount = 0;
604f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    for (NumberTest test : testCases) {
605f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia      Iterator<PhoneNumberMatch> iterator =
606f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia          findNumbersForLeniency(test.rawString, test.region, leniency);
607f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia      PhoneNumberMatch match = iterator.hasNext() ? iterator.next() : null;
608f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia      if (match == null) {
609f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia        noMatchFoundCount++;
610f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia        System.err.println("No match found in " + test.toString() + " for leniency: " + leniency);
611f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia      } else {
612f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia        if (!test.rawString.equals(match.rawString())) {
613f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia          wrongMatchFoundCount++;
614f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia          System.err.println("Found wrong match in test " + test.toString() +
615f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia                             ". Found " + match.rawString());
616f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia        }
617f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia      }
618f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    }
619f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    assertEquals(0, noMatchFoundCount);
620f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    assertEquals(0, wrongMatchFoundCount);
621f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia  }
622f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia
623bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia  private void doTestNumberNonMatchesForLeniency(List<NumberTest> testCases, Leniency leniency) {
624f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    int matchFoundCount = 0;
625f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    for (NumberTest test : testCases) {
626f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia      Iterator<PhoneNumberMatch> iterator =
627f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia          findNumbersForLeniency(test.rawString, test.region, leniency);
628f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia      PhoneNumberMatch match = iterator.hasNext() ? iterator.next() : null;
629f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia      if (match != null) {
630f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia        matchFoundCount++;
631f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia        System.err.println("Match found in " + test.toString() + " for leniency: " + leniency);
632f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia      }
633f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    }
634f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    assertEquals(0, matchFoundCount);
635f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia  }
636f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia
637d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia  /**
638d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia   * Helper method which tests the contexts provided and ensures that:
639d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia   * -- if isValid is true, they all find a test number inserted in the middle when leniency of
640d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia   *  matching is set to VALID; else no test number should be extracted at that leniency level
641d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia   * -- if isPossible is true, they all find a test number inserted in the middle when leniency of
642d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia   *  matching is set to POSSIBLE; else no test number should be extracted at that leniency level
643d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia   */
644d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia  private void findMatchesInContexts(List<NumberContext> contexts, boolean isValid,
645d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia                                     boolean isPossible, String region, String number) {
646d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia    if (isValid) {
647d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia      doTestInContext(number, region, contexts, Leniency.VALID);
648d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia    } else {
649d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia      for (NumberContext context : contexts) {
650d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia        String text = context.leadingText + number + context.trailingText;
651d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia        assertTrue("Should not have found a number in " + text,
652d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia                   hasNoMatches(phoneUtil.findNumbers(text, region)));
653d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia      }
654d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia    }
655d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia    if (isPossible) {
656d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia      doTestInContext(number, region, contexts, Leniency.POSSIBLE);
657d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia    } else {
658d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia      for (NumberContext context : contexts) {
659d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia        String text = context.leadingText + number + context.trailingText;
660d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia        assertTrue("Should not have found a number in " + text,
661d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia                   hasNoMatches(phoneUtil.findNumbers(text, region, Leniency.POSSIBLE,
662d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia                                                      Long.MAX_VALUE)));
663d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia      }
664d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia    }
665d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia  }
666d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia
667d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia  /**
668d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia   * Variant of findMatchesInContexts that uses a default number and region.
669d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia   */
670d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia  private void findMatchesInContexts(List<NumberContext> contexts, boolean isValid,
671d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia                                     boolean isPossible) {
672ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    String region = RegionCode.US;
673d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia    String number = "415-666-7777";
674d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia
675d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia    findMatchesInContexts(contexts, isValid, isPossible, region, number);
676d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia  }
677d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia
678372bff8dd464574d36737d47e495cad14346653cShaopeng Jia  public void testNonMatchingBracketsAreInvalid() throws Exception {
679372bff8dd464574d36737d47e495cad14346653cShaopeng Jia    // The digits up to the ", " form a valid US number, but it shouldn't be matched as one since
680372bff8dd464574d36737d47e495cad14346653cShaopeng Jia    // there was a non-matching bracket present.
681372bff8dd464574d36737d47e495cad14346653cShaopeng Jia    assertTrue(hasNoMatches(phoneUtil.findNumbers(
682ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia        "80.585 [79.964, 81.191]", RegionCode.US)));
683372bff8dd464574d36737d47e495cad14346653cShaopeng Jia
684372bff8dd464574d36737d47e495cad14346653cShaopeng Jia    // The trailing "]" is thrown away before parsing, so the resultant number, while a valid US
685372bff8dd464574d36737d47e495cad14346653cShaopeng Jia    // number, does not have matching brackets.
686372bff8dd464574d36737d47e495cad14346653cShaopeng Jia    assertTrue(hasNoMatches(phoneUtil.findNumbers(
687ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia        "80.585 [79.964]", RegionCode.US)));
688372bff8dd464574d36737d47e495cad14346653cShaopeng Jia
689372bff8dd464574d36737d47e495cad14346653cShaopeng Jia    assertTrue(hasNoMatches(phoneUtil.findNumbers(
690ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia        "80.585 ((79.964)", RegionCode.US)));
691372bff8dd464574d36737d47e495cad14346653cShaopeng Jia
692372bff8dd464574d36737d47e495cad14346653cShaopeng Jia    // This case has too many sets of brackets to be valid.
693372bff8dd464574d36737d47e495cad14346653cShaopeng Jia    assertTrue(hasNoMatches(phoneUtil.findNumbers(
694ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia        "(80).(585) (79).(9)64", RegionCode.US)));
695372bff8dd464574d36737d47e495cad14346653cShaopeng Jia  }
696372bff8dd464574d36737d47e495cad14346653cShaopeng Jia
69752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  public void testNoMatchIfRegionIsNull() throws Exception {
69852699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    // Fail on non-international prefix if region code is null.
69952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    assertTrue(hasNoMatches(phoneUtil.findNumbers(
70052699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia        "Random text body - number is 0331 6005, see you there", null)));
70152699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  }
70252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
70352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  public void testNoMatchInEmptyString() throws Exception {
704ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    assertTrue(hasNoMatches(phoneUtil.findNumbers("", RegionCode.US)));
705ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    assertTrue(hasNoMatches(phoneUtil.findNumbers("  ", RegionCode.US)));
70652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  }
70752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
70852699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  public void testNoMatchIfNoNumber() throws Exception {
70952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    assertTrue(hasNoMatches(phoneUtil.findNumbers(
710ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia        "Random text body - number is foobar, see you there", RegionCode.US)));
71152699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  }
71252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
71352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  public void testSequences() throws Exception {
71452699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    // Test multiple occurrences.
71552699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    String text = "Call 033316005  or 032316005!";
716ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    String region = RegionCode.NZ;
71752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
71852699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    PhoneNumber number1 = new PhoneNumber();
71952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    number1.setCountryCode(phoneUtil.getCountryCodeForRegion(region));
72052699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    number1.setNationalNumber(33316005);
72152699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    PhoneNumberMatch match1 = new PhoneNumberMatch(5, "033316005", number1);
72252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
72352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    PhoneNumber number2 = new PhoneNumber();
72452699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    number2.setCountryCode(phoneUtil.getCountryCodeForRegion(region));
72552699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    number2.setNationalNumber(32316005);
72652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    PhoneNumberMatch match2 = new PhoneNumberMatch(19, "032316005", number2);
72752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
72852699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    Iterator<PhoneNumberMatch> matches =
72952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia        phoneUtil.findNumbers(text, region, Leniency.POSSIBLE, Long.MAX_VALUE).iterator();
73052699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
73152699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    assertEquals(match1, matches.next());
73252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    assertEquals(match2, matches.next());
73352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  }
73452699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
73552699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  public void testNullInput() throws Exception {
736ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    assertTrue(hasNoMatches(phoneUtil.findNumbers(null, RegionCode.US)));
73752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    assertTrue(hasNoMatches(phoneUtil.findNumbers(null, null)));
73852699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  }
73952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
74052699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  public void testMaxMatches() throws Exception {
74152699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    // Set up text with 100 valid phone numbers.
74252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    StringBuilder numbers = new StringBuilder();
74352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    for (int i = 0; i < 100; i++) {
74452699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia      numbers.append("My info: 415-666-7777,");
74552699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    }
74652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
74752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    // Matches all 100. Max only applies to failed cases.
74852699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    List<PhoneNumber> expected = new ArrayList<PhoneNumber>(100);
74952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    PhoneNumber number = phoneUtil.parse("+14156667777", null);
75052699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    for (int i = 0; i < 100; i++) {
75152699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia      expected.add(number);
75252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    }
75352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
75452699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    Iterable<PhoneNumberMatch> iterable =
755ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia        phoneUtil.findNumbers(numbers.toString(), RegionCode.US, Leniency.VALID, 10);
75652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    List<PhoneNumber> actual = new ArrayList<PhoneNumber>(100);
75752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    for (PhoneNumberMatch match : iterable) {
75852699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia      actual.add(match.number());
75952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    }
76052699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    assertEquals(expected, actual);
76152699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  }
76252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
76352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  public void testMaxMatchesInvalid() throws Exception {
76452699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    // Set up text with 10 invalid phone numbers followed by 100 valid.
76552699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    StringBuilder numbers = new StringBuilder();
76652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    for (int i = 0; i < 10; i++) {
76752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia      numbers.append("My address 949-8945-0");
76852699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    }
76952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    for (int i = 0; i < 100; i++) {
77052699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia      numbers.append("My info: 415-666-7777,");
77152699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    }
77252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
77352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    Iterable<PhoneNumberMatch> iterable =
774ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia        phoneUtil.findNumbers(numbers.toString(), RegionCode.US, Leniency.VALID, 10);
77552699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    assertFalse(iterable.iterator().hasNext());
77652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  }
77752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
77852699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  public void testMaxMatchesMixed() throws Exception {
77952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    // Set up text with 100 valid numbers inside an invalid number.
78052699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    StringBuilder numbers = new StringBuilder();
78152699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    for (int i = 0; i < 100; i++) {
78252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia      numbers.append("My info: 415-666-7777 123 fake street");
78352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    }
78452699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
785f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    // Only matches the first 10 despite there being 100 numbers due to max matches.
78652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    List<PhoneNumber> expected = new ArrayList<PhoneNumber>(100);
78752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    PhoneNumber number = phoneUtil.parse("+14156667777", null);
788f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    for (int i = 0; i < 10; i++) {
78952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia      expected.add(number);
79052699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    }
79152699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
79252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    Iterable<PhoneNumberMatch> iterable =
793ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia        phoneUtil.findNumbers(numbers.toString(), RegionCode.US, Leniency.VALID, 10);
79452699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    List<PhoneNumber> actual = new ArrayList<PhoneNumber>(100);
79552699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    for (PhoneNumberMatch match : iterable) {
79652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia      actual.add(match.number());
79752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    }
79852699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    assertEquals(expected, actual);
79952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  }
80052699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
801b0e21c22b1ca6b9aeb1426924cdf42a221c3d416Shaopeng Jia  public void testNonPlusPrefixedNumbersNotFoundForInvalidRegion() throws Exception {
802b0e21c22b1ca6b9aeb1426924cdf42a221c3d416Shaopeng Jia    // Does not start with a "+", we won't match it.
803b0e21c22b1ca6b9aeb1426924cdf42a221c3d416Shaopeng Jia    Iterable<PhoneNumberMatch> iterable = phoneUtil.findNumbers("1 456 764 156", RegionCode.ZZ);
804b0e21c22b1ca6b9aeb1426924cdf42a221c3d416Shaopeng Jia    Iterator<PhoneNumberMatch> iterator = iterable.iterator();
805b0e21c22b1ca6b9aeb1426924cdf42a221c3d416Shaopeng Jia
806b0e21c22b1ca6b9aeb1426924cdf42a221c3d416Shaopeng Jia    assertFalse(iterator.hasNext());
807b0e21c22b1ca6b9aeb1426924cdf42a221c3d416Shaopeng Jia    try {
808b0e21c22b1ca6b9aeb1426924cdf42a221c3d416Shaopeng Jia      iterator.next();
809b0e21c22b1ca6b9aeb1426924cdf42a221c3d416Shaopeng Jia      fail("Violation of the Iterator contract.");
810b0e21c22b1ca6b9aeb1426924cdf42a221c3d416Shaopeng Jia    } catch (NoSuchElementException e) { /* Success */ }
811b0e21c22b1ca6b9aeb1426924cdf42a221c3d416Shaopeng Jia    assertFalse(iterator.hasNext());
812b0e21c22b1ca6b9aeb1426924cdf42a221c3d416Shaopeng Jia  }
813b0e21c22b1ca6b9aeb1426924cdf42a221c3d416Shaopeng Jia
81452699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  public void testEmptyIteration() throws Exception {
815ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    Iterable<PhoneNumberMatch> iterable = phoneUtil.findNumbers("", RegionCode.ZZ);
81652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    Iterator<PhoneNumberMatch> iterator = iterable.iterator();
81752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
81852699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    assertFalse(iterator.hasNext());
81952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    assertFalse(iterator.hasNext());
82052699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    try {
82152699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia      iterator.next();
82252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia      fail("Violation of the Iterator contract.");
82352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    } catch (NoSuchElementException e) { /* Success */ }
82452699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    assertFalse(iterator.hasNext());
82552699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  }
82652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
82752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  public void testSingleIteration() throws Exception {
828ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    Iterable<PhoneNumberMatch> iterable = phoneUtil.findNumbers("+14156667777", RegionCode.ZZ);
82952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
83052699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    // With hasNext() -> next().
83152699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    Iterator<PhoneNumberMatch> iterator = iterable.iterator();
83252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    // Double hasNext() to ensure it does not advance.
83352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    assertTrue(iterator.hasNext());
83452699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    assertTrue(iterator.hasNext());
83552699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    assertNotNull(iterator.next());
83652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    assertFalse(iterator.hasNext());
83752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    try {
83852699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia      iterator.next();
83952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia      fail("Violation of the Iterator contract.");
84052699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    } catch (NoSuchElementException e) { /* Success */ }
84152699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    assertFalse(iterator.hasNext());
84252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
84352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    // With next() only.
84452699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    iterator = iterable.iterator();
84552699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    assertNotNull(iterator.next());
84652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    try {
84752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia      iterator.next();
84852699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia      fail("Violation of the Iterator contract.");
84952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    } catch (NoSuchElementException e) { /* Success */ }
85052699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  }
85152699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
85252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  public void testDoubleIteration() throws Exception {
85352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    Iterable<PhoneNumberMatch> iterable =
854ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia        phoneUtil.findNumbers("+14156667777 foobar +14156667777 ", RegionCode.ZZ);
85552699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
85652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    // With hasNext() -> next().
85752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    Iterator<PhoneNumberMatch> iterator = iterable.iterator();
85852699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    // Double hasNext() to ensure it does not advance.
85952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    assertTrue(iterator.hasNext());
86052699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    assertTrue(iterator.hasNext());
86152699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    assertNotNull(iterator.next());
86252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    assertTrue(iterator.hasNext());
86352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    assertTrue(iterator.hasNext());
86452699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    assertNotNull(iterator.next());
86552699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    assertFalse(iterator.hasNext());
86652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    try {
86752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia      iterator.next();
86852699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia      fail("Violation of the Iterator contract.");
86952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    } catch (NoSuchElementException e) { /* Success */ }
87052699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    assertFalse(iterator.hasNext());
87152699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
87252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    // With next() only.
87352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    iterator = iterable.iterator();
87452699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    assertNotNull(iterator.next());
87552699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    assertNotNull(iterator.next());
87652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    try {
87752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia      iterator.next();
87852699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia      fail("Violation of the Iterator contract.");
87952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    } catch (NoSuchElementException e) { /* Success */ }
88052699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  }
88152699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
88252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  /**
88352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia   * Ensures that {@link Iterator#remove()} is not supported and that calling it does not
88452699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia   * change iteration behavior.
88552699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia   */
88652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  public void testRemovalNotSupported() throws Exception {
887ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia    Iterable<PhoneNumberMatch> iterable = phoneUtil.findNumbers("+14156667777", RegionCode.ZZ);
88852699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
88952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    Iterator<PhoneNumberMatch> iterator = iterable.iterator();
89052699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    try {
89152699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia      iterator.remove();
89252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia      fail("Iterator must not support remove.");
89352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    } catch (UnsupportedOperationException e) { /* success */ }
89452699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
89552699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    assertTrue(iterator.hasNext());
89652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
89752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    try {
89852699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia      iterator.remove();
89952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia      fail("Iterator must not support remove.");
90052699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    } catch (UnsupportedOperationException e) { /* success */ }
90152699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
90252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    assertNotNull(iterator.next());
90352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
90452699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    try {
90552699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia      iterator.remove();
90652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia      fail("Iterator must not support remove.");
90752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    } catch (UnsupportedOperationException e) { /* success */ }
90852699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
90952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    assertFalse(iterator.hasNext());
91052699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  }
911b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia
912b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia  /**
913b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia   * Asserts that the expected match is non-null, and that the raw string and expected
914b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia   * proto buffer are set appropriately.
915b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia   */
916b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia  private void assertMatchProperties(
917b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia      PhoneNumberMatch match, String text, String number, String region) throws Exception {
918b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia    PhoneNumber expectedResult = phoneUtil.parse(number, region);
919b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia    assertNotNull("Did not find a number in '" + text + "'; expected " + number, match);
920b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia    assertEquals(expectedResult, match.number());
921b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia    assertEquals(number, match.rawString());
922b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia  }
92352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
92452699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  /**
92552699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia   * Asserts that another number can be found in {@code text} starting at {@code index}, and that
92652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia   * its corresponding range is {@code [start, end)}.
92752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia   */
92852699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  private void assertEqualRange(CharSequence text, int index, int start, int end) {
92952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    CharSequence sub = text.subSequence(index, text.length());
93052699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    Iterator<PhoneNumberMatch> matches =
931ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia      phoneUtil.findNumbers(sub, RegionCode.NZ, Leniency.POSSIBLE, Long.MAX_VALUE).iterator();
93252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    assertTrue(matches.hasNext());
93352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    PhoneNumberMatch match = matches.next();
93452699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    assertEquals(start - index, match.start());
93552699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    assertEquals(end - index, match.end());
936f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    assertEquals(sub.subSequence(match.start(), match.end()).toString(), match.rawString());
93752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  }
93852699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
93952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  /**
940372bff8dd464574d36737d47e495cad14346653cShaopeng Jia   * Tests numbers found by {@link PhoneNumberUtil#findNumbers(CharSequence, String)} in various
94152699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia   * textual contexts.
94252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia   *
94352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia   * @param number the number to test and the corresponding region code to use
94452699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia   */
94552699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  private void doTestFindInContext(String number, String defaultCountry) throws Exception {
94652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    findPossibleInContext(number, defaultCountry);
94752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
94852699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    PhoneNumber parsed = phoneUtil.parse(number, defaultCountry);
94952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    if (phoneUtil.isValidNumber(parsed)) {
95052699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia      findValidInContext(number, defaultCountry);
95152699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    }
95252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  }
95352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
954d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia  /**
955d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia   * Tests valid numbers in contexts that should pass for {@link Leniency#POSSIBLE}.
956d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia   */
95752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  private void findPossibleInContext(String number, String defaultCountry) {
958f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    ArrayList<NumberContext> contextPairs = new ArrayList<NumberContext>();
95952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    contextPairs.add(new NumberContext("", ""));  // no context
96052699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    contextPairs.add(new NumberContext("   ", "\t"));  // whitespace only
96152699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    contextPairs.add(new NumberContext("Hello ", ""));  // no context at end
96252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    contextPairs.add(new NumberContext("", " to call me!"));  // no context at start
96352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    contextPairs.add(new NumberContext("Hi there, call ", " to reach me!"));  // no context at start
96452699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    contextPairs.add(new NumberContext("Hi there, call ", ", or don't"));  // with commas
96552699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    // Three examples without whitespace around the number.
96652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    contextPairs.add(new NumberContext("Hi call", ""));
96752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    contextPairs.add(new NumberContext("", "forme"));
96852699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    contextPairs.add(new NumberContext("Hi call", "forme"));
96952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    // With other small numbers.
97052699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    contextPairs.add(new NumberContext("It's cheap! Call ", " before 6:30"));
97152699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    // With a second number later.
97252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    contextPairs.add(new NumberContext("Call ", " or +1800-123-4567!"));
9734b867acb917b73e699a596df94445c634c916519Shaopeng Jia    contextPairs.add(new NumberContext("Call me on June 2 at", ""));  // with a Month-Day date
97452699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    // With publication pages.
97552699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    contextPairs.add(new NumberContext(
97652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia        "As quoted by Alfonso 12-15 (2009), you may call me at ", ""));
97752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    contextPairs.add(new NumberContext(
97852699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia        "As quoted by Alfonso et al. 12-15 (2009), you may call me at ", ""));
979372bff8dd464574d36737d47e495cad14346653cShaopeng Jia    // With dates, written in the American style.
980372bff8dd464574d36737d47e495cad14346653cShaopeng Jia    contextPairs.add(new NumberContext(
981372bff8dd464574d36737d47e495cad14346653cShaopeng Jia        "As I said on 03/10/2011, you may call me at ", ""));
982f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    // With trailing numbers after a comma. The 45 should not be considered an extension.
983f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    contextPairs.add(new NumberContext("", ", 45 days a year"));
984f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia     // With a postfix stripped off as it looks like the start of another number.
98552699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    contextPairs.add(new NumberContext("Call ", "/x12 more"));
98652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
98752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    doTestInContext(number, defaultCountry, contextPairs, Leniency.POSSIBLE);
98852699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  }
98952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
99052699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  /**
991d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia   * Tests valid numbers in contexts that fail for {@link Leniency#POSSIBLE} but are valid for
992d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia   * {@link Leniency#VALID}.
99352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia   */
99452699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  private void findValidInContext(String number, String defaultCountry) {
995f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    ArrayList<NumberContext> contextPairs = new ArrayList<NumberContext>();
99652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    // With other small numbers.
99752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    contextPairs.add(new NumberContext("It's only 9.99! Call ", " to buy"));
99852699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    // With a number Day.Month.Year date.
99952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    contextPairs.add(new NumberContext("Call me on 21.6.1984 at ", ""));
100052699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    // With a number Month/Day date.
100152699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    contextPairs.add(new NumberContext("Call me on 06/21 at ", ""));
1002f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    // With a number Day.Month date.
100352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    contextPairs.add(new NumberContext("Call me on 21.6. at ", ""));
100452699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    // With a number Month/Day/Year date.
100552699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    contextPairs.add(new NumberContext("Call me on 06/21/84 at ", ""));
1006f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia
100752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    doTestInContext(number, defaultCountry, contextPairs, Leniency.VALID);
100852699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  }
100952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
101052699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  private void doTestInContext(String number, String defaultCountry,
101152699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia      List<NumberContext> contextPairs, Leniency leniency) {
101252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    for (NumberContext context : contextPairs) {
101352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia      String prefix = context.leadingText;
101452699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia      String text = prefix + number + context.trailingText;
101552699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
101652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia      int start = prefix.length();
101752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia      int end = start + number.length();
1018f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia      Iterator<PhoneNumberMatch> iterator =
1019f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia          phoneUtil.findNumbers(text, defaultCountry, leniency, Long.MAX_VALUE).iterator();
102052699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
1021f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia      PhoneNumberMatch match = iterator.hasNext() ? iterator.next() : null;
102252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia      assertNotNull("Did not find a number in '" + text + "'; expected '" + number + "'", match);
102352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
102452699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia      CharSequence extracted = text.subSequence(match.start(), match.end());
102552699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia      assertTrue("Unexpected phone region in '" + text + "'; extracted '" + extracted + "'",
102652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia          start == match.start() && end == match.end());
102752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia      assertTrue(number.contentEquals(extracted));
102852699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia      assertTrue(match.rawString().contentEquals(extracted));
102952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
103052699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia      ensureTermination(text, defaultCountry, leniency);
103152699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    }
103252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  }
103352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
103452699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  /**
103552699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia   * Exhaustively searches for phone numbers from each index within {@code text} to test that
103652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia   * finding matches always terminates.
103752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia   */
103852699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  private void ensureTermination(String text, String defaultCountry, Leniency leniency) {
103952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    for (int index = 0; index <= text.length(); index++) {
104052699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia      String sub = text.substring(index);
1041372bff8dd464574d36737d47e495cad14346653cShaopeng Jia      StringBuilder matches = new StringBuilder();
104252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia      // Iterates over all matches.
104352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia      for (PhoneNumberMatch match :
104452699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia           phoneUtil.findNumbers(sub, defaultCountry, leniency, Long.MAX_VALUE)) {
104552699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia        matches.append(", ").append(match.toString());
104652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia      }
104752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    }
104852699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  }
104952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
1050f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia  private Iterator<PhoneNumberMatch> findNumbersForLeniency(
1051bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia      String text, String defaultCountry, Leniency leniency) {
1052f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    return phoneUtil.findNumbers(text, defaultCountry, leniency, Long.MAX_VALUE).iterator();
1053f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia  }
1054f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia
105552699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  private boolean hasNoMatches(Iterable<PhoneNumberMatch> iterable) {
105652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    return !iterable.iterator().hasNext();
105752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  }
105852699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
105952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  /**
106052699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia   * Small class that holds the context of the number we are testing against. The test will
106152699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia   * insert the phone number to be found between leadingText and trailingText.
106252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia   */
1063f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia  private static class NumberContext {
106452699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    final String leadingText;
106552699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    final String trailingText;
106652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia
106752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    NumberContext(String leadingText, String trailingText) {
106852699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia      this.leadingText = leadingText;
106952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia      this.trailingText = trailingText;
107052699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia    }
107152699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia  }
1072f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia
1073f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia  /**
1074f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia   * Small class that holds the number we want to test and the region for which it should be valid.
1075f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia   */
1076f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia  private static class NumberTest {
1077f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    final String rawString;
1078f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    final String region;
1079f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia
1080f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    NumberTest(String rawString, String regionCode) {
1081f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia      this.rawString = rawString;
1082f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia      this.region = regionCode;
1083f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    }
1084f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia
1085f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    @Override
1086f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    public String toString() {
1087f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia      return rawString + " (" + region.toString() + ")";
1088f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia    }
1089f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia  }
109052699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia}
1091