"src/phonenumbers/phonenumber.pb.cc" # Generated by Protocol Buffers.
"src/phonenumbers/phonenumberutil.cc"
"src/phonenumbers/regexp_cache.cc"
+ "src/phonenumbers/shortnumberutil.cc"
"src/phonenumbers/string_byte_sink.cc"
"src/phonenumbers/stringutil.cc"
"src/phonenumbers/unicodestring.cc"
"test/phonenumbers/regexp_adapter_test.cc"
"test/phonenumbers/regexp_cache_test.cc"
"test/phonenumbers/run_tests.cc"
+ "test/phonenumbers/shortnumberutil_test.cc"
"test/phonenumbers/stringutil_test.cc"
"test/phonenumbers/test_util.cc"
"test/phonenumbers/unicodestring_test.cc"
"src/phonenumbers/phonenumberutil.h"
"src/phonenumbers/regexp_adapter.h"
"src/phonenumbers/regexp_cache.h"
+ "src/phonenumbers/shortnumberutil.h"
"src/phonenumbers/unicodestring.h"
DESTINATION include/phonenumbers/
)
0x7B, 0x37, 0x7D, 0x7C, 0x31, 0x28, 0x3F, 0x3A, 0x28, 0x3F, 0x3A, 0x31, 0x28,
0x3F, 0x3A, 0x33, 0x5B, 0x30, 0x2D, 0x34, 0x38, 0x5D, 0x7C, 0x5B, 0x34, 0x36,
0x5D, 0x5B, 0x30, 0x2D, 0x34, 0x5D, 0x7C, 0x35, 0x5B, 0x30, 0x31, 0x32, 0x37,
- 0x38, 0x39, 0x5D, 0x7C, 0x37, 0x5B, 0x30, 0x2D, 0x33, 0x39, 0x5D, 0x7C, 0x38,
+ 0x38, 0x39, 0x5D, 0x7C, 0x37, 0x5B, 0x30, 0x2D, 0x34, 0x39, 0x5D, 0x7C, 0x38,
0x5B, 0x30, 0x31, 0x33, 0x34, 0x39, 0x5D, 0x29, 0x7C, 0x32, 0x31, 0x5B, 0x30,
0x2D, 0x37, 0x5D, 0x7C, 0x33, 0x31, 0x5B, 0x30, 0x2D, 0x38, 0x5D, 0x7C, 0x5B,
0x34, 0x35, 0x39, 0x5D, 0x31, 0x5C, 0x64, 0x7C, 0x36, 0x31, 0x5B, 0x30, 0x2D,
0x28, 0x3F, 0x3A, 0x31, 0x28, 0x3F, 0x3A, 0x33, 0x5B, 0x30, 0x2D, 0x34, 0x38,
0x5D, 0x7C, 0x5B, 0x34, 0x36, 0x5D, 0x5B, 0x30, 0x2D, 0x34, 0x5D, 0x7C, 0x35,
0x5B, 0x30, 0x31, 0x32, 0x37, 0x38, 0x39, 0x5D, 0x7C, 0x37, 0x5B, 0x30, 0x2D,
- 0x33, 0x39, 0x5D, 0x7C, 0x38, 0x5B, 0x30, 0x31, 0x33, 0x34, 0x39, 0x5D, 0x29,
+ 0x34, 0x39, 0x5D, 0x7C, 0x38, 0x5B, 0x30, 0x31, 0x33, 0x34, 0x39, 0x5D, 0x29,
0x7C, 0x32, 0x31, 0x5B, 0x30, 0x2D, 0x37, 0x5D, 0x7C, 0x33, 0x31, 0x5B, 0x30,
0x2D, 0x38, 0x5D, 0x7C, 0x5B, 0x34, 0x35, 0x39, 0x5D, 0x31, 0x5C, 0x64, 0x7C,
0x36, 0x31, 0x5B, 0x30, 0x2D, 0x34, 0x36, 0x2D, 0x39, 0x5D, 0x29, 0x29, 0x5C,
namespace i18n {
namespace phonenumbers {
+template <class R, class A1, class A2, class A3, class A4>
+ class ResultCallback4;
+
using std::string;
using std::vector;
#include "phonenumbers/phonenumberutil.h"
+#include <string.h>
#include <algorithm>
#include <cctype>
-#include <cstddef>
#include <fstream>
#include <iostream>
#include <iterator>
// unicode character.
// static
const char PhoneNumberUtil::kValidPunctuation[] =
- /* "-x‐-―−ー--/ <U+200B><U+2060> ()()[].\\[\\]/~⁓∼" */
+ /* "-x‐-―−ー--/ <U+200B><U+2060> ()()[].\\[\\]/~⁓∼" */
"-x\xE2\x80\x90-\xE2\x80\x95\xE2\x88\x92\xE3\x83\xBC\xEF\xBC\x8D-\xEF\xBC"
- "\x8F \xC2\xA0\xE2\x80\x8B\xE2\x81\xA0\xE3\x80\x80()\xEF\xBC\x88\xEF\xBC"
- "\x89\xEF\xBC\xBB\xEF\xBC\xBD.\\[\\]/~\xE2\x81\x93\xE2\x88\xBC";
+ "\x8F \xC2\xA0\xC2\xAD\xE2\x80\x8B\xE2\x81\xA0\xE3\x80\x80()\xEF\xBC\x88"
+ "\xEF\xBC\x89\xEF\xBC\xBB\xEF\xBC\xBD.\\[\\]/~\xE2\x81\x93\xE2\x88\xBC";
// static
const char PhoneNumberUtil::kCaptureUpToSecondNumberStart[] = "(.*)[\\\\/] *x";
const char kRfc3966ExtnPrefix[] = ";ext=";
const char kRfc3966Prefix[] = "tel:";
-// We include the "+" here since RFC3966 format specifies that the context must
-// be specified in international format.
-const char kRfc3966PhoneContext[] = ";phone-context=+";
+const char kRfc3966PhoneContext[] = ";phone-context=";
+const char kRfc3966IsdnSubaddress[] = ";isub=";
const char kDigits[] = "\\p{Nd}";
// We accept alpha characters in phone numbers, ASCII only. We store lower-case
kStarSign)),
valid_phone_number_(
StrCat("[", PhoneNumberUtil::kPlusChars, "]*(?:[",
- punctuation_and_star_sign_, "]*[",
- kDigits, "]){3,}[", kValidAlpha,
+ punctuation_and_star_sign_, "]*",
+ kDigits, "){3,}[", kValidAlpha,
punctuation_and_star_sign_, kDigits,
"]*")),
extn_patterns_for_parsing_(
return reg_exps_->extn_patterns_for_matching_;
}
+bool PhoneNumberUtil::StartsWithPlusCharsPattern(const string& number)
+ const {
+ const scoped_ptr<RegExpInput> number_string_piece(
+ reg_exps_->regexp_factory_->CreateInput(number));
+ return reg_exps_->plus_chars_pattern_->Consume(number_string_piece.get());
+}
+
bool PhoneNumberUtil::ContainsOnlyValidDigits(const string& s) const {
return reg_exps_->digits_pattern_->FullMatch(s);
}
// user entered.
if (!formatted_number->empty()) {
string formatted_number_copy(*formatted_number);
- NormalizeDigitsOnly(&formatted_number_copy);
+ NormalizeHelper(reg_exps_->diallable_char_mappings_,
+ true /* remove non matches */, &formatted_number_copy);
string raw_input_copy(number.raw_input());
- NormalizeDigitsOnly(&raw_input_copy);
+ NormalizeHelper(reg_exps_->diallable_char_mappings_,
+ true /* remove non matches */, &raw_input_copy);
if (formatted_number_copy != raw_input_copy) {
formatted_number->assign(number.raw_input());
}
return true;
}
-PhoneNumberUtil::ErrorType PhoneNumberUtil::ParseHelper(
- const string& number_to_parse,
- const string& default_region,
- bool keep_raw_input,
- bool check_region,
- PhoneNumber* phone_number) const {
- DCHECK(phone_number);
-
+// Converts number_to_parse to a form that we can parse and write it to
+// national_number if it is written in RFC3966; otherwise extract a possible
+// number out of it and write to national_number.
+void PhoneNumberUtil::BuildNationalNumberForParsing(
+ const string& number_to_parse, string* national_number) const {
size_t index_of_phone_context = number_to_parse.find(kRfc3966PhoneContext);
- string national_number;
if (index_of_phone_context != string::npos) {
- // Prefix the number with the phone context. The offset here is because the
- // context we are expecting to match should start with a "+" sign, and we
- // want to include this at the start of the number.
- StrAppend(
- &national_number,
- number_to_parse.substr(
- index_of_phone_context + strlen(kRfc3966PhoneContext) - 1));
+ int phone_context_start =
+ index_of_phone_context + strlen(kRfc3966PhoneContext);
+ // If the phone context contains a phone number prefix, we need to capture
+ // it, whereas domains will be ignored.
+ if (number_to_parse.at(phone_context_start) == kPlusSign[0]) {
+ // Additional parameters might follow the phone context. If so, we will
+ // remove them here because the parameters after phone context are not
+ // important for parsing the phone number.
+ size_t phone_context_end = number_to_parse.find(';', phone_context_start);
+ if (phone_context_end != string::npos) {
+ StrAppend(
+ national_number, number_to_parse.substr(
+ phone_context_start, phone_context_end - phone_context_start));
+ } else {
+ StrAppend(national_number, number_to_parse.substr(phone_context_start));
+ }
+ }
+
// Now append everything between the "tel:" prefix and the phone-context.
+ // This should include the national number, an optional extension or
+ // isdn-subaddress component.
int end_of_rfc_prefix =
number_to_parse.find(kRfc3966Prefix) + strlen(kRfc3966Prefix);
StrAppend(
- &national_number,
+ national_number,
number_to_parse.substr(end_of_rfc_prefix,
index_of_phone_context - end_of_rfc_prefix));
- // Note that phone-contexts that are URLs will not be parsed -
- // IsViablePhoneNumber will throw an exception below.
} else {
// Extract a possible number from the string passed in (this strips leading
// characters that could not be the start of a phone number.)
- ExtractPossibleNumber(number_to_parse, &national_number);
+ ExtractPossibleNumber(number_to_parse, national_number);
+ }
+
+ // Delete the isdn-subaddress and everything after it if it is present. Note
+ // extension won't appear at the same time with isdn-subaddress according to
+ // paragraph 5.3 of the RFC3966 spec.
+ size_t index_of_isdn = national_number->find(kRfc3966IsdnSubaddress);
+ if (index_of_isdn != string::npos) {
+ national_number->erase(index_of_isdn);
}
+ // If both phone context and isdn-subaddress are absent but other parameters
+ // are present, the parameters are left in nationalNumber. This is because
+ // we are concerned about deleting content from a potential number string
+ // when there is no strong evidence that the number is actually written in
+ // RFC3966.
+}
+
+PhoneNumberUtil::ErrorType PhoneNumberUtil::ParseHelper(
+ const string& number_to_parse,
+ const string& default_region,
+ bool keep_raw_input,
+ bool check_region,
+ PhoneNumber* phone_number) const {
+ DCHECK(phone_number);
+
+ string national_number;
+ BuildNationalNumberForParsing(number_to_parse, &national_number);
if (!IsViablePhoneNumber(national_number)) {
VLOG(2) << "The string supplied did not seem to be a phone number.";
phone_number->set_country_code_source(country_code_source);
}
if (country_code_source != PhoneNumber::FROM_DEFAULT_COUNTRY) {
- if (national_number->length() < kMinLengthForNsn) {
+ if (national_number->length() <= kMinLengthForNsn) {
VLOG(2) << "Phone number had an IDD, but after this was not "
<< "long enough to be a viable phone number.";
return TOO_SHORT_AFTER_IDD;
friend class PhoneNumberMatcherTest;
friend class PhoneNumberRegExpsAndMappings;
friend class PhoneNumberUtilTest;
+ friend class ShortNumberUtil;
+ friend class ShortNumberUtilTest;
public:
~PhoneNumberUtil();
static const char kRegionCodeForNonGeoEntity[];
// particular region is not performed. This can be done separately with
// IsValidNumber().
//
+ // number_to_parse can also be provided in RFC3966 format.
+ //
// default_region represents the country that we are expecting the number to
// be from. This is only used if the number being parsed is not written in
// international format. The country_code for the number in this case would be
typedef pair<int, list<string>*> IntRegionsPair;
// The minimum and maximum length of the national significant number.
- static const size_t kMinLengthForNsn = 3;
+ static const size_t kMinLengthForNsn = 2;
// The ITU says the maximum length should be 15, but we have found longer
// numbers in Germany.
static const size_t kMaxLengthForNsn = 16;
// in a number, for use when matching.
const string& GetExtnPatternsForMatching() const;
+ // Checks if a number matches the plus chars pattern.
+ bool StartsWithPlusCharsPattern(const string& number) const;
+
// Checks whether a string contains only valid digits.
bool ContainsOnlyValidDigits(const string& s) const;
bool check_region,
PhoneNumber* phone_number) const;
+ void BuildNationalNumberForParsing(const string& number_to_parse,
+ string* national_number) const;
+
// Returns true if the number can be dialled from outside the region, or
// unknown. If the number can only be dialled from within the region, returns
// false. Does not check the number is a valid number.
--- /dev/null
+// Copyright (C) 2012 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.
+
+// Author: David Yonge-Mallo
+
+#include "phonenumbers/shortnumberutil.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "phonenumbers/phonemetadata.pb.h"
+#include "phonenumbers/phonenumberutil.h"
+#include "phonenumbers/regexp_adapter.h"
+#include "phonenumbers/regexp_factory.h"
+
+namespace i18n {
+namespace phonenumbers {
+
+using std::string;
+
+ShortNumberUtil::ShortNumberUtil()
+ : phone_util_(*PhoneNumberUtil::GetInstance()) {
+}
+
+bool ShortNumberUtil::ConnectsToEmergencyNumber(const string& number,
+ const string& region_code) const {
+ return MatchesEmergencyNumberHelper(number, region_code,
+ true /* allows prefix match */);
+}
+
+bool ShortNumberUtil::IsEmergencyNumber(const string& number,
+ const string& region_code) const {
+ return MatchesEmergencyNumberHelper(number, region_code,
+ false /* doesn't allow prefix match */);
+}
+
+bool ShortNumberUtil::MatchesEmergencyNumberHelper(const string& number,
+ const string& region_code, bool allow_prefix_match) const {
+ string extracted_number;
+ phone_util_.ExtractPossibleNumber(number, &extracted_number);
+ if (phone_util_.StartsWithPlusCharsPattern(extracted_number)) {
+ // Returns false if the number starts with a plus sign. We don't believe
+ // dialing the country code before emergency numbers (e.g. +1911) works,
+ // but later, if that proves to work, we can add additional logic here to
+ // handle it.
+ return false;
+ }
+ const PhoneMetadata* metadata = phone_util_.GetMetadataForRegion(region_code);
+ if (!metadata || !metadata->has_emergency()) {
+ return false;
+ }
+ const scoped_ptr<const AbstractRegExpFactory> regexp_factory(
+ new RegExpFactory());
+ const scoped_ptr<const RegExp> emergency_number_pattern(
+ regexp_factory->CreateRegExp(
+ metadata->emergency().national_number_pattern()));
+ phone_util_.NormalizeDigitsOnly(&extracted_number);
+ const scoped_ptr<RegExpInput> normalized_number_input(
+ regexp_factory->CreateInput(extracted_number));
+
+ // In Brazil, it is impossible to append additional digits to an emergency
+ // number to dial the number.
+ return (!allow_prefix_match || region_code == "BR")
+ ? emergency_number_pattern->FullMatch(extracted_number)
+ : emergency_number_pattern->Consume(normalized_number_input.get());
+}
+
+} // namespace phonenumbers
+} // namespace i18n
--- /dev/null
+// Copyright (C) 2012 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.
+
+// Utility for international short phone numbers, such as short codes and
+// emergency numbers. Note most commercial short numbers are not handled here,
+// but by the phonenumberutil.
+//
+// Author: David Yonge-Mallo
+//
+// This is a direct port from ShortNumberUtil.java.
+// Changes to this class should also happen to the Java version, whenever it
+// makes sense.
+
+#ifndef I18N_PHONENUMBERS_SHORTNUMBERUTIL_H_
+#define I18N_PHONENUMBERS_SHORTNUMBERUTIL_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+
+namespace i18n {
+namespace phonenumbers {
+
+using std::string;
+
+class PhoneNumberUtil;
+
+class ShortNumberUtil {
+ public:
+ ShortNumberUtil();
+
+ // Returns true if the number might be used to connect to an emergency service
+ // in the given region.
+ //
+ // This method takes into account cases where the number might contain
+ // formatting, or might have additional digits appended (when it is okay to do
+ // that in the region specified).
+ bool ConnectsToEmergencyNumber(const string& number,
+ const string& region_code) const;
+
+ // Returns true if the number exactly matches an emergency service number in
+ // the given region.
+ //
+ // This method takes into account cases where the number might contain
+ // formatting, but doesn't allow additional digits to be appended.
+ bool IsEmergencyNumber(const string& number,
+ const string& region_code) const;
+
+ private:
+ const PhoneNumberUtil& phone_util_;
+
+ bool MatchesEmergencyNumberHelper(const string& number,
+ const string& region_code,
+ bool allow_prefix_match) const;
+
+ DISALLOW_COPY_AND_ASSIGN(ShortNumberUtil);
+};
+
+} // namespace phonenumbers
+} // namespace i18n
+
+#endif // I18N_PHONENUMBERS_SHORTNUMBERUTIL_H_
phone_util_.GetExampleNumberForNonGeoEntity(800 , &test_number);
EXPECT_TRUE(success);
EXPECT_EQ(toll_free_number, test_number);
+
+ PhoneNumber universal_premium_rate;
+ universal_premium_rate.set_country_code(979);
+ universal_premium_rate.set_national_number(123456789ULL);
+ success = phone_util_.GetExampleNumberForNonGeoEntity(979 , &test_number);
+ EXPECT_TRUE(success);
+ EXPECT_EQ(universal_premium_rate, test_number);
}
TEST_F(PhoneNumberUtilTest, FormatUSNumber) {
intl_toll_free_number.set_country_code(800);
intl_toll_free_number.set_national_number(12345678ULL);
EXPECT_TRUE(phone_util_.IsValidNumber(intl_toll_free_number));
+
+ PhoneNumber universal_premium_rate;
+ universal_premium_rate.set_country_code(979);
+ universal_premium_rate.set_national_number(123456789ULL);
+ EXPECT_TRUE(phone_util_.IsValidNumber(universal_premium_rate));
}
TEST_F(PhoneNumberUtilTest, IsValidForRegion) {
EXPECT_FALSE(phone_util_.IsValidNumber(intl_toll_free_number_too_long));
}
+TEST_F(PhoneNumberUtilTest, GetRegionCodeForCountryCode) {
+ string region_code;
+ phone_util_.GetRegionCodeForCountryCode(1, ®ion_code);
+ EXPECT_EQ(RegionCode::US(), region_code);
+ phone_util_.GetRegionCodeForCountryCode(44, ®ion_code);
+ EXPECT_EQ(RegionCode::GB(), region_code);
+ phone_util_.GetRegionCodeForCountryCode(49, ®ion_code);
+ EXPECT_EQ(RegionCode::DE(), region_code);
+ phone_util_.GetRegionCodeForCountryCode(800, ®ion_code);
+ EXPECT_EQ(RegionCode::UN001(), region_code);
+ phone_util_.GetRegionCodeForCountryCode(979, ®ion_code);
+ EXPECT_EQ(RegionCode::UN001(), region_code);
+}
+
+TEST_F(PhoneNumberUtilTest, GetRegionCodeForNumber) {
+ string region_code;
+ PhoneNumber bs_number;
+ bs_number.set_country_code(1);
+ bs_number.set_national_number(2423232345ULL);
+ phone_util_.GetRegionCodeForNumber(bs_number, ®ion_code);
+ EXPECT_EQ(RegionCode::BS(), region_code);
+
+ PhoneNumber us_number;
+ us_number.set_country_code(1);
+ us_number.set_national_number(4241231234ULL);
+ phone_util_.GetRegionCodeForNumber(us_number, ®ion_code);
+ EXPECT_EQ(RegionCode::US(), region_code);
+
+ PhoneNumber gb_mobile;
+ gb_mobile.set_country_code(44);
+ gb_mobile.set_national_number(7912345678ULL);
+ phone_util_.GetRegionCodeForNumber(gb_mobile, ®ion_code);
+ EXPECT_EQ(RegionCode::GB(), region_code);
+
+ PhoneNumber intl_toll_free_number;
+ intl_toll_free_number.set_country_code(800);
+ intl_toll_free_number.set_national_number(12345678ULL);
+ phone_util_.GetRegionCodeForNumber(intl_toll_free_number, ®ion_code);
+ EXPECT_EQ(RegionCode::UN001(), region_code);
+
+ PhoneNumber universal_premium_rate;
+ universal_premium_rate.set_country_code(979);
+ universal_premium_rate.set_national_number(123456789ULL);
+ phone_util_.GetRegionCodeForNumber(universal_premium_rate, ®ion_code);
+ EXPECT_EQ(RegionCode::UN001(), region_code);
+}
+
TEST_F(PhoneNumberUtilTest, IsPossibleNumber) {
PhoneNumber number;
number.set_country_code(1);
EXPECT_EQ(PhoneNumberUtil::IS_POSSIBLE,
phone_util_.IsPossibleNumberWithReason(ad_number));
ad_number.set_country_code(376);
- ad_number.set_national_number(13ULL);
+ ad_number.set_national_number(1ULL);
EXPECT_EQ(PhoneNumberUtil::TOO_SHORT,
phone_util_.IsPossibleNumberWithReason(ad_number));
ad_number.set_country_code(376);
phone_util_.FormatInOriginalFormat(phone_number, RegionCode::AU(),
&formatted_number);
EXPECT_EQ("0011 1 650 253 0000", formatted_number);
+
+ // Test the star sign is not removed from or added to the original input by
+ // this method.
+ phone_number.Clear();
+ formatted_number.clear();
+ EXPECT_EQ(PhoneNumberUtil::NO_PARSING_ERROR,
+ phone_util_.ParseAndKeepRawInput("*1234",
+ RegionCode::JP(),
+ &phone_number));
+ phone_util_.FormatInOriginalFormat(phone_number, RegionCode::JP(),
+ &formatted_number);
+ EXPECT_EQ("*1234", formatted_number);
+ phone_number.Clear();
+ formatted_number.clear();
+ EXPECT_EQ(PhoneNumberUtil::NO_PARSING_ERROR,
+ phone_util_.ParseAndKeepRawInput("1234",
+ RegionCode::JP(),
+ &phone_number));
+ phone_util_.FormatInOriginalFormat(phone_number, RegionCode::JP(),
+ &formatted_number);
+ EXPECT_EQ("1234", formatted_number);
}
TEST_F(PhoneNumberUtilTest, IsPremiumRate) {
number.set_country_code(49);
number.set_national_number(90091234567ULL);
EXPECT_EQ(PhoneNumberUtil::PREMIUM_RATE, phone_util_.GetNumberType(number));
+
+ number.set_country_code(979);
+ number.set_national_number(123456789ULL);
+ EXPECT_EQ(PhoneNumberUtil::PREMIUM_RATE, phone_util_.GetNumberType(number));
}
TEST_F(PhoneNumberUtilTest, IsTollFree) {
}
TEST_F(PhoneNumberUtilTest, NormaliseRemovePunctuation) {
- string input_number("034-56&+#234");
+ string input_number("034-56&+#2" "\xC2\xAD" "34");
Normalize(&input_number);
static const string kExpectedOutput("03456234");
EXPECT_EQ(kExpectedOutput, input_number)
EXPECT_EQ(PhoneNumberUtil::EXACT_MATCH,
phone_util_.IsNumberMatchWithTwoStrings("+64 3 331-6005",
"+6433316005"));
+ EXPECT_EQ(PhoneNumberUtil::EXACT_MATCH,
+ phone_util_.IsNumberMatchWithTwoStrings(
+ "+64 3 331-6005", "tel:+64-3-331-6005;isub=123"));
// Test alpha numbers.
EXPECT_EQ(PhoneNumberUtil::EXACT_MATCH,
phone_util_.IsNumberMatchWithTwoStrings("+1800 siX-Flags",
phone_util_.IsNumberMatch(br_number_1, br_number_2));
}
-TEST_F(PhoneNumberUtilTest, IsNumberMatchNonMetches) {
+TEST_F(PhoneNumberUtilTest, IsNumberMatchNonMatches) {
// NSN matches.
EXPECT_EQ(PhoneNumberUtil::NO_MATCH,
phone_util_.IsNumberMatchWithTwoStrings("03 331 6005",
EXPECT_EQ(PhoneNumberUtil::NO_MATCH,
phone_util_.IsNumberMatchWithTwoStrings("+64 3 331-6005 extn 1234",
"+0116433316005#1235"));
+ EXPECT_EQ(PhoneNumberUtil::NO_MATCH,
+ phone_util_.IsNumberMatchWithTwoStrings(
+ "+64 3 331-6005 extn 1234", "tel:+64-3-331-6005;ext=1235"));
// NSN matches, but extension is different - not the same number.
EXPECT_EQ(PhoneNumberUtil::NO_MATCH,
phone_util_.IsNumberMatchWithTwoStrings("+64 3 331-6005 ext.1235",
EXPECT_EQ(PhoneNumberUtil::NSN_MATCH,
phone_util_.IsNumberMatchWithTwoStrings("+64 3 331-6005",
"03 331 6005"));
+ EXPECT_EQ(PhoneNumberUtil::NSN_MATCH,
+ phone_util_.IsNumberMatchWithTwoStrings(
+ "+64 3 331-6005",
+ "tel:03-331-6005;isub=1234;phone-context=abc.nz"));
PhoneNumber nz_number;
nz_number.set_country_code(64);
EXPECT_EQ(PhoneNumberUtil::SHORT_NSN_MATCH,
phone_util_.IsNumberMatchWithTwoStrings("+64 3 331-6005",
"331 6005"));
+ EXPECT_EQ(PhoneNumberUtil::SHORT_NSN_MATCH,
+ phone_util_.IsNumberMatchWithTwoStrings(
+ "+64 3 331-6005", "tel:331-6005;phone-context=abc.nz"));
+ EXPECT_EQ(PhoneNumberUtil::SHORT_NSN_MATCH,
+ phone_util_.IsNumberMatchWithTwoStrings(
+ "+64 3 331-6005",
+ "tel:331-6005;isub=1234;phone-context=abc.nz"));
+ EXPECT_EQ(PhoneNumberUtil::SHORT_NSN_MATCH,
+ phone_util_.IsNumberMatchWithTwoStrings(
+ "+64 3 331-6005",
+ "tel:331-6005;isub=1234;phone-context=abc.nz;a=%A1"));
// We did not know that the "0" was a national prefix since neither number has
// a country code, so this is considered a SHORT_NSN_MATCH.
"331 6005"));
EXPECT_EQ(PhoneNumberUtil::SHORT_NSN_MATCH,
+ phone_util_.IsNumberMatchWithTwoStrings(
+ "3 331-6005", "tel:331-6005;phone-context=abc.nz"));
+ EXPECT_EQ(PhoneNumberUtil::SHORT_NSN_MATCH,
phone_util_.IsNumberMatchWithTwoStrings("3 331-6005",
"+64 331 6005"));
phone_util_.Parse("tel:331-6005;phone-context=+64-3",
RegionCode::US(), &test_number));
EXPECT_EQ(nz_number, test_number);
-
+ // Test parsing RFC3966 format with optional user-defined parameters. The
+ // parameters will appear after the context if present.
+ EXPECT_EQ(PhoneNumberUtil::NO_PARSING_ERROR,
+ phone_util_.Parse("tel:03-331-6005;phone-context=+64;a=%A1",
+ RegionCode::NZ(), &test_number));
+ EXPECT_EQ(nz_number, test_number);
+ // Test parsing RFC3966 with an ISDN subaddress.
+ EXPECT_EQ(PhoneNumberUtil::NO_PARSING_ERROR,
+ phone_util_.Parse("tel:03-331-6005;isub=12345;phone-context=+64",
+ RegionCode::NZ(), &test_number));
+ EXPECT_EQ(nz_number, test_number);
+ EXPECT_EQ(PhoneNumberUtil::NO_PARSING_ERROR,
+ phone_util_.Parse("tel:+64-3-331-6005;isub=12345",
+ RegionCode::US(), &test_number));
+ EXPECT_EQ(nz_number, test_number);
// Testing international prefixes.
// Should strip country code.
test_number.Clear();
RegionCode::NZ(), &test_number));
EXPECT_EQ(nz_number, test_number);
+ PhoneNumber us_local_number;
+ us_local_number.set_country_code(1);
+ us_local_number.set_national_number(2530000ULL);
+ test_number.Clear();
+ EXPECT_EQ(PhoneNumberUtil::NO_PARSING_ERROR,
+ phone_util_.Parse("tel:253-0000;phone-context=www.google.com",
+ RegionCode::US(), &test_number));
+ EXPECT_EQ(us_local_number, test_number);
+ test_number.Clear();
+ EXPECT_EQ(PhoneNumberUtil::NO_PARSING_ERROR,
+ phone_util_.Parse(
+ "tel:253-0000;isub=12345;phone-context=www.google.com",
+ RegionCode::US(), &test_number));
+ EXPECT_EQ(us_local_number, test_number);
+ // This is invalid because no "+" sign is present as part of phone-context.
+ // The phone context is simply ignored in this case just as if it contains a
+ // domain.
+ test_number.Clear();
+ EXPECT_EQ(PhoneNumberUtil::NO_PARSING_ERROR,
+ phone_util_.Parse("tel:2530000;isub=12345;phone-context=1-650",
+ RegionCode::US(), &test_number));
+ EXPECT_EQ(us_local_number, test_number);
+ test_number.Clear();
+ EXPECT_EQ(PhoneNumberUtil::NO_PARSING_ERROR,
+ phone_util_.Parse("tel:2530000;isub=12345;phone-context=1234.com",
+ RegionCode::US(), &test_number));
+ EXPECT_EQ(us_local_number, test_number);
+
// Test for http://b/issue?id=2247493
nz_number.Clear();
nz_number.set_country_code(64);
phone_util_.Parse("\xEF\xBC\x8B" "1 (650) 333-6000",
/* "+1 (650) 333-6000" */
RegionCode::SG(), &test_number));
+ // Using a soft hyphen U+00AD.
+ test_number.Clear();
+ EXPECT_EQ(PhoneNumberUtil::NO_PARSING_ERROR,
+ phone_util_.Parse("1 (650) 333" "\xC2\xAD" "-6000",
+ /* "1 (650) 333-6000" */
+ RegionCode::US(), &test_number));
EXPECT_EQ(us_number, test_number);
// The whole number, including punctuation, is here represented in full-width
// form.
EXPECT_EQ(PhoneNumber::default_instance(), test_number);
// RFC3966 phone-context is a website.
- EXPECT_EQ(PhoneNumberUtil::NOT_A_NUMBER,
- phone_util_.Parse("tel:555-1234;phone-context:www.google.com",
- RegionCode::US(), &test_number));
+ EXPECT_EQ(PhoneNumberUtil::INVALID_COUNTRY_CODE_ERROR,
+ phone_util_.Parse("tel:555-1234;phone-context=www.google.com",
+ RegionCode::ZZ(), &test_number));
EXPECT_EQ(PhoneNumber::default_instance(), test_number);
// This is invalid because no "+" sign is present as part of phone-context.
// This should not succeed in being parsed.
- EXPECT_EQ(PhoneNumberUtil::NOT_A_NUMBER,
- phone_util_.Parse("tel:555-1234;phone-context:1-331",
- RegionCode::US(), &test_number));
+ EXPECT_EQ(PhoneNumberUtil::INVALID_COUNTRY_CODE_ERROR,
+ phone_util_.Parse("tel:555-1234;phone-context=1-331",
+ RegionCode::ZZ(), &test_number));
EXPECT_EQ(PhoneNumber::default_instance(), test_number);
}
RegionCode::GetUnknown(), &result_proto));
EXPECT_EQ(toll_free_number, result_proto);
+ PhoneNumber universal_premium_rate;
+ universal_premium_rate.set_country_code(979);
+ universal_premium_rate.set_national_number(123456789ULL);
+ result_proto.Clear();
+ EXPECT_EQ(PhoneNumberUtil::NO_PARSING_ERROR,
+ phone_util_.Parse("+979 123 456 789",
+ RegionCode::GetUnknown(), &result_proto));
+ EXPECT_EQ(universal_premium_rate, result_proto);
+
result_proto.Clear();
// Test parsing RFC3966 format with a phone context.
EXPECT_EQ(PhoneNumberUtil::NO_PARSING_ERROR,
phone_util_.Parse(" tel:03-331-6005;phone-context=+64",
RegionCode::GetUnknown(), &result_proto));
EXPECT_EQ(nz_number, result_proto);
+ result_proto.Clear();
+ EXPECT_EQ(PhoneNumberUtil::NO_PARSING_ERROR,
+ phone_util_.Parse("tel:03-331-6005;isub=12345;phone-context=+64",
+ RegionCode::GetUnknown(), &result_proto));
+ EXPECT_EQ(nz_number, result_proto);
nz_number.set_raw_input("+64 3 331 6005");
nz_number.set_country_code_source(PhoneNumber::FROM_NUMBER_WITH_PLUS_SIGN);
EXPECT_TRUE(phone_util_.IsAlphaNumber(kAlphaNumber));
static const string kAlphaNumberWithExtension = "1800 six-flags ext. 1234";
EXPECT_TRUE(phone_util_.IsAlphaNumber(kAlphaNumberWithExtension));
- static const string kI18NAlphaNumber("+800 six-flags");
- EXPECT_TRUE(phone_util_.IsAlphaNumber(kI18NAlphaNumber));
+ static const string kI18nAlphaNumber("+800 six-flags");
+ EXPECT_TRUE(phone_util_.IsAlphaNumber(kI18nAlphaNumber));
static const string kNonAlphaNumber("1800 123-1234");
EXPECT_FALSE(phone_util_.IsAlphaNumber(kNonAlphaNumber));
static const string kNonAlphaNumberWithExtension(
"1800 123-1234 extension: 1234");
EXPECT_FALSE(phone_util_.IsAlphaNumber(kNonAlphaNumberWithExtension));
- static const string kI18NNonAlphaNumber("+800 1234-1234");
- EXPECT_FALSE(phone_util_.IsAlphaNumber(kI18NNonAlphaNumber));
+ static const string kI18nNonAlphaNumber("+800 1234-1234");
+ EXPECT_FALSE(phone_util_.IsAlphaNumber(kI18nNonAlphaNumber));
}
} // namespace phonenumbers
--- /dev/null
+// Copyright (C) 2009 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.
+
+// Author: David Yonge-Mallo
+
+#include <gtest/gtest.h>
+
+#include "phonenumbers/phonenumberutil.h"
+#include "phonenumbers/shortnumberutil.h"
+#include "phonenumbers/test_util.h"
+
+namespace i18n {
+namespace phonenumbers {
+
+class ShortNumberUtilTest : public testing::Test {
+ protected:
+ ShortNumberUtilTest() : short_util_() {
+ }
+
+ const ShortNumberUtil short_util_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ShortNumberUtilTest);
+};
+
+TEST_F(ShortNumberUtilTest, ConnectsToEmergencyNumber_US) {
+ EXPECT_TRUE(short_util_.ConnectsToEmergencyNumber("911", RegionCode::US()));
+ EXPECT_TRUE(short_util_.ConnectsToEmergencyNumber("119", RegionCode::US()));
+ EXPECT_FALSE(short_util_.ConnectsToEmergencyNumber("999", RegionCode::US()));
+}
+
+TEST_F(ShortNumberUtilTest, ConnectsToEmergencyNumberLongNumber_US) {
+ EXPECT_TRUE(short_util_.ConnectsToEmergencyNumber("9116666666",
+ RegionCode::US()));
+ EXPECT_TRUE(short_util_.ConnectsToEmergencyNumber("1196666666",
+ RegionCode::US()));
+ EXPECT_FALSE(short_util_.ConnectsToEmergencyNumber("9996666666",
+ RegionCode::US()));
+}
+
+TEST_F(ShortNumberUtilTest, ConnectsToEmergencyNumberWithFormatting_US) {
+ EXPECT_TRUE(short_util_.ConnectsToEmergencyNumber("9-1-1", RegionCode::US()));
+ EXPECT_TRUE(short_util_.ConnectsToEmergencyNumber("1-1-9", RegionCode::US()));
+ EXPECT_FALSE(short_util_.ConnectsToEmergencyNumber("9-9-9",
+ RegionCode::US()));
+}
+
+TEST_F(ShortNumberUtilTest, ConnectsToEmergencyNumberWithPlusSign_US) {
+ EXPECT_FALSE(short_util_.ConnectsToEmergencyNumber("+911", RegionCode::US()));
+ // This hex sequence is the full-width plus sign U+FF0B.
+ EXPECT_FALSE(short_util_.ConnectsToEmergencyNumber("\xEF\xBC\x8B" "911",
+ RegionCode::US()));
+ EXPECT_FALSE(short_util_.ConnectsToEmergencyNumber(" +911",
+ RegionCode::US()));
+ EXPECT_FALSE(short_util_.ConnectsToEmergencyNumber("+119", RegionCode::US()));
+ EXPECT_FALSE(short_util_.ConnectsToEmergencyNumber("+999", RegionCode::US()));
+}
+
+TEST_F(ShortNumberUtilTest, ConnectsToEmergencyNumber_BR) {
+ EXPECT_TRUE(short_util_.ConnectsToEmergencyNumber("911", RegionCode::BR()));
+ EXPECT_TRUE(short_util_.ConnectsToEmergencyNumber("190", RegionCode::BR()));
+ EXPECT_FALSE(short_util_.ConnectsToEmergencyNumber("999", RegionCode::BR()));
+}
+
+TEST_F(ShortNumberUtilTest, ConnectsToEmergencyNumberLongNumber_BR) {
+ // Brazilian emergency numbers don't work when additional digits are appended.
+ EXPECT_FALSE(short_util_.ConnectsToEmergencyNumber("9111", RegionCode::BR()));
+ EXPECT_FALSE(short_util_.ConnectsToEmergencyNumber("1900", RegionCode::BR()));
+ EXPECT_FALSE(short_util_.ConnectsToEmergencyNumber("9996", RegionCode::BR()));
+}
+
+TEST_F(ShortNumberUtilTest, ConnectsToEmergencyNumber_AO) {
+ // Angola doesn't have any metadata for emergency numbers in the test
+ // metadata.
+ EXPECT_FALSE(short_util_.ConnectsToEmergencyNumber("911", RegionCode::AO()));
+ EXPECT_FALSE(short_util_.ConnectsToEmergencyNumber("222123456",
+ RegionCode::AO()));
+ EXPECT_FALSE(short_util_.ConnectsToEmergencyNumber("923123456",
+ RegionCode::AO()));
+}
+
+TEST_F(ShortNumberUtilTest, ConnectsToEmergencyNumber_ZW) {
+ // Zimbabwe doesn't have any metadata in the test metadata.
+ EXPECT_FALSE(short_util_.ConnectsToEmergencyNumber("911", RegionCode::ZW()));
+ EXPECT_FALSE(short_util_.ConnectsToEmergencyNumber("01312345",
+ RegionCode::ZW()));
+ EXPECT_FALSE(short_util_.ConnectsToEmergencyNumber("0711234567",
+ RegionCode::ZW()));
+}
+
+TEST_F(ShortNumberUtilTest, IsEmergencyNumber_US) {
+ EXPECT_TRUE(short_util_.IsEmergencyNumber("911", RegionCode::US()));
+ EXPECT_TRUE(short_util_.IsEmergencyNumber("119", RegionCode::US()));
+ EXPECT_FALSE(short_util_.IsEmergencyNumber("999", RegionCode::US()));
+}
+
+TEST_F(ShortNumberUtilTest, IsEmergencyNumberLongNumber_US) {
+ EXPECT_FALSE(short_util_.IsEmergencyNumber("9116666666", RegionCode::US()));
+ EXPECT_FALSE(short_util_.IsEmergencyNumber("1196666666", RegionCode::US()));
+ EXPECT_FALSE(short_util_.IsEmergencyNumber("9996666666", RegionCode::US()));
+}
+
+TEST_F(ShortNumberUtilTest, IsEmergencyNumberWithFormatting_US) {
+ EXPECT_TRUE(short_util_.IsEmergencyNumber("9-1-1", RegionCode::US()));
+ EXPECT_TRUE(short_util_.IsEmergencyNumber("*911", RegionCode::US()));
+ EXPECT_TRUE(short_util_.IsEmergencyNumber("1-1-9", RegionCode::US()));
+ EXPECT_TRUE(short_util_.IsEmergencyNumber("*119", RegionCode::US()));
+ EXPECT_FALSE(short_util_.IsEmergencyNumber("9-9-9", RegionCode::US()));
+ EXPECT_FALSE(short_util_.IsEmergencyNumber("*999", RegionCode::US()));
+}
+
+TEST_F(ShortNumberUtilTest, IsEmergencyNumberWithPlusSign_US) {
+ EXPECT_FALSE(short_util_.IsEmergencyNumber("+911", RegionCode::US()));
+ // This hex sequence is the full-width plus sign U+FF0B.
+ EXPECT_FALSE(short_util_.IsEmergencyNumber("\xEF\xBC\x8B" "911",
+ RegionCode::US()));
+ EXPECT_FALSE(short_util_.IsEmergencyNumber(" +911", RegionCode::US()));
+ EXPECT_FALSE(short_util_.IsEmergencyNumber("+119", RegionCode::US()));
+ EXPECT_FALSE(short_util_.IsEmergencyNumber("+999", RegionCode::US()));
+}
+
+TEST_F(ShortNumberUtilTest, IsEmergencyNumber_BR) {
+ EXPECT_TRUE(short_util_.IsEmergencyNumber("911", RegionCode::BR()));
+ EXPECT_TRUE(short_util_.IsEmergencyNumber("190", RegionCode::BR()));
+ EXPECT_FALSE(short_util_.IsEmergencyNumber("999", RegionCode::BR()));
+}
+
+TEST_F(ShortNumberUtilTest, EmergencyNumberLongNumber_BR) {
+ EXPECT_FALSE(short_util_.IsEmergencyNumber("9111", RegionCode::BR()));
+ EXPECT_FALSE(short_util_.IsEmergencyNumber("1900", RegionCode::BR()));
+ EXPECT_FALSE(short_util_.IsEmergencyNumber("9996", RegionCode::BR()));
+}
+
+TEST_F(ShortNumberUtilTest, IsEmergencyNumber_AO) {
+ // Angola doesn't have any metadata for emergency numbers in the test
+ // metadata.
+ EXPECT_FALSE(short_util_.IsEmergencyNumber("911", RegionCode::AO()));
+ EXPECT_FALSE(short_util_.IsEmergencyNumber("222123456", RegionCode::AO()));
+ EXPECT_FALSE(short_util_.IsEmergencyNumber("923123456", RegionCode::AO()));
+}
+
+TEST_F(ShortNumberUtilTest, IsEmergencyNumber_ZW) {
+ // Zimbabwe doesn't have any metadata in the test metadata.
+ EXPECT_FALSE(short_util_.IsEmergencyNumber("911", RegionCode::ZW()));
+ EXPECT_FALSE(short_util_.IsEmergencyNumber("01312345", RegionCode::ZW()));
+ EXPECT_FALSE(short_util_.IsEmergencyNumber("0711234567", RegionCode::ZW()));
+}
+
+} // namespace phonenumbers
+} // namespace i18n
return "YT";
}
+ static const char* ZW() {
+ return "ZW";
+ }
+
// Returns a region code string representing the "unknown" region.
static const char* GetUnknown() {
return "ZZ";