1 /* 2 * Copyright (C) 2011 The Libphonenumber Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.i18n.phonenumbers; 18 19 import com.google.i18n.phonenumbers.Phonemetadata.NumberFormat; 20 import com.google.i18n.phonenumbers.Phonemetadata.PhoneMetadata; 21 import com.google.i18n.phonenumbers.Phonemetadata.PhoneMetadataCollection; 22 import com.google.i18n.phonenumbers.Phonemetadata.PhoneNumberDesc; 23 import java.io.IOException; 24 import java.io.StringReader; 25 import java.util.Arrays; 26 import java.util.regex.PatternSyntaxException; 27 import javax.xml.parsers.DocumentBuilder; 28 import javax.xml.parsers.DocumentBuilderFactory; 29 import javax.xml.parsers.ParserConfigurationException; 30 import junit.framework.TestCase; 31 import org.w3c.dom.Document; 32 import org.w3c.dom.Element; 33 import org.xml.sax.InputSource; 34 import org.xml.sax.SAXException; 35 36 /** 37 * Unit tests for BuildMetadataFromXml.java 38 * 39 * @author Philippe Liard 40 */ 41 public class BuildMetadataFromXmlTest extends TestCase { 42 43 // Helper method that outputs a DOM element from a XML string. parseXmlString(String xmlString)44 private static Element parseXmlString(String xmlString) 45 throws ParserConfigurationException, SAXException, IOException { 46 DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); 47 DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); 48 InputSource inputSource = new InputSource(); 49 inputSource.setCharacterStream(new StringReader(xmlString)); 50 return documentBuilder.parse(inputSource).getDocumentElement(); 51 } 52 53 // Tests validateRE(). testValidateRERemovesWhiteSpaces()54 public void testValidateRERemovesWhiteSpaces() { 55 String input = " hello world "; 56 // Should remove all the white spaces contained in the provided string. 57 assertEquals("helloworld", BuildMetadataFromXml.validateRE(input, true)); 58 // Make sure it only happens when the last parameter is set to true. 59 assertEquals(" hello world ", BuildMetadataFromXml.validateRE(input, false)); 60 } 61 testValidateREThrowsException()62 public void testValidateREThrowsException() { 63 String invalidPattern = "["; 64 // Should throw an exception when an invalid pattern is provided independently of the last 65 // parameter (remove white spaces). 66 try { 67 BuildMetadataFromXml.validateRE(invalidPattern, false); 68 fail(); 69 } catch (PatternSyntaxException e) { 70 // Test passed. 71 } 72 try { 73 BuildMetadataFromXml.validateRE(invalidPattern, true); 74 fail(); 75 } catch (PatternSyntaxException e) { 76 // Test passed. 77 } 78 // We don't allow | to be followed by ) because it introduces bugs, since we typically use it at 79 // the end of each line and when a line is deleted, if the pipe from the previous line is not 80 // removed, we end up erroneously accepting an empty group as well. 81 String patternWithPipeFollowedByClosingParentheses = "|)"; 82 try { 83 BuildMetadataFromXml.validateRE(patternWithPipeFollowedByClosingParentheses, true); 84 fail(); 85 } catch (PatternSyntaxException e) { 86 // Test passed. 87 } 88 String patternWithPipeFollowedByNewLineAndClosingParentheses = "|\n)"; 89 try { 90 BuildMetadataFromXml.validateRE(patternWithPipeFollowedByNewLineAndClosingParentheses, true); 91 fail(); 92 } catch (PatternSyntaxException e) { 93 // Test passed. 94 } 95 } 96 testValidateRE()97 public void testValidateRE() { 98 String validPattern = "[a-zA-Z]d{1,9}"; 99 // The provided pattern should be left unchanged. 100 assertEquals(validPattern, BuildMetadataFromXml.validateRE(validPattern, false)); 101 } 102 103 // Tests getNationalPrefix(). testGetNationalPrefix()104 public void testGetNationalPrefix() 105 throws ParserConfigurationException, SAXException, IOException { 106 String xmlInput = "<territory nationalPrefix='00'/>"; 107 Element territoryElement = parseXmlString(xmlInput); 108 assertEquals("00", BuildMetadataFromXml.getNationalPrefix(territoryElement)); 109 } 110 111 // Tests loadTerritoryTagMetadata(). testLoadTerritoryTagMetadata()112 public void testLoadTerritoryTagMetadata() 113 throws ParserConfigurationException, SAXException, IOException { 114 String xmlInput = "<territory" 115 + " countryCode='33' leadingDigits='2' internationalPrefix='00'" 116 + " preferredInternationalPrefix='00~11' nationalPrefixForParsing='0'" 117 + " nationalPrefixTransformRule='9$1'" // nationalPrefix manually injected. 118 + " preferredExtnPrefix=' x' mainCountryForCode='true'" 119 + " leadingZeroPossible='true' mobileNumberPortableRegion='true'>" 120 + "</territory>"; 121 Element territoryElement = parseXmlString(xmlInput); 122 PhoneMetadata.Builder phoneMetadata = 123 BuildMetadataFromXml.loadTerritoryTagMetadata("33", territoryElement, "0"); 124 assertEquals(33, phoneMetadata.getCountryCode()); 125 assertEquals("2", phoneMetadata.getLeadingDigits()); 126 assertEquals("00", phoneMetadata.getInternationalPrefix()); 127 assertEquals("00~11", phoneMetadata.getPreferredInternationalPrefix()); 128 assertEquals("0", phoneMetadata.getNationalPrefixForParsing()); 129 assertEquals("9$1", phoneMetadata.getNationalPrefixTransformRule()); 130 assertEquals("0", phoneMetadata.getNationalPrefix()); 131 assertEquals(" x", phoneMetadata.getPreferredExtnPrefix()); 132 assertTrue(phoneMetadata.getMainCountryForCode()); 133 assertTrue(phoneMetadata.isMobileNumberPortableRegion()); 134 } 135 testLoadTerritoryTagMetadataSetsBooleanFieldsToFalseByDefault()136 public void testLoadTerritoryTagMetadataSetsBooleanFieldsToFalseByDefault() 137 throws ParserConfigurationException, SAXException, IOException { 138 String xmlInput = "<territory countryCode='33'/>"; 139 Element territoryElement = parseXmlString(xmlInput); 140 PhoneMetadata.Builder phoneMetadata = 141 BuildMetadataFromXml.loadTerritoryTagMetadata("33", territoryElement, ""); 142 assertFalse(phoneMetadata.getMainCountryForCode()); 143 assertFalse(phoneMetadata.isMobileNumberPortableRegion()); 144 } 145 testLoadTerritoryTagMetadataSetsNationalPrefixForParsingByDefault()146 public void testLoadTerritoryTagMetadataSetsNationalPrefixForParsingByDefault() 147 throws ParserConfigurationException, SAXException, IOException { 148 String xmlInput = "<territory countryCode='33'/>"; 149 Element territoryElement = parseXmlString(xmlInput); 150 PhoneMetadata.Builder phoneMetadata = 151 BuildMetadataFromXml.loadTerritoryTagMetadata("33", territoryElement, "00"); 152 // When unspecified, nationalPrefixForParsing defaults to nationalPrefix. 153 assertEquals("00", phoneMetadata.getNationalPrefix()); 154 assertEquals(phoneMetadata.getNationalPrefix(), phoneMetadata.getNationalPrefixForParsing()); 155 } 156 testLoadTerritoryTagMetadataWithRequiredAttributesOnly()157 public void testLoadTerritoryTagMetadataWithRequiredAttributesOnly() 158 throws ParserConfigurationException, SAXException, IOException { 159 String xmlInput = "<territory countryCode='33' internationalPrefix='00'/>"; 160 Element territoryElement = parseXmlString(xmlInput); 161 // Should not throw any exception. 162 BuildMetadataFromXml.loadTerritoryTagMetadata("33", territoryElement, ""); 163 } 164 165 // Tests loadInternationalFormat(). testLoadInternationalFormat()166 public void testLoadInternationalFormat() 167 throws ParserConfigurationException, SAXException, IOException { 168 String intlFormat = "$1 $2"; 169 String xmlInput = "<numberFormat><intlFormat>" + intlFormat + "</intlFormat></numberFormat>"; 170 Element numberFormatElement = parseXmlString(xmlInput); 171 PhoneMetadata.Builder metadata = PhoneMetadata.newBuilder(); 172 NumberFormat nationalFormat = NumberFormat.newBuilder().build(); 173 174 assertTrue(BuildMetadataFromXml.loadInternationalFormat(metadata, numberFormatElement, 175 nationalFormat)); 176 assertEquals(intlFormat, metadata.getIntlNumberFormat(0).getFormat()); 177 } 178 testLoadInternationalFormatWithBothNationalAndIntlFormatsDefined()179 public void testLoadInternationalFormatWithBothNationalAndIntlFormatsDefined() 180 throws ParserConfigurationException, SAXException, IOException { 181 String intlFormat = "$1 $2"; 182 String xmlInput = "<numberFormat><intlFormat>" + intlFormat + "</intlFormat></numberFormat>"; 183 Element numberFormatElement = parseXmlString(xmlInput); 184 PhoneMetadata.Builder metadata = PhoneMetadata.newBuilder(); 185 NumberFormat.Builder nationalFormat = NumberFormat.newBuilder(); 186 nationalFormat.setFormat("$1"); 187 188 assertTrue(BuildMetadataFromXml.loadInternationalFormat(metadata, numberFormatElement, 189 nationalFormat.build())); 190 assertEquals(intlFormat, metadata.getIntlNumberFormat(0).getFormat()); 191 } 192 testLoadInternationalFormatExpectsOnlyOnePattern()193 public void testLoadInternationalFormatExpectsOnlyOnePattern() 194 throws ParserConfigurationException, SAXException, IOException { 195 String xmlInput = "<numberFormat><intlFormat/><intlFormat/></numberFormat>"; 196 Element numberFormatElement = parseXmlString(xmlInput); 197 PhoneMetadata.Builder metadata = PhoneMetadata.newBuilder(); 198 199 // Should throw an exception as multiple intlFormats are provided. 200 try { 201 BuildMetadataFromXml.loadInternationalFormat(metadata, numberFormatElement, 202 NumberFormat.newBuilder().build()); 203 fail(); 204 } catch (RuntimeException e) { 205 // Test passed. 206 } 207 } 208 testLoadInternationalFormatUsesNationalFormatByDefault()209 public void testLoadInternationalFormatUsesNationalFormatByDefault() 210 throws ParserConfigurationException, SAXException, IOException { 211 String xmlInput = "<numberFormat></numberFormat>"; 212 Element numberFormatElement = parseXmlString(xmlInput); 213 PhoneMetadata.Builder metadata = PhoneMetadata.newBuilder(); 214 NumberFormat.Builder nationalFormat = NumberFormat.newBuilder(); 215 String nationalPattern = "$1 $2 $3"; 216 nationalFormat.setFormat(nationalPattern); 217 218 assertFalse(BuildMetadataFromXml.loadInternationalFormat(metadata, numberFormatElement, 219 nationalFormat.build())); 220 assertEquals(nationalPattern, metadata.getIntlNumberFormat(0).getFormat()); 221 } 222 testLoadInternationalFormatCopiesNationalFormatData()223 public void testLoadInternationalFormatCopiesNationalFormatData() 224 throws ParserConfigurationException, SAXException, IOException { 225 String xmlInput = "<numberFormat></numberFormat>"; 226 Element numberFormatElement = parseXmlString(xmlInput); 227 PhoneMetadata.Builder metadata = PhoneMetadata.newBuilder(); 228 NumberFormat.Builder nationalFormat = NumberFormat.newBuilder(); 229 nationalFormat.setFormat("$1-$2"); 230 nationalFormat.setNationalPrefixOptionalWhenFormatting(true); 231 232 assertFalse(BuildMetadataFromXml.loadInternationalFormat(metadata, numberFormatElement, 233 nationalFormat.build())); 234 assertTrue(metadata.getIntlNumberFormat(0).getNationalPrefixOptionalWhenFormatting()); 235 } 236 testLoadNationalFormat()237 public void testLoadNationalFormat() 238 throws ParserConfigurationException, SAXException, IOException { 239 String nationalFormat = "$1 $2"; 240 String xmlInput = String.format("<numberFormat><format>%s</format></numberFormat>", 241 nationalFormat); 242 Element numberFormatElement = parseXmlString(xmlInput); 243 PhoneMetadata.Builder metadata = PhoneMetadata.newBuilder(); 244 NumberFormat.Builder numberFormat = NumberFormat.newBuilder(); 245 BuildMetadataFromXml.loadNationalFormat(metadata, numberFormatElement, numberFormat); 246 assertEquals(nationalFormat, numberFormat.getFormat()); 247 } 248 testLoadNationalFormatRequiresFormat()249 public void testLoadNationalFormatRequiresFormat() 250 throws ParserConfigurationException, SAXException, IOException { 251 String xmlInput = "<numberFormat></numberFormat>"; 252 Element numberFormatElement = parseXmlString(xmlInput); 253 PhoneMetadata.Builder metadata = PhoneMetadata.newBuilder(); 254 NumberFormat.Builder numberFormat = NumberFormat.newBuilder(); 255 256 try { 257 BuildMetadataFromXml.loadNationalFormat(metadata, numberFormatElement, numberFormat); 258 fail(); 259 } catch (RuntimeException e) { 260 // Test passed. 261 } 262 } 263 testLoadNationalFormatExpectsExactlyOneFormat()264 public void testLoadNationalFormatExpectsExactlyOneFormat() 265 throws ParserConfigurationException, SAXException, IOException { 266 String xmlInput = "<numberFormat><format/><format/></numberFormat>"; 267 Element numberFormatElement = parseXmlString(xmlInput); 268 PhoneMetadata.Builder metadata = PhoneMetadata.newBuilder(); 269 NumberFormat.Builder numberFormat = NumberFormat.newBuilder(); 270 271 try { 272 BuildMetadataFromXml.loadNationalFormat(metadata, numberFormatElement, numberFormat); 273 fail(); 274 } catch (RuntimeException e) { 275 // Test passed. 276 } 277 } 278 279 // Tests loadAvailableFormats(). testLoadAvailableFormats()280 public void testLoadAvailableFormats() 281 throws ParserConfigurationException, SAXException, IOException { 282 String xmlInput = "<territory>" 283 + " <availableFormats>" 284 + " <numberFormat nationalPrefixFormattingRule='($FG)'" 285 + " carrierCodeFormattingRule='$NP $CC ($FG)'>" 286 + " <format>$1 $2 $3</format>" 287 + " </numberFormat>" 288 + " </availableFormats>" 289 + "</territory>"; 290 Element element = parseXmlString(xmlInput); 291 PhoneMetadata.Builder metadata = PhoneMetadata.newBuilder(); 292 BuildMetadataFromXml.loadAvailableFormats( 293 metadata, element, "0", "", false /* NP not optional */); 294 assertEquals("($1)", metadata.getNumberFormat(0).getNationalPrefixFormattingRule()); 295 assertEquals("0 $CC ($1)", metadata.getNumberFormat(0).getDomesticCarrierCodeFormattingRule()); 296 assertEquals("$1 $2 $3", metadata.getNumberFormat(0).getFormat()); 297 } 298 testLoadAvailableFormatsPropagatesCarrierCodeFormattingRule()299 public void testLoadAvailableFormatsPropagatesCarrierCodeFormattingRule() 300 throws ParserConfigurationException, SAXException, IOException { 301 String xmlInput = 302 "<territory carrierCodeFormattingRule='$NP $CC ($FG)'>" 303 + " <availableFormats>" 304 + " <numberFormat nationalPrefixFormattingRule='($FG)'>" 305 + " <format>$1 $2 $3</format>" 306 + " </numberFormat>" 307 + " </availableFormats>" 308 + "</territory>"; 309 Element element = parseXmlString(xmlInput); 310 PhoneMetadata.Builder metadata = PhoneMetadata.newBuilder(); 311 BuildMetadataFromXml.loadAvailableFormats( 312 metadata, element, "0", "", false /* NP not optional */); 313 assertEquals("($1)", metadata.getNumberFormat(0).getNationalPrefixFormattingRule()); 314 assertEquals("0 $CC ($1)", metadata.getNumberFormat(0).getDomesticCarrierCodeFormattingRule()); 315 assertEquals("$1 $2 $3", metadata.getNumberFormat(0).getFormat()); 316 } 317 testLoadAvailableFormatsSetsProvidedNationalPrefixFormattingRule()318 public void testLoadAvailableFormatsSetsProvidedNationalPrefixFormattingRule() 319 throws ParserConfigurationException, SAXException, IOException { 320 String xmlInput = "<territory>" 321 + " <availableFormats>" 322 + " <numberFormat><format>$1 $2 $3</format></numberFormat>" 323 + " </availableFormats>" 324 + "</territory>"; 325 Element element = parseXmlString(xmlInput); 326 PhoneMetadata.Builder metadata = PhoneMetadata.newBuilder(); 327 BuildMetadataFromXml.loadAvailableFormats( 328 metadata, element, "", "($1)", false /* NP not optional */); 329 assertEquals("($1)", metadata.getNumberFormat(0).getNationalPrefixFormattingRule()); 330 } 331 testLoadAvailableFormatsClearsIntlFormat()332 public void testLoadAvailableFormatsClearsIntlFormat() 333 throws ParserConfigurationException, SAXException, IOException { 334 String xmlInput = "<territory>" 335 + " <availableFormats>" 336 + " <numberFormat><format>$1 $2 $3</format></numberFormat>" 337 + " </availableFormats>" 338 + "</territory>"; 339 Element element = parseXmlString(xmlInput); 340 PhoneMetadata.Builder metadata = PhoneMetadata.newBuilder(); 341 BuildMetadataFromXml.loadAvailableFormats( 342 metadata, element, "0", "($1)", false /* NP not optional */); 343 assertEquals(0, metadata.getIntlNumberFormatCount()); 344 } 345 testLoadAvailableFormatsHandlesMultipleNumberFormats()346 public void testLoadAvailableFormatsHandlesMultipleNumberFormats() 347 throws ParserConfigurationException, SAXException, IOException { 348 String xmlInput = "<territory>" 349 + " <availableFormats>" 350 + " <numberFormat><format>$1 $2 $3</format></numberFormat>" 351 + " <numberFormat><format>$1-$2</format></numberFormat>" 352 + " </availableFormats>" 353 + "</territory>"; 354 Element element = parseXmlString(xmlInput); 355 PhoneMetadata.Builder metadata = PhoneMetadata.newBuilder(); 356 BuildMetadataFromXml.loadAvailableFormats( 357 metadata, element, "0", "($1)", false /* NP not optional */); 358 assertEquals("$1 $2 $3", metadata.getNumberFormat(0).getFormat()); 359 assertEquals("$1-$2", metadata.getNumberFormat(1).getFormat()); 360 } 361 testLoadInternationalFormatDoesNotSetIntlFormatWhenNA()362 public void testLoadInternationalFormatDoesNotSetIntlFormatWhenNA() 363 throws ParserConfigurationException, SAXException, IOException { 364 String xmlInput = "<numberFormat><intlFormat>NA</intlFormat></numberFormat>"; 365 Element numberFormatElement = parseXmlString(xmlInput); 366 PhoneMetadata.Builder metadata = PhoneMetadata.newBuilder(); 367 NumberFormat.Builder nationalFormat = NumberFormat.newBuilder(); 368 nationalFormat.setFormat("$1 $2"); 369 370 BuildMetadataFromXml.loadInternationalFormat(metadata, numberFormatElement, 371 nationalFormat.build()); 372 assertEquals(0, metadata.getIntlNumberFormatCount()); 373 } 374 375 // Tests setLeadingDigitsPatterns(). testSetLeadingDigitsPatterns()376 public void testSetLeadingDigitsPatterns() 377 throws ParserConfigurationException, SAXException, IOException { 378 String xmlInput = "<numberFormat>" 379 + "<leadingDigits>1</leadingDigits><leadingDigits>2</leadingDigits>" 380 + "</numberFormat>"; 381 Element numberFormatElement = parseXmlString(xmlInput); 382 NumberFormat.Builder numberFormat = NumberFormat.newBuilder(); 383 BuildMetadataFromXml.setLeadingDigitsPatterns(numberFormatElement, numberFormat); 384 385 assertEquals("1", numberFormat.getLeadingDigitsPattern(0)); 386 assertEquals("2", numberFormat.getLeadingDigitsPattern(1)); 387 } 388 389 // Tests setLeadingDigitsPatterns() in the case of international and national formatting rules 390 // being present but not both defined for this numberFormat - we don't want to add them twice. testSetLeadingDigitsPatternsNotAddedTwiceWhenInternationalFormatsPresent()391 public void testSetLeadingDigitsPatternsNotAddedTwiceWhenInternationalFormatsPresent() 392 throws ParserConfigurationException, SAXException, IOException { 393 String xmlInput = "<availableFormats>" 394 + " <numberFormat pattern=\"(1)(\\d{3})\">" 395 + " <leadingDigits>1</leadingDigits>" 396 + " <format>$1</format>" 397 + " </numberFormat>" 398 + " <numberFormat pattern=\"(2)(\\d{3})\">" 399 + " <leadingDigits>2</leadingDigits>" 400 + " <format>$1</format>" 401 + " <intlFormat>9-$1</intlFormat>" 402 + " </numberFormat>" 403 + "</availableFormats>"; 404 Element element = parseXmlString(xmlInput); 405 PhoneMetadata.Builder metadata = PhoneMetadata.newBuilder(); 406 BuildMetadataFromXml.loadAvailableFormats( 407 metadata, element, "0", "", false /* NP not optional */); 408 assertEquals(1, metadata.getNumberFormat(0).leadingDigitsPatternSize()); 409 assertEquals(1, metadata.getNumberFormat(1).leadingDigitsPatternSize()); 410 // When we merge the national format rules into the international format rules, we shouldn't add 411 // the leading digit patterns multiple times. 412 assertEquals(1, metadata.getIntlNumberFormat(0).leadingDigitsPatternSize()); 413 assertEquals(1, metadata.getIntlNumberFormat(1).leadingDigitsPatternSize()); 414 } 415 416 // Tests getNationalPrefixFormattingRuleFromElement(). testGetNationalPrefixFormattingRuleFromElement()417 public void testGetNationalPrefixFormattingRuleFromElement() 418 throws ParserConfigurationException, SAXException, IOException { 419 String xmlInput = "<territory nationalPrefixFormattingRule='$NP$FG'/>"; 420 Element element = parseXmlString(xmlInput); 421 assertEquals("0$1", 422 BuildMetadataFromXml.getNationalPrefixFormattingRuleFromElement(element, "0")); 423 } 424 425 // Tests getDomesticCarrierCodeFormattingRuleFromElement(). testGetDomesticCarrierCodeFormattingRuleFromElement()426 public void testGetDomesticCarrierCodeFormattingRuleFromElement() 427 throws ParserConfigurationException, SAXException, IOException { 428 String xmlInput = "<territory carrierCodeFormattingRule='$NP$CC $FG'/>"; 429 Element element = parseXmlString(xmlInput); 430 assertEquals("0$CC $1", 431 BuildMetadataFromXml.getDomesticCarrierCodeFormattingRuleFromElement(element, 432 "0")); 433 } 434 435 // Tests processPhoneNumberDescElement(). testProcessPhoneNumberDescElementWithInvalidInput()436 public void testProcessPhoneNumberDescElementWithInvalidInput() 437 throws ParserConfigurationException, SAXException, IOException { 438 PhoneNumberDesc.Builder generalDesc = PhoneNumberDesc.newBuilder(); 439 Element territoryElement = parseXmlString("<territory/>"); 440 PhoneNumberDesc.Builder phoneNumberDesc; 441 442 phoneNumberDesc = BuildMetadataFromXml.processPhoneNumberDescElement( 443 generalDesc, territoryElement, "invalidType"); 444 assertFalse(phoneNumberDesc.hasNationalNumberPattern()); 445 } 446 testProcessPhoneNumberDescElementOverridesGeneralDesc()447 public void testProcessPhoneNumberDescElementOverridesGeneralDesc() 448 throws ParserConfigurationException, SAXException, IOException { 449 PhoneNumberDesc.Builder generalDesc = PhoneNumberDesc.newBuilder(); 450 generalDesc.setNationalNumberPattern("\\d{8}"); 451 String xmlInput = "<territory><fixedLine>" 452 + " <nationalNumberPattern>\\d{6}</nationalNumberPattern>" 453 + "</fixedLine></territory>"; 454 Element territoryElement = parseXmlString(xmlInput); 455 PhoneNumberDesc.Builder phoneNumberDesc; 456 457 phoneNumberDesc = BuildMetadataFromXml.processPhoneNumberDescElement( 458 generalDesc, territoryElement, "fixedLine"); 459 assertEquals("\\d{6}", phoneNumberDesc.getNationalNumberPattern()); 460 } 461 testBuildPhoneMetadataCollection_liteBuild()462 public void testBuildPhoneMetadataCollection_liteBuild() throws Exception { 463 String xmlInput = 464 "<phoneNumberMetadata>" 465 + " <territories>" 466 + " <territory id=\"AM\" countryCode=\"374\" internationalPrefix=\"00\">" 467 + " <generalDesc>" 468 + " <nationalNumberPattern>[1-9]\\d{7}</nationalNumberPattern>" 469 + " </generalDesc>" 470 + " <fixedLine>" 471 + " <nationalNumberPattern>[1-9]\\d{7}</nationalNumberPattern>" 472 + " <possibleLengths national=\"8\" localOnly=\"5,6\"/>" 473 + " <exampleNumber>10123456</exampleNumber>" 474 + " </fixedLine>" 475 + " <mobile>" 476 + " <nationalNumberPattern>[1-9]\\d{7}</nationalNumberPattern>" 477 + " <possibleLengths national=\"8\" localOnly=\"5,6\"/>" 478 + " <exampleNumber>10123456</exampleNumber>" 479 + " </mobile>" 480 + " </territory>" 481 + " </territories>" 482 + "</phoneNumberMetadata>"; 483 Document document = parseXmlString(xmlInput).getOwnerDocument(); 484 485 PhoneMetadataCollection metadataCollection = BuildMetadataFromXml.buildPhoneMetadataCollection( 486 document, 487 true, // liteBuild 488 false, // specialBuild 489 false, // isShortNumberMetadata 490 false); // isAlternateFormatsMetadata 491 492 assertTrue(metadataCollection.getMetadataCount() == 1); 493 PhoneMetadata metadata = metadataCollection.getMetadataList().get(0); 494 assertTrue(metadata.hasGeneralDesc()); 495 assertFalse(metadata.getGeneralDesc().hasExampleNumber()); 496 // Some Phonemetadata.java implementations may have custom logic, so we ensure this 497 // implementation is doing the right thing by checking the value of the example number even when 498 // hasExampleNumber is false. 499 assertEquals("", metadata.getGeneralDesc().getExampleNumber()); 500 assertTrue(metadata.hasFixedLine()); 501 assertFalse(metadata.getFixedLine().hasExampleNumber()); 502 assertEquals("", metadata.getFixedLine().getExampleNumber()); 503 assertTrue(metadata.hasMobile()); 504 assertFalse(metadata.getMobile().hasExampleNumber()); 505 assertEquals("", metadata.getMobile().getExampleNumber()); 506 } 507 testBuildPhoneMetadataCollection_specialBuild()508 public void testBuildPhoneMetadataCollection_specialBuild() throws Exception { 509 String xmlInput = 510 "<phoneNumberMetadata>" 511 + " <territories>" 512 + " <territory id=\"AM\" countryCode=\"374\" internationalPrefix=\"00\">" 513 + " <generalDesc>" 514 + " <nationalNumberPattern>[1-9]\\d{7}</nationalNumberPattern>" 515 + " </generalDesc>" 516 + " <fixedLine>" 517 + " <nationalNumberPattern>[1-9]\\d{7}</nationalNumberPattern>" 518 + " <possibleLengths national=\"8\" localOnly=\"5,6\"/>" 519 + " <exampleNumber>10123456</exampleNumber>" 520 + " </fixedLine>" 521 + " <mobile>" 522 + " <nationalNumberPattern>[1-9]\\d{7}</nationalNumberPattern>" 523 + " <possibleLengths national=\"8\" localOnly=\"5,6\"/>" 524 + " <exampleNumber>10123456</exampleNumber>" 525 + " </mobile>" 526 + " </territory>" 527 + " </territories>" 528 + "</phoneNumberMetadata>"; 529 Document document = parseXmlString(xmlInput).getOwnerDocument(); 530 531 PhoneMetadataCollection metadataCollection = BuildMetadataFromXml.buildPhoneMetadataCollection( 532 document, 533 false, // liteBuild 534 true, // specialBuild 535 false, // isShortNumberMetadata 536 false); // isAlternateFormatsMetadata 537 538 assertTrue(metadataCollection.getMetadataCount() == 1); 539 PhoneMetadata metadata = metadataCollection.getMetadataList().get(0); 540 assertTrue(metadata.hasGeneralDesc()); 541 assertFalse(metadata.getGeneralDesc().hasExampleNumber()); 542 // Some Phonemetadata.java implementations may have custom logic, so we ensure this 543 // implementation is doing the right thing by checking the value of the example number even when 544 // hasExampleNumber is false. 545 assertEquals("", metadata.getGeneralDesc().getExampleNumber()); 546 // TODO: Consider clearing fixed-line if empty after being filtered. 547 assertTrue(metadata.hasFixedLine()); 548 assertFalse(metadata.getFixedLine().hasExampleNumber()); 549 assertEquals("", metadata.getFixedLine().getExampleNumber()); 550 assertTrue(metadata.hasMobile()); 551 assertTrue(metadata.getMobile().hasExampleNumber()); 552 assertEquals("10123456", metadata.getMobile().getExampleNumber()); 553 } 554 testBuildPhoneMetadataCollection_fullBuild()555 public void testBuildPhoneMetadataCollection_fullBuild() throws Exception { 556 String xmlInput = 557 "<phoneNumberMetadata>" 558 + " <territories>" 559 + " <territory id=\"AM\" countryCode=\"374\" internationalPrefix=\"00\">" 560 + " <generalDesc>" 561 + " <nationalNumberPattern>[1-9]\\d{7}</nationalNumberPattern>" 562 + " </generalDesc>" 563 + " <fixedLine>" 564 + " <nationalNumberPattern>[1-9]\\d{7}</nationalNumberPattern>" 565 + " <possibleLengths national=\"8\" localOnly=\"5,6\"/>" 566 + " <exampleNumber>10123456</exampleNumber>" 567 + " </fixedLine>" 568 + " <mobile>" 569 + " <nationalNumberPattern>[1-9]\\d{7}</nationalNumberPattern>" 570 + " <possibleLengths national=\"8\" localOnly=\"5,6\"/>" 571 + " <exampleNumber>10123456</exampleNumber>" 572 + " </mobile>" 573 + " </territory>" 574 + " </territories>" 575 + "</phoneNumberMetadata>"; 576 Document document = parseXmlString(xmlInput).getOwnerDocument(); 577 578 PhoneMetadataCollection metadataCollection = BuildMetadataFromXml.buildPhoneMetadataCollection( 579 document, 580 false, // liteBuild 581 false, // specialBuild 582 false, // isShortNumberMetadata 583 false); // isAlternateFormatsMetadata 584 585 assertTrue(metadataCollection.getMetadataCount() == 1); 586 PhoneMetadata metadata = metadataCollection.getMetadataList().get(0); 587 assertTrue(metadata.hasGeneralDesc()); 588 assertFalse(metadata.getGeneralDesc().hasExampleNumber()); 589 // Some Phonemetadata.java implementations may have custom logic, so we ensure this 590 // implementation is doing the right thing by checking the value of the example number even when 591 // hasExampleNumber is false. 592 assertEquals("", metadata.getGeneralDesc().getExampleNumber()); 593 assertTrue(metadata.hasFixedLine()); 594 assertTrue(metadata.getFixedLine().hasExampleNumber()); 595 assertEquals("10123456", metadata.getFixedLine().getExampleNumber()); 596 assertTrue(metadata.hasMobile()); 597 assertTrue(metadata.getMobile().hasExampleNumber()); 598 assertEquals("10123456", metadata.getMobile().getExampleNumber()); 599 } 600 testProcessPhoneNumberDescOutputsExampleNumberByDefault()601 public void testProcessPhoneNumberDescOutputsExampleNumberByDefault() 602 throws ParserConfigurationException, SAXException, IOException { 603 PhoneNumberDesc.Builder generalDesc = PhoneNumberDesc.newBuilder(); 604 String xmlInput = "<territory><fixedLine>" 605 + " <exampleNumber>01 01 01 01</exampleNumber>" 606 + "</fixedLine></territory>"; 607 Element territoryElement = parseXmlString(xmlInput); 608 PhoneNumberDesc.Builder phoneNumberDesc; 609 610 phoneNumberDesc = BuildMetadataFromXml.processPhoneNumberDescElement( 611 generalDesc, territoryElement, "fixedLine"); 612 assertEquals("01 01 01 01", phoneNumberDesc.getExampleNumber()); 613 } 614 testProcessPhoneNumberDescRemovesWhiteSpacesInPatterns()615 public void testProcessPhoneNumberDescRemovesWhiteSpacesInPatterns() 616 throws ParserConfigurationException, SAXException, IOException { 617 PhoneNumberDesc.Builder generalDesc = PhoneNumberDesc.newBuilder(); 618 String xmlInput = "<territory><fixedLine>" 619 + " <nationalNumberPattern>\t \\d { 6 } </nationalNumberPattern>" 620 + "</fixedLine></territory>"; 621 Element countryElement = parseXmlString(xmlInput); 622 PhoneNumberDesc.Builder phoneNumberDesc = BuildMetadataFromXml.processPhoneNumberDescElement( 623 generalDesc, countryElement, "fixedLine"); 624 assertEquals("\\d{6}", phoneNumberDesc.getNationalNumberPattern()); 625 } 626 627 // Tests setRelevantDescPatterns(). testSetRelevantDescPatternsSetsSameMobileAndFixedLinePattern()628 public void testSetRelevantDescPatternsSetsSameMobileAndFixedLinePattern() 629 throws ParserConfigurationException, SAXException, IOException { 630 String xmlInput = "<territory countryCode=\"33\">" 631 + " <fixedLine><nationalNumberPattern>\\d{6}</nationalNumberPattern></fixedLine>" 632 + " <mobile><nationalNumberPattern>\\d{6}</nationalNumberPattern></mobile>" 633 + "</territory>"; 634 Element territoryElement = parseXmlString(xmlInput); 635 PhoneMetadata.Builder metadata = PhoneMetadata.newBuilder(); 636 // Should set sameMobileAndFixedPattern to true. 637 BuildMetadataFromXml.setRelevantDescPatterns(metadata, territoryElement, 638 false /* isShortNumberMetadata */); 639 assertTrue(metadata.getSameMobileAndFixedLinePattern()); 640 } 641 testSetRelevantDescPatternsSetsAllDescriptionsForRegularLengthNumbers()642 public void testSetRelevantDescPatternsSetsAllDescriptionsForRegularLengthNumbers() 643 throws ParserConfigurationException, SAXException, IOException { 644 String xmlInput = "<territory countryCode=\"33\">" 645 + " <fixedLine><nationalNumberPattern>\\d{1}</nationalNumberPattern></fixedLine>" 646 + " <mobile><nationalNumberPattern>\\d{2}</nationalNumberPattern></mobile>" 647 + " <pager><nationalNumberPattern>\\d{3}</nationalNumberPattern></pager>" 648 + " <tollFree><nationalNumberPattern>\\d{4}</nationalNumberPattern></tollFree>" 649 + " <premiumRate><nationalNumberPattern>\\d{5}</nationalNumberPattern></premiumRate>" 650 + " <sharedCost><nationalNumberPattern>\\d{6}</nationalNumberPattern></sharedCost>" 651 + " <personalNumber><nationalNumberPattern>\\d{7}</nationalNumberPattern></personalNumber>" 652 + " <voip><nationalNumberPattern>\\d{8}</nationalNumberPattern></voip>" 653 + " <uan><nationalNumberPattern>\\d{9}</nationalNumberPattern></uan>" 654 + "</territory>"; 655 Element territoryElement = parseXmlString(xmlInput); 656 PhoneMetadata.Builder metadata = PhoneMetadata.newBuilder(); 657 BuildMetadataFromXml.setRelevantDescPatterns(metadata, territoryElement, 658 false /* isShortNumberMetadata */); 659 assertEquals("\\d{1}", metadata.getFixedLine().getNationalNumberPattern()); 660 assertEquals("\\d{2}", metadata.getMobile().getNationalNumberPattern()); 661 assertEquals("\\d{3}", metadata.getPager().getNationalNumberPattern()); 662 assertEquals("\\d{4}", metadata.getTollFree().getNationalNumberPattern()); 663 assertEquals("\\d{5}", metadata.getPremiumRate().getNationalNumberPattern()); 664 assertEquals("\\d{6}", metadata.getSharedCost().getNationalNumberPattern()); 665 assertEquals("\\d{7}", metadata.getPersonalNumber().getNationalNumberPattern()); 666 assertEquals("\\d{8}", metadata.getVoip().getNationalNumberPattern()); 667 assertEquals("\\d{9}", metadata.getUan().getNationalNumberPattern()); 668 } 669 testSetRelevantDescPatternsSetsAllDescriptionsForShortNumbers()670 public void testSetRelevantDescPatternsSetsAllDescriptionsForShortNumbers() 671 throws ParserConfigurationException, SAXException, IOException { 672 String xmlInput = "<territory ID=\"FR\">" 673 + " <tollFree><nationalNumberPattern>\\d{1}</nationalNumberPattern></tollFree>" 674 + " <standardRate><nationalNumberPattern>\\d{2}</nationalNumberPattern></standardRate>" 675 + " <premiumRate><nationalNumberPattern>\\d{3}</nationalNumberPattern></premiumRate>" 676 + " <shortCode><nationalNumberPattern>\\d{4}</nationalNumberPattern></shortCode>" 677 + " <carrierSpecific>" 678 + " <nationalNumberPattern>\\d{5}</nationalNumberPattern>" 679 + " </carrierSpecific>" 680 + " <smsServices>" 681 + " <nationalNumberPattern>\\d{6}</nationalNumberPattern>" 682 + " </smsServices>" 683 + "</territory>"; 684 Element territoryElement = parseXmlString(xmlInput); 685 PhoneMetadata.Builder metadata = PhoneMetadata.newBuilder(); 686 BuildMetadataFromXml.setRelevantDescPatterns(metadata, territoryElement, 687 true /* isShortNumberMetadata */); 688 assertEquals("\\d{1}", metadata.getTollFree().getNationalNumberPattern()); 689 assertEquals("\\d{2}", metadata.getStandardRate().getNationalNumberPattern()); 690 assertEquals("\\d{3}", metadata.getPremiumRate().getNationalNumberPattern()); 691 assertEquals("\\d{4}", metadata.getShortCode().getNationalNumberPattern()); 692 assertEquals("\\d{5}", metadata.getCarrierSpecific().getNationalNumberPattern()); 693 assertEquals("\\d{6}", metadata.getSmsServices().getNationalNumberPattern()); 694 } 695 testSetRelevantDescPatternsThrowsErrorIfTypePresentMultipleTimes()696 public void testSetRelevantDescPatternsThrowsErrorIfTypePresentMultipleTimes() 697 throws ParserConfigurationException, SAXException, IOException { 698 String xmlInput = "<territory countryCode=\"33\">" 699 + " <fixedLine><nationalNumberPattern>\\d{6}</nationalNumberPattern></fixedLine>" 700 + " <fixedLine><nationalNumberPattern>\\d{6}</nationalNumberPattern></fixedLine>" 701 + "</territory>"; 702 Element territoryElement = parseXmlString(xmlInput); 703 PhoneMetadata.Builder metadata = PhoneMetadata.newBuilder(); 704 try { 705 BuildMetadataFromXml.setRelevantDescPatterns(metadata, territoryElement, 706 false /* isShortNumberMetadata */); 707 fail("Fixed-line info present twice for France: we should fail."); 708 } catch (RuntimeException expected) { 709 assertEquals("Multiple elements with type fixedLine found.", expected.getMessage()); 710 } 711 } 712 testAlternateFormatsOmitsDescPatterns()713 public void testAlternateFormatsOmitsDescPatterns() 714 throws ParserConfigurationException, SAXException, IOException { 715 String xmlInput = "<territory countryCode=\"33\">" 716 + " <availableFormats>" 717 + " <numberFormat pattern=\"(1)(\\d{3})\">" 718 + " <leadingDigits>1</leadingDigits>" 719 + " <format>$1</format>" 720 + " </numberFormat>" 721 + " </availableFormats>" 722 + " <fixedLine><nationalNumberPattern>\\d{1}</nationalNumberPattern></fixedLine>" 723 + " <shortCode><nationalNumberPattern>\\d{2}</nationalNumberPattern></shortCode>" 724 + "</territory>"; 725 Element territoryElement = parseXmlString(xmlInput); 726 PhoneMetadata metadata = BuildMetadataFromXml.loadCountryMetadata("FR", territoryElement, 727 false /* isShortNumberMetadata */, true /* isAlternateFormatsMetadata */).build(); 728 assertEquals("(1)(\\d{3})", metadata.getNumberFormat(0).getPattern()); 729 assertEquals("1", metadata.getNumberFormat(0).getLeadingDigitsPattern(0)); 730 assertEquals("$1", metadata.getNumberFormat(0).getFormat()); 731 assertFalse(metadata.hasFixedLine()); 732 assertNull(metadata.getFixedLine()); 733 assertFalse(metadata.hasShortCode()); 734 assertNull(metadata.getShortCode()); 735 } 736 testNationalPrefixRulesSetCorrectly()737 public void testNationalPrefixRulesSetCorrectly() 738 throws ParserConfigurationException, SAXException, IOException { 739 String xmlInput = "<territory countryCode=\"33\" nationalPrefix=\"0\"" 740 + " nationalPrefixFormattingRule=\"$NP$FG\">" 741 + " <availableFormats>" 742 + " <numberFormat pattern=\"(1)(\\d{3})\" nationalPrefixOptionalWhenFormatting=\"true\">" 743 + " <leadingDigits>1</leadingDigits>" 744 + " <format>$1</format>" 745 + " </numberFormat>" 746 + " <numberFormat pattern=\"(\\d{3})\" nationalPrefixOptionalWhenFormatting=\"false\">" 747 + " <leadingDigits>2</leadingDigits>" 748 + " <format>$1</format>" 749 + " </numberFormat>" 750 + " </availableFormats>" 751 + " <fixedLine><nationalNumberPattern>\\d{1}</nationalNumberPattern></fixedLine>" 752 + "</territory>"; 753 Element territoryElement = parseXmlString(xmlInput); 754 PhoneMetadata metadata = BuildMetadataFromXml.loadCountryMetadata("FR", territoryElement, 755 false /* isShortNumberMetadata */, true /* isAlternateFormatsMetadata */).build(); 756 assertTrue(metadata.getNumberFormat(0).getNationalPrefixOptionalWhenFormatting()); 757 // This is inherited from the territory, with $NP replaced by the actual national prefix, and 758 // $FG replaced with $1. 759 assertEquals("0$1", metadata.getNumberFormat(0).getNationalPrefixFormattingRule()); 760 // Here it is explicitly set to false. 761 assertFalse(metadata.getNumberFormat(1).getNationalPrefixOptionalWhenFormatting()); 762 } 763 testProcessPhoneNumberDescElement_PossibleLengthsSetCorrectly()764 public void testProcessPhoneNumberDescElement_PossibleLengthsSetCorrectly() throws Exception { 765 PhoneNumberDesc.Builder generalDesc = PhoneNumberDesc.newBuilder(); 766 // The number lengths set for the general description must be a super-set of those in the 767 // element being parsed. 768 generalDesc.addPossibleLength(4); 769 generalDesc.addPossibleLength(6); 770 generalDesc.addPossibleLength(7); 771 generalDesc.addPossibleLength(13); 772 Element territoryElement = parseXmlString("<territory>" 773 + "<fixedLine>" 774 // Sorting will be done when parsing. 775 + " <possibleLengths national=\"13,4\" localOnly=\"6\"/>" 776 + "</fixedLine>" 777 + "</territory>"); 778 779 PhoneNumberDesc.Builder fixedLine; 780 PhoneNumberDesc.Builder mobile; 781 782 fixedLine = BuildMetadataFromXml.processPhoneNumberDescElement( 783 generalDesc, territoryElement, "fixedLine"); 784 mobile = BuildMetadataFromXml.processPhoneNumberDescElement( 785 generalDesc, territoryElement, "mobile"); 786 787 assertEquals(2, fixedLine.getPossibleLengthCount()); 788 assertEquals(4, fixedLine.getPossibleLength(0)); 789 assertEquals(13, fixedLine.getPossibleLength(1)); 790 assertEquals(1, fixedLine.getPossibleLengthLocalOnlyCount()); 791 792 // We use [-1] to denote that there are no possible lengths; we don't leave it empty, since for 793 // compression reasons, we use the empty list to mean that the generalDesc possible lengths 794 // apply. 795 assertEquals(1, mobile.getPossibleLengthCount()); 796 assertEquals(-1, mobile.getPossibleLength(0)); 797 assertEquals(0, mobile.getPossibleLengthLocalOnlyCount()); 798 } 799 testSetPossibleLengthsGeneralDesc_BuiltFromChildElements()800 public void testSetPossibleLengthsGeneralDesc_BuiltFromChildElements() throws Exception { 801 Element territoryElement = parseXmlString("<territory>" 802 + "<fixedLine>" 803 + " <possibleLengths national=\"13\" localOnly=\"6\"/>" 804 + "</fixedLine>" 805 + "<mobile>" 806 + " <possibleLengths national=\"15\" localOnly=\"7,13\"/>" 807 + "</mobile>" 808 + "<tollFree>" 809 + " <possibleLengths national=\"15\"/>" 810 + "</tollFree>" 811 + "</territory>"); 812 PhoneNumberDesc.Builder generalDesc = PhoneNumberDesc.newBuilder(); 813 BuildMetadataFromXml.setPossibleLengthsGeneralDesc( 814 generalDesc, "someId", territoryElement, false /* not short-number metadata */); 815 816 assertEquals(2, generalDesc.getPossibleLengthCount()); 817 assertEquals(13, generalDesc.getPossibleLength(0)); 818 // 15 is present twice in the input in different sections, but only once in the output. 819 assertEquals(15, generalDesc.getPossibleLength(1)); 820 assertEquals(2, generalDesc.getPossibleLengthLocalOnlyCount()); 821 assertEquals(6, generalDesc.getPossibleLengthLocalOnly(0)); 822 assertEquals(7, generalDesc.getPossibleLengthLocalOnly(1)); 823 // 13 is skipped as a "local only" length, since it is also present as a normal length. 824 } 825 testSetPossibleLengthsGeneralDesc_IgnoresNoIntlDialling()826 public void testSetPossibleLengthsGeneralDesc_IgnoresNoIntlDialling() throws Exception { 827 Element territoryElement = parseXmlString("<territory>" 828 + "<fixedLine>" 829 + " <possibleLengths national=\"13\"/>" 830 + "</fixedLine>" 831 + "<noInternationalDialling>" 832 + " <possibleLengths national=\"15\"/>" 833 + "</noInternationalDialling>" 834 + "</territory>"); 835 PhoneNumberDesc.Builder generalDesc = PhoneNumberDesc.newBuilder(); 836 BuildMetadataFromXml.setPossibleLengthsGeneralDesc( 837 generalDesc, "someId", territoryElement, false /* not short-number metadata */); 838 839 assertEquals(1, generalDesc.getPossibleLengthCount()); 840 assertEquals(13, generalDesc.getPossibleLength(0)); 841 // 15 is skipped because noInternationalDialling should not contribute to the general lengths; 842 // it isn't a particular "type" of number per se, it is a property that different types may 843 // have. 844 } 845 testSetPossibleLengthsGeneralDesc_ShortNumberMetadata()846 public void testSetPossibleLengthsGeneralDesc_ShortNumberMetadata() throws Exception { 847 Element territoryElement = parseXmlString("<territory>" 848 + "<shortCode>" 849 + " <possibleLengths national=\"6,13\"/>" 850 + "</shortCode>" 851 + "<carrierSpecific>" 852 + " <possibleLengths national=\"7,13,15\"/>" 853 + "</carrierSpecific>" 854 + "<tollFree>" 855 + " <possibleLengths national=\"15\"/>" 856 + "</tollFree>" 857 + "<smsServices>" 858 + " <possibleLengths national=\"5\"/>" 859 + "</smsServices>" 860 + "</territory>"); 861 PhoneNumberDesc.Builder generalDesc = PhoneNumberDesc.newBuilder(); 862 BuildMetadataFromXml.setPossibleLengthsGeneralDesc( 863 generalDesc, "someId", territoryElement, true /* short-number metadata */); 864 865 // All elements other than shortCode are ignored when creating the general desc. 866 assertEquals(2, generalDesc.getPossibleLengthCount()); 867 assertEquals(6, generalDesc.getPossibleLength(0)); 868 assertEquals(13, generalDesc.getPossibleLength(1)); 869 } 870 testSetPossibleLengthsGeneralDesc_ShortNumberMetadataErrorsOnLocalLengths()871 public void testSetPossibleLengthsGeneralDesc_ShortNumberMetadataErrorsOnLocalLengths() 872 throws Exception { 873 Element territoryElement = parseXmlString("<territory>" 874 + "<shortCode>" 875 + " <possibleLengths national=\"13\" localOnly=\"6\"/>" 876 + "</shortCode>" 877 + "</territory>"); 878 879 PhoneNumberDesc.Builder generalDesc = PhoneNumberDesc.newBuilder(); 880 try { 881 BuildMetadataFromXml.setPossibleLengthsGeneralDesc( 882 generalDesc, "someId", territoryElement, true /* short-number metadata */); 883 fail(); 884 } catch (RuntimeException expected) { 885 // This should be an error, localOnly is not permitted in short-code metadata. 886 assertEquals("Found local-only lengths in short-number metadata", expected.getMessage()); 887 } 888 } 889 testProcessPhoneNumberDescElement_ErrorDuplicates()890 public void testProcessPhoneNumberDescElement_ErrorDuplicates() throws Exception { 891 PhoneNumberDesc.Builder generalDesc = PhoneNumberDesc.newBuilder(); 892 generalDesc.addPossibleLength(6); 893 894 Element territoryElement = parseXmlString("<territory>" 895 + "<mobile>" 896 + " <possibleLengths national=\"6,6\"/>" 897 + "</mobile>" 898 + "</territory>"); 899 900 try { 901 BuildMetadataFromXml.processPhoneNumberDescElement(generalDesc, territoryElement, "mobile"); 902 fail("Invalid data seen: expected failure."); 903 } catch (RuntimeException expected) { 904 // This should be an error, 6 is seen twice. 905 assertEquals("Duplicate length element found (6) in possibleLength string 6,6", 906 expected.getMessage()); 907 } 908 } 909 testProcessPhoneNumberDescElement_ErrorDuplicatesOneLocal()910 public void testProcessPhoneNumberDescElement_ErrorDuplicatesOneLocal() throws Exception { 911 PhoneNumberDesc.Builder generalDesc = PhoneNumberDesc.newBuilder(); 912 generalDesc.addPossibleLength(6); 913 914 Element territoryElement = parseXmlString("<territory>" 915 + "<mobile>" 916 + " <possibleLengths national=\"6\" localOnly=\"6\"/>" 917 + "</mobile>" 918 + "</territory>"); 919 920 try { 921 BuildMetadataFromXml.processPhoneNumberDescElement(generalDesc, territoryElement, "mobile"); 922 fail("Invalid data seen: expected failure."); 923 } catch (RuntimeException expected) { 924 // This should be an error, 6 is seen twice. 925 assertEquals("Possible length(s) found specified as a normal and local-only length: [6]", 926 expected.getMessage()); 927 } 928 } 929 testProcessPhoneNumberDescElement_ErrorUncoveredLengths()930 public void testProcessPhoneNumberDescElement_ErrorUncoveredLengths() throws Exception { 931 PhoneNumberDesc.Builder generalDesc = PhoneNumberDesc.newBuilder(); 932 generalDesc.addPossibleLength(4); 933 Element territoryElement = parseXmlString("<territory>" 934 + "<noInternationalDialling>" 935 // Sorting will be done when parsing. 936 + " <possibleLengths national=\"6,7,4\"/>" 937 + "</noInternationalDialling>" 938 + "</territory>"); 939 try { 940 BuildMetadataFromXml.processPhoneNumberDescElement( 941 generalDesc, territoryElement, "noInternationalDialling"); 942 fail("Lengths present not covered by the general desc: should fail."); 943 } catch (RuntimeException expected) { 944 // Lengths were present that the general description didn't know about. 945 assertTrue(expected.getMessage().contains("Out-of-range possible length")); 946 } 947 } 948 testProcessPhoneNumberDescElement_SameAsParent()949 public void testProcessPhoneNumberDescElement_SameAsParent() throws Exception { 950 PhoneNumberDesc.Builder generalDesc = PhoneNumberDesc.newBuilder(); 951 // The number lengths set for the general description must be a super-set of those in the 952 // element being parsed. 953 generalDesc.addPossibleLength(4); 954 generalDesc.addPossibleLength(6); 955 generalDesc.addPossibleLength(7); 956 generalDesc.addPossibleLengthLocalOnly(2); 957 Element territoryElement = parseXmlString("<territory>" 958 + "<fixedLine>" 959 // Sorting will be done when parsing. 960 + " <possibleLengths national=\"6,7,4\" localOnly=\"2\"/>" 961 + "</fixedLine>" 962 + "</territory>"); 963 964 PhoneNumberDesc.Builder phoneNumberDesc = BuildMetadataFromXml.processPhoneNumberDescElement( 965 generalDesc, territoryElement, "fixedLine"); 966 // No possible lengths should be present, because they match the general description. 967 assertEquals(0, phoneNumberDesc.getPossibleLengthCount()); 968 // Local-only lengths should be present for child elements such as fixed-line. 969 assertEquals(1, phoneNumberDesc.getPossibleLengthLocalOnlyCount()); 970 } 971 testProcessPhoneNumberDescElement_InvalidNumber()972 public void testProcessPhoneNumberDescElement_InvalidNumber() throws Exception { 973 PhoneNumberDesc.Builder generalDesc = PhoneNumberDesc.newBuilder(); 974 generalDesc.addPossibleLength(4); 975 Element territoryElement = parseXmlString("<territory>" 976 + "<fixedLine>" 977 + " <possibleLengths national=\"4d\"/>" 978 + "</fixedLine>" 979 + "</territory>"); 980 981 try { 982 BuildMetadataFromXml.processPhoneNumberDescElement( 983 generalDesc, territoryElement, "fixedLine"); 984 fail("4d is not a number."); 985 } catch (NumberFormatException expected) { 986 assertEquals("For input string: \"4d\"", expected.getMessage()); 987 } 988 } 989 testLoadCountryMetadata_GeneralDescHasNumberLengthsSet()990 public void testLoadCountryMetadata_GeneralDescHasNumberLengthsSet() throws Exception { 991 Element territoryElement = parseXmlString("<territory>" 992 + "<generalDesc>" 993 // This shouldn't be set, the possible lengths should be derived for generalDesc. 994 + " <possibleLengths national=\"4\"/>" 995 + "</generalDesc>" 996 + "<fixedLine>" 997 + " <possibleLengths national=\"4\"/>" 998 + "</fixedLine>" 999 + "</territory>"); 1000 1001 try { 1002 BuildMetadataFromXml.loadCountryMetadata("FR", territoryElement, 1003 false /* isShortNumberMetadata */, false /* isAlternateFormatsMetadata */); 1004 fail("Possible lengths explicitly set for generalDesc and should not be: we should fail."); 1005 } catch (RuntimeException expected) { 1006 assertEquals("Found possible lengths specified at general desc: this should be derived" 1007 + " from child elements. Affected country: FR", expected.getMessage()); 1008 } 1009 } 1010 testProcessPhoneNumberDescElement_ErrorEmptyPossibleLengthStringAttribute()1011 public void testProcessPhoneNumberDescElement_ErrorEmptyPossibleLengthStringAttribute() 1012 throws Exception { 1013 PhoneNumberDesc.Builder generalDesc = PhoneNumberDesc.newBuilder(); 1014 generalDesc.addPossibleLength(4); 1015 Element territoryElement = parseXmlString("<territory>" 1016 + "<fixedLine>" 1017 + " <possibleLengths national=\"\"/>" 1018 + "</fixedLine>" 1019 + "</territory>"); 1020 try { 1021 BuildMetadataFromXml.processPhoneNumberDescElement( 1022 generalDesc, territoryElement, "fixedLine"); 1023 fail("Empty possible length string."); 1024 } catch (RuntimeException expected) { 1025 assertEquals("Empty possibleLength string found.", expected.getMessage()); 1026 } 1027 } 1028 testProcessPhoneNumberDescElement_ErrorRangeSpecifiedWithComma()1029 public void testProcessPhoneNumberDescElement_ErrorRangeSpecifiedWithComma() 1030 throws Exception { 1031 PhoneNumberDesc.Builder generalDesc = PhoneNumberDesc.newBuilder(); 1032 generalDesc.addPossibleLength(4); 1033 Element territoryElement = parseXmlString("<territory>" 1034 + "<fixedLine>" 1035 + " <possibleLengths national=\"[4,7]\"/>" 1036 + "</fixedLine>" 1037 + "</territory>"); 1038 try { 1039 BuildMetadataFromXml.processPhoneNumberDescElement( 1040 generalDesc, territoryElement, "fixedLine"); 1041 fail("Ranges shouldn't use a comma."); 1042 } catch (RuntimeException expected) { 1043 assertEquals("Missing end of range character in possible length string [4,7].", 1044 expected.getMessage()); 1045 } 1046 } 1047 testProcessPhoneNumberDescElement_ErrorIncompleteRange()1048 public void testProcessPhoneNumberDescElement_ErrorIncompleteRange() throws Exception { 1049 PhoneNumberDesc.Builder generalDesc = PhoneNumberDesc.newBuilder(); 1050 generalDesc.addPossibleLength(4); 1051 Element territoryElement = parseXmlString("<territory>" 1052 + "<fixedLine>" 1053 + " <possibleLengths national=\"[4-\"/>" 1054 + "</fixedLine>" 1055 + "</territory>"); 1056 1057 try { 1058 BuildMetadataFromXml.processPhoneNumberDescElement( 1059 generalDesc, territoryElement, "fixedLine"); 1060 fail("Should fail: range incomplete."); 1061 } catch (RuntimeException expected) { 1062 assertEquals("Missing end of range character in possible length string [4-.", 1063 expected.getMessage()); 1064 } 1065 } 1066 testProcessPhoneNumberDescElement_ErrorNoDashInRange()1067 public void testProcessPhoneNumberDescElement_ErrorNoDashInRange() throws Exception { 1068 PhoneNumberDesc.Builder generalDesc = PhoneNumberDesc.newBuilder(); 1069 generalDesc.addPossibleLength(4); 1070 Element territoryElement = parseXmlString("<territory>" 1071 + "<fixedLine>" 1072 + " <possibleLengths national=\"[4:10]\"/>" 1073 + "</fixedLine>" 1074 + "</territory>"); 1075 1076 try { 1077 BuildMetadataFromXml.processPhoneNumberDescElement( 1078 generalDesc, territoryElement, "fixedLine"); 1079 fail("Should fail: range incomplete."); 1080 } catch (RuntimeException expected) { 1081 assertEquals("Ranges must have exactly one - character: missing for [4:10].", 1082 expected.getMessage()); 1083 } 1084 } 1085 testProcessPhoneNumberDescElement_ErrorRangeIsNotFromMinToMax()1086 public void testProcessPhoneNumberDescElement_ErrorRangeIsNotFromMinToMax() throws Exception { 1087 PhoneNumberDesc.Builder generalDesc = PhoneNumberDesc.newBuilder(); 1088 generalDesc.addPossibleLength(4); 1089 Element territoryElement = parseXmlString("<territory>" 1090 + "<fixedLine>" 1091 + " <possibleLengths national=\"[10-10]\"/>" 1092 + "</fixedLine>" 1093 + "</territory>"); 1094 1095 try { 1096 BuildMetadataFromXml.processPhoneNumberDescElement( 1097 generalDesc, territoryElement, "fixedLine"); 1098 fail("Should fail: range even."); 1099 } catch (RuntimeException expected) { 1100 assertEquals("The first number in a range should be two or more digits lower than the second." 1101 + " Culprit possibleLength string: [10-10]", expected.getMessage()); 1102 } 1103 } 1104 testGetMetadataFilter()1105 public void testGetMetadataFilter() { 1106 assertEquals(BuildMetadataFromXml.getMetadataFilter(false, false), 1107 MetadataFilter.emptyFilter()); 1108 assertEquals(BuildMetadataFromXml.getMetadataFilter(true, false), 1109 MetadataFilter.forLiteBuild()); 1110 assertEquals(BuildMetadataFromXml.getMetadataFilter(false, true), 1111 MetadataFilter.forSpecialBuild()); 1112 try { 1113 BuildMetadataFromXml.getMetadataFilter(true, true); 1114 fail("getMetadataFilter should fail when liteBuild and specialBuild are both set"); 1115 } catch (RuntimeException e) { 1116 // Test passed. 1117 } 1118 } 1119 } 1120