]> git.madduck.net Git - etc/vim.git/blob - test/test_code_action.vader

madduck's git repository

Every one of the projects in this repository is available at the canonical URL git://git.madduck.net/madduck/pub/<projectpath> — see each project's metadata for the exact URL.

All patches and comments are welcome. Please squash your changes to logical commits before using git-format-patch and git-send-email to patches@git.madduck.net. If you'd read over the Git project's submission guidelines and adhered to them, I'd be especially grateful.

SSH access, as well as push access can be individually arranged.

If you use my repositories frequently, consider adding the following snippet to ~/.gitconfig and using the third clone URL listed for each project:

[url "git://git.madduck.net/madduck/"]
  insteadOf = madduck:

Squashed '.vim/bundle/ale/' content from commit 22185c4c
[etc/vim.git] / test / test_code_action.vader
1 Before:
2   let g:notified_changes = []
3
4   runtime autoload/ale/lsp.vim
5
6   function! ale#lsp#NotifyForChanges(conn_id, buffer) abort
7     call add(g:notified_changes, {
8     \ 'conn_id': a:conn_id,
9     \ 'buffer': a:buffer
10     \})
11   endfunction
12
13   Save g:ale_enabled
14   let g:ale_enabled = 0
15
16   let g:file1 = tempname()
17   let g:file2 = tempname()
18   let g:test = {}
19
20   let g:test.create_change = {line, offset, end_line, end_offset, value ->
21   \{
22   \   'changes': [{
23   \      'fileName': g:file1,
24   \      'textChanges': [{
25   \        'start': {
26   \          'line': line,
27   \          'offset': offset,
28   \        },
29   \        'end': {
30   \          'line': end_line,
31   \          'offset': end_offset,
32   \        },
33   \        'newText': value,
34   \      }],
35   \   }]
36   \}}
37
38   function! WriteFileAndEdit() abort
39     let g:test.text = [
40     \ 'class Name {',
41     \ '  value: string',
42     \ '}',
43     \]
44     call writefile(g:test.text, g:file1, 'S')
45     execute 'edit ' . g:file1
46   endfunction!
47
48 After:
49   " Close the extra buffers if we opened it.
50   if bufnr(g:file1) != -1 && buflisted(bufnr(g:file1))
51     execute ':bp! | :bd! ' . bufnr(g:file1)
52   endif
53   if bufnr(g:file2) != -1 && buflisted(bufnr(g:file2))
54     execute ':bp! | :bd! ' . bufnr(g:file2)
55   endif
56
57   if filereadable(g:file1)
58     call delete(g:file1)
59   endif
60   if filereadable(g:file2)
61     call delete(g:file2)
62   endif
63
64   unlet! g:notified_changes
65   " unlet! g:expected_notified_changes
66   unlet! g:file1
67   unlet! g:file2
68   unlet! g:test
69   unlet! g:changes
70   delfunction WriteFileAndEdit
71
72   runtime autoload/ale/lsp.vim
73
74   Restore
75
76
77 Execute(It should modify and save multiple files):
78   call writefile([
79   \ 'class Name {',
80   \ '  value: string',
81   \ '}',
82   \ '',
83   \ 'class B {',
84   \ '  constructor(readonly a: Name) {}',
85   \ '}'
86   \], g:file1, 'S')
87   call writefile([
88   \ 'import A from "A"',
89   \ 'import {',
90   \ '  B,',
91   \ '  C,',
92   \ '} from "module"',
93   \ 'import D from "D"',
94   \], g:file2, 'S')
95
96   call ale#code_action#HandleCodeAction(
97   \ {
98   \   'changes': [{
99   \      'fileName': g:file1,
100   \      'textChanges': [{
101   \        'start': {
102   \          'line': 1,
103   \          'offset': 7,
104   \        },
105   \        'end': {
106   \          'line': 1,
107   \          'offset': 11,
108   \        },
109   \        'newText': 'Value',
110   \      }, {
111   \        'start': {
112   \          'line': 6,
113   \          'offset': 27,
114   \        },
115   \        'end': {
116   \          'line': 6,
117   \          'offset': 31,
118   \        },
119   \        'newText': 'Value',
120   \      }],
121   \   }, {
122   \     'fileName': g:file2,
123   \     'textChanges': [{
124   \       'start': {
125   \         'line': 2,
126   \         'offset': 1,
127   \       },
128   \       'end': {
129   \         'line': 6,
130   \         'offset': 1,
131   \       },
132   \       'newText': "import {A, B} from 'module'\n\n",
133   \     }]
134   \   }],
135   \ },
136   \ {'should_save': 1, 'conn_id': 'test_conn'},
137   \)
138
139   AssertEqual [
140   \ 'class Value {',
141   \ '  value: string',
142   \ '}',
143   \ '',
144   \ 'class B {',
145   \ '  constructor(readonly a: Value) {}',
146   \ '}',
147   \ '',
148   \], readfile(g:file1, 'b')
149
150   AssertEqual [
151   \ 'import A from "A"',
152   \ 'import {A, B} from ''module''',
153   \ '',
154   \ 'import D from "D"',
155   \ '',
156   \], readfile(g:file2, 'b')
157
158   AssertEqual [{
159   \ 'conn_id': 'test_conn',
160   \ 'buffer': bufnr(g:file1),
161   \}, {
162   \ 'conn_id': 'test_conn',
163   \ 'buffer': bufnr(g:file2),
164   \}], g:notified_changes
165
166 Execute(Beginning of file can be modified):
167   let g:test.text = [
168   \ 'class Name {',
169   \ '  value: string',
170   \ '}',
171   \]
172   call writefile(g:test.text, g:file1, 'S')
173
174   call ale#code_action#HandleCodeAction(
175   \ {
176   \   'changes': [{
177   \      'fileName': g:file1,
178   \      'textChanges': [{
179   \        'start': {
180   \          'line': 1,
181   \          'offset': 1,
182   \        },
183   \        'end': {
184   \          'line': 1,
185   \          'offset': 1,
186   \        },
187   \        'newText': "type A: string\ntype B: number\n",
188   \      }],
189   \   }]
190   \ },
191   \ {'should_save': 1, 'conn_id': 'test_conn'},
192   \)
193
194   AssertEqual [
195   \  'type A: string',
196   \  'type B: number',
197   \] + g:test.text + [''], readfile(g:file1, 'b')
198
199   AssertEqual [{
200   \ 'conn_id': 'test_conn',
201   \ 'buffer': bufnr(g:file1),
202   \}], g:notified_changes
203
204
205 Execute(End of file can be modified):
206   let g:test.text = [
207   \ 'class Name {',
208   \ '  value: string',
209   \ '}',
210   \]
211   call writefile(g:test.text, g:file1, 'S')
212
213   call ale#code_action#HandleCodeAction(
214   \ {
215   \   'changes': [{
216   \    'fileName': g:file1,
217   \    'textChanges': [{
218   \      'start': {
219   \        'line': 4,
220   \        'offset': 1,
221   \      },
222   \      'end': {
223   \        'line': 4,
224   \        'offset': 1,
225   \      },
226   \      'newText': "type A: string\ntype B: number\n",
227   \     }],
228   \   }]
229   \ },
230   \ {'should_save': 1, 'conn_id': 'test_conn'},
231   \)
232
233   AssertEqual g:test.text + [
234   \  'type A: string',
235   \  'type B: number',
236   \  '',
237   \], readfile(g:file1, 'b')
238
239   AssertEqual [{
240   \ 'conn_id': 'test_conn',
241   \ 'buffer': bufnr(g:file1),
242   \}], g:notified_changes
243
244
245 Execute(Current buffer contents will be reloaded):
246   let g:test.text = [
247   \ 'class Name {',
248   \ '  value: string',
249   \ '}',
250   \]
251   call writefile(g:test.text, g:file1, 'S')
252
253   execute 'edit ' . g:file1
254   let g:test.buffer = bufnr(g:file1)
255
256   call ale#code_action#HandleCodeAction(
257   \ {
258   \   'changes': [{
259   \      'fileName': g:file1,
260   \      'textChanges': [{
261   \        'start': {
262   \          'line': 1,
263   \          'offset': 1,
264   \        },
265   \        'end': {
266   \          'line': 1,
267   \          'offset': 1,
268   \        },
269   \        'newText': "type A: string\ntype B: number\n",
270   \      }],
271   \   }]
272   \ },
273   \ {'should_save': 1, 'conn_id': 'test_conn'},
274   \)
275
276   AssertEqual [
277   \  'type A: string',
278   \  'type B: number',
279   \] + g:test.text + [''], readfile(g:file1, 'b')
280
281   AssertEqual [
282   \  'type A: string',
283   \  'type B: number',
284   \] + g:test.text, getbufline(g:test.buffer, 1, '$')
285
286   AssertEqual [{
287   \ 'conn_id': 'test_conn',
288   \ 'buffer': bufnr(g:file1),
289   \}], g:notified_changes
290
291
292 Execute(Unlisted buffer contents will be modified correctly):
293   let g:test.text = [
294   \ 'class Name {',
295   \ '  value: string',
296   \ '}',
297   \]
298   call writefile(g:test.text, g:file1, 'S')
299
300   execute 'edit ' . g:file1
301   let g:test.buffer = bufnr(g:file1)
302
303   execute 'bd'
304   AssertEqual bufnr(g:file1), g:test.buffer
305
306   call ale#code_action#HandleCodeAction(
307   \ {
308   \   'changes': [{
309   \      'fileName': g:file1,
310   \      'textChanges': [{
311   \        'start': {
312   \          'line': 1,
313   \          'offset': 1,
314   \        },
315   \        'end': {
316   \          'line': 1,
317   \          'offset': 1,
318   \        },
319   \        'newText': "type A: string\ntype B: number\n",
320   \      }],
321   \   }]
322   \ },
323   \ {'should_save': 1, 'conn_id': 'test_conn'},
324   \)
325
326   AssertEqual [
327   \  'type A: string',
328   \  'type B: number',
329   \] + g:test.text + [''], readfile(g:file1, 'b')
330
331   AssertEqual [{
332   \ 'conn_id': 'test_conn',
333   \ 'buffer': bufnr(g:file1),
334   \}], g:notified_changes
335
336 # Tests for cursor repositioning. In comments `=` designates change range, and
337 # `C` cursor position
338
339 #     C ===
340 Execute(Cursor will not move when it is before text change):
341   call WriteFileAndEdit()
342   let g:test.changes = g:test.create_change(2, 3, 2, 8, 'value2')
343
344   call setpos('.', [0, 1, 1, 0])
345   call ale#code_action#HandleCodeAction(g:test.changes, {
346   \ 'should_save': 1,
347   \ 'conn_id': 'test_conn',
348   \})
349   AssertEqual [1, 1], getpos('.')[1:2]
350
351   AssertEqual [{
352   \ 'conn_id': 'test_conn',
353   \ 'buffer': bufnr(''),
354   \}], g:notified_changes
355
356   call setpos('.', [0, 2, 2, 0])
357   call ale#code_action#HandleCodeAction(g:test.changes, {
358   \ 'should_save': 1,
359   \ 'conn_id': 'test_conn',
360   \})
361   AssertEqual [2, 2], getpos('.')[1:2]
362
363   AssertEqual [{
364   \ 'conn_id': 'test_conn',
365   \ 'buffer': bufnr(''),
366   \}, {
367   \ 'conn_id': 'test_conn',
368   \ 'buffer': bufnr(''),
369   \}], g:notified_changes
370
371 # ====C====
372 Execute(Cursor column will move to the change end when cursor between start/end):
373   let g:test.changes = g:test.create_change(2, 3, 2, 8, 'value2')
374
375   for r in range(3, 8)
376     call WriteFileAndEdit()
377     call setpos('.', [0, 2, r, 0])
378     AssertEqual '  value: string', getline('.')
379     call ale#code_action#HandleCodeAction(g:test.changes, {
380     \ 'should_save': 1,
381     \ 'conn_id': 'test_conn',
382     \})
383     AssertEqual '  value2: string', getline('.')
384     AssertEqual [2, 9], getpos('.')[1:2]
385   endfor
386
387   AssertEqual [{
388   \ 'conn_id': 'test_conn',
389   \ 'buffer': bufnr(''),
390   \}, {
391   \ 'conn_id': 'test_conn',
392   \ 'buffer': bufnr(''),
393   \}, {
394   \ 'conn_id': 'test_conn',
395   \ 'buffer': bufnr(''),
396   \}, {
397   \ 'conn_id': 'test_conn',
398   \ 'buffer': bufnr(''),
399   \}, {
400   \ 'conn_id': 'test_conn',
401   \ 'buffer': bufnr(''),
402   \}, {
403   \ 'conn_id': 'test_conn',
404   \ 'buffer': bufnr(''),
405   \}], g:notified_changes
406
407
408 # ====C
409 Execute(Cursor column will move back when new text is shorter):
410   call WriteFileAndEdit()
411   call setpos('.', [0, 2, 8, 0])
412   AssertEqual '  value: string', getline('.')
413   call ale#code_action#HandleCodeAction(
414   \ g:test.create_change(2, 3, 2, 8, 'val'),
415   \ {
416   \   'should_save': 1,
417   \   'conn_id': 'test_conn',
418   \ })
419   AssertEqual '  val: string', getline('.')
420   AssertEqual [2, 6], getpos('.')[1:2]
421
422   AssertEqual [{
423   \ 'conn_id': 'test_conn',
424   \ 'buffer': bufnr(''),
425   \}], g:notified_changes
426
427
428 # ==== C
429 Execute(Cursor column will move forward when new text is longer):
430   call WriteFileAndEdit()
431
432   call setpos('.', [0, 2, 8, 0])
433   AssertEqual '  value: string', getline('.')
434   call ale#code_action#HandleCodeAction(
435   \ g:test.create_change(2, 3, 2, 8, 'longValue'),
436   \ {
437   \   'should_save': 1,
438   \   'conn_id': 'test_conn',
439   \ })
440   AssertEqual '  longValue: string', getline('.')
441   AssertEqual [2, 12], getpos('.')[1:2]
442
443   AssertEqual [{
444   \ 'conn_id': 'test_conn',
445   \ 'buffer': bufnr(''),
446   \}], g:notified_changes
447
448 # =========
449 # =
450 # C
451 Execute(Cursor line will move when updates are happening on lines above):
452   call WriteFileAndEdit()
453   call setpos('.', [0, 3, 1, 0])
454   AssertEqual '}', getline('.')
455   call ale#code_action#HandleCodeAction(
456   \ g:test.create_change(1, 1, 2, 1, "test\ntest\n"),
457   \ {
458   \   'should_save': 1,
459   \   'conn_id': 'test_conn',
460   \ })
461   AssertEqual '}', getline('.')
462   AssertEqual [4, 1], getpos('.')[1:2]
463
464   AssertEqual [{
465   \ 'conn_id': 'test_conn',
466   \ 'buffer': bufnr(''),
467   \}], g:notified_changes
468
469
470 # =========
471 # =C
472 Execute(Cursor line and column will move when change on lines above and just before cursor column):
473   call WriteFileAndEdit()
474   call setpos('.', [0, 2, 2, 0])
475   AssertEqual '  value: string', getline('.')
476   call ale#code_action#HandleCodeAction(
477   \ g:test.create_change(1, 1, 2, 1, "test\ntest\n123"),
478   \ {
479   \   'should_save': 1,
480   \   'conn_id': 'test_conn',
481   \ })
482   AssertEqual '123  value: string', getline('.')
483   AssertEqual [3, 5], getpos('.')[1:2]
484
485   AssertEqual [{
486   \ 'conn_id': 'test_conn',
487   \ 'buffer': bufnr(''),
488   \}], g:notified_changes
489
490 # =========
491 # ======C==
492 # =
493 Execute(Cursor line and column will move at the end of changes):
494   call WriteFileAndEdit()
495   call setpos('.', [0, 2, 10, 0])
496   AssertEqual '  value: string', getline('.')
497   call ale#code_action#HandleCodeAction(
498   \ g:test.create_change(1, 1, 3, 1, "test\n"),
499   \ {
500   \   'should_save': 1,
501   \   'conn_id': 'test_conn',
502   \ })
503   AssertEqual '}', getline('.')
504   AssertEqual [2, 1], getpos('.')[1:2]
505
506   AssertEqual [{
507   \ 'conn_id': 'test_conn',
508   \ 'buffer': bufnr(''),
509   \}], g:notified_changes
510
511 #      C ==
512 # ===
513 Execute(Cursor will not move when changes happening on lines >= cursor, but after cursor):
514   call WriteFileAndEdit()
515   call setpos('.', [0, 2, 3, 0])
516   AssertEqual '  value: string', getline('.')
517   call ale#code_action#HandleCodeAction(
518   \ g:test.create_change(2, 10, 3, 1, "number\n"),
519   \ {
520   \   'should_save': 1,
521   \   'conn_id': 'test_conn',
522   \ })
523   AssertEqual '  value: number', getline('.')
524   AssertEqual [2, 3], getpos('.')[1:2]
525
526   AssertEqual [{
527   \ 'conn_id': 'test_conn',
528   \ 'buffer': bufnr(''),
529   \}], g:notified_changes
530
531 Execute(Cursor will not move when change covers entire file):
532   call WriteFileAndEdit()
533   call setpos('.', [0, 2, 3, 0])
534   call ale#code_action#HandleCodeAction(
535   \ g:test.create_change(1, 1, len(g:test.text) + 1, 1,
536   \   join(g:test.text + ['x'], "\n")),
537   \ {
538   \   'should_save': 1,
539   \   'conn_id': 'test_conn',
540   \ })
541   AssertEqual [2, 3], getpos('.')[1:2]
542
543   AssertEqual [{
544   \ 'conn_id': 'test_conn',
545   \ 'buffer': bufnr(''),
546   \}], g:notified_changes
547
548 Execute(It should just modify file when should_save is set to v:false):
549   call WriteFileAndEdit()
550   let g:test.change = g:test.create_change(1, 1, 1, 1, "import { writeFile } from 'fs';\n")
551   call ale#code_action#HandleCodeAction(g:test.change, {
552   \ 'conn_id': 'test_conn',
553   \})
554   AssertEqual 1, getbufvar(bufnr(''), '&modified')
555   AssertEqual [
556   \ 'import { writeFile } from ''fs'';',
557   \ 'class Name {',
558   \ '  value: string',
559   \ '}',
560   \], getline(1, '$')
561
562   AssertEqual [{
563   \ 'conn_id': 'test_conn',
564   \ 'buffer': bufnr(''),
565   \}], g:notified_changes
566
567 Given typescript(An example TypeScript file):
568   type Foo = {}
569
570   export interface ISomething {
571     fooLongName: Foo | null
572   }
573
574   export class SomethingElse implements ISomething {
575     // Bindings
576     fooLongName!: ISomething['fooLongName']
577   }
578
579 Execute():
580   let g:changes = [
581   \ {'end': {'offset': 14, 'line': 4}, 'newText': 'foo', 'start': {'offset': 3, 'line': 4}},
582   \ {'end': {'offset': 40, 'line': 9}, 'newText': 'foo', 'start': {'offset': 29, 'line': 9}},
583   \ {'end': {'offset': 14, 'line': 9}, 'newText': 'foo', 'start': {'offset': 3, 'line': 9}},
584   \]
585
586   call ale#code_action#ApplyChanges(expand('%:p'), g:changes, {
587   \ 'conn_id': 'test_conn',
588   \})
589
590   AssertEqual [{
591   \ 'conn_id': 'test_conn',
592   \ 'buffer': bufnr(''),
593   \}], g:notified_changes
594
595 Expect(The changes should be applied correctly):
596   type Foo = {}
597
598   export interface ISomething {
599     foo: Foo | null
600   }
601
602   export class SomethingElse implements ISomething {
603     // Bindings
604     foo!: ISomething['foo']
605   }