test_filecompletion.c revision 1.1 1 1.1 abhinav #include "config.h"
2 1.1 abhinav
3 1.1 abhinav #include <assert.h>
4 1.1 abhinav #include <err.h>
5 1.1 abhinav #include <stdio.h>
6 1.1 abhinav #include <histedit.h>
7 1.1 abhinav #include <stdlib.h>
8 1.1 abhinav #include <string.h>
9 1.1 abhinav #include <wchar.h>
10 1.1 abhinav
11 1.1 abhinav #include "filecomplete.h"
12 1.1 abhinav #include "el.h"
13 1.1 abhinav
14 1.1 abhinav typedef struct {
15 1.1 abhinav const wchar_t *user_typed_text; /* The actual text typed by the user on the terminal */
16 1.1 abhinav const char *completion_function_input ; /*the text received by fn_filename_completion_function */
17 1.1 abhinav const char *expanded_text; /* the value to which completion_function_input should be expanded */
18 1.1 abhinav const wchar_t *escaped_output; /* expected escaped value of expanded_text */
19 1.1 abhinav } test_input;
20 1.1 abhinav
21 1.1 abhinav static test_input inputs[] = {
22 1.1 abhinav {
23 1.1 abhinav /* simple test for escaping angular brackets */
24 1.1 abhinav L"ls ang",
25 1.1 abhinav "ang",
26 1.1 abhinav "ang<ular>test",
27 1.1 abhinav L"ls ang\\<ular\\>test "
28 1.1 abhinav },
29 1.1 abhinav {
30 1.1 abhinav /* test angular bracket inside double quotes: ls "dq_ang */
31 1.1 abhinav L"ls \"dq_ang",
32 1.1 abhinav "dq_ang",
33 1.1 abhinav "dq_ang<ular>test",
34 1.1 abhinav L"ls \"dq_ang<ular>test\" "
35 1.1 abhinav },
36 1.1 abhinav {
37 1.1 abhinav /* test angular bracket inside singlq quotes: ls "sq_ang */
38 1.1 abhinav L"ls 'sq_ang",
39 1.1 abhinav "sq_ang",
40 1.1 abhinav "sq_ang<ular>test",
41 1.1 abhinav L"ls 'sq_ang<ular>test' "
42 1.1 abhinav },
43 1.1 abhinav {
44 1.1 abhinav /* simple test for backslash */
45 1.1 abhinav L"ls back",
46 1.1 abhinav "back",
47 1.1 abhinav "backslash\\test",
48 1.1 abhinav L"ls backslash\\\\test "
49 1.1 abhinav },
50 1.1 abhinav {
51 1.1 abhinav /* backslash inside single quotes */
52 1.1 abhinav L"ls 'sback",
53 1.1 abhinav "sback",
54 1.1 abhinav "sbackslash\\test",
55 1.1 abhinav L"ls 'sbackslash\\test' "
56 1.1 abhinav },
57 1.1 abhinav {
58 1.1 abhinav /* backslash inside double quotes */
59 1.1 abhinav L"ls \"dback",
60 1.1 abhinav "dback",
61 1.1 abhinav "dbackslash\\test",
62 1.1 abhinav L"ls \"dbackslash\\\\test\" "
63 1.1 abhinav },
64 1.1 abhinav {
65 1.1 abhinav /* test braces */
66 1.1 abhinav L"ls br",
67 1.1 abhinav "br",
68 1.1 abhinav "braces{test}",
69 1.1 abhinav L"ls braces\\{test\\} "
70 1.1 abhinav },
71 1.1 abhinav {
72 1.1 abhinav /* test braces inside single quotes */
73 1.1 abhinav L"ls 'sbr",
74 1.1 abhinav "sbr",
75 1.1 abhinav "sbraces{test}",
76 1.1 abhinav L"ls 'sbraces{test}' "
77 1.1 abhinav },
78 1.1 abhinav {
79 1.1 abhinav /* test braces inside double quotes */
80 1.1 abhinav L"ls \"dbr",
81 1.1 abhinav "dbr",
82 1.1 abhinav "dbraces{test}",
83 1.1 abhinav L"ls \"dbraces{test}\" "
84 1.1 abhinav },
85 1.1 abhinav {
86 1.1 abhinav /* test dollar */
87 1.1 abhinav L"ls doll",
88 1.1 abhinav "doll",
89 1.1 abhinav "doll$artest",
90 1.1 abhinav L"ls doll\\$artest "
91 1.1 abhinav },
92 1.1 abhinav {
93 1.1 abhinav /* test dollar inside single quotes */
94 1.1 abhinav L"ls 'sdoll",
95 1.1 abhinav "sdoll",
96 1.1 abhinav "sdoll$artest",
97 1.1 abhinav L"ls 'sdoll$artest' "
98 1.1 abhinav },
99 1.1 abhinav {
100 1.1 abhinav /* test dollar inside double quotes */
101 1.1 abhinav L"ls \"ddoll",
102 1.1 abhinav "ddoll",
103 1.1 abhinav "ddoll$artest",
104 1.1 abhinav L"ls \"ddoll\\$artest\" "
105 1.1 abhinav },
106 1.1 abhinav {
107 1.1 abhinav /* test equals */
108 1.1 abhinav L"ls eq",
109 1.1 abhinav "eq",
110 1.1 abhinav "equals==test",
111 1.1 abhinav L"ls equals\\=\\=test "
112 1.1 abhinav },
113 1.1 abhinav {
114 1.1 abhinav /* test equals inside sinqle quotes */
115 1.1 abhinav L"ls 'seq",
116 1.1 abhinav "seq",
117 1.1 abhinav "sequals==test",
118 1.1 abhinav L"ls 'sequals==test' "
119 1.1 abhinav },
120 1.1 abhinav {
121 1.1 abhinav /* test equals inside double quotes */
122 1.1 abhinav L"ls \"deq",
123 1.1 abhinav "deq",
124 1.1 abhinav "dequals==test",
125 1.1 abhinav L"ls \"dequals==test\" "
126 1.1 abhinav },
127 1.1 abhinav {
128 1.1 abhinav /* test \n */
129 1.1 abhinav L"ls new",
130 1.1 abhinav "new",
131 1.1 abhinav "new\\nline",
132 1.1 abhinav L"ls new\\\\nline "
133 1.1 abhinav },
134 1.1 abhinav {
135 1.1 abhinav /* test \n inside single quotes */
136 1.1 abhinav L"ls 'snew",
137 1.1 abhinav "snew",
138 1.1 abhinav "snew\nline",
139 1.1 abhinav L"ls 'snew\nline' "
140 1.1 abhinav },
141 1.1 abhinav {
142 1.1 abhinav /* test \n inside double quotes */
143 1.1 abhinav L"ls \"dnew",
144 1.1 abhinav "dnew",
145 1.1 abhinav "dnew\nline",
146 1.1 abhinav L"ls \"dnew\nline\" "
147 1.1 abhinav },
148 1.1 abhinav {
149 1.1 abhinav /* test single space */
150 1.1 abhinav L"ls spac",
151 1.1 abhinav "spac",
152 1.1 abhinav "space test",
153 1.1 abhinav L"ls space\\ test "
154 1.1 abhinav },
155 1.1 abhinav {
156 1.1 abhinav /* test single space inside singlq quotes */
157 1.1 abhinav L"ls 's_spac",
158 1.1 abhinav "s_spac",
159 1.1 abhinav "s_space test",
160 1.1 abhinav L"ls 's_space test' "
161 1.1 abhinav },
162 1.1 abhinav {
163 1.1 abhinav /* test single space inside double quotes */
164 1.1 abhinav L"ls \"d_spac",
165 1.1 abhinav "d_spac",
166 1.1 abhinav "d_space test",
167 1.1 abhinav L"ls \"d_space test\" "
168 1.1 abhinav },
169 1.1 abhinav {
170 1.1 abhinav /* test multiple spaces */
171 1.1 abhinav L"ls multi",
172 1.1 abhinav "multi",
173 1.1 abhinav "multi space test",
174 1.1 abhinav L"ls multi\\ space\\ \\ test "
175 1.1 abhinav },
176 1.1 abhinav {
177 1.1 abhinav /* test multiple spaces inside single quotes */
178 1.1 abhinav L"ls 's_multi",
179 1.1 abhinav "s_multi",
180 1.1 abhinav "s_multi space test",
181 1.1 abhinav L"ls 's_multi space test' "
182 1.1 abhinav },
183 1.1 abhinav {
184 1.1 abhinav /* test multiple spaces inside double quotes */
185 1.1 abhinav L"ls \"d_multi",
186 1.1 abhinav "d_multi",
187 1.1 abhinav "d_multi space test",
188 1.1 abhinav L"ls \"d_multi space test\" "
189 1.1 abhinav },
190 1.1 abhinav {
191 1.1 abhinav /* test double quotes */
192 1.1 abhinav L"ls doub",
193 1.1 abhinav "doub",
194 1.1 abhinav "doub\"quotes",
195 1.1 abhinav L"ls doub\\\"quotes "
196 1.1 abhinav },
197 1.1 abhinav {
198 1.1 abhinav /* test double quotes inside single quotes */
199 1.1 abhinav L"ls 's_doub",
200 1.1 abhinav "s_doub",
201 1.1 abhinav "s_doub\"quotes",
202 1.1 abhinav L"ls 's_doub\"quotes' "
203 1.1 abhinav },
204 1.1 abhinav {
205 1.1 abhinav /* test double quotes inside double quotes */
206 1.1 abhinav L"ls \"d_doub",
207 1.1 abhinav "d_doub",
208 1.1 abhinav "d_doub\"quotes",
209 1.1 abhinav L"ls \"d_doub\\\"quotes\" "
210 1.1 abhinav },
211 1.1 abhinav {
212 1.1 abhinav /* test multiple double quotes */
213 1.1 abhinav L"ls mud",
214 1.1 abhinav "mud",
215 1.1 abhinav "mud\"qu\"otes\"",
216 1.1 abhinav L"ls mud\\\"qu\\\"otes\\\" "
217 1.1 abhinav },
218 1.1 abhinav {
219 1.1 abhinav /* test multiple double quotes inside single quotes */
220 1.1 abhinav L"ls 'smud",
221 1.1 abhinav "smud",
222 1.1 abhinav "smud\"qu\"otes\"",
223 1.1 abhinav L"ls 'smud\"qu\"otes\"' "
224 1.1 abhinav },
225 1.1 abhinav {
226 1.1 abhinav /* test multiple double quotes inside double quotes */
227 1.1 abhinav L"ls \"dmud",
228 1.1 abhinav "dmud",
229 1.1 abhinav "dmud\"qu\"otes\"",
230 1.1 abhinav L"ls \"dmud\\\"qu\\\"otes\\\"\" "
231 1.1 abhinav },
232 1.1 abhinav {
233 1.1 abhinav /* test one single quote */
234 1.1 abhinav L"ls sing",
235 1.1 abhinav "sing",
236 1.1 abhinav "single'quote",
237 1.1 abhinav L"ls single\\'quote "
238 1.1 abhinav },
239 1.1 abhinav {
240 1.1 abhinav /* test one single quote inside single quote */
241 1.1 abhinav L"ls 'ssing",
242 1.1 abhinav "ssing",
243 1.1 abhinav "ssingle'quote",
244 1.1 abhinav L"ls 'ssingle'\\''quote' "
245 1.1 abhinav },
246 1.1 abhinav {
247 1.1 abhinav /* test one single quote inside double quote */
248 1.1 abhinav L"ls \"dsing",
249 1.1 abhinav "dsing",
250 1.1 abhinav "dsingle'quote",
251 1.1 abhinav L"ls \"dsingle'quote\" "
252 1.1 abhinav },
253 1.1 abhinav {
254 1.1 abhinav /* test multiple single quotes */
255 1.1 abhinav L"ls mu_sing",
256 1.1 abhinav "mu_sing",
257 1.1 abhinav "mu_single''quotes''",
258 1.1 abhinav L"ls mu_single\\'\\'quotes\\'\\' "
259 1.1 abhinav },
260 1.1 abhinav {
261 1.1 abhinav /* test multiple single quotes inside single quote */
262 1.1 abhinav L"ls 'smu_sing",
263 1.1 abhinav "smu_sing",
264 1.1 abhinav "smu_single''quotes''",
265 1.1 abhinav L"ls 'smu_single'\\'''\\''quotes'\\\'''\\''' "
266 1.1 abhinav },
267 1.1 abhinav {
268 1.1 abhinav /* test multiple single quotes inside double quote */
269 1.1 abhinav L"ls \"dmu_sing",
270 1.1 abhinav "dmu_sing",
271 1.1 abhinav "dmu_single''quotes''",
272 1.1 abhinav L"ls \"dmu_single''quotes''\" "
273 1.1 abhinav },
274 1.1 abhinav {
275 1.1 abhinav /* test parenthesis */
276 1.1 abhinav L"ls paren",
277 1.1 abhinav "paren",
278 1.1 abhinav "paren(test)",
279 1.1 abhinav L"ls paren\\(test\\) "
280 1.1 abhinav },
281 1.1 abhinav {
282 1.1 abhinav /* test parenthesis inside single quote */
283 1.1 abhinav L"ls 'sparen",
284 1.1 abhinav "sparen",
285 1.1 abhinav "sparen(test)",
286 1.1 abhinav L"ls 'sparen(test)' "
287 1.1 abhinav },
288 1.1 abhinav {
289 1.1 abhinav /* test parenthesis inside double quote */
290 1.1 abhinav L"ls \"dparen",
291 1.1 abhinav "dparen",
292 1.1 abhinav "dparen(test)",
293 1.1 abhinav L"ls \"dparen(test)\" "
294 1.1 abhinav },
295 1.1 abhinav {
296 1.1 abhinav /* test pipe */
297 1.1 abhinav L"ls pip",
298 1.1 abhinav "pip",
299 1.1 abhinav "pipe|test",
300 1.1 abhinav L"ls pipe\\|test "
301 1.1 abhinav },
302 1.1 abhinav {
303 1.1 abhinav /* test pipe inside single quote */
304 1.1 abhinav L"ls 'spip",
305 1.1 abhinav "spip",
306 1.1 abhinav "spipe|test",
307 1.1 abhinav L"ls 'spipe|test' ",
308 1.1 abhinav },
309 1.1 abhinav {
310 1.1 abhinav /* test pipe inside double quote */
311 1.1 abhinav L"ls \"dpip",
312 1.1 abhinav "dpip",
313 1.1 abhinav "dpipe|test",
314 1.1 abhinav L"ls \"dpipe|test\" "
315 1.1 abhinav },
316 1.1 abhinav {
317 1.1 abhinav /* test tab */
318 1.1 abhinav L"ls ta",
319 1.1 abhinav "ta",
320 1.1 abhinav "tab\ttest",
321 1.1 abhinav L"ls tab\\\ttest "
322 1.1 abhinav },
323 1.1 abhinav {
324 1.1 abhinav /* test tab inside single quote */
325 1.1 abhinav L"ls 'sta",
326 1.1 abhinav "sta",
327 1.1 abhinav "stab\ttest",
328 1.1 abhinav L"ls 'stab\ttest' "
329 1.1 abhinav },
330 1.1 abhinav {
331 1.1 abhinav /* test tab inside double quote */
332 1.1 abhinav L"ls \"dta",
333 1.1 abhinav "dta",
334 1.1 abhinav "dtab\ttest",
335 1.1 abhinav L"ls \"dtab\ttest\" "
336 1.1 abhinav },
337 1.1 abhinav {
338 1.1 abhinav /* test back tick */
339 1.1 abhinav L"ls tic",
340 1.1 abhinav "tic",
341 1.1 abhinav "tick`test`",
342 1.1 abhinav L"ls tick\\`test\\` "
343 1.1 abhinav },
344 1.1 abhinav {
345 1.1 abhinav /* test back tick inside single quote */
346 1.1 abhinav L"ls 'stic",
347 1.1 abhinav "stic",
348 1.1 abhinav "stick`test`",
349 1.1 abhinav L"ls 'stick`test`' "
350 1.1 abhinav },
351 1.1 abhinav {
352 1.1 abhinav /* test back tick inside double quote */
353 1.1 abhinav L"ls \"dtic",
354 1.1 abhinav "dtic",
355 1.1 abhinav "dtick`test`",
356 1.1 abhinav L"ls \"dtick\\`test\\`\" "
357 1.1 abhinav },
358 1.1 abhinav {
359 1.1 abhinav /* test for @ */
360 1.1 abhinav L"ls at",
361 1.1 abhinav "at",
362 1.1 abhinav "atthe@rate",
363 1.1 abhinav L"ls atthe\\@rate "
364 1.1 abhinav },
365 1.1 abhinav {
366 1.1 abhinav /* test for @ inside single quote */
367 1.1 abhinav L"ls 'sat",
368 1.1 abhinav "sat",
369 1.1 abhinav "satthe@rate",
370 1.1 abhinav L"ls 'satthe@rate' "
371 1.1 abhinav },
372 1.1 abhinav {
373 1.1 abhinav /* test for @ inside double quote */
374 1.1 abhinav L"ls \"dat",
375 1.1 abhinav "dat",
376 1.1 abhinav "datthe@rate",
377 1.1 abhinav L"ls \"datthe@rate\" "
378 1.1 abhinav },
379 1.1 abhinav {
380 1.1 abhinav /* test ; */
381 1.1 abhinav L"ls semi",
382 1.1 abhinav "semi",
383 1.1 abhinav "semi;colon;test",
384 1.1 abhinav L"ls semi\\;colon\\;test "
385 1.1 abhinav },
386 1.1 abhinav {
387 1.1 abhinav /* test ; inside single quote */
388 1.1 abhinav L"ls 'ssemi",
389 1.1 abhinav "ssemi",
390 1.1 abhinav "ssemi;colon;test",
391 1.1 abhinav L"ls 'ssemi;colon;test' "
392 1.1 abhinav },
393 1.1 abhinav {
394 1.1 abhinav /* test ; inside double quote */
395 1.1 abhinav L"ls \"dsemi",
396 1.1 abhinav "dsemi",
397 1.1 abhinav "dsemi;colon;test",
398 1.1 abhinav L"ls \"dsemi;colon;test\" "
399 1.1 abhinav },
400 1.1 abhinav {
401 1.1 abhinav /* test & */
402 1.1 abhinav L"ls amp",
403 1.1 abhinav "amp",
404 1.1 abhinav "ampers&and",
405 1.1 abhinav L"ls ampers\\&and "
406 1.1 abhinav },
407 1.1 abhinav {
408 1.1 abhinav /* test & inside single quote */
409 1.1 abhinav L"ls 'samp",
410 1.1 abhinav "samp",
411 1.1 abhinav "sampers&and",
412 1.1 abhinav L"ls 'sampers&and' "
413 1.1 abhinav },
414 1.1 abhinav {
415 1.1 abhinav /* test & inside double quote */
416 1.1 abhinav L"ls \"damp",
417 1.1 abhinav "damp",
418 1.1 abhinav "dampers&and",
419 1.1 abhinav L"ls \"dampers&and\" "
420 1.1 abhinav },
421 1.1 abhinav {
422 1.1 abhinav /* test multiple words */
423 1.1 abhinav L"ls word",
424 1.1 abhinav "word",
425 1.1 abhinav "word1 \"word2\\`with many \\ $characters\"",
426 1.1 abhinav L"ls word1 \"word2\\`with many \\ $characters\""
427 1.1 abhinav }
428 1.1 abhinav
429 1.1 abhinav };
430 1.1 abhinav
431 1.1 abhinav static const wchar_t break_chars[] = L" \t\n\"\\'`@$><=;|&{(";
432 1.1 abhinav
433 1.1 abhinav /*
434 1.1 abhinav * Custom completion function passed to fn_complete.
435 1.1 abhinav * The function returns hardcoded completion matches
436 1.1 abhinav * based on the test cases present in inputs[] (above)
437 1.1 abhinav */
438 1.1 abhinav static char *
439 1.1 abhinav mycomplet_func(const char *text, int index)
440 1.1 abhinav {
441 1.1 abhinav static char *last_input = NULL;
442 1.1 abhinav size_t i = 0;
443 1.1 abhinav if (last_input && strcmp(last_input, text) == 0) {
444 1.1 abhinav free(last_input);
445 1.1 abhinav last_input = NULL;
446 1.1 abhinav return NULL;
447 1.1 abhinav }
448 1.1 abhinav last_input = strdup(text);
449 1.1 abhinav
450 1.1 abhinav for (i = 0; i < sizeof(inputs)/sizeof(inputs[0]); i++) {
451 1.1 abhinav if (strcmp(text, inputs[i].completion_function_input) == 0)
452 1.1 abhinav return strdup(inputs[i].expanded_text);
453 1.1 abhinav }
454 1.1 abhinav
455 1.1 abhinav return NULL;
456 1.1 abhinav }
457 1.1 abhinav
458 1.1 abhinav int
459 1.1 abhinav main(int argc, char **argv)
460 1.1 abhinav {
461 1.1 abhinav EditLine *el = el_init(argv[0], stdin, stdout, stderr);
462 1.1 abhinav size_t i;
463 1.1 abhinav size_t input_len;
464 1.1 abhinav el_line_t line;
465 1.1 abhinav wchar_t *buffer = malloc(64 * sizeof(*buffer));
466 1.1 abhinav if (buffer == NULL)
467 1.1 abhinav err(EXIT_FAILURE, "malloc failed");
468 1.1 abhinav
469 1.1 abhinav for (i = 0; i < sizeof(inputs)/sizeof(inputs[0]); i++) {
470 1.1 abhinav memset(buffer, 0, 64 * sizeof(*buffer));
471 1.1 abhinav input_len = wcslen(inputs[i].user_typed_text);
472 1.1 abhinav wmemcpy(buffer, inputs[i].user_typed_text, input_len);
473 1.1 abhinav buffer[input_len] = 0;
474 1.1 abhinav line.buffer = buffer;
475 1.1 abhinav line.cursor = line.buffer + input_len ;
476 1.1 abhinav line.lastchar = line.cursor - 1;
477 1.1 abhinav line.limit = line.buffer + 64 * sizeof(*buffer);
478 1.1 abhinav el->el_line = line;
479 1.1 abhinav fn_complete(el, mycomplet_func, NULL, break_chars, NULL, NULL, 10, NULL, NULL, NULL, NULL);
480 1.1 abhinav
481 1.1 abhinav /*
482 1.1 abhinav * fn_complete would have expanded and escaped the input in el->el_line.buffer.
483 1.1 abhinav * We need to assert that it matches with the expected value in our test data
484 1.1 abhinav */
485 1.1 abhinav printf("User input: %ls\t Expected output: %ls\t Generated output: %ls\n",
486 1.1 abhinav inputs[i].user_typed_text, inputs[i].escaped_output, el->el_line.buffer);
487 1.1 abhinav assert(wcscmp(el->el_line.buffer, inputs[i].escaped_output) == 0);
488 1.1 abhinav }
489 1.1 abhinav el_end(el);
490 1.1 abhinav return 0;
491 1.1 abhinav
492 1.1 abhinav }
493