Patrick Mézard avatar Patrick Mézard committed c9f1bce

C#: porting from Java

Comments (0)

Files changed (39)

+\.suo$
+\.user$
+^csharp/PhoneNumbers/obj/
+^csharp/PhoneNumbers/bin/
+^csharp/PhoneNumbers.Test/obj/
+^csharp/PhoneNumbers.Test/bin/
+~$
+csharp/lib/Phonenumber.cs
+csharp/lib/Phonemetadata.cs

csharp/PhoneNumbers.Test/CountryCodeToRegionCodeMapForTesting.cs

+/*
+ * Copyright (C) 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace PhoneNumbers.Test
+{
+    class CountryCodeToRegionCodeMapForTesting
+    {
+        // A mapping from a country code to the region codes which denote the
+        // country/region represented by that country code. In the case of multiple
+        // countries sharing a calling code, such as the NANPA countries, the one
+        // indicated with "isMainCountryForCode" in the metadata should be first.
+        internal static Dictionary<int, List<String>> GetCountryCodeToRegionCodeMap()
+        {
+            // The capacity is set to 20 as there are 15 different country codes,
+            // and this offers a load factor of roughly 0.75.
+            var countryCodeToRegionCodeMap = new Dictionary<int, List<String>>(20);
+
+            List<String> listWithRegionCode;
+            listWithRegionCode = new List<String>(2);
+            listWithRegionCode.Add("US");
+            listWithRegionCode.Add("BS");
+            countryCodeToRegionCodeMap[1] = listWithRegionCode;
+
+            listWithRegionCode = new List<String>(1);
+            listWithRegionCode.Add("IT");
+            countryCodeToRegionCodeMap[39] = listWithRegionCode;
+
+            listWithRegionCode = new List<String>(1);
+            listWithRegionCode.Add("GB");
+            countryCodeToRegionCodeMap[44] = listWithRegionCode;
+
+            listWithRegionCode = new List<String>(1);
+            listWithRegionCode.Add("PL");
+            countryCodeToRegionCodeMap[48] = listWithRegionCode;
+
+            listWithRegionCode = new List<String>(1);
+            listWithRegionCode.Add("DE");
+            countryCodeToRegionCodeMap[49] = listWithRegionCode;
+
+            listWithRegionCode = new List<String>(1);
+            listWithRegionCode.Add("MX");
+            countryCodeToRegionCodeMap[52] = listWithRegionCode;
+
+            listWithRegionCode = new List<String>(1);
+            listWithRegionCode.Add("AR");
+            countryCodeToRegionCodeMap[54] = listWithRegionCode;
+
+            listWithRegionCode = new List<String>(1);
+            listWithRegionCode.Add("AU");
+            countryCodeToRegionCodeMap[61] = listWithRegionCode;
+
+            listWithRegionCode = new List<String>(1);
+            listWithRegionCode.Add("NZ");
+            countryCodeToRegionCodeMap[64] = listWithRegionCode;
+
+            listWithRegionCode = new List<String>(1);
+            listWithRegionCode.Add("SG");
+            countryCodeToRegionCodeMap[65] = listWithRegionCode;
+
+            listWithRegionCode = new List<String>(1);
+            listWithRegionCode.Add("JP");
+            countryCodeToRegionCodeMap[81] = listWithRegionCode;
+
+            listWithRegionCode = new List<String>(1);
+            listWithRegionCode.Add("KR");
+            countryCodeToRegionCodeMap[82] = listWithRegionCode;
+
+            listWithRegionCode = new List<String>(1);
+            listWithRegionCode.Add("AO");
+            countryCodeToRegionCodeMap[244] = listWithRegionCode;
+
+            listWithRegionCode = new List<String>(2);
+            listWithRegionCode.Add("RE");
+            listWithRegionCode.Add("YT");
+            countryCodeToRegionCodeMap[262] = listWithRegionCode;
+
+            listWithRegionCode = new List<String>(1);
+            listWithRegionCode.Add("AD");
+            countryCodeToRegionCodeMap[376] = listWithRegionCode;
+
+            return countryCodeToRegionCodeMap;
+        }
+    }
+}

csharp/PhoneNumbers.Test/PhoneNumbers.Test.csproj

+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>9.0.30729</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{8E08D659-BBF6-4967-A56E-EA695DA6B45C}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>PhoneNumbers.Test</RootNamespace>
+    <AssemblyName>PhoneNumbers.Test</AssemblyName>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="nunit.framework, Version=2.5.8.10295, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\lib\nunit.framework.dll</HintPath>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Core">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Xml.Linq">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Data.DataSetExtensions">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="CountryCodeToRegionCodeMapForTesting.cs" />
+    <Compile Include="TestAsYouTypeFormatter.cs" />
+    <Compile Include="TestExampleNumbers.cs" />
+    <Compile Include="TestPhonenumber.cs" />
+    <Compile Include="TestPhoneNumberMatch.cs" />
+    <Compile Include="TestPhoneNumberMatcher.cs" />
+    <Compile Include="TestPhoneNumberOfflineGeocoder.cs" />
+    <Compile Include="TestPhoneNumberUtil.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="TestRegexCache.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\PhoneNumbers\PhoneNumbers.csproj">
+      <Project>{775A5AF2-FB45-4CE5-88D0-B1BE8AD56459}</Project>
+      <Name>PhoneNumbers</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>

csharp/PhoneNumbers.Test/Properties/AssemblyInfo.cs

+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("PhoneNumbers.Test")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Warner Brothers Movie World")]
+[assembly: AssemblyProduct("PhoneNumbers.Test")]
+[assembly: AssemblyCopyright("Copyright © Warner Brothers Movie World 2011")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("91f7ccf5-0d88-4a00-a599-499628767e60")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]

csharp/PhoneNumbers.Test/TestAsYouTypeFormatter.cs

+/*
+ * Copyright (C) 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using NUnit.Framework;
+
+namespace PhoneNumbers.Test
+{
+    [TestFixture]
+    class TestAsYouTypeFormatter
+    {
+        private PhoneNumberUtil phoneUtil;
+
+        [TestFixtureSetUp]
+        public void SetupFixture()
+        {
+            phoneUtil = TestPhoneNumberUtil.InitializePhoneUtilForTesting();
+        }
+
+        [Test]
+        public void TestInvalidRegion()
+        {
+            AsYouTypeFormatter formatter = phoneUtil.GetAsYouTypeFormatter("ZZ");
+            Assert.AreEqual("+", formatter.InputDigit('+'));
+            Assert.AreEqual("+4", formatter.InputDigit('4'));
+            Assert.AreEqual("+48 ", formatter.InputDigit('8'));
+            Assert.AreEqual("+48 8", formatter.InputDigit('8'));
+            Assert.AreEqual("+48 88", formatter.InputDigit('8'));
+            Assert.AreEqual("+48 88 1", formatter.InputDigit('1'));
+            Assert.AreEqual("+48 88 12", formatter.InputDigit('2'));
+            Assert.AreEqual("+48 88 123", formatter.InputDigit('3'));
+            Assert.AreEqual("+48 88 123 1", formatter.InputDigit('1'));
+            Assert.AreEqual("+48 88 123 12", formatter.InputDigit('2'));
+
+            formatter.Clear();
+            Assert.AreEqual("6", formatter.InputDigit('6'));
+            Assert.AreEqual("65", formatter.InputDigit('5'));
+            Assert.AreEqual("650", formatter.InputDigit('0'));
+            Assert.AreEqual("6502", formatter.InputDigit('2'));
+            Assert.AreEqual("65025", formatter.InputDigit('5'));
+            Assert.AreEqual("650253", formatter.InputDigit('3'));
+        }
+
+        [Test]
+        public void TestAYTFUS()
+        {
+            AsYouTypeFormatter formatter = phoneUtil.GetAsYouTypeFormatter("US");
+            Assert.AreEqual("6", formatter.InputDigit('6'));
+            Assert.AreEqual("65", formatter.InputDigit('5'));
+            Assert.AreEqual("650", formatter.InputDigit('0'));
+            Assert.AreEqual("650 2", formatter.InputDigit('2'));
+            Assert.AreEqual("650 25", formatter.InputDigit('5'));
+            Assert.AreEqual("650 253", formatter.InputDigit('3'));
+            // Note this is how a US local number (without area code) should be formatted.
+            Assert.AreEqual("650 2532", formatter.InputDigit('2'));
+            Assert.AreEqual("650 253 22", formatter.InputDigit('2'));
+            Assert.AreEqual("650 253 222", formatter.InputDigit('2'));
+            Assert.AreEqual("650 253 2222", formatter.InputDigit('2'));
+
+            formatter.Clear();
+            Assert.AreEqual("1", formatter.InputDigit('1'));
+            Assert.AreEqual("16", formatter.InputDigit('6'));
+            Assert.AreEqual("1 65", formatter.InputDigit('5'));
+            Assert.AreEqual("1 650", formatter.InputDigit('0'));
+            Assert.AreEqual("1 650 2", formatter.InputDigit('2'));
+            Assert.AreEqual("1 650 25", formatter.InputDigit('5'));
+            Assert.AreEqual("1 650 253", formatter.InputDigit('3'));
+            Assert.AreEqual("1 650 253 2", formatter.InputDigit('2'));
+            Assert.AreEqual("1 650 253 22", formatter.InputDigit('2'));
+            Assert.AreEqual("1 650 253 222", formatter.InputDigit('2'));
+            Assert.AreEqual("1 650 253 2222", formatter.InputDigit('2'));
+
+            formatter.Clear();
+            Assert.AreEqual("0", formatter.InputDigit('0'));
+            Assert.AreEqual("01", formatter.InputDigit('1'));
+            Assert.AreEqual("011 ", formatter.InputDigit('1'));
+            Assert.AreEqual("011 4", formatter.InputDigit('4'));
+            Assert.AreEqual("011 44 ", formatter.InputDigit('4'));
+            Assert.AreEqual("011 44 6", formatter.InputDigit('6'));
+            Assert.AreEqual("011 44 61", formatter.InputDigit('1'));
+            Assert.AreEqual("011 44 6 12", formatter.InputDigit('2'));
+            Assert.AreEqual("011 44 6 123", formatter.InputDigit('3'));
+            Assert.AreEqual("011 44 6 123 1", formatter.InputDigit('1'));
+            Assert.AreEqual("011 44 6 123 12", formatter.InputDigit('2'));
+            Assert.AreEqual("011 44 6 123 123", formatter.InputDigit('3'));
+            Assert.AreEqual("011 44 6 123 123 1", formatter.InputDigit('1'));
+            Assert.AreEqual("011 44 6 123 123 12", formatter.InputDigit('2'));
+            Assert.AreEqual("011 44 6 123 123 123", formatter.InputDigit('3'));
+
+            formatter.Clear();
+            Assert.AreEqual("0", formatter.InputDigit('0'));
+            Assert.AreEqual("01", formatter.InputDigit('1'));
+            Assert.AreEqual("011 ", formatter.InputDigit('1'));
+            Assert.AreEqual("011 5", formatter.InputDigit('5'));
+            Assert.AreEqual("011 54 ", formatter.InputDigit('4'));
+            Assert.AreEqual("011 54 9", formatter.InputDigit('9'));
+            Assert.AreEqual("011 54 91", formatter.InputDigit('1'));
+            Assert.AreEqual("011 54 9 11", formatter.InputDigit('1'));
+            Assert.AreEqual("011 54 9 11 2", formatter.InputDigit('2'));
+            Assert.AreEqual("011 54 9 11 23", formatter.InputDigit('3'));
+            Assert.AreEqual("011 54 9 11 231", formatter.InputDigit('1'));
+            Assert.AreEqual("011 54 9 11 2312", formatter.InputDigit('2'));
+            Assert.AreEqual("011 54 9 11 2312 1", formatter.InputDigit('1'));
+            Assert.AreEqual("011 54 9 11 2312 12", formatter.InputDigit('2'));
+            Assert.AreEqual("011 54 9 11 2312 123", formatter.InputDigit('3'));
+            Assert.AreEqual("011 54 9 11 2312 1234", formatter.InputDigit('4'));
+
+            formatter.Clear();
+            Assert.AreEqual("0", formatter.InputDigit('0'));
+            Assert.AreEqual("01", formatter.InputDigit('1'));
+            Assert.AreEqual("011 ", formatter.InputDigit('1'));
+            Assert.AreEqual("011 2", formatter.InputDigit('2'));
+            Assert.AreEqual("011 24", formatter.InputDigit('4'));
+            Assert.AreEqual("011 244 ", formatter.InputDigit('4'));
+            Assert.AreEqual("011 244 2", formatter.InputDigit('2'));
+            Assert.AreEqual("011 244 28", formatter.InputDigit('8'));
+            Assert.AreEqual("011 244 280", formatter.InputDigit('0'));
+            Assert.AreEqual("011 244 280 0", formatter.InputDigit('0'));
+            Assert.AreEqual("011 244 280 00", formatter.InputDigit('0'));
+            Assert.AreEqual("011 244 280 000", formatter.InputDigit('0'));
+            Assert.AreEqual("011 244 280 000 0", formatter.InputDigit('0'));
+            Assert.AreEqual("011 244 280 000 00", formatter.InputDigit('0'));
+            Assert.AreEqual("011 244 280 000 000", formatter.InputDigit('0'));
+
+            formatter.Clear();
+            Assert.AreEqual("+", formatter.InputDigit('+'));
+            Assert.AreEqual("+4", formatter.InputDigit('4'));
+            Assert.AreEqual("+48 ", formatter.InputDigit('8'));
+            Assert.AreEqual("+48 8", formatter.InputDigit('8'));
+            Assert.AreEqual("+48 88", formatter.InputDigit('8'));
+            Assert.AreEqual("+48 88 1", formatter.InputDigit('1'));
+            Assert.AreEqual("+48 88 12", formatter.InputDigit('2'));
+            Assert.AreEqual("+48 88 123", formatter.InputDigit('3'));
+            Assert.AreEqual("+48 88 123 1", formatter.InputDigit('1'));
+            Assert.AreEqual("+48 88 123 12", formatter.InputDigit('2'));
+            Assert.AreEqual("+48 88 123 12 1", formatter.InputDigit('1'));
+            Assert.AreEqual("+48 88 123 12 12", formatter.InputDigit('2'));
+        }
+
+        [Test]
+        public void TestAYTFUSFullWidthCharacters()
+        {
+            AsYouTypeFormatter formatter = phoneUtil.GetAsYouTypeFormatter("US");
+            Assert.AreEqual("\uFF16", formatter.InputDigit('\uFF16'));
+            Assert.AreEqual("\uFF16\uFF15", formatter.InputDigit('\uFF15'));
+            Assert.AreEqual("650", formatter.InputDigit('\uFF10'));
+            Assert.AreEqual("650 2", formatter.InputDigit('\uFF12'));
+            Assert.AreEqual("650 25", formatter.InputDigit('\uFF15'));
+            Assert.AreEqual("650 253", formatter.InputDigit('\uFF13'));
+            Assert.AreEqual("650 2532", formatter.InputDigit('\uFF12'));
+            Assert.AreEqual("650 253 22", formatter.InputDigit('\uFF12'));
+            Assert.AreEqual("650 253 222", formatter.InputDigit('\uFF12'));
+            Assert.AreEqual("650 253 2222", formatter.InputDigit('\uFF12'));
+        }
+
+        [Test]
+        public void TestAYTFUSMobileShortCode()
+        {
+            AsYouTypeFormatter formatter = phoneUtil.GetAsYouTypeFormatter("US");
+            Assert.AreEqual("*", formatter.InputDigit('*'));
+            Assert.AreEqual("*1", formatter.InputDigit('1'));
+            Assert.AreEqual("*12", formatter.InputDigit('2'));
+            Assert.AreEqual("*121", formatter.InputDigit('1'));
+            Assert.AreEqual("*121#", formatter.InputDigit('#'));
+        }
+
+        [Test]
+        public void TestAYTFUSVanityNumber()
+        {
+            AsYouTypeFormatter formatter = phoneUtil.GetAsYouTypeFormatter("US");
+            Assert.AreEqual("8", formatter.InputDigit('8'));
+            Assert.AreEqual("80", formatter.InputDigit('0'));
+            Assert.AreEqual("800", formatter.InputDigit('0'));
+            Assert.AreEqual("800 ", formatter.InputDigit(' '));
+            Assert.AreEqual("800 M", formatter.InputDigit('M'));
+            Assert.AreEqual("800 MY", formatter.InputDigit('Y'));
+            Assert.AreEqual("800 MY ", formatter.InputDigit(' '));
+            Assert.AreEqual("800 MY A", formatter.InputDigit('A'));
+            Assert.AreEqual("800 MY AP", formatter.InputDigit('P'));
+            Assert.AreEqual("800 MY APP", formatter.InputDigit('P'));
+            Assert.AreEqual("800 MY APPL", formatter.InputDigit('L'));
+            Assert.AreEqual("800 MY APPLE", formatter.InputDigit('E'));
+        }
+
+        [Test]
+        public void TestAYTFAndRememberPositionUS()
+        {
+            AsYouTypeFormatter formatter = phoneUtil.GetAsYouTypeFormatter("US");
+            Assert.AreEqual("1", formatter.InputDigitAndRememberPosition('1'));
+            Assert.AreEqual(1, formatter.GetRememberedPosition());
+            Assert.AreEqual("16", formatter.InputDigit('6'));
+            Assert.AreEqual("1 65", formatter.InputDigit('5'));
+            Assert.AreEqual(1, formatter.GetRememberedPosition());
+            Assert.AreEqual("1 650", formatter.InputDigitAndRememberPosition('0'));
+            Assert.AreEqual(5, formatter.GetRememberedPosition());
+            Assert.AreEqual("1 650 2", formatter.InputDigit('2'));
+            Assert.AreEqual("1 650 25", formatter.InputDigit('5'));
+            // Note the remembered position for digit "0" changes from 4 to 5, because a space is now
+            // inserted in the front.
+            Assert.AreEqual(5, formatter.GetRememberedPosition());
+            Assert.AreEqual("1 650 253", formatter.InputDigit('3'));
+            Assert.AreEqual("1 650 253 2", formatter.InputDigit('2'));
+            Assert.AreEqual("1 650 253 22", formatter.InputDigit('2'));
+            Assert.AreEqual(5, formatter.GetRememberedPosition());
+            Assert.AreEqual("1 650 253 222", formatter.InputDigitAndRememberPosition('2'));
+            Assert.AreEqual(13, formatter.GetRememberedPosition());
+            Assert.AreEqual("1 650 253 2222", formatter.InputDigit('2'));
+            Assert.AreEqual(13, formatter.GetRememberedPosition());
+            Assert.AreEqual("165025322222", formatter.InputDigit('2'));
+            Assert.AreEqual(10, formatter.GetRememberedPosition());
+            Assert.AreEqual("1650253222222", formatter.InputDigit('2'));
+            Assert.AreEqual(10, formatter.GetRememberedPosition());
+
+            formatter.Clear();
+            Assert.AreEqual("1", formatter.InputDigit('1'));
+            Assert.AreEqual("16", formatter.InputDigitAndRememberPosition('6'));
+            Assert.AreEqual(2, formatter.GetRememberedPosition());
+            Assert.AreEqual("1 65", formatter.InputDigit('5'));
+            Assert.AreEqual("1 650", formatter.InputDigit('0'));
+            Assert.AreEqual(3, formatter.GetRememberedPosition());
+            Assert.AreEqual("1 650 2", formatter.InputDigit('2'));
+            Assert.AreEqual("1 650 25", formatter.InputDigit('5'));
+            Assert.AreEqual(3, formatter.GetRememberedPosition());
+            Assert.AreEqual("1 650 253", formatter.InputDigit('3'));
+            Assert.AreEqual("1 650 253 2", formatter.InputDigit('2'));
+            Assert.AreEqual("1 650 253 22", formatter.InputDigit('2'));
+            Assert.AreEqual(3, formatter.GetRememberedPosition());
+            Assert.AreEqual("1 650 253 222", formatter.InputDigit('2'));
+            Assert.AreEqual("1 650 253 2222", formatter.InputDigit('2'));
+            Assert.AreEqual("165025322222", formatter.InputDigit('2'));
+            Assert.AreEqual(2, formatter.GetRememberedPosition());
+            Assert.AreEqual("1650253222222", formatter.InputDigit('2'));
+            Assert.AreEqual(2, formatter.GetRememberedPosition());
+
+            formatter.Clear();
+            Assert.AreEqual("6", formatter.InputDigit('6'));
+            Assert.AreEqual("65", formatter.InputDigit('5'));
+            Assert.AreEqual("650", formatter.InputDigit('0'));
+            Assert.AreEqual("650 2", formatter.InputDigit('2'));
+            Assert.AreEqual("650 25", formatter.InputDigit('5'));
+            Assert.AreEqual("650 253", formatter.InputDigit('3'));
+            Assert.AreEqual("650 2532", formatter.InputDigitAndRememberPosition('2'));
+            Assert.AreEqual(8, formatter.GetRememberedPosition());
+            Assert.AreEqual("650 253 22", formatter.InputDigit('2'));
+            Assert.AreEqual(9, formatter.GetRememberedPosition());
+            Assert.AreEqual("650 253 222", formatter.InputDigit('2'));
+            // No more formatting when semicolon is entered.
+            Assert.AreEqual("650253222;", formatter.InputDigit(';'));
+            Assert.AreEqual(7, formatter.GetRememberedPosition());
+            Assert.AreEqual("650253222;2", formatter.InputDigit('2'));
+
+            formatter.Clear();
+            Assert.AreEqual("6", formatter.InputDigit('6'));
+            Assert.AreEqual("65", formatter.InputDigit('5'));
+            Assert.AreEqual("650", formatter.InputDigit('0'));
+            // No more formatting when users choose to do their own formatting.
+            Assert.AreEqual("650-", formatter.InputDigit('-'));
+            Assert.AreEqual("650-2", formatter.InputDigitAndRememberPosition('2'));
+            Assert.AreEqual(5, formatter.GetRememberedPosition());
+            Assert.AreEqual("650-25", formatter.InputDigit('5'));
+            Assert.AreEqual(5, formatter.GetRememberedPosition());
+            Assert.AreEqual("650-253", formatter.InputDigit('3'));
+            Assert.AreEqual(5, formatter.GetRememberedPosition());
+            Assert.AreEqual("650-253-", formatter.InputDigit('-'));
+            Assert.AreEqual("650-253-2", formatter.InputDigit('2'));
+            Assert.AreEqual("650-253-22", formatter.InputDigit('2'));
+            Assert.AreEqual("650-253-222", formatter.InputDigit('2'));
+            Assert.AreEqual("650-253-2222", formatter.InputDigit('2'));
+
+            formatter.Clear();
+            Assert.AreEqual("0", formatter.InputDigit('0'));
+            Assert.AreEqual("01", formatter.InputDigit('1'));
+            Assert.AreEqual("011 ", formatter.InputDigit('1'));
+            Assert.AreEqual("011 4", formatter.InputDigitAndRememberPosition('4'));
+            Assert.AreEqual("011 48 ", formatter.InputDigit('8'));
+            Assert.AreEqual(5, formatter.GetRememberedPosition());
+            Assert.AreEqual("011 48 8", formatter.InputDigit('8'));
+            Assert.AreEqual(5, formatter.GetRememberedPosition());
+            Assert.AreEqual("011 48 88", formatter.InputDigit('8'));
+            Assert.AreEqual("011 48 88 1", formatter.InputDigit('1'));
+            Assert.AreEqual("011 48 88 12", formatter.InputDigit('2'));
+            Assert.AreEqual(5, formatter.GetRememberedPosition());
+            Assert.AreEqual("011 48 88 123", formatter.InputDigit('3'));
+            Assert.AreEqual("011 48 88 123 1", formatter.InputDigit('1'));
+            Assert.AreEqual("011 48 88 123 12", formatter.InputDigit('2'));
+            Assert.AreEqual("011 48 88 123 12 1", formatter.InputDigit('1'));
+            Assert.AreEqual("011 48 88 123 12 12", formatter.InputDigit('2'));
+
+            formatter.Clear();
+            Assert.AreEqual("+", formatter.InputDigit('+'));
+            Assert.AreEqual("+1", formatter.InputDigit('1'));
+            Assert.AreEqual("+1 6", formatter.InputDigitAndRememberPosition('6'));
+            Assert.AreEqual("+1 65", formatter.InputDigit('5'));
+            Assert.AreEqual("+1 650", formatter.InputDigit('0'));
+            Assert.AreEqual(4, formatter.GetRememberedPosition());
+            Assert.AreEqual("+1 650 2", formatter.InputDigit('2'));
+            Assert.AreEqual(4, formatter.GetRememberedPosition());
+            Assert.AreEqual("+1 650 25", formatter.InputDigit('5'));
+            Assert.AreEqual("+1 650 253", formatter.InputDigitAndRememberPosition('3'));
+            Assert.AreEqual("+1 650 253 2", formatter.InputDigit('2'));
+            Assert.AreEqual("+1 650 253 22", formatter.InputDigit('2'));
+            Assert.AreEqual("+1 650 253 222", formatter.InputDigit('2'));
+            Assert.AreEqual(10, formatter.GetRememberedPosition());
+
+            formatter.Clear();
+            Assert.AreEqual("+", formatter.InputDigit('+'));
+            Assert.AreEqual("+1", formatter.InputDigit('1'));
+            Assert.AreEqual("+1 6", formatter.InputDigitAndRememberPosition('6'));
+            Assert.AreEqual("+1 65", formatter.InputDigit('5'));
+            Assert.AreEqual("+1 650", formatter.InputDigit('0'));
+            Assert.AreEqual(4, formatter.GetRememberedPosition());
+            Assert.AreEqual("+1 650 2", formatter.InputDigit('2'));
+            Assert.AreEqual(4, formatter.GetRememberedPosition());
+            Assert.AreEqual("+1 650 25", formatter.InputDigit('5'));
+            Assert.AreEqual("+1 650 253", formatter.InputDigit('3'));
+            Assert.AreEqual("+1 650 253 2", formatter.InputDigit('2'));
+            Assert.AreEqual("+1 650 253 22", formatter.InputDigit('2'));
+            Assert.AreEqual("+1 650 253 222", formatter.InputDigit('2'));
+            Assert.AreEqual("+1650253222;", formatter.InputDigit(';'));
+            Assert.AreEqual(3, formatter.GetRememberedPosition());
+        }
+
+        [Test]
+        public void TestAYTFGBFixedLine()
+        {
+            AsYouTypeFormatter formatter = phoneUtil.GetAsYouTypeFormatter("GB");
+            Assert.AreEqual("0", formatter.InputDigit('0'));
+            Assert.AreEqual("02", formatter.InputDigit('2'));
+            Assert.AreEqual("020", formatter.InputDigit('0'));
+            Assert.AreEqual("020 7", formatter.InputDigitAndRememberPosition('7'));
+            Assert.AreEqual(5, formatter.GetRememberedPosition());
+            Assert.AreEqual("020 70", formatter.InputDigit('0'));
+            Assert.AreEqual("020 703", formatter.InputDigit('3'));
+            Assert.AreEqual(5, formatter.GetRememberedPosition());
+            Assert.AreEqual("020 7031", formatter.InputDigit('1'));
+            Assert.AreEqual("020 7031 3", formatter.InputDigit('3'));
+            Assert.AreEqual("020 7031 30", formatter.InputDigit('0'));
+            Assert.AreEqual("020 7031 300", formatter.InputDigit('0'));
+            Assert.AreEqual("020 7031 3000", formatter.InputDigit('0'));
+        }
+
+        [Test]
+        public void TestAYTFGBTollFree()
+        {
+            AsYouTypeFormatter formatter = phoneUtil.GetAsYouTypeFormatter("gb");
+            Assert.AreEqual("0", formatter.InputDigit('0'));
+            Assert.AreEqual("08", formatter.InputDigit('8'));
+            Assert.AreEqual("080", formatter.InputDigit('0'));
+            Assert.AreEqual("080 7", formatter.InputDigit('7'));
+            Assert.AreEqual("080 70", formatter.InputDigit('0'));
+            Assert.AreEqual("080 703", formatter.InputDigit('3'));
+            Assert.AreEqual("080 7031", formatter.InputDigit('1'));
+            Assert.AreEqual("080 7031 3", formatter.InputDigit('3'));
+            Assert.AreEqual("080 7031 30", formatter.InputDigit('0'));
+            Assert.AreEqual("080 7031 300", formatter.InputDigit('0'));
+            Assert.AreEqual("080 7031 3000", formatter.InputDigit('0'));
+        }
+
+        [Test]
+        public void TestAYTFGBPremiumRate()
+        {
+            AsYouTypeFormatter formatter = phoneUtil.GetAsYouTypeFormatter("GB");
+            Assert.AreEqual("0", formatter.InputDigit('0'));
+            Assert.AreEqual("09", formatter.InputDigit('9'));
+            Assert.AreEqual("090", formatter.InputDigit('0'));
+            Assert.AreEqual("090 7", formatter.InputDigit('7'));
+            Assert.AreEqual("090 70", formatter.InputDigit('0'));
+            Assert.AreEqual("090 703", formatter.InputDigit('3'));
+            Assert.AreEqual("090 7031", formatter.InputDigit('1'));
+            Assert.AreEqual("090 7031 3", formatter.InputDigit('3'));
+            Assert.AreEqual("090 7031 30", formatter.InputDigit('0'));
+            Assert.AreEqual("090 7031 300", formatter.InputDigit('0'));
+            Assert.AreEqual("090 7031 3000", formatter.InputDigit('0'));
+        }
+
+        [Test]
+        public void TestAYTFNZMobile()
+        {
+            AsYouTypeFormatter formatter = phoneUtil.GetAsYouTypeFormatter("NZ");
+            Assert.AreEqual("0", formatter.InputDigit('0'));
+            Assert.AreEqual("02", formatter.InputDigit('2'));
+            Assert.AreEqual("021", formatter.InputDigit('1'));
+            Assert.AreEqual("02-11", formatter.InputDigit('1'));
+            Assert.AreEqual("02-112", formatter.InputDigit('2'));
+            // Note the unittest is using fake metadata which might produce non-ideal results.
+            Assert.AreEqual("02-112 3", formatter.InputDigit('3'));
+            Assert.AreEqual("02-112 34", formatter.InputDigit('4'));
+            Assert.AreEqual("02-112 345", formatter.InputDigit('5'));
+            Assert.AreEqual("02-112 3456", formatter.InputDigit('6'));
+        }
+
+        [Test]
+        public void TestAYTFDE()
+        {
+            AsYouTypeFormatter formatter = phoneUtil.GetAsYouTypeFormatter("DE");
+            Assert.AreEqual("0", formatter.InputDigit('0'));
+            Assert.AreEqual("03", formatter.InputDigit('3'));
+            Assert.AreEqual("030", formatter.InputDigit('0'));
+            Assert.AreEqual("030/1", formatter.InputDigit('1'));
+            Assert.AreEqual("030/12", formatter.InputDigit('2'));
+            Assert.AreEqual("030/123", formatter.InputDigit('3'));
+            Assert.AreEqual("030/1234", formatter.InputDigit('4'));
+
+            // 04134 1234
+            formatter.Clear();
+            Assert.AreEqual("0", formatter.InputDigit('0'));
+            Assert.AreEqual("04", formatter.InputDigit('4'));
+            Assert.AreEqual("041", formatter.InputDigit('1'));
+            Assert.AreEqual("041 3", formatter.InputDigit('3'));
+            Assert.AreEqual("041 34", formatter.InputDigit('4'));
+            Assert.AreEqual("04134 1", formatter.InputDigit('1'));
+            Assert.AreEqual("04134 12", formatter.InputDigit('2'));
+            Assert.AreEqual("04134 123", formatter.InputDigit('3'));
+            Assert.AreEqual("04134 1234", formatter.InputDigit('4'));
+
+            // 08021 2345
+            formatter.Clear();
+            Assert.AreEqual("0", formatter.InputDigit('0'));
+            Assert.AreEqual("08", formatter.InputDigit('8'));
+            Assert.AreEqual("080", formatter.InputDigit('0'));
+            Assert.AreEqual("080 2", formatter.InputDigit('2'));
+            Assert.AreEqual("080 21", formatter.InputDigit('1'));
+            Assert.AreEqual("08021 2", formatter.InputDigit('2'));
+            Assert.AreEqual("08021 23", formatter.InputDigit('3'));
+            Assert.AreEqual("08021 234", formatter.InputDigit('4'));
+            Assert.AreEqual("08021 2345", formatter.InputDigit('5'));
+
+            // 00 1 650 253 2250
+            formatter.Clear();
+            Assert.AreEqual("0", formatter.InputDigit('0'));
+            Assert.AreEqual("00", formatter.InputDigit('0'));
+            Assert.AreEqual("00 1 ", formatter.InputDigit('1'));
+            Assert.AreEqual("00 1 6", formatter.InputDigit('6'));
+            Assert.AreEqual("00 1 65", formatter.InputDigit('5'));
+            Assert.AreEqual("00 1 650", formatter.InputDigit('0'));
+            Assert.AreEqual("00 1 650 2", formatter.InputDigit('2'));
+            Assert.AreEqual("00 1 650 25", formatter.InputDigit('5'));
+            Assert.AreEqual("00 1 650 253", formatter.InputDigit('3'));
+            Assert.AreEqual("00 1 650 253 2", formatter.InputDigit('2'));
+            Assert.AreEqual("00 1 650 253 22", formatter.InputDigit('2'));
+            Assert.AreEqual("00 1 650 253 222", formatter.InputDigit('2'));
+            Assert.AreEqual("00 1 650 253 2222", formatter.InputDigit('2'));
+        }
+
+        [Test]
+        public void TestAYTFAR()
+        {
+            AsYouTypeFormatter formatter = phoneUtil.GetAsYouTypeFormatter("AR");
+            Assert.AreEqual("0", formatter.InputDigit('0'));
+            Assert.AreEqual("01", formatter.InputDigit('1'));
+            Assert.AreEqual("011", formatter.InputDigit('1'));
+            Assert.AreEqual("011 7", formatter.InputDigit('7'));
+            Assert.AreEqual("011 70", formatter.InputDigit('0'));
+            Assert.AreEqual("011 703", formatter.InputDigit('3'));
+            Assert.AreEqual("011 7031", formatter.InputDigit('1'));
+            Assert.AreEqual("011 7031-3", formatter.InputDigit('3'));
+            Assert.AreEqual("011 7031-30", formatter.InputDigit('0'));
+            Assert.AreEqual("011 7031-300", formatter.InputDigit('0'));
+            Assert.AreEqual("011 7031-3000", formatter.InputDigit('0'));
+        }
+
+        [Test]
+        public void TestAYTFARMobile()
+        {
+            AsYouTypeFormatter formatter = phoneUtil.GetAsYouTypeFormatter("AR");
+            Assert.AreEqual("+", formatter.InputDigit('+'));
+            Assert.AreEqual("+5", formatter.InputDigit('5'));
+            Assert.AreEqual("+54 ", formatter.InputDigit('4'));
+            Assert.AreEqual("+54 9", formatter.InputDigit('9'));
+            Assert.AreEqual("+54 91", formatter.InputDigit('1'));
+            Assert.AreEqual("+54 9 11", formatter.InputDigit('1'));
+            Assert.AreEqual("+54 9 11 2", formatter.InputDigit('2'));
+            Assert.AreEqual("+54 9 11 23", formatter.InputDigit('3'));
+            Assert.AreEqual("+54 9 11 231", formatter.InputDigit('1'));
+            Assert.AreEqual("+54 9 11 2312", formatter.InputDigit('2'));
+            Assert.AreEqual("+54 9 11 2312 1", formatter.InputDigit('1'));
+            Assert.AreEqual("+54 9 11 2312 12", formatter.InputDigit('2'));
+            Assert.AreEqual("+54 9 11 2312 123", formatter.InputDigit('3'));
+            Assert.AreEqual("+54 9 11 2312 1234", formatter.InputDigit('4'));
+        }
+
+        [Test]
+        public void TestAYTFKR()
+        {
+            // +82 51 234 5678
+            AsYouTypeFormatter formatter = phoneUtil.GetAsYouTypeFormatter("KR");
+            Assert.AreEqual("+", formatter.InputDigit('+'));
+            Assert.AreEqual("+8", formatter.InputDigit('8'));
+            Assert.AreEqual("+82 ", formatter.InputDigit('2'));
+            Assert.AreEqual("+82 5", formatter.InputDigit('5'));
+            Assert.AreEqual("+82 51", formatter.InputDigit('1'));
+            Assert.AreEqual("+82 51-2", formatter.InputDigit('2'));
+            Assert.AreEqual("+82 51-23", formatter.InputDigit('3'));
+            Assert.AreEqual("+82 51-234", formatter.InputDigit('4'));
+            Assert.AreEqual("+82 51-234-5", formatter.InputDigit('5'));
+            Assert.AreEqual("+82 51-234-56", formatter.InputDigit('6'));
+            Assert.AreEqual("+82 51-234-567", formatter.InputDigit('7'));
+            Assert.AreEqual("+82 51-234-5678", formatter.InputDigit('8'));
+
+            // +82 2 531 5678
+            formatter.Clear();
+            Assert.AreEqual("+", formatter.InputDigit('+'));
+            Assert.AreEqual("+8", formatter.InputDigit('8'));
+            Assert.AreEqual("+82 ", formatter.InputDigit('2'));
+            Assert.AreEqual("+82 2", formatter.InputDigit('2'));
+            Assert.AreEqual("+82 25", formatter.InputDigit('5'));
+            Assert.AreEqual("+82 2-53", formatter.InputDigit('3'));
+            Assert.AreEqual("+82 2-531", formatter.InputDigit('1'));
+            Assert.AreEqual("+82 2-531-5", formatter.InputDigit('5'));
+            Assert.AreEqual("+82 2-531-56", formatter.InputDigit('6'));
+            Assert.AreEqual("+82 2-531-567", formatter.InputDigit('7'));
+            Assert.AreEqual("+82 2-531-5678", formatter.InputDigit('8'));
+
+            // +82 2 3665 5678
+            formatter.Clear();
+            Assert.AreEqual("+", formatter.InputDigit('+'));
+            Assert.AreEqual("+8", formatter.InputDigit('8'));
+            Assert.AreEqual("+82 ", formatter.InputDigit('2'));
+            Assert.AreEqual("+82 2", formatter.InputDigit('2'));
+            Assert.AreEqual("+82 23", formatter.InputDigit('3'));
+            Assert.AreEqual("+82 2-36", formatter.InputDigit('6'));
+            Assert.AreEqual("+82 2-366", formatter.InputDigit('6'));
+            Assert.AreEqual("+82 2-3665", formatter.InputDigit('5'));
+            Assert.AreEqual("+82 2-3665-5", formatter.InputDigit('5'));
+            Assert.AreEqual("+82 2-3665-56", formatter.InputDigit('6'));
+            Assert.AreEqual("+82 2-3665-567", formatter.InputDigit('7'));
+            Assert.AreEqual("+82 2-3665-5678", formatter.InputDigit('8'));
+
+            // 02-114
+            formatter.Clear();
+            Assert.AreEqual("0", formatter.InputDigit('0'));
+            Assert.AreEqual("02", formatter.InputDigit('2'));
+            Assert.AreEqual("021", formatter.InputDigit('1'));
+            Assert.AreEqual("02-11", formatter.InputDigit('1'));
+            Assert.AreEqual("02-114", formatter.InputDigit('4'));
+
+            // 02-1300
+            formatter.Clear();
+            Assert.AreEqual("0", formatter.InputDigit('0'));
+            Assert.AreEqual("02", formatter.InputDigit('2'));
+            Assert.AreEqual("021", formatter.InputDigit('1'));
+            Assert.AreEqual("02-13", formatter.InputDigit('3'));
+            Assert.AreEqual("02-130", formatter.InputDigit('0'));
+            Assert.AreEqual("02-1300", formatter.InputDigit('0'));
+
+            // 011-456-7890
+            formatter.Clear();
+            Assert.AreEqual("0", formatter.InputDigit('0'));
+            Assert.AreEqual("01", formatter.InputDigit('1'));
+            Assert.AreEqual("011", formatter.InputDigit('1'));
+            Assert.AreEqual("011-4", formatter.InputDigit('4'));
+            Assert.AreEqual("011-45", formatter.InputDigit('5'));
+            Assert.AreEqual("011-456", formatter.InputDigit('6'));
+            Assert.AreEqual("011-456-7", formatter.InputDigit('7'));
+            Assert.AreEqual("011-456-78", formatter.InputDigit('8'));
+            Assert.AreEqual("011-456-789", formatter.InputDigit('9'));
+            Assert.AreEqual("011-456-7890", formatter.InputDigit('0'));
+
+            // 011-9876-7890
+            formatter.Clear();
+            Assert.AreEqual("0", formatter.InputDigit('0'));
+            Assert.AreEqual("01", formatter.InputDigit('1'));
+            Assert.AreEqual("011", formatter.InputDigit('1'));
+            Assert.AreEqual("011-9", formatter.InputDigit('9'));
+            Assert.AreEqual("011-98", formatter.InputDigit('8'));
+            Assert.AreEqual("011-987", formatter.InputDigit('7'));
+            Assert.AreEqual("011-9876", formatter.InputDigit('6'));
+            Assert.AreEqual("011-9876-7", formatter.InputDigit('7'));
+            Assert.AreEqual("011-9876-78", formatter.InputDigit('8'));
+            Assert.AreEqual("011-9876-789", formatter.InputDigit('9'));
+            Assert.AreEqual("011-9876-7890", formatter.InputDigit('0'));
+        }
+
+        [Test]
+        public void TestAYTF_MX()
+        {
+            AsYouTypeFormatter formatter = phoneUtil.GetAsYouTypeFormatter("MX");
+
+            // +52 800 123 4567
+            Assert.AreEqual("+", formatter.InputDigit('+'));
+            Assert.AreEqual("+5", formatter.InputDigit('5'));
+            Assert.AreEqual("+52 ", formatter.InputDigit('2'));
+            Assert.AreEqual("+52 8", formatter.InputDigit('8'));
+            Assert.AreEqual("+52 80", formatter.InputDigit('0'));
+            Assert.AreEqual("+52 800", formatter.InputDigit('0'));
+            Assert.AreEqual("+52 800 1", formatter.InputDigit('1'));
+            Assert.AreEqual("+52 800 12", formatter.InputDigit('2'));
+            Assert.AreEqual("+52 800 123", formatter.InputDigit('3'));
+            Assert.AreEqual("+52 800 123 4", formatter.InputDigit('4'));
+            Assert.AreEqual("+52 800 123 45", formatter.InputDigit('5'));
+            Assert.AreEqual("+52 800 123 456", formatter.InputDigit('6'));
+            Assert.AreEqual("+52 800 123 4567", formatter.InputDigit('7'));
+
+            // +52 55 1234 5678
+            formatter.Clear();
+            Assert.AreEqual("+", formatter.InputDigit('+'));
+            Assert.AreEqual("+5", formatter.InputDigit('5'));
+            Assert.AreEqual("+52 ", formatter.InputDigit('2'));
+            Assert.AreEqual("+52 5", formatter.InputDigit('5'));
+            Assert.AreEqual("+52 55", formatter.InputDigit('5'));
+            Assert.AreEqual("+52 55 1", formatter.InputDigit('1'));
+            Assert.AreEqual("+52 55 12", formatter.InputDigit('2'));
+            Assert.AreEqual("+52 55 123", formatter.InputDigit('3'));
+            Assert.AreEqual("+52 55 1234", formatter.InputDigit('4'));
+            Assert.AreEqual("+52 55 1234 5", formatter.InputDigit('5'));
+            Assert.AreEqual("+52 55 1234 56", formatter.InputDigit('6'));
+            Assert.AreEqual("+52 55 1234 567", formatter.InputDigit('7'));
+            Assert.AreEqual("+52 55 1234 5678", formatter.InputDigit('8'));
+
+            // +52 212 345 6789
+            formatter.Clear();
+            Assert.AreEqual("+", formatter.InputDigit('+'));
+            Assert.AreEqual("+5", formatter.InputDigit('5'));
+            Assert.AreEqual("+52 ", formatter.InputDigit('2'));
+            Assert.AreEqual("+52 2", formatter.InputDigit('2'));
+            Assert.AreEqual("+52 21", formatter.InputDigit('1'));
+            Assert.AreEqual("+52 212", formatter.InputDigit('2'));
+            Assert.AreEqual("+52 212 3", formatter.InputDigit('3'));
+            Assert.AreEqual("+52 212 34", formatter.InputDigit('4'));
+            Assert.AreEqual("+52 212 345", formatter.InputDigit('5'));
+            Assert.AreEqual("+52 212 345 6", formatter.InputDigit('6'));
+            Assert.AreEqual("+52 212 345 67", formatter.InputDigit('7'));
+            Assert.AreEqual("+52 212 345 678", formatter.InputDigit('8'));
+            Assert.AreEqual("+52 212 345 6789", formatter.InputDigit('9'));
+
+            // +52 1 55 1234 5678
+            formatter.Clear();
+            Assert.AreEqual("+", formatter.InputDigit('+'));
+            Assert.AreEqual("+5", formatter.InputDigit('5'));
+            Assert.AreEqual("+52 ", formatter.InputDigit('2'));
+            Assert.AreEqual("+52 1", formatter.InputDigit('1'));
+            Assert.AreEqual("+52 15", formatter.InputDigit('5'));
+            Assert.AreEqual("+52 1 55", formatter.InputDigit('5'));
+            Assert.AreEqual("+52 1 55 1", formatter.InputDigit('1'));
+            Assert.AreEqual("+52 1 55 12", formatter.InputDigit('2'));
+            Assert.AreEqual("+52 1 55 123", formatter.InputDigit('3'));
+            Assert.AreEqual("+52 1 55 1234", formatter.InputDigit('4'));
+            Assert.AreEqual("+52 1 55 1234 5", formatter.InputDigit('5'));
+            Assert.AreEqual("+52 1 55 1234 56", formatter.InputDigit('6'));
+            Assert.AreEqual("+52 1 55 1234 567", formatter.InputDigit('7'));
+            Assert.AreEqual("+52 1 55 1234 5678", formatter.InputDigit('8'));
+
+            // +52 1 541 234 5678
+            formatter.Clear();
+            Assert.AreEqual("+", formatter.InputDigit('+'));
+            Assert.AreEqual("+5", formatter.InputDigit('5'));
+            Assert.AreEqual("+52 ", formatter.InputDigit('2'));
+            Assert.AreEqual("+52 1", formatter.InputDigit('1'));
+            Assert.AreEqual("+52 15", formatter.InputDigit('5'));
+            Assert.AreEqual("+52 1 54", formatter.InputDigit('4'));
+            Assert.AreEqual("+52 1 541", formatter.InputDigit('1'));
+            Assert.AreEqual("+52 1 541 2", formatter.InputDigit('2'));
+            Assert.AreEqual("+52 1 541 23", formatter.InputDigit('3'));
+            Assert.AreEqual("+52 1 541 234", formatter.InputDigit('4'));
+            Assert.AreEqual("+52 1 541 234 5", formatter.InputDigit('5'));
+            Assert.AreEqual("+52 1 541 234 56", formatter.InputDigit('6'));
+            Assert.AreEqual("+52 1 541 234 567", formatter.InputDigit('7'));
+            Assert.AreEqual("+52 1 541 234 5678", formatter.InputDigit('8'));
+        }
+
+        [Test]
+        public void TestAYTFMultipleLeadingDigitPatterns()
+        {
+            // +81 50 2345 6789
+            AsYouTypeFormatter formatter = phoneUtil.GetAsYouTypeFormatter("JP");
+            Assert.AreEqual("+", formatter.InputDigit('+'));
+            Assert.AreEqual("+8", formatter.InputDigit('8'));
+            Assert.AreEqual("+81 ", formatter.InputDigit('1'));
+            Assert.AreEqual("+81 5", formatter.InputDigit('5'));
+            Assert.AreEqual("+81 50", formatter.InputDigit('0'));
+            Assert.AreEqual("+81 50 2", formatter.InputDigit('2'));
+            Assert.AreEqual("+81 50 23", formatter.InputDigit('3'));
+            Assert.AreEqual("+81 50 234", formatter.InputDigit('4'));
+            Assert.AreEqual("+81 50 2345", formatter.InputDigit('5'));
+            Assert.AreEqual("+81 50 2345 6", formatter.InputDigit('6'));
+            Assert.AreEqual("+81 50 2345 67", formatter.InputDigit('7'));
+            Assert.AreEqual("+81 50 2345 678", formatter.InputDigit('8'));
+            Assert.AreEqual("+81 50 2345 6789", formatter.InputDigit('9'));
+
+            // +81 222 12 5678
+            formatter.Clear();
+            Assert.AreEqual("+", formatter.InputDigit('+'));
+            Assert.AreEqual("+8", formatter.InputDigit('8'));
+            Assert.AreEqual("+81 ", formatter.InputDigit('1'));
+            Assert.AreEqual("+81 2", formatter.InputDigit('2'));
+            Assert.AreEqual("+81 22", formatter.InputDigit('2'));
+            Assert.AreEqual("+81 22 2", formatter.InputDigit('2'));
+            Assert.AreEqual("+81 22 21", formatter.InputDigit('1'));
+            Assert.AreEqual("+81 2221 2", formatter.InputDigit('2'));
+            Assert.AreEqual("+81 222 12 5", formatter.InputDigit('5'));
+            Assert.AreEqual("+81 222 12 56", formatter.InputDigit('6'));
+            Assert.AreEqual("+81 222 12 567", formatter.InputDigit('7'));
+            Assert.AreEqual("+81 222 12 5678", formatter.InputDigit('8'));
+
+            // +81 3332 2 5678
+            formatter.Clear();
+            Assert.AreEqual("+", formatter.InputDigit('+'));
+            Assert.AreEqual("+8", formatter.InputDigit('8'));
+            Assert.AreEqual("+81 ", formatter.InputDigit('1'));
+            Assert.AreEqual("+81 3", formatter.InputDigit('3'));
+            Assert.AreEqual("+81 33", formatter.InputDigit('3'));
+            Assert.AreEqual("+81 33 3", formatter.InputDigit('3'));
+            Assert.AreEqual("+81 3332", formatter.InputDigit('2'));
+            Assert.AreEqual("+81 3332 2", formatter.InputDigit('2'));
+            Assert.AreEqual("+81 3332 2 5", formatter.InputDigit('5'));
+            Assert.AreEqual("+81 3332 2 56", formatter.InputDigit('6'));
+            Assert.AreEqual("+81 3332 2 567", formatter.InputDigit('7'));
+            Assert.AreEqual("+81 3332 2 5678", formatter.InputDigit('8'));
+        }
+    }
+}

csharp/PhoneNumbers.Test/TestExampleNumbers.cs

+/*
+ * Copyright (C) 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using NUnit.Framework;
+
+namespace PhoneNumbers.Test
+{
+    [TestFixture]
+    class TestExampleNumbers
+    {
+        private PhoneNumberUtil phoneNumberUtil;
+        private List<PhoneNumber> invalidCases = new List<PhoneNumber>();
+        private List<PhoneNumber> wrongTypeCases = new List<PhoneNumber>();
+
+        [TestFixtureSetUp]
+        public void SetupFixture()
+        {
+            PhoneNumberUtil.ResetInstance();
+            phoneNumberUtil = PhoneNumberUtil.GetInstance();
+        }
+
+        [SetUp]
+        protected void SetUp()
+        {
+            invalidCases.Clear();
+            wrongTypeCases.Clear();
+        }
+
+        /**
+        * @param exampleNumberRequestedType  type we are requesting an example number for
+        * @param possibleExpectedTypes       acceptable types that this number should match, such as
+        *     FIXED_LINE and FIXED_LINE_OR_MOBILE for a fixed line example number.
+        */
+        private void checkNumbersValidAndCorrectType(PhoneNumberType exampleNumberRequestedType,
+            HashSet<PhoneNumberType> possibleExpectedTypes)
+        {
+            foreach (var regionCode in phoneNumberUtil.GetSupportedRegions())
+            {
+                PhoneNumber exampleNumber =
+                phoneNumberUtil.GetExampleNumberForType(regionCode, exampleNumberRequestedType);
+                if (exampleNumber != null)
+                {
+                    if (!phoneNumberUtil.IsValidNumber(exampleNumber))
+                    {
+                        invalidCases.Add(exampleNumber);
+                        //LOGGER.log(Level.SEVERE, "Failed validation for " + exampleNumber.toString());
+                    }
+                    else
+                    {
+                        // We know the number is valid, now we check the type.
+                        PhoneNumberType exampleNumberType = phoneNumberUtil.GetNumberType(exampleNumber);
+                        if (!possibleExpectedTypes.Contains(exampleNumberType))
+                        {
+                            wrongTypeCases.Add(exampleNumber);
+                            //LOGGER.log(Level.SEVERE, "Wrong type for " + exampleNumber.toString() + ": got " + exampleNumberType);
+                            //LOGGER.log(Level.WARNING, "Expected types: ");
+                            //for (PhoneNumberType type : possibleExpectedTypes) {
+                            //LOGGER.log(Level.WARNING, type.toString());
+                        }
+                    }
+                }
+            }
+        }
+
+        private HashSet<PhoneNumberType> MakeSet(PhoneNumberType t1, PhoneNumberType t2)
+        {
+            return new HashSet<PhoneNumberType>(new PhoneNumberType[] { t1, t2 });
+        }
+
+        private HashSet<PhoneNumberType> MakeSet(PhoneNumberType t1)
+        {
+            return MakeSet(t1, t1);
+        }
+
+        [Test]
+        public void TestFixedLine()
+        {
+            HashSet<PhoneNumberType> fixedLineTypes = MakeSet(PhoneNumberType.FIXED_LINE,
+                                            PhoneNumberType.FIXED_LINE_OR_MOBILE);
+            checkNumbersValidAndCorrectType(PhoneNumberType.FIXED_LINE, fixedLineTypes);
+            Assert.AreEqual(0, invalidCases.Count);
+            Assert.AreEqual(0, wrongTypeCases.Count);
+        }
+
+        [Test]
+        public void TestMobile()
+        {
+            HashSet<PhoneNumberType> mobileTypes = MakeSet(PhoneNumberType.MOBILE,
+                                                          PhoneNumberType.FIXED_LINE_OR_MOBILE);
+            checkNumbersValidAndCorrectType(PhoneNumberType.MOBILE, mobileTypes);
+            Assert.AreEqual(0, invalidCases.Count);
+            Assert.AreEqual(0, wrongTypeCases.Count);
+        }
+
+        [Test]
+        public void TestTollFree()
+        {
+
+            HashSet<PhoneNumberType> tollFreeTypes = MakeSet(PhoneNumberType.TOLL_FREE);
+            checkNumbersValidAndCorrectType(PhoneNumberType.TOLL_FREE, tollFreeTypes);
+            Assert.AreEqual(0, invalidCases.Count);
+            Assert.AreEqual(0, wrongTypeCases.Count);
+        }
+
+        [Test]
+        public void TestPremiumRate()
+        {
+            HashSet<PhoneNumberType> premiumRateTypes = MakeSet(PhoneNumberType.PREMIUM_RATE);
+            checkNumbersValidAndCorrectType(PhoneNumberType.PREMIUM_RATE, premiumRateTypes);
+            Assert.AreEqual(0, invalidCases.Count);
+            Assert.AreEqual(0, wrongTypeCases.Count);
+        }
+
+        [Test]
+        public void TestVoip()
+        {
+            HashSet<PhoneNumberType> voipTypes = MakeSet(PhoneNumberType.VOIP);
+            checkNumbersValidAndCorrectType(PhoneNumberType.VOIP, voipTypes);
+            Assert.AreEqual(0, invalidCases.Count);
+            Assert.AreEqual(0, wrongTypeCases.Count);
+        }
+
+        [Test]
+        public void TestPager()
+        {
+            HashSet<PhoneNumberType> pagerTypes = MakeSet(PhoneNumberType.PAGER);
+            checkNumbersValidAndCorrectType(PhoneNumberType.PAGER, pagerTypes);
+            Assert.AreEqual(0, invalidCases.Count);
+            Assert.AreEqual(0, wrongTypeCases.Count);
+        }
+
+        [Test]
+        public void TestUan()
+        {
+            HashSet<PhoneNumberType> uanTypes = MakeSet(PhoneNumberType.UAN);
+            checkNumbersValidAndCorrectType(PhoneNumberType.UAN, uanTypes);
+            Assert.AreEqual(0, invalidCases.Count);
+            Assert.AreEqual(0, wrongTypeCases.Count);
+        }
+
+        [Test]
+        public void TestSharedCost()
+        {
+            HashSet<PhoneNumberType> sharedCostTypes = MakeSet(PhoneNumberType.SHARED_COST);
+            checkNumbersValidAndCorrectType(PhoneNumberType.SHARED_COST, sharedCostTypes);
+            Assert.AreEqual(0, invalidCases.Count);
+            Assert.AreEqual(0, wrongTypeCases.Count);
+        }
+
+        [Test]
+        public void TestCanBeInternationallyDialled()
+        {
+            foreach (var regionCode in phoneNumberUtil.GetSupportedRegions())
+            {
+                PhoneNumber exampleNumber = null;
+                PhoneNumberDesc desc =
+                    phoneNumberUtil.GetMetadataForRegion(regionCode).NoInternationalDialling;
+                try
+                {
+                    if (desc.HasExampleNumber)
+                    {
+                        exampleNumber = phoneNumberUtil.Parse(desc.ExampleNumber, regionCode);
+                    }
+                }
+                catch (NumberParseException)
+                {
+                }
+                if (exampleNumber != null && phoneNumberUtil.CanBeInternationallyDialled(exampleNumber))
+                {
+                    wrongTypeCases.Add(exampleNumber);
+                }
+            }
+            Assert.AreEqual(0, wrongTypeCases.Count);
+        }
+    }
+}

csharp/PhoneNumbers.Test/TestPhoneNumberMatch.cs

+/*
+ * Copyright (C) 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using NUnit.Framework;
+
+namespace PhoneNumbers.Test
+{
+    [TestFixture]
+    class TestPhoneNumberMatch
+    {
+        [Test]
+        public void TestValueTypeSemantics()
+        {
+            PhoneNumber number = new PhoneNumber();
+            PhoneNumberMatch match1 = new PhoneNumberMatch(10, "1 800 234 45 67", number);
+            PhoneNumberMatch match2 = new PhoneNumberMatch(10, "1 800 234 45 67", number);
+
+            Assert.AreEqual(match1, match2);
+            Assert.AreEqual(match1.GetHashCode(), match2.GetHashCode());
+            Assert.AreEqual(match1.Start, match2.Start);
+            Assert.AreEqual(match1.Length, match2.Length);
+            Assert.AreEqual(match1.Number, match2.Number);
+            Assert.AreEqual(match1.RawString, match2.RawString);
+            Assert.AreEqual("1 800 234 45 67", match1.RawString);
+        }
+
+        /**
+        * Tests the value type semantics for matches with a null number.
+        */
+        [Test]
+        public void TestIllegalArguments()
+        {
+            try
+            {
+                new PhoneNumberMatch(-110, "1 800 234 45 67", new PhoneNumber());
+                Assert.Fail();
+            }
+            catch (ArgumentException) { /* success */ }
+
+            try
+            {
+                new PhoneNumberMatch(10, "1 800 234 45 67", null);
+                Assert.Fail();
+            }
+            catch (ArgumentNullException) { /* success */ }
+
+            try
+            {
+                new PhoneNumberMatch(10, null, new PhoneNumber());
+                Assert.Fail();
+            }
+            catch (ArgumentNullException) { /* success */ }
+
+            try
+            {
+                new PhoneNumberMatch(10, null, null);
+                Assert.Fail();
+            }
+            catch (ArgumentNullException) { /* success */ }
+        }
+    }
+}

csharp/PhoneNumbers.Test/TestPhoneNumberMatcher.cs

+/*
+ * Copyright (C) 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using NUnit.Framework;
+
+namespace PhoneNumbers.Test
+{
+    [TestFixture]
+    class TestPhoneNumberMatcher
+    {
+        private PhoneNumberUtil phoneUtil;
+
+        [SetUp]
+        protected void SetUp()
+        {
+            phoneUtil = TestPhoneNumberUtil.InitializePhoneUtilForTesting();
+        }
+
+        /** See {@link PhoneNumberUtilTest#testParseNationalNumber()}. */
+        [Test]
+        public void TestFindNationalNumber()
+        {
+            // same cases as in testParseNationalNumber
+            doTestFindInContext("033316005", "NZ");
+            doTestFindInContext("33316005", "NZ");
+            // National prefix attached and some formatting present.
+            doTestFindInContext("03-331 6005", "NZ");
+            doTestFindInContext("03 331 6005", "NZ");
+            // Testing international prefixes.
+            // Should strip country code.
+            doTestFindInContext("0064 3 331 6005", "NZ");
+            // Try again, but this time we have an international number with Region Code US. It should
+            // recognize the country code and parse accordingly.
+            doTestFindInContext("01164 3 331 6005", "US");
+            doTestFindInContext("+64 3 331 6005", "US");
+
+            doTestFindInContext("64(0)64123456", "NZ");
+            // Check that using a "/" is fine in a phone number.
+            doTestFindInContext("123/45678", "DE");
+            doTestFindInContext("123-456-7890", "US");
+        }
+
+          /** See {@link PhoneNumberUtilTest#testParseWithInternationalPrefixes()}. */
+        [Test]
+        public void TestFindWithInternationalPrefixes()
+        {
+            doTestFindInContext("+1 (650) 333-6000", "NZ");
+            doTestFindInContext("1-650-333-6000", "US");
+            // Calling the US number from Singapore by using different service providers
+            // 1st test: calling using SingTel IDD service (IDD is 001)
+            doTestFindInContext("0011-650-333-6000", "SG");
+            // 2nd test: calling using StarHub IDD service (IDD is 008)
+            doTestFindInContext("0081-650-333-6000", "SG");
+            // 3rd test: calling using SingTel V019 service (IDD is 019)
+            doTestFindInContext("0191-650-333-6000", "SG");
+            // Calling the US number from Poland
+            doTestFindInContext("0~01-650-333-6000", "PL");
+            // Using "++" at the start.
+            doTestFindInContext("++1 (650) 333-6000", "PL");
+            // Using a full-width plus sign.
+            doTestFindInContext("\uFF0B1 (650) 333-6000", "SG");
+            // The whole number, including punctuation, is here represented in full-width form.
+            doTestFindInContext("\uFF0B\uFF11\u3000\uFF08\uFF16\uFF15\uFF10\uFF09" +
+                "\u3000\uFF13\uFF13\uFF13\uFF0D\uFF16\uFF10\uFF10\uFF10",
+                "SG");
+        }
+
+        /** See {@link PhoneNumberUtilTest#testParseWithLeadingZero()}. */
+        [Test]
+        public void TestFindWithLeadingZero()
+        {
+            doTestFindInContext("+39 02-36618 300", "NZ");
+            doTestFindInContext("02-36618 300", "IT");
+            doTestFindInContext("312 345 678", "IT");
+        }
+
+        /** See {@link PhoneNumberUtilTest#testParseNationalNumberArgentina()}. */
+        [Test]
+        public void TestFindNationalNumberArgentina()
+        {
+            // Test parsing mobile numbers of Argentina.
+            doTestFindInContext("+54 9 343 555 1212", "AR");
+            doTestFindInContext("0343 15 555 1212", "AR");
+
+            doTestFindInContext("+54 9 3715 65 4320", "AR");
+            doTestFindInContext("03715 15 65 4320", "AR");
+
+            // Test parsing fixed-line numbers of Argentina.
+            doTestFindInContext("+54 11 3797 0000", "AR");
+            doTestFindInContext("011 3797 0000", "AR");
+
+            doTestFindInContext("+54 3715 65 4321", "AR");
+            doTestFindInContext("03715 65 4321", "AR");
+
+            doTestFindInContext("+54 23 1234 0000", "AR");
+            doTestFindInContext("023 1234 0000", "AR");
+        }
+
+        /** See {@link PhoneNumberUtilTest#testParseWithXInNumber()}. */
+        [Test]
+        public void TestFindWithXInNumber()
+        {
+            doTestFindInContext("(0xx) 123456789", "AR");
+
+            // This test is intentionally constructed such that the number of digit after xx is larger than
+            // 7, so that the number won't be mistakenly treated as an extension, as we allow extensions up
+            // to 7 digits. This assumption is okay for now as all the countries where a carrier selection
+            // code is written in the form of xx have a national significant number of length larger than 7.
+            doTestFindInContext("011xx5481429712", "US");
+        }
+
+        /** See {@link PhoneNumberUtilTest#testParseNumbersMexico()}. */
+        [Test]
+        public void TestFindNumbersMexico()
+        {
+            // Test parsing fixed-line numbers of Mexico.
+            doTestFindInContext("+52 (449)978-0001", "MX");
+            doTestFindInContext("01 (449)978-0001", "MX");
+            doTestFindInContext("(449)978-0001", "MX");
+
+            // Test parsing mobile numbers of Mexico.
+            doTestFindInContext("+52 1 33 1234-5678", "MX");
+            doTestFindInContext("044 (33) 1234-5678", "MX");
+            doTestFindInContext("045 33 1234-5678", "MX");
+        }
+
+        /** See {@link PhoneNumberUtilTest#testParseNumbersWithPlusWithNoRegion()}. */
+        [Test]
+        public void TestFindNumbersWithPlusWithNoRegion()
+        {
+            // "ZZ" is allowed only if the number starts with a '+' - then the country code can be
+            // calculated.
+            doTestFindInContext("+64 3 331 6005", "ZZ");
+            // Null is also allowed for the region code in these cases.
+            doTestFindInContext("+64 3 331 6005", null);
+        }
+
+        /** See {@link PhoneNumberUtilTest#testParseExtensions()}. */
+        [Test]
+        public void TestFindExtensions()
+        {
+            doTestFindInContext("03 331 6005 ext 3456", "NZ");
+            doTestFindInContext("03-3316005x3456", "NZ");
+            doTestFindInContext("03-3316005 int.3456", "NZ");
+            doTestFindInContext("03 3316005 #3456", "NZ");
+            doTestFindInContext("0~0 1800 7493 524", "PL");
+            doTestFindInContext("(1800) 7493.524", "US");
+            // Check that the last instance of an extension token is matched.
+            doTestFindInContext("0~0 1800 7493 524 ~1234", "PL");
+            // Verifying bug-fix where the last digit of a number was previously omitted if it was a 0 when
+            // extracting the extension. Also verifying a few different cases of extensions.
+            doTestFindInContext("+44 2034567890x456", "NZ");
+            doTestFindInContext("+44 2034567890x456", "GB");
+            doTestFindInContext("+44 2034567890 x456", "GB");
+            doTestFindInContext("+44 2034567890 X456", "GB");
+            doTestFindInContext("+44 2034567890 X 456", "GB");
+            doTestFindInContext("+44 2034567890 X  456", "GB");
+            doTestFindInContext("+44 2034567890  X 456", "GB");
+
+            doTestFindInContext("(800) 901-3355 x 7246433", "US");
+            doTestFindInContext("(800) 901-3355 , ext 7246433", "US");
+            doTestFindInContext("(800) 901-3355 ,extension 7246433", "US");
+            doTestFindInContext("(800) 901-3355 , 7246433", "US");
+            doTestFindInContext("(800) 901-3355 ext: 7246433", "US");
+        }
+
+        [Test]
+        public void TestFindInterspersedWithSpace()
+        {
+            doTestFindInContext("0 3   3 3 1   6 0 0 5", "NZ");
+        }
+
+        /**
+        * Test matching behavior when starting in the middle of a phone number.
+        */
+        [Test]
+        public void TestIntermediateParsePositions()
+        {
+            String text = "Call 033316005  or 032316005!";
+            //             |    |    |    |    |    |
+            //             0    5   10   15   20   25
+
+            // Iterate over all possible indices.
+            for (int i = 0; i <= 5; i++)
+                AssertEqualRange(text, i, 5, 14);
+            // 7 and 8 digits in a row are still parsed as number.
+            AssertEqualRange(text, 6, 6, 14);
+            AssertEqualRange(text, 7, 7, 14);
+            // Anything smaller is skipped to the second instance.
+            for (int i = 8; i <= 19; i++)
+                AssertEqualRange(text, i, 19, 28);
+        }
+
+        [Test]
+        public void TestMatchWithSurroundingZipcodes()
+        {
+            String number = "415-666-7777";
+            String zipPreceding = "My address is CA 34215. " + number + " is my number.";
+            PhoneNumber expectedResult = phoneUtil.Parse(number, "US");
+
+            var iterator = phoneUtil.FindNumbers(zipPreceding, "US").GetEnumerator();
+            PhoneNumberMatch match = iterator.MoveNext() ? iterator.Current : null;
+            Assert.IsNotNull(match, "Did not find a number in '" + zipPreceding + "'; expected " + number);
+            Assert.AreEqual(expectedResult, match.Number);
+            Assert.AreEqual(number, match.RawString);
+
+            // Now repeat, but this time the phone number has spaces in it. It should still be found.
+            number = "(415) 666 7777";
+
+            String zipFollowing = "My number is " + number + ". 34215 is my zip-code.";
+            iterator = phoneUtil.FindNumbers(zipFollowing, "US").GetEnumerator();
+
+            PhoneNumberMatch matchWithSpaces = iterator.MoveNext() ? iterator.Current : null;
+            Assert.IsNotNull(matchWithSpaces, "Did not find a number in '" + zipFollowing + "'; expected " + number);
+            Assert.AreEqual(expectedResult, matchWithSpaces.Number);
+            Assert.AreEqual(number, matchWithSpaces.RawString);
+        }
+
+        [Test]
+        public void TestNonMatchingBracketsAreInvalid()
+        {
+            // The digits up to the ", " form a valid US number, but it shouldn't be matched as one since
+            // there was a non-matching bracket present.
+            Assert.That(hasNoMatches(phoneUtil.FindNumbers(
+            "80.585 [79.964, 81.191]", "US")));
+
+            // The trailing "]" is thrown away before parsing, so the resultant number, while a valid US
+            // number, does not have matching brackets.
+            Assert.That(hasNoMatches(phoneUtil.FindNumbers(
+            "80.585 [79.964]", "US")));
+
+            Assert.That(hasNoMatches(phoneUtil.FindNumbers(
+            "80.585 ((79.964)", "US")));
+
+            // This case has too many sets of brackets to be valid.
+            Assert.That(hasNoMatches(phoneUtil.FindNumbers(
+            "(80).(585) (79).(9)64", "US")));
+        }
+
+        [Test]
+        public void TestNoMatchIfRegionIsNull()
+        {
+            // Fail on non-international prefix if region code is null.
+            Assert.That(hasNoMatches(phoneUtil.FindNumbers(
+                "Random text body - number is 0331 6005, see you there", null)));
+        }
+
+        [Test]
+        public void TestNoMatchInEmptyString()
+        {
+            Assert.That(hasNoMatches(phoneUtil.FindNumbers("", "US")));
+            Assert.That(hasNoMatches(phoneUtil.FindNumbers("  ", "US")));
+        }
+
+        [Test]
+        public void TestNoMatchIfNoNumber()
+        {
+            Assert.That(hasNoMatches(phoneUtil.FindNumbers(
+                "Random text body - number is foobar, see you there", "US")));
+        }
+
+        [Test]
+        public void TestSequences()
+        {
+            // Test multiple occurrences.
+            String text = "Call 033316005  or 032316005!";
+            String region = "NZ";
+
+            PhoneNumber number1 = new PhoneNumber.Builder()
+                .SetCountryCode(phoneUtil.GetCountryCodeForRegion(region))
+                .SetNationalNumber(33316005).Build();
+            PhoneNumberMatch match1 = new PhoneNumberMatch(5, "033316005", number1);
+
+            PhoneNumber number2 = new PhoneNumber.Builder()
+                .SetCountryCode(phoneUtil.GetCountryCodeForRegion(region))
+                .SetNationalNumber(32316005).Build();
+            PhoneNumberMatch match2 = new PhoneNumberMatch(19, "032316005", number2);
+
+            var matches = phoneUtil.FindNumbers(text, region, PhoneNumberUtil.Leniency.POSSIBLE, long.MaxValue).GetEnumerator();
+            matches.MoveNext();
+            Assert.AreEqual(match1, matches.Current);
+            matches.MoveNext();
+            Assert.AreEqual(match2, matches.Current);
+        }
+
+        [Test]
+        public void TestNullInput()
+        {
+            Assert.That(hasNoMatches(phoneUtil.FindNumbers(null, "US")));
+            Assert.That(hasNoMatches(phoneUtil.FindNumbers(null, null)));
+        }
+
+        [Test]
+        public void TestMaxMatches()
+        {
+            // Set up text with 100 valid phone numbers.
+            StringBuilder numbers = new StringBuilder();
+            for (int i = 0; i < 100; i++)
+                numbers.Append("My info: 415-666-7777,");
+
+            // Matches all 100. Max only applies to failed cases.
+            List<PhoneNumber> expected = new List<PhoneNumber>(100);
+            PhoneNumber number = phoneUtil.Parse("+14156667777", null);
+            for (int i = 0; i < 100; i++)
+            expected.Add(number);
+
+            var iterable = phoneUtil.FindNumbers(numbers.ToString(), "US", PhoneNumberUtil.Leniency.VALID, 10);
+            List<PhoneNumber> actual = new List<PhoneNumber>(100);
+            foreach(var match in iterable)
+                actual.Add(match.Number); 
+            Assert.AreEqual(expected, actual);
+        }
+
+        [Test]
+        public void TestMaxMatchesInvalid()
+        {
+            // Set up text with 10 invalid phone numbers followed by 100 valid.
+            StringBuilder numbers = new StringBuilder();
+            for (int i = 0; i < 10; i++)
+                numbers.Append("My address 949-8945-0");
+            for (int i = 0; i < 100; i++)
+            numbers.Append("My info: 415-666-7777,");
+
+            var iterable = phoneUtil.FindNumbers(numbers.ToString(), "US", PhoneNumberUtil.Leniency.VALID, 10);
+            Assert.IsFalse(iterable.GetEnumerator().MoveNext());
+        }
+
+        [Test]
+        public void TestMaxMatchesMixed()
+        {
+            // Set up text with 100 valid numbers inside an invalid number.
+            StringBuilder numbers = new StringBuilder();
+            for (int i = 0; i < 100; i++)
+                numbers.Append("My info: 415-666-7777 123 fake street");
+
+            // Only matches the first 5 despite there being 100 numbers due to max matches.
+            // There are two false positives per line as "123" is also tried.
+            List<PhoneNumber> expected = new List<PhoneNumber>(100);
+            PhoneNumber number = phoneUtil.Parse("+14156667777", null);
+            for (int i = 0; i < 5; i++)
+                expected.Add(number);
+
+            var iterable = phoneUtil.FindNumbers(numbers.ToString(), "US", PhoneNumberUtil.Leniency.VALID, 10);
+            List<PhoneNumber> actual = new List<PhoneNumber>(100);
+            foreach(var match in iterable)
+                actual.Add(match.Number);
+            Assert.AreEqual(expected, actual);
+        }
+
+        [Test]
+        public void TestEmptyIteration()
+        {
+            var iterable = phoneUtil.FindNumbers("", "ZZ");
+            var iterator = iterable.GetEnumerator();
+
+            Assert.IsFalse(iterator.MoveNext());
+            Assert.IsFalse(iterator.MoveNext());
+        }
+
+        [Test]
+        public void TestSingleIteration()
+        {
+            var iterable = phoneUtil.FindNumbers("+14156667777", "ZZ");
+
+            // With hasNext() -> next().
+            var iterator = iterable.GetEnumerator();
+            // Double hasNext() to ensure it does not advance.
+            Assert.That(iterator.MoveNext());
+            Assert.IsNotNull(iterator.Current);
+            Assert.IsFalse(iterator.MoveNext());
+
+            // With next() only.
+            iterator = iterable.GetEnumerator();
+            Assert.That(iterator.MoveNext());
+            Assert.IsFalse(iterator.MoveNext());
+        }
+
+        /**
+        * Asserts that another number can be found in {@code text} starting at {@code index}, and that
+        * its corresponding range is {@code [start, end)}.
+        */
+        private void AssertEqualRange(String text, int index, int start, int end)
+        {
+            String sub = text.Substring(index);
+            var matches =
+                phoneUtil.FindNumbers(sub, "NZ", PhoneNumberUtil.Leniency.POSSIBLE, long.MaxValue).GetEnumerator();
+            Assert.That(matches.MoveNext());
+            PhoneNumberMatch match = matches.Current;
+            Assert.AreEqual(start - index, match.Start);
+            Assert.AreEqual(end - start, match.Length);
+            Assert.AreEqual(match.RawString, sub.Substring(match.Start, match.Length));
+        }
+
+        /**
+        * Tests numbers found by {@link PhoneNumberUtil#FindNumbers(CharSequence, String)} in various
+        * textual contexts.
+        *
+        * @param number the number to test and the corresponding region code to use
+        */
+        private void doTestFindInContext(String number, String defaultCountry)
+        {
+            findPossibleInContext(number, defaultCountry);
+
+            PhoneNumber parsed = phoneUtil.Parse(number, defaultCountry);
+            if (phoneUtil.IsValidNumber(parsed))
+                findValidInContext(number, defaultCountry);
+        }
+
+        private void findPossibleInContext(String number, String defaultCountry)
+        {
+            List<NumberContext> contextPairs = new List<NumberContext>(15);
+            contextPairs.Add(new NumberContext("", ""));  // no context
+            contextPairs.Add(new NumberContext("   ", "\t"));  // whitespace only
+            contextPairs.Add(new NumberContext("Hello ", ""));  // no context at end
+            contextPairs.Add(new NumberContext("", " to call me!"));  // no context at start
+            contextPairs.Add(new NumberContext("Hi there, call ", " to reach me!"));  // no context at start
+            contextPairs.Add(new NumberContext("Hi there, call ", ", or don't"));  // with commas
+            // Three examples without whitespace around the number.
+            contextPairs.Add(new NumberContext("Hi call", ""));
+            contextPairs.Add(new NumberContext("", "forme"));
+            contextPairs.Add(new NumberContext("Hi call", "forme"));
+            // With other small numbers.
+            contextPairs.Add(new NumberContext("It's cheap! Call ", " before 6:30"));
+            // With a second number later.
+            contextPairs.Add(new NumberContext("Call ", " or +1800-123-4567!"));
+            contextPairs.Add(new NumberContext("Call me on June 21 at", ""));  // with a Month-Day date
+            // With publication pages.
+            contextPairs.Add(new NumberContext(
+            "As quoted by Alfonso 12-15 (2009), you may call me at ", ""));
+            contextPairs.Add(new NumberContext(
+            "As quoted by Alfonso et al. 12-15 (2009), you may call me at ", ""));
+            // With dates, written in the American style.
+            contextPairs.Add(new NumberContext(
+            "As I said on 03/10/2011, you may call me at ", ""));
+            contextPairs.Add(new NumberContext(
+            "As I said on 03/27/2011, you may call me at ", ""));
+            contextPairs.Add(new NumberContext(
+            "As I said on 31/8/2011, you may call me at ", ""));
+            contextPairs.Add(new NumberContext(
+            "As I said on 1/12/2011, you may call me at ", ""));
+            contextPairs.Add(new NumberContext(
+            "I was born on 10/12/82. Please call me at ", ""));
+            // With a postfix stripped off as it looks like the start of another number
+            contextPairs.Add(new NumberContext("Call ", "/x12 more"));
+
+            doTestInContext(number, defaultCountry, contextPairs, PhoneNumberUtil.Leniency.POSSIBLE);
+        }
+
+        /**
+        * Tests valid numbers in contexts that fail for {@link Leniency#POSSIBLE}.
+        */
+        private void findValidInContext(String number, String defaultCountry)
+        {
+            List<NumberContext> contextPairs = new List<NumberContext>(5);
+            // With other small numbers.
+            contextPairs.Add(new NumberContext("It's only 9.99! Call ", " to buy"));
+            // With a number Day.Month.Year date.
+            contextPairs.Add(new NumberContext("Call me on 21.6.1984 at ", ""));
+            // With a number Month/Day date.
+            contextPairs.Add(new NumberContext("Call me on 06/21 at ", ""));
+            // With a number Day.Month date
+            contextPairs.Add(new NumberContext("Call me on 21.6. at ", ""));
+            // With a number Month/Day/Year date.
+            contextPairs.Add(new NumberContext("Call me on 06/21/84 at ", ""));
+            doTestInContext(number, defaultCountry, contextPairs, PhoneNumberUtil.Leniency.VALID);
+        }
+
+        private void doTestInContext(String number, String defaultCountry,
+            List<NumberContext> contextPairs, PhoneNumberUtil.Leniency leniency)
+        {
+            foreach(var context in contextPairs)
+            {
+                String prefix = context.leadingText;
+                String text = prefix + number + context.trailingText;
+
+                int start = prefix.Length;
+                int length = number.Length;
+                var iterable = phoneUtil.FindNumbers(text, defaultCountry, leniency, long.MaxValue);
+
+                PhoneNumberMatch match = iterable.First();
+                Assert.IsNotNull(match, "Did not find a number in '" + text + "'; expected '" + number + "'");
+
+                String extracted = text.Substring(match.Start, match.Length);
+                Assert.That(start == match.Start && length == match.Length,
+                    "Unexpected phone region in '" + text + "'; extracted '" + extracted + "'");
+                Assert.AreEqual(number, extracted);
+                Assert.AreEqual(match.RawString, extracted);
+
+                EnsureTermination(text, defaultCountry, leniency);
+            }
+        }
+
+        /**
+        * Exhaustively searches for phone numbers from each index within {@code text} to test that
+        * finding matches always terminates.
+        */
+        private void EnsureTermination(String text, String defaultCountry, PhoneNumberUtil.Leniency leniency)
+        {
+            for (int index = 0; index <= text.Length; index++)
+            {
+                String sub = text.Substring(index);
+                StringBuilder matches = new StringBuilder();
+                // Iterates over all matches.
+                foreach(var match in phoneUtil.FindNumbers(sub, defaultCountry, leniency, long.MaxValue))
+                    matches.Append(", ").Append(match.ToString());
+            }
+        }
+
+        /**
+        * Returns true if there were no matches found.
+        */
+        private bool hasNoMatches(IEnumerable<PhoneNumberMatch> iterable)
+        {
+            return !iterable.GetEnumerator().MoveNext();
+        }
+
+        /**
+        * Small class that holds the context of the number we are testing against. The test will
+        * insert the phone number to be found between leadingText and trailingText.
+        */
+        private class NumberContext
+        {
+            public readonly String leadingText;
+            public readonly String trailingText;
+
+            public NumberContext(String leadingText, String trailingText)
+            {
+                this.leadingText = leadingText;
+                this.trailingText = trailingText;
+            }
+        }
+    }
+}

csharp/PhoneNumbers.Test/TestPhoneNumberOfflineGeocoder.cs

+/*
+ * Copyright (C) 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using NUnit.Framework;
+
+namespace PhoneNumbers.Test
+{
+    [TestFixture]
+    class TestPhoneNumberOfflineGeocoder
+    {
+        private PhoneNumberOfflineGeocoder geocoder;
+        const String TEST_META_DATA_FILE_PREFIX = "PhoneNumberMetaDataForTesting.xml";
+
+        // Set up some test numbers to re-use.
+        private static readonly PhoneNumber US_NUMBER1 =
+            new PhoneNumber.Builder().SetCountryCode(1).SetNationalNumber(6502530000L).Build();
+        private static readonly PhoneNumber BS_NUMBER1 =
+            new PhoneNumber.Builder().SetCountryCode(1).SetNationalNumber(2423651234L).Build();
+        private static readonly PhoneNumber AU_NUMBER =
+            new PhoneNumber.Builder().SetCountryCode(61).SetNationalNumber(236618300L).Build();
+        private static readonly PhoneNumber NUMBER_WITH_INVALID_COUNTRY_CODE =
+            new PhoneNumber.Builder().SetCountryCode(999).SetNationalNumber(2423651234L).Build();
+
+        [TestFixtureSetUp]
+        public void SetupFixture()
+        {
+            PhoneNumberUtil.ResetInstance();
+            PhoneNumberUtil phoneUtil = PhoneNumberUtil.GetInstance(
+                TEST_META_DATA_FILE_PREFIX,
+                CountryCodeToRegionCodeMapForTesting.GetCountryCodeToRegionCodeMap());
+            geocoder = new PhoneNumberOfflineGeocoder(phoneUtil);
+        }
+
+        [Test]
+        public void TestGetCompactDescriptionForNumber()
+        {
+            Assert.AreEqual("United States",
+                geocoder.GetDescriptionForNumber(US_NUMBER1));
+            // XXX: No RegionInfo for Bahamas, skipping for now...
+            //Assert.AreEqual("Bahamas",
+            //    geocoder.GetDescriptionForNumber(BS_NUMBER1));
+            Assert.AreEqual("Australia",
+                geocoder.GetDescriptionForNumber(AU_NUMBER));
+            Assert.AreEqual("", geocoder.GetDescriptionForNumber(NUMBER_WITH_INVALID_COUNTRY_CODE));
+        }
+    }
+}

csharp/PhoneNumbers.Test/TestPhoneNumberUtil.cs

+/*
+ * Copyright (C) 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Configuration;
+using System.IO;
+using System.Text;
+using System.Web;
+using NUnit.Framework;
+
+namespace PhoneNumbers.Test
+{
+    [TestFixture]
+    public class TestPhoneNumberUtil
+    {
+        private PhoneNumberUtil phoneUtil;
+        // This is used by BuildMetadataProtoFromXml.
+        const String TEST_META_DATA_FILE_PREFIX = "PhoneNumberMetaDataForTesting.xml";
+
+        // Set up some test numbers to re-use.
+        private static readonly PhoneNumber ALPHA_NUMERIC_NUMBER =
+            new PhoneNumber.Builder().SetCountryCode(1).SetNationalNumber(80074935247L).Build();
+        private static readonly PhoneNumber AR_MOBILE =
+            new PhoneNumber.Builder().SetCountryCode(54).SetNationalNumber(91187654321L).Build();
+        private static readonly PhoneNumber AR_NUMBER =
+            new PhoneNumber.Builder().SetCountryCode(54).SetNationalNumber(1187654321).Build();