瀏覽代碼

Add tests for current directory

micbou 8 年之前
父節點
當前提交
3109c9d8a4

+ 6 - 0
python/ycm/tests/__init__.py

@@ -27,6 +27,7 @@ from ycm.tests.test_utils import MockVimModule
 MockVimModule()
 MockVimModule()
 
 
 import functools
 import functools
+import os
 import requests
 import requests
 import time
 import time
 
 
@@ -48,6 +49,11 @@ DEFAULT_CLIENT_OPTIONS = {
 }
 }
 
 
 
 
+def PathToTestFile( *args ):
+  dir_of_current_script = os.path.dirname( os.path.abspath( __file__ ) )
+  return os.path.join( dir_of_current_script, 'testdata', *args )
+
+
 def _MakeUserOptions( custom_options = {} ):
 def _MakeUserOptions( custom_options = {} ):
   options = dict( user_options_store.DefaultOptions() )
   options = dict( user_options_store.DefaultOptions() )
   options.update( DEFAULT_CLIENT_OPTIONS )
   options.update( DEFAULT_CLIENT_OPTIONS )

+ 54 - 0
python/ycm/tests/completion_test.py

@@ -0,0 +1,54 @@
+# coding: utf-8
+#
+# Copyright (C) 2016 YouCompleteMe contributors
+#
+# This file is part of YouCompleteMe.
+#
+# YouCompleteMe is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# YouCompleteMe is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with YouCompleteMe.  If not, see <http://www.gnu.org/licenses/>.
+
+from __future__ import unicode_literals
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+from future import standard_library
+standard_library.install_aliases()
+from builtins import *  # noqa
+
+from ycm.tests.test_utils import ( CurrentWorkingDirectory, MockVimModule,
+                                   MockVimBuffers, VimBuffer )
+MockVimModule()
+
+from hamcrest import assert_that, empty, has_entries
+
+from ycm.tests import PathToTestFile, YouCompleteMeInstance
+
+
+@YouCompleteMeInstance()
+def CreateCompletionRequest_UnicodeWorkingDirectory_test( ycm ):
+  unicode_dir = PathToTestFile( 'uni¢𐍈d€' )
+  current_buffer = VimBuffer( PathToTestFile( 'uni¢𐍈d€', 'current_buffer' ) )
+
+  with CurrentWorkingDirectory( unicode_dir ):
+    with MockVimBuffers( [ current_buffer ], current_buffer, ( 5, 2 ) ):
+      ycm.CreateCompletionRequest(),
+
+    results = ycm.GetCompletions()
+
+  assert_that(
+    results,
+    has_entries( {
+      'words': empty(),
+      'refresh': 'always'
+    } )
+  )

+ 55 - 23
python/ycm/tests/event_notification_test.py

@@ -1,3 +1,5 @@
+# coding: utf-8
+#
 # Copyright (C) 2015-2016 YouCompleteMe contributors
 # Copyright (C) 2015-2016 YouCompleteMe contributors
 #
 #
 # This file is part of YouCompleteMe.
 # This file is part of YouCompleteMe.
@@ -23,17 +25,18 @@ from future import standard_library
 standard_library.install_aliases()
 standard_library.install_aliases()
 from builtins import *  # noqa
 from builtins import *  # noqa
 
 
-from ycm.tests.test_utils import ExtendedMock, MockVimModule, VimBuffer
+from ycm.tests.test_utils import ( CurrentWorkingDirectory, ExtendedMock,
+                                   MockVimBuffers, MockVimModule, VimBuffer )
 MockVimModule()
 MockVimModule()
 
 
 import contextlib
 import contextlib
 import os
 import os
 
 
-from ycm.tests import YouCompleteMeInstance
+from ycm.tests import PathToTestFile, YouCompleteMeInstance
 from ycmd.responses import ( BuildDiagnosticData, Diagnostic, Location, Range,
 from ycmd.responses import ( BuildDiagnosticData, Diagnostic, Location, Range,
                              UnknownExtraConf, ServerError )
                              UnknownExtraConf, ServerError )
 
 
-from hamcrest import assert_that, contains, has_entries
+from hamcrest import assert_that, contains, has_entries, has_item
 from mock import call, MagicMock, patch
 from mock import call, MagicMock, patch
 from nose.tools import eq_, ok_
 from nose.tools import eq_, ok_
 
 
@@ -56,23 +59,17 @@ def UnplaceSign_Call( sign_id, buffer_num ):
 
 
 
 
 @contextlib.contextmanager
 @contextlib.contextmanager
-def MockArbitraryBuffer( filetype, native_available = True ):
-  """Used via the with statement, set up mocked versions of the vim module such
-  that a single buffer is open with an arbitrary name and arbirary contents. Its
-  filetype is set to the supplied filetype"""
+def MockArbitraryBuffer( filetype ):
+  """Used via the with statement, set up a single buffer with an arbitrary name
+  and no contents. Its filetype is set to the supplied filetype."""
 
 
   # Arbitrary, but valid, single buffer open.
   # Arbitrary, but valid, single buffer open.
   current_buffer = VimBuffer( os.path.realpath( 'TEST_BUFFER' ),
   current_buffer = VimBuffer( os.path.realpath( 'TEST_BUFFER' ),
                               window = 1,
                               window = 1,
                               filetype = filetype )
                               filetype = filetype )
 
 
-  # The rest just mock up the Vim module so that our single arbitrary buffer
-  # makes sense to vimsupport module.
-  with patch( 'vim.buffers', [ current_buffer ] ):
-    with patch( 'vim.current.buffer', current_buffer ):
-      # Arbitrary but valid cursor position.
-      with patch( 'vim.current.window.cursor', ( 1, 2 ) ):
-        yield
+  with MockVimBuffers( [ current_buffer ], current_buffer ):
+    yield
 
 
 
 
 @contextlib.contextmanager
 @contextlib.contextmanager
@@ -352,6 +349,44 @@ def _Check_FileReadyToParse_Diagnostic_Clean( ycm, vim_command ):
       eq_( ycm.GetWarningCount(), 0 )
       eq_( ycm.GetWarningCount(), 0 )
 
 
 
 
+@patch( 'ycm.youcompleteme.YouCompleteMe._AddUltiSnipsDataIfNeeded' )
+@YouCompleteMeInstance( { 'collect_identifiers_from_tags_files': 1 } )
+def EventNotification_FileReadyToParse_TagFiles_UnicodeWorkingDirectory_test(
+    ycm, *args ):
+  unicode_dir = PathToTestFile( 'uni¢𐍈d€' )
+  current_buffer_file = PathToTestFile( 'uni¢𐍈d€', 'current_buffer' )
+  current_buffer = VimBuffer( name = current_buffer_file,
+                              contents = [ 'current_buffer_contents' ],
+                              filetype = 'some_filetype' )
+
+  with patch( 'ycm.client.base_request.BaseRequest.'
+              'PostDataToHandlerAsync' ) as post_data_to_handler_async:
+    with CurrentWorkingDirectory( unicode_dir ):
+      with MockVimBuffers( [ current_buffer ], current_buffer, ( 6, 5 ) ):
+        ycm.OnFileReadyToParse()
+
+    assert_that(
+      # Positional arguments passed to PostDataToHandlerAsync.
+      post_data_to_handler_async.call_args[ 0 ],
+      contains(
+        has_entries( {
+          'filepath': current_buffer_file,
+          'line_num': 6,
+          'column_num': 6,
+          'file_data': has_entries( {
+            current_buffer_file: has_entries( {
+              'contents': 'current_buffer_contents\n',
+              'filetypes': [ 'some_filetype' ]
+            } )
+          } ),
+          'event_name': 'FileReadyToParse',
+          'tag_files': has_item( PathToTestFile( 'uni¢𐍈d€', 'tags' ) )
+        } ),
+        'event_notification'
+      )
+    )
+
+
 @patch( 'ycm.youcompleteme.YouCompleteMe._AddUltiSnipsDataIfNeeded' )
 @patch( 'ycm.youcompleteme.YouCompleteMe._AddUltiSnipsDataIfNeeded' )
 @YouCompleteMeInstance()
 @YouCompleteMeInstance()
 def EventNotification_BufferVisit_BuildRequestForCurrentAndUnsavedBuffers_test(
 def EventNotification_BufferVisit_BuildRequestForCurrentAndUnsavedBuffers_test(
@@ -380,12 +415,10 @@ def EventNotification_BufferVisit_BuildRequestForCurrentAndUnsavedBuffers_test(
 
 
   with patch( 'ycm.client.base_request.BaseRequest.'
   with patch( 'ycm.client.base_request.BaseRequest.'
               'PostDataToHandlerAsync' ) as post_data_to_handler_async:
               'PostDataToHandlerAsync' ) as post_data_to_handler_async:
-    with patch( 'vim.buffers', [ current_buffer,
-                                 modified_buffer,
-                                 unmodified_buffer ] ):
-      with patch( 'vim.current.buffer', current_buffer ):
-        with patch( 'vim.current.window.cursor', ( 3, 5 ) ):
-          ycm.OnBufferVisit()
+    with MockVimBuffers( [ current_buffer, modified_buffer, unmodified_buffer ],
+                         current_buffer,
+                         ( 3, 5 ) ):
+      ycm.OnBufferVisit()
 
 
     assert_that(
     assert_that(
       # Positional arguments passed to PostDataToHandlerAsync.
       # Positional arguments passed to PostDataToHandlerAsync.
@@ -431,9 +464,8 @@ def EventNotification_BufferUnload_BuildRequestForDeletedAndUnsavedBuffers_test(
 
 
   with patch( 'ycm.client.base_request.BaseRequest.'
   with patch( 'ycm.client.base_request.BaseRequest.'
               'PostDataToHandlerAsync' ) as post_data_to_handler_async:
               'PostDataToHandlerAsync' ) as post_data_to_handler_async:
-    with patch( 'vim.buffers', [ current_buffer, deleted_buffer ] ):
-      with patch( 'vim.current.buffer', current_buffer ):
-        ycm.OnBufferUnload( deleted_buffer_file )
+    with MockVimBuffers( [ current_buffer, deleted_buffer ], current_buffer ):
+      ycm.OnBufferUnload( deleted_buffer_file )
 
 
   assert_that(
   assert_that(
     # Positional arguments passed to PostDataToHandlerAsync.
     # Positional arguments passed to PostDataToHandlerAsync.

+ 84 - 28
python/ycm/tests/test_utils.py

@@ -24,12 +24,14 @@ from future import standard_library
 standard_library.install_aliases()
 standard_library.install_aliases()
 from builtins import *  # noqa
 from builtins import *  # noqa
 
 
-from mock import MagicMock
+from mock import MagicMock, patch
 from hamcrest import assert_that, equal_to
 from hamcrest import assert_that, equal_to
+import contextlib
+import functools
+import nose
+import os
 import re
 import re
 import sys
 import sys
-import nose
-import functools
 
 
 from ycmd.utils import ToUnicode
 from ycmd.utils import ToUnicode
 
 
@@ -52,21 +54,31 @@ GETBUFVAR_REGEX = re.compile(
 VIM_MOCK = MagicMock()
 VIM_MOCK = MagicMock()
 
 
 
 
-def MockGetBufferNumber( buffer_filename ):
+@contextlib.contextmanager
+def CurrentWorkingDirectory( path ):
+  old_cwd = os.getcwd()
+  os.chdir( path )
+  try:
+    yield
+  finally:
+    os.chdir( old_cwd )
+
+
+def _MockGetBufferNumber( buffer_filename ):
   for vim_buffer in VIM_MOCK.buffers:
   for vim_buffer in VIM_MOCK.buffers:
     if vim_buffer.name == buffer_filename:
     if vim_buffer.name == buffer_filename:
       return vim_buffer.number
       return vim_buffer.number
   return -1
   return -1
 
 
 
 
-def MockGetBufferWindowNumber( buffer_number ):
+def _MockGetBufferWindowNumber( buffer_number ):
   for vim_buffer in VIM_MOCK.buffers:
   for vim_buffer in VIM_MOCK.buffers:
     if vim_buffer.number == buffer_number and vim_buffer.window:
     if vim_buffer.number == buffer_number and vim_buffer.window:
       return vim_buffer.window
       return vim_buffer.window
   return -1
   return -1
 
 
 
 
-def MockGetBufferVariable( buffer_number, option ):
+def _MockGetBufferVariable( buffer_number, option ):
   for vim_buffer in VIM_MOCK.buffers:
   for vim_buffer in VIM_MOCK.buffers:
     if vim_buffer.number == buffer_number:
     if vim_buffer.number == buffer_number:
       if option == 'mod':
       if option == 'mod':
@@ -77,20 +89,7 @@ def MockGetBufferVariable( buffer_number, option ):
   return ''
   return ''
 
 
 
 
-def MockVimEval( value ):
-  if value == 'g:ycm_min_num_of_chars_for_completion':
-    return 0
-
-  if value == 'g:ycm_server_python_interpreter':
-    return ''
-
-  if value == 'tempname()':
-    return '_TEMP_FILE_'
-
-  if value == '&previewheight':
-    # Default value from Vim
-    return 12
-
+def _MockVimBufferEval( value ):
   if value == '&omnifunc':
   if value == '&omnifunc':
     return VIM_MOCK.current.buffer.omnifunc
     return VIM_MOCK.current.buffer.omnifunc
 
 
@@ -100,23 +99,66 @@ def MockVimEval( value ):
   match = BUFNR_REGEX.search( value )
   match = BUFNR_REGEX.search( value )
   if match:
   if match:
     buffer_filename = match.group( 'buffer_filename' )
     buffer_filename = match.group( 'buffer_filename' )
-    return MockGetBufferNumber( buffer_filename )
+    return _MockGetBufferNumber( buffer_filename )
 
 
   match = BUFWINNR_REGEX.search( value )
   match = BUFWINNR_REGEX.search( value )
   if match:
   if match:
     buffer_number = int( match.group( 'buffer_number' ) )
     buffer_number = int( match.group( 'buffer_number' ) )
-    return MockGetBufferWindowNumber( buffer_number )
+    return _MockGetBufferWindowNumber( buffer_number )
 
 
   match = GETBUFVAR_REGEX.search( value )
   match = GETBUFVAR_REGEX.search( value )
   if match:
   if match:
     buffer_number = int( match.group( 'buffer_number' ) )
     buffer_number = int( match.group( 'buffer_number' ) )
     option = match.group( 'option' )
     option = match.group( 'option' )
-    return MockGetBufferVariable( buffer_number, option )
+    return _MockGetBufferVariable( buffer_number, option )
+
+  return None
+
+
+def _MockVimOptionsEval( value ):
+  if value == '&previewheight':
+    return 12
+
+  if value == '&columns':
+    return 80
+
+  if value == '&ruler':
+    return 0
+
+  if value == '&showcmd':
+    return 1
+
+  return None
+
+
+def _MockVimEval( value ):
+  if value == 'g:ycm_min_num_of_chars_for_completion':
+    return 0
+
+  if value == 'g:ycm_server_python_interpreter':
+    return ''
+
+  if value == 'tempname()':
+    return '_TEMP_FILE_'
+
+  if value == 'complete_check()':
+    return 0
+
+  if value == 'tagfiles()':
+    return [ 'tags' ]
+
+  result = _MockVimOptionsEval( value )
+  if result is not None:
+    return result
+
+  result = _MockVimBufferEval( value )
+  if result is not None:
+    return result
 
 
   raise ValueError( 'Unexpected evaluation: {0}'.format( value ) )
   raise ValueError( 'Unexpected evaluation: {0}'.format( value ) )
 
 
 
 
-def MockWipeoutBuffer( buffer_number ):
+def _MockWipeoutBuffer( buffer_number ):
   buffers = VIM_MOCK.buffers
   buffers = VIM_MOCK.buffers
 
 
   for index, buffer in enumerate( buffers ):
   for index, buffer in enumerate( buffers ):
@@ -127,7 +169,7 @@ def MockWipeoutBuffer( buffer_number ):
 def MockVimCommand( command ):
 def MockVimCommand( command ):
   match = BWIPEOUT_REGEX.search( command )
   match = BWIPEOUT_REGEX.search( command )
   if match:
   if match:
-    return MockWipeoutBuffer( int( match.group( 1 ) ) )
+    return _MockWipeoutBuffer( int( match.group( 1 ) ) )
 
 
   raise RuntimeError( 'Unexpected command: ' + command )
   raise RuntimeError( 'Unexpected command: ' + command )
 
 
@@ -159,7 +201,7 @@ class VimBuffer( object ):
 
 
 
 
   def __getitem__( self, index ):
   def __getitem__( self, index ):
-    """Return the bytes for a given line at index |index|."""
+    """Returns the bytes for a given line at index |index|."""
     return self.contents[ index ]
     return self.contents[ index ]
 
 
 
 
@@ -172,10 +214,24 @@ class VimBuffer( object ):
 
 
 
 
   def GetLines( self ):
   def GetLines( self ):
-    """Return the contents of the buffer as a list of unicode strings."""
+    """Returns the contents of the buffer as a list of unicode strings."""
     return [ ToUnicode( x ) for x in self.contents ]
     return [ ToUnicode( x ) for x in self.contents ]
 
 
 
 
+@contextlib.contextmanager
+def MockVimBuffers( buffers, current_buffer, cursor_position = ( 1, 1 ) ):
+  """Simulates the Vim buffers list |buffers| where |current_buffer| is the
+  buffer displayed in the current window and |cursor_position| is the current
+  cursor position. All buffers are represented by a VimBuffer object."""
+  if current_buffer not in buffers:
+    raise RuntimeError( 'Current buffer must be part of the buffers list.' )
+
+  with patch( 'vim.buffers', buffers ):
+    with patch( 'vim.current.buffer', current_buffer ):
+      with patch( 'vim.current.window.cursor', cursor_position ):
+        yield
+
+
 def MockVimModule():
 def MockVimModule():
   """The 'vim' module is something that is only present when running inside the
   """The 'vim' module is something that is only present when running inside the
   Vim Python interpreter, so we replace it with a MagicMock for tests. If you
   Vim Python interpreter, so we replace it with a MagicMock for tests. If you
@@ -199,7 +255,7 @@ def MockVimModule():
   tests."""
   tests."""
 
 
   VIM_MOCK.buffers = {}
   VIM_MOCK.buffers = {}
-  VIM_MOCK.eval = MagicMock( side_effect = MockVimEval )
+  VIM_MOCK.eval = MagicMock( side_effect = _MockVimEval )
   sys.modules[ 'vim' ] = VIM_MOCK
   sys.modules[ 'vim' ] = VIM_MOCK
 
 
   return VIM_MOCK
   return VIM_MOCK

+ 0 - 0
python/ycm/tests/testdata/uni¢𐍈d€/tags


+ 12 - 3
python/ycm/tests/vimsupport_test.py

@@ -25,13 +25,14 @@ from future import standard_library
 standard_library.install_aliases()
 standard_library.install_aliases()
 from builtins import *  # noqa
 from builtins import *  # noqa
 
 
-from ycm.tests.test_utils import ( ExtendedMock, MockVimCommand, VimBuffer,
-                                   MockVimModule )
+from ycm.tests import PathToTestFile
+from ycm.tests.test_utils import ( CurrentWorkingDirectory, ExtendedMock,
+                                   MockVimCommand, MockVimModule, VimBuffer )
 MockVimModule()
 MockVimModule()
 
 
 from ycm import vimsupport
 from ycm import vimsupport
 from nose.tools import eq_
 from nose.tools import eq_
-from hamcrest import assert_that, calling, raises, none, has_entry
+from hamcrest import assert_that, calling, equal_to, has_entry, none, raises
 from mock import MagicMock, call, patch
 from mock import MagicMock, call, patch
 from ycmd.utils import ToBytes
 from ycmd.utils import ToBytes
 import os
 import os
@@ -1418,6 +1419,14 @@ def GetUnsavedAndSpecifiedBufferData_EncodedUnicodeCharsInBuffers_test():
                             has_entry( u'contents', u'abc\nfДa\n' ) ) )
                             has_entry( u'contents', u'abc\nfДa\n' ) ) )
 
 
 
 
+def GetBufferFilepath_NoBufferName_UnicodeWorkingDirectory_test():
+  vim_buffer = VimBuffer( '', number = 42 )
+  unicode_dir = PathToTestFile( u'uni¢𐍈d€' )
+  with CurrentWorkingDirectory( unicode_dir ):
+    assert_that( vimsupport.GetBufferFilepath( vim_buffer ),
+                 equal_to( os.path.join( unicode_dir, '42' ) ) )
+
+
 # NOTE: Vim returns byte offsets for columns, not actual character columns. This
 # NOTE: Vim returns byte offsets for columns, not actual character columns. This
 # makes 'ДД' have 4 columns: column 0, column 2 and column 4.
 # makes 'ДД' have 4 columns: column 0, column 2 and column 4.
 @patch( 'vim.current.line', ToBytes( 'ДДaa' ) )
 @patch( 'vim.current.line', ToBytes( 'ДДaa' ) )