use crate::docs::Check;
use crate::docs::tests::{fires_once_at, of_kind, run, silent, wide};
fn fence_sensitive() -> Vec<(Check, String)> {
vec),
]
}
fn fence_blind() -> Vec<(Check, String)> {
vec![(Check::TrailingWhitespace, "text ".to_owned())]
}
const STRUCTURAL: [Check; 3] = [
Check::MultipleBlankLines,
Check::TrailingBlankLines,
Check::UnclosedCodeFence,
];
#[test]
fn every_check_has_declared_a_fence_position() {
let mut declared: Vec<&str> = fence_sensitive()
.iter()
.chain(fence_blind().iter())
.map(|(c, _)| c.as_str())
.chain(STRUCTURAL.iter().map(|c| c.as_str()))
.collect();
declared.sort_unstable();
let mut all: Vec<&str> = Check::ALL.iter().map(|c| c.as_str()).collect();
all.sort_unstable();
assert_eq!(
declared, all,
"a check must appear in exactly one of fence_sensitive / fence_blind / \
STRUCTURAL - if you added one, decide what it does inside a fence"
);
}
#[test]
fn fence_sensitive_checks_fire_in_prose() {
for (check, snippet) in fence_sensitive() {
assert_eq!(
of_kind(&snippet, check).len(),
1,
"{} must fire on {snippet:?} standing alone",
check.as_str()
);
}
}
#[test]
fn fence_sensitive_checks_are_silent_inside_a_fence() {
for (check, snippet) in fence_sensitive() {
let fenced = format!("```text\n{snippet}\n```\n");
silent(&fenced, check);
}
}
#[test]
fn fence_blind_checks_fire_in_prose_and_inside_a_fence() {
for (check, snippet) in fence_blind() {
assert_eq!(of_kind(&snippet, check).len(), 1, "{}", check.as_str());
let fenced = format!("```text\n{snippet}\n```\n");
fires_once_at(&fenced, check, 2, snippet.chars().count() as u32 - 1);
}
}
#[test]
fn the_delimiter_line_is_itself_inside_the_fence() {
let opener = format!("```{}", wide(130));
let content = format!("{opener}\ncode\n```\n");
silent(&content, Check::LongLine);
assert_eq!(of_kind(&opener.replace('`', "x"), Check::LongLine).len(), 1);
}
#[test]
fn an_indented_fence_still_opens_a_fence() {
let content = "- item:\n\n ```bash\n #!/bin/bash\n ```\n";
silent(content, Check::MissingSpaceAfterHeading);
}
#[test]
fn text_after_a_closing_fence_is_prose_again() {
let content = "```bash\n#!/bin/bash\n```\n\n#Heading\n";
fires_once_at(content, Check::MissingSpaceAfterHeading, 5, 2);
}
#[test]
fn a_file_with_no_fence_at_all_leaves_every_line_in_prose() {
let content = "#Heading\n\nmore\n";
assert!(run(content).iter().any(|f| f.line == 1));
}