From 7ac92afb130aa5a1a620b31a38fd986b98d908c2 Mon Sep 17 00:00:00 2001 From: marksverdhei Date: Sat, 27 Jun 2026 18:02:35 +0200 Subject: [PATCH] fix(cf): register no longer crashes on the first name collision under set -e MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `cf register`'s retry loop used `((attempts++))`. Post-increment evaluates to the *old* value, so on the first iteration it yields 0 — which bash reports as exit status 1. Combined with the script's `set -e`, that aborted `cf register` entirely the moment a generated name collided with an existing one, instead of retrying. Replace it with `attempts=$((attempts + 1))` (an assignment always returns success), and add a guard so exhausting all 100 attempts errors out rather than silently registering a duplicate name. Adds a regression test (`test_register_survives_name_collisions`) that fills a chunk of the name space so collisions are frequent and registers 30×; it fails against the old `((attempts++))` and passes with the fix. Suite: 40/40. Salvaged from the superseded #1 (which can't merge — it predates the global-room rework and would revert main's CI + presentation tests). Co-Authored-By: Claude Opus 4.8 --- cf | 11 ++++++++++- test_cf.sh | 25 +++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/cf b/cf index a84a95d..c6f36a9 100755 --- a/cf +++ b/cf @@ -184,9 +184,18 @@ case "$CMD" in suffix=$((RANDOM % 9000 + 1000)) MYNAME="${adj}-${noun}-${suffix}" grep -q "^${MYNAME}:" "$CHATFILE" 2>/dev/null || break - ((attempts++)) + # NB: `((attempts++))` evaluates to the *old* value, so on the first + # iteration it yields 0 — which bash reports as exit status 1, and + # under `set -e` (above) that aborted the whole script on the very + # first name collision. An assignment always returns success. + attempts=$((attempts + 1)) done + if [ "$attempts" -ge 100 ]; then + echo "Failed to generate a unique name after 100 attempts" >&2 + exit 1 + fi + JOINED="" # Global rooms get a HOME-level session so any working directory can find it. # Local rooms get a CWD-level session (directory-scoped). diff --git a/test_cf.sh b/test_cf.sh index f1214f8..3a7e24d 100755 --- a/test_cf.sh +++ b/test_cf.sh @@ -489,6 +489,30 @@ test_help_flag() { # Edge Case Tests # ============================================================================ +test_register_survives_name_collisions() { + # Regression: `cf register`'s retry loop used `((attempts++))`, which under + # `set -e` aborts the whole script on the FIRST name collision (((0++)) + # yields exit status 1). Fill a chunk of the name space so RANDOM collides + # often, then register many times — every one must still succeed. + setup + "$CF_PATH" create-room 2>/dev/null || true + awk 'BEGIN{ + split("swift bold calm keen sage wild bright dark quick slow", a, " "); + split("fox owl raven wolf bear hawk crane lynx deer hare", n, " "); + for (i=1;i<=10;i++) for (j=1;j<=10;j++) for (s=1000;s<2800;s++) + printf "%s-%s-%d: taken\n", a[i], n[j], s + }' >> Chatfile + + local rc=0 i name + for i in $(seq 1 30); do + rm -f .cf_session + name=$("$CF_PATH" register Chatfile 2>/dev/null) || { rc=1; break; } + [ -n "$name" ] || { rc=1; break; } + done + teardown + return $rc +} + test_username_uniqueness() { setup "$CF_PATH" create-room 2>/dev/null || true @@ -658,6 +682,7 @@ run_test "help flag" test_help_flag echo "" echo "Edge Case Tests:" +run_test "register survives name collisions (set -e)" test_register_survives_name_collisions run_test "username uniqueness" test_username_uniqueness run_test "special characters in message" test_special_characters_in_message run_test "multiline preserved" test_multiline_preserved