use text_document::{BatchDocument, DjotExportOptions, DjotImportOptions, FindOptions};
fn round_trip(djot: &str) -> String {
let batch = BatchDocument::new().expect("BatchDocument::new");
batch
.set_djot(djot, &DjotImportOptions::default())
.expect("set_djot");
batch
.to_djot(&DjotExportOptions::default())
.expect("to_djot")
}
#[test]
fn a_batch_document_round_trips_djot() {
for source in [
"Just a plain paragraph.",
"A paragraph with *emphasis* and _more_ of it.",
"# A heading\n\nAnd a paragraph beneath it.",
"One paragraph.\n\nAnd a second one.",
] {
let out = round_trip(source);
assert_eq!(
out.trim(),
source.trim(),
"round-tripping this Djot changed it:\n in: {source:?}\n out: {out:?}"
);
}
}
#[test]
fn a_tight_list_comes_back_loose_and_that_is_known() {
let out = round_trip("- a list item\n- another one");
assert_eq!(
out.trim(),
"- a list item\n\n- another one",
"if this now round-trips tightly, the model learned tight/loose — delete this \
test and fold the case back into `a_batch_document_round_trips_djot`"
);
}
#[test]
fn a_batch_document_costs_no_thread() {
fn threads() -> usize {
std::fs::read_to_string("/proc/self/status")
.expect("/proc/self/status")
.lines()
.find_map(|l| l.strip_prefix("Threads:"))
.and_then(|v| v.trim().parse().ok())
.expect("Threads: line")
}
let before = threads();
let docs: Vec<BatchDocument> = (0..32)
.map(|i| {
let b = BatchDocument::new().expect("BatchDocument::new");
b.set_djot(
&format!("Scene {i}: she called his name into the trees."),
&DjotImportOptions::default(),
)
.expect("set_djot");
b
})
.collect();
let after = threads();
assert_eq!(docs.len(), 32);
assert!(
after <= before + 2,
"32 BatchDocuments started {} extra thread(s) ({before} -> {after}). \
BatchDocument exists precisely so a batch does not pay a thread per document; \
something reintroduced EventHubClient::start.",
after.saturating_sub(before)
);
}
#[test]
fn find_all_searches_the_prose_not_the_markup() {
let batch = BatchDocument::new().expect("BatchDocument::new");
batch
.set_djot(
"She called *Aurélien* into the trees, and Aurélien did not answer.",
&DjotImportOptions::default(),
)
.expect("set_djot");
let hits = batch
.find_all("Aurélien", &FindOptions::default())
.expect("find_all");
assert_eq!(
hits.len(),
2,
"both occurrences, including the emphasised one"
);
assert_eq!(
hits[0].position, 11,
"the offset must be into the parsed text; a Djot-source offset would be 12 \
(the emphasis marker) and would corrupt any replace built on it"
);
assert_eq!(hits[0].length, "Aurélien".chars().count());
}
#[test]
fn set_djot_replaces_rather_than_appends() {
let batch = BatchDocument::new().expect("BatchDocument::new");
batch
.set_djot("the first scene", &DjotImportOptions::default())
.expect("first");
batch
.set_djot("the second scene", &DjotImportOptions::default())
.expect("second");
let out = batch
.to_djot(&DjotExportOptions::default())
.expect("to_djot");
assert!(out.contains("second"), "the newest import must be present");
assert!(
!out.contains("first"),
"the previous import must be gone, not appended: {out:?}"
);
}