The measured ladder tried every single-line variant before considering a second line, so whenever line one plus the full group did not fit — from around 92 usable columns upwards, depending on how long the branch, cwd and model names are — it emitted rl_bare (5h and 7d only) and silently dropped the per-model (Fable) bar that is the main reason the group is worth rendering. On a 110-column laptop the limit was invisible. Reorder so a second line beats losing that bar: one line rich/mid/lean, then wrap, and rl_bare only when WRAP_NARROW is false. Reset times and extra-usage credits are still given up rather than wrapped for, which makes the rendered content non-monotone in width; the comment on the ladder spells that out. Also stop the tests writing fixtures to the caches the live status line reads. ~/.claude/statusline.sh is a symlink to the script, so a test run was visibly rendering fabricated usage — a Fable bar at 10%, extra-usage credits of $1234.56/$2000.00 — in whatever session happened to be open, and a run killed before its trap fired would have left that in place for an hour. The cache directory is now $STATUSLINE_CACHE_DIR (default /tmp/claude) and each suite points it at a temporary directory, which also removes the backup/restore dance and the deletion of the live git-status cache. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
90 lines
4.4 KiB
Shell
Executable file
90 lines
4.4 KiB
Shell
Executable file
#!/bin/bash
|
|
# Tests for claude/statusline.isaacaudet.sh — the Isaac Audet-inspired Claude
|
|
# Code status line (the variant symlinked from ~/.claude/statusline.sh).
|
|
#
|
|
# Sibling variants in claude/ (statusline.burnrate.sh, statusline.original.sh)
|
|
# are NOT covered by these tests.
|
|
#
|
|
# Width invariants.
|
|
#
|
|
# Expressed in USABLE width (what the renderer actually has: COLUMNS minus
|
|
# padding on both sides minus a margin), since that is what the script wraps on.
|
|
# Asserting invariants rather than fixed line counts keeps these from rotting
|
|
# every time a segment's content changes.
|
|
SCRIPT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)/statusline.isaacaudet.sh"
|
|
PAD=$(jq -r '.statusLine.padding // 0' "$HOME/.claude/settings.json" 2>/dev/null || echo 0)
|
|
OVERHEAD=$(( 2 * PAD + 1 ))
|
|
# Throwaway cache directory, so fixtures never reach the live status line's
|
|
# cache (~/.claude/statusline.sh is a symlink to the script under test).
|
|
export STATUSLINE_CACHE_DIR=$(mktemp -d)
|
|
CACHE="$STATUSLINE_CACHE_DIR/statusline-usage-cache.json"
|
|
REPO=$(mktemp -d)
|
|
cleanup() { rm -rf "$STATUSLINE_CACHE_DIR" "$REPO"; }
|
|
trap cleanup EXIT
|
|
|
|
cat > "$CACHE" <<'JSON'
|
|
{"five_hour":{"utilization":5.0,"resets_at":"2026-08-27T15:40:00+00:00"},
|
|
"seven_day":{"utilization":7.0,"resets_at":"2026-08-28T02:00:00+00:00"},
|
|
"extra_usage":{"is_enabled":false},
|
|
"limits":[{"kind":"weekly_scoped","group":"weekly","percent":10,"resets_at":"2026-08-28T02:00:00+00:00","scope":{"model":{"display_name":"Fable"}},"is_active":true}]}
|
|
JSON
|
|
git -C "$REPO" init -q 2>/dev/null
|
|
git -C "$REPO" -c user.email=t@t -c user.name=t commit -q --allow-empty -m init 2>/dev/null
|
|
|
|
widths() { python3 -c "
|
|
import sys,re,unicodedata
|
|
for ln in sys.stdin.read().rstrip('\n').split('\n'):
|
|
p=re.sub(r'\033\[[0-9;]*m','',ln)
|
|
print(sum(2 if unicodedata.east_asian_width(c) in 'WF' else 1 for c in p))"; }
|
|
|
|
pass=0; fail=0
|
|
check() { # usable, branch, model, cost, [xfail-reason]
|
|
local u="$1" branch="$2" model="$3" cost="$4" xfail="${5:-}"
|
|
local w=$(( u + OVERHEAD ))
|
|
git -C "$REPO" checkout -q -B "$branch" 2>/dev/null; rm -f "$STATUSLINE_CACHE_DIR"/git-*
|
|
local stdin="{\"model\":{\"display_name\":\"$model\"},\"cwd\":\"$REPO\",\"cost\":{\"total_cost_usd\":$cost},\"context_window\":{\"context_window_size\":200000,\"current_usage\":{\"input_tokens\":45000,\"cache_read_input_tokens\":30000}}}"
|
|
local out ws n mx=0 over=0
|
|
out=$(TERM_WIDTH=$w bash "$SCRIPT" <<<"$stdin")
|
|
ws=$(printf '%s' "$out" | widths)
|
|
n=$(printf '%s\n' "$ws" | wc -l | tr -d ' ')
|
|
while read -r c; do [ "$c" -gt "$u" ] && over=1; [ "$c" -gt "$mx" ] && mx=$c; done <<< "$ws"
|
|
|
|
local why=""
|
|
# INVARIANT 1: never exceed the usable width
|
|
[ "$over" = "1" ] && why="line exceeds usable width"
|
|
# INVARIANT 2: at most two lines
|
|
[ "$n" -gt 2 ] && why="${why:-more than two lines}"
|
|
# INVARIANT 3: only wrap when it was actually necessary
|
|
if [ -z "$why" ] && [ "$n" = "2" ]; then
|
|
local l1 l2; l1=$(printf '%s\n' "$ws" | sed -n 1p); l2=$(printf '%s\n' "$ws" | sed -n 2p)
|
|
[ $(( l1 + 3 + l2 )) -le "$u" ] && why="wrapped unnecessarily (would have fit on one line)"
|
|
fi
|
|
|
|
local label="usable=$u branch=${#branch}ch model='${model:0:12}' lines=$n max=$mx"
|
|
if [ -n "$xfail" ] && [ -n "$why" ]; then
|
|
echo " XFAIL $label -- $why (known, pre-existing: $xfail)"; pass=$((pass+1)); return
|
|
fi
|
|
if [ -z "$why" ]; then echo " PASS $label"; pass=$((pass+1))
|
|
else echo " FAIL $label -- $why"
|
|
printf '%s\n' "$out" | sed $'s/\033\[[0-9;]*m//g' | sed 's/^/ /'; fail=$((fail+1)); fi
|
|
}
|
|
|
|
SHORT=main
|
|
LONG=feature/some-really-long-branch-name-here
|
|
M1="Opus 5"
|
|
M2="Opus 5 (1M context)"
|
|
|
|
echo "Sweep of usable widths, short branch:"
|
|
for u in 200 155 150 130 116 110 100 95 85 75 68 67 60 40; do check "$u" "$SHORT" "$M1" 0.50; done
|
|
# Narrow tier has a ~35-col floor; nothing can fit below that. Verified byte-identical
|
|
# on the pre-change script, so not a regression.
|
|
check 25 "$SHORT" "$M1" 0.50 "narrow tier floor ~35 cols"
|
|
echo "Sweep with the real long model name:"
|
|
for u in 200 150 116 100 85 68 40; do check "$u" "$SHORT" "$M2" 4.61; done
|
|
echo "Sweep with a long branch name:"
|
|
for u in 200 150 116 100 85 68; do check "$u" "$LONG" "$M2" 4.61; done
|
|
check 40 "$LONG" "$M2" 4.61 "narrow tier floor ~43 cols with a long branch"
|
|
echo "Large cost figure:"
|
|
for u in 116 85 68; do check "$u" "$SHORT" "$M1" 1234.56; done
|
|
|
|
echo; echo "pass=$pass fail=$fail"; [ "$fail" -eq 0 ]
|