diff --git a/cpp/src/phonenumbers/phonenumber.cc b/cpp/src/phonenumbers/phonenumber.cc index a0b50c16e..41b6f1266 100644 --- a/cpp/src/phonenumbers/phonenumber.cc +++ b/cpp/src/phonenumbers/phonenumber.cc @@ -41,6 +41,12 @@ bool ExactlySameAs(const PhoneNumber& first_number, second_number.italian_leading_zero()) { return false; } + if (first_number.has_number_of_leading_zeros() != + second_number.has_number_of_leading_zeros() || + first_number.number_of_leading_zeros() != + second_number.number_of_leading_zeros()) { + return false; + } if (first_number.has_raw_input() != second_number.has_raw_input() || first_number.raw_input() != second_number.raw_input()) { return false; diff --git a/cpp/src/phonenumbers/phonenumberutil.cc b/cpp/src/phonenumbers/phonenumberutil.cc index 56f9319cc..3b969aeb2 100644 --- a/cpp/src/phonenumbers/phonenumberutil.cc +++ b/cpp/src/phonenumbers/phonenumberutil.cc @@ -300,6 +300,25 @@ PhoneNumberUtil::ValidationResult TestNumberLength( ? PhoneNumberUtil::IS_POSSIBLE : PhoneNumberUtil::TOO_LONG; } +// Returns a new phone number containing only the fields needed to uniquely +// identify a phone number, rather than any fields that capture the context in +// which the phone number was created. +// These fields correspond to those set in Parse() rather than +// ParseAndKeepRawInput(). +void CopyCoreFieldsOnly(const PhoneNumber& number, PhoneNumber* pruned_number) { + pruned_number->set_country_code(number.country_code()); + pruned_number->set_national_number(number.national_number()); + if (!number.extension().empty()) { + pruned_number->set_extension(number.extension()); + } + if (number.italian_leading_zero()) { + pruned_number->set_italian_leading_zero(true); + // This field is only relevant if there are leading zeros at all. + pruned_number->set_number_of_leading_zeros( + number.number_of_leading_zeros()); + } +} + } // namespace void PhoneNumberUtil::SetLogger(Logger* logger) { @@ -1937,6 +1956,9 @@ void PhoneNumberUtil::BuildNationalNumberForParsing( // RFC3966. } +// Note if any new field is added to this method that should always be filled +// in, even when keepRawInput is false, it should also be handled in the +// CopyCoreFieldsOnly() method. PhoneNumberUtil::ErrorType PhoneNumberUtil::ParseHelper( const string& number_to_parse, const string& default_region, @@ -2790,25 +2812,12 @@ PhoneNumberUtil::ErrorType PhoneNumberUtil::MaybeExtractCountryCode( PhoneNumberUtil::MatchType PhoneNumberUtil::IsNumberMatch( const PhoneNumber& first_number_in, const PhoneNumber& second_number_in) const { - // Make copies of the phone number so that the numbers passed in are not - // edited. - PhoneNumber first_number(first_number_in); - PhoneNumber second_number(second_number_in); - // First clear raw_input and country_code_source and - // preferred_domestic_carrier_code fields and any empty-string extensions so - // that we can use the proto-buffer equality method. - first_number.clear_raw_input(); - first_number.clear_country_code_source(); - first_number.clear_preferred_domestic_carrier_code(); - second_number.clear_raw_input(); - second_number.clear_country_code_source(); - second_number.clear_preferred_domestic_carrier_code(); - if (first_number.extension().empty()) { - first_number.clear_extension(); - } - if (second_number.extension().empty()) { - second_number.clear_extension(); - } + // We only are about the fields that uniquely define a number, so we copy + // these across explicitly. + PhoneNumber first_number; + CopyCoreFieldsOnly(first_number_in, &first_number); + PhoneNumber second_number; + CopyCoreFieldsOnly(second_number_in, &second_number); // Early exit if both had extensions and these are different. if (first_number.has_extension() && second_number.has_extension() && first_number.extension() != second_number.extension()) { diff --git a/cpp/test/phonenumbers/phonenumberutil_test.cc b/cpp/test/phonenumbers/phonenumberutil_test.cc index 841320a9f..571a51105 100644 --- a/cpp/test/phonenumbers/phonenumberutil_test.cc +++ b/cpp/test/phonenumbers/phonenumberutil_test.cc @@ -2835,7 +2835,72 @@ TEST_F(PhoneNumberUtilTest, IsNumberMatchMatches) { nz_number_2.set_national_number(33316005ULL); EXPECT_EQ(PhoneNumberUtil::EXACT_MATCH, phone_util_.IsNumberMatch(nz_number, nz_number_2)); +} + +TEST_F(PhoneNumberUtilTest, IsNumberMatchShortMatchIfDiffNumLeadingZeros) { + PhoneNumber nz_number_one; + nz_number_one.set_country_code(64); + nz_number_one.set_national_number(33316005ULL); + nz_number_one.set_italian_leading_zero(true); + + PhoneNumber nz_number_two; + nz_number_two.set_country_code(64); + nz_number_two.set_national_number(33316005ULL); + nz_number_two.set_italian_leading_zero(true); + nz_number_two.set_number_of_leading_zeros(2); + + EXPECT_EQ(PhoneNumberUtil::SHORT_NSN_MATCH, + phone_util_.IsNumberMatch(nz_number_one, nz_number_two)); + + nz_number_one.set_italian_leading_zero(false); + nz_number_one.set_number_of_leading_zeros(1); + nz_number_two.set_italian_leading_zero(true); + nz_number_two.set_number_of_leading_zeros(1); + // Since one doesn't have the "italian_leading_zero" set to true, we ignore + // the number of leading zeros present (1 is in any case the default value). + EXPECT_EQ(PhoneNumberUtil::SHORT_NSN_MATCH, + phone_util_.IsNumberMatch(nz_number_one, nz_number_two)); +} + +TEST_F(PhoneNumberUtilTest, IsNumberMatchAcceptsProtoDefaultsAsMatch) { + PhoneNumber nz_number_one; + nz_number_one.set_country_code(64); + nz_number_one.set_national_number(33316005ULL); + nz_number_one.set_italian_leading_zero(true); + + PhoneNumber nz_number_two; + nz_number_two.set_country_code(64); + nz_number_two.set_national_number(33316005ULL); + nz_number_two.set_italian_leading_zero(true); + // The default for number_of_leading_zeros is 1, so it shouldn't normally be + // set, however if it is it should be considered equivalent. + nz_number_two.set_number_of_leading_zeros(1); + EXPECT_EQ(PhoneNumberUtil::EXACT_MATCH, + phone_util_.IsNumberMatch(nz_number_one, nz_number_two)); +} + +TEST_F(PhoneNumberUtilTest, + IsNumberMatchMatchesDiffLeadingZerosIfItalianLeadingZeroFalse) { + PhoneNumber nz_number_one; + nz_number_one.set_country_code(64); + nz_number_one.set_national_number(33316005ULL); + + PhoneNumber nz_number_two; + nz_number_two.set_country_code(64); + nz_number_two.set_national_number(33316005ULL); + // The default for number_of_leading_zeros is 1, so it shouldn't normally be + // set, however if it is it should be considered equivalent. + nz_number_two.set_number_of_leading_zeros(1); + EXPECT_EQ(PhoneNumberUtil::EXACT_MATCH, + phone_util_.IsNumberMatch(nz_number_one, nz_number_two)); + // Even if it is set to ten, it is still equivalent because in both cases + // italian_leading_zero is not true. + nz_number_two.set_number_of_leading_zeros(10); + EXPECT_EQ(PhoneNumberUtil::EXACT_MATCH, + phone_util_.IsNumberMatch(nz_number_one, nz_number_two)); +} +TEST_F(PhoneNumberUtilTest, IsNumberMatchIgnoresSomeFields) { // Check raw_input, country_code_source and preferred_domestic_carrier_code // are ignored. PhoneNumber br_number_1; diff --git a/java/libphonenumber/src/com/google/i18n/phonenumbers/PhoneNumberUtil.java b/java/libphonenumber/src/com/google/i18n/phonenumbers/PhoneNumberUtil.java index 68961c43a..90a969e25 100644 --- a/java/libphonenumber/src/com/google/i18n/phonenumbers/PhoneNumberUtil.java +++ b/java/libphonenumber/src/com/google/i18n/phonenumbers/PhoneNumberUtil.java @@ -2943,6 +2943,9 @@ public class PhoneNumberUtil { * parse() method, with the exception that it allows the default region to be null, for use by * isNumberMatch(). checkRegion should be set to false if it is permitted for the default region * to be null or unknown ("ZZ"). + * + * Note if any new field is added to this method that should always be filled in, even when + * keepRawInput is false, it should also be handled in the copyCoreFieldsOnly() method. */ private void parseHelper(String numberToParse, String defaultRegion, boolean keepRawInput, boolean checkRegion, PhoneNumber phoneNumber) @@ -3105,6 +3108,26 @@ public class PhoneNumberUtil { // actually written in RFC3966. } + /** + * Returns a new phone number containing only the fields needed to uniquely identify a phone + * number, rather than any fields that capture the context in which the phone number was created. + * These fields correspond to those set in parse() rather than parseHelper(). + */ + private static PhoneNumber copyCoreFieldsOnly(PhoneNumber phoneNumberIn) { + PhoneNumber phoneNumber = new PhoneNumber(); + phoneNumber.setCountryCode(phoneNumberIn.getCountryCode()); + phoneNumber.setNationalNumber(phoneNumberIn.getNationalNumber()); + if (phoneNumberIn.getExtension().length() > 0) { + phoneNumber.setExtension(phoneNumberIn.getExtension()); + } + if (phoneNumberIn.isItalianLeadingZero()) { + phoneNumber.setItalianLeadingZero(true); + // This field is only relevant if there are leading zeros at all. + phoneNumber.setNumberOfLeadingZeros(phoneNumberIn.getNumberOfLeadingZeros()); + } + return phoneNumber; + } + /** * Takes two phone numbers and compares them for equality. * @@ -3126,27 +3149,10 @@ public class PhoneNumberUtil { * of the two numbers, described in the method definition. */ public MatchType isNumberMatch(PhoneNumber firstNumberIn, PhoneNumber secondNumberIn) { - // Make copies of the phone number so that the numbers passed in are not edited. - PhoneNumber firstNumber = new PhoneNumber(); - firstNumber.mergeFrom(firstNumberIn); - PhoneNumber secondNumber = new PhoneNumber(); - secondNumber.mergeFrom(secondNumberIn); - // First clear raw_input, country_code_source and preferred_domestic_carrier_code fields and any - // empty-string extensions so that we can use the proto-buffer equality method. - firstNumber.clearRawInput(); - firstNumber.clearCountryCodeSource(); - firstNumber.clearPreferredDomesticCarrierCode(); - secondNumber.clearRawInput(); - secondNumber.clearCountryCodeSource(); - secondNumber.clearPreferredDomesticCarrierCode(); - if (firstNumber.hasExtension() - && firstNumber.getExtension().length() == 0) { - firstNumber.clearExtension(); - } - if (secondNumber.hasExtension() - && secondNumber.getExtension().length() == 0) { - secondNumber.clearExtension(); - } + // We only care about the fields that uniquely define a number, so we copy these across + // explicitly. + PhoneNumber firstNumber = copyCoreFieldsOnly(firstNumberIn); + PhoneNumber secondNumber = copyCoreFieldsOnly(secondNumberIn); // Early exit if both had extensions and these are different. if (firstNumber.hasExtension() && secondNumber.hasExtension() && !firstNumber.getExtension().equals(secondNumber.getExtension())) { diff --git a/java/libphonenumber/test/com/google/i18n/phonenumbers/PhoneNumberUtilTest.java b/java/libphonenumber/test/com/google/i18n/phonenumbers/PhoneNumberUtilTest.java index 145dbe14f..faf11f9d5 100644 --- a/java/libphonenumber/test/com/google/i18n/phonenumbers/PhoneNumberUtilTest.java +++ b/java/libphonenumber/test/com/google/i18n/phonenumbers/PhoneNumberUtilTest.java @@ -2426,6 +2426,55 @@ public class PhoneNumberUtilTest extends TestMetadataTestCase { PhoneNumberUtil.MatchType.EXACT_MATCH, phoneUtil.isNumberMatch(nzNumber, NZ_NUMBER)); + } + + public void testIsNumberMatchShortMatchIfDiffNumLeadingZeros() throws Exception { + PhoneNumber nzNumberOne = new PhoneNumber(); + PhoneNumber nzNumberTwo = new PhoneNumber(); + nzNumberOne.setCountryCode(64).setNationalNumber(33316005L).setItalianLeadingZero(true); + nzNumberTwo.setCountryCode(64).setNationalNumber(33316005L).setItalianLeadingZero(true) + .setNumberOfLeadingZeros(2); + assertEquals(PhoneNumberUtil.MatchType.SHORT_NSN_MATCH, + phoneUtil.isNumberMatch(nzNumberOne, nzNumberTwo)); + + nzNumberOne.setItalianLeadingZero(false).setNumberOfLeadingZeros(1); + nzNumberTwo.setItalianLeadingZero(true).setNumberOfLeadingZeros(1); + // Since one doesn't have the "italian_leading_zero" set to true, we ignore the number of + // leading zeros present (1 is in any case the default value). + assertEquals(PhoneNumberUtil.MatchType.SHORT_NSN_MATCH, + phoneUtil.isNumberMatch(nzNumberOne, nzNumberTwo)); + } + + public void testIsNumberMatchAcceptsProtoDefaultsAsMatch() throws Exception { + PhoneNumber nzNumberOne = new PhoneNumber(); + PhoneNumber nzNumberTwo = new PhoneNumber(); + nzNumberOne.setCountryCode(64).setNationalNumber(33316005L).setItalianLeadingZero(true); + // The default for number_of_leading_zeros is 1, so it shouldn't normally be set, however if it + // is it should be considered equivalent. + nzNumberTwo.setCountryCode(64).setNationalNumber(33316005L).setItalianLeadingZero(true) + .setNumberOfLeadingZeros(1); + assertEquals(PhoneNumberUtil.MatchType.EXACT_MATCH, + phoneUtil.isNumberMatch(nzNumberOne, nzNumberTwo)); + } + + public void testIsNumberMatchMatchesDiffLeadingZerosIfItalianLeadingZeroFalse() throws Exception { + PhoneNumber nzNumberOne = new PhoneNumber(); + PhoneNumber nzNumberTwo = new PhoneNumber(); + nzNumberOne.setCountryCode(64).setNationalNumber(33316005L); + // The default for number_of_leading_zeros is 1, so it shouldn't normally be set, however if it + // is it should be considered equivalent. + nzNumberTwo.setCountryCode(64).setNationalNumber(33316005L).setNumberOfLeadingZeros(1); + assertEquals(PhoneNumberUtil.MatchType.EXACT_MATCH, + phoneUtil.isNumberMatch(nzNumberOne, nzNumberTwo)); + + // Even if it is set to ten, it is still equivalent because in both cases + // italian_leading_zero is not true. + nzNumberTwo.setNumberOfLeadingZeros(10); + assertEquals(PhoneNumberUtil.MatchType.EXACT_MATCH, + phoneUtil.isNumberMatch(nzNumberOne, nzNumberTwo)); + } + + public void testIsNumberMatchIgnoresSomeFields() throws Exception { // Check raw_input, country_code_source and preferred_domestic_carrier_code are ignored. PhoneNumber brNumberOne = new PhoneNumber(); PhoneNumber brNumberTwo = new PhoneNumber(); diff --git a/java/pending_code_changes.txt b/java/pending_code_changes.txt index f51397c7c..7471b7f56 100644 --- a/java/pending_code_changes.txt +++ b/java/pending_code_changes.txt @@ -6,3 +6,11 @@ Code changes: IS_POSSIBLE_LOCAL_ONLY will be returned for some values which currently return IS_POSSIBLE, and INVALID_LENGTH will be returned for some values which currently return TOO_LONG. + - Fix for isNumberMatch to ignore the numberOfLeadingZeros field when comparing + numbers unless hasItalianLeadingZero is true, and to consider default values + to match the same value when explicitly set for these two fields. This fix + shouldn't be needed for anyone correctly creating phone numbers using "parse" + as recommended. + - C++ only: Fix for ExactlySameAs when comparing phone numbers to include + comparison of the number_of_leading_zeros field. + - C++ only: Updating maximum length for NSN to be 17 (matches Java and JS) diff --git a/javascript/i18n/phonenumbers/demo-compiled.js b/javascript/i18n/phonenumbers/demo-compiled.js index 48898bdd8..84ca4f6ba 100644 --- a/javascript/i18n/phonenumbers/demo-compiled.js +++ b/javascript/i18n/phonenumbers/demo-compiled.js @@ -1,15 +1,16 @@ -(function(){for(var aa="function"==typeof Object.defineProperties?Object.defineProperty:function(a,b,c){if(c.get||c.set)throw new TypeError("ES3 does not support getters and setters.");a!=Array.prototype&&a!=Object.prototype&&(a[b]=c.value)},k="undefined"!=typeof window&&window===this?this:"undefined"!=typeof global&&null!=global?global:this,l=["String","prototype","repeat"],ba=0;baa||1342177279>>=1)b+=b;return c};fa!=ea&&null!=fa&&aa(k,da,{configurable:!0,writable:!0,value:fa}); -function ga(a){var b=typeof a;if("object"==b)if(a){if(a instanceof Array)return"array";if(a instanceof Object)return b;var c=Object.prototype.toString.call(a);if("[object Window]"==c)return"object";if("[object Array]"==c||"number"==typeof a.length&&"undefined"!=typeof a.splice&&"undefined"!=typeof a.propertyIsEnumerable&&!a.propertyIsEnumerable("splice"))return"array";if("[object Function]"==c||"undefined"!=typeof a.call&&"undefined"!=typeof a.propertyIsEnumerable&&!a.propertyIsEnumerable("call"))return"function"}else return"null"; -else if("function"==b&&"undefined"==typeof a.call)return"object";return b}function n(a){return"string"==typeof a}function p(a,b){function c(){}c.prototype=b.prototype;a.ca=b.prototype;a.prototype=new c;a.prototype.constructor=a;a.ma=function(a,c,f){for(var d=Array(arguments.length-2),e=2;ec?Math.max(0,a.length+c):c;if(n(a))return n(b)&&1==b.length?a.indexOf(b,c):-1;for(;cb?1:aa||1342177279>>=1)b+=b;return d}});ca("Math.sign",function(a){return a?a:function(a){a=Number(a);return!a||isNaN(a)?a:0c?Math.max(0,a.length+c):c;if(k(a))return k(b)&&1==b.length?a.indexOf(b,c):-1;for(;cb?1:aa.length?!1:N(eb,a)}function nb(a){return N(cb,a)?O(a,Wa):O(a,L)}function ob(a){var b=nb(a.toString());C(a);a.a(b)}function O(a,b){for(var c=new B,d,e=a.length,f=0;f=e)a=c;else if(d=d.substring(0,e),d=O(d,L),d.length)if(g=g.clone(),La(g,4),d=[g],g=x(b,1),c=Q(b),g in J){a=T(a,g,U(g));if(e=wb(d,c))d=e.clone(),e=x(e,4),0e?2:c[c.length-1]=f&&f<=e;++f)if(d=parseInt(c.substring(0,f),10),d in J)return b.a(c.substring(f)),d;return 0} -function Gb(a,b,c,d,e){if(!a.length)return 0;a=new B(a);var f;b&&(f=u(b,11));null==f&&(f="NonMatch");var g=a.toString();if(g.length)if(M.test(g))g=g.replace(M,""),C(a),a.a(nb(g)),f=1;else{g=new RegExp(f);ob(a);f=a.toString();if(f.search(g))f=!1;else{var g=f.match(g)[0].length,h=f.substring(g).match(Za);h&&null!=h[1]&&0=a.b.length)throw Error("Phone number too short after IDD");if(c=Fb(a, -c))return v(e,1,c),c;throw Error("Invalid country calling code");}if(b&&(f=x(b,10),g=""+f,h=a.toString(),!h.lastIndexOf(g,0))){var m=new B(h.substring(g.length)),g=u(b,1),h=new RegExp(x(g,2));Hb(m,b,null);b=m.toString();if(!N(h,a.toString())&&N(h,b)||3==Db(a.toString(),g))return c.a(b),d&&v(e,6,10),v(e,1,f),f}v(e,1,0);return 0} -function Hb(a,b,c){var d=a.toString(),e=d.length,f=u(b,15);if(e&&null!=f&&f.length){var g=new RegExp("^(?:"+f+")");if(e=g.exec(d)){var f=new RegExp(x(u(b,1),2)),h=N(f,d),m=e.length-1;b=u(b,16);if(null!=b&&b.length&&null!=e[m]&&e[m].length){if(d=d.replace(g,b),!h||N(f,d))c&&0g.b.length)throw Error("The string supplied is too short to be a phone number");b&&(a=new B,c=new B(g.toString()),Hb(c,b,a),2!=Db(c.toString(),u(b,1))&&(g=c,d&&0a)throw Error("The string supplied is too short to be a phone number");if(17a.length?!1:N($a,a)}function ib(a){return N(Ya,a)?O(a,Ra):O(a,L)}function jb(a){var b=ib(a.toString());C(a);a.a(b)}function O(a,b){for(var c=new B,d,e=a.length,f=0;f=e)a=c;else if(d=d.substring(0,e),d=O(d,L),d.length)if(g=g.clone(),Ga(g,4),d=[g],g=x(b,1),c=R(b),g in J){a=T(a,g,U(g));if(e=rb(d,c))d=e.clone(),e=x(e,4),0e?2:c[c.length-1]=f&&f<=e;++f)if(d=parseInt(c.substring(0,f),10),d in J)return b.a(c.substring(f)),d;return 0} +function Bb(a,b,c,d,e){if(!a.length)return 0;a=new B(a);var f;b&&(f=u(b,11));null==f&&(f="NonMatch");var g=a.toString();if(g.length)if(M.test(g))g=g.replace(M,""),C(a),a.a(ib(g)),f=1;else{g=new RegExp(f);jb(a);f=a.toString();if(f.search(g))f=!1;else{var g=f.match(g)[0].length,h=f.substring(g).match(Ua);h&&null!=h[1]&&0=a.b.length)throw Error("Phone number too short after IDD");if(c=Ab(a, +c))return v(e,1,c),c;throw Error("Invalid country calling code");}if(b&&(f=x(b,10),g=""+f,h=a.toString(),!h.lastIndexOf(g,0))){var m=new B(h.substring(g.length)),g=u(b,1),h=new RegExp(x(g,2));Cb(m,b,null);b=m.toString();if(!N(h,a.toString())&&N(h,b)||3==yb(a.toString(),g))return c.a(b),d&&v(e,6,10),v(e,1,f),f}v(e,1,0);return 0} +function Cb(a,b,c){var d=a.toString(),e=d.length,f=u(b,15);if(e&&null!=f&&f.length){var g=new RegExp("^(?:"+f+")");if(e=g.exec(d)){var f=new RegExp(x(u(b,1),2)),h=N(f,d),m=e.length-1;b=u(b,16);if(null!=b&&b.length&&null!=e[m]&&e[m].length){if(d=d.replace(g,b),!h||N(f,d))c&&0g.b.length)throw Error("The string supplied is too short to be a phone number");b&&(a=new B,c=new B(g.toString()),Cb(c,b,a),2!=yb(c.toString(),u(b,1))&&(g=c,d&&0a)throw Error("The string supplied is too short to be a phone number");if(17 0) { + phoneNumber.setExtension(numberIn.getExtensionOrDefault()); + } + if (numberIn.getItalianLeadingZero()) { + phoneNumber.setItalianLeadingZero(true); + // This field is only relevant if there are leading zeros at all. + phoneNumber.setNumberOfLeadingZeros( + numberIn.getNumberOfLeadingZerosOrDefault()); + } + return phoneNumber; +}; + + /** * Takes two phone numbers and compares them for equality. * @@ -4149,37 +4183,29 @@ i18n.phonenumbers.PhoneNumberUtil.prototype.isNumberMatch = } else { secondNumber = secondNumberIn.clone(); } - // First clear raw_input, country_code_source and - // preferred_domestic_carrier_code fields and any empty-string extensions so - // that we can use the proto-buffer equality method. - firstNumber.clearRawInput(); - firstNumber.clearCountryCodeSource(); - firstNumber.clearPreferredDomesticCarrierCode(); - secondNumber.clearRawInput(); - secondNumber.clearCountryCodeSource(); - secondNumber.clearPreferredDomesticCarrierCode(); - if (firstNumber.hasExtension() && firstNumber.getExtension().length == 0) { - firstNumber.clearExtension(); - } - if (secondNumber.hasExtension() && secondNumber.getExtension().length == 0) { - secondNumber.clearExtension(); - } + var firstNumberToCompare = + i18n.phonenumbers.PhoneNumberUtil.copyCoreFieldsOnly_(firstNumber); + var secondNumberToCompare = + i18n.phonenumbers.PhoneNumberUtil.copyCoreFieldsOnly_(secondNumber); // Early exit if both had extensions and these are different. - if (firstNumber.hasExtension() && secondNumber.hasExtension() && - firstNumber.getExtension() != secondNumber.getExtension()) { + if (firstNumberToCompare.hasExtension() && + secondNumberToCompare.hasExtension() && + firstNumberToCompare.getExtension() != + secondNumberToCompare.getExtension()) { return i18n.phonenumbers.PhoneNumberUtil.MatchType.NO_MATCH; } /** @type {number} */ - var firstNumberCountryCode = firstNumber.getCountryCodeOrDefault(); + var firstNumberCountryCode = firstNumberToCompare.getCountryCodeOrDefault(); /** @type {number} */ - var secondNumberCountryCode = secondNumber.getCountryCodeOrDefault(); + var secondNumberCountryCode = secondNumberToCompare.getCountryCodeOrDefault(); // Both had country_code specified. if (firstNumberCountryCode != 0 && secondNumberCountryCode != 0) { - if (firstNumber.equals(secondNumber)) { + if (firstNumberToCompare.equals(secondNumberToCompare)) { return i18n.phonenumbers.PhoneNumberUtil.MatchType.EXACT_MATCH; } else if (firstNumberCountryCode == secondNumberCountryCode && - this.isNationalNumberSuffixOfTheOther_(firstNumber, secondNumber)) { + this.isNationalNumberSuffixOfTheOther_( + firstNumberToCompare, secondNumberToCompare)) { // A SHORT_NSN_MATCH occurs if there is a difference because of the // presence or absence of an 'Italian leading zero', the presence or // absence of an extension, or one NSN being a shorter variant of the @@ -4192,13 +4218,14 @@ i18n.phonenumbers.PhoneNumberUtil.prototype.isNumberMatch = // Checks cases where one or both country_code fields were not specified. To // make equality checks easier, we first set the country_code fields to be // equal. - firstNumber.setCountryCode(0); - secondNumber.setCountryCode(0); + firstNumberToCompare.setCountryCode(0); + secondNumberToCompare.setCountryCode(0); // If all else was the same, then this is an NSN_MATCH. - if (firstNumber.equals(secondNumber)) { + if (firstNumberToCompare.equals(secondNumberToCompare)) { return i18n.phonenumbers.PhoneNumberUtil.MatchType.NSN_MATCH; } - if (this.isNationalNumberSuffixOfTheOther_(firstNumber, secondNumber)) { + if (this.isNationalNumberSuffixOfTheOther_(firstNumberToCompare, + secondNumberToCompare)) { return i18n.phonenumbers.PhoneNumberUtil.MatchType.SHORT_NSN_MATCH; } return i18n.phonenumbers.PhoneNumberUtil.MatchType.NO_MATCH; diff --git a/javascript/i18n/phonenumbers/phonenumberutil_test.js b/javascript/i18n/phonenumbers/phonenumberutil_test.js index 1e11bed93..22e85205a 100644 --- a/javascript/i18n/phonenumbers/phonenumberutil_test.js +++ b/javascript/i18n/phonenumbers/phonenumberutil_test.js @@ -3156,7 +3156,82 @@ function testIsNumberMatchMatches() { assertEquals('Numbers did not match', i18n.phonenumbers.PhoneNumberUtil.MatchType.EXACT_MATCH, phoneUtil.isNumberMatch(nzNumber, NZ_NUMBER)); +} + +function testIsNumberMatchShortMatchIfDiffNumLeadingZeros() { + /** @type {i18n.phonenumbers.PhoneNumber} */ + var nzNumberOne = new i18n.phonenumbers.PhoneNumber(); + /** @type {i18n.phonenumbers.PhoneNumber} */ + var nzNumberTwo = new i18n.phonenumbers.PhoneNumber(); + + nzNumberOne.setCountryCode(64); + nzNumberOne.setNationalNumber(33316005); + nzNumberOne.setItalianLeadingZero(true); + + nzNumberTwo.setCountryCode(64); + nzNumberTwo.setNationalNumber(33316005); + nzNumberTwo.setItalianLeadingZero(true); + nzNumberTwo.setNumberOfLeadingZeros(2); + + assertEquals(i18n.phonenumbers.PhoneNumberUtil.MatchType.SHORT_NSN_MATCH, + phoneUtil.isNumberMatch(nzNumberOne, nzNumberTwo)); + + nzNumberOne.setItalianLeadingZero(false); + nzNumberOne.setNumberOfLeadingZeros(1); + nzNumberTwo.setItalianLeadingZero(true); + nzNumberTwo.setNumberOfLeadingZeros(1); + // Since one doesn't have the "italian_leading_zero" set to true, we ignore + // the number of leading zeros present (1 is in any case the default value). + assertEquals(i18n.phonenumbers.PhoneNumberUtil.MatchType.SHORT_NSN_MATCH, + phoneUtil.isNumberMatch(nzNumberOne, nzNumberTwo)); +} + +function testIsNumberMatchAcceptsProtoDefaultsAsMatch() { + /** @type {i18n.phonenumbers.PhoneNumber} */ + var nzNumberOne = new i18n.phonenumbers.PhoneNumber(); + /** @type {i18n.phonenumbers.PhoneNumber} */ + var nzNumberTwo = new i18n.phonenumbers.PhoneNumber(); + + nzNumberOne.setCountryCode(64); + nzNumberOne.setNationalNumber(33316005); + nzNumberOne.setItalianLeadingZero(true); + + // The default for number_of_leading_zeros is 1, so it shouldn't normally be + // set, however if it is it should be considered equivalent. + nzNumberTwo.setCountryCode(64); + nzNumberTwo.setNationalNumber(33316005); + nzNumberTwo.setItalianLeadingZero(true); + nzNumberTwo.setNumberOfLeadingZeros(1); + + assertEquals(i18n.phonenumbers.PhoneNumberUtil.MatchType.EXACT_MATCH, + phoneUtil.isNumberMatch(nzNumberOne, nzNumberTwo)); +} + +function testIsNumberMatchMatchesDiffLeadingZerosIfItalianLeadingZeroFalse() { + /** @type {i18n.phonenumbers.PhoneNumber} */ + var nzNumberOne = new i18n.phonenumbers.PhoneNumber(); + /** @type {i18n.phonenumbers.PhoneNumber} */ + var nzNumberTwo = new i18n.phonenumbers.PhoneNumber(); + + nzNumberOne.setCountryCode(64); + nzNumberOne.setNationalNumber(33316005); + + // The default for number_of_leading_zeros is 1, so it shouldn't normally be + // set, however if it is it should be considered equivalent. + nzNumberTwo.setCountryCode(64); + nzNumberTwo.setNationalNumber(33316005); + nzNumberTwo.setNumberOfLeadingZeros(1); + + assertEquals(i18n.phonenumbers.PhoneNumberUtil.MatchType.EXACT_MATCH, + phoneUtil.isNumberMatch(nzNumberOne, nzNumberTwo)); + + // Even if it is set to ten, it is still equivalent because in both cases + // italian_leading_zero is not true. + assertEquals(i18n.phonenumbers.PhoneNumberUtil.MatchType.EXACT_MATCH, + phoneUtil.isNumberMatch(nzNumberOne, nzNumberTwo)); +} +function testIsNumberMatchIgnoresSomeFields() { var CCS = i18n.phonenumbers.PhoneNumber.CountryCodeSource; // Check raw_input, country_code_source and preferred_domestic_carrier_code // are ignored.