use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct DeadPattern {
pub scope: String,
pub pattern: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ScopesLintReport {
pub roots: Vec<String>,
pub project_only: bool,
pub scopes_checked: usize,
pub files_checked: usize,
pub dead_patterns: Vec<DeadPattern>,
pub unscoped_files: Vec<String>,
}
impl ScopesLintReport {
#[must_use]
pub fn has_violations(&self) -> bool {
!self.dead_patterns.is_empty() || !self.unscoped_files.is_empty()
}
#[must_use]
pub fn exit_code(&self) -> i32 {
i32::from(self.has_violations())
}
}
#[cfg(test)]
mod tests {
use super::*;
fn clean_report() -> ScopesLintReport {
ScopesLintReport {
roots: vec!["src".to_string()],
project_only: true,
scopes_checked: 1,
files_checked: 1,
dead_patterns: Vec::new(),
unscoped_files: Vec::new(),
}
}
#[test]
fn clean_report_has_no_violations() {
let report = clean_report();
assert!(!report.has_violations());
assert_eq!(report.exit_code(), 0);
}
#[test]
fn dead_pattern_only_is_a_violation() {
let mut report = clean_report();
report.dead_patterns.push(DeadPattern {
scope: "cli".to_string(),
pattern: "src/nonexistent/**".to_string(),
});
assert!(report.has_violations());
assert_eq!(report.exit_code(), 1);
}
#[test]
fn unscoped_file_only_is_a_violation() {
let mut report = clean_report();
report.unscoped_files.push("src/worktrees.rs".to_string());
assert!(report.has_violations());
assert_eq!(report.exit_code(), 1);
}
}