event_notification_test.py 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603
  1. # coding: utf-8
  2. #
  3. # Copyright (C) 2015-2018 YouCompleteMe contributors
  4. #
  5. # This file is part of YouCompleteMe.
  6. #
  7. # YouCompleteMe is free software: you can redistribute it and/or modify
  8. # it under the terms of the GNU General Public License as published by
  9. # the Free Software Foundation, either version 3 of the License, or
  10. # (at your option) any later version.
  11. #
  12. # YouCompleteMe is distributed in the hope that it will be useful,
  13. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. # GNU General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU General Public License
  18. # along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>.
  19. from __future__ import unicode_literals
  20. from __future__ import print_function
  21. from __future__ import division
  22. from __future__ import absolute_import
  23. # Not installing aliases from python-future; it's unreliable and slow.
  24. from builtins import * # noqa
  25. from ycm.tests.test_utils import ( CurrentWorkingDirectory, ExtendedMock,
  26. MockVimBuffers, MockVimModule, VimBuffer,
  27. VimSign )
  28. MockVimModule()
  29. import contextlib
  30. import os
  31. from ycm.tests import ( PathToTestFile, test_utils, YouCompleteMeInstance,
  32. WaitUntilReady )
  33. from ycm.vimsupport import SIGN_BUFFER_ID_INITIAL_VALUE
  34. from ycmd.responses import ( BuildDiagnosticData, Diagnostic, Location, Range,
  35. UnknownExtraConf, ServerError )
  36. from hamcrest import ( assert_that, contains, empty, has_entries, has_entry,
  37. has_item, has_items, has_key, is_not )
  38. from mock import call, MagicMock, patch
  39. from nose.tools import eq_, ok_
  40. def PresentDialog_Confirm_Call( message ):
  41. """Return a mock.call object for a call to vimsupport.PresentDialog, as called
  42. why vimsupport.Confirm with the supplied confirmation message"""
  43. return call( message, [ 'Ok', 'Cancel' ] )
  44. @contextlib.contextmanager
  45. def MockArbitraryBuffer( filetype ):
  46. """Used via the with statement, set up a single buffer with an arbitrary name
  47. and no contents. Its filetype is set to the supplied filetype."""
  48. # Arbitrary, but valid, single buffer open.
  49. current_buffer = VimBuffer( os.path.realpath( 'TEST_BUFFER' ),
  50. filetype = filetype )
  51. with MockVimBuffers( [ current_buffer ], [ current_buffer ] ):
  52. yield
  53. @contextlib.contextmanager
  54. def MockEventNotification( response_method, native_filetype_completer = True ):
  55. """Mock out the EventNotification client request object, replacing the
  56. Response handler's JsonFromFuture with the supplied |response_method|.
  57. Additionally mock out YouCompleteMe's FiletypeCompleterExistsForFiletype
  58. method to return the supplied |native_filetype_completer| parameter, rather
  59. than querying the server"""
  60. # We don't want the event to actually be sent to the server, just have it
  61. # return success
  62. with patch( 'ycm.client.event_notification.EventNotification.'
  63. 'PostDataToHandlerAsync',
  64. return_value = MagicMock( return_value=True ) ):
  65. # We set up a fake a Response (as called by EventNotification.Response)
  66. # which calls the supplied callback method. Generally this callback just
  67. # raises an apropriate exception, otherwise it would have to return a mock
  68. # future object.
  69. with patch( 'ycm.client.base_request._JsonFromFuture',
  70. side_effect = response_method ):
  71. # Filetype available information comes from the server, so rather than
  72. # relying on that request, we mock out the check. The caller decides if
  73. # filetype completion is available
  74. with patch(
  75. 'ycm.youcompleteme.YouCompleteMe.FiletypeCompleterExistsForFiletype',
  76. return_value = native_filetype_completer ):
  77. yield
  78. @patch( 'ycm.vimsupport.PostVimMessage', new_callable = ExtendedMock )
  79. @YouCompleteMeInstance()
  80. def EventNotification_FileReadyToParse_NonDiagnostic_Error_test(
  81. ycm, post_vim_message ):
  82. # This test validates the behaviour of YouCompleteMe.HandleFileParseRequest
  83. # in combination with YouCompleteMe.OnFileReadyToParse when the completer
  84. # raises an exception handling FileReadyToParse event notification
  85. ERROR_TEXT = 'Some completer response text'
  86. def ErrorResponse( *args ):
  87. raise ServerError( ERROR_TEXT )
  88. with MockArbitraryBuffer( 'some_filetype' ):
  89. with MockEventNotification( ErrorResponse ):
  90. ycm.OnFileReadyToParse()
  91. ok_( ycm.FileParseRequestReady() )
  92. ycm.HandleFileParseRequest()
  93. # The first call raises a warning
  94. post_vim_message.assert_has_exact_calls( [
  95. call( ERROR_TEXT, truncate = True )
  96. ] )
  97. # Subsequent calls don't re-raise the warning
  98. ycm.HandleFileParseRequest()
  99. post_vim_message.assert_has_exact_calls( [
  100. call( ERROR_TEXT, truncate = True )
  101. ] )
  102. ok_( not ycm.ShouldResendFileParseRequest() )
  103. # But it does if a subsequent event raises again
  104. ycm.OnFileReadyToParse()
  105. ok_( ycm.FileParseRequestReady() )
  106. ycm.HandleFileParseRequest()
  107. post_vim_message.assert_has_exact_calls( [
  108. call( ERROR_TEXT, truncate = True ),
  109. call( ERROR_TEXT, truncate = True )
  110. ] )
  111. ok_( not ycm.ShouldResendFileParseRequest() )
  112. @YouCompleteMeInstance()
  113. def EventNotification_FileReadyToParse_NonDiagnostic_Error_NonNative_test(
  114. ycm ):
  115. test_utils.VIM_MATCHES = []
  116. test_utils.VIM_SIGNS = []
  117. with MockArbitraryBuffer( 'some_filetype' ):
  118. with MockEventNotification( None, False ):
  119. ycm.OnFileReadyToParse()
  120. ycm.HandleFileParseRequest()
  121. assert_that(
  122. test_utils.VIM_MATCHES,
  123. contains()
  124. )
  125. assert_that(
  126. test_utils.VIM_SIGNS,
  127. contains()
  128. )
  129. ok_( not ycm.ShouldResendFileParseRequest() )
  130. @YouCompleteMeInstance()
  131. def EventNotification_FileReadyToParse_NonDiagnostic_ConfirmExtraConf_test(
  132. ycm ):
  133. # This test validates the behaviour of YouCompleteMe.HandleFileParseRequest
  134. # in combination with YouCompleteMe.OnFileReadyToParse when the completer
  135. # raises the (special) UnknownExtraConf exception
  136. FILE_NAME = 'a_file'
  137. MESSAGE = ( 'Found ' + FILE_NAME + '. Load? \n\n(Question can be '
  138. 'turned off with options, see YCM docs)' )
  139. def UnknownExtraConfResponse( *args ):
  140. raise UnknownExtraConf( FILE_NAME )
  141. with patch( 'ycm.client.base_request.BaseRequest.PostDataToHandler',
  142. new_callable = ExtendedMock ) as post_data_to_handler:
  143. with MockArbitraryBuffer( 'some_filetype' ):
  144. with MockEventNotification( UnknownExtraConfResponse ):
  145. # When the user accepts the extra conf, we load it
  146. with patch( 'ycm.vimsupport.PresentDialog',
  147. return_value = 0,
  148. new_callable = ExtendedMock ) as present_dialog:
  149. ycm.OnFileReadyToParse()
  150. ok_( ycm.FileParseRequestReady() )
  151. ycm.HandleFileParseRequest()
  152. present_dialog.assert_has_exact_calls( [
  153. PresentDialog_Confirm_Call( MESSAGE ),
  154. ] )
  155. post_data_to_handler.assert_has_exact_calls( [
  156. call( { 'filepath': FILE_NAME }, 'load_extra_conf_file' )
  157. ] )
  158. # Subsequent calls don't re-raise the warning
  159. ycm.HandleFileParseRequest()
  160. present_dialog.assert_has_exact_calls( [
  161. PresentDialog_Confirm_Call( MESSAGE )
  162. ] )
  163. post_data_to_handler.assert_has_exact_calls( [
  164. call( { 'filepath': FILE_NAME }, 'load_extra_conf_file' )
  165. ] )
  166. ok_( ycm.ShouldResendFileParseRequest() )
  167. # But it does if a subsequent event raises again
  168. ycm.OnFileReadyToParse()
  169. ok_( ycm.FileParseRequestReady() )
  170. ycm.HandleFileParseRequest()
  171. present_dialog.assert_has_exact_calls( [
  172. PresentDialog_Confirm_Call( MESSAGE ),
  173. PresentDialog_Confirm_Call( MESSAGE ),
  174. ] )
  175. post_data_to_handler.assert_has_exact_calls( [
  176. call( { 'filepath': FILE_NAME }, 'load_extra_conf_file' ),
  177. call( { 'filepath': FILE_NAME }, 'load_extra_conf_file' )
  178. ] )
  179. ok_( ycm.ShouldResendFileParseRequest() )
  180. post_data_to_handler.reset_mock()
  181. # When the user rejects the extra conf, we reject it
  182. with patch( 'ycm.vimsupport.PresentDialog',
  183. return_value = 1,
  184. new_callable = ExtendedMock ) as present_dialog:
  185. ycm.OnFileReadyToParse()
  186. ok_( ycm.FileParseRequestReady() )
  187. ycm.HandleFileParseRequest()
  188. present_dialog.assert_has_exact_calls( [
  189. PresentDialog_Confirm_Call( MESSAGE ),
  190. ] )
  191. post_data_to_handler.assert_has_exact_calls( [
  192. call( { 'filepath': FILE_NAME }, 'ignore_extra_conf_file' )
  193. ] )
  194. # Subsequent calls don't re-raise the warning
  195. ycm.HandleFileParseRequest()
  196. present_dialog.assert_has_exact_calls( [
  197. PresentDialog_Confirm_Call( MESSAGE )
  198. ] )
  199. post_data_to_handler.assert_has_exact_calls( [
  200. call( { 'filepath': FILE_NAME }, 'ignore_extra_conf_file' )
  201. ] )
  202. ok_( ycm.ShouldResendFileParseRequest() )
  203. # But it does if a subsequent event raises again
  204. ycm.OnFileReadyToParse()
  205. ok_( ycm.FileParseRequestReady() )
  206. ycm.HandleFileParseRequest()
  207. present_dialog.assert_has_exact_calls( [
  208. PresentDialog_Confirm_Call( MESSAGE ),
  209. PresentDialog_Confirm_Call( MESSAGE ),
  210. ] )
  211. post_data_to_handler.assert_has_exact_calls( [
  212. call( { 'filepath': FILE_NAME }, 'ignore_extra_conf_file' ),
  213. call( { 'filepath': FILE_NAME }, 'ignore_extra_conf_file' )
  214. ] )
  215. ok_( ycm.ShouldResendFileParseRequest() )
  216. @YouCompleteMeInstance()
  217. def EventNotification_FileReadyToParse_Diagnostic_Error_Native_test( ycm ):
  218. test_utils.VIM_SIGNS = []
  219. _Check_FileReadyToParse_Diagnostic_Error( ycm )
  220. _Check_FileReadyToParse_Diagnostic_Warning( ycm )
  221. _Check_FileReadyToParse_Diagnostic_Clean( ycm )
  222. def _Check_FileReadyToParse_Diagnostic_Error( ycm ):
  223. # Tests Vim sign placement and error/warning count python API
  224. # when one error is returned.
  225. def DiagnosticResponse( *args ):
  226. start = Location( 1, 2, 'TEST_BUFFER' )
  227. end = Location( 1, 4, 'TEST_BUFFER' )
  228. extent = Range( start, end )
  229. diagnostic = Diagnostic( [], start, extent, 'expected ;', 'ERROR' )
  230. return [ BuildDiagnosticData( diagnostic ) ]
  231. with MockArbitraryBuffer( 'cpp' ):
  232. with MockEventNotification( DiagnosticResponse ):
  233. ycm.OnFileReadyToParse()
  234. ok_( ycm.FileParseRequestReady() )
  235. ycm.HandleFileParseRequest()
  236. assert_that(
  237. test_utils.VIM_SIGNS,
  238. contains(
  239. VimSign( SIGN_BUFFER_ID_INITIAL_VALUE, 1, 'YcmError', 1 )
  240. )
  241. )
  242. eq_( ycm.GetErrorCount(), 1 )
  243. eq_( ycm.GetWarningCount(), 0 )
  244. # Consequent calls to HandleFileParseRequest shouldn't mess with
  245. # existing diagnostics, when there is no new parse request.
  246. ycm.HandleFileParseRequest()
  247. assert_that(
  248. test_utils.VIM_SIGNS,
  249. contains(
  250. VimSign( SIGN_BUFFER_ID_INITIAL_VALUE, 1, 'YcmError', 1 )
  251. )
  252. )
  253. eq_( ycm.GetErrorCount(), 1 )
  254. eq_( ycm.GetWarningCount(), 0 )
  255. ok_( not ycm.ShouldResendFileParseRequest() )
  256. # New identical requests should result in the same diagnostics.
  257. ycm.OnFileReadyToParse()
  258. ok_( ycm.FileParseRequestReady() )
  259. ycm.HandleFileParseRequest()
  260. assert_that(
  261. test_utils.VIM_SIGNS,
  262. contains(
  263. VimSign( SIGN_BUFFER_ID_INITIAL_VALUE, 1, 'YcmError', 1 )
  264. )
  265. )
  266. eq_( ycm.GetErrorCount(), 1 )
  267. eq_( ycm.GetWarningCount(), 0 )
  268. ok_( not ycm.ShouldResendFileParseRequest() )
  269. def _Check_FileReadyToParse_Diagnostic_Warning( ycm ):
  270. # Tests Vim sign placement/unplacement and error/warning count python API
  271. # when one warning is returned.
  272. # Should be called after _Check_FileReadyToParse_Diagnostic_Error
  273. def DiagnosticResponse( *args ):
  274. start = Location( 2, 2, 'TEST_BUFFER' )
  275. end = Location( 2, 4, 'TEST_BUFFER' )
  276. extent = Range( start, end )
  277. diagnostic = Diagnostic( [], start, extent, 'cast', 'WARNING' )
  278. return [ BuildDiagnosticData( diagnostic ) ]
  279. with MockArbitraryBuffer( 'cpp' ):
  280. with MockEventNotification( DiagnosticResponse ):
  281. ycm.OnFileReadyToParse()
  282. ok_( ycm.FileParseRequestReady() )
  283. ycm.HandleFileParseRequest()
  284. assert_that(
  285. test_utils.VIM_SIGNS,
  286. contains(
  287. VimSign( SIGN_BUFFER_ID_INITIAL_VALUE + 2, 2, 'YcmWarning', 1 )
  288. )
  289. )
  290. eq_( ycm.GetErrorCount(), 0 )
  291. eq_( ycm.GetWarningCount(), 1 )
  292. # Consequent calls to HandleFileParseRequest shouldn't mess with
  293. # existing diagnostics, when there is no new parse request.
  294. ycm.HandleFileParseRequest()
  295. assert_that(
  296. test_utils.VIM_SIGNS,
  297. contains(
  298. VimSign( SIGN_BUFFER_ID_INITIAL_VALUE + 2, 2, 'YcmWarning', 1 )
  299. )
  300. )
  301. eq_( ycm.GetErrorCount(), 0 )
  302. eq_( ycm.GetWarningCount(), 1 )
  303. ok_( not ycm.ShouldResendFileParseRequest() )
  304. def _Check_FileReadyToParse_Diagnostic_Clean( ycm ):
  305. # Tests Vim sign unplacement and error/warning count python API
  306. # when there are no errors/warnings left.
  307. # Should be called after _Check_FileReadyToParse_Diagnostic_Warning
  308. with MockArbitraryBuffer( 'cpp' ):
  309. with MockEventNotification( MagicMock( return_value = [] ) ):
  310. ycm.OnFileReadyToParse()
  311. ycm.HandleFileParseRequest()
  312. assert_that(
  313. test_utils.VIM_SIGNS,
  314. empty()
  315. )
  316. eq_( ycm.GetErrorCount(), 0 )
  317. eq_( ycm.GetWarningCount(), 0 )
  318. ok_( not ycm.ShouldResendFileParseRequest() )
  319. @patch( 'ycm.youcompleteme.YouCompleteMe._AddUltiSnipsDataIfNeeded' )
  320. @YouCompleteMeInstance( { 'g:ycm_collect_identifiers_from_tags_files': 1 } )
  321. def EventNotification_FileReadyToParse_TagFiles_UnicodeWorkingDirectory_test(
  322. ycm, *args ):
  323. unicode_dir = PathToTestFile( 'uni¢𐍈d€' )
  324. current_buffer_file = PathToTestFile( 'uni¢𐍈d€', 'current_buffer' )
  325. current_buffer = VimBuffer( name = current_buffer_file,
  326. contents = [ 'current_buffer_contents' ],
  327. filetype = 'some_filetype' )
  328. with patch( 'ycm.client.event_notification.EventNotification.'
  329. 'PostDataToHandlerAsync' ) as post_data_to_handler_async:
  330. with CurrentWorkingDirectory( unicode_dir ):
  331. with MockVimBuffers( [ current_buffer ], [ current_buffer ], ( 1, 5 ) ):
  332. ycm.OnFileReadyToParse()
  333. assert_that(
  334. # Positional arguments passed to PostDataToHandlerAsync.
  335. post_data_to_handler_async.call_args[ 0 ],
  336. contains(
  337. has_entries( {
  338. 'filepath': current_buffer_file,
  339. 'line_num': 1,
  340. 'column_num': 6,
  341. 'file_data': has_entries( {
  342. current_buffer_file: has_entries( {
  343. 'contents': 'current_buffer_contents\n',
  344. 'filetypes': [ 'some_filetype' ]
  345. } )
  346. } ),
  347. 'event_name': 'FileReadyToParse',
  348. 'tag_files': has_item( PathToTestFile( 'uni¢𐍈d€', 'tags' ) )
  349. } ),
  350. 'event_notification'
  351. )
  352. )
  353. @patch( 'ycm.youcompleteme.YouCompleteMe._AddUltiSnipsDataIfNeeded' )
  354. @YouCompleteMeInstance()
  355. def EventNotification_BufferVisit_BuildRequestForCurrentAndUnsavedBuffers_test(
  356. ycm, *args ):
  357. current_buffer_file = os.path.realpath( 'current_buffer' )
  358. current_buffer = VimBuffer( name = current_buffer_file,
  359. number = 1,
  360. contents = [ 'current_buffer_contents' ],
  361. filetype = 'some_filetype',
  362. modified = False )
  363. modified_buffer_file = os.path.realpath( 'modified_buffer' )
  364. modified_buffer = VimBuffer( name = modified_buffer_file,
  365. number = 2,
  366. contents = [ 'modified_buffer_contents' ],
  367. filetype = 'some_filetype',
  368. modified = True )
  369. unmodified_buffer_file = os.path.realpath( 'unmodified_buffer' )
  370. unmodified_buffer = VimBuffer( name = unmodified_buffer_file,
  371. number = 3,
  372. contents = [ 'unmodified_buffer_contents' ],
  373. filetype = 'some_filetype',
  374. modified = False )
  375. with patch( 'ycm.client.event_notification.EventNotification.'
  376. 'PostDataToHandlerAsync' ) as post_data_to_handler_async:
  377. with MockVimBuffers( [ current_buffer, modified_buffer, unmodified_buffer ],
  378. [ current_buffer ],
  379. ( 1, 5 ) ):
  380. ycm.OnBufferVisit()
  381. assert_that(
  382. # Positional arguments passed to PostDataToHandlerAsync.
  383. post_data_to_handler_async.call_args[ 0 ],
  384. contains(
  385. has_entries( {
  386. 'filepath': current_buffer_file,
  387. 'line_num': 1,
  388. 'column_num': 6,
  389. 'file_data': has_entries( {
  390. current_buffer_file: has_entries( {
  391. 'contents': 'current_buffer_contents\n',
  392. 'filetypes': [ 'some_filetype' ]
  393. } ),
  394. modified_buffer_file: has_entries( {
  395. 'contents': 'modified_buffer_contents\n',
  396. 'filetypes': [ 'some_filetype' ]
  397. } )
  398. } ),
  399. 'event_name': 'BufferVisit'
  400. } ),
  401. 'event_notification'
  402. )
  403. )
  404. @YouCompleteMeInstance()
  405. def EventNotification_BufferUnload_BuildRequestForDeletedAndUnsavedBuffers_test(
  406. ycm ):
  407. current_buffer_file = os.path.realpath( 'current_βuffer' )
  408. current_buffer = VimBuffer( name = current_buffer_file,
  409. number = 1,
  410. contents = [ 'current_buffer_contents' ],
  411. filetype = 'some_filetype',
  412. modified = True )
  413. deleted_buffer_file = os.path.realpath( 'deleted_βuffer' )
  414. deleted_buffer = VimBuffer( name = deleted_buffer_file,
  415. number = 2,
  416. contents = [ 'deleted_buffer_contents' ],
  417. filetype = 'some_filetype',
  418. modified = False )
  419. with patch( 'ycm.client.event_notification.EventNotification.'
  420. 'PostDataToHandlerAsync' ) as post_data_to_handler_async:
  421. with MockVimBuffers( [ current_buffer, deleted_buffer ],
  422. [ current_buffer ] ):
  423. ycm.OnBufferUnload( deleted_buffer.number )
  424. assert_that(
  425. # Positional arguments passed to PostDataToHandlerAsync.
  426. post_data_to_handler_async.call_args[ 0 ],
  427. contains(
  428. has_entries( {
  429. 'filepath': deleted_buffer_file,
  430. 'line_num': 1,
  431. 'column_num': 1,
  432. 'file_data': has_entries( {
  433. current_buffer_file: has_entries( {
  434. 'contents': 'current_buffer_contents\n',
  435. 'filetypes': [ 'some_filetype' ]
  436. } ),
  437. deleted_buffer_file: has_entries( {
  438. 'contents': 'deleted_buffer_contents\n',
  439. 'filetypes': [ 'some_filetype' ]
  440. } )
  441. } ),
  442. 'event_name': 'BufferUnload'
  443. } ),
  444. 'event_notification'
  445. )
  446. )
  447. @patch( 'ycm.vimsupport.CaptureVimCommand', return_value = """
  448. fooGroup xxx foo bar
  449. links to Statement""" )
  450. @YouCompleteMeInstance( { 'g:ycm_seed_identifiers_with_syntax': 1 } )
  451. def EventNotification_FileReadyToParse_SyntaxKeywords_SeedWithCache_test(
  452. ycm, *args ):
  453. current_buffer = VimBuffer( name = 'current_buffer',
  454. filetype = 'some_filetype' )
  455. with patch( 'ycm.client.event_notification.EventNotification.'
  456. 'PostDataToHandlerAsync' ) as post_data_to_handler_async:
  457. with MockVimBuffers( [ current_buffer ], [ current_buffer ] ):
  458. ycm.OnFileReadyToParse()
  459. assert_that(
  460. # Positional arguments passed to PostDataToHandlerAsync.
  461. post_data_to_handler_async.call_args[ 0 ],
  462. contains(
  463. has_entry( 'syntax_keywords', has_items( 'foo', 'bar' ) ),
  464. 'event_notification'
  465. )
  466. )
  467. # Do not send again syntax keywords in subsequent requests.
  468. ycm.OnFileReadyToParse()
  469. assert_that(
  470. # Positional arguments passed to PostDataToHandlerAsync.
  471. post_data_to_handler_async.call_args[ 0 ],
  472. contains(
  473. is_not( has_key( 'syntax_keywords' ) ),
  474. 'event_notification'
  475. )
  476. )
  477. @patch( 'ycm.vimsupport.CaptureVimCommand', return_value = """
  478. fooGroup xxx foo bar
  479. links to Statement""" )
  480. @YouCompleteMeInstance( { 'g:ycm_seed_identifiers_with_syntax': 1 } )
  481. def EventNotification_FileReadyToParse_SyntaxKeywords_ClearCacheIfRestart_test(
  482. ycm, *args ):
  483. current_buffer = VimBuffer( name = 'current_buffer',
  484. filetype = 'some_filetype' )
  485. with patch( 'ycm.client.event_notification.EventNotification.'
  486. 'PostDataToHandlerAsync' ) as post_data_to_handler_async:
  487. with MockVimBuffers( [ current_buffer ], [ current_buffer ] ):
  488. ycm.OnFileReadyToParse()
  489. assert_that(
  490. # Positional arguments passed to PostDataToHandlerAsync.
  491. post_data_to_handler_async.call_args[ 0 ],
  492. contains(
  493. has_entry( 'syntax_keywords', has_items( 'foo', 'bar' ) ),
  494. 'event_notification'
  495. )
  496. )
  497. # Send again the syntax keywords after restarting the server.
  498. ycm.RestartServer()
  499. WaitUntilReady()
  500. ycm.OnFileReadyToParse()
  501. assert_that(
  502. # Positional arguments passed to PostDataToHandlerAsync.
  503. post_data_to_handler_async.call_args[ 0 ],
  504. contains(
  505. has_entry( 'syntax_keywords', has_items( 'foo', 'bar' ) ),
  506. 'event_notification'
  507. )
  508. )