pub struct Report {
pub schema_version: u32,
pub subject: String,
pub subject_version: String,
pub producer: Option<String>,
pub started_at: DateTime<Utc>,
pub finished_at: Option<DateTime<Utc>>,
pub checks: Vec<CheckResult>,
}Expand description
A full report. The output of one verification run.
§Example
use dev_report::{CheckResult, Report, Verdict};
let mut r = Report::new("my-crate", "0.1.0").with_producer("my-harness");
r.push(CheckResult::pass("compile"));
r.finish();
assert_eq!(r.overall_verdict(), Verdict::Pass);Fields§
§schema_version: u32Schema version for this report format.
subject: StringCrate or project being reported on.
subject_version: StringVersion of the subject at the time of the run.
producer: Option<String>Producer of the report (e.g. dev-bench, dev-async).
started_at: DateTime<Utc>Time the report was started.
finished_at: Option<DateTime<Utc>>Time the report was finalized.
checks: Vec<CheckResult>All individual check results in this report.
Implementations§
Source§impl Report
impl Report
Sourcepub fn new(
subject: impl Into<String>,
subject_version: impl Into<String>,
) -> Self
pub fn new( subject: impl Into<String>, subject_version: impl Into<String>, ) -> Self
Begin a new report for the given subject and version.
§Example
use dev_report::Report;
let r = Report::new("my-crate", "0.1.0");
assert_eq!(r.subject, "my-crate");
assert_eq!(r.schema_version, 1);Examples found in repository?
15fn main() {
16 let mut r = Report::new("sample-subject", "0.9.3").with_producer("dev-bench");
17
18 r.push(CheckResult::pass("compile"));
19 r.push(CheckResult::skip("network"));
20
21 r.push(
22 CheckResult::fail("test::round_trip", Severity::Error)
23 .with_detail("expected 42, got 41")
24 .with_evidence(Evidence::file_ref_lines("site", "src/math.rs", 10, 12)),
25 );
26
27 r.push(
28 CheckResult::fail("integration::startup", Severity::Critical)
29 .with_detail("service refused to start")
30 .with_evidence(Evidence::file_ref("source", "src/bin/server.rs")),
31 );
32
33 r.push(
34 CheckResult::warn("style::trailing_ws", Severity::Warning)
35 .with_detail("3 trailing-whitespace warnings"),
36 );
37
38 r.finish();
39
40 println!("{}", r.to_sarif());
41}More examples
16fn main() {
17 let mut r = Report::new("sample-subject", "0.9.3").with_producer("dev-bench");
18
19 r.push(CheckResult::pass("compile").with_duration_ms(120));
20 r.push(CheckResult::pass("test::math").with_duration_ms(7));
21
22 r.push(
23 CheckResult::fail("test::round_trip", Severity::Error)
24 .with_duration_ms(13)
25 .with_detail("expected 42, got 41"),
26 );
27
28 r.push(
29 CheckResult::fail("integration::startup", Severity::Critical)
30 .with_detail("service refused to start"),
31 );
32
33 r.push(
34 CheckResult::warn("style::trailing_ws", Severity::Warning)
35 .with_detail("3 trailing-whitespace warnings"),
36 );
37
38 r.push(CheckResult::skip("integration::network").with_detail("no network in sandbox"));
39
40 r.finish();
41
42 println!("{}", r.to_junit_xml());
43}21fn build_report(producer: &str) -> Report {
22 let frozen_start = chrono::Utc.with_ymd_and_hms(2026, 5, 11, 12, 0, 0).unwrap();
23 let frozen_end = chrono::Utc.with_ymd_and_hms(2026, 5, 11, 12, 0, 5).unwrap();
24
25 let mut r = Report::new("sample-subject", "0.9.3").with_producer(producer);
26 r.set_started_at(frozen_start);
27
28 // Pass with no detail, no severity, no tags, no evidence.
29 let mut c1 = CheckResult::pass("compile");
30 c1.at = frozen_start;
31 r.push(c1);
32
33 // Pass with a duration and a single numeric evidence.
34 let mut c2 = CheckResult::pass("bench::parse")
35 .with_duration_ms(7)
36 .with_tag("bench")
37 .with_evidence(Evidence::numeric("mean_ns", 1234.5))
38 .with_evidence(Evidence::numeric_int("iterations", 1_000_000));
39 c2.at = frozen_start;
40 r.push(c2);
41
42 // Warn with key-value evidence.
43 let mut c3 = CheckResult::warn("env::leaked", Severity::Warning)
44 .with_detail("RUST_LOG was set during test")
45 .with_evidence(Evidence::kv("env", [("CI", "true"), ("RUST_LOG", "debug")]));
46 c3.at = frozen_start;
47 r.push(c3);
48
49 // Fail with snippet + file_ref (no line range) + file_ref (with line range).
50 let mut c4 = CheckResult::fail("test::round_trip", Severity::Error)
51 .with_detail("expected 42, got 41")
52 .with_duration_ms(13)
53 .with_tags(["unit", "flaky"])
54 .with_evidence(Evidence::snippet(
55 "panic",
56 "assertion `left == right` failed",
57 ))
58 .with_evidence(Evidence::file_ref("source", "src/math.rs"))
59 .with_evidence(Evidence::file_ref_lines(
60 "call_site",
61 "tests/smoke.rs",
62 42,
63 47,
64 ));
65 c4.at = frozen_start;
66 r.push(c4);
67
68 // Fail with Critical severity.
69 let mut c5 = CheckResult::fail("integration::startup", Severity::Critical)
70 .with_detail("service refused to start");
71 c5.at = frozen_start;
72 r.push(c5);
73
74 // Warn with Info severity (lowest severity, still warn verdict).
75 let mut c6 = CheckResult::warn("style::trailing_ws", Severity::Info)
76 .with_detail("3 trailing-whitespace warnings");
77 c6.at = frozen_start;
78 r.push(c6);
79
80 // Skip with no severity.
81 let mut c7 = CheckResult::skip("integration::network").with_detail("no network in sandbox");
82 c7.at = frozen_start;
83 r.push(c7);
84
85 // Manually-constructed FileRef via Evidence::file_ref (covered above);
86 // also exercise a standalone FileRef with line_start but no line_end —
87 // valid per the schema (both are optional independently).
88 let mut c8 = CheckResult::pass("doc::link_check");
89 c8.at = frozen_start;
90 let standalone = FileRef::new("docs/index.md").with_line_range(10, 10);
91 c8 = c8.with_evidence(Evidence {
92 label: "anchor".into(),
93 data: dev_report::EvidenceData::FileRef(standalone),
94 });
95 r.push(c8);
96
97 r.set_finished_at(Some(frozen_end));
98 r
99}Sourcepub fn with_producer(self, producer: impl Into<String>) -> Self
pub fn with_producer(self, producer: impl Into<String>) -> Self
Set the producer of this report.
§Example
use dev_report::Report;
let r = Report::new("crate", "0.1.0").with_producer("dev-bench");
assert_eq!(r.producer.as_deref(), Some("dev-bench"));Examples found in repository?
15fn main() {
16 let mut r = Report::new("sample-subject", "0.9.3").with_producer("dev-bench");
17
18 r.push(CheckResult::pass("compile"));
19 r.push(CheckResult::skip("network"));
20
21 r.push(
22 CheckResult::fail("test::round_trip", Severity::Error)
23 .with_detail("expected 42, got 41")
24 .with_evidence(Evidence::file_ref_lines("site", "src/math.rs", 10, 12)),
25 );
26
27 r.push(
28 CheckResult::fail("integration::startup", Severity::Critical)
29 .with_detail("service refused to start")
30 .with_evidence(Evidence::file_ref("source", "src/bin/server.rs")),
31 );
32
33 r.push(
34 CheckResult::warn("style::trailing_ws", Severity::Warning)
35 .with_detail("3 trailing-whitespace warnings"),
36 );
37
38 r.finish();
39
40 println!("{}", r.to_sarif());
41}More examples
16fn main() {
17 let mut r = Report::new("sample-subject", "0.9.3").with_producer("dev-bench");
18
19 r.push(CheckResult::pass("compile").with_duration_ms(120));
20 r.push(CheckResult::pass("test::math").with_duration_ms(7));
21
22 r.push(
23 CheckResult::fail("test::round_trip", Severity::Error)
24 .with_duration_ms(13)
25 .with_detail("expected 42, got 41"),
26 );
27
28 r.push(
29 CheckResult::fail("integration::startup", Severity::Critical)
30 .with_detail("service refused to start"),
31 );
32
33 r.push(
34 CheckResult::warn("style::trailing_ws", Severity::Warning)
35 .with_detail("3 trailing-whitespace warnings"),
36 );
37
38 r.push(CheckResult::skip("integration::network").with_detail("no network in sandbox"));
39
40 r.finish();
41
42 println!("{}", r.to_junit_xml());
43}21fn build_report(producer: &str) -> Report {
22 let frozen_start = chrono::Utc.with_ymd_and_hms(2026, 5, 11, 12, 0, 0).unwrap();
23 let frozen_end = chrono::Utc.with_ymd_and_hms(2026, 5, 11, 12, 0, 5).unwrap();
24
25 let mut r = Report::new("sample-subject", "0.9.3").with_producer(producer);
26 r.set_started_at(frozen_start);
27
28 // Pass with no detail, no severity, no tags, no evidence.
29 let mut c1 = CheckResult::pass("compile");
30 c1.at = frozen_start;
31 r.push(c1);
32
33 // Pass with a duration and a single numeric evidence.
34 let mut c2 = CheckResult::pass("bench::parse")
35 .with_duration_ms(7)
36 .with_tag("bench")
37 .with_evidence(Evidence::numeric("mean_ns", 1234.5))
38 .with_evidence(Evidence::numeric_int("iterations", 1_000_000));
39 c2.at = frozen_start;
40 r.push(c2);
41
42 // Warn with key-value evidence.
43 let mut c3 = CheckResult::warn("env::leaked", Severity::Warning)
44 .with_detail("RUST_LOG was set during test")
45 .with_evidence(Evidence::kv("env", [("CI", "true"), ("RUST_LOG", "debug")]));
46 c3.at = frozen_start;
47 r.push(c3);
48
49 // Fail with snippet + file_ref (no line range) + file_ref (with line range).
50 let mut c4 = CheckResult::fail("test::round_trip", Severity::Error)
51 .with_detail("expected 42, got 41")
52 .with_duration_ms(13)
53 .with_tags(["unit", "flaky"])
54 .with_evidence(Evidence::snippet(
55 "panic",
56 "assertion `left == right` failed",
57 ))
58 .with_evidence(Evidence::file_ref("source", "src/math.rs"))
59 .with_evidence(Evidence::file_ref_lines(
60 "call_site",
61 "tests/smoke.rs",
62 42,
63 47,
64 ));
65 c4.at = frozen_start;
66 r.push(c4);
67
68 // Fail with Critical severity.
69 let mut c5 = CheckResult::fail("integration::startup", Severity::Critical)
70 .with_detail("service refused to start");
71 c5.at = frozen_start;
72 r.push(c5);
73
74 // Warn with Info severity (lowest severity, still warn verdict).
75 let mut c6 = CheckResult::warn("style::trailing_ws", Severity::Info)
76 .with_detail("3 trailing-whitespace warnings");
77 c6.at = frozen_start;
78 r.push(c6);
79
80 // Skip with no severity.
81 let mut c7 = CheckResult::skip("integration::network").with_detail("no network in sandbox");
82 c7.at = frozen_start;
83 r.push(c7);
84
85 // Manually-constructed FileRef via Evidence::file_ref (covered above);
86 // also exercise a standalone FileRef with line_start but no line_end —
87 // valid per the schema (both are optional independently).
88 let mut c8 = CheckResult::pass("doc::link_check");
89 c8.at = frozen_start;
90 let standalone = FileRef::new("docs/index.md").with_line_range(10, 10);
91 c8 = c8.with_evidence(Evidence {
92 label: "anchor".into(),
93 data: dev_report::EvidenceData::FileRef(standalone),
94 });
95 r.push(c8);
96
97 r.set_finished_at(Some(frozen_end));
98 r
99}Sourcepub fn push(&mut self, result: CheckResult)
pub fn push(&mut self, result: CheckResult)
Append a check result to this report.
§Example
use dev_report::{CheckResult, Report};
let mut r = Report::new("crate", "0.1.0");
r.push(CheckResult::pass("compile"));
assert_eq!(r.checks.len(), 1);Examples found in repository?
15fn main() {
16 let mut r = Report::new("sample-subject", "0.9.3").with_producer("dev-bench");
17
18 r.push(CheckResult::pass("compile"));
19 r.push(CheckResult::skip("network"));
20
21 r.push(
22 CheckResult::fail("test::round_trip", Severity::Error)
23 .with_detail("expected 42, got 41")
24 .with_evidence(Evidence::file_ref_lines("site", "src/math.rs", 10, 12)),
25 );
26
27 r.push(
28 CheckResult::fail("integration::startup", Severity::Critical)
29 .with_detail("service refused to start")
30 .with_evidence(Evidence::file_ref("source", "src/bin/server.rs")),
31 );
32
33 r.push(
34 CheckResult::warn("style::trailing_ws", Severity::Warning)
35 .with_detail("3 trailing-whitespace warnings"),
36 );
37
38 r.finish();
39
40 println!("{}", r.to_sarif());
41}More examples
16fn main() {
17 let mut r = Report::new("sample-subject", "0.9.3").with_producer("dev-bench");
18
19 r.push(CheckResult::pass("compile").with_duration_ms(120));
20 r.push(CheckResult::pass("test::math").with_duration_ms(7));
21
22 r.push(
23 CheckResult::fail("test::round_trip", Severity::Error)
24 .with_duration_ms(13)
25 .with_detail("expected 42, got 41"),
26 );
27
28 r.push(
29 CheckResult::fail("integration::startup", Severity::Critical)
30 .with_detail("service refused to start"),
31 );
32
33 r.push(
34 CheckResult::warn("style::trailing_ws", Severity::Warning)
35 .with_detail("3 trailing-whitespace warnings"),
36 );
37
38 r.push(CheckResult::skip("integration::network").with_detail("no network in sandbox"));
39
40 r.finish();
41
42 println!("{}", r.to_junit_xml());
43}21fn build_report(producer: &str) -> Report {
22 let frozen_start = chrono::Utc.with_ymd_and_hms(2026, 5, 11, 12, 0, 0).unwrap();
23 let frozen_end = chrono::Utc.with_ymd_and_hms(2026, 5, 11, 12, 0, 5).unwrap();
24
25 let mut r = Report::new("sample-subject", "0.9.3").with_producer(producer);
26 r.set_started_at(frozen_start);
27
28 // Pass with no detail, no severity, no tags, no evidence.
29 let mut c1 = CheckResult::pass("compile");
30 c1.at = frozen_start;
31 r.push(c1);
32
33 // Pass with a duration and a single numeric evidence.
34 let mut c2 = CheckResult::pass("bench::parse")
35 .with_duration_ms(7)
36 .with_tag("bench")
37 .with_evidence(Evidence::numeric("mean_ns", 1234.5))
38 .with_evidence(Evidence::numeric_int("iterations", 1_000_000));
39 c2.at = frozen_start;
40 r.push(c2);
41
42 // Warn with key-value evidence.
43 let mut c3 = CheckResult::warn("env::leaked", Severity::Warning)
44 .with_detail("RUST_LOG was set during test")
45 .with_evidence(Evidence::kv("env", [("CI", "true"), ("RUST_LOG", "debug")]));
46 c3.at = frozen_start;
47 r.push(c3);
48
49 // Fail with snippet + file_ref (no line range) + file_ref (with line range).
50 let mut c4 = CheckResult::fail("test::round_trip", Severity::Error)
51 .with_detail("expected 42, got 41")
52 .with_duration_ms(13)
53 .with_tags(["unit", "flaky"])
54 .with_evidence(Evidence::snippet(
55 "panic",
56 "assertion `left == right` failed",
57 ))
58 .with_evidence(Evidence::file_ref("source", "src/math.rs"))
59 .with_evidence(Evidence::file_ref_lines(
60 "call_site",
61 "tests/smoke.rs",
62 42,
63 47,
64 ));
65 c4.at = frozen_start;
66 r.push(c4);
67
68 // Fail with Critical severity.
69 let mut c5 = CheckResult::fail("integration::startup", Severity::Critical)
70 .with_detail("service refused to start");
71 c5.at = frozen_start;
72 r.push(c5);
73
74 // Warn with Info severity (lowest severity, still warn verdict).
75 let mut c6 = CheckResult::warn("style::trailing_ws", Severity::Info)
76 .with_detail("3 trailing-whitespace warnings");
77 c6.at = frozen_start;
78 r.push(c6);
79
80 // Skip with no severity.
81 let mut c7 = CheckResult::skip("integration::network").with_detail("no network in sandbox");
82 c7.at = frozen_start;
83 r.push(c7);
84
85 // Manually-constructed FileRef via Evidence::file_ref (covered above);
86 // also exercise a standalone FileRef with line_start but no line_end —
87 // valid per the schema (both are optional independently).
88 let mut c8 = CheckResult::pass("doc::link_check");
89 c8.at = frozen_start;
90 let standalone = FileRef::new("docs/index.md").with_line_range(10, 10);
91 c8 = c8.with_evidence(Evidence {
92 label: "anchor".into(),
93 data: dev_report::EvidenceData::FileRef(standalone),
94 });
95 r.push(c8);
96
97 r.set_finished_at(Some(frozen_end));
98 r
99}Sourcepub fn finish(&mut self)
pub fn finish(&mut self)
Mark the report as finished, stamping the finish time.
§Example
use dev_report::Report;
let mut r = Report::new("crate", "0.1.0");
r.finish();
assert!(r.finished_at.is_some());Examples found in repository?
15fn main() {
16 let mut r = Report::new("sample-subject", "0.9.3").with_producer("dev-bench");
17
18 r.push(CheckResult::pass("compile"));
19 r.push(CheckResult::skip("network"));
20
21 r.push(
22 CheckResult::fail("test::round_trip", Severity::Error)
23 .with_detail("expected 42, got 41")
24 .with_evidence(Evidence::file_ref_lines("site", "src/math.rs", 10, 12)),
25 );
26
27 r.push(
28 CheckResult::fail("integration::startup", Severity::Critical)
29 .with_detail("service refused to start")
30 .with_evidence(Evidence::file_ref("source", "src/bin/server.rs")),
31 );
32
33 r.push(
34 CheckResult::warn("style::trailing_ws", Severity::Warning)
35 .with_detail("3 trailing-whitespace warnings"),
36 );
37
38 r.finish();
39
40 println!("{}", r.to_sarif());
41}More examples
16fn main() {
17 let mut r = Report::new("sample-subject", "0.9.3").with_producer("dev-bench");
18
19 r.push(CheckResult::pass("compile").with_duration_ms(120));
20 r.push(CheckResult::pass("test::math").with_duration_ms(7));
21
22 r.push(
23 CheckResult::fail("test::round_trip", Severity::Error)
24 .with_duration_ms(13)
25 .with_detail("expected 42, got 41"),
26 );
27
28 r.push(
29 CheckResult::fail("integration::startup", Severity::Critical)
30 .with_detail("service refused to start"),
31 );
32
33 r.push(
34 CheckResult::warn("style::trailing_ws", Severity::Warning)
35 .with_detail("3 trailing-whitespace warnings"),
36 );
37
38 r.push(CheckResult::skip("integration::network").with_detail("no network in sandbox"));
39
40 r.finish();
41
42 println!("{}", r.to_junit_xml());
43}Sourcepub fn set_started_at(&mut self, ts: DateTime<Utc>)
pub fn set_started_at(&mut self, ts: DateTime<Utc>)
Override started_at with a fixed timestamp.
Useful when reconstructing a Report from external data
(replay, import from a different schema, deterministic test
fixtures). Most producers should let Report::new capture the
real start time and not call this.
§Example
use chrono::TimeZone;
use dev_report::Report;
let mut r = Report::new("crate", "0.1.0");
let frozen = chrono::Utc.with_ymd_and_hms(2026, 1, 1, 0, 0, 0).unwrap();
r.set_started_at(frozen);
assert_eq!(r.started_at, frozen);Examples found in repository?
21fn build_report(producer: &str) -> Report {
22 let frozen_start = chrono::Utc.with_ymd_and_hms(2026, 5, 11, 12, 0, 0).unwrap();
23 let frozen_end = chrono::Utc.with_ymd_and_hms(2026, 5, 11, 12, 0, 5).unwrap();
24
25 let mut r = Report::new("sample-subject", "0.9.3").with_producer(producer);
26 r.set_started_at(frozen_start);
27
28 // Pass with no detail, no severity, no tags, no evidence.
29 let mut c1 = CheckResult::pass("compile");
30 c1.at = frozen_start;
31 r.push(c1);
32
33 // Pass with a duration and a single numeric evidence.
34 let mut c2 = CheckResult::pass("bench::parse")
35 .with_duration_ms(7)
36 .with_tag("bench")
37 .with_evidence(Evidence::numeric("mean_ns", 1234.5))
38 .with_evidence(Evidence::numeric_int("iterations", 1_000_000));
39 c2.at = frozen_start;
40 r.push(c2);
41
42 // Warn with key-value evidence.
43 let mut c3 = CheckResult::warn("env::leaked", Severity::Warning)
44 .with_detail("RUST_LOG was set during test")
45 .with_evidence(Evidence::kv("env", [("CI", "true"), ("RUST_LOG", "debug")]));
46 c3.at = frozen_start;
47 r.push(c3);
48
49 // Fail with snippet + file_ref (no line range) + file_ref (with line range).
50 let mut c4 = CheckResult::fail("test::round_trip", Severity::Error)
51 .with_detail("expected 42, got 41")
52 .with_duration_ms(13)
53 .with_tags(["unit", "flaky"])
54 .with_evidence(Evidence::snippet(
55 "panic",
56 "assertion `left == right` failed",
57 ))
58 .with_evidence(Evidence::file_ref("source", "src/math.rs"))
59 .with_evidence(Evidence::file_ref_lines(
60 "call_site",
61 "tests/smoke.rs",
62 42,
63 47,
64 ));
65 c4.at = frozen_start;
66 r.push(c4);
67
68 // Fail with Critical severity.
69 let mut c5 = CheckResult::fail("integration::startup", Severity::Critical)
70 .with_detail("service refused to start");
71 c5.at = frozen_start;
72 r.push(c5);
73
74 // Warn with Info severity (lowest severity, still warn verdict).
75 let mut c6 = CheckResult::warn("style::trailing_ws", Severity::Info)
76 .with_detail("3 trailing-whitespace warnings");
77 c6.at = frozen_start;
78 r.push(c6);
79
80 // Skip with no severity.
81 let mut c7 = CheckResult::skip("integration::network").with_detail("no network in sandbox");
82 c7.at = frozen_start;
83 r.push(c7);
84
85 // Manually-constructed FileRef via Evidence::file_ref (covered above);
86 // also exercise a standalone FileRef with line_start but no line_end —
87 // valid per the schema (both are optional independently).
88 let mut c8 = CheckResult::pass("doc::link_check");
89 c8.at = frozen_start;
90 let standalone = FileRef::new("docs/index.md").with_line_range(10, 10);
91 c8 = c8.with_evidence(Evidence {
92 label: "anchor".into(),
93 data: dev_report::EvidenceData::FileRef(standalone),
94 });
95 r.push(c8);
96
97 r.set_finished_at(Some(frozen_end));
98 r
99}Sourcepub fn set_finished_at(&mut self, ts: Option<DateTime<Utc>>)
pub fn set_finished_at(&mut self, ts: Option<DateTime<Utc>>)
Override finished_at with a fixed timestamp.
Useful for replay / import scenarios where the real finish
time is known but Utc::now() would be wrong.
§Example
use chrono::TimeZone;
use dev_report::Report;
let mut r = Report::new("crate", "0.1.0");
let frozen = chrono::Utc.with_ymd_and_hms(2026, 1, 1, 0, 0, 1).unwrap();
r.set_finished_at(Some(frozen));
assert_eq!(r.finished_at, Some(frozen));Examples found in repository?
21fn build_report(producer: &str) -> Report {
22 let frozen_start = chrono::Utc.with_ymd_and_hms(2026, 5, 11, 12, 0, 0).unwrap();
23 let frozen_end = chrono::Utc.with_ymd_and_hms(2026, 5, 11, 12, 0, 5).unwrap();
24
25 let mut r = Report::new("sample-subject", "0.9.3").with_producer(producer);
26 r.set_started_at(frozen_start);
27
28 // Pass with no detail, no severity, no tags, no evidence.
29 let mut c1 = CheckResult::pass("compile");
30 c1.at = frozen_start;
31 r.push(c1);
32
33 // Pass with a duration and a single numeric evidence.
34 let mut c2 = CheckResult::pass("bench::parse")
35 .with_duration_ms(7)
36 .with_tag("bench")
37 .with_evidence(Evidence::numeric("mean_ns", 1234.5))
38 .with_evidence(Evidence::numeric_int("iterations", 1_000_000));
39 c2.at = frozen_start;
40 r.push(c2);
41
42 // Warn with key-value evidence.
43 let mut c3 = CheckResult::warn("env::leaked", Severity::Warning)
44 .with_detail("RUST_LOG was set during test")
45 .with_evidence(Evidence::kv("env", [("CI", "true"), ("RUST_LOG", "debug")]));
46 c3.at = frozen_start;
47 r.push(c3);
48
49 // Fail with snippet + file_ref (no line range) + file_ref (with line range).
50 let mut c4 = CheckResult::fail("test::round_trip", Severity::Error)
51 .with_detail("expected 42, got 41")
52 .with_duration_ms(13)
53 .with_tags(["unit", "flaky"])
54 .with_evidence(Evidence::snippet(
55 "panic",
56 "assertion `left == right` failed",
57 ))
58 .with_evidence(Evidence::file_ref("source", "src/math.rs"))
59 .with_evidence(Evidence::file_ref_lines(
60 "call_site",
61 "tests/smoke.rs",
62 42,
63 47,
64 ));
65 c4.at = frozen_start;
66 r.push(c4);
67
68 // Fail with Critical severity.
69 let mut c5 = CheckResult::fail("integration::startup", Severity::Critical)
70 .with_detail("service refused to start");
71 c5.at = frozen_start;
72 r.push(c5);
73
74 // Warn with Info severity (lowest severity, still warn verdict).
75 let mut c6 = CheckResult::warn("style::trailing_ws", Severity::Info)
76 .with_detail("3 trailing-whitespace warnings");
77 c6.at = frozen_start;
78 r.push(c6);
79
80 // Skip with no severity.
81 let mut c7 = CheckResult::skip("integration::network").with_detail("no network in sandbox");
82 c7.at = frozen_start;
83 r.push(c7);
84
85 // Manually-constructed FileRef via Evidence::file_ref (covered above);
86 // also exercise a standalone FileRef with line_start but no line_end —
87 // valid per the schema (both are optional independently).
88 let mut c8 = CheckResult::pass("doc::link_check");
89 c8.at = frozen_start;
90 let standalone = FileRef::new("docs/index.md").with_line_range(10, 10);
91 c8 = c8.with_evidence(Evidence {
92 label: "anchor".into(),
93 data: dev_report::EvidenceData::FileRef(standalone),
94 });
95 r.push(c8);
96
97 r.set_finished_at(Some(frozen_end));
98 r
99}Sourcepub fn verdict_counts(&self) -> (usize, usize, usize, usize)
pub fn verdict_counts(&self) -> (usize, usize, usize, usize)
Count of checks per verdict, returned as (pass, fail, warn, skip).
§Example
use dev_report::{CheckResult, Report, Severity};
let mut r = Report::new("c", "0.1.0");
r.push(CheckResult::pass("a"));
r.push(CheckResult::pass("b"));
r.push(CheckResult::fail("c", Severity::Error));
let (pass, fail, warn, skip) = r.verdict_counts();
assert_eq!((pass, fail, warn, skip), (2, 1, 0, 0));Sourcepub fn overall_verdict(&self) -> Verdict
pub fn overall_verdict(&self) -> Verdict
Compute the overall verdict for this report.
Rules:
- Any
Fail->Fail - Else any
Warn->Warn - Else any
Pass->Pass - Else (all
Skipor empty) ->Skip
§Example
use dev_report::{CheckResult, Report, Severity, Verdict};
let mut r = Report::new("crate", "0.1.0");
r.push(CheckResult::pass("a"));
r.push(CheckResult::fail("b", Severity::Error));
assert_eq!(r.overall_verdict(), Verdict::Fail);Sourcepub fn passed(&self) -> bool
pub fn passed(&self) -> bool
true when overall_verdict is Pass.
§Example
use dev_report::{CheckResult, Report};
let mut r = Report::new("c", "0.1.0");
r.push(CheckResult::pass("ok"));
assert!(r.passed());Sourcepub fn failed(&self) -> bool
pub fn failed(&self) -> bool
true when overall_verdict is Fail.
§Example
use dev_report::{CheckResult, Report, Severity};
let mut r = Report::new("c", "0.1.0");
r.push(CheckResult::fail("oops", Severity::Error));
assert!(r.failed());Sourcepub fn warned(&self) -> bool
pub fn warned(&self) -> bool
true when overall_verdict is Warn.
Sourcepub fn skipped(&self) -> bool
pub fn skipped(&self) -> bool
true when overall_verdict is Skip
(all checks were skipped, or there were no checks).
Sourcepub fn checks_with_severity(
&self,
severity: Severity,
) -> impl Iterator<Item = &CheckResult>
pub fn checks_with_severity( &self, severity: Severity, ) -> impl Iterator<Item = &CheckResult>
Iterate over checks whose severity
matches the given level.
Pass and Skip checks have severity = None and never match.
§Example
use dev_report::{CheckResult, Report, Severity};
let mut r = Report::new("c", "0.1.0");
r.push(CheckResult::fail("a", Severity::Error));
r.push(CheckResult::warn("b", Severity::Warning));
r.push(CheckResult::fail("c", Severity::Error));
let errors: Vec<_> = r.checks_with_severity(Severity::Error).collect();
assert_eq!(errors.len(), 2);Sourcepub fn checks_with_tag<'a>(
&'a self,
tag: &'a str,
) -> impl Iterator<Item = &'a CheckResult>
pub fn checks_with_tag<'a>( &'a self, tag: &'a str, ) -> impl Iterator<Item = &'a CheckResult>
Iterate over checks that carry the given tag.
§Example
use dev_report::{CheckResult, Report};
let mut r = Report::new("crate", "0.1.0");
r.push(CheckResult::pass("a").with_tag("slow"));
r.push(CheckResult::pass("b"));
r.push(CheckResult::pass("c").with_tag("slow"));
let slow: Vec<_> = r.checks_with_tag("slow").collect();
assert_eq!(slow.len(), 2);Sourcepub fn to_json(&self) -> Result<String>
pub fn to_json(&self) -> Result<String>
Serialize this report to JSON.
§Example
use dev_report::Report;
let r = Report::new("crate", "0.1.0");
let json = r.to_json().unwrap();
assert!(json.contains("\"subject\": \"crate\""));Examples found in repository?
114fn main() {
115 let arg = std::env::args()
116 .nth(1)
117 .unwrap_or_else(|| "report".to_string());
118 let json = match arg.as_str() {
119 "multi" => build_multi().to_json().expect("serialize MultiReport"),
120 _ => build_report("dev-bench")
121 .to_json()
122 .expect("serialize Report"),
123 };
124 println!("{}", json);
125}Sourcepub fn from_json(s: &str) -> Result<Self>
pub fn from_json(s: &str) -> Result<Self>
Deserialize a report from JSON.
§Example
use dev_report::Report;
let r = Report::new("crate", "0.1.0");
let json = r.to_json().unwrap();
let parsed = Report::from_json(&json).unwrap();
assert_eq!(parsed.subject, "crate");Sourcepub fn to_terminal(&self) -> String
Available on crate feature terminal only.
pub fn to_terminal(&self) -> String
terminal only.Render this report to a TTY-friendly string. Monochrome.
Available with the terminal feature.
Sourcepub fn to_terminal_color(&self) -> String
Available on crate feature terminal only.
pub fn to_terminal_color(&self) -> String
terminal only.Render this report with ANSI color codes.
Available with the terminal feature.
Sourcepub fn to_markdown(&self) -> String
Available on crate feature markdown only.
pub fn to_markdown(&self) -> String
markdown only.Render this report to a Markdown string.
Available with the markdown feature.
Sourcepub fn to_sarif(&self) -> String
Available on crate feature sarif only.
pub fn to_sarif(&self) -> String
sarif only.Render this report as a SARIF 2.1.0 document.
Only Fail and Warn checks are emitted; Pass and Skip are
omitted (SARIF is a defect report format). See crate::sarif
for the severity-to-level mapping.
Available with the sarif feature.
Examples found in repository?
15fn main() {
16 let mut r = Report::new("sample-subject", "0.9.3").with_producer("dev-bench");
17
18 r.push(CheckResult::pass("compile"));
19 r.push(CheckResult::skip("network"));
20
21 r.push(
22 CheckResult::fail("test::round_trip", Severity::Error)
23 .with_detail("expected 42, got 41")
24 .with_evidence(Evidence::file_ref_lines("site", "src/math.rs", 10, 12)),
25 );
26
27 r.push(
28 CheckResult::fail("integration::startup", Severity::Critical)
29 .with_detail("service refused to start")
30 .with_evidence(Evidence::file_ref("source", "src/bin/server.rs")),
31 );
32
33 r.push(
34 CheckResult::warn("style::trailing_ws", Severity::Warning)
35 .with_detail("3 trailing-whitespace warnings"),
36 );
37
38 r.finish();
39
40 println!("{}", r.to_sarif());
41}Sourcepub fn to_junit_xml(&self) -> String
Available on crate feature junit only.
pub fn to_junit_xml(&self) -> String
junit only.Render this report as a JUnit XML document.
Every check becomes a <testcase>; fail verdicts emit a
<failure> child, skip verdicts emit a <skipped/> child. See
crate::junit for the verdict-to-element mapping.
Available with the junit feature.
Examples found in repository?
16fn main() {
17 let mut r = Report::new("sample-subject", "0.9.3").with_producer("dev-bench");
18
19 r.push(CheckResult::pass("compile").with_duration_ms(120));
20 r.push(CheckResult::pass("test::math").with_duration_ms(7));
21
22 r.push(
23 CheckResult::fail("test::round_trip", Severity::Error)
24 .with_duration_ms(13)
25 .with_detail("expected 42, got 41"),
26 );
27
28 r.push(
29 CheckResult::fail("integration::startup", Severity::Critical)
30 .with_detail("service refused to start"),
31 );
32
33 r.push(
34 CheckResult::warn("style::trailing_ws", Severity::Warning)
35 .with_detail("3 trailing-whitespace warnings"),
36 );
37
38 r.push(CheckResult::skip("integration::network").with_detail("no network in sandbox"));
39
40 r.finish();
41
42 println!("{}", r.to_junit_xml());
43}Sourcepub fn diff(&self, baseline: &Self) -> Diff
pub fn diff(&self, baseline: &Self) -> Diff
Compare this report against a baseline using default options.
self is the new report; baseline is the previous one.
Default options flag duration regressions over 20% slower.
§Example
use dev_report::{CheckResult, Report, Severity};
let mut prev = Report::new("c", "0.1.0");
prev.push(CheckResult::pass("a"));
let mut curr = Report::new("c", "0.1.0");
curr.push(CheckResult::fail("a", Severity::Error));
let diff = curr.diff(&prev);
assert_eq!(diff.newly_failing, vec!["a".to_string()]);Sourcepub fn diff_with(&self, baseline: &Self, opts: &DiffOptions) -> Diff
pub fn diff_with(&self, baseline: &Self, opts: &DiffOptions) -> Diff
Compare this report against a baseline using custom options.
§Example
use dev_report::{CheckResult, DiffOptions, Report};
let mut prev = Report::new("c", "0.1.0");
prev.push(CheckResult::pass("a").with_duration_ms(100));
let mut curr = Report::new("c", "0.1.0");
curr.push(CheckResult::pass("a").with_duration_ms(150));
let opts = DiffOptions {
duration_regression_pct: Some(10.0),
duration_regression_abs_ms: None,
};
let diff = curr.diff_with(&prev, &opts);
assert_eq!(diff.duration_regressions.len(), 1);