]> git.madduck.net Git - etc/vim.git/blob - autoload/ale/test.vim

madduck's git repository

Every one of the projects in this repository is available at the canonical URL git://git.madduck.net/madduck/pub/<projectpath> — see each project's metadata for the exact URL.

All patches and comments are welcome. Please squash your changes to logical commits before using git-format-patch and git-send-email to patches@git.madduck.net. If you'd read over the Git project's submission guidelines and adhered to them, I'd be especially grateful.

SSH access, as well as push access can be individually arranged.

If you use my repositories frequently, consider adding the following snippet to ~/.gitconfig and using the third clone URL listed for each project:

[url "git://git.madduck.net/madduck/"]
  insteadOf = madduck:

Squashed '.vim/bundle/ale/' content from commit 22185c4c
[etc/vim.git] / autoload / ale / test.vim
1 " Author: w0rp <devw0rp@gmail.com>
2 " Description: Functions for making testing ALE easier.
3 "
4 " This file should not typically be loaded during the normal execution of ALE.
5
6 " Change the directory for checking things in particular test directories
7 "
8 " This function will set the g:dir variable, which represents the working
9 " directory after changing the path. This variable allows a test to change
10 " directories, and then switch back to a directory at the start of the test
11 " run.
12 "
13 " This function should be run in a Vader Before: block.
14 function! ale#test#SetDirectory(docker_path) abort
15     if a:docker_path[:len('/testplugin/') - 1] isnot# '/testplugin/'
16         throw 'docker_path must start with /testplugin/!'
17     endif
18
19     " Try to switch directory, which will fail when running tests directly,
20     " and not through the Docker image.
21     silent! execute 'cd ' . fnameescape(a:docker_path)
22     let g:dir = getcwd() " no-custom-checks
23 endfunction
24
25 " When g:dir is defined, switch back to the directory we saved, and then
26 " delete that variable.
27 "
28 " The filename will be reset to dummy.txt
29 "
30 " This function should be run in a Vader After: block.
31 function! ale#test#RestoreDirectory() abort
32     call ale#test#SetFilename('dummy.txt')
33     silent execute 'cd ' . fnameescape(g:dir)
34     unlet! g:dir
35 endfunction
36
37 " Get a filename for the current buffer using a relative path to the script.
38 "
39 " If a g:dir variable is set, it will be used as the path to the directory
40 " containing the test file.
41 function! ale#test#GetFilename(path) abort
42     let l:dir = get(g:, 'dir', '')
43
44     if empty(l:dir)
45         let l:dir = getcwd() " no-custom-checks
46     endif
47
48     let l:full_path = ale#path#IsAbsolute(a:path)
49     \   ? a:path
50     \   : l:dir . '/' . a:path
51
52     return ale#path#Simplify(l:full_path)
53 endfunction
54
55 " Change the filename for the current buffer using a relative path to
56 " the script without running autocmd commands.
57 "
58 " If a g:dir variable is set, it will be used as the path to the directory
59 " containing the test file.
60 function! ale#test#SetFilename(path) abort
61     let l:full_path = ale#test#GetFilename(a:path)
62     silent! noautocmd execute 'file ' . fnameescape(l:full_path)
63 endfunction
64
65 function! RemoveNewerKeys(results) abort
66     for l:item in a:results
67         if has_key(l:item, 'module')
68             call remove(l:item, 'module')
69         endif
70
71         if has_key(l:item, 'end_col')
72             call remove(l:item, 'end_col')
73         endif
74
75         if has_key(l:item, 'end_lnum')
76             call remove(l:item, 'end_lnum')
77         endif
78     endfor
79 endfunction
80
81 " Return loclist data with only the keys supported by the lowest Vim versions.
82 function! ale#test#GetLoclistWithoutNewerKeys() abort
83     let l:results = getloclist(0)
84     call RemoveNewerKeys(l:results)
85
86     return l:results
87 endfunction
88
89 " Return quickfix data with only the keys supported by the lowest Vim versions.
90 function! ale#test#GetQflistWithoutNewerKeys() abort
91     let l:results = getqflist()
92     call RemoveNewerKeys(l:results)
93
94     return l:results
95 endfunction
96
97 function! ale#test#GetPreviewWindowText() abort
98     for l:window in range(1, winnr('$'))
99         if getwinvar(l:window, '&previewwindow', 0)
100             let l:buffer = winbufnr(l:window)
101
102             return getbufline(l:buffer, 1, '$')
103         endif
104     endfor
105 endfunction
106
107 " This function can be called with a timeout to wait for all jobs to finish.
108 " If the jobs to not finish in the given number of milliseconds,
109 " an exception will be thrown.
110 "
111 " The time taken will be a very rough approximation, and more time may be
112 " permitted than is specified.
113 function! ale#test#WaitForJobs(deadline) abort
114     let l:start_time = ale#events#ClockMilliseconds()
115
116     if l:start_time == 0
117         throw 'Failed to read milliseconds from the clock!'
118     endif
119
120     let l:job_list = []
121
122     " Gather all of the jobs from every buffer.
123     for [l:buffer, l:data] in items(ale#command#GetData())
124         call extend(l:job_list, map(keys(l:data.jobs), 'str2nr(v:val)'))
125     endfor
126
127     " NeoVim has a built-in API for this, so use that.
128     if has('nvim')
129         let l:nvim_code_list = jobwait(l:job_list, a:deadline)
130
131         if index(l:nvim_code_list, -1) >= 0
132             throw 'Jobs did not complete on time!'
133         endif
134
135         return
136     endif
137
138     let l:should_wait_more = 1
139
140     while l:should_wait_more
141         let l:should_wait_more = 0
142
143         for l:job_id in l:job_list
144             if ale#job#IsRunning(l:job_id)
145                 let l:now = ale#events#ClockMilliseconds()
146
147                 if l:now - l:start_time > a:deadline
148                     " Stop waiting after a timeout, so we don't wait forever.
149                     throw 'Jobs did not complete on time!'
150                 endif
151
152                 " Wait another 10 milliseconds
153                 let l:should_wait_more = 1
154                 sleep 10ms
155                 break
156             endif
157         endfor
158     endwhile
159
160     " Sleep for a small amount of time after all jobs finish.
161     " This seems to be enough to let handlers after jobs end run, and
162     " prevents the occasional failure where this function exits after jobs
163     " end, but before handlers are run.
164     sleep 10ms
165
166     " We must check the buffer data again to see if new jobs started for
167     " linters with chained commands.
168     let l:has_new_jobs = 0
169
170     " Check again to see if any jobs are running.
171     for l:info in values(g:ale_buffer_info)
172         for [l:job_id, l:linter] in get(l:info, 'job_list', [])
173             if ale#job#IsRunning(l:job_id)
174                 let l:has_new_jobs = 1
175                 break
176             endif
177         endfor
178     endfor
179
180     if l:has_new_jobs
181         " We have to wait more. Offset the timeout by the time taken so far.
182         let l:now = ale#events#ClockMilliseconds()
183         let l:new_deadline = a:deadline - (l:now - l:start_time)
184
185         if l:new_deadline <= 0
186             " Enough time passed already, so stop immediately.
187             throw 'Jobs did not complete on time!'
188         endif
189
190         call ale#test#WaitForJobs(l:new_deadline)
191     endif
192 endfunction
193
194 function! ale#test#FlushJobs() abort
195     " The variable is checked for in a loop, as calling one series of
196     " callbacks can trigger a further series of callbacks.
197     while exists('g:ale_run_synchronously_callbacks')
198         let l:callbacks = g:ale_run_synchronously_callbacks
199         unlet g:ale_run_synchronously_callbacks
200
201         for l:Callback in l:callbacks
202             call l:Callback()
203         endfor
204     endwhile
205 endfunction