#![allow(clippy::indexing_slicing, reason = "tests are allowed to panic")]
#![allow(
clippy::unwrap_in_result,
reason = "A test can unwrap wherever it wants"
)]
#![allow(
clippy::panic_in_result_fn,
reason = "A test can unwrap wherever it wants"
)]
use std::assert_matches;
use super::{find_or_infer, Source};
use crate::{cdr, test, timezone::Warning, warning::test::VerdictTestExt as _, Verdict, Version};
#[test]
fn should_find_timezone() {
const JSON: &str = r#"{
"country_code": "NL",
"cdr_location": {
"time_zone": "Europe/Amsterdam"
}
}"#;
test::setup();
let timezone = parse_expect_v221_and_time_zone_field(JSON)
.unwrap()
.unwrap();
assert_matches!(timezone, Source::Found(chrono_tz::Tz::Europe__Amsterdam));
}
#[test]
fn should_find_timezone_but_warn_about_use_of_location_for_v221_cdr() {
const JSON: &str = r#"{
"country_code": "NL",
"location": {
"time_zone": "Europe/Amsterdam"
}
}"#;
test::setup();
let cdr = cdr::build(crate::json::parse_object(JSON).unwrap(), Version::V221);
test::assert_unexpected_fields(&cdr, &["$.location"]);
let (timezone_source, warnings) = find_or_infer(&cdr).unwrap().into_parts();
let warnings = warnings.into_path_as_str_map();
let warnings = &warnings["$"];
assert_matches!(
timezone_source,
Source::Found(chrono_tz::Tz::Europe__Amsterdam)
);
assert_matches!(warnings.as_slice(), [Warning::V221CdrHasLocationField]);
}
#[test]
fn should_find_timezone_without_cdr_country() {
const JSON: &str = r#"{
"cdr_location": {
"time_zone": "Europe/Amsterdam"
}
}"#;
test::setup();
let timezone = parse_expect_v221_and_time_zone_field(JSON)
.unwrap()
.unwrap();
assert_matches!(timezone, Source::Found(chrono_tz::Tz::Europe__Amsterdam));
}
#[test]
fn should_infer_timezone_and_warn_about_invalid_type() {
const JSON: &str = r#"{
"country_code": "NL",
"cdr_location": {
"time_zone": null,
"country": "BEL"
}
}"#;
test::setup();
let (timezone, warnings) = parse_expect_v221_and_time_zone_field(JSON)
.unwrap()
.into_parts();
let warnings = warnings.into_path_as_str_map();
let warnings = &warnings["$.cdr_location.time_zone"];
assert_matches!(timezone, Source::Inferred(chrono_tz::Tz::Europe__Brussels));
assert_matches!(warnings.as_slice(), [Warning::InvalidTimezoneType]);
}
#[test]
fn should_find_timezone_and_warn_about_invalid_type() {
const JSON: &str = r#"{
"country_code": "NL",
"cdr_location": {
"time_zone": "Europe/Hamsterdam",
"country": "BEL"
}
}"#;
test::setup();
let (timezone, warnings) = parse_expect_v221_and_time_zone_field(JSON)
.unwrap()
.into_parts();
assert_matches!(timezone, Source::Inferred(chrono_tz::Tz::Europe__Brussels));
let warnings = warnings.into_path_as_str_map();
let warnings = &warnings["$.cdr_location.time_zone"];
assert_matches!(warnings.as_slice(), [Warning::InvalidTimezone]);
}
#[test]
fn should_find_timezone_and_warn_about_escape_codes_and_invalid_type() {
const JSON: &str = r#"{
"country_code": "NL",
"cdr_location": {
"time_zone": "Europe\/Hamsterdam",
"country": "BEL"
}
}"#;
test::setup();
let (timezone, warnings) = parse_expect_v221_and_time_zone_field(JSON)
.unwrap()
.into_parts();
assert_matches!(timezone, Source::Inferred(chrono_tz::Tz::Europe__Brussels));
let groups = warnings.into_path_as_str_map();
let warnings = &groups["$.cdr_location.time_zone"];
assert_matches!(
warnings.as_slice(),
[Warning::ContainsEscapeCodes, Warning::InvalidTimezone]
);
}
#[test]
fn should_find_timezone_and_warn_about_escape_codes() {
const JSON: &str = r#"{
"country_code": "NL",
"cdr_location": {
"time_zone": "Europe\/Amsterdam",
"country": "BEL"
}
}"#;
test::setup();
let (timezone, warnings) = parse_expect_v221_and_time_zone_field(JSON)
.unwrap()
.into_parts();
assert_matches!(timezone, Source::Found(chrono_tz::Tz::Europe__Amsterdam));
let groups = warnings.into_path_as_str_map();
let warnings = &groups["$.cdr_location.time_zone"];
assert_matches!(warnings.as_slice(), [Warning::ContainsEscapeCodes]);
}
#[test]
fn should_infer_timezone_from_location_country() {
const JSON: &str = r#"{
"country_code": "NL",
"cdr_location": {
"country": "BEL"
}
}"#;
test::setup();
let timezone = parse_expect_v221(JSON).unwrap().unwrap();
assert_matches!(timezone, Source::Inferred(chrono_tz::Tz::Europe__Brussels));
}
#[test]
fn should_find_timezone_but_report_alpha2_location_country_code() {
const JSON: &str = r#"{
"country_code": "NL",
"cdr_location": {
"country": "BE"
}
}"#;
test::setup();
let (timezone, warnings) = parse_expect_v221(JSON).unwrap().into_parts();
assert_matches!(timezone, Source::Inferred(chrono_tz::Tz::Europe__Brussels));
let groups = warnings.into_path_as_str_map();
let warnings = &groups["$.cdr_location.country"];
assert_matches!(
warnings.as_slice(),
[Warning::LocationCountryShouldBeAlpha3,]
);
}
#[test]
fn should_not_find_timezone_due_to_no_location() {
const JSON: &str = r#"{ "country_code": "BE" }"#;
test::setup();
let error = parse_expect_v221(JSON).unwrap_only_error();
assert_eq!(error.element().path.as_str(), "$");
assert_matches!(error.warning(), Warning::NoLocation);
}
#[test]
fn should_not_find_timezone_due_to_no_country() {
const JSON: &str = r#"{
"country_code": "BE",
"cdr_location": {}
}"#;
test::setup();
let error = parse_expect_v221(JSON).unwrap_only_error();
assert_eq!(error.element().path.as_str(), "$.cdr_location");
assert_matches!(error.warning(), Warning::NoLocationCountry);
}
#[test]
fn should_not_find_timezone_due_to_country_having_many_timezones() {
const JSON: &str = r#"{
"country_code": "BE",
"cdr_location": {
"country": "CHN"
}
}"#;
test::setup();
let error = parse_expect_v221(JSON).unwrap_only_error();
assert_eq!(error.element().path.as_str(), "$.cdr_location.country");
assert_matches!(error.warning(), Warning::CantInferTimezoneFromCountry("CN"));
}
#[test]
fn should_fail_due_to_json_not_being_object() {
const JSON: &str = r#"["not_a_cdr"]"#;
test::setup();
let error = crate::json::parse_object(JSON).unwrap_err();
assert_matches!(error, crate::json::ParseError::ShouldBeAnObject);
}
#[track_caller]
fn parse_expect_v221(json: &str) -> Verdict<Source, Warning> {
let json = crate::json::parse_object(json).unwrap();
let (cdr, mut warnings) = cdr::build(json, Version::V221).into_parts();
warnings.remove_missing_fields();
assert!(
warnings.is_empty(),
"The CDR has warnings;\n{:?}",
warnings.path_id_map()
);
find_or_infer(&cdr)
}
#[track_caller]
fn parse_expect_v221_and_time_zone_field(json: &str) -> Verdict<Source, Warning> {
let cdr = cdr::build(crate::json::parse_object(json).unwrap(), Version::V221);
test::assert_unexpected_fields(&cdr, &["$.cdr_location.time_zone"]);
find_or_infer(&cdr)
}