test(config): verify Vim/Neovim config payload parity
CI / cargo fmt --check (push) Successful in 15s
CI / cargo clippy (push) Successful in 27s
CI / cargo test (push) Successful in 30s
CI / editor keymaps (push) Successful in 1m24s

Expose the init_options payload builders publicly in both clients
(M.init_options/M.server_settings in Lua, nuwiki#lsp#settings() in Vim) so
they can be inspected. Add editor harnesses that dump each client's
server-bound config as deterministic key=value lines and diff against a
shared golden file: nvim == golden and vim == golden together prove the two
clients send identical config. Add a server-side test asserting the Vim flat
shape and the Neovim {nuwiki:{...}} wrapper desugar to the same WikiConfig.
Wire both harnesses into CI.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-30 19:24:20 -03:00
parent 47af0d6c1e
commit b922f0d612
9 changed files with 319 additions and 6 deletions
+17
View File
@@ -0,0 +1,17 @@
[default]
wiki_root=~/vimwiki
file_extension=.wiki
syntax=vimwiki
log_level=warn
[sample]
wiki_root=/tmp/base
file_extension=.md
syntax=vimwiki
log_level=debug
wikis[0].diary_rel_path=journal
wikis[0].file_extension=.wiki
wikis[0].index=home
wikis[0].name=personal
wikis[0].root=/tmp/personal
wikis[1].name=work
wikis[1].root=/tmp/work
+58
View File
@@ -0,0 +1,58 @@
#!/usr/bin/env bash
#
# development/tests/test-config-vim.sh — Vim counterpart of test-config.sh.
#
# Runs development/tests/test-config-vim.vim under headless Vim, which dumps
# the Vim client's `initialization_options` payload (nuwiki#lsp#settings())
# as `key=value` lines, then diffs against the shared golden
# config-expected.txt. Matching the same golden the Neovim harness uses is
# what proves Vim/Neovim config parity.
#
# Exit code: 0 when the payload matches the golden, 1 otherwise. Skips
# (exit 0) when vim is not installed.
set -euo pipefail
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
log() { printf '\033[1;34m[config-vim]\033[0m %s\n' "$*"; }
if ! command -v vim >/dev/null 2>&1; then
log 'vim not installed — skipping'
exit 0
fi
TMP="$(mktemp -d -t nuwiki-config-vim-test-XXXXXX)"
trap 'rm -rf "$TMP"' EXIT
GOLDEN="$REPO_ROOT/development/tests/config-expected.txt"
OUT="$TMP/vim-config.txt"
VIMRC="$TMP/vimrc"
cat > "$VIMRC" <<EOF
set nocompatible
let &runtimepath = '$REPO_ROOT' . ',' . &runtimepath
filetype plugin indent on
EOF
log 'running Vim config harness…'
# `</dev/null` so ex-mode doesn't hang on stdin; `timeout` guards CI.
NUWIKI_CONFIG_OUT="$OUT" \
timeout 30 vim -e -s -u "$VIMRC" \
-c "source $REPO_ROOT/development/tests/test-config-vim.vim" \
</dev/null >"$TMP/vim.log" 2>&1 || true
if [[ ! -f "$OUT" ]]; then
echo 'config harness produced no output' >&2
echo '--- vim log ---' >&2
cat "$TMP/vim.log" >&2 || true
exit 1
fi
if diff -u "$GOLDEN" "$OUT"; then
log 'Vim config payload matches golden ✓'
exit 0
fi
echo 'Vim config payload DIVERGED from golden (see diff above)' >&2
exit 1
+50
View File
@@ -0,0 +1,50 @@
" development/tests/test-config-vim.vim — Vim counterpart of
" test-config.lua. Dumps the Vim client's `initialization_options` payload
" (nuwiki#lsp#settings()) for the same two scenarios as the Neovim harness,
" as byte-identical `key=value` lines, so both can be diffed against the
" shared golden development/tests/config-expected.txt.
"
" "nvim == golden" and "vim == golden" together prove Vim/Neovim config
" parity for everything the server consumes.
let s:out = $NUWIKI_CONFIG_OUT
let s:lines = []
function! s:dump(payload) abort
call add(s:lines, 'wiki_root=' . a:payload.wiki_root)
call add(s:lines, 'file_extension=' . a:payload.file_extension)
call add(s:lines, 'syntax=' . a:payload.syntax)
call add(s:lines, 'log_level=' . a:payload.log_level)
if has_key(a:payload, 'wikis')
let l:i = 0
for l:w in a:payload.wikis
for l:k in sort(keys(l:w))
call add(s:lines, printf('wikis[%d].%s=%s', l:i, l:k, l:w[l:k]))
endfor
let l:i += 1
endfor
endif
endfunction
" Scenario 1: defaults (no globals set).
unlet! g:nuwiki_wiki_root g:nuwiki_file_extension g:nuwiki_syntax
unlet! g:nuwiki_log_level g:nuwiki_wikis
call add(s:lines, '[default]')
call s:dump(nuwiki#lsp#settings())
" Scenario 2: same representative config as the Neovim harness.
let g:nuwiki_wiki_root = '/tmp/base'
let g:nuwiki_file_extension = '.md'
let g:nuwiki_syntax = 'vimwiki'
let g:nuwiki_log_level = 'debug'
let g:nuwiki_wikis = [
\ { 'name': 'personal', 'root': '/tmp/personal',
\ 'file_extension': '.wiki', 'index': 'home',
\ 'diary_rel_path': 'journal' },
\ { 'name': 'work', 'root': '/tmp/work' },
\ ]
call add(s:lines, '[sample]')
call s:dump(nuwiki#lsp#settings())
call writefile(s:lines, s:out)
qall!
+74
View File
@@ -0,0 +1,74 @@
-- development/tests/test-config.lua — dump the Neovim client's
-- `initialization_options` payload for two scenarios (default config and a
-- representative multi-wiki sample) as deterministic `key=value` lines.
--
-- The runner (test-config.sh) diffs the output against
-- development/tests/config-expected.txt. The Vim harness
-- (test-config-vim.vim) emits byte-identical lines against the SAME golden,
-- so "nvim == golden" and "vim == golden" together prove the two clients
-- send the same server-bound config — i.e. Vim/Neovim config parity.
--
-- Only the server-relevant keys are emitted (wiki_root, file_extension,
-- syntax, log_level, wikis[*]). `mappings`/`folding` are client-side
-- concerns the server ignores, so they're intentionally excluded.
local out = assert(os.getenv('NUWIKI_CONFIG_OUT'), 'NUWIKI_CONFIG_OUT unset')
local config = require('nuwiki.config')
local lsp = require('nuwiki.lsp')
local lines = {}
local function emit(s)
lines[#lines + 1] = s
end
local function dump(payload)
emit('wiki_root=' .. tostring(payload.wiki_root))
emit('file_extension=' .. tostring(payload.file_extension))
emit('syntax=' .. tostring(payload.syntax))
emit('log_level=' .. tostring(payload.log_level))
if payload.wikis then
for i, w in ipairs(payload.wikis) do
local keys = {}
for k in pairs(w) do
keys[#keys + 1] = k
end
table.sort(keys)
for _, k in ipairs(keys) do
emit(string.format('wikis[%d].%s=%s', i - 1, k, tostring(w[k])))
end
end
end
end
-- Scenario 1: defaults (no user config, no VimL globals).
vim.g.nuwiki_wikis = nil
config.apply({})
emit('[default]')
dump(lsp.init_options())
-- Scenario 2: representative config exercising scalar keys + a wikis list.
config.apply({
wiki_root = '/tmp/base',
file_extension = '.md',
syntax = 'vimwiki',
log_level = 'debug',
wikis = {
{
name = 'personal',
root = '/tmp/personal',
file_extension = '.wiki',
index = 'home',
diary_rel_path = 'journal',
},
{ name = 'work', root = '/tmp/work' },
},
})
emit('[sample]')
dump(lsp.init_options())
local f = assert(io.open(out, 'w'))
f:write(table.concat(lines, '\n') .. '\n')
f:close()
vim.cmd('qa!')
+52
View File
@@ -0,0 +1,52 @@
#!/usr/bin/env bash
#
# development/tests/test-config.sh — verify the Neovim client builds the
# exact `initialization_options` payload the server expects.
#
# Runs development/tests/test-config.lua under headless Neovim, which dumps
# the server-bound config (wiki_root, file_extension, syntax, log_level,
# wikis[*]) for a default and a sample scenario as `key=value` lines, then
# diffs the result against the shared golden config-expected.txt.
#
# The Vim harness (test-config-vim.sh) diffs against the SAME golden, so a
# green run of both proves Vim/Neovim config parity.
#
# Exit code: 0 when the payload matches the golden, 1 otherwise.
set -euo pipefail
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
TMP="$(mktemp -d -t nuwiki-config-test-XXXXXX)"
trap 'rm -rf "$TMP"' EXIT
log() { printf '\033[1;34m[config-test]\033[0m %s\n' "$*"; }
GOLDEN="$REPO_ROOT/development/tests/config-expected.txt"
OUT="$TMP/nvim-config.txt"
# No LSP server needed — we only inspect the payload the client would send.
INIT="$TMP/init.lua"
cat > "$INIT" <<EOF
vim.opt.runtimepath:prepend('$REPO_ROOT')
EOF
log 'running Neovim config harness…'
NUWIKI_CONFIG_OUT="$OUT" \
timeout 30 nvim --clean -u "$INIT" --headless \
-c "luafile $REPO_ROOT/development/tests/test-config.lua" \
>"$TMP/nvim.log" 2>&1 || true
if [[ ! -f "$OUT" ]]; then
echo 'config harness produced no output' >&2
echo '--- nvim log ---' >&2
cat "$TMP/nvim.log" >&2 || true
exit 1
fi
if diff -u "$GOLDEN" "$OUT"; then
log 'Neovim config payload matches golden ✓'
exit 0
fi
echo 'Neovim config payload DIVERGED from golden (see diff above)' >&2
exit 1