class YouCompleteMe_test(): # Minimal options to create the YouCompleteMe object. DEFAULT_OPTIONS = { 'ycm_server_log_level': 'info', 'ycm_server_keep_logfiles': 0, 'ycm_min_num_of_chars_for_completion': 2, 'ycm_auto_trigger': 1, 'ycm_semantic_triggers': {} } def setUp(self): with patch('vim.eval', side_effect=self.VimEval): user_options_store.SetAll(base.BuildServerConf()) self.ycm = YouCompleteMe(user_options_store.GetAll()) def tearDown(self): self.ycm.OnVimLeave() def VimEval(self, value): if value == 'g:': return self.DEFAULT_OPTIONS def YcmCoreNotImported_test(self): assert_that('ycm_core', is_not(is_in(sys.modules)))
def Wrapper(*args, **kwargs): ycm = YouCompleteMe(_MakeUserOptions(custom_options)) _WaitUntilReady() try: test(ycm, *args, **kwargs) finally: ycm.OnVimLeave() WaitUntilProcessIsTerminated(ycm._server_popen)
class YouCompleteMe_test(): def setUp(self): self.ycm = YouCompleteMe(MagicMock(spec_set=dict)) def tearDown(self): self.ycm.OnVimLeave() def YcmCoreNotImported_test(self): assert_that('ycm_core', is_not(is_in(sys.modules)))
class EventNotification_test(object): def setUp(self): options = dict(user_options_store.DefaultOptions()) options.update(DEFAULT_CLIENT_OPTIONS) user_options_store.SetAll(options) self.server_state = YouCompleteMe(user_options_store.GetAll()) pass def tearDown(self): if self.server_state: self.server_state.OnVimLeave() @patch('vim.command', new_callable=ExtendedMock) def FileReadyToParse_NonDiagnostic_Error_test(self, vim_command): # This test validates the behaviour of YouCompleteMe.HandleFileParseRequest # in combination with YouCompleteMe.OnFileReadyToParse when the completer # raises an exception handling FileReadyToParse event notification ERROR_TEXT = 'Some completer response text' def ErrorResponse(*args): raise RuntimeError(ERROR_TEXT) with MockArbitraryBuffer('javascript'): with MockEventNotification(ErrorResponse): self.server_state.OnFileReadyToParse() assert self.server_state.FileParseRequestReady() self.server_state.HandleFileParseRequest() # The first call raises a warning vim_command.assert_has_exact_calls([ PostVimMessage_Call(ERROR_TEXT), ]) # Subsequent calls don't re-raise the warning self.server_state.HandleFileParseRequest() vim_command.assert_has_exact_calls([ PostVimMessage_Call(ERROR_TEXT), ]) # But it does if a subsequent event raises again self.server_state.OnFileReadyToParse() assert self.server_state.FileParseRequestReady() self.server_state.HandleFileParseRequest() vim_command.assert_has_exact_calls([ PostVimMessage_Call(ERROR_TEXT), PostVimMessage_Call(ERROR_TEXT), ]) @patch('vim.command') def FileReadyToParse_NonDiagnostic_Error_NonNative_test(self, vim_command): with MockArbitraryBuffer('javascript'): with MockEventNotification(None, False): self.server_state.OnFileReadyToParse() self.server_state.HandleFileParseRequest() vim_command.assert_not_called() @patch('ycm.client.event_notification._LoadExtraConfFile', new_callable=ExtendedMock) @patch('ycm.client.event_notification._IgnoreExtraConfFile', new_callable=ExtendedMock) def FileReadyToParse_NonDiagnostic_ConfirmExtraConf_test( self, ignore_extra_conf, load_extra_conf, *args): # This test validates the behaviour of YouCompleteMe.HandleFileParseRequest # in combination with YouCompleteMe.OnFileReadyToParse when the completer # raises the (special) UnknownExtraConf exception FILE_NAME = 'a_file' MESSAGE = ('Found ' + FILE_NAME + '. Load? \n\n(Question can be ' 'turned off with options, see YCM docs)') def UnknownExtraConfResponse(*args): raise UnknownExtraConf(FILE_NAME) with MockArbitraryBuffer('javascript'): with MockEventNotification(UnknownExtraConfResponse): # When the user accepts the extra conf, we load it with patch('ycm.vimsupport.PresentDialog', return_value=0, new_callable=ExtendedMock) as present_dialog: self.server_state.OnFileReadyToParse() assert self.server_state.FileParseRequestReady() self.server_state.HandleFileParseRequest() present_dialog.assert_has_exact_calls([ PresentDialog_Confirm_Call(MESSAGE), ]) load_extra_conf.assert_has_exact_calls([ call(FILE_NAME), ]) # Subsequent calls don't re-raise the warning self.server_state.HandleFileParseRequest() present_dialog.assert_has_exact_calls( [PresentDialog_Confirm_Call(MESSAGE)]) load_extra_conf.assert_has_exact_calls([ call(FILE_NAME), ]) # But it does if a subsequent event raises again self.server_state.OnFileReadyToParse() assert self.server_state.FileParseRequestReady() self.server_state.HandleFileParseRequest() present_dialog.assert_has_exact_calls([ PresentDialog_Confirm_Call(MESSAGE), PresentDialog_Confirm_Call(MESSAGE), ]) load_extra_conf.assert_has_exact_calls([ call(FILE_NAME), call(FILE_NAME), ]) # When the user rejects the extra conf, we reject it with patch('ycm.vimsupport.PresentDialog', return_value=1, new_callable=ExtendedMock) as present_dialog: self.server_state.OnFileReadyToParse() assert self.server_state.FileParseRequestReady() self.server_state.HandleFileParseRequest() present_dialog.assert_has_exact_calls([ PresentDialog_Confirm_Call(MESSAGE), ]) ignore_extra_conf.assert_has_exact_calls([ call(FILE_NAME), ]) # Subsequent calls don't re-raise the warning self.server_state.HandleFileParseRequest() present_dialog.assert_has_exact_calls( [PresentDialog_Confirm_Call(MESSAGE)]) ignore_extra_conf.assert_has_exact_calls([ call(FILE_NAME), ]) # But it does if a subsequent event raises again self.server_state.OnFileReadyToParse() assert self.server_state.FileParseRequestReady() self.server_state.HandleFileParseRequest() present_dialog.assert_has_exact_calls([ PresentDialog_Confirm_Call(MESSAGE), PresentDialog_Confirm_Call(MESSAGE), ]) ignore_extra_conf.assert_has_exact_calls([ call(FILE_NAME), call(FILE_NAME), ]) def FileReadyToParse_Diagnostic_Error_Native_test(self): self._Check_FileReadyToParse_Diagnostic_Error() self._Check_FileReadyToParse_Diagnostic_Warning() self._Check_FileReadyToParse_Diagnostic_Clean() @patch('vim.command') def _Check_FileReadyToParse_Diagnostic_Error(self, vim_command): # Tests Vim sign placement and error/warning count python API # when one error is returned. def DiagnosticResponse(*args): start = Location(1, 2, 'TEST_BUFFER') end = Location(1, 4, 'TEST_BUFFER') extent = Range(start, end) diagnostic = Diagnostic([], start, extent, 'expected ;', 'ERROR') return [BuildDiagnosticData(diagnostic)] with MockArbitraryBuffer('cpp'): with MockEventNotification(DiagnosticResponse): self.server_state.OnFileReadyToParse() ok_(self.server_state.FileParseRequestReady()) self.server_state.HandleFileParseRequest() vim_command.assert_has_calls([PlaceSign_Call(1, 1, 0, True)]) eq_(self.server_state.GetErrorCount(), 1) eq_(self.server_state.GetWarningCount(), 0) # Consequent calls to HandleFileParseRequest shouldn't mess with # existing diagnostics, when there is no new parse request. vim_command.reset_mock() ok_(not self.server_state.FileParseRequestReady()) self.server_state.HandleFileParseRequest() vim_command.assert_not_called() eq_(self.server_state.GetErrorCount(), 1) eq_(self.server_state.GetWarningCount(), 0) @patch('vim.command') def _Check_FileReadyToParse_Diagnostic_Warning(self, vim_command): # Tests Vim sign placement/unplacement and error/warning count python API # when one warning is returned. # Should be called after _Check_FileReadyToParse_Diagnostic_Error def DiagnosticResponse(*args): start = Location(2, 2, 'TEST_BUFFER') end = Location(2, 4, 'TEST_BUFFER') extent = Range(start, end) diagnostic = Diagnostic([], start, extent, 'cast', 'WARNING') return [BuildDiagnosticData(diagnostic)] with MockArbitraryBuffer('cpp'): with MockEventNotification(DiagnosticResponse): self.server_state.OnFileReadyToParse() ok_(self.server_state.FileParseRequestReady()) self.server_state.HandleFileParseRequest() vim_command.assert_has_calls( [PlaceSign_Call(2, 2, 0, False), UnplaceSign_Call(1, 0)]) eq_(self.server_state.GetErrorCount(), 0) eq_(self.server_state.GetWarningCount(), 1) # Consequent calls to HandleFileParseRequest shouldn't mess with # existing diagnostics, when there is no new parse request. vim_command.reset_mock() ok_(not self.server_state.FileParseRequestReady()) self.server_state.HandleFileParseRequest() vim_command.assert_not_called() eq_(self.server_state.GetErrorCount(), 0) eq_(self.server_state.GetWarningCount(), 1) @patch('vim.command') def _Check_FileReadyToParse_Diagnostic_Clean(self, vim_command): # Tests Vim sign unplacement and error/warning count python API # when there are no errors/warnings left. # Should be called after _Check_FileReadyToParse_Diagnostic_Warning with MockArbitraryBuffer('cpp'): with MockEventNotification(MagicMock(return_value=[])): self.server_state.OnFileReadyToParse() self.server_state.HandleFileParseRequest() vim_command.assert_has_calls([UnplaceSign_Call(2, 0)]) eq_(self.server_state.GetErrorCount(), 0) eq_(self.server_state.GetWarningCount(), 0)
class PostComplete_test(): def setUp( self ): self.ycm = YouCompleteMe( MagicMock( spec_set = dict ) ) def tearDown( self ): self.ycm.OnVimLeave() @contextlib.contextmanager def _SetupForCsharpCompletionDone( self, completions ): with patch( 'ycm.vimsupport.InsertNamespace' ): with patch( 'ycm.vimsupport.TextBeforeCursor', return_value = ' Test' ): request = MagicMock() request.Done = MagicMock( return_value = True ) request.RawResponse = MagicMock( return_value = completions ) self.ycm._latest_completion_request = request yield @patch( 'ycm.vimsupport.CurrentFiletypes', return_value = [ "cs" ] ) def GetCompleteDoneHooks_ResultOnCsharp_test( self, *args ): result = self.ycm.GetCompleteDoneHooks() eq_( 1, len( list( result ) ) ) @patch( 'ycm.vimsupport.CurrentFiletypes', return_value = [ "txt" ] ) def GetCompleteDoneHooks_EmptyOnOtherFiletype_test( self, *args ): result = self.ycm.GetCompleteDoneHooks() eq_( 0, len( list( result ) ) ) @patch( 'ycm.vimsupport.CurrentFiletypes', return_value = [ "txt" ] ) def OnCompleteDone_WithActionCallsIt_test( self, *args ): action = MagicMock() self.ycm._complete_done_hooks[ "txt" ] = action self.ycm.OnCompleteDone() ok_( action.called ) @patch( 'ycm.vimsupport.CurrentFiletypes', return_value = [ "txt" ] ) def OnCompleteDone_NoActionNoError_test( self, *args ): self.ycm.OnCompleteDone() @patch( 'ycm.vimsupport.VimVersionAtLeast', return_value = True ) @patch( 'ycm.vimsupport.GetVariableValue', GetVariableValue_CompleteItemIs( 'Test' ) ) def FilterToCompletedCompletions_NewVim_MatchIsReturned_test( self, *args ): completions = [ BuildCompletion( "Test" ) ] result = self.ycm._FilterToMatchingCompletions( completions, False ) eq_( list( result ), completions ) @patch( 'ycm.vimsupport.VimVersionAtLeast', return_value = True ) @patch( 'ycm.vimsupport.GetVariableValue', GetVariableValue_CompleteItemIs( 'A' ) ) def FilterToCompletedCompletions_NewVim_ShortTextDoesntRaise_test( self, *args ): completions = [ BuildCompletion( "AAA" ) ] self.ycm._FilterToMatchingCompletions( completions, False ) @patch( 'ycm.vimsupport.VimVersionAtLeast', return_value = True ) @patch( 'ycm.vimsupport.GetVariableValue', GetVariableValue_CompleteItemIs( 'Test' ) ) def FilterToCompletedCompletions_NewVim_ExactMatchIsReturned_test( self, *args ): completions = [ BuildCompletion( "Test" ) ] result = self.ycm._FilterToMatchingCompletions( completions, False ) eq_( list( result ), completions ) @patch( 'ycm.vimsupport.VimVersionAtLeast', return_value = True ) @patch( 'ycm.vimsupport.GetVariableValue', GetVariableValue_CompleteItemIs( ' Quote' ) ) def FilterToCompletedCompletions_NewVim_NonMatchIsntReturned_test( self, *args ): completions = [ BuildCompletion( "A" ) ] result = self.ycm._FilterToMatchingCompletions( completions, False ) assert_that( list( result ), empty() ) @patch( 'ycm.vimsupport.VimVersionAtLeast', return_value = False ) @patch( 'ycm.vimsupport.TextBeforeCursor', return_value = " Test" ) def FilterToCompletedCompletions_OldVim_MatchIsReturned_test( self, *args ): completions = [ BuildCompletion( "Test" ) ] result = self.ycm._FilterToMatchingCompletions( completions, False ) eq_( list( result ), completions ) @patch( 'ycm.vimsupport.VimVersionAtLeast', return_value = False ) @patch( 'ycm.vimsupport.TextBeforeCursor', return_value = "X" ) def FilterToCompletedCompletions_OldVim_ShortTextDoesntRaise_test( self, *args ): completions = [ BuildCompletion( "AAA" ) ] self.ycm._FilterToMatchingCompletions( completions, False ) @patch( 'ycm.vimsupport.VimVersionAtLeast', return_value = False ) @patch( 'ycm.vimsupport.TextBeforeCursor', return_value = "Test" ) def FilterToCompletedCompletions_OldVim_ExactMatchIsReturned_test( self, *args ): completions = [ BuildCompletion( "Test" ) ] result = self.ycm._FilterToMatchingCompletions( completions, False ) eq_( list( result ), completions ) @patch( 'ycm.vimsupport.VimVersionAtLeast', return_value = False ) @patch( 'ycm.vimsupport.TextBeforeCursor', return_value = " Quote" ) def FilterToCompletedCompletions_OldVim_NonMatchIsntReturned_test( self, *args ): completions = [ BuildCompletion( "A" ) ] result = self.ycm._FilterToMatchingCompletions( completions, False ) assert_that( list( result ), empty() ) @patch( 'ycm.vimsupport.VimVersionAtLeast', return_value = False ) @patch( 'ycm.vimsupport.TextBeforeCursor', return_value = " Te" ) def HasCompletionsThatCouldBeCompletedWithMoreText_OldVim_MatchIsReturned_test( # noqa self, *args ): completions = [ BuildCompletion( "Test" ) ] result = self.ycm._HasCompletionsThatCouldBeCompletedWithMoreText( completions ) eq_( result, True ) @patch( 'ycm.vimsupport.VimVersionAtLeast', return_value = False ) @patch( 'ycm.vimsupport.TextBeforeCursor', return_value = "X" ) def HasCompletionsThatCouldBeCompletedWithMoreText_OldVim_ShortTextDoesntRaise_test( # noqa self, *args ): completions = [ BuildCompletion( "AAA" ) ] self.ycm._HasCompletionsThatCouldBeCompletedWithMoreText( completions ) @patch( 'ycm.vimsupport.VimVersionAtLeast', return_value = False ) @patch( 'ycm.vimsupport.TextBeforeCursor', return_value = "Test" ) def HasCompletionsThatCouldBeCompletedWithMoreText_OldVim_ExactMatchIsntReturned_test( # noqa self, *args ): completions = [ BuildCompletion( "Test" ) ] result = self.ycm._HasCompletionsThatCouldBeCompletedWithMoreText( completions ) eq_( result, False ) @patch( 'ycm.vimsupport.VimVersionAtLeast', return_value = False ) @patch( 'ycm.vimsupport.TextBeforeCursor', return_value = " Quote" ) def HasCompletionsThatCouldBeCompletedWithMoreText_OldVim_NonMatchIsntReturned_test( # noqa self, *args ): completions = [ BuildCompletion( "A" ) ] result = self.ycm._HasCompletionsThatCouldBeCompletedWithMoreText( completions ) eq_( result, False ) @patch( 'ycm.vimsupport.VimVersionAtLeast', return_value = True ) @patch( 'ycm.vimsupport.GetVariableValue', GetVariableValue_CompleteItemIs( "Te") ) @patch( 'ycm.vimsupport.TextBeforeCursor', return_value = " Quote" ) def HasCompletionsThatCouldBeCompletedWithMoreText_NewVim_MatchIsReturned_test( # noqa self, *args ): completions = [ BuildCompletion( "Test" ) ] result = self.ycm._HasCompletionsThatCouldBeCompletedWithMoreText( completions ) eq_( result, True ) @patch( 'ycm.vimsupport.VimVersionAtLeast', return_value = True ) @patch( 'ycm.vimsupport.GetVariableValue', GetVariableValue_CompleteItemIs( "X") ) @patch( 'ycm.vimsupport.TextBeforeCursor', return_value = " Quote" ) def HasCompletionsThatCouldBeCompletedWithMoreText_NewVim_ShortTextDoesntRaise_test( # noqa self, *args ): completions = [ BuildCompletion( "AAA" ) ] self.ycm._HasCompletionsThatCouldBeCompletedWithMoreText( completions ) @patch( 'ycm.vimsupport.VimVersionAtLeast', return_value = True ) @patch( 'ycm.vimsupport.GetVariableValue', GetVariableValue_CompleteItemIs( "Test" ) ) @patch( 'ycm.vimsupport.TextBeforeCursor', return_value = ' Quote' ) def HasCompletionsThatCouldBeCompletedWithMoreText_NewVim_ExactMatchIsntReturned_test( # noqa self, *args ): completions = [ BuildCompletion( "Test" ) ] result = self.ycm._HasCompletionsThatCouldBeCompletedWithMoreText( completions ) eq_( result, False ) @patch( 'ycm.vimsupport.VimVersionAtLeast', return_value = True ) @patch( 'ycm.vimsupport.GetVariableValue', GetVariableValue_CompleteItemIs( " Quote" ) ) @patch( 'ycm.vimsupport.TextBeforeCursor', return_value = ' Quote' ) def HasCompletionsThatCouldBeCompletedWithMoreText_NewVim_NonMatchIsntReturned_test( # noqa self, *args ): completions = [ BuildCompletion( "A" ) ] result = self.ycm._HasCompletionsThatCouldBeCompletedWithMoreText( completions ) eq_( result, False ) def GetRequiredNamespaceImport_ReturnNoneForNoExtraData_test( self ): eq_( None, self.ycm._GetRequiredNamespaceImport( {} ) ) def GetRequiredNamespaceImport_ReturnNamespaceFromExtraData_test( self ): namespace = "A_NAMESPACE" eq_( namespace, self.ycm._GetRequiredNamespaceImport( BuildCompletion( namespace ) ) ) def GetCompletionsUserMayHaveCompleted_ReturnEmptyIfNotDone_test( self ): with self._SetupForCsharpCompletionDone( [] ): self.ycm._latest_completion_request.Done = MagicMock( return_value = False ) eq_( [], self.ycm.GetCompletionsUserMayHaveCompleted() ) def GetCompletionsUserMayHaveCompleted_ReturnEmptyIfPendingMatches_NewVim_test( # noqa self ): completions = [ BuildCompletion( None ) ] with self._SetupForCsharpCompletionDone( completions ): with patch( 'ycm.vimsupport.VimVersionAtLeast', return_value = True ): with patch( 'ycm.vimsupport.GetVariableValue', GetVariableValue_CompleteItemIs( 'Te' ) ): eq_( [], self.ycm.GetCompletionsUserMayHaveCompleted() ) def GetCompletionsUserMayHaveCompleted_ReturnEmptyIfPendingMatches_OldVim_test( # noqa self, *args ): completions = [ BuildCompletion( None ) ] with self._SetupForCsharpCompletionDone( completions ): with patch( 'ycm.vimsupport.VimVersionAtLeast', return_value = True ): with patch( 'ycm.vimsupport.GetVariableValue', GetVariableValue_CompleteItemIs( 'Te' ) ): eq_( [], self.ycm.GetCompletionsUserMayHaveCompleted() ) def GetCompletionsUserMayHaveCompleted_ReturnMatchIfExactMatches_NewVim_test( self, *args ): info = [ "NS", "Test", "Abbr", "Menu", "Info", "Kind" ] completions = [ BuildCompletion( *info ) ] with self._SetupForCsharpCompletionDone( completions ): with patch( 'ycm.vimsupport.VimVersionAtLeast', return_value = True ): with patch( 'ycm.vimsupport.GetVariableValue', GetVariableValue_CompleteItemIs( *info[ 1: ] ) ): eq_( completions, self.ycm.GetCompletionsUserMayHaveCompleted() ) def GetCompletionsUserMayHaveCompleted_ReturnMatchIfExactMatchesEvenIfPartial_NewVim_test( # noqa self, *args ): info = [ "NS", "Test", "Abbr", "Menu", "Info", "Kind" ] completions = [ BuildCompletion( *info ), BuildCompletion( insertion_text = "TestTest" ) ] with self._SetupForCsharpCompletionDone( completions ): with patch( 'ycm.vimsupport.VimVersionAtLeast', return_value = True ): with patch( 'ycm.vimsupport.GetVariableValue', GetVariableValue_CompleteItemIs( *info[ 1: ] ) ): eq_( [ completions[ 0 ] ], self.ycm.GetCompletionsUserMayHaveCompleted() ) def GetCompletionsUserMayHaveCompleted_DontReturnMatchIfNontExactMatchesAndPartial_NewVim_test( # noqa self ): info = [ "NS", "Test", "Abbr", "Menu", "Info", "Kind" ] completions = [ BuildCompletion( insertion_text = info[ 0 ] ), BuildCompletion( insertion_text = "TestTest" ) ] with self._SetupForCsharpCompletionDone( completions ): with patch( 'ycm.vimsupport.VimVersionAtLeast', return_value = True ): with patch( 'ycm.vimsupport.GetVariableValue', GetVariableValue_CompleteItemIs( *info[ 1: ] ) ): eq_( [], self.ycm.GetCompletionsUserMayHaveCompleted() ) def GetCompletionsUserMayHaveCompleted_ReturnMatchIfMatches_NewVim_test( self, *args ): completions = [ BuildCompletion( None ) ] with self._SetupForCsharpCompletionDone( completions ): with patch( 'ycm.vimsupport.VimVersionAtLeast', return_value = True ): with patch( 'ycm.vimsupport.GetVariableValue', GetVariableValue_CompleteItemIs( "Test" ) ): eq_( completions, self.ycm.GetCompletionsUserMayHaveCompleted() ) def GetCompletionsUserMayHaveCompleted_ReturnMatchIfMatches_OldVim_test( self, *args ): completions = [ BuildCompletion( None ) ] with self._SetupForCsharpCompletionDone( completions ): with patch( 'ycm.vimsupport.VimVersionAtLeast', return_value = False ): eq_( completions, self.ycm.GetCompletionsUserMayHaveCompleted() ) def PostCompleteCsharp_EmptyDoesntInsertNamespace_test( self, *args ): with self._SetupForCsharpCompletionDone( [] ): with patch( 'ycm.vimsupport.VimVersionAtLeast', return_value = False ): self.ycm._OnCompleteDone_Csharp() ok_( not vimsupport.InsertNamespace.called ) def PostCompleteCsharp_ExistingWithoutNamespaceDoesntInsertNamespace_test( self, *args ): completions = [ BuildCompletion( None ) ] with self._SetupForCsharpCompletionDone( completions ): with patch( 'ycm.vimsupport.VimVersionAtLeast', return_value = False ): self.ycm._OnCompleteDone_Csharp() ok_( not vimsupport.InsertNamespace.called ) def PostCompleteCsharp_ValueDoesInsertNamespace_test( self, *args ): namespace = "A_NAMESPACE" completions = [ BuildCompletion( namespace ) ] with self._SetupForCsharpCompletionDone( completions ): with patch( 'ycm.vimsupport.VimVersionAtLeast', return_value = False ): self.ycm._OnCompleteDone_Csharp() vimsupport.InsertNamespace.assert_called_once_with( namespace ) def PostCompleteCsharp_InsertSecondNamespaceIfSelected_test( self, *args ): namespace = "A_NAMESPACE" namespace2 = "ANOTHER_NAMESPACE" completions = [ BuildCompletion( namespace ), BuildCompletion( namespace2 ), ] with self._SetupForCsharpCompletionDone( completions ): with patch( 'ycm.vimsupport.VimVersionAtLeast', return_value = False ): with patch( 'ycm.vimsupport.PresentDialog', return_value = 1 ): self.ycm._OnCompleteDone_Csharp() vimsupport.InsertNamespace.assert_called_once_with( namespace2 )
class EventNotification_test(object): def setUp(self): options = dict(user_options_store.DefaultOptions()) options.update(DEFAULT_CLIENT_OPTIONS) user_options_store.SetAll(options) self.server_state = YouCompleteMe(user_options_store.GetAll()) pass def tearDown(self): if self.server_state: self.server_state.OnVimLeave() @patch('vim.command') def FileReadyToParse_NonDiagnostic_Error_test(self, vim_command): # This test validates the behaviour of YouCompleteMe.ValidateParseRequest in # combination with YouCompleteMe.OnFileReadyToParse when the completer # raises an exception handling FileReadyToParse event notification ERROR_TEXT = 'Some completer response text' def ErrorResponse(*args): raise RuntimeError(ERROR_TEXT) with MockArbitraryBuffer('javascript'): with MockEventNotification(ErrorResponse): self.server_state.OnFileReadyToParse() assert self.server_state.DiagnosticsForCurrentFileReady() self.server_state.ValidateParseRequest() # The first call raises a warning vim_command.assert_has_calls([ PostVimMessage_Call(ERROR_TEXT), ]) # Subsequent calls don't re-raise the warning self.server_state.ValidateParseRequest() vim_command.assert_has_calls([ PostVimMessage_Call(ERROR_TEXT), ]) # But it does if a subsequent event raises again self.server_state.OnFileReadyToParse() assert self.server_state.DiagnosticsForCurrentFileReady() self.server_state.ValidateParseRequest() vim_command.assert_has_calls([ PostVimMessage_Call(ERROR_TEXT), PostVimMessage_Call(ERROR_TEXT), ]) @patch('vim.command') def FileReadyToParse_NonDiagnostic_Error_NonNative_test(self, vim_command): with MockArbitraryBuffer('javascript'): with MockEventNotification(None, False): self.server_state.OnFileReadyToParse() self.server_state.ValidateParseRequest() vim_command.assert_not_called() @patch('ycm.client.event_notification._LoadExtraConfFile') @patch('ycm.client.event_notification._IgnoreExtraConfFile') def FileReadyToParse_NonDiagnostic_ConfirmExtraConf_test( self, ignore_extra_conf, load_extra_conf, *args): # This test validates the behaviour of YouCompleteMe.ValidateParseRequest in # combination with YouCompleteMe.OnFileReadyToParse when the completer # raises the (special) UnknownExtraConf exception FILE_NAME = 'a_file' MESSAGE = ('Found ' + FILE_NAME + '. Load? \n\n(Question can be ' 'turned off with options, see YCM docs)') def UnknownExtraConfResponse(*args): raise UnknownExtraConf(FILE_NAME) with MockArbitraryBuffer('javascript'): with MockEventNotification(UnknownExtraConfResponse): # When the user accepts the extra conf, we load it with patch('ycm.vimsupport.PresentDialog', return_value=0) as present_dialog: self.server_state.OnFileReadyToParse() assert self.server_state.DiagnosticsForCurrentFileReady() self.server_state.ValidateParseRequest() present_dialog.assert_has_calls([ PresentDialog_Confirm_Call(MESSAGE), ]) load_extra_conf.assert_has_calls([ call(FILE_NAME), ]) # Subsequent calls don't re-raise the warning self.server_state.ValidateParseRequest() present_dialog.assert_has_calls( [PresentDialog_Confirm_Call(MESSAGE)]) load_extra_conf.assert_has_calls([ call(FILE_NAME), ]) # But it does if a subsequent event raises again self.server_state.OnFileReadyToParse() assert self.server_state.DiagnosticsForCurrentFileReady() self.server_state.ValidateParseRequest() present_dialog.assert_has_calls([ PresentDialog_Confirm_Call(MESSAGE), PresentDialog_Confirm_Call(MESSAGE), ]) load_extra_conf.assert_has_calls([ call(FILE_NAME), call(FILE_NAME), ]) # When the user rejects the extra conf, we reject it with patch('ycm.vimsupport.PresentDialog', return_value=1) as present_dialog: self.server_state.OnFileReadyToParse() assert self.server_state.DiagnosticsForCurrentFileReady() self.server_state.ValidateParseRequest() present_dialog.assert_has_calls([ PresentDialog_Confirm_Call(MESSAGE), ]) ignore_extra_conf.assert_has_calls([ call(FILE_NAME), ]) # Subsequent calls don't re-raise the warning self.server_state.ValidateParseRequest() present_dialog.assert_has_calls( [PresentDialog_Confirm_Call(MESSAGE)]) ignore_extra_conf.assert_has_calls([ call(FILE_NAME), ]) # But it does if a subsequent event raises again self.server_state.OnFileReadyToParse() assert self.server_state.DiagnosticsForCurrentFileReady() self.server_state.ValidateParseRequest() present_dialog.assert_has_calls([ PresentDialog_Confirm_Call(MESSAGE), PresentDialog_Confirm_Call(MESSAGE), ]) ignore_extra_conf.assert_has_calls([ call(FILE_NAME), call(FILE_NAME), ])
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': 'Ê' }])