diff options
Diffstat (limited to 'test/t/unit')
-rw-r--r-- | test/t/unit/Makefile.am | 5 | ||||
-rw-r--r-- | test/t/unit/test_unit_count_args.py | 4 | ||||
-rw-r--r-- | test/t/unit/test_unit_expand.py | 20 | ||||
-rw-r--r-- | test/t/unit/test_unit_expand_tilde_by_ref.py | 32 | ||||
-rw-r--r-- | test/t/unit/test_unit_filedir.py | 138 | ||||
-rw-r--r-- | test/t/unit/test_unit_get_comp_words_by_ref.py | 101 | ||||
-rw-r--r-- | test/t/unit/test_unit_get_cword.py | 25 | ||||
-rw-r--r-- | test/t/unit/test_unit_init_completion.py | 16 | ||||
-rw-r--r-- | test/t/unit/test_unit_known_hosts_real.py | 158 | ||||
-rw-r--r-- | test/t/unit/test_unit_longopt.py | 18 | ||||
-rw-r--r-- | test/t/unit/test_unit_quote.py | 2 | ||||
-rw-r--r-- | test/t/unit/test_unit_quote_readline.py | 15 | ||||
-rw-r--r-- | test/t/unit/test_unit_variables.py | 10 | ||||
-rw-r--r-- | test/t/unit/test_unit_xinetd_services.py | 22 |
14 files changed, 531 insertions, 35 deletions
diff --git a/test/t/unit/Makefile.am b/test/t/unit/Makefile.am index b96b326c..3eb652af 100644 --- a/test/t/unit/Makefile.am +++ b/test/t/unit/Makefile.am @@ -8,12 +8,15 @@ EXTRA_DIST = \ test_unit_get_cword.py \ test_unit_init_completion.py \ test_unit_ip_addresses.py \ + test_unit_known_hosts_real.py \ test_unit_longopt.py \ test_unit_parse_help.py \ test_unit_parse_usage.py \ test_unit_quote.py \ + test_unit_quote_readline.py \ test_unit_tilde.py \ - test_unit_variables.py + test_unit_variables.py \ + test_unit_xinetd_services.py all: diff --git a/test/t/unit/test_unit_count_args.py b/test/t/unit/test_unit_count_args.py index c0afe736..56bce2cb 100644 --- a/test/t/unit/test_unit_count_args.py +++ b/test/t/unit/test_unit_count_args.py @@ -1,6 +1,6 @@ import pytest -from conftest import assert_bash_exec, TestUnitBase +from conftest import TestUnitBase, assert_bash_exec @pytest.mark.bashcomp( @@ -11,7 +11,7 @@ class TestUnitCountArgs(TestUnitBase): return self._test_unit("_count_args %s; echo $args", *args, **kwargs) def test_1(self, bash): - assert_bash_exec(bash, "_count_args >/dev/null") + assert_bash_exec(bash, "COMP_CWORD= _count_args >/dev/null") def test_2(self, bash): """a b| should set args to 1""" diff --git a/test/t/unit/test_unit_expand.py b/test/t/unit/test_unit_expand.py index 7c0a9836..d2a3ebc4 100644 --- a/test/t/unit/test_unit_expand.py +++ b/test/t/unit/test_unit_expand.py @@ -3,7 +3,7 @@ import pytest from conftest import assert_bash_exec -@pytest.mark.bashcomp(cmd=None) +@pytest.mark.bashcomp(cmd=None, ignore_env=r"^[+-](cur|COMPREPLY)=") class TestUnitExpand: def test_1(self, bash): assert_bash_exec(bash, "_expand >/dev/null") @@ -11,3 +11,21 @@ class TestUnitExpand: def test_2(self, bash): """Test environment non-pollution, detected at teardown.""" assert_bash_exec(bash, "foo() { _expand; }; foo; unset foo") + + def test_user_home_compreply(self, bash, user_home): + user, home = user_home + output = assert_bash_exec( + bash, + r'cur="~%s"; _expand; printf "%%s\n" "$COMPREPLY"' % user, + want_output=True, + ) + assert output.strip() == home + + def test_user_home_cur(self, bash, user_home): + user, home = user_home + output = assert_bash_exec( + bash, + r'cur="~%s/a"; _expand; printf "%%s\n" "$cur"' % user, + want_output=True, + ) + assert output.strip() == "%s/a" % home diff --git a/test/t/unit/test_unit_expand_tilde_by_ref.py b/test/t/unit/test_unit_expand_tilde_by_ref.py index fbc172df..17bdedfe 100644 --- a/test/t/unit/test_unit_expand_tilde_by_ref.py +++ b/test/t/unit/test_unit_expand_tilde_by_ref.py @@ -3,7 +3,7 @@ import pytest from conftest import assert_bash_exec -@pytest.mark.bashcomp(cmd=None) +@pytest.mark.bashcomp(cmd=None, ignore_env=r"^[+-]var=") class TestUnitExpandTildeByRef: def test_1(self, bash): assert_bash_exec(bash, "__expand_tilde_by_ref >/dev/null") @@ -14,3 +14,33 @@ class TestUnitExpandTildeByRef: bash, '_x() { local aa="~"; __expand_tilde_by_ref aa; }; _x; unset _x', ) + + @pytest.mark.parametrize("plain_tilde", (True, False)) + @pytest.mark.parametrize( + "suffix_expanded", + ( + ("", True), + ("/foo", True), + (r"/\$HOME", True), + ("/a b", True), + ("/*", True), + (";echo hello", False), + ("/a;echo hello", True), + ), + ) + def test_expand(self, bash, user_home, plain_tilde, suffix_expanded): + user, home = user_home + suffix, expanded = suffix_expanded + if plain_tilde: + user = "" + if not suffix or not expanded: + home = "~" + elif not expanded: + home = "~%s" % user + output = assert_bash_exec( + bash, + r'var="~%s%s"; __expand_tilde_by_ref var; printf "%%s\n" "$var"' + % (user, suffix), + want_output=True, + ) + assert output.strip() == "%s%s" % (home, suffix.replace(r"\$", "$"),) diff --git a/test/t/unit/test_unit_filedir.py b/test/t/unit/test_unit_filedir.py index 7f14f294..b847efc2 100644 --- a/test/t/unit/test_unit_filedir.py +++ b/test/t/unit/test_unit_filedir.py @@ -1,3 +1,9 @@ +import os +import shutil +import sys +import tempfile +from pathlib import Path + import pytest from conftest import assert_bash_exec, assert_complete @@ -24,102 +30,206 @@ class TestUnitFiledir: "complete -F _fd fd", ) + @pytest.fixture(scope="class") + def non_windows_testdir(self, request, bash): + if sys.platform.startswith("win"): + pytest.skip("Filenames not allowed on Windows") + tempdir = Path(tempfile.mkdtemp(prefix="bash-completion_filedir")) + request.addfinalizer(lambda: shutil.rmtree(str(tempdir))) + subdir = tempdir / 'a"b' + subdir.mkdir() + (subdir / "d").touch() + subdir = tempdir / "a*b" + subdir.mkdir() + (subdir / "j").touch() + subdir = tempdir / r"a\b" + subdir.mkdir() + (subdir / "g").touch() + return tempdir + + @pytest.fixture(scope="class") + def utf8_ctype(self, bash): + # TODO: this likely is not the right thing to do. Instead we should + # grab the setting from the running shell, possibly eval $(locale) + # in a subshell and grab LC_CTYPE from there. That doesn't seem to work + # either everywhere though. + lc_ctype = os.environ.get("LC_CTYPE", "") + if "UTF-8" not in lc_ctype: + pytest.skip("Applicable only in LC_CTYPE=UTF-8 setups") + return lc_ctype + def test_1(self, bash): assert_bash_exec(bash, "_filedir >/dev/null") @pytest.mark.parametrize("funcname", "f f2".split()) def test_2(self, bash, functions, funcname): completion = assert_complete(bash, "%s ab/" % funcname, cwd="_filedir") - assert completion == "ab/e" + assert completion == "e" @pytest.mark.parametrize("funcname", "f f2".split()) def test_3(self, bash, functions, funcname): completion = assert_complete( bash, r"%s a\ b/" % funcname, cwd="_filedir" ) - assert completion == "a b/i" + assert completion == "i" @pytest.mark.parametrize("funcname", "f f2".split()) def test_4(self, bash, functions, funcname): completion = assert_complete( bash, r"%s a\'b/" % funcname, cwd="_filedir" ) - assert completion == "a'b/c" + assert completion == "c" @pytest.mark.parametrize("funcname", "f f2".split()) def test_5(self, bash, functions, funcname): completion = assert_complete( bash, r"%s a\&b/" % funcname, cwd="_filedir" ) - assert completion == "a&b/f" + assert completion == "f" @pytest.mark.parametrize("funcname", "f f2".split()) def test_6(self, bash, functions, funcname): completion = assert_complete( bash, r"%s a\$" % funcname, cwd="_filedir" ) - assert completion == "a$b/" + assert completion == "b/" @pytest.mark.parametrize("funcname", "f f2".split()) def test_7(self, bash, functions, funcname): completion = assert_complete( bash, r"%s 'ab/" % funcname, cwd="_filedir" ) - assert completion == "ab/e" + assert completion == "e'" @pytest.mark.parametrize("funcname", "f f2".split()) def test_8(self, bash, functions, funcname): completion = assert_complete( bash, r"%s 'a b/" % funcname, cwd="_filedir" ) - assert completion == "a b/i" + assert completion == "i'" @pytest.mark.parametrize("funcname", "f f2".split()) def test_9(self, bash, functions, funcname): completion = assert_complete( bash, r"%s 'a$b/" % funcname, cwd="_filedir" ) - assert completion == "a$b/h" + assert completion == "h'" @pytest.mark.parametrize("funcname", "f f2".split()) def test_10(self, bash, functions, funcname): completion = assert_complete( bash, r"%s 'a&b/" % funcname, cwd="_filedir" ) - assert completion == "a&b/f" + assert completion == "f'" @pytest.mark.parametrize("funcname", "f f2".split()) def test_11(self, bash, functions, funcname): completion = assert_complete( bash, r'%s "ab/' % funcname, cwd="_filedir" ) - assert completion == "ab/e" + assert completion == 'e"' @pytest.mark.parametrize("funcname", "f f2".split()) def test_12(self, bash, functions, funcname): completion = assert_complete( bash, r'%s "a b/' % funcname, cwd="_filedir" ) - assert completion == "a b/i" + assert completion == 'i"' @pytest.mark.parametrize("funcname", "f f2".split()) def test_13(self, bash, functions, funcname): completion = assert_complete( bash, "%s \"a'b/" % funcname, cwd="_filedir" ) - assert completion == "a'b/c" + assert completion == 'c"' @pytest.mark.parametrize("funcname", "f f2".split()) def test_14(self, bash, functions, funcname): completion = assert_complete( bash, '%s "a&b/' % funcname, cwd="_filedir" ) - assert completion == "a&b/f" + assert completion == 'f"' @pytest.mark.complete(r"fd a\ ", cwd="_filedir") def test_15(self, functions, completion): - assert completion == "a b/" + assert completion == "b/" @pytest.mark.complete("g ", cwd="_filedir/ext") def test_16(self, functions, completion): assert completion == sorted("ee.e1 foo/ gg.e1 ii.E1".split()) + + @pytest.mark.parametrize("funcname", "f f2".split()) + def test_17(self, bash, functions, funcname): + completion = assert_complete( + bash, r"%s a\$b/" % funcname, cwd="_filedir" + ) + assert completion == "h" + + @pytest.mark.parametrize("funcname", "f f2".split()) + def test_18(self, bash, functions, funcname): + completion = assert_complete( + bash, r"%s \[x" % funcname, cwd="_filedir/brackets" + ) + assert completion == r"\]" + + @pytest.mark.parametrize("funcname", "f f2".split()) + def test_19(self, bash, functions, funcname, non_windows_testdir): + completion = assert_complete( + bash, '%s a\\"b/' % funcname, cwd=non_windows_testdir + ) + assert completion == "d" + + @pytest.mark.parametrize("funcname", "f f2".split()) + def test_20(self, bash, functions, funcname, non_windows_testdir): + completion = assert_complete( + bash, r"%s a\\b/" % funcname, cwd=non_windows_testdir + ) + assert completion == "g" + + @pytest.mark.parametrize("funcname", "f f2".split()) + def test_21(self, bash, functions, funcname, non_windows_testdir): + completion = assert_complete( + bash, "%s 'a\"b/" % funcname, cwd=non_windows_testdir + ) + assert completion == "d'" + + @pytest.mark.parametrize("funcname", "f f2".split()) + def test_22(self, bash, functions, funcname, non_windows_testdir): + completion = assert_complete( + bash, r"%s '%s/a\b/" % (funcname, non_windows_testdir) + ) + assert completion == "g'" + + @pytest.mark.parametrize("funcname", "f f2".split()) + def test_23(self, bash, functions, funcname, non_windows_testdir): + completion = assert_complete( + bash, r'%s "a\"b/' % funcname, cwd=non_windows_testdir + ) + assert completion == 'd"' + + @pytest.mark.parametrize("funcname", "f f2".split()) + def test_24(self, bash, functions, funcname, non_windows_testdir): + completion = assert_complete( + bash, r'%s "a\\b/' % funcname, cwd=non_windows_testdir + ) + assert completion == 'g"' + + @pytest.mark.parametrize("funcname", "f f2".split()) + def test_25(self, bash, functions, funcname): + completion = assert_complete( + bash, r'%s "a\b/' % funcname, cwd="_filedir" + ) + assert completion == '\b\b\bb/e"' + + @pytest.mark.parametrize("funcname", "f f2".split()) + def test_26(self, bash, functions, funcname): + completion = assert_complete( + bash, r'%s "a\$b/' % funcname, cwd="_filedir" + ) + assert completion == 'h"' + + @pytest.mark.xfail(reason="TODO: non-ASCII issues with test suite?") + @pytest.mark.parametrize("funcname", "f f2".split()) + def test_27(self, bash, functions, funcname, utf8_ctype): + completion = assert_complete(bash, "%s aé/" % funcname, cwd="_filedir") + assert completion == "g" diff --git a/test/t/unit/test_unit_get_comp_words_by_ref.py b/test/t/unit/test_unit_get_comp_words_by_ref.py index 1603bad6..b6498fa7 100644 --- a/test/t/unit/test_unit_get_comp_words_by_ref.py +++ b/test/t/unit/test_unit_get_comp_words_by_ref.py @@ -1,16 +1,17 @@ import pytest -from conftest import assert_bash_exec, TestUnitBase +from conftest import TestUnitBase, assert_bash_exec @pytest.mark.bashcomp( - cmd=None, ignore_env=r"^(\+(cur|prev)|[+-]COMP_(WORDS|CWORD|LINE|POINT))=" + cmd=None, + ignore_env=r"^(\+(words|cword|cur|prev)|[+-]COMP_(WORDS|CWORD|LINE|POINT))=", ) class TestUnitGetCompWordsByRef(TestUnitBase): def _test(self, bash, *args, **kwargs): assert_bash_exec(bash, "unset cur prev") output = self._test_unit( - "_get_comp_words_by_ref %s cur prev; echo $cur,$prev", + "_get_comp_words_by_ref %s cur prev; echo $cur,${prev-}", bash, *args, **kwargs @@ -18,7 +19,11 @@ class TestUnitGetCompWordsByRef(TestUnitBase): return output.strip() def test_1(self, bash): - assert_bash_exec(bash, "_get_comp_words_by_ref cur >/dev/null") + assert_bash_exec( + bash, + "COMP_WORDS=() COMP_CWORD= COMP_POINT= COMP_LINE= " + "_get_comp_words_by_ref cur >/dev/null", + ) def test_2(self, bash): """a b|""" @@ -165,3 +170,91 @@ class TestUnitGetCompWordsByRef(TestUnitBase): """a 'b&c|""" output = self._test(bash, '(a "\'b&c")', 1, "a 'b&c", 6) assert output == "'b&c,a" + + def test_30(self, bash): + """a b| to all vars""" + assert_bash_exec(bash, "unset words cword cur prev") + output = self._test_unit( + "_get_comp_words_by_ref words cword cur prev%s; " + 'echo "${words[@]}",$cword,$cur,$prev', + bash, + "(a b)", + 1, + "a b", + 3, + ) + assert output == "a b,1,b,a" + + def test_31(self, bash): + """a b| to alternate vars""" + assert_bash_exec(bash, "unset words2 cword2 cur2 prev2") + output = self._test_unit( + "_get_comp_words_by_ref -w words2 -i cword2 -c cur2 -p prev2%s; " + 'echo $cur2,$prev2,"${words2[@]}",$cword2', + bash, + "(a b)", + 1, + "a b", + 3, + ) + assert output == "b,a,a b,1" + assert_bash_exec(bash, "unset words2 cword2 cur2 prev2") + + def test_32(self, bash): + """a b : c| with wordbreaks -= :""" + assert_bash_exec(bash, "unset words") + output = self._test_unit( + '_get_comp_words_by_ref -n : words%s; echo "${words[@]}"', + bash, + "(a b : c)", + 3, + "a b : c", + 7, + ) + assert output == "a b : c" + + def test_33(self, bash): + """a b: c| with wordbreaks -= :""" + assert_bash_exec(bash, "unset words") + output = self._test_unit( + '_get_comp_words_by_ref -n : words%s; echo "${words[@]}"', + bash, + "(a b : c)", + 3, + "a b: c", + 6, + ) + assert output == "a b: c" + + def test_34(self, bash): + """a b :c| with wordbreaks -= :""" + assert_bash_exec(bash, "unset words") + output = self._test_unit( + '_get_comp_words_by_ref -n : words%s; echo "${words[@]}"', + bash, + "(a b : c)", + 3, + "a b :c", + 6, + ) + assert output == "a b :c" + + def test_35(self, bash): + r"""a b\ :c| with wordbreaks -= :""" + assert_bash_exec(bash, "unset words") + output = self._test_unit( + '_get_comp_words_by_ref -n : words%s; echo "${words[@]}"', + bash, + "(a 'b ' : c)", + 3, + r"a b\ :c", + 7, + ) + assert output == "a b :c" + + def test_unknown_arg_error(self, bash): + with pytest.raises(AssertionError) as ex: + _ = assert_bash_exec( + bash, "_get_comp_words_by_ref dummy", want_output=True + ) + ex.match("dummy.* unknown argument") diff --git a/test/t/unit/test_unit_get_cword.py b/test/t/unit/test_unit_get_cword.py index 3042dd29..0b56d163 100644 --- a/test/t/unit/test_unit_get_cword.py +++ b/test/t/unit/test_unit_get_cword.py @@ -1,17 +1,22 @@ +import pexpect import pytest -from conftest import assert_bash_exec, TestUnitBase +from conftest import PS1, TestUnitBase, assert_bash_exec @pytest.mark.bashcomp( - cmd=None, ignore_env=r"^[+-]COMP_(WORDS|CWORD|LINE|POINT)=" + cmd=None, ignore_env=r"^[+-](COMP_(WORDS|CWORD|LINE|POINT)|_scp_path_esc)=" ) class TestUnitGetCword(TestUnitBase): def _test(self, *args, **kwargs): return self._test_unit("_get_cword %s; echo", *args, **kwargs) def test_1(self, bash): - assert_bash_exec(bash, "_get_cword >/dev/null") + assert_bash_exec( + bash, + "COMP_WORDS=() COMP_CWORD= COMP_LINE= COMP_POINT= " + "_get_cword >/dev/null", + ) def test_2(self, bash): """a b| should return b""" @@ -133,3 +138,17 @@ class TestUnitGetCword(TestUnitBase): """a 'b&c| should return 'b&c""" output = self._test(bash, '(a "\'b&c")', 1, "a 'b&c", 6) assert output == "'b&c" + + @pytest.mark.xfail(reason="TODO: non-ASCII issues with test suite?") + def test_24(self, bash): + """Index shouldn't drop below 0""" + bash.send("scp ääää§ se\t\r\n") + got = bash.expect_exact( + [ + "index: substring expression < 0", + PS1, + pexpect.EOF, + pexpect.TIMEOUT, + ] + ) + assert got == 1 diff --git a/test/t/unit/test_unit_init_completion.py b/test/t/unit/test_unit_init_completion.py index 64f3b511..64a5a790 100644 --- a/test/t/unit/test_unit_init_completion.py +++ b/test/t/unit/test_unit_init_completion.py @@ -1,6 +1,6 @@ import pytest -from conftest import assert_bash_exec, TestUnitBase +from conftest import TestUnitBase, assert_bash_exec, assert_complete @pytest.mark.bashcomp( @@ -13,12 +13,22 @@ class TestUnitInitCompletion(TestUnitBase): """Test environment non-pollution, detected at teardown.""" assert_bash_exec( bash, - "foo() { local cur prev words cword; _init_completion; }; " + "foo() { " + "local cur prev words cword " + "COMP_WORDS=() COMP_CWORD=0 COMP_LINE= COMP_POINT=0; " + "_init_completion; }; " "foo; unset foo", ) def test_2(self, bash): output = self._test_unit( - "_init_completion %s; echo $cur,$prev", bash, "(a)", 0, "a", 0 + "_init_completion %s; echo $cur,${prev-}", bash, "(a)", 0, "a", 0 ) assert output == "," + + @pytest.mark.parametrize("redirect", "> >> 2> < &>".split()) + def test_redirect(self, bash, redirect): + completion = assert_complete( + bash, "%s " % redirect, cwd="shared/default" + ) + assert all(x in completion for x in "foo bar".split()) diff --git a/test/t/unit/test_unit_known_hosts_real.py b/test/t/unit/test_unit_known_hosts_real.py new file mode 100644 index 00000000..ac5205e1 --- /dev/null +++ b/test/t/unit/test_unit_known_hosts_real.py @@ -0,0 +1,158 @@ +from itertools import chain + +import pytest + +from conftest import assert_bash_exec + + +@pytest.mark.bashcomp( + cmd=None, + ignore_env="^[+-](COMP(REPLY|_KNOWN_HOSTS_WITH_HOSTFILE)|OLDHOME)=", +) +class TestUnitKnownHostsReal: + @pytest.mark.parametrize( + "prefix,colon_flag,hostfile", + [("", "", True), ("", "", False), ("user@", "c", True)], + ) + def test_basic( + self, bash, hosts, avahi_hosts, prefix, colon_flag, hostfile + ): + expected = ( + "%s%s%s" % (prefix, x, ":" if colon_flag else "") + for x in chain( + hosts if hostfile else avahi_hosts, + # fixtures/_known_hosts_real/config + "gee hus jar #not-a-comment".split(), + # fixtures/_known_hosts_real/known_hosts + ( + "doo", + "ike", + "jub", + "10.0.0.1", + "kyl", + "100.0.0.2", + "10.10.0.3", + "blah", + "fd00:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:5555", + "fe80::123:0xff:dead:beef%eth0", + "1111:2222:3333:4444:5555:6666:xxxx:abab", + "11xx:2222:3333:4444:5555:6666:xxxx:abab", + "::42", + ), + ) + ) + assert_bash_exec( + bash, + "unset -v COMP_KNOWN_HOSTS_WITH_HOSTFILE" + if hostfile + else "COMP_KNOWN_HOSTS_WITH_HOSTFILE=", + ) + output = assert_bash_exec( + bash, + "_known_hosts_real -a%sF _known_hosts_real/config '%s'; " + r'printf "%%s\n" "${COMPREPLY[@]}"; unset COMPREPLY' + % (colon_flag, prefix), + want_output=True, + ) + assert sorted(set(output.split())) == sorted(expected) + + @pytest.mark.parametrize( + "family,result", + ( + ("4", "127.0.0.1 localhost"), + ("6", "::1 localhost"), + ("46", "localhost"), + ), + ) + def test_ip_filtering(self, bash, family, result): + assert_bash_exec( + bash, "unset -v COMPREPLY COMP_KNOWN_HOSTS_WITH_HOSTFILE" + ) + output = assert_bash_exec( + bash, + "COMP_KNOWN_HOSTS_WITH_HOSTFILE= " + "_known_hosts_real -%sF _known_hosts_real/localhost_config ''; " + r'printf "%%s\n" "${COMPREPLY[@]}"' % family, + want_output=True, + ) + assert sorted(set(output.strip().split())) == sorted(result.split()) + + def test_consecutive_spaces(self, bash, hosts): + expected = hosts.copy() + # fixtures/_known_hosts_real/spaced conf + expected.extend("gee hus #not-a-comment".split()) + # fixtures/_known_hosts_real/known_hosts2 + expected.extend("two two2 two3 two4".split()) + # fixtures/_known_hosts_/spaced known_hosts + expected.extend("doo ike".split()) + + output = assert_bash_exec( + bash, + "unset -v COMPREPLY COMP_KNOWN_HOSTS_WITH_HOSTFILE; " + "_known_hosts_real -aF '_known_hosts_real/spaced conf' ''; " + r'printf "%s\n" "${COMPREPLY[@]}"', + want_output=True, + ) + assert sorted(set(output.strip().split())) == sorted(expected) + + def test_files_starting_with_tilde(self, bash, hosts): + expected = hosts.copy() + # fixtures/_known_hosts_real/known_hosts2 + expected.extend("two two2 two3 two4".split()) + # fixtures/_known_hosts_real/known_hosts3 + expected.append("three") + # fixtures/_known_hosts_real/known_hosts4 + expected.append("four") + + assert_bash_exec(bash, 'OLDHOME="$HOME"; HOME="%s"' % bash.cwd) + output = assert_bash_exec( + bash, + "unset -v COMPREPLY COMP_KNOWN_HOSTS_WITH_HOSTFILE; " + "_known_hosts_real -aF _known_hosts_real/config_tilde ''; " + r'printf "%s\n" "${COMPREPLY[@]}"', + want_output=True, + ) + assert_bash_exec(bash, 'HOME="$OLDHOME"') + assert sorted(set(output.strip().split())) == sorted(expected) + + def test_included_configs(self, bash, hosts): + expected = hosts.copy() + # fixtures/_known_hosts_real/config_include_recursion + expected.append("recursion") + # fixtures/_known_hosts_real/.ssh/config_relative_path + expected.append("relative_path") + # fixtures/_known_hosts_real/.ssh/config_asterisk_* + expected.extend("asterisk_1 asterisk_2".split()) + # fixtures/_known_hosts_real/.ssh/config_question_mark + expected.append("question_mark") + + assert_bash_exec( + bash, 'OLDHOME="$HOME"; HOME="%s/_known_hosts_real"' % bash.cwd + ) + output = assert_bash_exec( + bash, + "unset -v COMPREPLY COMP_KNOWN_HOSTS_WITH_HOSTFILE; " + "_known_hosts_real -aF _known_hosts_real/config_include ''; " + r'printf "%s\n" "${COMPREPLY[@]}"', + want_output=True, + ) + assert_bash_exec(bash, 'HOME="$OLDHOME"') + assert sorted(set(output.strip().split())) == sorted(expected) + + def test_no_globbing(self, bash): + assert_bash_exec( + bash, 'OLDHOME="$HOME"; HOME="%s/_known_hosts_real"' % bash.cwd + ) + output = assert_bash_exec( + bash, + "cd _known_hosts_real; " + "unset -v COMPREPLY COMP_KNOWN_HOSTS_WITH_HOSTFILE; " + "_known_hosts_real -aF config ''; " + r'printf "%s\n" "${COMPREPLY[@]}"; ' + "cd - &>/dev/null", + want_output=True, + ) + assert_bash_exec(bash, 'HOME="$OLDHOME"') + completion = sorted(set(output.strip().split())) + assert "gee" in completion + assert "gee-filename-canary" not in completion diff --git a/test/t/unit/test_unit_longopt.py b/test/t/unit/test_unit_longopt.py index ac0ac836..c5488e34 100644 --- a/test/t/unit/test_unit_longopt.py +++ b/test/t/unit/test_unit_longopt.py @@ -11,6 +11,8 @@ class TestUnitLongopt: def functions(self, request, bash): assert_bash_exec(bash, "_grephelp() { cat _longopt/grep--help.txt; }") assert_bash_exec(bash, "complete -F _longopt _grephelp") + assert_bash_exec(bash, "_various() { cat _longopt/various.txt; }") + assert_bash_exec(bash, "complete -F _longopt _various") @pytest.mark.complete("_grephelp --") def test_1(self, functions, completion): @@ -32,3 +34,19 @@ class TestUnitLongopt: assert completion assert any(x.endswith("=") for x in completion) assert any(not x.endswith("=") for x in completion) + + @pytest.mark.complete("_various --") + def test_no_dashdashdash(self, functions, completion): + assert all(not x.startswith("---") for x in completion) + + @pytest.mark.complete("_various --") + def test_no_trailingdash(self, functions, completion): + assert all(not x.endswith("-") for x in completion) + + @pytest.mark.complete("_various --") + def test_underscore(self, functions, completion): + assert "--foo_bar" in completion + + @pytest.mark.complete("_various --") + def test_equals(self, functions, completion): + assert "--foo=" in completion diff --git a/test/t/unit/test_unit_quote.py b/test/t/unit/test_unit_quote.py index e9f81c2d..b280bd68 100644 --- a/test/t/unit/test_unit_quote.py +++ b/test/t/unit/test_unit_quote.py @@ -1,6 +1,6 @@ import pytest -from conftest import assert_bash_exec, TestUnitBase +from conftest import TestUnitBase, assert_bash_exec @pytest.mark.bashcomp(cmd=None) diff --git a/test/t/unit/test_unit_quote_readline.py b/test/t/unit/test_unit_quote_readline.py new file mode 100644 index 00000000..e2b437e3 --- /dev/null +++ b/test/t/unit/test_unit_quote_readline.py @@ -0,0 +1,15 @@ +import pytest + +from conftest import assert_bash_exec + + +@pytest.mark.bashcomp(cmd=None) +class TestUnitQuoteReadline: + def test_exec(self, bash): + assert_bash_exec(bash, "quote_readline '' >/dev/null") + + def test_env_non_pollution(self, bash): + """Test environment non-pollution, detected at teardown.""" + assert_bash_exec( + bash, "foo() { quote_readline meh >/dev/null; }; foo; unset foo" + ) diff --git a/test/t/unit/test_unit_variables.py b/test/t/unit/test_unit_variables.py index dd7a4219..d62bc4a4 100644 --- a/test/t/unit/test_unit_variables.py +++ b/test/t/unit/test_unit_variables.py @@ -18,11 +18,11 @@ class TestUnitVariables: @pytest.mark.complete(": $___v") def test_simple_variable_name(self, functions, completion): - assert completion == "$___var".split() + assert completion == "ar" @pytest.mark.complete(": ${assoc1[") def test_single_array_index(self, functions, completion): - assert completion == "${assoc1[idx]}".split() + assert completion == "idx]}" @pytest.mark.complete(": ${assoc2[") def test_multiple_array_indexes(self, functions, completion): @@ -30,12 +30,12 @@ class TestUnitVariables: @pytest.mark.complete(": ${assoc1[bogus]") def test_closing_curly_after_square(self, functions, completion): - assert completion == "${assoc1[bogus]}".split() + assert completion == "}" @pytest.mark.complete(": ${assoc1[@") def test_closing_brackets_after_at(self, functions, completion): - assert completion == "${assoc1[@]}".split() + assert completion == "]}" @pytest.mark.complete(": ${#___v") def test_hash_prefix(self, functions, completion): - assert completion == "${#___var}".split() + assert completion == "ar}" diff --git a/test/t/unit/test_unit_xinetd_services.py b/test/t/unit/test_unit_xinetd_services.py new file mode 100644 index 00000000..7a90cb7f --- /dev/null +++ b/test/t/unit/test_unit_xinetd_services.py @@ -0,0 +1,22 @@ +import pytest + +from conftest import assert_bash_exec + + +@pytest.mark.bashcomp(cmd=None, ignore_env=r"^\+COMPREPLY=") +class TestUnitXinetdServices: + def test_direct(self, bash): + assert_bash_exec(bash, "_xinetd_services >/dev/null") + + def test_env_non_pollution(self, bash): + """Test environment non-pollution, detected at teardown.""" + assert_bash_exec(bash, "foo() { _xinetd_services; }; foo; unset foo") + + def test_basic(self, bash): + output = assert_bash_exec( + bash, + "foo() { local BASHCOMP_XINETDDIR=$PWD/shared/bin;unset COMPREPLY; " + '_xinetd_services; printf "%s\\n" "${COMPREPLY[@]}"; }; foo; unset foo', + want_output=True, + ) + assert sorted(output.split()) == ["arp", "ifconfig"] |