#[cfg(test)]
mod tests {
use crate::{
analyze_phone_numbers_batch, are_phone_numbers_equal, detect_phone_number_type,
detect_phone_number_types_batch, extract_countries_batch, extract_country,
format_phone_number, generate_random_phone_number, generate_random_phone_numbers,
group_equivalent_phone_numbers, guess_country_from_number, is_landline_number,
is_mobile_number, is_potentially_valid_phone_number, is_toll_free_number,
is_valid_phone_number, normalize_phone_number, normalize_phone_number_in_place,
normalize_phone_numbers_batch, suggest_phone_number_corrections,
validate_phone_numbers_batch, PhoneFormat, PhoneNumberType,
};
struct PhoneNumber {
country_code: &'static str,
phone_number: &'static str,
}
const PHONE_NUMBERS: [PhoneNumber; 212] = [
PhoneNumber {
country_code: "US",
phone_number: "+12025550173",
},
PhoneNumber {
country_code: "GB",
phone_number: "+442079460958",
},
PhoneNumber {
country_code: "IN",
phone_number: "+919876543210",
},
PhoneNumber {
country_code: "DE",
phone_number: "+493012345678",
},
PhoneNumber {
country_code: "AU",
phone_number: "+61412345678",
},
PhoneNumber {
country_code: "CN",
phone_number: "+8613800138000",
},
PhoneNumber {
country_code: "FR",
phone_number: "+33123456789",
},
PhoneNumber {
country_code: "BR",
phone_number: "+5511912345678",
},
PhoneNumber {
country_code: "JP",
phone_number: "+819012345678",
},
PhoneNumber {
country_code: "ZA",
phone_number: "+27821234567",
},
PhoneNumber {
country_code: "LB",
phone_number: "+96179123123",
},
PhoneNumber {
country_code: "SY",
phone_number: "+963944567890",
},
PhoneNumber {
country_code: "IQ",
phone_number: "+9647901234567",
},
PhoneNumber {
country_code: "KW",
phone_number: "+96550012345",
},
PhoneNumber {
country_code: "SA",
phone_number: "+966512345678",
},
PhoneNumber {
country_code: "YE",
phone_number: "+967711234567",
},
PhoneNumber {
country_code: "OM",
phone_number: "+96892123456",
},
PhoneNumber {
country_code: "PS",
phone_number: "+970599123456",
},
PhoneNumber {
country_code: "AE",
phone_number: "+971501234567",
},
PhoneNumber {
country_code: "IL",
phone_number: "+972501234567",
},
PhoneNumber {
country_code: "BH",
phone_number: "+97336012345",
},
PhoneNumber {
country_code: "QA",
phone_number: "+97433123456",
},
PhoneNumber {
country_code: "BT",
phone_number: "+97517123456",
},
PhoneNumber {
country_code: "MN",
phone_number: "+97699123456",
},
PhoneNumber {
country_code: "NP",
phone_number: "+9779841234567",
},
PhoneNumber {
country_code: "IR",
phone_number: "+989123456789",
},
PhoneNumber {
country_code: "TJ",
phone_number: "+992931234567",
},
PhoneNumber {
country_code: "TM",
phone_number: "+99365123456",
},
PhoneNumber {
country_code: "AZ",
phone_number: "+994401234567",
},
PhoneNumber {
country_code: "GE",
phone_number: "+995591234567",
},
PhoneNumber {
country_code: "KG",
phone_number: "+996551234567",
},
PhoneNumber {
country_code: "UZ",
phone_number: "+998971234567",
},
PhoneNumber {
country_code: "BS",
phone_number: "+12425571234",
},
PhoneNumber {
country_code: "BB",
phone_number: "+12462311234",
},
PhoneNumber {
country_code: "AI",
phone_number: "+12642351234",
},
PhoneNumber {
country_code: "AG",
phone_number: "+12684641234",
},
PhoneNumber {
country_code: "VG",
phone_number: "+12844681234",
},
PhoneNumber {
country_code: "VI",
phone_number: "+13406901234",
},
PhoneNumber {
country_code: "KY",
phone_number: "+13453211234",
},
PhoneNumber {
country_code: "BM",
phone_number: "+14412341234",
},
PhoneNumber {
country_code: "GD",
phone_number: "+14732341234",
},
PhoneNumber {
country_code: "TC",
phone_number: "+16492311234",
},
PhoneNumber {
country_code: "MS",
phone_number: "+16642351234",
},
PhoneNumber {
country_code: "MP",
phone_number: "+16702351234",
},
PhoneNumber {
country_code: "GU",
phone_number: "+16712351234",
},
PhoneNumber {
country_code: "AS",
phone_number: "+16842351234",
},
PhoneNumber {
country_code: "SX",
phone_number: "+17215431234",
},
PhoneNumber {
country_code: "LC",
phone_number: "+17582841234",
},
PhoneNumber {
country_code: "DM",
phone_number: "+17672351234",
},
PhoneNumber {
country_code: "VC",
phone_number: "+17842351234",
},
PhoneNumber {
country_code: "PR",
phone_number: "+17872351234",
},
PhoneNumber {
country_code: "DO",
phone_number: "+18092351234",
},
PhoneNumber {
country_code: "DO",
phone_number: "+18292351234",
},
PhoneNumber {
country_code: "DO",
phone_number: "+18492351234",
},
PhoneNumber {
country_code: "TT",
phone_number: "+18682351234",
},
PhoneNumber {
country_code: "KN",
phone_number: "+18692351234",
},
PhoneNumber {
country_code: "JM",
phone_number: "+18762351234",
},
PhoneNumber {
country_code: "RE",
phone_number: "+262692691234",
},
PhoneNumber {
country_code: "ZW",
phone_number: "+263772112345",
},
PhoneNumber {
country_code: "NA",
phone_number: "+264601234567",
},
PhoneNumber {
country_code: "MW",
phone_number: "+265991234567",
},
PhoneNumber {
country_code: "LS",
phone_number: "+26662012345",
},
PhoneNumber {
country_code: "BW",
phone_number: "+26771123456",
},
PhoneNumber {
country_code: "SZ",
phone_number: "+26876123456",
},
PhoneNumber {
country_code: "KM",
phone_number: "+2693112345",
},
PhoneNumber {
country_code: "SH",
phone_number: "+29022123",
},
PhoneNumber {
country_code: "ER",
phone_number: "+2917111234",
},
PhoneNumber {
country_code: "AW",
phone_number: "+2975601234",
},
PhoneNumber {
country_code: "FO",
phone_number: "+298201234",
},
PhoneNumber {
country_code: "GL",
phone_number: "+299201234",
},
PhoneNumber {
country_code: "GI",
phone_number: "+35056012345",
},
PhoneNumber {
country_code: "PT",
phone_number: "+351201234567",
},
PhoneNumber {
country_code: "LU",
phone_number: "+35220123456",
},
PhoneNumber {
country_code: "IE",
phone_number: "+353201234567",
},
PhoneNumber {
country_code: "IS",
phone_number: "+3544101234",
},
PhoneNumber {
country_code: "AL",
phone_number: "+355691234567",
},
PhoneNumber {
country_code: "MT",
phone_number: "+35679012345",
},
PhoneNumber {
country_code: "CY",
phone_number: "+35796123456",
},
PhoneNumber {
country_code: "FI",
phone_number: "+358201234567",
},
PhoneNumber {
country_code: "BG",
phone_number: "+35920123456",
},
PhoneNumber {
country_code: "LT",
phone_number: "+37061234567",
},
PhoneNumber {
country_code: "LV",
phone_number: "+37120123456",
},
PhoneNumber {
country_code: "EE",
phone_number: "+37251234567",
},
PhoneNumber {
country_code: "MD",
phone_number: "+37368123456",
},
PhoneNumber {
country_code: "AM",
phone_number: "+37491234567",
},
PhoneNumber {
country_code: "BY",
phone_number: "+375291234567",
},
PhoneNumber {
country_code: "AD",
phone_number: "+376312345",
},
PhoneNumber {
country_code: "MC",
phone_number: "+37761234567",
},
PhoneNumber {
country_code: "SM",
phone_number: "+378661234567",
},
PhoneNumber {
country_code: "VA",
phone_number: "+379612345678",
},
PhoneNumber {
country_code: "UA",
phone_number: "+380501234567",
},
PhoneNumber {
country_code: "RS",
phone_number: "+381601234567",
},
PhoneNumber {
country_code: "ME",
phone_number: "+38267123456",
},
PhoneNumber {
country_code: "HR",
phone_number: "+385911234567",
},
PhoneNumber {
country_code: "SI",
phone_number: "+38631234567",
},
PhoneNumber {
country_code: "BA",
phone_number: "+38761123456",
},
PhoneNumber {
country_code: "MK",
phone_number: "+38970123456",
},
PhoneNumber {
country_code: "CZ",
phone_number: "+420601123456",
},
PhoneNumber {
country_code: "SK",
phone_number: "+421912345678",
},
PhoneNumber {
country_code: "LI",
phone_number: "+4236608811",
},
PhoneNumber {
country_code: "FK",
phone_number: "+50051234",
},
PhoneNumber {
country_code: "BZ",
phone_number: "+5018221234",
},
PhoneNumber {
country_code: "GT",
phone_number: "+50251234567",
},
PhoneNumber {
country_code: "SV",
phone_number: "+50370123456",
},
PhoneNumber {
country_code: "HN",
phone_number: "+50491234567",
},
PhoneNumber {
country_code: "NI",
phone_number: "+50581234567",
},
PhoneNumber {
country_code: "CR",
phone_number: "+50670123456",
},
PhoneNumber {
country_code: "PA",
phone_number: "+50761234567",
},
PhoneNumber {
country_code: "PM",
phone_number: "+50850123456",
},
PhoneNumber {
country_code: "HT",
phone_number: "+50928123456",
},
PhoneNumber {
country_code: "GP",
phone_number: "+590590123456",
},
PhoneNumber {
country_code: "BO",
phone_number: "+59171234567",
},
PhoneNumber {
country_code: "GY",
phone_number: "+5926091234",
},
PhoneNumber {
country_code: "EC",
phone_number: "+593991234567",
},
PhoneNumber {
country_code: "GF",
phone_number: "+594694201234",
},
PhoneNumber {
country_code: "PY",
phone_number: "+595961456789",
},
PhoneNumber {
country_code: "MQ",
phone_number: "+596696201234",
},
PhoneNumber {
country_code: "SR",
phone_number: "+5977412345",
},
PhoneNumber {
country_code: "UY",
phone_number: "+59894231234",
},
PhoneNumber {
country_code: "CW",
phone_number: "+59995181234",
},
PhoneNumber {
country_code: "TL",
phone_number: "+67077231234",
},
PhoneNumber {
country_code: "NF",
phone_number: "+672312345",
},
PhoneNumber {
country_code: "BN",
phone_number: "+6737123456",
},
PhoneNumber {
country_code: "NR",
phone_number: "+6745571234",
},
PhoneNumber {
country_code: "PG",
phone_number: "+67570123456",
},
PhoneNumber {
country_code: "TO",
phone_number: "+67677151234",
},
PhoneNumber {
country_code: "SB",
phone_number: "+67762123",
},
PhoneNumber {
country_code: "VU",
phone_number: "+67824612",
},
PhoneNumber {
country_code: "FJ",
phone_number: "+6797012345",
},
PhoneNumber {
country_code: "PW",
phone_number: "+6806201234",
},
PhoneNumber {
country_code: "WF",
phone_number: "+681501234",
},
PhoneNumber {
country_code: "CK",
phone_number: "+68222123",
},
PhoneNumber {
country_code: "KI",
phone_number: "+68660123",
},
PhoneNumber {
country_code: "NC",
phone_number: "+687501234",
},
PhoneNumber {
country_code: "TV",
phone_number: "+688901234",
},
PhoneNumber {
country_code: "PF",
phone_number: "+68987123456",
},
PhoneNumber {
country_code: "TK",
phone_number: "+6903012",
},
PhoneNumber {
country_code: "FM",
phone_number: "+6913501234",
},
PhoneNumber {
country_code: "MH",
phone_number: "+6922471234",
},
PhoneNumber {
country_code: "KP",
phone_number: "+8501912345678",
},
PhoneNumber {
country_code: "HK",
phone_number: "+85251234567",
},
PhoneNumber {
country_code: "MO",
phone_number: "+85366123456",
},
PhoneNumber {
country_code: "KH",
phone_number: "+85512345678",
},
PhoneNumber {
country_code: "LA",
phone_number: "+85620911234",
},
PhoneNumber {
country_code: "BD",
phone_number: "+8801812345678",
},
PhoneNumber {
country_code: "TW",
phone_number: "+886912345678",
},
PhoneNumber {
country_code: "MV",
phone_number: "+9607712345",
},
PhoneNumber {
country_code: "JO",
phone_number: "+962791234567",
},
PhoneNumber {
country_code: "SG",
phone_number: "+6581234567",
}, PhoneNumber {
country_code: "MY",
phone_number: "+60121234567",
}, PhoneNumber {
country_code: "PH",
phone_number: "+639171234567",
}, PhoneNumber {
country_code: "TH",
phone_number: "+66812345678",
}, PhoneNumber {
country_code: "VN",
phone_number: "+84912345678",
}, PhoneNumber {
country_code: "PK",
phone_number: "+923001234567",
}, PhoneNumber {
country_code: "LK",
phone_number: "+94771234567",
}, PhoneNumber {
country_code: "AF",
phone_number: "+93700123456",
}, PhoneNumber {
country_code: "MM",
phone_number: "+959123456789",
}, PhoneNumber {
country_code: "KZ",
phone_number: "+77012345678",
}, PhoneNumber {
country_code: "UZ",
phone_number: "+998901234567",
}, PhoneNumber {
country_code: "TJ",
phone_number: "+992551234567",
}, PhoneNumber {
country_code: "KG",
phone_number: "+996701234567",
}, PhoneNumber {
country_code: "TM",
phone_number: "+993651234567",
}, PhoneNumber {
country_code: "MN",
phone_number: "+97688123456",
}, PhoneNumber {
country_code: "NP",
phone_number: "+9779812345678",
}, PhoneNumber {
country_code: "BT",
phone_number: "+97517123456",
}, PhoneNumber {
country_code: "AM",
phone_number: "+37494123456",
}, PhoneNumber {
country_code: "AZ",
phone_number: "+994501234567",
}, PhoneNumber {
country_code: "GE",
phone_number: "+995555123456",
}, PhoneNumber {
country_code: "TM",
phone_number: "+99312123456",
}, PhoneNumber {
country_code: "AE",
phone_number: "+971501234567",
}, PhoneNumber {
country_code: "BH",
phone_number: "+97333123456",
}, PhoneNumber {
country_code: "QA",
phone_number: "+97450123456",
}, PhoneNumber {
country_code: "KW",
phone_number: "+96550123456",
}, PhoneNumber {
country_code: "OM",
phone_number: "+96892123456",
}, PhoneNumber {
country_code: "YE",
phone_number: "+967711234567",
}, PhoneNumber {
country_code: "SO",
phone_number: "+252615123456",
}, PhoneNumber {
country_code: "KE",
phone_number: "+254701234567",
}, PhoneNumber {
country_code: "TZ",
phone_number: "+255621234567",
}, PhoneNumber {
country_code: "UG",
phone_number: "+256701234567",
}, PhoneNumber {
country_code: "ET",
phone_number: "+251911234567",
}, PhoneNumber {
country_code: "NG",
phone_number: "+234701234567",
}, PhoneNumber {
country_code: "GH",
phone_number: "+233501234567",
}, PhoneNumber {
country_code: "SN",
phone_number: "+221771234567",
}, PhoneNumber {
country_code: "CI",
phone_number: "+22551234567",
}, PhoneNumber {
country_code: "ML",
phone_number: "+22365123456",
}, PhoneNumber {
country_code: "ZM",
phone_number: "+260961234567",
}, PhoneNumber {
country_code: "ZW",
phone_number: "+263771234567",
}, PhoneNumber {
country_code: "BW",
phone_number: "+26772123456",
}, PhoneNumber {
country_code: "NA",
phone_number: "+264811234567",
}, PhoneNumber {
country_code: "MG",
phone_number: "+261341234567",
}, PhoneNumber {
country_code: "RE",
phone_number: "+262692123456",
}, PhoneNumber {
country_code: "MU",
phone_number: "+23057123456",
}, PhoneNumber {
country_code: "SC",
phone_number: "+2482512345",
}, PhoneNumber {
country_code: "MW",
phone_number: "+265991234567",
}, PhoneNumber {
country_code: "LS",
phone_number: "+26650123456",
}, PhoneNumber {
country_code: "SZ",
phone_number: "+26876123456",
}, PhoneNumber {
country_code: "CV",
phone_number: "+2389912345",
}, PhoneNumber {
country_code: "ST",
phone_number: "+2399912345",
}, PhoneNumber {
country_code: "GQ",
phone_number: "+240222123456",
}, PhoneNumber {
country_code: "CD",
phone_number: "+243991234567",
}, PhoneNumber {
country_code: "AO",
phone_number: "+244921234567",
}, PhoneNumber {
country_code: "GW",
phone_number: "+245501234511",
}, PhoneNumber {
country_code: "IO",
phone_number: "+2463801234",
}, PhoneNumber {
country_code: "AC",
phone_number: "+2473612",
}, PhoneNumber {
country_code: "SC",
phone_number: "+2482512345",
}, PhoneNumber {
country_code: "SD",
phone_number: "+249911231234",
}, PhoneNumber {
country_code: "RW",
phone_number: "+250720123456",
}, PhoneNumber {
country_code: "SO",
phone_number: "+252615123456",
}, PhoneNumber {
country_code: "DJ",
phone_number: "+25377123123",
}, PhoneNumber {
country_code: "BI",
phone_number: "+25779123456",
}, PhoneNumber {
country_code: "MZ",
phone_number: "+258821234567",
}, PhoneNumber {
country_code: "GB-CYM",
phone_number: "+442079460958",
}, ];
#[test]
fn test_is_valid_phone_number() {
assert!(is_valid_phone_number("+96179123123"));
assert!(is_valid_phone_number("12025550173"));
assert!(is_valid_phone_number("+1.202.555.0173"));
assert!(is_valid_phone_number("+1 (202) 555-0173 ext. 99"));
assert!(is_valid_phone_number("1-800-FLOWERS"));
assert!(!is_valid_phone_number("invalid_phone_number"));
assert!(is_valid_phone_number("+1 (234) 567-8990"));
assert!(!is_valid_phone_number("+1 (234) 567-890"));
assert!(!is_valid_phone_number("1+2025550173"));
assert!(!is_valid_phone_number("+1 (234 567-8990"));
}
#[test]
fn test_normalize_phone_number_in_place() {
assert_eq!(
normalize_phone_number_in_place(&mut "+12345678912".to_string()),
Some("+12345678912".to_string())
);
assert_eq!(
normalize_phone_number_in_place(&mut "invalid_phone_number".to_string()),
None
);
assert_eq!(
normalize_phone_number_in_place(&mut "+0012345678912".to_string()),
Some("+12345678912".to_string())
);
assert_eq!(
normalize_phone_number_in_place(&mut "+96109123123".to_string()),
Some("+9619123123".to_string())
);
assert_eq!(
normalize_phone_number_in_place(&mut "+0012345678901".to_string()),
Some("+12345678901".to_string())
);
assert_eq!(
normalize_phone_number_in_place(&mut "+1 (234) 567-8910".to_string()),
Some("+12345678910".to_string())
);
assert_eq!(
normalize_phone_number_in_place(&mut "+1 (202) 555-0173 ext. 99".to_string()),
Some("+12025550173".to_string())
);
assert_eq!(
normalize_phone_number_in_place(&mut "1-800-FLOWERS".to_string()),
Some("+18003569377".to_string())
);
}
#[test]
fn test_extract_country() {
assert_eq!(
extract_country("+11231231232")
.unwrap()
.code
.to_string(),
"US".to_string()
);
assert_eq!(extract_country("+987654321"), None);
assert_eq!(extract_country("1-800-FLOWERS").map(|country| country.code), Some("US"));
}
#[test]
fn test_normalize_phone_number() {
for phone_number in PHONE_NUMBERS.iter() {
let normalized_phone_number =
normalize_phone_number(phone_number.phone_number);
assert_eq!(
normalized_phone_number,
Some(phone_number.phone_number.to_string())
);
assert!(!phone_number.country_code.is_empty());
}
assert_eq!(
normalize_phone_number("invalid_phone_number"),
None
);
assert_eq!(
normalize_phone_number("+1 (202) 555-0173 ext. 99"),
Some("+12025550173".to_string())
);
assert_eq!(
normalize_phone_number("1-800-FLOWERS"),
Some("+18003569377".to_string())
);
}
#[test]
fn test_cases() {
let test_cases = vec![
("+61485906541", true),
("+4306935893571", true),
("+32468799972", true),
("+5561981737725", true),
("+44 7406514755", true),
("+54 9119298464", true),
("+61 4129228042", true),
("+43 6642428349", true),
("+32 4706460538", true),
("+420 601139706", true),
];
for (phone, valid) in test_cases {
let is_valid = is_valid_phone_number(phone);
assert_eq!(is_valid, valid);
}
}
#[test]
fn test_phone_number_formatting() {
let number = "+12345678901";
let e164 = format_phone_number(number, PhoneFormat::E164);
assert_eq!(e164, Some("+12345678901".to_string()));
let intl = format_phone_number(number, PhoneFormat::International);
assert!(intl.is_some());
let national = format_phone_number(number, PhoneFormat::National);
assert!(national.is_some());
let rfc = format_phone_number(number, PhoneFormat::RFC3966);
assert!(rfc.is_some());
}
#[test]
fn test_phone_number_formatting_major_country_national_patterns() {
assert_eq!(
format_phone_number("+493012345678", PhoneFormat::National),
Some("30 1234 5678".to_string())
);
assert_eq!(
format_phone_number("+33123456789", PhoneFormat::National),
Some("1 23 45 67 89".to_string())
);
assert_eq!(
format_phone_number("+919876543210", PhoneFormat::National),
Some("98765 43210".to_string())
);
assert_eq!(
format_phone_number("+61412345678", PhoneFormat::National),
Some("4 1234 5678".to_string())
);
}
#[test]
fn test_phone_number_type_detection() {
let toll_free = is_toll_free_number("18001234567");
assert!(toll_free || !is_valid_phone_number("18001234567"));
let mobile_result = is_mobile_number("447123456789");
assert!(mobile_result || !is_valid_phone_number("447123456789"));
let landline_result = is_landline_number("12025551234");
assert!(landline_result || !is_valid_phone_number("12025551234"));
}
#[test]
fn test_random_phone_number_generation() {
let random_us = generate_random_phone_number("US");
if let Some(ref number) = random_us {
assert!(is_valid_phone_number(number));
}
let random_gb = generate_random_phone_number("GB");
if let Some(ref number) = random_gb {
assert!(is_valid_phone_number(number));
}
let invalid = generate_random_phone_number("XX");
assert!(invalid.is_none());
}
#[test]
fn test_phone_number_equality() {
let num1 = "+12345678901";
let num2 = "12345678901";
let num3 = "+12345678902";
assert!(are_phone_numbers_equal(num1, num2));
assert!(!are_phone_numbers_equal(num1, num3));
}
#[test]
fn test_batch_processing() {
let numbers = [
"+12345678901",
"invalid",
"+442079460958",
];
let results = validate_phone_numbers_batch(&numbers);
assert_eq!(results.len(), 3);
assert!(results[0]);
assert!(!results[1]);
assert!(results[2]);
}
#[test]
fn test_phone_number_suggestions() {
let suggestions = suggest_phone_number_corrections("123456789", Some("US"));
assert!(!suggestions.is_empty());
let potentially_valid = is_potentially_valid_phone_number("123-456-7890");
assert!(potentially_valid);
let not_valid = is_potentially_valid_phone_number("123");
assert!(!not_valid);
}
#[test]
fn test_type_detection_specific_cases() {
let phone_type = detect_phone_number_type("447123456789");
assert!(phone_type.is_some() || !is_valid_phone_number("447123456789"));
if let Some(ptype) = phone_type {
assert!(ptype == PhoneNumberType::Mobile || ptype == PhoneNumberType::Unknown);
}
}
#[test]
fn test_extract_phone_numbers_from_text() {
use crate::extract_phone_numbers_from_text;
let text = "Call me at +12025550173 or +442079460958 for support.";
let numbers = extract_phone_numbers_from_text(text);
assert_eq!(numbers.len(), 2);
assert!(numbers[0].raw.contains("12025550173"));
assert!(numbers[1].raw.contains("442079460958"));
}
#[test]
fn test_extract_phone_with_various_formats() {
use crate::extract_phone_numbers_from_text;
let text = "Numbers: (202) 555-0173, 202.555.0174, 202-555-0175";
let numbers = extract_phone_numbers_from_text(text);
assert!(!numbers.is_empty());
}
#[test]
fn test_extract_valid_phone_numbers_only() {
use crate::extract_valid_phone_numbers_from_text;
let text = "Valid: +12025550173, Invalid: 123";
let numbers = extract_valid_phone_numbers_from_text(text);
for num in &numbers {
assert!(num.is_valid);
}
}
#[test]
fn test_extract_with_country_hint() {
use crate::extract_phone_numbers_with_country_hint;
let text = "Call (202) 555-0173";
let numbers = extract_phone_numbers_with_country_hint(text, "US");
assert!(!numbers.is_empty());
}
#[test]
fn test_extract_french_national_format_with_leading_zero() {
use crate::extract_phone_numbers_with_country_hint;
let numbers = extract_phone_numbers_with_country_hint("0645342545", "FR");
assert_eq!(numbers.len(), 1);
assert!(numbers[0].is_valid);
assert_eq!(numbers[0].normalized, Some("+33645342545".to_string()));
let numbers_no_zero = extract_phone_numbers_with_country_hint("645342545", "FR");
assert_eq!(numbers_no_zero.len(), 1);
assert!(numbers_no_zero[0].is_valid);
assert_eq!(numbers_no_zero[0].normalized, Some("+33645342545".to_string()));
let uk_numbers = extract_phone_numbers_with_country_hint("07911123456", "GB");
assert_eq!(uk_numbers.len(), 1);
assert!(uk_numbers[0].is_valid);
assert_eq!(uk_numbers[0].normalized, Some("+447911123456".to_string()));
}
#[test]
fn test_country_hint_priority_over_ambiguous_normalization() {
use crate::extract_phone_numbers_with_country_hint;
let result = extract_phone_numbers_with_country_hint("0612345678", "FR");
assert_eq!(result.len(), 1);
assert!(result[0].is_valid);
assert_eq!(result[0].normalized, Some("+33612345678".to_string()));
}
#[test]
fn test_extract_with_country_hint_german_numbers() {
use crate::extract_phone_numbers_with_country_hint;
let numbers = extract_phone_numbers_with_country_hint("030 12345678", "DE");
assert_eq!(numbers.len(), 1);
assert!(numbers[0].is_valid);
assert_eq!(numbers[0].normalized, Some("+493012345678".to_string()));
let mobile = extract_phone_numbers_with_country_hint("0151 12345678", "DE");
assert_eq!(mobile.len(), 1);
assert!(mobile[0].is_valid);
assert_eq!(mobile[0].normalized, Some("+4915112345678".to_string()));
}
#[test]
fn test_extract_with_country_hint_already_international() {
use crate::extract_phone_numbers_with_country_hint;
let numbers = extract_phone_numbers_with_country_hint("+33645342545", "FR");
assert_eq!(numbers.len(), 1);
assert!(numbers[0].is_valid);
assert_eq!(numbers[0].normalized, Some("+33645342545".to_string()));
let us_in_fr = extract_phone_numbers_with_country_hint("+12025550173", "FR");
assert_eq!(us_in_fr.len(), 1);
assert!(us_in_fr[0].is_valid);
assert_eq!(us_in_fr[0].normalized, Some("+12025550173".to_string()));
}
#[test]
fn test_extract_with_country_hint_multiple_numbers() {
use crate::extract_phone_numbers_with_country_hint;
let text = "Call 0645342545 or 0712345678 for support";
let numbers = extract_phone_numbers_with_country_hint(text, "FR");
assert_eq!(numbers.len(), 2);
assert!(numbers[0].is_valid);
assert!(numbers[1].is_valid);
assert_eq!(numbers[0].normalized, Some("+33645342545".to_string()));
assert_eq!(numbers[1].normalized, Some("+33712345678".to_string()));
}
#[test]
fn test_extract_with_country_hint_mixed_formats() {
use crate::extract_phone_numbers_with_country_hint;
let text = "Numbers: 06 45 34 25 45, +33 6 12 34 56 78";
let numbers = extract_phone_numbers_with_country_hint(text, "FR");
assert_eq!(numbers.len(), 2);
for num in &numbers {
assert!(num.is_valid);
assert!(num.normalized.as_ref().unwrap().starts_with("+33"));
}
}
#[test]
fn test_extract_with_country_hint_us_formats() {
use crate::extract_phone_numbers_with_country_hint;
let formats = [
("(202) 555-0173", "+12025550173"),
("202-555-0173", "+12025550173"),
("202.555.0173", "+12025550173"),
("2025550173", "+12025550173"),
];
for (input, expected) in formats {
let numbers = extract_phone_numbers_with_country_hint(input, "US");
assert_eq!(numbers.len(), 1, "Failed for input: {}", input);
assert!(numbers[0].is_valid, "Invalid for input: {}", input);
assert_eq!(numbers[0].normalized, Some(expected.to_string()), "Wrong normalization for: {}", input);
}
}
#[test]
fn test_extract_with_country_hint_invalid_country_code() {
use crate::extract_phone_numbers_with_country_hint;
let numbers = extract_phone_numbers_with_country_hint("+12025550173", "XX");
assert_eq!(numbers.len(), 1);
assert!(numbers[0].is_valid);
assert_eq!(numbers[0].normalized, Some("+12025550173".to_string()));
let national = extract_phone_numbers_with_country_hint("0645342545", "XX");
assert_eq!(national.len(), 1);
assert!(!national[0].is_valid);
}
#[test]
fn test_extract_with_country_hint_australian_numbers() {
use crate::extract_phone_numbers_with_country_hint;
let numbers = extract_phone_numbers_with_country_hint("0412345678", "AU");
assert_eq!(numbers.len(), 1);
assert!(numbers[0].is_valid);
assert_eq!(numbers[0].normalized, Some("+61412345678".to_string()));
}
#[test]
fn test_extract_with_country_hint_preserves_raw() {
use crate::extract_phone_numbers_with_country_hint;
let text = "Call (06) 45-34-25-45";
let numbers = extract_phone_numbers_with_country_hint(text, "FR");
assert_eq!(numbers.len(), 1);
assert!(numbers[0].raw.contains("06"));
assert_eq!(numbers[0].normalized, Some("+33645342545".to_string()));
}
#[test]
fn test_extract_with_country_hint_positions() {
use crate::extract_phone_numbers_with_country_hint;
let text = "Phone: 0645342545";
let numbers = extract_phone_numbers_with_country_hint(text, "FR");
assert_eq!(numbers.len(), 1);
assert!(numbers[0].start > 0); assert!(numbers[0].end > numbers[0].start);
assert!(numbers[0].end <= text.len());
let extracted = &text[numbers[0].start..numbers[0].end];
assert!(extracted.contains("0645342545") || extracted == "0645342545");
}
#[test]
fn test_extract_with_country_hint_empty_text() {
use crate::extract_phone_numbers_with_country_hint;
let numbers = extract_phone_numbers_with_country_hint("", "FR");
assert!(numbers.is_empty());
}
#[test]
fn test_extract_with_country_hint_no_numbers() {
use crate::extract_phone_numbers_with_country_hint;
let text = "No phone numbers here, just text!";
let numbers = extract_phone_numbers_with_country_hint(text, "FR");
assert!(numbers.is_empty());
}
#[test]
fn test_extract_with_country_hint_short_numbers_ignored() {
use crate::extract_phone_numbers_with_country_hint;
let text = "Code: 12345, PIN: 9999";
let numbers = extract_phone_numbers_with_country_hint(text, "US");
assert!(numbers.is_empty());
}
#[test]
fn test_count_phone_numbers() {
use crate::count_phone_numbers_in_text;
let text = "Contact: +12025550173, +442079460958";
let count = count_phone_numbers_in_text(text);
assert_eq!(count, 2);
}
#[test]
fn test_replace_phone_numbers() {
use crate::replace_phone_numbers_in_text;
let text = "Call +12025550173 today!";
let replaced = replace_phone_numbers_in_text(text, |_| "[PHONE]".to_string());
assert!(replaced.contains("[PHONE]"));
assert!(!replaced.contains("12025550173"));
}
#[test]
fn test_redact_phone_numbers() {
use crate::redact_phone_numbers;
let text = "Call +12025550173";
let redacted = redact_phone_numbers(text, 4);
assert!(redacted.contains("*") || redacted.contains("[PHONE]"));
}
#[test]
fn test_extract_positions() {
use crate::extract_phone_numbers_from_text;
let text = "Phone: +12025550173";
let numbers = extract_phone_numbers_from_text(text);
if !numbers.is_empty() {
let num = &numbers[0];
assert!(num.start < num.end);
assert!(num.end <= text.len());
}
}
#[test]
fn test_phone_number_struct_parse() {
use crate::PhoneNumber as PhoneNum;
let phone = PhoneNum::parse("+12025550173");
assert!(phone.is_some());
let phone = phone.unwrap();
assert_eq!(phone.e164(), "+12025550173");
}
#[test]
fn test_phone_number_equality_trait() {
use crate::PhoneNumber as PhoneNum;
let num1 = PhoneNum::parse("+12025550173").unwrap();
let num2 = PhoneNum::parse("12025550173").unwrap();
let num3 = PhoneNum::parse("+442079460958").unwrap();
assert_eq!(num1, num2);
assert_ne!(num1, num3);
}
#[test]
fn test_phone_number_hash() {
use crate::PhoneNumber as PhoneNum;
use std::collections::HashSet;
let mut set = HashSet::new();
let num1 = PhoneNum::parse("+12025550173").unwrap();
let num2 = PhoneNum::parse("12025550173").unwrap();
set.insert(num1);
set.insert(num2);
assert_eq!(set.len(), 1);
}
#[test]
fn test_phone_number_with_country_hint() {
use crate::PhoneNumber as PhoneNum;
let phone = PhoneNum::parse_with_country("2025550173", "US");
if let Some(p) = phone {
assert!(p.e164().starts_with("+1"));
}
}
#[test]
fn test_phone_number_national_number() {
use crate::PhoneNumber as PhoneNum;
let phone = PhoneNum::parse("+12025550173").unwrap();
let national = phone.national_number();
assert!(!national.starts_with("+"));
assert!(!national.starts_with("1") || national.len() < 11);
}
#[test]
fn test_phone_number_format_method() {
use crate::PhoneFormat;
use crate::PhoneNumber as PhoneNum;
let phone = PhoneNum::parse("+12025550173").unwrap();
let e164 = phone.format(PhoneFormat::E164);
assert!(e164.starts_with("+"));
}
#[test]
fn test_phone_number_display() {
use crate::PhoneNumber as PhoneNum;
let phone = PhoneNum::parse("+12025550173").unwrap();
let display = format!("{}", phone);
assert_eq!(display, "+12025550173");
}
#[test]
fn test_phone_number_from_str() {
use crate::PhoneNumber as PhoneNum;
let phone: Result<PhoneNum, _> = "+12025550173".parse();
assert!(phone.is_ok());
let invalid: Result<PhoneNum, _> = "invalid".parse();
assert!(invalid.is_err());
}
#[test]
fn test_phone_number_set_basic() {
use crate::PhoneNumberSet;
let mut set = PhoneNumberSet::new();
assert!(set.add("+12025550173"));
assert!(!set.add("12025550173"));
assert_eq!(set.len(), 1);
}
#[test]
fn test_phone_number_set_contains() {
use crate::PhoneNumberSet;
let mut set = PhoneNumberSet::new();
set.add("+12025550173");
assert!(set.contains("+12025550173"));
assert!(set.contains("12025550173")); assert!(!set.contains("+442079460958"));
}
#[test]
fn test_phone_number_set_remove() {
use crate::PhoneNumberSet;
let mut set = PhoneNumberSet::new();
set.add("+12025550173");
assert!(set.remove("12025550173")); assert!(set.is_empty());
}
#[test]
fn test_phone_number_set_from_iterator() {
use crate::PhoneNumberSet;
let numbers = vec!["+12025550173", "12025550173", "+442079460958"];
let set: PhoneNumberSet = numbers.into_iter().collect();
assert_eq!(set.len(), 2); }
#[test]
fn test_phone_number_set_iter() {
use crate::PhoneNumberSet;
let mut set = PhoneNumberSet::new();
set.add("+12025550173");
set.add("+442079460958");
let count = set.iter().count();
assert_eq!(count, 2);
}
#[test]
fn test_phone_number_type_checks() {
use crate::PhoneNumber as PhoneNum;
let phone = PhoneNum::parse("+18005551234"); if let Some(p) = phone {
let _ = p.is_mobile();
let _ = p.is_landline();
let _ = p.is_toll_free();
}
}
#[test]
fn test_guess_country_from_number_us() {
let country = guess_country_from_number("2025550173");
assert!(country.is_some());
assert_eq!(country.unwrap().code, "US");
}
#[test]
fn test_guess_country_from_number_with_country_code() {
let country = guess_country_from_number("12025550173");
assert!(country.is_some());
assert_eq!(country.unwrap().code, "US");
let country_gb = guess_country_from_number("442079460958");
assert!(country_gb.is_some());
let gb_code = country_gb.unwrap().code;
assert!(gb_code == "GB" || gb_code == "GB-CYM");
}
#[test]
fn test_guess_country_from_number_invalid() {
let country = guess_country_from_number("");
assert!(country.is_none());
let country_short = guess_country_from_number("123");
assert!(country_short.is_none());
}
#[test]
fn test_guess_country_from_number_various_countries() {
let de = guess_country_from_number("493012345678");
assert!(de.is_some());
let fr = guess_country_from_number("33123456789");
assert!(fr.is_some());
}
#[test]
fn test_extract_countries_batch_basic() {
let numbers = ["+12025550173", "+442079460958", "+493012345678"];
let countries = extract_countries_batch(&numbers);
assert_eq!(countries.len(), 3);
assert!(countries[0].is_some());
assert_eq!(countries[0].unwrap().code, "US");
assert!(countries[1].is_some());
let gb_code = countries[1].unwrap().code;
assert!(gb_code == "GB" || gb_code == "GB-CYM");
assert!(countries[2].is_some());
assert_eq!(countries[2].unwrap().code, "DE");
}
#[test]
fn test_extract_countries_batch_with_invalid() {
let numbers = ["+12025550173", "invalid", "+442079460958"];
let countries = extract_countries_batch(&numbers);
assert_eq!(countries.len(), 3);
assert!(countries[0].is_some());
assert!(countries[1].is_none());
assert!(countries[2].is_some());
}
#[test]
fn test_extract_countries_batch_empty() {
let numbers: [&str; 0] = [];
let countries = extract_countries_batch(&numbers);
assert!(countries.is_empty());
}
#[test]
fn test_extract_countries_batch_with_vec() {
let numbers = vec!["+12025550173".to_string(), "+442079460958".to_string()];
let countries = extract_countries_batch(&numbers);
assert_eq!(countries.len(), 2);
assert!(countries.iter().all(|c| c.is_some()));
}
#[test]
fn test_normalize_phone_numbers_batch_basic() {
let numbers = ["12025550173", "+442079460958", "invalid"];
let normalized = normalize_phone_numbers_batch(&numbers);
assert_eq!(normalized.len(), 3);
assert_eq!(normalized[0], Some("+12025550173".to_string()));
assert_eq!(normalized[1], Some("+442079460958".to_string()));
assert!(normalized[2].is_none());
}
#[test]
fn test_normalize_phone_numbers_batch_various_formats() {
let numbers = [
"+1 (202) 555-0173",
"1-202-555-0174",
"(202) 555-0175",
];
let normalized = normalize_phone_numbers_batch(&numbers);
assert_eq!(normalized.len(), 3);
for norm in &normalized {
if let Some(n) = norm {
assert!(n.starts_with("+"));
}
}
}
#[test]
fn test_normalize_phone_numbers_batch_empty() {
let numbers: [&str; 0] = [];
let normalized = normalize_phone_numbers_batch(&numbers);
assert!(normalized.is_empty());
}
#[test]
fn test_normalize_phone_numbers_batch_with_string_vec() {
let numbers = vec!["12025550173".to_string(), "442079460958".to_string()];
let normalized = normalize_phone_numbers_batch(&numbers);
assert_eq!(normalized.len(), 2);
assert!(normalized[0].is_some());
assert!(normalized[1].is_some());
}
#[test]
fn test_detect_phone_number_types_batch_basic() {
let numbers = ["+12025550173", "+442079460958", "+18001234567"];
let types = detect_phone_number_types_batch(&numbers);
assert_eq!(types.len(), 3);
for phone_type in &types {
assert!(phone_type.is_some());
}
}
#[test]
fn test_detect_phone_number_types_batch_toll_free() {
let numbers = ["+18001234567", "+18881234567", "+18771234567"];
let types = detect_phone_number_types_batch(&numbers);
for phone_type in &types {
if let Some(t) = phone_type {
assert_eq!(*t, PhoneNumberType::TollFree);
}
}
}
#[test]
fn test_detect_phone_number_types_batch_with_invalid() {
let numbers = ["+12025550173", "invalid", "+442079460958"];
let types = detect_phone_number_types_batch(&numbers);
assert_eq!(types.len(), 3);
assert!(types[0].is_some());
assert!(types[1].is_none());
assert!(types[2].is_some());
}
#[test]
fn test_detect_phone_number_types_batch_uk_mobile() {
let numbers = ["+447123456789", "+447987654321"];
let types = detect_phone_number_types_batch(&numbers);
for phone_type in &types {
if let Some(t) = phone_type {
assert_eq!(*t, PhoneNumberType::Mobile);
}
}
}
#[test]
fn test_analyze_phone_numbers_batch_basic() {
let numbers = ["+12025550173", "+442079460958"];
let analyses = analyze_phone_numbers_batch(&numbers);
assert_eq!(analyses.len(), 2);
for analysis in &analyses {
assert!(analysis.is_valid);
assert!(analysis.normalized.is_some());
assert!(analysis.country.is_some());
assert!(analysis.phone_type.is_some());
}
}
#[test]
fn test_analyze_phone_numbers_batch_mixed() {
let numbers = ["+12025550173", "invalid", "+442079460958"];
let analyses = analyze_phone_numbers_batch(&numbers);
assert_eq!(analyses.len(), 3);
assert!(analyses[0].is_valid);
assert_eq!(analyses[0].original, "+12025550173");
assert!(!analyses[1].is_valid);
assert!(analyses[1].normalized.is_none());
assert!(analyses[2].is_valid);
}
#[test]
fn test_analyze_phone_numbers_batch_original_preserved() {
let numbers = ["+1 (202) 555-0173", "1-202-555-0174"];
let analyses = analyze_phone_numbers_batch(&numbers);
assert_eq!(analyses[0].original, "+1 (202) 555-0173");
assert_eq!(analyses[1].original, "1-202-555-0174");
}
#[test]
fn test_analyze_phone_numbers_batch_empty() {
let numbers: [&str; 0] = [];
let analyses = analyze_phone_numbers_batch(&numbers);
assert!(analyses.is_empty());
}
#[test]
fn test_group_equivalent_phone_numbers_basic() {
let numbers = ["+12025550173", "12025550173", "+442079460958"];
let groups = group_equivalent_phone_numbers(&numbers);
assert_eq!(groups.len(), 2);
}
#[test]
fn test_group_equivalent_phone_numbers_all_same() {
let numbers = [
"+12025550173",
"12025550173",
"+1 (202) 555-0173",
"1-202-555-0173",
];
let groups = group_equivalent_phone_numbers(&numbers);
assert_eq!(groups.len(), 1);
assert_eq!(groups[0].len(), 4);
}
#[test]
fn test_group_equivalent_phone_numbers_all_different() {
let numbers = ["+12025550173", "+12025550174", "+12025550175"];
let groups = group_equivalent_phone_numbers(&numbers);
assert_eq!(groups.len(), 3);
}
#[test]
fn test_group_equivalent_phone_numbers_empty() {
let numbers: [&str; 0] = [];
let groups = group_equivalent_phone_numbers(&numbers);
assert!(groups.is_empty());
}
#[test]
fn test_group_equivalent_phone_numbers_with_invalid() {
let numbers = ["+12025550173", "invalid", "+12025550173"];
let groups = group_equivalent_phone_numbers(&numbers);
assert!(groups.len() >= 1);
}
#[test]
fn test_generate_random_phone_numbers_basic() {
let numbers = generate_random_phone_numbers("US", 5);
assert_eq!(numbers.len(), 5);
}
#[test]
fn test_generate_random_phone_numbers_do_not_repeat_same_value() {
let numbers = generate_random_phone_numbers("US", 8);
let unique_numbers: std::collections::HashSet<_> = numbers.iter().collect();
assert_eq!(numbers.len(), 8);
assert!(unique_numbers.len() > 1);
}
#[test]
fn test_generate_random_phone_numbers_various_countries() {
let us_numbers = generate_random_phone_numbers("US", 3);
assert_eq!(us_numbers.len(), 3);
for num in &us_numbers {
assert!(num.starts_with("+1"));
}
let gb_numbers = generate_random_phone_numbers("GB", 3);
assert_eq!(gb_numbers.len(), 3);
for num in &gb_numbers {
assert!(num.starts_with("+44"));
}
}
#[test]
fn test_generate_random_phone_numbers_invalid_country() {
let numbers = generate_random_phone_numbers("XX", 5);
assert!(numbers.is_empty());
}
#[test]
fn test_generate_random_phone_numbers_zero_count() {
let numbers = generate_random_phone_numbers("US", 0);
assert!(numbers.is_empty());
}
#[test]
fn test_is_potentially_valid_phone_number_valid_lengths() {
assert!(is_potentially_valid_phone_number("1234567"));
assert!(is_potentially_valid_phone_number("1234567890"));
assert!(is_potentially_valid_phone_number("123456789012345"));
}
#[test]
fn test_is_potentially_valid_phone_number_invalid_lengths() {
assert!(!is_potentially_valid_phone_number("123456"));
assert!(!is_potentially_valid_phone_number("1234567890123456"));
}
#[test]
fn test_is_potentially_valid_phone_number_formatted() {
assert!(is_potentially_valid_phone_number("123-456-7890"));
assert!(is_potentially_valid_phone_number("123 456 7890"));
assert!(is_potentially_valid_phone_number("(123) 456-7890"));
}
#[test]
fn test_is_potentially_valid_phone_number_all_zeros() {
assert!(!is_potentially_valid_phone_number("0000000000"));
}
#[test]
fn test_suggest_phone_number_corrections_with_country_hint() {
let suggestions = suggest_phone_number_corrections("2025550173", Some("US"));
assert!(!suggestions.is_empty());
if !suggestions.is_empty() {
assert!(suggestions[0].starts_with("+1"));
}
}
#[test]
fn test_suggest_phone_number_corrections_already_valid() {
let suggestions = suggest_phone_number_corrections("+12025550173", None);
assert_eq!(suggestions.len(), 1);
assert_eq!(suggestions[0], "+12025550173");
}
#[test]
fn test_suggest_phone_number_corrections_without_hint() {
let suggestions = suggest_phone_number_corrections("2025550173", None);
assert!(suggestions.len() <= 5); }
#[test]
fn test_full_workflow_validation_to_analysis() {
let numbers = [
"+12025550173",
"+442079460958",
"+919876543210",
"invalid",
];
let valid_results = validate_phone_numbers_batch(&numbers);
assert_eq!(valid_results, vec![true, true, true, false]);
let normalized = normalize_phone_numbers_batch(&numbers);
assert_eq!(normalized.len(), 4);
let countries = extract_countries_batch(&numbers);
assert_eq!(countries[0].unwrap().code, "US");
let gb_code = countries[1].unwrap().code;
assert!(gb_code == "GB" || gb_code == "GB-CYM");
assert_eq!(countries[2].unwrap().code, "IN");
assert!(countries[3].is_none());
let types = detect_phone_number_types_batch(&numbers);
assert!(types[0].is_some());
assert!(types[1].is_some());
assert!(types[2].is_some());
assert!(types[3].is_none());
let analyses = analyze_phone_numbers_batch(&numbers);
assert_eq!(analyses.len(), 4);
}
#[test]
fn test_batch_functions_accept_various_types() {
let arr = ["+12025550173", "+442079460958"];
assert_eq!(validate_phone_numbers_batch(&arr).len(), 2);
let vec = vec!["+12025550173", "+442079460958"];
assert_eq!(normalize_phone_numbers_batch(&vec).len(), 2);
let string_vec = vec!["+12025550173".to_string(), "+442079460958".to_string()];
assert_eq!(extract_countries_batch(&string_vec).len(), 2);
let slice: &[&str] = &["+12025550173", "+442079460958"];
assert_eq!(detect_phone_number_types_batch(slice).len(), 2);
}
#[test]
fn test_cymru_wales_support() {
let wales_number = "+442079460958";
assert!(is_valid_phone_number(wales_number));
let country = extract_country(wales_number);
assert!(country.is_some());
let code = country.unwrap().code;
assert!(code == "GB" || code == "GB-CYM");
}
#[test]
fn test_phone_format_all_variants() {
let number = "+12025550173";
let e164 = format_phone_number(number, PhoneFormat::E164);
assert!(e164.is_some());
assert!(e164.unwrap().starts_with("+"));
let international = format_phone_number(number, PhoneFormat::International);
assert!(international.is_some());
let national = format_phone_number(number, PhoneFormat::National);
assert!(national.is_some());
let rfc3966 = format_phone_number(number, PhoneFormat::RFC3966);
assert!(rfc3966.is_some());
assert!(rfc3966.unwrap().starts_with("tel:"));
}
#[test]
fn test_detect_phone_number_type_comprehensive() {
let toll_free = detect_phone_number_type("+18005551234");
assert_eq!(toll_free, Some(PhoneNumberType::TollFree));
let uk_mobile = detect_phone_number_type("+447123456789");
assert_eq!(uk_mobile, Some(PhoneNumberType::Mobile));
let invalid = detect_phone_number_type("invalid");
assert!(invalid.is_none());
}
#[test]
fn test_are_phone_numbers_equal_comprehensive() {
assert!(are_phone_numbers_equal("+12025550173", "12025550173"));
assert!(are_phone_numbers_equal("+12025550173", "+1 (202) 555-0173"));
assert!(are_phone_numbers_equal("12025550173", "1-202-555-0173"));
assert!(!are_phone_numbers_equal("+12025550173", "+12025550174"));
assert!(!are_phone_numbers_equal("+12025550173", "+442079460958"));
assert!(!are_phone_numbers_equal("+12025550173", "invalid"));
assert!(!are_phone_numbers_equal("invalid1", "invalid2"));
}
#[test]
fn test_type_specific_check_functions() {
let uk_mobile = "+447123456789";
assert!(is_mobile_number(uk_mobile));
let us_toll_free = "+18005551234";
assert!(is_toll_free_number(us_toll_free));
let us_landline = "+12025550173";
assert!(is_landline_number(us_landline) || is_valid_phone_number(us_landline));
}
#[test]
fn test_validation_worldwide() {
let valid_numbers = vec![
("+12025550173", "US"),
("+14155552671", "US"),
("+18005551234", "US toll-free"),
("+14165550198", "CA"),
("+15145551234", "CA"),
("+442087654321", "GB"),
("+447911123456", "GB"),
("+493012345678", "DE"),
("+4915112345678", "DE mobile"),
("+33123456789", "FR"),
("+33612345678", "FR mobile"),
("+34612345678", "ES"),
("+41446681800", "CH"),
("+31201234567", "NL"),
("+32234567890", "BE"),
("+4721234567", "NO"),
("+46812345678", "SE"),
("+4512345678", "DK"),
("+48221234567", "PL"),
("+351212345678", "PT"),
("+353123456789", "IE"),
("+302101234567", "GR"),
("+36123456789", "HU"),
("+402112345678", "RO"),
("+905321234567", "TR"),
("+39123456789", "IT"),
("+61412345678", "AU"),
("+819012345678", "JP"),
("+8613800138000", "CN"),
("+919876543210", "IN"),
("+82221234567", "KR"),
("+6591234567", "SG"),
("+66812345678", "TH"),
("+85212345678", "HK"),
("+639171234567", "PH"),
("+5511987654321", "BR"),
("+525512345678", "MX"),
("+541112345678", "AR"),
("+56912345678", "CL"),
("+571234567890", "CO"),
("+971501234567", "AE"),
("+972541234567", "IL"),
("+966501234567", "SA"),
("+27211234567", "ZA"),
("+2348012345678", "NG"),
("+254712345678", "KE"),
("+201012345678", "EG"),
("+79161234567", "RU"),
("+77272501234", "KZ"),
("+6491234567", "NZ"),
("+64211234567", "NZ mobile"),
];
for (number, label) in &valid_numbers {
assert!(
is_valid_phone_number(number),
"Expected {} ({}) to be valid",
number,
label
);
}
for (number, label) in &valid_numbers {
let normalized = normalize_phone_number(number);
assert!(
normalized.is_some(),
"Expected {} ({}) to normalize",
number,
label
);
}
}
#[test]
fn test_country_detection_worldwide() {
let cases: Vec<(&str, &str)> = vec![
("+12025550173", "US"), ("+493012345678", "DE"), ("+33123456789", "FR"), ("+34612345678", "ES"), ("+41446681800", "CH"), ("+31201234567", "NL"), ("+32234567890", "BE"), ("+46812345678", "SE"), ("+4512345678", "DK"), ("+48221234567", "PL"), ("+351212345678", "PT"), ("+353123456789", "IE"), ("+302101234567", "GR"), ("+36123456789", "HU"), ("+402112345678", "RO"), ("+905321234567", "TR"), ("+61412345678", "AU"), ("+819012345678", "JP"), ("+8613800138000", "CN"), ("+919876543210", "IN"), ("+82221234567", "KR"), ("+6591234567", "SG"), ("+66812345678", "TH"), ("+85212345678", "HK"), ("+639171234567", "PH"), ("+5511987654321", "BR"), ("+525512345678", "MX"), ("+56912345678", "CL"), ("+571234567890", "CO"), ("+971501234567", "AE"), ("+966501234567", "SA"), ("+972541234567", "IL"), ("+27211234567", "ZA"), ("+254712345678", "KE"), ("+201012345678", "EG"), ("+2348012345678", "NG"), ("+6491234567", "NZ"), ("+4721234567", "NO"), ];
for (number, expected_code) in cases {
let country = extract_country(number);
assert!(
country.is_some(),
"Failed to detect country for {}",
number
);
assert_eq!(
country.unwrap().code, expected_code,
"Wrong country for {}: expected {}, got {}",
number, expected_code, country.unwrap().code
);
}
}
#[test]
fn test_parse_with_country_worldwide() {
let shared_prefix_cases: Vec<(&str, &str, &str)> = vec![
("+14165550198", "CA", "CA"),
("+12025550173", "US", "US"),
("+79161234567", "RU", "RU"),
("+77272501234", "KZ", "KZ"),
("+442087654321", "GB", "GB"),
("+447911123456", "GB", "GB"),
];
for (number, hint, expected_code) in shared_prefix_cases {
let phone = crate::PhoneNumber::parse_with_country(number, hint);
assert!(
phone.is_some(),
"Failed to parse {} with hint {}",
number, hint
);
assert_eq!(
phone.as_ref().unwrap().country.unwrap().code,
expected_code,
"Wrong country for {} with hint {}: got {}",
number,
hint,
phone.unwrap().country.unwrap().code
);
}
let national_cases: Vec<(&str, &str, &str)> = vec![
("(202) 555-0173", "US", "+12025550173"),
("416-555-0198", "CA", "+14165550198"),
("020 8765 4321", "GB", "+442087654321"),
("030 12345678", "DE", "+493012345678"),
("0412 345 678", "AU", "+61412345678"),
];
for (input, country, expected_e164) in national_cases {
let phone = crate::PhoneNumber::parse_with_country(input, country);
assert!(
phone.is_some(),
"Failed to parse '{}' with country '{}'",
input, country
);
let p = phone.unwrap();
assert_eq!(
p.e164(),
expected_e164,
"Wrong E.164 for '{}' with country '{}': got {}",
input, country, p.e164()
);
}
}
#[test]
fn test_normalization_formats_worldwide() {
let cases: Vec<(&str, &str)> = vec![
("+12025550173", "+12025550173"),
("+493012345678", "+493012345678"),
("+33123456789", "+33123456789"),
("+8613800138000", "+8613800138000"),
("+919876543210", "+919876543210"),
("+79161234567", "+79161234567"),
("+972541234567", "+972541234567"),
("+85212345678", "+85212345678"),
("+639171234567", "+639171234567"),
("+254712345678", "+254712345678"),
("+1 202 555 0173", "+12025550173"),
("+49 30 1234 5678", "+493012345678"),
("+86 138 0013 8000", "+8613800138000"),
("+91 98765 43210", "+919876543210"),
("+7 916 123 4567", "+79161234567"),
("+65 9123 4567", "+6591234567"),
("+52 55 1234 5678", "+525512345678"),
("+972 54 123 4567", "+972541234567"),
("+27 21 123 4567", "+27211234567"),
("12025550173", "+12025550173"),
("493012345678", "+493012345678"),
("8613800138000", "+8613800138000"),
];
for (input, expected) in cases {
let result = normalize_phone_number(input);
assert_eq!(
result.as_deref(),
Some(expected),
"Normalization of '{}' failed: got {:?}",
input,
result
);
}
}
#[test]
fn test_format_all_types_worldwide() {
let numbers = vec![
"+12025550173", "+493012345678", "+33123456789", "+34612345678", "+41446681800", "+31201234567", "+61412345678", "+8613800138000", "+919876543210", "+819012345678", "+82221234567", "+6591234567", "+66812345678", "+85212345678", "+525512345678", "+971501234567", "+972541234567", "+27211234567", "+302101234567", "+48221234567", "+351212345678", "+905321234567", "+56912345678", "+254712345678", "+6491234567", ];
for number in &numbers {
let e164 = format_phone_number(number, PhoneFormat::E164);
assert!(e164.is_some(), "E164 failed for {}", number);
assert!(
e164.as_ref().unwrap().starts_with('+'),
"E164 should start with + for {}",
number
);
let intl = format_phone_number(number, PhoneFormat::International);
assert!(intl.is_some(), "International failed for {}", number);
assert!(
intl.as_ref().unwrap().starts_with('+'),
"International should start with + for {}",
number
);
assert!(
intl.as_ref().unwrap().contains(' '),
"International should contain space for {}",
number
);
let national = format_phone_number(number, PhoneFormat::National);
assert!(national.is_some(), "National failed for {}", number);
assert!(
!national.as_ref().unwrap().starts_with('+'),
"National should not start with + for {}",
number
);
let rfc = format_phone_number(number, PhoneFormat::RFC3966);
assert!(rfc.is_some(), "RFC3966 failed for {}", number);
assert!(
rfc.as_ref().unwrap().starts_with("tel:+"),
"RFC3966 should start with tel:+ for {}",
number
);
}
}
#[test]
fn test_phone_number_struct_fields_worldwide() {
let cases: Vec<(&str, &str, u32)> = vec![
("+12025550173", "US", 1),
("+493012345678", "DE", 49),
("+33123456789", "FR", 33),
("+34612345678", "ES", 34),
("+41446681800", "CH", 41),
("+61412345678", "AU", 61),
("+8613800138000", "CN", 86),
("+919876543210", "IN", 91),
("+819012345678", "JP", 81),
("+6591234567", "SG", 65),
("+66812345678", "TH", 66),
("+85212345678", "HK", 852),
("+639171234567", "PH", 63),
("+525512345678", "MX", 52),
("+56912345678", "CL", 56),
("+571234567890", "CO", 57),
("+971501234567", "AE", 971),
("+972541234567", "IL", 972),
("+966501234567", "SA", 966),
("+27211234567", "ZA", 27),
("+254712345678", "KE", 254),
("+201012345678", "EG", 20),
("+302101234567", "GR", 30),
("+48221234567", "PL", 48),
("+351212345678", "PT", 351),
("+6491234567", "NZ", 64),
];
for (number, expected_code, expected_prefix) in cases {
let phone = crate::PhoneNumber::parse(number);
assert!(phone.is_some(), "Failed to parse {}", number);
let phone = phone.unwrap();
assert_eq!(
phone.country.unwrap().code, expected_code,
"Wrong country for {}",
number
);
assert_eq!(
phone.country_code(),
Some(expected_prefix),
"Wrong prefix for {}",
number
);
assert_eq!(phone.e164(), number, "E164 mismatch for {}", number);
let national = phone.national_number();
assert!(
!national.is_empty(),
"Empty national number for {}",
number
);
assert!(
national.chars().all(|c| c.is_ascii_digit()),
"National number should be all digits for {}",
number
);
}
}
#[test]
fn test_equality_across_formats_worldwide() {
let equivalent_pairs: Vec<(&str, &str)> = vec![
("+12025550173", "12025550173"),
("+12025550173", "+1 202 555 0173"),
("+493012345678", "493012345678"),
("+493012345678", "+49 30 1234 5678"),
("+8613800138000", "8613800138000"),
("+8613800138000", "+86 138 0013 8000"),
("+919876543210", "+91 98765 43210"),
("+79161234567", "+7 916 123 4567"),
];
for (a, b) in equivalent_pairs {
assert!(
are_phone_numbers_equal(a, b),
"'{}' and '{}' should be equal",
a, b
);
}
}
}