diff --git a/python/ycm/server/tests/diagnostics_test.py b/python/ycm/server/tests/diagnostics_test.py new file mode 100644 index 00000000..6f1d199b --- /dev/null +++ b/python/ycm/server/tests/diagnostics_test.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python +# +# Copyright (C) 2013 Strahinja Val Markovic +# +# 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 . + +from ..server_utils import SetUpPythonPath +SetUpPythonPath() +from .test_utils import Setup, BuildRequest +from webtest import TestApp +from nose.tools import with_setup +from hamcrest import ( assert_that, contains, contains_string, has_entries, + has_entry ) +from .. import handlers +import bottle + +bottle.debug( True ) + +@with_setup( Setup ) +def Diagnostics_ClangCompleter_ZeroBasedLineAndColumn_test(): + app = TestApp( handlers.app ) + contents = """ +struct Foo { + int x // semicolon missing here! + int y; + int c; + int d; +}; +""" + + event_data = BuildRequest( compilation_flags = ['-x', 'c++'], + event_name = 'FileReadyToParse', + contents = contents, + filetype = 'cpp' ) + + results = app.post_json( '/event_notification', event_data ).json + assert_that( results, + contains( + has_entries( { 'text': contains_string( "expected ';'" ), + 'line_num': 2, + 'column_num': 7 } ) ) ) + + +@with_setup( Setup ) +def GetDetailedDiagnostic_ClangCompleter_Works_test(): + app = TestApp( handlers.app ) + contents = """ +struct Foo { + int x // semicolon missing here! + int y; + int c; + int d; +}; +""" + + diag_data = BuildRequest( compilation_flags = ['-x', 'c++'], + line_num = 2, + contents = contents, + filetype = 'cpp' ) + + event_data = diag_data.copy() + event_data.update( { + 'event_name': 'FileReadyToParse', + } ) + + app.post_json( '/event_notification', event_data ) + results = app.post_json( '/detailed_diagnostic', diag_data ).json + assert_that( results, + has_entry( 'message', contains_string( "expected ';'" ) ) ) + diff --git a/python/ycm/server/tests/basic_test.py b/python/ycm/server/tests/get_completions_test.py similarity index 60% rename from python/ycm/server/tests/basic_test.py rename to python/ycm/server/tests/get_completions_test.py index 6d226324..36054981 100644 --- a/python/ycm/server/tests/basic_test.py +++ b/python/ycm/server/tests/get_completions_test.py @@ -17,76 +17,27 @@ # You should have received a copy of the GNU General Public License # along with YouCompleteMe. If not, see . -import os -import httplib -import time from ..server_utils import SetUpPythonPath SetUpPythonPath() +import time +import httplib +from .test_utils import Setup, BuildRequest, PathToTestFile from webtest import TestApp -from .. import handlers +from nose.tools import eq_, with_setup +from hamcrest import ( assert_that, has_items, has_entry, + contains_inanyorder ) from ..responses import BuildCompletionData, UnknownExtraConf -from nose.tools import ok_, eq_, with_setup -from hamcrest import ( assert_that, has_items, has_entry, contains, - contains_string, has_entries, contains_inanyorder ) +from .. import handlers import bottle bottle.debug( True ) -# TODO: Split this file into multiple files. - -def BuildRequest( **kwargs ): - filepath = kwargs[ 'filepath' ] if 'filepath' in kwargs else '/foo' - contents = kwargs[ 'contents' ] if 'contents' in kwargs else '' - filetype = kwargs[ 'filetype' ] if 'filetype' in kwargs else 'foo' - - request = { - 'query': '', - 'line_num': 0, - 'column_num': 0, - 'start_column': 0, - 'filetypes': [ filetype ], - 'filepath': filepath, - 'line_value': contents, - 'file_data': { - filepath: { - 'contents': contents, - 'filetypes': [ filetype ] - } - } - } - - for key, value in kwargs.iteritems(): - if key in [ 'contents', 'filetype', 'filepath' ]: - continue - request[ key ] = value - - if key == 'line_num': - lines = contents.splitlines() - if len( lines ) > 1: - # NOTE: assumes 0-based line_num - request[ 'line_value' ] = lines[ value ] - - return request - # TODO: Make the other tests use this helper too instead of BuildCompletionData def CompletionEntryMatcher( insertion_text ): return has_entry( 'insertion_text', insertion_text ) -def Setup(): - handlers.SetServerStateToDefaults() - - -def PathToTestDataDir(): - dir_of_current_script = os.path.dirname( os.path.abspath( __file__ ) ) - return os.path.join( dir_of_current_script, 'testdata' ) - - -def PathToTestFile( test_basename ): - return os.path.join( PathToTestDataDir(), test_basename ) - - @with_setup( Setup ) def GetCompletions_IdentifierCompleter_Works_test(): app = TestApp( handlers.app ) @@ -292,160 +243,3 @@ def GetCompletions_UltiSnipsCompleter_Works_test(): app.post_json( '/completions', completion_data ).json ) -@with_setup( Setup ) -def RunCompleterCommand_GoTo_Jedi_ZeroBasedLineAndColumn_test(): - app = TestApp( handlers.app ) - contents = """ -def foo(): - pass - -foo() -""" - - goto_data = BuildRequest( completer_target = 'filetype_default', - command_arguments = ['GoToDefinition'], - line_num = 4, - contents = contents, - filetype = 'python', - filepath = '/foo.py' ) - - # 0-based line and column! - eq_( { - 'filepath': '/foo.py', - 'line_num': 1, - 'column_num': 4 - }, - app.post_json( '/run_completer_command', goto_data ).json ) - - -@with_setup( Setup ) -def RunCompleterCommand_GoTo_Clang_ZeroBasedLineAndColumn_test(): - app = TestApp( handlers.app ) - contents = """ -struct Foo { - int x; - int y; - char c; -}; - -int main() -{ - Foo foo; - return 0; -} -""" - - goto_data = BuildRequest( completer_target = 'filetype_default', - command_arguments = ['GoToDefinition'], - compilation_flags = ['-x', 'c++'], - line_num = 9, - column_num = 2, - contents = contents, - filetype = 'cpp' ) - - # 0-based line and column! - eq_( { - 'filepath': '/foo', - 'line_num': 1, - 'column_num': 7 - }, - app.post_json( '/run_completer_command', goto_data ).json ) - - -@with_setup( Setup ) -def DefinedSubcommands_Works_test(): - app = TestApp( handlers.app ) - subcommands_data = BuildRequest( completer_target = 'python' ) - - eq_( [ 'GoToDefinition', - 'GoToDeclaration', - 'GoToDefinitionElseDeclaration' ], - app.post_json( '/defined_subcommands', subcommands_data ).json ) - - -@with_setup( Setup ) -def DefinedSubcommands_WorksWhenNoExplicitCompleterTargetSpecified_test(): - app = TestApp( handlers.app ) - subcommands_data = BuildRequest( filetype = 'python' ) - - eq_( [ 'GoToDefinition', - 'GoToDeclaration', - 'GoToDefinitionElseDeclaration' ], - app.post_json( '/defined_subcommands', subcommands_data ).json ) - - -@with_setup( Setup ) -def Diagnostics_ClangCompleter_ZeroBasedLineAndColumn_test(): - app = TestApp( handlers.app ) - contents = """ -struct Foo { - int x // semicolon missing here! - int y; - int c; - int d; -}; -""" - - event_data = BuildRequest( compilation_flags = ['-x', 'c++'], - event_name = 'FileReadyToParse', - contents = contents, - filetype = 'cpp' ) - - results = app.post_json( '/event_notification', event_data ).json - assert_that( results, - contains( - has_entries( { 'text': contains_string( "expected ';'" ), - 'line_num': 2, - 'column_num': 7 } ) ) ) - - -@with_setup( Setup ) -def GetDetailedDiagnostic_ClangCompleter_Works_test(): - app = TestApp( handlers.app ) - contents = """ -struct Foo { - int x // semicolon missing here! - int y; - int c; - int d; -}; -""" - - diag_data = BuildRequest( compilation_flags = ['-x', 'c++'], - line_num = 2, - contents = contents, - filetype = 'cpp' ) - - event_data = diag_data.copy() - event_data.update( { - 'event_name': 'FileReadyToParse', - } ) - - app.post_json( '/event_notification', event_data ) - results = app.post_json( '/detailed_diagnostic', diag_data ).json - assert_that( results, - has_entry( 'message', contains_string( "expected ';'" ) ) ) - - -@with_setup( Setup ) -def FiletypeCompletionAvailable_Works_test(): - app = TestApp( handlers.app ) - request_data = { - 'filetypes': ['python'] - } - - ok_( app.post_json( '/semantic_completion_available', - request_data ).json ) - - -@with_setup( Setup ) -def UserOptions_Works_test(): - app = TestApp( handlers.app ) - options = app.get( '/user_options' ).json - ok_( len( options ) ) - - options[ 'foobar' ] = 'zoo' - - app.post_json( '/user_options', options ) - eq_( options, app.get( '/user_options' ).json ) - diff --git a/python/ycm/server/tests/misc_handlers_test.py b/python/ycm/server/tests/misc_handlers_test.py new file mode 100644 index 00000000..e7d4f819 --- /dev/null +++ b/python/ycm/server/tests/misc_handlers_test.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python +# +# Copyright (C) 2013 Strahinja Val Markovic +# +# 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 . + +from ..server_utils import SetUpPythonPath +SetUpPythonPath() +from webtest import TestApp +from .. import handlers +from nose.tools import ok_, eq_, with_setup +from .test_utils import Setup +import bottle + +bottle.debug( True ) + + +@with_setup( Setup ) +def SemanticCompletionAvailable_Works_test(): + app = TestApp( handlers.app ) + request_data = { + 'filetypes': ['python'] + } + + ok_( app.post_json( '/semantic_completion_available', + request_data ).json ) + + +@with_setup( Setup ) +def UserOptions_Works_test(): + app = TestApp( handlers.app ) + options = app.get( '/user_options' ).json + ok_( len( options ) ) + + options[ 'foobar' ] = 'zoo' + + app.post_json( '/user_options', options ) + eq_( options, app.get( '/user_options' ).json ) + diff --git a/python/ycm/server/tests/subcommands_test.py b/python/ycm/server/tests/subcommands_test.py new file mode 100644 index 00000000..4c629e62 --- /dev/null +++ b/python/ycm/server/tests/subcommands_test.py @@ -0,0 +1,111 @@ +#!/usr/bin/env python +# +# Copyright (C) 2013 Strahinja Val Markovic +# +# 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 . + +from ..server_utils import SetUpPythonPath +SetUpPythonPath() +from .test_utils import Setup, BuildRequest +from webtest import TestApp +from nose.tools import eq_, with_setup +from .. import handlers +import bottle + +bottle.debug( True ) + + +@with_setup( Setup ) +def RunCompleterCommand_GoTo_Jedi_ZeroBasedLineAndColumn_test(): + app = TestApp( handlers.app ) + contents = """ +def foo(): + pass + +foo() +""" + + goto_data = BuildRequest( completer_target = 'filetype_default', + command_arguments = ['GoToDefinition'], + line_num = 4, + contents = contents, + filetype = 'python', + filepath = '/foo.py' ) + + # 0-based line and column! + eq_( { + 'filepath': '/foo.py', + 'line_num': 1, + 'column_num': 4 + }, + app.post_json( '/run_completer_command', goto_data ).json ) + + +@with_setup( Setup ) +def RunCompleterCommand_GoTo_Clang_ZeroBasedLineAndColumn_test(): + app = TestApp( handlers.app ) + contents = """ +struct Foo { + int x; + int y; + char c; +}; + +int main() +{ + Foo foo; + return 0; +} +""" + + goto_data = BuildRequest( completer_target = 'filetype_default', + command_arguments = ['GoToDefinition'], + compilation_flags = ['-x', 'c++'], + line_num = 9, + column_num = 2, + contents = contents, + filetype = 'cpp' ) + + # 0-based line and column! + eq_( { + 'filepath': '/foo', + 'line_num': 1, + 'column_num': 7 + }, + app.post_json( '/run_completer_command', goto_data ).json ) + + +@with_setup( Setup ) +def DefinedSubcommands_Works_test(): + app = TestApp( handlers.app ) + subcommands_data = BuildRequest( completer_target = 'python' ) + + eq_( [ 'GoToDefinition', + 'GoToDeclaration', + 'GoToDefinitionElseDeclaration' ], + app.post_json( '/defined_subcommands', subcommands_data ).json ) + + +@with_setup( Setup ) +def DefinedSubcommands_WorksWhenNoExplicitCompleterTargetSpecified_test(): + app = TestApp( handlers.app ) + subcommands_data = BuildRequest( filetype = 'python' ) + + eq_( [ 'GoToDefinition', + 'GoToDeclaration', + 'GoToDefinitionElseDeclaration' ], + app.post_json( '/defined_subcommands', subcommands_data ).json ) + diff --git a/python/ycm/server/tests/test_utils.py b/python/ycm/server/tests/test_utils.py new file mode 100644 index 00000000..1638da9c --- /dev/null +++ b/python/ycm/server/tests/test_utils.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python +# +# Copyright (C) 2013 Strahinja Val Markovic +# +# 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 . + +import os +from .. import handlers + +def BuildRequest( **kwargs ): + filepath = kwargs[ 'filepath' ] if 'filepath' in kwargs else '/foo' + contents = kwargs[ 'contents' ] if 'contents' in kwargs else '' + filetype = kwargs[ 'filetype' ] if 'filetype' in kwargs else 'foo' + + request = { + 'query': '', + 'line_num': 0, + 'column_num': 0, + 'start_column': 0, + 'filetypes': [ filetype ], + 'filepath': filepath, + 'line_value': contents, + 'file_data': { + filepath: { + 'contents': contents, + 'filetypes': [ filetype ] + } + } + } + + for key, value in kwargs.iteritems(): + if key in [ 'contents', 'filetype', 'filepath' ]: + continue + request[ key ] = value + + if key == 'line_num': + lines = contents.splitlines() + if len( lines ) > 1: + # NOTE: assumes 0-based line_num + request[ 'line_value' ] = lines[ value ] + + return request + + +def Setup(): + handlers.SetServerStateToDefaults() + + +def PathToTestDataDir(): + dir_of_current_script = os.path.dirname( os.path.abspath( __file__ ) ) + return os.path.join( dir_of_current_script, 'testdata' ) + + +def PathToTestFile( test_basename ): + return os.path.join( PathToTestDataDir(), test_basename ) + +