use std::collections::BTreeSet;
use std::path::Path;
use crate::docs::tests::{run, wide};
use crate::docs::{Check, analyze};
fn kitchen_sink() -> String {
let mut doc = String::new();
doc.push_str("##\n"); doc.push_str("#Heading\n"); doc.push_str("trailing \n"); doc.push_str("has\ttab\n"); doc.push_str(&format!("{}\n", wide(130))); doc.push_str("see https://example.com/x\n"); doc.push_str("[broken](\n"); doc.push_str("\n\n\n"); doc.push_str("```rust\n"); doc.push_str("fn main() {}\n");
doc.push('\n'); doc
}
#[test]
fn every_check_can_fire() {
let fired: BTreeSet<String> = run(&kitchen_sink()).into_iter().map(|f| f.kind).collect();
let expected: BTreeSet<String> = Check::ALL.iter().map(|c| c.as_str().to_owned()).collect();
assert_eq!(fired, expected);
}
#[test]
fn findings_are_sorted_by_position() {
let findings = run(&kitchen_sink());
let positions: Vec<(u32, Option<u32>)> = findings.iter().map(|f| (f.line, f.column)).collect();
let mut sorted = positions.clone();
sorted.sort_unstable();
assert_eq!(positions, sorted, "output must read top to bottom");
}
#[test]
fn two_runs_over_the_same_content_are_identical() {
assert_eq!(run(&kitchen_sink()), run(&kitchen_sink()));
}
#[test]
fn a_clean_document_produces_nothing() {
let content = "# Title\n\nSome prose with a [link](https://example.com).\n\n\
```rust\nfn main() {}\n```\n\nMore prose.\n";
assert_eq!(run(content), Vec::new());
}
#[test]
fn empty_and_blank_documents_are_distinguished() {
assert_eq!(run(""), Vec::new());
let findings = run("\n");
let positions: Vec<_> = findings
.iter()
.map(|finding| (finding.kind.as_str(), finding.line, finding.column))
.collect();
assert_eq!(positions, vec![("trailing_blank_lines", 1, Some(1))]);
}
#[test]
fn every_finding_carries_the_path_it_was_given() {
let findings = analyze(Path::new("docs/guide.md"), &kitchen_sink());
assert!(!findings.is_empty());
for finding in findings {
assert_eq!(finding.file_path, "docs/guide.md");
}
}
#[test]
fn every_finding_carries_a_suggestion_and_a_severity_from_its_check() {
for finding in run(&kitchen_sink()) {
let check = Check::ALL
.into_iter()
.find(|c| c.as_str() == finding.kind)
.expect("kind must be a declared check");
assert_eq!(finding.severity, check.severity(), "{}", finding.kind);
assert_eq!(
finding.suggestion.as_deref(),
Some(check.suggestion()),
"{}",
finding.kind
);
}
}
#[test]
fn a_crlf_document_does_not_report_the_carriage_return_as_whitespace() {
let findings = run("# Title\r\n\r\nprose\r\n");
assert_eq!(findings, Vec::new(), "{findings:?}");
}
#[test]
fn a_line_number_is_never_zero() {
for finding in run(&kitchen_sink()) {
assert!(finding.line >= 1, "{}", finding.kind);
assert!(finding.column.is_some_and(|c| c >= 1), "{}", finding.kind);
}
}