Add tests for omni completer GetCompletions

This commit is contained in:
Ben Jackson 2016-04-24 14:22:52 +01:00
parent 81db1c0b23
commit e73426187d
7 changed files with 834 additions and 23 deletions

View File

@ -66,8 +66,7 @@ class OmniCompleter( Completer ):
def ComputeCandidates( self, request_data ): def ComputeCandidates( self, request_data ):
if self.ShouldUseCache(): if self.ShouldUseCache():
return super( OmniCompleter, self ).ComputeCandidates( return super( OmniCompleter, self ).ComputeCandidates( request_data )
request_data )
else: else:
if self.ShouldUseNowInner( request_data ): if self.ShouldUseNowInner( request_data ):
return self.ComputeCandidatesInner( request_data ) return self.ComputeCandidatesInner( request_data )
@ -81,6 +80,7 @@ class OmniCompleter( Completer ):
try: try:
return_value = int( vim.eval( self._omnifunc + '(1,"")' ) ) return_value = int( vim.eval( self._omnifunc + '(1,"")' ) )
if return_value < 0: if return_value < 0:
# FIXME: Technically, if the return is -1 we should raise an error
return [] return []
omnifunc_call = [ self._omnifunc, omnifunc_call = [ self._omnifunc,
@ -90,13 +90,13 @@ class OmniCompleter( Completer ):
items = vim.eval( ''.join( omnifunc_call ) ) items = vim.eval( ''.join( omnifunc_call ) )
if hasattr( items, '__getitem__' ) and 'words' in items: if isinstance( items, dict ) and 'words' in items:
items = items[ 'words' ] items = items[ 'words' ]
if not hasattr( items, '__iter__' ): if not hasattr( items, '__iter__' ):
raise TypeError( OMNIFUNC_NOT_LIST ) raise TypeError( OMNIFUNC_NOT_LIST )
return [ utils.ToUnicode( i ) for i in items if bool( i ) ] return list( filter( bool, items ) )
except ( TypeError, ValueError, vim.error ) as error: except ( TypeError, ValueError, vim.error ) as error:
vimsupport.PostVimMessage( vimsupport.PostVimMessage(
@ -105,7 +105,7 @@ class OmniCompleter( Completer ):
def OnFileReadyToParse( self, request_data ): def OnFileReadyToParse( self, request_data ):
self._omnifunc = vim.eval( '&omnifunc' ) self._omnifunc = utils.ToUnicode( vim.eval( '&omnifunc' ) )
def FilterAndSortCandidatesInner( self, candidates, sort_property, query ): def FilterAndSortCandidatesInner( self, candidates, sort_property, query ):

View File

@ -27,6 +27,10 @@ from mock import MagicMock
from hamcrest import assert_that, equal_to from hamcrest import assert_that, equal_to
import re import re
import sys import sys
import nose
import functools
from ycmd.utils import ToUnicode
BUFNR_REGEX = re.compile( r"^bufnr\('(.+)', ([0-9]+)\)$" ) BUFNR_REGEX = re.compile( r"^bufnr\('(.+)', ([0-9]+)\)$" )
@ -43,6 +47,18 @@ BWIPEOUT_REGEX = re.compile( r"^(?:silent! )bwipeout!? ([0-9]+)$" )
# https://github.com/Valloric/YouCompleteMe/pull/1694 # https://github.com/Valloric/YouCompleteMe/pull/1694
VIM_MOCK = MagicMock() VIM_MOCK = MagicMock()
# The default options which are only relevant to the client, not the server and
# thus are not part of default_options.json, but are required for a working
# YouCompleteMe or OmniCompleter object.
DEFAULT_CLIENT_OPTIONS = {
'server_log_level': 'info',
'extra_conf_vim_data': [],
'show_diagnostics_ui': 1,
'enable_diagnostic_signs': 1,
'enable_diagnostic_highlighting': 0,
'always_populate_location_list': 0,
}
def MockGetBufferNumber( buffer_filename ): def MockGetBufferNumber( buffer_filename ):
for buffer in VIM_MOCK.buffers: for buffer in VIM_MOCK.buffers:
@ -126,7 +142,60 @@ def MockVimModule():
class ExtendedMock( MagicMock ): class ExtendedMock( MagicMock ):
"""An extension to the MagicMock class which adds the ability to check that a
callable is called with a precise set of calls in a precise order.
Example Usage:
from ycm.test_utils import ExtendedMock
@patch( 'test.testing', new_callable = ExtendedMock, ... )
def my_test( test_testing ):
...
"""
def assert_has_exact_calls( self, calls, any_order = False ): def assert_has_exact_calls( self, calls, any_order = False ):
self.assert_has_calls( calls, any_order ) self.assert_has_calls( calls, any_order )
assert_that( self.call_count, equal_to( len( calls ) ) ) assert_that( self.call_count, equal_to( len( calls ) ) )
def ExpectedFailure( reason, *exception_matchers ):
"""Defines a decorator to be attached to tests. This decorator
marks the test as being known to fail, e.g. where documenting or exercising
known incorrect behaviour.
The parameters are:
- |reason| a textual description of the reason for the known issue. This
is used for the skip reason
- |exception_matchers| additional arguments are hamcrest matchers to apply
to the exception thrown. If the matchers don't match, then the
test is marked as error, with the original exception.
If the test fails (for the correct reason), then it is marked as skipped.
If it fails for any other reason, it is marked as failed.
If the test passes, then it is also marked as failed."""
def decorator( test ):
@functools.wraps( test )
def Wrapper( *args, **kwargs ):
try:
test( *args, **kwargs )
except Exception as test_exception:
# Ensure that we failed for the right reason
test_exception_message = ToUnicode( test_exception )
try:
for matcher in exception_matchers:
assert_that( test_exception_message, matcher )
except AssertionError:
# Failed for the wrong reason!
import traceback
print( 'Test failed for the wrong reason: ' + traceback.format_exc() )
# Real failure reason is the *original* exception, we're only trapping
# and ignoring the exception that is expected.
raise test_exception
# Failed for the right reason
raise nose.SkipTest( reason )
else:
raise AssertionError( 'Test was expected to fail: {0}'.format(
reason ) )
return Wrapper
return decorator

View File

@ -23,7 +23,7 @@ from future import standard_library
standard_library.install_aliases() standard_library.install_aliases()
from builtins import * # noqa from builtins import * # noqa
from ycm.test_utils import MockVimModule, ExtendedMock from ycm.test_utils import MockVimModule, ExtendedMock, DEFAULT_CLIENT_OPTIONS
MockVimModule() MockVimModule()
import contextlib import contextlib
@ -38,19 +38,6 @@ from mock import call, MagicMock, patch
from nose.tools import eq_, ok_ from nose.tools import eq_, ok_
# The default options which are only relevant to the client, not the server and
# thus are not part of default_options.json, but are required for a working
# YouCompleteMe object.
DEFAULT_CLIENT_OPTIONS = {
'server_log_level': 'info',
'extra_conf_vim_data': [],
'show_diagnostics_ui': 1,
'enable_diagnostic_signs': 1,
'enable_diagnostic_highlighting': 0,
'always_populate_location_list': 0,
}
def PostVimMessage_Call( message ): def PostVimMessage_Call( message ):
"""Return a mock.call object for a call to vimsupport.PostVimMesasge with the """Return a mock.call object for a call to vimsupport.PostVimMesasge with the
supplied message""" supplied message"""

View File

@ -0,0 +1,758 @@
# encoding: 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 future.utils import PY2
from mock import patch, call
from nose.tools import eq_
from hamcrest import contains_string
from ycm.test_utils import MockVimModule, ExtendedMock
MockVimModule()
from ycm.test_utils import DEFAULT_CLIENT_OPTIONS, ExpectedFailure
from ycm.omni_completer import OmniCompleter
from ycm.youcompleteme import YouCompleteMe
from ycmd import user_options_store
from ycmd.utils import ToBytes
from ycmd.request_wrap import RequestWrap
def ToBytesOnPY2( data ):
# To test the omnifunc, etc. returning strings, which can be of different
# types depending on python version, we use ToBytes on PY2 and just the native
# str on python3. This roughly matches what happens between py2 and py3
# versions within Vim
if PY2:
return ToBytes( data )
return data
def BuildRequest( line_num, column_num, contents ):
# Note: it would be nice to use ycmd.test_utils.BuildRequest directly here,
# but we can't import ycmd.test_utils because that in turn imports ycm_core,
# which would cause our "ycm_core not imported" test to fail.
return {
'line_num': line_num,
'column_num': column_num,
'filepath': '/test',
'file_data': {
'/test': {
'contents': contents,
'filetypes': [ 'java' ] # We need a filetype with a trigger, so we just
# use java
}
}
}
def BuildRequestWrap( line_num, column_num, contents ):
return RequestWrap( BuildRequest( line_num, column_num, contents ) )
def MakeUserOptions( custom_options = {} ):
options = dict( user_options_store.DefaultOptions() )
options.update( DEFAULT_CLIENT_OPTIONS )
options.update( custom_options )
return options
class OmniCompleter_test( object ):
def setUp( self ):
# We need a server instance for FilterAndSortCandidates
self._server_state = YouCompleteMe( MakeUserOptions() )
def tearDown( self ):
self._server_state.OnVimLeave()
def OmniCompleter_GetCompletions_Cache_List_test( self ):
omni_completer = OmniCompleter( MakeUserOptions( {
'cache_omnifunc': 1
} ) )
contents = 'test.'
request_data = BuildRequestWrap( line_num = 1,
column_num = 6,
contents = contents )
# Make sure there is an omnifunc set up.
with patch( 'vim.eval', return_value = ToBytesOnPY2( 'test_omnifunc' ) ):
omni_completer.OnFileReadyToParse( request_data )
omnifunc_result = [ ToBytesOnPY2( 'a' ),
ToBytesOnPY2( 'b' ),
ToBytesOnPY2( 'cdef' ) ]
# And get the completions
with patch( 'vim.eval',
new_callable = ExtendedMock,
side_effect = [ 6, omnifunc_result ] ) as vim_eval:
results = omni_completer.ComputeCandidates( request_data )
vim_eval.assert_has_exact_calls( [
call( 'test_omnifunc(1,"")' ),
call( "test_omnifunc(0,'')" ),
] )
eq_( results, omnifunc_result )
def OmniCompleter_GetCompletions_Cache_ListFilter_test( self ):
omni_completer = OmniCompleter( MakeUserOptions( {
'cache_omnifunc': 1
} ) )
contents = 'test.t'
request_data = BuildRequestWrap( line_num = 1,
column_num = 7,
contents = contents )
eq_( request_data[ 'query' ], 't' )
# Make sure there is an omnifunc set up.
with patch( 'vim.eval', return_value = ToBytesOnPY2( 'test_omnifunc' ) ):
omni_completer.OnFileReadyToParse( request_data )
omnifunc_result = [ ToBytesOnPY2( 'a' ),
ToBytesOnPY2( 'b' ),
ToBytesOnPY2( 'cdef' ) ]
# And get the completions
with patch( 'vim.eval',
new_callable = ExtendedMock,
side_effect = [ 6, omnifunc_result ] ) as vim_eval:
results = omni_completer.ComputeCandidates( request_data )
vim_eval.assert_has_exact_calls( [
call( 'test_omnifunc(1,"")' ),
call( "test_omnifunc(0,'t')" ),
] )
eq_( results, [] )
def OmniCompleter_GetCompletions_NoCache_List_test( self ):
omni_completer = OmniCompleter( MakeUserOptions( {
'cache_omnifunc': 0
} ) )
contents = 'test.'
request_data = BuildRequestWrap( line_num = 1,
column_num = 6,
contents = contents )
# Make sure there is an omnifunc set up.
with patch( 'vim.eval', return_value = ToBytesOnPY2( 'test_omnifunc' ) ):
omni_completer.OnFileReadyToParse( request_data )
omnifunc_result = [ ToBytesOnPY2( 'a' ),
ToBytesOnPY2( 'b' ),
ToBytesOnPY2( 'cdef' ) ]
# And get the completions
with patch( 'vim.eval',
new_callable = ExtendedMock,
side_effect = [ 6, omnifunc_result ] ) as vim_eval:
results = omni_completer.ComputeCandidates( request_data )
vim_eval.assert_has_exact_calls( [
call( 'test_omnifunc(1,"")' ),
call( "test_omnifunc(0,'')" ),
] )
eq_( results, omnifunc_result )
def OmniCompleter_GetCompletions_NoCache_ListFilter_test( self ):
omni_completer = OmniCompleter( MakeUserOptions( {
'cache_omnifunc': 0
} ) )
contents = 'test.t'
request_data = BuildRequestWrap( line_num = 1,
column_num = 7,
contents = contents )
eq_( request_data[ 'query' ], 't' )
# Make sure there is an omnifunc set up.
with patch( 'vim.eval', return_value = ToBytesOnPY2( 'test_omnifunc' ) ):
omni_completer.OnFileReadyToParse( request_data )
omnifunc_result = [ ToBytesOnPY2( 'a' ),
ToBytesOnPY2( 'b' ),
ToBytesOnPY2( 'cdef' ) ]
# And get the completions
with patch( 'vim.eval',
new_callable = ExtendedMock,
side_effect = [ 6, omnifunc_result ] ) as vim_eval:
results = omni_completer.ComputeCandidates( request_data )
vim_eval.assert_has_exact_calls( [
call( 'test_omnifunc(1,"")' ),
call( "test_omnifunc(0,'t')" ),
] )
# actual result is that the results are not filtered, as we expect the
# omniufunc or vim itself to do this filtering
eq_( results, omnifunc_result )
@ExpectedFailure( 'We ignore the result of the call to findstart and use our '
'own interpretation of where the identifier should be',
contains_string( "test_omnifunc(0,'t')" ) )
def OmniCompleter_GetCompletsions_UseFindStart_test( self ):
omni_completer = OmniCompleter( MakeUserOptions( {
'cache_omnifunc': 1
} ) )
contents = 'test.t'
request_data = BuildRequestWrap( line_num = 1,
column_num = 7,
contents = contents )
eq_( request_data[ 'query' ], 't' )
# Make sure there is an omnifunc set up.
with patch( 'vim.eval', return_value = ToBytesOnPY2( 'test_omnifunc' ) ):
omni_completer.OnFileReadyToParse( request_data )
omnifunc_result = [ ToBytesOnPY2( 'a' ),
ToBytesOnPY2( 'b' ),
ToBytesOnPY2( 'cdef' ) ]
# And get the completions
with patch( 'vim.eval',
new_callable = ExtendedMock,
side_effect = [ 1, omnifunc_result ] ) as vim_eval:
results = omni_completer.ComputeCandidates( request_data )
vim_eval.assert_has_exact_calls( [
call( 'test_omnifunc(1,"")' ),
# Fails here: actual result is that the findstart result (1) is ignored
# and we use the 't' query as we normally would on the server side
call( "test_omnifunc(0,'test.t')" ),
] )
eq_( results, omnifunc_result )
def OmniCompleter_GetCompletions_Cache_Object_test( self ):
omni_completer = OmniCompleter( MakeUserOptions( {
'cache_omnifunc': 1
} ) )
contents = 'test.t'
request_data = BuildRequestWrap( line_num = 1,
column_num = 7,
contents = contents )
eq_( request_data[ 'query' ], 't' )
# Make sure there is an omnifunc set up.
with patch( 'vim.eval', return_value = ToBytesOnPY2( 'test_omnifunc' ) ):
omni_completer.OnFileReadyToParse( request_data )
omnifunc_result = {
'words': [
ToBytesOnPY2( 'a' ),
ToBytesOnPY2( 'b' ),
ToBytesOnPY2( 'CDtEF' )
]
}
# And get the completions
with patch( 'vim.eval',
new_callable = ExtendedMock,
side_effect = [ 6, omnifunc_result ] ) as vim_eval:
results = omni_completer.ComputeCandidates( request_data )
vim_eval.assert_has_exact_calls( [
call( 'test_omnifunc(1,"")' ),
call( "test_omnifunc(0,'t')" ),
] )
eq_( results, [ ToBytesOnPY2( 'CDtEF' ) ] )
def OmniCompleter_GetCompletions_Cache_ObjectList_test( self ):
omni_completer = OmniCompleter( MakeUserOptions( {
'cache_omnifunc': 1
} ) )
contents = 'test.tt'
request_data = BuildRequestWrap( line_num = 1,
column_num = 8,
contents = contents )
eq_( request_data[ 'query' ], 'tt' )
# Make sure there is an omnifunc set up.
with patch( 'vim.eval', return_value = ToBytesOnPY2( 'test_omnifunc' ) ):
omni_completer.OnFileReadyToParse( request_data )
omnifunc_result = [
{
'word': ToBytesOnPY2( 'a' ),
'abbr': ToBytesOnPY2( 'ABBR'),
'menu': ToBytesOnPY2( 'MENU' ),
'info': ToBytesOnPY2( 'INFO' ),
'kind': ToBytesOnPY2( 'K' )
},
{
'word': ToBytesOnPY2( 'test' ),
'abbr': ToBytesOnPY2( 'ABBRTEST'),
'menu': ToBytesOnPY2( 'MENUTEST' ),
'info': ToBytesOnPY2( 'INFOTEST' ),
'kind': ToBytesOnPY2( 'T' )
}
]
# And get the completions
with patch( 'vim.eval',
new_callable = ExtendedMock,
side_effect = [ 6, omnifunc_result ] ) as vim_eval:
results = omni_completer.ComputeCandidates( request_data )
vim_eval.assert_has_exact_calls( [
call( 'test_omnifunc(1,"")' ),
call( "test_omnifunc(0,'tt')" ),
] )
eq_( results, [ omnifunc_result[ 1 ] ] )
def OmniCompleter_GetCompletions_NoCache_ObjectList_test( self ):
omni_completer = OmniCompleter( MakeUserOptions( {
'cache_omnifunc': 0
} ) )
contents = 'test.tt'
request_data = BuildRequestWrap( line_num = 1,
column_num = 8,
contents = contents )
eq_( request_data[ 'query' ], 'tt' )
# Make sure there is an omnifunc set up.
with patch( 'vim.eval', return_value = ToBytesOnPY2( 'test_omnifunc' ) ):
omni_completer.OnFileReadyToParse( request_data )
omnifunc_result = [
{
'word': ToBytesOnPY2( 'a' ),
'abbr': ToBytesOnPY2( 'ABBR'),
'menu': ToBytesOnPY2( 'MENU' ),
'info': ToBytesOnPY2( 'INFO' ),
'kind': ToBytesOnPY2( 'K' )
},
{
'word': ToBytesOnPY2( 'test' ),
'abbr': ToBytesOnPY2( 'ABBRTEST'),
'menu': ToBytesOnPY2( 'MENUTEST' ),
'info': ToBytesOnPY2( 'INFOTEST' ),
'kind': ToBytesOnPY2( 'T' )
}
]
# And get the completions
with patch( 'vim.eval',
new_callable = ExtendedMock,
side_effect = [ 6, omnifunc_result ] ) as vim_eval:
results = omni_completer.ComputeCandidates( request_data )
vim_eval.assert_has_exact_calls( [
call( 'test_omnifunc(1,"")' ),
call( "test_omnifunc(0,'tt')" ),
] )
# We don't filter the result - we expect the omnifunc to do that
# based on the query we supplied (Note: that means no fuzzy matching!)
eq_( results, omnifunc_result )
def OmniCompleter_GetCompletions_Cache_ObjectListObject_test( self ):
omni_completer = OmniCompleter( MakeUserOptions( {
'cache_omnifunc': 1
} ) )
contents = 'test.tt'
request_data = BuildRequestWrap( line_num = 1,
column_num = 8,
contents = contents )
eq_( request_data[ 'query' ], 'tt' )
# Make sure there is an omnifunc set up.
with patch( 'vim.eval', return_value = ToBytesOnPY2( 'test_omnifunc' ) ):
omni_completer.OnFileReadyToParse( request_data )
omnifunc_result = {
'words': [
{
'word': ToBytesOnPY2( 'a' ),
'abbr': ToBytesOnPY2( 'ABBR'),
'menu': ToBytesOnPY2( 'MENU' ),
'info': ToBytesOnPY2( 'INFO' ),
'kind': ToBytesOnPY2( 'K' )
},
{
'word': ToBytesOnPY2( 'test' ),
'abbr': ToBytesOnPY2( 'ABBRTEST'),
'menu': ToBytesOnPY2( 'MENUTEST' ),
'info': ToBytesOnPY2( 'INFOTEST' ),
'kind': ToBytesOnPY2( 'T' )
}
]
}
# And get the completions
with patch( 'vim.eval',
new_callable = ExtendedMock,
side_effect = [ 6, omnifunc_result ] ) as vim_eval:
results = omni_completer.ComputeCandidates( request_data )
vim_eval.assert_has_exact_calls( [
call( 'test_omnifunc(1,"")' ),
call( "test_omnifunc(0,'tt')" ),
] )
eq_( results, [ omnifunc_result[ 'words' ][ 1 ] ] )
def OmniCompleter_GetCompletions_NoCache_ObjectListObject_test( self ):
omni_completer = OmniCompleter( MakeUserOptions( {
'cache_omnifunc': 0
} ) )
contents = 'test.tt'
request_data = BuildRequestWrap( line_num = 1,
column_num = 8,
contents = contents )
eq_( request_data[ 'query' ], 'tt' )
# Make sure there is an omnifunc set up.
with patch( 'vim.eval', return_value = ToBytesOnPY2( 'test_omnifunc' ) ):
omni_completer.OnFileReadyToParse( request_data )
omnifunc_result = {
'words': [
{
'word': ToBytesOnPY2( 'a' ),
'abbr': ToBytesOnPY2( 'ABBR'),
'menu': ToBytesOnPY2( 'MENU' ),
'info': ToBytesOnPY2( 'INFO' ),
'kind': ToBytesOnPY2( 'K' )
},
{
'word': ToBytesOnPY2( 'test' ),
'abbr': ToBytesOnPY2( 'ABBRTEST'),
'menu': ToBytesOnPY2( 'MENUTEST' ),
'info': ToBytesOnPY2( 'INFOTEST' ),
'kind': ToBytesOnPY2( 'T' )
}
]
}
# And get the completions
with patch( 'vim.eval',
new_callable = ExtendedMock,
side_effect = [ 6, omnifunc_result ] ) as vim_eval:
results = omni_completer.ComputeCandidates( request_data )
vim_eval.assert_has_exact_calls( [
call( 'test_omnifunc(1,"")' ),
call( "test_omnifunc(0,'tt')" ),
] )
# No FilterAndSortCandidates for cache_omnifunc=0 (we expect the omnifunc
# to do the filtering?)
eq_( results, omnifunc_result[ 'words' ] )
def OmniCompleter_GetCompletions_Cache_List_Unicode_test( self ):
omni_completer = OmniCompleter( MakeUserOptions( {
'cache_omnifunc': 1
} ) )
contents = '†åsty_π.'
request_data = BuildRequestWrap( line_num = 1,
column_num = 13,
contents = contents )
# Make sure there is an omnifunc set up.
with patch( 'vim.eval', return_value = ToBytesOnPY2( 'test_omnifunc' ) ):
omni_completer.OnFileReadyToParse( request_data )
omnifunc_result = [ ToBytesOnPY2( '†est' ),
ToBytesOnPY2( 'å_unicode_identifier' ),
ToBytesOnPY2( 'πππππππ yummy πie' ) ]
# And get the completions
with patch( 'vim.eval',
new_callable = ExtendedMock,
side_effect = [ 6, omnifunc_result ] ) as vim_eval:
results = omni_completer.ComputeCandidates( request_data )
vim_eval.assert_has_exact_calls( [
call( 'test_omnifunc(1,"")' ),
call( "test_omnifunc(0,'')" ),
] )
eq_( results, omnifunc_result )
def OmniCompleter_GetCompletions_NoCache_List_Unicode_test( self ):
omni_completer = OmniCompleter( MakeUserOptions( {
'cache_omnifunc': 0
} ) )
contents = '†åsty_π.'
request_data = BuildRequestWrap( line_num = 1,
column_num = 13,
contents = contents )
# Make sure there is an omnifunc set up.
with patch( 'vim.eval', return_value = ToBytesOnPY2( 'test_omnifunc' ) ):
omni_completer.OnFileReadyToParse( request_data )
omnifunc_result = [ ToBytesOnPY2( '†est' ),
ToBytesOnPY2( 'å_unicode_identifier' ),
ToBytesOnPY2( 'πππππππ yummy πie' ) ]
# And get the completions
with patch( 'vim.eval',
new_callable = ExtendedMock,
side_effect = [ 6, omnifunc_result ] ) as vim_eval:
results = omni_completer.ComputeCandidates( request_data )
vim_eval.assert_has_exact_calls( [
call( 'test_omnifunc(1,"")' ),
call( "test_omnifunc(0,'')" ),
] )
eq_( results, omnifunc_result )
@ExpectedFailure( 'Filtering on unicode is not supported by the server' )
def OmniCompleter_GetCompletions_Cache_List_Filter_Unicode_test( self ):
omni_completer = OmniCompleter( MakeUserOptions( {
'cache_omnifunc': 1
} ) )
contents = '†åsty_π.ππ'
request_data = BuildRequestWrap( line_num = 1,
column_num = 17,
contents = contents )
# Make sure there is an omnifunc set up.
with patch( 'vim.eval', return_value = ToBytesOnPY2( 'test_omnifunc' ) ):
omni_completer.OnFileReadyToParse( request_data )
omnifunc_result = [ ToBytesOnPY2( '†est' ),
ToBytesOnPY2( 'å_unicode_identifier' ),
ToBytesOnPY2( 'πππππππ yummy πie' ) ]
# And get the completions
with patch( 'vim.eval',
new_callable = ExtendedMock,
side_effect = [ 6, omnifunc_result ] ) as vim_eval:
results = omni_completer.ComputeCandidates( request_data )
vim_eval.assert_has_exact_calls( [
call( 'test_omnifunc(1,"")' ),
call( "test_omnifunc(0,'ππ')" ),
] )
# Fails here: Filtering on unicode is not supported
eq_( results, [ omnifunc_result[ 2 ] ] )
def OmniCompleter_GetCompletions_NoCache_List_Filter_Unicode_test( self ):
omni_completer = OmniCompleter( MakeUserOptions( {
'cache_omnifunc': 0
} ) )
contents = '†åsty_π.ππ'
request_data = BuildRequestWrap( line_num = 1,
column_num = 17,
contents = contents )
# Make sure there is an omnifunc set up.
with patch( 'vim.eval', return_value = ToBytesOnPY2( 'test_omnifunc' ) ):
omni_completer.OnFileReadyToParse( request_data )
omnifunc_result = [ ToBytesOnPY2( 'πππππππ yummy πie' ) ]
# And get the completions
with patch( 'vim.eval',
new_callable = ExtendedMock,
side_effect = [ 6, omnifunc_result ] ) as vim_eval:
results = omni_completer.ComputeCandidates( request_data )
vim_eval.assert_has_exact_calls( [
call( 'test_omnifunc(1,"")' ),
call( "test_omnifunc(0,'ππ')" ),
] )
eq_( results, omnifunc_result )
@ExpectedFailure( 'Filtering on unicode is not supported by the server' )
def OmniCompleter_GetCompletions_Cache_ObjectList_Unicode_test( self ):
omni_completer = OmniCompleter( MakeUserOptions( {
'cache_omnifunc': 1
} ) )
contents = '†åsty_π.ππ'
request_data = BuildRequestWrap( line_num = 1,
column_num = 17,
contents = contents )
eq_( request_data[ 'query' ], 'ππ' )
# Make sure there is an omnifunc set up.
with patch( 'vim.eval', return_value = ToBytesOnPY2( 'test_omnifunc' ) ):
omni_completer.OnFileReadyToParse( request_data )
omnifunc_result = [
{
'word': ToBytesOnPY2( 'ålpha∫et' ),
'abbr': ToBytesOnPY2( 'å∫∫®'),
'menu': ToBytesOnPY2( 'µ´~¨á' ),
'info': ToBytesOnPY2( '^~fo' ),
'kind': ToBytesOnPY2( '˚' )
},
{
'word': ToBytesOnPY2( 'π†´ß†π' ),
'abbr': ToBytesOnPY2( 'ÅııÂʉÍÊ'),
'menu': ToBytesOnPY2( '˜‰ˆËʉÍÊ' ),
'info': ToBytesOnPY2( 'ȈÏØʉÍÊ' ),
'kind': ToBytesOnPY2( 'Ê' )
}
]
# And get the completions
with patch( 'vim.eval',
new_callable = ExtendedMock,
side_effect = [ 6, omnifunc_result ] ) as vim_eval:
results = omni_completer.ComputeCandidates( request_data )
vim_eval.assert_has_exact_calls( [
call( 'test_omnifunc(1,"")' ),
call( "test_omnifunc(0,'ππ')" ),
] )
# Fails here: Filtering on unicode is not supported
eq_( results, [ omnifunc_result[ 1 ] ] )
def OmniCompleter_GetCompletions_Cache_ObjectListObject_Unicode_test( self ):
omni_completer = OmniCompleter( MakeUserOptions( {
'cache_omnifunc': 1
} ) )
contents = '†åsty_π.t'
request_data = BuildRequestWrap( line_num = 1,
column_num = 14,
contents = contents )
eq_( request_data[ 'query' ], 't' )
# Make sure there is an omnifunc set up.
with patch( 'vim.eval', return_value = ToBytesOnPY2( 'test_omnifunc' ) ):
omni_completer.OnFileReadyToParse( request_data )
omnifunc_result = {
'words': [
{
'word': ToBytesOnPY2( 'ålpha∫et' ),
'abbr': ToBytesOnPY2( 'å∫∫®'),
'menu': ToBytesOnPY2( 'µ´~¨á' ),
'info': ToBytesOnPY2( '^~fo' ),
'kind': ToBytesOnPY2( '˚' )
},
{
'word': ToBytesOnPY2( 'π†´ß†π' ),
'abbr': ToBytesOnPY2( 'ÅııÂʉÍÊ'),
'menu': ToBytesOnPY2( '˜‰ˆËʉÍÊ' ),
'info': ToBytesOnPY2( 'ȈÏØʉÍÊ' ),
'kind': ToBytesOnPY2( 'Ê' )
},
{
'word': ToBytesOnPY2( 'test' ),
'abbr': ToBytesOnPY2( 'ÅııÂʉÍÊ'),
'menu': ToBytesOnPY2( '˜‰ˆËʉÍÊ' ),
'info': ToBytesOnPY2( 'ȈÏØʉÍÊ' ),
'kind': ToBytesOnPY2( 'Ê' )
}
]
}
# And get the completions
with patch( 'vim.eval',
new_callable = ExtendedMock,
side_effect = [ 6, omnifunc_result ] ) as vim_eval:
results = omni_completer.ComputeCandidates( request_data )
vim_eval.assert_has_exact_calls( [
call( 'test_omnifunc(1,"")' ),
call( "test_omnifunc(0,'t')" ),
] )
# Note: the filtered results are all unicode objects (not bytes) because
# they are passed through the FilterAndSortCandidates machinery
# (via the server)
eq_( results, [ {
'word': 'test',
'abbr': 'ÅııÂʉÍÊ',
'menu': '˜‰ˆËʉÍÊ',
'info': 'ȈÏØʉÍÊ',
'kind': 'Ê'
} ] )

View File

@ -28,13 +28,12 @@ from builtins import * # noqa
from ycm.test_utils import MockVimModule from ycm.test_utils import MockVimModule
MockVimModule() MockVimModule()
from ycmd.utils import ToBytes
import contextlib import contextlib
from hamcrest import assert_that, empty from hamcrest import assert_that, empty
from mock import MagicMock, DEFAULT, patch from mock import MagicMock, DEFAULT, patch
from nose.tools import eq_, ok_ from nose.tools import eq_, ok_
from ycmd.utils import ToBytes
from ycm import vimsupport from ycm import vimsupport
from ycm.youcompleteme import YouCompleteMe from ycm.youcompleteme import YouCompleteMe

View File

@ -72,10 +72,8 @@ def NoseTests( extra_args ):
def Main(): def Main():
( parsed_args, extra_args ) = ParseArguments() ( parsed_args, extra_args ) = ParseArguments()
if not parsed_args.no_flake8: if not parsed_args.no_flake8:
RunFlake8() RunFlake8()
BuildYcmdLibs( parsed_args ) BuildYcmdLibs( parsed_args )
NoseTests( extra_args ) NoseTests( extra_args )