Skip to content

Commit 90cb566

Browse files
committed
update tests
1 parent 9a01a18 commit 90cb566

File tree

2 files changed

+165
-91
lines changed

2 files changed

+165
-91
lines changed

apps/language_server/lib/language_server/experimental/source_file.ex

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ defmodule ElixirLS.LanguageServer.Experimental.SourceFile do
55
alias ElixirLS.LanguageServer.Experimental.Protocol.Types.TextDocument.ContentChangeEvent.TextDocumentContentChangeEvent1,
66
as: ReplaceContentChangeEvent
77

8+
alias ElixirLS.LanguageServer.Experimental.Protocol.Types.TextEdit
89
alias ElixirLS.LanguageServer.Experimental.SourceFile.Conversions
910
alias ElixirLS.LanguageServer.Experimental.SourceFile.Document
1011
alias ElixirLS.LanguageServer.Experimental.SourceFile.Line
@@ -162,6 +163,14 @@ defmodule ElixirLS.LanguageServer.Experimental.SourceFile do
162163
end
163164
end
164165

166+
defp apply_change(%__MODULE__{} = source, %TextEdit{} = change) do
167+
with {:ok, ex_range} <- Conversions.to_elixir(change.range, source) do
168+
apply_change(source, ex_range, change.new_text)
169+
else
170+
_ -> {:error, {:invalid_range, change.range}}
171+
end
172+
end
173+
165174
defp apply_change(
166175
%__MODULE__{} = source,
167176
%{
Lines changed: 156 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
defmodule ElixirLS.LanguageServer.Experimental.Provider.CodeAction.ReplaceRemoteFunctionTest do
2-
alias ElixirLS.LanguageServer.Experimental.CodeMod.Diff
32
alias ElixirLS.LanguageServer.Experimental.Protocol.Requests
43
alias ElixirLS.LanguageServer.Experimental.Protocol.Requests.CodeAction, as: CodeActionRequest
54
alias ElixirLS.LanguageServer.Experimental.Protocol.Types.CodeAction
65
alias ElixirLS.LanguageServer.Experimental.Protocol.Types.CodeAction, as: CodeActionReply
76
alias ElixirLS.LanguageServer.Experimental.Protocol.Types.Diagnostic
87
alias ElixirLS.LanguageServer.Experimental.Protocol.Types.Range
9-
alias ElixirLS.LanguageServer.Experimental.Protocol.Types.Position
10-
alias ElixirLS.LanguageServer.Experimental.Protocol.Types.TextEdit
118
alias ElixirLS.LanguageServer.Experimental.Provider.CodeAction.ReplaceRemoteFunction
129
alias ElixirLS.LanguageServer.Experimental.SourceFile
10+
alias ElixirLS.LanguageServer.Experimental.SourceFile.Document
1311
alias ElixirLS.LanguageServer.Fixtures.LspProtocol
1412
alias ElixirLS.LanguageServer.SourceFile.Path, as: SourceFilePath
1513

@@ -36,10 +34,8 @@ defmodule ElixirLS.LanguageServer.Experimental.Provider.CodeAction.ReplaceRemote
3634
end
3735

3836
defp code_action(file_body, file_path, line, opts \\ []) do
39-
trimmed_body = String.trim(file_body, "\n")
40-
4137
file_uri = SourceFilePath.to_uri(file_path)
42-
SourceFile.Store.open(file_uri, trimmed_body, 0)
38+
SourceFile.Store.open(file_uri, file_body, 0)
4339

4440
{:ok, range} =
4541
build(Range,
@@ -63,43 +59,45 @@ defmodule ElixirLS.LanguageServer.Experimental.Provider.CodeAction.ReplaceRemote
6359
)
6460

6561
{:ok, action} = Requests.to_elixir(action)
66-
{file_uri, action}
62+
63+
{file_uri, file_body, action}
6764
end
6865

69-
defp assert_expected_text_edits(file_uri, action, expected_name, line) do
70-
assert %CodeActionReply{edit: %{changes: %{^file_uri => edits}}} = action
66+
defp apply_selected_action({file_uri, file_body, code_action}, index) do
67+
action =
68+
code_action
69+
|> apply()
70+
|> Enum.at(index)
7171

72-
expected_edits = Diff.diff("counts", expected_name)
72+
assert %CodeActionReply{edit: %{changes: %{^file_uri => edits}}} = action
7373

74-
assert edits
75-
|> Enum.zip(expected_edits)
76-
|> Enum.all?(fn {%TextEdit{new_text: new_text}, %TextEdit{new_text: expected_new_text}} ->
77-
new_text == expected_new_text
78-
end)
74+
{:ok, %SourceFile{document: document}} =
75+
file_uri
76+
|> SourceFile.new(file_body, 0)
77+
|> SourceFile.apply_content_changes(1, edits)
7978

80-
assert Enum.all?(edits, fn edit -> edit.range.start.line == line end)
81-
assert Enum.all?(edits, fn edit -> edit.range.end.line == line end)
79+
document
8280
end
8381

8482
test "produces no actions if the function is not found" do
85-
assert {_, action} = code_action("Enum.count([1, 2])", "/project/file.ex", 0)
83+
assert {_, _, action} = code_action("Enum.count([1, 2])", "/project/file.ex", 0)
8684
assert [] = apply(action)
8785
end
8886

8987
test "produces no actions if the line is empty" do
90-
{_, action} = code_action("", "/project/file.ex", 0)
88+
{_, _, action} = code_action("", "/project/file.ex", 0)
9189
assert [] = apply(action)
9290
end
9391

9492
test "produces no results if the diagnostic message doesn't fit the format" do
95-
assert {_, action} =
93+
assert {_, _, action} =
9694
code_action("", "/project/file.ex", 0, diagnostic_message: "This isn't cool")
9795

9896
assert [] = apply(action)
9997
end
10098

10199
test "produces no results for buggy source code" do
102-
{_, action} =
100+
{_, _, action} =
103101
~S[
104102
1 + 2~/3 ; 4ab(
105103
]
@@ -109,72 +107,115 @@ defmodule ElixirLS.LanguageServer.Experimental.Provider.CodeAction.ReplaceRemote
109107
end
110108

111109
test "handles nil context" do
112-
assert {_, action} = code_action("other_var = 6", "/project/file.ex", 0)
110+
assert {_, _, action} = code_action("other_var = 6", "/project/file.ex", 0)
113111

114112
action = put_in(action, [:context], nil)
115113

116114
assert [] = apply(action)
117115
end
118116

119117
test "handles nil diagnostics" do
120-
assert {_, action} = code_action("other_var = 6", "/project/file.ex", 0)
118+
assert {_, _, action} = code_action("other_var = 6", "/project/file.ex", 0)
121119

122120
action = put_in(action, [:context, :diagnostics], nil)
123121

124122
assert [] = apply(action)
125123
end
126124

127125
test "handles empty diagnostics" do
128-
assert {_, action} = code_action("other_var = 6", "/project/file.ex", 0)
126+
assert {_, _, action} = code_action("other_var = 6", "/project/file.ex", 0)
129127

130128
action = put_in(action, [:context, :diagnostics], [])
131129

132130
assert [] = apply(action)
133131
end
134132

135133
test "applied to an isolated function" do
136-
{file_uri, code_action} =
137-
~S[
138-
Enum.counts(a)
139-
]
140-
|> code_action("/project/file.ex", 0)
141-
142-
assert [to_count_action, to_concat_action] = apply(code_action)
143-
144-
assert_expected_text_edits(file_uri, to_count_action, "count", 0)
145-
assert_expected_text_edits(file_uri, to_concat_action, "concat", 0)
134+
actual_code = ~S[
135+
Enum.counts(a)
136+
]
137+
138+
expected_doc = ~S[
139+
Enum.count(a)
140+
] |> Document.new()
141+
142+
assert expected_doc ==
143+
actual_code
144+
|> code_action("/project/file.ex", 1)
145+
|> apply_selected_action(0)
146+
147+
expected_doc = ~S[
148+
Enum.concat(a)
149+
] |> Document.new()
150+
151+
assert expected_doc ==
152+
actual_code
153+
|> code_action("/project/file.ex", 1)
154+
|> apply_selected_action(1)
146155
end
147156

148157
test "works for a function assigned to a variable" do
149-
{file_uri, code_action} =
150-
~S[
151-
var = &Enum.counts/1
152-
]
153-
|> code_action("/project/file.ex", 0)
158+
actual_code = ~S[
159+
var = &Enum.counts/1
160+
]
161+
162+
expected_doc = ~S[
163+
var = &Enum.count/1
164+
] |> Document.new()
165+
166+
assert expected_doc ==
167+
actual_code
168+
|> code_action("/project/file.ex", 1)
169+
|> apply_selected_action(0)
154170

155-
assert [to_count_action, to_concat_action] = apply(code_action)
171+
expected_doc = ~S[
172+
var = &Enum.concat/1
173+
] |> Document.new()
156174

157-
assert_expected_text_edits(file_uri, to_count_action, "count", 0)
158-
assert_expected_text_edits(file_uri, to_concat_action, "concat", 0)
175+
assert expected_doc ==
176+
actual_code
177+
|> code_action("/project/file.ex", 1)
178+
|> apply_selected_action(1)
159179
end
160180

161181
test "works with multiple lines" do
162-
{file_uri, code_action} = ~S[
182+
actual_code = ~S[
163183
defmodule MyModule do
164184
def my_func(a) do
165185
Enum.counts(a)
166186
end
167187
end
168-
] |> code_action("/project/file.ex", 2)
188+
]
169189

170-
assert [to_count_action, to_concat_action] = apply(code_action)
190+
expected_doc = ~S[
191+
defmodule MyModule do
192+
def my_func(a) do
193+
Enum.count(a)
194+
end
195+
end
196+
] |> Document.new()
197+
198+
assert expected_doc ==
199+
actual_code
200+
|> code_action("/project/file.ex", 3)
201+
|> apply_selected_action(0)
171202

172-
assert_expected_text_edits(file_uri, to_count_action, "count", 2)
173-
assert_expected_text_edits(file_uri, to_concat_action, "concat", 2)
203+
expected_doc = ~S[
204+
defmodule MyModule do
205+
def my_func(a) do
206+
Enum.concat(a)
207+
end
208+
end
209+
] |> Document.new()
210+
211+
assert expected_doc ==
212+
actual_code
213+
|> code_action("/project/file.ex", 3)
214+
|> apply_selected_action(1)
174215
end
175216

176217
test "proposed functions need to match the replaced function arity" do
177-
{_, code_action} =
218+
{_, _, code_action} =
178219
~S[
179220
Enum.counts(a)
180221
]
@@ -184,7 +225,7 @@ defmodule ElixirLS.LanguageServer.Experimental.Provider.CodeAction.ReplaceRemote
184225
end
185226

186227
test "does not replace variables" do
187-
{_, code_action} =
228+
{_, _, code_action} =
188229
~S[
189230
counts + 42
190231
]
@@ -200,58 +241,82 @@ defmodule ElixirLS.LanguageServer.Experimental.Provider.CodeAction.ReplaceRemote
200241
* my_func/1
201242
"""
202243

203-
code = ~S[
204-
defmodule Example do
205-
defmodule A.B do
206-
def my_func(a), do: a
207-
end
244+
actual_code = ~S[
245+
defmodule Example do
246+
defmodule A.B do
247+
def my_func(a), do: a
248+
end
208249
209-
defmodule C do
210-
def my_fun(a), do: a
211-
end
250+
defmodule C do
251+
def my_fun(a), do: a
252+
end
212253
213-
defmodule D do
214-
alias Example.A
215-
alias Example.A.B
216-
alias Example.C
217-
def bar() do
218-
A.B.my_fun(42)
219-
C.my_fun(42) + B.my_fun(42)
220-
end
254+
defmodule D do
255+
alias Example.A
256+
alias Example.A.B
257+
alias Example.C
258+
def bar() do
259+
A.B.my_fun(42)
260+
C.my_fun(42) + B.my_fun(42)
221261
end
222262
end
263+
end
223264
]
224265

225266
# A.B.my_fun(42)
226-
{file_uri, code_action} =
227-
code_action(code, "/project/file.ex", 14, diagnostic_message: diagnostic_message)
267+
expected_doc = ~S[
268+
defmodule Example do
269+
defmodule A.B do
270+
def my_func(a), do: a
271+
end
272+
273+
defmodule C do
274+
def my_fun(a), do: a
275+
end
228276
229-
assert [%CodeActionReply{edit: %{changes: %{^file_uri => edits}}}] = apply(code_action)
277+
defmodule D do
278+
alias Example.A
279+
alias Example.A.B
280+
alias Example.C
281+
def bar() do
282+
A.B.my_func(42)
283+
C.my_fun(42) + B.my_fun(42)
284+
end
285+
end
286+
end
287+
] |> Document.new()
230288

231-
assert [
232-
%TextEdit{
233-
new_text: "c",
234-
range: %Range{
235-
end: %Position{character: 24, line: 14},
236-
start: %Position{character: 24, line: 14}
237-
}
238-
}
239-
] = edits
289+
assert expected_doc ==
290+
actual_code
291+
|> code_action("/project/file.ex", 15, diagnostic_message: diagnostic_message)
292+
|> apply_selected_action(0)
240293

241294
# B.my_fun(42)
242-
{file_uri, code_action} =
243-
code_action(code, "/project/file.ex", 15, diagnostic_message: diagnostic_message)
244-
245-
assert [%CodeActionReply{edit: %{changes: %{^file_uri => edits}}}] = apply(code_action)
246-
247-
assert [
248-
%TextEdit{
249-
new_text: "c",
250-
range: %Range{
251-
end: %Position{character: 37, line: 15},
252-
start: %Position{character: 37, line: 15}
253-
}
254-
}
255-
] = edits
295+
expected_doc = ~S[
296+
defmodule Example do
297+
defmodule A.B do
298+
def my_func(a), do: a
299+
end
300+
301+
defmodule C do
302+
def my_fun(a), do: a
303+
end
304+
305+
defmodule D do
306+
alias Example.A
307+
alias Example.A.B
308+
alias Example.C
309+
def bar() do
310+
A.B.my_fun(42)
311+
C.my_fun(42) + B.my_func(42)
312+
end
313+
end
314+
end
315+
] |> Document.new()
316+
317+
assert expected_doc ==
318+
actual_code
319+
|> code_action("/project/file.ex", 16, diagnostic_message: diagnostic_message)
320+
|> apply_selected_action(0)
256321
end
257322
end

0 commit comments

Comments
 (0)