mod common;
use common::{copy_store_to_temp, corpus_a, dbmd, write_db_md, write_file};
const SCRAMBLED: &str = "\
---
summary: a contact
tags:
- vip
status: active
updated: 2026-05-02T00:00:00+00:00
created: 2026-05-01T00:00:00+00:00
type: contact
email: sarah@acme.com
---
# Sarah
Body stays [[records/companies/acme]] verbatim.
";
#[test]
fn reorders_frontmatter_to_canonical_and_reports_changed() {
let tmp = tempfile::TempDir::new().unwrap();
write_db_md(tmp.path());
let file = write_file(tmp.path(), "records/contacts/sarah.md", SCRAMBLED);
let out = dbmd().arg("format").arg(&file).assert().success();
let stdout = String::from_utf8(out.get_output().stdout.clone()).unwrap();
assert!(
stdout.contains("formatted records/contacts/sarah.md"),
"text mode reports the store-relative formatted path: {stdout:?}"
);
let rewritten = std::fs::read_to_string(&file).unwrap();
let order: Vec<&str> = [
"type", "created", "updated", "summary", "email", "status", "tags",
]
.into_iter()
.collect();
let positions: Vec<usize> = order
.iter()
.map(|k| {
rewritten
.find(&format!("{k}:"))
.unwrap_or_else(|| panic!("`{k}:` present after format:\n{rewritten}"))
})
.collect();
let mut sorted = positions.clone();
sorted.sort();
assert_eq!(
positions, sorted,
"keys are in canonical order:\n{rewritten}"
);
assert!(rewritten.contains("Body stays [[records/companies/acme]] verbatim."));
assert!(rewritten.starts_with("---\n"));
assert!(rewritten.contains("\n---\n"));
}
#[test]
fn already_canonical_file_reports_unchanged() {
let tmp = tempfile::TempDir::new().unwrap();
write_db_md(tmp.path());
let file = write_file(tmp.path(), "records/contacts/sarah.md", SCRAMBLED);
dbmd().arg("format").arg(&file).assert().success();
let canonical = std::fs::read_to_string(&file).unwrap();
let out = dbmd()
.arg("--json")
.arg("format")
.arg(&file)
.assert()
.success();
let stdout = String::from_utf8(out.get_output().stdout.clone()).unwrap();
let parsed: serde_json::Value = serde_json::from_str(&stdout).unwrap();
assert_eq!(parsed["file"], "records/contacts/sarah.md");
assert_eq!(parsed["changed"], false, "idempotent on a canonical file");
assert_eq!(
std::fs::read_to_string(&file).unwrap(),
canonical,
"a no-op format leaves the bytes untouched"
);
}
#[test]
fn format_is_idempotent() {
let tmp = tempfile::TempDir::new().unwrap();
write_db_md(tmp.path());
let file = write_file(tmp.path(), "records/contacts/sarah.md", SCRAMBLED);
dbmd().arg("format").arg(&file).assert().success();
let once = std::fs::read_to_string(&file).unwrap();
dbmd().arg("format").arg(&file).assert().success();
let twice = std::fs::read_to_string(&file).unwrap();
assert_eq!(once, twice, "format(format(x)) == format(x)");
}
#[test]
fn frozen_page_is_refused_exit_four_no_write() {
let tmp = tempfile::TempDir::new().unwrap();
std::fs::write(
tmp.path().join("DB.md"),
"---\ntype: db-md\nscope: company\nowner: T\n---\n\n# S\n\n\
## Policies\n\n### Frozen pages\n- `wiki/synthesis/plan.md` — signed off.\n",
)
.unwrap();
let file = write_file(
tmp.path(),
"wiki/synthesis/plan.md",
SCRAMBLED, );
let before = std::fs::read_to_string(&file).unwrap();
dbmd().arg("format").arg(&file).assert().failure().code(4);
assert_eq!(
std::fs::read_to_string(&file).unwrap(),
before,
"a refused format must not modify the frozen file"
);
}
#[test]
fn corpus_a_copy_format_preserves_body_and_is_idempotent() {
let (_guard, store) = copy_store_to_temp(&corpus_a());
let file = store.join("records/contacts/sarah-chen.md");
let original = std::fs::read_to_string(&file).unwrap();
let original_body = original.rsplit_once("\n---\n").map(|(_, b)| b.to_string());
dbmd().arg("format").arg(&file).assert().success();
let once = std::fs::read_to_string(&file).unwrap();
if let Some(body) = &original_body {
let after_body = once.rsplit_once("\n---\n").map(|(_, b)| b.to_string());
assert_eq!(
after_body.as_ref(),
Some(body),
"the markdown body is preserved verbatim across a reformat"
);
}
let out = dbmd()
.arg("--json")
.arg("format")
.arg(&file)
.assert()
.success();
let stdout = String::from_utf8(out.get_output().stdout.clone()).unwrap();
let parsed: serde_json::Value = serde_json::from_str(&stdout).unwrap();
assert_eq!(
parsed["changed"], false,
"the second format of an already-canonical file is a no-op"
);
assert_eq!(std::fs::read_to_string(&file).unwrap(), once);
}
#[test]
fn missing_file_is_error() {
let tmp = tempfile::TempDir::new().unwrap();
write_db_md(tmp.path());
let missing = tmp.path().join("records/contacts/ghost.md");
dbmd().arg("format").arg(&missing).assert().failure();
}