#![allow(clippy::pedantic)]
use std::path::{Path, PathBuf};
use std::process::Command;
const TYPO: &str = "definitly";
const SYNTAXES: &[(&str, &str, &str, &str)] = &[
("markdown", "md", "<!-- ", " -->"),
("latex", "tex", "% ", ""),
("typst", "typ", "// ", ""),
];
fn temp_workspace() -> PathBuf {
let dir = std::env::temp_dir().join(format!(
"lang_check_directives_{}_{}",
std::process::id(),
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_nanos()
));
std::fs::create_dir_all(&dir).unwrap();
std::fs::write(
dir.join(".languagecheck.yaml"),
"engines:\n harper:\n enabled: true\n languagetool:\n enabled: false\n spell_language: en-US\n",
)
.unwrap();
dir
}
fn flagged_lines(dir: &Path, name: &str, lang: &str) -> Vec<usize> {
let output = Command::new(env!("CARGO_BIN_EXE_language-check"))
.current_dir(dir)
.args(["check", name, "--lang", lang, "--format", "json"])
.output()
.expect("run language-check");
let stdout = String::from_utf8(output.stdout).expect("utf8 stdout");
let parsed: serde_json::Value = serde_json::from_str(&stdout)
.unwrap_or_else(|e| panic!("JSON from {name}: {e}\n--- stdout ---\n{stdout}"));
let mut lines: Vec<usize> = parsed
.as_array()
.unwrap_or_else(|| panic!("unexpected JSON shape from {name}: {parsed}"))
.iter()
.map(|d| {
usize::try_from(
d.get("line")
.and_then(serde_json::Value::as_u64)
.expect("every diagnostic carries a line"),
)
.unwrap()
})
.collect();
lines.sort_unstable();
lines.dedup();
lines
}
fn begin_end_document(open: &str, close: &str) -> String {
format!(
"A {TYPO} sentence here.\n\
\n\
{open}lang-check-begin{close}\n\
Another {TYPO} sentence in the region.\n\
{open}lang-check-end{close}\n\
\n\
A final {TYPO} sentence.\n"
)
}
fn disable_document(open: &str, close: &str) -> String {
format!(
"A {TYPO} sentence here.\n\
\n\
{open}lang-check-disable{close}\n\
Another {TYPO} sentence in the region.\n\
{open}lang-check-enable{close}\n\
\n\
{open}lang-check-disable-next-line{close}\n\
A nextline {TYPO} sentence.\n\
\n\
A final {TYPO} sentence.\n"
)
}
#[test]
fn begin_end_region_is_suppressed_in_every_format() {
let dir = temp_workspace();
for &(lang, ext, open, close) in SYNTAXES {
let name = format!("region.{ext}");
std::fs::write(dir.join(&name), begin_end_document(open, close)).unwrap();
assert_eq!(
flagged_lines(&dir, &name, lang),
vec![1, 7],
"begin/end region not honoured in {lang}"
);
}
}
#[test]
fn disable_directives_are_honoured_in_every_format() {
let dir = temp_workspace();
for &(lang, ext, open, close) in SYNTAXES {
let name = format!("disable.{ext}");
std::fs::write(dir.join(&name), disable_document(open, close)).unwrap();
assert_eq!(
flagged_lines(&dir, &name, lang),
vec![1, 10],
"disable directives not honoured in {lang}"
);
}
}
#[test]
fn a_document_without_directives_keeps_every_diagnostic() {
let dir = temp_workspace();
std::fs::write(
dir.join("plain.md"),
format!("A {TYPO} sentence here.\n\nA final {TYPO} sentence.\n"),
)
.unwrap();
assert_eq!(flagged_lines(&dir, "plain.md", "markdown"), vec![1, 3]);
}