From af7bbb7354f9fc79180193ba397dae91ea89af59 Mon Sep 17 00:00:00 2001 From: marksverdhei Date: Sat, 27 Jun 2026 19:08:16 +0200 Subject: [PATCH] fix(cf): collapse newlines in send/send-await (preserve one-line invariant) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `cf send "$msg"` wrote the arg verbatim, so a message containing a newline landed as two physical lines. The chatroom is line-oriented ("Format: Name: msg") and `await` derives the sender via `tail -n 1 | cut -d: -f1`, so the wrapped second line — which has no "Name:" prefix — gets parsed as a phantom message from a sender named after the text. Collapse newlines to spaces in both `send` and `send-await`. Adds `test_send_collapses_newlines` (a 2-line message must add exactly one physical line, prefixed by the sender). Fails against the old code, passes with the fix; suite 41/41. Second of the follow-ups noted when #1 was closed as superseded. Co-Authored-By: Claude Opus 4.8 --- cf | 7 +++++-- test_cf.sh | 23 +++++++++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/cf b/cf index c6f36a9..dfd08aa 100755 --- a/cf +++ b/cf @@ -230,7 +230,10 @@ case "$CMD" in [ -z "$1" ] && { echo "Usage: cf send \"message\"" >&2; exit 1; } load_session [ -z "$JOINED" ] && { echo "Must join first: cf join" >&2; exit 1; } - printf '%s: %s\n' "$MYNAME" "$1" >> "$CHATFILE" + # Collapse newlines so one send stays one line — the "Name: msg" invariant + # that read/await depend on. A literal newline would otherwise land as a + # prefix-less second line that await parses as a phantom sender. + printf '%s: %s\n' "$MYNAME" "${1//$'\n'/ }" >> "$CHATFILE" ;; await|a|wait|w) @@ -248,7 +251,7 @@ case "$CMD" in [ -z "$1" ] && { echo "Usage: cf send-await \"message\"" >&2; exit 1; } load_session [ -z "$JOINED" ] && { echo "Must join first: cf join" >&2; exit 1; } - printf '%s: %s\n' "$MYNAME" "$1" >> "$CHATFILE" + printf '%s: %s\n' "$MYNAME" "${1//$'\n'/ }" >> "$CHATFILE" tail -f -n 0 "$CHATFILE" | head -n 1 ;; diff --git a/test_cf.sh b/test_cf.sh index 3a7e24d..4a96180 100755 --- a/test_cf.sh +++ b/test_cf.sh @@ -542,6 +542,28 @@ test_special_characters_in_message() { teardown } +test_send_collapses_newlines() { + # Regression: a multi-line `send` arg must stay one physical line, or + # read/await misparse the wrapped text as a phantom sender (it has no + # "Name:" prefix). Newlines collapse to spaces. + setup + "$CF_PATH" create-room 2>/dev/null || true + local name rc=0 before after last + name=$("$CF_PATH" register Chatfile) + "$CF_PATH" join >/dev/null + before=$(wc -l < Chatfile) + "$CF_PATH" send "line one +line two" + after=$(wc -l < Chatfile) + last=$(tail -n 1 Chatfile) + if [ "$((after - before))" -ne 1 ] || [ "$last" != "$name: line one line two" ]; then + echo " multi-line send not collapsed: +$((after - before)) line(s), last='$last'" >&2 + rc=1 + fi + teardown + return $rc +} + test_multiline_preserved() { setup "$CF_PATH" create-room 2>/dev/null || true @@ -685,6 +707,7 @@ 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 "send collapses newlines (one-line invariant)" test_send_collapses_newlines run_test "multiline preserved" test_multiline_preserved echo ""