Skip to content

Commit

Permalink
bring all tests from SingleDocumentTestCase
Browse files Browse the repository at this point in the history
  • Loading branch information
predragnikolic committed Apr 10, 2024
1 parent 09bca59 commit 9e6bf1a
Showing 1 changed file with 336 additions and 0 deletions.
336 changes: 336 additions & 0 deletions tests/test_single_document.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
from copy import deepcopy
from LSP.plugin import apply_text_edits, Request
from LSP.plugin.core.protocol import UINT_MAX
from LSP.plugin.core.url import filename_to_uri
from LSP.plugin.core.views import entire_content
from LSP.plugin.hover import _test_contents
from setup import TextDocumentTestCase
from setup import TIMEOUT_TIME
from setup import YieldPromise
import os
import sublime


try:
Expand Down Expand Up @@ -52,6 +59,25 @@ def test_did_open(self) -> None:
# -> "shutdown" -> client shut down
pass

def test_out_of_bounds_column_for_text_document_edit(self) -> None:
self.insert_characters("a\nb\nc\n")
apply_text_edits(self.view, [
{
'newText': 'hello there',
'range': {
'start': {
'line': 1,
'character': 0,
},
'end': {
'line': 1,
'character': 10000,
}
}
},
])
self.assertEqual(entire_content(self.view), "a\nhello there\nc\n")

def test_did_close(self) -> 'Generator':
self.assertTrue(self.view)
self.assertTrue(self.view.is_valid())
Expand Down Expand Up @@ -82,3 +108,313 @@ def test_did_change(self) -> 'Generator':
'uri': filename_to_uri(TEST_FILE_PATH)
}
})

def test_sends_save_with_purge(self) -> 'Generator':
assert self.view
self.view.settings().set("lsp_format_on_save", False)
self.insert_characters("A")
self.view.run_command("lsp_save", {'async': True})
yield from self.await_message("textDocument/didChange")
yield from self.await_message("textDocument/didSave")
yield from self.await_clear_view_and_save()

def test_formats_on_save(self) -> 'Generator':
assert self.view
self.view.settings().set("lsp_format_on_save", True)
self.insert_characters("A")
yield from self.await_message("textDocument/didChange")
self.set_response('textDocument/formatting', [{
'newText': "BBB",
'range': {
'start': {'line': 0, 'character': 0},
'end': {'line': 0, 'character': 1}
}
}])
self.view.run_command("lsp_save", {'async': True})
yield from self.await_message("textDocument/formatting")
yield from self.await_message("textDocument/didChange")
yield from self.await_message("textDocument/didSave")
text = self.view.substr(sublime.Region(0, self.view.size()))
self.assertEquals("BBB", text)
yield from self.await_clear_view_and_save()

def test_hover_info(self) -> 'Generator':
assert self.view
self.set_response('textDocument/hover', {"contents": "greeting"})
self.view.run_command('insert', {"characters": "Hello Wrld"})
self.assertFalse(self.view.is_popup_visible())
self.view.run_command('lsp_hover', {'point': 3})
yield lambda: self.view.is_popup_visible()
last_content = _test_contents[-1]
self.assertTrue("greeting" in last_content)

def test_remove_line_and_then_insert_at_that_line_at_end(self) -> 'Generator':
original = (
'a\n'
'b\n'
'c'
)
file_changes = [
((2, 0), (3, 0), ''), # out-of-bounds end position, but this is fine
((3, 0), (3, 0), 'c\n') # out-of-bounds start and end, this line doesn't exist
]
expected = (
'a\n'
'b\n'
'c\n'
)
# Old behavior:
# 1) first we end up with ('a\n', 'b\n', 'cc\n')
# 2) then we end up with ('a\n', 'b\n', '')
# New behavior:
# 1) line index 3 is "created" ('a\n', 'b\n', 'c\n', c\n'))
# 2) deletes line index 2.
yield from self.__run_formatting_test(original, expected, file_changes)

def test_apply_formatting(self) -> 'Generator':
original = (
'<dom-module id="some-thing">\n'
'<style></style>\n'
'<template>\n'
'</template>\n'
'</dom-module>\n'
)
file_changes = [
((0, 28), (1, 0), ''), # delete first \n
((1, 0), (1, 15), ''), # delete second line (but not the \n)
((2, 10), (2, 10), '\n <style></style>'), # insert after <template>
]
expected = (
'<dom-module id="some-thing">\n'
'<template>\n'
' <style></style>\n'
'</template>\n'
'</dom-module>\n'
)
yield from self.__run_formatting_test(original, expected, file_changes)

def test_apply_formatting_and_preserve_order(self) -> 'Generator':
original = (
'abcde\n'
'fghij\n'
)
# Note that (1, 2) comes before (0, 1) in the text.
file_changes = [
((1, 2), (1, 2), '4'), # insert after the g
((1, 2), (1, 2), '5'),
((1, 2), (1, 3), '6'), # replace the h
((0, 1), (0, 1), '1'), # insert after a
((0, 1), (0, 1), '2'),
((0, 1), (0, 1), '3'),
]
expected = (
'a123bcde\n'
'fg456ij\n'
)
yield from self.__run_formatting_test(original, expected, file_changes)

def test_tabs_are_respected_even_when_translate_tabs_to_spaces_is_set_to_true(self) -> 'Generator':
original = ' ' * 4
file_changes = [((0, 0), (0, 4), '\t')]
expected = '\t'
assert self.view
self.view.settings().set("translate_tabs_to_spaces", True)
yield from self.__run_formatting_test(original, expected, file_changes)
# Make sure the user's settings haven't changed
self.assertTrue(self.view.settings().get("translate_tabs_to_spaces"))

def __run_formatting_test(
self,
original: 'Iterable[str]',
expected: 'Iterable[str]',
file_changes: 'List[Tuple[Tuple[int, int], Tuple[int, int], str]]'
) -> 'Generator':
assert self.view
original_change_count = self.insert_characters(''.join(original))
# self.assertEqual(original_change_count, 1)
self.set_response('textDocument/formatting', [{
'newText': new_text,
'range': {
'start': {'line': start[0], 'character': start[1]},
'end': {'line': end[0], 'character': end[1]}}} for start, end, new_text in file_changes])
self.view.run_command('lsp_format_document')
yield from self.await_message('textDocument/formatting')
yield from self.await_view_change(original_change_count + len(file_changes))
edited_content = self.view.substr(sublime.Region(0, self.view.size()))
self.assertEquals(edited_content, ''.join(expected))

def __run_goto_test(self, response: list, text_document_request: str, subl_command_suffix: str) -> 'Generator':
assert self.view
self.insert_characters(GOTO_CONTENT)
# Put the cursor back at the start of the buffer, otherwise is_at_word fails in goto.py.
self.view.sel().clear()
self.view.sel().add(sublime.Region(0, 0))
method = 'textDocument/{}'.format(text_document_request)
self.set_response(method, response)
self.view.run_command('lsp_symbol_{}'.format(subl_command_suffix))
yield from self.await_message(method)

def condition() -> bool:
nonlocal self
assert self.view
s = self.view.sel()
if len(s) != 1:
return False
return s[0].begin() > 0

yield {"condition": condition, "timeout": TIMEOUT_TIME}
first = self.view.sel()[0].begin()
self.assertEqual(self.view.substr(sublime.Region(first, first + 1)), "F")

def test_definition(self) -> 'Generator':
yield from self.__run_goto_test(GOTO_RESPONSE, 'definition', 'definition')

def test_definition_location_link(self) -> 'Generator':
yield from self.__run_goto_test(GOTO_RESPONSE_LOCATION_LINK, 'definition', 'definition')

def test_type_definition(self) -> 'Generator':
yield from self.__run_goto_test(GOTO_RESPONSE, 'typeDefinition', 'type_definition')

def test_type_definition_location_link(self) -> 'Generator':
yield from self.__run_goto_test(GOTO_RESPONSE_LOCATION_LINK, 'typeDefinition', 'type_definition')

def test_declaration(self) -> 'Generator':
yield from self.__run_goto_test(GOTO_RESPONSE, 'declaration', 'declaration')

def test_declaration_location_link(self) -> 'Generator':
yield from self.__run_goto_test(GOTO_RESPONSE_LOCATION_LINK, 'declaration', 'declaration')

def test_implementation(self) -> 'Generator':
yield from self.__run_goto_test(GOTO_RESPONSE, 'implementation', 'implementation')

def test_implementation_location_link(self) -> 'Generator':
yield from self.__run_goto_test(GOTO_RESPONSE_LOCATION_LINK, 'implementation', 'implementation')

def test_expand_selection(self) -> 'Generator':
self.insert_characters("abcba\nabcba\nabcba\n")
self.view.run_command("lsp_selection_set", {"regions": [(2, 2)]})
self.assertEqual(len(self.view.sel()), 1)
self.assertEqual(self.view.substr(self.view.sel()[0]), "")
self.assertEqual(self.view.substr(self.view.sel()[0].a), "c")
response = [{
"parent": {
"parent": {
"range": {"start": {"line": 0, "character": 0}, "end": {"line": 0, "character": 5}}
},
"range": {"start": {"line": 0, "character": 1}, "end": {"line": 0, "character": 3}}
},
"range": {"start": {"line": 0, "character": 2}, "end": {"line": 0, "character": 3}}
}]

def expand_and_check(a: int, b: int) -> 'Generator':
self.set_response("textDocument/selectionRange", response)
self.view.run_command("lsp_expand_selection")
yield from self.await_message("textDocument/selectionRange")
yield lambda: self.view.sel()[0] == sublime.Region(a, b)

yield from expand_and_check(2, 3)
yield from expand_and_check(1, 3)
yield from expand_and_check(0, 5)

def test_rename(self) -> 'Generator':
self.insert_characters("foo\nfoo\nfoo\n")
self.set_response("textDocument/rename", {
'changes': {
filename_to_uri(TEST_FILE_PATH): [
{
'range': {'start': {'character': 0, 'line': 0}, 'end': {'character': 3, 'line': 0}},
'newText': 'bar'
},
{
'range': {'start': {'character': 0, 'line': 1}, 'end': {'character': 3, 'line': 1}},
'newText': 'bar'
},
{
'range':
{
'start': {'character': 0, 'line': 2},
# Check that lsp_apply_document_edit guards for overflow over LSP spec limit of UINT_MAX
'end': {'character': UINT_MAX + 1, 'line': 2}
},
'newText': 'bar'
}
]
}
}
)
self.view.run_command("lsp_selection_set", {"regions": [(0, 0)]})
self.view.run_command("lsp_symbol_rename", {"new_name": "bar"})
yield from self.await_message("textDocument/rename")
yield from self.await_view_change(9)
self.assertEqual(self.view.substr(sublime.Region(0, self.view.size())), "bar\nbar\nbar\n")

def test_run_command(self) -> 'Generator':
self.set_response("workspace/executeCommand", {"canReturnAnythingHere": "asdf"})
promise = YieldPromise()
sublime.set_timeout_async(
lambda: self.session.execute_command(
{"command": "foo", "arguments": ["hello", "there", "general", "kenobi"]},
progress=False,
view=self.view,
).then(promise.fulfill)
)
yield from self.await_promise(promise)
yield from self.await_message("workspace/executeCommand")
self.assertEqual(promise.result(), {"canReturnAnythingHere": "asdf"})

def test_progress(self) -> 'Generator':
request = Request("foobar", {"hello": "world"}, self.view, progress=True)
self.set_response("foobar", {"general": "kenobi"})
promise = self.session.send_request_task(request)
yield lambda: "workDoneToken" in request.params
result = yield from self.await_promise(promise)
self.assertEqual(result, {"general": "kenobi"})


class WillSaveWaitUntilTestCase(TextDocumentTestCase):

@classmethod
def get_test_server_capabilities(cls) -> dict:
capabilities = deepcopy(super().get_test_server_capabilities())
capabilities['capabilities']['textDocumentSync']['willSaveWaitUntil'] = True
return capabilities

def test_will_save_wait_until(self) -> 'Generator':
assert self.view
self.insert_characters("A")
yield from self.await_message("textDocument/didChange")
self.set_response('textDocument/willSaveWaitUntil', [{
'newText': "BBB",
'range': {
'start': {'line': 0, 'character': 0},
'end': {'line': 0, 'character': 1}
}
}])
self.view.settings().set("lsp_format_on_save", False)
self.view.run_command("lsp_save", {'async': True})
yield from self.await_message("textDocument/willSaveWaitUntil")
yield from self.await_message("textDocument/didChange")
yield from self.await_message("textDocument/didSave")
text = self.view.substr(sublime.Region(0, self.view.size()))
self.assertEquals("BBB", text)
yield from self.await_clear_view_and_save()


class AnotherDocumentTestCase(TextDocumentTestCase):

@classmethod
def get_test_name(cls) -> str:
return "testfile2"

def test_did_change_before_did_close(self) -> 'Generator':
assert self.view
self.view.window().run_command("chain", {
"commands": [
["insert", {"characters": "TEST"}],
["save", {"async": False}],
["close", {}]
]
})
yield from self.await_message('textDocument/didChange')
# yield from self.await_message('textDocument/didSave') # TODO why is this not sent?
yield from self.await_message('textDocument/didClose')

0 comments on commit 9e6bf1a

Please sign in to comment.