1#!/usr/bin/env python 2"""Unit tests for geocoder.py""" 3 4# Based on original Java code: 5# java/test/com/google/i18n/phonenumbers/geocoding/PhoneNumberOfflineGeocoderTest.java 6# Copyright (C) 2011 The Libphonenumber Authors 7# 8# Licensed under the Apache License, Version 2.0 (the "License"); 9# you may not use this file except in compliance with the License. 10# You may obtain a copy of the License at 11# 12# http://www.apache.org/licenses/LICENSE-2.0 13# 14# Unless required by applicable law or agreed to in writing, software 15# distributed under the License is distributed on an "AS IS" BASIS, 16# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17# See the License for the specific language governing permissions and 18# limitations under the License. 19 20import unittest 21 22from phonenumbers import PhoneNumber, FrozenPhoneNumber 23from phonenumbers import geocoder 24from phonenumbers.geocoder import description_for_number, country_name_for_number 25from phonenumbers.geocoder import description_for_valid_number 26from phonenumbers.prefix import _prefix_description_for_number 27from phonenumbers.util import u 28 29# Allow override library geocoding metadata with the test metadata. 30REAL_GEOCODE_DATA = geocoder.GEOCODE_DATA 31REAL_GEOCODE_LONGEST_PREFIX = geocoder.GEOCODE_LONGEST_PREFIX 32from .testgeodata import GEOCODE_DATA as TEST_GEOCODE_DATA 33from .testgeodata import GEOCODE_LONGEST_PREFIX as TEST_GEOCODE_LONGEST_PREFIX 34 35 36def reinstate_real_geodata(): 37 """Reinstate real phone number geocoding metadata""" 38 geocoder.GEOCODE_DATA = REAL_GEOCODE_DATA 39 geocoder.GEOCODE_LONGEST_PREFIX = REAL_GEOCODE_LONGEST_PREFIX 40 41 42def insert_test_geodata(): 43 """Insert test geocoding metadata into library""" 44 geocoder.GEOCODE_DATA = TEST_GEOCODE_DATA 45 geocoder.GEOCODE_LONGEST_PREFIX = TEST_GEOCODE_LONGEST_PREFIX 46 47 48# Set up some test numbers to re-use. 49KO_NUMBER1 = FrozenPhoneNumber(country_code=82, national_number=22123456) 50KO_NUMBER2 = FrozenPhoneNumber(country_code=82, national_number=322123456) 51KO_NUMBER3 = FrozenPhoneNumber(country_code=82, national_number=6421234567) 52KO_INVALID_NUMBER = FrozenPhoneNumber(country_code=82, national_number=1234) 53KO_MOBILE = FrozenPhoneNumber(country_code=82, national_number=101234567) 54US_NUMBER1 = FrozenPhoneNumber(country_code=1, national_number=6502530000) 55US_NUMBER2 = FrozenPhoneNumber(country_code=1, national_number=6509600000) 56US_NUMBER3 = FrozenPhoneNumber(country_code=1, national_number=2128120000) 57US_NUMBER4 = FrozenPhoneNumber(country_code=1, national_number=6174240000) 58US_INVALID_NUMBER = FrozenPhoneNumber(country_code=1, national_number=123456789) 59NANPA_TOLL_FREE = FrozenPhoneNumber(country_code=1, national_number=8002431234) 60BS_NUMBER1 = FrozenPhoneNumber(country_code=1, national_number=2423651234) 61AU_NUMBER = FrozenPhoneNumber(country_code=61, national_number=236618300) 62AR_MOBILE_NUMBER = FrozenPhoneNumber(country_code=54, national_number=92214000000) 63NUMBER_WITH_INVALID_COUNTRY_CODE = FrozenPhoneNumber(country_code=999, national_number=2423651234) 64INTERNATIONAL_TOLL_FREE = FrozenPhoneNumber(country_code=800, national_number=12345678) 65 66# Language/country codes 67_CHINA = "CN" 68_CHINESE = "zh" 69_ITALIAN = "it" 70_ENGLISH = "en" 71_KOREAN = "ko" 72_GERMAN = "de" 73_FRENCH = "fr" 74_SPANISH = "es" 75_USA = "US" 76 77 78class PhoneNumberGeocoderTest(unittest.TestCase): 79 """Unit tests for geocoder.py""" 80 81 def setUp(self): 82 insert_test_geodata() 83 84 def tearDown(self): 85 reinstate_real_geodata() 86 87 def testGetDescriptionForNumberWithNoDataFile(self): 88 # No data file containing mappings for US numbers is available in Chinese for the unittests. As 89 # a result, the country name of United States in simplified Chinese is returned. 90 self.assertEqual(u("\u7F8E\u56FD"), 91 description_for_number(US_NUMBER1, _CHINESE, region=_CHINA)) 92 self.assertEqual("Bahamas", 93 description_for_number(BS_NUMBER1, _ENGLISH, region=_USA)) 94 self.assertEqual("Australia", 95 description_for_number(AU_NUMBER, _ENGLISH, region=_USA)) 96 self.assertEqual("", 97 description_for_number(NUMBER_WITH_INVALID_COUNTRY_CODE, _ENGLISH, region=_USA)) 98 self.assertEqual("", 99 description_for_number(INTERNATIONAL_TOLL_FREE, _ENGLISH, region=_USA)) 100 101 def testGetDescriptionForNumberWithMissingPrefix(self): 102 # Test that the name of the country is returned when the number passed in 103 # is valid but not covered by the geocoding data file. 104 self.assertEqual("United States", 105 description_for_number(US_NUMBER4, _ENGLISH, region=_USA)) 106 107 def testGetDescriptionForNumberBelongingToMultipleCountriesIsEmpty(self): 108 # Test that nothing is returned when the number passed in is valid but 109 # not covered by the geocoding data file and belongs to multiple 110 # countries 111 self.assertEqual("", description_for_number(NANPA_TOLL_FREE, _ENGLISH, region=_USA)) 112 113 def testGetDescriptionForNumber_en_US(self): 114 self.assertEqual("CA", 115 description_for_number(US_NUMBER1, _ENGLISH, region=_USA)) 116 self.assertEqual("Mountain View, CA", 117 description_for_number(US_NUMBER2, _ENGLISH, region=_USA)) 118 self.assertEqual("New York, NY", 119 description_for_number(US_NUMBER3, _ENGLISH, region=_USA)) 120 121 def testGetDescriptionForKoreanNumber(self): 122 self.assertEqual("Seoul", 123 description_for_number(KO_NUMBER1, _ENGLISH)) 124 self.assertEqual("Incheon", 125 description_for_number(KO_NUMBER2, _ENGLISH)) 126 self.assertEqual("Jeju", 127 description_for_number(KO_NUMBER3, _ENGLISH)) 128 self.assertEqual(u("\uC11C\uC6B8"), 129 description_for_number(KO_NUMBER1, _KOREAN)) 130 self.assertEqual(u("\uC778\uCC9C"), 131 description_for_number(KO_NUMBER2, _KOREAN)) 132 133 def testGetDescriptionForArgentinianMobileNumber(self): 134 self.assertEqual("La Plata", description_for_number(AR_MOBILE_NUMBER, _ENGLISH)) 135 # Python version extra test 136 # Put an invalid number after the mobile token ("9") and lie about 137 # this being a valid number 138 arInvalidMobileNumber = PhoneNumber(country_code=54, national_number=91) 139 self.assertEqual("Argentina", description_for_valid_number(arInvalidMobileNumber, _ENGLISH)) 140 141 def testGetDescriptionForFallBack(self): 142 # No fallback, as the location name for the given phone number is 143 # available in the requested language. 144 self.assertEqual("Kalifornien", 145 description_for_number(US_NUMBER1, _GERMAN)) 146 # German falls back to English. 147 self.assertEqual("New York, NY", 148 description_for_number(US_NUMBER3, _GERMAN)) 149 # Italian falls back to English. 150 self.assertEqual("CA", 151 description_for_number(US_NUMBER1, _ITALIAN)) 152 # Korean doesn't fall back to English. 153 self.assertEqual(u("\uB300\uD55C\uBBFC\uAD6D"), 154 description_for_number(KO_NUMBER3, _KOREAN)) 155 156 def testGetDescriptionForNumberWithUserRegion(self): 157 # User in Italy, American number. We should just show United States, in 158 # Spanish, and not more detailed information. 159 self.assertEqual("Estados Unidos", 160 description_for_number(US_NUMBER1, _SPANISH, region="IT")) 161 # Unknown region - should just show country name. 162 self.assertEqual("Estados Unidos", 163 description_for_number(US_NUMBER1, _SPANISH, region="ZZ")) 164 # User in the States, language German, should show detailed data. 165 self.assertEqual("Kalifornien", 166 description_for_number(US_NUMBER1, _GERMAN, region="US")) 167 # User in the States, language French, no data for French, so we fallback 168 # to English detailed data. 169 self.assertEqual("CA", 170 description_for_number(US_NUMBER1, _FRENCH, region="US")) 171 # Invalid number - return an empty string. 172 self.assertEqual("", description_for_number(US_INVALID_NUMBER, _ENGLISH, region="US")) 173 174 def testGetDescriptionForInvalidNumber(self): 175 self.assertEqual("", description_for_number(KO_INVALID_NUMBER, _ENGLISH)) 176 self.assertEqual("", description_for_number(US_INVALID_NUMBER, _ENGLISH)) 177 178 def testGetDescriptionForNonGeographicalNumberWithGeocodingPrefix(self): 179 # We have a geocoding prefix, but we shouldn't use it since this is not geographical. 180 self.assertEqual("South Korea", description_for_number(KO_MOBILE, _ENGLISH)) 181 182 def testCoverage(self): 183 # Python version extra tests 184 invalid_number = PhoneNumber(country_code=210, national_number=123456) 185 self.assertEqual("", country_name_for_number(invalid_number, "en")) 186 # Ensure we exercise all public entrypoints directly 187 self.assertEqual("CA", _prefix_description_for_number(TEST_GEOCODE_DATA, TEST_GEOCODE_LONGEST_PREFIX, US_NUMBER1, "en")) 188 self.assertEqual("CA", description_for_valid_number(US_NUMBER1, "en")) 189 self.assertEqual("", description_for_valid_number(US_INVALID_NUMBER, "en")) 190 # Add in some script and region specific fictional names 191 TEST_GEOCODE_DATA['1650960'] = {'en': u("Mountain View, CA"), 192 "en_GB": u("Mountain View California"), 193 "en_US": u("Mountain View, Sunny California"), 194 "en_Xyzz_US": u("MTV - xyzz"), 195 "en_Latn": u("MountainView")} 196 # The following test might one day return "Mountain View California" 197 self.assertEqual("United States", 198 description_for_number(US_NUMBER2, _ENGLISH, region="GB")) 199 self.assertEqual("Mountain View, Sunny California", 200 description_for_number(US_NUMBER2, _ENGLISH, region="US")) 201 self.assertEqual("MountainView", 202 description_for_number(US_NUMBER2, _ENGLISH, script="Latn")) 203 self.assertEqual("United States", 204 description_for_number(US_NUMBER2, _ENGLISH, script="Latn", region="GB")) 205 self.assertEqual("MTV - xyzz", 206 description_for_number(US_NUMBER2, _ENGLISH, script="Xyzz", region="US")) 207 self.assertEqual("Mountain View, Sunny California", 208 description_for_number(US_NUMBER2, _ENGLISH, script="Zazz", region="US")) 209 # Get a different result when there is a script-specific variant 210 self.assertEqual("MountainView", 211 description_for_number(US_NUMBER2, _ENGLISH, script="Latn", region="US")) 212 TEST_GEOCODE_DATA['1650960'] = {'en': u("Mountain View, CA")} 213 214 # Test the locale mapping 215 TEST_GEOCODE_DATA['8868'] = {'zh': u("Chinese"), 'zh_Hant': u("Hant-specific")} 216 tw_number = FrozenPhoneNumber(country_code=886, national_number=810080123) 217 self.assertEqual("Hant-specific", 218 description_for_number(tw_number, "zh", region="TW")) 219 del TEST_GEOCODE_DATA['8868'] 220