#!/usr/bin/env bats # tests/unit/template_vars.bats # Unit tests for template variable substitution patterns. # # These tests replicate the escape_sed_pattern_literal logic from trbldoc.sh # and verify that: # - the canonical {{ var }} format (two brackets, one space each side) is matched # - the old {{varname}} format (two brackets, no spaces) is NOT matched # - the layout-specific patterns ({{ title }}, {{ nav }}, {{ yield }}, # {{ breadcrumb }}) work correctly in sed address and substitution position load "../helpers/common.bash" setup() { setup_workspace } teardown() { teardown_workspace } # Replicate escape_sed_pattern_literal from trbldoc.sh. escape_pat() { printf '%s' "$1" | sed -e 's/[][\\.^$*+?(){}|]/\\&/g' } # ── chunk template variables ────────────────────────────────────────────────── @test "template vars: {{ src_repo }} is matched and substituted" { local pat result pat=$(escape_pat '{{ src_repo }}') result=$(printf '%s' 'Link: {{ src_repo }}/file.c' | sed -E "s|$pat|https://example.com|g") assert_equal "$result" 'Link: https://example.com/file.c' } @test "template vars: {{src_repo}} without spaces is NOT matched" { local pat result pat=$(escape_pat '{{ src_repo }}') result=$(printf '%s' 'Old: {{src_repo}}' | sed -E "s|$pat|https://example.com|g") assert_equal "$result" 'Old: {{src_repo}}' } @test "template vars: {{ toc }} is matched and substituted" { local pat result pat=$(escape_pat '{{ toc }}') result=$(printf '%s' 'Nav: {{ toc }}' | sed -E "s|$pat||g") assert_equal "$result" 'Nav: ' } @test "template vars: {{toc}} without spaces is NOT matched" { local pat result pat=$(escape_pat '{{ toc }}') result=$(printf '%s' 'Old: {{toc}}' | sed -E "s|$pat||g") assert_equal "$result" 'Old: {{toc}}' } @test "template vars: {{ ref_string }} is matched and substituted" { local pat result pat=$(escape_pat '{{ ref_string }}') result=$(printf '%s' "See: {{ ref_string }}." | sed -E "s|$pat|x|g") assert_equal "$result" "See: x." } @test "template vars: {{ref_string}} without spaces is NOT matched" { local pat result pat=$(escape_pat '{{ ref_string }}') result=$(printf '%s' 'Old: {{ref_string}}' | sed -E "s|$pat|x|g") assert_equal "$result" 'Old: {{ref_string}}' } @test "template vars: multiple {{ src_repo }} occurrences are all substituted" { local pat result pat=$(escape_pat '{{ src_repo }}') result=$(printf '%s' '{{ src_repo }}/a and {{ src_repo }}/b' | sed -E "s|$pat|https://r|g") assert_equal "$result" 'https://r/a and https://r/b' } # ── layout template variables ───────────────────────────────────────────────── @test "template vars: layout {{ title }} is matched and substituted" { local result result=$(printf '%s' '{{ title }}' \ | sed -E "s|\\{\\{ title \\}\\}|My Page|g") assert_equal "$result" 'My Page' } @test "template vars: layout {{title}} without spaces is NOT matched" { local result result=$(printf '%s' '{{title}}' \ | sed -E "s|\\{\\{ title \\}\\}|My Page|g") assert_equal "$result" '{{title}}' } @test "template vars: layout {{ breadcrumb }} is matched and substituted" { local result result=$(printf '%s' '

{{ breadcrumb }}

' \ | sed -E "s|\\{\\{ breadcrumb \\}\\}|Section|g") assert_equal "$result" '

Section

' } @test "template vars: layout {{breadcrumb}} without spaces is NOT matched" { local result result=$(printf '%s' '{{breadcrumb}}' \ | sed -E "s|\\{\\{ breadcrumb \\}\\}|Section|g") assert_equal "$result" '{{breadcrumb}}' } @test "template vars: layout {{ nav }} is matched and substituted" { local result result=$(printf '%s' '' \ | sed -E "s|\\{\\{ nav \\}\\}|
  • item
  • |g") assert_equal "$result" '' } @test "template vars: layout old {{> nav}} partial syntax is NOT matched by {{ nav }} pattern" { local result result=$(printf '%s' '' \ | sed -E "s|\\{\\{ nav \\}\\}|
  • item
  • |g") assert_equal "$result" '' } @test "template vars: layout {{ yield }} works as sed address to include a file" { local tmpbody tmplayout output tmpbody=$(mktemp) tmplayout=$(mktemp) printf '

    body content

    \n' > "$tmpbody" printf '{{ yield }}\n' > "$tmplayout" output=$(sed -E \ -e "/\\{\\{ yield \\}\\}/r $tmpbody" \ -e "/\\{\\{ yield \\}\\}/d" \ "$tmplayout") rm -f "$tmpbody" "$tmplayout" assert_equal "$output" '

    body content

    ' } @test "template vars: layout old {{{yield}}} triple-brace is NOT matched by {{ yield }} pattern" { local tmpbody tmplayout output tmpbody=$(mktemp) tmplayout=$(mktemp) printf '

    body content

    \n' > "$tmpbody" printf '{{{yield}}}\n' > "$tmplayout" output=$(sed -E \ -e "/\\{\\{ yield \\}\\}/r $tmpbody" \ -e "/\\{\\{ yield \\}\\}/d" \ "$tmplayout") rm -f "$tmpbody" "$tmplayout" # {{{yield}}} should remain unchanged — the new pattern only matches {{ yield }} assert_equal "$output" '{{{yield}}}' } @test "template vars: substitution value containing special sed chars is safe" { # Verify that replacement values with & and \ don't corrupt the output # (this exercises the escape_sed_replacement_literal path) local pat esc_repl result pat=$(escape_pat '{{ src_repo }}') # Simulate escape_sed_replacement_literal for a URL containing & esc_repl=$(printf '%s' 'https://example.com/a&b' | sed -e 's/[\\&|]/\\&/g') result=$(printf '%s' '{{ src_repo }}/path' | sed -E "s|$pat|$esc_repl|g") assert_equal "$result" 'https://example.com/a&b/path' }