go/pkg/cli/stream_test.go
Claude 228170d610
feat(cli): TUI components, Frame AppShell, command builders (#11-15)
Issues #11-13: WithAppName for variant binaries, NewPassthrough builder
for flag.FlagSet commands, RegisterCommands test coverage with resetGlobals
helper. Fix pre-existing daemon_test.go break.

Issue #14: Rich Table with box-drawing borders (Normal, Rounded, Heavy,
Double), per-column CellStyleFn, WithMaxWidth responsive truncation.
Tree renderer with box-drawing connectors and styled nodes. Parallel
TaskTracker with braille spinners, thread-safe concurrent updates, and
non-TTY fallback. Streaming text renderer with word-wrap and channel
pattern support.

Issue #15: Frame live compositional AppShell using HLCRF regions with
Model interface, Navigate/Back content swapping, alt-screen live mode,
graceful non-TTY fallback. Built-in region components: StatusLine,
KeyHints, Breadcrumb. Zero new dependencies — pure ANSI + x/term.

68 tests, all passing with -race.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 19:45:23 +00:00

159 lines
3.4 KiB
Go

package cli
import (
"bytes"
"strings"
"testing"
"github.com/stretchr/testify/assert"
)
func TestStream_Good(t *testing.T) {
t.Run("basic write", func(t *testing.T) {
var buf bytes.Buffer
s := NewStream(WithStreamOutput(&buf))
s.Write("hello ")
s.Write("world")
s.Done()
s.Wait()
assert.Equal(t, "hello world\n", buf.String())
})
t.Run("write with newlines", func(t *testing.T) {
var buf bytes.Buffer
s := NewStream(WithStreamOutput(&buf))
s.Write("line1\nline2\n")
s.Done()
s.Wait()
assert.Equal(t, "line1\nline2\n", buf.String())
})
t.Run("word wrap", func(t *testing.T) {
var buf bytes.Buffer
s := NewStream(WithWordWrap(10), WithStreamOutput(&buf))
s.Write("1234567890ABCDE")
s.Done()
s.Wait()
lines := strings.Split(strings.TrimRight(buf.String(), "\n"), "\n")
assert.Equal(t, 2, len(lines))
assert.Equal(t, "1234567890", lines[0])
assert.Equal(t, "ABCDE", lines[1])
})
t.Run("word wrap preserves explicit newlines", func(t *testing.T) {
var buf bytes.Buffer
s := NewStream(WithWordWrap(20), WithStreamOutput(&buf))
s.Write("short\nanother")
s.Done()
s.Wait()
lines := strings.Split(strings.TrimRight(buf.String(), "\n"), "\n")
assert.Equal(t, 2, len(lines))
assert.Equal(t, "short", lines[0])
assert.Equal(t, "another", lines[1])
})
t.Run("word wrap resets column on newline", func(t *testing.T) {
var buf bytes.Buffer
s := NewStream(WithWordWrap(5), WithStreamOutput(&buf))
s.Write("12345\n67890ABCDE")
s.Done()
s.Wait()
lines := strings.Split(strings.TrimRight(buf.String(), "\n"), "\n")
assert.Equal(t, 3, len(lines))
assert.Equal(t, "12345", lines[0])
assert.Equal(t, "67890", lines[1])
assert.Equal(t, "ABCDE", lines[2])
})
t.Run("no wrap when disabled", func(t *testing.T) {
var buf bytes.Buffer
s := NewStream(WithStreamOutput(&buf))
s.Write(strings.Repeat("x", 200))
s.Done()
s.Wait()
lines := strings.Split(strings.TrimRight(buf.String(), "\n"), "\n")
assert.Equal(t, 1, len(lines))
assert.Equal(t, 200, len(lines[0]))
})
t.Run("column tracking", func(t *testing.T) {
var buf bytes.Buffer
s := NewStream(WithStreamOutput(&buf))
s.Write("hello")
assert.Equal(t, 5, s.Column())
s.Write(" world")
assert.Equal(t, 11, s.Column())
})
t.Run("WriteFrom io.Reader", func(t *testing.T) {
var buf bytes.Buffer
s := NewStream(WithStreamOutput(&buf))
r := strings.NewReader("streamed content")
err := s.WriteFrom(r)
assert.NoError(t, err)
s.Done()
s.Wait()
assert.Equal(t, "streamed content\n", buf.String())
})
t.Run("channel pattern", func(t *testing.T) {
var buf bytes.Buffer
s := NewStream(WithStreamOutput(&buf))
tokens := make(chan string, 3)
tokens <- "one "
tokens <- "two "
tokens <- "three"
close(tokens)
go func() {
for tok := range tokens {
s.Write(tok)
}
s.Done()
}()
s.Wait()
assert.Equal(t, "one two three\n", buf.String())
})
t.Run("Done adds trailing newline only if needed", func(t *testing.T) {
var buf bytes.Buffer
s := NewStream(WithStreamOutput(&buf))
s.Write("text\n") // ends with newline, col=0
s.Done()
s.Wait()
assert.Equal(t, "text\n", buf.String()) // no double newline
})
}
func TestStream_Bad(t *testing.T) {
t.Run("empty stream", func(t *testing.T) {
var buf bytes.Buffer
s := NewStream(WithStreamOutput(&buf))
s.Done()
s.Wait()
assert.Equal(t, "", buf.String())
})
}