171 lines
5.8 KiB
Rust
171 lines
5.8 KiB
Rust
//! Tests of `tp.file.include` and of the Bases fallback (spec D3).
|
|
|
|
use std::collections::BTreeMap;
|
|
|
|
use notescraft_bases::Value;
|
|
use notescraft_templater::{Answers, Ctx, Rendered, parse};
|
|
use notescraft_templates::{Date, DateTime, Weekday};
|
|
|
|
/// The reference moment of the tests: Tuesday, 2026-10-13 15:04:05.
|
|
fn now() -> DateTime {
|
|
DateTime::new(Date::new(2026, 10, 13).unwrap(), 15, 4, 5).unwrap()
|
|
}
|
|
|
|
/// The notes of the tests, by path.
|
|
fn notes() -> BTreeMap<String, String> {
|
|
let mut notes = BTreeMap::new();
|
|
notes.insert("Note.md".to_owned(), "# Title\n\nIntro.\n\n## Section\n\nSection body.\n\n## Other\n\nOther body.\n".to_owned());
|
|
notes.insert("Block.md".to_owned(), "First paragraph.\n\nSecond paragraph with an id ^abc\n\nThird paragraph.\n".to_owned());
|
|
notes.insert("Templated.md".to_owned(), "Hello <% tp.file.title %>!\n".to_owned());
|
|
notes.insert("A.md".to_owned(), "<% tp.file.include(\"[[A]]\") %>\n".to_owned());
|
|
notes
|
|
}
|
|
|
|
/// The tags of the target note.
|
|
fn tags() -> Vec<String> {
|
|
vec!["alpha".to_owned()]
|
|
}
|
|
|
|
/// The frontmatter of the target note.
|
|
fn frontmatter() -> Vec<(String, Value)> {
|
|
vec![("project".to_owned(), Value::Str("NotesCraft".to_owned()))]
|
|
}
|
|
|
|
/// A context with the notes of the tests.
|
|
fn ctx<'a>(read_note: &'a dyn Fn(&str) -> Option<String>, exists: &'a dyn Fn(&str) -> bool, tags: &'a [String], frontmatter: &'a [(String, Value)]) -> Ctx<'a> {
|
|
Ctx {
|
|
title: "Note",
|
|
folder: "Folder",
|
|
path: "Folder/Note.md",
|
|
absolute_path: Some("/vault/Folder/Note.md"),
|
|
now: now(),
|
|
week_start: Weekday::Monday,
|
|
created: Some(now()),
|
|
modified: Some(now()),
|
|
tags,
|
|
frontmatter,
|
|
selection: "",
|
|
clipboard: "",
|
|
read_note,
|
|
exists,
|
|
}
|
|
}
|
|
|
|
/// Renders a template with the notes of the tests.
|
|
fn render(template: &str) -> Rendered {
|
|
let notes = notes();
|
|
let read_note = |path: &str| notes.get(path).cloned();
|
|
let exists = |_: &str| -> bool { true };
|
|
let tags = tags();
|
|
let frontmatter = frontmatter();
|
|
let ctx = ctx(&read_note, &exists, &tags, &frontmatter);
|
|
let template = parse(template).expect("the template parses");
|
|
template.render(&ctx, &Answers::default())
|
|
}
|
|
|
|
#[test]
|
|
fn a_whole_note_is_included() {
|
|
let rendered = render("<% tp.file.include(\"[[Note]]\") %>");
|
|
assert_eq!(rendered.text, notes()["Note.md"]);
|
|
assert_eq!(rendered.errors, Vec::new());
|
|
}
|
|
|
|
#[test]
|
|
fn a_note_is_included_without_brackets() {
|
|
let rendered = render("<% tp.file.include(\"Note\") %>");
|
|
assert_eq!(rendered.text, notes()["Note.md"]);
|
|
assert_eq!(rendered.errors, Vec::new());
|
|
}
|
|
|
|
#[test]
|
|
fn a_heading_section_is_included() {
|
|
let rendered = render("<% tp.file.include(\"[[Note#Section]]\") %>");
|
|
assert_eq!(rendered.text, "## Section\n\nSection body.\n\n");
|
|
assert_eq!(rendered.errors, Vec::new());
|
|
}
|
|
|
|
#[test]
|
|
fn a_block_is_included() {
|
|
let rendered = render("<% tp.file.include(\"[[Block#^abc]]\") %>");
|
|
assert_eq!(rendered.text, "Second paragraph with an id");
|
|
assert_eq!(rendered.errors, Vec::new());
|
|
}
|
|
|
|
#[test]
|
|
fn the_templates_inside_an_included_note_are_rendered() {
|
|
let rendered = render("<% tp.file.include(\"[[Templated]]\") %>");
|
|
assert_eq!(rendered.text, "Hello Note!\n");
|
|
assert_eq!(rendered.errors, Vec::new());
|
|
}
|
|
|
|
#[test]
|
|
fn a_cycle_stops_with_an_error() {
|
|
let rendered = render("<% tp.file.include(\"[[A]]\") %>");
|
|
assert_eq!(rendered.errors.len(), 1, "{:?}", rendered.errors);
|
|
assert!(rendered.errors[0].message.contains("deeper than 4 levels"), "{}", rendered.errors[0].message);
|
|
assert_eq!(rendered.text, "<% tp.file.include(\"[[A]]\") %>\n\n\n\n");
|
|
}
|
|
|
|
#[test]
|
|
fn a_missing_note_is_reported() {
|
|
let rendered = render("<% tp.file.include(\"[[Missing]]\") %>");
|
|
assert_eq!(rendered.errors.len(), 1);
|
|
assert!(rendered.errors[0].message.contains("does not exist"), "{}", rendered.errors[0].message);
|
|
assert_eq!(rendered.text, "<% tp.file.include(\"[[Missing]]\") %>");
|
|
}
|
|
|
|
#[test]
|
|
fn a_missing_section_is_reported() {
|
|
let rendered = render("<% tp.file.include(\"[[Note#Nowhere]]\") %>");
|
|
assert_eq!(rendered.errors.len(), 1);
|
|
assert!(rendered.errors[0].message.contains("is not in the note"), "{}", rendered.errors[0].message);
|
|
}
|
|
|
|
#[test]
|
|
fn a_bases_expression_is_evaluated() {
|
|
let rendered = render("<% file.name.upper() %>");
|
|
assert_eq!(rendered.text, "NOTE.MD");
|
|
assert_eq!(rendered.errors, Vec::new());
|
|
}
|
|
|
|
#[test]
|
|
fn a_bases_path_reads_the_note_of_the_context() {
|
|
let rendered = render("<% file.folder %>|<% file.basename %>");
|
|
assert_eq!(rendered.text, "Folder|Note");
|
|
assert_eq!(rendered.errors, Vec::new());
|
|
}
|
|
|
|
#[test]
|
|
fn a_bases_path_works_inside_a_template_command() {
|
|
let rendered = render("<% tp.file.title + file.name %>");
|
|
assert_eq!(rendered.text, "NoteNote.md");
|
|
assert_eq!(rendered.errors, Vec::new());
|
|
}
|
|
|
|
#[test]
|
|
fn the_date_of_the_fallback_is_the_date_of_the_module() {
|
|
let fallback = render("<% now().format(\"YYYY\") %>");
|
|
let module = render("<% tp.date.now(\"YYYY\") %>");
|
|
assert_eq!(fallback.text, "2026");
|
|
assert_eq!(fallback.text, module.text);
|
|
assert_eq!(fallback.errors, Vec::new());
|
|
let dated = render("<% date(now()).format(\"YYYY\") %>");
|
|
assert_eq!(dated.text, module.text);
|
|
assert_eq!(dated.errors, Vec::new());
|
|
}
|
|
|
|
#[test]
|
|
fn a_failing_bases_expression_is_reported() {
|
|
let rendered = render("<% file.nope() %>");
|
|
assert_eq!(rendered.errors.len(), 1, "{:?}", rendered.errors);
|
|
assert_eq!(rendered.text, "<% file.nope() %>");
|
|
}
|
|
|
|
#[test]
|
|
fn an_unknown_template_command_is_not_a_bases_expression() {
|
|
let rendered = render("<% tp.foo.bar %>");
|
|
assert_eq!(rendered.errors.len(), 1);
|
|
assert_eq!(rendered.errors[0].message, "tp.foo.bar is not supported");
|
|
assert_eq!(rendered.text, "<% tp.foo.bar %>");
|
|
}
|