package state_test import ( "testing" "github.com/StevanFreeborn/term-tier/internal/core" "github.com/StevanFreeborn/term-tier/internal/state" tea "github.com/charmbracelet/bubbletea" ) func TestNew_Defaults(t *testing.T) { s := state.New() if s.Mode() != state.NavigationMode { t.Errorf("Expected default mode NavigationMode, got %v", s.Mode()) } tiers := s.Tiers() if len(tiers) != 6 { t.Errorf("Expected 6 default tiers, got %d", len(tiers)) } if tiers[0].Name != "S Tier" { t.Errorf("Expected first tier to be 'S Tier', got '%s'", tiers[0].Name) } if s.CursorRow() != 5 { t.Errorf("Expected cursor to start at row 5 (Pool), got %d", s.CursorRow()) } if s.CursorCol() != 0 { t.Errorf("Expected cursor to start at col 0, got %d", s.CursorCol()) } } func TestInputMode_Flow(t *testing.T) { s := state.New() triggered := false s.StartInputMode("Title", func(v string, _ state.State) tea.Cmd { triggered = true return nil }) if s.Mode() != state.InputMode { t.Fatal("Failed to enter input mode") } s.SubmitInput() if !triggered { t.Error("SubmitInput failed to trigger callback") } if s.Mode() != state.NavigationMode { t.Error("SubmitInput failed to reset mode to Navigation") } } func TestAddItem(t *testing.T) { s := state.New() initialPoolSize := len(s.Tiers()[5].Items) s.AddItemToPool("New Item") newPool := s.Tiers()[5].Items if len(newPool) != initialPoolSize+1 { t.Errorf("Expected pool size to increase by 1, got %d", len(newPool)) } if newPool[len(newPool)-1] != "New Item" { t.Error("Item was not appended to the end of the pool") } } func TestNavigation_Movement(t *testing.T) { fullTiers := make([]core.Tier, 6) fullTiers[0] = core.Tier{Name: "S", Items: []core.Item{"1", "2", "3"}} fullTiers[1] = core.Tier{Name: "A", Items: []core.Item{"4"}} s := state.New(state.WithTiers(fullTiers), state.WithCursor(0, 0)) s.MoveRight() if s.CursorCol() != 1 { t.Errorf("Expected Col 1, got %d", s.CursorCol()) } s.MoveRight() s.MoveRight() if s.CursorCol() != 2 { t.Errorf("Expected Col 2, got %d", s.CursorCol()) } s.MoveLeft() if s.CursorCol() != 1 { t.Errorf("Expected Col 1 after MoveLeft, got %d", s.CursorCol()) } s.MoveLeft() s.MoveLeft() if s.CursorCol() != 0 { t.Error("Cursor went out of bounds left") } s.MoveRight() s.MoveRight() s.MoveDown() if s.CursorRow() != 1 { t.Errorf("Expected Row 1, got %d", s.CursorRow()) } if s.CursorCol() != 0 { t.Errorf("Expected Col to clamp to 0, got %d", s.CursorCol()) } s.MoveUp() if s.CursorRow() != 0 { t.Error("Expected to return to Row 0") } } func TestDragAndDrop(t *testing.T) { tiers := make([]core.Tier, 6) tiers[0] = core.Tier{Name: "0", Items: []core.Item{"A", "B"}} tiers[1] = core.Tier{Name: "1", Items: []core.Item{"C"}} s := state.New(state.WithTiers(tiers), state.WithCursor(0, 0)) s.SelectItem() if !s.Dragging() { t.Fatal("Expected dragging to be true") } s.MoveRight() items := s.Tiers()[0].Items if items[0] != "B" || items[1] != "A" { t.Errorf("Expected swap [B, A], got %v", items) } s.MoveDown() if len(s.Tiers()[0].Items) != 1 || s.Tiers()[0].Items[0] != "B" { t.Error("Row 0 should only contain 'B'") } row1 := s.Tiers()[1].Items if len(row1) != 2 { t.Errorf("Row 1 should have 2 items, got %d", len(row1)) } if row1[0] != "A" { t.Errorf("Expected 'A' at index 0, got %v", row1) } s.SelectItem() if s.Dragging() { t.Error("Expected dragging to stop") } } func TestDeleteItem(t *testing.T) { tiers := make([]core.Tier, 6) tiers[0] = core.Tier{Name: "0", Items: []core.Item{"DeleteMe", "KeepMe"}} s := state.New(state.WithTiers(tiers), state.WithCursor(0, 0)) s.DeleteItem() items := s.Tiers()[0].Items if len(items) != 1 { t.Fatalf("Expected 1 item remaining, got %d", len(items)) } if items[0] != "KeepMe" { t.Errorf("Expected 'KeepMe', got '%s'", items[0]) } if s.StatusMsg() != "Item Deleted" { t.Error("Status message not set") } } func TestSaveLoad(t *testing.T) { tiers := make([]core.Tier, 6) tiers[0] = core.Tier{Name: "S", Items: []core.Item{"UniqueData"}} s1 := state.New(state.WithTiers(tiers)) savedData := s1.Save() s2 := state.New() s2.Load(savedData) loadedItem := s2.Tiers()[0].Items[0] if loadedItem != "UniqueData" { t.Errorf("Failed to persist data. Got '%s'", loadedItem) } } func TestUpdateItem(t *testing.T) { tiers := make([]core.Tier, 6) tiers[0] = core.Tier{Name: "0", Items: []core.Item{"OldName"}} s := state.New(state.WithTiers(tiers), state.WithCursor(0, 0)) cmd := s.UpdateItem() if s.Mode() != state.InputMode { t.Fatal("UpdateItem should trigger InputMode") } if cmd == nil { t.Error("UpdateItem should return command") } if s.Input().Value() != "OldName" { t.Errorf("Expected input to be pre-filled with 'OldName', got '%s'", s.Input().Value()) } s.UpdateCurrentItem("NewName") if s.Tiers()[0].Items[0] != "NewName" { t.Errorf("Item was not renamed. Got '%s'", s.Tiers()[0].Items[0]) } } func TestWindowSize(t *testing.T) { s := state.New() s.SetWindowSize(100, 50) if s.WindowWidth() != 100 || s.WindowHeight() != 50 { t.Error("SetWindowSize failed") } } func TestToggleHelp(t *testing.T) { s := state.New(state.WithMode(state.NavigationMode)) s.ToggleHelp() if s.Mode() != state.HelpMode { t.Error("Expected HelpMode") } s.ToggleHelp() if s.Mode() != state.NavigationMode { t.Error("Expected NavigationMode") } }