ito_core/validate/
issue.rs1use super::{LEVEL_ERROR, LEVEL_INFO, LEVEL_WARNING, ValidationIssue, ValidationLevel};
16
17pub fn issue(
22 level: ValidationLevel,
23 path: impl AsRef<str>,
24 message: impl Into<String>,
25) -> ValidationIssue {
26 ValidationIssue {
27 level: level.to_string(),
28 path: path.as_ref().to_string(),
29 message: message.into(),
30 line: None,
31 column: None,
32 metadata: None,
33 }
34}
35
36pub fn error(path: impl AsRef<str>, message: impl Into<String>) -> ValidationIssue {
40 issue(LEVEL_ERROR, path, message)
41}
42
43pub fn warning(path: impl AsRef<str>, message: impl Into<String>) -> ValidationIssue {
48 issue(LEVEL_WARNING, path, message)
49}
50
51pub fn info(path: impl AsRef<str>, message: impl Into<String>) -> ValidationIssue {
56 issue(LEVEL_INFO, path, message)
57}
58
59pub fn with_line(mut i: ValidationIssue, line: u32) -> ValidationIssue {
63 i.line = Some(line);
64 i
65}
66
67pub fn with_loc(mut i: ValidationIssue, line: u32, column: u32) -> ValidationIssue {
71 i.line = Some(line);
72 i.column = Some(column);
73 i
74}
75
76pub fn with_metadata(mut i: ValidationIssue, metadata: serde_json::Value) -> ValidationIssue {
81 i.metadata = Some(metadata);
82 i
83}
84
85#[cfg(test)]
86mod tests {
87 use super::*;
88
89 #[test]
90 fn constructors_set_expected_fields() {
91 let err = error("spec.md", "missing requirement");
92 let warn = warning("spec.md", "brief purpose");
93 let info_issue = info("spec.md", "looks good");
94
95 assert_eq!(err.level, LEVEL_ERROR);
96 assert_eq!(err.path, "spec.md");
97 assert_eq!(err.message, "missing requirement");
98 assert_eq!(err.line, None);
99 assert_eq!(err.column, None);
100 assert_eq!(err.metadata, None);
101
102 assert_eq!(warn.level, LEVEL_WARNING);
103 assert_eq!(info_issue.level, LEVEL_INFO);
104 }
105
106 #[test]
107 fn location_helpers_set_line_and_column() {
108 let base = issue(LEVEL_WARNING, "tasks.md", "task warning");
109
110 let with_line_only = with_line(base.clone(), 8);
111 assert_eq!(with_line_only.line, Some(8));
112 assert_eq!(with_line_only.column, None);
113
114 let with_both = with_loc(base, 11, 3);
115 assert_eq!(with_both.line, Some(11));
116 assert_eq!(with_both.column, Some(3));
117 }
118
119 #[test]
120 fn metadata_helper_attaches_json_context() {
121 let base = issue(LEVEL_ERROR, "config.json", "invalid value");
122 let metadata = serde_json::json!({ "expected": "string", "actual": 42 });
123
124 let enriched = with_metadata(base, metadata.clone());
125
126 assert_eq!(enriched.metadata, Some(metadata));
127 }
128}