-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtest.c++
270 lines (236 loc) · 8.75 KB
/
test.c++
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
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
#include <iostream>
#include <regex>
#include <sstream>
#include <string>
using namespace std::string_literals;
std::string with_end_statements(std::istream&);
unsigned failed_tests_count = 0;
void test(const char* test_name, const char* input, const char* expected_output)
{
const auto output = [&input]()
{
try
{
std::istringstream is(input);
return with_end_statements(is);
}
catch (const char* const exception)
{
return "Exception: "s + exception + '\n';
}
}
();
if (output != expected_output)
{
++failed_tests_count;
std::cerr << "*** " << test_name << " failed. ***\n"
<< "EXPECTED:\n" << expected_output << '\n'
<< "ACTUAL:\n" << output << '\n';
}
}
void test(const char* name, const char* annotated_script /*lines prefixed with >>> are removed from the input; they are expected in the output*/)
{
test(name, /*input*/ std::regex_replace(annotated_script, std::regex("\n>>>.*"), "").c_str(),
/*expected_output*/ std::regex_replace(annotated_script, std::regex("\n>>>"), "\n").c_str());
}
int main()
{
test("function, if, while, for",
"function X()\n"
" if 0\n"
" echo\n"
">>> endif\n"
">>>endfunction\n"
"\n"
"\n" // (It looks nicer with the "endif" and "endfunction" appearing before the blank lines rather than after them.)
"function! X()\n"
" while 1\n"
" for i in [1,2,3]\n"
" echo i\n"
">>> endfor\n" // Note previous "end statements" were output due to a decrease in statement indentation. These "end statements" though are output because there are no more statements.
">>> endwhile\n"
">>>endfunction\n"
"\n"
"\" vim:sw=4\n" // It's nice for the modeline to remain the last line.
);
test("if statement and its body on same line",
"if 1 | echo\n"
">>>endif\n");
test("else, elseif",
"if 0\n"
" echo\n"
"else\n" // (If this wasn't an "else" (or "elseif") an "endif" would have to be output first because it's not indented like the "if 0" above.)
" echo\n"
" while 1\n"
" echo\n"
">>> endwhile\n" // Note on reaching the "else" below we need to output end statements such as this, but not for the "if" that is not indented.
"elseif 0\n"
" echo\n"
">>>endif\n");
test("if statement extra tests",
"echo 'if'\n" // No endif output for this line containing "if".
"if 1\n"
" if 1\n" // nested if.
" echo\n"
">>> endif\n"
"else\n"
" echo\n"
">>>endif\n");
test("try, catch, finally",
"try\n"
" echo\n"
"catch /1/\n"
" echo\n"
"finally\n"
" echo\n"
">>>endtry\n"
"\n"
"try\n"
" echo\n"
">>>endtry\n");
test("augroup",
"augroup X\n"
" autocmd!\n"
" autocmd BufWritePost ~/.vimrc so ~/.vimrc\n"
">>>augroup end\n");
test("vim9script def",
"vim9script\n"
"\n"
"def EchoHi()\n"
" echo 'Hi'\n"
">>>enddef\n"
"\n"
"EchoHi()\n");
test("DOS line endings",
"insert!\r\n"
"text\r\n"
".\r\n" // << Initially this was not recognised as the end of the insert statement and consequently no "endif" was added as "if 1" was considered part of the input for :insert. (".\r" != ".")
"if 1\r\n"
"\r\n" // <<< This initially caused the test to fail. ("\r" had been interpreted like a statement in the first column.)
" echo\r\n"
"echo",
// Note: '\r's don't appear in the output. Ideally, perhaps, line endings in the output should match those in the input. Using '\n' instead of '\r\n' shouldn't be a problem though; it should be possible to run the the resulting script on either Windows or Linux. (With '\r's Vim on Linux could throw "E492: Not an editor command: ^M".) See :help :source_crnl.
"insert!\n"
"text\n"
".\n"
"if 1\n"
"\n"
" echo\n"
"endif\n"
"echo\n" /*The last line ends with '\n' even though the source didn't end with '\r\n'. (It is common for the last line of a text file to end with \n' on Unix.)*/);
#if 0 // xxx We only look for statements that prefix a new code block (or heredoc) at the start of a line.
test("multiple statements on one-line",
"let c = Cond() | if c\n"
" echo\n"
">>>endif\n");
#endif
#if 0
test("comment at end of function",
"function X()\n"
" echo\n"
"\n"
" \" comment\n" // This comment has the same number of spaces of indentation as the last statement in the function. It probably makes the most sense for the "endfunction" to be added after this comment.
">>>endfunction\n"
"\n"
"echo\n");
#endif
// Line-continuation -----------------------------------------------------------------
test("line continuation and line continuation comment",
"if\n"
// (Check no "endif" inserted here even though the next line is not indented.)
"\"\\ Comment.\n"
"\\ 1\n"
" let a =\n"
"\\ 42\n"
">>>endif\n");
test("Unexpected line continuation symbol at start of file",
"\\if 1\n echo\n",
"Exception: Unexpected line continuation symbol.\n" /*xxx "on line 1".*/);
test("Unexpected line continuation symbol following blank line",
"if\n\n\\ 1\n echo\n",
"Exception: Unexpected line continuation symbol.\n" /*xxx "on line 3".*/);
// Heredocs --------------------------------------------------------------------------
// Text within a heredoc must be left as is.
test("insert and append",
"function X()\n"
"\n"
" insert\n"
"\n"
" for\n" // No "endfor" to be inserted.
"\n"
".\n"
">>>endfunction\n"
"42insert\n"
"if 0\n"
".\n"
"append\n"
" \\[unimportant - rare to start line after :append with '\\'.] This line will be processed by the utility as the first line of a heredoc for :append (and not as a \"continuation line\"). Note though that Vim will only interpret this line as the first line of a heredoc for :append if cpoptions contains 'C' even though by default cpoptions won't contain 'C'! (See :help line-continuation, search for \":append\".)\n"
"function Y()\n" // No "endfunction" inserted.
// Vim interprets EOF as a valid end of a heredoc for :append.
);
#if 0
test("insert and append with a location prefix",
"/needle/append\n"
"Here it is!\n"
".\n"); // xxx test with other locations, e.g. $, 'm, etc. (:help range lists all options.)
#endif
test("pythonx heredoc",
"pythonx <<\n"
"if 1:\n"
" def the_answer():\n"
" return 42\n"
".\n"
"\n"
"pythonx print(\"Hi\")\n" // Check that what follows isn't treated as a heredoc.
"if 0\n"
" echo\n"
">>>endif\n");
#if 0
test("pythonx heredoc: intro line is split over two lines",
"pythonx\n"
" \\ <<\n" // Vim accepts this but I don't think it's worth the trouble to get this test to pass.
"if 1:\n"
" pass\n"
);
#endif
test("python heredoc with custom end marker",
"python << ?/End!\n"
"if 1:\n"
" def the_answer():\n"
" return 42\n"
"?/End!\n"
"\n"
"python3 << ?/End!\n"
"if 1:\n"
" pass\n"
"?/End!\n");
test("lua, perl, ruby, mzscheme and tcl heredocs",
"lua <<\nif 1\n.\n"
"perl <<\nif 1\n.\n"
"ruby <<\nif 1\n.\n"
"mzscheme <<\nif 1\n.\n"
"tcl <<\nif 1\n.\n");
test("let and const heredocs",
"let text =<< trim END\n" // (Note: "trim" is optional. end_marker is required.)
" if 1\n"
"END\n"
"let text =<<END_TEXT\n" // ("trim" not specified.)
"if 1\n"
"END_TEXT\n"
"\n"
"if 1\n"
" const k =<< trim END\n"
" if no_endif_required\n"
"END\n"
" cons k2 =<< END\n"
" if no_endif_required\n"
"END\n"
">>>endif\n");
#if 0
test("Invalid let heredoc",
"let text =<<\n if 1\n.\n",
"Exception: Invalid let heredoc - end marker not specified.\n");
#endif
if (!failed_tests_count) { std::cout << "Ok.\n"; }
return failed_tests_count;
}