use super::*;
use crate::test_tracing_capture::with_test_subscriber;
use anyhow::{Context, Result, ensure};
use rstest::rstest;
use tracing_subscriber::filter::LevelFilter;
fn capture<T>(test: impl FnOnce() -> T) -> (T, Vec<String>) {
with_test_subscriber(LevelFilter::TRACE, |captured| {
let value = test();
(value, captured.snapshot())
})
}
fn find_event<'a>(events: &'a [String], needle: &str) -> Result<&'a String> {
events
.iter()
.find(|event| event.contains(needle))
.with_context(|| format!("expected an event containing {needle:?}, got {events:?}"))
}
#[rstest]
#[case("not a locale")]
#[case("!!")]
fn an_unparseable_locale_reports_why_it_was_dropped(#[case] requested: &str) -> Result<()> {
let (_, events) = capture(|| build_localizer(Some(requested)));
let event = find_event(&events, "locale request did not parse")?;
ensure!(
event.contains(requested),
"event must name the requested tag {requested:?}, got {event}"
);
ensure!(
event.contains("unparseable"),
"event must carry reason=\"unparseable\", got {event}"
);
ensure!(
event.contains(locales::SOURCE_LOCALE),
"event must name the effective locale, got {event}"
);
Ok(())
}
#[test]
fn a_resolved_locale_reports_requested_and_effective_tags() -> Result<()> {
let (_, events) = capture(|| build_localizer(Some("zh-TW")));
let event = find_event(&events, "resolved locale catalogue")?;
ensure!(
event.contains("zh-TW"),
"event must name the requested tag, got {event}"
);
ensure!(
event.contains("zh-Hant"),
"event must name the effective catalogue, got {event}"
);
Ok(())
}
#[test]
fn a_malformed_catalogue_reports_its_tag_and_error() -> Result<()> {
let malformed = "= not a message\n";
let locale = parse_locale_identifier("fr").context("fr must parse as a language identifier")?;
let builder = FluentLocalizer::builder(locale);
let (built, events) = capture(|| build_consumer_localizer(builder, "fr", malformed));
ensure!(
built.is_none(),
"a malformed catalogue must not yield a localizer"
);
let event = find_event(&events, "failed to load locale catalogue")?;
ensure!(
event.contains("fr"),
"event must name the offending locale, got {event}"
);
ensure!(
event.contains("failed to parse") && event.contains("resources for fr"),
"event must carry the rendered parse error, got {event}"
);
Ok(())
}
#[test]
fn a_well_formed_catalogue_reports_no_failure() -> Result<()> {
let (_, events) = capture(|| build_localizer(Some("fr")));
ensure!(
!events
.iter()
.any(|event| event.contains("failed to load locale catalogue")),
"a shipped catalogue must load without warning, got {events:?}"
);
Ok(())
}
#[rstest]
#[case("pt-AO", "pt-PT")]
#[case("es-MX", "es-419")]
#[case("zh-TW", "zh-Hant")]
fn a_fallback_resolved_request_renders_as_its_catalogue(
#[case] requested: &str,
#[case] catalogue_tag: &str,
) -> Result<()> {
let via_fallback = build_localizer(Some(requested));
let via_catalogue = build_localizer(Some(catalogue_tag));
let via_source = build_localizer(Some(locales::SOURCE_LOCALE));
for count in [0_i64, 1, 2, 5] {
let mut args = ortho_config::LocalizationArgs::new();
args.insert("count", fluent_bundle::FluentValue::from(count));
let fallback_text = via_fallback.lookup(
crate::localization::keys::EXAMPLE_FILES_PROCESSED,
Some(&args),
);
let catalogue_text = via_catalogue.lookup(
crate::localization::keys::EXAMPLE_FILES_PROCESSED,
Some(&args),
);
ensure!(
fallback_text == catalogue_text,
"{requested} must render as {catalogue_tag} for count {count}: {fallback_text:?} vs {catalogue_text:?}"
);
let source_text = via_source.lookup(
crate::localization::keys::EXAMPLE_FILES_PROCESSED,
Some(&args),
);
ensure!(
fallback_text != source_text,
"{requested} rendered the English source rather than {catalogue_tag} for count {count}: {fallback_text:?}"
);
ensure!(
fallback_text.is_some_and(|text| !text.trim().is_empty()),
"{requested} rendered nothing for count {count}"
);
}
Ok(())
}
#[rstest]
#[case("is-IS")]
#[case("not a locale")]
fn an_english_fallback_is_reported_at_warn(#[case] requested: &str) -> Result<()> {
let (_, at_warn) = with_test_subscriber(LevelFilter::WARN, |captured| {
let localizer = build_localizer(Some(requested));
(localizer, captured.snapshot())
});
ensure!(
at_warn
.iter()
.any(|event| event.contains("falling back to the source locale")),
"a fallback to English must be reported at WARN, got {at_warn:?}"
);
ensure!(
at_warn.iter().any(|event| event.contains(requested)),
"the event must name the requested tag {requested:?}, got {at_warn:?}"
);
Ok(())
}
#[test]
fn a_supported_locale_warns_about_nothing() -> Result<()> {
let (_, at_warn) = with_test_subscriber(LevelFilter::WARN, |captured| {
let localizer = build_localizer(Some("fr"));
(localizer, captured.snapshot())
});
ensure!(
at_warn.is_empty(),
"a shipped catalogue must not warn, got {at_warn:?}"
);
Ok(())
}
#[rstest]
#[case("en-US")]
#[case("en-us")]
#[case("EN-US")]
#[case("en")]
#[case("en-AU")]
fn a_source_locale_spelling_warns_about_nothing(#[case] requested: &str) -> Result<()> {
let (_, at_warn) = with_test_subscriber(LevelFilter::WARN, |captured| {
let localizer = build_localizer(Some(requested));
(localizer, captured.snapshot())
});
ensure!(
at_warn.is_empty(),
"{requested} resolves to the source catalogue and must not warn, got {at_warn:?}"
);
Ok(())
}