patchette

test-hermetic.sh

#!/bin/bash
## Hermeticity: hostile repo-local git config and attributes, in the subject
## or the target repo, must not change what patchette writes or replays.
##
## Nulling global and system config doesn't reach a repo's own .git/config,
## its info/attributes, or a worktree .gitattributes; git reads all of those.
## Each case plants one hostile setup into a copy of a repo, then checks:
## export bytes match a clean export, verify passes, and import reproduces exact tips.
set -euo pipefail
cd "$(dirname "$0")"
source ./lib.sh

work=$(mktemp -d)
trap 'rm -rf "$work"' EXIT

make_corpus "$work/corpus"
source "$work/corpus/FACTS"
branches=(topic/fancy docs-polish odd-bytes)
want_tips=$(printf '%s\n' "$tip_topic_fancy" "$tip_docs_polish" "$tip_odd_bytes")
"$PATCHETTE" export "$work/corpus/dev" "$work/clean" "$base" "${branches[@]}" >/dev/null
printf 'odd/trailing.txt\n' >"$work/orderfile"

# Each case is `|`-separated items:
# `key=value` sets repo-local config; `@line` appends to the repo's info/attributes;
# `%line` appends to an uncommitted worktree .gitattributes;
# `!line` commits a .gitattributes on a new branch and checks it out
# (export bytes must not vary with which branch happens to be checked out).
cases=(
	diff.context=1
	diff.context=8
	diff.interHunkContext=10
	diff.algorithm=histogram
	diff.algorithm=minimal
	diff.indentHeuristic=false
	diff.renames=copies
	diff.noprefix=true
	diff.mnemonicPrefix=true
	'diff.srcPrefix=old/|diff.dstPrefix=new/'
	diff.relative=true
	diff.suppressBlankEmpty=true
	"diff.orderFile=$work/orderfile"
	diff.wsErrorHighlight=all
	color.ui=always
	color.diff=always
	core.abbrev=12
	core.quotePath=false
	core.bigFileThreshold=1
	core.autocrlf=true
	core.autocrlf=input
	core.eol=crlf
	'core.autocrlf=true|core.safecrlf=true'
	core.fileMode=false
	core.symlinks=false
	core.ignoreCase=true
	core.precomposeUnicode=true
	core.whitespace=trailing-space,space-before-tab,cr-at-eol,blank-at-eof
	core.splitIndex=true
	index.version=4
	apply.whitespace=fix
	apply.whitespace=error
	apply.ignoreWhitespace=change
	i18n.logOutputEncoding=ISO-8859-1
	log.showSignature=true
	format.pretty=oneline
	'@* -diff'
	'@* binary'
	'@*.c diff=cpp'
	'@* diff=hostile|diff.hostile.xfuncname=^/\*.*$'
	'@* diff=hostile|diff.hostile.textconv=tr a-z A-Z'
	'@* diff=hostile|diff.hostile.binary=true'
	'@* filter=hostile|filter.hostile.clean=tr a-z A-Z|filter.hostile.smudge=cat'
	'@* text eol=crlf'
	'@* text=auto'
	'@* whitespace=trailing-space,cr-at-eol'
	'%*.c diff=cpp'
	'%* -diff'
	'!* -diff'
	'!*.c diff=cpp'
)

## Plant one hostile case into a repo.
##
## - @param $1 repo path (non-bare)
## - @param $2 case string, as described above the table
hostilize() {
	local repo=$1 item
	local -a items
	IFS='|' read -ra items <<<"$2"
	for item in "${items[@]}"; do
		case $item in
		@*) printf '%s\n' "${item#@}" >>"$repo/.git/info/attributes" ;;
		%*) printf '%s\n' "${item#%}" >>"$repo/.gitattributes" ;;
		'!'*)
			printf '%s\n' "${item#!}" >>"$repo/.gitattributes"
			git -C "$repo" switch -qc hostile-attrs
			git -C "$repo" add .gitattributes
			git -C "$repo" commit -qm "hostile attributes"
			;;
		*) git -C "$repo" config "${item%%=*}" "${item#*=}" ;;
		esac
	done
}

n=0
for c in "${cases[@]}"; do
	n=$((n + 1))
	d="$work/case$n"
	mkdir "$d"

	# Command failures here surface on stderr just above the FAIL they cause.
	cp -a "$work/corpus/dev" "$d/subject"
	hostilize "$d/subject" "$c"
	"$PATCHETTE" export "$d/subject" "$d/out" "$base" "${branches[@]}" >/dev/null || true
	EXPECT success "subject has $c: export bytes match a clean export" -- \
		diff -r "$work/clean" "$d/out"
	EXPECT success "subject has $c: verify passes" -- \
		"$PATCHETTE" verify "$d/subject" "$work/clean"

	git clone -q "$work/corpus/upstream" "$d/target"
	hostilize "$d/target" "$c"
	"$PATCHETTE" import "$d/target" "$work/clean" >/dev/null || true
	EXPECT equal "target has $c: import reproduces exact tips" -- \
		"$(git -C "$d/target" rev-parse "${branches[@]/#/refs/heads/}" 2>/dev/null || true)" "$want_tips"
done

exit "$RESULT"

tests/test-hermetic.sh · 4.0 KiB · 2169820719