pub mod format;
pub mod frontmatter;
mod adr001;
mod adr002;
mod adr003;
mod adr004;
mod adr005;
mod adr006;
mod adr007;
mod adr008;
mod adr009;
mod adr010;
mod adr011;
mod adr012;
mod adr013;
mod adr014;
mod adr015;
mod adr016;
mod adr017;
use crate::{RuleProvider, RuleRegistry};
pub use adr001::Adr001;
pub use adr002::Adr002;
pub use adr003::Adr003;
pub use adr004::Adr004;
pub use adr005::Adr005;
pub use adr006::Adr006;
pub use adr007::Adr007;
pub use adr008::Adr008;
pub use adr009::Adr009;
pub use adr010::Adr010;
pub use adr011::Adr011;
pub use adr012::Adr012;
pub use adr013::Adr013;
pub use adr014::Adr014;
pub use adr015::Adr015;
pub use adr016::Adr016;
pub use adr017::Adr017;
pub use format::AdrFormat;
pub use frontmatter::AdrFrontmatter;
pub struct AdrRuleProvider;
impl RuleProvider for AdrRuleProvider {
fn provider_id(&self) -> &'static str {
"adr"
}
fn description(&self) -> &'static str {
"Architecture Decision Record linting rules (ADR001-ADR017)"
}
fn version(&self) -> &'static str {
"0.1.0"
}
fn register_rules(&self, registry: &mut RuleRegistry) {
registry.register(Box::new(Adr001::default()));
registry.register(Box::new(Adr002::default()));
registry.register(Box::new(Adr003::default()));
registry.register(Box::new(Adr004::default()));
registry.register(Box::new(Adr005::default()));
registry.register(Box::new(Adr006::default()));
registry.register(Box::new(Adr007::default()));
registry.register(Box::new(Adr008::default()));
registry.register(Box::new(Adr009::default()));
registry.register(Box::new(Adr014::default()));
registry.register(Box::new(Adr015::default()));
registry.register(Box::new(Adr016::default()));
registry.register(Box::new(Adr017::default()));
registry.register_collection_rule(Box::new(Adr010));
registry.register_collection_rule(Box::new(Adr011));
registry.register_collection_rule(Box::new(Adr012));
registry.register_collection_rule(Box::new(Adr013));
}
fn rule_ids(&self) -> Vec<&'static str> {
vec![
"ADR001", "ADR002", "ADR003", "ADR004", "ADR005", "ADR006", "ADR007", "ADR008",
"ADR009", "ADR010", "ADR011", "ADR012", "ADR013", "ADR014", "ADR015", "ADR016",
"ADR017",
]
}
}
#[cfg(test)]
mod tests {
use super::*;
use mdbook_lint_core::Document;
use mdbook_lint_core::rule::Rule;
use std::path::PathBuf;
fn create_test_document(content: &str) -> Document {
Document::new(content.to_string(), PathBuf::from("adr/0001-test-adr.md")).unwrap()
}
#[test]
fn test_provider_metadata() {
let provider = AdrRuleProvider;
assert_eq!(provider.provider_id(), "adr");
assert!(provider.description().contains("ADR"));
assert_eq!(provider.version(), "0.1.0");
}
#[test]
fn test_provider_rule_ids() {
let provider = AdrRuleProvider;
let ids = provider.rule_ids();
assert!(ids.contains(&"ADR001"));
assert!(ids.contains(&"ADR002"));
assert!(ids.contains(&"ADR003"));
}
#[test]
fn test_valid_nygard_adr() {
let content = r#"# 1. Use Rust for implementation
Date: 2024-01-15
## Status
Accepted
## Context
We need to choose a programming language.
## Decision
We will use Rust.
## Consequences
Team will need Rust training.
"#;
let doc = create_test_document(content);
let rule1 = Adr001::default();
let rule2 = Adr002::default();
let rule3 = Adr003::default();
assert!(rule1.check(&doc).unwrap().is_empty());
assert!(rule2.check(&doc).unwrap().is_empty());
assert!(rule3.check(&doc).unwrap().is_empty());
}
#[test]
fn test_valid_madr_adr() {
let content = r#"---
status: accepted
date: 2024-01-15
decision-makers:
- Alice Smith
---
# Use PostgreSQL for persistence
## Context and Problem Statement
We need to select a database.
## Decision Outcome
Chosen option: PostgreSQL.
"#;
let doc = create_test_document(content);
let rule1 = Adr001::default();
let rule2 = Adr002::default();
let rule3 = Adr003::default();
assert!(rule1.check(&doc).unwrap().is_empty());
assert!(rule2.check(&doc).unwrap().is_empty());
assert!(rule3.check(&doc).unwrap().is_empty());
}
#[test]
fn test_invalid_nygard_adr_all_rules_fail() {
let content = r#"# Use Rust
## Context
We need a language.
"#;
let doc = create_test_document(content);
let rule1 = Adr001::default();
let rule2 = Adr002::default();
let rule3 = Adr003::default();
assert!(!rule1.check(&doc).unwrap().is_empty(), "ADR001 should fail");
assert!(!rule2.check(&doc).unwrap().is_empty(), "ADR002 should fail");
assert!(!rule3.check(&doc).unwrap().is_empty(), "ADR003 should fail");
}
#[test]
fn test_invalid_madr_adr_missing_fields() {
let content = r#"---
decision-makers:
- Alice
---
# Title
## Context
Content.
"#;
let doc = create_test_document(content);
let rule1 = Adr001::default();
let rule2 = Adr002::default();
let rule3 = Adr003::default();
assert!(
rule1.check(&doc).unwrap().is_empty(),
"ADR001 should pass (title exists)"
);
assert!(
!rule2.check(&doc).unwrap().is_empty(),
"ADR002 should fail (no status)"
);
assert!(
!rule3.check(&doc).unwrap().is_empty(),
"ADR003 should fail (no date)"
);
}
}