src/page-template.test.lua

108 lines

1#!/usr/bin/env lua
2
3-- Tests for page-template: the marker substitution engine behind the editable
4-- explore-page copy (Issue 11-005). Run directly: luajit src/page-template.test.lua
5-- Every behavior the explore generators rely on has a case here, because the
6-- whole point of the module is that a typo'd marker fails loudly instead of
7-- shipping broken text to the live site.
8
9-- {{{ setup_path()
10-- Resolve the module relative to this test file so it runs from any directory.
11local function setup_path()
12 local this = debug.getinfo(1, "S").source:sub(2)
13 local dir = this:match("(.*/)") or "./"
14 package.path = dir .. "?.lua;" .. package.path
15 return dir
16end
17-- }}}
18
19local DIR = setup_path()
20local tmpl = require("page-template")
21
22local passed, failed = 0, 0
23
24-- {{{ check()
25local function check(name, cond)
26 if cond then
27 passed = passed + 1
28 print(" ok " .. name)
29 else
30 failed = failed + 1
31 print(" FAIL " .. name)
32 end
33end
34-- }}}
35
36-- Plain scalar substitution, strings and numbers both stringified.
37do
38 local out = tmpl.substitute("{A} poems across {B} sources", { A = 42, B = "three" })
39 check("scalars fill in", out == "42 poems across three sources")
40end
41
42-- Lowercase braces are not markers and must survive untouched.
43do
44 local out = tmpl.substitute("keep {this} literal {NAME}", { NAME = "ok" })
45 check("lowercase braces untouched", out == "keep {this} literal ok")
46end
47
48-- An unknown marker is an error, and the message names it (the core promise).
49do
50 local out, err = tmpl.substitute("hello {MISSING}", {})
51 check("missing marker -> nil", out == nil)
52 check("missing marker named in error", err ~= nil and err:find("MISSING", 1, true) ~= nil)
53end
54
55-- Every missing marker is reported at once, not one rebuild at a time.
56do
57 local _, err = tmpl.substitute("{ONE} {TWO}", {})
58 check("all missing markers reported", err:find("ONE", 1, true) and err:find("TWO", 1, true))
59end
60
61-- OMIT drops the whole line that mentions it, leaving no blank gap.
62do
63 local t = "line one\n{GONE} should vanish\nline three"
64 local out = tmpl.substitute(t, { GONE = tmpl.OMIT })
65 check("OMIT drops the line", out == "line one\nline three")
66end
67
68-- A surviving (kept) line with a real value is unaffected by OMIT elsewhere.
69do
70 local t = "{KEEP} stays\n{DROP} goes"
71 local out = tmpl.substitute(t, { KEEP = "X", DROP = tmpl.OMIT })
72 check("OMIT is per-line", out == "X stays")
73end
74
75-- Percent signs in a value must not be treated as gsub specials.
76do
77 local out = tmpl.substitute("rate {R}", { R = "50% done %s" })
78 check("percent signs are literal", out == "rate 50% done %s")
79end
80
81-- A multi-line block value (the way the source list / bar charts are injected).
82do
83 local block = " a\n b\n c"
84 local out = tmpl.substitute("head:\n{BLOCK}\ntail", { BLOCK = block })
85 check("block value spans lines", out == "head:\n a\n b\n c\ntail")
86end
87
88-- Trailing-newline structure is preserved through the OMIT split/rejoin.
89do
90 local out = tmpl.substitute("a\nb\n", { })
91 check("trailing newline preserved", out == "a\nb\n")
92end
93
94-- Wrong argument types are caught at the door.
95do
96 local out, err = tmpl.substitute(nil, {})
97 check("non-string template -> error", out == nil and err ~= nil)
98end
99
100-- render_file: a missing file is a clear error, not a crash.
101do
102 local out, err = tmpl.render_file(DIR .. "no-such-template.txt", {})
103 check("missing file -> error", out == nil and err ~= nil and err:find("could not open", 1, true))
104end
105
106print(string.format("\npage-template: %d passed, %d failed", passed, failed))
107os.exit(failed == 0 and 0 or 1)
108