diff --git a/python/ycm/tests/test_utils.py b/python/ycm/tests/test_utils.py index 0734cdc4..1f076d05 100644 --- a/python/ycm/tests/test_utils.py +++ b/python/ycm/tests/test_utils.py @@ -34,7 +34,12 @@ import os import re import sys -from ycmd.utils import GetCurrentDirectory, ToBytes, ToUnicode +try: + from unittest import skipIf +except ImportError: + from unittest2 import skipIf + +from ycmd.utils import GetCurrentDirectory, OnMac, OnWindows, ToBytes, ToUnicode BUFNR_REGEX = re.compile( '^bufnr\\(\'(?P.+)\', ([01])\\)$' ) @@ -102,6 +107,9 @@ REDIR = { 'output': '' } +WindowsAndMacOnly = skipIf( not OnWindows() or not OnMac(), + 'Windows and macOS only' ) + @contextlib.contextmanager def CurrentWorkingDirectory( path ): @@ -293,7 +301,7 @@ def _MockVimEval( value ): if value == REDIR[ 'variable' ]: return REDIR[ 'output' ] - raise VimError( 'Unexpected evaluation: {0}'.format( value ) ) + raise VimError( 'Unexpected evaluation: {}'.format( value ) ) def _MockWipeoutBuffer( buffer_number ): @@ -444,6 +452,11 @@ class VimBuffer( object ): raise ValueError( 'Unexpected mark: {name}'.format( name = name ) ) + def __repr__( self ): + return "VimBuffer( name = '{}', number = {} )".format( self.name, + self.number ) + + class VimBuffers( object ): """An object that looks like a vim.buffers object.""" @@ -483,6 +496,13 @@ class VimWindow( object ): self.options = {} + def __repr__( self ): + return "VimWindow( number = {}, buffer = {}, cursor = {} )".format( + self.number, + self.buffer, + self.cursor ) + + class VimWindows( object ): """An object that looks like a vim.windows object.""" @@ -534,8 +554,8 @@ class VimMatch( object ): def __repr__( self ): - return "VimMatch( group = '{0}', pattern = '{1}' )".format( self.group, - self.pattern ) + return "VimMatch( group = '{}', pattern = '{}' )".format( self.group, + self.pattern ) def __getitem__( self, key ): @@ -562,11 +582,11 @@ class VimSign( object ): def __repr__( self ): - return ( "VimSign( id = {0}, line = {1}, " - "name = '{2}', bufnr = {3} )".format( self.id, - self.line, - self.name, - self.bufnr ) ) + return ( "VimSign( id = {}, line = {}, " + "name = '{}', bufnr = {} )".format( self.id, + self.line, + self.name, + self.bufnr ) ) def __getitem__( self, key ): @@ -692,7 +712,7 @@ def ExpectedFailure( reason, *exception_matchers ): # Failed for the right reason raise nose.SkipTest( reason ) else: - raise AssertionError( 'Test was expected to fail: {0}'.format( + raise AssertionError( 'Test was expected to fail: {}'.format( reason ) ) return Wrapper diff --git a/python/ycm/tests/vimsupport_test.py b/python/ycm/tests/vimsupport_test.py index 6fde2a36..f769f84f 100644 --- a/python/ycm/tests/vimsupport_test.py +++ b/python/ycm/tests/vimsupport_test.py @@ -27,7 +27,7 @@ from builtins import * # noqa from ycm.tests import PathToTestFile from ycm.tests.test_utils import ( CurrentWorkingDirectory, ExtendedMock, MockVimBuffers, MockVimModule, Version, - VimBuffer, VimError ) + VimBuffer, VimError, WindowsAndMacOnly ) MockVimModule() from ycm import vimsupport @@ -1858,6 +1858,35 @@ def JumpToLocation_DifferentFile_Split_CurrentTab_AlreadyOpened_test( ] ) +@WindowsAndMacOnly +@patch( 'vim.command', new_callable = ExtendedMock ) +def JumpToLocation_DifferentFile_Split_CurrentTab_AlreadyOpened_Case_test( + vim_command ): + + current_buffer = VimBuffer( 'current_buffer' ) + different_buffer = VimBuffer( 'AnotHer_buFfeR' ) + current_window = MagicMock( buffer = current_buffer ) + different_window = MagicMock( buffer = different_buffer ) + current_tab = MagicMock( windows = [ current_window, different_window ] ) + with MockVimBuffers( [ current_buffer, different_buffer ], + [ current_buffer ] ) as vim: + vim.current.tabpage = current_tab + + vimsupport.JumpToLocation( os.path.realpath( 'anOther_BuffEr' ), + 4, + 1, + 'belowright', + 'split-or-existing-window' ) + + assert_that( vim.current.tabpage, equal_to( current_tab ) ) + assert_that( vim.current.window, equal_to( different_window ) ) + assert_that( vim.current.window.cursor, equal_to( ( 4, 0 ) ) ) + vim_command.assert_has_exact_calls( [ + call( 'normal! m\'' ), + call( 'normal! zz' ) + ] ) + + @patch( 'vim.command', new_callable = ExtendedMock ) def JumpToLocation_DifferentFile_Split_AllTabs_NotAlreadyOpened_test( vim_command ): diff --git a/python/ycm/vimsupport.py b/python/ycm/vimsupport.py index 2b24ea7f..e2d89c05 100644 --- a/python/ycm/vimsupport.py +++ b/python/ycm/vimsupport.py @@ -28,8 +28,13 @@ import os import json import re from collections import defaultdict, namedtuple -from ycmd.utils import ( ByteOffsetToCodepointOffset, GetCurrentDirectory, - JoinLinesAsUnicode, ToBytes, ToUnicode ) +from ycmd.utils import ( ByteOffsetToCodepointOffset, + GetCurrentDirectory, + JoinLinesAsUnicode, + OnMac, + OnWindows, + ToBytes, + ToUnicode ) BUFFER_COMMAND_MAP = { 'same-buffer' : 'edit', 'split' : 'split', @@ -460,10 +465,21 @@ def EscapeFilepathForVimCommand( filepath ): return GetVariableValue( to_eval ) +def ComparePaths( path1, path2 ): + # Assume that the file system is case-insensitive on Windows and macOS and + # case-sensitive on other platforms. While this is not necessarily true, being + # completely correct here is not worth the trouble as this assumption + # represents the overwhelming use case and detecting the case sensitivity of a + # file system is tricky. + if OnWindows() or OnMac(): + return path1.lower() == path2.lower() + return path1 == path2 + + # Both |line| and |column| need to be 1-based def TryJumpLocationInTab( tab, filename, line, column ): for win in tab.windows: - if GetBufferFilepath( win.buffer ) == filename: + if ComparePaths( GetBufferFilepath( win.buffer ), filename ): vim.current.tabpage = tab vim.current.window = win vim.current.window.cursor = ( line, column - 1 )