" " Adapted from https://github.com/vim/vim/blob/master/src/testdir/runtest.vim " " When debugging tests it can help to write debug output: " call Log('oh noes') " function RunTest(test) if exists("*SetUp") call SetUp() endif try execute 'call '.a:test catch call Exception() let s:errored = 1 endtry if exists("*TearDown") call TearDown() endif endfunction function Log(msg) if type(a:msg) == type('') call add(s:messages, a:msg) elseif type(a:msg) == type([]) call extend(s:messages, a:msg) else call add(v:errors, 'Exception: unsupported type: '.type(a:msg)) endif endfunction function Exception() call add(v:errors, v:throwpoint.'..'.'Exception: '.v:exception) endfunction " Shuffles list in place. function Shuffle(list) " Fisher-Yates-Durstenfeld-Knuth let n = len(a:list) if n < 2 return a:list endif for i in range(0, n-2) let j = Random(0, n-i-1) let e = a:list[i] let a:list[i] = a:list[i+j] let a:list[i+j] = e endfor return a:list endfunction " Returns a pseudorandom integer i such that 0 <= i <= max function Random(min, max) if has('unix') let i = system('echo $RANDOM') " 0 <= i <= 32767 else let i = system('echo %RANDOM%') " 0 <= i <= 32767 endif return i * (a:max - a:min + 1) / 32768 + a:min endfunction function FriendlyName(test_name) return substitute(a:test_name[5:-3], '_', ' ', 'g') endfunction function Align(left, right) if type(a:right) == type([]) let result = [] for s in a:right if empty(result) call add(result, printf('%-'.s:indent.'S', a:left).s) else call add(result, printf('%-'.s:indent.'S', '').s) endif endfor return result endif return printf('%-'.s:indent.'S', a:left).a:right endfunction let g:testname = expand('%') let s:errored = 0 let s:done = 0 let s:fail = 0 let s:errors = 0 let s:messages = [] let s:indent = '' call Log(g:testname.':') " Source the test script. try source % catch let s:errors += 1 call Exception() endtry " Locate the test functions. set nomore redir @q silent function /^Test_ redir END let s:tests = split(substitute(@q, 'function \(\k*()\)', '\1', 'g')) " If there is another argument, filter test-functions' names against it. if argc() > 1 let s:tests = filter(s:tests, 'v:val =~ argv(1)') endif let s:indent = max(map(copy(s:tests), {_, val -> len(FriendlyName(val))})) " Run the tests in random order. for test in Shuffle(s:tests) call RunTest(test) let s:done += 1 let friendly_name = FriendlyName(test) if len(v:errors) == 0 call Log(Align(friendly_name, ' - ok')) else if s:errored let s:errors += 1 let s:errored = 0 else let s:fail += 1 endif call Log(Align(friendly_name, ' - not ok')) let i = 0 for error in v:errors if i != 0 call Log(Align('',' ! ----')) endif for trace in reverse(split(error, '\.\.')) call Log(Align('', ' ! '.trace)) endfor let i += 1 endfor let v:errors = [] endif endfor let summary = [ \ s:done.( s:done == 1 ? ' test' : ' tests'), \ s:errors.(s:errors == 1 ? ' error' : ' errors'), \ s:fail.( s:fail == 1 ? ' failure' : ' failures'), \ ] call Log('') call Log(join(summary, ', ')) split messages.log call append(line('$'), s:messages) write qall!