108 lines
3.7 KiB
Rust
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 ) );
|
|
}
|