mirror of https://github.com/zkat/miette.git
914 lines
27 KiB
Rust
914 lines
27 KiB
Rust
mod json_report_handler {
|
|
use miette::{Diagnostic, MietteError, NamedSource, Report, SourceSpan};
|
|
|
|
use miette::JSONReportHandler;
|
|
|
|
use thiserror::Error;
|
|
|
|
fn fmt_report(diag: Report) -> String {
|
|
let mut out = String::new();
|
|
JSONReportHandler::new()
|
|
.render_report(&mut out, diag)
|
|
.unwrap();
|
|
out
|
|
}
|
|
|
|
#[test]
|
|
fn single_line_with_wide_char() -> Result<(), MietteError> {
|
|
#[derive(Debug, Diagnostic, Error)]
|
|
#[error("oops!")]
|
|
#[diagnostic(code(oops::my::bad), help("try doing it better next time?"))]
|
|
struct MyBad {
|
|
#[source_code]
|
|
src: NamedSource<String>,
|
|
#[label("this bit here")]
|
|
highlight: SourceSpan,
|
|
}
|
|
|
|
let src = "source\n 👼🏼text\n here".to_string();
|
|
let err = MyBad {
|
|
src: NamedSource::new("bad_file.rs", src),
|
|
highlight: (9, 6).into(),
|
|
};
|
|
let out = fmt_report(err.into());
|
|
println!("Error: {}", out);
|
|
let expected: String = r#"
|
|
{
|
|
"message": "oops!",
|
|
"code": "oops::my::bad",
|
|
"severity": "error",
|
|
"causes": [],
|
|
"help": "try doing it better next time?",
|
|
"filename": "bad_file.rs",
|
|
"labels": [
|
|
{
|
|
"label": "this bit here",
|
|
"span": {
|
|
"offset": 9,
|
|
"length": 6
|
|
}
|
|
}
|
|
],
|
|
"related": []
|
|
}"#
|
|
.lines()
|
|
.map(|s| s.trim_matches(|c| c == ' ' || c == '\n'))
|
|
.collect();
|
|
assert_eq!(expected, out);
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn single_line_highlight() -> Result<(), MietteError> {
|
|
#[derive(Debug, Diagnostic, Error)]
|
|
#[error("oops!")]
|
|
#[diagnostic(code(oops::my::bad), help("try doing it better next time?"))]
|
|
struct MyBad {
|
|
#[source_code]
|
|
src: NamedSource<String>,
|
|
#[label("this bit here")]
|
|
highlight: SourceSpan,
|
|
}
|
|
|
|
let src = "source\n text\n here".to_string();
|
|
let err = MyBad {
|
|
src: NamedSource::new("bad_file.rs", src),
|
|
highlight: (9, 4).into(),
|
|
};
|
|
let out = fmt_report(err.into());
|
|
println!("Error: {}", out);
|
|
let expected: String = r#"
|
|
{
|
|
"message": "oops!",
|
|
"code": "oops::my::bad",
|
|
"severity": "error",
|
|
"causes": [],
|
|
"help": "try doing it better next time?",
|
|
"filename": "bad_file.rs",
|
|
"labels": [
|
|
{
|
|
"label": "this bit here",
|
|
"span": {
|
|
"offset": 9,
|
|
"length": 4
|
|
}
|
|
}
|
|
],
|
|
"related": []
|
|
}"#
|
|
.lines()
|
|
.map(|s| s.trim_matches(|c| c == ' ' || c == '\n'))
|
|
.collect();
|
|
assert_eq!(expected, out);
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn single_line_highlight_offset_zero() -> Result<(), MietteError> {
|
|
#[derive(Debug, Diagnostic, Error)]
|
|
#[error("oops!")]
|
|
#[diagnostic(code(oops::my::bad), help("try doing it better next time?"))]
|
|
struct MyBad {
|
|
#[source_code]
|
|
src: NamedSource<String>,
|
|
#[label("this bit here")]
|
|
highlight: SourceSpan,
|
|
}
|
|
|
|
let src = "source\n text\n here".to_string();
|
|
let err = MyBad {
|
|
src: NamedSource::new("bad_file.rs", src),
|
|
highlight: (0, 0).into(),
|
|
};
|
|
let out = fmt_report(err.into());
|
|
println!("Error: {}", out);
|
|
let expected: String = r#"
|
|
{
|
|
"message": "oops!",
|
|
"code": "oops::my::bad",
|
|
"severity": "error",
|
|
"causes": [],
|
|
"help": "try doing it better next time?",
|
|
"filename": "bad_file.rs",
|
|
"labels": [
|
|
{
|
|
"label": "this bit here",
|
|
"span": {
|
|
"offset": 0,
|
|
"length": 0
|
|
}
|
|
}
|
|
],
|
|
"related": []
|
|
}"#
|
|
.lines()
|
|
.map(|s| s.trim_matches(|c| c == ' ' || c == '\n'))
|
|
.collect();
|
|
assert_eq!(expected, out);
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn single_line_highlight_with_empty_span() -> Result<(), MietteError> {
|
|
#[derive(Debug, Diagnostic, Error)]
|
|
#[error("oops!")]
|
|
#[diagnostic(code(oops::my::bad), help("try doing it better next time?"))]
|
|
struct MyBad {
|
|
#[source_code]
|
|
src: NamedSource<String>,
|
|
#[label("this bit here")]
|
|
highlight: SourceSpan,
|
|
}
|
|
|
|
let src = "source\n text\n here".to_string();
|
|
let err = MyBad {
|
|
src: NamedSource::new("bad_file.rs", src),
|
|
highlight: (9, 0).into(),
|
|
};
|
|
let out = fmt_report(err.into());
|
|
println!("Error: {}", out);
|
|
let expected: String = r#"
|
|
{
|
|
"message": "oops!",
|
|
"code": "oops::my::bad",
|
|
"severity": "error",
|
|
"causes": [],
|
|
"help": "try doing it better next time?",
|
|
"filename": "bad_file.rs",
|
|
"labels": [
|
|
{
|
|
"label": "this bit here",
|
|
"span": {
|
|
"offset": 9,
|
|
"length": 0
|
|
}
|
|
}
|
|
],
|
|
"related": []
|
|
}"#
|
|
.lines()
|
|
.map(|s| s.trim_matches(|c| c == ' ' || c == '\n'))
|
|
.collect();
|
|
assert_eq!(expected, out);
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn single_line_highlight_no_label() -> Result<(), MietteError> {
|
|
#[derive(Debug, Diagnostic, Error)]
|
|
#[error("oops!")]
|
|
#[diagnostic(code(oops::my::bad), help("try doing it better next time?"))]
|
|
struct MyBad {
|
|
#[source_code]
|
|
src: NamedSource<String>,
|
|
#[label]
|
|
highlight: SourceSpan,
|
|
}
|
|
|
|
let src = "source\n text\n here".to_string();
|
|
let err = MyBad {
|
|
src: NamedSource::new("bad_file.rs", src),
|
|
highlight: (9, 4).into(),
|
|
};
|
|
let out = fmt_report(err.into());
|
|
println!("Error: {}", out);
|
|
let expected: String = r#"
|
|
{
|
|
"message": "oops!",
|
|
"code": "oops::my::bad",
|
|
"severity": "error",
|
|
"causes": [],
|
|
"help": "try doing it better next time?",
|
|
"filename": "bad_file.rs",
|
|
"labels": [
|
|
{
|
|
"span": {
|
|
"offset": 9,
|
|
"length": 4
|
|
}
|
|
}
|
|
],
|
|
"related": []
|
|
}"#
|
|
.lines()
|
|
.map(|s| s.trim_matches(|c| c == ' ' || c == '\n'))
|
|
.collect();
|
|
assert_eq!(expected, out);
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn single_line_highlight_at_line_start() -> Result<(), MietteError> {
|
|
#[derive(Debug, Diagnostic, Error)]
|
|
#[error("oops!")]
|
|
#[diagnostic(code(oops::my::bad), help("try doing it better next time?"))]
|
|
struct MyBad {
|
|
#[source_code]
|
|
src: NamedSource<String>,
|
|
#[label("this bit here")]
|
|
highlight: SourceSpan,
|
|
}
|
|
|
|
let src = "source\ntext\n here".to_string();
|
|
let err = MyBad {
|
|
src: NamedSource::new("bad_file.rs", src),
|
|
highlight: (7, 4).into(),
|
|
};
|
|
let out = fmt_report(err.into());
|
|
println!("Error: {}", out);
|
|
let expected: String = r#"
|
|
{
|
|
"message": "oops!",
|
|
"code": "oops::my::bad",
|
|
"severity": "error",
|
|
"causes": [],
|
|
"help": "try doing it better next time?",
|
|
"filename": "bad_file.rs",
|
|
"labels": [
|
|
{
|
|
"label": "this bit here",
|
|
"span": {
|
|
"offset": 7,
|
|
"length": 4
|
|
}
|
|
}
|
|
],
|
|
"related": []
|
|
}"#
|
|
.lines()
|
|
.map(|s| s.trim_matches(|c| c == ' ' || c == '\n'))
|
|
.collect();
|
|
assert_eq!(expected, out);
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn multiple_same_line_highlights() -> Result<(), MietteError> {
|
|
#[derive(Debug, Diagnostic, Error)]
|
|
#[error("oops!")]
|
|
#[diagnostic(code(oops::my::bad), help("try doing it better next time?"))]
|
|
struct MyBad {
|
|
#[source_code]
|
|
src: NamedSource<String>,
|
|
#[label = "x"]
|
|
highlight1: SourceSpan,
|
|
#[label = "y"]
|
|
highlight2: SourceSpan,
|
|
#[label = "z"]
|
|
highlight3: SourceSpan,
|
|
}
|
|
|
|
let src = "source\n text text text text text\n here".to_string();
|
|
let err = MyBad {
|
|
src: NamedSource::new("bad_file.rs", src),
|
|
highlight1: (9, 4).into(),
|
|
highlight2: (14, 4).into(),
|
|
highlight3: (24, 4).into(),
|
|
};
|
|
let out = fmt_report(err.into());
|
|
println!("Error: {}", out);
|
|
let expected: String = r#"
|
|
{
|
|
"message": "oops!",
|
|
"code": "oops::my::bad",
|
|
"severity": "error",
|
|
"causes": [],
|
|
"help": "try doing it better next time?",
|
|
"filename": "bad_file.rs",
|
|
"labels": [
|
|
{
|
|
"label": "x",
|
|
"span": {
|
|
"offset": 9,
|
|
"length": 4
|
|
}
|
|
},
|
|
{
|
|
"label": "y",
|
|
"span": {
|
|
"offset": 14,
|
|
"length": 4
|
|
}
|
|
},
|
|
{
|
|
"label": "z",
|
|
"span": {
|
|
"offset": 24,
|
|
"length": 4
|
|
}
|
|
}
|
|
],
|
|
"related": []
|
|
}"#
|
|
.lines()
|
|
.map(|s| s.trim_matches(|c| c == ' ' || c == '\n'))
|
|
.collect();
|
|
assert_eq!(expected, out);
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn multiline_highlight_adjacent() -> Result<(), MietteError> {
|
|
#[derive(Debug, Diagnostic, Error)]
|
|
#[error("oops!")]
|
|
#[diagnostic(code(oops::my::bad), help("try doing it better next time?"))]
|
|
struct MyBad {
|
|
#[source_code]
|
|
src: NamedSource<String>,
|
|
#[label = "these two lines"]
|
|
highlight: SourceSpan,
|
|
}
|
|
|
|
let src = "source\n text\n here".to_string();
|
|
let err = MyBad {
|
|
src: NamedSource::new("bad_file.rs", src),
|
|
highlight: (9, 11).into(),
|
|
};
|
|
let out = fmt_report(err.into());
|
|
println!("Error: {}", out);
|
|
let expected: String = r#"
|
|
{
|
|
"message": "oops!",
|
|
"code": "oops::my::bad",
|
|
"severity": "error",
|
|
"causes": [],
|
|
"help": "try doing it better next time?",
|
|
"filename": "bad_file.rs",
|
|
"labels": [
|
|
{
|
|
"label": "these two lines",
|
|
"span": {
|
|
"offset": 9,
|
|
"length": 11
|
|
}
|
|
}
|
|
],
|
|
"related": []
|
|
}"#
|
|
.lines()
|
|
.map(|s| s.trim_matches(|c| c == ' ' || c == '\n'))
|
|
.collect();
|
|
assert_eq!(expected, out);
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn multiline_highlight_flyby() -> Result<(), MietteError> {
|
|
#[derive(Debug, Diagnostic, Error)]
|
|
#[error("oops!")]
|
|
#[diagnostic(code(oops::my::bad), help("try doing it better next time?"))]
|
|
struct MyBad {
|
|
#[source_code]
|
|
src: NamedSource<String>,
|
|
#[label = "block 1"]
|
|
highlight1: SourceSpan,
|
|
#[label = "block 2"]
|
|
highlight2: SourceSpan,
|
|
}
|
|
|
|
let src = r#"line1
|
|
line2
|
|
line3
|
|
line4
|
|
line5
|
|
"#
|
|
.to_string();
|
|
let len = src.len();
|
|
let err = MyBad {
|
|
src: NamedSource::new("bad_file.rs", src),
|
|
highlight1: (0, len).into(),
|
|
highlight2: (10, 9).into(),
|
|
};
|
|
let out = fmt_report(err.into());
|
|
println!("Error: {}", out);
|
|
let expected: String = r#"
|
|
{
|
|
"message": "oops!",
|
|
"code": "oops::my::bad",
|
|
"severity": "error",
|
|
"causes": [],
|
|
"help": "try doing it better next time?",
|
|
"filename": "bad_file.rs",
|
|
"labels": [
|
|
{
|
|
"label": "block 1",
|
|
"span": {
|
|
"offset": 0,
|
|
"length": 50
|
|
}
|
|
},
|
|
{
|
|
"label": "block 2",
|
|
"span": {
|
|
"offset": 10,
|
|
"length": 9
|
|
}
|
|
}
|
|
],
|
|
"related": []
|
|
}"#
|
|
.lines()
|
|
.map(|s| s.trim_matches(|c| c == ' ' || c == '\n'))
|
|
.collect();
|
|
assert_eq!(expected, out);
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn multiline_highlight_no_label() -> Result<(), MietteError> {
|
|
#[derive(Debug, Diagnostic, Error)]
|
|
#[error("wtf?!\nit broke :(")]
|
|
#[diagnostic(code(oops::my::bad), help("try doing it better next time?"))]
|
|
struct MyBad {
|
|
#[source]
|
|
source: Inner,
|
|
#[source_code]
|
|
src: NamedSource<String>,
|
|
#[label = "block 1"]
|
|
highlight1: SourceSpan,
|
|
#[label]
|
|
highlight2: SourceSpan,
|
|
}
|
|
|
|
#[derive(Debug, Error)]
|
|
#[error("something went wrong\n\nHere's a more detailed explanation of everything that actually went wrong because it's actually important.\n")]
|
|
struct Inner(#[source] InnerInner);
|
|
|
|
#[derive(Debug, Error)]
|
|
#[error("very much went wrong")]
|
|
struct InnerInner;
|
|
|
|
let src = r#"line1
|
|
line2
|
|
line3
|
|
line4
|
|
line5
|
|
"#
|
|
.to_string();
|
|
let len = src.len();
|
|
let err = MyBad {
|
|
source: Inner(InnerInner),
|
|
src: NamedSource::new("bad_file.rs", src),
|
|
highlight1: (0, len).into(),
|
|
highlight2: (10, 9).into(),
|
|
};
|
|
let out = fmt_report(err.into());
|
|
println!("Error: {}", out);
|
|
let expected: String = r#"
|
|
{
|
|
"message": "wtf?!\nit broke :(",
|
|
"code": "oops::my::bad",
|
|
"severity": "error",
|
|
"causes": [
|
|
"something went wrong\n\nHere's a more detailed explanation of everything that actually went wrong because it's actually important.\n",
|
|
"very much went wrong"
|
|
],
|
|
"help": "try doing it better next time?",
|
|
"filename": "bad_file.rs",
|
|
"labels": [
|
|
{
|
|
"label": "block 1",
|
|
"span": {
|
|
"offset": 0,
|
|
"length": 50
|
|
}
|
|
},
|
|
{
|
|
"span": {
|
|
"offset": 10,
|
|
"length": 9
|
|
}
|
|
}
|
|
],
|
|
"related": []
|
|
}"#
|
|
.lines()
|
|
.map(|s| s.trim_matches(|c| c == ' ' || c == '\n'))
|
|
.collect();
|
|
assert_eq!(expected, out);
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn multiple_multiline_highlights_adjacent() -> Result<(), MietteError> {
|
|
#[derive(Debug, Diagnostic, Error)]
|
|
#[error("oops!")]
|
|
#[diagnostic(code(oops::my::bad), help("try doing it better next time?"))]
|
|
struct MyBad {
|
|
#[source_code]
|
|
src: NamedSource<String>,
|
|
#[label = "this bit here"]
|
|
highlight1: SourceSpan,
|
|
#[label = "also this bit"]
|
|
highlight2: SourceSpan,
|
|
}
|
|
|
|
let src = "source\n text\n here\nmore here".to_string();
|
|
let err = MyBad {
|
|
src: NamedSource::new("bad_file.rs", src),
|
|
highlight1: (0, 10).into(),
|
|
highlight2: (20, 6).into(),
|
|
};
|
|
let out = fmt_report(err.into());
|
|
println!("Error: {}", out);
|
|
let expected: String = r#"
|
|
{
|
|
"message": "oops!",
|
|
"code": "oops::my::bad",
|
|
"severity": "error",
|
|
"causes": [],
|
|
"help": "try doing it better next time?",
|
|
"filename": "bad_file.rs",
|
|
"labels": [
|
|
{
|
|
"label": "this bit here",
|
|
"span": {
|
|
"offset": 0,
|
|
"length": 10
|
|
}
|
|
},
|
|
{
|
|
"label": "also this bit",
|
|
"span": {
|
|
"offset": 20,
|
|
"length": 6
|
|
}
|
|
}
|
|
],
|
|
"related": []
|
|
}"#
|
|
.lines()
|
|
.map(|s| s.trim_matches(|c| c == ' ' || c == '\n'))
|
|
.collect();
|
|
assert_eq!(expected, out);
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn multiple_multiline_highlights_overlapping_lines() -> Result<(), MietteError> {
|
|
#[derive(Debug, Diagnostic, Error)]
|
|
#[error("oops!")]
|
|
#[diagnostic(code(oops::my::bad), help("try doing it better next time?"))]
|
|
struct MyBad {
|
|
#[source_code]
|
|
src: NamedSource<String>,
|
|
#[label = "this bit here"]
|
|
highlight1: SourceSpan,
|
|
#[label = "also this bit"]
|
|
highlight2: SourceSpan,
|
|
}
|
|
|
|
let src = "source\n text\n here".to_string();
|
|
let err = MyBad {
|
|
src: NamedSource::new("bad_file.rs", src),
|
|
highlight1: (0, 8).into(),
|
|
highlight2: (9, 10).into(),
|
|
};
|
|
let out = fmt_report(err.into());
|
|
println!("Error: {}", out);
|
|
let expected: String = r#"
|
|
{
|
|
"message": "oops!",
|
|
"code": "oops::my::bad",
|
|
"severity": "error",
|
|
"causes": [],
|
|
"help": "try doing it better next time?",
|
|
"filename": "bad_file.rs",
|
|
"labels": [
|
|
{
|
|
"label": "this bit here",
|
|
"span": {
|
|
"offset": 0,
|
|
"length": 8
|
|
}
|
|
},
|
|
{
|
|
"label": "also this bit",
|
|
"span": {
|
|
"offset": 9,
|
|
"length": 10
|
|
}
|
|
}
|
|
],
|
|
"related": []
|
|
}"#
|
|
.lines()
|
|
.map(|s| s.trim_matches(|c| c == ' ' || c == '\n'))
|
|
.collect();
|
|
assert_eq!(expected, out);
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn multiple_multiline_highlights_overlapping_offsets() -> Result<(), MietteError> {
|
|
#[derive(Debug, Diagnostic, Error)]
|
|
#[error("oops!")]
|
|
#[diagnostic(code(oops::my::bad), help("try doing it better next time?"))]
|
|
struct MyBad {
|
|
#[source_code]
|
|
src: NamedSource<String>,
|
|
#[label = "this bit here"]
|
|
highlight1: SourceSpan,
|
|
#[label = "also this bit"]
|
|
highlight2: SourceSpan,
|
|
}
|
|
|
|
let src = "source\n text\n here".to_string();
|
|
let err = MyBad {
|
|
src: NamedSource::new("bad_file.rs", src),
|
|
highlight1: (0, 8).into(),
|
|
highlight2: (10, 10).into(),
|
|
};
|
|
let out = fmt_report(err.into());
|
|
println!("Error: {}", out);
|
|
let expected: String = r#"
|
|
{
|
|
"message": "oops!",
|
|
"code": "oops::my::bad",
|
|
"severity": "error",
|
|
"causes": [],
|
|
"help": "try doing it better next time?",
|
|
"filename": "bad_file.rs",
|
|
"labels": [
|
|
{
|
|
"label": "this bit here",
|
|
"span": {
|
|
"offset": 0,
|
|
"length": 8
|
|
}
|
|
},
|
|
{
|
|
"label": "also this bit",
|
|
"span": {
|
|
"offset": 10,
|
|
"length": 10
|
|
}
|
|
}
|
|
],
|
|
"related": []
|
|
}"#
|
|
.lines()
|
|
.map(|s| s.trim_matches(|c| c == ' ' || c == '\n'))
|
|
.collect();
|
|
assert_eq!(expected, out);
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn url() -> Result<(), MietteError> {
|
|
#[derive(Debug, Diagnostic, Error)]
|
|
#[error("oops!")]
|
|
#[diagnostic(help("try doing it better next time?"), url("https://example.com"))]
|
|
struct MyBad;
|
|
|
|
let err = MyBad;
|
|
let out = fmt_report(err.into());
|
|
println!("Error: {}", out);
|
|
let expected: String = r#"
|
|
{
|
|
"message": "oops!",
|
|
"severity": "error",
|
|
"causes": [],
|
|
"url": "https://example.com",
|
|
"help": "try doing it better next time?",
|
|
"labels": [],
|
|
"related": []
|
|
}"#
|
|
.lines()
|
|
.map(|s| s.trim_matches(|c| c == ' ' || c == '\n'))
|
|
.collect();
|
|
assert_eq!(expected, out);
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn related() -> Result<(), MietteError> {
|
|
#[derive(Debug, Diagnostic, Error)]
|
|
#[error("oops!")]
|
|
#[diagnostic(code(oops::my::bad), help("try doing it better next time?"))]
|
|
struct MyBad {
|
|
#[source_code]
|
|
src: NamedSource<String>,
|
|
#[label("this bit here")]
|
|
highlight: SourceSpan,
|
|
#[related]
|
|
related: Vec<MyBad>,
|
|
}
|
|
|
|
let src = "source\n text\n here".to_string();
|
|
let err = MyBad {
|
|
src: NamedSource::new("bad_file.rs", src.clone()),
|
|
highlight: (9, 4).into(),
|
|
related: vec![
|
|
MyBad {
|
|
src: NamedSource::new("bad_file2.rs", src.clone()),
|
|
highlight: (0, 6).into(),
|
|
related: vec![],
|
|
},
|
|
MyBad {
|
|
src: NamedSource::new("bad_file3.rs", src),
|
|
highlight: (0, 6).into(),
|
|
related: vec![],
|
|
},
|
|
],
|
|
};
|
|
let out = fmt_report(err.into());
|
|
println!("Error: {}", out);
|
|
let expected: String = r#"
|
|
{
|
|
"message": "oops!",
|
|
"code": "oops::my::bad",
|
|
"severity": "error",
|
|
"causes": [],
|
|
"help": "try doing it better next time?",
|
|
"filename": "bad_file.rs",
|
|
"labels": [
|
|
{
|
|
"label": "this bit here",
|
|
"span": {
|
|
"offset": 9,
|
|
"length": 4
|
|
}
|
|
}
|
|
],
|
|
"related": [{
|
|
"message": "oops!",
|
|
"code": "oops::my::bad",
|
|
"severity": "error",
|
|
"causes": [],
|
|
"help": "try doing it better next time?",
|
|
"filename": "bad_file2.rs",
|
|
"labels": [
|
|
{
|
|
"label": "this bit here",
|
|
"span": {
|
|
"offset": 0,
|
|
"length": 6
|
|
}
|
|
}
|
|
],
|
|
"related": []
|
|
},{
|
|
"message": "oops!",
|
|
"code": "oops::my::bad",
|
|
"severity": "error",
|
|
"causes": [],
|
|
"help": "try doing it better next time?",
|
|
"filename": "bad_file3.rs",
|
|
"labels": [
|
|
{
|
|
"label": "this bit here",
|
|
"span": {
|
|
"offset": 0,
|
|
"length": 6
|
|
}
|
|
}
|
|
],
|
|
"related": []
|
|
}]
|
|
}"#
|
|
.lines()
|
|
.map(|s| s.trim_matches(|c| c == ' ' || c == '\n'))
|
|
.collect();
|
|
assert_eq!(expected, out);
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn related_source_code_propagation() -> Result<(), MietteError> {
|
|
#[derive(Debug, Diagnostic, Error)]
|
|
#[error("oops!")]
|
|
#[diagnostic(code(oops::my::bad), help("try doing it better next time?"))]
|
|
struct MyBad {
|
|
#[source_code]
|
|
src: NamedSource<String>,
|
|
#[label("this bit here")]
|
|
highlight: SourceSpan,
|
|
#[related]
|
|
related: Vec<InnerError>,
|
|
}
|
|
|
|
#[derive(Debug, Diagnostic, Error)]
|
|
#[error("oops!")]
|
|
#[diagnostic(code(oops::my::bad), help("try doing it better next time?"))]
|
|
struct InnerError {
|
|
#[label("this bit here")]
|
|
highlight: SourceSpan,
|
|
}
|
|
|
|
let src = "source\n text\n here".to_string();
|
|
let err = MyBad {
|
|
src: NamedSource::new("bad_file.rs", src),
|
|
highlight: (9, 4).into(),
|
|
related: vec![
|
|
InnerError {
|
|
highlight: (0, 6).into(),
|
|
},
|
|
InnerError {
|
|
highlight: (0, 6).into(),
|
|
},
|
|
],
|
|
};
|
|
let out = fmt_report(err.into());
|
|
println!("Error: {}", out);
|
|
let expected: String = r#"
|
|
{
|
|
"message": "oops!",
|
|
"code": "oops::my::bad",
|
|
"severity": "error",
|
|
"causes": [],
|
|
"help": "try doing it better next time?",
|
|
"filename": "bad_file.rs",
|
|
"labels": [
|
|
{
|
|
"label": "this bit here",
|
|
"span": {
|
|
"offset": 9,
|
|
"length": 4
|
|
}
|
|
}
|
|
],
|
|
"related": [{
|
|
"message": "oops!",
|
|
"code": "oops::my::bad",
|
|
"severity": "error",
|
|
"causes": [],
|
|
"help": "try doing it better next time?",
|
|
"filename": "bad_file.rs",
|
|
"labels": [
|
|
{
|
|
"label": "this bit here",
|
|
"span": {
|
|
"offset": 0,
|
|
"length": 6
|
|
}
|
|
}
|
|
],
|
|
"related": []
|
|
},{
|
|
"message": "oops!",
|
|
"code": "oops::my::bad",
|
|
"severity": "error",
|
|
"causes": [],
|
|
"help": "try doing it better next time?",
|
|
"filename": "bad_file.rs",
|
|
"labels": [
|
|
{
|
|
"label": "this bit here",
|
|
"span": {
|
|
"offset": 0,
|
|
"length": 6
|
|
}
|
|
}
|
|
],
|
|
"related": []
|
|
}]
|
|
}"#
|
|
.lines()
|
|
.map(|s| s.trim_matches(|c| c == ' ' || c == '\n'))
|
|
.collect();
|
|
assert_eq!(expected, out);
|
|
Ok(())
|
|
}
|
|
}
|