|
#!/bin/sh |
|
set -eu |
|
|
|
SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) |
|
GIT_LOC="$SCRIPT_DIR/git_loc.sh" |
|
TEST_ROOT=$(mktemp -d "${TMPDIR:-/tmp}/git-loc-test.XXXXXX") |
|
TEST_COUNT=0 |
|
|
|
cleanup() { |
|
status=$? |
|
trap - 0 1 2 3 15 |
|
rm -rf "$TEST_ROOT" |
|
exit "$status" |
|
} |
|
|
|
trap cleanup 0 |
|
trap 'exit 129' 1 |
|
trap 'exit 130' 2 |
|
trap 'exit 131' 3 |
|
trap 'exit 143' 15 |
|
|
|
fail() { |
|
printf 'not ok %d - %s\n' "$TEST_COUNT" "$1" >&2 |
|
if [ "$#" -ge 2 ]; then |
|
printf '%s\n' "$2" >&2 |
|
fi |
|
exit 1 |
|
} |
|
|
|
begin_test() { |
|
TEST_COUNT=$((TEST_COUNT + 1)) |
|
TEST_NAME=$1 |
|
} |
|
|
|
pass() { |
|
printf 'ok %d - %s\n' "$TEST_COUNT" "$TEST_NAME" |
|
} |
|
|
|
assert_equal() { |
|
ASSERT_EXPECTED=$1 |
|
ASSERT_ACTUAL=$2 |
|
ASSERT_MESSAGE=$3 |
|
if [ "$ASSERT_ACTUAL" != "$ASSERT_EXPECTED" ]; then |
|
fail "$TEST_NAME: $ASSERT_MESSAGE" "expected: |
|
$ASSERT_EXPECTED |
|
actual: |
|
$ASSERT_ACTUAL" |
|
fi |
|
} |
|
|
|
assert_line() { |
|
ASSERT_LINE=$1 |
|
ASSERT_OUTPUT=$2 |
|
ASSERT_MESSAGE=$3 |
|
printf '%s\n' "$ASSERT_OUTPUT" | grep -F -x -- "$ASSERT_LINE" >/dev/null || |
|
fail "$TEST_NAME: $ASSERT_MESSAGE" "missing line: $ASSERT_LINE |
|
output: |
|
$ASSERT_OUTPUT" |
|
} |
|
|
|
assert_contains() { |
|
ASSERT_FRAGMENT=$1 |
|
ASSERT_OUTPUT=$2 |
|
ASSERT_MESSAGE=$3 |
|
case "$ASSERT_OUTPUT" in |
|
*"$ASSERT_FRAGMENT"*) ;; |
|
*) |
|
fail "$TEST_NAME: $ASSERT_MESSAGE" "missing fragment: $ASSERT_FRAGMENT |
|
output: |
|
$ASSERT_OUTPUT" |
|
;; |
|
esac |
|
} |
|
|
|
assert_no_ansi() { |
|
ASSERT_OUTPUT=$1 |
|
ASSERT_MESSAGE=$2 |
|
ASSERT_ESCAPE=$(printf '\033') |
|
case "$ASSERT_OUTPUT" in |
|
*"$ASSERT_ESCAPE"*) fail "$TEST_NAME: $ASSERT_MESSAGE" ;; |
|
esac |
|
} |
|
|
|
run_tty_all() { |
|
TTY_REPO=$1 |
|
TTY_CAPTURE=$2 |
|
|
|
case $(uname -s) in |
|
Darwin) |
|
(cd "$TTY_REPO" && GIT_LOC_UNDER_TEST=$GIT_LOC \ |
|
script -q "$TTY_CAPTURE" sh -c \ |
|
'exec "$GIT_LOC_UNDER_TEST" all' >/dev/null) |
|
;; |
|
*) |
|
(cd "$TTY_REPO" && GIT_LOC_UNDER_TEST=$GIT_LOC \ |
|
script -q -e -c \ |
|
'exec "$GIT_LOC_UNDER_TEST" all' "$TTY_CAPTURE" >/dev/null) |
|
;; |
|
esac |
|
} |
|
|
|
new_repo() { |
|
repo=$TEST_ROOT/repo-$TEST_COUNT |
|
mkdir "$repo" |
|
git -C "$repo" init -q |
|
git -C "$repo" config user.name 'git-loc test' |
|
git -C "$repo" config user.email 'git-loc@example.invalid' |
|
printf '%s\n' "$repo" |
|
} |
|
|
|
commit_all() { |
|
git -C "$1" add -A |
|
git -C "$1" commit -q -m baseline |
|
} |
|
|
|
make_lines() { |
|
MAKE_LINE_COUNT=$1 |
|
MAKE_LINE_FILE=$2 |
|
awk -v count="$MAKE_LINE_COUNT" 'BEGIN { |
|
for (line = 1; line <= count; line++) print "line " line |
|
}' >"$MAKE_LINE_FILE" |
|
} |
|
|
|
replace_first_line() { |
|
REPLACE_FILE=$1 |
|
REPLACE_TMP=$REPLACE_FILE.tmp |
|
{ |
|
printf 'changed\n' |
|
awk 'NR > 1' "$REPLACE_FILE" |
|
} >"$REPLACE_TMP" |
|
mv "$REPLACE_TMP" "$REPLACE_FILE" |
|
} |
|
|
|
printf '1..9\n' |
|
|
|
begin_test 'empty repository and empty sections' |
|
repo=$(new_repo) |
|
actual=$(cd "$repo" && "$GIT_LOC" all) |
|
expected='DIFF |
|
TOTAL 0 (+0/-0) UNCHANGED |
|
|
|
DIFF CACHED |
|
TOTAL 0 (+0/-0) UNCHANGED |
|
|
|
UNTRACKED FILES |
|
TOTAL 0 (+0/-0) UNCHANGED |
|
|
|
GRAND TOTAL 0 (+0/-0) UNCHANGED' |
|
assert_equal "$expected" "$actual" 'empty all-mode output differs' |
|
assert_equal 'TOTAL 0 (+0/-0) UNCHANGED' "$(cd "$repo" && "$GIT_LOC" diff)" 'empty diff output differs' |
|
assert_equal 'TOTAL 0 (+0/-0) UNCHANGED' "$(cd "$repo" && "$GIT_LOC" cached)" 'empty cached output differs' |
|
assert_equal 'TOTAL 0 (+0/-0) UNCHANGED' "$(cd "$repo" && "$GIT_LOC" untracked)" 'empty untracked output differs' |
|
pass |
|
|
|
begin_test 'growing working tree' |
|
repo=$(new_repo) |
|
printf 'one\ntwo\nthree\n' >"$repo/growth.txt" |
|
actual=$(cd "$repo" && "$GIT_LOC" all) |
|
assert_line '+3 (+3/-0) growth.txt LOC:3' "$actual" 'untracked file counts differ' |
|
assert_line 'TOTAL +3 (+3/-0) GROWING' "$actual" 'untracked total differs' |
|
assert_line 'GRAND TOTAL +3 (+3/-0) GROWING' "$actual" 'growth grand total differs' |
|
pass |
|
|
|
begin_test 'shrinking working tree' |
|
repo=$(new_repo) |
|
printf 'one\ntwo\nthree\n' >"$repo/shrink.txt" |
|
commit_all "$repo" |
|
: >"$repo/shrink.txt" |
|
actual=$(cd "$repo" && "$GIT_LOC" all) |
|
assert_line '-3 (+0/-3) shrink.txt LOC:0' "$actual" 'deletion or current LOC count differs' |
|
assert_line 'TOTAL -3 (+0/-3) SHRINKING' "$actual" 'diff total differs' |
|
assert_line 'GRAND TOTAL -3 (+0/-3) SHRINKING' "$actual" 'shrinkage grand total differs' |
|
pass |
|
|
|
begin_test 'unchanged net working tree' |
|
repo=$(new_repo) |
|
printf 'before\n' >"$repo/unchanged.txt" |
|
commit_all "$repo" |
|
printf 'after\n' >"$repo/unchanged.txt" |
|
actual=$(cd "$repo" && "$GIT_LOC" all) |
|
assert_line '0 (+1/-1) unchanged.txt LOC:1' "$actual" 'replacement or current LOC count differs' |
|
assert_line 'GRAND TOTAL 0 (+1/-1) UNCHANGED' "$actual" 'unchanged grand total differs' |
|
pass |
|
|
|
begin_test 'combined unstaged, staged, and untracked totals' |
|
repo=$(new_repo) |
|
printf 'u1\nu2\nu3\n' >"$repo/unstaged.txt" |
|
printf 's1\ns2\n' >"$repo/staged.txt" |
|
commit_all "$repo" |
|
printf 'u1\n' >"$repo/unstaged.txt" |
|
printf 's1\nnew\ns2\n' >"$repo/staged.txt" |
|
git -C "$repo" add staged.txt |
|
printf 'n1\nn2\n' >"$repo/untracked.txt" |
|
actual=$(cd "$repo" && "$GIT_LOC" all) |
|
assert_no_ansi "$actual" 'non-TTY output contained ANSI escapes' |
|
assert_line '-2 (+0/-2) unstaged.txt LOC:1' "$actual" 'unstaged counts differ' |
|
assert_line '+1 (+1/-0) staged.txt LOC:3' "$actual" 'staged counts differ' |
|
assert_line '+2 (+2/-0) untracked.txt LOC:2' "$actual" 'untracked counts differ' |
|
assert_line 'GRAND TOTAL +1 (+3/-2) GROWING' "$actual" 'combined grand total differs' |
|
pass |
|
|
|
begin_test 'special filenames, empty files, and binary exclusion' |
|
repo=$(new_repo) |
|
printf 'space\n' >"$repo/a file.txt" |
|
printf 'dash\n' >"$repo/-leading.txt" |
|
printf 'tab\n' >"$repo/tab name.txt" |
|
printf 'newline\n' >"$repo/newline |
|
name.txt" |
|
: >"$repo/empty file.txt" |
|
printf '\000\001\002' >"$repo/binary file.bin" |
|
actual=$(cd "$repo" && "$GIT_LOC" untracked) |
|
assert_line 'TOTAL +4 (+4/-0) GROWING' "$actual" 'special-name total differs' |
|
binary_count=$(printf '%s\n' "$actual" | grep -c '^BINARY ' || :) |
|
assert_equal '1' "$binary_count" 'binary file was not reported exactly once' |
|
numeric_count=$(printf '%s\n' "$actual" | grep -c '^+1 (+1/-0) .* LOC:1$' || :) |
|
assert_equal '4' "$numeric_count" 'special text files or LOC counts differ' |
|
zero_count=$(printf '%s\n' "$actual" | grep -c '^0 (+0/-0) .* LOC:0$' || :) |
|
assert_equal '1' "$zero_count" 'empty file was not counted as zero' |
|
all_output=$(cd "$repo" && "$GIT_LOC" all) |
|
assert_line 'GRAND TOTAL +4 (+4/-0) GROWING' "$all_output" \ |
|
'binary or empty file incorrectly affected the grand total' |
|
pass |
|
|
|
begin_test 'current LOC thresholds, final non-newline, and symlink safety' |
|
repo=$(new_repo) |
|
make_lines 499 "$repo/loc499.txt" |
|
make_lines 500 "$repo/loc500.txt" |
|
make_lines 999 "$repo/loc999.txt" |
|
make_lines 1000 "$repo/loc1000.txt" |
|
printf 'first\nsecond' >"$repo/final-no-newline.txt" |
|
ln -s loc1000.txt "$repo/linked.txt" |
|
actual=$(cd "$repo" && "$GIT_LOC" untracked) |
|
assert_no_ansi "$actual" 'plain threshold output contained ANSI escapes' |
|
assert_line '+499 (+499/-0) loc499.txt LOC:499' "$actual" 'LOC 499 output differs' |
|
assert_line '+500 (+500/-0) loc500.txt LOC:500' "$actual" 'LOC 500 output differs' |
|
assert_line '+999 (+999/-0) loc999.txt LOC:999' "$actual" 'LOC 999 output differs' |
|
assert_line '+1000 (+1000/-0) loc1000.txt LOC:1000' "$actual" 'LOC 1000 output differs' |
|
assert_line '+2 (+2/-0) final-no-newline.txt LOC:2' "$actual" \ |
|
'unterminated final line was not counted' |
|
assert_line '+1 (+1/-0) linked.txt LOC:0' "$actual" \ |
|
'symlink target was followed while counting LOC' |
|
pass |
|
|
|
begin_test 'caller-relative pathspec and invalid mode failure' |
|
repo=$(new_repo) |
|
mkdir "$repo/sub" |
|
printf 'old\n' >"$repo/sub/tracked.txt" |
|
printf 'outside\n' >"$repo/outside.txt" |
|
commit_all "$repo" |
|
printf 'new\n' >"$repo/sub/tracked.txt" |
|
printf 'changed\n' >"$repo/outside.txt" |
|
printf 'first\nsecond' >"$repo/sub/untracked.txt" |
|
printf 'outside untracked\n' >"$repo/outside-untracked.txt" |
|
actual=$(cd "$repo" && GIT_PREFIX='sub/' "$GIT_LOC" diff tracked.txt) |
|
expected='0 (+1/-1) sub/tracked.txt LOC:1 |
|
TOTAL 0 (+1/-1) UNCHANGED' |
|
assert_equal "$expected" "$actual" 'caller-relative pathspec selected the wrong tracked files' |
|
actual=$(cd "$repo" && GIT_PREFIX='sub/' "$GIT_LOC" untracked -- untracked.txt) |
|
expected='+2 (+2/-0) untracked.txt LOC:2 |
|
TOTAL +2 (+2/-0) GROWING' |
|
assert_equal "$expected" "$actual" \ |
|
'caller-relative untracked pathspec used the wrong LOC path or selected extra files' |
|
actual=$(cd "$repo" && GIT_PREFIX='sub/' "$GIT_LOC" all -- untracked.txt) |
|
assert_line '+2 (+2/-0) untracked.txt LOC:2' "$actual" \ |
|
'all mode used the wrong LOC path for caller-relative untracked selection' |
|
assert_line 'GRAND TOTAL +2 (+2/-0) GROWING' "$actual" \ |
|
'all mode caller-relative grand total differs' |
|
if (cd "$repo" && "$GIT_LOC" invalid >/dev/null 2>&1); then |
|
fail "$TEST_NAME: invalid mode unexpectedly succeeded" |
|
fi |
|
pass |
|
|
|
begin_test 'TTY colors for nets, splits, filenames, and LOC thresholds' |
|
if ! command -v script >/dev/null 2>&1; then |
|
printf 'ok %d - %s # SKIP script utility unavailable\n' "$TEST_COUNT" "$TEST_NAME" |
|
else |
|
repo=$(new_repo) |
|
make_lines 499 "$repo/loc499.txt" |
|
make_lines 500 "$repo/loc500.txt" |
|
make_lines 999 "$repo/loc999.txt" |
|
make_lines 1000 "$repo/loc1000.txt" |
|
printf 's1\ns2\n' >"$repo/staged.txt" |
|
commit_all "$repo" |
|
replace_first_line "$repo/loc499.txt" |
|
replace_first_line "$repo/loc500.txt" |
|
replace_first_line "$repo/loc999.txt" |
|
replace_first_line "$repo/loc1000.txt" |
|
printf 's1\n' >"$repo/staged.txt" |
|
git -C "$repo" add staged.txt |
|
printf 'n1\nn2\n' >"$repo/untracked.txt" |
|
: >"$repo/empty.txt" |
|
printf '\000\001\002' >"$repo/binary file.bin" |
|
|
|
tty_capture=$TEST_ROOT/tty-$TEST_COUNT |
|
run_tty_all "$repo" "$tty_capture" |
|
actual=$(tr -d '\r' <"$tty_capture") |
|
|
|
escape=$(printf '\033') |
|
green=${escape}'[32m' |
|
red=${escape}'[31m' |
|
amber=${escape}'[38;5;214m' |
|
reset=${escape}'[0m' |
|
|
|
assert_contains \ |
|
"0 (${green}+1${reset}/${red}-1${reset}) ${amber}loc499.txt${reset} LOC:${green}499${reset}" \ |
|
"$actual" 'LOC 499 color or zero net differs' |
|
assert_contains \ |
|
"0 (${green}+1${reset}/${red}-1${reset}) ${amber}loc500.txt${reset} LOC:${amber}500${reset}" \ |
|
"$actual" 'LOC 500 color differs' |
|
assert_contains \ |
|
"0 (${green}+1${reset}/${red}-1${reset}) ${amber}loc999.txt${reset} LOC:${amber}999${reset}" \ |
|
"$actual" 'LOC 999 color differs' |
|
assert_contains \ |
|
"0 (${green}+1${reset}/${red}-1${reset}) ${amber}loc1000.txt${reset} LOC:${red}1000${reset}" \ |
|
"$actual" 'LOC 1000 color differs' |
|
assert_contains \ |
|
"${red}-1${reset} (${green}+0${reset}/${red}-1${reset}) ${green}staged.txt${reset} LOC:${green}1${reset}" \ |
|
"$actual" 'negative net or cached filename color differs' |
|
assert_contains \ |
|
"${green}+2${reset} (${green}+2${reset}/${red}-0${reset}) ${red}untracked.txt${reset} LOC:${green}2${reset}" \ |
|
"$actual" 'positive net or untracked filename color differs' |
|
assert_contains \ |
|
"0 (${green}+0${reset}/${red}-0${reset}) ${red}empty.txt${reset} LOC:${red}0${reset}" \ |
|
"$actual" 'empty-file LOC zero was not red' |
|
assert_contains "BINARY ${red}binary file.bin${reset}" "$actual" \ |
|
'binary filename color differs' |
|
assert_contains \ |
|
"TOTAL 0 (${green}+4${reset}/${red}-4${reset}) UNCHANGED" \ |
|
"$actual" 'section total component colors differ' |
|
assert_contains \ |
|
"GRAND TOTAL ${green}+1${reset} (${green}+6${reset}/${red}-5${reset}) GROWING" \ |
|
"$actual" 'grand total colors differ' |
|
|
|
plain_capture=$TEST_ROOT/plain-$TEST_COUNT |
|
(cd "$repo" && "$GIT_LOC" all >"$plain_capture") |
|
plain_output=$(cat "$plain_capture") |
|
assert_no_ansi "$plain_output" 'redirected output contained ANSI escapes' |
|
assert_line '0 (+1/-1) loc500.txt LOC:500' "$plain_output" \ |
|
'redirected plain file output differs' |
|
assert_line 'GRAND TOTAL +1 (+6/-5) GROWING' "$plain_output" \ |
|
'redirected plain grand total differs' |
|
pass |
|
fi |