diff options
Diffstat (limited to 'intl/l10n/rust/l10nregistry-rs/src/testing.rs')
-rw-r--r-- | intl/l10n/rust/l10nregistry-rs/src/testing.rs | 322 |
1 files changed, 322 insertions, 0 deletions
diff --git a/intl/l10n/rust/l10nregistry-rs/src/testing.rs b/intl/l10n/rust/l10nregistry-rs/src/testing.rs new file mode 100644 index 0000000000..f1ff47e2db --- /dev/null +++ b/intl/l10n/rust/l10nregistry-rs/src/testing.rs @@ -0,0 +1,322 @@ +use crate::env::ErrorReporter; +use crate::errors::L10nRegistryError; +use crate::fluent::FluentBundle; +use crate::registry::BundleAdapter; +use crate::registry::L10nRegistry; +use crate::source::FileFetcher; +use async_trait::async_trait; +use fluent_fallback::{env::LocalesProvider, types::ResourceId}; +use fluent_testing::MockFileSystem; +use std::cell::RefCell; +use std::rc::Rc; +use unic_langid::LanguageIdentifier; + +pub struct RegistrySetup { + pub name: String, + pub file_sources: Vec<FileSource>, + pub locales: Vec<LanguageIdentifier>, +} + +pub struct FileSource { + pub name: String, + pub metasource: String, + pub locales: Vec<LanguageIdentifier>, + pub path_scheme: String, +} + +#[derive(Clone)] +pub struct MockBundleAdapter; + +impl BundleAdapter for MockBundleAdapter { + fn adapt_bundle(&self, _bundle: &mut FluentBundle) {} +} + +impl FileSource { + pub fn new<S>( + name: S, + metasource: Option<S>, + locales: Vec<LanguageIdentifier>, + path_scheme: S, + ) -> Self + where + S: ToString, + { + let metasource = match metasource { + Some(s) => s.to_string(), + None => String::default(), + }; + + Self { + name: name.to_string(), + metasource, + locales, + path_scheme: path_scheme.to_string(), + } + } +} + +impl RegistrySetup { + pub fn new( + name: &str, + file_sources: Vec<FileSource>, + locales: Vec<LanguageIdentifier>, + ) -> Self { + Self { + name: name.to_string(), + file_sources, + locales, + } + } +} + +impl From<fluent_testing::scenarios::structs::Scenario> for RegistrySetup { + fn from(s: fluent_testing::scenarios::structs::Scenario) -> Self { + Self { + name: s.name, + file_sources: s + .file_sources + .into_iter() + .map(|source| { + FileSource::new( + source.name, + None, + source + .locales + .into_iter() + .map(|l| l.parse().unwrap()) + .collect(), + source.path_scheme, + ) + }) + .collect(), + locales: s + .locales + .into_iter() + .map(|loc| loc.parse().unwrap()) + .collect(), + } + } +} + +impl From<&fluent_testing::scenarios::structs::Scenario> for RegistrySetup { + fn from(s: &fluent_testing::scenarios::structs::Scenario) -> Self { + Self { + name: s.name.clone(), + file_sources: s + .file_sources + .iter() + .map(|source| { + FileSource::new( + source.name.clone(), + None, + source.locales.iter().map(|l| l.parse().unwrap()).collect(), + source.path_scheme.clone(), + ) + }) + .collect(), + locales: s.locales.iter().map(|loc| loc.parse().unwrap()).collect(), + } + } +} + +#[derive(Default)] +struct InnerFileFetcher { + fs: MockFileSystem, +} + +#[derive(Clone)] +pub struct TestFileFetcher { + inner: Rc<InnerFileFetcher>, +} + +impl TestFileFetcher { + pub fn new() -> Self { + Self { + inner: Rc::new(InnerFileFetcher::default()), + } + } + + pub fn get_test_file_source( + &self, + name: &str, + metasource: Option<String>, + locales: Vec<LanguageIdentifier>, + path: &str, + ) -> crate::source::FileSource { + crate::source::FileSource::new( + name.to_string(), + metasource, + locales, + path.to_string(), + Default::default(), + self.clone(), + ) + } + + pub fn get_test_file_source_with_index( + &self, + name: &str, + metasource: Option<String>, + locales: Vec<LanguageIdentifier>, + path: &str, + index: Vec<&str>, + ) -> crate::source::FileSource { + crate::source::FileSource::new_with_index( + name.to_string(), + metasource, + locales, + path.to_string(), + Default::default(), + self.clone(), + index.into_iter().map(|s| s.to_string()).collect(), + ) + } + + pub fn get_registry<S>(&self, setup: S) -> L10nRegistry<TestEnvironment, MockBundleAdapter> + where + S: Into<RegistrySetup>, + { + self.get_registry_and_environment(setup).1 + } + + pub fn get_registry_and_environment<S>( + &self, + setup: S, + ) -> ( + TestEnvironment, + L10nRegistry<TestEnvironment, MockBundleAdapter>, + ) + where + S: Into<RegistrySetup>, + { + let setup: RegistrySetup = setup.into(); + let provider = TestEnvironment::new(setup.locales); + + let reg = L10nRegistry::with_provider(provider.clone()); + let sources = setup + .file_sources + .into_iter() + .map(|source| { + let mut s = self.get_test_file_source( + &source.name, + Some(source.metasource), + source.locales, + &source.path_scheme, + ); + s.set_reporter(provider.clone()); + s + }) + .collect(); + reg.register_sources(sources).unwrap(); + (provider, reg) + } + + pub fn get_registry_and_environment_with_adapter<S, B>( + &self, + setup: S, + bundle_adapter: B, + ) -> (TestEnvironment, L10nRegistry<TestEnvironment, B>) + where + S: Into<RegistrySetup>, + B: BundleAdapter, + { + let setup: RegistrySetup = setup.into(); + let provider = TestEnvironment::new(setup.locales); + + let mut reg = L10nRegistry::with_provider(provider.clone()); + let sources = setup + .file_sources + .into_iter() + .map(|source| { + let mut s = self.get_test_file_source( + &source.name, + None, + source.locales, + &source.path_scheme, + ); + s.set_reporter(provider.clone()); + s + }) + .collect(); + reg.register_sources(sources).unwrap(); + reg.set_bundle_adapter(bundle_adapter) + .expect("Failed to set bundle adapter."); + (provider, reg) + } +} + +#[async_trait(?Send)] +impl FileFetcher for TestFileFetcher { + fn fetch_sync(&self, resource_id: &ResourceId) -> std::io::Result<String> { + self.inner.fs.get_test_file_sync(&resource_id.value) + } + + async fn fetch(&self, resource_id: &ResourceId) -> std::io::Result<String> { + self.inner.fs.get_test_file_async(&resource_id.value).await + } +} + +pub enum ErrorStrategy { + Panic, + Report, + Nothing, +} + +pub struct InnerTestEnvironment { + locales: Vec<LanguageIdentifier>, + errors: Vec<L10nRegistryError>, + error_strategy: ErrorStrategy, +} + +#[derive(Clone)] +pub struct TestEnvironment { + inner: Rc<RefCell<InnerTestEnvironment>>, +} + +impl TestEnvironment { + pub fn new(locales: Vec<LanguageIdentifier>) -> Self { + Self { + inner: Rc::new(RefCell::new(InnerTestEnvironment { + locales, + errors: vec![], + error_strategy: ErrorStrategy::Report, + })), + } + } + + pub fn set_locales(&self, locales: Vec<LanguageIdentifier>) { + self.inner.borrow_mut().locales = locales; + } + + pub fn errors(&self) -> Vec<L10nRegistryError> { + self.inner.borrow().errors.clone() + } + + pub fn clear_errors(&self) { + self.inner.borrow_mut().errors.clear() + } +} + +impl LocalesProvider for TestEnvironment { + type Iter = std::vec::IntoIter<LanguageIdentifier>; + + fn locales(&self) -> Self::Iter { + self.inner.borrow().locales.clone().into_iter() + } +} + +impl ErrorReporter for TestEnvironment { + fn report_errors(&self, errors: Vec<L10nRegistryError>) { + match self.inner.borrow().error_strategy { + ErrorStrategy::Panic => { + panic!("Errors: {:#?}", errors); + } + ErrorStrategy::Report => { + #[cfg(test)] // Don't let printing affect benchmarks + eprintln!("Errors: {:#?}", errors); + } + ErrorStrategy::Nothing => {} + } + self.inner.borrow_mut().errors.extend(errors); + } +} |