diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /intl/l10n/rust/l10nregistry-tests/tests | |
parent | Initial commit. (diff) | |
download | firefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz firefox-26a029d407be480d791972afb5975cf62c9360a6.zip |
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'intl/l10n/rust/l10nregistry-tests/tests')
-rw-r--r-- | intl/l10n/rust/l10nregistry-tests/tests/localization.rs | 201 | ||||
-rw-r--r-- | intl/l10n/rust/l10nregistry-tests/tests/registry.rs | 304 | ||||
-rw-r--r-- | intl/l10n/rust/l10nregistry-tests/tests/scenarios_async.rs | 109 | ||||
-rw-r--r-- | intl/l10n/rust/l10nregistry-tests/tests/scenarios_sync.rs | 107 | ||||
-rw-r--r-- | intl/l10n/rust/l10nregistry-tests/tests/source.rs | 305 | ||||
-rw-r--r-- | intl/l10n/rust/l10nregistry-tests/tests/tokio.rs | 65 |
6 files changed, 1091 insertions, 0 deletions
diff --git a/intl/l10n/rust/l10nregistry-tests/tests/localization.rs b/intl/l10n/rust/l10nregistry-tests/tests/localization.rs new file mode 100644 index 0000000000..1362fc030e --- /dev/null +++ b/intl/l10n/rust/l10nregistry-tests/tests/localization.rs @@ -0,0 +1,201 @@ +use std::borrow::Cow; + +use fluent_fallback::{ + env::LocalesProvider, + types::{L10nKey, ResourceId}, + Localization, +}; +use l10nregistry_tests::{ + FileSource, MockBundleAdapter, RegistrySetup, TestEnvironment, TestFileFetcher, +}; +use serial_test::serial; +use unic_langid::{langid, LanguageIdentifier}; + +type L10nRegistry = l10nregistry::registry::L10nRegistry<TestEnvironment, MockBundleAdapter>; + +static LOCALES: &[LanguageIdentifier] = &[langid!("pl"), langid!("en-US")]; +static mut FILE_FETCHER: Option<TestFileFetcher> = None; +static mut L10N_REGISTRY: Option<L10nRegistry> = None; + +const FTL_RESOURCE: &str = "toolkit/updates/history.ftl"; +const L10N_ID_PL_EN: (&str, Option<&str>) = ("history-title", Some("Historia aktualizacji")); +const L10N_ID_MISSING: (&str, Option<&str>) = ("missing-id", None); +const L10N_ID_ONLY_EN: (&str, Option<&str>) = ( + "history-intro", + Some("The following updates have been installed"), +); + +fn get_file_fetcher() -> &'static TestFileFetcher { + let fetcher: &mut Option<TestFileFetcher> = unsafe { &mut FILE_FETCHER }; + + fetcher.get_or_insert_with(|| TestFileFetcher::new()) +} + +fn get_l10n_registry() -> &'static L10nRegistry { + let reg: &mut Option<L10nRegistry> = unsafe { &mut L10N_REGISTRY }; + + reg.get_or_insert_with(|| { + let fetcher = get_file_fetcher(); + let setup = RegistrySetup::new( + "test", + vec![ + FileSource::new( + "toolkit", + None, + get_app_locales().to_vec(), + "toolkit/{locale}/", + ), + FileSource::new( + "browser", + None, + get_app_locales().to_vec(), + "browser/{locale}/", + ), + ], + get_app_locales().to_vec(), + ); + fetcher.get_registry_and_environment(setup).1 + }) +} + +fn get_app_locales() -> &'static [LanguageIdentifier] { + LOCALES +} + +struct LocalesService; + +impl LocalesProvider for LocalesService { + type Iter = std::vec::IntoIter<LanguageIdentifier>; + + fn locales(&self) -> Self::Iter { + get_app_locales().to_vec().into_iter() + } +} + +fn sync_localization( + reg: &'static L10nRegistry, + res_ids: Vec<ResourceId>, +) -> Localization<L10nRegistry, LocalesService> { + Localization::with_env(res_ids, true, LocalesService, reg.clone()) +} + +fn async_localization( + reg: &'static L10nRegistry, + res_ids: Vec<ResourceId>, +) -> Localization<L10nRegistry, LocalesService> { + Localization::with_env(res_ids, false, LocalesService, reg.clone()) +} + +fn setup_sync_test() -> Localization<L10nRegistry, LocalesService> { + sync_localization(get_l10n_registry(), vec![FTL_RESOURCE.into()]) +} + +fn setup_async_test() -> Localization<L10nRegistry, LocalesService> { + async_localization(get_l10n_registry(), vec![FTL_RESOURCE.into()]) +} + +#[test] +#[serial] +fn localization_format_value_sync() { + let loc = setup_sync_test(); + let bundles = loc.bundles(); + let mut errors = vec![]; + + for query in &[L10N_ID_PL_EN, L10N_ID_MISSING, L10N_ID_ONLY_EN] { + let value = bundles + .format_value_sync(query.0, None, &mut errors) + .unwrap(); + assert_eq!(value, query.1.map(|s| Cow::Borrowed(s))); + } + + assert_eq!(errors.len(), 4); +} + +#[test] +#[serial] +fn localization_format_values_sync() { + let loc = setup_sync_test(); + let bundles = loc.bundles(); + let mut errors = vec![]; + + let ids = &[L10N_ID_PL_EN, L10N_ID_MISSING, L10N_ID_ONLY_EN]; + let keys = ids + .iter() + .map(|query| L10nKey { + id: query.0.into(), + args: None, + }) + .collect::<Vec<_>>(); + + let values = bundles.format_values_sync(&keys, &mut errors).unwrap(); + + assert_eq!(values.len(), ids.len()); + + for (value, query) in values.iter().zip(ids) { + if let Some(expected) = query.1 { + assert_eq!(*value, Some(Cow::Borrowed(expected))); + } + } + assert_eq!(errors.len(), 4); +} + +#[tokio::test] +#[serial] +async fn localization_format_value_async() { + let loc = setup_async_test(); + let bundles = loc.bundles(); + let mut errors = vec![]; + + for query in &[L10N_ID_PL_EN, L10N_ID_MISSING, L10N_ID_ONLY_EN] { + let value = bundles.format_value(query.0, None, &mut errors).await; + if let Some(expected) = query.1 { + assert_eq!(value, Some(Cow::Borrowed(expected))); + } + } +} + +#[tokio::test] +#[serial] +async fn localization_format_values_async() { + let loc = setup_async_test(); + let bundles = loc.bundles(); + let mut errors = vec![]; + + let ids = &[L10N_ID_PL_EN, L10N_ID_MISSING, L10N_ID_ONLY_EN]; + let keys = ids + .iter() + .map(|query| L10nKey { + id: query.0.into(), + args: None, + }) + .collect::<Vec<_>>(); + + let values = bundles.format_values(&keys, &mut errors).await; + + assert_eq!(values.len(), ids.len()); + + for (value, query) in values.iter().zip(ids) { + if let Some(expected) = query.1 { + assert_eq!(*value, Some(Cow::Borrowed(expected))); + } + } +} + +#[tokio::test] +#[serial] +async fn localization_upgrade() { + let mut loc = setup_sync_test(); + let bundles = loc.bundles(); + let mut errors = vec![]; + let value = bundles + .format_value_sync(L10N_ID_PL_EN.0, None, &mut errors) + .unwrap(); + assert_eq!(value, L10N_ID_PL_EN.1.map(|s| Cow::Borrowed(s))); + + loc.set_async(); + let bundles = loc.bundles(); + let value = bundles + .format_value(L10N_ID_PL_EN.0, None, &mut errors) + .await; + assert_eq!(value, L10N_ID_PL_EN.1.map(|s| Cow::Borrowed(s))); +} diff --git a/intl/l10n/rust/l10nregistry-tests/tests/registry.rs b/intl/l10n/rust/l10nregistry-tests/tests/registry.rs new file mode 100644 index 0000000000..72d6e6ed8b --- /dev/null +++ b/intl/l10n/rust/l10nregistry-tests/tests/registry.rs @@ -0,0 +1,304 @@ +use l10nregistry_tests::{FileSource, RegistrySetup, TestFileFetcher}; +use unic_langid::LanguageIdentifier; + +static FTL_RESOURCE_TOOLKIT: &str = "toolkit/global/textActions.ftl"; +static FTL_RESOURCE_BROWSER: &str = "branding/brand.ftl"; + +#[test] +fn test_get_sources_for_resource() { + let en_us: LanguageIdentifier = "en-US".parse().unwrap(); + let setup = RegistrySetup::new( + "test", + vec![ + FileSource::new("toolkit", None, vec![en_us.clone()], "toolkit/{locale}/"), + FileSource::new("browser", None, vec![en_us.clone()], "browser/{locale}/"), + ], + vec![en_us.clone()], + ); + let fetcher = TestFileFetcher::new(); + let (_, reg) = fetcher.get_registry_and_environment(setup); + + { + let metasources = reg + .try_borrow_metasources() + .expect("Unable to borrow metasources."); + + let toolkit = metasources.file_source_by_name(0, "toolkit").unwrap(); + let browser = metasources.file_source_by_name(0, "browser").unwrap(); + let toolkit_resource_id = FTL_RESOURCE_TOOLKIT.into(); + + let mut i = metasources.get_sources_for_resource(0, &en_us, &toolkit_resource_id); + + assert_eq!(i.next(), Some(toolkit)); + assert_eq!(i.next(), Some(browser)); + assert_eq!(i.next(), None); + + assert!(browser + .fetch_file_sync(&en_us, &FTL_RESOURCE_TOOLKIT.into(), false) + .is_none()); + + let mut i = metasources.get_sources_for_resource(0, &en_us, &toolkit_resource_id); + assert_eq!(i.next(), Some(toolkit)); + assert_eq!(i.next(), None); + + assert!(toolkit + .fetch_file_sync(&en_us, &FTL_RESOURCE_TOOLKIT.into(), false) + .is_some()); + + let mut i = metasources.get_sources_for_resource(0, &en_us, &toolkit_resource_id); + assert_eq!(i.next(), Some(toolkit)); + assert_eq!(i.next(), None); + } +} + +#[test] +fn test_generate_bundles_for_lang_sync() { + let en_us: LanguageIdentifier = "en-US".parse().unwrap(); + let setup = RegistrySetup::new( + "test", + vec![ + FileSource::new("toolkit", None, vec![en_us.clone()], "toolkit/{locale}/"), + FileSource::new("browser", None, vec![en_us.clone()], "browser/{locale}/"), + ], + vec![en_us.clone()], + ); + let fetcher = TestFileFetcher::new(); + let (_, reg) = fetcher.get_registry_and_environment(setup); + + let paths = vec![FTL_RESOURCE_TOOLKIT.into(), FTL_RESOURCE_BROWSER.into()]; + let mut i = reg.generate_bundles_for_lang_sync(en_us.clone(), paths); + + assert!(i.next().is_some()); + assert!(i.next().is_none()); +} + +#[test] +fn test_generate_bundles_sync() { + let en_us: LanguageIdentifier = "en-US".parse().unwrap(); + let setup = RegistrySetup::new( + "test", + vec![ + FileSource::new("toolkit", None, vec![en_us.clone()], "toolkit/{locale}/"), + FileSource::new("browser", None, vec![en_us.clone()], "browser/{locale}/"), + ], + vec![en_us.clone()], + ); + let fetcher = TestFileFetcher::new(); + let (_, reg) = fetcher.get_registry_and_environment(setup); + + let paths = vec![FTL_RESOURCE_TOOLKIT.into(), FTL_RESOURCE_BROWSER.into()]; + let lang_ids = vec![en_us]; + let mut i = reg.generate_bundles_sync(lang_ids.into_iter(), paths); + + assert!(i.next().is_some()); + assert!(i.next().is_none()); +} + +#[tokio::test] +async fn test_generate_bundles_for_lang() { + use futures::stream::StreamExt; + + let en_us: LanguageIdentifier = "en-US".parse().unwrap(); + let setup = RegistrySetup::new( + "test", + vec![ + FileSource::new("toolkit", None, vec![en_us.clone()], "toolkit/{locale}/"), + FileSource::new("browser", None, vec![en_us.clone()], "browser/{locale}/"), + ], + vec![en_us.clone()], + ); + let fetcher = TestFileFetcher::new(); + let (_, reg) = fetcher.get_registry_and_environment(setup); + + let paths = vec![FTL_RESOURCE_TOOLKIT.into(), FTL_RESOURCE_BROWSER.into()]; + let mut i = reg + .generate_bundles_for_lang(en_us, paths) + .expect("Failed to get GenerateBundles."); + + assert!(i.next().await.is_some()); + assert!(i.next().await.is_none()); +} + +#[tokio::test] +async fn test_generate_bundles() { + use futures::stream::StreamExt; + + let en_us: LanguageIdentifier = "en-US".parse().unwrap(); + let setup = RegistrySetup::new( + "test", + vec![ + FileSource::new("toolkit", None, vec![en_us.clone()], "toolkit/{locale}/"), + FileSource::new("browser", None, vec![en_us.clone()], "browser/{locale}/"), + ], + vec![en_us.clone()], + ); + let fetcher = TestFileFetcher::new(); + let (_, reg) = fetcher.get_registry_and_environment(setup); + + let paths = vec![FTL_RESOURCE_TOOLKIT.into(), FTL_RESOURCE_BROWSER.into()]; + let langs = vec![en_us]; + let mut i = reg + .generate_bundles(langs.into_iter(), paths) + .expect("Failed to get GenerateBundles."); + + assert!(i.next().await.is_some()); + assert!(i.next().await.is_none()); +} + +#[test] +fn test_manage_sources() { + let en_us: LanguageIdentifier = "en-US".parse().unwrap(); + let setup = RegistrySetup::new( + "test", + vec![ + FileSource::new("toolkit", None, vec![en_us.clone()], "toolkit/{locale}/"), + FileSource::new("browser", None, vec![en_us.clone()], "browser/{locale}/"), + ], + vec![en_us.clone()], + ); + let fetcher = TestFileFetcher::new(); + let (_, reg) = fetcher.get_registry_and_environment(setup); + + let lang_ids = vec![en_us]; + + let paths = vec![FTL_RESOURCE_TOOLKIT.into(), FTL_RESOURCE_BROWSER.into()]; + + let mut i = reg.generate_bundles_sync(lang_ids.clone().into_iter(), paths); + + assert!(i.next().is_some()); + assert!(i.next().is_none()); + + reg.clone() + .remove_sources(vec!["toolkit"]) + .expect("Failed to remove a source."); + + let paths = vec![FTL_RESOURCE_TOOLKIT.into(), FTL_RESOURCE_BROWSER.into()]; + let mut i = reg.generate_bundles_sync(lang_ids.clone().into_iter(), paths); + assert!(i.next().is_none()); + + let paths = vec![FTL_RESOURCE_BROWSER.into()]; + let mut i = reg.generate_bundles_sync(lang_ids.clone().into_iter(), paths); + assert!(i.next().is_some()); + assert!(i.next().is_none()); + + reg.register_sources(vec![fetcher.get_test_file_source( + "toolkit", + None, + lang_ids.clone(), + "browser/{locale}/", + )]) + .expect("Failed to register a source."); + + let paths = vec![FTL_RESOURCE_TOOLKIT.into(), FTL_RESOURCE_BROWSER.into()]; + let mut i = reg.generate_bundles_sync(lang_ids.clone().into_iter(), paths); + assert!(i.next().is_none()); + + reg.update_sources(vec![fetcher.get_test_file_source( + "toolkit", + None, + lang_ids.clone(), + "toolkit/{locale}/", + )]) + .expect("Failed to update a source."); + + let paths = vec![FTL_RESOURCE_TOOLKIT.into(), FTL_RESOURCE_BROWSER.into()]; + let mut i = reg.generate_bundles_sync(lang_ids.clone().into_iter(), paths); + assert!(i.next().is_some()); + assert!(i.next().is_none()); +} + +#[test] +fn test_generate_bundles_with_metasources_sync() { + let en_us: LanguageIdentifier = "en-US".parse().unwrap(); + let setup = RegistrySetup::new( + "test", + vec![ + FileSource::new( + "toolkit", + Some("app"), + vec![en_us.clone()], + "toolkit/{locale}/", + ), + FileSource::new( + "browser", + Some("app"), + vec![en_us.clone()], + "browser/{locale}/", + ), + FileSource::new( + "toolkit", + Some("langpack"), + vec![en_us.clone()], + "toolkit/{locale}/", + ), + FileSource::new( + "browser", + Some("langpack"), + vec![en_us.clone()], + "browser/{locale}/", + ), + ], + vec![en_us.clone()], + ); + let fetcher = TestFileFetcher::new(); + let (_, reg) = fetcher.get_registry_and_environment(setup); + + let paths = vec![FTL_RESOURCE_TOOLKIT.into(), FTL_RESOURCE_BROWSER.into()]; + let lang_ids = vec![en_us]; + let mut i = reg.generate_bundles_sync(lang_ids.into_iter(), paths); + + assert!(i.next().is_some()); + assert!(i.next().is_some()); + assert!(i.next().is_none()); +} + +#[tokio::test] +async fn test_generate_bundles_with_metasources() { + use futures::stream::StreamExt; + + let en_us: LanguageIdentifier = "en-US".parse().unwrap(); + + let setup = RegistrySetup::new( + "test", + vec![ + FileSource::new( + "toolkit", + Some("app"), + vec![en_us.clone()], + "toolkit/{locale}/", + ), + FileSource::new( + "browser", + Some("app"), + vec![en_us.clone()], + "browser/{locale}/", + ), + FileSource::new( + "toolkit", + Some("langpack"), + vec![en_us.clone()], + "toolkit/{locale}/", + ), + FileSource::new( + "browser", + Some("langpack"), + vec![en_us.clone()], + "browser/{locale}/", + ), + ], + vec![en_us.clone()], + ); + + let fetcher = TestFileFetcher::new(); + let (_, reg) = fetcher.get_registry_and_environment(setup); + + let paths = vec![FTL_RESOURCE_TOOLKIT.into(), FTL_RESOURCE_BROWSER.into()]; + let langs = vec![en_us]; + let mut i = reg + .generate_bundles(langs.into_iter(), paths) + .expect("Failed to get GenerateBundles."); + + assert!(i.next().await.is_some()); + assert!(i.next().await.is_some()); + assert!(i.next().await.is_none()); +} diff --git a/intl/l10n/rust/l10nregistry-tests/tests/scenarios_async.rs b/intl/l10n/rust/l10nregistry-tests/tests/scenarios_async.rs new file mode 100644 index 0000000000..cdbf373d84 --- /dev/null +++ b/intl/l10n/rust/l10nregistry-tests/tests/scenarios_async.rs @@ -0,0 +1,109 @@ +use fluent_bundle::FluentArgs; +use fluent_fallback::Localization; +use fluent_testing::get_scenarios; +use l10nregistry::fluent::FluentBundle; +use l10nregistry::registry::BundleAdapter; +use l10nregistry_tests::{RegistrySetup, TestFileFetcher}; + +#[derive(Clone)] +struct ScenarioBundleAdapter {} + +impl BundleAdapter for ScenarioBundleAdapter { + fn adapt_bundle(&self, bundle: &mut FluentBundle) { + bundle.set_use_isolating(false); + bundle + .add_function("PLATFORM", |_positional, _named| "linux".into()) + .expect("Failed to add a function to the bundle."); + } +} + +#[tokio::test] +async fn scenarios_async() { + use fluent_testing::scenarios::structs::Scenario; + let fetcher = TestFileFetcher::new(); + + let scenarios = get_scenarios(); + + let adapter = ScenarioBundleAdapter {}; + + let cannot_produce_bundle = |scenario: &Scenario| { + scenario + .queries + .iter() + .any(|query| query.exceptional_context.blocks_bundle_generation()) + }; + + for scenario in scenarios { + println!("scenario: {}", scenario.name); + let setup: RegistrySetup = (&scenario).into(); + let (env, reg) = fetcher.get_registry_and_environment_with_adapter(setup, adapter.clone()); + + let loc = Localization::with_env(scenario.res_ids.clone(), false, env.clone(), reg); + let bundles = loc.bundles(); + let no_bundles = cannot_produce_bundle(&scenario); + + let mut errors = vec![]; + + for query in scenario.queries.iter() { + let errors_start_len = errors.len(); + + let args = query.input.args.as_ref().map(|args| { + let mut result = FluentArgs::new(); + for arg in args.as_slice() { + result.set(arg.id.clone(), arg.value.clone()); + } + result + }); + + if let Some(output) = &query.output { + if let Some(value) = &output.value { + let v = bundles + .format_value(&query.input.id, args.as_ref(), &mut errors) + .await; + if no_bundles || query.exceptional_context.causes_failed_value_lookup() { + assert!(v.is_none()); + if no_bundles { + continue; + } + } else { + assert_eq!(v.unwrap(), value.as_str()) + } + } + } + + if query.exceptional_context.causes_reported_format_error() { + assert!( + errors.len() > errors_start_len, + "expected reported errors for query {:#?}", + query + ); + } else { + assert_eq!( + errors.len(), + errors_start_len, + "expected no reported errors for query {:#?}", + query + ); + } + } + + if scenario + .queries + .iter() + .any(|query| query.exceptional_context.missing_required_resource()) + { + assert!( + !env.errors().is_empty(), + "expected errors for scenario {{ {} }}, but found none", + scenario.name + ); + } else { + assert!( + env.errors().is_empty(), + "expected no errors for scenario {{ {} }}, but found {:#?}", + scenario.name, + env.errors() + ); + } + } +} diff --git a/intl/l10n/rust/l10nregistry-tests/tests/scenarios_sync.rs b/intl/l10n/rust/l10nregistry-tests/tests/scenarios_sync.rs new file mode 100644 index 0000000000..ce13b241fe --- /dev/null +++ b/intl/l10n/rust/l10nregistry-tests/tests/scenarios_sync.rs @@ -0,0 +1,107 @@ +use fluent_bundle::FluentArgs; +use fluent_fallback::Localization; +use fluent_testing::get_scenarios; +use l10nregistry::fluent::FluentBundle; +use l10nregistry::registry::BundleAdapter; +use l10nregistry_tests::{RegistrySetup, TestFileFetcher}; + +#[derive(Clone)] +struct ScenarioBundleAdapter {} + +impl BundleAdapter for ScenarioBundleAdapter { + fn adapt_bundle(&self, bundle: &mut FluentBundle) { + bundle.set_use_isolating(false); + bundle + .add_function("PLATFORM", |_positional, _named| "linux".into()) + .expect("Failed to add a function to the bundle."); + } +} + +#[test] +fn scenarios_sync() { + use fluent_testing::scenarios::structs::Scenario; + let fetcher = TestFileFetcher::new(); + + let scenarios = get_scenarios(); + + let adapter = ScenarioBundleAdapter {}; + + let cannot_produce_bundle = |scenario: &Scenario| { + scenario + .queries + .iter() + .any(|query| query.exceptional_context.blocks_bundle_generation()) + }; + + for scenario in scenarios { + println!("scenario: {}", scenario.name); + let setup: RegistrySetup = (&scenario).into(); + let (env, reg) = fetcher.get_registry_and_environment_with_adapter(setup, adapter.clone()); + + let loc = Localization::with_env(scenario.res_ids.clone(), true, env.clone(), reg); + let bundles = loc.bundles(); + let no_bundles = cannot_produce_bundle(&scenario); + + let mut errors = vec![]; + + for query in scenario.queries.iter() { + let errors_start_len = errors.len(); + + let args = query.input.args.as_ref().map(|args| { + let mut result = FluentArgs::new(); + for arg in args.as_slice() { + result.set(arg.id.clone(), arg.value.clone()); + } + result + }); + + if let Some(output) = &query.output { + if let Some(value) = &output.value { + let v = bundles.format_value_sync(&query.input.id, args.as_ref(), &mut errors); + if no_bundles || query.exceptional_context.causes_failed_value_lookup() { + assert!(v.is_err() || v.unwrap().is_none()); + if no_bundles { + continue; + } + } else { + assert_eq!(v.unwrap().unwrap(), value.as_str()) + } + } + } + + if query.exceptional_context.causes_reported_format_error() { + assert!( + errors.len() > errors_start_len, + "expected reported errors for query {:#?}", + query + ); + } else { + assert_eq!( + errors.len(), + errors_start_len, + "expected no reported errors for query {:#?}", + query + ); + } + } + + if scenario + .queries + .iter() + .any(|query| query.exceptional_context.missing_required_resource()) + { + assert!( + !env.errors().is_empty(), + "expected errors for scenario {{ {} }}, but found none", + scenario.name + ); + } else { + assert!( + env.errors().is_empty(), + "expected no errors for scenario {{ {} }}, but found {:#?}", + scenario.name, + env.errors() + ); + } + } +} diff --git a/intl/l10n/rust/l10nregistry-tests/tests/source.rs b/intl/l10n/rust/l10nregistry-tests/tests/source.rs new file mode 100644 index 0000000000..63104db8eb --- /dev/null +++ b/intl/l10n/rust/l10nregistry-tests/tests/source.rs @@ -0,0 +1,305 @@ +use fluent_fallback::types::{ResourceType, ToResourceId}; +use futures::future::join_all; +use l10nregistry_tests::TestFileFetcher; +use unic_langid::LanguageIdentifier; + +static FTL_RESOURCE_PRESENT: &str = "toolkit/global/textActions.ftl"; +static FTL_RESOURCE_MISSING: &str = "missing.ftl"; + +#[test] +fn test_fetch_sync() { + let fetcher = TestFileFetcher::new(); + let en_us: LanguageIdentifier = "en-US".parse().unwrap(); + + let fs1 = + fetcher.get_test_file_source("toolkit", None, vec![en_us.clone()], "toolkit/{locale}/"); + + let file = fs1.fetch_file_sync(&en_us, &FTL_RESOURCE_PRESENT.into(), false); + assert!(file.is_some()); + assert!(!file.is_none()); + assert!(!file.is_required_and_missing()); + + let file = fs1.fetch_file_sync( + &en_us, + &FTL_RESOURCE_PRESENT.to_resource_id(ResourceType::Required), + false, + ); + assert!(file.is_some()); + assert!(!file.is_none()); + assert!(!file.is_required_and_missing()); + + let file = fs1.fetch_file_sync( + &en_us, + &FTL_RESOURCE_PRESENT.to_resource_id(ResourceType::Optional), + false, + ); + assert!(file.is_some()); + assert!(!file.is_none()); + assert!(!file.is_required_and_missing()); + + let file = fs1.fetch_file_sync(&en_us, &FTL_RESOURCE_MISSING.into(), false); + assert!(!file.is_some()); + assert!(file.is_none()); + assert!(file.is_required_and_missing()); + + let file = fs1.fetch_file_sync( + &en_us, + &FTL_RESOURCE_MISSING.to_resource_id(ResourceType::Required), + false, + ); + assert!(!file.is_some()); + assert!(file.is_none()); + assert!(file.is_required_and_missing()); + + let file = fs1.fetch_file_sync( + &en_us, + &FTL_RESOURCE_MISSING.to_resource_id(ResourceType::Optional), + false, + ); + assert!(!file.is_some()); + assert!(file.is_none()); + assert!(!file.is_required_and_missing()); +} + +#[tokio::test] +async fn test_fetch_async() { + let fetcher = TestFileFetcher::new(); + let en_us: LanguageIdentifier = "en-US".parse().unwrap(); + + let fs1 = + fetcher.get_test_file_source("toolkit", None, vec![en_us.clone()], "toolkit/{locale}/"); + + let file = fs1.fetch_file(&en_us, &FTL_RESOURCE_PRESENT.into()).await; + assert!(file.is_some()); + assert!(!file.is_none()); + assert!(!file.is_required_and_missing()); + + let file = fs1 + .fetch_file( + &en_us, + &FTL_RESOURCE_PRESENT.to_resource_id(ResourceType::Required), + ) + .await; + assert!(file.is_some()); + assert!(!file.is_none()); + assert!(!file.is_required_and_missing()); + + let file = fs1 + .fetch_file( + &en_us, + &FTL_RESOURCE_PRESENT.to_resource_id(ResourceType::Optional), + ) + .await; + assert!(file.is_some()); + assert!(!file.is_none()); + assert!(!file.is_required_and_missing()); + + let file = fs1.fetch_file(&en_us, &FTL_RESOURCE_MISSING.into()).await; + assert!(!file.is_some()); + assert!(file.is_none()); + assert!(file.is_required_and_missing()); + + let file = fs1 + .fetch_file( + &en_us, + &FTL_RESOURCE_MISSING.to_resource_id(ResourceType::Required), + ) + .await; + assert!(!file.is_some()); + assert!(file.is_none()); + assert!(file.is_required_and_missing()); + + let file = fs1 + .fetch_file( + &en_us, + &FTL_RESOURCE_MISSING.to_resource_id(ResourceType::Optional), + ) + .await; + assert!(!file.is_some()); + assert!(file.is_none()); + assert!(!file.is_required_and_missing()); +} + +#[tokio::test] +async fn test_fetch_sync_2_async() { + let fetcher = TestFileFetcher::new(); + let en_us: LanguageIdentifier = "en-US".parse().unwrap(); + + let fs1 = + fetcher.get_test_file_source("toolkit", None, vec![en_us.clone()], "toolkit/{locale}/"); + + assert!(fs1 + .fetch_file_sync(&en_us, &FTL_RESOURCE_PRESENT.into(), false) + .is_some()); + assert!(fs1 + .fetch_file(&en_us, &FTL_RESOURCE_PRESENT.into()) + .await + .is_some()); + assert!(fs1 + .fetch_file_sync(&en_us, &FTL_RESOURCE_PRESENT.into(), false) + .is_some()); +} + +#[tokio::test] +async fn test_fetch_async_2_sync() { + let fetcher = TestFileFetcher::new(); + let en_us: LanguageIdentifier = "en-US".parse().unwrap(); + + let fs1 = + fetcher.get_test_file_source("toolkit", None, vec![en_us.clone()], "toolkit/{locale}/"); + + assert!(fs1 + .fetch_file(&en_us, &FTL_RESOURCE_PRESENT.into()) + .await + .is_some()); + assert!(fs1 + .fetch_file_sync(&en_us, &FTL_RESOURCE_PRESENT.into(), false) + .is_some()); +} + +#[test] +fn test_fetch_has_value_required_sync() { + let fetcher = TestFileFetcher::new(); + let en_us: LanguageIdentifier = "en-US".parse().unwrap(); + let path = FTL_RESOURCE_PRESENT.into(); + let path_missing = FTL_RESOURCE_MISSING.into(); + + let fs1 = + fetcher.get_test_file_source("toolkit", None, vec![en_us.clone()], "toolkit/{locale}/"); + + assert_eq!(fs1.has_file(&en_us, &path), None); + assert!(fs1.fetch_file_sync(&en_us, &path, false).is_some()); + assert_eq!(fs1.has_file(&en_us, &path), Some(true)); + + assert_eq!(fs1.has_file(&en_us, &path_missing), None); + assert!(fs1.fetch_file_sync(&en_us, &path_missing, false).is_none()); + assert_eq!(fs1.has_file(&en_us, &path_missing), Some(false)); +} + +#[test] +fn test_fetch_has_value_optional_sync() { + let fetcher = TestFileFetcher::new(); + let en_us: LanguageIdentifier = "en-US".parse().unwrap(); + let path = FTL_RESOURCE_PRESENT.to_resource_id(ResourceType::Optional); + let path_missing = FTL_RESOURCE_MISSING.to_resource_id(ResourceType::Optional); + + let fs1 = + fetcher.get_test_file_source("toolkit", None, vec![en_us.clone()], "toolkit/{locale}/"); + + assert_eq!(fs1.has_file(&en_us, &path), None); + assert!(fs1.fetch_file_sync(&en_us, &path, false).is_some()); + assert_eq!(fs1.has_file(&en_us, &path), Some(true)); + + assert_eq!(fs1.has_file(&en_us, &path_missing), None); + assert!(fs1.fetch_file_sync(&en_us, &path_missing, false).is_none()); + assert_eq!(fs1.has_file(&en_us, &path_missing), Some(false)); +} + +#[tokio::test] +async fn test_fetch_has_value_required_async() { + let fetcher = TestFileFetcher::new(); + let en_us: LanguageIdentifier = "en-US".parse().unwrap(); + let path = FTL_RESOURCE_PRESENT.into(); + let path_missing = FTL_RESOURCE_MISSING.into(); + + let fs1 = + fetcher.get_test_file_source("toolkit", None, vec![en_us.clone()], "toolkit/{locale}/"); + + assert_eq!(fs1.has_file(&en_us, &path), None); + assert!(fs1.fetch_file(&en_us, &path).await.is_some()); + println!("Completed"); + assert_eq!(fs1.has_file(&en_us, &path), Some(true)); + + assert_eq!(fs1.has_file(&en_us, &path_missing), None); + + assert!(fs1.fetch_file(&en_us, &path_missing).await.is_none()); + assert!(fs1 + .fetch_file(&en_us, &path_missing) + .await + .is_required_and_missing()); + + assert_eq!(fs1.has_file(&en_us, &path_missing), Some(false)); + + assert!(fs1.fetch_file_sync(&en_us, &path_missing, false).is_none()); + assert!(fs1 + .fetch_file_sync(&en_us, &path_missing, false) + .is_required_and_missing()); +} + +#[tokio::test] +async fn test_fetch_has_value_optional_async() { + let fetcher = TestFileFetcher::new(); + let en_us: LanguageIdentifier = "en-US".parse().unwrap(); + let path = FTL_RESOURCE_PRESENT.to_resource_id(ResourceType::Optional); + let path_missing = FTL_RESOURCE_MISSING.to_resource_id(ResourceType::Optional); + + let fs1 = + fetcher.get_test_file_source("toolkit", None, vec![en_us.clone()], "toolkit/{locale}/"); + + assert_eq!(fs1.has_file(&en_us, &path), None); + assert!(fs1.fetch_file(&en_us, &path).await.is_some()); + println!("Completed"); + assert_eq!(fs1.has_file(&en_us, &path), Some(true)); + + assert_eq!(fs1.has_file(&en_us, &path_missing), None); + assert!(fs1.fetch_file(&en_us, &path_missing).await.is_none()); + assert!(!fs1 + .fetch_file(&en_us, &path_missing) + .await + .is_required_and_missing()); + + assert_eq!(fs1.has_file(&en_us, &path_missing), Some(false)); + + assert!(fs1.fetch_file_sync(&en_us, &path_missing, false).is_none()); + assert!(!fs1 + .fetch_file_sync(&en_us, &path_missing, false) + .is_required_and_missing()); +} + +#[tokio::test] +async fn test_fetch_async_consecutive() { + let fetcher = TestFileFetcher::new(); + let en_us: LanguageIdentifier = "en-US".parse().unwrap(); + + let fs1 = + fetcher.get_test_file_source("toolkit", None, vec![en_us.clone()], "toolkit/{locale}/"); + + let results = join_all(vec![ + fs1.fetch_file(&en_us, &FTL_RESOURCE_PRESENT.into()), + fs1.fetch_file(&en_us, &FTL_RESOURCE_PRESENT.into()), + ]) + .await; + assert!(results[0].is_some()); + assert!(results[1].is_some()); + + assert!(fs1 + .fetch_file(&en_us, &FTL_RESOURCE_PRESENT.into()) + .await + .is_some()); +} + +#[test] +fn test_indexed() { + let fetcher = TestFileFetcher::new(); + let en_us: LanguageIdentifier = "en-US".parse().unwrap(); + let path = FTL_RESOURCE_PRESENT; + let path_missing = FTL_RESOURCE_MISSING; + + let fs1 = fetcher.get_test_file_source_with_index( + "toolkit", + None, + vec![en_us.clone()], + "toolkit/{locale}/", + vec!["toolkit/en-US/toolkit/global/textActions.ftl"], + ); + + assert_eq!(fs1.has_file(&en_us, &path.into()), Some(true)); + assert!(fs1.fetch_file_sync(&en_us, &path.into(), false).is_some()); + assert_eq!(fs1.has_file(&en_us, &path.into()), Some(true)); + + assert_eq!(fs1.has_file(&en_us, &path_missing.into()), Some(false)); + assert!(fs1 + .fetch_file_sync(&en_us, &path_missing.into(), false) + .is_none()); + assert_eq!(fs1.has_file(&en_us, &path_missing.into()), Some(false)); +} diff --git a/intl/l10n/rust/l10nregistry-tests/tests/tokio.rs b/intl/l10n/rust/l10nregistry-tests/tests/tokio.rs new file mode 100644 index 0000000000..0f404c3a08 --- /dev/null +++ b/intl/l10n/rust/l10nregistry-tests/tests/tokio.rs @@ -0,0 +1,65 @@ +use l10nregistry_tests::TestFileFetcher; +use unic_langid::LanguageIdentifier; + +static FTL_RESOURCE_PRESENT: &str = "toolkit/global/textActions.ftl"; +static FTL_RESOURCE_MISSING: &str = "missing.ftl"; + +#[tokio::test] +async fn file_source_fetch() { + let fetcher = TestFileFetcher::new(); + let en_us: LanguageIdentifier = "en-US".parse().unwrap(); + let fs1 = + fetcher.get_test_file_source("toolkit", None, vec![en_us.clone()], "toolkit/{locale}/"); + + let file = fs1.fetch_file(&en_us, &FTL_RESOURCE_PRESENT.into()).await; + assert!(file.is_some()); +} + +#[tokio::test] +async fn file_source_fetch_missing() { + let fetcher = TestFileFetcher::new(); + let en_us: LanguageIdentifier = "en-US".parse().unwrap(); + let fs1 = + fetcher.get_test_file_source("toolkit", None, vec![en_us.clone()], "toolkit/{locale}/"); + + let file = fs1.fetch_file(&en_us, &FTL_RESOURCE_MISSING.into()).await; + assert!(file.is_none()); +} + +#[tokio::test] +async fn file_source_already_loaded() { + let fetcher = TestFileFetcher::new(); + let en_us: LanguageIdentifier = "en-US".parse().unwrap(); + let fs1 = + fetcher.get_test_file_source("toolkit", None, vec![en_us.clone()], "toolkit/{locale}/"); + + let file = fs1.fetch_file(&en_us, &FTL_RESOURCE_PRESENT.into()).await; + assert!(file.is_some()); + let file = fs1.fetch_file(&en_us, &FTL_RESOURCE_PRESENT.into()).await; + assert!(file.is_some()); +} + +#[tokio::test] +async fn file_source_concurrent() { + let fetcher = TestFileFetcher::new(); + let en_us: LanguageIdentifier = "en-US".parse().unwrap(); + let fs1 = + fetcher.get_test_file_source("toolkit", None, vec![en_us.clone()], "toolkit/{locale}/"); + + let file1 = fs1.fetch_file(&en_us, &FTL_RESOURCE_PRESENT.into()); + let file2 = fs1.fetch_file(&en_us, &FTL_RESOURCE_PRESENT.into()); + assert!(file1.await.is_some()); + assert!(file2.await.is_some()); +} + +#[test] +fn file_source_sync_after_async_fail() { + let fetcher = TestFileFetcher::new(); + let en_us: LanguageIdentifier = "en-US".parse().unwrap(); + let fs1 = + fetcher.get_test_file_source("toolkit", None, vec![en_us.clone()], "toolkit/{locale}/"); + + let _ = fs1.fetch_file(&en_us, &FTL_RESOURCE_PRESENT.into()); + let file2 = fs1.fetch_file_sync(&en_us, &FTL_RESOURCE_PRESENT.into(), true); + assert!(file2.is_some()); +} |