blob: d28349a70ca2dcd8138d71ed8b053833ec881e9f [file] [log] [blame]
Bram Moolenaar10561fe2018-05-19 15:01:10 +02001" Test the :compiler command
2
3func Test_compiler()
Bram Moolenaaraeb313f2020-11-27 19:13:28 +01004 CheckExecutable perl
Bram Moolenaar5a4c3082019-12-01 15:23:11 +01005 CheckFeature quickfix
Bram Moolenaar10561fe2018-05-19 15:01:10 +02006
Dominique Pelléca0ffc02023-09-24 22:57:41 +02007 let save_LC_ALL = $LC_ALL
8 let $LC_ALL= "C"
Bram Moolenaarf0447e82018-07-03 21:26:38 +02009
Bram Moolenaardff2adc2019-07-31 22:18:22 +020010 " %:S does not work properly with 'shellslash' set
11 let save_shellslash = &shellslash
12 set noshellslash
13
Bram Moolenaar10561fe2018-05-19 15:01:10 +020014 e Xfoo.pl
Aliaksei Budavei368ef5a2024-12-16 21:37:54 +010015 " Play nice with other tests.
16 defer setqflist([])
zeertzjq5e8b2262025-02-28 17:32:07 +010017
Bram Moolenaar10561fe2018-05-19 15:01:10 +020018 compiler perl
19 call assert_equal('perl', b:current_compiler)
20 call assert_fails('let g:current_compiler', 'E121:')
Bram Moolenaar58ef8a32021-11-12 11:25:11 +000021 let verbose_efm = execute('verbose set efm')
Bram Moolenaar0a15c762021-11-12 16:09:54 +000022 call assert_match('Last set from .*[/\\]compiler[/\\]perl.vim ', verbose_efm)
zeertzjq5e8b2262025-02-28 17:32:07 +010023 " Not using the global value
24 call assert_notequal('', &l:efm)
Bram Moolenaar58ef8a32021-11-12 11:25:11 +000025
Bram Moolenaar10561fe2018-05-19 15:01:10 +020026 call setline(1, ['#!/usr/bin/perl -w', 'use strict;', 'my $foo=1'])
27 w!
28 call feedkeys(":make\<CR>\<CR>", 'tx')
29 call assert_fails('clist', 'E42:')
30
31 call setline(1, ['#!/usr/bin/perl -w', 'use strict;', '$foo=1'])
32 w!
33 call feedkeys(":make\<CR>\<CR>", 'tx')
34 let a=execute('clist')
Bram Moolenaarcebfcff2019-09-18 21:42:38 +020035 call assert_match('\n \d\+ Xfoo.pl:3: Global symbol "$foo" '
36 \ . 'requires explicit package name', a)
37
zeertzjq5e8b2262025-02-28 17:32:07 +010038 compiler make
39 call assert_fails('let b:current_compiler', 'E121:')
40 call assert_fails('let g:current_compiler', 'E121:')
41 let verbose_efm = execute('verbose set efm')
42 call assert_match('Last set from .*[/\\]compiler[/\\]make.vim ', verbose_efm)
43
44 compiler! perl
45 call assert_equal('perl', b:current_compiler)
46 call assert_equal('perl', g:current_compiler)
47 let verbose_efm = execute('verbose set efm')
48 call assert_match('Last set from .*[/\\]compiler[/\\]perl.vim ', verbose_efm)
49 call assert_equal(verbose_efm, execute('verbose setglobal efm'))
50 " Using the global value
51 call assert_equal('', &l:efm)
52
53 compiler! make
54 call assert_fails('let b:current_compiler', 'E121:')
55 call assert_fails('let g:current_compiler', 'E121:')
56 let verbose_efm = execute('verbose set efm')
57 call assert_match('Last set from .*[/\\]compiler[/\\]make.vim ', verbose_efm)
58 call assert_equal(verbose_efm, execute('verbose setglobal efm'))
59 " Using the global value
60 call assert_equal('', &l:efm)
Bram Moolenaar10561fe2018-05-19 15:01:10 +020061
Bram Moolenaardff2adc2019-07-31 22:18:22 +020062 let &shellslash = save_shellslash
Bram Moolenaar10561fe2018-05-19 15:01:10 +020063 call delete('Xfoo.pl')
64 bw!
Dominique Pelléca0ffc02023-09-24 22:57:41 +020065 let $LC_ALL = save_LC_ALL
Bram Moolenaar10561fe2018-05-19 15:01:10 +020066endfunc
67
Bram Moolenaar60bc8e72020-11-23 21:24:58 +010068func GetCompilerNames()
69 return glob('$VIMRUNTIME/compiler/*.vim', 0, 1)
Bram Moolenaar142f2352020-11-23 21:39:14 +010070 \ ->map({i, v -> substitute(v, '.*[\\/]\([a-zA-Z0-9_\-]*\).vim', '\1', '')})
71 \ ->sort()
Bram Moolenaar60bc8e72020-11-23 21:24:58 +010072endfunc
73
Bram Moolenaar10561fe2018-05-19 15:01:10 +020074func Test_compiler_without_arg()
Bram Moolenaarc25e7022019-10-10 14:08:26 +020075 let runtime = substitute($VIMRUNTIME, '\\', '/', 'g')
76 let a = split(execute('compiler'))
Bram Moolenaar60bc8e72020-11-23 21:24:58 +010077 let exp = GetCompilerNames()
78 call assert_match(runtime .. '/compiler/' .. exp[0] .. '.vim$', a[0])
79 call assert_match(runtime .. '/compiler/' .. exp[1] .. '.vim$', a[1])
80 call assert_match(runtime .. '/compiler/' .. exp[-1] .. '.vim$', a[-1])
Bram Moolenaar10561fe2018-05-19 15:01:10 +020081endfunc
82
Bram Moolenaar16531552020-02-08 16:00:46 +010083" Test executing :compiler from the command line, not from a script
84func Test_compiler_commandline()
85 call system(GetVimCommandClean() .. ' --not-a-term -c "compiler gcc" -c "call writefile([b:current_compiler], ''XcompilerOut'')" -c "quit"')
86 call assert_equal(0, v:shell_error)
87 call assert_equal(["gcc"], readfile('XcompilerOut'))
88
89 call delete('XcompilerOut')
90endfunc
91
Bram Moolenaar10561fe2018-05-19 15:01:10 +020092func Test_compiler_completion()
Bram Moolenaar60bc8e72020-11-23 21:24:58 +010093 let clist = GetCompilerNames()->join(' ')
Bram Moolenaar10561fe2018-05-19 15:01:10 +020094 call feedkeys(":compiler \<C-A>\<C-B>\"\<CR>", 'tx')
Bram Moolenaar60bc8e72020-11-23 21:24:58 +010095 call assert_match('^"compiler ' .. clist .. '$', @:)
Bram Moolenaar10561fe2018-05-19 15:01:10 +020096
97 call feedkeys(":compiler p\<C-A>\<C-B>\"\<CR>", 'tx')
Konfekt3c2596a2024-11-30 11:32:49 +010098 call assert_match('"compiler pandoc pbx perl\( p[a-z_]\+\)\+ pyunit', @:)
Bram Moolenaar10561fe2018-05-19 15:01:10 +020099
100 call feedkeys(":compiler! p\<C-A>\<C-B>\"\<CR>", 'tx')
Konfekt3c2596a2024-11-30 11:32:49 +0100101 call assert_match('"compiler! pandoc pbx perl\( p[a-z_]\+\)\+ pyunit', @:)
Bram Moolenaar10561fe2018-05-19 15:01:10 +0200102endfunc
103
104func Test_compiler_error()
Bram Moolenaare20b9ec2020-02-03 21:40:04 +0100105 let g:current_compiler = 'abc'
Bram Moolenaar10561fe2018-05-19 15:01:10 +0200106 call assert_fails('compiler doesnotexist', 'E666:')
Bram Moolenaare20b9ec2020-02-03 21:40:04 +0100107 call assert_equal('abc', g:current_compiler)
108 call assert_fails('compiler! doesnotexist', 'E666:')
109 unlet! g:current_compiler
Bram Moolenaar10561fe2018-05-19 15:01:10 +0200110endfunc
Bram Moolenaar6d91bcb2020-08-12 18:50:36 +0200111
Aliaksei Budavei60ddb1a2024-11-28 22:05:37 +0100112func s:SpotBugsParseFilterMakePrg(dirname, makeprg)
113 let result = {}
114 let result.sourcepath = ''
115 let result.classfiles = []
116
117 " Get the argument after the rightmost occurrence of "-sourcepath".
118 let offset = strridx(a:makeprg, '-sourcepath')
119 if offset < 0
120 return result
121 endif
122 let offset += 1 + strlen('-sourcepath')
123 let result.sourcepath = matchstr(strpart(a:makeprg, offset), '.\{-}\ze[ \t]')
Aliaksei Budavei368ef5a2024-12-16 21:37:54 +0100124 let offset += 1 + strlen(result.sourcepath)
Aliaksei Budavei60ddb1a2024-11-28 22:05:37 +0100125
126 " Get the class file arguments, dropping the pathname prefix.
127 let offset = stridx(a:makeprg, a:dirname, offset)
128 if offset < 0
129 return result
130 endif
131
132 while offset > -1
133 let candidate = matchstr(a:makeprg, '[^ \t]\{-}\.class\>', offset)
134 if empty(candidate)
135 break
136 endif
137 call add(result.classfiles, candidate)
138 let offset = stridx(a:makeprg, a:dirname, (1 + strlen(candidate) + offset))
139 endwhile
140
141 call sort(result.classfiles)
142 return result
143endfunc
144
145func Test_compiler_spotbugs_makeprg()
146 let save_shellslash = &shellslash
147 set shellslash
148
149 call assert_true(mkdir('Xspotbugs/src/tests/α/β/γ/δ', 'pR'))
150 call assert_true(mkdir('Xspotbugs/tests/α/β/γ/δ', 'pR'))
151
152 let lines =<< trim END
153 // EOL comment. /*
154 abstract class
155 𐌂1 /* Multiline comment. */ {
156 /* Multiline comment. */ // EOL comment. /*
157 static final String COMMENT_A_LIKE = "/*";
158 { new Object() {/* Try globbing. */}; }
159 static { interface 𐌉𐌉1 {} }
160 static class 𐌂11 { interface 𐌉𐌉2 {} }
161 }
162 /* Multiline comment. */ // EOL comment. /*
163 final class 𐌂2 {
164 public static void main(String... aa) {
165 record 𐌓() {}
166 enum 𐌄 {}
167 }
168 } // class
169 END
170
171 " THE EXPECTED RESULTS.
172 let results = {}
173 let results['Xspotbugs/src/tests/𐌂1.java'] = {
Aliaksei Budavei368ef5a2024-12-16 21:37:54 +0100174 \ 'Sourcepath': {-> fnamemodify('Xspotbugs/src/tests/𐌂1.java',
175 \ ':p:h:S')},
Aliaksei Budavei60ddb1a2024-11-28 22:05:37 +0100176 \ 'classfiles': sort([
177 \ 'Xspotbugs/tests/𐌂1$1.class',
178 \ 'Xspotbugs/tests/𐌂1$1𐌉𐌉1.class',
179 \ 'Xspotbugs/tests/𐌂1$𐌂11$𐌉𐌉2.class',
180 \ 'Xspotbugs/tests/𐌂1$𐌂11.class',
181 \ 'Xspotbugs/tests/𐌂1.class',
182 \ 'Xspotbugs/tests/𐌂2$1𐌄.class',
183 \ 'Xspotbugs/tests/𐌂2$1𐌓.class',
184 \ 'Xspotbugs/tests/𐌂2.class']),
185 \ }
186 " No class file for an empty source file even with "-Xpkginfo:always".
187 let results['Xspotbugs/src/tests/package-info.java'] = {
Aliaksei Budavei368ef5a2024-12-16 21:37:54 +0100188 \ 'Sourcepath': {-> ''},
Aliaksei Budavei60ddb1a2024-11-28 22:05:37 +0100189 \ 'classfiles': [],
190 \ }
191 let results['Xspotbugs/src/tests/α/𐌂1.java'] = {
Aliaksei Budavei368ef5a2024-12-16 21:37:54 +0100192 \ 'Sourcepath': {-> fnamemodify('Xspotbugs/src/tests/α/𐌂1.java',
193 \ ':p:h:h:S')},
Aliaksei Budavei60ddb1a2024-11-28 22:05:37 +0100194 \ 'classfiles': sort([
195 \ 'Xspotbugs/tests/α/𐌂1$1.class',
196 \ 'Xspotbugs/tests/α/𐌂1$1𐌉𐌉1.class',
197 \ 'Xspotbugs/tests/α/𐌂1$𐌂11$𐌉𐌉2.class',
198 \ 'Xspotbugs/tests/α/𐌂1$𐌂11.class',
199 \ 'Xspotbugs/tests/α/𐌂1.class',
200 \ 'Xspotbugs/tests/α/𐌂2$1𐌄.class',
201 \ 'Xspotbugs/tests/α/𐌂2$1𐌓.class',
202 \ 'Xspotbugs/tests/α/𐌂2.class']),
203 \ }
204 let results['Xspotbugs/src/tests/α/package-info.java'] = {
Aliaksei Budavei368ef5a2024-12-16 21:37:54 +0100205 \ 'Sourcepath': {-> fnamemodify('Xspotbugs/src/tests/α/package-info.java',
206 \ ':p:h:S')},
Aliaksei Budavei60ddb1a2024-11-28 22:05:37 +0100207 \ 'classfiles': ['Xspotbugs/tests/α/package-info.class'],
208 \ }
209 let results['Xspotbugs/src/tests/α/β/𐌂1.java'] = {
Aliaksei Budavei368ef5a2024-12-16 21:37:54 +0100210 \ 'Sourcepath': {-> fnamemodify('Xspotbugs/src/tests/α/β/𐌂1.java',
211 \ ':p:h:h:h:S')},
Aliaksei Budavei60ddb1a2024-11-28 22:05:37 +0100212 \ 'classfiles': sort([
213 \ 'Xspotbugs/tests/α/β/𐌂1$1.class',
214 \ 'Xspotbugs/tests/α/β/𐌂1$1𐌉𐌉1.class',
215 \ 'Xspotbugs/tests/α/β/𐌂1$𐌂11$𐌉𐌉2.class',
216 \ 'Xspotbugs/tests/α/β/𐌂1$𐌂11.class',
217 \ 'Xspotbugs/tests/α/β/𐌂1.class',
218 \ 'Xspotbugs/tests/α/β/𐌂2$1𐌄.class',
219 \ 'Xspotbugs/tests/α/β/𐌂2$1𐌓.class',
220 \ 'Xspotbugs/tests/α/β/𐌂2.class']),
221 \ }
222 let results['Xspotbugs/src/tests/α/β/package-info.java'] = {
Aliaksei Budavei368ef5a2024-12-16 21:37:54 +0100223 \ 'Sourcepath': {-> fnamemodify('Xspotbugs/src/tests/α/β/package-info.java',
224 \ ':p:h:S')},
Aliaksei Budavei60ddb1a2024-11-28 22:05:37 +0100225 \ 'classfiles': ['Xspotbugs/tests/α/β/package-info.class'],
226 \ }
227 let results['Xspotbugs/src/tests/α/β/γ/𐌂1.java'] = {
Aliaksei Budavei368ef5a2024-12-16 21:37:54 +0100228 \ 'Sourcepath': {-> fnamemodify('Xspotbugs/src/tests/α/β/γ/𐌂1.java',
229 \ ':p:h:h:h:h:S')},
Aliaksei Budavei60ddb1a2024-11-28 22:05:37 +0100230 \ 'classfiles': sort([
231 \ 'Xspotbugs/tests/α/β/γ/𐌂1$1.class',
232 \ 'Xspotbugs/tests/α/β/γ/𐌂1$1𐌉𐌉1.class',
233 \ 'Xspotbugs/tests/α/β/γ/𐌂1$𐌂11$𐌉𐌉2.class',
234 \ 'Xspotbugs/tests/α/β/γ/𐌂1$𐌂11.class',
235 \ 'Xspotbugs/tests/α/β/γ/𐌂1.class',
236 \ 'Xspotbugs/tests/α/β/γ/𐌂2$1𐌄.class',
237 \ 'Xspotbugs/tests/α/β/γ/𐌂2$1𐌓.class',
238 \ 'Xspotbugs/tests/α/β/γ/𐌂2.class']),
239 \ }
240 let results['Xspotbugs/src/tests/α/β/γ/package-info.java'] = {
Aliaksei Budavei368ef5a2024-12-16 21:37:54 +0100241 \ 'Sourcepath': {-> fnamemodify('Xspotbugs/src/tests/α/β/γ/package-info.java',
242 \ ':p:h:S')},
Aliaksei Budavei60ddb1a2024-11-28 22:05:37 +0100243 \ 'classfiles': ['Xspotbugs/tests/α/β/γ/package-info.class'],
244 \ }
245 let results['Xspotbugs/src/tests/α/β/γ/δ/𐌂1.java'] = {
Aliaksei Budavei368ef5a2024-12-16 21:37:54 +0100246 \ 'Sourcepath': {-> fnamemodify('Xspotbugs/src/tests/α/β/γ/δ/𐌂1.java',
247 \ ':p:h:h:h:h:h:S')},
Aliaksei Budavei60ddb1a2024-11-28 22:05:37 +0100248 \ 'classfiles': sort([
249 \ 'Xspotbugs/tests/α/β/γ/δ/𐌂1$1.class',
250 \ 'Xspotbugs/tests/α/β/γ/δ/𐌂1$1𐌉𐌉1.class',
251 \ 'Xspotbugs/tests/α/β/γ/δ/𐌂1$𐌂11$𐌉𐌉2.class',
252 \ 'Xspotbugs/tests/α/β/γ/δ/𐌂1$𐌂11.class',
253 \ 'Xspotbugs/tests/α/β/γ/δ/𐌂1.class',
254 \ 'Xspotbugs/tests/α/β/γ/δ/𐌂2$1𐌄.class',
255 \ 'Xspotbugs/tests/α/β/γ/δ/𐌂2$1𐌓.class',
256 \ 'Xspotbugs/tests/α/β/γ/δ/𐌂2.class']),
257 \ }
258 let results['Xspotbugs/src/tests/α/β/γ/δ/package-info.java'] = {
Aliaksei Budavei368ef5a2024-12-16 21:37:54 +0100259 \ 'Sourcepath': {-> fnamemodify('Xspotbugs/src/tests/α/β/γ/δ/package-info.java',
260 \ ':p:h:S')},
Aliaksei Budavei60ddb1a2024-11-28 22:05:37 +0100261 \ 'classfiles': ['Xspotbugs/tests/α/β/γ/δ/package-info.class'],
262 \ }
263
264 " MAKE CLASS FILES DISCOVERABLE!
265 let g:spotbugs_properties = {
Aliaksei Budavei368ef5a2024-12-16 21:37:54 +0100266 \ 'sourceDirPath': ['src/tests'],
267 \ 'classDirPath': ['tests'],
Aliaksei Budavei60ddb1a2024-11-28 22:05:37 +0100268 \ }
269
270 call assert_true(has_key(s:SpotBugsParseFilterMakePrg('Xspotbugs', ''), 'sourcepath'))
271 call assert_true(has_key(s:SpotBugsParseFilterMakePrg('Xspotbugs', ''), 'classfiles'))
272
273 " Write 45 mock-up class files for 10 source files.
274 for [class_dir, src_dir, package] in [
275 \ ['Xspotbugs/tests/', 'Xspotbugs/src/tests/', ''],
276 \ ['Xspotbugs/tests/α/', 'Xspotbugs/src/tests/α/', 'package α;'],
277 \ ['Xspotbugs/tests/α/β/', 'Xspotbugs/src/tests/α/β/', 'package α.β;'],
278 \ ['Xspotbugs/tests/α/β/γ/', 'Xspotbugs/src/tests/α/β/γ/', 'package α.β.γ;'],
279 \ ['Xspotbugs/tests/α/β/γ/δ/', 'Xspotbugs/src/tests/α/β/γ/δ/', 'package α.β.γ.δ;']]
280 for class_file in ['𐌂1$1.class', '𐌂1$1𐌉𐌉1.class', '𐌂1$𐌂11$𐌉𐌉2.class',
281 \ '𐌂1$𐌂11.class', '𐌂1.class', '𐌂2$1𐌄.class', '𐌂2$1𐌓.class', '𐌂2.class']
282 call writefile(0zcafe.babe.0000.0041, class_dir .. class_file)
283 endfor
284 call writefile(0zcafe.babe.0000.0041, class_dir .. 'package-info.class')
285
286 " Write Java source files.
287 let type_file = src_dir .. '𐌂1.java'
288 call writefile(insert(copy(lines), package), type_file)
289 let package_file = src_dir .. 'package-info.java'
290 call writefile([package], src_dir .. 'package-info.java')
291
Aliaksei Budavei368ef5a2024-12-16 21:37:54 +0100292 " Note that using "off" for the first _outer_ iteration is preferable
293 " because only then "hlexists()" may be 0 (see "compiler/spotbugs.vim").
294 for s in ['off', 'on']
Aliaksei Budavei60ddb1a2024-11-28 22:05:37 +0100295 execute 'syntax ' .. s
296
297 execute 'edit ' .. type_file
298 compiler spotbugs
299 let result = s:SpotBugsParseFilterMakePrg('Xspotbugs', &l:makeprg)
Aliaksei Budavei368ef5a2024-12-16 21:37:54 +0100300 call assert_equal(results[type_file].Sourcepath(), result.sourcepath)
Aliaksei Budavei60ddb1a2024-11-28 22:05:37 +0100301 call assert_equal(results[type_file].classfiles, result.classfiles)
302 bwipeout
303
304 execute 'edit ' .. package_file
305 compiler spotbugs
306 let result = s:SpotBugsParseFilterMakePrg('Xspotbugs', &l:makeprg)
Aliaksei Budavei368ef5a2024-12-16 21:37:54 +0100307 call assert_equal(results[package_file].Sourcepath(), result.sourcepath)
Aliaksei Budavei60ddb1a2024-11-28 22:05:37 +0100308 call assert_equal(results[package_file].classfiles, result.classfiles)
309 bwipeout
310 endfor
311 endfor
312
313 let &shellslash = save_shellslash
314endfunc
315
Aliaksei Budavei368ef5a2024-12-16 21:37:54 +0100316func s:SpotBugsBeforeFileTypeTryPluginAndClearCache(state)
317 " Ponder over "extend(spotbugs#DefaultProperties(), g:spotbugs_properties)"
318 " in "ftplugin/java.vim".
319 let g:spotbugs#state = a:state
320 runtime autoload/spotbugs.vim
321endfunc
322
323func Test_compiler_spotbugs_properties()
324 let save_shellslash = &shellslash
325 set shellslash
326 setlocal makeprg=
327 filetype plugin on
328
329 call assert_true(mkdir('Xspotbugs/src', 'pR'))
330 call assert_true(mkdir('Xspotbugs/tests', 'pR'))
331 let type_file = 'Xspotbugs/src/𐌄.java'
332 let test_file = 'Xspotbugs/tests/𐌄$.java'
333 call writefile(['enum 𐌄{}'], type_file)
334 call writefile(['class 𐌄${}'], test_file)
335
336 " TEST INTEGRATION WITH A BOGUS COMPILER PLUGIN.
337 if !filereadable($VIMRUNTIME .. '/compiler/foo.vim') && !executable('foo')
338 let g:spotbugs_properties = {'compiler': 'foo'}
339 " XXX: In case this "if" block is no longer first.
340 call s:SpotBugsBeforeFileTypeTryPluginAndClearCache({
341 \ 'compiler': g:spotbugs_properties.compiler,
342 \ })
343 execute 'edit ' .. type_file
344 call assert_equal('java', &l:filetype)
345 " This variable will indefinitely keep the compiler name.
346 call assert_equal('foo', g:spotbugs#state.compiler)
347 " The "compiler" entry should be gone after FileType and default entries
348 " should only appear for a supported compiler.
349 call assert_false(has_key(g:spotbugs_properties, 'compiler'))
350 call assert_true(empty(g:spotbugs_properties))
351 " Query default implementations.
352 call assert_true(exists('*spotbugs#DefaultProperties'))
353 call assert_true(exists('*spotbugs#DefaultPreCompilerAction'))
354 call assert_true(exists('*spotbugs#DefaultPreCompilerTestAction'))
355 call assert_true(empty(spotbugs#DefaultProperties()))
356 " Get a ":message".
357 redir => out
358 call spotbugs#DefaultPreCompilerAction()
359 redir END
360 call assert_equal('Not supported: "foo"', out[stridx(out, 'Not') :])
361 " Get a ":message".
362 redir => out
363 call spotbugs#DefaultPreCompilerTestAction()
364 redir END
365 call assert_equal('Not supported: "foo"', out[stridx(out, 'Not') :])
366 " No ":autocmd"s without one of "PreCompiler*Action", "PostCompilerAction".
367 call assert_false(exists('#java_spotbugs'))
368 bwipeout
369 endif
370
371 let s:spotbugs_results = {
372 \ 'preActionDone': 0,
373 \ 'preTestActionDone': 0,
374 \ 'preTestLocalActionDone': 0,
375 \ 'postActionDone': 0,
376 \ 'preCommandArguments': '',
377 \ 'preTestCommandArguments': '',
378 \ 'postCommandArguments': '',
379 \ }
380 defer execute('unlet s:spotbugs_results')
381
382 func! g:SpotBugsPreAction() abort
383 let s:spotbugs_results.preActionDone = 1
384 " XXX: Notify the spotbugs compiler about success or failure.
385 cc
386 endfunc
387 defer execute('delfunction g:SpotBugsPreAction')
388
389 func! g:SpotBugsPreTestAction() abort
390 let s:spotbugs_results.preTestActionDone = 1
391 " XXX: Let see compilation fail.
392 throw 'Oops'
393 endfunc
394 defer execute('delfunction g:SpotBugsPreTestAction')
395
396 func! g:SpotBugsPreTestLocalAction() abort
397 let s:spotbugs_results.preTestLocalActionDone = 1
398 " XXX: Notify the spotbugs compiler about success or failure.
399 cc
400 endfunc
401 defer execute('delfunction g:SpotBugsPreTestLocalAction')
402
403 func! g:SpotBugsPostAction() abort
404 let s:spotbugs_results.postActionDone = 1
405 endfunc
406 defer execute('delfunction g:SpotBugsPostAction')
407
408 func! g:SpotBugsPreCommand(arguments) abort
409 let s:spotbugs_results.preActionDone = 1
410 let s:spotbugs_results.preCommandArguments = a:arguments
411 " XXX: Notify the spotbugs compiler about success or failure.
412 cc
413 endfunc
414 defer execute('delfunction g:SpotBugsPreCommand')
415
416 func! g:SpotBugsPreTestCommand(arguments) abort
417 let s:spotbugs_results.preTestActionDone = 1
418 let s:spotbugs_results.preTestCommandArguments = a:arguments
419 " XXX: Notify the spotbugs compiler about success or failure.
420 cc
421 endfunc
422 defer execute('delfunction g:SpotBugsPreTestCommand')
423
424 func! g:SpotBugsPostCommand(arguments) abort
425 let s:spotbugs_results.postActionDone = 1
426 let s:spotbugs_results.postCommandArguments = a:arguments
427 endfunc
428 defer execute('delfunction g:SpotBugsPostCommand')
429
Aliaksei Budavei2e252472024-12-27 16:46:36 +0100430 func! g:SpotBugsPostCompilerActionExecutor(action) abort
431 try
432 " XXX: Notify the spotbugs compiler about success or failure.
433 cc
434 catch /\<E42:/
435 execute a:action
436 endtry
437 endfunc
438 defer execute('delfunction g:SpotBugsPostCompilerActionExecutor')
439
Aliaksei Budavei368ef5a2024-12-16 21:37:54 +0100440 " TEST INTEGRATION WITH A SUPPORTED COMPILER PLUGIN.
441 if filereadable($VIMRUNTIME .. '/compiler/maven.vim')
zeertzjq23da16d2025-02-03 18:53:28 +0100442 let save_PATH = $PATH
Aliaksei Budavei368ef5a2024-12-16 21:37:54 +0100443 if !executable('mvn')
444 if has('win32')
zeertzjq23da16d2025-02-03 18:53:28 +0100445 let $PATH = 'Xspotbugs;' .. $PATH
Aliaksei Budavei368ef5a2024-12-16 21:37:54 +0100446 " This is what ":help executable()" suggests.
Aliaksei Budavei2e252472024-12-27 16:46:36 +0100447 call writefile([], 'Xspotbugs/mvn.cmd')
Aliaksei Budavei368ef5a2024-12-16 21:37:54 +0100448 else
449 let $PATH = 'Xspotbugs:' .. $PATH
450 call writefile([], 'Xspotbugs/mvn')
451 call setfperm('Xspotbugs/mvn', 'rwx------')
452 endif
453 endif
454
455 let g:spotbugs_properties = {
456 \ 'compiler': 'maven',
457 \ 'PreCompilerAction': function('g:SpotBugsPreAction'),
458 \ 'PreCompilerTestAction': function('g:SpotBugsPreTestAction'),
459 \ 'PostCompilerAction': function('g:SpotBugsPostAction'),
460 \ }
461 " XXX: In case this is a runner-up ":edit".
462 call s:SpotBugsBeforeFileTypeTryPluginAndClearCache({
463 \ 'compiler': g:spotbugs_properties.compiler,
464 \ })
465 execute 'edit ' .. type_file
466 call assert_equal('java', &l:filetype)
467 call assert_equal('maven', g:spotbugs#state.compiler)
468 call assert_false(has_key(g:spotbugs_properties, 'compiler'))
469 call assert_false(empty(g:spotbugs_properties))
470 " Query default implementations.
471 call assert_true(exists('*spotbugs#DefaultProperties'))
472 call assert_equal(sort([
473 \ 'PreCompilerAction',
474 \ 'PreCompilerTestAction',
475 \ 'PostCompilerAction',
476 \ 'sourceDirPath',
477 \ 'classDirPath',
478 \ 'testSourceDirPath',
479 \ 'testClassDirPath',
480 \ ]),
481 \ sort(keys(spotbugs#DefaultProperties())))
482 " Some ":autocmd"s with one of "PreCompiler*Action", "PostCompilerAction".
483 call assert_true(exists('#java_spotbugs'))
484 call assert_true(exists('#java_spotbugs#Syntax'))
485 call assert_true(exists('#java_spotbugs#User'))
486 call assert_equal(2, exists(':SpotBugsDefineBufferAutocmd'))
487 SpotBugsDefineBufferAutocmd SigUSR1 User SigUSR1 User SigUSR1 User
488 call assert_true(exists('#java_spotbugs#SigUSR1'))
489 call assert_true(exists('#java_spotbugs#Syntax'))
490 call assert_true(exists('#java_spotbugs#User'))
491 call assert_equal(2, exists(':SpotBugsRemoveBufferAutocmd'))
492 SpotBugsRemoveBufferAutocmd SigUSR1 User SigUSR1 User UserGettingBored
493 call assert_false(exists('#java_spotbugs#SigUSR1'))
494 call assert_true(exists('#java_spotbugs#Syntax'))
495 call assert_true(exists('#java_spotbugs#User'))
496
497 let s:spotbugs_results.preActionDone = 0
498 let s:spotbugs_results.preTestActionDone = 0
499 let s:spotbugs_results.postActionDone = 0
500
501 doautocmd java_spotbugs Syntax
502 call assert_false(exists('#java_spotbugs#Syntax'))
503
504 " No match: "type_file !~# 'src/main/java'".
505 call assert_false(s:spotbugs_results.preActionDone)
506 " No match: "type_file !~# 'src/test/java'".
507 call assert_false(s:spotbugs_results.preTestActionDone)
508 " No pre-match, no post-action.
509 call assert_false(s:spotbugs_results.postActionDone)
510 " Without a match, confirm that ":compiler spotbugs" has NOT run.
511 call assert_true(empty(&l:makeprg))
512
513 let s:spotbugs_results.preActionDone = 0
514 let s:spotbugs_results.preTestActionDone = 0
515 let s:spotbugs_results.postActionDone = 0
516 " Update path entries. (Note that we cannot use just "src" because there
517 " is another "src" directory nearer the filesystem root directory, i.e.
518 " "vim/vim/src/testdir/Xspotbugs/src", and "s:DispatchAction()" (see
519 " "ftplugin/java.vim") will match "vim/vim/src/testdir/Xspotbugs/tests"
520 " against "src".)
521 let g:spotbugs_properties.sourceDirPath = ['Xspotbugs/src']
522 let g:spotbugs_properties.classDirPath = ['Xspotbugs/src']
523 let g:spotbugs_properties.testSourceDirPath = ['tests']
524 let g:spotbugs_properties.testClassDirPath = ['tests']
525
526 doautocmd java_spotbugs User
527 " No match: "type_file !~# 'src/main/java'" (with old "*DirPath" values
528 " cached).
529 call assert_false(s:spotbugs_results.preActionDone)
530 " No match: "type_file !~# 'src/test/java'" (with old "*DirPath" values
531 " cached).
532 call assert_false(s:spotbugs_results.preTestActionDone)
533 " No pre-match, no post-action.
534 call assert_false(s:spotbugs_results.postActionDone)
535 " Without a match, confirm that ":compiler spotbugs" has NOT run.
536 call assert_true(empty(&l:makeprg))
537
538 let s:spotbugs_results.preActionDone = 0
539 let s:spotbugs_results.preTestActionDone = 0
540 let s:spotbugs_results.postActionDone = 0
541 " XXX: Re-build ":autocmd"s from scratch with new values applied.
542 doautocmd FileType
543
544 call assert_true(exists('b:spotbugs_syntax_once'))
545 doautocmd java_spotbugs User
546 " A match: "type_file =~# 'Xspotbugs/src'" (with new "*DirPath" values
547 " cached).
548 call assert_true(s:spotbugs_results.preActionDone)
549 " No match: "type_file !~# 'tests'" (with new "*DirPath" values cached).
550 call assert_false(s:spotbugs_results.preTestActionDone)
551 " For a pre-match, a post-action.
552 call assert_true(s:spotbugs_results.postActionDone)
553
554 " With a match, confirm that ":compiler spotbugs" has run.
555 if has('win32')
556 call assert_match('^spotbugs\.bat\s', &l:makeprg)
557 else
558 call assert_match('^spotbugs\s', &l:makeprg)
559 endif
560
561 bwipeout
562 setlocal makeprg=
563 let s:spotbugs_results.preActionDone = 0
564 let s:spotbugs_results.preTestActionDone = 0
565 let s:spotbugs_results.preTestLocalActionDone = 0
566 let s:spotbugs_results.postActionDone = 0
567
568 execute 'edit ' .. test_file
569 " Prepare a buffer-local, incomplete variant of properties, relying on
570 " "ftplugin/java.vim" to take care of merging in unique entries, if any,
571 " from "g:spotbugs_properties".
572 let b:spotbugs_properties = {
573 \ 'PreCompilerTestAction': function('g:SpotBugsPreTestLocalAction'),
574 \ }
575 call assert_equal('java', &l:filetype)
576 call assert_true(exists('#java_spotbugs'))
577 call assert_true(exists('#java_spotbugs#Syntax'))
578 call assert_true(exists('#java_spotbugs#User'))
579 call assert_fails('doautocmd java_spotbugs Syntax', 'Oops')
580 call assert_false(exists('#java_spotbugs#Syntax'))
581 " No match: "test_file !~# 'Xspotbugs/src'".
582 call assert_false(s:spotbugs_results.preActionDone)
583 " A match: "test_file =~# 'tests'".
584 call assert_true(s:spotbugs_results.preTestActionDone)
585 call assert_false(s:spotbugs_results.preTestLocalActionDone)
586 " No action after pre-failure (the thrown "Oops" doesn't qualify for ":cc").
587 call assert_false(s:spotbugs_results.postActionDone)
588 " No ":compiler spotbugs" will be run after pre-failure.
589 call assert_true(empty(&l:makeprg))
590
591 let s:spotbugs_results.preActionDone = 0
592 let s:spotbugs_results.preTestActionDone = 0
593 let s:spotbugs_results.preTestLocalActionDone = 0
594 let s:spotbugs_results.postActionDone = 0
595 " XXX: Re-build ":autocmd"s from scratch with buffer-local values applied.
596 doautocmd FileType
597
598 call assert_true(exists('b:spotbugs_syntax_once'))
599 doautocmd java_spotbugs User
600 " No match: "test_file !~# 'Xspotbugs/src'".
601 call assert_false(s:spotbugs_results.preActionDone)
602 " A match: "test_file =~# 'tests'".
603 call assert_true(s:spotbugs_results.preTestLocalActionDone)
604 call assert_false(s:spotbugs_results.preTestActionDone)
605 " For a pre-match, a post-action.
606 call assert_true(s:spotbugs_results.postActionDone)
607
608 " With a match, confirm that ":compiler spotbugs" has run.
609 if has('win32')
610 call assert_match('^spotbugs\.bat\s', &l:makeprg)
611 else
612 call assert_match('^spotbugs\s', &l:makeprg)
613 endif
614
615 setlocal makeprg=
616 let s:spotbugs_results.preActionDone = 0
617 let s:spotbugs_results.preTestActionDone = 0
618 let s:spotbugs_results.preTestLocalActionDone = 0
619 let s:spotbugs_results.postActionDone = 0
620 let s:spotbugs_results.preCommandArguments = ''
621 let s:spotbugs_results.preTestCommandArguments = ''
622 let s:spotbugs_results.postCommandArguments = ''
623 " XXX: Compose the assigned "*Command"s with the default Maven "*Action"s.
624 let b:spotbugs_properties = {
625 \ 'compiler': 'maven',
626 \ 'DefaultPreCompilerTestCommand': function('g:SpotBugsPreTestCommand'),
627 \ 'DefaultPreCompilerCommand': function('g:SpotBugsPreCommand'),
628 \ 'DefaultPostCompilerCommand': function('g:SpotBugsPostCommand'),
Aliaksei Budavei2e252472024-12-27 16:46:36 +0100629 \ 'PostCompilerActionExecutor': function('g:SpotBugsPostCompilerActionExecutor'),
630 \ 'augroupForPostCompilerAction': 'java_spotbugs_test',
Aliaksei Budavei368ef5a2024-12-16 21:37:54 +0100631 \ 'sourceDirPath': ['Xspotbugs/src'],
632 \ 'classDirPath': ['Xspotbugs/src'],
633 \ 'testSourceDirPath': ['tests'],
634 \ 'testClassDirPath': ['tests'],
635 \ }
636 unlet g:spotbugs_properties
637 " XXX: Re-build ":autocmd"s from scratch with buffer-local values applied.
638 call s:SpotBugsBeforeFileTypeTryPluginAndClearCache({
639 \ 'compiler': b:spotbugs_properties.compiler,
640 \ 'commands': {
641 \ 'DefaultPreCompilerTestCommand':
642 \ b:spotbugs_properties.DefaultPreCompilerTestCommand,
643 \ 'DefaultPreCompilerCommand':
644 \ b:spotbugs_properties.DefaultPreCompilerCommand,
645 \ 'DefaultPostCompilerCommand':
646 \ b:spotbugs_properties.DefaultPostCompilerCommand,
647 \ },
648 \ })
649 doautocmd FileType
650
651 call assert_equal('maven', g:spotbugs#state.compiler)
652 call assert_equal(sort([
653 \ 'DefaultPreCompilerTestCommand',
654 \ 'DefaultPreCompilerCommand',
655 \ 'DefaultPostCompilerCommand',
656 \ ]),
657 \ sort(keys(g:spotbugs#state.commands)))
658 call assert_true(exists('b:spotbugs_syntax_once'))
659 doautocmd java_spotbugs User
660 " No match: "test_file !~# 'Xspotbugs/src'".
661 call assert_false(s:spotbugs_results.preActionDone)
662 call assert_true(empty(s:spotbugs_results.preCommandArguments))
663 " A match: "test_file =~# 'tests'".
664 call assert_true(s:spotbugs_results.preTestActionDone)
665 call assert_equal('test-compile', s:spotbugs_results.preTestCommandArguments)
666 " For a pre-match, a post-action.
667 call assert_true(s:spotbugs_results.postActionDone)
668 call assert_equal('%:S', s:spotbugs_results.postCommandArguments)
669
670 " With a match, confirm that ":compiler spotbugs" has run.
671 if has('win32')
672 call assert_match('^spotbugs\.bat\s', &l:makeprg)
673 else
674 call assert_match('^spotbugs\s', &l:makeprg)
675 endif
676
Aliaksei Budavei2e252472024-12-27 16:46:36 +0100677 setlocal makeprg=
678 let s:spotbugs_results.preActionDone = 0
679 let s:spotbugs_results.preTestActionOtherDone = 0
680 let s:spotbugs_results.preTestLocalActionDone = 0
681 let s:spotbugs_results.postActionDone = 0
682 let s:spotbugs_results.preCommandArguments = ''
683 let s:spotbugs_results.preTestCommandArguments = ''
684 let s:spotbugs_results.postCommandArguments = ''
685
686 " When "PostCompilerActionExecutor", "Pre*Action" and/or "Pre*TestAction",
687 " and "Post*Action" are available, "#java_spotbugs_post" must be defined.
688 call assert_true(exists('#java_spotbugs_post'))
689 call assert_true(exists('#java_spotbugs_post#User'))
690 call assert_false(exists('#java_spotbugs_post#ShellCmdPost'))
691 call assert_false(exists('#java_spotbugs_test#ShellCmdPost'))
692
693 " Re-link a Funcref on the fly.
694 func! g:SpotBugsPreTestCommand(arguments) abort
695 let s:spotbugs_results.preTestActionOtherDone = 1
696 let s:spotbugs_results.preTestCommandArguments = a:arguments
697 " Define a once-only ":autocmd" for "#java_spotbugs_test#ShellCmdPost".
698 doautocmd java_spotbugs_post User
699 " XXX: Do NOT use ":cc" to notify the spotbugs compiler about success or
700 " failure, and assume the transfer of control to a ShellCmdPost command.
701 endfunc
702
703 doautocmd java_spotbugs User
704 " No match: "test_file !~# 'Xspotbugs/src'".
705 call assert_false(s:spotbugs_results.preActionDone)
706 call assert_true(empty(s:spotbugs_results.preCommandArguments))
707 " A match: "test_file =~# 'tests'".
708 call assert_true(s:spotbugs_results.preTestActionOtherDone)
709 call assert_equal('test-compile', s:spotbugs_results.preTestCommandArguments)
710 " For a pre-match, no post-action (without ":cc") UNLESS a ShellCmdPost
711 " event is consumed whose command will invoke "PostCompilerActionExecutor"
712 " and the latter will accept a post-compiler action argument.
713 call assert_false(s:spotbugs_results.postActionDone)
714 call assert_true(exists('#java_spotbugs_test#ShellCmdPost'))
715 doautocmd ShellCmdPost
716 call assert_false(exists('#java_spotbugs_test#ShellCmdPost'))
717 call assert_true(s:spotbugs_results.postActionDone)
718 call assert_equal('%:S', s:spotbugs_results.postCommandArguments)
719
720 " With a match, confirm that ":compiler spotbugs" has run.
721 if has('win32')
722 call assert_match('^spotbugs\.bat\s', &l:makeprg)
723 else
724 call assert_match('^spotbugs\s', &l:makeprg)
725 endif
726
Aliaksei Budavei368ef5a2024-12-16 21:37:54 +0100727 bwipeout
728 setlocal makeprg=
zeertzjq23da16d2025-02-03 18:53:28 +0100729 let $PATH = save_PATH
Aliaksei Budavei368ef5a2024-12-16 21:37:54 +0100730 endif
731
732 filetype plugin off
733 setlocal makeprg=
734 let &shellslash = save_shellslash
735endfunc
736
Bram Moolenaar6d91bcb2020-08-12 18:50:36 +0200737" vim: shiftwidth=2 sts=2 expandtab