diff --git a/scripts/mutation-test-changed.sh b/scripts/mutation-test-changed.sh index d1fc149c7..fd8b3c70a 100755 --- a/scripts/mutation-test-changed.sh +++ b/scripts/mutation-test-changed.sh @@ -307,9 +307,16 @@ main() { for pkg in "${testable_packages[@]}"; do pkg_index=$((pkg_index + 1)) module_root=$(find_module_root "$pkg") - # Compute relative package path from the module root + # Compute relative package path from the module root. A package that is + # itself the module root has nothing to strip — the prefix pattern below + # carries a trailing slash and would leave the absolute path intact — so + # it is addressed as the current directory instead. rel_pkg="${REPO_ROOT}/${pkg#/}" - rel_pkg="${rel_pkg#"$module_root"/}" + if [[ "$rel_pkg" == "$module_root" ]]; then + rel_pkg="." + else + rel_pkg="${rel_pkg#"$module_root"/}" + fi echo "" echo "=== $pkg (module: ${module_root#"$REPO_ROOT"/}) ===" diff --git a/scripts/tests/mutation-test-changed_test.sh b/scripts/tests/mutation-test-changed_test.sh index 55e3e53fe..ae021fe78 100755 --- a/scripts/tests/mutation-test-changed_test.sh +++ b/scripts/tests/mutation-test-changed_test.sh @@ -371,6 +371,37 @@ test_a_report_with_a_zero_exit_is_ok() { assert_status 0 "a completed run passes" } +# A changed package that is its own module root (it holds a go.mod) is invoked +# on itself: gremlins runs in that directory targeting the directory, not a +# path re-rooted below it. +test_a_module_root_package_is_invoked_on_itself() { + local work repo bin invocation + work=$(new_workdir) + repo="$work/repo" + bin="$work/bin" + invocation="$work/invocation" + + make_fixture_repo "$repo" + add_changed_package "$repo" "pkg/plugin" + printf 'module example/plugin\n\ngo 1.26\n' > "$repo/pkg/plugin/go.mod" + fixture_commit "$repo" "make pkg/plugin its own module" + + stub_gremlins "$bin" "pwd > '$invocation'; echo \"\$target\" >> '$invocation' +printf '%s' '$(mutation_report KILLED)' > \"\$report_path\"; exit 0" + + run_script "$repo" "$bin" + + assert_status 0 "a module-root package produces a usable result" + assert_output_matches '\| `pkg/plugin` \| ok \|' \ + "the module-root package row is ok" + if [[ "$(sed -n 1p "$invocation" 2>/dev/null)" != "$repo/pkg/plugin" ]]; then + fail "gremlins did not run in the package's own module root (got '$(sed -n 1p "$invocation" 2>/dev/null)')" + fi + if [[ "$(sed -n 2p "$invocation" 2>/dev/null)" != "./." ]]; then + fail "gremlins was not invoked on the module root itself (got '$(sed -n 2p "$invocation" 2>/dev/null)')" + fi +} + # Surviving mutants make gremlins exit non-zero: advisory content, not a crash. test_surviving_mutants_are_not_a_failure() { local work repo bin @@ -883,6 +914,7 @@ run_test() { main() { run_test test_exit_zero_without_report_is_a_failure run_test test_a_report_with_a_zero_exit_is_ok + run_test test_a_module_root_package_is_invoked_on_itself run_test test_surviving_mutants_are_not_a_failure run_test test_an_unknown_non_zero_exit_with_a_report_is_ok run_test test_a_zero_mutant_report_is_ok_without_a_score