Add tests and refactor config

This commit is contained in:
2026-05-20 08:30:21 +02:00
parent 8b760b2897
commit cd9550ee8a
13 changed files with 1070 additions and 558 deletions

106
tests/test_config.sh Executable file
View File

@@ -0,0 +1,106 @@
test_config_defaults() {
. "$project_dir/lib/config.sh"
assert_eq "kewt" "$title" "default title"
assert_eq "kewt" "$style" "default style"
assert_eq "en" "$lang" "default lang"
assert_eq "false" "$draft_by_default" "default draft_by_default"
assert_eq "true" "$dir_indexes" "default dir_indexes"
assert_eq "true" "$single_file_index" "default single_file_index"
assert_eq "false" "$flatten" "default flatten"
assert_eq "Home" "$home_name" "default home_name"
assert_eq "true" "$show_home_in_nav" "default show_home_in_nav"
assert_eq "false" "$generate_feed" "default generate_feed"
assert_eq "rss.xml" "$feed_file" "default feed_file"
assert_eq "12" "$posts_per_page" "default posts_per_page"
assert_eq "false" "$generate_tags" "default generate_tags"
assert_eq "tags" "$tags_dir" "default tags_dir"
assert_eq "false" "$generate_search" "default generate_search"
assert_eq "true" "$enable_header_links" "default enable_header_links"
assert_eq "true" "$cw_hide_url" "default cw_hide_url"
}
test_config_reset() {
. "$project_dir/lib/config.sh"
title="custom"
style="nord"
generate_feed="true"
reset_config
assert_eq "kewt" "$title" "reset title"
assert_eq "kewt" "$style" "reset style"
assert_eq "false" "$generate_feed" "reset generate_feed"
}
test_config_load() {
. "$project_dir/lib/config.sh"
tmpdir="${TMPDIR:-/tmp}/kewt_test.$$"
mkdir -p "$tmpdir"
cat > "$tmpdir/test.conf" <<EOF
title = "My Site"
style = "nord"
generate_feed = true
base_url = "https://example.com"
posts_per_page = 5
EOF
reset_config
load_config "$tmpdir/test.conf"
assert_eq "My Site" "$title" "load title"
assert_eq "nord" "$style" "load style"
assert_eq "true" "$generate_feed" "load generate_feed"
assert_eq "https://example.com" "$base_url" "load base_url"
assert_eq "5" "$posts_per_page" "load posts_per_page"
rm -rf "$tmpdir"
}
test_config_load_quoted() {
. "$project_dir/lib/config.sh"
tmpdir="${TMPDIR:-/tmp}/kewt_test.$$"
mkdir -p "$tmpdir"
cat > "$tmpdir/test.conf" <<'EOF'
footer = "made with <a href=\"https://kewt.krzak.org\">kewt</a>"
nav_links = "[Docs](/docs), [About](/about)"
EOF
reset_config
load_config "$tmpdir/test.conf"
assert_eq 'made with <a href="https://kewt.krzak.org">kewt</a>' "$footer" "load quoted footer"
assert_eq "[Docs](/docs), [About](/about)" "$nav_links" "load quoted nav_links"
rm -rf "$tmpdir"
}
test_config_load_skips_comments() {
. "$project_dir/lib/config.sh"
tmpdir="${TMPDIR:-/tmp}/kewt_test.$$"
mkdir -p "$tmpdir"
cat > "$tmpdir/test.conf" <<EOF
# This is a comment
title = "Test Site"
# Another comment
style = "kewt"
EOF
reset_config
load_config "$tmpdir/test.conf"
assert_eq "Test Site" "$title" "load with comments title"
assert_eq "kewt" "$style" "load with comments style"
rm -rf "$tmpdir"
}
test_config_load_missing_file() {
. "$project_dir/lib/config.sh"
reset_config
load_config "/nonexistent/path/site.conf"
assert_eq "kewt" "$title" "missing file keeps defaults"
}

92
tests/test_metadata.sh Executable file
View File

@@ -0,0 +1,92 @@
test_strip_markdown_bold() {
. "$project_dir/lib/metadata.sh"
result=$(strip_markdown_text "**bold text**")
assert_eq "bold text" "$result" "strip bold"
}
test_strip_markdown_italic() {
. "$project_dir/lib/metadata.sh"
result=$(strip_markdown_text "*italic text*")
assert_eq "italic text" "$result" "strip italic"
}
test_strip_markdown_link() {
. "$project_dir/lib/metadata.sh"
result=$(strip_markdown_text "[link](http://example.com)")
assert_eq "link" "$result" "strip link"
}
test_strip_markdown_code() {
. "$project_dir/lib/metadata.sh"
result=$(strip_markdown_text "\`code\`")
assert_eq "code" "$result" "strip code"
}
test_first_heading() {
tmpdir="${TMPDIR:-/tmp}/kewt_test.$$"
mkdir -p "$tmpdir"
printf '# Hello World\n\nSome content\n' > "$tmpdir/test.md"
. "$project_dir/lib/metadata.sh"
result=$(first_heading_from_markdown "$tmpdir/test.md")
assert_eq "Hello World" "$result" "first heading"
rm -rf "$tmpdir"
}
test_first_heading_no_heading() {
tmpdir="${TMPDIR:-/tmp}/kewt_test.$$"
mkdir -p "$tmpdir"
printf 'Random content\n' > "$tmpdir/test.md"
. "$project_dir/lib/metadata.sh"
result=$(first_heading_from_markdown "$tmpdir/test.md")
assert_eq "" "$result" "no heading returns empty"
rm -rf "$tmpdir"
}
test_parse_frontmatter() {
tmpdir="${TMPDIR:-/tmp}/kewt_test.$$"
mkdir -p "$tmpdir"
cat > "$tmpdir/test.md" <<'EOF'
---
title = "My Post"
date = "2026-05-20 10:00"
draft = false
description = "A test post"
tags = "test, example"
---
# Content
EOF
export KEWT_TMPDIR="$tmpdir"
export awk_dir="$project_dir/awk"
. "$project_dir/lib/metadata.sh"
. "$project_dir/lib/config.sh"
parse_frontmatter "$tmpdir/test.md"
assert_eq "My Post" "$fm_title" "parse title"
assert_eq "2026-05-20 10:00" "$fm_date" "parse date"
assert_eq "false" "$fm_draft" "parse draft"
assert_eq "A test post" "$fm_description" "parse description"
assert_eq "test, example" "$fm_tags" "parse tags"
rm -rf "$tmpdir"
}
test_set_post_datetime_from_date() {
. "$project_dir/lib/metadata.sh"
set_post_datetime "2026-05-20 14:30" "fallback"
assert_eq "2026-05-20" "$post_date" "post date from date field"
assert_eq "14:30" "$post_time" "post time from date field"
}
test_set_post_datetime_from_filename() {
. "$project_dir/lib/metadata.sh"
set_post_datetime "" "2026-05-20-14-30-slug"
assert_eq "2026-05-20" "$post_date" "post date from filename"
assert_eq "14:30" "$post_time" "post time from filename"
}

93
tests/test_runner.sh Executable file
View File

@@ -0,0 +1,93 @@
#!/bin/sh
script_dir=$(CDPATH="" cd -- "$(dirname -- "$0")" && pwd)
project_dir=$(CDPATH="" cd -- "$script_dir/.." && pwd)
passed=0
failed=0
total=0
assert_eq() {
total=$((total + 1))
expected="$1"
actual="$2"
label="$3"
if [ "$expected" = "$actual" ]; then
passed=$((passed + 1))
printf " PASS: %s\n" "$label"
else
failed=$((failed + 1))
printf " FAIL: %s\n" "$label"
printf " expected: %s\n" "$expected"
printf " actual: %s\n" "$actual"
fi
}
assert_contains() {
total=$((total + 1))
needle="$1"
haystack="$2"
label="$3"
case "$haystack" in
*"$needle"*)
passed=$((passed + 1))
printf " PASS: %s\n" "$label"
;;
*)
failed=$((failed + 1))
printf " FAIL: %s\n" "$label"
printf " expected to contain: %s\n" "$needle"
printf " actual: %s\n" "$haystack"
;;
esac
}
assert_file_exists() {
total=$((total + 1))
path="$1"
label="$2"
if [ -f "$path" ]; then
passed=$((passed + 1))
printf " PASS: %s\n" "$label"
else
failed=$((failed + 1))
printf " FAIL: %s\n" "$label"
printf " file not found: %s\n" "$path"
fi
}
run_test_file() {
test_file="$1"
test_name=$(basename "$test_file" .sh)
printf "\n== %s ==\n" "$test_name"
saved_total=$total
saved_passed=$passed
saved_failed=$failed
. "$test_file"
for func in $(grep '^test_' "$test_file" | sed 's/().*//' | sort -u); do
$func
done
file_total=$((total - saved_total))
file_passed=$((passed - saved_passed))
file_failed=$((failed - saved_failed))
if [ "$file_total" -eq 0 ]; then
printf " (no tests found)\n"
fi
}
for test_file in "$script_dir"/test_*.sh; do
[ "$(basename "$test_file")" = "test_runner.sh" ] && continue
run_test_file "$test_file"
done
printf "\n== Results ==\n"
printf " %d passed, %d failed, %d total\n" "$passed" "$failed" "$total"
[ "$failed" -eq 0 ] && exit 0 || exit 1

71
tests/test_runtime.sh Executable file
View File

@@ -0,0 +1,71 @@
test_url_encode_spaces() {
. "$project_dir/lib/runtime.sh"
result=$(encode_url_path "hello world")
assert_eq "hello%20world" "$result" "encode spaces"
}
test_url_encode_hash() {
. "$project_dir/lib/runtime.sh"
result=$(encode_url_path "file#section")
assert_eq "file%23section" "$result" "encode hash"
}
test_url_encode_question() {
. "$project_dir/lib/runtime.sh"
result=$(encode_url_path "search?q=test")
assert_eq "search%3Fq=test" "$result" "encode question mark"
}
test_url_encode_percent() {
. "$project_dir/lib/runtime.sh"
result=$(encode_url_path "100%")
assert_eq "100%25" "$result" "encode percent"
}
test_markdown_file_url() {
. "$project_dir/lib/runtime.sh"
result=$(markdown_file_url "docs/readme.md")
assert_eq "/docs/readme.html" "$result" "markdown file url"
}
test_directory_index_url_root() {
. "$project_dir/lib/runtime.sh"
result=$(directory_index_url "")
assert_eq "/index.html" "$result" "root index url"
}
test_directory_index_url_subdir() {
. "$project_dir/lib/runtime.sh"
result=$(directory_index_url "docs")
assert_eq "/docs/index.html" "$result" "subdir index url"
}
test_directory_index_url_dot() {
. "$project_dir/lib/runtime.sh"
result=$(directory_index_url ".")
assert_eq "/index.html" "$result" "dot index url"
}
test_format_rfc2822_utc() {
. "$project_dir/lib/runtime.sh"
result=$(format_rfc2822_utc "2026-05-20" "14:30")
assert_eq "Wed, 20 May 2026 14:30:00 +0000" "$result" "rfc2822 format"
}
test_format_rfc2822_utc_default_time() {
. "$project_dir/lib/runtime.sh"
result=$(format_rfc2822_utc "2026-01-01")
assert_eq "Thu, 01 Jan 2026 00:00:00 +0000" "$result" "rfc2822 default time"
}
test_trim_whitespace() {
. "$project_dir/lib/runtime.sh"
result=$(trim_whitespace " hello ")
assert_eq "hello" "$result" "trim whitespace"
}
test_trim_whitespace_tabs() {
. "$project_dir/lib/runtime.sh"
result=$(trim_whitespace " world ")
assert_eq "world" "$result" "trim tabs"
}