def test_default_completion_items(self):
        """
        Test that the completion handler returns a set of default values
        when not connected to any URI
        """
        # If: The script file exists
        input_text = 'create tab'
        doc_position = TextDocumentPosition.from_dict({
            'text_document': {
                'uri': self.default_uri
            },
            'position': {
                'line': 0,
                'character': 10  # end of 'tab' word
            }
        })
        context: RequestContext = utils.MockRequestContext()
        config = Configuration()
        config.sql.intellisense.enable_intellisense = True
        self.mock_workspace_service._configuration = config
        workspace, script_file = self._get_test_workspace(True, input_text)
        self.mock_workspace_service._workspace = workspace
        service: LanguageService = self._init_service()
        service._valid_uri.add(doc_position.text_document.uri)

        # When: I request completion item
        service.handle_completion_request(context, doc_position)

        # Then:
        # ... An default completion set should be sent over the notification
        context.send_response.assert_called_once()
        completions: List[CompletionItem] = context.last_response_params
        self.assertTrue(len(completions) > 0)
        self.verify_match('TABLE', completions, Range.from_data(0, 7, 0, 10))
    def test_format_doc_no_pgsql_format(self):
        """
        Test that the format codepath succeeds even if the configuration options aren't defined
        """
        input_text = 'select * from foo where id in (select id from bar);'

        context: RequestContext = utils.MockRequestContext()

        self.mock_workspace_service._configuration = None
        workspace, script_file = self._get_test_workspace(True, input_text)
        self.mock_workspace_service._workspace = workspace
        service: LanguageService = self._init_service()

        format_options = FormattingOptions()
        format_options.insert_spaces = False
        format_params = DocumentFormattingParams()
        format_params.options = format_options
        format_params.text_document = self.default_text_document_id
        # add uri to valid uri set ensure request passes uri check
        # normally done in flavor change handler, but we are not testing that here
        service._valid_uri.add(format_params.text_document.uri)

        # When: I have no useful formatting defaults defined
        service.handle_doc_format_request(context, format_params)

        # Then:
        # ... There should be no changes to the doc
        context.send_response.assert_called_once()
        edits: List[TextEdit] = context.last_response_params
        self.assertTrue(len(edits) > 0)
        self.assert_range_equals(edits[0].range,
                                 Range.from_data(0, 0, 0, len(input_text)))
        self.assertEqual(edits[0].new_text, input_text)
Example #3
0
    def test_get_lines_in_range_invalid_start(self):
        # Setup: Create a script file with a selection of test text
        sf = self._get_test_script_file()

        with self.assertRaises(ValueError):
            # If: I ask for the lines of a file that have an invalid start
            # Then: I should get an exception
            params = Range.from_data(-1, 200, 2, 3)
            sf.get_lines_in_range(params)
Example #4
0
    def test_get_lines_in_range_valid(self):
        # Setup: Create a script file with a selection of test text
        sf = self._get_test_script_file()

        # If: I ask for the valid lines of the file
        params = Range.from_data(1, 1, 3, 1)
        result = sf.get_lines_in_range(params)

        # Then: I should get a set of lines with the expected result
        expected_result = ['ef', 'ghij', 'k']
        self.assertEqual(result, expected_result)
Example #5
0
    def test_get_text_in_range_start_of_line(self):
        """Test that get_text_in_range works when the cursor is at the start of a line"""
        sf = self._get_test_script_file()

        # If I get text from a range that covers the entire first line and ends on the second line before any text
        params = Range.from_data(0, 0, 1, 0)
        result = sf.get_text_in_range(params)

        # Then I should get the first line and a line with no content as the result
        expected_result = os.linesep.join(['abc', ''])
        self.assertEqual(result, expected_result)
    def test_format_mysql_doc_range(self):
        """
        Test that the format document range codepath works as expected with a mysql doc
        """
        # set up service provider with mysql connection
        self.mock_service_provider = ServiceProvider(self.mock_server, {},
                                                     MYSQL_PROVIDER_NAME, None)
        self.mock_service_provider._services[
            constants.WORKSPACE_SERVICE_NAME] = self.mock_workspace_service
        self.mock_service_provider._services[
            constants.CONNECTION_SERVICE_NAME] = self.mock_connection_service
        self.mock_service_provider._is_initialized = True

        # If: The script file doesn't exist (there is an empty workspace)
        input_lines: List[str] = [
            'select * from t1',
            'select * from foo where id in (select id from bar);'
        ]
        input_text = '\n'.join(input_lines)
        expected_output = '\n'.join([
            'SELECT *', 'FROM foo', 'WHERE id IN', '\t\t\t\t(SELECT id',
            '\t\t\t\t\tFROM bar);'
        ])

        context: RequestContext = utils.MockRequestContext()
        config = Configuration()
        config.my_sql = MySQLConfiguration()
        config.my_sql.format.keyword_case = 'upper'
        self.mock_workspace_service._configuration = config
        workspace, script_file = self._get_test_workspace(True, input_text)
        self.mock_workspace_service._workspace = workspace
        service: LanguageService = self._init_service()

        format_options = FormattingOptions()
        format_options.insert_spaces = False
        format_params = DocumentRangeFormattingParams()
        format_params.options = format_options
        format_params.text_document = self.default_text_document_id
        # add uri to valid uri set ensure request passes uri check
        # normally done in flavor change handler, but we are not testing that here
        service._valid_uri.add(format_params.text_document.uri)

        # When: I request format the 2nd line of a document
        format_params.range = Range.from_data(1, 0, 1, len(input_lines[1]))
        service.handle_doc_range_format_request(context, format_params)

        # Then:
        # ... only the 2nd line should be formatted
        context.send_response.assert_called_once()
        edits: List[TextEdit] = context.last_response_params
        self.assertTrue(len(edits) > 0)
        self.assert_range_equals(edits[0].range, format_params.range)
        self.assertEqual(edits[0].new_text, expected_output)
Example #7
0
 def test_get_matches_full_keyword(self):
     """Test get matches on a keyword"""
     # Given a default completion helper
     helper = DefaultCompletionHelper()
     text_range = Range.from_data(1, 1, 1, 2)
     start = 'create'
     # When I match 'create'
     matches: List[CompletionItem] = helper.get_matches(
         start, text_range, False)
     # Then I expect only 1 match
     self.assertEqual(1, len(matches))
     # ... and I expect words to be uppercased
     self.verify_match('CREATE', matches, text_range)
    def test_format_mysql_doc(self):
        """
        Test that the format document codepath works as expected with a mysql doc
        """
        # set up service provider with mysql connection
        self.mock_service_provider = ServiceProvider(self.mock_server, {},
                                                     MYSQL_PROVIDER_NAME, None)
        self.mock_service_provider._services[
            constants.WORKSPACE_SERVICE_NAME] = self.mock_workspace_service
        self.mock_service_provider._services[
            constants.CONNECTION_SERVICE_NAME] = self.mock_connection_service
        self.mock_service_provider._is_initialized = True

        # If: We have a basic string to be formatted
        input_text = 'select * from foo where id in (select id from bar);'
        # Note: sqlparse always uses '\n\ for line separator even on windows.
        # For now, respecting this behavior and leaving as-is
        expected_output = '\n'.join([
            'SELECT *', 'FROM foo', 'WHERE id IN', '\t\t\t\t(SELECT id',
            '\t\t\t\t\tFROM bar);'
        ])

        context: RequestContext = utils.MockRequestContext()
        config = Configuration()
        config.my_sql = MySQLConfiguration()
        config.my_sql.format.keyword_case = 'upper'
        self.mock_workspace_service._configuration = config
        workspace, script_file = self._get_test_workspace(True, input_text)
        self.mock_workspace_service._workspace = workspace
        service: LanguageService = self._init_service()

        format_options = FormattingOptions()
        format_options.insert_spaces = False
        format_params = DocumentFormattingParams()
        format_params.options = format_options
        format_params.text_document = self.default_text_document_id
        # add uri to valid uri set ensure request passes uri check
        # normally done in flavor change handler, but we are not testing that here
        service._valid_uri.add(format_params.text_document.uri)

        # When: I request document formatting
        service.handle_doc_format_request(context, format_params)

        # Then:
        # ... The entire document text should be formatted
        context.send_response.assert_called_once()
        edits: List[TextEdit] = context.last_response_params
        self.assertTrue(len(edits) > 0)
        self.assert_range_equals(edits[0].range,
                                 Range.from_data(0, 0, 0, len(input_text)))
        self.assertEqual(edits[0].new_text, expected_output)
Example #9
0
    def handle_definition_request(
            self, request_context: RequestContext,
            text_document_position: TextDocumentPosition) -> None:
        request_context.send_notification(
            STATUS_CHANGE_NOTIFICATION,
            StatusChangeParams(
                owner_uri=text_document_position.text_document.uri,
                status="DefinitionRequested"))

        def do_send_default_empty_response():
            request_context.send_response([])

        if self.should_skip_intellisense(
                text_document_position.text_document.uri):
            do_send_default_empty_response()
            return

        script_file: ScriptFile = self._workspace_service.workspace.get_file(
            text_document_position.text_document.uri)
        if script_file is None:
            do_send_default_empty_response()
            return

        script_parse_info: ScriptParseInfo = self.get_script_parse_info(
            text_document_position.text_document.uri,
            create_if_not_exists=False)
        if not script_parse_info or not script_parse_info.can_queue():
            do_send_default_empty_response()
            return

        cursor_position: int = len(
            script_file.get_text_in_range(
                Range.from_data(0, 0, text_document_position.position.line,
                                text_document_position.position.character)))
        text: str = script_file.get_all_text()
        script_parse_info.document = Document(text, cursor_position)

        operation = QueuedOperation(
            script_parse_info.connection_key,
            functools.partial(self.send_definition_using_connected_completions,
                              request_context, script_parse_info,
                              text_document_position),
            functools.partial(do_send_default_empty_response))
        self.operations_queue.add_operation(operation)
        request_context.send_notification(
            STATUS_CHANGE_NOTIFICATION,
            StatusChangeParams(
                owner_uri=text_document_position.text_document.uri,
                status="DefinitionRequestCompleted"))
Example #10
0
    def handle_completion_request(self, request_context: RequestContext,
                                  params: TextDocumentPosition) -> None:
        """
        Lookup available completions when valid completion suggestions are requested.
        Sends an array of CompletionItem objects over the wire
        """
        response = []

        def do_send_default_empty_response():
            request_context.send_response(response)

        script_file: ScriptFile = self._workspace_service.workspace.get_file(
            params.text_document.uri)
        if script_file is None:
            do_send_default_empty_response()
            return

        if self.should_skip_intellisense(script_file.file_uri):
            do_send_default_empty_response()
            return

        script_parse_info: ScriptParseInfo = self.get_script_parse_info(
            params.text_document.uri, create_if_not_exists=False)
        if not script_parse_info or not script_parse_info.can_queue():
            self._send_default_completions(request_context, script_file,
                                           params)
        else:
            cursor_position: int = len(
                script_file.get_text_in_range(
                    Range.from_data(0, 0, params.position.line,
                                    params.position.character)))
            text: str = script_file.get_all_text()
            script_parse_info.document = Document(text, cursor_position)
            operation = QueuedOperation(
                script_parse_info.connection_key,
                functools.partial(self.send_connected_completions,
                                  request_context, script_parse_info, params),
                functools.partial(self._send_default_completions,
                                  request_context, script_file, params))
            self.operations_queue.add_operation(operation)
Example #11
0
    def test_get_matches_one_char(self):
        """Test get matches on 1 character range"""
        # Given a default completion helper
        helper = DefaultCompletionHelper()
        text_range = Range.from_data(1, 1, 1, 2)
        start = 'c'
        # When I match 'c'
        matches: List[CompletionItem] = helper.get_matches(
            start, text_range, False)
        # Then I expect keywords starting with c to be returned
        self.assertTrue(len(matches) > 0)
        # ... and I expect words to be uppercased
        self.verify_match('CREATE', matches, text_range)
        # ... and I expect keywords starting in d to be skipped
        self.verify_miss('DELETE', matches)

        # and When I match with lowercase
        matches: List[CompletionItem] = helper.get_matches(
            start, text_range, True)
        # then I expect a lowercase result
        self.verify_match('create', matches, text_range)
        self.verify_miss('CREATE', matches)
Example #12
0
 def _prepare_edit(self, file: ScriptFile) -> TextEdit:
     file_line_count: int = len(file.file_lines)
     last_char = len(file.file_lines[file_line_count - 1])
     text_range = Range.from_data(0, 0, file_line_count - 1, last_char)
     return TextEdit.from_data(text_range, None)