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='0011' 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("0011", 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.intlNumberFormatSize()); 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.intlNumberFormatSize()); 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; 623 624 phoneNumberDesc = BuildMetadataFromXml.processPhoneNumberDescElement( 625 generalDesc, countryElement, "fixedLine"); 626 assertEquals("\\d{6}", phoneNumberDesc.getNationalNumberPattern()); 627 } 628 629 // Tests setRelevantDescPatterns(). testSetRelevantDescPatternsSetsSameMobileAndFixedLinePattern()630 public void testSetRelevantDescPatternsSetsSameMobileAndFixedLinePattern() 631 throws ParserConfigurationException, SAXException, IOException { 632 String xmlInput = "<territory countryCode=\"33\">" 633 + " <fixedLine><nationalNumberPattern>\\d{6}</nationalNumberPattern></fixedLine>" 634 + " <mobile><nationalNumberPattern>\\d{6}</nationalNumberPattern></mobile>" 635 + "</territory>"; 636 Element territoryElement = parseXmlString(xmlInput); 637 PhoneMetadata.Builder metadata = PhoneMetadata.newBuilder(); 638 // Should set sameMobileAndFixedPattern to true. 639 BuildMetadataFromXml.setRelevantDescPatterns(metadata, territoryElement, 640 false /* isShortNumberMetadata */); 641 assertTrue(metadata.getSameMobileAndFixedLinePattern()); 642 } 643 testSetRelevantDescPatternsSetsAllDescriptionsForRegularLengthNumbers()644 public void testSetRelevantDescPatternsSetsAllDescriptionsForRegularLengthNumbers() 645 throws ParserConfigurationException, SAXException, IOException { 646 String xmlInput = "<territory countryCode=\"33\">" 647 + " <fixedLine><nationalNumberPattern>\\d{1}</nationalNumberPattern></fixedLine>" 648 + " <mobile><nationalNumberPattern>\\d{2}</nationalNumberPattern></mobile>" 649 + " <pager><nationalNumberPattern>\\d{3}</nationalNumberPattern></pager>" 650 + " <tollFree><nationalNumberPattern>\\d{4}</nationalNumberPattern></tollFree>" 651 + " <premiumRate><nationalNumberPattern>\\d{5}</nationalNumberPattern></premiumRate>" 652 + " <sharedCost><nationalNumberPattern>\\d{6}</nationalNumberPattern></sharedCost>" 653 + " <personalNumber><nationalNumberPattern>\\d{7}</nationalNumberPattern></personalNumber>" 654 + " <voip><nationalNumberPattern>\\d{8}</nationalNumberPattern></voip>" 655 + " <uan><nationalNumberPattern>\\d{9}</nationalNumberPattern></uan>" 656 + "</territory>"; 657 Element territoryElement = parseXmlString(xmlInput); 658 PhoneMetadata.Builder metadata = PhoneMetadata.newBuilder(); 659 BuildMetadataFromXml.setRelevantDescPatterns(metadata, territoryElement, 660 false /* isShortNumberMetadata */); 661 assertEquals("\\d{1}", metadata.getFixedLine().getNationalNumberPattern()); 662 assertEquals("\\d{2}", metadata.getMobile().getNationalNumberPattern()); 663 assertEquals("\\d{3}", metadata.getPager().getNationalNumberPattern()); 664 assertEquals("\\d{4}", metadata.getTollFree().getNationalNumberPattern()); 665 assertEquals("\\d{5}", metadata.getPremiumRate().getNationalNumberPattern()); 666 assertEquals("\\d{6}", metadata.getSharedCost().getNationalNumberPattern()); 667 assertEquals("\\d{7}", metadata.getPersonalNumber().getNationalNumberPattern()); 668 assertEquals("\\d{8}", metadata.getVoip().getNationalNumberPattern()); 669 assertEquals("\\d{9}", metadata.getUan().getNationalNumberPattern()); 670 } 671 testSetRelevantDescPatternsSetsAllDescriptionsForShortNumbers()672 public void testSetRelevantDescPatternsSetsAllDescriptionsForShortNumbers() 673 throws ParserConfigurationException, SAXException, IOException { 674 String xmlInput = "<territory ID=\"FR\">" 675 + " <tollFree><nationalNumberPattern>\\d{1}</nationalNumberPattern></tollFree>" 676 + " <standardRate><nationalNumberPattern>\\d{2}</nationalNumberPattern></standardRate>" 677 + " <premiumRate><nationalNumberPattern>\\d{3}</nationalNumberPattern></premiumRate>" 678 + " <shortCode><nationalNumberPattern>\\d{4}</nationalNumberPattern></shortCode>" 679 + " <carrierSpecific>" 680 + " <nationalNumberPattern>\\d{5}</nationalNumberPattern>" 681 + " </carrierSpecific>" 682 + " <smsServices>" 683 + " <nationalNumberPattern>\\d{6}</nationalNumberPattern>" 684 + " </smsServices>" 685 + "</territory>"; 686 Element territoryElement = parseXmlString(xmlInput); 687 PhoneMetadata.Builder metadata = PhoneMetadata.newBuilder(); 688 BuildMetadataFromXml.setRelevantDescPatterns(metadata, territoryElement, 689 true /* isShortNumberMetadata */); 690 assertEquals("\\d{1}", metadata.getTollFree().getNationalNumberPattern()); 691 assertEquals("\\d{2}", metadata.getStandardRate().getNationalNumberPattern()); 692 assertEquals("\\d{3}", metadata.getPremiumRate().getNationalNumberPattern()); 693 assertEquals("\\d{4}", metadata.getShortCode().getNationalNumberPattern()); 694 assertEquals("\\d{5}", metadata.getCarrierSpecific().getNationalNumberPattern()); 695 assertEquals("\\d{6}", metadata.getSmsServices().getNationalNumberPattern()); 696 } 697 testSetRelevantDescPatternsThrowsErrorIfTypePresentMultipleTimes()698 public void testSetRelevantDescPatternsThrowsErrorIfTypePresentMultipleTimes() 699 throws ParserConfigurationException, SAXException, IOException { 700 String xmlInput = "<territory countryCode=\"33\">" 701 + " <fixedLine><nationalNumberPattern>\\d{6}</nationalNumberPattern></fixedLine>" 702 + " <fixedLine><nationalNumberPattern>\\d{6}</nationalNumberPattern></fixedLine>" 703 + "</territory>"; 704 Element territoryElement = parseXmlString(xmlInput); 705 PhoneMetadata.Builder metadata = PhoneMetadata.newBuilder(); 706 try { 707 BuildMetadataFromXml.setRelevantDescPatterns(metadata, territoryElement, 708 false /* isShortNumberMetadata */); 709 fail("Fixed-line info present twice for France: we should fail."); 710 } catch (RuntimeException expected) { 711 assertEquals("Multiple elements with type fixedLine found.", expected.getMessage()); 712 } 713 } 714 testAlternateFormatsOmitsDescPatterns()715 public void testAlternateFormatsOmitsDescPatterns() 716 throws ParserConfigurationException, SAXException, IOException { 717 String xmlInput = "<territory countryCode=\"33\">" 718 + " <availableFormats>" 719 + " <numberFormat pattern=\"(1)(\\d{3})\">" 720 + " <leadingDigits>1</leadingDigits>" 721 + " <format>$1</format>" 722 + " </numberFormat>" 723 + " </availableFormats>" 724 + " <fixedLine><nationalNumberPattern>\\d{1}</nationalNumberPattern></fixedLine>" 725 + " <shortCode><nationalNumberPattern>\\d{2}</nationalNumberPattern></shortCode>" 726 + "</territory>"; 727 Element territoryElement = parseXmlString(xmlInput); 728 PhoneMetadata metadata = BuildMetadataFromXml.loadCountryMetadata("FR", territoryElement, 729 false /* isShortNumberMetadata */, true /* isAlternateFormatsMetadata */).build(); 730 assertEquals("(1)(\\d{3})", metadata.getNumberFormat(0).getPattern()); 731 assertEquals("1", metadata.getNumberFormat(0).getLeadingDigitsPattern(0)); 732 assertEquals("$1", metadata.getNumberFormat(0).getFormat()); 733 assertFalse(metadata.hasFixedLine()); 734 assertNull(metadata.getFixedLine()); 735 assertFalse(metadata.hasShortCode()); 736 assertNull(metadata.getShortCode()); 737 } 738 testNationalPrefixRulesSetCorrectly()739 public void testNationalPrefixRulesSetCorrectly() 740 throws ParserConfigurationException, SAXException, IOException { 741 String xmlInput = "<territory countryCode=\"33\" nationalPrefix=\"0\"" 742 + " nationalPrefixFormattingRule=\"$NP$FG\">" 743 + " <availableFormats>" 744 + " <numberFormat pattern=\"(1)(\\d{3})\" nationalPrefixOptionalWhenFormatting=\"true\">" 745 + " <leadingDigits>1</leadingDigits>" 746 + " <format>$1</format>" 747 + " </numberFormat>" 748 + " <numberFormat pattern=\"(\\d{3})\" nationalPrefixOptionalWhenFormatting=\"false\">" 749 + " <leadingDigits>2</leadingDigits>" 750 + " <format>$1</format>" 751 + " </numberFormat>" 752 + " </availableFormats>" 753 + " <fixedLine><nationalNumberPattern>\\d{1}</nationalNumberPattern></fixedLine>" 754 + "</territory>"; 755 Element territoryElement = parseXmlString(xmlInput); 756 PhoneMetadata metadata = BuildMetadataFromXml.loadCountryMetadata("FR", territoryElement, 757 false /* isShortNumberMetadata */, true /* isAlternateFormatsMetadata */).build(); 758 assertTrue(metadata.getNumberFormat(0).getNationalPrefixOptionalWhenFormatting()); 759 // This is inherited from the territory, with $NP replaced by the actual national prefix, and 760 // $FG replaced with $1. 761 assertEquals("0$1", metadata.getNumberFormat(0).getNationalPrefixFormattingRule()); 762 // Here it is explicitly set to false. 763 assertFalse(metadata.getNumberFormat(1).getNationalPrefixOptionalWhenFormatting()); 764 } 765 testProcessPhoneNumberDescElement_PossibleLengthsSetCorrectly()766 public void testProcessPhoneNumberDescElement_PossibleLengthsSetCorrectly() throws Exception { 767 PhoneNumberDesc.Builder generalDesc = PhoneNumberDesc.newBuilder(); 768 // The number lengths set for the general description must be a super-set of those in the 769 // element being parsed. 770 generalDesc.addPossibleLength(4); 771 generalDesc.addPossibleLength(6); 772 generalDesc.addPossibleLength(7); 773 generalDesc.addPossibleLength(13); 774 Element territoryElement = parseXmlString("<territory>" 775 + "<fixedLine>" 776 // Sorting will be done when parsing. 777 + " <possibleLengths national=\"13,4\" localOnly=\"6\"/>" 778 + "</fixedLine>" 779 + "</territory>"); 780 781 PhoneNumberDesc.Builder fixedLine; 782 PhoneNumberDesc.Builder mobile; 783 784 fixedLine = BuildMetadataFromXml.processPhoneNumberDescElement( 785 generalDesc, territoryElement, "fixedLine"); 786 mobile = BuildMetadataFromXml.processPhoneNumberDescElement( 787 generalDesc, territoryElement, "mobile"); 788 789 assertEquals(2, fixedLine.getPossibleLengthCount()); 790 assertEquals(4, fixedLine.getPossibleLength(0)); 791 assertEquals(13, fixedLine.getPossibleLength(1)); 792 assertEquals(1, fixedLine.getPossibleLengthLocalOnlyCount()); 793 794 // We use [-1] to denote that there are no possible lengths; we don't leave it empty, since for 795 // compression reasons, we use the empty list to mean that the generalDesc possible lengths 796 // apply. 797 assertEquals(1, mobile.getPossibleLengthCount()); 798 assertEquals(-1, mobile.getPossibleLength(0)); 799 assertEquals(0, mobile.getPossibleLengthLocalOnlyCount()); 800 } 801 testSetPossibleLengthsGeneralDesc_BuiltFromChildElements()802 public void testSetPossibleLengthsGeneralDesc_BuiltFromChildElements() throws Exception { 803 Element territoryElement = parseXmlString("<territory>" 804 + "<fixedLine>" 805 + " <possibleLengths national=\"13\" localOnly=\"6\"/>" 806 + "</fixedLine>" 807 + "<mobile>" 808 + " <possibleLengths national=\"15\" localOnly=\"7,13\"/>" 809 + "</mobile>" 810 + "<tollFree>" 811 + " <possibleLengths national=\"15\"/>" 812 + "</tollFree>" 813 + "</territory>"); 814 PhoneNumberDesc.Builder generalDesc = PhoneNumberDesc.newBuilder(); 815 BuildMetadataFromXml.setPossibleLengthsGeneralDesc( 816 generalDesc, "someId", territoryElement, false /* not short-number metadata */); 817 818 assertEquals(2, generalDesc.getPossibleLengthCount()); 819 assertEquals(13, generalDesc.getPossibleLength(0)); 820 // 15 is present twice in the input in different sections, but only once in the output. 821 assertEquals(15, generalDesc.getPossibleLength(1)); 822 assertEquals(2, generalDesc.getPossibleLengthLocalOnlyCount()); 823 assertEquals(6, generalDesc.getPossibleLengthLocalOnly(0)); 824 assertEquals(7, generalDesc.getPossibleLengthLocalOnly(1)); 825 // 13 is skipped as a "local only" length, since it is also present as a normal length. 826 } 827 testSetPossibleLengthsGeneralDesc_IgnoresNoIntlDialling()828 public void testSetPossibleLengthsGeneralDesc_IgnoresNoIntlDialling() throws Exception { 829 Element territoryElement = parseXmlString("<territory>" 830 + "<fixedLine>" 831 + " <possibleLengths national=\"13\"/>" 832 + "</fixedLine>" 833 + "<noInternationalDialling>" 834 + " <possibleLengths national=\"15\"/>" 835 + "</noInternationalDialling>" 836 + "</territory>"); 837 PhoneNumberDesc.Builder generalDesc = PhoneNumberDesc.newBuilder(); 838 BuildMetadataFromXml.setPossibleLengthsGeneralDesc( 839 generalDesc, "someId", territoryElement, false /* not short-number metadata */); 840 841 assertEquals(1, generalDesc.getPossibleLengthCount()); 842 assertEquals(13, generalDesc.getPossibleLength(0)); 843 // 15 is skipped because noInternationalDialling should not contribute to the general lengths; 844 // it isn't a particular "type" of number per se, it is a property that different types may 845 // have. 846 } 847 testSetPossibleLengthsGeneralDesc_ShortNumberMetadata()848 public void testSetPossibleLengthsGeneralDesc_ShortNumberMetadata() throws Exception { 849 Element territoryElement = parseXmlString("<territory>" 850 + "<shortCode>" 851 + " <possibleLengths national=\"6,13\"/>" 852 + "</shortCode>" 853 + "<carrierSpecific>" 854 + " <possibleLengths national=\"7,13,15\"/>" 855 + "</carrierSpecific>" 856 + "<tollFree>" 857 + " <possibleLengths national=\"15\"/>" 858 + "</tollFree>" 859 + "<smsServices>" 860 + " <possibleLengths national=\"5\"/>" 861 + "</smsServices>" 862 + "</territory>"); 863 PhoneNumberDesc.Builder generalDesc = PhoneNumberDesc.newBuilder(); 864 BuildMetadataFromXml.setPossibleLengthsGeneralDesc( 865 generalDesc, "someId", territoryElement, true /* short-number metadata */); 866 867 // All elements other than shortCode are ignored when creating the general desc. 868 assertEquals(2, generalDesc.getPossibleLengthCount()); 869 assertEquals(6, generalDesc.getPossibleLength(0)); 870 assertEquals(13, generalDesc.getPossibleLength(1)); 871 } 872 testSetPossibleLengthsGeneralDesc_ShortNumberMetadataErrorsOnLocalLengths()873 public void testSetPossibleLengthsGeneralDesc_ShortNumberMetadataErrorsOnLocalLengths() 874 throws Exception { 875 Element territoryElement = parseXmlString("<territory>" 876 + "<shortCode>" 877 + " <possibleLengths national=\"13\" localOnly=\"6\"/>" 878 + "</shortCode>" 879 + "</territory>"); 880 881 PhoneNumberDesc.Builder generalDesc = PhoneNumberDesc.newBuilder(); 882 try { 883 BuildMetadataFromXml.setPossibleLengthsGeneralDesc( 884 generalDesc, "someId", territoryElement, true /* short-number metadata */); 885 fail(); 886 } catch (RuntimeException expected) { 887 // This should be an error, localOnly is not permitted in short-code metadata. 888 assertEquals("Found local-only lengths in short-number metadata", expected.getMessage()); 889 } 890 } 891 testProcessPhoneNumberDescElement_ErrorDuplicates()892 public void testProcessPhoneNumberDescElement_ErrorDuplicates() throws Exception { 893 PhoneNumberDesc.Builder generalDesc = PhoneNumberDesc.newBuilder(); 894 generalDesc.addPossibleLength(6); 895 896 Element territoryElement = parseXmlString("<territory>" 897 + "<mobile>" 898 + " <possibleLengths national=\"6,6\"/>" 899 + "</mobile>" 900 + "</territory>"); 901 902 try { 903 BuildMetadataFromXml.processPhoneNumberDescElement(generalDesc, territoryElement, "mobile"); 904 fail("Invalid data seen: expected failure."); 905 } catch (RuntimeException expected) { 906 // This should be an error, 6 is seen twice. 907 assertEquals("Duplicate length element found (6) in possibleLength string 6,6", 908 expected.getMessage()); 909 } 910 } 911 testProcessPhoneNumberDescElement_ErrorDuplicatesOneLocal()912 public void testProcessPhoneNumberDescElement_ErrorDuplicatesOneLocal() throws Exception { 913 PhoneNumberDesc.Builder generalDesc = PhoneNumberDesc.newBuilder(); 914 generalDesc.addPossibleLength(6); 915 916 Element territoryElement = parseXmlString("<territory>" 917 + "<mobile>" 918 + " <possibleLengths national=\"6\" localOnly=\"6\"/>" 919 + "</mobile>" 920 + "</territory>"); 921 922 try { 923 BuildMetadataFromXml.processPhoneNumberDescElement(generalDesc, territoryElement, "mobile"); 924 fail("Invalid data seen: expected failure."); 925 } catch (RuntimeException expected) { 926 // This should be an error, 6 is seen twice. 927 assertEquals("Possible length(s) found specified as a normal and local-only length: [6]", 928 expected.getMessage()); 929 } 930 } 931 testProcessPhoneNumberDescElement_ErrorUncoveredLengths()932 public void testProcessPhoneNumberDescElement_ErrorUncoveredLengths() throws Exception { 933 PhoneNumberDesc.Builder generalDesc = PhoneNumberDesc.newBuilder(); 934 generalDesc.addPossibleLength(4); 935 Element territoryElement = parseXmlString("<territory>" 936 + "<noInternationalDialling>" 937 // Sorting will be done when parsing. 938 + " <possibleLengths national=\"6,7,4\"/>" 939 + "</noInternationalDialling>" 940 + "</territory>"); 941 try { 942 BuildMetadataFromXml.processPhoneNumberDescElement( 943 generalDesc, territoryElement, "noInternationalDialling"); 944 fail("Lengths present not covered by the general desc: should fail."); 945 } catch (RuntimeException expected) { 946 // Lengths were present that the general description didn't know about. 947 assertTrue(expected.getMessage().contains("Out-of-range possible length")); 948 } 949 } 950 testProcessPhoneNumberDescElement_SameAsParent()951 public void testProcessPhoneNumberDescElement_SameAsParent() throws Exception { 952 PhoneNumberDesc.Builder generalDesc = PhoneNumberDesc.newBuilder(); 953 // The number lengths set for the general description must be a super-set of those in the 954 // element being parsed. 955 generalDesc.addPossibleLength(4); 956 generalDesc.addPossibleLength(6); 957 generalDesc.addPossibleLength(7); 958 generalDesc.addPossibleLengthLocalOnly(2); 959 Element territoryElement = parseXmlString("<territory>" 960 + "<fixedLine>" 961 // Sorting will be done when parsing. 962 + " <possibleLengths national=\"6,7,4\" localOnly=\"2\"/>" 963 + "</fixedLine>" 964 + "</territory>"); 965 966 PhoneNumberDesc.Builder phoneNumberDesc = BuildMetadataFromXml.processPhoneNumberDescElement( 967 generalDesc, territoryElement, "fixedLine"); 968 // No possible lengths should be present, because they match the general description. 969 assertEquals(0, phoneNumberDesc.getPossibleLengthCount()); 970 // Local-only lengths should be present for child elements such as fixed-line. 971 assertEquals(1, phoneNumberDesc.getPossibleLengthLocalOnlyCount()); 972 } 973 testProcessPhoneNumberDescElement_InvalidNumber()974 public void testProcessPhoneNumberDescElement_InvalidNumber() throws Exception { 975 PhoneNumberDesc.Builder generalDesc = PhoneNumberDesc.newBuilder(); 976 generalDesc.addPossibleLength(4); 977 Element territoryElement = parseXmlString("<territory>" 978 + "<fixedLine>" 979 + " <possibleLengths national=\"4d\"/>" 980 + "</fixedLine>" 981 + "</territory>"); 982 983 try { 984 BuildMetadataFromXml.processPhoneNumberDescElement( 985 generalDesc, territoryElement, "fixedLine"); 986 fail("4d is not a number."); 987 } catch (NumberFormatException expected) { 988 assertEquals("For input string: \"4d\"", expected.getMessage()); 989 } 990 } 991 testLoadCountryMetadata_GeneralDescHasNumberLengthsSet()992 public void testLoadCountryMetadata_GeneralDescHasNumberLengthsSet() throws Exception { 993 Element territoryElement = parseXmlString("<territory>" 994 + "<generalDesc>" 995 // This shouldn't be set, the possible lengths should be derived for generalDesc. 996 + " <possibleLengths national=\"4\"/>" 997 + "</generalDesc>" 998 + "<fixedLine>" 999 + " <possibleLengths national=\"4\"/>" 1000 + "</fixedLine>" 1001 + "</territory>"); 1002 1003 try { 1004 BuildMetadataFromXml.loadCountryMetadata("FR", territoryElement, 1005 false /* isShortNumberMetadata */, false /* isAlternateFormatsMetadata */); 1006 fail("Possible lengths explicitly set for generalDesc and should not be: we should fail."); 1007 } catch (RuntimeException expected) { 1008 assertEquals("Found possible lengths specified at general desc: this should be derived" 1009 + " from child elements. Affected country: FR", expected.getMessage()); 1010 } 1011 } 1012 testProcessPhoneNumberDescElement_ErrorEmptyPossibleLengthStringAttribute()1013 public void testProcessPhoneNumberDescElement_ErrorEmptyPossibleLengthStringAttribute() 1014 throws Exception { 1015 PhoneNumberDesc.Builder generalDesc = PhoneNumberDesc.newBuilder(); 1016 generalDesc.addPossibleLength(4); 1017 Element territoryElement = parseXmlString("<territory>" 1018 + "<fixedLine>" 1019 + " <possibleLengths national=\"\"/>" 1020 + "</fixedLine>" 1021 + "</territory>"); 1022 try { 1023 BuildMetadataFromXml.processPhoneNumberDescElement( 1024 generalDesc, territoryElement, "fixedLine"); 1025 fail("Empty possible length string."); 1026 } catch (RuntimeException expected) { 1027 assertEquals("Empty possibleLength string found.", expected.getMessage()); 1028 } 1029 } 1030 testProcessPhoneNumberDescElement_ErrorRangeSpecifiedWithComma()1031 public void testProcessPhoneNumberDescElement_ErrorRangeSpecifiedWithComma() 1032 throws Exception { 1033 PhoneNumberDesc.Builder generalDesc = PhoneNumberDesc.newBuilder(); 1034 generalDesc.addPossibleLength(4); 1035 Element territoryElement = parseXmlString("<territory>" 1036 + "<fixedLine>" 1037 + " <possibleLengths national=\"[4,7]\"/>" 1038 + "</fixedLine>" 1039 + "</territory>"); 1040 try { 1041 BuildMetadataFromXml.processPhoneNumberDescElement( 1042 generalDesc, territoryElement, "fixedLine"); 1043 fail("Ranges shouldn't use a comma."); 1044 } catch (RuntimeException expected) { 1045 assertEquals("Missing end of range character in possible length string [4,7].", 1046 expected.getMessage()); 1047 } 1048 } 1049 testProcessPhoneNumberDescElement_ErrorIncompleteRange()1050 public void testProcessPhoneNumberDescElement_ErrorIncompleteRange() throws Exception { 1051 PhoneNumberDesc.Builder generalDesc = PhoneNumberDesc.newBuilder(); 1052 generalDesc.addPossibleLength(4); 1053 Element territoryElement = parseXmlString("<territory>" 1054 + "<fixedLine>" 1055 + " <possibleLengths national=\"[4-\"/>" 1056 + "</fixedLine>" 1057 + "</territory>"); 1058 1059 try { 1060 BuildMetadataFromXml.processPhoneNumberDescElement( 1061 generalDesc, territoryElement, "fixedLine"); 1062 fail("Should fail: range incomplete."); 1063 } catch (RuntimeException expected) { 1064 assertEquals("Missing end of range character in possible length string [4-.", 1065 expected.getMessage()); 1066 } 1067 } 1068 testProcessPhoneNumberDescElement_ErrorNoDashInRange()1069 public void testProcessPhoneNumberDescElement_ErrorNoDashInRange() throws Exception { 1070 PhoneNumberDesc.Builder generalDesc = PhoneNumberDesc.newBuilder(); 1071 generalDesc.addPossibleLength(4); 1072 Element territoryElement = parseXmlString("<territory>" 1073 + "<fixedLine>" 1074 + " <possibleLengths national=\"[4:10]\"/>" 1075 + "</fixedLine>" 1076 + "</territory>"); 1077 1078 try { 1079 BuildMetadataFromXml.processPhoneNumberDescElement( 1080 generalDesc, territoryElement, "fixedLine"); 1081 fail("Should fail: range incomplete."); 1082 } catch (RuntimeException expected) { 1083 assertEquals("Ranges must have exactly one - character: missing for [4:10].", 1084 expected.getMessage()); 1085 } 1086 } 1087 testProcessPhoneNumberDescElement_ErrorRangeIsNotFromMinToMax()1088 public void testProcessPhoneNumberDescElement_ErrorRangeIsNotFromMinToMax() throws Exception { 1089 PhoneNumberDesc.Builder generalDesc = PhoneNumberDesc.newBuilder(); 1090 generalDesc.addPossibleLength(4); 1091 Element territoryElement = parseXmlString("<territory>" 1092 + "<fixedLine>" 1093 + " <possibleLengths national=\"[10-10]\"/>" 1094 + "</fixedLine>" 1095 + "</territory>"); 1096 1097 try { 1098 BuildMetadataFromXml.processPhoneNumberDescElement( 1099 generalDesc, territoryElement, "fixedLine"); 1100 fail("Should fail: range even."); 1101 } catch (RuntimeException expected) { 1102 assertEquals("The first number in a range should be two or more digits lower than the second." 1103 + " Culprit possibleLength string: [10-10]", expected.getMessage()); 1104 } 1105 } 1106 testGetMetadataFilter()1107 public void testGetMetadataFilter() { 1108 assertEquals(BuildMetadataFromXml.getMetadataFilter(false, false), 1109 MetadataFilter.emptyFilter()); 1110 assertEquals(BuildMetadataFromXml.getMetadataFilter(true, false), 1111 MetadataFilter.forLiteBuild()); 1112 assertEquals(BuildMetadataFromXml.getMetadataFilter(false, true), 1113 MetadataFilter.forSpecialBuild()); 1114 try { 1115 BuildMetadataFromXml.getMetadataFilter(true, true); 1116 fail("getMetadataFilter should fail when liteBuild and specialBuild are both set"); 1117 } catch (RuntimeException e) { 1118 // Test passed. 1119 } 1120 } 1121 } 1122