1
1
defmodule ElixirLS.LanguageServer.Experimental.Provider.CodeAction.ReplaceRemoteFunctionTest do
2
- alias ElixirLS.LanguageServer.Experimental.CodeMod.Diff
3
2
alias ElixirLS.LanguageServer.Experimental.Protocol.Requests
4
3
alias ElixirLS.LanguageServer.Experimental.Protocol.Requests.CodeAction , as: CodeActionRequest
5
4
alias ElixirLS.LanguageServer.Experimental.Protocol.Types.CodeAction
6
5
alias ElixirLS.LanguageServer.Experimental.Protocol.Types.CodeAction , as: CodeActionReply
7
6
alias ElixirLS.LanguageServer.Experimental.Protocol.Types.Diagnostic
8
7
alias ElixirLS.LanguageServer.Experimental.Protocol.Types.Range
9
- alias ElixirLS.LanguageServer.Experimental.Protocol.Types.Position
10
- alias ElixirLS.LanguageServer.Experimental.Protocol.Types.TextEdit
11
8
alias ElixirLS.LanguageServer.Experimental.Provider.CodeAction.ReplaceRemoteFunction
12
9
alias ElixirLS.LanguageServer.Experimental.SourceFile
10
+ alias ElixirLS.LanguageServer.Experimental.SourceFile.Document
13
11
alias ElixirLS.LanguageServer.Fixtures.LspProtocol
14
12
alias ElixirLS.LanguageServer.SourceFile.Path , as: SourceFilePath
15
13
@@ -36,10 +34,8 @@ defmodule ElixirLS.LanguageServer.Experimental.Provider.CodeAction.ReplaceRemote
36
34
end
37
35
38
36
defp code_action ( file_body , file_path , line , opts \\ [ ] ) do
39
- trimmed_body = String . trim ( file_body , "\n " )
40
-
41
37
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 )
43
39
44
40
{ :ok , range } =
45
41
build ( Range ,
@@ -63,43 +59,45 @@ defmodule ElixirLS.LanguageServer.Experimental.Provider.CodeAction.ReplaceRemote
63
59
)
64
60
65
61
{ :ok , action } = Requests . to_elixir ( action )
66
- { file_uri , action }
62
+
63
+ { file_uri , file_body , action }
67
64
end
68
65
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 )
71
71
72
- expected_edits = Diff . diff ( "counts" , expected_name )
72
+ assert % CodeActionReply { edit: % { changes: % { ^ file_uri => edits } } } = action
73
73
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 )
79
78
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
82
80
end
83
81
84
82
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 )
86
84
assert [ ] = apply ( action )
87
85
end
88
86
89
87
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 )
91
89
assert [ ] = apply ( action )
92
90
end
93
91
94
92
test "produces no results if the diagnostic message doesn't fit the format" do
95
- assert { _ , action } =
93
+ assert { _ , _ , action } =
96
94
code_action ( "" , "/project/file.ex" , 0 , diagnostic_message: "This isn't cool" )
97
95
98
96
assert [ ] = apply ( action )
99
97
end
100
98
101
99
test "produces no results for buggy source code" do
102
- { _ , action } =
100
+ { _ , _ , action } =
103
101
~S[
104
102
1 + 2~/3 ; 4ab(
105
103
]
@@ -109,72 +107,115 @@ defmodule ElixirLS.LanguageServer.Experimental.Provider.CodeAction.ReplaceRemote
109
107
end
110
108
111
109
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 )
113
111
114
112
action = put_in ( action , [ :context ] , nil )
115
113
116
114
assert [ ] = apply ( action )
117
115
end
118
116
119
117
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 )
121
119
122
120
action = put_in ( action , [ :context , :diagnostics ] , nil )
123
121
124
122
assert [ ] = apply ( action )
125
123
end
126
124
127
125
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 )
129
127
130
128
action = put_in ( action , [ :context , :diagnostics ] , [ ] )
131
129
132
130
assert [ ] = apply ( action )
133
131
end
134
132
135
133
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 )
146
155
end
147
156
148
157
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 )
154
170
155
- assert [ to_count_action , to_concat_action ] = apply ( code_action )
171
+ expected_doc = ~S[
172
+ var = &Enum.concat/1
173
+ ] |> Document . new ( )
156
174
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 )
159
179
end
160
180
161
181
test "works with multiple lines" do
162
- { file_uri , code_action } = ~S[
182
+ actual_code = ~S[
163
183
defmodule MyModule do
164
184
def my_func(a) do
165
185
Enum.counts(a)
166
186
end
167
187
end
168
- ] |> code_action ( "/project/file.ex" , 2 )
188
+ ]
169
189
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 )
171
202
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 )
174
215
end
175
216
176
217
test "proposed functions need to match the replaced function arity" do
177
- { _ , code_action } =
218
+ { _ , _ , code_action } =
178
219
~S[
179
220
Enum.counts(a)
180
221
]
@@ -184,7 +225,7 @@ defmodule ElixirLS.LanguageServer.Experimental.Provider.CodeAction.ReplaceRemote
184
225
end
185
226
186
227
test "does not replace variables" do
187
- { _ , code_action } =
228
+ { _ , _ , code_action } =
188
229
~S[
189
230
counts + 42
190
231
]
@@ -200,58 +241,82 @@ defmodule ElixirLS.LanguageServer.Experimental.Provider.CodeAction.ReplaceRemote
200
241
* my_func/1
201
242
"""
202
243
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
208
249
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
212
253
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)
221
261
end
222
262
end
263
+ end
223
264
]
224
265
225
266
# 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
228
276
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 ( )
230
288
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 )
240
293
241
294
# 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 )
256
321
end
257
322
end
0 commit comments