Home | History | Annotate | Line # | Download | only in TEST
test_filecompletion.c revision 1.2.2.1
      1 /*	$NetBSD: test_filecompletion.c,v 1.2.2.1 2018/05/21 04:35:55 pgoyette Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2017 Abhinav Upadhyay <abhinav (at) NetBSD.org>
      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; /* 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",
     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",
     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",
     72 		L"ls 'sq_ang<ular>test' "
     73 	},
     74 	{
     75 		/* simple test for backslash */
     76 		L"ls back",
     77 		"back",
     78 		"backslash\\test",
     79 		L"ls backslash\\\\test "
     80 	},
     81 	{
     82 		/* backslash inside single quotes */
     83 		L"ls 'sback",
     84 		"sback",
     85 		"sbackslash\\test",
     86 		L"ls 'sbackslash\\test' "
     87 	},
     88 	{
     89 		/* backslash inside double quotes */
     90 		L"ls \"dback",
     91 		"dback",
     92 		"dbackslash\\test",
     93 		L"ls \"dbackslash\\\\test\" "
     94 	},
     95 	{
     96 		/* test braces */
     97 		L"ls br",
     98 		"br",
     99 		"braces{test}",
    100 		L"ls braces\\{test\\} "
    101 	},
    102 	{
    103 		/* test braces inside single quotes */
    104 		L"ls 'sbr",
    105 		"sbr",
    106 		"sbraces{test}",
    107 		L"ls 'sbraces{test}' "
    108 	},
    109 	{
    110 		/* test braces inside double quotes */
    111 		L"ls \"dbr",
    112 		"dbr",
    113 		"dbraces{test}",
    114 		L"ls \"dbraces{test}\" "
    115 	},
    116 	{
    117 		/* test dollar */
    118 		L"ls doll",
    119 		"doll",
    120 		"doll$artest",
    121 		L"ls doll\\$artest "
    122 	},
    123 	{
    124 		/* test dollar inside single quotes */
    125 		L"ls 'sdoll",
    126 		"sdoll",
    127 		"sdoll$artest",
    128 		L"ls 'sdoll$artest' "
    129 	},
    130 	{
    131 		/* test dollar inside double quotes */
    132 		L"ls \"ddoll",
    133 		"ddoll",
    134 		"ddoll$artest",
    135 		L"ls \"ddoll\\$artest\" "
    136 	},
    137 	{
    138 		/* test equals */
    139 		L"ls eq",
    140 		"eq",
    141 		"equals==test",
    142 		L"ls equals\\=\\=test "
    143 	},
    144 	{
    145 		/* test equals inside sinqle quotes */
    146 		L"ls 'seq",
    147 		"seq",
    148 		"sequals==test",
    149 		L"ls 'sequals==test' "
    150 	},
    151 	{
    152 		/* test equals inside double quotes */
    153 		L"ls \"deq",
    154 		"deq",
    155 		"dequals==test",
    156 		L"ls \"dequals==test\" "
    157 	},
    158 	{
    159 		/* test \n */
    160 		L"ls new",
    161 		"new",
    162 		"new\\nline",
    163 		L"ls new\\\\nline "
    164 	},
    165 	{
    166 		/* test \n inside single quotes */
    167 		L"ls 'snew",
    168 		"snew",
    169 		"snew\nline",
    170 		L"ls 'snew\nline' "
    171 	},
    172 	{
    173 		/* test \n inside double quotes */
    174 		L"ls \"dnew",
    175 		"dnew",
    176 		"dnew\nline",
    177 		L"ls \"dnew\nline\" "
    178 	},
    179 	{
    180 		/* test single space */
    181 		L"ls spac",
    182 		"spac",
    183 		"space test",
    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",
    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",
    198 		L"ls \"d_space test\" "
    199 	},
    200 	{
    201 		/* test multiple spaces */
    202 		L"ls multi",
    203 		"multi",
    204 		"multi space  test",
    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",
    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",
    219 		L"ls \"d_multi space  test\" "
    220 	},
    221 	{
    222 		/* test double quotes */
    223 		L"ls doub",
    224 		"doub",
    225 		"doub\"quotes",
    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",
    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",
    240 		L"ls \"d_doub\\\"quotes\" "
    241 	},
    242 	{
    243 		/* test multiple double quotes */
    244 		L"ls mud",
    245 		"mud",
    246 		"mud\"qu\"otes\"",
    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\"",
    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\"",
    261 		L"ls \"dmud\\\"qu\\\"otes\\\"\" "
    262 	},
    263 	{
    264 		/* test one single quote */
    265 		L"ls sing",
    266 		"sing",
    267 		"single'quote",
    268 		L"ls single\\'quote "
    269 	},
    270 	{
    271 		/* test one single quote inside single quote */
    272 		L"ls 'ssing",
    273 		"ssing",
    274 		"ssingle'quote",
    275 		L"ls 'ssingle'\\''quote' "
    276 	},
    277 	{
    278 		/* test one single quote inside double quote */
    279 		L"ls \"dsing",
    280 		"dsing",
    281 		"dsingle'quote",
    282 		L"ls \"dsingle'quote\" "
    283 	},
    284 	{
    285 		/* test multiple single quotes */
    286 		L"ls mu_sing",
    287 		"mu_sing",
    288 		"mu_single''quotes''",
    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''",
    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''",
    303 		L"ls \"dmu_single''quotes''\" "
    304 	},
    305 	{
    306 		/* test parenthesis */
    307 		L"ls paren",
    308 		"paren",
    309 		"paren(test)",
    310 		L"ls paren\\(test\\) "
    311 	},
    312 	{
    313 		/* test parenthesis inside single quote */
    314 		L"ls 'sparen",
    315 		"sparen",
    316 		"sparen(test)",
    317 		L"ls 'sparen(test)' "
    318 	},
    319 	{
    320 		/* test parenthesis inside double quote */
    321 		L"ls \"dparen",
    322 		"dparen",
    323 		"dparen(test)",
    324 		L"ls \"dparen(test)\" "
    325 	},
    326 	{
    327 		/* test pipe */
    328 		L"ls pip",
    329 		"pip",
    330 		"pipe|test",
    331 		L"ls pipe\\|test "
    332 	},
    333 	{
    334 		/* test pipe inside single quote */
    335 		L"ls 'spip",
    336 		"spip",
    337 		"spipe|test",
    338 		L"ls 'spipe|test' ",
    339 	},
    340 	{
    341 		/* test pipe inside double quote */
    342 		L"ls \"dpip",
    343 		"dpip",
    344 		"dpipe|test",
    345 		L"ls \"dpipe|test\" "
    346 	},
    347 	{
    348 		/* test tab */
    349 		L"ls ta",
    350 		"ta",
    351 		"tab\ttest",
    352 		L"ls tab\\\ttest "
    353 	},
    354 	{
    355 		/* test tab inside single quote */
    356 		L"ls 'sta",
    357 		"sta",
    358 		"stab\ttest",
    359 		L"ls 'stab\ttest' "
    360 	},
    361 	{
    362 		/* test tab inside double quote */
    363 		L"ls \"dta",
    364 		"dta",
    365 		"dtab\ttest",
    366 		L"ls \"dtab\ttest\" "
    367 	},
    368 	{
    369 		/* test back tick */
    370 		L"ls tic",
    371 		"tic",
    372 		"tick`test`",
    373 		L"ls tick\\`test\\` "
    374 	},
    375 	{
    376 		/* test back tick inside single quote */
    377 		L"ls 'stic",
    378 		"stic",
    379 		"stick`test`",
    380 		L"ls 'stick`test`' "
    381 	},
    382 	{
    383 		/* test back tick inside double quote */
    384 		L"ls \"dtic",
    385 		"dtic",
    386 		"dtick`test`",
    387 		L"ls \"dtick\\`test\\`\" "
    388 	},
    389 	{
    390 		/* test for @ */
    391 		L"ls at",
    392 		"at",
    393 		"atthe@rate",
    394 		L"ls atthe\\@rate "
    395 	},
    396 	{
    397 		/* test for @ inside single quote */
    398 		L"ls 'sat",
    399 		"sat",
    400 		"satthe@rate",
    401 		L"ls 'satthe@rate' "
    402 	},
    403 	{
    404 		/* test for @ inside double quote */
    405 		L"ls \"dat",
    406 		"dat",
    407 		"datthe@rate",
    408 		L"ls \"datthe@rate\" "
    409 	},
    410 	{
    411 		/* test ; */
    412 		L"ls semi",
    413 		"semi",
    414 		"semi;colon;test",
    415 		L"ls semi\\;colon\\;test "
    416 	},
    417 	{
    418 		/* test ; inside single quote */
    419 		L"ls 'ssemi",
    420 		"ssemi",
    421 		"ssemi;colon;test",
    422 		L"ls 'ssemi;colon;test' "
    423 	},
    424 	{
    425 		/* test ; inside double quote */
    426 		L"ls \"dsemi",
    427 		"dsemi",
    428 		"dsemi;colon;test",
    429 		L"ls \"dsemi;colon;test\" "
    430 	},
    431 	{
    432 		/* test & */
    433 		L"ls amp",
    434 		"amp",
    435 		"ampers&and",
    436 		L"ls ampers\\&and "
    437 	},
    438 	{
    439 		/* test & inside single quote */
    440 		L"ls 'samp",
    441 		"samp",
    442 		"sampers&and",
    443 		L"ls 'sampers&and' "
    444 	},
    445 	{
    446 		/* test & inside double quote */
    447 		L"ls \"damp",
    448 		"damp",
    449 		"dampers&and",
    450 		L"ls \"dampers&and\" "
    451 	},
    452 	{
    453 		/* test completion when cursor at \ */
    454 		L"ls foo\\",
    455 		"foo",
    456 		"foo bar",
    457 		L"ls foo\\ bar "
    458 	},
    459 	{
    460 		/* test completion when cursor at single quote */
    461 		L"ls foo'",
    462 		"foo",
    463 		"foo bar",
    464 		L"ls foo\\ bar "
    465 	},
    466 	{
    467 		/* test completion when cursor at double quote */
    468 		L"ls foo\"",
    469 		"foo",
    470 		"foo bar",
    471 		L"ls foo\\ bar "
    472 	}
    473 };
    474 
    475 static const wchar_t break_chars[] = L" \t\n\"\\'`@$><=;|&{(";
    476 
    477 /*
    478  * Custom completion function passed to fn_complete.
    479  * The function returns hardcoded completion matches
    480  * based on the test cases present in inputs[] (above)
    481  */
    482 static char *
    483 mycomplet_func(const char *text, int index)
    484 {
    485 	static char *last_input = NULL;
    486 	size_t i = 0;
    487 	if (last_input && strcmp(last_input, text) == 0) {
    488 		free(last_input);
    489 		last_input = NULL;
    490 		return NULL;
    491 	}
    492 	last_input = strdup(text);
    493 
    494 	for (i = 0; i < sizeof(inputs)/sizeof(inputs[0]); i++) {
    495 		if (strcmp(text, inputs[i].completion_function_input) == 0)
    496 			return strdup(inputs[i].expanded_text);
    497 	}
    498 
    499 	return NULL;
    500 }
    501 
    502 int
    503 main(int argc, char **argv)
    504 {
    505 	EditLine *el = el_init(argv[0], stdin, stdout, stderr);
    506 	size_t i;
    507 	size_t input_len;
    508 	el_line_t line;
    509 	wchar_t *buffer = malloc(64 * sizeof(*buffer));
    510 	if (buffer == NULL)
    511 		err(EXIT_FAILURE, "malloc failed");
    512 
    513 	for (i = 0; i < sizeof(inputs)/sizeof(inputs[0]); i++) {
    514 		memset(buffer, 0, 64 * sizeof(*buffer));
    515 		input_len = wcslen(inputs[i].user_typed_text);
    516 		wmemcpy(buffer, inputs[i].user_typed_text, input_len);
    517 		buffer[input_len] = 0;
    518 		line.buffer = buffer;
    519 		line.cursor = line.buffer + input_len ;
    520 		line.lastchar = line.cursor - 1;
    521 		line.limit = line.buffer + 64 * sizeof(*buffer);
    522 		el->el_line = line;
    523 		fn_complete(el, mycomplet_func, NULL, break_chars, NULL, NULL, 10, NULL, NULL, NULL, NULL);
    524 
    525 		/*
    526 		 * fn_complete would have expanded and escaped the input in el->el_line.buffer.
    527 		 * We need to assert that it matches with the expected value in our test data
    528 		 */
    529 		printf("User input: %ls\t Expected output: %ls\t Generated output: %ls\n",
    530 				inputs[i].user_typed_text, inputs[i].escaped_output, el->el_line.buffer);
    531 		assert(wcscmp(el->el_line.buffer, inputs[i].escaped_output) == 0);
    532 	}
    533 	el_end(el);
    534 	return 0;
    535 
    536 }
    537