first commit
This commit is contained in:
@@ -0,0 +1,164 @@
|
||||
package tui
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/smallnest/pigo/internal/agentcore"
|
||||
"github.com/smallnest/pigo/internal/cli/ui"
|
||||
)
|
||||
|
||||
// newTestStatusBar builds a status bar with a known cwd (already ~-abbreviated
|
||||
// by the caller's intent) so tests do not depend on the real $HOME.
|
||||
func newTestStatusBar() statusBar {
|
||||
opts := Options{Model: "claude-opus", ThinkingLevel: agentcore.ThinkingHigh}
|
||||
s := newStatusBar(DefaultTheme(), opts, "/tmp/project")
|
||||
s.cwd = "~/project"
|
||||
return s
|
||||
}
|
||||
|
||||
func TestStatusBarRendersAllFields(t *testing.T) {
|
||||
s := newTestStatusBar()
|
||||
s.SetGit(gitInfoMsg{branch: "master", dirty: 3, ahead: 4, ok: true})
|
||||
s.SetTelemetry(telemetryEventView{util: 0.42, window: 200000})
|
||||
s.SetTask("running: Read")
|
||||
|
||||
const width = 200
|
||||
out := s.Render(width)
|
||||
|
||||
for _, want := range []string{
|
||||
"pigo", // app badge
|
||||
"claude-opus", // model
|
||||
"high", // thinking level
|
||||
"~/project", // cwd
|
||||
"master", // git branch
|
||||
glyphDirty + "3", // dirty marker
|
||||
glyphAhead + "4", // ahead marker
|
||||
"42%", // context usage
|
||||
"running: Read", // task
|
||||
} {
|
||||
if !strings.Contains(out, want) {
|
||||
t.Errorf("render missing %q; got %q", want, out)
|
||||
}
|
||||
}
|
||||
|
||||
if w := ui.Width(out); w > width {
|
||||
t.Errorf("render width %d exceeds terminal width %d", w, width)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStatusBarHidesGitWhenNotRepo(t *testing.T) {
|
||||
s := newTestStatusBar()
|
||||
s.SetGit(gitInfoMsg{ok: false})
|
||||
|
||||
out := s.Render(120)
|
||||
if strings.Contains(out, "master") || strings.Contains(out, "*") || strings.Contains(out, "+") {
|
||||
t.Errorf("git segment should be hidden when ok=false; got %q", out)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStatusBarHidesContextWhenUnknown(t *testing.T) {
|
||||
s := newTestStatusBar()
|
||||
// No telemetry set (window 0) → context segment hidden.
|
||||
s.SetTelemetry(telemetryEventView{util: 0.5, window: 0})
|
||||
|
||||
out := s.Render(120)
|
||||
if strings.Contains(out, glyphCtx) {
|
||||
t.Errorf("context segment should be hidden when window unknown; got %q", out)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStatusBarTruncationKeepsPriorityFields(t *testing.T) {
|
||||
s := newTestStatusBar()
|
||||
s.SetGit(gitInfoMsg{branch: "master", dirty: 3, ahead: 4, ok: true})
|
||||
s.SetTelemetry(telemetryEventView{util: 0.42, window: 200000})
|
||||
s.SetTask("TASK")
|
||||
|
||||
// Narrow width: only the highest-priority fields (task > model > token)
|
||||
// should survive; cwd and git should drop first.
|
||||
const width = 24
|
||||
out := s.Render(width)
|
||||
|
||||
if w := ui.Width(out); w > width {
|
||||
t.Fatalf("truncated render width %d exceeds %d: %q", w, width, out)
|
||||
}
|
||||
if !strings.Contains(out, "TASK") {
|
||||
t.Errorf("highest-priority task field dropped under truncation: %q", out)
|
||||
}
|
||||
// cwd (lowest priority) must be gone before task.
|
||||
if strings.Contains(out, "~/project") {
|
||||
t.Errorf("lowest-priority cwd should drop first under truncation: %q", out)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStatusBarVeryNarrowNeverOverflows(t *testing.T) {
|
||||
s := newTestStatusBar()
|
||||
s.SetTask("a-fairly-long-task-description-that-cannot-fit")
|
||||
|
||||
for _, width := range []int{1, 2, 3, 5, 8} {
|
||||
out := s.Render(width)
|
||||
if w := ui.Width(out); w > width {
|
||||
t.Errorf("width %d: render width %d overflows: %q", width, w, out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStatusBarZeroWidthEmpty(t *testing.T) {
|
||||
s := newTestStatusBar()
|
||||
if out := s.Render(0); out != "" {
|
||||
t.Errorf("zero width should render empty, got %q", out)
|
||||
}
|
||||
}
|
||||
|
||||
// TestStatusBarContextTokenCount checks the context segment shows a
|
||||
// comma-grouped token count with the percentage once telemetry reports tokens.
|
||||
func TestStatusBarContextTokenCount(t *testing.T) {
|
||||
s := newTestStatusBar()
|
||||
s.SetTelemetry(telemetryEventView{util: 0.46, window: 200000, tokens: 90866})
|
||||
|
||||
out := s.Render(200)
|
||||
for _, want := range []string{glyphCtx, "90,866", "46%"} {
|
||||
if !strings.Contains(out, want) {
|
||||
t.Errorf("render missing %q; got %q", want, out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestHumanizeInt(t *testing.T) {
|
||||
cases := map[int]string{0: "0", 90866: "90,866", 1000: "1,000", 999: "999", 1234567: "1,234,567"}
|
||||
for in, want := range cases {
|
||||
if got := humanizeInt(in); got != want {
|
||||
t.Errorf("humanizeInt(%d) = %q, want %q", in, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAbbreviateHome(t *testing.T) {
|
||||
home := homeDir()
|
||||
if home == "" {
|
||||
t.Skip("no home dir available")
|
||||
}
|
||||
if got := abbreviateHome(home); got != "~" {
|
||||
t.Errorf("abbreviateHome(home) = %q, want ~", got)
|
||||
}
|
||||
if got := abbreviateHome(home + "/foo/bar"); got != "~/foo/bar" {
|
||||
t.Errorf("abbreviateHome(home/foo/bar) = %q, want ~/foo/bar", got)
|
||||
}
|
||||
if got := abbreviateHome("/etc/passwd"); got != "/etc/passwd" {
|
||||
t.Errorf("abbreviateHome(/etc/passwd) = %q, want unchanged", got)
|
||||
}
|
||||
}
|
||||
|
||||
// TestStatusBarGitTextFormatting checks the "*N +N" markers appear only when
|
||||
// non-zero.
|
||||
func TestStatusBarGitTextFormatting(t *testing.T) {
|
||||
s := newTestStatusBar()
|
||||
s.SetGit(gitInfoMsg{branch: "main", ok: true})
|
||||
out := s.Render(120)
|
||||
if strings.Contains(out, "*") || strings.Contains(out, "+") {
|
||||
t.Errorf("clean tree should show no *N/+N markers: %q", out)
|
||||
}
|
||||
if !strings.Contains(out, "main") {
|
||||
t.Errorf("branch name missing: %q", out)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user