summaryrefslogtreecommitdiff
path: root/test/test_code_action_corner_cases.vader
blob: c44cf0eaf2a59e598976d0c6b4a875e650b61057 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
" Tests for various corner cases of applying code changes from LSP.
"
" These can be verified against the reference vscode implementation using the
" following javascript program:
"
"   const { TextDocument } = require('vscode-languageserver-textdocument');
"   const { TextEdit, Position, Range } = require('vscode-languageserver-types');
"   function MkPos(line, offset) { return Position.create(line - 1, offset - 1); }
"   function MkInsert(pos, newText) { return TextEdit.insert(pos, newText); }
"   function MkDelete(start, end) { return TextEdit.del(Range.create(start, end)); }
"   function TestChanges(s, es) {
"     return TextDocument.applyEdits(TextDocument.create(null, null, null, s), es);
"   }
"
"   const fs = require("fs");
"   const assert = require('assert').strict;
"   const testRegex = /(?<!vscode skip.*)AssertEqual\s+("[^"]*"),\s*TestChanges\(("[^"]*"),\s*(\[[^\]]*\])/g;
"   const data = fs.readFileSync(0, "utf-8");
"   const tests = data.matchAll(testRegex);
"   for (const test of tests) {
"     console.log(test[0]);
"     assert.equal(eval(test[1]), TestChanges(eval(test[2]), eval(test[3])));
"   }
"
" Save it to test_code_action_corner_cases.js and invoke it using:
"
"   $ npm install vscode-languageserver-{textdocument,types}
"   $ node test_code_action_corner_cases.js <test_code_action_corner_cases.vader

Before:
  Save &fixeol
  set nofixeol

  Save &fileformats
  set fileformats=unix

  " two files, one accessed through a buffer, the other using write/readfile only
  let g:files = [tempname(), tempname()]

  function! TestChanges(contents, changes, mode) abort
    let l:file = g:files[a:mode is 'file' ? 0 : 1]
    call writefile(split(a:contents, '\n', 1), l:file, 'bS')
    if a:mode isnot 'file'
      execute 'edit ' . l:file
    endif
    call ale#code_action#ApplyChanges(l:file, a:changes, a:mode isnot 'buffer')
    if a:mode is 'buffer'
      execute 'write ' . l:file
    endif
    return join(readfile(l:file, 'b'), "\n")
  endfunction!

  function! MkPos(line, offset) abort
    return {'line': a:line, 'offset': a:offset}
  endfunction!

  function! MkInsert(pos, newText) abort
    return {'start': a:pos, 'end': a:pos, 'newText': a:newText}
  endfunction!

  function! MkDelete(start, end) abort
    return {'start': a:start, 'end': a:end, 'newText': ''}
  endfunction!

After:
  for g:file in g:files
    if bufnr(g:file) != -1
      execute ':bp! | :bd! ' . bufnr(g:file)
    endif
    if filereadable(g:file)
      call delete(g:file)
    endif
  endfor
  unlet! g:files g:file

  unlet! g:mode

  delfunction TestChanges
  delfunction MkPos
  delfunction MkInsert
  delfunction MkDelete

  Restore

Execute(Preserve (no)eol at eof):
  for g:mode in ['save', 'file', 'buffer']
    Log g:mode
    AssertEqual "noeol",    TestChanges("noeol",    [], g:mode)
    AssertEqual "eol\n",    TestChanges("eol\n",    [], g:mode)
    AssertEqual "eols\n\n", TestChanges("eols\n\n", [], g:mode)
  endfor

  " there doesn't seem to be a way to tell if a buffer is empty or contains one
  " empty line :-(
  AssertEqual "", TestChanges("", [], 'file')

Execute(Respect fixeol):
  set fixeol
  for g:mode in ['save', 'file', 'buffer']
    Log g:mode
    silent echo "vscode skip" | AssertEqual "noeol\n", TestChanges("noeol", [], g:mode)
    silent echo "vscode skip" | AssertEqual "eol\n",   TestChanges("eol\n", [], g:mode)
  endfor

Execute(Add/del eol at eof):
  for g:mode in ['save', 'file', 'buffer']
    Log g:mode
    AssertEqual "addeol\n", TestChanges("addeol",   [MkInsert(MkPos(1, 7), "\n")], g:mode)
    AssertEqual "deleol",   TestChanges("deleol\n", [MkDelete(MkPos(1, 7), MkPos(1, 8))], g:mode)
  endfor

Execute(One character insertions to first line):
  for g:mode in ['save', 'file', 'buffer']
    Log g:mode
    AssertEqual "xabc\ndef1\nghi\n", TestChanges("abc\ndef1\nghi\n", [MkInsert(MkPos(1, 0), "x")], g:mode)
    AssertEqual "xabc\ndef2\nghi\n", TestChanges("abc\ndef2\nghi\n", [MkInsert(MkPos(1, 1), "x")], g:mode)
    AssertEqual "axbc\ndef3\nghi\n", TestChanges("abc\ndef3\nghi\n", [MkInsert(MkPos(1, 2), "x")], g:mode)
    AssertEqual "abcx\ndef4\nghi\n", TestChanges("abc\ndef4\nghi\n", [MkInsert(MkPos(1, 4), "x")], g:mode)
    AssertEqual "abc\nxdef5\nghi\n", TestChanges("abc\ndef5\nghi\n", [MkInsert(MkPos(1, 5), "x")], g:mode)
    AssertEqual "abc\nxdef6\nghi\n", TestChanges("abc\ndef6\nghi\n", [MkInsert(MkPos(1, 6), "x")], g:mode)
  endfor

Execute(One character + newline insertions to first line):
  for g:mode in ['save', 'file', 'buffer']
    Log g:mode
    AssertEqual "x\nabc\ndef1\nghi\n", TestChanges("abc\ndef1\nghi\n", [MkInsert(MkPos(1, 0), "x\n")], g:mode)
    AssertEqual "x\nabc\ndef2\nghi\n", TestChanges("abc\ndef2\nghi\n", [MkInsert(MkPos(1, 1), "x\n")], g:mode)
    AssertEqual "ax\nbc\ndef3\nghi\n", TestChanges("abc\ndef3\nghi\n", [MkInsert(MkPos(1, 2), "x\n")], g:mode)
    AssertEqual "abcx\n\ndef4\nghi\n", TestChanges("abc\ndef4\nghi\n", [MkInsert(MkPos(1, 4), "x\n")], g:mode)
    AssertEqual "abc\nx\ndef5\nghi\n", TestChanges("abc\ndef5\nghi\n", [MkInsert(MkPos(1, 5), "x\n")], g:mode)
    AssertEqual "abc\nx\ndef6\nghi\n", TestChanges("abc\ndef6\nghi\n", [MkInsert(MkPos(1, 6), "x\n")], g:mode)
  endfor

Execute(One character insertions near end):
  for g:mode in ['save', 'file', 'buffer']
    Log g:mode
    AssertEqual "abc\ndef1\nghxi\n", TestChanges("abc\ndef1\nghi\n", [MkInsert(MkPos(3, 3), "x")], g:mode)
    AssertEqual "abc\ndef2\nghix\n", TestChanges("abc\ndef2\nghi\n", [MkInsert(MkPos(3, 4), "x")], g:mode)
    AssertEqual "abc\ndef3\nghi\nx", TestChanges("abc\ndef3\nghi\n", [MkInsert(MkPos(3, 5), "x")], g:mode)
    AssertEqual "abc\ndef4\nghi\nx", TestChanges("abc\ndef4\nghi\n", [MkInsert(MkPos(3, 6), "x")], g:mode)
    AssertEqual "abc\ndef5\nghi\nx", TestChanges("abc\ndef5\nghi\n", [MkInsert(MkPos(4, 1), "x")], g:mode)
    AssertEqual "abc\ndef6\nghi\nx", TestChanges("abc\ndef6\nghi\n", [MkInsert(MkPos(4, 2), "x")], g:mode)
    AssertEqual "abc\ndef7\nghi\nx", TestChanges("abc\ndef7\nghi\n", [MkInsert(MkPos(5, 1), "x")], g:mode)
    AssertEqual "abc\ndef8\nghi\nx", TestChanges("abc\ndef8\nghi\n", [MkInsert(MkPos(5, 2), "x")], g:mode)
  endfor

Execute(One character + newline insertions near end):
  for g:mode in ['save', 'file', 'buffer']
    Log g:mode
    AssertEqual "abc\ndef1\nghx\ni\n", TestChanges("abc\ndef1\nghi\n", [MkInsert(MkPos(3, 3), "x\n")], g:mode)
    AssertEqual "abc\ndef2\nghix\n\n", TestChanges("abc\ndef2\nghi\n", [MkInsert(MkPos(3, 4), "x\n")], g:mode)
    AssertEqual "abc\ndef3\nghi\nx\n", TestChanges("abc\ndef3\nghi\n", [MkInsert(MkPos(3, 5), "x\n")], g:mode)
    AssertEqual "abc\ndef4\nghi\nx\n", TestChanges("abc\ndef4\nghi\n", [MkInsert(MkPos(3, 6), "x\n")], g:mode)
    AssertEqual "abc\ndef5\nghi\nx\n", TestChanges("abc\ndef5\nghi\n", [MkInsert(MkPos(4, 1), "x\n")], g:mode)
    AssertEqual "abc\ndef6\nghi\nx\n", TestChanges("abc\ndef6\nghi\n", [MkInsert(MkPos(4, 2), "x\n")], g:mode)
  endfor

Execute(Newline insertions near end):
  for g:mode in ['save', 'file', 'buffer']
    Log g:mode
    AssertEqual "abc\ndef1\ngh\ni\n", TestChanges("abc\ndef1\nghi\n", [MkInsert(MkPos(3, 3), "\n")], g:mode)
    AssertEqual "abc\ndef2\nghi\n\n", TestChanges("abc\ndef2\nghi\n", [MkInsert(MkPos(3, 4), "\n")], g:mode)
    AssertEqual "abc\ndef3\nghi\n\n", TestChanges("abc\ndef3\nghi\n", [MkInsert(MkPos(3, 5), "\n")], g:mode)
    AssertEqual "abc\ndef4\nghi\n\n", TestChanges("abc\ndef4\nghi\n", [MkInsert(MkPos(3, 6), "\n")], g:mode)
    AssertEqual "abc\ndef5\nghi\n\n", TestChanges("abc\ndef5\nghi\n", [MkInsert(MkPos(4, 1), "\n")], g:mode)
  endfor

Execute(Single char deletions):
  for g:mode in ['save', 'file', 'buffer']
    Log g:mode
    AssertEqual "bc\ndef1\nghi\n",  TestChanges("abc\ndef1\nghi\n", [MkDelete(MkPos(1, 1), MkPos(1, 2))], g:mode)
    AssertEqual "ab\ndef2\nghi\n",  TestChanges("abc\ndef2\nghi\n", [MkDelete(MkPos(1, 3), MkPos(1, 4))], g:mode)
    AssertEqual "abcdef3\nghi\n",   TestChanges("abc\ndef3\nghi\n", [MkDelete(MkPos(1, 4), MkPos(1, 5))], g:mode)
    AssertEqual "abcdef4\nghi\n",   TestChanges("abc\ndef4\nghi\n", [MkDelete(MkPos(1, 4), MkPos(1, 6))], g:mode)
    AssertEqual "abc\ndef5\ngh\n",  TestChanges("abc\ndef5\nghi\n", [MkDelete(MkPos(3, 3), MkPos(3, 4))], g:mode)
    AssertEqual "abc\ndef6\nghi",   TestChanges("abc\ndef6\nghi\n", [MkDelete(MkPos(3, 4), MkPos(3, 5))], g:mode)
    AssertEqual "abc\ndef7\nghi",   TestChanges("abc\ndef7\nghi\n", [MkDelete(MkPos(3, 4), MkPos(3, 6))], g:mode)
    AssertEqual "abc\ndef8\nghi\n", TestChanges("abc\ndef8\nghi\n", [MkDelete(MkPos(4, 1), MkPos(4, 2))], g:mode)
  endfor