summaryrefslogtreecommitdiff
path: root/tests/cli.sh
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-06-16 18:00:47 +0300
committerPaul Buetow <paul@buetow.org>2026-06-16 18:00:47 +0300
commitcd7cf797bc633700c5ee7e986077f366c000f0b9 (patch)
treedb7bda7af7a71359cba6bc6c0557552e8659fe8c /tests/cli.sh
parentb58d9b3f656f2e6be803a1d2d567a066bb8b902a (diff)
hn0 make template render kind dispatch extensible (OCP)
Replace the hardcoded `case "$kind"` block in prepare_template_render_vars with a name-based registration/dispatch pattern. Each render field kind is now implemented by one prepare_template_render_var__<kind> handler; the core loop resolves the handler by name (prepare_template_render_var__$kind), verifies it exists via `declare -F`, calls it with a uniform signature (out_nameref, context_name, source_name), and reports a config_error for an unknown kind (no matching handler) -- preserving the previous error behavior. Adding a new kind now means defining a new handler function only; the loop never changes. Handlers cover all existing kinds: context_css, context_html, context_raw, current_date_html, config_html (keeps its inner source_name dispatch for HEIGHT/MAXPREVIEWS/TITLE/etc. and the same :- defaults), original_basepath_is_set, preview_num_next_html, preview_num_prev_html, and tarball_include. Escaping and defaults are unchanged, so rendered output is byte-identical (verified by diff -r of a full --generate album, before vs after). Add test_template_render_var_dispatch_is_extensible proving every declared kind resolves to a handler and that a newly defined handler is dispatched without touching the core loop (OCP). just test, just shellcheck, just check-generated and git diff --check all pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Diffstat (limited to 'tests/cli.sh')
-rwxr-xr-xtests/cli.sh61
1 files changed, 61 insertions, 0 deletions
diff --git a/tests/cli.sh b/tests/cli.sh
index 8727532..fdd2cec 100755
--- a/tests/cli.sh
+++ b/tests/cli.sh
@@ -3975,6 +3975,64 @@ BASH
fi
}
+# Open/Closed proof: render field kinds are dispatched by resolving a
+# prepare_template_render_var__<kind> handler by name. Adding a kind therefore
+# means only defining a new handler function -- the core loop never changes. We
+# assert (1) every kind in TEMPLATE_RENDER_FIELD_SPECS has a matching handler,
+# (2) defining a brand-new handler makes it resolvable and dispatch-able, and
+# (3) an unknown kind (no handler) is rejected as a config error.
+test_template_render_var_dispatch_is_extensible() {
+ local output
+
+ output=$(
+ bash -euo pipefail -s "$TEST_REPO_ROOT" <<'BASH'
+repo_root="$1"; shift
+
+# config_error (used for the unknown-kind path) lives in the validate lib.
+# shellcheck source=src/lib/config.validate.source.sh
+source "$repo_root/src/lib/config.validate.source.sh"
+# shellcheck source=src/lib/template.source.sh
+source "$repo_root/src/lib/template.source.sh"
+
+# Every declared kind must resolve to a handler function by name.
+missing=0
+for field_spec in "${TEMPLATE_RENDER_FIELD_SPECS[@]}"; do
+ IFS='|' read -r _ kind _ _ _ <<< "$field_spec"
+ if ! declare -F "prepare_template_render_var__$kind" > /dev/null; then
+ missing=1
+ fi
+done
+printf 'all_kinds_have_handlers=%s\n' "$([ "$missing" -eq 0 ] && echo yes || echo no)"
+
+# A brand-new kind, added purely by defining a handler function (OCP): the
+# dispatcher resolves and calls it without any change to the core loop.
+prepare_template_render_var__ocp_demo() {
+ local -n out_ref="$1"; shift
+ out_ref='dispatched'
+}
+demo_out=''
+handler="prepare_template_render_var__ocp_demo"
+declare -F "$handler" > /dev/null && "$handler" demo_out ctx ''
+printf 'demo=%s\n' "$demo_out"
+
+# An unknown kind has no handler, so the dispatcher must reject it.
+if declare -F "prepare_template_render_var__ocp_no_handler" > /dev/null; then
+ printf 'unknown=resolved\n'
+else
+ printf 'unknown=unresolved\n'
+fi
+BASH
+ )
+
+ if [ "$output" != \
+ $'all_kinds_have_handlers=yes\ndemo=dispatched\nunknown=unresolved' ]
+ then
+ printf 'FAIL: render var dispatch not extensible\n' >&2
+ printf 'actual:\n%s\n' "$output" >&2
+ exit 1
+ fi
+}
+
test_render_stats_page_renders_sections_and_escapes() {
local html
local output_file
@@ -5821,6 +5879,9 @@ main() {
'template required context vars come from render specs' \
test_template_required_context_vars_come_from_render_specs
test::run_case \
+ 'template render var dispatch is extensible (OCP)' \
+ test_template_render_var_dispatch_is_extensible
+ test::run_case \
'render_stats_page renders sections and escapes EXIF labels' \
test_render_stats_page_renders_sections_and_escapes
test::run_case \