diff --git a/tools/java/common/pom.xml b/tools/java/common/pom.xml index ee297d9b0..0273d6521 100644 --- a/tools/java/common/pom.xml +++ b/tools/java/common/pom.xml @@ -17,6 +17,12 @@ src test + + + src/com/google/i18n/phonenumbers + com/google/i18n/phonenumbers + + org.apache.maven.plugins diff --git a/tools/java/common/src/com/google/i18n/phonenumbers/MetadataFilter.java b/tools/java/common/src/com/google/i18n/phonenumbers/MetadataFilter.java index b9d290e7f..7d39db78b 100644 --- a/tools/java/common/src/com/google/i18n/phonenumbers/MetadataFilter.java +++ b/tools/java/common/src/com/google/i18n/phonenumbers/MetadataFilter.java @@ -19,7 +19,6 @@ 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; @@ -36,14 +35,14 @@ 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. + // excludableParentFields are PhoneMetadata fields of type PhoneNumberDesc. + // excludableChildFields are PhoneNumberDesc fields of primitive type. + // excludableChildlessFields 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 EXCLUDABLE_PARENT_FIELDS = new TreeSet(Arrays.asList( + static final TreeSet excludableParentFields = new TreeSet(Arrays.asList( "fixedLine", "mobile", "tollFree", @@ -61,14 +60,14 @@ final class MetadataFilter { "noInternationalDialling")); // @VisibleForTesting - static final TreeSet EXCLUDABLE_CHILD_FIELDS = new TreeSet(Arrays.asList( + static final TreeSet excludableChildFields = new TreeSet(Arrays.asList( "nationalNumberPattern", "possibleLength", "possibleLengthLocalOnly", "exampleNumber")); // @VisibleForTesting - static final TreeSet EXCLUDABLE_CHILDLESS_FIELDS = new TreeSet(Arrays.asList( + static final TreeSet excludableChildlessFields = new TreeSet(Arrays.asList( "preferredInternationalPrefix", "nationalPrefix", "preferredExtnPrefix", @@ -165,28 +164,28 @@ final class MetadataFilter { metadata.setNoInternationalDialling(getFiltered("noInternationalDialling", metadata.getNoInternationalDialling())); } - if (drop("preferredInternationalPrefix")) { + if (shouldDrop("preferredInternationalPrefix")) { metadata.clearPreferredInternationalPrefix(); } - if (drop("nationalPrefix")) { + if (shouldDrop("nationalPrefix")) { metadata.clearNationalPrefix(); } - if (drop("preferredExtnPrefix")) { + if (shouldDrop("preferredExtnPrefix")) { metadata.clearPreferredExtnPrefix(); } - if (drop("nationalPrefixTransformRule")) { + if (shouldDrop("nationalPrefixTransformRule")) { metadata.clearNationalPrefixTransformRule(); } - if (drop("sameMobileAndFixedLinePattern")) { + if (shouldDrop("sameMobileAndFixedLinePattern")) { metadata.clearSameMobileAndFixedLinePattern(); } - if (drop("mainCountryForCode")) { + if (shouldDrop("mainCountryForCode")) { metadata.clearMainCountryForCode(); } - if (drop("leadingZeroPossible")) { + if (shouldDrop("leadingZeroPossible")) { metadata.clearLeadingZeroPossible(); } - if (drop("mobileNumberPortableRegion")) { + if (shouldDrop("mobileNumberPortableRegion")) { metadata.clearMobileNumberPortableRegion(); } } @@ -216,17 +215,17 @@ final class MetadataFilter { int leftParenIndex = group.indexOf('('); int rightParenIndex = group.indexOf(')'); if (leftParenIndex < 0 && rightParenIndex < 0) { - if (EXCLUDABLE_PARENT_FIELDS.contains(group)) { + if (excludableParentFields.contains(group)) { if (fieldMap.containsKey(group)) { throw new RuntimeException(group + " given more than once in " + string); } - fieldMap.put(group, new TreeSet(EXCLUDABLE_CHILD_FIELDS)); - } else if (EXCLUDABLE_CHILDLESS_FIELDS.contains(group)) { + fieldMap.put(group, new TreeSet(excludableChildFields)); + } else if (excludableChildlessFields.contains(group)) { if (fieldMap.containsKey(group)) { throw new RuntimeException(group + " given more than once in " + string); } fieldMap.put(group, new TreeSet()); - } else if (EXCLUDABLE_CHILD_FIELDS.contains(group)) { + } else if (excludableChildFields.contains(group)) { if (wildcardChildren.contains(group)) { throw new RuntimeException(group + " given more than once in " + string); } @@ -238,7 +237,7 @@ final class MetadataFilter { // 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)) { + if (!excludableParentFields.contains(parent)) { throw new RuntimeException(parent + " is not a valid parent token"); } if (fieldMap.containsKey(parent)) { @@ -246,7 +245,7 @@ final class MetadataFilter { } TreeSet children = new TreeSet(); for (String child : group.substring(leftParenIndex + 1, rightParenIndex).split(",", -1)) { - if (!EXCLUDABLE_CHILD_FIELDS.contains(child)) { + if (!excludableChildFields.contains(child)) { throw new RuntimeException(child + " is not a valid child token"); } if (!children.add(child)) { @@ -259,14 +258,14 @@ final class MetadataFilter { } } for (String wildcardChild : wildcardChildren) { - for (String parent : EXCLUDABLE_PARENT_FIELDS) { + for (String parent : excludableParentFields) { TreeSet children = fieldMap.get(parent); if (children == null) { children = new TreeSet(); fieldMap.put(parent, children); } if (!children.add(wildcardChild) - && fieldMap.get(parent).size() != EXCLUDABLE_CHILD_FIELDS.size()) { + && fieldMap.get(parent).size() != excludableChildFields.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. @@ -285,16 +284,16 @@ final class MetadataFilter { static TreeMap> computeComplement( TreeMap> fieldMap) { TreeMap> complement = new TreeMap>(); - for (String parent : EXCLUDABLE_PARENT_FIELDS) { + for (String parent : excludableParentFields) { if (!fieldMap.containsKey(parent)) { - complement.put(parent, new TreeSet(EXCLUDABLE_CHILD_FIELDS)); + complement.put(parent, new TreeSet(excludableChildFields)); } else { TreeSet 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()) { + if (otherChildren.size() != excludableChildFields.size()) { TreeSet children = new TreeSet(); - for (String child : EXCLUDABLE_CHILD_FIELDS) { + for (String child : excludableChildFields) { if (!otherChildren.contains(child)) { children.add(child); } @@ -303,7 +302,7 @@ final class MetadataFilter { } } } - for (String childlessField : EXCLUDABLE_CHILDLESS_FIELDS) { + for (String childlessField : excludableChildlessFields) { if (!fieldMap.containsKey(childlessField)) { complement.put(childlessField, new TreeSet()); } @@ -312,19 +311,19 @@ final class MetadataFilter { } // @VisibleForTesting - boolean drop(String parent, String child) { - if (!EXCLUDABLE_PARENT_FIELDS.contains(parent)) { + boolean shouldDrop(String parent, String child) { + if (!excludableParentFields.contains(parent)) { throw new RuntimeException(parent + " is not an excludable parent field"); } - if (!EXCLUDABLE_CHILD_FIELDS.contains(child)) { + if (!excludableChildFields.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)) { + boolean shouldDrop(String childlessField) { + if (!excludableChildlessFields.contains(childlessField)) { throw new RuntimeException(childlessField + " is not an excludable childless field"); } return blacklist.containsKey(childlessField); @@ -332,16 +331,16 @@ final class MetadataFilter { private PhoneNumberDesc getFiltered(String type, PhoneNumberDesc desc) { PhoneNumberDesc.Builder builder = PhoneNumberDesc.newBuilder().mergeFrom(desc); - if (drop(type, "nationalNumberPattern")) { + if (shouldDrop(type, "nationalNumberPattern")) { builder.clearNationalNumberPattern(); } - if (drop(type, "possibleLength")) { + if (shouldDrop(type, "possibleLength")) { builder.clearPossibleLength(); } - if (drop(type, "possibleLengthLocalOnly")) { + if (shouldDrop(type, "possibleLengthLocalOnly")) { builder.clearPossibleLengthLocalOnly(); } - if (drop(type, "exampleNumber")) { + if (shouldDrop(type, "exampleNumber")) { builder.clearExampleNumber(); } return builder.build(); diff --git a/tools/java/common/test/com/google/i18n/phonenumbers/BuildMetadataFromXmlTest.java b/tools/java/common/test/com/google/i18n/phonenumbers/BuildMetadataFromXmlTest.java index 60a4fb04e..8a8086e02 100644 --- a/tools/java/common/test/com/google/i18n/phonenumbers/BuildMetadataFromXmlTest.java +++ b/tools/java/common/test/com/google/i18n/phonenumbers/BuildMetadataFromXmlTest.java @@ -495,6 +495,9 @@ public class BuildMetadataFromXmlTest extends TestCase { PhoneMetadata metadata = metadataCollection.getMetadataList().get(0); assertTrue(metadata.hasGeneralDesc()); assertFalse(metadata.getGeneralDesc().hasExampleNumber()); + // Some Phonemetadata.java implementations may have custom logic, so we ensure this + // implementation is doing the right thing by checking the value of the example number even when + // hasExampleNumber is false. assertEquals("", metadata.getGeneralDesc().getExampleNumber()); assertTrue(metadata.hasFixedLine()); assertFalse(metadata.getFixedLine().hasExampleNumber()); @@ -538,6 +541,9 @@ public class BuildMetadataFromXmlTest extends TestCase { PhoneMetadata metadata = metadataCollection.getMetadataList().get(0); assertTrue(metadata.hasGeneralDesc()); assertFalse(metadata.getGeneralDesc().hasExampleNumber()); + // Some Phonemetadata.java implementations may have custom logic, so we ensure this + // implementation is doing the right thing by checking the value of the example number even when + // hasExampleNumber is false. assertEquals("", metadata.getGeneralDesc().getExampleNumber()); // TODO: Consider clearing fixed-line if empty after being filtered. assertTrue(metadata.hasFixedLine()); @@ -582,6 +588,9 @@ public class BuildMetadataFromXmlTest extends TestCase { PhoneMetadata metadata = metadataCollection.getMetadataList().get(0); assertTrue(metadata.hasGeneralDesc()); assertFalse(metadata.getGeneralDesc().hasExampleNumber()); + // Some Phonemetadata.java implementations may have custom logic, so we ensure this + // implementation is doing the right thing by checking the value of the example number even when + // hasExampleNumber is false. assertEquals("", metadata.getGeneralDesc().getExampleNumber()); assertTrue(metadata.hasFixedLine()); assertTrue(metadata.getFixedLine().hasExampleNumber()); diff --git a/tools/java/common/test/com/google/i18n/phonenumbers/MetadataFilterCoverageTest.java b/tools/java/common/test/com/google/i18n/phonenumbers/MetadataFilterCoverageTest.java new file mode 100644 index 000000000..6f56e3600 --- /dev/null +++ b/tools/java/common/test/com/google/i18n/phonenumbers/MetadataFilterCoverageTest.java @@ -0,0 +1,102 @@ +/* + * 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 static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.BufferedInputStream; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.Charset; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** + * Tests to ensure that the {@link MetadataFilter} logic over excludable fields cover all applicable + * fields. + */ +@RunWith(JUnit4.class) +public final class MetadataFilterCoverageTest { + private static final String CODE; + + static { + try { + BufferedReader source = new BufferedReader(new InputStreamReader(new BufferedInputStream( + MetadataFilterTest.class.getResourceAsStream( + "/com/google/i18n/phonenumbers/MetadataFilter.java")), + Charset.forName("UTF-8"))); + StringBuilder codeBuilder = new StringBuilder(); + for (String line = source.readLine(); line != null; line = source.readLine()) { + codeBuilder.append(line).append("\n"); + } + CODE = codeBuilder.toString(); + } catch (IOException e) { + throw new RuntimeException("MetadataFilter.java resource not set up properly", e); + } + } + + @Test + public void testCoverageOfExcludableParentFields() { + for (String field : MetadataFilter.excludableParentFields) { + String capitalized = Character.toUpperCase(field.charAt(0)) + field.substring(1); + String conditional = String.format( + "if (metadata.has%s()) {\n metadata.set%s(getFiltered(\"%s\", metadata.get%s()));\n" + + " }", capitalized, capitalized, field, capitalized); + assertTrue("Code is missing correct conditional for " + field, CODE.contains(conditional)); + } + + assertEquals(countOccurrencesOf("metadata.has", CODE), + MetadataFilter.excludableParentFields.size()); + } + + @Test + public void testCoverageOfExcludableChildFields() { + for (String field : MetadataFilter.excludableChildFields) { + String capitalized = Character.toUpperCase(field.charAt(0)) + field.substring(1); + String conditional = String.format( + "if (shouldDrop(type, \"%s\")) {\n builder.clear%s();\n }", field, capitalized); + assertTrue("Code is missing correct conditional for " + field, CODE.contains(conditional)); + } + + assertEquals(countOccurrencesOf("shouldDrop(type, \"", CODE), + MetadataFilter.excludableChildFields.size()); + } + + @Test + public void testCoverageOfExcludableChildlessFields() { + for (String field : MetadataFilter.excludableChildlessFields) { + String capitalized = Character.toUpperCase(field.charAt(0)) + field.substring(1); + String conditional = String.format( + "if (shouldDrop(\"%s\")) {\n metadata.clear%s();\n }", field, capitalized); + assertTrue("Code is missing correct conditional for " + field, CODE.contains(conditional)); + } + + assertEquals(countOccurrencesOf("shouldDrop(\"", CODE), + MetadataFilter.excludableChildlessFields.size()); + } + + private static int countOccurrencesOf(String substring, String string) { + int count = 0; + for (int i = string.indexOf(substring); i != -1; i = string.indexOf(substring, i + 1)) { + count++; + } + return count; + } +} diff --git a/tools/java/common/test/com/google/i18n/phonenumbers/MetadataFilterTest.java b/tools/java/common/test/com/google/i18n/phonenumbers/MetadataFilterTest.java index 8c8494c79..d1f1276d8 100644 --- a/tools/java/common/test/com/google/i18n/phonenumbers/MetadataFilterTest.java +++ b/tools/java/common/test/com/google/i18n/phonenumbers/MetadataFilterTest.java @@ -16,15 +16,35 @@ package com.google.i18n.phonenumbers; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import com.google.i18n.phonenumbers.Phonemetadata.PhoneMetadata; +import com.google.i18n.phonenumbers.Phonemetadata.PhoneNumberDesc; import java.util.Arrays; +import java.util.List; import java.util.TreeMap; import java.util.TreeSet; -import junit.framework.TestCase; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** + * Unit tests for {@link MetadataFilter}. + */ +@RunWith(JUnit4.class) +public class MetadataFilterTest { + private static final String NATIONAL_NUMBER_PATTERN = "[1-9]\\d{7}"; + private static final int[] possibleLengths = {8}; + private static final int[] possibleLengthsLocalOnly = {5, 6}; + private static final String EXAMPLE_NUMBER = "10123456"; -public 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. + @Test public void testForLiteBuild() { TreeMap> blacklist = new TreeMap>(); blacklist.put("fixedLine", new TreeSet(Arrays.asList("exampleNumber"))); @@ -50,23 +70,24 @@ public 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. + @Test public void testForSpecialBuild() { TreeMap> blacklist = new TreeMap>(); - blacklist.put("fixedLine", new TreeSet(MetadataFilter.EXCLUDABLE_CHILD_FIELDS)); - blacklist.put("tollFree", new TreeSet(MetadataFilter.EXCLUDABLE_CHILD_FIELDS)); - blacklist.put("premiumRate", new TreeSet(MetadataFilter.EXCLUDABLE_CHILD_FIELDS)); - blacklist.put("sharedCost", new TreeSet(MetadataFilter.EXCLUDABLE_CHILD_FIELDS)); - blacklist.put("personalNumber", new TreeSet(MetadataFilter.EXCLUDABLE_CHILD_FIELDS)); - blacklist.put("voip", new TreeSet(MetadataFilter.EXCLUDABLE_CHILD_FIELDS)); - blacklist.put("pager", new TreeSet(MetadataFilter.EXCLUDABLE_CHILD_FIELDS)); - blacklist.put("uan", new TreeSet(MetadataFilter.EXCLUDABLE_CHILD_FIELDS)); - blacklist.put("emergency", new TreeSet(MetadataFilter.EXCLUDABLE_CHILD_FIELDS)); - blacklist.put("voicemail", new TreeSet(MetadataFilter.EXCLUDABLE_CHILD_FIELDS)); - blacklist.put("shortCode", new TreeSet(MetadataFilter.EXCLUDABLE_CHILD_FIELDS)); - blacklist.put("standardRate", new TreeSet(MetadataFilter.EXCLUDABLE_CHILD_FIELDS)); - blacklist.put("carrierSpecific", new TreeSet(MetadataFilter.EXCLUDABLE_CHILD_FIELDS)); + blacklist.put("fixedLine", new TreeSet(MetadataFilter.excludableChildFields)); + blacklist.put("tollFree", new TreeSet(MetadataFilter.excludableChildFields)); + blacklist.put("premiumRate", new TreeSet(MetadataFilter.excludableChildFields)); + blacklist.put("sharedCost", new TreeSet(MetadataFilter.excludableChildFields)); + blacklist.put("personalNumber", new TreeSet(MetadataFilter.excludableChildFields)); + blacklist.put("voip", new TreeSet(MetadataFilter.excludableChildFields)); + blacklist.put("pager", new TreeSet(MetadataFilter.excludableChildFields)); + blacklist.put("uan", new TreeSet(MetadataFilter.excludableChildFields)); + blacklist.put("emergency", new TreeSet(MetadataFilter.excludableChildFields)); + blacklist.put("voicemail", new TreeSet(MetadataFilter.excludableChildFields)); + blacklist.put("shortCode", new TreeSet(MetadataFilter.excludableChildFields)); + blacklist.put("standardRate", new TreeSet(MetadataFilter.excludableChildFields)); + blacklist.put("carrierSpecific", new TreeSet(MetadataFilter.excludableChildFields)); blacklist.put("noInternationalDialling", - new TreeSet(MetadataFilter.EXCLUDABLE_CHILD_FIELDS)); + new TreeSet(MetadataFilter.excludableChildFields)); blacklist.put("preferredInternationalPrefix", new TreeSet()); blacklist.put("nationalPrefix", new TreeSet()); blacklist.put("preferredExtnPrefix", new TreeSet()); @@ -79,11 +100,13 @@ public class MetadataFilterTest extends TestCase { assertEquals(MetadataFilter.forSpecialBuild(), new MetadataFilter(blacklist)); } + @Test public void testEmptyFilter() { assertEquals(MetadataFilter.emptyFilter(), new MetadataFilter(new TreeMap>())); } + @Test public void testParseFieldMapFromString_parentAsGroup() { TreeMap> fieldMap = new TreeMap>(); fieldMap.put("fixedLine", new TreeSet(Arrays.asList( @@ -92,6 +115,7 @@ public class MetadataFilterTest extends TestCase { assertEquals(MetadataFilter.parseFieldMapFromString("fixedLine"), fieldMap); } + @Test public void testParseFieldMapFromString_childAsGroup() { TreeMap> fieldMap = new TreeMap>(); fieldMap.put("fixedLine", new TreeSet(Arrays.asList("exampleNumber"))); @@ -113,6 +137,7 @@ public class MetadataFilterTest extends TestCase { assertEquals(MetadataFilter.parseFieldMapFromString("exampleNumber"), fieldMap); } + @Test public void testParseFieldMapFromString_childlessFieldAsGroup() { TreeMap> fieldMap = new TreeMap>(); fieldMap.put("nationalPrefix", new TreeSet()); @@ -120,6 +145,7 @@ public class MetadataFilterTest extends TestCase { assertEquals(MetadataFilter.parseFieldMapFromString("nationalPrefix"), fieldMap); } + @Test public void testParseFieldMapFromString_parentWithOneChildAsGroup() { TreeMap> fieldMap = new TreeMap>(); fieldMap.put("fixedLine", new TreeSet(Arrays.asList("exampleNumber"))); @@ -127,6 +153,7 @@ public class MetadataFilterTest extends TestCase { assertEquals(MetadataFilter.parseFieldMapFromString("fixedLine(exampleNumber)"), fieldMap); } + @Test public void testParseFieldMapFromString_parentWithTwoChildrenAsGroup() { TreeMap> fieldMap = new TreeMap>(); fieldMap.put("fixedLine", new TreeSet(Arrays.asList( @@ -137,6 +164,7 @@ public class MetadataFilterTest extends TestCase { fieldMap); } + @Test public void testParseFieldMapFromString_mixOfGroups() { TreeMap> fieldMap = new TreeMap>(); fieldMap.put("uan", new TreeSet(Arrays.asList( @@ -169,6 +197,7 @@ public class MetadataFilterTest extends TestCase { fieldMap); } + @Test // 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 @@ -286,6 +315,7 @@ public class MetadataFilterTest extends TestCase { + ":noInternationalDialling")); } + @Test public void testParseFieldMapFromString_RuntimeExceptionCases() { // Null input. try { @@ -702,24 +732,25 @@ public class MetadataFilterTest extends TestCase { } } + @Test public void testComputeComplement_allAndNothing() { TreeMap> map1 = new TreeMap>(); - map1.put("fixedLine", new TreeSet(MetadataFilter.EXCLUDABLE_CHILD_FIELDS)); - map1.put("mobile", new TreeSet(MetadataFilter.EXCLUDABLE_CHILD_FIELDS)); - map1.put("tollFree", new TreeSet(MetadataFilter.EXCLUDABLE_CHILD_FIELDS)); - map1.put("premiumRate", new TreeSet(MetadataFilter.EXCLUDABLE_CHILD_FIELDS)); - map1.put("sharedCost", new TreeSet(MetadataFilter.EXCLUDABLE_CHILD_FIELDS)); - map1.put("personalNumber", new TreeSet(MetadataFilter.EXCLUDABLE_CHILD_FIELDS)); - map1.put("voip", new TreeSet(MetadataFilter.EXCLUDABLE_CHILD_FIELDS)); - map1.put("pager", new TreeSet(MetadataFilter.EXCLUDABLE_CHILD_FIELDS)); - map1.put("uan", new TreeSet(MetadataFilter.EXCLUDABLE_CHILD_FIELDS)); - map1.put("emergency", new TreeSet(MetadataFilter.EXCLUDABLE_CHILD_FIELDS)); - map1.put("voicemail", new TreeSet(MetadataFilter.EXCLUDABLE_CHILD_FIELDS)); - map1.put("shortCode", new TreeSet(MetadataFilter.EXCLUDABLE_CHILD_FIELDS)); - map1.put("standardRate", new TreeSet(MetadataFilter.EXCLUDABLE_CHILD_FIELDS)); - map1.put("carrierSpecific", new TreeSet(MetadataFilter.EXCLUDABLE_CHILD_FIELDS)); + map1.put("fixedLine", new TreeSet(MetadataFilter.excludableChildFields)); + map1.put("mobile", new TreeSet(MetadataFilter.excludableChildFields)); + map1.put("tollFree", new TreeSet(MetadataFilter.excludableChildFields)); + map1.put("premiumRate", new TreeSet(MetadataFilter.excludableChildFields)); + map1.put("sharedCost", new TreeSet(MetadataFilter.excludableChildFields)); + map1.put("personalNumber", new TreeSet(MetadataFilter.excludableChildFields)); + map1.put("voip", new TreeSet(MetadataFilter.excludableChildFields)); + map1.put("pager", new TreeSet(MetadataFilter.excludableChildFields)); + map1.put("uan", new TreeSet(MetadataFilter.excludableChildFields)); + map1.put("emergency", new TreeSet(MetadataFilter.excludableChildFields)); + map1.put("voicemail", new TreeSet(MetadataFilter.excludableChildFields)); + map1.put("shortCode", new TreeSet(MetadataFilter.excludableChildFields)); + map1.put("standardRate", new TreeSet(MetadataFilter.excludableChildFields)); + map1.put("carrierSpecific", new TreeSet(MetadataFilter.excludableChildFields)); map1.put("noInternationalDialling", - new TreeSet(MetadataFilter.EXCLUDABLE_CHILD_FIELDS)); + new TreeSet(MetadataFilter.excludableChildFields)); map1.put("preferredInternationalPrefix", new TreeSet()); map1.put("nationalPrefix", new TreeSet()); map1.put("preferredExtnPrefix", new TreeSet()); @@ -735,19 +766,20 @@ public class MetadataFilterTest extends TestCase { assertEquals(MetadataFilter.computeComplement(map2), map1); } + @Test public void testComputeComplement_inBetween() { TreeMap> map1 = new TreeMap>(); - map1.put("fixedLine", new TreeSet(MetadataFilter.EXCLUDABLE_CHILD_FIELDS)); - map1.put("mobile", new TreeSet(MetadataFilter.EXCLUDABLE_CHILD_FIELDS)); - map1.put("tollFree", new TreeSet(MetadataFilter.EXCLUDABLE_CHILD_FIELDS)); - map1.put("premiumRate", new TreeSet(MetadataFilter.EXCLUDABLE_CHILD_FIELDS)); + map1.put("fixedLine", new TreeSet(MetadataFilter.excludableChildFields)); + map1.put("mobile", new TreeSet(MetadataFilter.excludableChildFields)); + map1.put("tollFree", new TreeSet(MetadataFilter.excludableChildFields)); + map1.put("premiumRate", new TreeSet(MetadataFilter.excludableChildFields)); map1.put("emergency", new TreeSet(Arrays.asList("nationalNumberPattern"))); map1.put("voicemail", new TreeSet(Arrays.asList("possibleLength", "exampleNumber"))); map1.put("shortCode", new TreeSet(Arrays.asList("exampleNumber"))); - map1.put("standardRate", new TreeSet(MetadataFilter.EXCLUDABLE_CHILD_FIELDS)); - map1.put("carrierSpecific", new TreeSet(MetadataFilter.EXCLUDABLE_CHILD_FIELDS)); + map1.put("standardRate", new TreeSet(MetadataFilter.excludableChildFields)); + map1.put("carrierSpecific", new TreeSet(MetadataFilter.excludableChildFields)); map1.put("noInternationalDialling", - new TreeSet(MetadataFilter.EXCLUDABLE_CHILD_FIELDS)); + new TreeSet(MetadataFilter.excludableChildFields)); map1.put("nationalPrefixTransformRule", new TreeSet()); map1.put("sameMobileAndFixedLinePattern", new TreeSet()); map1.put("mainCountryForCode", new TreeSet()); @@ -755,11 +787,11 @@ public class MetadataFilterTest extends TestCase { map1.put("mobileNumberPortableRegion", new TreeSet()); TreeMap> map2 = new TreeMap>(); - map2.put("sharedCost", new TreeSet(MetadataFilter.EXCLUDABLE_CHILD_FIELDS)); - map2.put("personalNumber", new TreeSet(MetadataFilter.EXCLUDABLE_CHILD_FIELDS)); - map2.put("voip", new TreeSet(MetadataFilter.EXCLUDABLE_CHILD_FIELDS)); - map2.put("pager", new TreeSet(MetadataFilter.EXCLUDABLE_CHILD_FIELDS)); - map2.put("uan", new TreeSet(MetadataFilter.EXCLUDABLE_CHILD_FIELDS)); + map2.put("sharedCost", new TreeSet(MetadataFilter.excludableChildFields)); + map2.put("personalNumber", new TreeSet(MetadataFilter.excludableChildFields)); + map2.put("voip", new TreeSet(MetadataFilter.excludableChildFields)); + map2.put("pager", new TreeSet(MetadataFilter.excludableChildFields)); + map2.put("uan", new TreeSet(MetadataFilter.excludableChildFields)); map2.put("emergency", new TreeSet(Arrays.asList( "possibleLength", "possibleLengthLocalOnly", "exampleNumber"))); map2.put("voicemail", new TreeSet(Arrays.asList( @@ -774,20 +806,21 @@ public class MetadataFilterTest extends TestCase { assertEquals(MetadataFilter.computeComplement(map2), map1); } - public void testDrop() { + @Test + public void testShouldDrop() { TreeMap> blacklist = new TreeMap>(); - blacklist.put("fixedLine", new TreeSet(MetadataFilter.EXCLUDABLE_CHILD_FIELDS)); - blacklist.put("mobile", new TreeSet(MetadataFilter.EXCLUDABLE_CHILD_FIELDS)); - blacklist.put("tollFree", new TreeSet(MetadataFilter.EXCLUDABLE_CHILD_FIELDS)); - blacklist.put("premiumRate", new TreeSet(MetadataFilter.EXCLUDABLE_CHILD_FIELDS)); + blacklist.put("fixedLine", new TreeSet(MetadataFilter.excludableChildFields)); + blacklist.put("mobile", new TreeSet(MetadataFilter.excludableChildFields)); + blacklist.put("tollFree", new TreeSet(MetadataFilter.excludableChildFields)); + blacklist.put("premiumRate", new TreeSet(MetadataFilter.excludableChildFields)); blacklist.put("emergency", new TreeSet(Arrays.asList("nationalNumberPattern"))); blacklist.put("voicemail", new TreeSet(Arrays.asList( "possibleLength", "exampleNumber"))); blacklist.put("shortCode", new TreeSet(Arrays.asList("exampleNumber"))); - blacklist.put("standardRate", new TreeSet(MetadataFilter.EXCLUDABLE_CHILD_FIELDS)); - blacklist.put("carrierSpecific", new TreeSet(MetadataFilter.EXCLUDABLE_CHILD_FIELDS)); + blacklist.put("standardRate", new TreeSet(MetadataFilter.excludableChildFields)); + blacklist.put("carrierSpecific", new TreeSet(MetadataFilter.excludableChildFields)); blacklist.put("noInternationalDialling", - new TreeSet(MetadataFilter.EXCLUDABLE_CHILD_FIELDS)); + new TreeSet(MetadataFilter.excludableChildFields)); blacklist.put("nationalPrefixTransformRule", new TreeSet()); blacklist.put("sameMobileAndFixedLinePattern", new TreeSet()); blacklist.put("mainCountryForCode", new TreeSet()); @@ -795,54 +828,184 @@ public class MetadataFilterTest extends TestCase { blacklist.put("mobileNumberPortableRegion", new TreeSet()); 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")); + assertTrue(filter.shouldDrop("fixedLine", "exampleNumber")); + assertFalse(filter.shouldDrop("sharedCost", "exampleNumber")); + assertFalse(filter.shouldDrop("emergency", "exampleNumber")); + assertTrue(filter.shouldDrop("emergency", "nationalNumberPattern")); + assertFalse(filter.shouldDrop("preferredInternationalPrefix")); + assertTrue(filter.shouldDrop("mobileNumberPortableRegion")); // Integration tests starting with flag values. assertTrue(BuildMetadataFromXml.getMetadataFilter(true, false) - .drop("fixedLine", "exampleNumber")); + .shouldDrop("fixedLine", "exampleNumber")); // Integration tests starting with blacklist strings. assertTrue(new MetadataFilter(MetadataFilter.parseFieldMapFromString("fixedLine")) - .drop("fixedLine", "exampleNumber")); + .shouldDrop("fixedLine", "exampleNumber")); assertFalse(new MetadataFilter(MetadataFilter.parseFieldMapFromString("uan")) - .drop("fixedLine", "exampleNumber")); + .shouldDrop("fixedLine", "exampleNumber")); // Integration tests starting with whitelist strings. assertFalse(new MetadataFilter(MetadataFilter.computeComplement( MetadataFilter.parseFieldMapFromString("exampleNumber"))) - .drop("fixedLine", "exampleNumber")); + .shouldDrop("fixedLine", "exampleNumber")); assertTrue(new MetadataFilter(MetadataFilter.computeComplement( - MetadataFilter.parseFieldMapFromString("uan"))).drop("fixedLine", "exampleNumber")); + MetadataFilter.parseFieldMapFromString("uan"))).shouldDrop("fixedLine", "exampleNumber")); // Integration tests with an empty blacklist. assertFalse(new MetadataFilter(new TreeMap>()) - .drop("fixedLine", "exampleNumber")); + .shouldDrop("fixedLine", "exampleNumber")); + } + + // Test that a fake PhoneMetadata filtered for liteBuild ends up clearing exactly the expected + // fields. The lite build is used to clear example_number fields from all PhoneNumberDescs. + @Test + public void testFilterMetadata_liteBuild() { + PhoneMetadata.Builder metadata = getFakeArmeniaPhoneMetadata(); + + MetadataFilter.forLiteBuild().filterMetadata(metadata); + + // id, country_code, and international_prefix should never be cleared. + assertEquals(metadata.getId(), "AM"); + assertEquals(metadata.getCountryCode(), 374); + assertEquals(metadata.getInternationalPrefix(), "0[01]"); + + // preferred_international_prefix should not be cleared in liteBuild. + assertEquals(metadata.getPreferredInternationalPrefix(), "00"); + + // All PhoneNumberDescs must have only example_number cleared. + for (PhoneNumberDesc desc : Arrays.asList( + metadata.getGeneralDesc(), + metadata.getFixedLine(), + metadata.getMobile(), + metadata.getTollFree())) { + assertEquals(desc.getNationalNumberPattern(), NATIONAL_NUMBER_PATTERN); + assertContentsEqual(desc.getPossibleLengthList(), possibleLengths); + assertContentsEqual(desc.getPossibleLengthLocalOnlyList(), possibleLengthsLocalOnly); + assertFalse(desc.hasExampleNumber()); + } + } + + // Test that a fake PhoneMetadata filtered for specialBuild ends up clearing exactly the expected + // fields. The special build is used to clear PhoneNumberDescs other than general_desc and mobile, + // and non-PhoneNumberDesc PhoneMetadata fields that aren't needed for parsing. + @Test + public void testFilterMetadata_specialBuild() { + PhoneMetadata.Builder metadata = getFakeArmeniaPhoneMetadata(); + + MetadataFilter.forSpecialBuild().filterMetadata(metadata); + + // id, country_code, and international_prefix should never be cleared. + assertEquals(metadata.getId(), "AM"); + assertEquals(metadata.getCountryCode(), 374); + assertEquals(metadata.getInternationalPrefix(), "0[01]"); + + // preferred_international_prefix should be cleared in specialBuild. + assertFalse(metadata.hasPreferredInternationalPrefix()); + + // general_desc should have all fields but example_number; mobile should have all fields. + for (PhoneNumberDesc desc : Arrays.asList( + metadata.getGeneralDesc(), + metadata.getMobile())) { + assertEquals(desc.getNationalNumberPattern(), NATIONAL_NUMBER_PATTERN); + assertContentsEqual(desc.getPossibleLengthList(), possibleLengths); + assertContentsEqual(desc.getPossibleLengthLocalOnlyList(), possibleLengthsLocalOnly); + } + assertFalse(metadata.getGeneralDesc().hasExampleNumber()); + assertEquals(metadata.getMobile().getExampleNumber(), EXAMPLE_NUMBER); + + // All other PhoneNumberDescs must have all fields cleared. + for (PhoneNumberDesc desc : Arrays.asList( + metadata.getFixedLine(), + metadata.getTollFree())) { + assertFalse(desc.hasNationalNumberPattern()); + assertEquals(desc.getPossibleLengthList().size(), 0); + assertEquals(desc.getPossibleLengthLocalOnlyList().size(), 0); + assertFalse(desc.hasExampleNumber()); + } + } + + // Test that filtering a fake PhoneMetadata with the empty MetadataFilter results in no change. + @Test + public void testFilterMetadata_emptyFilter() { + PhoneMetadata.Builder metadata = getFakeArmeniaPhoneMetadata(); + + MetadataFilter.emptyFilter().filterMetadata(metadata); + + // None of the fields should be cleared. + assertEquals(metadata.getId(), "AM"); + assertEquals(metadata.getCountryCode(), 374); + assertEquals(metadata.getInternationalPrefix(), "0[01]"); + assertEquals(metadata.getPreferredInternationalPrefix(), "00"); + for (PhoneNumberDesc desc : Arrays.asList( + metadata.getGeneralDesc(), + metadata.getFixedLine(), + metadata.getMobile(), + metadata.getTollFree())) { + assertEquals(desc.getNationalNumberPattern(), NATIONAL_NUMBER_PATTERN); + assertContentsEqual(desc.getPossibleLengthList(), possibleLengths); + assertContentsEqual(desc.getPossibleLengthLocalOnlyList(), possibleLengthsLocalOnly); + } + assertFalse(metadata.getGeneralDesc().hasExampleNumber()); + assertEquals(metadata.getFixedLine().getExampleNumber(), EXAMPLE_NUMBER); + assertEquals(metadata.getMobile().getExampleNumber(), EXAMPLE_NUMBER); + assertEquals(metadata.getTollFree().getExampleNumber(), EXAMPLE_NUMBER); } + @Test public void testIntegrityOfFieldSets() { TreeSet union = new TreeSet(); - union.addAll(MetadataFilter.EXCLUDABLE_PARENT_FIELDS); - union.addAll(MetadataFilter.EXCLUDABLE_CHILD_FIELDS); - union.addAll(MetadataFilter.EXCLUDABLE_CHILDLESS_FIELDS); + union.addAll(MetadataFilter.excludableParentFields); + union.addAll(MetadataFilter.excludableChildFields); + union.addAll(MetadataFilter.excludableChildlessFields); // Mutually exclusive sets. - assertTrue(union.size() == MetadataFilter.EXCLUDABLE_PARENT_FIELDS.size() - + MetadataFilter.EXCLUDABLE_CHILD_FIELDS.size() - + MetadataFilter.EXCLUDABLE_CHILDLESS_FIELDS.size()); + assertTrue(union.size() == MetadataFilter.excludableParentFields.size() + + MetadataFilter.excludableChildFields.size() + + MetadataFilter.excludableChildlessFields.size()); // Nonempty sets. - assertTrue(MetadataFilter.EXCLUDABLE_PARENT_FIELDS.size() > 0 - && MetadataFilter.EXCLUDABLE_CHILD_FIELDS.size() > 0 - && MetadataFilter.EXCLUDABLE_CHILDLESS_FIELDS.size() > 0); + assertTrue(MetadataFilter.excludableParentFields.size() > 0 + && MetadataFilter.excludableChildFields.size() > 0 + && MetadataFilter.excludableChildlessFields.size() > 0); // Nonempty and canonical field names. for (String field : union) { assertTrue(field.length() > 0 && field.trim().equals(field)); } } + + private static PhoneMetadata.Builder getFakeArmeniaPhoneMetadata() { + PhoneMetadata.Builder metadata = PhoneMetadata.newBuilder(); + metadata.setId("AM"); + metadata.setCountryCode(374); + metadata.setInternationalPrefix("0[01]"); + metadata.setPreferredInternationalPrefix("00"); + metadata.setGeneralDesc(getFakeArmeniaPhoneNumberDesc(true)); + metadata.setFixedLine(getFakeArmeniaPhoneNumberDesc(false)); + metadata.setMobile(getFakeArmeniaPhoneNumberDesc(false)); + metadata.setTollFree(getFakeArmeniaPhoneNumberDesc(false)); + return metadata; + } + + private static PhoneNumberDesc getFakeArmeniaPhoneNumberDesc(boolean generalDesc) { + PhoneNumberDesc desc = new PhoneNumberDesc().setNationalNumberPattern(NATIONAL_NUMBER_PATTERN); + if (!generalDesc) { + desc.setExampleNumber(EXAMPLE_NUMBER); + } + for (int i : possibleLengths) { + desc.addPossibleLength(i); + } + for (int i : possibleLengthsLocalOnly) { + desc.addPossibleLengthLocalOnly(i); + } + return desc; + } + + private static void assertContentsEqual(List list, int[] array) { + assertEquals(list.size(), array.length); + for (int i = 0; i < list.size(); i++) { + assertEquals((int) list.get(i), array[i]); + } + } } diff --git a/tools/java/cpp-build/target/cpp-build-1.0-SNAPSHOT-jar-with-dependencies.jar b/tools/java/cpp-build/target/cpp-build-1.0-SNAPSHOT-jar-with-dependencies.jar index 48dd0e36a..af88e9f8d 100644 Binary files a/tools/java/cpp-build/target/cpp-build-1.0-SNAPSHOT-jar-with-dependencies.jar and b/tools/java/cpp-build/target/cpp-build-1.0-SNAPSHOT-jar-with-dependencies.jar differ diff --git a/tools/java/java-build/target/java-build-1.0-SNAPSHOT-jar-with-dependencies.jar b/tools/java/java-build/target/java-build-1.0-SNAPSHOT-jar-with-dependencies.jar index 31889b4d7..889e4cfe7 100644 Binary files a/tools/java/java-build/target/java-build-1.0-SNAPSHOT-jar-with-dependencies.jar and b/tools/java/java-build/target/java-build-1.0-SNAPSHOT-jar-with-dependencies.jar differ