From 174b313c5ea475ff0baadf409f226d3e7b65738a Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Sat, 23 May 2026 20:54:36 +0300 Subject: test: add unit tests for REPL subsystems Add dedicated unit tests for four REPL components that lacked test coverage: - SignalHandler (signal_test.go): 5 tests covering constructor, Stop() without Start, callback execution, goroutine semantics, and single-shot signal handling behavior - TTYChecker (tty_test.go): 5 tests covering EnsureTTY error in non-TTY context, error message content, IsTTY return value, IsTTY/EnsureTTY consistency, and idempotent behavior - HistoryManager (history_test.go): 11 tests covering constructor, Path() with default and custom baseDir, Save/Load roundtrip, maxEntries truncation, non-existent file, empty file/slice, special characters, and file overwrite behavior. Added WithBaseDir() method to enable testing with temp directories. - AutoCompleteAdapter (completer_adapter_test.go): 5 tests covering Do() with empty/whitespace input, exact/partial/no matches, case-insensitive matching, multi-word completion, cursor position, common prefix calculation, and command order preservation --- internal/repl/tty_test.go | 70 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 internal/repl/tty_test.go (limited to 'internal/repl/tty_test.go') diff --git a/internal/repl/tty_test.go b/internal/repl/tty_test.go new file mode 100644 index 0000000..3f04860 --- /dev/null +++ b/internal/repl/tty_test.go @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2026 Paul Buetow + +package repl + +import ( + "strings" + "testing" +) + +func TestTTYCheckerEnsureTTYNotATerminal(t *testing.T) { + // In test context, stdin is never a terminal + checker := &TTYChecker{} + err := checker.EnsureTTY() + if err == nil { + t.Error("EnsureTTY should return an error when stdin is not a TTY") + } +} + +func TestTTYCheckerEnsureTTYErrorMessage(t *testing.T) { + checker := &TTYChecker{} + err := checker.EnsureTTY() + if err == nil { + t.Skip("stdin appears to be a TTY; skipping error message check") + } + if !strings.Contains(err.Error(), "TTY") { + t.Errorf("error message should mention TTY, got: %q", err.Error()) + } +} + +func TestTTYCheckerIsTTYReturnsFalseInTests(t *testing.T) { + // In test context, stdin is not a terminal + checker := &TTYChecker{} + if checker.IsTTY() { + t.Skip("stdin appears to be a TTY (e.g., interactive terminal); skipping") + } + // Good — IsTTY correctly returned false +} + +func TestTTYCheckerIsTTYConsistentWithEnsureTTY(t *testing.T) { + checker := &TTYChecker{} + isTTY := checker.IsTTY() + err := checker.EnsureTTY() + + if isTTY && err != nil { + t.Error("IsTTY returned true but EnsureTTY returned an error") + } + if !isTTY && err == nil { + t.Error("IsTTY returned false but EnsureTTY returned nil") + } +} + +func TestTTYCheckerMultipleCalls(t *testing.T) { + checker := &TTYChecker{} + // Multiple calls should be consistent + result1 := checker.IsTTY() + result2 := checker.IsTTY() + if result1 != result2 { + t.Errorf("IsTTY returned inconsistent results: %v, %v", result1, result2) + } + + err1 := checker.EnsureTTY() + err2 := checker.EnsureTTY() + // Both errors should be the same type (both nil or both non-nil) + bothNil := err1 == nil && err2 == nil + bothNonNil := err1 != nil && err2 != nil + if !bothNil && !bothNonNil { + t.Errorf("EnsureTTY returned inconsistent results: %v, %v", err1, err2) + } +} -- cgit v1.2.3