Browse Source

CPP: libphonenumber 4.5

pull/567/head
Philippe Liard 14 years ago
committed by Mihaela Rosca
parent
commit
1899ea03ca
7 changed files with 11899 additions and 10804 deletions
  1. +4
    -2
      cpp/src/phonenumbers/asyoutypeformatter.cc
  2. +10535
    -10059
      cpp/src/phonenumbers/metadata.cc
  3. +272
    -103
      cpp/src/phonenumbers/phonenumberutil.cc
  4. +53
    -17
      cpp/src/phonenumbers/phonenumberutil.h
  5. +661
    -614
      cpp/src/phonenumbers/test_metadata.cc
  6. +366
    -9
      cpp/test/phonenumbers/phonenumberutil_test.cc
  7. +8
    -0
      cpp/test/phonenumbers/test_util.h

+ 4
- 2
cpp/src/phonenumbers/asyoutypeformatter.cc View File

@ -618,8 +618,10 @@ bool AsYouTypeFormatter::AttemptToExtractCountryCode() {
national_number_.assign(number_without_country_code);
string new_region_code;
phone_util_.GetRegionCodeForCountryCode(country_code, &new_region_code);
if (new_region_code != default_country_) {
if (PhoneNumberUtil::kRegionCodeForNonGeoEntity == new_region_code) {
current_metadata_ =
phone_util_.GetMetadataForNonGeographicalRegion(country_code);
} else if (new_region_code != default_country_) {
current_metadata_ = GetMetadataForRegion(new_region_code);
}
StrAppend(&prefix_before_national_number_, country_code, " ");


+ 10535
- 10059
cpp/src/phonenumbers/metadata.cc
File diff suppressed because it is too large
View File


+ 272
- 103
cpp/src/phonenumbers/phonenumberutil.cc View File

@ -81,6 +81,9 @@ const char PhoneNumberUtil::kValidPunctuation[] =
// static
const char PhoneNumberUtil::kCaptureUpToSecondNumberStart[] = "(.*)[\\\\/] *x";
// static
const char PhoneNumberUtil::kRegionCodeForNonGeoEntity[] = "001";
namespace {
// The prefix that needs to be inserted in front of a Colombian landline
@ -141,6 +144,8 @@ const PhoneNumberDesc* GetNumberDescByType(
return &metadata.pager();
case PhoneNumberUtil::UAN:
return &metadata.uan();
case PhoneNumberUtil::VOICEMAIL:
return &metadata.voicemail();
default:
return &metadata.general_desc();
}
@ -246,6 +251,11 @@ PhoneNumberUtil::PhoneNumberType GetNumberTypeHelper(
VLOG(4) << "Number is a UAN.";
return PhoneNumberUtil::UAN;
}
if (IsNumberMatchingDesc(national_number, metadata.voicemail(),
regexp_cache)) {
VLOG(4) << "Number is a voicemail number.";
return PhoneNumberUtil::VOICEMAIL;
}
bool is_fixed_line =
IsNumberMatchingDesc(national_number, metadata.fixed_line(),
@ -302,11 +312,11 @@ string CreateExtnPattern(const string& single_extn_symbols) {
// unicode decomposed form with the combining acute accent.
return (StrCat(
kRfc3966ExtnPrefix, capturing_extn_digits, "|"
/* "[  \\t,]*(?:ext(?:ensi(?:ó?|ó))?n?|extn?|single_extn_symbols|"
/* "[  \\t,]*(?:e?xt(?:ensi(?:ó?|ó))?n?|e?xtn?|single_extn_symbols|"
"int|int|anexo)"
"[:\\..]?[  \\t,-]*", capturing_extn_digits, "#?|" */
"[ \xC2\xA0\\t,]*(?:ext(?:ensi(?:o\xCC\x81?|\xC3\xB3))?n?|\xEF\xBD"
"\x85\xEF\xBD\x98\xEF\xBD\x94\xEF\xBD\x8E?|"
"[ \xC2\xA0\\t,]*(?:e?xt(?:ensi(?:o\xCC\x81?|\xC3\xB3))?n?|"
"(?:\xEF\xBD\x85)?\xEF\xBD\x98\xEF\xBD\x94(?:\xEF\xBD\x8E)?|"
"[", single_extn_symbols, "]|int|"
"\xEF\xBD\x89\xEF\xBD\x8E\xEF\xBD\x94|anexo)"
"[:\\.\xEF\xBC\x8E]?[ \xC2\xA0\\t,-]*", capturing_extn_digits,
@ -638,8 +648,12 @@ PhoneNumberUtil::PhoneNumberUtil()
reg_exps_(new PhoneNumberRegExpsAndMappings),
country_calling_code_to_region_code_map_(new vector<IntRegionsPair>()),
nanpa_regions_(new set<string>()),
region_to_metadata_map_(new map<string, PhoneMetadata>()) {
region_to_metadata_map_(new map<string, PhoneMetadata>()),
country_code_to_non_geographical_metadata_map_(
new map<int, PhoneMetadata>) {
Logger::set_logger_impl(logger_.get());
// TODO: Update the java version to put the contents of the init
// method inside the constructor as well to keep both in sync.
PhoneMetadataCollection metadata_collection;
if (!LoadCompiledInMetadata(&metadata_collection)) {
LOG(DFATAL) << "Could not parse compiled-in metadata.";
@ -652,11 +666,15 @@ PhoneNumberUtil::PhoneNumberUtil()
metadata_collection.metadata().begin();
it != metadata_collection.metadata().end();
++it) {
const PhoneMetadata& phone_metadata = *it;
const string& region_code = phone_metadata.id();
region_to_metadata_map_->insert(make_pair(region_code, *it));
const string& region_code = it->id();
int country_calling_code = it->country_code();
map<int, list<string>*>::iterator calling_code_in_map =
if (kRegionCodeForNonGeoEntity == region_code) {
country_code_to_non_geographical_metadata_map_->insert(
make_pair(country_calling_code, *it));
} else {
region_to_metadata_map_->insert(make_pair(region_code, *it));
}
map<int, list<string>* >::iterator calling_code_in_map =
country_calling_code_to_region_map.find(country_calling_code);
if (calling_code_in_map != country_calling_code_to_region_map.end()) {
if (it->main_country_for_code()) {
@ -756,7 +774,8 @@ void PhoneNumberUtil::GetNddPrefixForRegion(const string& region_code,
string* national_prefix) const {
DCHECK(national_prefix);
if (!IsValidRegionCode(region_code)) {
LOG(ERROR) << "Invalid region code provided.";
LOG(ERROR) << "Invalid or unknown region code (" << region_code
<< ") provided.";
return;
}
const PhoneMetadata* metadata = GetMetadataForRegion(region_code);
@ -773,17 +792,15 @@ bool PhoneNumberUtil::IsValidRegionCode(const string& region_code) const {
region_to_metadata_map_->end());
}
bool PhoneNumberUtil::HasValidRegionCode(const string& region_code,
int country_calling_code,
const string& number) const {
if (!IsValidRegionCode(region_code)) {
VLOG(1) << "Number " << number
<< " has invalid or missing country calling code ("
<< country_calling_code
<< ")";
return false;
}
return true;
bool PhoneNumberUtil::HasValidCountryCallingCode(
int country_calling_code) const {
// Create an IntRegionsPair with the country_code passed in, and use it to
// locate the pair with the same country_code in the sorted vector.
IntRegionsPair target_pair;
target_pair.first = country_calling_code;
return (binary_search(country_calling_code_to_region_code_map_->begin(),
country_calling_code_to_region_code_map_->end(),
target_pair, OrderByFirst()));
}
// Returns a pointer to the phone metadata for the appropriate region.
@ -797,6 +814,17 @@ const PhoneMetadata* PhoneNumberUtil::GetMetadataForRegion(
return NULL;
}
const PhoneMetadata* PhoneNumberUtil::GetMetadataForNonGeographicalRegion(
int country_calling_code) const {
map<int, PhoneMetadata>::const_iterator it =
country_code_to_non_geographical_metadata_map_->find(
country_calling_code);
if (it != country_code_to_non_geographical_metadata_map_->end()) {
return &it->second;
}
return NULL;
}
void PhoneNumberUtil::Format(const PhoneNumber& number,
PhoneNumberFormat number_format,
string* formatted_number) const {
@ -824,16 +852,17 @@ void PhoneNumberUtil::Format(const PhoneNumber& number,
// contained by Réunion.
string region_code;
GetRegionCodeForCountryCode(country_calling_code, &region_code);
if (!HasValidRegionCode(region_code, country_calling_code,
national_significant_number)) {
if (!HasValidCountryCallingCode(country_calling_code)) {
formatted_number->assign(national_significant_number);
return;
}
const PhoneMetadata* metadata =
GetMetadataForRegionOrCallingCode(country_calling_code, region_code);
string formatted_extension;
MaybeGetFormattedExtension(number, region_code, number_format,
MaybeGetFormattedExtension(number, *metadata, number_format,
&formatted_extension);
string formatted_national_number;
FormatNationalNumber(national_significant_number, region_code, number_format,
FormatNationalNumber(national_significant_number, *metadata, number_format,
&formatted_national_number);
FormatNumberByFormat(country_calling_code, number_format,
formatted_national_number,
@ -855,12 +884,13 @@ void PhoneNumberUtil::FormatByPattern(
GetRegionCodeForCountryCode(country_calling_code, &region_code);
string national_significant_number;
GetNationalSignificantNumber(number, &national_significant_number);
if (!HasValidRegionCode(region_code, country_calling_code,
national_significant_number)) {
if (!HasValidCountryCallingCode(country_calling_code)) {
formatted_number->assign(national_significant_number);
return;
}
RepeatedPtrField<NumberFormat> user_defined_formats_copy;
const PhoneMetadata* metadata =
GetMetadataForRegionOrCallingCode(country_calling_code, region_code);
for (RepeatedPtrField<NumberFormat>::const_iterator it =
user_defined_formats.begin();
it != user_defined_formats.end();
@ -868,8 +898,7 @@ void PhoneNumberUtil::FormatByPattern(
string national_prefix_formatting_rule(
it->national_prefix_formatting_rule());
if (!national_prefix_formatting_rule.empty()) {
const string& national_prefix =
GetMetadataForRegion(region_code)->national_prefix();
const string& national_prefix = metadata->national_prefix();
NumberFormat* num_format_copy = user_defined_formats_copy.Add();
num_format_copy->MergeFrom(*it);
if (!national_prefix.empty()) {
@ -895,7 +924,7 @@ void PhoneNumberUtil::FormatByPattern(
number_format, national_significant_number,
&formatted_number_without_extension);
string formatted_extension;
MaybeGetFormattedExtension(number, region_code, NATIONAL,
MaybeGetFormattedExtension(number, *metadata, NATIONAL,
&formatted_extension);
FormatNumberByFormat(country_calling_code, number_format,
formatted_number_without_extension, formatted_extension,
@ -915,15 +944,16 @@ void PhoneNumberUtil::FormatNationalNumberWithCarrierCode(
// contained in the metadata for US.
string region_code;
GetRegionCodeForCountryCode(country_calling_code, &region_code);
if (!HasValidRegionCode(region_code, country_calling_code,
national_significant_number)) {
if (!HasValidCountryCallingCode(country_calling_code)) {
formatted_number->assign(national_significant_number);
}
const PhoneMetadata* metadata =
GetMetadataForRegionOrCallingCode(country_calling_code, region_code);
string formatted_extension;
MaybeGetFormattedExtension(number, region_code, NATIONAL,
MaybeGetFormattedExtension(number, *metadata, NATIONAL,
&formatted_extension);
string formatted_national_number;
FormatNationalNumberWithCarrier(national_significant_number, region_code,
FormatNationalNumberWithCarrier(national_significant_number, *metadata,
NATIONAL, carrier_code,
&formatted_national_number);
FormatNumberByFormat(country_calling_code, NATIONAL,
@ -931,6 +961,13 @@ void PhoneNumberUtil::FormatNationalNumberWithCarrierCode(
formatted_number);
}
const PhoneMetadata* PhoneNumberUtil::GetMetadataForRegionOrCallingCode(
int country_calling_code, const string& region_code) const {
return kRegionCodeForNonGeoEntity == region_code
? GetMetadataForNonGeographicalRegion(country_calling_code)
: GetMetadataForRegion(region_code);
}
void PhoneNumberUtil::FormatNationalNumberWithPreferredCarrierCode(
const PhoneNumber& number,
const string& fallback_carrier_code,
@ -948,9 +985,8 @@ void PhoneNumberUtil::FormatNumberForMobileDialing(
const string& calling_from,
bool with_formatting,
string* formatted_number) const {
string region_code;
GetRegionCodeForCountryCode(number.country_code(), &region_code);
if (!IsValidRegionCode(region_code)) {
int country_calling_code = number.country_code();
if (!HasValidCountryCallingCode(country_calling_code)) {
formatted_number->assign(number.has_raw_input() ? number.raw_input() : "");
return;
}
@ -960,6 +996,8 @@ void PhoneNumberUtil::FormatNumberForMobileDialing(
PhoneNumber number_no_extension(number);
number_no_extension.clear_extension();
PhoneNumberType number_type = GetNumberType(number_no_extension);
string region_code;
GetRegionCodeForCountryCode(country_calling_code, &region_code);
if ((region_code == "CO") && (calling_from == "CO")) {
if (number_type == FIXED_LINE) {
FormatNationalNumberWithCarrierCode(
@ -1015,12 +1053,9 @@ void PhoneNumberUtil::FormatOutOfCountryCallingNumber(
return;
}
int country_code = number.country_code();
string region_code;
GetRegionCodeForCountryCode(country_code, &region_code);
string national_significant_number;
GetNationalSignificantNumber(number, &national_significant_number);
if (!HasValidRegionCode(region_code, country_code,
national_significant_number)) {
if (!HasValidCountryCallingCode(country_code)) {
formatted_number->assign(national_significant_number);
return;
}
@ -1049,21 +1084,27 @@ void PhoneNumberUtil::FormatOutOfCountryCallingNumber(
Format(number, NATIONAL, formatted_number);
return;
}
string formatted_national_number;
FormatNationalNumber(national_significant_number, region_code, INTERNATIONAL,
&formatted_national_number);
const PhoneMetadata* metadata = GetMetadataForRegion(calling_from);
const string& international_prefix = metadata->international_prefix();
string formatted_extension;
MaybeGetFormattedExtension(number, region_code, INTERNATIONAL,
&formatted_extension);
string region_code;
GetRegionCodeForCountryCode(country_code, &region_code);
const PhoneMetadata* metadata_for_region =
GetMetadataForRegionOrCallingCode(country_code, region_code);
const PhoneMetadata* metadata_calling_from =
GetMetadataForRegion(calling_from);
const string& international_prefix =
metadata_calling_from->international_prefix();
// For regions that have multiple international prefixes, the international
// format of the number is returned, unless there is a preferred international
// prefix.
const string international_prefix_for_formatting(
reg_exps_->unique_international_prefix_->FullMatch(international_prefix)
? international_prefix
: metadata->preferred_international_prefix());
: metadata_calling_from->preferred_international_prefix());
string formatted_national_number;
FormatNationalNumber(national_significant_number, *metadata_for_region,
INTERNATIONAL, &formatted_national_number);
string formatted_extension;
MaybeGetFormattedExtension(number, *metadata_for_region, INTERNATIONAL,
&formatted_extension);
if (!international_prefix_for_formatting.empty()) {
formatted_number->assign(
StrCat(international_prefix_for_formatting, " ", country_code, " ",
@ -1080,11 +1121,10 @@ void PhoneNumberUtil::FormatInOriginalFormat(const PhoneNumber& number,
DCHECK(formatted_number);
if (number.has_raw_input() &&
(!HasFormattingPatternForNumber(number) || !IsValidNumber(number))) {
(HasUnexpectedItalianLeadingZero(number) ||
!HasFormattingPatternForNumber(number))) {
// We check if we have the formatting pattern because without that, we might
// format the number as a group without national prefix. We also want to
// check the validity of the number because we don't want to risk formatting
// the number if we don't really understand it.
// format the number as a group without national prefix.
formatted_number->assign(number.raw_input());
return;
}
@ -1095,26 +1135,125 @@ void PhoneNumberUtil::FormatInOriginalFormat(const PhoneNumber& number,
switch (number.country_code_source()) {
case PhoneNumber::FROM_NUMBER_WITH_PLUS_SIGN:
Format(number, INTERNATIONAL, formatted_number);
return;
break;
case PhoneNumber::FROM_NUMBER_WITH_IDD:
FormatOutOfCountryCallingNumber(number, region_calling_from,
formatted_number);
return;
break;
case PhoneNumber::FROM_NUMBER_WITHOUT_PLUS_SIGN:
Format(number, INTERNATIONAL, formatted_number);
formatted_number->erase(formatted_number->begin());
return;
break;
case PhoneNumber::FROM_DEFAULT_COUNTRY:
// Fall-through to default case.
default:
Format(number, NATIONAL, formatted_number);
string region_code;
GetRegionCodeForCountryCode(number.country_code(), &region_code);
// We strip non-digits from the NDD here, and from the raw input later, so
// that we can compare them easily.
string national_prefix;
GetNddPrefixForRegion(region_code, true /* strip non-digits */,
&national_prefix);
if (national_prefix.empty()) {
// If the region doesn't have a national prefix at all, we can safely
// return the national format without worrying about a national prefix
// being added.
Format(number, NATIONAL, formatted_number);
break;
}
// Otherwise, we check if the original number was entered with a national
// prefix.
if (RawInputContainsNationalPrefix(number.raw_input(), national_prefix,
region_code)) {
// If so, we can safely return the national format.
Format(number, NATIONAL, formatted_number);
break;
}
const PhoneMetadata* metadata = GetMetadataForRegion(region_code);
string national_number;
GetNationalSignificantNumber(number, &national_number);
// This shouldn't be NULL, because we have checked that above with
// HasFormattingPatternForNumber.
const NumberFormat* format_rule =
ChooseFormattingPatternForNumber(metadata->number_format(),
national_number, national_number);
// When the format we apply to this number doesn't contain national
// prefix, we can just return the national format.
// TODO: Refactor the code below with the code in
// IsNationalPrefixPresentIfRequired.
string candidate_national_prefix_rule(
format_rule->national_prefix_formatting_rule());
// We assume that the first-group symbol will never be _before_ the
// national prefix.
if (!candidate_national_prefix_rule.empty()) {
candidate_national_prefix_rule.erase(
candidate_national_prefix_rule.find("$1"));
NormalizeDigitsOnly(&candidate_national_prefix_rule);
}
if (candidate_national_prefix_rule.empty()) {
// National prefix not used when formatting this number.
Format(number, NATIONAL, formatted_number);
break;
}
// Otherwise, we need to remove the national prefix from our output.
RepeatedPtrField<NumberFormat> number_formats;
NumberFormat* number_format = number_formats.Add();
number_format->MergeFrom(*format_rule);
number_format->clear_national_prefix_formatting_rule();
FormatByPattern(number, NATIONAL, number_formats, formatted_number);
break;
}
// If no digit is inserted/removed/modified as a result of our formatting, we
// return the formatted phone number; otherwise we return the raw input the
// user entered.
if (!formatted_number->empty()) {
string formatted_number_copy(*formatted_number);
NormalizeDigitsOnly(&formatted_number_copy);
string raw_input_copy(number.raw_input());
NormalizeDigitsOnly(&raw_input_copy);
if (formatted_number_copy != raw_input_copy) {
formatted_number->assign(number.raw_input());
}
}
}
// Check if raw_input, which is assumed to be in the national format, has a
// national prefix. The national prefix is assumed to be in digits-only form.
bool PhoneNumberUtil::RawInputContainsNationalPrefix(
const string& raw_input,
const string& national_prefix,
const string& region_code) const {
string normalized_national_number(raw_input);
NormalizeDigitsOnly(&normalized_national_number);
if (HasPrefixString(normalized_national_number, national_prefix)) {
// Some Japanese numbers (e.g. 00777123) might be mistaken to contain
// the national prefix when written without it (e.g. 0777123) if we just
// do prefix matching. To tackle that, we check the validity of the
// number if the assumed national prefix is removed (777123 won't be
// valid in Japan).
PhoneNumber number_without_national_prefix;
if (Parse(normalized_national_number.substr(national_prefix.length()),
region_code, &number_without_national_prefix)
== NO_PARSING_ERROR) {
return IsValidNumber(number_without_national_prefix);
}
}
return false;
}
bool PhoneNumberUtil::HasUnexpectedItalianLeadingZero(
const PhoneNumber& number) const {
return number.has_italian_leading_zero() &&
!IsLeadingZeroPossible(number.country_code());
}
bool PhoneNumberUtil::HasFormattingPatternForNumber(
const PhoneNumber& number) const {
int country_calling_code = number.country_code();
string region_code;
GetRegionCodeForCountryCode(number.country_code(), &region_code);
const PhoneMetadata* metadata = GetMetadataForRegion(region_code);
GetRegionCodeForCountryCode(country_calling_code, &region_code);
const PhoneMetadata* metadata =
GetMetadataForRegionOrCallingCode(country_calling_code, region_code);
if (!metadata) {
return false;
}
@ -1137,10 +1276,7 @@ void PhoneNumberUtil::FormatOutOfCountryKeepingAlphaChars(
FormatOutOfCountryCallingNumber(number, calling_from, formatted_number);
return;
}
string region_code;
GetRegionCodeForCountryCode(number.country_code(), &region_code);
if (!HasValidRegionCode(region_code, number.country_code(),
number.raw_input())) {
if (!HasValidCountryCallingCode(number.country_code())) {
formatted_number->assign(number.raw_input());
return;
}
@ -1196,19 +1332,25 @@ void PhoneNumberUtil::FormatOutOfCountryKeepingAlphaChars(
return;
}
const string& international_prefix = metadata->international_prefix();
// For regions that have multiple international prefixes, the international
// format of the number is returned, unless there is a preferred international
// prefix.
const string international_prefix_for_formatting(
reg_exps_->unique_international_prefix_->FullMatch(international_prefix)
? international_prefix
: metadata->preferred_international_prefix());
string international_prefix_for_formatting;
// If an unsupported region-calling-from is entered, or a country with
// multiple international prefixes, the international format of the number is
// returned, unless there is a preferred international prefix.
if (metadata) {
const string& international_prefix = metadata->international_prefix();
international_prefix_for_formatting =
reg_exps_->unique_international_prefix_->FullMatch(international_prefix)
? international_prefix
: metadata->preferred_international_prefix();
}
if (!international_prefix_for_formatting.empty()) {
formatted_number->assign(
StrCat(international_prefix_for_formatting, " ", number.country_code(),
" ", raw_input_copy));
} else {
// Invalid region entered as country-calling-from (so no metadata was found
// for it) or the region chosen has multiple international dialling
// prefixes.
FormatNumberByFormat(number.country_code(), INTERNATIONAL, raw_input_copy,
"", formatted_number);
}
@ -1312,11 +1454,11 @@ void PhoneNumberUtil::FormatAccordingToFormats(
void PhoneNumberUtil::FormatNationalNumber(
const string& number,
const string& region_code,
const PhoneMetadata& metadata,
PhoneNumberFormat number_format,
string* formatted_number) const {
DCHECK(formatted_number);
FormatNationalNumberWithCarrier(number, region_code, number_format, "",
FormatNationalNumberWithCarrier(number, metadata, number_format, "",
formatted_number);
}
@ -1327,18 +1469,17 @@ void PhoneNumberUtil::FormatNationalNumber(
// will be inserted into the formatted string to replace $CC.
void PhoneNumberUtil::FormatNationalNumberWithCarrier(
const string& number,
const string& region_code,
const PhoneMetadata& metadata,
PhoneNumberFormat number_format,
const string& carrier_code,
string* formatted_number) const {
DCHECK(formatted_number);
const PhoneMetadata* metadata = GetMetadataForRegion(region_code);
// When the intl_number_formats exists, we use that to format national number
// for the INTERNATIONAL format instead of using the number_formats.
const RepeatedPtrField<NumberFormat> available_formats =
(metadata->intl_number_format_size() == 0 || number_format == NATIONAL)
? metadata->number_format()
: metadata->intl_number_format();
(metadata.intl_number_format_size() == 0 || number_format == NATIONAL)
? metadata.number_format()
: metadata.intl_number_format();
FormatAccordingToFormatsWithCarrier(number, available_formats, number_format,
number, carrier_code, formatted_number);
if (number_format == RFC3966) {
@ -1351,7 +1492,7 @@ void PhoneNumberUtil::FormatNationalNumberWithCarrier(
// extension specified. If not, it returns an empty string.
void PhoneNumberUtil::MaybeGetFormattedExtension(
const PhoneNumber& number,
const string& region_code,
const PhoneMetadata& metadata,
PhoneNumberFormat number_format,
string* extension) const {
DCHECK(extension);
@ -1362,7 +1503,7 @@ void PhoneNumberUtil::MaybeGetFormattedExtension(
StrAppend(extension, kRfc3966ExtnPrefix, number.extension());
return;
}
FormatExtension(number.extension(), region_code, extension);
FormatExtension(number.extension(), metadata, extension);
}
}
@ -1370,12 +1511,11 @@ void PhoneNumberUtil::MaybeGetFormattedExtension(
// appropriate extension prefix. This will be the default extension prefix,
// unless overridden by a preferred extension prefix for this region.
void PhoneNumberUtil::FormatExtension(const string& extension_digits,
const string& region_code,
const PhoneMetadata& metadata,
string* extension) const {
DCHECK(extension);
const PhoneMetadata* metadata = GetMetadataForRegion(region_code);
if (metadata->has_preferred_extn_prefix()) {
extension->assign(StrCat(metadata->preferred_extn_prefix(),
if (metadata.has_preferred_extn_prefix()) {
extension->assign(StrCat(metadata.preferred_extn_prefix(),
extension_digits));
} else {
extension->assign(StrCat(kDefaultExtnPrefix, extension_digits));
@ -1472,7 +1612,8 @@ void PhoneNumberUtil::GetRegionCodeForNumberFromRegionList(
int PhoneNumberUtil::GetCountryCodeForRegion(const string& region_code) const {
if (!IsValidRegionCode(region_code)) {
LOG(ERROR) << "Invalid or unknown region code provided.";
LOG(ERROR) << "Invalid or unknown region code (" << region_code
<< ") provided.";
return 0;
}
const PhoneMetadata* metadata = GetMetadataForRegion(region_code);
@ -1480,7 +1621,8 @@ int PhoneNumberUtil::GetCountryCodeForRegion(const string& region_code) const {
}
// Gets a valid fixed-line number for the specified region_code. Returns false
// if the country was unknown or if no number exists.
// if the region was unknown or 001 (representing non-geographical regions), or
// if no number exists.
bool PhoneNumberUtil::GetExampleNumber(const string& region_code,
PhoneNumber* number) const {
DCHECK(number);
@ -1490,6 +1632,7 @@ bool PhoneNumberUtil::GetExampleNumber(const string& region_code,
}
// Gets a valid number for the specified region_code and type. Returns false if
// the country was unknown or 001 (representing non-geographical regions), or if
// the country was unknown or if no number exists.
bool PhoneNumberUtil::GetExampleNumberForType(
const string& region_code,
@ -1497,7 +1640,8 @@ bool PhoneNumberUtil::GetExampleNumberForType(
PhoneNumber* number) const {
DCHECK(number);
if (!IsValidRegionCode(region_code)) {
LOG(WARNING) << "Invalid or unknown region code provided.";
LOG(ERROR) << "Invalid or unknown region code (" << region_code
<< ") provided.";
return false;
}
const PhoneMetadata* region_metadata = GetMetadataForRegion(region_code);
@ -1511,6 +1655,22 @@ bool PhoneNumberUtil::GetExampleNumberForType(
return false;
}
bool PhoneNumberUtil::GetExampleNumberForNonGeoEntity(
int country_calling_code, PhoneNumber* number) const {
DCHECK(number);
const PhoneMetadata* metadata =
GetMetadataForNonGeographicalRegion(country_calling_code);
if (metadata) {
const PhoneNumberDesc& desc = metadata->general_desc();
if (desc.has_example_number()) {
return (Parse(StrCat(kPlusSign, SimpleItoa(country_calling_code),
desc.example_number()),
"ZZ", number) == NO_PARSING_ERROR);
}
}
return false;
}
PhoneNumberUtil::ErrorType PhoneNumberUtil::Parse(const string& number_to_parse,
const string& default_region,
PhoneNumber* number) const {
@ -1605,7 +1765,8 @@ PhoneNumberUtil::ErrorType PhoneNumberUtil::ParseHelper(
string phone_number_region;
GetRegionCodeForCountryCode(country_code, &phone_number_region);
if (phone_number_region != default_region) {
country_metadata = GetMetadataForRegion(phone_number_region);
country_metadata =
GetMetadataForRegionOrCallingCode(country_code, phone_number_region);
}
} else if (country_metadata) {
// If no extracted country calling code, use the region supplied instead.
@ -1719,13 +1880,14 @@ PhoneNumberUtil::ValidationResult PhoneNumberUtil::IsPossibleNumberWithReason(
// work if the number is possible but not valid. This would need to be
// revisited if the possible number pattern ever differed between various
// regions within those plans.
string region_code;
GetRegionCodeForCountryCode(country_code, &region_code);
if (!HasValidRegionCode(region_code, country_code, national_number)) {
if (!HasValidCountryCallingCode(country_code)) {
return INVALID_COUNTRY_CODE;
}
const PhoneNumberDesc& general_num_desc =
GetMetadataForRegion(region_code)->general_desc();
string region_code;
GetRegionCodeForCountryCode(country_code, &region_code);
const PhoneMetadata* metadata =
GetMetadataForRegionOrCallingCode(country_code, region_code);
const PhoneNumberDesc& general_num_desc = metadata->general_desc();
// Handling case of numbers with no metadata.
if (!general_num_desc.has_national_number_pattern()) {
size_t number_length = national_number.length();
@ -1765,29 +1927,35 @@ PhoneNumberUtil::PhoneNumberType PhoneNumberUtil::GetNumberType(
const PhoneNumber& number) const {
string region_code;
GetRegionCodeForNumber(number, &region_code);
if (!IsValidRegionCode(region_code)) {
if (!IsValidRegionCode(region_code) &&
kRegionCodeForNonGeoEntity != region_code) {
return UNKNOWN;
}
string national_significant_number;
GetNationalSignificantNumber(number, &national_significant_number);
const PhoneMetadata* metadata =
GetMetadataForRegionOrCallingCode(number.country_code(), region_code);
return GetNumberTypeHelper(national_significant_number,
*GetMetadataForRegion(region_code),
*metadata,
reg_exps_->regexp_cache_.get());
}
bool PhoneNumberUtil::IsValidNumber(const PhoneNumber& number) const {
string region_code;
GetRegionCodeForNumber(number, &region_code);
return IsValidRegionCode(region_code) &&
IsValidNumberForRegion(number, region_code);
return IsValidNumberForRegion(number, region_code);
}
bool PhoneNumberUtil::IsValidNumberForRegion(const PhoneNumber& number,
const string& region_code) const {
if (number.country_code() != GetCountryCodeForRegion(region_code)) {
int country_code = number.country_code();
if (country_code == 0 ||
(kRegionCodeForNonGeoEntity != region_code &&
country_code != GetCountryCodeForRegion(region_code))) {
return false;
}
const PhoneMetadata* metadata = GetMetadataForRegion(region_code);
const PhoneMetadata* metadata =
GetMetadataForRegionOrCallingCode(country_code, region_code);
const PhoneNumberDesc& general_desc = metadata->general_desc();
string national_number;
GetNationalSignificantNumber(number, &national_number);
@ -2403,13 +2571,14 @@ bool PhoneNumberUtil::CanBeInternationallyDialled(
const PhoneNumber& number) const {
string region_code;
GetRegionCodeForNumber(number, &region_code);
string national_significant_number;
GetNationalSignificantNumber(number, &national_significant_number);
if (!HasValidRegionCode(region_code, number.country_code(),
national_significant_number)) {
if (!IsValidRegionCode(region_code)) {
// Note numbers belonging to non-geographical entities (e.g. +800 numbers)
// are always internationally diallable, and will be caught here.
return true;
}
const PhoneMetadata* metadata = GetMetadataForRegion(region_code);
string national_significant_number;
GetNationalSignificantNumber(number, &national_significant_number);
return !IsNumberMatchingDesc(
national_significant_number, metadata->no_international_dialling(),
reg_exps_->regexp_cache_.get());


+ 53
- 17
cpp/src/phonenumbers/phonenumberutil.h View File

@ -75,6 +75,7 @@ class PhoneNumberUtil : public Singleton<PhoneNumberUtil> {
friend class PhoneNumberUtilTest;
public:
~PhoneNumberUtil();
static const char kRegionCodeForNonGeoEntity[];
// INTERNATIONAL and NATIONAL formats are consistent with the definition
// in ITU-T Recommendation E. 123. For example, the number of the Google
@ -116,6 +117,8 @@ class PhoneNumberUtil : public Singleton<PhoneNumberUtil> {
// further routed to specific offices, but allow one number to be used for a
// company.
UAN,
// Used for "Voice Mail Access Numbers".
VOICEMAIL,
// A phone number is of type UNKNOWN when it does not fit any of the known
// patterns for a specific region.
UNKNOWN
@ -221,7 +224,8 @@ class PhoneNumberUtil : public Singleton<PhoneNumberUtil> {
// - subscriber numbers may not be diallable from all devices (notably mobile
// devices, which typically requires the full national_number to be dialled
// in most regions).
// - most non-geographical numbers have no area codes.
// - most non-geographical numbers have no area codes, including numbers
// from non-geographical entities.
// - some geographical numbers have no area codes.
int GetLengthOfGeographicalAreaCode(const PhoneNumber& number) const;
@ -455,17 +459,27 @@ class PhoneNumberUtil : public Singleton<PhoneNumberUtil> {
const string& region_dialing_from) const;
// Gets a valid fixed-line number for the specified region. Returns false if
// the region was unknown.
// the region was unknown, or the region 001 is passed in. For 001
// (representing non-geographical numbers), call
// GetExampleNumberForNonGeoEntity instead.
bool GetExampleNumber(const string& region_code,
PhoneNumber* number) const;
// Gets a valid number of the specified type for the specified region.
// Returns false if the region was unknown or if no example number of that
// type could be found.
// Returns false if the region was unknown or 001, or if no example number of
// that type could be found. For 001 (representing non-geographical numbers),
// call GetExampleNumberForNonGeoEntity instead.
bool GetExampleNumberForType(const string& region_code,
PhoneNumberType type,
PhoneNumber* number) const;
// Gets a valid number for the specified country calling code for a
// non-geographical entity. Returns false if the metadata does not contain
// such information, or the country calling code passed in does not belong to
// a non-geographical entity.
bool GetExampleNumberForNonGeoEntity(
int country_calling_code, PhoneNumber* number) const;
// Parses a string and returns it in proto buffer format. This method will
// return an error like INVALID_COUNTRY_CODE if the number is not considered
// to be a possible number, and NO_PARSING_ERROR if it parsed correctly. Note
@ -595,6 +609,13 @@ class PhoneNumberUtil : public Singleton<PhoneNumberUtil> {
// A mapping from a region code to a PhoneMetadata for that region.
scoped_ptr<map<string, PhoneMetadata> > region_to_metadata_map_;
// A mapping from a country calling code for a non-geographical entity to the
// PhoneMetadata for that country calling code. Examples of the country
// calling codes include 800 (International Toll Free Service) and 808
// (International Shared Cost Service).
scoped_ptr<map<int, PhoneMetadata> >
country_code_to_non_geographical_metadata_map_;
PhoneNumberUtil();
// Returns a regular expression for the possible extensions that may be found
@ -613,16 +634,19 @@ class PhoneNumberUtil : public Singleton<PhoneNumberUtil> {
// Helper function to check region code is not unknown or null.
bool IsValidRegionCode(const string& region_code) const;
// Helper function to check region code is not unknown. The
// country_calling_code and number supplied is used only for the resultant log
// message.
bool HasValidRegionCode(const string& region_code,
int country_code,
const string& number) const;
// Helper function to check the country calling code is valid.
bool HasValidCountryCallingCode(int country_calling_code) const;
const i18n::phonenumbers::PhoneMetadata* GetMetadataForRegion(
const string& region_code) const;
const i18n::phonenumbers::PhoneMetadata* GetMetadataForNonGeographicalRegion(
int country_calling_code) const;
const i18n::phonenumbers::PhoneMetadata* GetMetadataForRegionOrCallingCode(
int country_calling_code,
const string& region_code) const;
void GetRegionCodesForCountryCallingCode(
int country_calling_code,
list<string>* region_codes) const;
@ -647,28 +671,40 @@ class PhoneNumberUtil : public Singleton<PhoneNumberUtil> {
const string& national_number,
string* formatted_number) const;
// Check if raw_input, which is assumed to be in the national format, has a
// national prefix. The national prefix is assumed to be in digits-only form.
bool RawInputContainsNationalPrefix(
const string& raw_input,
const string& national_prefix,
const string& region_code) const;
// Returns true if a number is from a region whose national significant number
// couldn't contain a leading zero, but has the italian_leading_zero field set
// to true.
bool HasUnexpectedItalianLeadingZero(const PhoneNumber& number) const;
bool HasFormattingPatternForNumber(const PhoneNumber& number) const;
// Simple wrapper of FormatNationalNumberWithCarrier for the common case of
// no carrier code.
void FormatNationalNumber(const string& number,
const string& region_code,
const PhoneMetadata& metadata,
PhoneNumberFormat number_format,
string* formatted_number) const;
void FormatNationalNumberWithCarrier(const string& number,
const string& region_code,
const PhoneMetadata& metadata,
PhoneNumberFormat number_format,
const string& carrier_code,
string* formatted_number) const;
void MaybeGetFormattedExtension(
const PhoneNumber& number,
const string& region_code,
const PhoneMetadata& metadata,
PhoneNumberFormat number_format,
string* extension) const;
void FormatExtension(const string& extension_digits,
const string& region_code,
const PhoneMetadata& metadata,
string* extension) const;
void GetRegionCodeForNumberFromRegionList(
@ -714,9 +750,9 @@ class PhoneNumberUtil : public Singleton<PhoneNumberUtil> {
bool check_region,
PhoneNumber* phone_number) const;
// Returns true if the number can only be dialled from within the region. If
// unknown, or the number can be dialled from outside the region as well,
// returns false. Does not check the number is a valid number.
// 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.
bool CanBeInternationallyDialled(const PhoneNumber& number) const;
DISALLOW_COPY_AND_ASSIGN(PhoneNumberUtil);


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


+ 366
- 9
cpp/test/phonenumbers/phonenumberutil_test.cc View File

@ -47,6 +47,11 @@ class PhoneNumberUtilTest : public testing::Test {
return phone_util_.GetMetadataForRegion(region_code);
}
const PhoneMetadata* GetMetadataForNonGeographicalRegion(
int country_code) const {
return phone_util_.GetMetadataForNonGeographicalRegion(country_code);
}
void GetSupportedRegions(set<string>* regions) {
phone_util_.GetSupportedRegions(regions);
}
@ -198,6 +203,17 @@ TEST_F(PhoneNumberUtilTest, GetInstanceLoadARMetadata) {
EXPECT_EQ("$1 $2 $3 $4", metadata->intl_number_format(3).format());
}
TEST_F(PhoneNumberUtilTest, GetInstanceLoadInternationalTollFreeMetadata) {
const PhoneMetadata* metadata = GetMetadataForNonGeographicalRegion(800);
EXPECT_FALSE(metadata == NULL);
EXPECT_EQ("001", metadata->id());
EXPECT_EQ(800, metadata->country_code());
EXPECT_EQ("$1 $2", metadata->number_format(0).format());
EXPECT_EQ("(\\d{4})(\\d{4})", metadata->number_format(0).pattern());
EXPECT_EQ("12345678", metadata->general_desc().example_number());
EXPECT_EQ("12345678", metadata->toll_free().example_number());
}
TEST_F(PhoneNumberUtilTest, GetNationalSignificantNumber) {
PhoneNumber number;
number.set_country_code(1);
@ -223,6 +239,14 @@ TEST_F(PhoneNumberUtilTest, GetNationalSignificantNumber) {
phone_util_.GetNationalSignificantNumber(number,
&national_significant_number);
EXPECT_EQ("0236618300", national_significant_number);
national_significant_number.clear();
number.Clear();
number.set_country_code(800);
number.set_national_number(12345678ULL);
phone_util_.GetNationalSignificantNumber(number,
&national_significant_number);
EXPECT_EQ("12345678", national_significant_number);
}
TEST_F(PhoneNumberUtilTest, GetExampleNumber) {
@ -270,6 +294,22 @@ TEST_F(PhoneNumberUtilTest, GetExampleNumber) {
PhoneNumberUtil::MOBILE,
&test_number));
EXPECT_EQ(PhoneNumber::default_instance(), test_number);
test_number.Clear();
// RegionCode 001 is reserved for supporting non-geographical country calling
// code. We don't support getting an example number for it with this method.
EXPECT_FALSE(phone_util_.GetExampleNumber(RegionCode::UN001(), &test_number));
}
TEST_F(PhoneNumberUtilTest, GetExampleNumberForNonGeoEntity) {
PhoneNumber toll_free_number;
toll_free_number.set_country_code(800);
toll_free_number.set_national_number(12345678ULL);
PhoneNumber test_number;
bool success =
phone_util_.GetExampleNumberForNonGeoEntity(800 , &test_number);
EXPECT_TRUE(success);
EXPECT_EQ(toll_free_number, test_number);
}
TEST_F(PhoneNumberUtilTest, FormatUSNumber) {
@ -583,6 +623,12 @@ TEST_F(PhoneNumberUtilTest, FormatOutOfCountryCallingNumber) {
&formatted_number);
EXPECT_EQ("9477 7892", formatted_number);
test_number.set_country_code(800);
test_number.set_national_number(12345678ULL);
phone_util_.FormatOutOfCountryCallingNumber(test_number, RegionCode::US(),
&formatted_number);
EXPECT_EQ("011 800 1234 5678", formatted_number);
test_number.set_country_code(54);
test_number.set_national_number(91187654321ULL);
phone_util_.FormatOutOfCountryCallingNumber(test_number, RegionCode::US(),
@ -611,6 +657,11 @@ TEST_F(PhoneNumberUtilTest, FormatOutOfCountryWithInvalidRegion) {
phone_util_.FormatOutOfCountryCallingNumber(test_number, RegionCode::AQ(),
&formatted_number);
EXPECT_EQ("+1 650 253 0000", formatted_number);
// For region code 001, the out-of-country format always turns into the
// international format.
phone_util_.FormatOutOfCountryCallingNumber(test_number, RegionCode::UN001(),
&formatted_number);
EXPECT_EQ("+1 650 253 0000", formatted_number);
}
TEST_F(PhoneNumberUtilTest, FormatOutOfCountryWithPreferredIntlPrefix) {
@ -722,6 +773,11 @@ TEST_F(PhoneNumberUtilTest, FormatOutOfCountryKeepingAlphaChars) {
RegionCode::SG(),
&formatted_number);
EXPECT_EQ("+61 1-800-SIX-FLAG", formatted_number);
// Testing the case of calling from a non-supported region.
phone_util_.FormatOutOfCountryKeepingAlphaChars(alpha_numeric_number,
RegionCode::AQ(),
&formatted_number);
EXPECT_EQ("+61 1-800-SIX-FLAG", formatted_number);
// Testing the case with an invalid country code.
formatted_number.clear();
@ -744,6 +800,12 @@ TEST_F(PhoneNumberUtilTest, FormatOutOfCountryKeepingAlphaChars) {
&formatted_number);
// No country-code stripping can be done.
EXPECT_EQ("00 1 180-SIX", formatted_number);
// Testing the case of calling from a non-supported region.
phone_util_.FormatOutOfCountryKeepingAlphaChars(alpha_numeric_number,
RegionCode::AQ(),
&formatted_number);
// No country-code stripping can be done since the number is invalid.
EXPECT_EQ("+1 180-SIX", formatted_number);
}
TEST_F(PhoneNumberUtilTest, FormatWithCarrierCode) {
@ -874,6 +936,15 @@ TEST_F(PhoneNumberUtilTest, FormatNumberForMobileDialing) {
phone_util_.FormatNumberForMobileDialing(
test_number, RegionCode::JP(), false, &formatted_number);
EXPECT_EQ("*2345", formatted_number);
test_number.set_country_code(800);
test_number.set_national_number(12345678ULL);
phone_util_.FormatNumberForMobileDialing(
test_number, RegionCode::JP(), false, &formatted_number);
EXPECT_EQ("+80012345678", formatted_number);
phone_util_.FormatNumberForMobileDialing(
test_number, RegionCode::JP(), true, &formatted_number);
EXPECT_EQ("+800 1234 5678", formatted_number);
}
TEST_F(PhoneNumberUtilTest, FormatByPattern) {
@ -964,6 +1035,11 @@ TEST_F(PhoneNumberUtilTest, FormatE164Number) {
test_number.set_national_number(301234ULL);
phone_util_.Format(test_number, PhoneNumberUtil::E164, &formatted_number);
EXPECT_EQ("+49301234", formatted_number);
test_number.set_country_code(800);
test_number.set_national_number(12345678ULL);
phone_util_.Format(test_number, PhoneNumberUtil::E164, &formatted_number);
EXPECT_EQ("+80012345678", formatted_number);
}
TEST_F(PhoneNumberUtilTest, FormatNumberWithExtension) {
@ -1029,6 +1105,11 @@ TEST_F(PhoneNumberUtilTest, GetLengthOfGeographicalAreaCode) {
number.set_country_code(65);
number.set_national_number(65218000ULL);
EXPECT_EQ(0, phone_util_.GetLengthOfGeographicalAreaCode(number));
// An international toll free number, which has no area code.
number.set_country_code(800);
number.set_national_number(12345678ULL);
EXPECT_EQ(0, phone_util_.GetLengthOfGeographicalAreaCode(number));
}
TEST_F(PhoneNumberUtilTest, GetLengthOfNationalDestinationCode) {
@ -1089,6 +1170,12 @@ TEST_F(PhoneNumberUtilTest, GetLengthOfNationalDestinationCode) {
number.set_national_number(12345ULL);
number.set_extension("321");
EXPECT_EQ(0, phone_util_.GetLengthOfNationalDestinationCode(number));
// An international toll free number, which has NDC "1234".
number.Clear();
number.set_country_code(800);
number.set_national_number(12345678ULL);
EXPECT_EQ(4, phone_util_.GetLengthOfNationalDestinationCode(number));
}
TEST_F(PhoneNumberUtilTest, ExtractPossibleNumber) {
@ -1134,6 +1221,9 @@ TEST_F(PhoneNumberUtilTest, ExtractPossibleNumber) {
TEST_F(PhoneNumberUtilTest, IsNANPACountry) {
EXPECT_TRUE(phone_util_.IsNANPACountry(RegionCode::US()));
EXPECT_TRUE(phone_util_.IsNANPACountry(RegionCode::BS()));
EXPECT_FALSE(phone_util_.IsNANPACountry(RegionCode::DE()));
EXPECT_FALSE(phone_util_.IsNANPACountry(RegionCode::GetUnknown()));
EXPECT_FALSE(phone_util_.IsNANPACountry(RegionCode::UN001()));
}
TEST_F(PhoneNumberUtilTest, IsValidNumber) {
@ -1157,6 +1247,11 @@ TEST_F(PhoneNumberUtilTest, IsValidNumber) {
nz_number.set_country_code(64);
nz_number.set_national_number(21387835ULL);
EXPECT_TRUE(phone_util_.IsValidNumber(nz_number));
PhoneNumber intl_toll_free_number;
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));
}
TEST_F(PhoneNumberUtilTest, IsValidForRegion) {
@ -1190,11 +1285,19 @@ TEST_F(PhoneNumberUtilTest, IsValidForRegion) {
// However, it should be recognised as from La Mayotte.
string region_code;
phone_util_.GetRegionCodeForNumber(re_number, &region_code);
EXPECT_EQ("YT", region_code);
EXPECT_EQ(RegionCode::YT(), region_code);
// This number is valid in both places.
re_number.set_national_number(800123456ULL);
EXPECT_TRUE(phone_util_.IsValidNumberForRegion(re_number, RegionCode::YT()));
EXPECT_TRUE(phone_util_.IsValidNumberForRegion(re_number, RegionCode::RE()));
PhoneNumber intl_toll_free_number;
intl_toll_free_number.set_country_code(800);
intl_toll_free_number.set_national_number(12345678ULL);
EXPECT_TRUE(phone_util_.IsValidNumberForRegion(intl_toll_free_number,
RegionCode::UN001()));
EXPECT_FALSE(phone_util_.IsValidNumberForRegion(intl_toll_free_number,
RegionCode::US()));
}
TEST_F(PhoneNumberUtilTest, IsNotValidNumber) {
@ -1223,6 +1326,11 @@ TEST_F(PhoneNumberUtilTest, IsNotValidNumber) {
nz_number.set_country_code(64);
nz_number.set_national_number(3316005ULL);
EXPECT_FALSE(phone_util_.IsValidNumber(nz_number));
PhoneNumber intl_toll_free_number_too_long;
intl_toll_free_number_too_long.set_country_code(800);
intl_toll_free_number_too_long.set_national_number(123456789ULL);
EXPECT_FALSE(phone_util_.IsValidNumber(intl_toll_free_number_too_long));
}
TEST_F(PhoneNumberUtilTest, IsPossibleNumber) {
@ -1239,6 +1347,10 @@ TEST_F(PhoneNumberUtilTest, IsPossibleNumber) {
number.set_national_number(2070313000ULL);
EXPECT_TRUE(phone_util_.IsPossibleNumber(number));
number.set_country_code(800);
number.set_national_number(12345678ULL);
EXPECT_TRUE(phone_util_.IsPossibleNumber(number));
EXPECT_TRUE(phone_util_.IsPossibleNumberForString("+1 650 253 0000",
RegionCode::US()));
EXPECT_TRUE(phone_util_.IsPossibleNumberForString("+1 650 GOO OGLE",
@ -1257,6 +1369,8 @@ TEST_F(PhoneNumberUtilTest, IsPossibleNumber) {
RegionCode::GB()));
EXPECT_TRUE(phone_util_.IsPossibleNumberForString("3331 6005",
RegionCode::NZ()));
EXPECT_TRUE(phone_util_.IsPossibleNumberForString("+800 1234 5678",
RegionCode::UN001()));
}
TEST_F(PhoneNumberUtilTest, IsPossibleNumberWithReason) {
@ -1303,6 +1417,11 @@ TEST_F(PhoneNumberUtilTest, IsPossibleNumberWithReason) {
EXPECT_EQ(PhoneNumberUtil::IS_POSSIBLE,
phone_util_.IsPossibleNumberWithReason(number));
number.set_country_code(800);
number.set_national_number(123456789ULL);
EXPECT_EQ(PhoneNumberUtil::TOO_LONG,
phone_util_.IsPossibleNumberWithReason(number));
// Try with number that we don't have metadata for.
PhoneNumber ad_number;
ad_number.set_country_code(376);
@ -1325,6 +1444,10 @@ TEST_F(PhoneNumberUtilTest, IsNotPossibleNumber) {
number.set_national_number(65025300000ULL);
EXPECT_FALSE(phone_util_.IsPossibleNumber(number));
number.set_country_code(800);
number.set_national_number(123456789ULL);
EXPECT_FALSE(phone_util_.IsPossibleNumber(number));
number.set_country_code(1);
number.set_national_number(253000ULL);
EXPECT_FALSE(phone_util_.IsPossibleNumber(number));
@ -1345,6 +1468,8 @@ TEST_F(PhoneNumberUtilTest, IsNotPossibleNumber) {
RegionCode::GB()));
EXPECT_FALSE(phone_util_.IsPossibleNumberForString("+44 300",
RegionCode::GB()));
EXPECT_FALSE(phone_util_.IsPossibleNumberForString("+800 1234 5678 9",
RegionCode::UN001()));
}
TEST_F(PhoneNumberUtilTest, TruncateTooLongNumber) {
@ -1358,6 +1483,13 @@ TEST_F(PhoneNumberUtilTest, TruncateTooLongNumber) {
EXPECT_TRUE(phone_util_.TruncateTooLongNumber(&too_long_number));
EXPECT_EQ(valid_number, too_long_number);
too_long_number.set_country_code(800);
too_long_number.set_national_number(123456789ULL);
valid_number.set_country_code(800);
valid_number.set_national_number(12345678ULL);
EXPECT_TRUE(phone_util_.TruncateTooLongNumber(&too_long_number));
EXPECT_EQ(valid_number, too_long_number);
// GB number 080 1234 5678, but entered with 4 extra digits at the end.
too_long_number.set_country_code(44);
too_long_number.set_national_number(80123456780123ULL);
@ -1405,11 +1537,12 @@ TEST_F(PhoneNumberUtilTest, TruncateTooLongNumber) {
TEST_F(PhoneNumberUtilTest, IsLeadingZeroPossible) {
EXPECT_TRUE(IsLeadingZeroPossible(39)); // Italy
EXPECT_FALSE(IsLeadingZeroPossible(1)); // USA
EXPECT_FALSE(IsLeadingZeroPossible(800)); // Not in metadata file, should
EXPECT_FALSE(IsLeadingZeroPossible(800)); // International toll free numbers
EXPECT_FALSE(IsLeadingZeroPossible(888)); // Not in metadata file, should
// return default value of false.
}
TEST_F(PhoneNumberUtilTest, FormatUsingOriginalNumberFormat) {
TEST_F(PhoneNumberUtilTest, FormatInOriginalFormat) {
PhoneNumber phone_number;
string formatted_number;
@ -1456,8 +1589,8 @@ TEST_F(PhoneNumberUtilTest, FormatUsingOriginalNumberFormat) {
&formatted_number);
EXPECT_EQ("(020) 8765 4321", formatted_number);
// Invalid numbers should be formatted using its raw input when that is
// available. Note area codes starting with 7 are intentionally excluded in
// Invalid numbers that we have a formatting pattern for should be formatted
// properly. Note area codes starting with 7 are intentionally excluded in
// the test metadata for testing purposes.
phone_number.Clear();
formatted_number.clear();
@ -1466,16 +1599,18 @@ TEST_F(PhoneNumberUtilTest, FormatUsingOriginalNumberFormat) {
&phone_number));
phone_util_.FormatInOriginalFormat(phone_number, RegionCode::US(),
&formatted_number);
EXPECT_EQ("7345678901", formatted_number);
EXPECT_EQ("734 567 8901", formatted_number);
// When the raw input is unavailable, format as usual.
// US is not a leading zero country, and the presence of the leading zero
// leads us to format the number using raw_input.
phone_number.Clear();
formatted_number.clear();
EXPECT_EQ(PhoneNumberUtil::NO_PARSING_ERROR,
phone_util_.Parse("7345678901", RegionCode::US(), &phone_number));
phone_util_.ParseAndKeepRawInput("0734567 8901", RegionCode::US(),
&phone_number));
phone_util_.FormatInOriginalFormat(phone_number, RegionCode::US(),
&formatted_number);
EXPECT_EQ("734 567 8901", formatted_number);
EXPECT_EQ("0734567 8901", formatted_number);
// This number is valid, but we don't have a formatting pattern for it. Fall
// back to the raw input.
@ -1487,6 +1622,161 @@ TEST_F(PhoneNumberUtilTest, FormatUsingOriginalNumberFormat) {
phone_util_.FormatInOriginalFormat(phone_number, RegionCode::KR(),
&formatted_number);
EXPECT_EQ("02-4567-8900", formatted_number);
phone_number.Clear();
formatted_number.clear();
EXPECT_EQ(PhoneNumberUtil::NO_PARSING_ERROR,
phone_util_.ParseAndKeepRawInput("01180012345678",
RegionCode::US(), &phone_number));
phone_util_.FormatInOriginalFormat(phone_number, RegionCode::US(),
&formatted_number);
EXPECT_EQ("011 800 1234 5678", formatted_number);
phone_number.Clear();
formatted_number.clear();
EXPECT_EQ(PhoneNumberUtil::NO_PARSING_ERROR,
phone_util_.ParseAndKeepRawInput("+80012345678", RegionCode::KR(),
&phone_number));
phone_util_.FormatInOriginalFormat(phone_number, RegionCode::KR(),
&formatted_number);
EXPECT_EQ("+800 1234 5678", formatted_number);
// US local numbers are formatted correctly, as we have formatting patterns
// for them.
phone_number.Clear();
formatted_number.clear();
EXPECT_EQ(PhoneNumberUtil::NO_PARSING_ERROR,
phone_util_.ParseAndKeepRawInput("2530000", RegionCode::US(),
&phone_number));
phone_util_.FormatInOriginalFormat(phone_number, RegionCode::US(),
&formatted_number);
EXPECT_EQ("253 0000", formatted_number);
phone_number.Clear();
formatted_number.clear();
// Number with national prefix in the US.
EXPECT_EQ(PhoneNumberUtil::NO_PARSING_ERROR,
phone_util_.ParseAndKeepRawInput("18003456789", RegionCode::US(),
&phone_number));
phone_util_.FormatInOriginalFormat(phone_number, RegionCode::US(),
&formatted_number);
EXPECT_EQ("1 800 345 6789", formatted_number);
phone_number.Clear();
formatted_number.clear();
// Number without national prefix in the UK.
EXPECT_EQ(PhoneNumberUtil::NO_PARSING_ERROR,
phone_util_.ParseAndKeepRawInput("2087654321", RegionCode::GB(),
&phone_number));
phone_util_.FormatInOriginalFormat(phone_number, RegionCode::GB(),
&formatted_number);
EXPECT_EQ("20 8765 4321", formatted_number);
phone_number.Clear();
formatted_number.clear();
// Number with national prefix in Mexico.
EXPECT_EQ(PhoneNumberUtil::NO_PARSING_ERROR,
phone_util_.ParseAndKeepRawInput("013312345678", RegionCode::MX(),
&phone_number));
phone_util_.FormatInOriginalFormat(phone_number, RegionCode::MX(),
&formatted_number);
EXPECT_EQ("01 33 1234 5678", formatted_number);
phone_number.Clear();
formatted_number.clear();
// Number without national prefix in Mexico.
EXPECT_EQ(PhoneNumberUtil::NO_PARSING_ERROR,
phone_util_.ParseAndKeepRawInput("3312345678", RegionCode::MX(),
&phone_number));
phone_util_.FormatInOriginalFormat(phone_number, RegionCode::MX(),
&formatted_number);
EXPECT_EQ("33 1234 5678", formatted_number);
phone_number.Clear();
formatted_number.clear();
// Italian fixed-line number.
EXPECT_EQ(PhoneNumberUtil::NO_PARSING_ERROR,
phone_util_.ParseAndKeepRawInput("0212345678", RegionCode::IT(),
&phone_number));
phone_util_.FormatInOriginalFormat(phone_number, RegionCode::IT(),
&formatted_number);
EXPECT_EQ("02 1234 5678", formatted_number);
phone_number.Clear();
formatted_number.clear();
// Number with national prefix in Japan.
EXPECT_EQ(PhoneNumberUtil::NO_PARSING_ERROR,
phone_util_.ParseAndKeepRawInput("00777012", RegionCode::JP(),
&phone_number));
phone_util_.FormatInOriginalFormat(phone_number, RegionCode::JP(),
&formatted_number);
EXPECT_EQ("0077-7012", formatted_number);
phone_number.Clear();
formatted_number.clear();
// Number without national prefix in Japan.
EXPECT_EQ(PhoneNumberUtil::NO_PARSING_ERROR,
phone_util_.ParseAndKeepRawInput("0777012", RegionCode::JP(),
&phone_number));
phone_util_.FormatInOriginalFormat(phone_number, RegionCode::JP(),
&formatted_number);
EXPECT_EQ("0777012", formatted_number);
phone_number.Clear();
formatted_number.clear();
// Number with carrier code in Brazil.
EXPECT_EQ(PhoneNumberUtil::NO_PARSING_ERROR,
phone_util_.ParseAndKeepRawInput("012 3121286979", RegionCode::BR(),
&phone_number));
phone_util_.FormatInOriginalFormat(phone_number, RegionCode::BR(),
&formatted_number);
EXPECT_EQ("012 3121286979", formatted_number);
phone_number.Clear();
formatted_number.clear();
// The default national prefix used in this case is 045. When a number with
// national prefix 044 is entered, we return the raw input as we don't want to
// change the number entered.
EXPECT_EQ(PhoneNumberUtil::NO_PARSING_ERROR,
phone_util_.ParseAndKeepRawInput("044(33)1234-5678",
RegionCode::MX(),
&phone_number));
phone_util_.FormatInOriginalFormat(phone_number, RegionCode::MX(),
&formatted_number);
EXPECT_EQ("044(33)1234-5678", formatted_number);
phone_number.Clear();
formatted_number.clear();
EXPECT_EQ(PhoneNumberUtil::NO_PARSING_ERROR,
phone_util_.ParseAndKeepRawInput("045(33)1234-5678",
RegionCode::MX(),
&phone_number));
phone_util_.FormatInOriginalFormat(phone_number, RegionCode::MX(),
&formatted_number);
EXPECT_EQ("045 33 1234 5678", formatted_number);
// The default international prefix used in this case is 0011. When a number
// with international prefix 0012 is entered, we return the raw input as we
// don't want to change the number entered.
phone_number.Clear();
formatted_number.clear();
EXPECT_EQ(PhoneNumberUtil::NO_PARSING_ERROR,
phone_util_.ParseAndKeepRawInput("0012 16502530000",
RegionCode::AU(),
&phone_number));
phone_util_.FormatInOriginalFormat(phone_number, RegionCode::AU(),
&formatted_number);
EXPECT_EQ("0012 16502530000", formatted_number);
phone_number.Clear();
formatted_number.clear();
EXPECT_EQ(PhoneNumberUtil::NO_PARSING_ERROR,
phone_util_.ParseAndKeepRawInput("0011 16502530000",
RegionCode::AU(),
&phone_number));
phone_util_.FormatInOriginalFormat(phone_number, RegionCode::AU(),
&formatted_number);
EXPECT_EQ("0011 1 650 253 0000", formatted_number);
}
TEST_F(PhoneNumberUtilTest, IsPremiumRate) {
@ -1625,6 +1915,7 @@ TEST_F(PhoneNumberUtilTest, GetCountryCodeForRegion) {
EXPECT_EQ(1, phone_util_.GetCountryCodeForRegion(RegionCode::US()));
EXPECT_EQ(64, phone_util_.GetCountryCodeForRegion(RegionCode::NZ()));
EXPECT_EQ(0, phone_util_.GetCountryCodeForRegion(RegionCode::GetUnknown()));
EXPECT_EQ(0, phone_util_.GetCountryCodeForRegion(RegionCode::UN001()));
// CS is already deprecated so the library doesn't support it.
EXPECT_EQ(0, phone_util_.GetCountryCodeForRegion(RegionCode::CS()));
}
@ -1653,6 +1944,9 @@ TEST_F(PhoneNumberUtilTest, GetNationalDiallingPrefixForRegion) {
GetNddPrefixForRegion(RegionCode::GetUnknown(), false, &ndd_prefix);
EXPECT_EQ("", ndd_prefix);
GetNddPrefixForRegion(RegionCode::UN001(), false, &ndd_prefix);
EXPECT_EQ("", ndd_prefix);
// CS is already deprecated so the library doesn't support it.
GetNddPrefixForRegion(RegionCode::CS(), false, &ndd_prefix);
EXPECT_EQ("", ndd_prefix);
@ -1903,6 +2197,17 @@ TEST_F(PhoneNumberUtilTest, MaybeExtractCountryCode) {
EXPECT_EQ(PhoneNumber::FROM_NUMBER_WITH_IDD, number.country_code_source());
EXPECT_EQ(stripped_number, phone_number);
number.Clear();
phone_number.assign("+80012345678");
stripped_number.assign("12345678");
expected_country_code = 800;
EXPECT_EQ(PhoneNumberUtil::NO_PARSING_ERROR,
MaybeExtractCountryCode(metadata, true, &phone_number, &number));
EXPECT_EQ(expected_country_code, number.country_code());
EXPECT_EQ(PhoneNumber::FROM_NUMBER_WITH_PLUS_SIGN,
number.country_code_source());
EXPECT_EQ(stripped_number, phone_number);
number.Clear();
phone_number.assign("+6423456789");
stripped_number.assign("23456789");
@ -2015,6 +2320,9 @@ TEST_F(PhoneNumberUtilTest, IsNumberMatchMatches) {
EXPECT_EQ(PhoneNumberUtil::EXACT_MATCH,
phone_util_.IsNumberMatchWithTwoStrings("+64 3 331 6005",
"+64 03 331 6005"));
EXPECT_EQ(PhoneNumberUtil::EXACT_MATCH,
phone_util_.IsNumberMatchWithTwoStrings("+800 1234 5678",
"+80012345678"));
EXPECT_EQ(PhoneNumberUtil::EXACT_MATCH,
phone_util_.IsNumberMatchWithTwoStrings("+64 03 331-6005",
"+64 03331 6005"));
@ -2082,6 +2390,9 @@ TEST_F(PhoneNumberUtilTest, IsNumberMatchNonMetches) {
EXPECT_EQ(PhoneNumberUtil::NO_MATCH,
phone_util_.IsNumberMatchWithTwoStrings("03 331 6005",
"03 331 6006"));
EXPECT_EQ(PhoneNumberUtil::NO_MATCH,
phone_util_.IsNumberMatchWithTwoStrings("+800 1234 5678",
"+1 800 1234 5678"));
// Different country code, partial number match.
EXPECT_EQ(PhoneNumberUtil::NO_MATCH,
phone_util_.IsNumberMatchWithTwoStrings("+64 3 331-6005",
@ -2426,6 +2737,15 @@ TEST_F(PhoneNumberUtilTest, ParseWithInternationalPrefixes) {
/* "+1 (650) 333ー6000" */
RegionCode::SG(), &test_number));
EXPECT_EQ(us_number, test_number);
PhoneNumber toll_free_number;
toll_free_number.set_country_code(800);
toll_free_number.set_national_number(12345678ULL);
test_number.Clear();
EXPECT_EQ(PhoneNumberUtil::NO_PARSING_ERROR,
phone_util_.Parse("011 800 1234 5678",
RegionCode::US(), &test_number));
EXPECT_EQ(toll_free_number, test_number);
}
TEST_F(PhoneNumberUtilTest, ParseWithLeadingZero) {
@ -2679,6 +2999,15 @@ TEST_F(PhoneNumberUtilTest, ParseNumbersWithPlusWithNoRegion) {
&result_proto));
EXPECT_EQ(nz_number, result_proto);
PhoneNumber toll_free_number;
toll_free_number.set_country_code(800);
toll_free_number.set_national_number(12345678ULL);
result_proto.Clear();
EXPECT_EQ(PhoneNumberUtil::NO_PARSING_ERROR,
phone_util_.Parse("+800 1234 5678",
RegionCode::GetUnknown(), &result_proto));
EXPECT_EQ(toll_free_number, result_proto);
nz_number.set_raw_input("+64 3 331 6005");
nz_number.set_country_code_source(PhoneNumber::FROM_NUMBER_WITH_PLUS_SIGN);
// It is important that we set this to an empty string, since we used
@ -2806,6 +3135,26 @@ TEST_F(PhoneNumberUtilTest, ParseExtensions) {
phone_util_.Parse("+44-2034567890;ext=456", RegionCode::GB(),
&test_number));
EXPECT_EQ(uk_number, test_number);
// Full-width extension, "extn" only.
test_number.Clear();
EXPECT_EQ(PhoneNumberUtil::NO_PARSING_ERROR,
phone_util_.Parse(
"+442034567890\xEF\xBD\x85\xEF\xBD\x98\xEF\xBD\x94\xEF\xBD\x8E"
"456", RegionCode::GB(), &test_number));
EXPECT_EQ(uk_number, test_number);
// "xtn" only.
test_number.Clear();
EXPECT_EQ(PhoneNumberUtil::NO_PARSING_ERROR,
phone_util_.Parse(
"+44-2034567890\xEF\xBD\x98\xEF\xBD\x94\xEF\xBD\x8E""456",
RegionCode::GB(), &test_number));
EXPECT_EQ(uk_number, test_number);
// "xt" only.
test_number.Clear();
EXPECT_EQ(PhoneNumberUtil::NO_PARSING_ERROR,
phone_util_.Parse("+44-2034567890\xEF\xBD\x98\xEF\xBD\x94""456",
RegionCode::GB(), &test_number));
EXPECT_EQ(uk_number, test_number);
PhoneNumber us_with_extension;
us_with_extension.set_country_code(1);
@ -2969,6 +3318,10 @@ TEST_F(PhoneNumberUtilTest, CanBeInternationallyDialled) {
test_number.set_country_code(64);
test_number.set_national_number(33316005ULL);
EXPECT_TRUE(CanBeInternationallyDialled(test_number));
test_number.set_country_code(800);
test_number.set_national_number(12345678ULL);
EXPECT_TRUE(CanBeInternationallyDialled(test_number));
}
TEST_F(PhoneNumberUtilTest, IsAlphaNumber) {
@ -2976,11 +3329,15 @@ TEST_F(PhoneNumberUtilTest, IsAlphaNumber) {
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 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));
}
} // namespace phonenumbers


+ 8
- 0
cpp/test/phonenumbers/test_util.h View File

@ -69,6 +69,10 @@ class RegionCode {
return "AU";
}
static const char* BR() {
return "BR";
}
static const char* BS() {
return "BS";
}
@ -125,6 +129,10 @@ class RegionCode {
return "SG";
}
static const char* UN001() {
return "001";
}
static const char* US() {
return "US";
}


Loading…
Cancel
Save