Add more tests, better naming and bug fixes

This commit is contained in:
Vlasislav Kashin
2025-07-13 17:07:40 +03:00
parent 77fa0e2b09
commit 03911c0572
8 changed files with 765 additions and 55 deletions

View File

@@ -2,5 +2,7 @@ mod metadata;
mod test_metadata; mod test_metadata;
pub use metadata::METADATA; pub use metadata::METADATA;
// use only in test case
#[cfg(test)]
pub use test_metadata::TEST_METADATA; pub use test_metadata::TEST_METADATA;

View File

@@ -65,7 +65,7 @@ pub enum MatchType {
/// Possible outcomes when testing if a PhoneNumber is possible. /// Possible outcomes when testing if a PhoneNumber is possible.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ValidNumberLenType { pub enum NumberLengthType {
/// The number length matches that of valid numbers for this region. /// The number length matches that of valid numbers for this region.
IsPossible, IsPossible,
/// The number length matches that of local numbers for this region only /// The number length matches that of local numbers for this region only

View File

@@ -82,7 +82,7 @@ pub struct InvalidMetadataForValidRegionError;
/// Possible outcomes when testing if a PhoneNumber is possible. /// Possible outcomes when testing if a PhoneNumber is possible.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Error)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Error)]
pub enum ValidationResultErr { pub enum ValidationError {
/// The number has an invalid country calling code. /// The number has an invalid country calling code.
#[error("The number has an invalid country calling code")] #[error("The number has an invalid country calling code")]
InvalidCountryCode, InvalidCountryCode,

View File

@@ -11,8 +11,8 @@ use crate::{
}; };
use super::{ use super::{
PhoneNumberFormat, PhoneNumberType, ValidNumberLenType, PhoneNumberFormat, PhoneNumberType, NumberLengthType,
errors::ValidationResultErr, errors::ValidationError,
helper_constants::{ helper_constants::{
OPTIONAL_EXT_SUFFIX, PLUS_SIGN, POSSIBLE_CHARS_AFTER_EXT_LABEL, OPTIONAL_EXT_SUFFIX, PLUS_SIGN, POSSIBLE_CHARS_AFTER_EXT_LABEL,
POSSIBLE_SEPARATORS_BETWEEN_NUMBER_AND_EXT_LABEL, RFC3966_EXTN_PREFIX, RFC3966_PREFIX, POSSIBLE_SEPARATORS_BETWEEN_NUMBER_AND_EXT_LABEL, RFC3966_EXTN_PREFIX, RFC3966_PREFIX,
@@ -342,7 +342,7 @@ pub fn test_number_length(
phone_number: &str, phone_number: &str,
phone_metadata: &PhoneMetadata, phone_metadata: &PhoneMetadata,
phone_number_type: PhoneNumberType, phone_number_type: PhoneNumberType,
) -> Result<ValidNumberLenType, ValidationResultErr> { ) -> Result<NumberLengthType, ValidationError> {
let desc_for_type = get_number_desc_by_type(phone_metadata, phone_number_type); let desc_for_type = get_number_desc_by_type(phone_metadata, phone_number_type);
// There should always be "possibleLengths" set for every element. This is // There should always be "possibleLengths" set for every element. This is
// declared in the XML schema which is verified by // declared in the XML schema which is verified by
@@ -394,31 +394,31 @@ pub fn test_number_length(
// If the type is not suported at all (indicated by the possible lengths // If the type is not suported at all (indicated by the possible lengths
// containing -1 at this point) we return invalid length. // containing -1 at this point) we return invalid length.
if *possible_lengths.first().unwrap_or(&-1) == -1 { if *possible_lengths.first().unwrap_or(&-1) == -1 {
return Err(ValidationResultErr::InvalidLength); return Err(ValidationError::InvalidLength);
} }
let actual_length = phone_number.len() as i32; let actual_length = phone_number.len() as i32;
// This is safe because there is never an overlap beween the possible lengths // This is safe because there is never an overlap beween the possible lengths
// and the local-only lengths; this is checked at build time. // and the local-only lengths; this is checked at build time.
if local_lengths.contains(&actual_length) { if local_lengths.contains(&actual_length) {
return Ok(ValidNumberLenType::IsPossibleLocalOnly); return Ok(NumberLengthType::IsPossibleLocalOnly);
} }
// here we can unwrap safe // here we can unwrap safe
let minimum_length = possible_lengths[0]; let minimum_length = possible_lengths[0];
if minimum_length == actual_length { if minimum_length == actual_length {
return Ok(ValidNumberLenType::IsPossible); return Ok(NumberLengthType::IsPossible);
} else if minimum_length > actual_length { } else if minimum_length > actual_length {
return Err(ValidationResultErr::TooShort); return Err(ValidationError::TooShort);
} else if possible_lengths[possible_lengths.len() - 1] < actual_length { } else if possible_lengths[possible_lengths.len() - 1] < actual_length {
return Err(ValidationResultErr::TooLong); return Err(ValidationError::TooLong);
} }
// We skip the first element; we've already checked it. // We skip the first element; we've already checked it.
return if possible_lengths[1..].contains(&actual_length) { return if possible_lengths[1..].contains(&actual_length) {
Ok(ValidNumberLenType::IsPossible) Ok(NumberLengthType::IsPossible)
} else { } else {
Err(ValidationResultErr::InvalidLength) Err(ValidationError::InvalidLength)
}; };
} }
@@ -428,7 +428,7 @@ pub fn test_number_length(
pub fn test_number_length_with_unknown_type( pub fn test_number_length_with_unknown_type(
phone_number: &str, phone_number: &str,
phone_metadata: &PhoneMetadata, phone_metadata: &PhoneMetadata,
) -> Result<ValidNumberLenType, ValidationResultErr> { ) -> Result<NumberLengthType, ValidationError> {
return test_number_length(phone_number, phone_metadata, PhoneNumberType::Unknown); return test_number_length(phone_number, phone_metadata, PhoneNumberType::Unknown);
} }

View File

@@ -9,7 +9,7 @@ pub(self) mod comparisons;
use std::sync::LazyLock; use std::sync::LazyLock;
pub use enums::{MatchType, PhoneNumberFormat, PhoneNumberType, ValidNumberLenType}; pub use enums::{MatchType, PhoneNumberFormat, PhoneNumberType, NumberLengthType};
use crate::phonenumberutil::phonenumberutil::PhoneNumberUtil; use crate::phonenumberutil::phonenumberutil::PhoneNumberUtil;
pub static PHONE_NUMBER_UTIL: LazyLock<PhoneNumberUtil> = LazyLock::new(|| { pub static PHONE_NUMBER_UTIL: LazyLock<PhoneNumberUtil> = LazyLock::new(|| {

View File

@@ -25,7 +25,7 @@ use crate::{
errors::{ errors::{
ExtractNumberError, GetExampleNumberError, InternalLogicError, ExtractNumberError, GetExampleNumberError, InternalLogicError,
InvalidMetadataForValidRegionError, InvalidNumberError, ParseError, InvalidMetadataForValidRegionError, InvalidNumberError, ParseError,
ValidationResultErr, ValidationError,
}, helper_constants::{ }, helper_constants::{
DEFAULT_EXTN_PREFIX, MAX_LENGTH_COUNTRY_CODE, MAX_LENGTH_FOR_NSN, MIN_LENGTH_FOR_NSN, DEFAULT_EXTN_PREFIX, MAX_LENGTH_COUNTRY_CODE, MAX_LENGTH_FOR_NSN, MIN_LENGTH_FOR_NSN,
NANPA_COUNTRY_CODE, PLUS_SIGN, REGION_CODE_FOR_NON_GEO_ENTITY, RFC3966_EXTN_PREFIX, NANPA_COUNTRY_CODE, PLUS_SIGN, REGION_CODE_FOR_NON_GEO_ENTITY, RFC3966_EXTN_PREFIX,
@@ -35,7 +35,7 @@ use crate::{
is_national_number_suffix_of_the_other, load_compiled_metadata, normalize_helper, is_national_number_suffix_of_the_other, load_compiled_metadata, normalize_helper,
prefix_number_with_country_calling_code, test_number_length, prefix_number_with_country_calling_code, test_number_length,
test_number_length_with_unknown_type, test_number_length_with_unknown_type,
}, helper_types::{PhoneNumberWithCountryCodeSource}, MatchType, PhoneNumberFormat, PhoneNumberType, ValidNumberLenType }, helper_types::{PhoneNumberWithCountryCodeSource}, MatchType, PhoneNumberFormat, PhoneNumberType, NumberLengthType
}, },
phonemetadata::{NumberFormat, PhoneMetadata, PhoneNumberDesc}, phonemetadata::{NumberFormat, PhoneMetadata, PhoneNumberDesc},
phonenumber::{phone_number::CountryCodeSource, PhoneNumber}, phonenumber::{phone_number::CountryCodeSource, PhoneNumber},
@@ -53,7 +53,7 @@ pub type RegexResult<T> = std::result::Result<T, ErrorInvalidRegex>;
pub type ParseResult<T> = std::result::Result<T, ParseError>; pub type ParseResult<T> = std::result::Result<T, ParseError>;
pub type ExampleNumberResult = std::result::Result<PhoneNumber, GetExampleNumberError>; pub type ExampleNumberResult = std::result::Result<PhoneNumber, GetExampleNumberError>;
pub type ValidationResult = std::result::Result<ValidNumberLenType, ValidationResultErr>; pub type ValidationResult = std::result::Result<NumberLengthType, ValidationError>;
pub type MatchResult = std::result::Result<MatchType, InvalidNumberError>; pub type MatchResult = std::result::Result<MatchType, InvalidNumberError>;
pub type ExtractNumberResult<T> = std::result::Result<T, ExtractNumberError>; pub type ExtractNumberResult<T> = std::result::Result<T, ExtractNumberError>;
pub type InternalLogicResult<T> = std::result::Result<T, InternalLogicError>; pub type InternalLogicResult<T> = std::result::Result<T, InternalLogicError>;
@@ -780,8 +780,8 @@ impl PhoneNumberUtil {
.ok_or(InvalidMetadataForValidRegionError {})?; .ok_or(InvalidMetadataForValidRegionError {})?;
let national_number = self.get_national_significant_number(&number_no_extension); let national_number = self.get_national_significant_number(&number_no_extension);
let format = if self.can_be_internationally_dialled(&number_no_extension)? let format = if self.can_be_internationally_dialled(&number_no_extension)?
&& test_number_length_with_unknown_type(&national_number, region_metadata) && !test_number_length_with_unknown_type(&national_number, region_metadata)
.is_err_and(|e| matches!(e, ValidationResultErr::TooShort)) .is_err_and(|e| matches!(e, ValidationError::TooShort))
{ {
PhoneNumberFormat::International PhoneNumberFormat::International
} else { } else {
@@ -1686,14 +1686,14 @@ impl PhoneNumberUtil {
// with this country calling code in the metadata for the default region in // with this country calling code in the metadata for the default region in
// this case. // this case.
if !self.has_valid_country_calling_code(country_code) { if !self.has_valid_country_calling_code(country_code) {
return Err(ValidationResultErr::InvalidCountryCode); return Err(ValidationError::InvalidCountryCode);
} }
let region_code = self.get_region_code_for_country_code(country_code); let region_code = self.get_region_code_for_country_code(country_code);
// Metadata cannot be NULL because the country calling code is valid. // Metadata cannot be NULL because the country calling code is valid.
let Some(metadata) = let Some(metadata) =
self.get_metadata_for_region_or_calling_code(country_code, region_code) self.get_metadata_for_region_or_calling_code(country_code, region_code)
else { else {
return Err(ValidationResultErr::InvalidCountryCode); return Err(ValidationError::InvalidCountryCode);
}; };
return test_number_length(&national_number, metadata, phone_number_type); return test_number_length(&national_number, metadata, phone_number_type);
} }
@@ -1712,7 +1712,7 @@ impl PhoneNumberUtil {
number_copy.set_national_number(national_number); number_copy.set_national_number(national_number);
if self if self
.is_possible_number_with_reason(&number_copy) .is_possible_number_with_reason(&number_copy)
.is_err_and(|err| matches!(err, ValidationResultErr::TooShort)) .is_err_and(|err| matches!(err, ValidationError::TooShort))
|| national_number == 0 || national_number == 0
{ {
return Ok(false); return Ok(false);
@@ -1831,11 +1831,11 @@ impl PhoneNumberUtil {
let validation_result = let validation_result =
test_number_length_with_unknown_type(&potential_national_number, country_metadata); test_number_length_with_unknown_type(&potential_national_number, country_metadata);
if !validation_result if !validation_result
.is_ok_and(|res| matches!(res, ValidNumberLenType::IsPossibleLocalOnly)) .is_ok_and(|res| matches!(res, NumberLengthType::IsPossibleLocalOnly))
&& !validation_result.is_err_and(|err| { && !validation_result.is_err_and(|err| {
matches!( matches!(
err, err,
ValidationResultErr::TooShort | ValidationResultErr::InvalidLength ValidationError::TooShort | ValidationError::InvalidLength
) )
}) })
{ {
@@ -2040,7 +2040,7 @@ impl PhoneNumberUtil {
&national_number, &national_number,
default_region_metadata, default_region_metadata,
) )
.is_err_and(|e| matches!(e, ValidationResultErr::TooLong)) .is_err_and(|e| matches!(e, ValidationError::TooLong))
{ {
if keep_raw_input { if keep_raw_input {
phone_number.set_country_code_source( phone_number.set_country_code_source(
@@ -2379,11 +2379,10 @@ impl PhoneNumberUtil {
} }
if (matches!(phone_number_type, PhoneNumberType::Mobile) if (matches!(phone_number_type, PhoneNumberType::Mobile)
&& !self && self
.reg_exps .reg_exps
.geo_mobile_countries_without_mobile_area_codes .geo_mobile_countries_without_mobile_area_codes
.contains(&country_calling_code)) .contains(&country_calling_code)) {
{
return Ok(0); return Ok(0);
} }

View File

@@ -1,9 +1,9 @@
use protobuf::{Message, MessageField}; use protobuf::{Message, MessageField};
use crate::{ use crate::{
enums::{PhoneNumberFormat, PhoneNumberType, ValidNumberLenType}, enums::{PhoneNumberFormat, PhoneNumberType, NumberLengthType},
errors::{ParseError, ValidationResultErr}, errors::{ParseError, ValidationError},
phonemetadata::{PhoneMetadata, PhoneMetadataCollection, PhoneNumberDesc}, phonemetadata::{NumberFormat, PhoneMetadata, PhoneMetadataCollection, PhoneNumberDesc},
phonenumber::{phone_number::CountryCodeSource, PhoneNumber}, phonenumber::{phone_number::CountryCodeSource, PhoneNumber},
PhoneNumberUtil, PhoneNumberUtil,
}; };
@@ -679,6 +679,261 @@ fn format_with_preferred_carrier_code() {
assert_eq!("424 123 1234", formatted); assert_eq!("424 123 1234", formatted);
} }
#[test]
fn format_number_for_mobile_dialing() {
let phone_util = get_phone_util();
let mut test_number = PhoneNumber::new();
// Номера обычно набираются в национальном формате внутри страны и
// в международном формате из-за пределов страны.
test_number.set_country_code(57);
test_number.set_national_number(6012345678);
let formatted_number = phone_util.format_number_for_mobile_dialing(&test_number, "CO", false).unwrap();
assert_eq!("6012345678", formatted_number);
test_number.set_country_code(49);
test_number.set_national_number(30123456);
let formatted_number = phone_util.format_number_for_mobile_dialing(&test_number, "DE", false).unwrap();
assert_eq!("030123456", formatted_number);
let formatted_number = phone_util.format_number_for_mobile_dialing(&test_number, "CH", false).unwrap();
assert_eq!("+4930123456", formatted_number);
test_number.set_extension("1234".to_string());
let formatted_number = phone_util.format_number_for_mobile_dialing(&test_number, "DE", false).unwrap();
assert_eq!("030123456", formatted_number);
let formatted_number = phone_util.format_number_for_mobile_dialing(&test_number, "CH", false).unwrap();
assert_eq!("+4930123456", formatted_number);
test_number.set_country_code(1);
test_number.clear_extension();
// Бесплатные номера США помечены как noInternationalDialing в тестовых метаданных
// для целей тестирования. Для таких номеров мы ожидаем, что ничего не будет
// возвращено, если код региона не совпадает.
test_number.set_national_number(8002530000);
let formatted_number = phone_util.format_number_for_mobile_dialing(&test_number, "US", true).unwrap();
assert_eq!("800 253 0000", formatted_number);
let formatted_number = phone_util.format_number_for_mobile_dialing(&test_number, "CN", true).unwrap();
assert_eq!("", formatted_number);
let formatted_number = phone_util.format_number_for_mobile_dialing(&test_number, "US", false).unwrap();
assert_eq!("8002530000", formatted_number);
let formatted_number = phone_util.format_number_for_mobile_dialing(&test_number, "CN", false).unwrap();
assert_eq!("", formatted_number);
test_number.set_national_number(6502530000);
let formatted_number = phone_util
.format_number_for_mobile_dialing(&test_number, "US", true)
.unwrap();
assert_eq!("+1 650 253 0000", formatted_number);
let formatted_number = phone_util
.format_number_for_mobile_dialing(&test_number, "US", false)
.unwrap();
assert_eq!("+16502530000", formatted_number);
test_number.set_extension("1234".to_string());
let formatted_number = phone_util.format_number_for_mobile_dialing(&test_number, "US", true).unwrap();
assert_eq!("+1 650 253 0000", formatted_number);
let formatted_number = phone_util.format_number_for_mobile_dialing(&test_number, "US", false).unwrap();
assert_eq!("+16502530000", formatted_number);
// Невалидный номер США, который на одну цифру длиннее.
test_number.clear_extension();
test_number.set_national_number(65025300001);
let formatted_number = phone_util.format_number_for_mobile_dialing(&test_number, "US", true).unwrap();
assert_eq!("+1 65025300001", formatted_number);
let formatted_number = phone_util.format_number_for_mobile_dialing(&test_number, "US", false).unwrap();
assert_eq!("+165025300001", formatted_number);
// Номера со звёздочкой. В реальности они есть в Израиле, но в наших
// тестовых метаданных они есть для Японии (JP).
test_number.set_country_code(81);
test_number.set_national_number(2345);
let formatted_number = phone_util.format_number_for_mobile_dialing(&test_number, "JP", true).unwrap();
assert_eq!("*2345", formatted_number);
let formatted_number = phone_util.format_number_for_mobile_dialing(&test_number, "JP", false).unwrap();
assert_eq!("*2345", formatted_number);
test_number.set_country_code(800);
test_number.set_national_number(12345678);
let formatted_number = phone_util.format_number_for_mobile_dialing(&test_number, "JP", false).unwrap();
assert_eq!("+80012345678", formatted_number);
let formatted_number = phone_util.format_number_for_mobile_dialing(&test_number, "JP", true).unwrap();
assert_eq!("+800 1234 5678", formatted_number);
// Номера ОАЭ, начинающиеся с 600 (классифицируются как UAN), должны набираться
// без +971 на местном уровне.
test_number.set_country_code(971);
test_number.set_national_number(600123456);
let formatted_number = phone_util.format_number_for_mobile_dialing(&test_number, "JP", false).unwrap();
assert_eq!("+971600123456", formatted_number);
let formatted_number = phone_util.format_number_for_mobile_dialing(&test_number, "AE", true).unwrap();
assert_eq!("600123456", formatted_number);
test_number.set_country_code(52);
test_number.set_national_number(3312345678);
let formatted_number = phone_util.format_number_for_mobile_dialing(&test_number, "MX", false).unwrap();
assert_eq!("+523312345678", formatted_number);
let formatted_number = phone_util.format_number_for_mobile_dialing(&test_number, "US", false).unwrap();
assert_eq!("+523312345678", formatted_number);
// Проверяем, что узбекские номера возвращаются в международном формате, даже
// если набираются из того же региона или других регионов.
// Стационарный номер
test_number.set_country_code(998);
test_number.set_national_number(612201234);
let formatted_number = phone_util.format_number_for_mobile_dialing(&test_number, "UZ", false).unwrap();
assert_eq!("+998612201234", formatted_number);
// Мобильный номер
test_number.set_national_number(950123456);
let formatted_number = phone_util.format_number_for_mobile_dialing(&test_number, "UZ", false).unwrap();
assert_eq!("+998950123456", formatted_number);
let formatted_number = phone_util.format_number_for_mobile_dialing(&test_number, "US", false).unwrap();
assert_eq!("+998950123456", formatted_number);
// Негеографические номера всегда должны набираться в международном формате.
test_number.set_country_code(800);
test_number.set_national_number(12345678);
let formatted_number = phone_util.format_number_for_mobile_dialing(&test_number, "US", false).unwrap();
assert_eq!("+80012345678", formatted_number);
let formatted_number = phone_util.format_number_for_mobile_dialing(&test_number, "001", false).unwrap();
assert_eq!("+80012345678", formatted_number);
// Тестируем, что короткий номер форматируется корректно для мобильного набора
// внутри региона и не может быть набран из-за его пределов.
test_number.set_country_code(49);
test_number.set_national_number(123);
let formatted_number = phone_util.format_number_for_mobile_dialing(&test_number, "DE", false).unwrap();
assert_eq!("123", formatted_number);
let formatted_number = phone_util.format_number_for_mobile_dialing(&test_number, "IT", false).unwrap();
assert_eq!("", formatted_number);
// Тестируем специальную логику для стран NANPA, где номера обычной длины
// всегда выводятся в международном формате, а короткие — в национальном.
test_number.set_country_code(1);
test_number.set_national_number(6502530000);
let formatted_number = phone_util.format_number_for_mobile_dialing(&test_number, "US", false).unwrap();
assert_eq!("+16502530000", formatted_number);
let formatted_number = phone_util.format_number_for_mobile_dialing(&test_number, "CA", false).unwrap();
assert_eq!("+16502530000", formatted_number);
let formatted_number = phone_util.format_number_for_mobile_dialing(&test_number, "BR", false).unwrap();
assert_eq!("+16502530000", formatted_number);
test_number.set_national_number(911);
let formatted_number = phone_util.format_number_for_mobile_dialing(&test_number, "US", false).unwrap();
assert_eq!("911", formatted_number);
let formatted_number = phone_util.format_number_for_mobile_dialing(&test_number, "CA", false).unwrap();
assert_eq!("", formatted_number);
let formatted_number = phone_util.format_number_for_mobile_dialing(&test_number, "BR", false).unwrap();
assert_eq!("", formatted_number);
// Тестируем, что австралийский номер экстренной службы 000 форматируется корректно.
test_number.set_country_code(61);
test_number.set_national_number(0);
test_number.set_italian_leading_zero(true);
test_number.set_number_of_leading_zeros(2);
let formatted_number = phone_util.format_number_for_mobile_dialing(&test_number, "AU", false).unwrap();
assert_eq!("000", formatted_number);
let formatted_number = phone_util.format_number_for_mobile_dialing(&test_number, "NZ", false).unwrap();
assert_eq!("", formatted_number);
}
#[test]
fn format_by_pattern() {
let phone_util = get_phone_util();
let mut test_number = PhoneNumber::new();
let mut number_format = NumberFormat::new();
test_number.set_country_code(1);
test_number.set_national_number(6502530000);
number_format.set_pattern("(\\d{3})(\\d{3})(\\d{4})".to_string());
number_format.set_format("($1) $2-$3".to_string());
let number_formats = vec![number_format.clone()];
let formatted_number = phone_util
.format_by_pattern(&test_number, PhoneNumberFormat::National, &number_formats)
.unwrap();
assert_eq!("(650) 253-0000", formatted_number);
let formatted_number = phone_util
.format_by_pattern(&test_number, PhoneNumberFormat::International, &number_formats)
.unwrap();
assert_eq!("+1 (650) 253-0000", formatted_number);
let formatted_number = phone_util
.format_by_pattern(&test_number, PhoneNumberFormat::RFC3966, &number_formats)
.unwrap();
assert_eq!("tel:+1-650-253-0000", formatted_number);
// $NP устанавливается в '1' для США. Здесь мы проверяем, что для других стран
// NANPA (Североамериканский план нумерации) правила США соблюдаются.
number_format.set_national_prefix_formatting_rule("$NP ($FG)".to_string());
number_format.set_format("$1 $2-$3".to_string());
let number_formats = vec![number_format.clone()];
test_number.set_country_code(1);
test_number.set_national_number(4168819999);
let formatted_number = phone_util
.format_by_pattern(&test_number, PhoneNumberFormat::National, &number_formats)
.unwrap();
assert_eq!("1 (416) 881-9999", formatted_number);
let formatted_number = phone_util
.format_by_pattern(&test_number, PhoneNumberFormat::International, &number_formats)
.unwrap();
assert_eq!("+1 416 881-9999", formatted_number);
test_number.set_country_code(39);
test_number.set_national_number(236618300);
test_number.set_italian_leading_zero(true);
number_format.set_pattern("(\\d{2})(\\d{5})(\\d{3})".to_string());
number_format.set_format("$1-$2 $3".to_string());
number_format.clear_national_prefix_formatting_rule();
let number_formats = vec![number_format.clone()];
let formatted_number = phone_util
.format_by_pattern(&test_number, PhoneNumberFormat::National, &number_formats)
.unwrap();
assert_eq!("02-36618 300", formatted_number);
let formatted_number = phone_util
.format_by_pattern(&test_number, PhoneNumberFormat::International, &number_formats)
.unwrap();
assert_eq!("+39 02-36618 300", formatted_number);
test_number.set_country_code(44);
test_number.set_national_number(2012345678);
test_number.set_italian_leading_zero(false);
number_format.set_national_prefix_formatting_rule("$NP$FG".to_string());
number_format.set_pattern("(\\d{2})(\\d{4})(\\d{4})".to_string());
number_format.set_format("$1 $2 $3".to_string());
let mut number_formats = vec![number_format]; // mutable vec to modify the element inside
let formatted_number = phone_util
.format_by_pattern(&test_number, PhoneNumberFormat::National, &number_formats)
.unwrap();
assert_eq!("020 1234 5678", formatted_number);
number_formats[0].set_national_prefix_formatting_rule("($NP$FG)".to_string());
let formatted_number = phone_util
.format_by_pattern(&test_number, PhoneNumberFormat::National, &number_formats)
.unwrap();
assert_eq!("(020) 1234 5678", formatted_number);
number_formats[0].clear_national_prefix_formatting_rule();
let formatted_number = phone_util
.format_by_pattern(&test_number, PhoneNumberFormat::National, &number_formats)
.unwrap();
assert_eq!("20 1234 5678", formatted_number);
let formatted_number = phone_util
.format_by_pattern(&test_number, PhoneNumberFormat::International, &number_formats)
.unwrap();
assert_eq!("+44 20 1234 5678", formatted_number);
}
#[test] #[test]
fn format_in_original_format() { fn format_in_original_format() {
let phone_util = get_phone_util(); let phone_util = get_phone_util();
@@ -1047,6 +1302,221 @@ fn format_number_with_extension() {
assert_eq!("650 253 0000 extn. 4567", phone_util.format(&us_number_with_extension, PhoneNumberFormat::National).unwrap()); assert_eq!("650 253 0000 extn. 4567", phone_util.format(&us_number_with_extension, PhoneNumberFormat::National).unwrap());
} }
#[test]
fn get_length_of_geographical_area_code() {
let phone_util = get_phone_util();
let mut number = PhoneNumber::new();
// Google MTV, с кодом города "650".
number.set_country_code(1);
number.set_national_number(6502530000);
assert_eq!(3, phone_util.get_length_of_geographical_area_code(&number).unwrap());
// Бесплатный номер в Северной Америке, без кода города.
number.set_country_code(1);
number.set_national_number(8002530000);
assert_eq!(0, phone_util.get_length_of_geographical_area_code(&number).unwrap());
// Невалидный номер США (на 1 цифру короче), без кода города.
number.set_country_code(1);
number.set_national_number(650253000);
assert_eq!(0, phone_util.get_length_of_geographical_area_code(&number).unwrap());
// Google London, с кодом города "20".
number.set_country_code(44);
number.set_national_number(2070313000);
assert_eq!(2, phone_util.get_length_of_geographical_area_code(&number).unwrap());
// Мобильный номер в Великобритании не имеет кода города.
number.set_country_code(44);
number.set_national_number(7912345678);
assert_eq!(0, phone_util.get_length_of_geographical_area_code(&number).unwrap());
// Google Buenos Aires, с кодом города "11".
number.set_country_code(54);
number.set_national_number(1155303000);
assert_eq!(2, phone_util.get_length_of_geographical_area_code(&number).unwrap());
// Мобильный номер в Аргентине также имеет код города.
number.set_country_code(54);
number.set_national_number(91187654321);
assert_eq!(3, phone_util.get_length_of_geographical_area_code(&number).unwrap());
// Google Sydney, с кодом города "2".
number.set_country_code(61);
number.set_national_number(293744000);
assert_eq!(1, phone_util.get_length_of_geographical_area_code(&number).unwrap());
// Номера Мексики - нет национального префикса, но есть код города.
number.set_country_code(52);
number.set_national_number(3312345678);
assert_eq!(2, phone_util.get_length_of_geographical_area_code(&number).unwrap());
// Итальянские номера - нет национального префикса, но есть код города.
number.set_country_code(39);
number.set_national_number(236618300);
number.set_italian_leading_zero(true);
assert_eq!(2, phone_util.get_length_of_geographical_area_code(&number).unwrap());
// Google Singapore. В Сингапуре нет кода города и национального префикса.
number.set_country_code(65);
number.set_national_number(65218000);
number.set_italian_leading_zero(false);
assert_eq!(0, phone_util.get_length_of_geographical_area_code(&number).unwrap());
// Международный бесплатный номер, без кода города.
number.set_country_code(800);
number.set_national_number(12345678);
assert_eq!(0, phone_util.get_length_of_geographical_area_code(&number).unwrap());
// Мобильный номер из Китая является географическим, но не имеет кода города.
let mut cn_mobile = PhoneNumber::new();
cn_mobile.set_country_code(86);
cn_mobile.set_national_number(18912341234);
assert_eq!(0, phone_util.get_length_of_geographical_area_code(&cn_mobile).unwrap());
}
#[test]
fn get_length_of_national_destination_code() {
let phone_util = get_phone_util();
let mut number = PhoneNumber::new();
// Google MTV, с национальным кодом назначения (NDC) "650".
number.set_country_code(1);
number.set_national_number(6502530000);
assert_eq!(3, phone_util.get_length_of_national_destination_code(&number).unwrap());
// Бесплатный номер Северной Америки, с NDC "800".
number.set_country_code(1);
number.set_national_number(8002530000);
assert_eq!(3, phone_util.get_length_of_national_destination_code(&number).unwrap());
// Google London, с NDC "20".
number.set_country_code(44);
number.set_national_number(2070313000);
assert_eq!(2, phone_util.get_length_of_national_destination_code(&number).unwrap());
// Мобильный телефон в Великобритании, с NDC "7912".
number.set_country_code(44);
number.set_national_number(7912345678);
assert_eq!(4, phone_util.get_length_of_national_destination_code(&number).unwrap());
// Google Buenos Aires, с NDC "11".
number.set_country_code(54);
number.set_national_number(1155303000);
assert_eq!(2, phone_util.get_length_of_national_destination_code(&number).unwrap());
// Аргентинский мобильный, с NDC "911".
number.set_country_code(54);
number.set_national_number(91187654321);
assert_eq!(3, phone_util.get_length_of_national_destination_code(&number).unwrap());
// Google Sydney, с NDC "2".
number.set_country_code(61);
number.set_national_number(293744000);
assert_eq!(1, phone_util.get_length_of_national_destination_code(&number).unwrap());
// Google Singapore. Сингапур имеет NDC "6521".
number.set_country_code(65);
number.set_national_number(65218000);
assert_eq!(4, phone_util.get_length_of_national_destination_code(&number).unwrap());
// Невалидный номер США (на 1 цифру короче), без NDC.
number.set_country_code(1);
number.set_national_number(650253000);
assert_eq!(0, phone_util.get_length_of_national_destination_code(&number).unwrap());
// Номер с невалидным кодом страны, не должен иметь NDC.
number.set_country_code(123);
number.set_national_number(650253000);
assert_eq!(0, phone_util.get_length_of_national_destination_code(&number).unwrap());
// Номер, который имеет только одну группу цифр после кода страны при
// форматировании в международном формате.
number.set_country_code(376);
number.set_national_number(12345);
assert_eq!(0, phone_util.get_length_of_national_destination_code(&number).unwrap());
// Тот же номер, но с добавочным.
number.set_extension("321".to_string());
assert_eq!(0, phone_util.get_length_of_national_destination_code(&number).unwrap());
// Международный бесплатный номер, с NDC "1234".
number = PhoneNumber::new();
number.set_country_code(800);
number.set_national_number(12345678);
assert_eq!(4, phone_util.get_length_of_national_destination_code(&number).unwrap());
// Мобильный номер из Китая является географическим, но не имеет кода города,
// однако у него может быть национальный код назначения.
let mut cn_mobile = PhoneNumber::new();
cn_mobile.set_country_code(86);
cn_mobile.set_national_number(18912341234);
assert_eq!(3, phone_util.get_length_of_national_destination_code(&cn_mobile).unwrap());
}
#[test]
fn extract_possible_number() {
let phone_util = get_phone_util();
// Удаляет предшествующие знаки препинания и буквы, но оставляет остальное без изменений.
let extracted_number = phone_util
.extract_possible_number("Tel:0800-345-600")
.unwrap();
assert_eq!("0800-345-600", extracted_number);
let extracted_number = phone_util
.extract_possible_number("Tel:0800 FOR PIZZA")
.unwrap();
assert_eq!("0800 FOR PIZZA", extracted_number);
// Не должен удалять знак плюса.
let extracted_number = phone_util
.extract_possible_number("Tel:+800-345-600")
.unwrap();
assert_eq!("+800-345-600", extracted_number);
// Должен распознавать широкие цифры как возможные начальные значения.
let extracted_number = phone_util
.extract_possible_number("\u{FF10}\u{FF12}\u{FF13}")
.unwrap(); // ""
assert_eq!("\u{FF10}\u{FF12}\u{FF13}", extracted_number);
// Дефисы не являются возможными начальными значениями и должны быть удалены.
let extracted_number = phone_util.
extract_possible_number("Num-\u{FF11}\u{FF12}\u{FF13}")
.unwrap(); // "Num-"
assert_eq!("\u{FF11}\u{FF12}\u{FF13}", extracted_number);
// Если возможный номер отсутствует, возвращается пустая строка.
let extracted_number = phone_util
.extract_possible_number("Num-....");
assert!(extracted_number.is_err());
// Ведущие скобки удаляются - они не используются при парсинге.
let extracted_number = phone_util
.extract_possible_number("(650) 253-0000")
.unwrap();
assert_eq!("650) 253-0000", extracted_number);
// Конечные не-буквенно-цифровые символы должны быть удалены.
let extracted_number = phone_util
.extract_possible_number("(650) 253-0000..- ..")
.unwrap();
assert_eq!("650) 253-0000", extracted_number);
let extracted_number = phone_util
.extract_possible_number("(650) 253-0000.")
.unwrap();
assert_eq!("650) 253-0000", extracted_number);
// Этот случай имеет конечный символ RTL.
let extracted_number = phone_util
.extract_possible_number("(650) 253-0000\u{200F}")
.unwrap(); // "(650) 253-0000"
assert_eq!("650) 253-0000", extracted_number);
}
#[test] #[test]
fn is_valid_number() { fn is_valid_number() {
let phone_util = get_phone_util(); let phone_util = get_phone_util();
@@ -1232,6 +1702,106 @@ fn is_possible_number() {
assert!(phone_util.is_possible_number_for_string("+800 1234 5678", RegionCode::un001())); assert!(phone_util.is_possible_number_for_string("+800 1234 5678", RegionCode::un001()));
} }
#[test]
fn is_possible_number_for_type_different_type_lengths() {
let phone_util = get_phone_util();
// Мы используем аргентинские номера, так как у них разная возможная длина для
// разных типов.
let mut number = PhoneNumber::new();
number.set_country_code(54);
number.set_national_number(12345);
// Слишком короткий для любого аргентинского номера, включая стационарный.
assert!(!phone_util.is_possible_number_for_type(&number, PhoneNumberType::FixedLine));
assert!(!phone_util.is_possible_number_for_type(&number, PhoneNumberType::Unknown));
// 6-значные номера подходят для стационарных телефонов.
number.set_national_number(123456);
assert!(phone_util.is_possible_number_for_type(&number, PhoneNumberType::Unknown));
assert!(phone_util.is_possible_number_for_type(&number, PhoneNumberType::FixedLine));
// Но слишком короткие для мобильных.
assert!(!phone_util.is_possible_number_for_type(&number, PhoneNumberType::Mobile));
// И слишком короткие для бесплатных номеров.
assert!(!phone_util.is_possible_number_for_type(&number, PhoneNumberType::TollFree));
// То же самое относится к 9-значным номерам.
number.set_national_number(123456789);
assert!(phone_util.is_possible_number_for_type(&number, PhoneNumberType::Unknown));
assert!(phone_util.is_possible_number_for_type(&number, PhoneNumberType::FixedLine));
assert!(!phone_util.is_possible_number_for_type(&number, PhoneNumberType::Mobile));
assert!(!phone_util.is_possible_number_for_type(&number, PhoneNumberType::TollFree));
// 10-значные номера возможны для всех типов.
number.set_national_number(1234567890);
assert!(phone_util.is_possible_number_for_type(&number, PhoneNumberType::Unknown));
assert!(phone_util.is_possible_number_for_type(&number, PhoneNumberType::FixedLine));
assert!(phone_util.is_possible_number_for_type(&number, PhoneNumberType::Mobile));
assert!(phone_util.is_possible_number_for_type(&number, PhoneNumberType::TollFree));
// 11-значные номера возможны только для мобильных номеров. Обратите внимание, что мы не
// требуем ведущую 9, с которой начинаются все мобильные номера и которая
// была бы необходима для действительного мобильного номера.
number.set_national_number(12345678901);
assert!(phone_util.is_possible_number_for_type(&number, PhoneNumberType::Unknown));
assert!(!phone_util.is_possible_number_for_type(&number, PhoneNumberType::FixedLine));
assert!(phone_util.is_possible_number_for_type(&number, PhoneNumberType::Mobile));
assert!(!phone_util.is_possible_number_for_type(&number, PhoneNumberType::TollFree));
}
#[test]
fn is_possible_number_for_type_local_only() {
let phone_util = get_phone_util();
let mut number = PhoneNumber::new();
// Здесь мы тестируем длину номера, которая соответствует длине только для местных номеров.
number.set_country_code(49);
number.set_national_number(12);
assert!(phone_util.is_possible_number_for_type(&number, PhoneNumberType::Unknown));
assert!(phone_util.is_possible_number_for_type(&number, PhoneNumberType::FixedLine));
// Мобильные номера должны состоять из 10 или 11 цифр, и для них нет длин,
// предназначенных только для местных номеров.
assert!(!phone_util.is_possible_number_for_type(&number, PhoneNumberType::Mobile));
}
#[test]
fn is_possible_number_for_type_data_missing_for_size_reasons() {
let phone_util = get_phone_util();
let mut number = PhoneNumber::new();
// Здесь мы тестируем случай, когда возможные длины соответствуют возможным
// длинам страны в целом и, следовательно, отсутствуют в бинарных данных
// по соображениям размера - это все равно должно работать.
// Номер только для местного использования.
number.set_country_code(55);
number.set_national_number(12345678);
assert!(phone_util.is_possible_number_for_type(&number, PhoneNumberType::Unknown));
assert!(phone_util.is_possible_number_for_type(&number, PhoneNumberType::FixedLine));
number.set_national_number(1234567890);
assert!(phone_util.is_possible_number_for_type(&number, PhoneNumberType::Unknown));
assert!(phone_util.is_possible_number_for_type(&number, PhoneNumberType::FixedLine));
}
#[test]
fn is_possible_number_for_type_number_type_not_supported_for_region() {
let phone_util = get_phone_util();
let mut number = PhoneNumber::new();
// Для этого региона вообще нет мобильных номеров, поэтому мы возвращаем false.
number.set_country_code(55);
number.set_national_number(12345678);
assert!(!phone_util.is_possible_number_for_type(&number, PhoneNumberType::Mobile));
// Однако это соответствует длине стационарного номера.
assert!(phone_util.is_possible_number_for_type(&number, PhoneNumberType::FixedLine));
assert!(phone_util.is_possible_number_for_type(&number, PhoneNumberType::FixedLineOrMobile));
// Для этого кода страны вообще нет ни стационарных, ни мобильных номеров,
// поэтому мы возвращаем false для них.
number.set_country_code(979);
number.set_national_number(123456789);
assert!(!phone_util.is_possible_number_for_type(&number, PhoneNumberType::Mobile));
assert!(!phone_util.is_possible_number_for_type(&number, PhoneNumberType::FixedLine));
assert!(!phone_util.is_possible_number_for_type(&number, PhoneNumberType::FixedLineOrMobile));
assert!(phone_util.is_possible_number_for_type(&number, PhoneNumberType::PremiumRate));
}
#[test] #[test]
fn is_not_possible_number() { fn is_not_possible_number() {
let phone_util = get_phone_util(); let phone_util = get_phone_util();
@@ -1270,36 +1840,36 @@ fn is_possible_number_with_reason() {
number.set_country_code(1); number.set_country_code(1);
number.set_national_number(6502530000); number.set_national_number(6502530000);
assert_eq!(Ok(ValidNumberLenType::IsPossible), phone_util.is_possible_number_with_reason(&number)); assert_eq!(Ok(NumberLengthType::IsPossible), phone_util.is_possible_number_with_reason(&number));
number.set_national_number(2530000); number.set_national_number(2530000);
assert_eq!(Ok(ValidNumberLenType::IsPossibleLocalOnly), phone_util.is_possible_number_with_reason(&number)); assert_eq!(Ok(NumberLengthType::IsPossibleLocalOnly), phone_util.is_possible_number_with_reason(&number));
number.set_country_code(0); number.set_country_code(0);
assert_eq!(Err(ValidationResultErr::InvalidCountryCode), phone_util.is_possible_number_with_reason(&number)); assert_eq!(Err(ValidationError::InvalidCountryCode), phone_util.is_possible_number_with_reason(&number));
number.set_country_code(1); number.set_country_code(1);
number.set_national_number(253000); number.set_national_number(253000);
assert_eq!(Err(ValidationResultErr::TooShort), phone_util.is_possible_number_with_reason(&number)); assert_eq!(Err(ValidationError::TooShort), phone_util.is_possible_number_with_reason(&number));
number.set_national_number(65025300000); number.set_national_number(65025300000);
assert_eq!(Err(ValidationResultErr::TooLong), phone_util.is_possible_number_with_reason(&number)); assert_eq!(Err(ValidationError::TooLong), phone_util.is_possible_number_with_reason(&number));
number.set_country_code(44); number.set_country_code(44);
number.set_national_number(2070310000); number.set_national_number(2070310000);
assert_eq!(Ok(ValidNumberLenType::IsPossible), phone_util.is_possible_number_with_reason(&number)); assert_eq!(Ok(NumberLengthType::IsPossible), phone_util.is_possible_number_with_reason(&number));
number.set_country_code(49); number.set_country_code(49);
number.set_national_number(30123456); number.set_national_number(30123456);
assert_eq!(Ok(ValidNumberLenType::IsPossible), phone_util.is_possible_number_with_reason(&number)); assert_eq!(Ok(NumberLengthType::IsPossible), phone_util.is_possible_number_with_reason(&number));
number.set_country_code(65); number.set_country_code(65);
number.set_national_number(1234567890); number.set_national_number(1234567890);
assert_eq!(Ok(ValidNumberLenType::IsPossible), phone_util.is_possible_number_with_reason(&number)); assert_eq!(Ok(NumberLengthType::IsPossible), phone_util.is_possible_number_with_reason(&number));
number.set_country_code(800); number.set_country_code(800);
number.set_national_number(123456789); number.set_national_number(123456789);
assert_eq!(Err(ValidationResultErr::TooLong), phone_util.is_possible_number_with_reason(&number)); assert_eq!(Err(ValidationError::TooLong), phone_util.is_possible_number_with_reason(&number));
} }
#[test] #[test]
@@ -1309,33 +1879,170 @@ fn is_possible_number_for_type_with_reason() {
ar_number.set_country_code(54); ar_number.set_country_code(54);
ar_number.set_national_number(12345); ar_number.set_national_number(12345);
assert_eq!(Err(ValidationResultErr::TooShort), phone_util.is_possible_number_for_type_with_reason(&ar_number, PhoneNumberType::Unknown)); assert_eq!(Err(ValidationError::TooShort), phone_util.is_possible_number_for_type_with_reason(&ar_number, PhoneNumberType::Unknown));
assert_eq!(Err(ValidationResultErr::TooShort), phone_util.is_possible_number_for_type_with_reason(&ar_number, PhoneNumberType::FixedLine)); assert_eq!(Err(ValidationError::TooShort), phone_util.is_possible_number_for_type_with_reason(&ar_number, PhoneNumberType::FixedLine));
ar_number.set_national_number(123456); ar_number.set_national_number(123456);
assert_eq!(Ok(ValidNumberLenType::IsPossible), phone_util.is_possible_number_for_type_with_reason(&ar_number, PhoneNumberType::Unknown)); assert_eq!(Ok(NumberLengthType::IsPossible), phone_util.is_possible_number_for_type_with_reason(&ar_number, PhoneNumberType::Unknown));
assert_eq!(Ok(ValidNumberLenType::IsPossible), phone_util.is_possible_number_for_type_with_reason(&ar_number, PhoneNumberType::FixedLine)); assert_eq!(Ok(NumberLengthType::IsPossible), phone_util.is_possible_number_for_type_with_reason(&ar_number, PhoneNumberType::FixedLine));
assert_eq!(Err(ValidationResultErr::TooShort), phone_util.is_possible_number_for_type_with_reason(&ar_number, PhoneNumberType::Mobile)); assert_eq!(Err(ValidationError::TooShort), phone_util.is_possible_number_for_type_with_reason(&ar_number, PhoneNumberType::Mobile));
assert_eq!(Err(ValidationResultErr::TooShort), phone_util.is_possible_number_for_type_with_reason(&ar_number, PhoneNumberType::TollFree)); assert_eq!(Err(ValidationError::TooShort), phone_util.is_possible_number_for_type_with_reason(&ar_number, PhoneNumberType::TollFree));
ar_number.set_national_number(12345678901); ar_number.set_national_number(12345678901);
assert_eq!(Ok(ValidNumberLenType::IsPossible), phone_util.is_possible_number_for_type_with_reason(&ar_number, PhoneNumberType::Unknown)); assert_eq!(Ok(NumberLengthType::IsPossible), phone_util.is_possible_number_for_type_with_reason(&ar_number, PhoneNumberType::Unknown));
assert_eq!(Err(ValidationResultErr::TooLong), phone_util.is_possible_number_for_type_with_reason(&ar_number, PhoneNumberType::FixedLine)); assert_eq!(Err(ValidationError::TooLong), phone_util.is_possible_number_for_type_with_reason(&ar_number, PhoneNumberType::FixedLine));
assert_eq!(Ok(ValidNumberLenType::IsPossible), phone_util.is_possible_number_for_type_with_reason(&ar_number, PhoneNumberType::Mobile)); assert_eq!(Ok(NumberLengthType::IsPossible), phone_util.is_possible_number_for_type_with_reason(&ar_number, PhoneNumberType::Mobile));
assert_eq!(Err(ValidationResultErr::TooLong), phone_util.is_possible_number_for_type_with_reason(&ar_number, PhoneNumberType::TollFree)); assert_eq!(Err(ValidationError::TooLong), phone_util.is_possible_number_for_type_with_reason(&ar_number, PhoneNumberType::TollFree));
let mut de_number = PhoneNumber::new(); let mut de_number = PhoneNumber::new();
de_number.set_country_code(49); de_number.set_country_code(49);
de_number.set_national_number(12); de_number.set_national_number(12);
assert_eq!(Ok(ValidNumberLenType::IsPossibleLocalOnly), phone_util.is_possible_number_for_type_with_reason(&de_number, PhoneNumberType::Unknown)); assert_eq!(Ok(NumberLengthType::IsPossibleLocalOnly), phone_util.is_possible_number_for_type_with_reason(&de_number, PhoneNumberType::Unknown));
assert_eq!(Ok(ValidNumberLenType::IsPossibleLocalOnly), phone_util.is_possible_number_for_type_with_reason(&de_number, PhoneNumberType::FixedLine)); assert_eq!(Ok(NumberLengthType::IsPossibleLocalOnly), phone_util.is_possible_number_for_type_with_reason(&de_number, PhoneNumberType::FixedLine));
assert_eq!(Err(ValidationResultErr::TooShort), phone_util.is_possible_number_for_type_with_reason(&de_number, PhoneNumberType::Mobile)); assert_eq!(Err(ValidationError::TooShort), phone_util.is_possible_number_for_type_with_reason(&de_number, PhoneNumberType::Mobile));
let mut br_number = PhoneNumber::new(); let mut br_number = PhoneNumber::new();
br_number.set_country_code(55); br_number.set_country_code(55);
br_number.set_national_number(12345678); br_number.set_national_number(12345678);
assert_eq!(Err(ValidationResultErr::InvalidLength), phone_util.is_possible_number_for_type_with_reason(&br_number, PhoneNumberType::Mobile)); assert_eq!(Err(ValidationError::InvalidLength), phone_util.is_possible_number_for_type_with_reason(&br_number, PhoneNumberType::Mobile));
assert_eq!(Ok(ValidNumberLenType::IsPossibleLocalOnly), phone_util.is_possible_number_for_type_with_reason(&br_number, PhoneNumberType::FixedLineOrMobile)); assert_eq!(Ok(NumberLengthType::IsPossibleLocalOnly), phone_util.is_possible_number_for_type_with_reason(&br_number, PhoneNumberType::FixedLineOrMobile));
}
#[test]
fn is_possible_number_for_type_with_reason_different_type_lengths() {
// Мы используем аргентинские номера, так как у них разная возможная длина для разных типов.
let phone_util = get_phone_util();
let mut number = PhoneNumber::new();
number.set_country_code(54);
number.set_national_number(12345);
assert_eq!(Err(ValidationError::TooShort), phone_util.is_possible_number_for_type_with_reason(&number, PhoneNumberType::Unknown));
assert_eq!(Err(ValidationError::TooShort), phone_util.is_possible_number_for_type_with_reason(&number, PhoneNumberType::FixedLine));
// 6-значные номера подходят для стационарных телефонов.
number.set_national_number(123456);
assert_eq!(Ok(NumberLengthType::IsPossible), phone_util.is_possible_number_for_type_with_reason(&number, PhoneNumberType::Unknown));
assert_eq!(Ok(NumberLengthType::IsPossible), phone_util.is_possible_number_for_type_with_reason(&number, PhoneNumberType::FixedLine));
// Но слишком коротки для мобильных.
assert_eq!(Err(ValidationError::TooShort), phone_util.is_possible_number_for_type_with_reason(&number, PhoneNumberType::Mobile));
// И слишком коротки для бесплатных номеров.
assert_eq!(Err(ValidationError::TooShort), phone_util.is_possible_number_for_type_with_reason(&number, PhoneNumberType::TollFree));
// То же самое касается 9-значных номеров.
number.set_national_number(123456789);
assert_eq!(Ok(NumberLengthType::IsPossible), phone_util.is_possible_number_for_type_with_reason(&number, PhoneNumberType::Unknown));
assert_eq!(Ok(NumberLengthType::IsPossible), phone_util.is_possible_number_for_type_with_reason(&number, PhoneNumberType::FixedLine));
assert_eq!(Err(ValidationError::TooShort), phone_util.is_possible_number_for_type_with_reason(&number, PhoneNumberType::Mobile));
assert_eq!(Err(ValidationError::TooShort), phone_util.is_possible_number_for_type_with_reason(&number, PhoneNumberType::TollFree));
// 10-значные номера возможны для всех типов.
number.set_national_number(1234567890);
assert_eq!(Ok(NumberLengthType::IsPossible), phone_util.is_possible_number_for_type_with_reason(&number, PhoneNumberType::Unknown));
assert_eq!(Ok(NumberLengthType::IsPossible), phone_util.is_possible_number_for_type_with_reason(&number, PhoneNumberType::FixedLine));
assert_eq!(Ok(NumberLengthType::IsPossible), phone_util.is_possible_number_for_type_with_reason(&number, PhoneNumberType::Mobile));
assert_eq!(Ok(NumberLengthType::IsPossible), phone_util.is_possible_number_for_type_with_reason(&number, PhoneNumberType::TollFree));
// 11-значные номера возможны для мобильных номеров. Обратите внимание, что мы не требуем ведущую 9,
// с которой начинаются все мобильные номера и которая была бы необходима для действительного мобильного номера.
number.set_national_number(12345678901);
assert_eq!(Ok(NumberLengthType::IsPossible), phone_util.is_possible_number_for_type_with_reason(&number, PhoneNumberType::Unknown));
assert_eq!(Err(ValidationError::TooLong), phone_util.is_possible_number_for_type_with_reason(&number, PhoneNumberType::FixedLine));
assert_eq!(Ok(NumberLengthType::IsPossible), phone_util.is_possible_number_for_type_with_reason(&number, PhoneNumberType::Mobile));
assert_eq!(Err(ValidationError::TooLong), phone_util.is_possible_number_for_type_with_reason(&number, PhoneNumberType::TollFree));
}
#[test]
fn is_possible_number_for_type_with_reason_local_only() {
let phone_util = get_phone_util();
let mut number = PhoneNumber::new();
// Здесь мы тестируем длину номера, которая соответствует только местной длине.
number.set_country_code(49);
number.set_national_number(12);
assert_eq!(Ok(NumberLengthType::IsPossibleLocalOnly), phone_util.is_possible_number_for_type_with_reason(&number, PhoneNumberType::Unknown));
assert_eq!(Ok(NumberLengthType::IsPossibleLocalOnly), phone_util.is_possible_number_for_type_with_reason(&number, PhoneNumberType::FixedLine));
// Мобильные номера должны состоять из 10 или 11 цифр, и для них нет только местных длин.
assert_eq!(Err(ValidationError::TooShort), phone_util.is_possible_number_for_type_with_reason(&number, PhoneNumberType::Mobile));
}
#[test]
fn is_possible_number_for_type_with_reason_data_missing_for_size_reasons() {
let phone_util = get_phone_util();
let mut number = PhoneNumber::new();
// Здесь мы тестируем случай, когда возможные длины соответствуют возможным длинам страны в целом
// и поэтому отсутствуют в бинарных данных по соображениям размера - это все равно должно работать.
// Номер только для местного использования.
number.set_country_code(55);
number.set_national_number(12345678);
assert_eq!(Ok(NumberLengthType::IsPossibleLocalOnly), phone_util.is_possible_number_for_type_with_reason(&number, PhoneNumberType::Unknown));
assert_eq!(Ok(NumberLengthType::IsPossibleLocalOnly), phone_util.is_possible_number_for_type_with_reason(&number, PhoneNumberType::FixedLine));
// Номер нормальной длины.
number.set_national_number(1234567890);
assert_eq!(Ok(NumberLengthType::IsPossible), phone_util.is_possible_number_for_type_with_reason(&number, PhoneNumberType::Unknown));
assert_eq!(Ok(NumberLengthType::IsPossible), phone_util.is_possible_number_for_type_with_reason(&number, PhoneNumberType::FixedLine));
}
#[test]
fn is_possible_number_for_type_with_reason_number_type_not_supported_for_region() {
let phone_util = get_phone_util();
let mut number = PhoneNumber::new();
// В этом регионе вообще *нет* мобильных номеров, поэтому мы возвращаем INVALID_LENGTH.
number.set_country_code(55);
number.set_national_number(12345678);
assert_eq!(Err(ValidationError::InvalidLength), phone_util.is_possible_number_for_type_with_reason(&number, PhoneNumberType::Mobile));
// Однако это соответствует длине стационарного номера.
assert_eq!(Ok(NumberLengthType::IsPossibleLocalOnly), phone_util.is_possible_number_for_type_with_reason(&number, PhoneNumberType::FixedLineOrMobile));
// Этот номер слишком короткий для стационарного, а мобильных номеров не существует.
number.set_national_number(1234567);
assert_eq!(Err(ValidationError::InvalidLength), phone_util.is_possible_number_for_type_with_reason(&number, PhoneNumberType::Mobile));
assert_eq!(Err(ValidationError::TooShort), phone_util.is_possible_number_for_type_with_reason(&number, PhoneNumberType::FixedLineOrMobile));
assert_eq!(Err(ValidationError::TooShort), phone_util.is_possible_number_for_type_with_reason(&number, PhoneNumberType::FixedLine));
// Этот номер слишком короткий для мобильного, а стационарных номеров не существует.
number.set_country_code(882);
number.set_national_number(1234567);
assert_eq!(Err(ValidationError::TooShort), phone_util.is_possible_number_for_type_with_reason(&number, PhoneNumberType::Mobile));
assert_eq!(Err(ValidationError::TooShort), phone_util.is_possible_number_for_type_with_reason(&number, PhoneNumberType::FixedLineOrMobile));
assert_eq!(Err(ValidationError::InvalidLength), phone_util.is_possible_number_for_type_with_reason(&number, PhoneNumberType::FixedLine));
// Для этого кода страны вообще *нет* ни стационарных, ни мобильных номеров,
// поэтому мы возвращаем INVALID_LENGTH.
number.set_country_code(979);
number.set_national_number(123456789);
assert_eq!(Err(ValidationError::InvalidLength), phone_util.is_possible_number_for_type_with_reason(&number, PhoneNumberType::Mobile));
assert_eq!(Err(ValidationError::InvalidLength), phone_util.is_possible_number_for_type_with_reason(&number, PhoneNumberType::FixedLine));
assert_eq!(Err(ValidationError::InvalidLength), phone_util.is_possible_number_for_type_with_reason(&number, PhoneNumberType::FixedLineOrMobile));
assert_eq!(Ok(NumberLengthType::IsPossible), phone_util.is_possible_number_for_type_with_reason(&number, PhoneNumberType::PremiumRate));
}
#[test]
fn is_possible_number_for_type_with_reason_fixed_line_or_mobile() {
let phone_util = get_phone_util();
let mut number = PhoneNumber::new();
// Для FIXED_LINE_OR_MOBILE номер должен считаться действительным, если он соответствует
// возможным длинам для мобильных *или* стационарных номеров.
number.set_country_code(290);
number.set_national_number(1234);
assert_eq!(Err(ValidationError::TooShort), phone_util.is_possible_number_for_type_with_reason(&number, PhoneNumberType::FixedLine));
assert_eq!(Ok(NumberLengthType::IsPossible), phone_util.is_possible_number_for_type_with_reason(&number, PhoneNumberType::Mobile));
assert_eq!(Ok(NumberLengthType::IsPossible), phone_util.is_possible_number_for_type_with_reason(&number, PhoneNumberType::FixedLineOrMobile));
number.set_national_number(12345);
assert_eq!(Err(ValidationError::TooShort), phone_util.is_possible_number_for_type_with_reason(&number, PhoneNumberType::FixedLine));
assert_eq!(Err(ValidationError::TooLong), phone_util.is_possible_number_for_type_with_reason(&number, PhoneNumberType::Mobile));
assert_eq!(Err(ValidationError::InvalidLength), phone_util.is_possible_number_for_type_with_reason(&number, PhoneNumberType::FixedLineOrMobile));
number.set_national_number(123456);
assert_eq!(Ok(NumberLengthType::IsPossible), phone_util.is_possible_number_for_type_with_reason(&number, PhoneNumberType::FixedLine));
assert_eq!(Err(ValidationError::TooLong), phone_util.is_possible_number_for_type_with_reason(&number, PhoneNumberType::Mobile));
assert_eq!(Ok(NumberLengthType::IsPossible), phone_util.is_possible_number_for_type_with_reason(&number, PhoneNumberType::FixedLineOrMobile));
number.set_national_number(1234567);
assert_eq!(Err(ValidationError::TooLong), phone_util.is_possible_number_for_type_with_reason(&number, PhoneNumberType::FixedLine));
assert_eq!(Err(ValidationError::TooLong), phone_util.is_possible_number_for_type_with_reason(&number, PhoneNumberType::Mobile));
assert_eq!(Err(ValidationError::TooLong), phone_util.is_possible_number_for_type_with_reason(&number, PhoneNumberType::FixedLineOrMobile));
number.set_national_number(12345678);
assert_eq!(Ok(NumberLengthType::IsPossible), phone_util.is_possible_number_for_type_with_reason(&number, PhoneNumberType::TollFree));
assert_eq!(Err(ValidationError::TooLong), phone_util.is_possible_number_for_type_with_reason(&number, PhoneNumberType::FixedLineOrMobile));
} }
#[test] #[test]

View File

@@ -33,5 +33,7 @@ mod metadata;
mod test_metadata; mod test_metadata;
pub use metadata::METADATA; pub use metadata::METADATA;
// use only in test case
#[cfg(test)]
pub use test_metadata::TEST_METADATA; pub use test_metadata::TEST_METADATA;
" > "$generated_dir/mod.rs" " > "$generated_dir/mod.rs"