diff --git a/tools/test-tools.sh b/tools/test-tools.sh index 7a5e4cb..fa0228b 100644 --- a/tools/test-tools.sh +++ b/tools/test-tools.sh @@ -238,11 +238,12 @@ seqf a 40 >"$R/a.txt"; seqf b 40 >"$R/b.txt"; seqf c 10 >"$R/c.txt"; seqf d 20 > seqf e 10 >"$R/e.txt"; seqf f 20 >"$R/f.txt"; seqf g 300 >"$R/big.txt"; seqf h 5 | sed 's/$/ /' >"$R/h.txt"; seqf m 40 >"$R/m.txt" printf 's1\ns2\ns3\ns4\ndef needle_three\ns6\ns7 needle_many\ns8\nfoo::bar\ns10\n' >"$R/sym.txt" printf 'needle_three call 1\nneedle_three call 2\nneedle_three call 3\nneedle_threefold is another word\n' >"$R/zcallers.txt" -echo 'bound_fifty bound_fiftyone spread_sym long_symbol q.zq sym_bad' >"$R/anchors.txt" +echo 'bound_fifty bound_fiftyone spread_sym long_symbol q.zq sym_bad twenty_sym' >"$R/anchors.txt" seqf "bound_fifty x" 50 >"$R/bound50.txt"; seqf "bound_fiftyone x" 51 >"$R/bound51.txt"; seqf "q.zq x" 51 >"$R/dotted.txt" printf 'long_symbol %s%s\r' "$(printf '%0150d' 0 | tr 0 z)" "$(printf '%0100d' 0 | tr 0 y)" >"$R/longline.txt"; printf '\n' >>"$R/longline.txt" -printf 'sym_bad \377 end\n' >"$R/bad.txt" +printf 'sym_bad \377 endX\r\n' >"$R/bad.txt" mkdir -p "$R/manyf"; for i in $(seq -w 1 21); do seqf "spread_sym $i-" 3 >"$R/manyf/f$i.txt"; done; echo "spread_sym extra" >>"$R/manyf/f21.txt" +mkdir -p "$R/twf"; for i in $(seq -w 1 20); do seqf "twenty_sym $i-" 3 >"$R/twf/f$i.txt"; done seqf "needle_many x." 30 >"$R/many1.txt"; seqf "needle_many y." 30 >"$R/many2.txt" g add -A; g commit -q -m base; BASE=$(git -C "$R" rev-parse HEAD) { sed -n 1,5p "$R/a.txt"; printf 'ins1\nins2\nins3\n'; sed -n '6,$p' "$R/a.txt"; } >"$R/a.new"; mv "$R/a.new" "$R/a.txt" @@ -395,8 +396,8 @@ r=$(cpo --spec-json "$(wp "$T/cp-spec-r0.json")"); cchk "a spec of one read, sym cin "a read with a symbol present: no suffix" "[r1] a.txt:20-22 MOVED(+3) -> a.txt:23-25 # w" # caller-list bounds: 50 hits list, 51 count; 20 files; a hit's text is cut at 160; CR and bad bytes { echo '{"base": "'$BASE'", "deletes": [], "file_changes": [' - n=0; for sy in bound_fifty bound_fiftyone spread_sym long_symbol q.zq sym_bad; do n=$((n+1)) - echo '{"change": "'$sy'", "location": {"path": "anchors.txt", "line": 1, "end_line": 1, "symbol": "'$sy'"}}'$([ $n -lt 6 ] && echo ,); done + n=0; for sy in bound_fifty bound_fiftyone spread_sym long_symbol q.zq sym_bad twenty_sym; do n=$((n+1)) + echo '{"change": "'$sy'", "location": {"path": "anchors.txt", "line": 1, "end_line": 1, "symbol": "'$sy'"}}'$([ $n -lt 7 ] && echo ,); done echo ']}'; } >"$T/cp-specb.json" r=$(cpo --spec-json "$(wp "$T/cp-specb.json")" --max-lines 400); cchk "caller list bounds" 0 "$r" cin "exactly 50 hits are listed" "CALLERS bound_fifty: 50 hits in 1 files" @@ -404,7 +405,10 @@ cin "exactly 50 hits are listed" "CALLERS bound_fifty: 50 hits in 1 files" cin "51 hits are counted" "CALLERS bound_fiftyone: 51 hits in 1 files" cin "51 hits: the per-file count" " 51 bound51.txt" cnot "51 hits print no hit lines" "bound51.txt:1:" -cin "21 files: the 21st is named" "(1 more files)" +grep -qx "(1 more files)" "$T/cp.out" && echo "ok context-pack 21 files: the 21st is named" || { echo "FAIL context-pack 21st file line"; fail=1; } +grep -qx "narrow: git grep -n -I -F -e q.zq -- " "$T/cp.out" && echo "ok context-pack the narrowing line is exact" || { echo "FAIL context-pack narrowing line"; fail=1; } +cin "exactly 20 files name no more" "CALLERS twenty_sym: 60 hits in 20 files" +[ "$(grep -c '(0 more files)' "$T/cp.out")" = 0 ] && echo "ok context-pack 20 files print no more-files line" || { echo "FAIL context-pack 20 files"; fail=1; } [ "$(grep -c '^ *[34] manyf/' "$T/cp.out")" = 20 ] && echo "ok context-pack at most 20 files are counted" || { echo "FAIL context-pack file cap: $(grep -c '^ *[34] manyf/' "$T/cp.out")"; fail=1; } cin "files are ranked by hits, largest first" " 4 manyf/f21.txt" [ "$(grep -n 'manyf/f21.txt' "$T/cp.out" | cut -d: -f1)" -lt "$(grep -n 'manyf/f01.txt' "$T/cp.out" | cut -d: -f1)" ] && echo "ok context-pack the largest file prints first" || { echo "FAIL context-pack file order"; fail=1; } @@ -412,6 +416,8 @@ cin "a non-identifier narrowing command has no -w" "narrow: git grep -n -I -F -e LL=$(grep '^longline.txt:1: ' "$T/cp.out"); [ "${#LL}" = 176 ] && echo "ok context-pack a hit's text is cut at 160 characters" || { echo "FAIL context-pack hit text length ${#LL}"; fail=1; } cnot "a CR in a hit is stripped" "$(printf '\r')" cin "a hit with invalid UTF-8 still prints" "bad.txt:1: sym_bad" +cin "a hit keeps a trailing X and loses its CR" "endX" +grep -qx "bad.txt:1: sym_bad .* endX" "$T/cp.out" && echo "ok context-pack a hit ends at its last character" || { echo "FAIL context-pack hit end"; fail=1; } r=$(cpo --spec-json "$SR" --only 5); cchk "--only past the last edit anchor" 2 "$r"; grep -qxF "context-pack: --only: index outside file_changes" "$T/cp.err" && echo "ok context-pack --only 5 is outside four anchors" || { echo "FAIL context-pack --only 5"; fail=1; } r=$(cpo --spec-json "$SR" --only 4); cchk "--only the last edit anchor" 3 "$r"; cin "--only 4 prints that window" "== [4] sym.txt:9-9" r=$(cpo --spec-json "$SR" --only r6); cchk "--only past the last read" 2 "$r"; grep -qxF "context-pack: --only: index outside reads" "$T/cp.err" && echo "ok context-pack --only r6 is outside five reads" || { echo "FAIL context-pack --only r6"; fail=1; } @@ -438,6 +444,24 @@ for b in $((FULLN-1)) $((FULLN-3)) $((FULLN-6)) $((FULLN-9)) $((FULLN-30)); do done r=$(cpo --spec-json "$S10" --max-lines $((FULLN-1))); [ "$(grep -c '^CALLERS' "$T/cp.out")" = 6 ] && echo "ok context-pack one line short drops two lists for the note" || { echo "FAIL context-pack one line short: $(grep -c '^CALLERS' "$T/cp.out") lists"; fail=1; } cin "the dropped lists are named" "callers not printed: g7,g8: --max-lines $FULLN" +# window budgets: the exact thresholds, and what the caller lists leave of them +r=$(cpo --spec-json "$S1" --max-lines 104); cnot "104 lines expand no 100-line window" "== ["; cin "104 lines skip a 100-line window" "not expanded: --only 1" +r=$(cpo --spec-json "$S1" --max-lines 105); [ "$(wc -l <"$T/cp.out" | tr -d ' ')" = 105 ] && grep -qx "56 more lines: --only 1 --max-lines 160" "$T/cp.out" && echo "ok context-pack 105 lines hold a capped window and its note" || { echo "FAIL context-pack 105-line budget"; fail=1; } +S30=$(wp "$T/cp-spec30.json") +r=$(cpo --spec-json "$S30" --max-lines 186); [ "$(grep -c '^== ' "$T/cp.out")" = 9 ] && [ "$(wc -l <"$T/cp.out" | tr -d ' ')" = 186 ] && echo "ok context-pack 186 lines hold 9 windows and the note" || { echo "FAIL context-pack 186-line budget"; fail=1; } +r=$(cpo --spec-json "$S30" --max-lines 185); [ "$(grep -c '^== ' "$T/cp.out")" = 8 ] && echo "ok context-pack 185 lines hold 8 windows" || { echo "FAIL context-pack 185-line budget"; fail=1; } +r=$(cpo --spec-json "$S30" --max-lines 542); [ "$(grep -c '^== ' "$T/cp.out")" = 30 ] && echo "ok context-pack 542 lines hold all 30 windows" || { echo "FAIL context-pack 542-line budget"; fail=1; }; cnot "542 lines need no not-expanded note" "not expanded" +for b in 530 531 532 533 534 535 536 537 538 539 540 541; do + r=$(cpo --spec-json "$S30" --max-lines $b); [ "$(wc -l <"$T/cp.out" | tr -d ' ')" -le $b ] && grep -q '^not expanded: --only 30$' "$T/cp.out" && echo "ok context-pack budget $b skips only the last window" || { echo "FAIL context-pack budget $b: $(wc -l <"$T/cp.out") lines"; fail=1; } +done +for b in 37 38 39 40 41 42 43 44 45 46 47; do + r=$(cpo --spec-json "$S30" --only 1,2 --max-lines $b); [ "$(wc -l <"$T/cp.out" | tr -d ' ')" = $b ] && [ "$(grep -c '^== ' "$T/cp.out")" = 1 ] && grep -q 'more lines: --only 1 ' "$T/cp.out" && echo "ok context-pack --only 1,2 at $b lines truncates window 1 to fit" || { echo "FAIL context-pack --only 1,2 at $b: $(wc -l <"$T/cp.out") lines"; fail=1; } +done +r=$(cpo --spec-json "$S30" --only 1,2 --max-lines 36); cnot "--only 1,2 at 36 lines expands nothing" "== [" +r=$(cpo --spec-json "$S10" --max-lines 94); [ "$(wc -l <"$T/cp.out" | tr -d ' ')" = 94 ] && [ "$(grep -c '^== ' "$T/cp.out")" = 10 ] && [ "$(grep -c '^CALLERS' "$T/cp.out")" = 6 ] && echo "ok context-pack one line short keeps every window and 6 lists" || { echo "FAIL context-pack 94-line S10"; fail=1; } +r=$(cpo --spec-json "$S10" --max-lines 86); [ "$(wc -l <"$T/cp.out" | tr -d ' ')" = 86 ] && [ "$(grep -c '^== ' "$T/cp.out")" = 9 ] && [ "$(grep -c '^CALLERS' "$T/cp.out")" = 5 ] && echo "ok context-pack 86 lines: 9 windows, 5 lists, every note" || { echo "FAIL context-pack 86-line S10"; fail=1; } +r=$(cpo --spec-json "$S10" --max-lines 65); [ "$(grep -c '^== ' "$T/cp.out")" = 7 ] && [ "$(grep -c '^CALLERS' "$T/cp.out")" = 0 ] && grep -q '^callers not printed: ' "$T/cp.out" && grep -q '^callers not listed: g9,g10' "$T/cp.out" && echo "ok context-pack windows outrank caller lists" || { echo "FAIL context-pack 65-line S10"; fail=1; } +r=$(cpo --spec-json "$SR" --max-lines 62); [ "$(wc -l <"$T/cp.out" | tr -d ' ')" = 61 ] && [ "$(grep -c '^CALLERS' "$T/cp.out")" = 4 ] && echo "ok context-pack 62 lines: a list that needs 2 lines waits" || { echo "FAIL context-pack 62-line SR"; fail=1; } # usage and unreadable spec; no error echoes an input value r=$(cpo --spec-json "$SP" --max-lines CANARY-usage); cchk "bad --max-lines" 2 "$r"; cnot "usage error echoes no value" "CANARY-usage" r=$(cpo --spec-json "$T/CANARY-nofile.json"); cchk "unreadable --spec-json" 4 "$r"; grep -qF "context-pack: --spec-json: unreadable; --spec-json reads a saved view" "$T/cp.err" && echo "ok context-pack names the unreadable --spec-json" || { echo "FAIL context-pack names the unreadable --spec-json"; fail=1; }; cnot "unreadable --spec-json echoes no path" "CANARY-nofile"