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