Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions internal/tui/components/components_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,3 +137,17 @@ func TestRenderSessionRow(t *testing.T) {
t.Fatalf("expected updated-at label in row, got %q", row)
}
}

func TestNormalizeBlockRightEdgeBlankContent(t *testing.T) {
blank := " \n\t"
if got := NormalizeBlockRightEdge(blank, 20); got != blank {
t.Fatalf("expected blank content passthrough, got %q", got)
}
}

func TestCompactStatusTextWithLimit(t *testing.T) {
text := "\n first useful line \nsecond line"
if got := CompactStatusText(text, 9); got != "fir...ine" {
t.Fatalf("expected first non-empty line compacted with ellipsis, got %q", got)
}
}
100 changes: 100 additions & 0 deletions internal/tui/core/status/snapshot_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package status

import (
"strings"
"testing"

tuistate "neo-code/internal/tui/state"
)

func TestBuildFromUIState(t *testing.T) {
state := tuistate.UIState{
ActiveSessionID: "session-1",
ActiveSessionTitle: "My Session",
ActiveRunID: "run-1",
IsAgentRunning: true,
IsCompacting: false,
CurrentProvider: "openai",
CurrentModel: "gpt-5.4",
CurrentWorkdir: "/repo",
CurrentTool: "filesystem_read_file",
ToolStates: []tuistate.ToolState{
{ToolCallID: "call-1"},
{ToolCallID: "call-2"},
},
TokenUsage: tuistate.TokenUsageState{
RunTotalTokens: 12,
SessionTotalTokens: 34,
},
ExecutionError: "boom",
}

snapshot := BuildFromUIState(state, 7, "transcript", "provider")
if snapshot.ActiveSessionID != "session-1" || snapshot.ActiveRunID != "run-1" {
t.Fatalf("unexpected snapshot identifiers: %+v", snapshot)
}
if snapshot.ToolStateCount != 2 || snapshot.RunTotalTokens != 12 || snapshot.SessionTotalTokens != 34 {
t.Fatalf("unexpected snapshot counters: %+v", snapshot)
}
if snapshot.FocusLabel != "transcript" || snapshot.PickerLabel != "provider" || snapshot.MessageCount != 7 {
t.Fatalf("unexpected snapshot labels: %+v", snapshot)
}
}

func TestFormat(t *testing.T) {
formatted := Format(Snapshot{
ActiveSessionID: "",
ActiveSessionTitle: "",
ActiveRunID: " ",
IsAgentRunning: false,
IsCompacting: false,
CurrentProvider: "openai",
CurrentModel: "gpt-5.4",
CurrentWorkdir: "/repo",
CurrentTool: "",
ToolStateCount: 1,
RunTotalTokens: 2,
SessionTotalTokens: 3,
ExecutionError: "",
FocusLabel: "composer",
PickerLabel: "",
MessageCount: 4,
}, "Draft Session")

expectedParts := []string{
"Session: Draft Session",
"Session ID: <draft>",
"Run ID: <none>",
"Running: no",
"Picker: none",
"Current Tool: <none>",
"Error: <none>",
}
for _, part := range expectedParts {
if !strings.Contains(formatted, part) {
t.Fatalf("expected formatted status to contain %q, got:\n%s", part, formatted)
}
}

running := Format(Snapshot{
ActiveSessionID: "session-2",
ActiveSessionTitle: "Named Session",
ActiveRunID: "run-2",
IsCompacting: true,
CurrentProvider: "openai",
CurrentModel: "gpt-5.4-mini",
CurrentWorkdir: "/repo",
CurrentTool: "tool-x",
ToolStateCount: 2,
RunTotalTokens: 10,
SessionTotalTokens: 20,
ExecutionError: "failed",
FocusLabel: "activity",
PickerLabel: "model",
MessageCount: 5,
}, "Ignored Draft")

if !strings.Contains(running, "Session: Named Session") || !strings.Contains(running, "Running: yes") {
t.Fatalf("expected running status to keep explicit values, got:\n%s", running)
}
}
97 changes: 97 additions & 0 deletions internal/tui/core/utils/view_helpers_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package utils

import (
"testing"

tuistate "neo-code/internal/tui/state"
)

func TestPickerLabelFromMode(t *testing.T) {
if got := PickerLabelFromMode(tuistate.PickerProvider); got != "provider" {
t.Fatalf("expected provider label, got %q", got)
}
if got := PickerLabelFromMode(tuistate.PickerModel); got != "model" {
t.Fatalf("expected model label, got %q", got)
}
if got := PickerLabelFromMode(tuistate.PickerFile); got != "file" {
t.Fatalf("expected file label, got %q", got)
}
if got := PickerLabelFromMode(tuistate.PickerMode(99)); got != "none" {
t.Fatalf("expected default picker label none, got %q", got)
}
}

func TestRequestedWorkdirForRun(t *testing.T) {
if got := RequestedWorkdirForRun("", "/repo"); got != "/repo" {
t.Fatalf("expected current workdir when active session is blank, got %q", got)
}
if got := RequestedWorkdirForRun("session-1", "/repo"); got != "" {
t.Fatalf("expected empty requested workdir when active session exists, got %q", got)
}
}

func TestIsBusy(t *testing.T) {
if IsBusy(false, false) {
t.Fatalf("expected idle state")
}
if !IsBusy(true, false) || !IsBusy(false, true) || !IsBusy(true, true) {
t.Fatalf("expected busy state when any operation is running")
}
}

func TestFocusLabelFromPanel(t *testing.T) {
const (
sessions = "Sessions"
transcript = "Transcript"
activity = "Activity"
composer = "Composer"
)

if got := FocusLabelFromPanel(tuistate.PanelSessions, sessions, transcript, activity, composer); got != sessions {
t.Fatalf("expected sessions label, got %q", got)
}
if got := FocusLabelFromPanel(tuistate.PanelTranscript, sessions, transcript, activity, composer); got != transcript {
t.Fatalf("expected transcript label, got %q", got)
}
if got := FocusLabelFromPanel(tuistate.PanelActivity, sessions, transcript, activity, composer); got != activity {
t.Fatalf("expected activity label, got %q", got)
}
if got := FocusLabelFromPanel(tuistate.PanelInput, sessions, transcript, activity, composer); got != composer {
t.Fatalf("expected composer label, got %q", got)
}
}

func TestTrimHelpers(t *testing.T) {
if got := TrimRunes("abcdef", 3); got != "abcdef" {
t.Fatalf("expected original text when limit < 4, got %q", got)
}
if got := TrimRunes("abcdef", 5); got != "ab..." {
t.Fatalf("expected rune-safe truncation, got %q", got)
}

if got := TrimMiddle("abcdef", 6); got != "abcdef" {
t.Fatalf("expected no trim when limit < 7, got %q", got)
}
if got := TrimMiddle("abcdefghij", 7); got != "ab...ij" {
t.Fatalf("expected middle trim output, got %q", got)
}
}

func TestFallbackAndClamp(t *testing.T) {
if got := Fallback("value", "fallback"); got != "value" {
t.Fatalf("expected value when non-empty, got %q", got)
}
if got := Fallback(" ", "fallback"); got != "fallback" {
t.Fatalf("expected fallback for blank value, got %q", got)
}

if got := Clamp(-1, 0, 10); got != 0 {
t.Fatalf("expected clamp to min, got %d", got)
}
if got := Clamp(11, 0, 10); got != 10 {
t.Fatalf("expected clamp to max, got %d", got)
}
if got := Clamp(5, 0, 10); got != 5 {
t.Fatalf("expected in-range value unchanged, got %d", got)
}
}
57 changes: 57 additions & 0 deletions internal/tui/core/workspace/resolver_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package workspace

import (
"os"
"path/filepath"
"strings"
"testing"
)

func TestResolveWorkspacePath(t *testing.T) {
base := t.TempDir()
childDir := filepath.Join(base, "project")
if err := os.MkdirAll(childDir, 0o755); err != nil {
t.Fatalf("mkdir child dir: %v", err)
}

resolved, err := ResolveWorkspacePath(base, "project")
if err != nil {
t.Fatalf("ResolveWorkspacePath(relative) error = %v", err)
}
if resolved != filepath.Clean(childDir) {
t.Fatalf("unexpected resolved path: %q", resolved)
}

resolved, err = ResolveWorkspacePath(base, "")
if err != nil {
t.Fatalf("ResolveWorkspacePath(default current) error = %v", err)
}
if resolved != filepath.Clean(base) {
t.Fatalf("expected base directory for empty requested path, got %q", resolved)
}
}

func TestResolveWorkspacePathErrors(t *testing.T) {
base := t.TempDir()
filePath := filepath.Join(base, "not-dir.txt")
if err := os.WriteFile(filePath, []byte("x"), 0o644); err != nil {
t.Fatalf("write file: %v", err)
}

if _, err := ResolveWorkspacePath(base, "missing-dir"); err == nil {
t.Fatalf("expected missing path to return error")
}

if _, err := ResolveWorkspacePath(base, "not-dir.txt"); err == nil || !strings.Contains(err.Error(), "not a directory") {
t.Fatalf("expected non-directory path error, got %v", err)
}
}

func TestSelectSessionWorkdir(t *testing.T) {
if got := SelectSessionWorkdir(" /session ", "/default"); got != "/session" {
t.Fatalf("expected session workdir priority, got %q", got)
}
if got := SelectSessionWorkdir(" ", " /default "); got != "/default" {
t.Fatalf("expected default workdir fallback, got %q", got)
}
}
Loading
Loading