spec_driven_docs/domain/
finding.rs1use std::fmt;
9
10use camino::Utf8PathBuf;
11
12use crate::domain::rule_id::RuleId;
13
14#[derive(Debug, Clone, PartialEq, Eq)]
16pub struct Finding {
17 pub rule: RuleId,
19 pub path: Option<Utf8PathBuf>,
21 pub line: Option<usize>,
23 pub detail: String,
25}
26
27impl Finding {
28 #[must_use]
30 pub fn on_file(rule: RuleId, path: impl Into<Utf8PathBuf>, detail: impl Into<String>) -> Self {
31 Self {
32 rule,
33 path: Some(path.into()),
34 line: None,
35 detail: detail.into(),
36 }
37 }
38
39 #[must_use]
41 pub fn on_line(
42 rule: RuleId,
43 path: impl Into<Utf8PathBuf>,
44 line: usize,
45 detail: impl Into<String>,
46 ) -> Self {
47 Self {
48 rule,
49 path: Some(path.into()),
50 line: Some(line),
51 detail: detail.into(),
52 }
53 }
54
55 #[must_use]
57 pub fn global(rule: RuleId, detail: impl Into<String>) -> Self {
58 Self {
59 rule,
60 path: None,
61 line: None,
62 detail: detail.into(),
63 }
64 }
65}
66
67impl fmt::Display for Finding {
68 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
69 write!(f, "FAIL {}", self.rule)?;
70 if let Some(path) = &self.path {
71 write!(f, " {path}")?;
72 if let Some(line) = self.line {
73 write!(f, ":{line}")?;
74 }
75 }
76 if self.detail.is_empty() {
77 return Ok(());
78 }
79 write!(f, ": {}", self.detail)
80 }
81}
82
83#[cfg(test)]
84mod tests {
85 use super::*;
86
87 #[test]
88 fn renders_with_path_and_line() {
89 let finding = Finding::on_line(
90 RuleId::BugzillaReportBodyFitsReportWidth,
91 "_docs/reference/known-issues/KI-vendor-500.md",
92 12,
93 "83 columns",
94 );
95 assert_eq!(
96 finding.to_string(),
97 "FAIL known-issues:a-bugzilla-report-body-fits-in-79-columns \
98 _docs/reference/known-issues/KI-vendor-500.md:12: 83 columns"
99 );
100 }
101
102 #[test]
103 fn renders_without_a_path() {
104 let finding = Finding::global(
105 RuleId::GateMessageCitesTheRule,
106 "x:y resolves to no requirement",
107 );
108 assert_eq!(
109 finding.to_string(),
110 "FAIL spec-to-code:a-gate-message-cites-the-rule: x:y resolves to no requirement"
111 );
112 }
113}