" vim_feature_test.vim — comprehensive checks of the Klammertext Vim plugin, " beyond the fixture runs in editor_test.sh (which cover the Reindent and " Align commands' output bytes). Run headlessly: " " KT_FIX= KT_OUT= \ " vim -N -n -u NONE -i NONE -es --not-a-term \ " --cmd 'set rtp^=' -c 'source vim_feature_test.vim' " " What is checked: " * ftdetect: .kt maps to the klammertext filetype, overriding the stock " runtime's .kt -> kotlin mapping " * syntax: token classes at known positions (three @-tiers open/close, " removal line/block/file with markers, verbatim @code interior, " ^-escapes, abbreviated @name-arg) " * commands: KlammertextJumpToMatch (open->close, close->open, " multibyte columns), KlammertextCheck (location list) " * with +python3: 'indentexpr' drives the = operator (gg=G equals the " expected fixture), and the CursorMoved match highlighter sets " KlammertextMatch / KlammertextMismatch matches " " Writes PASS/FAIL lines to $KT_OUT; exits nonzero if anything failed. let s:results = [] function! s:Check(name, ok, ...) abort let detail = (a:ok || !a:0) ? '' : ' -- ' . string(a:1) call add(s:results, (a:ok ? 'PASS ' : 'FAIL ') . a:name . detail) endfunction function! s:Syn(l, c) abort return synIDattr(synID(a:l, a:c, 1), 'name') endfunction filetype plugin on if has('syntax') syntax enable endif " --- ftdetect: .kt is klammertext (the Kotlin override) -------------------- execute 'edit! ' . fnameescape($KT_FIX . '/indent_list.kt') call s:Check('ftdetect .kt -> klammertext (overrides kotlin)', \ &filetype ==# 'klammertext', &filetype) " --- syntax token classes --------------------------------------------------- if has('syntax') enew! call setline(1, [ \ '@i abc @ x', \ '@@def : x @@', \ '@@@target x @@@', \ '# removed line', \ '#[ rem ]# after', \ '^@ escaped', \ '@code x @ y code@', \ 'name@ x', \ '@name-arg x', \ '## tail', \ 'still removed']) set filetype=klammertext call s:Check('syntax loaded', b:current_syntax ==# 'klammertext') call s:Check('app open @i', s:Syn(1, 1) ==# 'klammertextAppOpen', s:Syn(1, 1)) call s:Check('app bare close', s:Syn(1, 8) ==# 'klammertextAppClose', s:Syn(1, 8)) call s:Check('plain text', s:Syn(1, 10) ==# '', s:Syn(1, 10)) call s:Check('def open @@def', s:Syn(2, 1) ==# 'klammertextDefOpen', s:Syn(2, 1)) call s:Check('def bare close', s:Syn(2, 11) ==# 'klammertextDefClose', s:Syn(2, 11)) call s:Check('sys open @@@target', s:Syn(3, 1) ==# 'klammertextSysOpen', s:Syn(3, 1)) call s:Check('sys bare close', s:Syn(3, 13) ==# 'klammertextSysClose', s:Syn(3, 13)) call s:Check('line marker #', s:Syn(4, 1) ==# 'klammertextMarkerLine', s:Syn(4, 1)) call s:Check('line removed text', s:Syn(4, 5) ==# 'klammertextRemovedLine', s:Syn(4, 5)) call s:Check('block marker #[', s:Syn(5, 1) ==# 'klammertextMarker', s:Syn(5, 1)) call s:Check('block removed text', s:Syn(5, 5) ==# 'klammertextRemovedBlock', s:Syn(5, 5)) call s:Check('block marker ]#', s:Syn(5, 8) ==# 'klammertextMarker', s:Syn(5, 8)) call s:Check('text after block', s:Syn(5, 12) ==# '', s:Syn(5, 12)) call s:Check('escape ^@ consumed', s:Syn(6, 1) ==# 'klammertextEscape' \ && s:Syn(6, 2) ==# 'klammertextEscape', s:Syn(6, 2)) call s:Check('verbatim open', s:Syn(7, 1) ==# 'klammertextAppOpen', s:Syn(7, 1)) call s:Check('verbatim interior @', s:Syn(7, 9) ==# 'klammertextVerbatim', s:Syn(7, 9)) call s:Check('verbatim close', s:Syn(7, 17) ==# 'klammertextAppClose', s:Syn(7, 17)) call s:Check('named close name@', s:Syn(8, 1) ==# 'klammertextAppClose' \ && s:Syn(8, 5) ==# 'klammertextAppClose', s:Syn(8, 1)) call s:Check('abbreviated @name-', s:Syn(9, 1) ==# 'klammertextAppOpen' \ && s:Syn(9, 6) ==# '' && s:Syn(9, 7) ==# '', s:Syn(9, 6)) call s:Check('file marker ##', s:Syn(10, 1) ==# 'klammertextMarker', s:Syn(10, 1)) call s:Check('## removes to EOF', s:Syn(11, 3) ==# 'klammertextRemovedFile', s:Syn(11, 3)) else call add(s:results, 'SKIP syntax checks (this Vim lacks +syntax)') endif " --- jump-to-match (the CLI shell-out path) --------------------------------- enew! call setline(1, ['@i abc @ x']) set filetype=klammertext call cursor(1, 1) KlammertextJumpToMatch call s:Check('jump open -> close', col('.') == 8, col('.')) KlammertextJumpToMatch call s:Check('jump close -> open', col('.') == 1, col('.')) " multibyte: 2-byte umlauts before the delimiters enew! call setline(1, ['üü @i x @']) set filetype=klammertext call cursor(1, 6) " byte col 6 = the @ of @i (2 x 2-byte ü) KlammertextJumpToMatch call s:Check('jump with multibyte line', \ (exists('*charcol') ? charcol('.') : col('.')) \ == (exists('*charcol') ? 9 : 11), \ [col('.'), getline('.')]) " --- KlammertextCheck: diagnostics into the location list ------------------- enew! call setline(1, ['@i abc', '@ol x ul@']) set filetype=klammertext KlammertextCheck let s:ll = getloclist(0) call s:Check('check fills the location list', len(s:ll) == 2, s:ll) call s:Check('check positions', len(s:ll) == 2 \ && s:ll[0].lnum == 1 && s:ll[0].col == 1 \ && s:ll[1].lnum == 2 && s:ll[1].col == 7, s:ll) call s:Check('check messages', len(s:ll) == 2 \ && s:ll[0].text =~# 'never closed' && s:ll[1].text =~# 'ul@', s:ll) lclose enew! call setline(1, ['@i balanced @']) set filetype=klammertext KlammertextCheck call s:Check('check clean buffer -> empty list', len(getloclist(0)) == 0) " --- +python3: indentexpr (= operator) and live match highlighting --------- if has('python3') for s:fix in ['indent_list', 'indent_document', 'indent_named_close'] execute 'edit! ' . fnameescape($KT_FIX . '/' . s:fix . '.kt') call s:Check(s:fix . ': indentexpr is set', \ &indentexpr ==# 'klammertext#IndentExpr()', &indentexpr) normal! gg=G call s:Check(s:fix . ': gg=G equals expected fixture', \ getline(1, '$') ==# readfile($KT_FIX . '/' . s:fix . '_expected.kt')) edit! endfor " live match highlighting via the CursorMoved autocmd enew! call setline(1, ['@i abc @ x']) set filetype=klammertext call cursor(1, 1) doautocmd CursorMoved let s:m = filter(getmatches(), 'v:val.group =~# "^Klammertext"') call s:Check('highlight: matched pair boxed', \ len(s:m) == 1 && s:m[0].group ==# 'KlammertextMatch' \ && len(filter(keys(s:m[0]), 'v:val =~# "^pos"')) == 2, s:m) call cursor(1, 5) " not on a delimiter doautocmd CursorMoved call s:Check('highlight: cleared off-delimiter', \ empty(filter(getmatches(), 'v:val.group =~# "^Klammertext"'))) enew! call setline(1, ['@ol x ul@']) set filetype=klammertext call cursor(1, 1) doautocmd CursorMoved let s:m = filter(getmatches(), 'v:val.group =~# "^Klammertext"') call s:Check('highlight: mismatch in red group', \ len(s:m) == 1 && s:m[0].group ==# 'KlammertextMismatch', s:m) " default mappings exist (buffer-local, LocalLeader) call s:Check('mappings defined', \ !empty(maparg('j', 'n')) \ && !empty(maparg('i', 'n')) \ && !empty(maparg('a', 'n'))) else call add(s:results, 'SKIP +python3 checks (this Vim lacks python3)') endif " --- write results and exit ------------------------------------------------- call writefile(s:results, $KT_OUT) if len(filter(copy(s:results), 'v:val =~# "^FAIL"')) > 0 cquit! endif qa!