// Testing of the `diagnostic` attr used by derive(Diagnostic) use miette::{Diagnostic, LabeledSpan, NamedSource, SourceSpan}; use thiserror::Error; #[test] fn enum_uses_base_attr() { #[derive(Debug, Diagnostic, Error)] #[error("oops!")] #[diagnostic(code(error::on::base))] enum MyBad { Only { #[source_code] src: NamedSource, #[label("this bit here")] highlight: SourceSpan, }, } let src = "source\n text\n here".to_string(); let err = MyBad::Only { src: NamedSource::new("bad_file.rs", src), highlight: (9, 4).into(), }; assert_eq!(err.code().unwrap().to_string(), "error::on::base"); } #[test] fn enum_uses_variant_attr() { #[derive(Debug, Diagnostic, Error)] #[error("oops!")] enum MyBad { #[diagnostic(code(error::on::variant))] Only { #[source_code] src: NamedSource, #[label("this bit here")] highlight: SourceSpan, }, } let src = "source\n text\n here".to_string(); let err = MyBad::Only { src: NamedSource::new("bad_file.rs", src), highlight: (9, 4).into(), }; assert_eq!(err.code().unwrap().to_string(), "error::on::variant"); } #[test] fn multiple_attrs_allowed_on_item() { #[derive(Debug, Diagnostic, Error)] #[error("oops!")] #[diagnostic(code(error::on::base))] #[diagnostic(help("try doing it correctly"))] enum MyBad { Only { #[source_code] src: NamedSource, #[label("this bit here")] highlight: SourceSpan, }, } let src = "source\n text\n here".to_string(); let err = MyBad::Only { src: NamedSource::new("bad_file.rs", src), highlight: (9, 4).into(), }; assert_eq!(err.code().unwrap().to_string(), "error::on::base"); assert_eq!(err.help().unwrap().to_string(), "try doing it correctly"); } #[test] fn multiple_attrs_allowed_on_variant() { #[derive(Debug, Diagnostic, Error)] #[error("oops!")] enum MyBad { #[diagnostic(code(error::on::variant))] #[diagnostic(help("try doing it correctly"))] Only { #[source_code] src: NamedSource, #[label("this bit here")] highlight: SourceSpan, }, } let src = "source\n text\n here".to_string(); let err = MyBad::Only { src: NamedSource::new("bad_file.rs", src), highlight: (9, 4).into(), }; assert_eq!(err.code().unwrap().to_string(), "error::on::variant"); assert_eq!(err.help().unwrap().to_string(), "try doing it correctly"); } #[test] fn attrs_can_be_split_between_item_and_variants() { #[derive(Debug, Diagnostic, Error)] #[error("oops!")] #[diagnostic(code(error::on::base))] enum MyBad { #[diagnostic(help("try doing it correctly"))] #[diagnostic(url("https://example.com/foo/bar"))] Only { #[source_code] src: NamedSource, #[label("this bit here")] highlight: SourceSpan, }, } let src = "source\n text\n here".to_string(); let err = MyBad::Only { src: NamedSource::new("bad_file.rs", src), highlight: (9, 4).into(), }; assert_eq!(err.code().unwrap().to_string(), "error::on::base"); assert_eq!(err.help().unwrap().to_string(), "try doing it correctly"); assert_eq!( err.url().unwrap().to_string(), "https://example.com/foo/bar".to_string() ); } #[test] fn attr_not_required() { #[derive(Debug, Diagnostic, Error)] #[error("oops!")] enum MyBad { Only { #[source_code] src: NamedSource, #[label("this bit here")] highlight: SourceSpan, }, } let src = "source\n text\n here".to_string(); let err = MyBad::Only { src: NamedSource::new("bad_file.rs", src), highlight: (9, 4).into(), }; let err_span = err.labels().unwrap().next().unwrap(); let expectation = LabeledSpan::new(Some("this bit here".into()), 9usize, 4usize); assert_eq!(err_span, expectation); } fn assert_impl_diagnostic() {} #[test] fn transparent_generic() { #[derive(Debug, Diagnostic, Error)] enum Combined { #[error(transparent)] #[diagnostic(transparent)] Other(T), #[error("foo")] Custom, } std::hint::black_box(Combined::::Other(1)); std::hint::black_box(Combined::::Custom); assert_impl_diagnostic::>(); } #[test] fn generic_label() { #[derive(Debug, Diagnostic, Error)] #[error("foo")] struct Combined { #[label] label: T, } assert_impl_diagnostic::>(); assert_impl_diagnostic::>(); } #[test] fn generic_source_code() { #[derive(Debug, Diagnostic, Error)] #[error("foo")] struct Combined { #[source_code] label: T, } assert_impl_diagnostic::>(); } #[test] fn generic_optional_source_code() { #[derive(Debug, Diagnostic, Error)] #[error("foo")] struct Combined { #[source_code] label: Option, } assert_impl_diagnostic::>(); } #[test] fn generic_label_primary() { #[derive(Debug, Diagnostic, Error)] #[error("foo")] struct Combined { #[label(primary)] label: T, } assert_impl_diagnostic::>(); assert_impl_diagnostic::>(); } #[test] fn generic_label_collection() { #[derive(Debug, Diagnostic, Error)] #[error("foo")] struct Combined { #[label(collection)] label: Vec, } assert_impl_diagnostic::>(); assert_impl_diagnostic::>(); } #[test] fn generic_label_generic_collection() { #[derive(Debug, Diagnostic, Error)] #[error("foo")] struct Combined { #[label(collection)] label: T, } assert_impl_diagnostic::>>(); assert_impl_diagnostic::>>(); } #[test] fn generic_related() { #[derive(Debug, Diagnostic, Error)] #[error("foo")] struct Combined { #[related] label: Vec, } assert_impl_diagnostic::>(); } #[test] fn generic_diagnostic_source() { #[derive(Debug, Diagnostic, Error)] enum Combined { #[error(transparent)] Other(#[diagnostic_source] T), #[error("foo")] Custom, } std::hint::black_box(Combined::::Other(1)); std::hint::black_box(Combined::::Custom); assert_impl_diagnostic::>(); } #[test] fn generic_not_influencing_default() { #[derive(Debug, Diagnostic, Error)] enum Combined { #[error("bar")] Other(T), #[error("foo")] Custom, } std::hint::black_box(Combined::::Other(1)); std::hint::black_box(Combined::::Custom); assert_impl_diagnostic::>(); }