use crate::error::{TranslateError, TranslateErrorKind}; use crate::fluent_bundle::*; use crate::translation::Translate; use crate::FluentBundle; use rustc_data_structures::sync::{IntoDynSyncSend, Lrc}; use rustc_error_messages::fluent_bundle::resolver::errors::{ReferenceKind, ResolverError}; use rustc_error_messages::langid; use rustc_error_messages::DiagnosticMessage; struct Dummy { bundle: FluentBundle, } impl Translate for Dummy { fn fluent_bundle(&self) -> Option<&Lrc> { None } fn fallback_fluent_bundle(&self) -> &FluentBundle { &self.bundle } } fn make_dummy(ftl: &'static str) -> Dummy { let resource = FluentResource::try_new(ftl.into()).expect("Failed to parse an FTL string."); let langid_en = langid!("en-US"); #[cfg(parallel_compiler)] let mut bundle: FluentBundle = IntoDynSyncSend(crate::fluent_bundle::bundle::FluentBundle::new_concurrent(vec![ langid_en, ])); #[cfg(not(parallel_compiler))] let mut bundle: FluentBundle = IntoDynSyncSend(crate::fluent_bundle::bundle::FluentBundle::new(vec![langid_en])); bundle.add_resource(resource).expect("Failed to add FTL resources to the bundle."); Dummy { bundle } } #[test] fn wellformed_fluent() { let dummy = make_dummy("mir_build_borrow_of_moved_value = borrow of moved value .label = value moved into `{$name}` here .occurs_because_label = move occurs because `{$name}` has type `{$ty}` which does not implement the `Copy` trait .value_borrowed_label = value borrowed here after move .suggestion = borrow this binding in the pattern to avoid moving the value"); let mut args = FluentArgs::new(); args.set("name", "Foo"); args.set("ty", "std::string::String"); { let message = DiagnosticMessage::FluentIdentifier( "mir_build_borrow_of_moved_value".into(), Some("suggestion".into()), ); assert_eq!( dummy.translate_message(&message, &args).unwrap(), "borrow this binding in the pattern to avoid moving the value" ); } { let message = DiagnosticMessage::FluentIdentifier( "mir_build_borrow_of_moved_value".into(), Some("value_borrowed_label".into()), ); assert_eq!( dummy.translate_message(&message, &args).unwrap(), "value borrowed here after move" ); } { let message = DiagnosticMessage::FluentIdentifier( "mir_build_borrow_of_moved_value".into(), Some("occurs_because_label".into()), ); assert_eq!( dummy.translate_message(&message, &args).unwrap(), "move occurs because `\u{2068}Foo\u{2069}` has type `\u{2068}std::string::String\u{2069}` which does not implement the `Copy` trait" ); { let message = DiagnosticMessage::FluentIdentifier( "mir_build_borrow_of_moved_value".into(), Some("label".into()), ); assert_eq!( dummy.translate_message(&message, &args).unwrap(), "value moved into `\u{2068}Foo\u{2069}` here" ); } } } #[test] fn misformed_fluent() { let dummy = make_dummy("mir_build_borrow_of_moved_value = borrow of moved value .label = value moved into `{name}` here .occurs_because_label = move occurs because `{$oops}` has type `{$ty}` which does not implement the `Copy` trait .suggestion = borrow this binding in the pattern to avoid moving the value"); let mut args = FluentArgs::new(); args.set("name", "Foo"); args.set("ty", "std::string::String"); { let message = DiagnosticMessage::FluentIdentifier( "mir_build_borrow_of_moved_value".into(), Some("value_borrowed_label".into()), ); let err = dummy.translate_message(&message, &args).unwrap_err(); assert!( matches!( &err, TranslateError::Two { primary: box TranslateError::One { kind: TranslateErrorKind::PrimaryBundleMissing, .. }, fallback: box TranslateError::One { kind: TranslateErrorKind::AttributeMissing { attr: "value_borrowed_label" }, .. } } ), "{err:#?}" ); assert_eq!( format!("{err}"), "failed while formatting fluent string `mir_build_borrow_of_moved_value`: \nthe attribute `value_borrowed_label` was missing\nhelp: add `.value_borrowed_label = `\n" ); } { let message = DiagnosticMessage::FluentIdentifier( "mir_build_borrow_of_moved_value".into(), Some("label".into()), ); let err = dummy.translate_message(&message, &args).unwrap_err(); if let TranslateError::Two { primary: box TranslateError::One { kind: TranslateErrorKind::PrimaryBundleMissing, .. }, fallback: box TranslateError::One { kind: TranslateErrorKind::Fluent { errs }, .. }, } = &err && let [FluentError::ResolverError(ResolverError::Reference( ReferenceKind::Message { id, .. } | ReferenceKind::Variable { id, .. }, ))] = &**errs && id == "name" {} else { panic!("{err:#?}") }; assert_eq!( format!("{err}"), "failed while formatting fluent string `mir_build_borrow_of_moved_value`: \nargument `name` exists but was not referenced correctly\nhelp: try using `{$name}` instead\n" ); } { let message = DiagnosticMessage::FluentIdentifier( "mir_build_borrow_of_moved_value".into(), Some("occurs_because_label".into()), ); let err = dummy.translate_message(&message, &args).unwrap_err(); if let TranslateError::Two { primary: box TranslateError::One { kind: TranslateErrorKind::PrimaryBundleMissing, .. }, fallback: box TranslateError::One { kind: TranslateErrorKind::Fluent { errs }, .. }, } = &err && let [FluentError::ResolverError(ResolverError::Reference( ReferenceKind::Message { id, .. } | ReferenceKind::Variable { id, .. }, ))] = &**errs && id == "oops" {} else { panic!("{err:#?}") }; assert_eq!( format!("{err}"), "failed while formatting fluent string `mir_build_borrow_of_moved_value`: \nthe fluent string has an argument `oops` that was not found.\nhelp: the arguments `name` and `ty` are available\n" ); } }