package tests::TestCursesUIDriverTest;
use strict;
use base qw/Test::Unit::TestSuite/;
sub name {
return "Lire::Test::CursesUIDriver Tests";
}
sub include_tests {
return qw/tests::TestCursesUIDriverTest::setup
tests::TestCursesUIDriverTest::events
/;
}
package tests::TestCursesUIDriverTest::setup;
use base qw/Lire::Test::TestCase/;
use Lire::Test::CursesUIDriver;
use Curses;
use Curses::UI;
sub set_up {
my $self = $_[0];
$self->SUPER::set_up();
$self->{'driver'} = new Lire::Test::CursesUIDriver();
return;
}
sub tear_down {
my $self = $_[0];
$self->SUPER::tear_down();
endwin()
unless isendwin();
return;
}
sub test_new {
my $self = $_[0];
my $driver = $self->{'driver'};
$self->assert( UNIVERSAL::isa( $driver, 'Lire::Test::CursesUIDriver' ),
"new() didn't return a Lire::Test::CursesUIDriver instance: $driver" );
$self->assert_deep_equals( [], $driver->{'_event_loop_handlers'} );
}
sub _default_mouse_support {
return Curses->can('NCURSES_MOUSE_VERSION') &&
NCURSES_MOUSE_VERSION() >= 1;
}
sub _check_curses_ui_globals {
my $self = $_[0];
$self->assert( ! isendwin(), 'isendwin was set' );
$self->assert_null( $Curses::UI::rootobject,
'$Curses::UI::rootobject != undef' );
foreach my $var ( qw/ debug screen_too_small initialized color_support color_object/ )
{
no strict 'refs';
my $var = 'Curses::UI::' . $var;
$self->assert_num_equals( 0, $$var, "$var != 0: $$var" );
}
$self->assert_num_equals( _default_mouse_support(),
$Curses::UI::ncurses_mouse );
return;
}
sub test_setup_curses_ui {
my $self = $_[0];
my $or_event_handler = \&Curses::UI::do_one_event;
my $or_fatalerror = \&Curses::UI::fatalerror;
my $driver = $self->{'driver'};
$driver->setup_curses_ui();
$self->assert( UNIVERSAL::isa( $driver->{'term'}, 'Curses::Screen' ),
"'term' attribute isn't a Curses::Screen instance: $driver->{'term'}" );
$self->_check_curses_ui_globals();
$self->assert_str_equals( $or_event_handler,
$driver->{'_do_one_event_ref'} );
$self->assert_not_equals( $or_event_handler, \&Curses::UI::do_one_event );
$self->assert_str_equals( $or_fatalerror,
$driver->{'_fatalerror_ref'} );
$self->assert_str_equals( \&Lire::Test::CursesUIDriver::fatalerror,
\&Curses::UI::fatalerror );
my $ui = new Curses::UI();
$self->assert_str_equals( $Curses::UI::rootobject, $ui );
$driver->{'_ui'} = $ui;
$driver->teardown_curses_ui();
$self->assert( isendwin(), 'isendwin was not set!' );
$self->assert_null( $driver->{'_ui'}, "'_ui' attribute wasn't removed" );
$self->assert_str_equals( $or_event_handler, \&Curses::UI::do_one_event );
$self->assert_str_equals( $or_fatalerror, \&Curses::UI::fatalerror );
$driver->setup_curses_ui();
$self->_check_curses_ui_globals();
$ui = undef;
$ui = new Curses::UI();
$self->assert_str_equals( $Curses::UI::rootobject, $ui );
$driver->teardown_curses_ui();
$self->assert( isendwin(), 'isendwin was not set!' );
return;
}
package tests::TestCursesUIDriverTest::events;
use base qw/Lire::Test::TestCase/;
use Lire::Test::CursesUIDriver;
use Curses;
use Curses::UI;
sub set_up {
my $self = $_[0];
$self->SUPER::set_up();
$self->{'driver'} = new Lire::Test::CursesUIDriver();
$self->{'driver'}->setup_curses_ui();
return;
}
sub tear_down {
my $self = $_[0];
$self->SUPER::tear_down();
$self->{'driver'}->teardown_curses_ui();
return;
}
sub test_set_curses_ui {
my $self = $_[0];
my $driver = $self->{'driver'};
$self->assert_died( sub { $driver->set_curses_ui( undef ) },
qr/missing \'ui\' parameter/ );
$self->assert_died( sub { $driver->set_curses_ui( {} ) },
qr/\'ui\' parameter should be a \'Curses::UI\' instance, not \'HASH/ );
my $ui = new Curses::UI();
$driver->set_curses_ui( $ui );
$self->assert_str_equals( $ui, $driver->{'_ui'} );
$self->assert_died( sub { $driver->set_curses_ui( $ui ) },
qr/you need to call teardown_curses_ui\(\) before calling set_curses_ui\(\) again/ );
}
sub test_find_menu_def {
my $self = $_[0];
my $driver = $self->{'driver'};
my $ui = new Curses::UI();
my $menu = [ { -label => 'File',
-submenu => [ { -label => 'Reports',
-submenu => [ { -label => 'Report 1' }, ],
},
{ -label => 'Scalar Menu',
-value => 'Hi!',
},
{ -label => 'Exit',
}, ],
} ];
my $menubar = $ui->add( 'menu', 'Menubar', -menu => $menu );
$self->assert_died( sub { $driver->activate_menu( 'menu/File/Exit' ) },
qr/set_curses_ui\(\) wasn't called/ );
$driver->set_curses_ui( $ui );
$self->assert_died( sub { $driver->activate_menu() },
qr/missing 'menu_path' parameter/ );
$self->assert_died( sub { $driver->activate_menu( 'menu' ) },
qr/'menu_path' should have at least 2 components/ );
$self->assert_died( sub { $driver->activate_menu( 'menu1/Reports' ) },
qr/no 'menu1' menubar/ ); #'/); # cperl-mode...
$self->assert_died( sub { $driver->activate_menu( 'menu/Reports' ) },
qr/no 'Reports' menu in 'menu' menubar/ );
$self->assert_died( sub { $driver->activate_menu('menu/File/Reports/Report 2') },
qr{no 'Report 2' submenu in 'menu/File/Reports} );
$self->assert_deep_equals( $menu->[0],
$driver->find_menu_def( 'menu/File' ) );
$self->assert_deep_equals( $menu->[0]{'-submenu'}[0],
$driver->find_menu_def( 'menu/File/Reports' ) );
$self->assert_deep_equals( $menu->[0]{'-submenu'}[2],
$driver->find_menu_def( 'menu/File/Exit' ) );
}
sub test_activate_menu {
my $self = $_[0];
my $driver = $self->{'driver'};
my $ui = new Curses::UI();
my $report_called =0;
my $exit_called = undef;
my $menu = [ { -label => 'File',
-submenu => [ { -label => 'Reports',
-submenu => [ { -label => 'Report 1',
-value => sub { $report_called = 1 },
}, ],
},
{ -label => 'Scalar Menu',
-value => 'Hi!',
},
{ -label => 'Exit',
-value => sub { $exit_called = shift },
}, ],
} ];
my $menubar = $ui->add( 'menu', 'Menubar', -menu => $menu );
$self->assert_died( sub { $driver->activate_menu( 'menu/File/Exit' ) },
qr/set_curses_ui\(\) wasn't called/ );
$driver->set_curses_ui( $ui );
$self->assert_died( sub { $driver->activate_menu() },
qr/missing 'menu_path' parameter/ );
$self->assert_died( sub { $driver->activate_menu( 'menu' ) },
qr/'menu_path' should have at least 2 components/ );
$self->assert_died( sub { $driver->activate_menu( 'menu1/Reports' ) },
qr/no 'menu1' menubar/ ); #'/); # cperl-mode...
$self->assert_died( sub { $driver->activate_menu( 'menu/Reports' ) },
qr/no 'Reports' menu in 'menu' menubar/ );
$self->assert_died( sub { $driver->activate_menu('menu/File/Reports/Report 2') },
qr{no 'Report 2' submenu in 'menu/File/Reports} );
$self->assert_died( sub { $driver->activate_menu( 'menu/File/Reports' ) },
qr{no callback defined for 'File/Reports' in 'menu' menubar} );
$self->assert_died( sub { $driver->activate_menu( 'menu/File/Scalar Menu' ) },
qr{no callback defined for 'File/Scalar Menu' in 'menu' menubar} );
$self->assert_equals( 0, $report_called );
$driver->activate_menu( 'menu/File/Reports/Report 1' );
$self->assert_equals( 1, $report_called );
$self->assert_null( $exit_called );
$driver->activate_menu( 'menu/File/Exit' );
$self->assert_str_equals( $menubar, $exit_called );
return;
}
sub test_find_menu {
my $self = $_[0];
my $menu = [ { -label => 'File',
-submenu => [ { -label => 'Reports',
-submenu => [ { -label => 'Report 1' }, ],
},
{ -label => 'Scalar Menu' },
{ -label => 'Exit' }, ],
} ];
my $driver = $self->{'driver'};
$self->assert_str_equals( $menu->[0], $driver->_find_menu( $menu, 'File') );
$self->assert_str_equals( $menu->[0]{'-submenu'}[1], $driver->_find_menu( $menu->[0]{'-submenu'}, 'Scalar Menu') );
$self->assert_null( $driver->_find_menu( $menu, 'wawa'),
'_find_menu should have returned undef' );
}
sub test_find_widget {
my $self = $_[0];
my $driver = $self->{'driver'};
$self->setup_three_pane_ui();
$self->{'widgets'}{'field_1'}->focus();
$self->assert_died( sub { $driver->find_widget() },
qr/missing 'path' parameter/ );
$self->assert_died( sub { $driver->find_widget( '/win3' )},
qr{no widget 'win3' in root container} );
$self->assert_str_equals( $self->{'widgets'}{'field_1'},
$driver->find_widget( '/win1/field_1' ) );
$self->assert_str_equals( $self->{'widgets'}{'field_1'},
$driver->find_widget( 'field_1' ) );
$self->assert_died( sub { $driver->find_widget( 'field_2' )},
qr{no widget 'field_2' in '/win1' container} );
$self->assert_str_equals( $self->{'widgets'}{'field_2'},
$driver->find_widget( 'win3/field_2' ) );
$self->assert_died( sub { $driver->find_widget( 'win3/field_3' )},
qr{no widget 'field_3' in '/win1/win3' container} );
$self->assert_str_equals( $self->{'widgets'}{'buttons'},
$driver->find_widget( '/win2/buttons' ) );
$self->assert_died( sub { $driver->find_widget( 'buttons' )},
qr{no widget 'buttons' in '/win1' container} );
$self->{'widgets'}{'win2'}->focus();
$self->assert_str_equals( $self->{'widgets'}{'buttons'},
$driver->find_widget( 'buttons' ) );
$self->assert_str_equals( $self->{'widgets'}{'ui'},
$driver->find_widget( '/' ) );
$self->{'widgets'}{'field_3'}->focus();
$self->assert_str_equals( $self->{'widgets'}{'field_3'},
$driver->find_widget( '.' ) );
}
sub setup_three_pane_ui {
my $self = $_[0];
my $driver = $self->{'driver'};
my $ui = new Curses::UI();
$driver->set_curses_ui( $ui );
my %w = ( 'ui' => $ui );
$w{'win1'} = $ui->add( 'win1', 'Window', -height => 30 );
$w{'field_1'} = $w{'win1'}->add( 'field_1', 'TextEntry' );
$w{'win3'} = $w{'win1'}->add( 'win3', 'Window' );
$w{'field_2'} = $w{'win3'}->add( 'field_2', 'TextEntry' );
$w{'win2'} = $ui->add( 'win2', 'Window', -height => 30 );
$w{'field_3'} = $w{'win2'}->add( 'field_3', 'TextEntry' );
$w{'buttons'} = $w{'win2'}->add( 'buttons', 'Buttonbox',
-buttons => [ { -label => '[ OK ]',
-value => 1 },
{ -label => '[ Cancel ]',
-value => 2 },
] );
$self->{'widgets'} = \%w;
return;
}
sub test_top_window {
my $self = $_[0];
my $driver = $self->{'driver'};
$self->setup_three_pane_ui();
$self->{'widgets'}{'field_2'}->focus();
$self->assert_str_equals( $self->{'widgets'}{'win3'},
$driver->top_window() );
$self->{'widgets'}{'field_3'}->focus();
$self->assert_str_equals( $self->{'widgets'}{'win2'},
$driver->top_window() );
$self->{'widgets'}{'field_1'}->focus();
$self->assert_str_equals( $self->{'widgets'}{'win1'},
$driver->top_window() );
$self->{'widgets'}{'win3'}->focus();
$self->assert_str_equals( $self->{'widgets'}{'win3'},
$driver->top_window() );
# Check that when focus is given to a container, it
# focuses the last focused widgets. And in this case,
# this also gives focus to a contained window.
$self->{'widgets'}{'field_2'}->focus();
$self->{'widgets'}{'win1'}->focus();
$self->assert_str_equals( $self->{'widgets'}{'win3'},
$driver->top_window() );
my $mbar = $self->{'widgets'}{'ui'}->add( 'menubar', 'Menubar',
'-menu' => [ { '-label' => 'A menu' } ],
);
$mbar->focus();
$self->assert_str_equals( $self->{'widgets'}{'win3'},
$driver->top_window() );
$self->assert_str_equals( $mbar,
$self->{'widgets'}{'ui'}->focus_path(-1) );
}
sub test_widget_path {
my $self = $_[0];
my $driver = $self->{'driver'};
$self->setup_three_pane_ui();
$self->assert_str_equals( '/',
$driver->_widget_path( $self->{'widgets'}{'ui'} )
);
$self->assert_str_equals( '/win1',
$driver->_widget_path( $self->{'widgets'}{'win1'} ) );
$self->assert_str_equals( '/win1/win3/field_2',
$driver->_widget_path( $self->{'widgets'}{'field_2'} ) );
}
sub test_click_button {
my $self = $_[0];
my $driver = $self->{'driver'};
my $ui = new Curses::UI();
$driver->set_curses_ui( $ui );
my $win = $ui->add( 'win', 'Window' );
my $clicked = 0;
my $box = $win->add( 'buttons', 'Buttonbox',
-buttons => [ { '-label' => '[ OK ]',
'-value' => 1 },
{ '-label' => '[ Cancel ]',
'-value' => 0 },
{ '-label' => '[ Weird ]',
'-onpress' => sub {$clicked = shift }}
] );
$box->focus();
$self->assert_died( sub { $driver->click_button() },
qr/missing 'path' parameter/ );
$self->assert_died( sub { $driver->click_button( 'buttons' ) },
qr/missing 'button' parameter/ );
$self->assert_died( sub { $driver->click_button( '/win', 'OK' ) },
qr{'/win' should be a Curses::UI::Buttonbox widget, not 'Curses::UI::Window} );
$self->assert_died( sub { $driver->click_button( 'buttons', 'OK' ) },
qr{no 'OK' button in '/win/buttons' Buttonbox} );
$driver->click_button( 'buttons', '[ Cancel ]' );
$self->assert_num_equals( 1, $box->{'-selected'} );
$driver->click_button( 'buttons', '[ OK ]' );
$self->assert_num_equals( 0, $box->{'-selected'} );
$self->assert_num_equals( 0, $clicked );
$driver->click_button( 'buttons', '[ Weird ]' );
$self->assert_num_equals( 2, $box->{'-selected'} );
$self->assert_num_equals( $box, $clicked );
return;
}
sub test_enter_text {
my $self = $_[0];
my $driver = $self->{'driver'};
my $ui = new Curses::UI();
$driver->set_curses_ui( $ui );
my $win = $ui->add( 'win', 'Window' );
my $editor = $win->add( 'editor', 'TextEditor', -height => 20 );
my $viewer = $win->add( 'viewer', 'TextViewer', -height => 20 );
my $entry = $win->add( 'entry', 'TextEntry', -regexp => '/^\w+$/' );
$self->assert_died( sub { $driver->enter_text() },
qr/missing 'path' parameter/ );
$self->assert_died( sub { $driver->enter_text( 'text' ) },
qr/missing 'text' parameter/ );
my $two_lines = "These are two lines\n of text.";
$driver->enter_text( 'editor', $two_lines );
$self->assert_num_equals( 1, $editor->{'-focus'} );
$self->assert_str_equals( $two_lines, $editor->text() );
$self->assert_num_equals( length $two_lines, $editor->pos() );
$self->assert_str_equals( $editor, $driver->find_widget( '.' ) );
$driver->enter_text( 'editor', " More text.\cA\cP" );
$self->assert_str_equals( $two_lines . " More text.", $editor->text() );
$self->assert_equals( 0, $editor->pos() );
$driver->enter_text( 'viewer', "Text" );
$self->assert_equals( 0, $editor->{'-focus'} );
$self->assert_equals( 1, $viewer->{'-focus'} );
$self->assert_str_equals( '', $viewer->text() );
$driver->enter_text( 'entry', "This is some text." );
$self->assert_equals( 1, $entry->{'-focus'} );
$self->assert_str_equals( 'Thisissometext', $entry->get() );
}
sub test_enter_key {
my $self = $_[0];
my $driver = $self->{'driver'};
my $ui = new Curses::UI();
my $widget_cb;
$driver->set_curses_ui( $ui );
my $win = $ui->add( 'win', 'Window' );
my $entry = $win->add( 'entry', 'TextEntry',
-onchange => sub { $widget_cb = shift }
);
$self->assert_died( sub { $driver->enter_key() },
qr/missing 'path' parameter/ );
$self->assert_died( sub { $driver->enter_key( 'text' ) },
qr/missing 'char' parameter/ );
$self->assert_died( sub { $driver->enter_key( 'text', 'wawa' ) },
qr/'char' should be either an integer or a single character: 'wawa'/ );
$driver->enter_key( 'entry', 'T' );
$self->assert_str_equals( $entry, $widget_cb );
$self->assert_equals( 1, $entry->{'-focus'} );
$self->assert_str_equals( 'T', $entry->get() );
$self->assert_num_equals( 1, $entry->pos() );
$driver->enter_key( 'entry', KEY_HOME() );
$self->assert_str_equals( 'T', $entry->get() );
$self->assert_num_equals( 0, $entry->pos() );
}
sub test_select_items {
my $self = $_[0];
my $driver = $self->{'driver'};
my $ui = new Curses::UI();
$driver->set_curses_ui( $ui );
my $win = $ui->add( 'win', 'Window' );
my ( $radio_cb, $list_cb, $pop_cb);
my $radio = $win->add( 'radio', 'Radiobuttonbox',
-values => [ 'radio1', 'radio2', 'radio3' ],
-labels => { 'radio3' => 'Radio Button3' },
-onchange => sub { $radio_cb = shift } );
my $list = $win->add( 'list', 'Listbox',
-multi => 1,
-values => [ 'option1', 'option2', 'option3' ],
-onchange => sub { $list_cb = shift } );
my $pop = $win->add( 'pop', 'Popupmenu',
-values => [ 'menu1', 'menu2', 'menu3' ],
-onchange => sub { $pop_cb = shift } );
$self->assert_died( sub { $driver->select_items() },
qr/missing 'path' parameter/ );
$self->assert_died( sub { $driver->select_items( 'radio' ) },
qr/at least one 'item' parameter is required/ );
$self->assert_died( sub { $driver->select_items( '/win', 'option1' ) },
qr{'/win' should be a Curses::UI::Listbox or Curses::UI::Popupmenu widget, not 'Curses::UI::Window} );
$self->assert_died( sub { $driver->select_items( 'radio', 'radio1', 'radio2' ) },
qr{'/win/radio' doesn't support multi-selection} );
$self->assert_died( sub { $driver->select_items( 'pop', 'menu1', 'menu2' ) },
qr{'/win/pop' doesn't support multi-selection} );
$self->assert_died( sub { $driver->select_items( 'list', 'option1', 'option4' ) },
qr{'/win/list' doesn't have any 'option4' item} );
$self->assert_died( sub { $driver->select_items( 'radio', 'radio3' ) },
qr{'/win/radio' doesn't have any 'radio3' item} );
$driver->select_items( 'radio', 'Radio Button3' );
$self->assert_str_equals( 'radio3', $radio->get() );
$self->assert_str_equals( $radio, $radio_cb );
$driver->select_items( 'pop', 'menu3' );
$self->assert_str_equals( 'menu3', $pop->get() );
$self->assert_str_equals( $pop, $pop_cb );
$pop_cb = undef;
$driver->select_items( 'pop', 'menu3' );
$self->assert_null( $pop_cb, 'callback was called' );
$driver->select_items( 'list', 'option1', 'option2', 'option3' );
$self->assert_deep_equals( [ 'option1', 'option2', 'option3' ] ,
[ sort $list->get() ] );
$self->assert_str_equals( $list, $list_cb );
}
sub test_widget_displayed_labels {
my $self = $_[0];
my $driver = $self->{'driver'};
my $empty_widget = { '-values' => [] };
my $widget_no_labels = { '-values' => [ 1, 2, 3 ] };
my $widget = { '-values' => [ 1, 2, 'c' ],
'-labels' => { '1' => 'a', '2' => 'b' } };
$self->assert_deep_equals( [], $driver->_widget_displayed_labels( $empty_widget ) );
$self->assert_deep_equals( [ 1, 2, 3 ], $driver->_widget_displayed_labels( $widget_no_labels ) );
$self->assert_deep_equals( [ 'a', 'b', 'c' ], $driver->_widget_displayed_labels( $widget ) );
}
sub test_event_loop_dispatcher {
my $self = $_[0];
my $driver = $self->{'driver'};
my $ui = new Curses::UI();
$driver->set_curses_ui( $ui );
$self->assert_died( sub { $driver->event_loop_dispatcher() },
qr/no event loop handlers available in current CursesUIDriver/ );
my $called = 0;
my $widget = { '-has_modal_focus' => 1 };
$driver->{'_event_loop_handlers'} = [ sub { $called = [ @_ ] } ];
$driver->event_loop_dispatcher( $driver->{'_ui'}, $widget );
$self->assert_deep_equals( [ $driver->{'_ui'}, $widget], $called );
$self->assert_equals( 0, $widget->{'-has_modal_focus'} );
$self->assert_deep_equals( [], $driver->{'_event_loop_handlers'} );
# Test that the closure dispatching is working
push @{$driver->{'_event_loop_handlers'}}, sub { $called = shift };
$driver->{'_ui'}->do_one_event();
$self->assert_str_equals( $driver->{'_ui'}, $called );
}
sub test_add_event_loop_handler {
my $self = $_[0];
my $driver = $self->{'driver'};
$self->assert_deep_equals( [], $driver->{'_event_loop_handlers'} );
$self->assert_died( sub { $driver->add_event_loop_handler() },
qr/missing 'handler' parameter/ );
$self->assert_died( sub { $driver->add_event_loop_handler( {} ) },
qr/'handler' should be a CODE ref, not 'HASH/ );
my $handler1 = sub {};
my $handler2 = sub {};
$driver->add_event_loop_handler( $handler1 );
$self->assert_deep_equals( [ $handler1 ],
$driver->{'_event_loop_handlers'} );
$driver->add_event_loop_handler( $handler2 );
$self->assert_deep_equals( [ $handler1, $handler2 ],
$driver->{'_event_loop_handlers'} );
}
1;
syntax highlighted by Code2HTML, v. 0.9.1