nix-archive-1(type directoryentry(name.gitattributesnode(typeregularcontents‘.gitattributes export-ignore .gitignore export-ignore doc/tags export-ignore *.md export-ignore test/* export-ignore ))entry(name .gitignorenode(typeregularcontentsdoc/tags *.zip ))entry(name .travis.ymlnode(typeregularcontents9dist: xenial language: minimal matrix: include: - env: ENV=vim addons: apt: packages: - ruby - ruby-dev - env: ENV=vim-travis addons: apt: packages: - vim-nox-py2 - env: ENV=nvim - env: ENV=nvim VADER_OUTPUT_FILE=/dev/stderr - env: ENV=nvim TESTVIM_OPTS=--headless - env: ENV=nvim-stable addons: apt: sources: - sourceline: 'ppa:neovim-ppa/stable' packages: - neovim install: - pip install --user covimerage - | set -e pushd /tmp if [ "$ENV" = vim ]; then rvm use system git clone --depth=1 https://github.com/vim/vim cd vim ./configure --with-features=huge --enable-rubyinterp --enable-pythoninterp --prefix /tmp/vim make make install PATH=/tmp/vim/bin:$PATH elif [ "$ENV" = nvim ] || [ "${ENV#nvim-}" != "$ENV" ]; then if [ "$ENV" = nvim ]; then # Install Neovim nightly (into /tmp/_neovim). TRAVIS_BUILD_DIR=/tmp eval "$(curl -Ss https://raw.githubusercontent.com/neovim/bot-ci/master/scripts/travis-setup.sh) nightly-x64" fi gem install neovim pip install --user pynvim fi popd script: - export TESTVIM="${ENV%%-*}" - $TESTVIM --version # Wrap $TESTVIM with covimerage for coverage reporting. # Uses --no-report, because test/run-tests.sh changes the directory, and that does not pick up .coveragerc then. - VADER_TEST_VIM="covimerage run --source $PWD --data-file $PWD/.coverage_covimerage --no-report $TESTVIM $TESTVIM_OPTS" ./test/run-tests.sh # Test/cover :Vader use case (without bang). - | covimerage run --append --source . --no-report $TESTVIM $TESTVIM_OPTS -Nu test/vimrc \ -c 'Vader test/*' \ -c 'exe get(get(g:, "vader_result", {}), "successful", 0) ? "qall!" : "cq"' # Report coverage. This should fail the build to detect any problems. - covimerage -vv xml - covimerage report -m - bash <(curl -s https://codecov.io/bash) -Z -f coverage.xml -F "$TESTVIM,${ENV//-/_}" ))entry(name README.mdnode(typeregularcontentsõ(vader.vim ========= I use Vader to test Vimscript. ### Vader test cases ![](https://raw.github.com/junegunn/i/master/vader.png) ### Vader result ![](https://raw.github.com/junegunn/i/master/vader-result.png) Installation ------------ Use your favorite plugin manager. - [vim-plug](https://github.com/junegunn/vim-plug) 1. Add `Plug 'junegunn/vader.vim'` to .vimrc 2. Run `:PlugInstall` Running Vader tests ------------------- - `Vader [file glob ...]` - `Vader! [file glob ...]` - Exit Vim after running the tests with exit status of 0 or 1 - `vim '+Vader!*' && echo Success || echo Failure` - (You need to pass `--nofork` option when using GVim) - If the description of `Do` or `Execute` block includes `FIXME` or `TODO`, the block is recognized as a pending test case and does not affect the exit status. - If the environment variable `VADER_OUTPUT_FILE` is set, the test results will be written to it as well, otherwise they are written to stderr using different methods (depending on Neovim/Vim). Syntax of .vader file --------------------- A Vader file is a flat sequence of blocks each of which starts with the block label, such as `Execute:`, followed by the content of the block indented by 2 spaces. - Given - Content to fill the execution buffer - Do - Normal-mode keystrokes that can span multiple lines - Execute - Vimscript to execute - Then - Vimscript to run after Do or Execute block. Used for assertions. - Expect - Expected result of the preceding Do/Execute block - Before - Vimscript to run before each test case - After - Vimscript to run after each test case If you want to skip 2-space indention, end the block label with a semi-colon instead of a colon. ### Basic blocks #### Given The content of a Given block is pasted into the "workbench buffer" for the subsequent Do/Execute blocks. If `filetype` parameter is given, `&filetype` of the buffer is set accordingly. It is also used to syntax-highlight the block in .vader file. ``` Given [filetype] [(comment)]: [input text] ``` #### Do The content of a Do block is a sequence of normal-mode keystrokes that can freely span multiple lines. A special key can be written in its name surrounded by angle brackets preceded by a backslash (e.g. `\`). Do block can be followed by an optional Expect block. ``` Do [(comment)]: [keystrokes] ``` #### Execute The content of an Execute block is plain Vimscript to be executed. Execute block can also be followed by an optional Expect block. ``` Execute [(comment)]: [vimscript] ``` In Execute block, the following commands are provided. - Assertions - `Assert [, message]` - `AssertEqual , [, message]` - `AssertNotEqual , [, message]` - `AssertThrows ` - This will set `g:vader_exception` (from `v:exception`) and `g:vader_throwpoint` (from `v:throwpoint`). - Other commands - `Log "Message"` - `Save [, ...]` - `Restore [, ...]` The following syntax helper functions are provided: - `SyntaxAt`: return a string with the name of the syntax group at the following position: - `SyntaxAt()`: current cursor position - `SyntaxAt(col)`: current cursor line, at given column - `SyntaxAt(lnum, col)`: line and column - `SyntaxOf(pattern[, nth=1])`: return a string with the name of the syntax group at the first character of the nth match of the given pattern. Return `''` if there was no match. The path of the current `.vader` file can be accessed via `g:vader_file`. In addition to plain Vimscript, you can also test Ruby/Python/Perl/Lua interface with Execute block as follows: ``` Execute [lang] [(comment)]: [ code] ``` See Ruby and Python examples [here](https://github.com/junegunn/vader.vim/blob/master/test/feature/lang-if.vader). #### Then A Then block containing Vimscript can follow a Do or an Execute block. Mostly used for assertions. Can be used in conjunction with an Expect block. ``` Then [(comment)]: [vimscript] ``` #### Expect If an Expect block follows an Execute block or a Do block, the result of the preceding block is compared to the content of the Expect block. Comparison is case-sensitive. `filetype` parameter is used to syntax-highlight the block. ``` Expect [filetype] [(comment)]: [expected output] ``` ### Hooks #### Before The content of a Before block is executed before every following Do/Execute block. ``` Before [(comment)]: [vim script] ``` #### After The content of an After block is executed after every following Do/Execute block. ``` After [(comment)]: [vim script] ``` ### Macros #### Include You can include other vader files using Include macro. ``` Include: setup.vader # ... Include: cleanup.vader ``` ### Comments Any line that starts with `#`, `"`, `=`, `-`, `~`, `^`, or `*` without indentation is considered to be a comment and simply ignored. ################### # Typical comment # ################### Given (fixture): ================ Hello Do (modification): ------------------ * change inner word ciw * to World Expect (result): ~~~~~~~~~~~~~~~~ World ### Example ``` # Test case Execute (test assertion): %d Assert 1 == line('$') setf python AssertEqual 'python', &filetype Given ruby (some ruby code): def a a = 1 end Do (indent the block): vip= Expect ruby (indented block): def a a = 1 end Do (indent and shift): vip= gv> Expect ruby (indented and shifted): def a a = 1 end Given c (C file): int i = 0; Execute (syntax is good): AssertEqual SyntaxAt(2), 'cType' AssertEqual SyntaxOf('0'), 'cNumber' ``` Setting up isolated testing environment --------------------------------------- When you test a plugin, it's generally a good idea to setup a testing environment that is isolated from the other plugins and settings irrelevant to the test. The simplest way to achieve this is to start Vim with a mini .vimrc as follows: ```sh vim -Nu <(cat << EOF filetype off set rtp+=~/.vim/bundle/vader.vim set rtp+=~/.vim/bundle/vim-markdown set rtp+=~/.vim/bundle/vim-markdown/after filetype plugin indent on syntax enable EOF) +Vader* ``` GitHub Actions -------------- Create `.github/workflows/test.yml` file with the following content: ```yaml --- name: Test on: push: branches: [master] pull_request: branches: [master] workflow_dispatch: jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 with: fetch-depth: 0 - name: Install Vim run: sudo apt-get install vim - name: Test run: | git clone https://github.com/junegunn/vader.vim.git vim -Nu <(cat << VIMRC set rtp+=vader.vim set rtp+=. VIMRC) -c 'silent Vader! test/*' > /dev/null ``` Travis CI integration --------------------- To make your project tested on [Travis CI](https://travis-ci.org), you need to add `.travis.yml` to your project root. For most plugins the following example should suffice. ```yaml language: vim before_script: | git clone https://github.com/junegunn/vader.vim.git script: | vim -Nu <(cat << VIMRC filetype off set rtp+=vader.vim set rtp+=. set rtp+=after filetype plugin indent on syntax enable VIMRC) -c 'Vader! test/*' > /dev/null ``` (Note that `vim` is not a valid language for Travis CI. It just sets up Ruby execution environment instead as the default.) ### Examples - [Simple .travis.yml](https://github.com/junegunn/seoul256.vim/blob/master/.travis.yml) - [Build result](https://travis-ci.org/junegunn/seoul256.vim/builds/23905890) - [Advanced .travis.yml](https://github.com/junegunn/vim-oblique/blob/master/.travis.yml) - Multiple dependencies - Builds Vim from source - [Build result](https://travis-ci.org/junegunn/vim-oblique/builds/25033116) Projects using Vader -------------------- See [the wiki page](https://github.com/junegunn/vader.vim/wiki/Projects-using-Vader). Known issues ------------ ### feedkeys() cannot be tested The keystrokes given to the feedkeys() function are consumed only after Vader finishes executing the content of the Do/Execute block. Take the following case as an example: ```vim Do (Test feedkeys() function): i123 \:call feedkeys('456')\ 789 Expect (Wrong!): 123456789 ``` You may have expected `123456789`, but the result is `123789456`. Unfortunately I have yet to find a workaround for this problem. Please let me know if you find one. ### Some events may not be triggered [It is reported](https://github.com/junegunn/vader.vim/issues/2) that CursorMoved event is not triggered inside a Do block. If you need to test a feature that involves autocommands on CursorMoved event, you have to manually invoke it in the middle of the block using `:doautocmd`. ```vim Do (Using doautocmd): jjj :doautocmd CursorMoved\ ``` ### Search history may not be correctly updated This is likely a bug of Vim itself. For some reason, search history is not correctly updated when searches are performed inside a Do block. The following test scenario fails due to this problem. ```vim Execute (Clear search history): for _ in range(&history) call histdel('/', -1) endfor Given (Search and destroy): I'm a street walking cheetah with a heart full of napalm I'm a runaway son of the nuclear A-bomb I'm a world's forgotten boy The one who searches and destroys Do (Searches): /street\ /walking\ /cheetah\ /runaway\ /search\ Execute (Assertions): Log string(map(range(1, &history), 'histget("/", - v:val)')) AssertEqual 'runaway', histget('/', -2) AssertEqual 'search', histget('/', -1) ``` The result is given as follows: ```vim Starting Vader: 1 suite(s), 3 case(s) Starting Vader: /Users/jg/.vim/plugged/vader.vim/search-and-destroy.vader (1/3) [EXECUTE] Clear search history (2/3) [ GIVEN] Search and destroy (2/3) [ DO] Searches (3/3) [ GIVEN] Search and destroy (3/3) [EXECUTE] Assertions > ['search', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', ''] (3/3) [EXECUTE] (X) Assertion failure: 'runaway' != '' Success/Total: 2/3 Success/Total: 2/3 (assertions: 0/1) Elapsed time: 0.36 sec. ``` License ------- MIT ))entry(nameautoloadnode(type directoryentry(namevadernode(type directoryentry(name assert.vimnode(typeregularcontentsX " Copyright (c) 2013 Junegunn Choi " " MIT License " " Permission is hereby granted, free of charge, to any person obtaining " a copy of this software and associated documentation files (the " "Software"), to deal in the Software without restriction, including " without limitation the rights to use, copy, modify, merge, publish, " distribute, sublicense, and/or sell copies of the Software, and to " permit persons to whom the Software is furnished to do so, subject to " the following conditions: " " The above copyright notice and this permission notice shall be " included in all copies or substantial portions of the Software. " " THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, " EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF " MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND " NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE " LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION " OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION " WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. let s:assertions = [0, 0] let s:type_names = { \ 0: 'Number', \ 1: 'String', \ 2: 'Funcref', \ 3: 'List', \ 4: 'Dictionary', \ 5: 'Float', \ 6: 'Boolean', \ 7: 'Null' } function! vader#assert#reset() let s:assertions = [0, 0] endfunction function! vader#assert#stat() return s:assertions endfunction function! vader#assert#true(...) let s:assertions[1] += 1 if a:0 == 1 let [expr, message] = [a:1, "Assertion failure"] elseif a:0 == 2 let [expr, message] = a:000 else throw 'Invalid number of arguments' endif if !expr throw message endif let s:assertions[0] += 1 return 1 endfunction function! s:check_types(...) let [Exp, Got] = a:000[0:1] if type(Exp) !=# type(Got) throw get(a:000, 2, printf("type mismatch: %s (%s) should be equal to %s (%s)", \ string(Got), get(s:type_names, type(Got), type(Got)), \ string(Exp), get(s:type_names, type(Exp), type(Exp)))) endif endfunction function! vader#assert#equal(...) let [Exp, Got] = a:000[0:1] let s:assertions[1] += 1 call s:check_types(Exp, Got) if Exp !=# Got let type = type(Exp) let type_name = get(s:type_names, type) let type_name_plural = type_name ==# 'Dictionary' ? 'Dictionaries' : type_name.'s' let msg = (type == type({}) || type == type([])) \ ? printf("Unequal %s\n %%s should be equal to\n %%s", type_name_plural) \ : '%s should be equal to %s' throw get(a:000, 2, printf(msg, string(Got), string(Exp))) endif let s:assertions[0] += 1 return 1 endfunction function! vader#assert#not_equal(...) let [Exp, Got] = a:000[0:1] let s:assertions[1] += 1 call s:check_types(Exp, Got) if Exp ==# Got throw get(a:000, 2, printf("%s should not be equal to %s", string(Got), string(Exp))) endif let s:assertions[0] += 1 return 1 endfunction function! vader#assert#throws(exp) let s:assertions[1] += 1 let g:vader_exception = '' let g:vader_throwpoint = '' let ok = 0 try execute a:exp catch let g:vader_exception = v:exception let g:vader_throwpoint = v:throwpoint let ok = 1 endtry let s:assertions[0] += ok if ok | return 1 else | throw 'Exception expected but not raised: '.a:exp endif endfunction ))entry(name helper.vimnode(typeregularcontentsÜfunction! vader#helper#syntax_at(...) syntax sync fromstart if a:0 < 2 let l:pos = getpos('.') let l:cur_lnum = pos[1] let l:cur_col = pos[2] if a:0 == 0 let l:lnum = l:cur_lnum let l:col = l:cur_col else let l:lnum = l:cur_lnum let l:col = a:1 endif else let l:lnum = a:1 let l:col = a:2 endif call map(synstack(l:lnum, l:col), 'synIDattr(v:val, "name")') return synIDattr(synID(l:lnum, l:col, 1), 'name') endfunction function! vader#helper#syntax_of(pattern, ...) if a:0 < 1 let l:nth = 1 else let l:nth = a:1 endif let l:pos_init = getpos('.') call cursor(1, 1) let found = search(a:pattern, 'cW') while found != 0 && nth > 1 let found = search(a:pattern, 'W') let nth -= 1 endwhile if found let l:pos = getpos('.') let l:output = vader#helper#syntax_at(l:pos[1], l:pos[2]) else let l:output = '' endif call setpos('.', l:pos_init) return l:output endfunction ))entry(name parser.vimnode(typeregularcontentsÊ" Copyright (c) 2013 Junegunn Choi " " MIT License " " Permission is hereby granted, free of charge, to any person obtaining " a copy of this software and associated documentation files (the " "Software"), to deal in the Software without restriction, including " without limitation the rights to use, copy, modify, merge, publish, " distribute, sublicense, and/or sell copies of the Software, and to " permit persons to whom the Software is furnished to do so, subject to " the following conditions: " " The above copyright notice and this permission notice shall be " included in all copies or substantial portions of the Software. " " THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, " EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF " MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND " NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE " LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION " OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION " WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. function! vader#parser#parse(fn, line1, line2) return s:parse_vader(s:read_vader(a:fn, a:line1, a:line2), a:line1) endfunction function! s:flush_buffer(cases, case, fn, lnum, raw, label, newlabel, buffer, final) let is_validation = index(['then', 'expect'], a:newlabel) >= 0 let fpos = a:fn.':'.a:lnum if empty(a:label) if is_validation echoerr 'Expect/Then should not appear before Do/Execute ('.fpos.')' endif else let rev = reverse(copy(a:buffer)) while len(rev) > 0 && empty(rev[0]) call remove(rev, 0) endwhile let data = map(reverse(rev), (a:case.raw ? 'v:val' : 'strpart(v:val, 2)')) let a:case[a:label] = data if !empty(a:buffer) call remove(a:buffer, 0, -1) endif let fulfilled = has_key(a:case, 'do') || has_key(a:case, 'execute') if is_validation if !fulfilled echoerr 'Expect/Then should not appear before Do/Execute ('.fpos.')' endif if has_key(a:case, a:newlabel) echoerr 'Expect/Then should appear only once for each Do/Execute ('.fpos.')' endif endif if a:final || \ a:newlabel == 'given' || \ index(['before', 'after', 'do', 'execute'], a:newlabel) >= 0 && fulfilled call add(a:cases, deepcopy(a:case)) let new = { 'comment': {}, 'lnum': a:lnum, 'pending': 0 } if !empty(get(a:case, 'type', '')) let new.type = a:case.type " To reuse Given block with type endif call extend(filter(a:case, '0'), new) endif endif let a:case.raw = a:raw endfunction function! s:read_vader(fn, line1, line2) let remains = readfile(a:fn)[a:line1 - 1 : a:line2 - 1] let lnum = a:line1 let lines = [] let reserved = 0 let depth = 0 " Not a strict depth let max_depth = 10 while len(remains) > 0 let line = remove(remains, 0) let m = matchlist(line, '^Include\(\s*(.*)\s*\)\?:\s*\(.\{-}\)\s*$') if !empty(m) let file = findfile(m[2], fnamemodify(a:fn, ':h')) if empty(file) echoerr "Cannot find ".m[2] endif if reserved > 0 let depth += 1 if depth >= max_depth echoerr 'Recursive inclusion limit exceeded' endif let reserved -= 1 endif let included = readfile(file) let reserved += len(included) call extend(remains, included, 0) continue end call add(lines, [a:fn, lnum, line]) if reserved > 0 let reserved -= 1 end if reserved == 0 let depth = 0 let lnum += 1 endif endwhile return lines endfunction function! s:parse_vader(lines, line1) let label = '' let newlabel = '' let buffer = [] let cases = [] let case = { 'lnum': a:line1, 'comment': {}, 'pending': 0, 'raw': 0 } if empty(a:lines) return [] endif for [fn, lnum, line] in a:lines " Comment / separators if !case.raw && line =~ '^[#"=~*^-]' continue endif let matched = 0 for l in ['Before', 'After', 'Given', 'Execute', 'Expect', 'Do', 'Then'] let m = matchlist(line, '^'.l.'\%(\s\+\([^:;(]\+\)\)\?\s*\%((\(.*\))\)\?\s*\([:;]\)\s*$') if !empty(m) let newlabel = tolower(l) call s:flush_buffer(cases, case, fn, lnum, m[3] == ';', label, newlabel, buffer, 0) let label = newlabel let arg = m[1] let comment = m[2] if !empty(arg) if l == 'Given' | let case.type = arg elseif l == 'Execute' | let case.lang_if = arg end elseif l == 'Given' let case.type = '' endif if !empty(comment) let case.comment[tolower(l)] = comment if index(['do', 'execute'], label) >= 0 && \ comment =~# '\\|\' let case.pending = 1 endif endif let matched = 1 break endif endfor if matched | continue | endif " Continuation if !empty(line) && !case.raw && line !~ '^ ' throw 'Syntax error (line does not start with two spaces): ' . line endif if !empty(label) call add(buffer, line) endif endfor call s:flush_buffer(cases, case, fn, lnum, case.raw, label, '', buffer, 1) let ret = [] let prev = {} for case in cases if has_key(case, "do") || has_key(case, "execute") call add(ret, extend(prev, case)) let prev = {} else let prev = case endif endfor return ret endfunction ))entry(name syntax.vimnode(typeregularcontents- " Copyright (c) 2014 Junegunn Choi " " MIT License " " Permission is hereby granted, free of charge, to any person obtaining " a copy of this software and associated documentation files (the " "Software"), to deal in the Software without restriction, including " without limitation the rights to use, copy, modify, merge, publish, " distribute, sublicense, and/or sell copies of the Software, and to " permit persons to whom the Software is furnished to do so, subject to " the following conditions: " " The above copyright notice and this permission notice shall be " included in all copies or substantial portions of the Software. " " THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, " EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF " MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND " NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE " LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION " OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION " WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. let s:ifs = ['lua', 'perl', 'ruby', 'python'] function! vader#syntax#reset() let b:vader_types = {} endfunction function! vader#syntax#include(l1, l2) let lines = filter(getline(a:l1, a:l2), '!empty(v:val) && v:val[0] != " "') for line in lines let match = matchlist(line, '^\(Given\|Expect\|Execute\)\s\+\([^:; (]\+\)') if len(match) >= 3 silent! call s:load(match[2]) endif endfor endfunction function! vader#syntax#_head() return '\(\(^\(Given\|Expect\|Do\|Execute\|Then\|Before\|After\)\(\s\+[^:;(]\+\)\?\s*\((.*)\)\?\s*[:;]\s*$\)\|\(^Include\(\s*(.*)\)\?\s*:\)\)\@=' endfunction function! s:load(type) let b:vader_types = get(b:, 'vader_types', {}) if has_key(b:vader_types, a:type) return endif if empty(globpath(&rtp, "syntax/".a:type.".vim", 1)) return endif let b:vader_types[a:type] = 1 unlet! b:current_syntax execute printf('syn include @%sSnippet syntax/%s.vim', a:type, a:type) execute printf('syn region vader_%s start=/^\s\{2,}/ end=/^\S\@=/ contains=@%sSnippet contained', a:type, a:type) execute printf('syn region vader_raw_%s start=/\(;\s*$\)\@<=/ end=/%s/ contains=@%sSnippet contained', a:type, vader#syntax#_head(), a:type) call s:define_syntax_region('Given', a:type) call s:define_syntax_region('Expect', a:type) if index(s:ifs, a:type) >= 0 call s:define_syntax_region('Execute', a:type) endif let b:current_syntax = 'vader' endfunction function! s:define_syntax_region(block, lang) execute printf('syn region vader%s start=/^%s\s\+%s\s*\((.*)\)\?\s*:\s*$/ end=/\(^[^ ^#~=*-]\)\@=/ contains=vader%sType,vaderMessage,@vaderIgnored,vader_%s nextgroup=@vaderTopLevel skipempty keepend', a:block, a:block, a:lang, a:block, a:lang) execute printf('syn region vader%sRaw start=/^%s\s\+%s\s*\((.*)\)\?\s*;\s*$/ end=/%s/ contains=vader%sType,vaderMessage,@vaderIgnored,vader_raw_%s nextgroup=@vaderTopLevel skipempty keepend', a:block, a:block, a:lang, vader#syntax#_head(), a:block, a:lang) endfunction ))entry(name window.vimnode(typeregularcontents" Copyright (c) 2013 Junegunn Choi " " MIT License " " Permission is hereby granted, free of charge, to any person obtaining " a copy of this software and associated documentation files (the " "Software"), to deal in the Software without restriction, including " without limitation the rights to use, copy, modify, merge, publish, " distribute, sublicense, and/or sell copies of the Software, and to " permit persons to whom the Software is furnished to do so, subject to " the following conditions: " " The above copyright notice and this permission notice shall be " included in all copies or substantial portions of the Software. " " THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, " EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF " MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND " NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE " LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION " OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION " WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. let s:quickfix_bfr = 0 let s:console_bfr = 0 let s:console_tab = 0 let s:workbench_tab = 0 let s:workbench_bfr = 0 function! s:switch_to_console() execute 'normal! '.s:console_tab.'gt' if tabpagenr() != s:console_tab call vader#window#append(printf('Vader warning: could not change to console tab (%d)', s:console_tab), 0) endif call append(line('$') - 1, s:console_buffered) let s:console_buffered = [] endfunction function! s:switch_to_workbench() execute 'normal! '.s:workbench_tab.'gt' execute 'b!' s:workbench_bfr endfunction function! vader#window#open() execute 'silent! bd' s:console_bfr execute 'silent! bd' s:workbench_bfr if bufexists(s:quickfix_bfr) execute "silent! bd ".s:quickfix_bfr endif let s:prev_winid = exists('*win_getid') ? win_getid() : 0 tabnew setlocal buftype=nofile noswapfile nospell setf vader-result silent f \[Vader\] let s:console_tab = tabpagenr() let s:console_bfr = bufnr('') let s:console_buffered = [] let b:vader_data = {} nnoremap :call action(line('.')) tabnew setlocal buftype=nofile setlocal noswapfile silent f \[Vader-workbench\] let s:workbench_tab = tabpagenr() let s:workbench_bfr = bufnr('') endfunction function! vader#window#execute(lines, lang_if) let temp = tempname() try if empty(a:lang_if) let lines = a:lines else let lines = copy(a:lines) call insert(lines, a:lang_if . ' << __VADER__LANG__IF__') call add(lines, '__VADER__LANG__IF__') endif call writefile(lines, temp) execute 'source '.temp finally call delete(temp) endtry endfunction function! vader#window#replay(lines) call setreg('x', substitute(join(a:lines, ''), '\\<[^>]\+>', '\=eval("\"".submatch(0)."\"")', 'g'), 'c') normal! @x endfunction function! vader#window#result() return getline(1, line('$')) endfunction function! vader#window#append(message, indent, ...) let message = repeat(' ', a:indent) . a:message if get(a:, 1, 1) let message = substitute(message, '\s*$', '', '') endif if !exists('s:console_buffered') call vader#print_stderr(printf("Vader: got message before startup: %s\n", message)) return 0 endif if get(g:, 'vader_bang', 0) call vader#print_stderr(message."\n") return 0 endif call add(s:console_buffered, message) return len(s:console_buffered) endfunction function! vader#window#prepare(lines, type) call s:switch_to_workbench() execute 'setlocal modifiable filetype='.a:type silent %d _ for line in a:lines call append(line('$') - 1, line) endfor silent d _ execute "normal! \\gg0" let &undolevels = &undolevels " Break undo block endfunction function! vader#window#cleanup() execute 'silent! bd' s:workbench_bfr call s:switch_to_console() setlocal nomodifiable nnoremap q :call quit() normal! Gzb endfunction function! vader#window#copen() copen let s:quickfix_bfr = bufnr('') 1wincmd w normal! Gzb 2wincmd w nnoremap q :call quit() nnoremap :call move() endfunction function! vader#window#set_data(l1, l2, data) try let var = getbufvar(s:console_bfr, 'vader_data', {}) for l in range(a:l1, a:l2) let var[l] = a:data endfor call setbufvar(s:console_bfr, 'vader_data', var) catch endtry endfunction function! s:scratch(type, data, title) setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile nowrap modifiable silent! execute 'setf '.a:type call append(0, a:data) nnoremap q :tabclose autocmd TabLeave tabclose execute 'silent f '.escape(a:title, '[]') normal! G"_ddgg diffthis setlocal nomodifiable endfunction function! s:action(line) if has_key(b:vader_data, a:line) let data = b:vader_data[a:line] if has_key(data, 'expect') tabnew call s:scratch(data.type, data.expect, '[Vader-expected]') vertical botright new call s:scratch(data.type, data.got, '[Vader-got]') redraw echo "Press 'q' to close" endif else execute "normal! \" endif endfunction function! s:move() let lno = matchstr(getline('.'), '(#[0-9]\+)')[2:-2] let wq = winnr() let wc = bufwinnr(s:console_bfr) if wc >= 0 execute wc . 'wincmd w' let scrolloff = &scrolloff set scrolloff=0 execute lno normal! zt redraw let &scrolloff = scrolloff execute wq . 'wincmd w' endif endfunction function! s:quit() if s:prev_winid let [s:t, s:w] = win_id2tabwin(s:prev_winid) if s:t execute printf('tabnext %d | %dwincmd w | %dtabclose', s:t, s:w, s:console_tab) return endif endif tabclose endfunction ))))entry(name vader.vimnode(typeregularcontents 3" Copyright (c) 2015 Junegunn Choi " " MIT License " " Permission is hereby granted, free of charge, to any person obtaining " a copy of this software and associated documentation files (the " "Software"), to deal in the Software without restriction, including " without limitation the rights to use, copy, modify, merge, publish, " distribute, sublicense, and/or sell copies of the Software, and to " permit persons to whom the Software is furnished to do so, subject to " the following conditions: " " The above copyright notice and this permission notice shall be " included in all copies or substantial portions of the Software. " " THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, " EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF " MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND " NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE " LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION " OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION " WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. let s:register = {} let s:register_undefined = [] let s:indent = 2 " Fallback to 'type' (on Windows). let s:cat = executable('cat') ? 'cat' : 'type' function! vader#run(bang, ...) range let s:error_line = 0 let g:vader_bang = a:bang if a:lastline - a:firstline > 0 if a:0 > 1 echoerr "You can't apply range on multiple files" return endif let [line1, line2] = [a:firstline, a:lastline] else let [line1, line2] = [1, 0] endif let options = { \ 'exitfirst': index(a:000, '-x') >= 0, \ 'quiet': index(a:000, '-q') >= 0, \ } let patterns = filter(copy(a:000), "index(['-x', '-q'], v:val) == -1") if empty(patterns) let patterns = [expand('%')] endif if a:bang && !options.quiet redir => ver silent version redir END call vader#print_stderr(ver . "\n\n") endif call vader#assert#reset() call s:prepare() try let all_cases = [] let qfl = [] let st = reltime() let [success, pending, total] = [0, 0, 0] for gl in patterns if filereadable(gl) let files = [gl] else let files = filter(split(glob(gl), "\n"), \ "fnamemodify(v:val, ':e') ==# 'vader'") endif for fn in files let afn = fnamemodify(fn, ':p') let cases = vader#parser#parse(afn, line1, line2) call add(all_cases, [afn, cases]) let total += len(cases) endfor endfor if empty(all_cases) throw 'Vader: no tests found for patterns ('.join(patterns).')' endif call vader#window#open() call vader#window#append( \ printf("Starting Vader: %d suite(s), %d case(s)", len(all_cases), total), 0) for pair in all_cases let [fn, case] = pair let [cs, cp, ct, lqfl] = s:run(fn, case, options) let success += cs let pending += cp call extend(qfl, lqfl) call vader#window#append( \ printf('Success/Total: %s/%s%s', \ cs, ct, cp > 0 ? (' ('.cp.' pending)') : ''), \ 1) if options.exitfirst && (cs + cp) < ct break endif endfor let successful = success + pending == total let g:vader_result = { \ 'total': total, \ 'success': success, \ 'pending': pending, \ 'successful': successful, \ } let stats = vader#assert#stat() call vader#window#append(printf('Success/Total: %s/%s (%sassertions: %d/%d)', \ success, total, (pending > 0 ? pending . ' pending, ' : ''), \ stats[0], stats[1]), 0) if 0 && exists('*reltimefloat') let duration = printf('%.2f', reltimefloat(reltime(st))) else let duration = substitute(substitute(reltimestr(reltime(st)), '^\s*', '', ''), '\.\d\d\zs.*', '', '') endif call vader#window#append(printf('Elapsed time: %s sec.', duration), 0) call vader#window#cleanup() if a:bang if exists('*s:output_stderr_buffer') call s:output_stderr_buffer() endif if successful qall! else cq endif else let g:vader_report = join(getline(1, '$'), "\n") let g:vader_errors = qfl call setqflist(qfl) if !empty(qfl) call vader#window#copen() endif endif catch let error = 'Vader error: '.v:exception.' (in '.v:throwpoint.')' if a:bang call vader#print_stderr(error) cq else echoerr error endif finally call s:cleanup() endtry endfunction " Define vader#print_stderr based on available features / used options. " This is done a) for performance reasons, but b) mainly because `mode()` " might be e.g. "ic" during tests, and we need to detect the initial usage of " "-es" / "-Es". if !empty($VADER_OUTPUT_FILE) function! vader#print_stderr(output) abort let lines = split(a:output, '\n') call writefile(lines, $VADER_OUTPUT_FILE, 'a') endfunction elseif has('nvim') if exists('v:stderr') function! vader#print_stderr(output) abort call chansend(v:stderr, a:output) endfunction elseif filewritable('/dev/stderr') function! vader#print_stderr(output) abort let lines = split(a:output, '\n') call writefile(lines, '/dev/stderr', 'a') endfunction else " Assume --headless mode being used. Could be detected using " "len(nvim_list_uis()) == 0 after VimEnter", but not available with " Neovim 0.2.0 at least. function! vader#print_stderr(output) abort for line in split(a:output, '\n') echom line endfor endfunction endif else if v:version >= 702 " mode(1) only works with Vim v7.2a. let mode = mode(1) else let mode = '' endif if mode ==# 'ce' || mode ==# 'cv' " -es (silent ex mode) function! vader#print_stderr(output) abort let lines = split(a:output, '\n') for line in lines verbose echon line."\n" endfor endfunction else " Cannot output single lines reliably in this case. let s:stderr_buffer = [] if !empty(mode) call add(s:stderr_buffer, \ printf('Vader note: cannot print to stderr reliably/directly. Please consider using %s''s -es/-Es option (mode=%s).', \ has('nvim') ? 'Neovim' : 'Vim', \ mode)) endif function! s:output_stderr_buffer() abort let s:tmpfile = tempname() call writefile(s:stderr_buffer, s:tmpfile) execute printf('silent !%s %s 1>&2', s:cat, s:tmpfile) let s:stderr_buffer = [] endfunction augroup vader_exit autocmd VimLeave * call s:output_stderr_buffer() augroup END function! vader#print_stderr(output) abort let lines = split(a:output, '\n') call extend(s:stderr_buffer, lines) endfunction endif endif function! s:split_args(arg) let varnames = split(a:arg, ',') let names = [] for varname in varnames let name = substitute(varname, '^\s*\(.*\)\s*$', '\1', '') let name = substitute(name, '^''\(.*\)''$', '\1', '') let name = substitute(name, '^"\(.*\)"$', '\1', '') call add(names, name) endfor return names endfunction function! vader#log(msg) let msg = type(a:msg) == 1 ? a:msg : string(a:msg) call vader#window#append('> ' . msg, s:indent) endfunction function! vader#save(args) for varname in s:split_args(a:args) if exists(varname) let s:register[varname] = deepcopy(eval(varname)) else let s:register_undefined += [varname] endif endfor endfunction function! vader#restore(args) let varnames = s:split_args(a:args) for varname in empty(varnames) ? keys(s:register) : varnames if has_key(s:register, varname) execute printf("let %s = deepcopy(s:register['%s'])", varname, varname) endif endfor let undefined = empty(varnames) ? s:register_undefined \ : filter(copy(varnames), 'index(s:register_undefined, v:val) != -1') for varname in undefined if varname[0] ==# '$' execute printf('let %s = ""', varname) else execute printf('unlet! %s', varname) endif endfor endfunction function! s:prepare() command! -nargs=+ Log :call vader#log() command! -nargs=+ Save :call vader#save() command! -nargs=* Restore :call vader#restore() command! -nargs=+ Assert :call vader#assert#true() command! -nargs=+ AssertEqual :call vader#assert#equal() command! -nargs=+ AssertNotEqual :call vader#assert#not_equal() command! -nargs=+ AssertThrows :call vader#assert#throws() let g:SyntaxAt = function('vader#helper#syntax_at') let g:SyntaxOf = function('vader#helper#syntax_of') endfunction function! s:cleanup() let s:register = {} let s:register_undefined = [] delcommand Log delcommand Save delcommand Restore delcommand Assert delcommand AssertEqual delcommand AssertNotEqual delcommand AssertThrows unlet g:SyntaxAt unlet g:SyntaxOf endfunction function! s:comment(case, label) return get(a:case.comment, a:label, '') endfunction function! s:execute(prefix, type, block, lang_if) try call vader#window#execute(a:block, a:lang_if) return 1 catch call s:append(a:prefix, a:type, v:exception, 1) call s:print_throwpoint() return 0 endtry endfunction function! s:print_throwpoint() if v:throwpoint !~ 'vader#assert' Log v:throwpoint endif endfunction function! s:run(filename, cases, options) let given = [] let before = [] let after = [] let then = [] let comment = { 'given': '', 'before': '', 'after': '' } let total = len(a:cases) let just = len(string(total)) let cnt = 0 let pending = 0 let success = 0 let exitfirst = get(a:options, 'exitfirst', 0) let qfl = [] let g:vader_file = a:filename call vader#window#append("Starting Vader: ". a:filename, 1) for case in a:cases let cnt += 1 let ok = 1 let prefix = printf('(%'.just.'d/%'.just.'d)', cnt, total) for label in ['given', 'before', 'after', 'then'] if has_key(case, label) execute 'let '.label.' = case[label]' let comment[label] = get(case.comment, label, '') endif endfor if !empty(given) call s:append(prefix, 'given', comment.given) endif call vader#window#prepare(given, get(case, 'type', '')) if !empty(before) let s:indent = 2 let ok = ok && s:execute(prefix, 'before', before, '') endif let s:indent = 3 if has_key(case, 'execute') call s:append(prefix, 'execute', s:comment(case, 'execute')) let ok = ok && s:execute(prefix, 'execute', case.execute, get(case, 'lang_if', '')) elseif has_key(case, 'do') call s:append(prefix, 'do', s:comment(case, 'do')) try call vader#window#replay(case.do) catch call s:append(prefix, 'do', v:exception, 1) call s:print_throwpoint() let ok = 0 endtry endif if has_key(case, 'then') call s:append(prefix, 'then', s:comment(case, 'then')) let ok = ok && s:execute(prefix, 'then', then, '') endif if has_key(case, 'expect') let result = vader#window#result() let match = case.expect ==# result if match call s:append(prefix, 'expect', s:comment(case, 'expect')) else let begin = s:append(prefix, 'expect', s:comment(case, 'expect'), 1) let ok = 0 let data = { 'type': get(case, 'type', ''), 'got': result, 'expect': case.expect } call vader#window#append('- Expected:', 3) for line in case.expect call vader#window#append(line, 5, 0) endfor let end = vader#window#append('- Got:', 3) for line in result let end = vader#window#append(line, 5, 0) endfor call vader#window#set_data(begin, end, data) endif endif if !empty(after) let s:indent = 2 let g:vader_case_ok = ok let ok = s:execute(prefix, 'after', after, '') && ok endif if ok let success += 1 else let pending += case.pending let description = join(filter([ \ comment.given, \ get(case.comment, 'do', get(case.comment, 'execute', '')), \ get(case.comment, 'then', ''), \ get(case.comment, 'expect', '')], '!empty(v:val)'), ' / ') . \ ' (#'.s:error_line.')' call add(qfl, { 'type': 'E', 'filename': a:filename, 'lnum': case.lnum, 'text': description }) if exitfirst && !case.pending call vader#window#append('Stopping after first failure.', 2) break endif endif endfor unlet g:vader_file return [success, pending, total, qfl] endfunction function! s:append(prefix, type, message, ...) let error = get(a:, 1, 0) let message = (error ? '(X) ' : '') . a:message let line = vader#window#append(printf("%s [%7s] %s", a:prefix, toupper(a:type), message), 2) if error let s:error_line = line endif return line endfunction ))))entry(name codecov.ymlnode(typeregularcontents comment: off ))entry(namedocnode(type directoryentry(name vader.txtnode(typeregularcontents;Fvader.txt vader Last change: December 28 2014 VADER - TABLE OF CONTENTS *vader* *vader-toc* ============================================================================== vader.vim Vader test cases Vader result Installation |vader-1| Running Vader tests |vader-2| Syntax of .vader file |vader-3| Basic blocks |vader-3-1| Given |vader-3-1-1| Do |vader-3-1-2| Execute |vader-3-1-3| Then |vader-3-1-4| Expect |vader-3-1-5| Hooks |vader-3-2| Before |vader-3-2-1| After |vader-3-2-2| Macros |vader-3-3| Include |vader-3-3-1| Comments |vader-3-4| Example |vader-3-5| Setting up isolated testing environment |vader-4| Travis CI integration |vader-5| Examples |vader-5-1| Projects using Vader |vader-6| Known issues |vader-7| feedkeys() cannot be tested |vader-7-1| Some events may not be triggered |vader-7-2| Search history may not be correctly updated |vader-7-3| License |vader-8| VADER.VIM *vader-vim* ============================================================================== I use Vader to test Vimscript. < Vader test cases >__________________________________________________________~ *vader-test-cases* https://raw.github.com/junegunn/i/master/vader.png < Vader result >______________________________________________________________~ *vader-result* https://raw.github.com/junegunn/i/master/vader-result.png *vader-1* INSTALLATION *vader-installation* ============================================================================== Use your favorite plugin manager. - {vim-plug}{1} 1. Add `Plug 'junegunn/vader.vim'` to .vimrc 2. Run `:PlugInstall` {1} https://github.com/junegunn/vim-plug *vader-2* RUNNING VADER TESTS *vader-running-vader-tests* ============================================================================== - `Vader [file glob ...]` - `Vader! [file glob ...]` - Exit Vim after running the tests with exit status of 0 or 1 - `vim '+Vader!*' && echo Success || echo Failure` - (You need to pass `--nofork` option when using GVim) - If the description of `Do` or `Execute` block includes `FIXME` or `TODO`, the block is recognized as a pending test case and does not affect the exit status. - If the environment variable `VADER_OUTPUT_FILE` is set, the test results will be written to it as well *vader-3* SYNTAX OF .VADER FILE *vader-syntax-of-vader-file* ============================================================================== A Vader file is a flat sequence of blocks each of which starts with the block label, such as `Execute:`, followed by the content of the block indented by 2 spaces. - Given - Content to fill the execution buffer - Do - Normal-mode keystrokes that can span multiple lines - Execute - Vimscript to execute - Then - Vimscript to run after Do or Execute block. Used for assertions. - Expect - Expected result of the preceding Do/Execute block - Before - Vimscript to run before each test case - After - Vimscript to run after each test case If you want to skip 2-space indention, end the block label with a semi-colon instead of a colon. < Basic blocks >______________________________________________________________~ *vader-basic-blocks* *vader-3-1* Given~ *vader-given* *vader-3-1-1* The content of a Given block is pasted into the "workbench buffer" for the subsequent Do/Execute blocks. If `filetype` parameter is given, 'filetype' of the buffer is set accordingly. It is also used to syntax-highlight the block in .vader file. > Given [filetype] [(comment)]: [input text] < Do~ *vader-do* *vader-3-1-2* The content of a Do block is a sequence of normal-mode keystrokes that can freely span multiple lines. A special key can be written in its name surrounded by angle brackets preceded by a backslash (e.g. \). Do block can be followed by an optional Expect block. > Do [(comment)]: [keystrokes] < Execute~ *vader-execute* *vader-3-1-3* The content of an Execute block is plain Vimscript to be executed. Execute block can also be followed by an optional Expect block. > Execute [(comment)]: [vimscript] < In Execute block, the following commands are provided. - Assertions - Assert [, message] - AssertEqual , [, message] - AssertNotEqual , [, message] - AssertThrows This will set `g:vader_exception` (see |v:exception|) and `g:vader_throwpoint` (see |v:throwpoint|). - Other commands - `Log "Message"` - Save [, ...] - Restore [, ...] The following syntax helper functions are provided: - `SyntaxAt`: return a string with the name of the syntax group at the following position: - `SyntaxAt()`: current cursor position - `SyntaxAt(col)`: current cursor line, at given column - `SyntaxAt(lnum, col)`: line and column - `SyntaxOf(pattern[, nth=1])`: return a string with the name of the syntax group at the first character of the nth match of the given pattern. Return `''` if there was no match. *g:vader_file* The path of the current `.vader` file can be accessed via `g:vader_file`. In addition to plain Vimscript, you can also test Ruby/Python/Perl/Lua interface with Execute block as follows: > Execute [lang] [(comment)]: [ code] < See Ruby and Python examples {here}{2}. {2} https://github.com/junegunn/vader.vim/blob/master/test/feature/lang-if.vader Then~ *vader-then* *vader-3-1-4* A Then block containing Vimscript can follow a Do or an Execute block. Mostly used for assertions. Can be used in conjunction with an Expect block. > Then [(comment)]: [vimscript] < Expect~ *vader-expect* *vader-3-1-5* If an Expect block follows an Execute block or a Do block, the result of the preceding block is compared to the content of the Expect block. Comparison is case-sensitive. `filetype` parameter is used to syntax-highlight the block. > Expect [filetype] [(comment)]: [expected output] < < Hooks >_____________________________________________________________________~ *vader-hooks* *vader-3-2* Before~ *vader-before* *vader-3-2-1* The content of a Before block is executed before every following Do/Execute block. > Before [(comment)]: [vim script] < After~ *vader-after* *vader-3-2-2* The content of an After block is executed after every following Do/Execute block. > After [(comment)]: [vim script] < < Macros >____________________________________________________________________~ *vader-macros* *vader-3-3* Include~ *vader-include* *vader-3-3-1* You can include other vader files using Include macro. > Include: setup.vader # ... Include: cleanup.vader < < Comments >__________________________________________________________________~ *vader-comments* *vader-3-4* Any line that starts with `#`, `"`, `=`, `-`, `~`, `^`, or `*` without indentation is considered to be a comment and simply ignored. > ################### # Typical comment # ################### Given (fixture): ================ Hello Do (modification): ------------------ * change inner word ciw * to World Expect (result): ~~~~~~~~~~~~~~~~ World < < Example >___________________________________________________________________~ *vader-example* *vader-3-5* > # Test case Execute (test assertion): %d Assert 1 == line('$') setf python AssertEqual 'python', &filetype Given ruby (some ruby code): def a a = 1 end Do (indent the block): vip= Expect ruby (indented block): def a a = 1 end Do (indent and shift): vip= gv> Expect ruby (indented and shifted): def a a = 1 end Given c (C file): int i = 0; Execute (syntax is good): AssertEqual SyntaxAt(2), 'cType' AssertEqual SyntaxOf('0'), 'cNumber' < *vader-4* *vader-setting-up-isolated-testing-environment* SETTING UP ISOLATED TESTING ENVIRONMENT ============================================================================== When you test a plugin, it's generally a good idea to setup a testing environment that is isolated from the other plugins and settings irrelevant to the test. The simplest way to achieve this is to start Vim with a mini .vimrc as follows: > vim -Nu <(cat << EOF filetype off set rtp+=~/.vim/bundle/vader.vim set rtp+=~/.vim/bundle/vim-markdown set rtp+=~/.vim/bundle/vim-markdown/after filetype plugin indent on syntax enable EOF) +Vader* < *vader-5* TRAVIS CI INTEGRATION *vader-travis-ci-integration* ============================================================================== To make your project tested on {Travis CI}{3}, you need to add `.travis.yml` to your project root. For most plugins the following example should suffice. > language: vim before_script: | git clone https://github.com/junegunn/vader.vim.git script: | vim -Nu <(cat << VIMRC filetype off set rtp+=vader.vim set rtp+=. set rtp+=after filetype plugin indent on syntax enable VIMRC) -c 'Vader! test/*' > /dev/null < (Note that `vim` is not a valid language for Travis CI. It just sets up Ruby execution environment instead as the default.) {3} https://travis-ci.org < Examples >__________________________________________________________________~ *vader-examples* *vader-5-1* - {Simple .travis.yml}{4} - {Build result}{5} - {Advanced .travis.yml}{6} - Multiple dependencies - Builds Vim from source - {Build result}{7} {4} https://github.com/junegunn/seoul256.vim/blob/master/.travis.yml {5} https://travis-ci.org/junegunn/seoul256.vim/builds/23905890 {6} https://github.com/junegunn/vim-oblique/blob/master/.travis.yml {7} https://travis-ci.org/junegunn/vim-oblique/builds/25033116 *vader-6* PROJECTS USING VADER *vader-projects-using-vader* ============================================================================== See {the wiki page}{8}. {8} https://github.com/junegunn/vader.vim/wiki/Projects-using-Vader *vader-7* KNOWN ISSUES *vader-known-issues* ============================================================================== < feedkeys() cannot be tested >_______________________________________________~ *vader-feedkeys-cannot-be-tested* *vader-7-1* The keystrokes given to the feedkeys() function are consumed only after Vader finishes executing the content of the Do/Execute block. Take the following case as an example: > Do (Test feedkeys() function): i123 \:call feedkeys('456')\ 789 Expect (Wrong!): 123456789 < You may have expected `123456789`, but the result is `123789456`. Unfortunately I have yet to find a workaround for this problem. Please let me know if you find one. < Some events may not be triggered >__________________________________________~ *vader-some-events-may-not-be-triggered* *vader-7-2* {It is reported}{9} that CursorMoved event is not triggered inside a Do block. If you need to test a feature that involves autocommands on CursorMoved event, you have to manually invoke it in the middle of the block using `:doautocmd`. > Do (Using doautocmd): jjj :doautocmd CursorMoved\ < {9} https://github.com/junegunn/vader.vim/issues/2 < Search history may not be correctly updated >_______________________________~ *vader-search-history-may-not-be-correctly-updated* *vader-7-3* This is likely a bug of Vim itself. For some reason, search history is not correctly updated when searches are performed inside a Do block. The following test scenario fails due to this problem. > Execute (Clear search history): for _ in range(&history) call histdel('/', -1) endfor Given (Search and destroy): I'm a street walking cheetah with a heart full of napalm I'm a runaway son of the nuclear A-bomb I'm a world's forgotten boy The one who searches and destroys Do (Searches): /street\ /walking\ /cheetah\ /runaway\ /search\ Execute (Assertions): Log string(map(range(1, &history), 'histget("/", - v:val)')) AssertEqual 'runaway', histget('/', -2) AssertEqual 'search', histget('/', -1) < The result is given as follows: > Starting Vader: 1 suite(s), 3 case(s) Starting Vader: /Users/jg/.vim/plugged/vader.vim/search-and-destroy.vader (1/3) [EXECUTE] Clear search history (2/3) [ GIVEN] Search and destroy (2/3) [ DO] Searches (3/3) [ GIVEN] Search and destroy (3/3) [EXECUTE] Assertions > ['search', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', ''] (3/3) [EXECUTE] (X) Assertion failure: 'runaway' != '' Success/Total: 2/3 Success/Total: 2/3 (assertions: 0/1) Elapsed time: 0.36 sec. < *vader-8* LICENSE *vader-license* ============================================================================== MIT ============================================================================== vim:tw=78:sw=2:ts=2:ft=help:norl:nowrap: ))))entry(nameftdetectnode(type directoryentry(name vader.vimnode(typeregularcontentsˆ" Copyright (c) 2013 Junegunn Choi " " MIT License " " Permission is hereby granted, free of charge, to any person obtaining " a copy of this software and associated documentation files (the " "Software"), to deal in the Software without restriction, including " without limitation the rights to use, copy, modify, merge, publish, " distribute, sublicense, and/or sell copies of the Software, and to " permit persons to whom the Software is furnished to do so, subject to " the following conditions: " " The above copyright notice and this permission notice shall be " included in all copies or substantial portions of the Software. " " THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, " EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF " MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND " NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE " LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION " OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION " WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. au BufRead,BufNewFile *.vader set filetype=vader ))))entry(nameftpluginnode(type directoryentry(name vader.vimnode(typeregularcontentsR " Copyright (c) 2014 Junegunn Choi " " MIT License " " Permission is hereby granted, free of charge, to any person obtaining " a copy of this software and associated documentation files (the " "Software"), to deal in the Software without restriction, including " without limitation the rights to use, copy, modify, merge, publish, " distribute, sublicense, and/or sell copies of the Software, and to " permit persons to whom the Software is furnished to do so, subject to " the following conditions: " " The above copyright notice and this permission notice shall be " included in all copies or substantial portions of the Software. " " THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, " EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF " MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND " NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE " LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION " OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION " WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. " Only do this when not done yet for this buffer if exists('b:did_ftplugin') finish endif let s:save_cpo = &cpo set cpo-=C let b:vader_label = vader#syntax#_head() let b:vader_eos = '\(.*\n'.vader#syntax#_head().'\)\|\%$' setlocal shiftwidth=2 tabstop=2 softtabstop=2 expandtab setlocal iskeyword+=# setlocal keywordprg=:help let &l:commentstring = '" %s' let &l:comments = 'sO:" -,mO:" ,eO:"",:"' nnoremap [[ :call search(b:vader_label, 'bW') nnoremap [] :call search(b:vader_eos, 'bW') nnoremap ]] :call search(b:vader_label, 'W') nnoremap ][ :call search(b:vader_eos, 'W') vnoremap [[ :execute "normal! gv"call search(b:vader_label, 'bW') vnoremap [] :execute "normal! gv"call search(b:vader_eos, 'bW') vnoremap ]] :execute "normal! gv"call search(b:vader_label, 'W') vnoremap ][ :execute "normal! gv"call search(b:vader_eos, 'W') augroup vader_syntax autocmd! if exists('##TextChangedI') autocmd TextChangedI call vader#syntax#include('.', '.') else autocmd CursorMovedI call vader#syntax#include('.', '.') endif " autocmd FileType call vader#syntax#include(1, '$') augroup END let b:undo_ftplugin = 'setl sw< ts< sts< et< cms< isk< kp<' \ . ' | exe "au! vader_syntax * "' \ . ' | unlet b:vader_label b:vader_eos' let &cpo = s:save_cpo ))))entry(namepluginnode(type directoryentry(name vader.vimnode(typeregularcontents‰" Copyright (c) 2015 Junegunn Choi " " MIT License " " Permission is hereby granted, free of charge, to any person obtaining " a copy of this software and associated documentation files (the " "Software"), to deal in the Software without restriction, including " without limitation the rights to use, copy, modify, merge, publish, " distribute, sublicense, and/or sell copies of the Software, and to " permit persons to whom the Software is furnished to do so, subject to " the following conditions: " " The above copyright notice and this permission notice shall be " included in all copies or substantial portions of the Software. " " THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, " EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF " MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND " NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE " LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION " OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION " WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. if exists('g:loaded_vader') finish endif if &compatible function! s:vader(...) range echoerr 'Cannot run Vader in compatible mode' endfunction else let g:loaded_vader = 1 function! s:vader(...) range if a:lastline - a:firstline > 0 && a:0 > 1 echoerr 'Range and file arguments are mutually exclusive' return endif execute printf("%d,%dcall vader#run(%s)", a:firstline, a:lastline, string(a:000)[1:-2]) endfunction endif command! -bang -nargs=* -range -complete=file Vader ,call s:vader(0, ) ))))entry(namesyntaxnode(type directoryentry(namevader-result.vimnode(typeregularcontentsR " Copyright (c) 2013 Junegunn Choi " " MIT License " " Permission is hereby granted, free of charge, to any person obtaining " a copy of this software and associated documentation files (the " "Software"), to deal in the Software without restriction, including " without limitation the rights to use, copy, modify, merge, publish, " distribute, sublicense, and/or sell copies of the Software, and to " permit persons to whom the Software is furnished to do so, subject to " the following conditions: " " The above copyright notice and this permission notice shall be " included in all copies or substantial portions of the Software. " " THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, " EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF " MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND " NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE " LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION " OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION " WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. if exists("b:current_syntax") finish endif syntax match vaderResultTitle /^[^:]*/ contains=vaderResultNumber syntax match vaderResultTitle /^[^:]*:\@=/ contains=vaderResultNumber syntax match vaderResultTitleRest /\(^[^:]*:\)\@<=.*/ contains=vaderResultNumber syntax match vaderResultTitle2 /^ [^:]*:\@=/ contains=vaderResultNumber syntax match vaderResultTitle2Rest /\(^ [^:]*:\)\@<=.*/ contains=vaderResultNumber syntax match vaderResultNumber /-\?[0-9]\+\(\.[0-9]\+\)\?/ contained syntax match vaderResultItem /^ [^\]]\+\]\( (X).*\)\?/ contains=vaderResultSequence,vaderResultType,vaderResultError syntax match vaderResultSequence /^ ([0-9/ ]\+)/ contains=vaderResultNumber contained syntax match vaderResultType /\[[A-Z ]\+\]/ contained contains=vaderResultDo,vaderResultThen,vaderResultGiven,vaderResultExpect,vaderResultExecute,vaderResultBefore,vaderResultAfter syntax match vaderResultDiff /^ .*/ syntax match vaderResultDo /DO/ contained syntax match vaderResultThen /THEN/ contained syntax match vaderResultGiven /GIVEN/ contained syntax match vaderResultExpect /EXPECT/ contained syntax match vaderResultExecute /EXECUTE/ contained syntax match vaderResultBefore /BEFORE/ contained syntax match vaderResultAfter /AFTER/ contained syntax match vaderResultError /(X).*/ contained syntax match vaderResultExpected /^ - Expected/ syntax match vaderResultGot /^ - Got/ syntax match vaderResultLog /^ > .*/ contains=vaderResultLogBullet syntax match vaderResultLog /^ > .*/ contains=vaderResultLogBullet syntax match vaderResultLogBullet /^\s*> / contained hi def link vaderResultTitle Title hi def link vaderResultTitle2 Conditional hi def link vaderResultNumber Number hi def link vaderResultSequence Label hi def link vaderResultType Delimiter hi def link vaderResultGiven Include hi def link vaderResultDo PreProc hi def link vaderResultThen Conditional hi def link vaderResultBefore Special hi def link vaderResultAfter Special hi def link vaderResultExecute Statement hi def link vaderResultExpect Boolean hi def link vaderResultError Error hi def link vaderResultDiff None hi def link vaderResultExpected Conditional hi def link vaderResultGot Exception hi def link vaderResultLog String hi def link vaderResultLogBullet Special ))entry(name vader.vimnode(typeregularcontents " Copyright (c) 2014 Junegunn Choi " " MIT License " " Permission is hereby granted, free of charge, to any person obtaining " a copy of this software and associated documentation files (the " "Software"), to deal in the Software without restriction, including " without limitation the rights to use, copy, modify, merge, publish, " distribute, sublicense, and/or sell copies of the Software, and to " permit persons to whom the Software is furnished to do so, subject to " the following conditions: " " The above copyright notice and this permission notice shall be " included in all copies or substantial portions of the Software. " " THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, " EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF " MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND " NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE " LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION " OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION " WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. if exists("b:current_syntax") finish endif let s:oisk = &isk syn clear syn include @vimSnippet syntax/vim.vim syntax/vim/*.vim syn region vaderText start=/^\s\{2,}/ end=/^\S\@=/ contained syn region vaderCommand start=/^\s\{2,}/ end=/^\S\@=/ contains=@vimSnippet contained execute printf('syn region vaderTextRaw start=/\(;$\)\@<=/ end=/%s/ contained', vader#syntax#_head()) execute printf('syn region vaderCommandRaw start=/\(;$\)\@<=/ end=/%s/ contains=@vimSnippet contained', vader#syntax#_head()) syn match vaderMessage /(\@<=.*)\@=/ contained contains=Todo syn match vaderGivenType /\(Given\s*\)\@<=[^:; (]\+/ contained syn match vaderExpectType /\(Expect\s*\)\@<=[^:; (]\+/ contained syn match vaderExecuteType /\(Execute\s*\)\@<=[^:; (]\+/ contained syn match vaderComment /^["#].*/ contains=Todo syn match vaderSepCaret /^^.*/ contains=Todo syn match vaderSepTilde /^\~.*/ contains=Todo syn match vaderSepDouble /^=.*/ contains=Todo syn match vaderSepSingle /^-.*/ contains=Todo syn match vaderSepAsterisk /^\*.*/ contains=Todo syn cluster vaderIgnored contains=vaderComment,vaderSepCaret,vaderSepTilde,vaderSepDouble,vaderSepSingle,vaderSepAsterisk syn region vaderGiven start=/^Given\(\s*(.*)\)\?\s*:\s*$/ end=/\(^[^ "^#~=*-]\)\@=/ contains=vaderMessage,vaderText,vaderComment,@vaderIgnored nextgroup=@vaderTopLevel skipempty syn region vaderExpect start=/^Expect\(\s*(.*)\)\?\s*:\s*$/ end=/\(^[^ "^#~=*-]\)\@=/ contains=vaderMessage,vaderText,vaderComment,@vaderIgnored nextgroup=@vaderTopLevel skipempty syn region vaderDo start=/^Do\(\s*(.*)\)\?\s*:\s*$/ end=/\(^[^ "^#~=*-]\)\@=/ contains=vaderMessage,vaderCommand,vaderComment,@vaderIgnored nextgroup=@vaderTopLevel skipempty syn region vaderThen start=/^Then\(\s*(.*)\)\?\s*:\s*$/ end=/\(^[^ "^#~=*-]\)\@=/ contains=vaderMessage,vaderCommand,vaderComment,@vaderIgnored nextgroup=@vaderTopLevel skipempty syn region vaderExecute start=/^Execute\(\s*(.*)\)\?\s*:\s*$/ end=/\(^[^ "^#~=*-]\)\@=/ contains=vaderMessage,vaderCommand,vaderComment,@vaderIgnored nextgroup=@vaderTopLevel skipempty syn region vaderBefore start=/^Before\(\s*(.*)\)\?\s*:\s*$/ end=/\(^[^ "^#~=*-]\)\@=/ contains=vaderMessage,vaderCommand,vaderComment,@vaderIgnored nextgroup=@vaderTopLevel skipempty syn region vaderAfter start=/^After\(\s*(.*)\)\?\s*:\s*$/ end=/\(^[^ "^#~=*-]\)\@=/ contains=vaderMessage,vaderCommand,vaderComment,@vaderIgnored nextgroup=@vaderTopLevel skipempty execute printf('syn region vaderGivenRaw start=/^Given\(\s*(.*)\)\?\s*;\s*$/ end=/%s/ contains=vaderMessage,vaderTextRaw,@vaderIgnored nextgroup=@vaderTopLevel skipempty', vader#syntax#_head()) execute printf('syn region vaderExpectRaw start=/^Expect\(\s*(.*)\)\?\s*;\s*$/ end=/%s/ contains=vaderMessage,vaderTextRaw,@vaderIgnored nextgroup=@vaderTopLevel skipempty', vader#syntax#_head()) execute printf('syn region vaderDoRaw start=/^Do\(\s*(.*)\)\?\s*;\s*$/ end=/%s/ contains=vaderMessage,vaderCommandRaw,@vaderIgnored nextgroup=@vaderTopLevel skipempty', vader#syntax#_head()) execute printf('syn region vaderThenRaw start=/^Then\(\s*(.*)\)\?\s*;\s*$/ end=/%s/ contains=vaderMessage,vaderCommandRaw,@vaderIgnored nextgroup=@vaderTopLevel skipempty', vader#syntax#_head()) execute printf('syn region vaderExecuteRaw start=/^Execute\(\s*(.*)\)\?\s*;\s*$/ end=/%s/ contains=vaderMessage,vaderCommandRaw,@vaderIgnored nextgroup=@vaderTopLevel skipempty', vader#syntax#_head()) execute printf('syn region vaderBeforeRaw start=/^Before\(\s*(.*)\)\?\s*;\s*$/ end=/%s/ contains=vaderMessage,vaderCommandRaw,@vaderIgnored nextgroup=@vaderTopLevel skipempty', vader#syntax#_head()) execute printf('syn region vaderAfterRaw start=/^After\(\s*(.*)\)\?\s*;\s*$/ end=/%s/ contains=vaderMessage,vaderCommandRaw,@vaderIgnored nextgroup=@vaderTopLevel skipempty', vader#syntax#_head()) syn match vaderInclude /^Include\(\s*(.*)\)\?\s*:/ contains=vaderMessage syn cluster vaderTopLevel contains=vaderGiven,vaderExpect,vaderDo,vaderText,vaderExpect,vaderBefore,vaderAfter,vaderExpectRaw,vaderDoRaw,vaderThenRaw,vaderExpectRaw,vaderBeforeRaw,vaderAfterRaw,vaderInclude syn keyword Todo TODO FIXME XXX TBD hi def link vaderInclude Repeat hi def link vaderGiven Include hi def link vaderGivenRaw Include hi def link vaderBefore Special hi def link vaderBeforeRaw Special hi def link vaderAfter Special hi def link vaderAfterRaw Special hi def link vaderDo PreProc hi def link vaderDoRaw PreProc hi def link vaderThen Conditional hi def link vaderThenRaw Conditional hi def link vaderExecute Statement hi def link vaderExecuteRaw Statement hi def link vaderExecuteType Identifier hi def link vaderExpect Boolean hi def link vaderExpectRaw Boolean hi def link vaderMessage Title hi def link vaderGivenType Identifier hi def link vaderExpectType Identifier hi def link vaderText String hi def link vaderTextRaw String hi def link vaderComment Comment hi def link vaderSepCaret Error hi def link vaderSepTilde Debug hi def link vaderSepDouble Label hi def link vaderSepSingle Label hi def link vaderSepAsterisk Exception let b:current_syntax = 'vader' call vader#syntax#reset() call vader#syntax#include(1, '$') let &isk = s:oisk ))))entry(nametestnode(type directoryentry(namefeaturenode(type directoryentry(namebefore-after.vadernode(typeregularcontentslExecute: let g:counter = 0 Before: Log 'Before block increases counter by 1' let g:counter += 1 After: Log 'After block increases counter by 2' let g:counter += 2 AssertEqual g:vader_case_ok, 1 Execute: Log 'It should be 1' AssertEqual 1, g:counter Execute: Log 'It should be 4' AssertEqual 4, g:counter # Remove Before and After hooks Before: After: Execute: AssertEqual 6, g:counter unlet g:counter # Test g:vader_case_ok with test failure. After (g:vader_case_ok should be 0): AssertEqual g:vader_case_ok, 0 Execute (TODO: expected failure): Assert 0 # Remove After hook After: ))entry(name comment.vadernode(typeregularcontents¾################# # Typical comment ################# Given (fixture): ================ Hello Do (modification): ------------------ * change inner word ciw * to World Expect (result): ~~~~~~~~~~~~~~~~ World ~~~~~~~~~~~~~~~~ Do (another modification): -------------------------- ^ change inner word ciw ^ to Goodbye Expect (invalid result): ~~~~~~~~~~~~~~~~~~~~~~~~ Goodbye ~~~~~~~~~~~~~~~~~~~~~~~~ # Remove Given block Given: ))entry(name helper.vadernode(typeregularcontentsGiven c (C file): int i = 0; char c = 'i'; Execute (SyntaxAt()): call cursor(1, 1) AssertEqual SyntaxAt(), 'cType' call cursor(1, 9) AssertEqual SyntaxAt(), 'cNumber' call cursor(2, 1) AssertEqual SyntaxAt(1), 'cType' call cursor(2, 11) AssertEqual SyntaxAt(11), 'cCharacter' Execute (SyntaxAt(col)): call cursor(1, 1) AssertEqual SyntaxAt(1), 'cType' AssertEqual SyntaxAt(9), 'cNumber' call cursor(2, 1) AssertEqual SyntaxAt(1), 'cType' AssertEqual SyntaxAt(11), 'cCharacter' Execute (SyntaxAt(lnum, col)): AssertEqual SyntaxAt(1, 1), 'cType' AssertEqual SyntaxAt(1, 9), 'cNumber' AssertEqual SyntaxAt(2, 1), 'cType' AssertEqual SyntaxAt(2, 11), 'cCharacter' Execute (SyntaxOf(pattern)): AssertEqual SyntaxOf('i'), 'cType' AssertEqual SyntaxOf('int'), 'cType' AssertEqual SyntaxOf('int i = 0;'), 'cType' AssertEqual SyntaxOf('0'), 'cNumber' AssertEqual SyntaxOf('\(c = ''\)\@<=i'), 'cCharacter' Execute (SyntaxOf(pattern, count)): AssertEqual SyntaxOf('i', 1), 'cType' AssertEqual SyntaxOf('i', 3), 'cCharacter' AssertEqual SyntaxOf('i', 4), '' Execute (SyntaxOf does not move cursor): call cursor(2, 1) AssertEqual SyntaxOf('0'), 'cNumber' let pos = getpos('.') AssertEqual pos[1], 2 AssertEqual pos[2], 1 ))entry(name lang-if.vadernode(typeregularcontents¼Given (Some string): Hello Execute ruby (Ruby code): VIM.command('normal! yyp') $curbuf.append $curbuf.count, File.basename(VIM.evaluate 'g:vader_file') Expect: Hello Hello vader.vader Execute python (Python code): import os import vim from vim import current, vars vim.command('normal! yy2p') current.buffer.append(os.path.basename(vars['vader_file'])) Expect: Hello Hello Hello vader.vader ))entry(name motion.vadernode(typeregularcontentsW# FIXME SLOW! Given vader: * Comments Given: Text More Text # Comments Do (things); This key That key Expect (something): Text MORE Text Do (]]): ]]dd ]] ]]dd Expect: * Comments Text More Text # Comments Do (things); This key That key Text MORE Text Do ([[): ]] ]] ]] [[dgg Expect: This key That key Expect (something): Text MORE Text Do (][ / []): ]]]]][dd [][]dk Expect: * Comments Given: Text More Text Do (things); This key That key Expect (something): Text MORE Text ))entry(nameno-indentation.vadernode(typeregularcontentsŽ# Without indentation Given markdown (markdown without indentation); Title ===== - item 1 - item 2 - item 3 Expect; Do; ----------- ### Execute: Before; Okay to have block labels if the line is not in a valid vader syntax After: This is the last line Include (To see if it's okay to interleave Include): include/setup.vader Do; 2j ddp Gp Expect markdown (without indentation); Title ===== - item 2 - item 1 - item 3 Expect; Do; ----------- ### Execute: Before; Okay to have block labels if the line is not in a valid vader syntax After: This is the last line - item 1 Execute; normal! Gyygg"_dGp Expect; After: This is the last line Given: ))entry(namesave-restore.vadernode(typeregularcontentsÙExecute (Initialize vars): let g:abc = 1 let g:def = 2 let g:xyz = 3 let g:dict = {'a': {'b': 'c'}} let $ENVVAR = 4 Execute (Save vars - comma-separated list of optionally-quoted names): Save g:abc, 'g:def', "g:xyz", $ENVVAR, &number, g:dict Save g:undefined Save $PREVIOUSLY_UNDEFINED Execute (Save/Restore vars by value): let g:dict.a.b = 'x' Restore g:dict Assert g:dict == {'a': {'b': 'c'}}, 'Save returns a copy' let g:dict.a.b = 'x' Restore g:dict Assert g:dict == {'a': {'b': 'c'}}, 'First Restore returns a copy' Execute (Set previously undefined vars): let g:undefined = 1 let $PREVIOUSLY_UNDEFINED = 1 Execute (Unlet vars): unlet g:abc unlet g:def unlet g:xyz let $ENVVAR = '' set number! Execute (Restore g:abc and g:def - names can be optionally quoted): Restore 'g:abc', g:def Execute (Check g:abc and g:def): AssertEqual 1, g:abc AssertEqual 2, g:def Execute (g:xyz and $ENVVAR should not exist): Assert !exists('g:xyz'), 'g:xyz should not exist' Assert empty($ENVVAR), '$ENVVAR should be empty' Execute (Restore everything): let number = &number Restore AssertEqual 3, g:xyz AssertEqual '4', $ENVVAR AssertEqual !number, &number Execute (g:undefined should not exist): Assert !exists('g:undefined') AssertEqual $PREVIOUSLY_UNDEFINED, '' Execute (Restore everthing again): let g:xyz = 5 Restore AssertEqual 3, g:xyz Execute (Cleanup): unlet g:abc unlet g:def unlet g:xyz unlet number ))entry(name suite1.vadernode(typeregularcontentsä # Test case Execute (Assert and AssertEqual command): Assert 1 == 1 AssertEqual 'hey', tolower('HEY') AssertEqual 'vader.vader', fnamemodify(g:vader_file, ':t') Execute (AssertThrows): function! VaderThrows() echoerr 'Error from VaderThrows' endfunction command! VaderThrows call VaderThrows() AssertThrows call reverse('not a list') " Might be either: " - Vim(call):E899: Argument of reverse() must be a List or Blob " - Vim(call):E686: Argument of reverse() must be a List Assert g:vader_exception =~# '\V\^Vim(call):E\.\*reverse()', 'Unexpected exception: '.g:vader_exception AssertEqual g:vader_throwpoint, 'function vader#assert#throws, line 7' AssertThrows VaderThrows AssertEqual g:vader_exception, 'Vim(echoerr):Error from VaderThrows' AssertEqual g:vader_throwpoint, 'function vader#assert#throws[7]..VaderThrows, line 1' try AssertThrows let g:vader_exception = 42 catch AssertEqual v:exception, 'Exception expected but not raised: let g:vader_exception = 42' let thrown = 1 finally AssertEqual v:exception, '' AssertEqual [g:vader_exception, g:vader_throwpoint, thrown], [42, '', 1] endtry Execute (AssertEqual handles funcrefs): function! F1() endfunction function! F2() endfunction AssertEqual function('F1'), function('F1') AssertNotEqual function('F1'), function('F2') Execute (FIXME: AssertThrows expects an exception to be thrown): AssertThrows call reverse([1, 2, 3]) Execute (FIXME: Optional message parameter to Assert command): Assert 1 == 2, '1 is not equal to 2' Execute (FIXME: Optional message parameter to AssertEqual): AssertEqual 1, 2, '1 != 2' Execute (FIXME: Optional message parameter to AssertNotEqual): AssertNotEqual 1, 1, '1 == 2' Execute (Save global option values before changing them): Save &expandtab, &tabstop set expandtab shiftwidth=2 Given ruby (Block content is injected and highlighted as ruby code): def a a = 1 end Do (Do block content is keystrokes in normal mode): vip = Expect ruby (Expect block content should match the result of previous Do block): def a a = 1 end Do (FIXME: Nothing): Expect ruby (Previous Given block is repeated, thus this should fail): def b a = 1 end Do (Indent and shift given ruby code): vip = gv > Expect ruby (indented and shifted): def a a = 1 end Do (FIXME: Execute a non-existent command should raise an error): :non-existent-command\ Execute (Revert changed option values): Restore ))entry(name suite2.vadernode(typeregularcontentsGiven: Some string Do: V~ Expect: sOME STRING Execute (FIXME: Execute block does not require an Expect block): AssertEqual 1, 2 Do (Do block *not* followed by an Expect block): Vu Do (Do block followed by an Expect block): Vu Expect: some string Execute (FIXME: Execute block can also be followed by an Expect block): " Ordinary Vim comment call append(line('$'), 'more string') call append(line('$'), 'even more string') Expect (Comparison is case-sensitive): some string MORE string even more string ))entry(name units.vadernode(typeregularcontentsQExecute (vader#assert#equal checks types): AssertThrows call vader#assert#equal({}, {1: 'a'}) AssertEqual g:vader_exception, "Unequal Dictionaries\n {'1': 'a'} should be equal to\n {}" AssertThrows call vader#assert#equal([], [1]) AssertEqual g:vader_exception, "Unequal Lists\n [1] should be equal to\n []" ))))entry(nameincludenode(type directoryentry(name setup.vadernode(typeregularcontentsExecute: Log 'Hello !' ))entry(nameteardown.vadernode(typeregularcontentsExecute: Log 'Good-bye !' ))))entry(name regressionnode(type directoryentry(namebuffer-switch-only-once.vadernode(typeregularcontents{Before: tabnew After: tabclose! Execute (buftype in new tabpage): AssertEqual &buftype, '' # Cleanup Before: After: ))entry(namecharacterwise-macro.vadernode(typeregularcontents•Given: Copyright (c) 2014 Junegunn Choi MIT License # :help let-@ # > If the result of {expr1} ends in a or , the # > register will be linewise, otherwise it will be set to # > characterwise. # A workaround is to use setreg() instead to force characterwise mode Do (Macro that ends with ): \ Expect: Copyright (c) 2014 Junegunn Choi MIT License Execute (Assertions): Assert getline(1) ==? tolower(getline(1)) Assert getline(1) ==# getline(1) AssertEqual getline(1), getline(1) AssertNotEqual getline(1), getline(3) AssertThrows getline() AssertEqual g:vader_exception, "Vim:E492: Not an editor command: getline()" ))entry(namefiletype.vadernode(typeregularcontents;Given (plain text): Execute (Check filetype): AssertEqual '', &filetype Given ruby (ruby code): Execute (Check filetype): AssertEqual 'ruby', &filetype Execute (Check filetype again): AssertEqual 'ruby', &filetype Given (plain text): Execute (Check filetype - should be reset): AssertEqual '', &filetype ))entry(namehighlight-after-comment.vadernode(typeregularcontents* https://github.com/junegunn/vader.vim/pull/44 Given vader (Vader file with interleaved comments): Execute: echom 'foo' " Vader comment (w/o indentation) echom 'bar' " Vimscript comment echom 'foobar' Execute (Check syntax): AssertEqual 'vimCommand', SyntaxAt(2, 3) AssertEqual 'vaderComment', SyntaxAt(3, 1) AssertEqual 'vaderComment', SyntaxAt(3, 3) AssertEqual 'vimCommand', SyntaxAt(4, 3) AssertEqual 'vimLineComment', SyntaxAt(5, 3) AssertEqual 'vimCommand', SyntaxAt(6, 3) ))entry(nameopening-different-buffer.vadernode(typeregularcontents¦Execute (Create temp file): call system('echo hello > /tmp/hello') Given (File path): /tmp/hello Do (Go to file): gf Expect (Should see the content of the current buffer instead of workbench buffer): hello Do (Vader should switch back to the workbench buffer): yyp Expect (Modified workbench buffer): /tmp/hello /tmp/hello Execute (The buffer shouldn't have been modified): AssertEqual 0, &modified ))))entry(name run-tests.shnode(typeregular executablecontentsÅ#!/usr/bin/env bash # Use privileged mode, to e.g. ignore $CDPATH. set -p cd "$( dirname "${BASH_SOURCE[0]}" )" || exit : "${VADER_TEST_VIM:=vim}" eval "$VADER_TEST_VIM -Nu vimrc -c 'Vader! *'" ))entry(name vader.vadernode(typeregularcontentsä # Vader file Include: include/setup.vader ~ Features Include (Basic tests 1): feature/suite1.vader Include (Basic tests 2): feature/suite2.vader Include (Motions): feature/motion.vader Include (Different types of comments): feature/comment.vader Include (Before/After): feature/before-after.vader Include (Save/Restore): feature/save-restore.vader Include (Testing Ruby/Python interface): feature/lang-if.vader Include (blocks w/o indentation): feature/no-indentation.vader Include (Helpers): feature/helper.vader Include (Units): feature/units.vader * Regressions Include (Macro set to linewise when it ends with ): regression/characterwise-macro.vader Include (Should switch back to workbench buffer): regression/opening-different-buffer.vader Include (Should clear filetype on Given block w/o filetype): regression/filetype.vader Include (#44 Vader comment starting with " should not break syntax highlighting): regression/highlight-after-comment.vader Include (#46 Vader should switch back to workbench buffer only once): regression/buffer-switch-only-once.vader Include: include/teardown.vader ))entry(namevimrcnode(typeregularcontentsŒfiletype off let &runtimepath .= ','.expand(':p:h:h') filetype plugin indent on syntax enable set nomore set noswapfile set viminfo= )))))