1
0

postcomplete_test.py 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  1. # encoding: utf-8
  2. #
  3. # Copyright (C) 2015-2016 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 MockVimModule
  26. MockVimModule()
  27. import contextlib
  28. from hamcrest import assert_that, empty
  29. from mock import MagicMock, DEFAULT, patch
  30. from nose.tools import eq_, ok_
  31. from ycm import vimsupport
  32. from ycm.tests import YouCompleteMeInstance
  33. from ycmd.utils import ToBytes
  34. from ycm.youcompleteme import _CompleteDoneHook_CSharp
  35. from ycm.youcompleteme import _CompleteDoneHook_Java
  36. def CompleteItemIs( word, abbr = None, menu = None,
  37. info = None, kind = None, **kwargs ):
  38. item = {
  39. 'word': ToBytes( word ),
  40. 'abbr': ToBytes( abbr ),
  41. 'menu': ToBytes( menu ),
  42. 'info': ToBytes( info ),
  43. 'kind': ToBytes( kind ),
  44. }
  45. item.update( **kwargs )
  46. return item
  47. def GetVariableValue_CompleteItemIs( word, abbr = None, menu = None,
  48. info = None, kind = None, **kwargs ):
  49. def Result( variable ):
  50. if variable == 'v:completed_item':
  51. return CompleteItemIs( word, abbr, menu, info, kind, **kwargs )
  52. return DEFAULT
  53. return MagicMock( side_effect = Result )
  54. def BuildCompletion( insertion_text = 'Test',
  55. menu_text = None,
  56. extra_menu_info = None,
  57. detailed_info = None,
  58. kind = None,
  59. extra_data = None ):
  60. if extra_data is None:
  61. extra_data = {}
  62. return {
  63. 'extra_data': extra_data,
  64. 'insertion_text': insertion_text,
  65. 'menu_text': menu_text,
  66. 'extra_menu_info': extra_menu_info,
  67. 'kind': kind,
  68. 'detailed_info': detailed_info,
  69. }
  70. def BuildCompletionNamespace( namespace = None,
  71. insertion_text = 'Test',
  72. menu_text = None,
  73. extra_menu_info = None,
  74. detailed_info = None,
  75. kind = None ):
  76. return BuildCompletion( insertion_text = insertion_text,
  77. menu_text = menu_text,
  78. extra_menu_info = extra_menu_info,
  79. detailed_info = detailed_info,
  80. kind = kind,
  81. extra_data = {
  82. 'required_namespace_import': namespace
  83. } )
  84. def BuildCompletionFixIt( fixits,
  85. insertion_text = 'Test',
  86. menu_text = None,
  87. extra_menu_info = None,
  88. detailed_info = None,
  89. kind = None ):
  90. return BuildCompletion( insertion_text = insertion_text,
  91. menu_text = menu_text,
  92. extra_menu_info = extra_menu_info,
  93. detailed_info = detailed_info,
  94. kind = kind,
  95. extra_data = {
  96. 'fixits': fixits,
  97. } )
  98. @contextlib.contextmanager
  99. def _SetupForCsharpCompletionDone( ycm, completions ):
  100. with patch( 'ycm.vimsupport.InsertNamespace' ):
  101. with _SetUpCompleteDone( ycm, completions ):
  102. yield
  103. @contextlib.contextmanager
  104. def _SetUpCompleteDone( ycm, completions ):
  105. with patch( 'ycm.vimsupport.TextBeforeCursor', return_value = ' Test' ):
  106. request = MagicMock()
  107. request.Done = MagicMock( return_value = True )
  108. request.RawResponse = MagicMock( return_value = {
  109. 'completions': completions
  110. } )
  111. ycm._latest_completion_request = request
  112. yield
  113. @patch( 'ycm.vimsupport.CurrentFiletypes', return_value = [ 'cs' ] )
  114. @YouCompleteMeInstance()
  115. def GetCompleteDoneHooks_ResultOnCsharp_test( ycm, *args ):
  116. result = list( ycm.GetCompleteDoneHooks() )
  117. eq_( [ _CompleteDoneHook_CSharp ], result )
  118. @patch( 'ycm.vimsupport.CurrentFiletypes', return_value = [ 'java' ] )
  119. @YouCompleteMeInstance()
  120. def GetCompleteDoneHooks_ResultOnJava_test( ycm, *args ):
  121. result = list( ycm.GetCompleteDoneHooks() )
  122. eq_( [ _CompleteDoneHook_Java ], result )
  123. @patch( 'ycm.vimsupport.CurrentFiletypes', return_value = [ 'ycmtest' ] )
  124. @YouCompleteMeInstance()
  125. def GetCompleteDoneHooks_EmptyOnOtherFiletype_test( ycm, *args ):
  126. result = ycm.GetCompleteDoneHooks()
  127. eq_( 0, len( list( result ) ) )
  128. @patch( 'ycm.vimsupport.CurrentFiletypes', return_value = [ 'ycmtest' ] )
  129. @YouCompleteMeInstance()
  130. def OnCompleteDone_WithActionCallsIt_test( ycm, *args ):
  131. action = MagicMock()
  132. ycm._complete_done_hooks[ 'ycmtest' ] = action
  133. ycm.OnCompleteDone()
  134. ok_( action.called )
  135. @patch( 'ycm.vimsupport.CurrentFiletypes', return_value = [ 'ycmtest' ] )
  136. @YouCompleteMeInstance()
  137. def OnCompleteDone_NoActionNoError_test( ycm, *args ):
  138. with patch.object( ycm, '_OnCompleteDone_Csharp' ) as csharp:
  139. with patch.object( ycm, '_OnCompleteDone_Java' ) as java:
  140. ycm.OnCompleteDone()
  141. csharp.assert_not_called()
  142. java.assert_not_called()
  143. @YouCompleteMeInstance()
  144. def FilterToCompletedCompletions_MatchIsReturned_test( ycm, *args ):
  145. completions = [ BuildCompletion( insertion_text = 'Test' ) ]
  146. result = ycm._FilterToMatchingCompletions( CompleteItemIs( 'Test' ),
  147. completions,
  148. False )
  149. eq_( list( result ), completions )
  150. @YouCompleteMeInstance()
  151. def FilterToCompletedCompletions_ShortTextDoesntRaise_test( ycm, *args ):
  152. completions = [ BuildCompletion( insertion_text = 'AAA' ) ]
  153. ycm._FilterToMatchingCompletions( CompleteItemIs( 'A' ),
  154. completions,
  155. False )
  156. @YouCompleteMeInstance()
  157. def FilterToCompletedCompletions_ExactMatchIsReturned_test( ycm, *args ):
  158. completions = [ BuildCompletion( insertion_text = 'Test' ) ]
  159. result = ycm._FilterToMatchingCompletions( CompleteItemIs( 'Test' ),
  160. completions,
  161. False )
  162. eq_( list( result ), completions )
  163. @YouCompleteMeInstance()
  164. def FilterToCompletedCompletions_NonMatchIsntReturned_test( ycm, *args ):
  165. completions = [ BuildCompletion( insertion_text = 'A' ) ]
  166. result = ycm._FilterToMatchingCompletions( CompleteItemIs( ' Quote' ),
  167. completions,
  168. False )
  169. assert_that( list( result ), empty() )
  170. @YouCompleteMeInstance()
  171. def FilterToCompletedCompletions_Unicode_test( ycm, *args ):
  172. completions = [ BuildCompletion( insertion_text = '†es†' ) ]
  173. result = ycm._FilterToMatchingCompletions( CompleteItemIs( '†es†' ),
  174. completions,
  175. False )
  176. eq_( list( result ), completions )
  177. @patch( 'ycm.vimsupport.TextBeforeCursor', return_value = ' Quote' )
  178. @YouCompleteMeInstance()
  179. def HasCompletionsThatCouldBeCompletedWithMoreText_MatchIsReturned_test(
  180. ycm, *args ):
  181. completions = [ BuildCompletion( insertion_text = 'Test' ) ]
  182. result = ycm._HasCompletionsThatCouldBeCompletedWithMoreText(
  183. CompleteItemIs( 'Te' ),
  184. completions )
  185. eq_( result, True )
  186. @patch( 'ycm.vimsupport.TextBeforeCursor', return_value = ' Quote' )
  187. @YouCompleteMeInstance()
  188. def HasCompletionsThatCouldBeCompletedWithMoreText_ShortTextDoesntRaise_test(
  189. ycm, *args ):
  190. completions = [ BuildCompletion( insertion_text = 'AAA' ) ]
  191. ycm._HasCompletionsThatCouldBeCompletedWithMoreText( CompleteItemIs( 'X' ),
  192. completions )
  193. @patch( 'ycm.vimsupport.TextBeforeCursor', return_value = ' Quote' )
  194. @YouCompleteMeInstance()
  195. def HasCompletionsThatCouldBeCompletedWithMoreText_ExactMatchIsntReturned_test(
  196. ycm, *args ):
  197. completions = [ BuildCompletion( insertion_text = 'Test' ) ]
  198. result = ycm._HasCompletionsThatCouldBeCompletedWithMoreText(
  199. CompleteItemIs( 'Test' ),
  200. completions )
  201. eq_( result, False )
  202. @patch( 'ycm.vimsupport.TextBeforeCursor', return_value = ' Quote' )
  203. @YouCompleteMeInstance()
  204. def HasCompletionsThatCouldBeCompletedWithMoreText_NonMatchIsntReturned_test(
  205. ycm, *args ):
  206. completions = [ BuildCompletion( insertion_text = "A" ) ]
  207. result = ycm._HasCompletionsThatCouldBeCompletedWithMoreText(
  208. CompleteItemIs( ' Quote' ),
  209. completions )
  210. eq_( result, False )
  211. @patch( 'ycm.vimsupport.TextBeforeCursor', return_value = 'Uniç' )
  212. @YouCompleteMeInstance()
  213. def HasCompletionsThatCouldBeCompletedWithMoreText_Unicode_test(
  214. ycm, *args ):
  215. completions = [ BuildCompletion( insertion_text = 'Uniçø∂¢' ) ]
  216. result = ycm._HasCompletionsThatCouldBeCompletedWithMoreText(
  217. CompleteItemIs( 'Uniç' ),
  218. completions )
  219. eq_( result, True )
  220. @YouCompleteMeInstance()
  221. def GetRequiredNamespaceImport_ReturnNoneForNoExtraData_test( ycm ):
  222. eq_( None, ycm._GetRequiredNamespaceImport( {} ) )
  223. @YouCompleteMeInstance()
  224. def GetRequiredNamespaceImport_ReturnNamespaceFromExtraData_test( ycm ):
  225. namespace = 'A_NAMESPACE'
  226. eq_( namespace, ycm._GetRequiredNamespaceImport(
  227. BuildCompletionNamespace( namespace )
  228. ) )
  229. @YouCompleteMeInstance()
  230. def GetCompletionsUserMayHaveCompleted_ReturnEmptyIfNotDone_test( ycm ):
  231. with _SetupForCsharpCompletionDone( ycm, [] ):
  232. ycm._latest_completion_request.Done = MagicMock( return_value = False )
  233. eq_( [], ycm.GetCompletionsUserMayHaveCompleted() )
  234. @patch( 'ycm.vimsupport.GetVariableValue',
  235. GetVariableValue_CompleteItemIs( 'Te' ) )
  236. @YouCompleteMeInstance()
  237. def GetCompletionsUserMayHaveCompleted_ReturnEmptyIfPendingMatches_test(
  238. ycm, *args ):
  239. completions = [ BuildCompletionNamespace( None ) ]
  240. with _SetupForCsharpCompletionDone( ycm, completions ):
  241. eq_( [], ycm.GetCompletionsUserMayHaveCompleted() )
  242. @YouCompleteMeInstance()
  243. def GetCompletionsUserMayHaveCompleted_ReturnMatchIfExactMatches_test(
  244. ycm, *args ):
  245. info = [ 'NS', 'Test', 'Abbr', 'Menu', 'Info', 'Kind' ]
  246. completions = [ BuildCompletionNamespace( *info ) ]
  247. with _SetupForCsharpCompletionDone( ycm, completions ):
  248. with patch( 'ycm.vimsupport.GetVariableValue',
  249. GetVariableValue_CompleteItemIs( *info[ 1: ] ) ):
  250. eq_( completions, ycm.GetCompletionsUserMayHaveCompleted() )
  251. @YouCompleteMeInstance()
  252. def GetCompletionsUserMayHaveCompleted_ReturnMatchIfExactMatchesEvenIfPartial_test( # noqa
  253. ycm, *args ):
  254. info = [ 'NS', 'Test', 'Abbr', 'Menu', 'Info', 'Kind' ]
  255. completions = [ BuildCompletionNamespace( *info ),
  256. BuildCompletion( insertion_text = 'TestTest' ) ]
  257. with _SetupForCsharpCompletionDone( ycm, completions ):
  258. with patch( 'ycm.vimsupport.GetVariableValue',
  259. GetVariableValue_CompleteItemIs( *info[ 1: ] ) ):
  260. eq_( [ completions[ 0 ] ], ycm.GetCompletionsUserMayHaveCompleted() )
  261. @YouCompleteMeInstance()
  262. def GetCompletionsUserMayHaveCompleted_DontReturnMatchIfNoExactMatchesAndPartial_test( # noqa
  263. ycm, *args ):
  264. info = [ 'NS', 'Test', 'Abbr', 'Menu', 'Info', 'Kind' ]
  265. completions = [ BuildCompletion( insertion_text = info[ 0 ] ),
  266. BuildCompletion( insertion_text = 'TestTest' ) ]
  267. with _SetupForCsharpCompletionDone( ycm, completions ):
  268. with patch( 'ycm.vimsupport.GetVariableValue',
  269. GetVariableValue_CompleteItemIs( *info[ 1: ] ) ):
  270. eq_( [], ycm.GetCompletionsUserMayHaveCompleted() )
  271. @patch( 'ycm.vimsupport.GetVariableValue',
  272. GetVariableValue_CompleteItemIs( 'Test' ) )
  273. @YouCompleteMeInstance()
  274. def GetCompletionsUserMayHaveCompleted_ReturnMatchIfMatches_test( ycm, *args ):
  275. completions = [ BuildCompletionNamespace( None ) ]
  276. with _SetupForCsharpCompletionDone( ycm, completions ):
  277. eq_( completions, ycm.GetCompletionsUserMayHaveCompleted() )
  278. @patch( 'ycm.vimsupport.GetVariableValue',
  279. GetVariableValue_CompleteItemIs( 'Test', user_data='0' ) )
  280. @YouCompleteMeInstance()
  281. def GetCompletionsUserMayHaveCompleted_UseUserData0_test( ycm, *args ):
  282. # identical completions but we specify the first one via user_data
  283. completions = [
  284. BuildCompletionNamespace( 'namespace1' ),
  285. BuildCompletionNamespace( 'namespace2' )
  286. ]
  287. with _SetupForCsharpCompletionDone( ycm, completions ):
  288. eq_( [ BuildCompletionNamespace( 'namespace1' ) ],
  289. ycm.GetCompletionsUserMayHaveCompleted() )
  290. @patch( 'ycm.vimsupport.GetVariableValue',
  291. GetVariableValue_CompleteItemIs( 'Test', user_data='1' ) )
  292. @YouCompleteMeInstance()
  293. def GetCompletionsUserMayHaveCompleted_UseUserData1_test( ycm, *args ):
  294. # identical completions but we specify the second one via user_data
  295. completions = [
  296. BuildCompletionNamespace( 'namespace1' ),
  297. BuildCompletionNamespace( 'namespace2' )
  298. ]
  299. with _SetupForCsharpCompletionDone( ycm, completions ):
  300. eq_( [ BuildCompletionNamespace( 'namespace2' ) ],
  301. ycm.GetCompletionsUserMayHaveCompleted() )
  302. @patch( 'ycm.vimsupport.GetVariableValue',
  303. GetVariableValue_CompleteItemIs( 'Test' ) )
  304. @YouCompleteMeInstance()
  305. def PostCompleteCsharp_EmptyDoesntInsertNamespace_test( ycm, *args ):
  306. with _SetupForCsharpCompletionDone( ycm, [] ):
  307. ycm._OnCompleteDone_Csharp()
  308. ok_( not vimsupport.InsertNamespace.called )
  309. @patch( 'ycm.vimsupport.GetVariableValue',
  310. GetVariableValue_CompleteItemIs( 'Test' ) )
  311. @YouCompleteMeInstance()
  312. def PostCompleteCsharp_ExistingWithoutNamespaceDoesntInsertNamespace_test(
  313. ycm, *args ):
  314. completions = [ BuildCompletionNamespace( None ) ]
  315. with _SetupForCsharpCompletionDone( ycm, completions ):
  316. ycm._OnCompleteDone_Csharp()
  317. ok_( not vimsupport.InsertNamespace.called )
  318. @patch( 'ycm.vimsupport.GetVariableValue',
  319. GetVariableValue_CompleteItemIs( 'Test' ) )
  320. @YouCompleteMeInstance()
  321. def PostCompleteCsharp_ValueDoesInsertNamespace_test( ycm, *args ):
  322. namespace = 'A_NAMESPACE'
  323. completions = [ BuildCompletionNamespace( namespace ) ]
  324. with _SetupForCsharpCompletionDone( ycm, completions ):
  325. ycm._OnCompleteDone_Csharp()
  326. vimsupport.InsertNamespace.assert_called_once_with( namespace )
  327. @patch( 'ycm.vimsupport.GetVariableValue',
  328. GetVariableValue_CompleteItemIs( 'Test' ) )
  329. @patch( 'ycm.vimsupport.PresentDialog', return_value = 1 )
  330. @YouCompleteMeInstance()
  331. def PostCompleteCsharp_InsertSecondNamespaceIfSelected_test( ycm, *args ):
  332. namespace = 'A_NAMESPACE'
  333. namespace2 = 'ANOTHER_NAMESPACE'
  334. completions = [
  335. BuildCompletionNamespace( namespace ),
  336. BuildCompletionNamespace( namespace2 ),
  337. ]
  338. with _SetupForCsharpCompletionDone( ycm, completions ):
  339. ycm._OnCompleteDone_Csharp()
  340. vimsupport.InsertNamespace.assert_called_once_with( namespace2 )
  341. @patch( 'ycm.vimsupport.GetVariableValue',
  342. GetVariableValue_CompleteItemIs( 'Test' ) )
  343. @patch( 'ycm.vimsupport.ReplaceChunks' )
  344. @YouCompleteMeInstance()
  345. def PostCompleteJava_ApplyFixIt_NoFixIts_test( ycm, replace_chunks, *args ):
  346. completions = [
  347. BuildCompletionFixIt( [] )
  348. ]
  349. with _SetUpCompleteDone( ycm, completions ):
  350. ycm._OnCompleteDone_Java()
  351. replace_chunks.assert_not_called()
  352. @patch( 'ycm.vimsupport.GetVariableValue',
  353. GetVariableValue_CompleteItemIs( 'Test' ) )
  354. @patch( 'ycm.vimsupport.ReplaceChunks' )
  355. @YouCompleteMeInstance()
  356. def PostCompleteJava_ApplyFixIt_EmptyFixIt_test( ycm, replace_chunks, *args ):
  357. completions = [
  358. BuildCompletionFixIt( [ { 'chunks': [] } ] )
  359. ]
  360. with _SetUpCompleteDone( ycm, completions ):
  361. ycm._OnCompleteDone_Java()
  362. replace_chunks.assert_called_once_with( [], silent=True )
  363. @patch( 'ycm.vimsupport.GetVariableValue',
  364. GetVariableValue_CompleteItemIs( 'Test' ) )
  365. @patch( 'ycm.vimsupport.ReplaceChunks' )
  366. @YouCompleteMeInstance()
  367. def PostCompleteJava_ApplyFixIt_NoFixIt_test( ycm, replace_chunks, *args ):
  368. completions = [
  369. BuildCompletion( )
  370. ]
  371. with _SetUpCompleteDone( ycm, completions ):
  372. ycm._OnCompleteDone_Java()
  373. replace_chunks.assert_not_called()
  374. @patch( 'ycm.vimsupport.GetVariableValue',
  375. GetVariableValue_CompleteItemIs( 'Test' ) )
  376. @patch( 'ycm.vimsupport.ReplaceChunks' )
  377. @YouCompleteMeInstance()
  378. def PostCompleteJava_ApplyFixIt_PickFirst_test( ycm, replace_chunks, *args ):
  379. completions = [
  380. BuildCompletionFixIt( [ { 'chunks': 'one' } ] ),
  381. BuildCompletionFixIt( [ { 'chunks': 'two' } ] ),
  382. ]
  383. with _SetUpCompleteDone( ycm, completions ):
  384. ycm._OnCompleteDone_Java()
  385. replace_chunks.assert_called_once_with( 'one', silent=True )
  386. @patch( 'ycm.vimsupport.GetVariableValue',
  387. GetVariableValue_CompleteItemIs( 'Test', user_data='0' ) )
  388. @patch( 'ycm.vimsupport.ReplaceChunks' )
  389. @YouCompleteMeInstance()
  390. def PostCompleteJava_ApplyFixIt_PickFirstUserData_test( ycm,
  391. replace_chunks,
  392. *args ):
  393. completions = [
  394. BuildCompletionFixIt( [ { 'chunks': 'one' } ] ),
  395. BuildCompletionFixIt( [ { 'chunks': 'two' } ] ),
  396. ]
  397. with _SetUpCompleteDone( ycm, completions ):
  398. ycm._OnCompleteDone_Java()
  399. replace_chunks.assert_called_once_with( 'one', silent=True )
  400. @patch( 'ycm.vimsupport.GetVariableValue',
  401. GetVariableValue_CompleteItemIs( 'Test', user_data='1' ) )
  402. @patch( 'ycm.vimsupport.ReplaceChunks' )
  403. @YouCompleteMeInstance()
  404. def PostCompleteJava_ApplyFixIt_PickSecond_test( ycm, replace_chunks, *args ):
  405. completions = [
  406. BuildCompletionFixIt( [ { 'chunks': 'one' } ] ),
  407. BuildCompletionFixIt( [ { 'chunks': 'two' } ] ),
  408. ]
  409. with _SetUpCompleteDone( ycm, completions ):
  410. ycm._OnCompleteDone_Java()
  411. replace_chunks.assert_called_once_with( 'two', silent=True )