Browse Source

Introduce MetadataFilter with custom configuration (#1392)

pull/1398/head
Keghani Kouzoujian 9 years ago
committed by GitHub
parent
commit
8ac47a2df4
20 changed files with 2644 additions and 1124 deletions
  1. +1004
    -980
      cpp/src/phonenumbers/test_metadata.cc
  2. BIN
      java/carrier/src/com/google/i18n/phonenumbers/carrier/data/config
  3. BIN
      java/geocoder/src/com/google/i18n/phonenumbers/geocoding/data/config
  4. +3
    -3
      java/libphonenumber/src/com/google/i18n/phonenumbers/PhoneNumberUtil.java
  5. +95
    -38
      java/libphonenumber/src/com/google/i18n/phonenumbers/Phonemetadata.java
  6. +6
    -2
      java/libphonenumber/test/com/google/i18n/phonenumbers/CountryCodeToRegionCodeMapForTesting.java
  7. BIN
      java/libphonenumber/test/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProtoForTesting_AM
  8. +5
    -1
      java/pending_code_changes.txt
  9. +25
    -0
      javascript/i18n/phonenumbers/metadatafortesting.js
  10. +23
    -0
      resources/PhoneNumberMetadataForTesting.xml
  11. +4
    -0
      resources/phonemetadata.proto
  12. +70
    -58
      tools/java/common/src/com/google/i18n/phonenumbers/BuildMetadataFromXml.java
  13. +361
    -0
      tools/java/common/src/com/google/i18n/phonenumbers/MetadataFilter.java
  14. +179
    -39
      tools/java/common/test/com/google/i18n/phonenumbers/BuildMetadataFromXmlTest.java
  15. +857
    -0
      tools/java/common/test/com/google/i18n/phonenumbers/MetadataFilterTest.java
  16. +2
    -1
      tools/java/cpp-build/src/com/google/i18n/phonenumbers/BuildMetadataCppFromXml.java
  17. BIN
      tools/java/cpp-build/target/cpp-build-1.0-SNAPSHOT-jar-with-dependencies.jar
  18. +1
    -1
      tools/java/java-build/src/com/google/i18n/phonenumbers/BuildMetadataJsonFromXml.java
  19. +9
    -1
      tools/java/java-build/src/com/google/i18n/phonenumbers/BuildMetadataProtoFromXml.java
  20. BIN
      tools/java/java-build/target/java-build-1.0-SNAPSHOT-jar-with-dependencies.jar

+ 1004
- 980
cpp/src/phonenumbers/test_metadata.cc
File diff suppressed because it is too large
View File


BIN
java/carrier/src/com/google/i18n/phonenumbers/carrier/data/config View File


BIN
java/geocoder/src/com/google/i18n/phonenumbers/geocoding/data/config View File


+ 3
- 3
java/libphonenumber/src/com/google/i18n/phonenumbers/PhoneNumberUtil.java View File

@ -1159,7 +1159,7 @@ public class PhoneNumberUtil {
// If no pattern above is matched, we format the number as a whole.
formattedNumber.append(nationalSignificantNumber);
} else {
NumberFormat numFormatCopy = new NumberFormat();
NumberFormat.Builder numFormatCopy = NumberFormat.newBuilder();
// Before we do a replacement of the national prefix pattern $NP with the national prefix, we
// need to copy the rule so that subsequent replacements for different numbers have the
// appropriate national prefix.
@ -1522,7 +1522,7 @@ public class PhoneNumberUtil {
break;
}
// Otherwise, we need to remove the national prefix from our output.
NumberFormat numFormatCopy = new NumberFormat();
NumberFormat.Builder numFormatCopy = NumberFormat.newBuilder();
numFormatCopy.mergeFrom(formatRule);
numFormatCopy.clearNationalPrefixFormattingRule();
List<NumberFormat> numberFormats = new ArrayList<NumberFormat>(1);
@ -1651,7 +1651,7 @@ public class PhoneNumberUtil {
// If no pattern above is matched, we format the original input.
return rawInput;
}
NumberFormat newFormat = new NumberFormat();
NumberFormat.Builder newFormat = NumberFormat.newBuilder();
newFormat.mergeFrom(formattingPattern);
// The first group is the first group of digits that the user wrote together.
newFormat.setPattern("(\\d+)(.*)");


+ 95
- 38
java/libphonenumber/src/com/google/i18n/phonenumbers/Phonemetadata.java View File

@ -47,6 +47,28 @@ public final class Phonemetadata {
public NumberFormat build() {
return this;
}
public Builder mergeFrom(NumberFormat other) {
if (other.hasPattern()) {
setPattern(other.getPattern());
}
if (other.hasFormat()) {
setFormat(other.getFormat());
}
for (int i = 0; i < other.leadingDigitsPatternSize(); i++) {
addLeadingDigitsPattern(other.getLeadingDigitsPattern(i));
}
if (other.hasNationalPrefixFormattingRule()) {
setNationalPrefixFormattingRule(other.getNationalPrefixFormattingRule());
}
if (other.hasDomesticCarrierCodeFormattingRule()) {
setDomesticCarrierCodeFormattingRule(other.getDomesticCarrierCodeFormattingRule());
}
if (other.hasNationalPrefixOptionalWhenFormatting()) {
setNationalPrefixOptionalWhenFormatting(other.isNationalPrefixOptionalWhenFormatting());
}
return this;
}
}
public static Builder newBuilder() {
@ -134,27 +156,6 @@ public final class Phonemetadata {
return this;
}
public NumberFormat mergeFrom(NumberFormat other) {
if (other.hasPattern()) {
setPattern(other.getPattern());
}
if (other.hasFormat()) {
setFormat(other.getFormat());
}
int leadingDigitsPatternSize = other.leadingDigitsPatternSize();
for (int i = 0; i < leadingDigitsPatternSize; i++) {
addLeadingDigitsPattern(other.getLeadingDigitsPattern(i));
}
if (other.hasNationalPrefixFormattingRule()) {
setNationalPrefixFormattingRule(other.getNationalPrefixFormattingRule());
}
if (other.hasDomesticCarrierCodeFormattingRule()) {
setDomesticCarrierCodeFormattingRule(other.getDomesticCarrierCodeFormattingRule());
}
setNationalPrefixOptionalWhenFormatting(other.isNationalPrefixOptionalWhenFormatting());
return this;
}
public void writeExternal(ObjectOutput objectOutput) throws IOException {
objectOutput.writeUTF(pattern_);
objectOutput.writeUTF(format_);
@ -205,7 +206,27 @@ public final class Phonemetadata {
public PhoneNumberDesc build() {
return this;
}
public Builder mergeFrom(PhoneNumberDesc other) {
if (other.hasNationalNumberPattern()) {
setNationalNumberPattern(other.getNationalNumberPattern());
}
if (other.hasPossibleNumberPattern()) {
setPossibleNumberPattern(other.getPossibleNumberPattern());
}
for (int i = 0; i < other.getPossibleLengthCount(); i++) {
addPossibleLength(other.getPossibleLength(i));
}
for (int i = 0; i < other.getPossibleLengthLocalOnlyCount(); i++) {
addPossibleLengthLocalOnly(other.getPossibleLengthLocalOnly(i));
}
if (other.hasExampleNumber()) {
setExampleNumber(other.getExampleNumber());
}
return this;
}
}
public static Builder newBuilder() {
return new Builder();
}
@ -220,6 +241,11 @@ public final class Phonemetadata {
nationalNumberPattern_ = value;
return this;
}
public PhoneNumberDesc clearNationalNumberPattern() {
hasNationalNumberPattern = false;
nationalNumberPattern_ = "";
return this;
}
// optional string possible_number_pattern = 3;
private boolean hasPossibleNumberPattern;
@ -231,6 +257,11 @@ public final class Phonemetadata {
possibleNumberPattern_ = value;
return this;
}
public PhoneNumberDesc clearPossibleNumberPattern() {
hasPossibleNumberPattern = false;
possibleNumberPattern_ = "";
return this;
}
// repeated int32 possible_length = 9;
private java.util.List<Integer> possibleLength_ = new java.util.ArrayList<Integer>();
@ -278,23 +309,9 @@ public final class Phonemetadata {
exampleNumber_ = value;
return this;
}
public PhoneNumberDesc mergeFrom(PhoneNumberDesc other) {
if (other.hasNationalNumberPattern()) {
setNationalNumberPattern(other.getNationalNumberPattern());
}
if (other.hasPossibleNumberPattern()) {
setPossibleNumberPattern(other.getPossibleNumberPattern());
}
for (int i = 0; i < other.getPossibleLengthCount(); i++) {
addPossibleLength(other.getPossibleLength(i));
}
for (int i = 0; i < other.getPossibleLengthLocalOnlyCount(); i++) {
addPossibleLengthLocalOnly(other.getPossibleLengthLocalOnly(i));
}
if (other.hasExampleNumber()) {
setExampleNumber(other.getExampleNumber());
}
public PhoneNumberDesc clearExampleNumber() {
hasExampleNumber = false;
exampleNumber_ = "";
return this;
}
@ -645,6 +662,11 @@ public final class Phonemetadata {
preferredInternationalPrefix_ = value;
return this;
}
public PhoneMetadata clearPreferredInternationalPrefix() {
hasPreferredInternationalPrefix = false;
preferredInternationalPrefix_ = "";
return this;
}
// optional string national_prefix = 12;
private boolean hasNationalPrefix;
@ -656,6 +678,11 @@ public final class Phonemetadata {
nationalPrefix_ = value;
return this;
}
public PhoneMetadata clearNationalPrefix() {
hasNationalPrefix = false;
nationalPrefix_ = "";
return this;
}
// optional string preferred_extn_prefix = 13;
private boolean hasPreferredExtnPrefix;
@ -667,6 +694,11 @@ public final class Phonemetadata {
preferredExtnPrefix_ = value;
return this;
}
public PhoneMetadata clearPreferredExtnPrefix() {
hasPreferredExtnPrefix = false;
preferredExtnPrefix_ = "";
return this;
}
// optional string national_prefix_for_parsing = 15;
private boolean hasNationalPrefixForParsing;
@ -689,6 +721,11 @@ public final class Phonemetadata {
nationalPrefixTransformRule_ = value;
return this;
}
public PhoneMetadata clearNationalPrefixTransformRule() {
hasNationalPrefixTransformRule = false;
nationalPrefixTransformRule_ = "";
return this;
}
// optional bool same_mobile_and_fixed_line_pattern = 18 [default = false];
private boolean hasSameMobileAndFixedLinePattern;
@ -700,6 +737,11 @@ public final class Phonemetadata {
sameMobileAndFixedLinePattern_ = value;
return this;
}
public PhoneMetadata clearSameMobileAndFixedLinePattern() {
hasSameMobileAndFixedLinePattern = false;
sameMobileAndFixedLinePattern_ = false;
return this;
}
// repeated NumberFormat number_format = 19;
private java.util.List<NumberFormat> numberFormat_ = new java.util.ArrayList<NumberFormat>();
@ -754,6 +796,11 @@ public final class Phonemetadata {
mainCountryForCode_ = value;
return this;
}
public PhoneMetadata clearMainCountryForCode() {
hasMainCountryForCode = false;
mainCountryForCode_ = false;
return this;
}
// optional string leading_digits = 23;
private boolean hasLeadingDigits;
@ -776,6 +823,11 @@ public final class Phonemetadata {
leadingZeroPossible_ = value;
return this;
}
public PhoneMetadata clearLeadingZeroPossible() {
hasLeadingZeroPossible = false;
leadingZeroPossible_ = false;
return this;
}
// optional bool mobile_number_portable_region = 32 [default = false];
private boolean hasMobileNumberPortableRegion;
@ -787,6 +839,11 @@ public final class Phonemetadata {
mobileNumberPortableRegion_ = value;
return this;
}
public PhoneMetadata clearMobileNumberPortableRegion() {
hasMobileNumberPortableRegion = false;
mobileNumberPortableRegion_ = false;
return this;
}
public void writeExternal(ObjectOutput objectOutput) throws IOException {
objectOutput.writeBoolean(hasGeneralDesc);


+ 6
- 2
java/libphonenumber/test/com/google/i18n/phonenumbers/CountryCodeToRegionCodeMapForTesting.java View File

@ -31,10 +31,10 @@ public class CountryCodeToRegionCodeMapForTesting {
// countries sharing a calling code, such as the NANPA countries, the one
// indicated with "isMainCountryForCode" in the metadata should be first.
static Map<Integer, List<String>> getCountryCodeToRegionCodeMap() {
// The capacity is set to 32 as there are 24 different entries,
// The capacity is set to 33 as there are 25 different entries,
// and this offers a load factor of roughly 0.75.
Map<Integer, List<String>> countryCodeToRegionCodeMap =
new HashMap<Integer, List<String>>(32);
new HashMap<Integer, List<String>>(33);
ArrayList<String> listWithRegionCode;
@ -121,6 +121,10 @@ public class CountryCodeToRegionCodeMapForTesting {
listWithRegionCode.add("YT");
countryCodeToRegionCodeMap.put(262, listWithRegionCode);
listWithRegionCode = new ArrayList<String>(1);
listWithRegionCode.add("AM");
countryCodeToRegionCodeMap.put(374, listWithRegionCode);
listWithRegionCode = new ArrayList<String>(1);
listWithRegionCode.add("BY");
countryCodeToRegionCodeMap.put(375, listWithRegionCode);


BIN
java/libphonenumber/test/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProtoForTesting_AM View File


+ 5
- 1
java/pending_code_changes.txt View File

@ -1 +1,5 @@
Internal changes:
- Fixed Phonemetadata.java not to merge from a NumberFormat's unset bool
national_prefix_optional_when_formatting.
- Added MetadataFilter, an internal API which is under development and subject
to backwards-incompatible changes without notice or guarantees.

+ 25
- 0
javascript/i18n/phonenumbers/metadatafortesting.js View File

@ -50,6 +50,7 @@ i18n.phonenumbers.metadata.countryCodeToRegionCodeMap = {
,86:["CN"]
,244:["AO"]
,262:["RE","YT"]
,374:["AM"]
,375:["BY"]
,376:["AD"]
,800:["001"]
@ -110,6 +111,30 @@ i18n.phonenumbers.metadata.countryToMetadata = {
,,,[,,"NA","NA",,,,,,[-1]
]
]
,"AM":[,[,,"[1-9]\\d{7}","\\d{5,8}",,,"10123456",,,[8]
,[5,6]
]
,[,,"[1-9]\\d{7}","\\d{5,8}",,,"10123456"]
,[,,"[1-9]\\d{7}","\\d{5,8}",,,"10123456"]
,[,,"NA","NA",,,,,,[-1]
]
,[,,"NA","NA",,,,,,[-1]
]
,[,,"NA","NA",,,,,,[-1]
]
,[,,"NA","NA",,,,,,[-1]
]
,[,,"NA","NA",,,,,,[-1]
]
,"AM",374,"00","0",,,"0",,,1,,,[,,"NA","NA",,,,,,[-1]
]
,,,[,,"NA","NA",,,,,,[-1]
]
,[,,"NA","NA",,,,,,[-1]
]
,,,[,,"NA","NA",,,,,,[-1]
]
]
,"AO":[,[,,"[29]\\d{8}","\\d{9}",,,,,,[9]
]
,[,,"2\\d(?:[26-9]\\d|\\d[26-9])\\d{5}","\\d{9}",,,"222123456"]


+ 23
- 0
resources/PhoneNumberMetadataForTesting.xml View File

@ -47,6 +47,29 @@
</uan>
</territory>
<!-- Armenia -->
<!-- Added to test same mobile and fixed-line in custom builds. -->
<territory id="AM" countryCode="374" internationalPrefix="00"
nationalPrefix="0">
<generalDesc>
<nationalNumberPattern>[1-9]\d{7}</nationalNumberPattern>
<possibleNumberPattern>\d{5,8}</possibleNumberPattern>
<exampleNumber>10123456</exampleNumber>
</generalDesc>
<fixedLine>
<nationalNumberPattern>[1-9]\d{7}</nationalNumberPattern>
<possibleNumberPattern>\d{5,8}</possibleNumberPattern>
<possibleLengths national="8" localOnly="5,6"/>
<exampleNumber>10123456</exampleNumber>
</fixedLine>
<mobile>
<nationalNumberPattern>[1-9]\d{7}</nationalNumberPattern>
<possibleNumberPattern>\d{5,8}</possibleNumberPattern>
<possibleLengths national="8" localOnly="5,6"/>
<exampleNumber>10123456</exampleNumber>
</mobile>
</territory>
<!-- Angola -->
<!-- This country has been coopted to test the case of a national prefix with a non-numeric
symbol in it. It is also useful since it has no national prefix formatting rule. -->


+ 4
- 0
resources/phonemetadata.proto View File

@ -93,6 +93,8 @@ message NumberFormat {
optional string domestic_carrier_code_formatting_rule = 5;
}
// If you add, remove, or rename fields, or change their semantics, check if you
// should change the excludable field sets or the behavior in MetadataFilter.
message PhoneNumberDesc {
// The national_number_pattern is the pattern that a valid national
// significant number would match. This specifies information such as its
@ -136,6 +138,8 @@ message PhoneNumberDesc {
optional string example_number = 6;
}
// If you add, remove, or rename fields, or change their semantics, check if you
// should change the excludable field sets or the behavior in MetadataFilter.
message PhoneMetadata {
// The general_desc contains information which is a superset of descriptions
// for all types of phone numbers. If any element is missing in the


+ 70
- 58
tools/java/common/src/com/google/i18n/phonenumbers/BuildMetadataFromXml.java View File

@ -95,20 +95,30 @@ public class BuildMetadataFromXml {
// Build the PhoneMetadataCollection from the input XML file.
public static PhoneMetadataCollection buildPhoneMetadataCollection(String inputXmlFile,
boolean liteBuild) throws Exception {
boolean liteBuild, boolean specialBuild) throws Exception {
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = builderFactory.newDocumentBuilder();
File xmlFile = new File(inputXmlFile);
Document document = builder.parse(xmlFile);
// TODO: Look for other uses of these constants and possibly pull them out into a separate
// constants file.
boolean isShortNumberMetadata = inputXmlFile.contains("ShortNumberMetadata");
boolean isAlternateFormatsMetadata = inputXmlFile.contains("PhoneNumberAlternateFormats");
return buildPhoneMetadataCollection(document, liteBuild, specialBuild,
isShortNumberMetadata, isAlternateFormatsMetadata);
}
// @VisibleForTesting
static PhoneMetadataCollection buildPhoneMetadataCollection(Document document,
boolean liteBuild, boolean specialBuild, boolean isShortNumberMetadata,
boolean isAlternateFormatsMetadata) throws Exception {
document.getDocumentElement().normalize();
Element rootElement = document.getDocumentElement();
NodeList territory = rootElement.getElementsByTagName("territory");
PhoneMetadataCollection.Builder metadataCollection = PhoneMetadataCollection.newBuilder();
int numOfTerritories = territory.getLength();
// TODO: Look for other uses of these constants and possibly pull them out into a separate
// constants file.
boolean isShortNumberMetadata = inputXmlFile.contains("ShortNumberMetadata");
boolean isAlternateFormatsMetadata = inputXmlFile.contains("PhoneNumberAlternateFormats");
// TODO: Infer filter from a single flag.
MetadataFilter metadataFilter = getMetadataFilter(liteBuild, specialBuild);
for (int i = 0; i < numOfTerritories; i++) {
Element territoryElement = (Element) territory.item(i);
String regionCode = "";
@ -117,8 +127,9 @@ public class BuildMetadataFromXml {
if (territoryElement.hasAttribute("id")) {
regionCode = territoryElement.getAttribute("id");
}
PhoneMetadata metadata = loadCountryMetadata(regionCode, territoryElement, liteBuild,
PhoneMetadata.Builder metadata = loadCountryMetadata(regionCode, territoryElement,
isShortNumberMetadata, isAlternateFormatsMetadata);
metadataFilter.filterMetadata(metadata);
metadataCollection.addMetadata(metadata);
}
return metadataCollection.build();
@ -434,8 +445,7 @@ public class BuildMetadataFromXml {
// @VisibleForTesting
static PhoneNumberDesc.Builder processPhoneNumberDescElement(PhoneNumberDesc parentDesc,
Element countryElement,
String numberType,
boolean liteBuild) {
String numberType) {
NodeList phoneNumberDescList = countryElement.getElementsByTagName(numberType);
PhoneNumberDesc.Builder numberDesc = PhoneNumberDesc.newBuilder();
if (phoneNumberDescList.getLength() == 0 && !numberTypeShouldAlwaysBeFilledIn(numberType)) {
@ -485,11 +495,9 @@ public class BuildMetadataFromXml {
validateRE(validPattern.item(0).getFirstChild().getNodeValue(), true));
}
if (!liteBuild) {
NodeList exampleNumber = element.getElementsByTagName(EXAMPLE_NUMBER);
if (exampleNumber.getLength() > 0) {
numberDesc.setExampleNumber(exampleNumber.item(0).getFirstChild().getNodeValue());
}
NodeList exampleNumber = element.getElementsByTagName(EXAMPLE_NUMBER);
if (exampleNumber.getLength() > 0) {
numberDesc.setExampleNumber(exampleNumber.item(0).getFirstChild().getNodeValue());
}
}
return numberDesc;
@ -497,9 +505,9 @@ public class BuildMetadataFromXml {
// @VisibleForTesting
static void setRelevantDescPatterns(PhoneMetadata.Builder metadata, Element element,
boolean liteBuild, boolean isShortNumberMetadata) {
PhoneNumberDesc.Builder generalDescBuilder =
processPhoneNumberDescElement(null, element, GENERAL_DESC, liteBuild);
boolean isShortNumberMetadata) {
PhoneNumberDesc.Builder generalDescBuilder = processPhoneNumberDescElement(null, element,
GENERAL_DESC);
// Calculate the possible lengths for the general description. This will be based on the
// possible lengths of the child elements.
setPossibleLengthsGeneralDesc(
@ -510,46 +518,30 @@ public class BuildMetadataFromXml {
if (!isShortNumberMetadata) {
// Set fields used by regular length phone numbers.
metadata.setFixedLine(
processPhoneNumberDescElement(generalDesc, element, FIXED_LINE, liteBuild));
metadata.setMobile(
processPhoneNumberDescElement(generalDesc, element, MOBILE, liteBuild));
metadata.setSharedCost(
processPhoneNumberDescElement(generalDesc, element, SHARED_COST, liteBuild));
metadata.setVoip(
processPhoneNumberDescElement(generalDesc, element, VOIP, liteBuild));
metadata.setPersonalNumber(
processPhoneNumberDescElement(generalDesc, element, PERSONAL_NUMBER, liteBuild));
metadata.setPager(
processPhoneNumberDescElement(generalDesc, element, PAGER, liteBuild));
metadata.setUan(
processPhoneNumberDescElement(generalDesc, element, UAN, liteBuild));
metadata.setVoicemail(
processPhoneNumberDescElement(generalDesc, element, VOICEMAIL, liteBuild));
metadata.setNoInternationalDialling(
processPhoneNumberDescElement(generalDesc, element, NO_INTERNATIONAL_DIALLING,
liteBuild));
metadata.setSameMobileAndFixedLinePattern(
metadata.getMobile().getNationalNumberPattern().equals(
metadata.getFixedLine().getNationalNumberPattern()));
metadata.setTollFree(
processPhoneNumberDescElement(generalDesc, element, TOLL_FREE, liteBuild));
metadata.setPremiumRate(
processPhoneNumberDescElement(generalDesc, element, PREMIUM_RATE, liteBuild));
metadata.setFixedLine(processPhoneNumberDescElement(generalDesc, element, FIXED_LINE));
metadata.setMobile(processPhoneNumberDescElement(generalDesc, element, MOBILE));
metadata.setSharedCost(processPhoneNumberDescElement(generalDesc, element, SHARED_COST));
metadata.setVoip(processPhoneNumberDescElement(generalDesc, element, VOIP));
metadata.setPersonalNumber(processPhoneNumberDescElement(generalDesc, element,
PERSONAL_NUMBER));
metadata.setPager(processPhoneNumberDescElement(generalDesc, element, PAGER));
metadata.setUan(processPhoneNumberDescElement(generalDesc, element, UAN));
metadata.setVoicemail(processPhoneNumberDescElement(generalDesc, element, VOICEMAIL));
metadata.setNoInternationalDialling(processPhoneNumberDescElement(generalDesc, element,
NO_INTERNATIONAL_DIALLING));
metadata.setSameMobileAndFixedLinePattern(metadata.getMobile().getNationalNumberPattern()
.equals(metadata.getFixedLine().getNationalNumberPattern()));
metadata.setTollFree(processPhoneNumberDescElement(generalDesc, element, TOLL_FREE));
metadata.setPremiumRate(processPhoneNumberDescElement(generalDesc, element, PREMIUM_RATE));
} else {
// Set fields used by short numbers.
metadata.setStandardRate(
processPhoneNumberDescElement(generalDesc, element, STANDARD_RATE, liteBuild));
metadata.setShortCode(
processPhoneNumberDescElement(generalDesc, element, SHORT_CODE, liteBuild));
metadata.setCarrierSpecific(
processPhoneNumberDescElement(generalDesc, element, CARRIER_SPECIFIC, liteBuild));
metadata.setEmergency(
processPhoneNumberDescElement(generalDesc, element, EMERGENCY, liteBuild));
metadata.setTollFree(
processPhoneNumberDescElement(generalDesc, element, TOLL_FREE, liteBuild));
metadata.setPremiumRate(
processPhoneNumberDescElement(generalDesc, element, PREMIUM_RATE, liteBuild));
metadata.setStandardRate(processPhoneNumberDescElement(generalDesc, element, STANDARD_RATE));
metadata.setShortCode(processPhoneNumberDescElement(generalDesc, element, SHORT_CODE));
metadata.setCarrierSpecific(processPhoneNumberDescElement(generalDesc, element,
CARRIER_SPECIFIC));
metadata.setEmergency(processPhoneNumberDescElement(generalDesc, element, EMERGENCY));
metadata.setTollFree(processPhoneNumberDescElement(generalDesc, element, TOLL_FREE));
metadata.setPremiumRate(processPhoneNumberDescElement(generalDesc, element, PREMIUM_RATE));
}
}
@ -759,9 +751,8 @@ public class BuildMetadataFromXml {
}
// @VisibleForTesting
static PhoneMetadata loadCountryMetadata(String regionCode,
static PhoneMetadata.Builder loadCountryMetadata(String regionCode,
Element element,
boolean liteBuild,
boolean isShortNumberMetadata,
boolean isAlternateFormatsMetadata) {
String nationalPrefix = getNationalPrefix(element);
@ -773,8 +764,29 @@ public class BuildMetadataFromXml {
element.hasAttribute(NATIONAL_PREFIX_OPTIONAL_WHEN_FORMATTING));
if (!isAlternateFormatsMetadata) {
// The alternate formats metadata does not need most of the patterns to be set.
setRelevantDescPatterns(metadata, element, liteBuild, isShortNumberMetadata);
setRelevantDescPatterns(metadata, element, isShortNumberMetadata);
}
return metadata;
}
/**
* Processes the custom build flags and gets a {@code MetadataFilter} which may be used to
* filter {@code PhoneMetadata} objects. Incompatible flag combinations throw RuntimeException.
*
* @param liteBuild The liteBuild flag value as given by the command-line
* @param specialBuild The specialBuild flag value as given by the command-line
*/
// @VisibleForTesting
static MetadataFilter getMetadataFilter(boolean liteBuild, boolean specialBuild) {
if (specialBuild) {
if (liteBuild) {
throw new RuntimeException("liteBuild and specialBuild may not both be set");
}
return MetadataFilter.forSpecialBuild();
}
if (liteBuild) {
return MetadataFilter.forLiteBuild();
}
return metadata.build();
return MetadataFilter.emptyFilter();
}
}

+ 361
- 0
tools/java/common/src/com/google/i18n/phonenumbers/MetadataFilter.java View File

@ -0,0 +1,361 @@
/*
* Copyright (C) 2016 The Libphonenumber Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.i18n.phonenumbers;
import com.google.i18n.phonenumbers.Phonemetadata.PhoneMetadata;
import com.google.i18n.phonenumbers.Phonemetadata.PhoneNumberDesc;
import java.util.Arrays;
import java.util.Map;
import java.util.TreeMap;
import java.util.TreeSet;
/**
* Class to encapsulate the metadata filtering logic and restrict visibility into raw data
* structures.
*
* <p>
* WARNING: This is an internal API which is under development and subject to backwards-incompatible
* changes without notice. Any changes are not guaranteed to be reflected in the versioning scheme
* of the public API, nor in release notes.
*/
final class MetadataFilter {
// The following 3 sets comprise all the PhoneMetadata fields as defined at phonemetadata.proto
// which may be excluded from customized serializations of the binary metadata. Fields that are
// core to the library functionality may not be listed here.
// EXCLUDABLE_PARENT_FIELDS are PhoneMetadata fields of type PhoneNumberDesc.
// EXCLUDABLE_CHILD_FIELDS are PhoneNumberDesc fields of primitive type.
// EXCLUDABLE_CHILDLESS_FIELDS are PhoneMetadata fields of primitive type.
// Currently we support only one non-primitive type and the depth of the "family tree" is 2,
// meaning a field may have only direct descendants, who may not have descendants of their
// own. If this changes, the blacklist handling in this class should also change.
// @VisibleForTesting
static final TreeSet<String> EXCLUDABLE_PARENT_FIELDS = new TreeSet<String>(Arrays.asList(
"fixedLine",
"mobile",
"tollFree",
"premiumRate",
"sharedCost",
"personalNumber",
"voip",
"pager",
"uan",
"emergency",
"voicemail",
"shortCode",
"standardRate",
"carrierSpecific",
"noInternationalDialling"));
// @VisibleForTesting
static final TreeSet<String> EXCLUDABLE_CHILD_FIELDS = new TreeSet<String>(Arrays.asList(
"nationalNumberPattern",
"possibleNumberPattern",
"possibleLength",
"possibleLengthLocalOnly",
"exampleNumber"));
// @VisibleForTesting
static final TreeSet<String> EXCLUDABLE_CHILDLESS_FIELDS = new TreeSet<String>(Arrays.asList(
"preferredInternationalPrefix",
"nationalPrefix",
"preferredExtnPrefix",
"nationalPrefixTransformRule",
"sameMobileAndFixedLinePattern",
"mainCountryForCode",
"leadingZeroPossible",
"mobileNumberPortableRegion"));
private final TreeMap<String, TreeSet<String>> blacklist;
static MetadataFilter forLiteBuild() {
// "exampleNumber" is a blacklist.
return new MetadataFilter(parseFieldMapFromString("exampleNumber"));
}
static MetadataFilter forSpecialBuild() {
// "mobile" is a whitelist.
return new MetadataFilter(computeComplement(parseFieldMapFromString("mobile")));
}
static MetadataFilter emptyFilter() {
// Empty blacklist, meaning we filter nothing.
return new MetadataFilter(new TreeMap<String, TreeSet<String>>());
}
// @VisibleForTesting
MetadataFilter(TreeMap<String, TreeSet<String>> blacklist) {
this.blacklist = blacklist;
}
@Override
public boolean equals(Object obj) {
return blacklist.equals(((MetadataFilter) obj).blacklist);
}
@Override
public int hashCode() {
return blacklist.hashCode();
}
/**
* Clears certain fields in {@code metadata} as defined by the {@code MetadataFilter} instance.
* Note that this changes the mutable {@code metadata} object, and is not thread-safe. If this
* method does not return successfully, do not assume {@code metadata} has not changed.
*
* @param metadata The {@code PhoneMetadata} object to be filtered
*/
void filterMetadata(PhoneMetadata.Builder metadata) {
// TODO: Resolve same as other fields in the filter.
if (!blacklist.isEmpty() && metadata.hasGeneralDesc()) {
PhoneNumberDesc.Builder builder =
PhoneNumberDesc.newBuilder().mergeFrom(metadata.getGeneralDesc());
builder.clearExampleNumber();
metadata.setGeneralDesc(builder);
}
// TODO: Consider clearing if the filtered PhoneNumberDesc is empty.
if (metadata.hasFixedLine()) {
metadata.setFixedLine(getFiltered("fixedLine", metadata.getFixedLine()));
}
if (metadata.hasMobile()) {
metadata.setMobile(getFiltered("mobile", metadata.getMobile()));
}
if (metadata.hasTollFree()) {
metadata.setTollFree(getFiltered("tollFree", metadata.getTollFree()));
}
if (metadata.hasPremiumRate()) {
metadata.setPremiumRate(getFiltered("premiumRate", metadata.getPremiumRate()));
}
if (metadata.hasSharedCost()) {
metadata.setSharedCost(getFiltered("sharedCost", metadata.getSharedCost()));
}
if (metadata.hasPersonalNumber()) {
metadata.setPersonalNumber(getFiltered("personalNumber", metadata.getPersonalNumber()));
}
if (metadata.hasVoip()) {
metadata.setVoip(getFiltered("voip", metadata.getVoip()));
}
if (metadata.hasPager()) {
metadata.setPager(getFiltered("pager", metadata.getPager()));
}
if (metadata.hasUan()) {
metadata.setUan(getFiltered("uan", metadata.getUan()));
}
if (metadata.hasEmergency()) {
metadata.setEmergency(getFiltered("emergency", metadata.getEmergency()));
}
if (metadata.hasVoicemail()) {
metadata.setVoicemail(getFiltered("voicemail", metadata.getVoicemail()));
}
if (metadata.hasShortCode()) {
metadata.setShortCode(getFiltered("shortCode", metadata.getShortCode()));
}
if (metadata.hasStandardRate()) {
metadata.setStandardRate(getFiltered("standardRate", metadata.getStandardRate()));
}
if (metadata.hasCarrierSpecific()) {
metadata.setCarrierSpecific(getFiltered("carrierSpecific", metadata.getCarrierSpecific()));
}
if (metadata.hasNoInternationalDialling()) {
metadata.setNoInternationalDialling(getFiltered("noInternationalDialling", metadata.getNoInternationalDialling()));
}
if (drop("preferredInternationalPrefix")) {
metadata.clearPreferredInternationalPrefix();
}
if (drop("nationalPrefix")) {
metadata.clearNationalPrefix();
}
if (drop("preferredExtnPrefix")) {
metadata.clearPreferredExtnPrefix();
}
if (drop("nationalPrefixTransformRule")) {
metadata.clearNationalPrefixTransformRule();
}
if (drop("sameMobileAndFixedLinePattern")) {
metadata.clearSameMobileAndFixedLinePattern();
}
if (drop("mainCountryForCode")) {
metadata.clearMainCountryForCode();
}
if (drop("leadingZeroPossible")) {
metadata.clearLeadingZeroPossible();
}
if (drop("mobileNumberPortableRegion")) {
metadata.clearMobileNumberPortableRegion();
}
}
/**
* The input blacklist or whitelist string is expected to be of the form "a(b,c):d(e):f", where
* b and c are children of a, e is a child of d, and f is either a parent field, a child field, or
* a childless field. Order and whitespace don't matter. We throw RuntimeException for any
* duplicates, malformed strings, or strings where field tokens do not correspond to strings in
* the sets of excludable fields. We also throw RuntimeException for empty strings since such
* strings should be treated as a special case by the flag checking code and not passed here.
*/
// @VisibleForTesting
static TreeMap<String, TreeSet<String>> parseFieldMapFromString(String string) {
if (string == null) {
throw new RuntimeException("Null string should not be passed to parseFieldMapFromString");
}
// Remove whitespace.
string = string.replaceAll("\\s", "");
if (string.isEmpty()) {
throw new RuntimeException("Empty string should not be passed to parseFieldMapFromString");
}
TreeMap<String, TreeSet<String>> fieldMap = new TreeMap<String, TreeSet<String>>();
TreeSet<String> wildcardChildren = new TreeSet<String>();
for (String group : string.split(":", -1)) {
int leftParenIndex = group.indexOf('(');
int rightParenIndex = group.indexOf(')');
if (leftParenIndex < 0 && rightParenIndex < 0) {
if (EXCLUDABLE_PARENT_FIELDS.contains(group)) {
if (fieldMap.containsKey(group)) {
throw new RuntimeException(group + " given more than once in " + string);
}
fieldMap.put(group, new TreeSet<String>(EXCLUDABLE_CHILD_FIELDS));
} else if (EXCLUDABLE_CHILDLESS_FIELDS.contains(group)) {
if (fieldMap.containsKey(group)) {
throw new RuntimeException(group + " given more than once in " + string);
}
fieldMap.put(group, new TreeSet<String>());
} else if (EXCLUDABLE_CHILD_FIELDS.contains(group)) {
if (wildcardChildren.contains(group)) {
throw new RuntimeException(group + " given more than once in " + string);
}
wildcardChildren.add(group);
} else {
throw new RuntimeException(group + " is not a valid token");
}
} else if (leftParenIndex > 0 && rightParenIndex == group.length() - 1) {
// We don't check for duplicate parentheses or illegal characters since these will be caught
// as not being part of valid field tokens.
String parent = group.substring(0, leftParenIndex);
if (!EXCLUDABLE_PARENT_FIELDS.contains(parent)) {
throw new RuntimeException(parent + " is not a valid parent token");
}
if (fieldMap.containsKey(parent)) {
throw new RuntimeException(parent + " given more than once in " + string);
}
TreeSet<String> children = new TreeSet<String>();
for (String child : group.substring(leftParenIndex + 1, rightParenIndex).split(",", -1)) {
if (!EXCLUDABLE_CHILD_FIELDS.contains(child)) {
throw new RuntimeException(child + " is not a valid child token");
}
if (!children.add(child)) {
throw new RuntimeException(child + " given more than once in " + group);
}
}
fieldMap.put(parent, children);
} else {
throw new RuntimeException("Incorrect location of parantheses in " + group);
}
}
for (String wildcardChild : wildcardChildren) {
for (String parent : EXCLUDABLE_PARENT_FIELDS) {
TreeSet<String> children = fieldMap.get(parent);
if (children == null) {
children = new TreeSet<String>();
fieldMap.put(parent, children);
}
if (!children.add(wildcardChild)
&& fieldMap.get(parent).size() != EXCLUDABLE_CHILD_FIELDS.size()) {
// The map already contains parent -> wildcardChild but not all possible children.
// So wildcardChild was given explicitly as a child of parent, which is a duplication
// since it's also given as a wildcard child.
throw new RuntimeException(
wildcardChild + " is present by itself so remove it from " + parent + "'s group");
}
}
}
return fieldMap;
}
// Does not check that legal tokens are used, assuming that fieldMap is constructed using
// parseFieldMapFromString(String) which does check. If fieldMap contains illegal tokens or parent
// fields with no children or other unexpected state, the behavior of this function is undefined.
// @VisibleForTesting
static TreeMap<String, TreeSet<String>> computeComplement(
TreeMap<String, TreeSet<String>> fieldMap) {
TreeMap<String, TreeSet<String>> complement = new TreeMap<String, TreeSet<String>>();
for (String parent : EXCLUDABLE_PARENT_FIELDS) {
if (!fieldMap.containsKey(parent)) {
complement.put(parent, new TreeSet<String>(EXCLUDABLE_CHILD_FIELDS));
} else {
TreeSet<String> otherChildren = fieldMap.get(parent);
// If the other map has all the children for this parent then we don't want to include the
// parent as a key.
if (otherChildren.size() != EXCLUDABLE_CHILD_FIELDS.size()) {
TreeSet<String> children = new TreeSet<String>();
for (String child : EXCLUDABLE_CHILD_FIELDS) {
if (!otherChildren.contains(child)) {
children.add(child);
}
}
complement.put(parent, children);
}
}
}
for (String childlessField : EXCLUDABLE_CHILDLESS_FIELDS) {
if (!fieldMap.containsKey(childlessField)) {
complement.put(childlessField, new TreeSet<String>());
}
}
return complement;
}
// @VisibleForTesting
boolean drop(String parent, String child) {
if (!EXCLUDABLE_PARENT_FIELDS.contains(parent)) {
throw new RuntimeException(parent + " is not an excludable parent field");
}
if (!EXCLUDABLE_CHILD_FIELDS.contains(child)) {
throw new RuntimeException(child + " is not an excludable child field");
}
return blacklist.containsKey(parent) && blacklist.get(parent).contains(child);
}
// @VisibleForTesting
boolean drop(String childlessField) {
if (!EXCLUDABLE_CHILDLESS_FIELDS.contains(childlessField)) {
throw new RuntimeException(childlessField + " is not an excludable childless field");
}
return blacklist.containsKey(childlessField);
}
private PhoneNumberDesc getFiltered(String type, PhoneNumberDesc desc) {
PhoneNumberDesc.Builder builder = PhoneNumberDesc.newBuilder().mergeFrom(desc);
if (drop(type, "nationalNumberPattern")) {
builder.clearNationalNumberPattern();
}
if (drop(type, "possibleNumberPattern")) {
builder.clearPossibleNumberPattern();
}
if (drop(type, "possibleLength")) {
builder.clearPossibleLength();
}
if (drop(type, "possibleLengthLocalOnly")) {
builder.clearPossibleLengthLocalOnly();
}
if (drop(type, "exampleNumber")) {
builder.clearExampleNumber();
}
return builder.build();
}
}

+ 179
- 39
tools/java/common/test/com/google/i18n/phonenumbers/BuildMetadataFromXmlTest.java View File

@ -18,6 +18,7 @@ package com.google.i18n.phonenumbers;
import com.google.i18n.phonenumbers.Phonemetadata.NumberFormat;
import com.google.i18n.phonenumbers.Phonemetadata.PhoneMetadata;
import com.google.i18n.phonenumbers.Phonemetadata.PhoneMetadataCollection;
import com.google.i18n.phonenumbers.Phonemetadata.PhoneNumberDesc;
import java.io.IOException;
import java.io.StringReader;
@ -27,6 +28,7 @@ import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import junit.framework.TestCase;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
@ -446,7 +448,7 @@ public class BuildMetadataFromXmlTest extends TestCase {
PhoneNumberDesc.Builder phoneNumberDesc;
phoneNumberDesc = BuildMetadataFromXml.processPhoneNumberDescElement(
generalDesc, territoryElement, "invalidType", false);
generalDesc, territoryElement, "invalidType");
assertEquals("NA", phoneNumberDesc.getPossibleNumberPattern());
assertEquals("NA", phoneNumberDesc.getNationalNumberPattern());
}
@ -459,7 +461,7 @@ public class BuildMetadataFromXmlTest extends TestCase {
PhoneNumberDesc.Builder phoneNumberDesc;
phoneNumberDesc = BuildMetadataFromXml.processPhoneNumberDescElement(
generalDesc, territoryElement, "fixedLine", false);
generalDesc, territoryElement, "fixedLine");
assertEquals("\\d{6}", phoneNumberDesc.getPossibleNumberPattern());
}
@ -474,22 +476,150 @@ public class BuildMetadataFromXmlTest extends TestCase {
PhoneNumberDesc.Builder phoneNumberDesc;
phoneNumberDesc = BuildMetadataFromXml.processPhoneNumberDescElement(
generalDesc, territoryElement, "fixedLine", false);
generalDesc, territoryElement, "fixedLine");
assertEquals("\\d{6}", phoneNumberDesc.getPossibleNumberPattern());
}
public void testProcessPhoneNumberDescElementHandlesLiteBuild()
throws ParserConfigurationException, SAXException, IOException {
PhoneNumberDesc.Builder generalDesc = PhoneNumberDesc.newBuilder();
String xmlInput = "<territory><fixedLine>"
+ " <exampleNumber>01 01 01 01</exampleNumber>"
+ "</fixedLine></territory>";
Element territoryElement = parseXmlString(xmlInput);
PhoneNumberDesc.Builder phoneNumberDesc;
public void testFilterMetadata_liteBuild() throws Exception {
String xmlInput =
"<phoneNumberMetadata>"
+ " <territories>"
+ " <territory id=\"AM\" countryCode=\"374\" internationalPrefix=\"00\">"
+ " <generalDesc>"
+ " <nationalNumberPattern>[1-9]\\d{7}</nationalNumberPattern>"
+ " <possibleNumberPattern>\\d{5,8}</possibleNumberPattern>"
+ " <exampleNumber>10123456</exampleNumber>"
+ " </generalDesc>"
+ " <fixedLine>"
+ " <nationalNumberPattern>[1-9]\\d{7}</nationalNumberPattern>"
+ " <possibleNumberPattern>\\d{5,8}</possibleNumberPattern>"
+ " <possibleLengths national=\"8\" localOnly=\"5,6\"/>"
+ " <exampleNumber>10123456</exampleNumber>"
+ " </fixedLine>"
+ " <mobile>"
+ " <nationalNumberPattern>[1-9]\\d{7}</nationalNumberPattern>"
+ " <possibleNumberPattern>\\d{5,8}</possibleNumberPattern>"
+ " <possibleLengths national=\"8\" localOnly=\"5,6\"/>"
+ " <exampleNumber>10123456</exampleNumber>"
+ " </mobile>"
+ " </territory>"
+ " </territories>"
+ "</phoneNumberMetadata>";
Document document = parseXmlString(xmlInput).getOwnerDocument();
PhoneMetadataCollection metadataCollection = BuildMetadataFromXml.buildPhoneMetadataCollection(
document,
true, // liteBuild
false, // specialBuild
false, // isShortNumberMetadata
false); // isAlternateFormatsMetadata
assertTrue(metadataCollection.getMetadataCount() == 1);
PhoneMetadata metadata = metadataCollection.getMetadataList().get(0);
assertTrue(metadata.hasGeneralDesc());
assertFalse(metadata.getGeneralDesc().hasExampleNumber());
assertEquals("", metadata.getGeneralDesc().getExampleNumber());
assertTrue(metadata.hasFixedLine());
assertFalse(metadata.getFixedLine().hasExampleNumber());
assertEquals("", metadata.getFixedLine().getExampleNumber());
assertTrue(metadata.hasMobile());
assertFalse(metadata.getMobile().hasExampleNumber());
assertEquals("", metadata.getMobile().getExampleNumber());
}
phoneNumberDesc = BuildMetadataFromXml.processPhoneNumberDescElement(
generalDesc, territoryElement, "fixedLine", true);
assertEquals("", phoneNumberDesc.getExampleNumber());
public void testFilterMetadata_specialBuild() throws Exception {
String xmlInput =
"<phoneNumberMetadata>"
+ " <territories>"
+ " <territory id=\"AM\" countryCode=\"374\" internationalPrefix=\"00\">"
+ " <generalDesc>"
+ " <nationalNumberPattern>[1-9]\\d{7}</nationalNumberPattern>"
+ " <possibleNumberPattern>\\d{5,8}</possibleNumberPattern>"
+ " <exampleNumber>10123456</exampleNumber>"
+ " </generalDesc>"
+ " <fixedLine>"
+ " <nationalNumberPattern>[1-9]\\d{7}</nationalNumberPattern>"
+ " <possibleNumberPattern>\\d{5,8}</possibleNumberPattern>"
+ " <possibleLengths national=\"8\" localOnly=\"5,6\"/>"
+ " <exampleNumber>10123456</exampleNumber>"
+ " </fixedLine>"
+ " <mobile>"
+ " <nationalNumberPattern>[1-9]\\d{7}</nationalNumberPattern>"
+ " <possibleNumberPattern>\\d{5,8}</possibleNumberPattern>"
+ " <possibleLengths national=\"8\" localOnly=\"5,6\"/>"
+ " <exampleNumber>10123456</exampleNumber>"
+ " </mobile>"
+ " </territory>"
+ " </territories>"
+ "</phoneNumberMetadata>";
Document document = parseXmlString(xmlInput).getOwnerDocument();
PhoneMetadataCollection metadataCollection = BuildMetadataFromXml.buildPhoneMetadataCollection(
document,
false, // liteBuild
true, // specialBuild
false, // isShortNumberMetadata
false); // isAlternateFormatsMetadata
assertTrue(metadataCollection.getMetadataCount() == 1);
PhoneMetadata metadata = metadataCollection.getMetadataList().get(0);
assertTrue(metadata.hasGeneralDesc());
assertFalse(metadata.getGeneralDesc().hasExampleNumber());
assertEquals("", metadata.getGeneralDesc().getExampleNumber());
// TODO: Consider clearing fixed-line if empty after being filtered.
assertTrue(metadata.hasFixedLine());
assertFalse(metadata.getFixedLine().hasExampleNumber());
assertEquals("", metadata.getFixedLine().getExampleNumber());
assertTrue(metadata.hasMobile());
assertTrue(metadata.getMobile().hasExampleNumber());
assertEquals("10123456", metadata.getMobile().getExampleNumber());
}
public void testFilterMetadata_fullBuild() throws Exception {
String xmlInput =
"<phoneNumberMetadata>"
+ " <territories>"
+ " <territory id=\"AM\" countryCode=\"374\" internationalPrefix=\"00\">"
+ " <generalDesc>"
+ " <nationalNumberPattern>[1-9]\\d{7}</nationalNumberPattern>"
+ " <possibleNumberPattern>\\d{5,8}</possibleNumberPattern>"
+ " <exampleNumber>10123456</exampleNumber>"
+ " </generalDesc>"
+ " <fixedLine>"
+ " <nationalNumberPattern>[1-9]\\d{7}</nationalNumberPattern>"
+ " <possibleNumberPattern>\\d{5,8}</possibleNumberPattern>"
+ " <possibleLengths national=\"8\" localOnly=\"5,6\"/>"
+ " <exampleNumber>10123456</exampleNumber>"
+ " </fixedLine>"
+ " <mobile>"
+ " <nationalNumberPattern>[1-9]\\d{7}</nationalNumberPattern>"
+ " <possibleNumberPattern>\\d{5,8}</possibleNumberPattern>"
+ " <possibleLengths national=\"8\" localOnly=\"5,6\"/>"
+ " <exampleNumber>10123456</exampleNumber>"
+ " </mobile>"
+ " </territory>"
+ " </territories>"
+ "</phoneNumberMetadata>";
Document document = parseXmlString(xmlInput).getOwnerDocument();
PhoneMetadataCollection metadataCollection = BuildMetadataFromXml.buildPhoneMetadataCollection(
document,
false, // liteBuild
false, // specialBuild
false, // isShortNumberMetadata
false); // isAlternateFormatsMetadata
assertTrue(metadataCollection.getMetadataCount() == 1);
PhoneMetadata metadata = metadataCollection.getMetadataList().get(0);
assertTrue(metadata.hasGeneralDesc());
assertTrue(metadata.getGeneralDesc().hasExampleNumber());
assertEquals("10123456", metadata.getGeneralDesc().getExampleNumber());
assertTrue(metadata.hasFixedLine());
assertTrue(metadata.getFixedLine().hasExampleNumber());
assertEquals("10123456", metadata.getFixedLine().getExampleNumber());
assertTrue(metadata.hasMobile());
assertTrue(metadata.getMobile().hasExampleNumber());
assertEquals("10123456", metadata.getMobile().getExampleNumber());
}
public void testProcessPhoneNumberDescOutputsExampleNumberByDefault()
@ -502,7 +632,7 @@ public class BuildMetadataFromXmlTest extends TestCase {
PhoneNumberDesc.Builder phoneNumberDesc;
phoneNumberDesc = BuildMetadataFromXml.processPhoneNumberDescElement(
generalDesc, territoryElement, "fixedLine", false);
generalDesc, territoryElement, "fixedLine");
assertEquals("01 01 01 01", phoneNumberDesc.getExampleNumber());
}
@ -516,7 +646,7 @@ public class BuildMetadataFromXmlTest extends TestCase {
PhoneNumberDesc.Builder phoneNumberDesc;
phoneNumberDesc = BuildMetadataFromXml.processPhoneNumberDescElement(
generalDesc, countryElement, "fixedLine", false);
generalDesc, countryElement, "fixedLine");
assertEquals("\\d{6}", phoneNumberDesc.getPossibleNumberPattern());
}
@ -530,7 +660,7 @@ public class BuildMetadataFromXmlTest extends TestCase {
Element territoryElement = parseXmlString(xmlInput);
PhoneMetadata.Builder metadata = PhoneMetadata.newBuilder();
// Should set sameMobileAndFixedPattern to true.
BuildMetadataFromXml.setRelevantDescPatterns(metadata, territoryElement, false /* liteBuild */,
BuildMetadataFromXml.setRelevantDescPatterns(metadata, territoryElement,
false /* isShortNumberMetadata */);
assertTrue(metadata.isSameMobileAndFixedLinePattern());
}
@ -550,7 +680,7 @@ public class BuildMetadataFromXmlTest extends TestCase {
+ "</territory>";
Element territoryElement = parseXmlString(xmlInput);
PhoneMetadata.Builder metadata = PhoneMetadata.newBuilder();
BuildMetadataFromXml.setRelevantDescPatterns(metadata, territoryElement, false /* liteBuild */,
BuildMetadataFromXml.setRelevantDescPatterns(metadata, territoryElement,
false /* isShortNumberMetadata */);
assertEquals("\\d{1}", metadata.getFixedLine().getNationalNumberPattern());
assertEquals("\\d{2}", metadata.getMobile().getNationalNumberPattern());
@ -576,7 +706,7 @@ public class BuildMetadataFromXmlTest extends TestCase {
+ "</territory>";
Element territoryElement = parseXmlString(xmlInput);
PhoneMetadata.Builder metadata = PhoneMetadata.newBuilder();
BuildMetadataFromXml.setRelevantDescPatterns(metadata, territoryElement, false /* liteBuild */,
BuildMetadataFromXml.setRelevantDescPatterns(metadata, territoryElement,
true /* isShortNumberMetadata */);
assertEquals("\\d{1}", metadata.getTollFree().getNationalNumberPattern());
assertEquals("\\d{2}", metadata.getStandardRate().getNationalNumberPattern());
@ -595,7 +725,7 @@ public class BuildMetadataFromXmlTest extends TestCase {
PhoneMetadata.Builder metadata = PhoneMetadata.newBuilder();
try {
BuildMetadataFromXml.setRelevantDescPatterns(metadata, territoryElement,
false /* liteBuild */, false /* isShortNumberMetadata */);
false /* isShortNumberMetadata */);
fail("Fixed-line info present twice for France: we should fail.");
} catch (RuntimeException expected) {
assertEquals("Multiple elements with type fixedLine found.", expected.getMessage());
@ -616,8 +746,7 @@ public class BuildMetadataFromXmlTest extends TestCase {
+ "</territory>";
Element territoryElement = parseXmlString(xmlInput);
PhoneMetadata metadata = BuildMetadataFromXml.loadCountryMetadata("FR", territoryElement,
false /* liteBuild */, false /* isShortNumberMetadata */,
true /* isAlternateFormatsMetadata */);
false /* isShortNumberMetadata */, true /* isAlternateFormatsMetadata */).build();
assertEquals("(1)(\\d{3})", metadata.getNumberFormat(0).getPattern());
assertEquals("1", metadata.getNumberFormat(0).getLeadingDigitsPattern(0));
assertEquals("$1", metadata.getNumberFormat(0).getFormat());
@ -645,8 +774,7 @@ public class BuildMetadataFromXmlTest extends TestCase {
+ "</territory>";
Element territoryElement = parseXmlString(xmlInput);
PhoneMetadata metadata = BuildMetadataFromXml.loadCountryMetadata("FR", territoryElement,
false /* liteBuild */, false /* isShortNumberMetadata */,
true /* isAlternateFormatsMetadata */);
false /* isShortNumberMetadata */, true /* isAlternateFormatsMetadata */).build();
assertTrue(metadata.getNumberFormat(0).isNationalPrefixOptionalWhenFormatting());
// This is inherited from the territory, with $NP replaced by the actual national prefix, and
// $FG replaced with $1.
@ -672,8 +800,7 @@ public class BuildMetadataFromXmlTest extends TestCase {
PhoneNumberDesc.Builder phoneNumberDesc;
phoneNumberDesc = BuildMetadataFromXml.processPhoneNumberDescElement(
generalDesc, territoryElement, "fixedLine",
false /* not light build */);
generalDesc, territoryElement, "fixedLine");
assertEquals(2, phoneNumberDesc.getPossibleLengthCount());
assertEquals(4, phoneNumberDesc.getPossibleLength(0));
assertEquals(13, phoneNumberDesc.getPossibleLength(1));
@ -779,8 +906,7 @@ public class BuildMetadataFromXmlTest extends TestCase {
+ "</territory>");
try {
BuildMetadataFromXml.processPhoneNumberDescElement(
generalDesc, territoryElement, "mobile", false /* not light build */);
BuildMetadataFromXml.processPhoneNumberDescElement(generalDesc, territoryElement, "mobile");
fail("Invalid data seen: expected failure.");
} catch (RuntimeException expected) {
// This should be an error, 6 is seen twice.
@ -800,8 +926,7 @@ public class BuildMetadataFromXmlTest extends TestCase {
+ "</territory>");
try {
BuildMetadataFromXml.processPhoneNumberDescElement(
generalDesc, territoryElement, "mobile", false /* not light build */);
BuildMetadataFromXml.processPhoneNumberDescElement(generalDesc, territoryElement, "mobile");
fail("Invalid data seen: expected failure.");
} catch (RuntimeException expected) {
// This should be an error, 6 is seen twice.
@ -821,7 +946,7 @@ public class BuildMetadataFromXmlTest extends TestCase {
+ "</territory>");
try {
BuildMetadataFromXml.processPhoneNumberDescElement(
generalDesc, territoryElement, "noInternationalDialling", false /* not light build */);
generalDesc, territoryElement, "noInternationalDialling");
fail("Lengths present not covered by the general desc: should fail.");
} catch (RuntimeException expected) {
// Lengths were present that the general description didn't know about.
@ -845,7 +970,7 @@ public class BuildMetadataFromXmlTest extends TestCase {
+ "</territory>");
PhoneNumberDesc.Builder phoneNumberDesc = BuildMetadataFromXml.processPhoneNumberDescElement(
generalDesc, territoryElement, "fixedLine", false /* not light build */);
generalDesc, territoryElement, "fixedLine");
// No possible lengths should be present, because they match the general description.
assertEquals(0, phoneNumberDesc.getPossibleLengthCount());
// No local-only lengths should be present for child elements such as fixed-line.
@ -863,7 +988,7 @@ public class BuildMetadataFromXmlTest extends TestCase {
try {
BuildMetadataFromXml.processPhoneNumberDescElement(
generalDesc, territoryElement, "fixedLine", false /* not light build */);
generalDesc, territoryElement, "fixedLine");
fail("4d is not a number.");
} catch (NumberFormatException expected) {
assertEquals("For input string: \"4d\"", expected.getMessage());
@ -882,7 +1007,7 @@ public class BuildMetadataFromXmlTest extends TestCase {
+ "</territory>");
try {
BuildMetadataFromXml.loadCountryMetadata("FR", territoryElement, false /* liteBuild */,
BuildMetadataFromXml.loadCountryMetadata("FR", territoryElement,
false /* isShortNumberMetadata */, false /* isAlternateFormatsMetadata */);
fail("Possible lengths explicitly set for generalDesc and should not be: we should fail.");
} catch (RuntimeException expected) {
@ -902,7 +1027,7 @@ public class BuildMetadataFromXmlTest extends TestCase {
+ "</territory>");
try {
BuildMetadataFromXml.processPhoneNumberDescElement(
generalDesc, territoryElement, "fixedLine", false /* not light build */);
generalDesc, territoryElement, "fixedLine");
fail("Empty possible length string.");
} catch (RuntimeException expected) {
assertEquals("Empty possibleLength string found.", expected.getMessage());
@ -920,7 +1045,7 @@ public class BuildMetadataFromXmlTest extends TestCase {
+ "</territory>");
try {
BuildMetadataFromXml.processPhoneNumberDescElement(
generalDesc, territoryElement, "fixedLine", false /* not light build */);
generalDesc, territoryElement, "fixedLine");
fail("Ranges shouldn't use a comma.");
} catch (RuntimeException expected) {
assertEquals("Missing end of range character in possible length string [4,7].",
@ -939,7 +1064,7 @@ public class BuildMetadataFromXmlTest extends TestCase {
try {
BuildMetadataFromXml.processPhoneNumberDescElement(
generalDesc, territoryElement, "fixedLine", false /* not light build */);
generalDesc, territoryElement, "fixedLine");
fail("Should fail: range incomplete.");
} catch (RuntimeException expected) {
assertEquals("Missing end of range character in possible length string [4-.",
@ -958,7 +1083,7 @@ public class BuildMetadataFromXmlTest extends TestCase {
try {
BuildMetadataFromXml.processPhoneNumberDescElement(
generalDesc, territoryElement, "fixedLine", false /* not light build */);
generalDesc, territoryElement, "fixedLine");
fail("Should fail: range incomplete.");
} catch (RuntimeException expected) {
assertEquals("Ranges must have exactly one - character: missing for [4:10].",
@ -977,11 +1102,26 @@ public class BuildMetadataFromXmlTest extends TestCase {
try {
BuildMetadataFromXml.processPhoneNumberDescElement(
generalDesc, territoryElement, "fixedLine", false /* not light build */);
generalDesc, territoryElement, "fixedLine");
fail("Should fail: range even.");
} catch (RuntimeException expected) {
assertEquals("The first number in a range should be two or more digits lower than the second."
+ " Culprit possibleLength string: [10-10]", expected.getMessage());
}
}
public void testGetMetadataFilter() {
assertEquals(BuildMetadataFromXml.getMetadataFilter(false, false),
MetadataFilter.emptyFilter());
assertEquals(BuildMetadataFromXml.getMetadataFilter(true, false),
MetadataFilter.forLiteBuild());
assertEquals(BuildMetadataFromXml.getMetadataFilter(false, true),
MetadataFilter.forSpecialBuild());
try {
BuildMetadataFromXml.getMetadataFilter(true, true);
fail("getMetadataFilter should fail when liteBuild and specialBuild are both set");
} catch (RuntimeException e) {
// Test passed.
}
}
}

+ 857
- 0
tools/java/common/test/com/google/i18n/phonenumbers/MetadataFilterTest.java View File

@ -0,0 +1,857 @@
/*
* Copyright (C) 2016 The Libphonenumber Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.i18n.phonenumbers;
import java.util.Arrays;
import java.util.TreeMap;
import java.util.TreeSet;
import junit.framework.TestCase;
public final class MetadataFilterTest extends TestCase {
// If this behavior changes then consider whether the change in the blacklist is intended, or you
// should change the special build configuration. Also look into any change in the size of the
// build.
public void testForLiteBuild() {
TreeMap<String, TreeSet<String>> blacklist = new TreeMap<String, TreeSet<String>>();
blacklist.put("fixedLine", new TreeSet<String>(Arrays.asList("exampleNumber")));
blacklist.put("mobile", new TreeSet<String>(Arrays.asList("exampleNumber")));
blacklist.put("tollFree", new TreeSet<String>(Arrays.asList("exampleNumber")));
blacklist.put("premiumRate", new TreeSet<String>(Arrays.asList("exampleNumber")));
blacklist.put("sharedCost", new TreeSet<String>(Arrays.asList("exampleNumber")));
blacklist.put("personalNumber", new TreeSet<String>(Arrays.asList("exampleNumber")));
blacklist.put("voip", new TreeSet<String>(Arrays.asList("exampleNumber")));
blacklist.put("pager", new TreeSet<String>(Arrays.asList("exampleNumber")));
blacklist.put("uan", new TreeSet<String>(Arrays.asList("exampleNumber")));
blacklist.put("emergency", new TreeSet<String>(Arrays.asList("exampleNumber")));
blacklist.put("voicemail", new TreeSet<String>(Arrays.asList("exampleNumber")));
blacklist.put("shortCode", new TreeSet<String>(Arrays.asList("exampleNumber")));
blacklist.put("standardRate", new TreeSet<String>(Arrays.asList("exampleNumber")));
blacklist.put("carrierSpecific", new TreeSet<String>(Arrays.asList("exampleNumber")));
blacklist.put("noInternationalDialling",
new TreeSet<String>(Arrays.asList("exampleNumber")));
assertEquals(MetadataFilter.forLiteBuild(), new MetadataFilter(blacklist));
}
// If this behavior changes then consider whether the change in the blacklist is intended, or you
// should change the special build configuration. Also look into any change in the size of the
// build.
public void testForSpecialBuild() {
TreeMap<String, TreeSet<String>> blacklist = new TreeMap<String, TreeSet<String>>();
blacklist.put("fixedLine", new TreeSet<String>(MetadataFilter.EXCLUDABLE_CHILD_FIELDS));
blacklist.put("tollFree", new TreeSet<String>(MetadataFilter.EXCLUDABLE_CHILD_FIELDS));
blacklist.put("premiumRate", new TreeSet<String>(MetadataFilter.EXCLUDABLE_CHILD_FIELDS));
blacklist.put("sharedCost", new TreeSet<String>(MetadataFilter.EXCLUDABLE_CHILD_FIELDS));
blacklist.put("personalNumber", new TreeSet<String>(MetadataFilter.EXCLUDABLE_CHILD_FIELDS));
blacklist.put("voip", new TreeSet<String>(MetadataFilter.EXCLUDABLE_CHILD_FIELDS));
blacklist.put("pager", new TreeSet<String>(MetadataFilter.EXCLUDABLE_CHILD_FIELDS));
blacklist.put("uan", new TreeSet<String>(MetadataFilter.EXCLUDABLE_CHILD_FIELDS));
blacklist.put("emergency", new TreeSet<String>(MetadataFilter.EXCLUDABLE_CHILD_FIELDS));
blacklist.put("voicemail", new TreeSet<String>(MetadataFilter.EXCLUDABLE_CHILD_FIELDS));
blacklist.put("shortCode", new TreeSet<String>(MetadataFilter.EXCLUDABLE_CHILD_FIELDS));
blacklist.put("standardRate", new TreeSet<String>(MetadataFilter.EXCLUDABLE_CHILD_FIELDS));
blacklist.put("carrierSpecific", new TreeSet<String>(MetadataFilter.EXCLUDABLE_CHILD_FIELDS));
blacklist.put("noInternationalDialling",
new TreeSet<String>(MetadataFilter.EXCLUDABLE_CHILD_FIELDS));
blacklist.put("preferredInternationalPrefix", new TreeSet<String>());
blacklist.put("nationalPrefix", new TreeSet<String>());
blacklist.put("preferredExtnPrefix", new TreeSet<String>());
blacklist.put("nationalPrefixTransformRule", new TreeSet<String>());
blacklist.put("sameMobileAndFixedLinePattern", new TreeSet<String>());
blacklist.put("mainCountryForCode", new TreeSet<String>());
blacklist.put("leadingZeroPossible", new TreeSet<String>());
blacklist.put("mobileNumberPortableRegion", new TreeSet<String>());
assertEquals(MetadataFilter.forSpecialBuild(), new MetadataFilter(blacklist));
}
public void testEmptyFilter() {
assertEquals(MetadataFilter.emptyFilter(),
new MetadataFilter(new TreeMap<String, TreeSet<String>>()));
}
public void testParseFieldMapFromString_parentAsGroup() {
TreeMap<String, TreeSet<String>> fieldMap = new TreeMap<String, TreeSet<String>>();
fieldMap.put("fixedLine", new TreeSet<String>(Arrays.asList(
"nationalNumberPattern", "possibleNumberPattern", "possibleLength",
"possibleLengthLocalOnly", "exampleNumber")));
assertEquals(MetadataFilter.parseFieldMapFromString("fixedLine"), fieldMap);
}
public void testParseFieldMapFromString_childAsGroup() {
TreeMap<String, TreeSet<String>> fieldMap = new TreeMap<String, TreeSet<String>>();
fieldMap.put("fixedLine", new TreeSet<String>(Arrays.asList("exampleNumber")));
fieldMap.put("mobile", new TreeSet<String>(Arrays.asList("exampleNumber")));
fieldMap.put("tollFree", new TreeSet<String>(Arrays.asList("exampleNumber")));
fieldMap.put("premiumRate", new TreeSet<String>(Arrays.asList("exampleNumber")));
fieldMap.put("sharedCost", new TreeSet<String>(Arrays.asList("exampleNumber")));
fieldMap.put("personalNumber", new TreeSet<String>(Arrays.asList("exampleNumber")));
fieldMap.put("voip", new TreeSet<String>(Arrays.asList("exampleNumber")));
fieldMap.put("pager", new TreeSet<String>(Arrays.asList("exampleNumber")));
fieldMap.put("uan", new TreeSet<String>(Arrays.asList("exampleNumber")));
fieldMap.put("emergency", new TreeSet<String>(Arrays.asList("exampleNumber")));
fieldMap.put("voicemail", new TreeSet<String>(Arrays.asList("exampleNumber")));
fieldMap.put("shortCode", new TreeSet<String>(Arrays.asList("exampleNumber")));
fieldMap.put("standardRate", new TreeSet<String>(Arrays.asList("exampleNumber")));
fieldMap.put("carrierSpecific", new TreeSet<String>(Arrays.asList("exampleNumber")));
fieldMap.put("noInternationalDialling", new TreeSet<String>(Arrays.asList("exampleNumber")));
assertEquals(MetadataFilter.parseFieldMapFromString("exampleNumber"), fieldMap);
}
public void testParseFieldMapFromString_childlessFieldAsGroup() {
TreeMap<String, TreeSet<String>> fieldMap = new TreeMap<String, TreeSet<String>>();
fieldMap.put("nationalPrefix", new TreeSet<String>());
assertEquals(MetadataFilter.parseFieldMapFromString("nationalPrefix"), fieldMap);
}
public void testParseFieldMapFromString_parentWithOneChildAsGroup() {
TreeMap<String, TreeSet<String>> fieldMap = new TreeMap<String, TreeSet<String>>();
fieldMap.put("fixedLine", new TreeSet<String>(Arrays.asList("exampleNumber")));
assertEquals(MetadataFilter.parseFieldMapFromString("fixedLine(exampleNumber)"), fieldMap);
}
public void testParseFieldMapFromString_parentWithTwoChildrenAsGroup() {
TreeMap<String, TreeSet<String>> fieldMap = new TreeMap<String, TreeSet<String>>();
fieldMap.put("fixedLine", new TreeSet<String>(Arrays.asList(
"exampleNumber", "possibleLength")));
assertEquals(
MetadataFilter.parseFieldMapFromString("fixedLine(exampleNumber,possibleLength)"),
fieldMap);
}
public void testParseFieldMapFromString_mixOfGroups() {
TreeMap<String, TreeSet<String>> fieldMap = new TreeMap<String, TreeSet<String>>();
fieldMap.put("uan", new TreeSet<String>(Arrays.asList(
"possibleLength", "exampleNumber", "possibleLengthLocalOnly",
"nationalNumberPattern")));
fieldMap.put("pager", new TreeSet<String>(Arrays.asList(
"exampleNumber", "nationalNumberPattern")));
fieldMap.put("fixedLine", new TreeSet<String>(Arrays.asList(
"nationalNumberPattern", "possibleNumberPattern", "possibleLength",
"possibleLengthLocalOnly", "exampleNumber")));
fieldMap.put("nationalPrefix", new TreeSet<String>());
fieldMap.put("mobile", new TreeSet<String>(Arrays.asList("nationalNumberPattern")));
fieldMap.put("tollFree", new TreeSet<String>(Arrays.asList("nationalNumberPattern")));
fieldMap.put("premiumRate", new TreeSet<String>(Arrays.asList("nationalNumberPattern")));
fieldMap.put("sharedCost", new TreeSet<String>(Arrays.asList("nationalNumberPattern")));
fieldMap.put("personalNumber", new TreeSet<String>(Arrays.asList("nationalNumberPattern")));
fieldMap.put("voip", new TreeSet<String>(Arrays.asList("nationalNumberPattern")));
fieldMap.put("emergency", new TreeSet<String>(Arrays.asList("nationalNumberPattern")));
fieldMap.put("voicemail", new TreeSet<String>(Arrays.asList("nationalNumberPattern")));
fieldMap.put("shortCode", new TreeSet<String>(Arrays.asList("nationalNumberPattern")));
fieldMap.put("standardRate", new TreeSet<String>(Arrays.asList("nationalNumberPattern")));
fieldMap.put("carrierSpecific", new TreeSet<String>(Arrays.asList("nationalNumberPattern")));
fieldMap.put("noInternationalDialling", new TreeSet<String>(Arrays.asList(
"nationalNumberPattern")));
assertEquals(MetadataFilter.parseFieldMapFromString(
"uan(possibleLength,exampleNumber,possibleLengthLocalOnly)"
+ ":pager(exampleNumber)"
+ ":fixedLine"
+ ":nationalPrefix"
+ ":nationalNumberPattern"),
fieldMap);
}
// Many of the strings in this test may be possible to express in shorter ways with the current
// sets of excludable fields, but their shortest representation changes as those sets change, as
// do their semantics; therefore we allow currently longer expressions, and we allow explicit
// listing of children, even if these are currently all the children.
public void testParseFieldMapFromString_equivalentExpressions() {
// Listing all excludable parent fields is equivalent to listing all excludable child fields.
assertEquals(
MetadataFilter.parseFieldMapFromString(
"fixedLine"
+ ":mobile"
+ ":tollFree"
+ ":premiumRate"
+ ":sharedCost"
+ ":personalNumber"
+ ":voip"
+ ":pager"
+ ":uan"
+ ":emergency"
+ ":voicemail"
+ ":shortCode"
+ ":standardRate"
+ ":carrierSpecific"
+ ":noInternationalDialling"),
MetadataFilter.parseFieldMapFromString(
"nationalNumberPattern"
+ ":possibleNumberPattern"
+ ":possibleLength"
+ ":possibleLengthLocalOnly"
+ ":exampleNumber"));
// Order and whitespace don't matter.
assertEquals(
MetadataFilter.parseFieldMapFromString(
" nationalNumberPattern "
+ ": uan ( exampleNumber , possibleLengthLocalOnly, possibleLength ) "
+ ": nationalPrefix "
+ ": fixedLine "
+ ": pager ( exampleNumber ) "),
MetadataFilter.parseFieldMapFromString(
"uan(possibleLength,exampleNumber,possibleLengthLocalOnly)"
+ ":pager(exampleNumber)"
+ ":fixedLine"
+ ":nationalPrefix"
+ ":nationalNumberPattern"));
// Parent explicitly listing all possible children.
assertEquals(
MetadataFilter.parseFieldMapFromString(
"uan(nationalNumberPattern,possibleNumberPattern,possibleLength,exampleNumber,"
+ "possibleLengthLocalOnly)"),
MetadataFilter.parseFieldMapFromString("uan"));
// All parent's children covered, some implicitly and some explicitly.
assertEquals(
MetadataFilter.parseFieldMapFromString(
"uan(nationalNumberPattern,possibleNumberPattern,possibleLength,exampleNumber)"
+ ":possibleLengthLocalOnly"),
MetadataFilter.parseFieldMapFromString("uan:possibleLengthLocalOnly"));
// Child field covered by all parents explicitly.
// It seems this will always be better expressed as a wildcard child, but the check is complex
// and may not be worth it.
assertEquals(
MetadataFilter.parseFieldMapFromString(
"fixedLine(exampleNumber)"
+ ":mobile(exampleNumber)"
+ ":tollFree(exampleNumber)"
+ ":premiumRate(exampleNumber)"
+ ":sharedCost(exampleNumber)"
+ ":personalNumber(exampleNumber)"
+ ":voip(exampleNumber)"
+ ":pager(exampleNumber)"
+ ":uan(exampleNumber)"
+ ":emergency(exampleNumber)"
+ ":voicemail(exampleNumber)"
+ ":shortCode(exampleNumber)"
+ ":standardRate(exampleNumber)"
+ ":carrierSpecific(exampleNumber)"
+ ":noInternationalDialling(exampleNumber)"),
MetadataFilter.parseFieldMapFromString("exampleNumber"));
// Child field given as a group by itself while it's covered by all parents implicitly.
// It seems this will always be better expressed without the wildcard child, but the check is
// complex and may not be worth it.
assertEquals(
MetadataFilter.parseFieldMapFromString(
"fixedLine"
+ ":mobile"
+ ":tollFree"
+ ":premiumRate"
+ ":sharedCost"
+ ":personalNumber"
+ ":voip"
+ ":pager"
+ ":uan"
+ ":emergency"
+ ":voicemail"
+ ":shortCode"
+ ":standardRate"
+ ":carrierSpecific"
+ ":noInternationalDialling"
+ ":exampleNumber"),
MetadataFilter.parseFieldMapFromString(
"fixedLine"
+ ":mobile"
+ ":tollFree"
+ ":premiumRate"
+ ":sharedCost"
+ ":personalNumber"
+ ":voip"
+ ":pager"
+ ":uan"
+ ":emergency"
+ ":voicemail"
+ ":shortCode"
+ ":standardRate"
+ ":carrierSpecific"
+ ":noInternationalDialling"));
}
public void testParseFieldMapFromString_RuntimeExceptionCases() {
// Null input.
try {
MetadataFilter.parseFieldMapFromString(null);
fail();
} catch (RuntimeException e) {
// Test passed.
}
// Empty input.
try {
MetadataFilter.parseFieldMapFromString("");
fail();
} catch (RuntimeException e) {
// Test passed.
}
// Whitespace input.
try {
MetadataFilter.parseFieldMapFromString(" ");
fail();
} catch (RuntimeException e) {
// Test passed.
}
// Bad token given as only group.
try {
MetadataFilter.parseFieldMapFromString("something_else");
fail();
} catch (RuntimeException e) {
// Test passed.
}
// Bad token given as last group.
try {
MetadataFilter.parseFieldMapFromString("fixedLine:something_else");
fail();
} catch (RuntimeException e) {
// Test passed.
}
// Bad token given as middle group.
try {
MetadataFilter.parseFieldMapFromString(
"pager:nationalPrefix:something_else:nationalNumberPattern");
fail();
} catch (RuntimeException e) {
// Test passed.
}
// Childless field given as parent.
try {
MetadataFilter.parseFieldMapFromString("nationalPrefix(exampleNumber)");
fail();
} catch (RuntimeException e) {
// Test passed.
}
// Child field given as parent.
try {
MetadataFilter.parseFieldMapFromString("possibleLength(exampleNumber)");
fail();
} catch (RuntimeException e) {
// Test passed.
}
// Bad token given as parent.
try {
MetadataFilter.parseFieldMapFromString("something_else(exampleNumber)");
fail();
} catch (RuntimeException e) {
// Test passed.
}
// Parent field given as only child.
try {
MetadataFilter.parseFieldMapFromString("fixedLine(uan)");
fail();
} catch (RuntimeException e) {
// Test passed.
}
// Parent field given as first child.
try {
MetadataFilter.parseFieldMapFromString("fixedLine(uan,possibleLength)");
fail();
} catch (RuntimeException e) {
// Test passed.
}
// Parent field given as last child.
try {
MetadataFilter.parseFieldMapFromString("fixedLine(possibleLength,uan)");
fail();
} catch (RuntimeException e) {
// Test passed.
}
// Parent field given as middle child.
try {
MetadataFilter.parseFieldMapFromString("fixedLine(possibleLength,uan,exampleNumber)");
fail();
} catch (RuntimeException e) {
// Test passed.
}
// Childless field given as only child.
try {
MetadataFilter.parseFieldMapFromString("fixedLine(nationalPrefix)");
fail();
} catch (RuntimeException e) {
// Test passed.
}
// Bad token given as only child.
try {
MetadataFilter.parseFieldMapFromString("fixedLine(something_else)");
fail();
} catch (RuntimeException e) {
// Test passed.
}
// Bad token given as last child.
try {
MetadataFilter.parseFieldMapFromString("uan(possibleLength,something_else)");
fail();
} catch (RuntimeException e) {
// Test passed.
}
// Empty parent.
try {
MetadataFilter.parseFieldMapFromString("(exampleNumber)");
fail();
} catch (RuntimeException e) {
// Test passed.
}
// Whitespace parent.
try {
MetadataFilter.parseFieldMapFromString(" (exampleNumber)");
fail();
} catch (RuntimeException e) {
// Test passed.
}
// Empty child.
try {
MetadataFilter.parseFieldMapFromString("fixedLine()");
fail();
} catch (RuntimeException e) {
// Test passed.
}
// Whitespace child.
try {
MetadataFilter.parseFieldMapFromString("fixedLine( )");
fail();
} catch (RuntimeException e) {
// Test passed.
}
// Empty parent and child.
try {
MetadataFilter.parseFieldMapFromString("()");
fail();
} catch (RuntimeException e) {
// Test passed.
}
// Whitespace parent and empty child.
try {
MetadataFilter.parseFieldMapFromString(" ()");
fail();
} catch (RuntimeException e) {
// Test passed.
}
// Parent field given as a group twice.
try {
MetadataFilter.parseFieldMapFromString("fixedLine:uan:fixedLine");
fail();
} catch (RuntimeException e) {
// Test passed.
}
// Parent field given as the parent of a group and as a group by itself.
try {
MetadataFilter.parseFieldMapFromString("fixedLine(exampleNumber):fixedLine");
fail();
} catch (RuntimeException e) {
// Test passed.
}
// Parent field given as the parent of one group and then as the parent of another group.
try {
MetadataFilter.parseFieldMapFromString("fixedLine(exampleNumber):fixedLine(possibleLength)");
fail();
} catch (RuntimeException e) {
// Test passed.
}
// Childless field given twice as a group.
try {
MetadataFilter.parseFieldMapFromString("nationalPrefix:uan:nationalPrefix");
fail();
} catch (RuntimeException e) {
// Test passed.
}
// Child field given twice as a group.
try {
MetadataFilter.parseFieldMapFromString("exampleNumber:uan:exampleNumber");
fail();
} catch (RuntimeException e) {
// Test passed.
}
// Child field given first as the only child in a group and then as a group by itself.
try {
MetadataFilter.parseFieldMapFromString("fixedLine(exampleNumber):exampleNumber");
fail();
} catch (RuntimeException e) {
// Test passed.
}
// Child field given first as a child in a group and then as a group by itself.
try {
MetadataFilter.parseFieldMapFromString(
"uan(nationalNumberPattern,possibleNumberPattern,possibleLength,exampleNumber)"
+ ":possibleLengthLocalOnly"
+ ":exampleNumber");
fail();
} catch (RuntimeException e) {
// Test passed.
}
// Child field given twice as children of the same parent.
try {
MetadataFilter.parseFieldMapFromString(
"fixedLine(possibleLength,exampleNumber,possibleLength)");
fail();
} catch (RuntimeException e) {
// Test passed.
}
// Child field given as a group by itself while it's covered by all parents explicitly.
try {
MetadataFilter.parseFieldMapFromString(
"fixedLine(exampleNumber)"
+ ":mobile(exampleNumber)"
+ ":tollFree(exampleNumber)"
+ ":premiumRate(exampleNumber)"
+ ":sharedCost(exampleNumber)"
+ ":personalNumber(exampleNumber)"
+ ":voip(exampleNumber)"
+ ":pager(exampleNumber)"
+ ":uan(exampleNumber)"
+ ":emergency(exampleNumber)"
+ ":voicemail(exampleNumber)"
+ ":shortCode(exampleNumber)"
+ ":standardRate(exampleNumber)"
+ ":carrierSpecific(exampleNumber)"
+ ":noInternationalDialling(exampleNumber)"
+ ":exampleNumber");
fail();
} catch (RuntimeException e) {
// Test passed.
}
// Child field given as a group by itself while it's covered by all parents, some implicitly and
// some explicitly.
try {
MetadataFilter.parseFieldMapFromString(
"fixedLine"
+ ":mobile"
+ ":tollFree"
+ ":premiumRate"
+ ":sharedCost"
+ ":personalNumber"
+ ":voip"
+ ":pager(exampleNumber)"
+ ":uan(exampleNumber)"
+ ":emergency(exampleNumber)"
+ ":voicemail(exampleNumber)"
+ ":shortCode(exampleNumber)"
+ ":standardRate(exampleNumber)"
+ ":carrierSpecific(exampleNumber)"
+ ":noInternationalDialling(exampleNumber)"
+ ":exampleNumber");
fail();
} catch (RuntimeException e) {
// Test passed.
}
// Missing right parenthesis in only group.
try {
MetadataFilter.parseFieldMapFromString("fixedLine(exampleNumber");
fail();
} catch (RuntimeException e) {
// Test passed.
}
// Missing right parenthesis in first group.
try {
MetadataFilter.parseFieldMapFromString("fixedLine(exampleNumber:pager");
fail();
} catch (RuntimeException e) {
// Test passed.
}
// Missing left parenthesis in only group.
try {
MetadataFilter.parseFieldMapFromString("fixedLineexampleNumber)");
fail();
} catch (RuntimeException e) {
// Test passed.
}
// Early right parenthesis in only group.
try {
MetadataFilter.parseFieldMapFromString("fixedLine(example_numb)er");
fail();
} catch (RuntimeException e) {
// Test passed.
}
// Extra right parenthesis at end of only group.
try {
MetadataFilter.parseFieldMapFromString("fixedLine(exampleNumber))");
fail();
} catch (RuntimeException e) {
// Test passed.
}
// Extra right parenthesis between proper parentheses.
try {
MetadataFilter.parseFieldMapFromString("fixedLine(example_numb)er)");
fail();
} catch (RuntimeException e) {
// Test passed.
}
// Extra left parenthesis in only group.
try {
MetadataFilter.parseFieldMapFromString("fixedLine((exampleNumber)");
fail();
} catch (RuntimeException e) {
// Test passed.
}
// Extra level of children.
try {
MetadataFilter.parseFieldMapFromString("fixedLine(exampleNumber(possibleLength))");
fail();
} catch (RuntimeException e) {
// Test passed.
}
// Trailing comma in children.
try {
MetadataFilter.parseFieldMapFromString("fixedLine(exampleNumber,)");
fail();
} catch (RuntimeException e) {
// Test passed.
}
// Leading comma in children.
try {
MetadataFilter.parseFieldMapFromString("fixedLine(,exampleNumber)");
fail();
} catch (RuntimeException e) {
// Test passed.
}
// Empty token between commas.
try {
MetadataFilter.parseFieldMapFromString("fixedLine(possibleLength,,exampleNumber)");
fail();
} catch (RuntimeException e) {
// Test passed.
}
// Trailing colon.
try {
MetadataFilter.parseFieldMapFromString("uan:");
fail();
} catch (RuntimeException e) {
// Test passed.
}
// Leading colon.
try {
MetadataFilter.parseFieldMapFromString(":uan");
fail();
} catch (RuntimeException e) {
// Test passed.
}
// Empty token between colons.
try {
MetadataFilter.parseFieldMapFromString("uan::fixedLine");
fail();
} catch (RuntimeException e) {
// Test passed.
}
// Missing colon between groups.
try {
MetadataFilter.parseFieldMapFromString("uan(possibleLength)pager");
fail();
} catch (RuntimeException e) {
// Test passed.
}
}
public void testComputeComplement_allAndNothing() {
TreeMap<String, TreeSet<String>> map1 = new TreeMap<String, TreeSet<String>>();
map1.put("fixedLine", new TreeSet<String>(MetadataFilter.EXCLUDABLE_CHILD_FIELDS));
map1.put("mobile", new TreeSet<String>(MetadataFilter.EXCLUDABLE_CHILD_FIELDS));
map1.put("tollFree", new TreeSet<String>(MetadataFilter.EXCLUDABLE_CHILD_FIELDS));
map1.put("premiumRate", new TreeSet<String>(MetadataFilter.EXCLUDABLE_CHILD_FIELDS));
map1.put("sharedCost", new TreeSet<String>(MetadataFilter.EXCLUDABLE_CHILD_FIELDS));
map1.put("personalNumber", new TreeSet<String>(MetadataFilter.EXCLUDABLE_CHILD_FIELDS));
map1.put("voip", new TreeSet<String>(MetadataFilter.EXCLUDABLE_CHILD_FIELDS));
map1.put("pager", new TreeSet<String>(MetadataFilter.EXCLUDABLE_CHILD_FIELDS));
map1.put("uan", new TreeSet<String>(MetadataFilter.EXCLUDABLE_CHILD_FIELDS));
map1.put("emergency", new TreeSet<String>(MetadataFilter.EXCLUDABLE_CHILD_FIELDS));
map1.put("voicemail", new TreeSet<String>(MetadataFilter.EXCLUDABLE_CHILD_FIELDS));
map1.put("shortCode", new TreeSet<String>(MetadataFilter.EXCLUDABLE_CHILD_FIELDS));
map1.put("standardRate", new TreeSet<String>(MetadataFilter.EXCLUDABLE_CHILD_FIELDS));
map1.put("carrierSpecific", new TreeSet<String>(MetadataFilter.EXCLUDABLE_CHILD_FIELDS));
map1.put("noInternationalDialling",
new TreeSet<String>(MetadataFilter.EXCLUDABLE_CHILD_FIELDS));
map1.put("preferredInternationalPrefix", new TreeSet<String>());
map1.put("nationalPrefix", new TreeSet<String>());
map1.put("preferredExtnPrefix", new TreeSet<String>());
map1.put("nationalPrefixTransformRule", new TreeSet<String>());
map1.put("sameMobileAndFixedLinePattern", new TreeSet<String>());
map1.put("mainCountryForCode", new TreeSet<String>());
map1.put("leadingZeroPossible", new TreeSet<String>());
map1.put("mobileNumberPortableRegion", new TreeSet<String>());
TreeMap<String, TreeSet<String>> map2 = new TreeMap<String, TreeSet<String>>();
assertEquals(MetadataFilter.computeComplement(map1), map2);
assertEquals(MetadataFilter.computeComplement(map2), map1);
}
public void testComputeComplement_inBetween() {
TreeMap<String, TreeSet<String>> map1 = new TreeMap<String, TreeSet<String>>();
map1.put("fixedLine", new TreeSet<String>(MetadataFilter.EXCLUDABLE_CHILD_FIELDS));
map1.put("mobile", new TreeSet<String>(MetadataFilter.EXCLUDABLE_CHILD_FIELDS));
map1.put("tollFree", new TreeSet<String>(MetadataFilter.EXCLUDABLE_CHILD_FIELDS));
map1.put("premiumRate", new TreeSet<String>(MetadataFilter.EXCLUDABLE_CHILD_FIELDS));
map1.put("emergency", new TreeSet<String>(Arrays.asList(
"nationalNumberPattern", "possibleNumberPattern")));
map1.put("voicemail", new TreeSet<String>(Arrays.asList("possibleLength", "exampleNumber")));
map1.put("shortCode", new TreeSet<String>(Arrays.asList("exampleNumber")));
map1.put("standardRate", new TreeSet<String>(MetadataFilter.EXCLUDABLE_CHILD_FIELDS));
map1.put("carrierSpecific", new TreeSet<String>(MetadataFilter.EXCLUDABLE_CHILD_FIELDS));
map1.put("noInternationalDialling",
new TreeSet<String>(MetadataFilter.EXCLUDABLE_CHILD_FIELDS));
map1.put("nationalPrefixTransformRule", new TreeSet<String>());
map1.put("sameMobileAndFixedLinePattern", new TreeSet<String>());
map1.put("mainCountryForCode", new TreeSet<String>());
map1.put("leadingZeroPossible", new TreeSet<String>());
map1.put("mobileNumberPortableRegion", new TreeSet<String>());
TreeMap<String, TreeSet<String>> map2 = new TreeMap<String, TreeSet<String>>();
map2.put("sharedCost", new TreeSet<String>(MetadataFilter.EXCLUDABLE_CHILD_FIELDS));
map2.put("personalNumber", new TreeSet<String>(MetadataFilter.EXCLUDABLE_CHILD_FIELDS));
map2.put("voip", new TreeSet<String>(MetadataFilter.EXCLUDABLE_CHILD_FIELDS));
map2.put("pager", new TreeSet<String>(MetadataFilter.EXCLUDABLE_CHILD_FIELDS));
map2.put("uan", new TreeSet<String>(MetadataFilter.EXCLUDABLE_CHILD_FIELDS));
map2.put("emergency", new TreeSet<String>(Arrays.asList(
"possibleLength", "possibleLengthLocalOnly", "exampleNumber")));
map2.put("voicemail", new TreeSet<String>(Arrays.asList(
"nationalNumberPattern", "possibleNumberPattern", "possibleLengthLocalOnly")));
map2.put("shortCode", new TreeSet<String>(Arrays.asList(
"nationalNumberPattern", "possibleNumberPattern", "possibleLength",
"possibleLengthLocalOnly")));
map2.put("preferredInternationalPrefix", new TreeSet<String>());
map2.put("nationalPrefix", new TreeSet<String>());
map2.put("preferredExtnPrefix", new TreeSet<String>());
assertEquals(MetadataFilter.computeComplement(map1), map2);
assertEquals(MetadataFilter.computeComplement(map2), map1);
}
public void testDrop() {
TreeMap<String, TreeSet<String>> blacklist = new TreeMap<String, TreeSet<String>>();
blacklist.put("fixedLine", new TreeSet<String>(MetadataFilter.EXCLUDABLE_CHILD_FIELDS));
blacklist.put("mobile", new TreeSet<String>(MetadataFilter.EXCLUDABLE_CHILD_FIELDS));
blacklist.put("tollFree", new TreeSet<String>(MetadataFilter.EXCLUDABLE_CHILD_FIELDS));
blacklist.put("premiumRate", new TreeSet<String>(MetadataFilter.EXCLUDABLE_CHILD_FIELDS));
blacklist.put("emergency", new TreeSet<String>(Arrays.asList(
"nationalNumberPattern", "possibleNumberPattern")));
blacklist.put("voicemail", new TreeSet<String>(Arrays.asList(
"possibleLength", "exampleNumber")));
blacklist.put("shortCode", new TreeSet<String>(Arrays.asList("exampleNumber")));
blacklist.put("standardRate", new TreeSet<String>(MetadataFilter.EXCLUDABLE_CHILD_FIELDS));
blacklist.put("carrierSpecific", new TreeSet<String>(MetadataFilter.EXCLUDABLE_CHILD_FIELDS));
blacklist.put("noInternationalDialling",
new TreeSet<String>(MetadataFilter.EXCLUDABLE_CHILD_FIELDS));
blacklist.put("nationalPrefixTransformRule", new TreeSet<String>());
blacklist.put("sameMobileAndFixedLinePattern", new TreeSet<String>());
blacklist.put("mainCountryForCode", new TreeSet<String>());
blacklist.put("leadingZeroPossible", new TreeSet<String>());
blacklist.put("mobileNumberPortableRegion", new TreeSet<String>());
MetadataFilter filter = new MetadataFilter(blacklist);
assertTrue(filter.drop("fixedLine", "exampleNumber"));
assertFalse(filter.drop("sharedCost", "exampleNumber"));
assertFalse(filter.drop("emergency", "exampleNumber"));
assertTrue(filter.drop("emergency", "nationalNumberPattern"));
assertFalse(filter.drop("preferredInternationalPrefix"));
assertTrue(filter.drop("mobileNumberPortableRegion"));
// Integration tests starting with flag values.
assertTrue(BuildMetadataFromXml.getMetadataFilter(true, false)
.drop("fixedLine", "exampleNumber"));
// Integration tests starting with blacklist strings.
assertTrue(new MetadataFilter(MetadataFilter.parseFieldMapFromString("fixedLine"))
.drop("fixedLine", "exampleNumber"));
assertFalse(new MetadataFilter(MetadataFilter.parseFieldMapFromString("uan"))
.drop("fixedLine", "exampleNumber"));
// Integration tests starting with whitelist strings.
assertFalse(new MetadataFilter(MetadataFilter.computeComplement(
MetadataFilter.parseFieldMapFromString("exampleNumber")))
.drop("fixedLine", "exampleNumber"));
assertTrue(new MetadataFilter(MetadataFilter.computeComplement(
MetadataFilter.parseFieldMapFromString("uan"))).drop("fixedLine", "exampleNumber"));
// Integration tests with an empty blacklist.
assertFalse(new MetadataFilter(new TreeMap<String, TreeSet<String>>())
.drop("fixedLine", "exampleNumber"));
}
public void testIntegrityOfFieldSets() {
TreeSet<String> union = new TreeSet<String>();
union.addAll(MetadataFilter.EXCLUDABLE_PARENT_FIELDS);
union.addAll(MetadataFilter.EXCLUDABLE_CHILD_FIELDS);
union.addAll(MetadataFilter.EXCLUDABLE_CHILDLESS_FIELDS);
// Mutually exclusive sets.
assertTrue(union.size() == MetadataFilter.EXCLUDABLE_PARENT_FIELDS.size()
+ MetadataFilter.EXCLUDABLE_CHILD_FIELDS.size()
+ MetadataFilter.EXCLUDABLE_CHILDLESS_FIELDS.size());
// Nonempty sets.
assertTrue(MetadataFilter.EXCLUDABLE_PARENT_FIELDS.size() > 0
&& MetadataFilter.EXCLUDABLE_CHILD_FIELDS.size() > 0
&& MetadataFilter.EXCLUDABLE_CHILDLESS_FIELDS.size() > 0);
// Nonempty and canonical field names.
for (String field : union) {
assertTrue(field.length() > 0 && field.trim().equals(field));
}
}
}

+ 2
- 1
tools/java/cpp-build/src/com/google/i18n/phonenumbers/BuildMetadataCppFromXml.java View File

@ -201,7 +201,8 @@ public class BuildMetadataCppFromXml extends Command {
// @VisibleForTesting
void writePhoneMetadataCollection(
String inputFilePath, boolean liteMetadata, OutputStream out) throws IOException, Exception {
BuildMetadataFromXml.buildPhoneMetadataCollection(inputFilePath, liteMetadata).writeTo(out);
BuildMetadataFromXml.buildPhoneMetadataCollection(inputFilePath, liteMetadata, false)
.writeTo(out);
}
// @VisibleForTesting


BIN
tools/java/cpp-build/target/cpp-build-1.0-SNAPSHOT-jar-with-dependencies.jar View File


+ 1
- 1
tools/java/java-build/src/com/google/i18n/phonenumbers/BuildMetadataJsonFromXml.java View File

@ -93,7 +93,7 @@ public class BuildMetadataJsonFromXml extends Command {
try {
PhoneMetadataCollection metadataCollection =
BuildMetadataFromXml.buildPhoneMetadataCollection(inputFile, liteBuild);
BuildMetadataFromXml.buildPhoneMetadataCollection(inputFile, liteBuild, false);
Map<Integer, List<String>> countryCodeToRegionCodeMap =
BuildMetadataFromXml.buildCountryCodeToRegionCodeMap(metadataCollection);


+ 9
- 1
tools/java/java-build/src/com/google/i18n/phonenumbers/BuildMetadataProtoFromXml.java View File

@ -38,6 +38,7 @@ import java.util.regex.Pattern;
/**
* Tool to convert phone number metadata from the XML format to protocol buffer format.
*
* <p>
* Based on the name of the {@code inputFile}, some optimization and removal of unnecessary metadata
* is carried out to reduce the size of the output file.
*
@ -55,6 +56,9 @@ public class BuildMetadataProtoFromXml extends Command {
private static final String COPYRIGHT = "copyright";
private static final String SINGLE_FILE = "single-file";
private static final String LITE_BUILD = "lite-build";
// Only supported for clients who have consulted with the libphonenumber team, and the behavior is
// subject to change without notice.
private static final String SPECIAL_BUILD = "special-build";
private static final String HELP_MESSAGE =
"Usage: " + CLASS_NAME + " [OPTION]...\n" +
@ -110,6 +114,7 @@ public class BuildMetadataProtoFromXml extends Command {
String copyright = null;
boolean singleFile = false;
boolean liteBuild = false;
boolean specialBuild = false;
for (int i = 1; i < getArgs().length; i++) {
String key = null;
@ -136,6 +141,9 @@ public class BuildMetadataProtoFromXml extends Command {
} else if (LITE_BUILD.equals(key) &&
("true".equalsIgnoreCase(value) || "false".equalsIgnoreCase(value))) {
liteBuild = "true".equalsIgnoreCase(value);
} else if (SPECIAL_BUILD.equals(key) &&
("true".equalsIgnoreCase(value) || "false".equalsIgnoreCase(value))) {
specialBuild = "true".equalsIgnoreCase(value);
} else {
System.err.println(HELP_MESSAGE);
System.err.println("Illegal command line parameter: " + getArgs()[i]);
@ -156,7 +164,7 @@ public class BuildMetadataProtoFromXml extends Command {
try {
PhoneMetadataCollection metadataCollection =
BuildMetadataFromXml.buildPhoneMetadataCollection(inputFile, liteBuild);
BuildMetadataFromXml.buildPhoneMetadataCollection(inputFile, liteBuild, specialBuild);
if (singleFile) {
FileOutputStream output = new FileOutputStream(filePrefix);


BIN
tools/java/java-build/target/java-build-1.0-SNAPSHOT-jar-with-dependencies.jar View File


Loading…
Cancel
Save