diagnostics.test.vim 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. function! SetUp()
  2. let g:ycm_use_clangd = 1
  3. let g:ycm_confirm_extra_conf = 0
  4. let g:ycm_auto_trigger = 1
  5. let g:ycm_keep_logfiles = 1
  6. let g:ycm_log_level = 'DEBUG'
  7. let g:ycm_always_populate_location_list = 1
  8. let g:ycm_enable_semantic_highlighting = 1
  9. " diagnostics take ages
  10. let g:ycm_test_min_delay = 7
  11. call youcompleteme#test#setup#SetUp()
  12. endfunction
  13. function! TearDown()
  14. call youcompleteme#test#setup#CleanUp()
  15. endfunction
  16. function! Test_Diagnostics_Update_In_Insert_Mode()
  17. call youcompleteme#test#setup#OpenFile(
  18. \ '/test/testdata/cpp/new_file.cpp', {} )
  19. " Required to trigger TextChangedI
  20. " https://github.com/vim/vim/issues/4665#event-2480928194
  21. call test_override( 'char_avail', 1 )
  22. " Must do the checks in a timer callback because we need to stay in insert
  23. " mode until done.
  24. function! Check( id ) closure
  25. call WaitForAssert( {-> assert_true( len( sign_getplaced(
  26. \ '%',
  27. \ { 'group': 'ycm_signs' } )[ 0 ][ 'signs' ] ) ) } )
  28. call feedkeys( "\<ESC>" )
  29. endfunction
  30. call FeedAndCheckMain( 'imain(', funcref( 'Check' ) )
  31. call test_override( 'ALL', 0 )
  32. endfunction
  33. function! SetUp_Test_Disable_Diagnostics_Update_In_insert_Mode()
  34. call youcompleteme#test#setup#PushGlobal(
  35. \ 'ycm_update_diagnostics_in_insert_mode', 0 )
  36. endfunction
  37. function! Test_Disable_Diagnostics_Update_In_insert_Mode()
  38. call youcompleteme#test#setup#OpenFile(
  39. \ '/test/testdata/cpp/new_file.cpp', {} )
  40. " Required to trigger TextChangedI
  41. " https://github.com/vim/vim/issues/4665#event-2480928194
  42. call test_override( 'char_avail', 1 )
  43. " Must do the checks in a timer callback because we need to stay in insert
  44. " mode until done.
  45. function! CheckNoDiagUIAfterOpenParenthesis( id ) closure
  46. call WaitForAssert( {->
  47. \ assert_true(
  48. \ py3eval(
  49. \ 'len( ycm_state.CurrentBuffer()._diag_interface._diagnostics )'
  50. \ ) ) } )
  51. call WaitForAssert( {-> assert_false( len( sign_getplaced(
  52. \ '%',
  53. \ { 'group': 'ycm_signs' } )[ 0 ][ 'signs' ] ) ) } )
  54. call FeedAndCheckAgain( " \<BS>\<BS>\<BS>)",
  55. \ funcref( 'CheckNoDiagUIAfterClosingPatenthesis' ) )
  56. endfunction
  57. function! CheckNoDiagUIAfterClosingPatenthesis( id ) closure
  58. call WaitForAssert( {->
  59. \ assert_true(
  60. \ py3eval(
  61. \ 'len( ycm_state.CurrentBuffer()._diag_interface._diagnostics )'
  62. \ ) ) } )
  63. call WaitForAssert( {-> assert_false( len( sign_getplaced(
  64. \ '%',
  65. \ { 'group': 'ycm_signs' } )[ 0 ][ 'signs' ] ) ) } )
  66. call feedkeys( "\<ESC>" )
  67. call FeedAndCheckAgain( "\<ESC>",
  68. \ funcref( 'CheckDiagUIRefreshedAfterLeavingInsertMode' ) )
  69. endfunction
  70. function! CheckDiagUIRefreshedAfterLeavingInsertMode( id ) closure
  71. call WaitForAssert( {->
  72. \ assert_true(
  73. \ py3eval(
  74. \ 'len( ycm_state.CurrentBuffer()._diag_interface._diagnostics )'
  75. \ ) ) } )
  76. call WaitForAssert( {-> assert_true( len( sign_getplaced(
  77. \ '%',
  78. \ { 'group': 'ycm_signs' } )[ 0 ][ 'signs' ] ) ) } )
  79. call FeedAndCheckAgain( "A\<CR>", funcref( 'CheckNoPropsAfterNewLine' )
  80. endfunction
  81. function! CheckNoPropsAfterNewLine( id ) closure
  82. call WaitForAssert( {->
  83. \ assert_true(
  84. \ py3eval(
  85. \ 'len( ycm_state.CurrentBuffer()._diag_interface._diagnostics )'
  86. \ ) ) } )
  87. call WaitForAssert( {-> assert_false( len( prop_list(
  88. \ 1, { 'end_lnum': -1,
  89. \ 'types': [ 'YcmVirtDiagWarning',
  90. \ 'YcmVirtDiagError',
  91. \ 'YcmVirtDiagPadding' ] } ) ) ) )
  92. endfunction
  93. call FeedAndCheckMain( 'imain(',
  94. \ funcref( 'CheckNoDiagUIAfterOpenParenthesis' ) )
  95. call test_override( 'ALL', 0 )
  96. endfunction
  97. function! TearDown_Test_Disable_Diagnostics_Update_In_insert_Mode()
  98. call youcompleteme#test#setup#PopGlobal(
  99. \ 'ycm_update_diagnostics_in_insert_mode' )
  100. endfunction
  101. function! Test_Changing_Filetype_Refreshes_Diagnostics()
  102. call youcompleteme#test#setup#OpenFile(
  103. \ '/test/testdata/diagnostics/foo.xml',
  104. \ { 'native_ft': 0 } )
  105. call assert_equal( 'xml', &ft )
  106. call assert_false(
  107. \ pyxeval( 'ycm_state._buffers[' . bufnr( '%' ) . ']._async_diags' ) )
  108. call assert_true( empty( sign_getplaced(
  109. \ '%',
  110. \ { 'group': 'ycm_signs' } )[ 0 ][ 'signs' ] ) )
  111. setf typescript
  112. call assert_equal( 'typescript', &ft )
  113. call assert_false(
  114. \ pyxeval( 'ycm_state._buffers[' . bufnr( '%' ) . ']._async_diags' ) )
  115. " Diagnostics are async, so wait for the assert to return 0 for a while.
  116. call WaitForAssert( {-> assert_equal( 1, len( sign_getplaced(
  117. \ '%',
  118. \ { 'group': 'ycm_signs' } )[ 0 ][ 'signs' ] ) ) } )
  119. call assert_equal( 1, len( sign_getplaced(
  120. \ '%',
  121. \ { 'group': 'ycm_signs' } )[ 0 ][ 'signs' ] ) )
  122. call assert_equal(
  123. \ 'YcmError',
  124. \ sign_getplaced(
  125. \ '%',
  126. \ { 'group': 'ycm_signs' } )[ 0 ][ 'signs' ][ 0 ][ 'name' ] )
  127. call assert_false( empty( getloclist( 0 ) ) )
  128. endfunction
  129. function! Test_MessagePoll_After_LocationList()
  130. call youcompleteme#test#setup#OpenFile(
  131. \ '/test/testdata/diagnostics/foo.cpp', {} )
  132. setf cpp
  133. call assert_equal( 'cpp', &ft )
  134. call WaitForAssert( {-> assert_equal( 2, len( sign_getplaced(
  135. \ '%',
  136. \ { 'group': 'ycm_signs' } )[ 0 ][ 'signs' ] ) ) } )
  137. call setline( 1, '' )
  138. " Wait for the parse request to be complete otherwise we won't send another
  139. " one when the TextChanged event fires
  140. call WaitFor( {-> pyxeval( 'ycm_state.FileParseRequestReady()' ) } )
  141. doautocmd TextChanged
  142. call WaitForAssert( {-> assert_true( empty( sign_getplaced(
  143. \ '%',
  144. \ { 'group': 'ycm_signs' } )[ 0 ][ 'signs' ] ) ) } )
  145. call assert_true( empty( getloclist( 0 ) ) )
  146. endfunction
  147. function! Test_MessagePoll_Multiple_Filetypes()
  148. call youcompleteme#test#setup#OpenFile(
  149. \ '/third_party/ycmd/ycmd/tests/java/testdata/simple_eclipse_project' .
  150. \ '/src/com/test/TestLauncher.java', {} )
  151. call WaitForAssert( {->
  152. \ assert_true( len( sign_getplaced(
  153. \ '%',
  154. \ { 'group': 'ycm_signs' } )[ 0 ][ 'signs' ] ) ) } )
  155. let java_signs = sign_getplaced(
  156. \ '%',
  157. \ { 'group': 'ycm_signs' } )[ 0 ][ 'signs' ]
  158. silent vsplit testdata/diagnostics/foo.cpp
  159. " Make sure we've left the java buffer
  160. call assert_equal( java_signs,
  161. \ sign_getplaced( '#', { 'group': 'ycm_signs' } )[ 0 ][ 'signs' ] )
  162. " Clangd emits two diagnostics for foo.cpp.
  163. call WaitForAssert( {->
  164. \ assert_equal(
  165. \ 2,
  166. \ len( sign_getplaced(
  167. \ '%',
  168. \ { 'group': 'ycm_signs' } )[ 0 ][ 'signs' ] ) ) } )
  169. let cpp_signs = sign_getplaced( '%',
  170. \ { 'group': 'ycm_signs' } )[ 0 ][ 'signs' ]
  171. call assert_false( java_signs == cpp_signs )
  172. endfunction
  173. function! Test_BufferWithoutAssociatedFile_HighlightingWorks()
  174. enew
  175. call setbufline( '%', 1, 'iiii' )
  176. setf c
  177. call WaitForAssert( {->
  178. \ assert_true( len( sign_getplaced(
  179. \ '%',
  180. \ { 'group': 'ycm_signs' } )[ 0 ][ 'signs' ] ) ) } )
  181. let expected_properties = [
  182. \ { 'id': 4,
  183. \ 'col': 1,
  184. \ 'end': 1,
  185. \ 'type': 'YcmErrorProperty',
  186. \ 'length': 0,
  187. \ 'start': 1 },
  188. \ { 'id': 3,
  189. \ 'col': 1,
  190. \ 'end': 1,
  191. \ 'type': 'YcmErrorProperty',
  192. \ 'length': 0,
  193. \ 'start': 1 },
  194. \ { 'id': 2,
  195. \ 'col': 1,
  196. \ 'end': 1,
  197. \ 'type': 'YcmErrorProperty',
  198. \ 'length': 4,
  199. \ 'start': 1 },
  200. \ { 'id': 1,
  201. \ 'col': 1,
  202. \ 'end': 1,
  203. \ 'type': 'YcmErrorProperty',
  204. \ 'length': 4,
  205. \ 'start': 1 } ]
  206. call CheckListOfDicts( prop_list( 1 ), expected_properties )
  207. endfunction
  208. function! Test_ThirdPartyDeletesItsTextProperty()
  209. enew
  210. call prop_type_add( 'ThirdPartyProperty', { 'highlight': 'Error' } )
  211. call prop_add( 1, 1, { 'type': 'ThirdPartyProperty', 'bufnr': bufnr('%'), 'id': 42 } )
  212. call prop_type_delete( 'ThirdPartyProperty' )
  213. py3 from ycm.vimsupport import GetTextProperties, GetIntValue
  214. call assert_equal( [], py3eval( 'GetTextProperties( GetIntValue( """bufnr( "%" )""" ) )' ) )
  215. endfunction
  216. function! Test_ShowDetailedDiagnostic_CmdLine()
  217. call youcompleteme#test#setup#OpenFile(
  218. \ '/test/testdata/cpp/fixit.cpp', {} )
  219. call cursor( [ 3, 1 ] )
  220. redir => output
  221. YcmShowDetailedDiagnostic
  222. redir END
  223. call assert_equal(
  224. \ "Format specifies type 'char *' but the argument has type 'int' "
  225. \ . '(fix available)',
  226. \ trim( output ) )
  227. %bwipe!
  228. endfunction
  229. function! Test_ShowDetailedDiagnostic_PopupAtCursor()
  230. call youcompleteme#test#setup#OpenFile(
  231. \ '/test/testdata/cpp/fixit.cpp', {} )
  232. call cursor( [ 3, 1 ] )
  233. YcmShowDetailedDiagnostic popup
  234. let id = popup_locate( 4, 1 )
  235. call assert_notequal( 0, id, "Couldn't find popup!" )
  236. if exists( '*popup_list' )
  237. let popups = popup_list()
  238. call assert_equal( 1, len( popups ) )
  239. endif
  240. call youcompleteme#test#popup#CheckPopupPosition( id, {
  241. \ 'visible': 1,
  242. \ 'col': 1,
  243. \ 'line': 4,
  244. \ } )
  245. call assert_equal(
  246. \ [
  247. \ "Format specifies type 'char *' but the argument has type 'int' "
  248. \ . '(fix available)',
  249. \ ],
  250. \ getbufline( winbufnr(id), 1, '$' ) )
  251. " From vim's test_popupwin.vim
  252. " trigger the check for last_cursormoved by going into insert mode
  253. call test_override( 'char_avail', 1 )
  254. call feedkeys( "ji\<Esc>", 'xt' )
  255. call assert_equal( {}, popup_getpos( id ) )
  256. call test_override( 'ALL', 0 )
  257. %bwipe!
  258. endfunction
  259. function! Test_ShowDetailedDiagnostic_Popup_WithCharacters()
  260. let f = tempname() . '.cc'
  261. execut 'edit' f
  262. call setline( 1, [
  263. \ 'struct Foo {};',
  264. \ 'template<char...> Foo operator""_foo() { return {}; }',
  265. \ 'int main() {',
  266. \ '""_foo',
  267. \ '}',
  268. \ ] )
  269. call youcompleteme#test#setup#WaitForInitialParse( {} )
  270. call WaitForAssert( {->
  271. \ assert_true(
  272. \ py3eval(
  273. \ 'len( ycm_state.CurrentBuffer()._diag_interface._diagnostics )'
  274. \ ) ) } )
  275. call cursor( [ 4, 1 ] )
  276. YcmShowDetailedDiagnostic popup
  277. let id = popup_locate( 5, 1 )
  278. call assert_notequal( 0, id, "Couldn't find popup!" )
  279. if exists( '*popup_list' )
  280. let popups = popup_list()
  281. call assert_equal( 1, len( popups ) )
  282. endif
  283. call youcompleteme#test#popup#CheckPopupPosition( id, {
  284. \ 'visible': 1,
  285. \ 'col': 1,
  286. \ 'line': 5,
  287. \ } )
  288. call assert_match(
  289. \ "^No matching literal operator for call to 'operator\"\"_foo'.*",
  290. \ getbufline( winbufnr(id), 1, '$' )[ 0 ] )
  291. " From vim's test_popupwin.vim
  292. " trigger the check for last_cursormoved by going into insert mode
  293. call test_override( 'char_avail', 1 )
  294. call feedkeys( "ji\<Esc>", 'xt' )
  295. call assert_equal( {}, popup_getpos( id ) )
  296. call test_override( 'ALL', 0 )
  297. %bwipe!
  298. endfunction