summaryrefslogtreecommitdiff
path: root/test/t/unit
diff options
context:
space:
mode:
Diffstat (limited to 'test/t/unit')
-rw-r--r--test/t/unit/Makefile.am5
-rw-r--r--test/t/unit/test_unit_count_args.py4
-rw-r--r--test/t/unit/test_unit_expand.py20
-rw-r--r--test/t/unit/test_unit_expand_tilde_by_ref.py32
-rw-r--r--test/t/unit/test_unit_filedir.py138
-rw-r--r--test/t/unit/test_unit_get_comp_words_by_ref.py101
-rw-r--r--test/t/unit/test_unit_get_cword.py25
-rw-r--r--test/t/unit/test_unit_init_completion.py16
-rw-r--r--test/t/unit/test_unit_known_hosts_real.py158
-rw-r--r--test/t/unit/test_unit_longopt.py18
-rw-r--r--test/t/unit/test_unit_quote.py2
-rw-r--r--test/t/unit/test_unit_quote_readline.py15
-rw-r--r--test/t/unit/test_unit_variables.py10
-rw-r--r--test/t/unit/test_unit_xinetd_services.py22
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"]