Files
ltk/tests/tab_navigation.rs

108 lines
3.7 KiB
Rust

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 ) );
}