@rm -rf $(COV_INSTALL)
@mkdir -p $(COV_INSTALL)
@export COV_DIR=$(COV_INSTALL); \
- kcov --bash-handle-sh-invocation \
+ kcov --bash-dont-parse-binary-dir \
--include-pattern=install.sh \
--exclude-path=$(PWD)/.git,$(PWD)/tests \
$(COV_INSTALL) \
- ./tests/test-install-logic.sh
+ ./tests/test-install-logic.sh 2>&1 | tee .tmp/kcov.log; \
+ if grep -q 'kcov: error:' .tmp/kcov.log; then \
+ echo "FAIL: kcov errors detected (see above)"; exit 1; \
+ fi
.PHONY: test/purity
_test_cov_internal:
@err=0; \
$(call CHECK_COVERAGE,$(COV_SYSTEM),git-remote-gcrypt,56) || err=1; \
- $(call CHECK_COVERAGE,$(COV_INSTALL),install.sh,78) || err=1; \
+ $(call CHECK_COVERAGE,$(COV_INSTALL),install.sh,84) || err=1; \
exit $$err
missed_lines = 0
for c in tree.findall(".//class"):
- if patt in c.get("filename", ""):
+ filename = c.get("filename", "")
+ # Use exact filename match, not substring (avoid "uninstall.sh" matching "install.sh")
+ if filename == patt or filename.endswith("/" + patt):
for line in c.findall(".//line"):
total_lines += 1
if line.get("hits") == "0":
print_info "Running install logic tests in $SANDBOX..."
-# 2. Symlink/Copy artifacts
-# Symlink core logic to help kcov find the source
-ln -s "$REPO_ROOT/install.sh" "$SANDBOX/install.sh"
+# 2. Copy/Symlink artifacts
+# Copy install.sh so kcov can track it correctly (symlinks confuse kcov)
+cp "$REPO_ROOT/install.sh" "$SANDBOX/install.sh"
ln -s "$REPO_ROOT/git-remote-gcrypt" "$SANDBOX/git-remote-gcrypt"
ln -s "$REPO_ROOT/utils" "$SANDBOX/utils"
ln -s "$REPO_ROOT/completions" "$SANDBOX/completions"
# Instead, we mock 'install' to fail, ensuring error paths are hit.
SHADOW_BIN_FAIL="$SANDBOX/shadow_bin_install_fail"
mkdir -p "$SHADOW_BIN_FAIL"
-cat >"$SHADOW_BIN_FAIL/install" <<EOF
-#!/bin/sh
-echo "Mock failure" >&2
-exit 1
-EOF
+echo '#!/bin/sh' >"$SHADOW_BIN_FAIL/install"
+echo 'echo "Mock failure" >&2' >>"$SHADOW_BIN_FAIL/install"
+echo 'exit 1' >>"$SHADOW_BIN_FAIL/install"
chmod +x "$SHADOW_BIN_FAIL/install"
if PATH="$SHADOW_BIN_FAIL:$PATH" prefix="$SANDBOX/usr" DESTDIR="" bash "$INSTALLER" >.install_log 2>&1; then
# Shadow rst2man in PATH
SHADOW_BIN="$SANDBOX/shadow_bin"
mkdir -p "$SHADOW_BIN"
-cat >"$SHADOW_BIN/rst2man" <<EOF
-#!/bin/sh
-exit 127
-EOF
+echo '#!/bin/sh' >"$SHADOW_BIN/rst2man"
+echo 'exit 127' >>"$SHADOW_BIN/rst2man"
chmod +x "$SHADOW_BIN/rst2man"
ln -sf "$SHADOW_BIN/rst2man" "$SHADOW_BIN/rst2man.py"
# We need to shadow 'uname' too
SHADOW_BIN_OS="$SANDBOX/shadow_bin_os"
mkdir -p "$SHADOW_BIN_OS"
-cat >"$SHADOW_BIN_OS/uname" <<EOF
-#!/bin/sh
-exit 127
-EOF
+echo '#!/bin/sh' >"$SHADOW_BIN_OS/uname"
+echo 'exit 127' >>"$SHADOW_BIN_OS/uname"
chmod +x "$SHADOW_BIN_OS/uname"
if PATH="$SHADOW_BIN_OS:$PATH" prefix="$SANDBOX/usr" DESTDIR="" OS_RELEASE_FILE="$SANDBOX/unknown" bash "$INSTALLER" >.install_log 2>&1; then