"============================================================================= " FILE: t/compare_movements_spec.vim " AUTHOR: YggdrasiI " Test: https://github.com/kana/vim-vspec " Description: EasyMotion keyword movement test with vim-vspec " License: 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. " }}} "============================================================================= " Setup {{{ let s:root_dir = matchstr(system('git rev-parse --show-cdup'), '[^\n]\+') " The consumed time depends from the length of the text and could be really high " on vimdoc pages. (See it 'Loop through Vim help buffer and compare movements') " Reduce this value to stop CompareMovements(...) before it reached the end of the " buffer. let s:maximal_number_of_compared_movments = 10000 execute 'set' 'rtp +=./'.s:root_dir runtime! plugin/EasyMotion.vim " }}} " Functions for Test {{{ function! AddLine(str) put =a:str endfunction function! CursorPos() return [line('.'), col('.'), getline('.')[col('.')-1]] endfunction " Nested normal to avoid throwing readonly errors. They abort the testing. function TryNormal(str) try exec 'normal ' . a:str catch /^Vim\%((\a\+)\)\=:E21/ endtry return 0 endfunction let s:to_cursor = {} function! s:to_cursor.match(actual, expected) return a:actual == a:expected endfunction " Add metadata about failure. function! s:to_cursor.failure_message_for_should(actual, expected) Expect a:actual[0] > 0 Expect a:expected[0] > 0 Expect a:actual[0] <= getpos('$')[1] Expect a:expected[0] <= getpos('$')[1] Expect a:actual[1] > 0 Expect a:expected[1] > 0 let l:line1 = getline(a:actual[0]) let l:line2 = getline(a:expected[0]) " Change char on cursor to '█'. let l:line1 = strpart(l:line1, 0, a:actual[1]-1) \ . '█' \ . strpart(l:line1, a:actual[1]) let line2 = strpart(l:line2, 0, a:expected[1]-1) \ . '█' \ . strpart(l:line2, a:expected[1]) " Separation of both cases with \n would be nice, but " vim-vspec allow oneliners as return string, only. let l:msg = 'Line ' . string(a:actual[0]) . ": '" . l:line1 \ . "',\x09\x09 Line " . string(a:expected[0]) . ": '" . l:line2 . "'\x0a" return l:msg endfunction function! CompareMovements(movement1, movement2, backward) let l:jumpmarks = [ \ [a:movement1, []], \ [a:movement2, []], \ ] " Loop through current buffer in both variants {{ for [l:handler, l:list] in l:jumpmarks if a:backward == 1 let l:last_line = line('$') let l:last_char = len(getline(l:last_line)) call cursor(l:last_line, l:last_char) else call cursor([1,1]) endif let l:lastpos = [0,0] " Centralize line. Otherwise, Easymotion functions aborts " at the end of the (virtual) window. call TryNormal('zz') call TryNormal(l:handler) let l:curpos = getpos(".")[1:2] while l:lastpos != l:curpos let l:list += [l:curpos] let l:lastpos = l:curpos call TryNormal('zz') call TryNormal(l:handler) let l:curpos = getpos(".")[1:2] " Abort after a fixed number of steps. if len(l:list) > s:maximal_number_of_compared_movments break endif endwhile endfor " }} " The resulting lists are stored in l:jumpmarks[*][1], now. let [l:cursor_positions1, l:cursor_positions2] = [ l:jumpmarks[0][1], l:jumpmarks[1][1] ] if l:cursor_positions1 == l:cursor_positions2 return 0 endif " Search for first unmatching position. {{ let l:index = 0 let l:len = min([len(l:cursor_positions2), len(l:cursor_positions1)]) while l:index < l:len Expect l:cursor_positions2[l:index] to_cursor l:cursor_positions1[l:index] let l:index += 1 endwhile " Collision with begin or end of file or while loop aborts to early. if a:backward == 1 Expect join([a:movement2, ': File begin reached after ', len(l:cursor_positions2), ' steps.']) \ == join([a:movement1, ': File begin reached after ', len(l:cursor_positions1), ' steps.']) else Expect l:cursor_positions2[l:index-1] to_cursor l:cursor_positions1[l:index] Expect join([a:movement2, ': File end reached after ', len(l:cursor_positions2), ' steps.']) \ == join([a:movement1, ': File end reached after ', len(l:cursor_positions1), ' steps.']) endif " }} return -1 endfunction " Hand crafted text with rare cases function! InsertTestText1() " Blanks at document begin call AddLine('') call AddLine(' ') call AddLine('') call AddLine('scriptencoding utf-8') " '^\s*[not-\k]'-case call AddLine('!foo') call AddLine(' !bar') call AddLine('s! ') " Blanks at document end call AddLine('') call AddLine(' ') call AddLine('') endfunction "}}} "Keyword word motion {{{ describe 'Keyword word motion' before new resize 10 nmap a let g:EasyMotion_keys = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' let g:EasyMotion_maximal_jumpmarks = 2 " Error for value 1 unanalyzed. nmap w (easymotion-iskeyword-w) nmap b (easymotion-iskeyword-b) nmap e (easymotion-iskeyword-e) nmap ge (easymotion-iskeyword-ge) nmap W (easymotion-W) nmap B (easymotion-B) nmap E (easymotion-E) nmap gE (easymotion-gE) call EasyMotion#init() call vspec#customize_matcher('to_cursor', s:to_cursor) end after close! end it 'Simple test to check setup of this test' " Check if a is remapped to to avoid start of insert mode. normal aa\ Expect getline(1) == '' call AddLine('word') Expect CompareMovements('w', 'w', 0) == 0 Expect CompareMovements('w', '\wa', 0) == 0 Expect CompareMovements('b', '\ba', 1) == 0 Expect CompareMovements('e', '\ea', 0) == 0 Expect CompareMovements('ge', '\gea', 1) == 0 Expect CompareMovements('W', '\Wa', 0) == 0 Expect CompareMovements('B', '\Ba', 1) == 0 Expect CompareMovements('E', '\Ea', 0) == 0 Expect CompareMovements('gE', '\gEa', 1) == 0 end it 'w' call InsertTestText1() Expect CompareMovements('w', '\wa', 0) == 0 end it 'b' call InsertTestText1() Expect CompareMovements('b', '\ba', 1) == 0 end it 'e' call InsertTestText1() Expect CompareMovements('e', '\ea', 0) == 0 end it 'ge' call InsertTestText1() Expect CompareMovements('ge', '\gea', 1) == 0 end it 'W' call InsertTestText1() Expect CompareMovements('W', 'W', 0) == 0 end it 'B' call InsertTestText1() Expect CompareMovements('B', 'B', 1) == 0 end it 'E' call InsertTestText1() Expect CompareMovements('E', 'E', 0) == 0 end it 'gE' call InsertTestText1() Expect CompareMovements('gE', 'gE', 1) == 0 end " Really time consuming test... "it 'Loop through Vim help buffer and compare movements' " help motion.txt " Expect expand('%:t') ==# 'motion.txt' " "Optional: Copy text into editable buffer " exec "normal! Gygg\cP" " Expect CompareMovements('w', '\wa', 0) == 0 "end end "}}} " __END__ {{{ " vim: fdm=marker:et:ts=4:sw=4:sts=4 " }}}