neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

test_compiler.vim (29998B)


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