Skip to content

Commit 4e0c3d2

Browse files
committed
Add tests for omnisharp server management
1 parent f925287 commit 4e0c3d2

File tree

3 files changed

+296
-1
lines changed

3 files changed

+296
-1
lines changed

ycmd/tests/cs/cs_completer.py

+101
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
# Copyright (C) 2021 ycmd contributors
2+
#
3+
# This file is part of ycmd.
4+
#
5+
# ycmd is free software: you can redistribute it and/or modify
6+
# it under the terms of the GNU General Public License as published by
7+
# the Free Software Foundation, either version 3 of the License, or
8+
# (at your option) any later version.
9+
#
10+
# ycmd is distributed in the hope that it will be useful,
11+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
# GNU General Public License for more details.
14+
#
15+
# You should have received a copy of the GNU General Public License
16+
# along with ycmd. If not, see <http://www.gnu.org/licenses/>.
17+
18+
from unittest.mock import patch
19+
from unittest import TestCase
20+
from hamcrest import assert_that, equal_to
21+
22+
from ycmd import user_options_store
23+
from ycmd.completers.cs.hook import GetCompleter
24+
from ycmd.completers.cs.cs_completer import PATH_TO_OMNISHARP_ROSLYN_BINARY
25+
from ycmd.tests.cs import setUpModule, tearDownModule # noqa
26+
27+
28+
class GoCompleterTest( TestCase ):
29+
def test_GetCompleter_OmniSharpFound( self ):
30+
assert_that( GetCompleter( user_options_store.GetAll() ) )
31+
32+
33+
@patch( 'ycmd.completers.cs.cs_completer.PATH_TO_OMNISHARP_ROSLYN_BINARY', None )
34+
def test_GetCompleter_OmniSharpNotFound( self, *args ):
35+
assert_that( not GetCompleter( user_options_store.GetAll() ) )
36+
37+
38+
@patch( 'ycmd.completers.cs.cs_completer.FindExecutableWithFallback',
39+
wraps = lambda x, fb: x if x == 'omnisharp' else None )
40+
@patch( 'os.path.isfile', return_value = False )
41+
def test_GetCompleter_CustomOmniSharpNotFound( self, *args ):
42+
user_options = user_options_store.GetAll().copy(
43+
roslyn_binary_path = 'omnisharp' )
44+
assert_that( not GetCompleter( user_options ) )
45+
46+
47+
@patch( 'ycmd.completers.cs.cs_completer.FindExecutableWithFallback',
48+
wraps = lambda x, fb: x if x == 'omnisharp' else None )
49+
@patch( 'os.path.isfile', return_value = True )
50+
def test_GetCompleter_CustomOmniSharpFound_MonoNotRequired( self, *args ):
51+
user_options = user_options_store.GetAll().copy(
52+
roslyn_binary_path = 'omnisharp' )
53+
assert_that( GetCompleter( user_options ) )
54+
55+
56+
@patch( 'ycmd.completers.cs.cs_completer.FindExecutableWithFallback',
57+
wraps = lambda x, fb: x if x in ( 'mono', 'omnisharp.exe' ) else None )
58+
@patch( 'os.path.isfile', return_value = True )
59+
def test_GetCompleter_CustomOmniSharpFound_MonoRequiredAndFound( self, *args ):
60+
user_options = user_options_store.GetAll().copy(
61+
roslyn_binary_path = 'omnisharp.exe',
62+
mono_binary_path = 'mono' )
63+
assert_that( GetCompleter( user_options ) )
64+
65+
66+
@patch( 'ycmd.completers.cs.cs_completer.FindExecutableWithFallback',
67+
wraps = lambda x, fb: x if x == 'omnisharp.exe' else None )
68+
@patch( 'os.path.isfile', return_value = True )
69+
def test_GetCompleter_CustomOmniSharpFound_MonoRequiredAndMissing( self, *args ):
70+
user_options = user_options_store.GetAll().copy(
71+
roslyn_binary_path = 'omnisharp.exe' )
72+
assert_that( not GetCompleter( user_options ) )
73+
74+
75+
def test_GetCompleter_OmniSharpDefaultOptions( self, *args ):
76+
completer = GetCompleter( user_options_store.GetAll() )
77+
assert_that( completer._roslyn_path, equal_to( PATH_TO_OMNISHARP_ROSLYN_BINARY ) )
78+
79+
80+
@patch( 'ycmd.completers.cs.cs_completer.FindExecutableWithFallback',
81+
wraps = lambda x, fb: x if x == 'omnisharp' else None )
82+
@patch( 'os.path.isfile', return_value = True )
83+
def test_GetCompleter_OmniSharpFromUserOption_NoMonoNeeded( self, *args ):
84+
user_options = user_options_store.GetAll().copy(
85+
roslyn_binary_path = 'omnisharp' )
86+
completer = GetCompleter( user_options )
87+
assert_that( completer._roslyn_path, equal_to( 'omnisharp' ) )
88+
assert_that( completer.GetCommandLine()[ 0 ], equal_to( 'omnisharp' ) )
89+
90+
91+
@patch( 'ycmd.completers.cs.cs_completer.FindExecutableWithFallback',
92+
wraps = lambda x, fb: x if x in ( 'omnisharp.exe', 'mono' ) else None )
93+
@patch( 'os.path.isfile', return_value = True )
94+
def test_GetCompleter_OmniSharpFromUserOption_MonoNeeded( self, *args ):
95+
user_options = user_options_store.GetAll().copy(
96+
roslyn_binary_path = 'omnisharp.exe',
97+
mono_binary_path = 'mono' )
98+
completer = GetCompleter( user_options )
99+
assert_that( completer._roslyn_path, equal_to( 'omnisharp.exe' ) )
100+
assert_that( completer._mono, equal_to( 'mono' ) )
101+
assert_that( completer.GetCommandLine()[ 0 ], equal_to( 'mono' ) )
+138
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
# Copyright (C) 2024 ycmd contributors
2+
#
3+
# This file is part of ycmd.
4+
#
5+
# ycmd is free software: you can redistribute it and/or modify
6+
# it under the terms of the GNU General Public License as published by
7+
# the Free Software Foundation, either version 3 of the License, or
8+
# (at your option) any later version.
9+
#
10+
# ycmd is distributed in the hope that it will be useful,
11+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
# GNU General Public License for more details.
14+
#
15+
# You should have received a copy of the GNU General Public License
16+
# along with ycmd. If not, see <http://www.gnu.org/licenses/>.
17+
18+
from hamcrest import assert_that, contains_exactly, equal_to, has_entry
19+
from unittest.mock import patch
20+
from unittest import TestCase
21+
22+
from ycmd.completers.language_server.language_server_completer import (
23+
LanguageServerConnectionTimeout )
24+
from ycmd.tests.cs import ( PathToTestFile,
25+
IsolatedYcmd,
26+
StartCsCompleterServerInDirectory )
27+
from ycmd.tests.test_utils import ( BuildRequest,
28+
MockProcessTerminationTimingOut,
29+
WaitUntilCompleterServerReady )
30+
31+
32+
def AssertCsCompleterServerIsRunning( app, is_running ):
33+
request_data = BuildRequest( filetype = 'cs' )
34+
assert_that( app.post_json( '/debug_info', request_data ).json,
35+
has_entry(
36+
'completer',
37+
has_entry( 'servers', contains_exactly(
38+
has_entry( 'is_running', is_running )
39+
) )
40+
) )
41+
42+
43+
class ServerManagementTest( TestCase ):
44+
@IsolatedYcmd()
45+
def test_ServerManagement_RestartServer( self, app ):
46+
filepath = PathToTestFile( 'Program.cs' )
47+
StartCsCompleterServerInDirectory( app, filepath )
48+
49+
AssertCsCompleterServerIsRunning( app, True )
50+
51+
app.post_json(
52+
'/run_completer_command',
53+
BuildRequest(
54+
filepath = filepath,
55+
filetype = 'cs',
56+
command_arguments = [ 'RestartServer' ],
57+
),
58+
)
59+
60+
WaitUntilCompleterServerReady( app, 'cs' )
61+
62+
AssertCsCompleterServerIsRunning( app, True )
63+
64+
65+
@IsolatedYcmd()
66+
@patch( 'shutil.rmtree', side_effect = OSError )
67+
@patch( 'ycmd.utils.WaitUntilProcessIsTerminated',
68+
MockProcessTerminationTimingOut )
69+
def test_ServerManagement_CloseServer_Unclean( self, app, *args ):
70+
StartCsCompleterServerInDirectory( app, PathToTestFile() )
71+
72+
app.post_json(
73+
'/run_completer_command',
74+
BuildRequest(
75+
filetype = 'cs',
76+
command_arguments = [ 'StopServer' ]
77+
)
78+
)
79+
80+
request_data = BuildRequest( filetype = 'cs' )
81+
assert_that( app.post_json( '/debug_info', request_data ).json,
82+
has_entry(
83+
'completer',
84+
has_entry( 'servers', contains_exactly(
85+
has_entry( 'is_running', False )
86+
) )
87+
) )
88+
89+
90+
@IsolatedYcmd()
91+
def test_ServerManagement_StopServerTwice( self, app ):
92+
StartCsCompleterServerInDirectory( app, PathToTestFile() )
93+
94+
app.post_json(
95+
'/run_completer_command',
96+
BuildRequest(
97+
filetype = 'cs',
98+
command_arguments = [ 'StopServer' ],
99+
),
100+
)
101+
102+
AssertCsCompleterServerIsRunning( app, False )
103+
104+
# Stopping a stopped server is a no-op
105+
app.post_json(
106+
'/run_completer_command',
107+
BuildRequest(
108+
filetype = 'cs',
109+
command_arguments = [ 'StopServer' ],
110+
),
111+
)
112+
113+
AssertCsCompleterServerIsRunning( app, False )
114+
115+
116+
@IsolatedYcmd
117+
def test_ServerManagement_StartServer_Fails( self, app ):
118+
with patch( 'ycmd.completers.language_server.language_server_completer.'
119+
'LanguageServerConnection.AwaitServerConnection',
120+
side_effect = LanguageServerConnectionTimeout ):
121+
resp = app.post_json( '/event_notification',
122+
BuildRequest(
123+
event_name = 'FileReadyToParse',
124+
filetype = 'cs',
125+
filepath = PathToTestFile( 'Program.cs' ),
126+
contents = ""
127+
) )
128+
129+
assert_that( resp.status_code, equal_to( 200 ) )
130+
131+
request_data = BuildRequest( filetype = 'cs' )
132+
assert_that( app.post_json( '/debug_info', request_data ).json,
133+
has_entry(
134+
'completer',
135+
has_entry( 'servers', contains_exactly(
136+
has_entry( 'is_running', False )
137+
) )
138+
) )

ycmd/tests/cs/subcommands_test.py

+57-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
# along with ycmd. If not, see <http://www.gnu.org/licenses/>.
1717

1818
from hamcrest import ( assert_that,
19+
contains_inanyorder,
1920
empty,
2021
has_entries,
2122
has_entry,
@@ -24,8 +25,9 @@
2425
from unittest.mock import patch
2526
from unittest import TestCase
2627
import os.path
28+
import requests
2729

28-
from ycmd import user_options_store
30+
from ycmd import handlers, user_options_store
2931
from ycmd.tests.cs import setUpModule, tearDownModule # noqa
3032
from ycmd.tests.cs import ( IsolatedYcmd,
3133
PathToTestFile,
@@ -76,6 +78,60 @@ def StopServer_KeepLogFiles( app ):
7678

7779

7880
class SubcommandsTest( TestCase ):
81+
@SharedYcmd
82+
def test_Subcommands_DefinedSubcommands( self, app ):
83+
subcommands_data = BuildRequest( completer_target = 'cs' )
84+
85+
assert_that( app.post_json( '/defined_subcommands', subcommands_data ).json,
86+
contains_inanyorder( 'FixIt',
87+
'Format',
88+
'GetDoc',
89+
'GetType',
90+
'GoTo',
91+
'GoToDeclaration',
92+
'GoToDefinition',
93+
'GoToDocumentOutline',
94+
'GoToImplementation',
95+
'GoToReferences',
96+
'GoToSymbol',
97+
'GoToType',
98+
'RefactorRename',
99+
'RestartServer' ) )
100+
101+
102+
@SharedYcmd
103+
def test_Subcommands_ServerNotInitialized( self, app ):
104+
filepath = PathToTestFile( 'testy', 'Program.cs' )
105+
106+
completer = handlers._server_state.GetFiletypeCompleter( [ 'cs' ] )
107+
108+
@patch.object( completer, '_ServerIsInitialized', return_value = False )
109+
def Test( app, cmd, arguments ):
110+
request = BuildRequest( completer_target = 'filetype_default',
111+
command_arguments = [ cmd ],
112+
line_num = 1,
113+
column_num = 15,
114+
contents = ReadFile( filepath ),
115+
filetype = 'cs',
116+
filepath = filepath )
117+
response = app.post_json( '/run_completer_command', request, expect_errors = True ).json
118+
assert_that( response, ErrorMatcher( RuntimeError, 'Server is initializing. Please wait.' ) )
119+
120+
Test( app, 'FixIt' )
121+
Test( app, 'Format' )
122+
Test( app, 'GetDoc' )
123+
Test( app, 'GetType' )
124+
Test( app, 'GoTo' )
125+
Test( app, 'GoToDeclaration' )
126+
Test( app, 'GoToDefinition' )
127+
Test( app, 'GoToDocumentOutline' )
128+
Test( app, 'GoToImplementation' )
129+
Test( app, 'GoToReferences' )
130+
Test( app, 'GoToSymbol' )
131+
Test( app, 'GoToType' )
132+
Test( app, 'RefactorRename' )
133+
134+
79135
@SharedYcmd
80136
def test_Subcommands_FixIt_NoFixitsFound( self, app ):
81137
fixit_test = PathToTestFile( 'testy', 'FixItTestCase.cs' )

0 commit comments

Comments
 (0)