#![ cfg( feature = "test-support" ) ] mod common; use common::{ lw_none, rect }; use ltk::test_support::next_focusable_index; // ── Empty / single-element edge cases ───────────────────────────────────────── #[ test ] fn empty_widget_list_returns_none() { let widgets: Vec<_> = vec![]; assert_eq!( next_focusable_index::<()>( &widgets, None, false ), None ); assert_eq!( next_focusable_index::<()>( &widgets, Some( 42 ), false ), None ); assert_eq!( next_focusable_index::<()>( &widgets, None, true ), None ); } #[ test ] fn single_widget_wraps_to_itself() { let widgets = vec![ lw_none( 7, rect( 0.0, 0.0, 10.0, 10.0 ) ) ]; assert_eq!( next_focusable_index( &widgets, Some( 7 ), false ), Some( 7 ) ); assert_eq!( next_focusable_index( &widgets, Some( 7 ), true ), Some( 7 ) ); } // ── Forward (Tab) ───────────────────────────────────────────────────────────── #[ test ] fn forward_advances_to_next_in_slice_order() { let widgets = vec![ lw_none( 10, rect( 0.0, 0.0, 10.0, 10.0 ) ), lw_none( 20, rect( 0.0, 0.0, 10.0, 10.0 ) ), lw_none( 30, rect( 0.0, 0.0, 10.0, 10.0 ) ), ]; assert_eq!( next_focusable_index( &widgets, Some( 10 ), false ), Some( 20 ) ); assert_eq!( next_focusable_index( &widgets, Some( 20 ), false ), Some( 30 ) ); } #[ test ] fn forward_wraps_around_at_end() { let widgets = vec![ lw_none( 1, rect( 0.0, 0.0, 10.0, 10.0 ) ), lw_none( 2, rect( 0.0, 0.0, 10.0, 10.0 ) ), ]; assert_eq!( next_focusable_index( &widgets, Some( 2 ), false ), Some( 1 ) ); } #[ test ] fn forward_with_no_focus_targets_first_widget() { let widgets = vec![ lw_none( 100, rect( 0.0, 0.0, 10.0, 10.0 ) ), lw_none( 200, rect( 0.0, 0.0, 10.0, 10.0 ) ), ]; assert_eq!( next_focusable_index( &widgets, None, false ), Some( 100 ) ); } // ── Reverse (Shift+Tab) ─────────────────────────────────────────────────────── #[ test ] fn reverse_steps_to_previous() { let widgets = vec![ lw_none( 10, rect( 0.0, 0.0, 10.0, 10.0 ) ), lw_none( 20, rect( 0.0, 0.0, 10.0, 10.0 ) ), lw_none( 30, rect( 0.0, 0.0, 10.0, 10.0 ) ), ]; assert_eq!( next_focusable_index( &widgets, Some( 30 ), true ), Some( 20 ) ); assert_eq!( next_focusable_index( &widgets, Some( 20 ), true ), Some( 10 ) ); } #[ test ] fn reverse_wraps_around_at_start() { let widgets = vec![ lw_none( 10, rect( 0.0, 0.0, 10.0, 10.0 ) ), lw_none( 20, rect( 0.0, 0.0, 10.0, 10.0 ) ), ]; assert_eq!( next_focusable_index( &widgets, Some( 10 ), true ), Some( 20 ) ); } #[ test ] fn reverse_with_no_focus_targets_last_widget() { let widgets = vec![ lw_none( 100, rect( 0.0, 0.0, 10.0, 10.0 ) ), lw_none( 200, rect( 0.0, 0.0, 10.0, 10.0 ) ), ]; assert_eq!( next_focusable_index( &widgets, None, true ), Some( 200 ) ); } // ── Stale focus index ───────────────────────────────────────────────────────── #[ test ] fn stale_focus_idx_falls_back_to_first() { // Common after a re-layout removes the previously-focused widget: the // stored focus idx no longer maps to any entry, and the walker falls // back to the same behaviour as `None`. let widgets = vec![ lw_none( 10, rect( 0.0, 0.0, 10.0, 10.0 ) ), lw_none( 20, rect( 0.0, 0.0, 10.0, 10.0 ) ), ]; assert_eq!( next_focusable_index( &widgets, Some( 999 ), false ), Some( 10 ) ); assert_eq!( next_focusable_index( &widgets, Some( 999 ), true ), Some( 20 ) ); }