Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/libedit/TEST/test_filecompletion.c
39586 views
1
/* $NetBSD: test_filecompletion.c,v 1.5 2019/09/08 05:50:58 abhinav Exp $ */
2
3
/*-
4
* Copyright (c) 2017 Abhinav Upadhyay <[email protected]>
5
* All rights reserved.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
10
*
11
* 1. Redistributions of source code must retain the above copyright
12
* notice, this list of conditions and the following disclaimer.
13
* 2. Redistributions in binary form must reproduce the above copyright
14
* notice, this list of conditions and the following disclaimer in
15
* the documentation and/or other materials provided with the
16
* distribution.
17
*
18
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22
* COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23
* INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
24
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
28
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29
* SUCH DAMAGE.
30
*/
31
32
#include "config.h"
33
34
#include <assert.h>
35
#include <err.h>
36
#include <stdio.h>
37
#include <histedit.h>
38
#include <stdlib.h>
39
#include <string.h>
40
#include <wchar.h>
41
42
#include "filecomplete.h"
43
#include "el.h"
44
45
typedef struct {
46
const wchar_t *user_typed_text; /* The actual text typed by the user on the terminal */
47
const char *completion_function_input ; /*the text received by fn_filename_completion_function */
48
const char *expanded_text[2]; /* the value to which completion_function_input should be expanded */
49
const wchar_t *escaped_output; /* expected escaped value of expanded_text */
50
} test_input;
51
52
static test_input inputs[] = {
53
{
54
/* simple test for escaping angular brackets */
55
L"ls ang",
56
"ang",
57
{"ang<ular>test", NULL},
58
L"ls ang\\<ular\\>test "
59
},
60
{
61
/* test angular bracket inside double quotes: ls "dq_ang */
62
L"ls \"dq_ang",
63
"dq_ang",
64
{"dq_ang<ular>test", NULL},
65
L"ls \"dq_ang<ular>test\""
66
},
67
{
68
/* test angular bracket inside singlq quotes: ls "sq_ang */
69
L"ls 'sq_ang",
70
"sq_ang",
71
{"sq_ang<ular>test", NULL},
72
L"ls 'sq_ang<ular>test'"
73
},
74
{
75
/* simple test for backslash */
76
L"ls back",
77
"back",
78
{"backslash\\test", NULL},
79
L"ls backslash\\\\test "
80
},
81
{
82
/* backslash inside single quotes */
83
L"ls 'sback",
84
"sback",
85
{"sbackslash\\test", NULL},
86
L"ls 'sbackslash\\test'"
87
},
88
{
89
/* backslash inside double quotes */
90
L"ls \"dback",
91
"dback",
92
{"dbackslash\\test", NULL},
93
L"ls \"dbackslash\\\\test\""
94
},
95
{
96
/* test braces */
97
L"ls br",
98
"br",
99
{"braces{test}", NULL},
100
L"ls braces\\{test\\} "
101
},
102
{
103
/* test braces inside single quotes */
104
L"ls 'sbr",
105
"sbr",
106
{"sbraces{test}", NULL},
107
L"ls 'sbraces{test}'"
108
},
109
{
110
/* test braces inside double quotes */
111
L"ls \"dbr",
112
"dbr",
113
{"dbraces{test}", NULL},
114
L"ls \"dbraces{test}\""
115
},
116
{
117
/* test dollar */
118
L"ls doll",
119
"doll",
120
{"doll$artest", NULL},
121
L"ls doll\\$artest "
122
},
123
{
124
/* test dollar inside single quotes */
125
L"ls 'sdoll",
126
"sdoll",
127
{"sdoll$artest", NULL},
128
L"ls 'sdoll$artest'"
129
},
130
{
131
/* test dollar inside double quotes */
132
L"ls \"ddoll",
133
"ddoll",
134
{"ddoll$artest", NULL},
135
L"ls \"ddoll\\$artest\""
136
},
137
{
138
/* test equals */
139
L"ls eq",
140
"eq",
141
{"equals==test", NULL},
142
L"ls equals\\=\\=test "
143
},
144
{
145
/* test equals inside sinqle quotes */
146
L"ls 'seq",
147
"seq",
148
{"sequals==test", NULL},
149
L"ls 'sequals==test'"
150
},
151
{
152
/* test equals inside double quotes */
153
L"ls \"deq",
154
"deq",
155
{"dequals==test", NULL},
156
L"ls \"dequals==test\""
157
},
158
{
159
/* test \n */
160
L"ls new",
161
"new",
162
{"new\\nline", NULL},
163
L"ls new\\\\nline "
164
},
165
{
166
/* test \n inside single quotes */
167
L"ls 'snew",
168
"snew",
169
{"snew\nline", NULL},
170
L"ls 'snew\nline'"
171
},
172
{
173
/* test \n inside double quotes */
174
L"ls \"dnew",
175
"dnew",
176
{"dnew\nline", NULL},
177
L"ls \"dnew\nline\""
178
},
179
{
180
/* test single space */
181
L"ls spac",
182
"spac",
183
{"space test", NULL},
184
L"ls space\\ test "
185
},
186
{
187
/* test single space inside singlq quotes */
188
L"ls 's_spac",
189
"s_spac",
190
{"s_space test", NULL},
191
L"ls 's_space test'"
192
},
193
{
194
/* test single space inside double quotes */
195
L"ls \"d_spac",
196
"d_spac",
197
{"d_space test", NULL},
198
L"ls \"d_space test\""
199
},
200
{
201
/* test multiple spaces */
202
L"ls multi",
203
"multi",
204
{"multi space test", NULL},
205
L"ls multi\\ space\\ \\ test "
206
},
207
{
208
/* test multiple spaces inside single quotes */
209
L"ls 's_multi",
210
"s_multi",
211
{"s_multi space test", NULL},
212
L"ls 's_multi space test'"
213
},
214
{
215
/* test multiple spaces inside double quotes */
216
L"ls \"d_multi",
217
"d_multi",
218
{"d_multi space test", NULL},
219
L"ls \"d_multi space test\""
220
},
221
{
222
/* test double quotes */
223
L"ls doub",
224
"doub",
225
{"doub\"quotes", NULL},
226
L"ls doub\\\"quotes "
227
},
228
{
229
/* test double quotes inside single quotes */
230
L"ls 's_doub",
231
"s_doub",
232
{"s_doub\"quotes", NULL},
233
L"ls 's_doub\"quotes'"
234
},
235
{
236
/* test double quotes inside double quotes */
237
L"ls \"d_doub",
238
"d_doub",
239
{"d_doub\"quotes", NULL},
240
L"ls \"d_doub\\\"quotes\""
241
},
242
{
243
/* test multiple double quotes */
244
L"ls mud",
245
"mud",
246
{"mud\"qu\"otes\"", NULL},
247
L"ls mud\\\"qu\\\"otes\\\" "
248
},
249
{
250
/* test multiple double quotes inside single quotes */
251
L"ls 'smud",
252
"smud",
253
{"smud\"qu\"otes\"", NULL},
254
L"ls 'smud\"qu\"otes\"'"
255
},
256
{
257
/* test multiple double quotes inside double quotes */
258
L"ls \"dmud",
259
"dmud",
260
{"dmud\"qu\"otes\"", NULL},
261
L"ls \"dmud\\\"qu\\\"otes\\\"\""
262
},
263
{
264
/* test one single quote */
265
L"ls sing",
266
"sing",
267
{"single'quote", NULL},
268
L"ls single\\'quote "
269
},
270
{
271
/* test one single quote inside single quote */
272
L"ls 'ssing",
273
"ssing",
274
{"ssingle'quote", NULL},
275
L"ls 'ssingle'\\''quote'"
276
},
277
{
278
/* test one single quote inside double quote */
279
L"ls \"dsing",
280
"dsing",
281
{"dsingle'quote", NULL},
282
L"ls \"dsingle'quote\""
283
},
284
{
285
/* test multiple single quotes */
286
L"ls mu_sing",
287
"mu_sing",
288
{"mu_single''quotes''", NULL},
289
L"ls mu_single\\'\\'quotes\\'\\' "
290
},
291
{
292
/* test multiple single quotes inside single quote */
293
L"ls 'smu_sing",
294
"smu_sing",
295
{"smu_single''quotes''", NULL},
296
L"ls 'smu_single'\\'''\\''quotes'\\\'''\\'''"
297
},
298
{
299
/* test multiple single quotes inside double quote */
300
L"ls \"dmu_sing",
301
"dmu_sing",
302
{"dmu_single''quotes''", NULL},
303
L"ls \"dmu_single''quotes''\""
304
},
305
{
306
/* test parenthesis */
307
L"ls paren",
308
"paren",
309
{"paren(test)", NULL},
310
L"ls paren\\(test\\) "
311
},
312
{
313
/* test parenthesis inside single quote */
314
L"ls 'sparen",
315
"sparen",
316
{"sparen(test)", NULL},
317
L"ls 'sparen(test)'"
318
},
319
{
320
/* test parenthesis inside double quote */
321
L"ls \"dparen",
322
"dparen",
323
{"dparen(test)", NULL},
324
L"ls \"dparen(test)\""
325
},
326
{
327
/* test pipe */
328
L"ls pip",
329
"pip",
330
{"pipe|test", NULL},
331
L"ls pipe\\|test "
332
},
333
{
334
/* test pipe inside single quote */
335
L"ls 'spip",
336
"spip",
337
{"spipe|test", NULL},
338
L"ls 'spipe|test'",
339
},
340
{
341
/* test pipe inside double quote */
342
L"ls \"dpip",
343
"dpip",
344
{"dpipe|test", NULL},
345
L"ls \"dpipe|test\""
346
},
347
{
348
/* test tab */
349
L"ls ta",
350
"ta",
351
{"tab\ttest", NULL},
352
L"ls tab\\\ttest "
353
},
354
{
355
/* test tab inside single quote */
356
L"ls 'sta",
357
"sta",
358
{"stab\ttest", NULL},
359
L"ls 'stab\ttest'"
360
},
361
{
362
/* test tab inside double quote */
363
L"ls \"dta",
364
"dta",
365
{"dtab\ttest", NULL},
366
L"ls \"dtab\ttest\""
367
},
368
{
369
/* test back tick */
370
L"ls tic",
371
"tic",
372
{"tick`test`", NULL},
373
L"ls tick\\`test\\` "
374
},
375
{
376
/* test back tick inside single quote */
377
L"ls 'stic",
378
"stic",
379
{"stick`test`", NULL},
380
L"ls 'stick`test`'"
381
},
382
{
383
/* test back tick inside double quote */
384
L"ls \"dtic",
385
"dtic",
386
{"dtick`test`", NULL},
387
L"ls \"dtick\\`test\\`\""
388
},
389
{
390
/* test for @ */
391
L"ls at",
392
"at",
393
{"atthe@rate", NULL},
394
L"ls atthe\\@rate "
395
},
396
{
397
/* test for @ inside single quote */
398
L"ls 'sat",
399
"sat",
400
{"satthe@rate", NULL},
401
L"ls 'satthe@rate'"
402
},
403
{
404
/* test for @ inside double quote */
405
L"ls \"dat",
406
"dat",
407
{"datthe@rate", NULL},
408
L"ls \"datthe@rate\""
409
},
410
{
411
/* test ; */
412
L"ls semi",
413
"semi",
414
{"semi;colon;test", NULL},
415
L"ls semi\\;colon\\;test "
416
},
417
{
418
/* test ; inside single quote */
419
L"ls 'ssemi",
420
"ssemi",
421
{"ssemi;colon;test", NULL},
422
L"ls 'ssemi;colon;test'"
423
},
424
{
425
/* test ; inside double quote */
426
L"ls \"dsemi",
427
"dsemi",
428
{"dsemi;colon;test", NULL},
429
L"ls \"dsemi;colon;test\""
430
},
431
{
432
/* test & */
433
L"ls amp",
434
"amp",
435
{"ampers&and", NULL},
436
L"ls ampers\\&and "
437
},
438
{
439
/* test & inside single quote */
440
L"ls 'samp",
441
"samp",
442
{"sampers&and", NULL},
443
L"ls 'sampers&and'"
444
},
445
{
446
/* test & inside double quote */
447
L"ls \"damp",
448
"damp",
449
{"dampers&and", NULL},
450
L"ls \"dampers&and\""
451
},
452
{
453
/* test completion when cursor at \ */
454
L"ls foo\\",
455
"foo",
456
{"foo bar", NULL},
457
L"ls foo\\ bar "
458
},
459
{
460
/* test completion when cursor at single quote */
461
L"ls foo'",
462
"foo'",
463
{"foo bar", NULL},
464
L"ls foo\\ bar "
465
},
466
{
467
/* test completion when cursor at double quote */
468
L"ls foo\"",
469
"foo\"",
470
{"foo bar", NULL},
471
L"ls foo\\ bar "
472
},
473
{
474
/* test multiple completion matches */
475
L"ls fo",
476
"fo",
477
{"foo bar", "foo baz"},
478
L"ls foo\\ ba"
479
},
480
{
481
L"ls ba",
482
"ba",
483
{"bar <bar>", "bar <baz>"},
484
L"ls bar\\ \\<ba"
485
}
486
};
487
488
static const wchar_t break_chars[] = L" \t\n\"\\'`@$><=;|&{(";
489
490
/*
491
* Custom completion function passed to fn_complet, NULLe.
492
* The function returns hardcoded completion matches
493
* based on the test cases present in inputs[] (above)
494
*/
495
static char *
496
mycomplet_func(const char *text, int index)
497
{
498
static int last_index = 0;
499
size_t i = 0;
500
if (last_index == 2) {
501
last_index = 0;
502
return NULL;
503
}
504
505
for (i = 0; i < sizeof(inputs)/sizeof(inputs[0]); i++) {
506
if (strcmp(text, inputs[i].completion_function_input) == 0) {
507
if (inputs[i].expanded_text[last_index] != NULL)
508
return strdup(inputs[i].expanded_text[last_index++]);
509
else {
510
last_index = 0;
511
return NULL;
512
}
513
}
514
}
515
516
return NULL;
517
}
518
519
int
520
main(int argc, char **argv)
521
{
522
EditLine *el = el_init(argv[0], stdin, stdout, stderr);
523
size_t i;
524
size_t input_len;
525
el_line_t line;
526
wchar_t *buffer = malloc(64 * sizeof(*buffer));
527
if (buffer == NULL)
528
err(EXIT_FAILURE, "malloc failed");
529
530
for (i = 0; i < sizeof(inputs)/sizeof(inputs[0]); i++) {
531
memset(buffer, 0, 64 * sizeof(*buffer));
532
input_len = wcslen(inputs[i].user_typed_text);
533
wmemcpy(buffer, inputs[i].user_typed_text, input_len);
534
buffer[input_len] = 0;
535
line.buffer = buffer;
536
line.cursor = line.buffer + input_len ;
537
line.lastchar = line.cursor - 1;
538
line.limit = line.buffer + 64 * sizeof(*buffer);
539
el->el_line = line;
540
fn_complete(el, mycomplet_func, NULL, break_chars, NULL, NULL, 10, NULL, NULL, NULL, NULL);
541
542
/*
543
* fn_complete would have expanded and escaped the input in el->el_line.buffer.
544
* We need to assert that it matches with the expected value in our test data
545
*/
546
printf("User input: %ls\t Expected output: %ls\t Generated output: %ls\n",
547
inputs[i].user_typed_text, inputs[i].escaped_output, el->el_line.buffer);
548
assert(wcscmp(el->el_line.buffer, inputs[i].escaped_output) == 0);
549
}
550
el_end(el);
551
return 0;
552
553
}
554
555