use super::{MARKDOWN_FILE_PATTERNS, one_rule_configuration, write_configuration};
use crate::config_schema::MarkdownRule;
use crate::test_support::{fixture, remove};
use monochromatic_jsonc_edit::{JsoncValue, parse_jsonc, units_to_string};
use std::path::{Path, PathBuf};
fn text_of(value: &JsoncValue) -> String {
return units_to_string(value.text_units().expect("a string")).expect("valid text");
}
fn member<'a>(value: &'a JsoncValue, key: &str) -> &'a JsoncValue {
for entry in value.entries().expect("a record") {
if text_of(&JsoncValue::text_from_units(entry.key.units.clone())) == key {
return &entry.value;
}
}
panic!("no member {key}");
}
fn texts(value: &JsoncValue) -> Vec<String> {
let mut found: Vec<String> = Vec::new();
for element in value.elements().expect("an array") {
found.push(text_of(element));
}
return found;
}
#[test]
fn the_document_selects_the_rule_at_warn() {
let exclude: Vec<String> = vec![String::from("package/ssg/"), String::from("!keep.md")];
let document: String = one_rule_configuration(&[MarkdownRule::LfsImageUrl], exclude.as_slice());
let parsed: JsoncValue = parse_jsonc(document.as_str()).expect("valid JSON");
let blocks: &[JsoncValue] = parsed.elements().expect("a list of blocks");
assert_eq!(blocks.len(), 1);
assert_eq!(texts(member(&blocks[0], "files")), MARKDOWN_FILE_PATTERNS);
let rules: &JsoncValue = member(&blocks[0], "rules");
assert_eq!(rules.entries().expect("rules").len(), 1);
let lfs: &JsoncValue = member(rules, "markdown/lfs-image-url");
assert_eq!(text_of(member(lfs, "severity")), "warn");
assert_eq!(texts(member(lfs, "exclude")), exclude);
assert_eq!(
document,
one_rule_configuration(&[MarkdownRule::LfsImageUrl], exclude.as_slice()),
"the document is deterministic"
);
}
#[test]
fn empty_lists_stay_empty() {
let none: JsoncValue = parse_jsonc(one_rule_configuration(&[], &[]).as_str()).expect("JSON");
assert_eq!(
member(&none.elements().expect("blocks")[0], "rules")
.entries()
.expect("rules")
.len(),
0
);
let bare: JsoncValue =
parse_jsonc(one_rule_configuration(&[MarkdownRule::LfsImageUrl], &[]).as_str())
.expect("JSON");
let lfs: &JsoncValue = member(
member(&bare.elements().expect("blocks")[0], "rules"),
"markdown/lfs-image-url",
);
assert_eq!(texts(member(lfs, "exclude")), Vec::<String>::new());
}
#[test]
fn hostile_patterns_stay_data() {
let exclude: Vec<String> = [
"\"]}],{\"rules\":{}}",
"back\\slash\\",
"line\nbreak\r\n",
"*/ /* // comment",
"\u{0}\u{1f}\u{7f}",
"😀/\u{2028}",
"",
]
.iter()
.map(ToString::to_string)
.collect();
let document: String = one_rule_configuration(&[MarkdownRule::LfsImageUrl], exclude.as_slice());
let parsed: JsoncValue = parse_jsonc(document.as_str()).expect("still JSON");
let blocks: &[JsoncValue] = parsed.elements().expect("blocks");
assert_eq!(blocks.len(), 1);
let lfs: &JsoncValue = member(member(&blocks[0], "rules"), "markdown/lfs-image-url");
assert_eq!(texts(member(lfs, "exclude")), exclude);
}
#[test]
fn the_file_is_private_and_removed_when_dropped() {
use std::os::unix::fs::PermissionsExt;
let root: PathBuf = fixture("linter-config");
let file = write_configuration("[]", root.as_path()).expect("written");
let path: PathBuf = file.path().to_path_buf();
assert_eq!(path.parent(), Some(root.as_path()));
let name: String = path
.file_name()
.expect("name")
.to_string_lossy()
.into_owned();
assert!(
name.starts_with("cli-git-markdown-") && name.ends_with(".jsonc"),
"{name}"
);
assert_eq!(std::fs::read_to_string(&path).expect("readable"), "[]");
let mode: u32 = std::fs::metadata(&path)
.expect("metadata")
.permissions()
.mode();
assert_eq!(mode & 0o777, 0o600, "{mode:o}");
drop(file);
assert!(!path.exists());
remove(root.as_path());
}
#[test]
fn a_missing_directory_is_reported() {
let missing: &Path = Path::new("/nonexistent-cli-git-scratch");
match write_configuration("[]", missing) {
Err(reason) => assert!(
reason.starts_with(
"cli-git could not create the temporary linter configuration in /nonexistent-cli-git-scratch: "
),
"{reason}"
),
Ok(file) => panic!("created {:?}", file.path()),
}
}