package navigation_test import ( "testing" "github.com/nebara/nebara-os/internal/model" "github.com/nebara/nebara-os/internal/ui/navigation" ) func sampleItems() []model.MenuItem { return []model.MenuItem{ {Label: "Item A", Description: "Desc A", Children: []model.MenuItem{ {Label: "Child A1", Description: "Desc A1"}, {Label: "Child A2", Description: "Desc A2"}, }}, {Label: "Item B", Description: "Desc B"}, {Label: "Item C", Description: "Desc C"}, } } func TestNewNavigator_InitialIndex(t *testing.T) { nav := navigation.NewNavigator(sampleItems(), 1) if nav.Current().SelectedIdx != 1 { t.Errorf("expected initial index 1, got %d", nav.Current().SelectedIdx) } } func TestNewNavigator_InvalidIndex(t *testing.T) { nav := navigation.NewNavigator(sampleItems(), 99) if nav.Current().SelectedIdx != 0 { t.Errorf("out-of-range index should clamp to 0, got %d", nav.Current().SelectedIdx) } } func TestMoveDown(t *testing.T) { nav := navigation.NewNavigator(sampleItems(), 0) nav.MoveDown() if nav.Current().SelectedIdx != 1 { t.Errorf("expected index 1 after MoveDown, got %d", nav.Current().SelectedIdx) } } func TestMoveDown_Clamps(t *testing.T) { items := sampleItems() nav := navigation.NewNavigator(items, len(items)-1) nav.MoveDown() if nav.Current().SelectedIdx != len(items)-1 { t.Errorf("MoveDown should clamp at last item") } } func TestMoveUp(t *testing.T) { nav := navigation.NewNavigator(sampleItems(), 2) nav.MoveUp() if nav.Current().SelectedIdx != 1 { t.Errorf("expected index 1 after MoveUp, got %d", nav.Current().SelectedIdx) } } func TestMoveUp_Clamps(t *testing.T) { nav := navigation.NewNavigator(sampleItems(), 0) nav.MoveUp() if nav.Current().SelectedIdx != 0 { t.Errorf("MoveUp should clamp at 0") } } func TestMoveFirst(t *testing.T) { nav := navigation.NewNavigator(sampleItems(), 2) nav.MoveFirst() if nav.Current().SelectedIdx != 0 { t.Errorf("MoveFirst should jump to 0") } } func TestMoveLast(t *testing.T) { nav := navigation.NewNavigator(sampleItems(), 0) nav.MoveLast() last := len(sampleItems()) - 1 if nav.Current().SelectedIdx != last { t.Errorf("MoveLast should jump to %d, got %d", last, nav.Current().SelectedIdx) } } func TestEnter_HasChildren(t *testing.T) { nav := navigation.NewNavigator(sampleItems(), 0) // Item A has children ok := nav.Enter() if !ok { t.Fatal("Enter on item with children should return true") } if nav.Depth() != 1 { t.Errorf("expected depth 1, got %d", nav.Depth()) } if nav.Current().Items[0].Label != "Child A1" { t.Errorf("expected Child A1, got %s", nav.Current().Items[0].Label) } } func TestEnter_NoChildren(t *testing.T) { nav := navigation.NewNavigator(sampleItems(), 1) // Item B has no children ok := nav.Enter() if ok { t.Fatal("Enter on leaf item should return false") } if nav.Depth() != 0 { t.Errorf("depth should remain 0 for leaf enter") } } func TestBack(t *testing.T) { nav := navigation.NewNavigator(sampleItems(), 0) nav.Enter() ok := nav.Back() if !ok { t.Fatal("Back from submenu should return true") } if nav.Depth() != 0 { t.Errorf("expected depth 0 after back, got %d", nav.Depth()) } } func TestBack_AtRoot(t *testing.T) { nav := navigation.NewNavigator(sampleItems(), 0) ok := nav.Back() if ok { t.Fatal("Back at root should return false") } } func TestIsAtRoot(t *testing.T) { nav := navigation.NewNavigator(sampleItems(), 0) if !nav.IsAtRoot() { t.Error("should be at root initially") } nav.Enter() if nav.IsAtRoot() { t.Error("should not be at root after Enter") } nav.Back() if !nav.IsAtRoot() { t.Error("should be at root after Back") } } func TestSelectionPreservedAfterBack(t *testing.T) { nav := navigation.NewNavigator(sampleItems(), 0) nav.MoveDown() // idx=1 nav.MoveDown() // idx=2 nav.Back() // at root, nothing changes if nav.Current().SelectedIdx != 2 { t.Errorf("selection should be 2, got %d", nav.Current().SelectedIdx) } nav.MoveFirst() // idx=0 nav.Enter() // into Item A's children nav.Back() // back to root, parent should restore idx=0 if nav.Current().SelectedIdx != 0 { t.Errorf("after returning from submenu, root selection should be 0, got %d", nav.Current().SelectedIdx) } } func TestBreadcrumbTitle(t *testing.T) { nav := navigation.NewNavigator(sampleItems(), 0) if nav.BreadcrumbTitle() != "" { t.Error("breadcrumb should be empty at root") } nav.Enter() if nav.BreadcrumbTitle() != "Item A" { t.Errorf("breadcrumb should be 'Item A', got %q", nav.BreadcrumbTitle()) } }