Skip to content

Commit

Permalink
Add tests for omnisharp server management
Browse files Browse the repository at this point in the history
  • Loading branch information
bstaletic committed Aug 18, 2024
1 parent f925287 commit 4e0c3d2
Show file tree
Hide file tree
Showing 3 changed files with 296 additions and 1 deletion.
101 changes: 101 additions & 0 deletions ycmd/tests/cs/cs_completer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# Copyright (C) 2021 ycmd contributors
#
# This file is part of ycmd.
#
# ycmd 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.
#
# ycmd 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 ycmd. If not, see <http://www.gnu.org/licenses/>.

from unittest.mock import patch
from unittest import TestCase
from hamcrest import assert_that, equal_to

from ycmd import user_options_store
from ycmd.completers.cs.hook import GetCompleter
from ycmd.completers.cs.cs_completer import PATH_TO_OMNISHARP_ROSLYN_BINARY
from ycmd.tests.cs import setUpModule, tearDownModule # noqa


class GoCompleterTest( TestCase ):
def test_GetCompleter_OmniSharpFound( self ):
assert_that( GetCompleter( user_options_store.GetAll() ) )


@patch( 'ycmd.completers.cs.cs_completer.PATH_TO_OMNISHARP_ROSLYN_BINARY', None )
def test_GetCompleter_OmniSharpNotFound( self, *args ):
assert_that( not GetCompleter( user_options_store.GetAll() ) )


@patch( 'ycmd.completers.cs.cs_completer.FindExecutableWithFallback',
wraps = lambda x, fb: x if x == 'omnisharp' else None )
@patch( 'os.path.isfile', return_value = False )
def test_GetCompleter_CustomOmniSharpNotFound( self, *args ):
user_options = user_options_store.GetAll().copy(
roslyn_binary_path = 'omnisharp' )
assert_that( not GetCompleter( user_options ) )


@patch( 'ycmd.completers.cs.cs_completer.FindExecutableWithFallback',
wraps = lambda x, fb: x if x == 'omnisharp' else None )
@patch( 'os.path.isfile', return_value = True )
def test_GetCompleter_CustomOmniSharpFound_MonoNotRequired( self, *args ):
user_options = user_options_store.GetAll().copy(
roslyn_binary_path = 'omnisharp' )
assert_that( GetCompleter( user_options ) )


@patch( 'ycmd.completers.cs.cs_completer.FindExecutableWithFallback',
wraps = lambda x, fb: x if x in ( 'mono', 'omnisharp.exe' ) else None )
@patch( 'os.path.isfile', return_value = True )
def test_GetCompleter_CustomOmniSharpFound_MonoRequiredAndFound( self, *args ):
user_options = user_options_store.GetAll().copy(
roslyn_binary_path = 'omnisharp.exe',
mono_binary_path = 'mono' )
assert_that( GetCompleter( user_options ) )


@patch( 'ycmd.completers.cs.cs_completer.FindExecutableWithFallback',
wraps = lambda x, fb: x if x == 'omnisharp.exe' else None )
@patch( 'os.path.isfile', return_value = True )
def test_GetCompleter_CustomOmniSharpFound_MonoRequiredAndMissing( self, *args ):
user_options = user_options_store.GetAll().copy(
roslyn_binary_path = 'omnisharp.exe' )
assert_that( not GetCompleter( user_options ) )


def test_GetCompleter_OmniSharpDefaultOptions( self, *args ):
completer = GetCompleter( user_options_store.GetAll() )
assert_that( completer._roslyn_path, equal_to( PATH_TO_OMNISHARP_ROSLYN_BINARY ) )


@patch( 'ycmd.completers.cs.cs_completer.FindExecutableWithFallback',
wraps = lambda x, fb: x if x == 'omnisharp' else None )
@patch( 'os.path.isfile', return_value = True )
def test_GetCompleter_OmniSharpFromUserOption_NoMonoNeeded( self, *args ):
user_options = user_options_store.GetAll().copy(
roslyn_binary_path = 'omnisharp' )
completer = GetCompleter( user_options )
assert_that( completer._roslyn_path, equal_to( 'omnisharp' ) )
assert_that( completer.GetCommandLine()[ 0 ], equal_to( 'omnisharp' ) )


@patch( 'ycmd.completers.cs.cs_completer.FindExecutableWithFallback',
wraps = lambda x, fb: x if x in ( 'omnisharp.exe', 'mono' ) else None )
@patch( 'os.path.isfile', return_value = True )
def test_GetCompleter_OmniSharpFromUserOption_MonoNeeded( self, *args ):
user_options = user_options_store.GetAll().copy(
roslyn_binary_path = 'omnisharp.exe',
mono_binary_path = 'mono' )
completer = GetCompleter( user_options )
assert_that( completer._roslyn_path, equal_to( 'omnisharp.exe' ) )
assert_that( completer._mono, equal_to( 'mono' ) )
assert_that( completer.GetCommandLine()[ 0 ], equal_to( 'mono' ) )
138 changes: 138 additions & 0 deletions ycmd/tests/cs/server_management_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
# Copyright (C) 2024 ycmd contributors
#
# This file is part of ycmd.
#
# ycmd 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.
#
# ycmd 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 ycmd. If not, see <http://www.gnu.org/licenses/>.

from hamcrest import assert_that, contains_exactly, equal_to, has_entry
from unittest.mock import patch
from unittest import TestCase

from ycmd.completers.language_server.language_server_completer import (
LanguageServerConnectionTimeout )
from ycmd.tests.cs import ( PathToTestFile,
IsolatedYcmd,
StartCsCompleterServerInDirectory )
from ycmd.tests.test_utils import ( BuildRequest,
MockProcessTerminationTimingOut,
WaitUntilCompleterServerReady )


def AssertCsCompleterServerIsRunning( app, is_running ):
request_data = BuildRequest( filetype = 'cs' )
assert_that( app.post_json( '/debug_info', request_data ).json,
has_entry(
'completer',
has_entry( 'servers', contains_exactly(
has_entry( 'is_running', is_running )
) )
) )


class ServerManagementTest( TestCase ):
@IsolatedYcmd()
def test_ServerManagement_RestartServer( self, app ):
filepath = PathToTestFile( 'Program.cs' )
StartCsCompleterServerInDirectory( app, filepath )

AssertCsCompleterServerIsRunning( app, True )

app.post_json(
'/run_completer_command',
BuildRequest(
filepath = filepath,
filetype = 'cs',
command_arguments = [ 'RestartServer' ],
),
)

WaitUntilCompleterServerReady( app, 'cs' )

AssertCsCompleterServerIsRunning( app, True )


@IsolatedYcmd()
@patch( 'shutil.rmtree', side_effect = OSError )
@patch( 'ycmd.utils.WaitUntilProcessIsTerminated',
MockProcessTerminationTimingOut )
def test_ServerManagement_CloseServer_Unclean( self, app, *args ):
StartCsCompleterServerInDirectory( app, PathToTestFile() )

app.post_json(
'/run_completer_command',
BuildRequest(
filetype = 'cs',
command_arguments = [ 'StopServer' ]
)
)

request_data = BuildRequest( filetype = 'cs' )
assert_that( app.post_json( '/debug_info', request_data ).json,
has_entry(
'completer',
has_entry( 'servers', contains_exactly(
has_entry( 'is_running', False )
) )
) )


@IsolatedYcmd()
def test_ServerManagement_StopServerTwice( self, app ):
StartCsCompleterServerInDirectory( app, PathToTestFile() )

app.post_json(
'/run_completer_command',
BuildRequest(
filetype = 'cs',
command_arguments = [ 'StopServer' ],
),
)

AssertCsCompleterServerIsRunning( app, False )

# Stopping a stopped server is a no-op
app.post_json(
'/run_completer_command',
BuildRequest(
filetype = 'cs',
command_arguments = [ 'StopServer' ],
),
)

AssertCsCompleterServerIsRunning( app, False )


@IsolatedYcmd
def test_ServerManagement_StartServer_Fails( self, app ):
with patch( 'ycmd.completers.language_server.language_server_completer.'
'LanguageServerConnection.AwaitServerConnection',
side_effect = LanguageServerConnectionTimeout ):
resp = app.post_json( '/event_notification',
BuildRequest(
event_name = 'FileReadyToParse',
filetype = 'cs',
filepath = PathToTestFile( 'Program.cs' ),
contents = ""
) )

assert_that( resp.status_code, equal_to( 200 ) )

request_data = BuildRequest( filetype = 'cs' )
assert_that( app.post_json( '/debug_info', request_data ).json,
has_entry(
'completer',
has_entry( 'servers', contains_exactly(
has_entry( 'is_running', False )
) )
) )
58 changes: 57 additions & 1 deletion ycmd/tests/cs/subcommands_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
# along with ycmd. If not, see <http://www.gnu.org/licenses/>.

from hamcrest import ( assert_that,
contains_inanyorder,
empty,
has_entries,
has_entry,
Expand All @@ -24,8 +25,9 @@
from unittest.mock import patch
from unittest import TestCase
import os.path
import requests

from ycmd import user_options_store
from ycmd import handlers, user_options_store
from ycmd.tests.cs import setUpModule, tearDownModule # noqa
from ycmd.tests.cs import ( IsolatedYcmd,
PathToTestFile,
Expand Down Expand Up @@ -76,6 +78,60 @@ def StopServer_KeepLogFiles( app ):


class SubcommandsTest( TestCase ):
@SharedYcmd
def test_Subcommands_DefinedSubcommands( self, app ):
subcommands_data = BuildRequest( completer_target = 'cs' )

assert_that( app.post_json( '/defined_subcommands', subcommands_data ).json,
contains_inanyorder( 'FixIt',
'Format',
'GetDoc',
'GetType',
'GoTo',
'GoToDeclaration',
'GoToDefinition',
'GoToDocumentOutline',
'GoToImplementation',
'GoToReferences',
'GoToSymbol',
'GoToType',
'RefactorRename',
'RestartServer' ) )


@SharedYcmd
def test_Subcommands_ServerNotInitialized( self, app ):
filepath = PathToTestFile( 'testy', 'Program.cs' )

completer = handlers._server_state.GetFiletypeCompleter( [ 'cs' ] )

@patch.object( completer, '_ServerIsInitialized', return_value = False )
def Test( app, cmd, arguments ):
request = BuildRequest( completer_target = 'filetype_default',
command_arguments = [ cmd ],
line_num = 1,
column_num = 15,
contents = ReadFile( filepath ),
filetype = 'cs',
filepath = filepath )
response = app.post_json( '/run_completer_command', request, expect_errors = True ).json
assert_that( response, ErrorMatcher( RuntimeError, 'Server is initializing. Please wait.' ) )

Test( app, 'FixIt' )
Test( app, 'Format' )
Test( app, 'GetDoc' )
Test( app, 'GetType' )
Test( app, 'GoTo' )
Test( app, 'GoToDeclaration' )
Test( app, 'GoToDefinition' )
Test( app, 'GoToDocumentOutline' )
Test( app, 'GoToImplementation' )
Test( app, 'GoToReferences' )
Test( app, 'GoToSymbol' )
Test( app, 'GoToType' )
Test( app, 'RefactorRename' )


@SharedYcmd
def test_Subcommands_FixIt_NoFixitsFound( self, app ):
fixit_test = PathToTestFile( 'testy', 'FixItTestCase.cs' )
Expand Down

0 comments on commit 4e0c3d2

Please sign in to comment.