diff --git a/src/eyreish/wrapper.rs b/src/eyreish/wrapper.rs index 91a5ef3e..6e65eb72 100644 --- a/src/eyreish/wrapper.rs +++ b/src/eyreish/wrapper.rs @@ -163,7 +163,7 @@ impl Diagnostic for WithSourceCode { } fn source_code(&self) -> Option<&dyn miette::SourceCode> { - Some(&self.source_code) + self.error.source_code().or(Some(&self.source_code)) } fn related<'a>(&'a self) -> Option + 'a>> { @@ -197,7 +197,7 @@ impl Diagnostic for WithSourceCode { } fn source_code(&self) -> Option<&dyn miette::SourceCode> { - Some(&self.source_code) + self.error.source_code().or(Some(&self.source_code)) } fn related<'a>(&'a self) -> Option + 'a>> { @@ -232,3 +232,88 @@ impl StdError for WithSourceCode { self.error.source() } } + +#[cfg(test)] +mod tests { + use thiserror::Error; + + use crate::{Diagnostic, LabeledSpan, Report, SourceCode, SourceSpan}; + + #[derive(Error, Debug)] + #[error("inner")] + struct Inner { + pub(crate) at: SourceSpan, + pub(crate) source_code: Option, + } + + impl Diagnostic for Inner { + fn labels(&self) -> Option + '_>> { + Some(Box::new(std::iter::once(LabeledSpan::underline(self.at)))) + } + + fn source_code(&self) -> Option<&dyn SourceCode> { + self.source_code.as_ref().map(|s| s as _) + } + } + + #[derive(Error, Debug)] + #[error("outer")] + struct Outer { + pub(crate) errors: Vec, + } + + impl Diagnostic for Outer { + fn related<'a>(&'a self) -> Option + 'a>> { + Some(Box::new(self.errors.iter().map(|e| e as _))) + } + } + + #[test] + fn no_override() { + let inner_source = "hello world"; + let outer_source = "abc"; + + let report = Report::from(Inner { + at: (0..5).into(), + source_code: Some(inner_source.to_string()), + }) + .with_source_code(outer_source.to_string()); + + let underlined = String::from_utf8( + report + .source_code() + .unwrap() + .read_span(&(0..5).into(), 0, 0) + .unwrap() + .data() + .to_vec(), + ) + .unwrap(); + assert_eq!(underlined, "hello"); + } + + #[test] + #[cfg(feature = "fancy")] + fn two_source_codes() { + let inner_source = "hello world"; + let outer_source = "abc"; + + let report = Report::from(Outer { + errors: vec![ + Inner { + at: (0..5).into(), + source_code: Some(inner_source.to_string()), + }, + Inner { + at: (1..2).into(), + source_code: None, + }, + ], + }) + .with_source_code(outer_source.to_string()); + + let message = format!("{:?}", report); + assert!(message.contains(inner_source)); + assert!(message.contains(outer_source)); + } +}