run_test.vim 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. " This script is sourced while editing the .vim file with the tests.
  2. " When the script is successful the .res file will be created.
  3. " Errors are appended to the test.log file.
  4. "
  5. " To execute only specific test functions, add a second argument. It will be
  6. " matched against the names of the Test_ funtion. E.g.:
  7. " ../vim -Nu NONE vimrc -S lib/run_test.vim test_channel.vim open_delay
  8. " The output can be found in the "messages" file.
  9. "
  10. " The test script may contain anything, only functions that start with
  11. " "Test_" are special. These will be invoked and should contain assert
  12. " functions. See test_assert.vim for an example.
  13. "
  14. " It is possible to source other files that contain "Test_" functions. This
  15. " can speed up testing, since Vim does not need to restart. But be careful
  16. " that the tests do not interfere with each other.
  17. "
  18. " If an error cannot be detected properly with an assert function add the
  19. " error to the v:errors list:
  20. " call add(v:errors, 'test foo failed: Cannot find xyz')
  21. "
  22. " If preparation for each Test_ function is needed, define a SetUp function.
  23. " It will be called before each Test_ function.
  24. "
  25. " If cleanup after each Test_ function is needed, define a TearDown function.
  26. " It will be called after each Test_ function.
  27. "
  28. " When debugging a test it can be useful to add messages to v:errors:
  29. " call add(v:errors, "this happened")
  30. "
  31. " But for real debug logging:
  32. " call ch_log( ",,,message..." )
  33. " Then view it in 'debuglog'
  34. " Let a test take up to 1 minute
  35. let s:single_test_timeout = 60000
  36. " Restrict the runtimepath to the exact minimum needed for testing
  37. let &rtp = getcwd() . '/lib'
  38. set rtp +=$VIM/vimfiles,$VIMRUNTIME,$VIM/vimfiles/after
  39. call ch_logfile( 'debuglog', 'w' )
  40. " For consistency run all tests with 'nocompatible' set.
  41. " This also enables use of line continuation.
  42. set nocp
  43. " Use utf-8 by default, instead of whatever the system default happens to be.
  44. " Individual tests can overrule this at the top of the file.
  45. set encoding=utf-8
  46. " Avoid stopping at the "hit enter" prompt
  47. set nomore
  48. " Output all messages in English.
  49. lang messages C
  50. " Always use forward slashes.
  51. set shellslash
  52. func s:TestFailed()
  53. if pyxeval( '"ycm_state" in globals()' )
  54. let logs = pyxeval( 'ycm_state.GetLogfiles()' )
  55. for log_name in sort( keys( logs ) )
  56. let log = readfile( logs[ log_name ] )
  57. let logfile = s:testid_filesafe . '_' . log_name . '.testlog'
  58. call writefile( log, logfile, 's' )
  59. call add( s:messages,
  60. \ 'Wrote '
  61. \ . log_name
  62. \ . ' log for failed test: '
  63. \ . logfile )
  64. call add( s:messages, '**** LOG FILE ' . log_name . ' ****' )
  65. call extend( s:messages, log )
  66. endfor
  67. endif
  68. endfunc
  69. func! Abort( timer_id )
  70. call assert_report( 'Test timed out!!!' )
  71. qa!
  72. endfunc
  73. func RunTheTest(test)
  74. echo 'Executing ' . a:test
  75. " Avoid stopping at the "hit enter" prompt
  76. set nomore
  77. " Avoid a three second wait when a message is about to be overwritten by the
  78. " mode message.
  79. set noshowmode
  80. " Clear any overrides.
  81. call test_override('ALL', 0)
  82. " Some tests wipe out buffers. To be consistent, always wipe out all
  83. " buffers.
  84. %bwipe!
  85. " The test may change the current directory. Save and restore the
  86. " directory after executing the test.
  87. let save_cwd = getcwd()
  88. if exists("*SetUp_" . a:test)
  89. try
  90. exe 'call SetUp_' . a:test
  91. catch
  92. call add(v:errors,
  93. \ 'Caught exception in SetUp_' . a:test . ' before '
  94. \ . a:test
  95. \ . ': '
  96. \ . v:exception
  97. \ . ' @ '
  98. \ . g:testpath
  99. \ . ':'
  100. \ . v:throwpoint)
  101. endtry
  102. endif
  103. if exists("*SetUp")
  104. try
  105. call SetUp()
  106. catch
  107. call add(v:errors,
  108. \ 'Caught exception in SetUp() before '
  109. \ . a:test
  110. \ . ': '
  111. \ . v:exception
  112. \ . ' @ '
  113. \ . g:testpath
  114. \ . ':'
  115. \ . v:throwpoint)
  116. endtry
  117. endif
  118. call add(s:messages, 'Executing ' . a:test)
  119. let s:done += 1
  120. let timer = timer_start( s:single_test_timeout, funcref( 'Abort' ) )
  121. try
  122. let s:test = a:test
  123. let s:testid = g:testpath . ':' . a:test
  124. let test_filesafe = substitute( a:test, '[)(,:]', '_', 'g' )
  125. let s:testid_filesafe = g:testpath . '_' . test_filesafe
  126. au VimLeavePre * call EarlyExit(s:test)
  127. call ch_log( 'StartTest: ' . a:test )
  128. messages clear
  129. exe 'call ' . a:test
  130. " We require that tests either don't make errors or that they call messages
  131. " clear
  132. call assert_true(
  133. \ empty( execute( 'messages' ) ),
  134. \ 'Test '
  135. \ .. a:test
  136. \ .. ' produced unexpected messages output '
  137. \ .. string( execute( 'messages' ) )
  138. \ .. ' (hint: call :messages clear if this is expected, '
  139. \ .. 'or use :silent)' )
  140. call ch_log( 'EndTest: ' . a:test )
  141. au! VimLeavePre
  142. catch /^\cskipped/
  143. let v:errors = []
  144. call ch_log( 'Skipped: ' . a:test )
  145. call add(s:messages, ' Skipped')
  146. call add(s:skipped,
  147. \ 'SKIPPED ' . a:test
  148. \ . ': '
  149. \ . substitute(v:exception, '^\S*\s\+', '', ''))
  150. catch
  151. call ch_log( 'Catch: ' . a:test )
  152. call add(v:errors,
  153. \ 'Caught exception in ' . a:test
  154. \ . ': '
  155. \ . v:exception
  156. \ . ' @ '
  157. \ . g:testpath
  158. \ . ':'
  159. \ . v:throwpoint)
  160. call s:TestFailed()
  161. endtry
  162. call timer_stop( timer )
  163. " In case 'insertmode' was set and something went wrong, make sure it is
  164. " reset to avoid trouble with anything else.
  165. set noinsertmode
  166. if exists("*TearDown")
  167. try
  168. call TearDown()
  169. catch
  170. call add(v:errors,
  171. \ 'Caught exception in TearDown() after ' . a:test
  172. \ . ': '
  173. \ . v:exception
  174. \ . ' @ '
  175. \ . g:testpath
  176. \ . ':'
  177. \ . v:throwpoint)
  178. endtry
  179. endif
  180. if exists("*TearDown_" . a:test)
  181. try
  182. exe 'call TearDown_' . a:test
  183. catch
  184. call add(v:errors,
  185. \ 'Caught exception in TearDown_' . a:test . ' after ' . a:test
  186. \ . ': '
  187. \ . v:exception
  188. \ . ' @ '
  189. \ . g:testpath
  190. \ . ':'
  191. \ . v:throwpoint)
  192. endtry
  193. endif
  194. " Clear any autocommands
  195. au!
  196. call test_override( 'ALL', 0 )
  197. %bwipe!
  198. " Close any extra tab pages and windows and make the current one not modified.
  199. while tabpagenr('$') > 1
  200. quit!
  201. endwhile
  202. while 1
  203. let wincount = winnr('$')
  204. if wincount == 1
  205. break
  206. endif
  207. bwipe!
  208. if wincount == winnr('$')
  209. " Did not manage to close a window.
  210. only!
  211. break
  212. endif
  213. endwhile
  214. exe 'cd ' . save_cwd
  215. endfunc
  216. func AfterTheTest()
  217. if len(v:errors) > 0
  218. let s:fail += 1
  219. call s:TestFailed()
  220. call add(s:errors, 'Found errors in ' . s:testid . ':')
  221. call extend(s:errors, v:errors)
  222. let v:errors = []
  223. endif
  224. endfunc
  225. func EarlyExit(test)
  226. " It's OK for the test we use to test the quit detection.
  227. call add(v:errors, 'Test caused Vim to exit: ' . a:test)
  228. call FinishTesting()
  229. endfunc
  230. " This function can be called by a test if it wants to abort testing.
  231. func FinishTesting()
  232. call AfterTheTest()
  233. " Don't write viminfo on exit.
  234. set viminfo=
  235. if s:fail == 0
  236. " Success, create the .res file so that make knows it's done.
  237. call writefile( [], g:testname . '.res', 's' )
  238. endif
  239. if len(s:errors) > 0
  240. " Append errors to test.log
  241. let l = []
  242. if filereadable( 'test.log' )
  243. let l = readfile( 'test.log' )
  244. endif
  245. call writefile( l->extend( [ '', 'From ' . g:testpath . ':' ] )
  246. \ ->extend( s:errors ),
  247. \ 'test.log',
  248. \ 's' )
  249. endif
  250. if s:done == 0
  251. let message = 'NO tests executed'
  252. else
  253. let message = 'Executed ' . s:done . (s:done > 1 ? ' tests' : ' test')
  254. endif
  255. echo message
  256. call add(s:messages, message)
  257. if s:fail > 0
  258. let message = s:fail . ' FAILED:'
  259. echo message
  260. call add(s:messages, message)
  261. call extend(s:messages, s:errors)
  262. endif
  263. " Add SKIPPED messages
  264. call extend(s:messages, s:skipped)
  265. " Append messages to the file "messages"
  266. let l = []
  267. if filereadable( 'messages' )
  268. let l = readfile( 'messages' )
  269. endif
  270. call writefile( l->extend( [ '', 'From ' . g:testpath . ':' ] )
  271. \ ->extend( s:messages ),
  272. \ 'messages',
  273. \ 's' )
  274. if exists( '$COVERAGE' ) && pyxeval( '_cov is not None' )
  275. pyx _cov.stop()
  276. pyx _cov.save()
  277. endif
  278. if s:fail > 0
  279. cquit!
  280. else
  281. qall!
  282. endif
  283. endfunc
  284. " Source the test script. First grab the file name, in case the script
  285. " navigates away. g:testname can be used by the tests.
  286. let g:testname = expand('%')
  287. let g:testpath = expand('%:p')
  288. let s:done = 0
  289. let s:fail = 0
  290. let s:errors = []
  291. let s:messages = []
  292. let s:skipped = []
  293. try
  294. source %
  295. catch
  296. let s:fail += 1
  297. call add(s:errors,
  298. \ 'Caught exception: ' .
  299. \ v:exception .
  300. \ ' @ ' . v:throwpoint)
  301. endtry
  302. " Names of flaky tests.
  303. let s:flaky_tests = []
  304. " Pattern indicating a common flaky test failure.
  305. let s:flaky_errors_re = '__does_not_match__'
  306. " Locate Test_ functions and execute them.
  307. redir @q
  308. silent function /^Test_
  309. redir END
  310. let s:tests = split(substitute(@q, 'function \(\k*()\)', '\1', 'g'))
  311. " If there is an extra argument filter the function names against it.
  312. if argc() > 1
  313. let s:tests = filter(s:tests, 'v:val =~ argv(1)')
  314. endif
  315. pyx <<EOF
  316. def _InitCoverage():
  317. try:
  318. import coverage
  319. except ImportError:
  320. return None
  321. cov = coverage.Coverage( data_file='.coverage.python', data_suffix = True )
  322. cov.start()
  323. return cov
  324. import os
  325. if 'COVERAGE' in os.environ:
  326. _cov = _InitCoverage()
  327. EOF
  328. " Init covimerage
  329. if exists( '$COVERAGE' )
  330. profile start .vim_profile
  331. exe 'profile! file */youcompleteme.vim'
  332. endif
  333. " Execute the tests in alphabetical order.
  334. for s:test in sort(s:tests)
  335. " Silence, please!
  336. set belloff=all
  337. call RunTheTest(s:test)
  338. call AfterTheTest()
  339. endfor
  340. call FinishTesting()
  341. " vim: shiftwidth=2 sts=2 expandtab