diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 48860e5f5c1..e7074eae1f1 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -94,3 +94,9 @@ jobs:
env:
GH_TOKEN: ${{github.token}}
if: steps.release.outputs.release_created
+
+ distcheck-macos:
+ runs-on: macos-latest
+ steps:
+ - uses: actions/checkout@v4
+ - run: env PYTESTFLAGS="--verbose -p no:cacheprovider --color=yes -k '(TestTar and test_25) or TestPs'" test/macos-script.sh
diff --git a/completions/patch b/completions/patch
index bba184ceb4a..6e24f64640d 100644
--- a/completions/patch
+++ b/completions/patch
@@ -50,7 +50,11 @@ _comp_cmd_patch()
[[ $was_split ]] && return
if [[ $cur == -* ]]; then
- _comp_compgen_help
+ if [[ $OSTYPE == *@(darwin)* ]]; then
+ _comp_compgen_usage
+ else
+ _comp_compgen_help
+ fi
[[ ${COMPREPLY-} == *= ]] && compopt -o nospace
return
fi
diff --git a/completions/tar b/completions/tar
index e4423b154bb..8b95653fbe9 100644
--- a/completions/tar
+++ b/completions/tar
@@ -299,6 +299,7 @@ _comp_cmd_tar__preparse_cmdline()
# Generate completions for -f/--file.
_comp_cmd_tar__file_option()
{
+ set -x
local ext="$1"
case "$tar_mode" in
@@ -510,6 +511,7 @@ _comp_cmd_tar__is_bsdtar()
_comp_cmd_tar__detect_ext()
{
+ set -x
local tars='@(@(tar|spkg)?(.@(Z|[bgx]z|bz2|lz?(ma|o)|zst))|t@([abglx]z|b?(z)2|zst)|cbt|gem|xbps)'
if _comp_cmd_tar__is_bsdtar; then
# https://github.com/libarchive/libarchive/wiki/LibarchiveFormats
@@ -787,6 +789,7 @@ _comp_cmd_tar__posix()
local ext
+ set -x
_comp_cmd_tar__detect_ext
_comp_cmd_tar__adjust_PREV_from_old_option
diff --git a/completions/truncate b/completions/truncate
index 94534a285bc..f8eddde2e6f 100644
--- a/completions/truncate
+++ b/completions/truncate
@@ -20,7 +20,11 @@ _comp_cmd_truncate()
[[ $was_split ]] && return
if [[ $cur == -* ]]; then
- _comp_compgen_help
+ if [[ $OSTYPE == *@(darwin)* ]]; then
+ _comp_compgen_usage
+ else
+ _comp_compgen_help
+ fi
[[ ${COMPREPLY-} == *= ]] && compopt -o nospace
return
fi
diff --git a/test/macos-script.sh b/test/macos-script.sh
new file mode 100755
index 00000000000..6cc067e4149
--- /dev/null
+++ b/test/macos-script.sh
@@ -0,0 +1,26 @@
+#!/bin/sh -eux
+
+# Note that this script is intended to be run only in throwaway environments;
+# it may install undesirable things to system locations (if it succeeds in
+# that).
+
+brew install \
+ automake \
+ bash
+
+oldpwd=$(pwd)
+
+python3 -m venv venv
+#shellcheck disable=SC1091
+source venv/bin/activate
+python3 -m pip install -r test/requirements.txt
+
+export bashcomp_bash=bash
+env
+
+autoreconf -i
+./configure
+make -j
+
+make distcheck \
+ PYTESTFLAGS="${PYTESTFLAGS---verbose -p no:cacheprovider --numprocesses=auto --dist=loadfile}"
diff --git a/test/t/conftest.py b/test/t/conftest.py
index 8d38d873990..bbd6b1abb36 100644
--- a/test/t/conftest.py
+++ b/test/t/conftest.py
@@ -951,7 +951,9 @@ def prepare_fixture_dir(
the tarball. This is to work better with case insensitive file systems.
"""
tempdir = Path(tempfile.mkdtemp(prefix="bash-completion-fixture-dir"))
- request.addfinalizer(lambda: shutil.rmtree(str(tempdir)))
+ request.addfinalizer(
+ lambda: shutil.rmtree(str(tempdir), ignore_errors=True)
+ )
old_cwd = os.getcwd()
try:
diff --git a/test/t/test_make.py b/test/t/test_make.py
index 34fc7e5906a..4af4285b665 100644
--- a/test/t/test_make.py
+++ b/test/t/test_make.py
@@ -1,4 +1,5 @@
import os
+import sys
import pytest
@@ -6,20 +7,25 @@
class TestMake:
+ @pytest.fixture
+ def remove_extra_makefile(self, bash):
+ yield
+ # For some reason macos make doesn't actually create extra_makefile
+ if sys.platform != "darwin":
+ os.remove(f"{bash.cwd}/make/extra_makefile")
+
@pytest.mark.complete("make -f Ma", cwd="make")
def test_1(self, completion):
assert completion == "kefile"
@pytest.mark.complete("make .", cwd="make", require_cmd=True)
- def test_2(self, bash, completion):
+ def test_2(self, bash, completion, remove_extra_makefile):
"""Hidden targets."""
assert completion == ".cache/ .test_passes".split()
- os.remove(f"{bash.cwd}/make/extra_makefile")
@pytest.mark.complete("make .cache/", cwd="make", require_cmd=True)
- def test_3(self, bash, completion):
+ def test_3(self, bash, completion, remove_extra_makefile):
assert completion == ".cache/1 .cache/2".split()
- os.remove(f"{bash.cwd}/make/extra_makefile")
@pytest.mark.complete("make ", cwd="shared/empty_dir")
def test_4(self, completion):
@@ -30,24 +36,20 @@ def test_5(self, completion):
assert completion
@pytest.mark.complete("make ", cwd="make", require_cmd=True)
- def test_6(self, bash, completion):
+ def test_6(self, bash, completion, remove_extra_makefile):
assert completion == "all clean extra_makefile install sample".split()
- os.remove(f"{bash.cwd}/make/extra_makefile")
@pytest.mark.complete("make .cache/.", cwd="make", require_cmd=True)
- def test_7(self, bash, completion):
+ def test_7(self, bash, completion, remove_extra_makefile):
assert completion == ".cache/.1 .cache/.2".split()
- os.remove(f"{bash.cwd}/make/extra_makefile")
@pytest.mark.complete("make -C make ", require_cmd=True)
- def test_8(self, bash, completion):
+ def test_8(self, bash, completion, remove_extra_makefile):
assert completion == "all clean extra_makefile install sample".split()
- os.remove(f"{bash.cwd}/make/extra_makefile")
@pytest.mark.complete("make -nC make ", require_cmd=True)
- def test_8n(self, bash, completion):
+ def test_8n(self, bash, completion, remove_extra_makefile):
assert completion == "all clean extra_makefile install sample".split()
- os.remove(f"{bash.cwd}/make/extra_makefile")
@pytest.mark.complete("make -", require_cmd=True)
def test_9(self, completion):
diff --git a/test/t/test_ps.py b/test/t/test_ps.py
index a6bfec13c7c..56378fbaff7 100644
--- a/test/t/test_ps.py
+++ b/test/t/test_ps.py
@@ -1,5 +1,7 @@
import pytest
+from conftest import assert_bash_exec
+
def is_int(s):
try:
@@ -35,7 +37,9 @@ def test_4(self, completion):
assert not completion
@pytest.mark.complete("ps --pid ")
- def test_5(self, completion):
+ def test_5(self, completion, bash):
+ ps_pid_output = assert_bash_exec(bash, "command ps ax -o pid=", want_output=True)
+ print("\n=====PS output=====\n", ps_pid_output, "\n======PS output end=====\n")
assert completion
assert all(map(is_int, completion))
diff --git a/test/t/test_vipw.py b/test/t/test_vipw.py
index b78fcbda8b0..07b454bff4f 100644
--- a/test/t/test_vipw.py
+++ b/test/t/test_vipw.py
@@ -1,12 +1,7 @@
-import sys
-
import pytest
class TestVipw:
@pytest.mark.complete("vipw -", require_cmd=True)
def test_1(self, completion):
- if sys.platform == "darwin":
- assert not completion # takes no options
- else:
- assert completion
+ assert completion
diff --git a/test/t/unit/test_unit_expand_glob.py b/test/t/unit/test_unit_expand_glob.py
index 7c1bcde3f9c..480fd37d0a8 100644
--- a/test/t/unit/test_unit_expand_glob.py
+++ b/test/t/unit/test_unit_expand_glob.py
@@ -1,8 +1,18 @@
+import unicodedata
+
import pytest
from conftest import assert_bash_exec, bash_env_saved
+def normalize(string):
+ # Applies "canonical decomposition", so might make errors look weird?
+ # The alternative is probably `NFC` which composes together some of
+ # the characters again.
+ # See https://docs.python.org/3/library/unicodedata.html#unicodedata.normalize
+ return unicodedata.normalize("NFD", string)
+
+
@pytest.mark.bashcomp(
cmd=None,
cwd="_filedir",
@@ -22,14 +32,15 @@ def functions(self, bash):
def test_match_all(self, bash, functions):
output = assert_bash_exec(bash, "__tester '*'", want_output=True)
- assert (
- output.strip()
- == ""
+ assert normalize(output.strip()) == normalize(
+ ""
)
def test_match_pattern(self, bash, functions):
output = assert_bash_exec(bash, "__tester 'a*'", want_output=True)
- assert output.strip() == ""
+ assert normalize(output.strip()) == normalize(
+ ""
+ )
def test_match_unmatched(self, bash, functions):
output = assert_bash_exec(
@@ -51,7 +62,9 @@ def test_protect_from_noglob(self, bash, functions):
with bash_env_saved(bash, functions) as bash_env:
bash_env.set("noglob", True)
output = assert_bash_exec(bash, "__tester 'a*'", want_output=True)
- assert output.strip() == ""
+ assert normalize(output.strip()) == normalize(
+ ""
+ )
def test_protect_from_failglob(self, bash, functions):
with bash_env_saved(bash) as bash_env:
@@ -83,4 +96,6 @@ def test_protect_from_GLOBIGNORE(self, bash, functions):
bash_env.save_shopt("dotglob")
bash_env.write_variable("GLOBIGNORE", "*")
output = assert_bash_exec(bash, "__tester 'a*'", want_output=True)
- assert output.strip() == ""
+ assert normalize(output.strip()) == normalize(
+ ""
+ )