package tests::UITest; use strict; use base qw/Test::Unit::TestSuite/; sub name { return "Lire::LireUI Tests"; } sub include_tests { return qw/tests::UITest::init tests::UITest::api /; } package tests::UITest::init; use base qw/Lire::Test::TestCase/; use Curses; use Lire::UI; use Lire::Test::CursesUIDriver; sub set_up { my $self = $_[0]; $self->SUPER::set_up(); $self->{'driver'} = new Lire::Test::CursesUIDriver(); $self->{'driver'}->setup_curses_ui(); $self->{'ui'} = bless { '_ui' => new Curses::UI() }, 'Lire::UI'; $self->{'driver'}->set_curses_ui( $self->{'ui'}{'_ui'} ); return; } sub tear_down { my $self = $_[0]; $self->SUPER::tear_down(); $self->{'driver'}->teardown_curses_ui(); return; } sub test_create_menubar { my $self = $_[0]; $self->{'ui'}->_create_menubar(); my $mbar = $self->{'ui'}{'_ui'}->getobj( 'menubar' ); $self->assert_isa( 'Curses::UI::Menubar', $mbar ); my @menus = map { $_->{'-label'} } @{$mbar->{'-menu'}}; $self->assert_deep_equals( [ 'Lire', 'Store' ], \@menus ); my @menu_cbs = ( [ \&Lire::UI::_lire_about_cb, \&Lire::UI::_lire_prefs_cb, \&Lire::UI::_lire_quit_cb ], [ \&Lire::UI::_store_new_cb, \&Lire::UI::_store_open_cb ] ); for ( my $menu_idx = 0; $menu_idx < @menu_cbs; $menu_idx++ ) { my $menu_cb = $menu_cbs[$menu_idx]; for ( my $i=0; $i < @$menu_cb; $i++ ) { my $menu_def = $mbar->{'-menu'}[$menu_idx]{'-submenu'}[$i]; $self->assert_str_equals( $menu_def->{'-value'}, $menu_cb->[$i], "'$menu_def->{'-label'}''s callback isn't set properly" ); } } $self->assert_str_equals( '__routine_' . \&Lire::UI::_focus_menubar_cb, $self->{'ui'}{'_ui'}{'-bindings'}{KEY_F(10)} ); } sub test_focus_menubar_cb { my $self = $_[0]; my $ui = $self->{'ui'}; $ui->_create_menubar(); $ui->_create_quickstart_win(); $ui->{'_ui'}->getobj( 'quickstart_win' )->focus(); my $mbar = $ui->{'_ui'}->getobj( 'menubar' ); $self->assert_equals( 0, $mbar->{'-focus'} ); Lire::UI::_focus_menubar_cb( $ui->{'_ui'} ); $self->assert_equals( 1, $mbar->{'-focus'} ); } sub test_create_quickstart_win { my $self = $_[0]; $self->{'ui'}->_create_quickstart_win(); my $win = $self->{'ui'}{'_ui'}->getobj( 'quickstart_win' ); $self->assert_isa( 'Curses::UI::Window', $win ); my $viewer = $win->getobj( 'text_viewer' ); $self->assert_isa( 'Curses::UI::TextViewer', $viewer ); } package tests::UITest::api; use base qw/Lire::Test::TestCase tests::TestStoreFixture/; use Lire::Config; use Lire::UI; use Lire::Test::CursesUIDriver; use Lire::Config::TypeSpec; use Lire::Config::ConfigFile; use Lire::Utils qw/tempdir create_file/; use Curses::UI::Dialog::Status; sub new { my $self = shift->SUPER::new( @_ ); $self->tests::TestStoreFixture::init(); return $self; } sub set_up { my $self = $_[0]; $self->SUPER::set_up(); $self->set_up_test_store(); $self->{'driver'} = new Lire::Test::CursesUIDriver(); $self->{'driver'}->setup_curses_ui(); $self->{'ui'} = new Lire::UI(); $self->{'driver'}->set_curses_ui( $self->{'ui'}->curses_ui() ); $self->{'cfg'}{'_lr_config_spec'} = $self->lire_default_config_spec(); $self->{'cfg'}{'lr_templates_path'} = []; $self->{'cfg_file'} = "$self->{'tmpdir'}/.lire/config.xml"; mkdir "$self->{'tmpdir'}/.lire"; $self->{'parsed_cfg'} = new Lire::Config::ConfigFile( 'spec'=> $self->{'cfg'}{'_lr_config_spec'}, 'filename' => $self->{'cfg_file'} ); $self->{'parsed_cfg'}->save(); return; } sub set_up_import_jobs { my $self = $_[0]; my $spec = $self->{'cfg'}{'_lr_config_spec'}; my $jobs = $spec->get( 'import_jobs' )->instance(); $self->{'cfg'}{ 'import_jobs' } = $jobs; my $job = $spec->get( 'import_jobs' )->get( 'import_job' )->instance(); $job->get( 'name' )->set( 'aJob' ); $job->get( 'filter' )->set( '' ); $job->get( 'log_encoding' )->set( 'UTF-8' ); $job->get( 'log_file' )->set( 'a file' ); $job->get( 'period' )->set( 'hourly' ); $job->get( 'service' )->set_plugin( 'www' ); $jobs->append( $job ); } sub tear_down { my $self = $_[0]; $self->SUPER::tear_down(); $self->{'driver'}->teardown_curses_ui(); return; } sub test_new { my $self = $_[0]; my $ui = $self->{'ui'}; $self->assert_isa( 'Lire::UI', $ui ); $self->assert_isa( 'Curses::UI', $ui->{'_ui'} ); $self->assert_str_equals( $ui, $ui->{'_ui'}->userdata() ); $self->assert_not_null( $ui->{'_ui'}->getobj( 'quickstart_win' ), "was _create_quickstart_win() called?" ); $self->assert_not_null( $ui->{'_ui'}->getobj( 'menubar' ), "was _create_menubar() called?" ); } sub test_quit_cb { my $self = $_[0]; $self->assert_dies( qr/^Quit$/, sub { $self->{'ui'}->_lire_quit_cb( $self->{'ui'}{'_ui'} )} ); } sub test_mainloop { my $self = $_[0]; my $called = 0; $self->{'driver'}->add_event_loop_handler( sub { $called++ } ); $self->{'driver'}->add_event_loop_handler( sub { die "Quit\n" } ); my $rc = $self->{'ui'}->mainloop(); $self->assert_equals( 1, $called ); $self->assert_equals( 0, $rc ); my $err_dialog; $self->{'driver'}->add_event_loop_handler( sub { die "Error\n" } ); $self->{'driver'}->add_event_loop_handler( sub { $err_dialog = $_[1]; } ); $rc = $self->{'ui'}->mainloop(); $self->assert_equals( 1, $rc ); $self->assert_isa( "Curses::UI::Dialog::Error", $err_dialog ); $self->assert_str_equals( $err_dialog->{'-message'}, "An error occured: Error\n" ); my $warn_dialog; no warnings 'redefine'; my $or_status_new = \&Curses::UI::Dialog::Status::new; local *Curses::UI::Dialog::Status::new = sub() { $warn_dialog = $or_status_new->( @_ ) }; $self->{'driver'}->add_event_loop_handler( sub { warn "Warning\n"; die "Quit\n"} ); $self->{'driver'}->add_event_loop_handler( sub { $warn_dialog = $_[1]; } ); $rc = $self->{'ui'}->mainloop(); $self->assert_equals( 0, $rc ); $self->assert( "Curses::UI::Dialog::Status", $warn_dialog ); $self->assert_str_equals( $warn_dialog->{'-message'}, "Warning\n" ); } sub test_cleanup { my $self = $_[0]; my $cui = $self->{'ui'}{'_ui'}; $cui->userdata( $self->{'ui'} ); $self->{'ui'}->cleanup(); $self->assert_null( $self->{'ui'}{'_ui'}, "'_ui' attribute should be null" ); $self->assert_null( $cui->userdata(), "userdata() should be null" ); } sub test_lire_about_cb { my $self = $_[0]; my $driver = $self->{'driver'}; my $about_dlg = ''; $driver->add_event_loop_handler( sub { $about_dlg = $_[1] } ); Lire::UI::_lire_about_cb( $self->{'ui'}{'_ui'} ); $self->assert_isa( "Curses::UI::Dialog::Basic", $about_dlg ); $self->assert_matches( qr/\(c\) 2000-2004/, $about_dlg->{'-message'} ); $self->assert_matches( qr/logreport\@logreport.org/, $about_dlg->{'-message'} ); $self->assert_matches( qr/About/, $about_dlg->{'-title'} ); } sub test_lire_prefs_cb { my $self = $_[0]; local $ENV{'HOME'} = $self->{'tmpdir'}; no warnings 'redefine'; local *Lire::Test::HashConfig::config_files = sub { $self->{'cfg_file'} }; local *Lire::Test::HashConfig::get_config_file = sub { return $self->{'parsed_cfg'} }; my $driver = $self->{'driver'}; my $prefs_dlg = ''; $driver->add_event_loop_handler( sub { $prefs_dlg = $_[1] } ); Lire::UI::_lire_prefs_cb( $self->{'ui'}{'_ui'} ); $self->assert_isa( "Curses::UI::Window", $prefs_dlg ); my $prefs_ui = $prefs_dlg->userdata() || ''; $self->assert_isa( 'Lire::UI::Prefs', $prefs_ui ); } sub test_store_new_cb_ok { my $self = $_[0]; my $dlg = ''; $self->{'driver'}->add_event_loop_handler( sub { $dlg = $_[1]; $dlg->getobj('pathvalue')->text( $self->{'tmpdir'} ); $dlg->getobj('filevalue')->text( 'new_store' ); $dlg->getobj('buttons')->{'-selected'} = 0; } ); Lire::UI::_store_new_cb( $self->{'ui'}{'_ui'} ); $self->assert_isa( 'Curses::UI::Dialog::Filebrowser', $dlg ); $self->assert( -d $self->{'tmpdir'} . '/new_store', "'$self->{'tmpdir'}/new_store' not created" ); my $store_win = $self->{'driver'}->top_window(); $self->assert_str_equals( $self->{'driver'}->find_widget( '/store_win' ), $store_win ); my $store = $store_win->store() || ''; $self->assert_isa( 'Lire::DlfStore', $store ); $self->assert_str_equals( "$self->{'tmpdir'}/new_store", $store->path() ); } sub test_store_new_cb_error { my $self = $_[0]; create_file( "$self->{'tmpdir'}/new_store", "" ); $self->{'driver'}->add_event_loop_handler( sub { my $dlg = $_[1]; $dlg->getobj('pathvalue')->text( $self->{'tmpdir'} ); $dlg->getobj('filevalue')->text( 'new_store' ); $dlg->getobj('buttons')->{'-selected'} = 0; } ); # Acknowledge dialog my $dlg = ''; $self->{'driver'}->add_event_loop_handler( sub { $dlg = $_[1] } ); Lire::UI::_store_new_cb( $self->{'ui'}{'_ui'} ); $self->assert_isa( "Curses::UI::Dialog::Error", $dlg ); $self->assert_matches( qr/Error creating store:\n can't create DLF/, $dlg->{'-message'},); } sub test_store_new_cb_cancel { my $self = $_[0]; my $dlg = ''; $self->{'driver'}->add_event_loop_handler( sub { $dlg = $_[1]; $dlg->getobj('pathvalue')->text( $self->{'tmpdir'} ); $dlg->getobj('filevalue')->text( 'new_store' ); $dlg->getobj('buttons')->{'-selected'} = 1; } ); Lire::UI::_store_new_cb( $self->{'ui'}{'_ui'} ); $self->assert( ! -d $self->{'tmpdir'} . '/new_store', "'$self->{'tmpdir'}/new_store' was created unexpectedly" ); $self->assert_str_equals($self->{'driver'}->find_widget('/quickstart_win'), $self->{'driver'}->top_window() ); return; } sub test_store_open_cb_ok { my $self = $_[0]; $self->{'store'}->close(); my $dlg = ''; $self->{'driver'}->add_event_loop_handler( sub { $dlg = $_[1]; $dlg->getobj('pathvalue')->text( $self->{'store'}->path() ); $dlg->getobj('buttons')->{'-selected'} = 0; } ); Lire::UI::_store_open_cb( $self->{'ui'}{'_ui'} ); $self->assert_isa( 'Curses::UI::Dialog::Dirbrowser', $dlg ); my $store_win = $self->{'driver'}->top_window(); $self->assert_str_equals( $self->{'driver'}->find_widget( '/store_win' ), $store_win ); my $store = $store_win->store() || ''; $self->assert_isa( 'Lire::DlfStore', $store ); $self->assert_str_equals( $self->{'store'}->path(), $store->path() ); } sub test_store_open_cb_cancel { my $self = $_[0]; $self->{'driver'}->add_event_loop_handler( sub { my $dlg = $_[1]; $dlg->getobj('pathvalue')->text( $self->{'store'}->path() ); $dlg->getobj('buttons')->{'-selected'} = 1; } ); Lire::UI::_store_open_cb( $self->{'ui'}{'_ui'} ); $self->assert_str_equals($self->{'driver'}->find_widget('/quickstart_win'), $self->{'driver'}->top_window() ); return; } sub test_store_open_cb_error { my $self = $_[0]; create_file( "$self->{'tmpdir'}/new_store", "" ); $self->{'driver'}->add_event_loop_handler( sub { my $dlg = $_[1]; $dlg->getobj('pathvalue')->text( "$self->{'tmpdir'}/new_store" ); $dlg->getobj('buttons')->{'-selected'} = 0; } ); # Acknowledge dialog my $dlg = ''; $self->{'driver'}->add_event_loop_handler( sub { $dlg = $_[1] } ); Lire::UI::_store_open_cb( $self->{'ui'}{'_ui'} ); $self->assert_isa( "Curses::UI::Dialog::Error", $dlg ); $self->assert_matches( qr/Error opening store:\n DlfStore /, $dlg->{'-message'},); } sub test_get_config_file { my $self = $_[0]; local $ENV{'HOME'} = $self->{'tmpdir'}; my @files = ( $self->{'cfg_file'} ); my %parsed_files = ( $self->{'cfg_file'} => 'Success' ); no warnings 'redefine'; local *Lire::Test::HashConfig::config_files = sub { return @files }; local *Lire::Test::HashConfig::add_config_file = sub { push @files, $_[1] }; local *Lire::Test::HashConfig::get_config_file = sub { return $parsed_files{$_[1]} }; unlink $self->{'cfg_file'}; $self->assert_str_equals( 'Success', $self->{'ui'}->_get_config_file() ); $self->assert_deep_equals( [ $self->{'cfg_file'} ], \@files ); $self->assert( !-f $self->{'cfg_file'}, "'$self->{'cfg_file'}' shouldn't exists" ); @files = (); $self->assert_str_equals( 'Success', $self->{'ui'}->_get_config_file() ); $self->assert_deep_equals( [ $self->{'cfg_file'} ], \@files ); $self->assert( -s $self->{'cfg_file'}, "empty '$self->{'cfg_file'}'" ); } sub test_update_store_menu { my $self = $_[0]; $self->{'ui'}->_update_store_menu( 1 ); my $store_menu = $self->{'driver'}->find_menu_def( 'menubar/Store' ); $self->assert_deep_equals( [ { '-label' => 'Close', '-value' => \&Lire::UI::_store_close_cb } ], $store_menu->{'-submenu'} ); $self->{'ui'}->_update_store_menu( 0 ); $self->assert_deep_equals( [ { '-label' => 'New...', '-value' => \&Lire::UI::_store_new_cb }, { '-label' => 'Open...', '-value' => \&Lire::UI::_store_open_cb } ], $store_menu->{'-submenu'} ); } sub test_store_close_cb { my $self = $_[0]; $self->{'ui'}->_open_store_window( $self->{'store'} ); Lire::UI::_store_close_cb( $self->{'ui'}{'_ui'} ); $self->assert_null( $self->{'ui'}{'_ui'}->getobj( 'store_win' ), 'store_win should be closed' ); $self->assert( $self->{'store'}->is_closed(), 'store should have been closed' ); my $menubar = $self->{'driver'}->find_widget( '/menubar' ); $self->assert_equals( 'New...', $menubar->{'-menu'}[1]->{'-submenu'}[0]{'-label'} ); } sub test_open_store_window { my $self = $_[0]; $self->{'ui'}->_open_store_window( $self->{'store'} ); my $store_win = $self->{'driver'}->top_window(); $self->assert_str_equals( $self->{'driver'}->find_widget( '/store_win' ), $store_win ); $self->assert_isa( 'Lire::UI::StoreWindow', $store_win ); my $store = $store_win->store() || ''; $self->assert_isa( 'Lire::DlfStore', $store ); my $menubar = $self->{'driver'}->find_widget( '/menubar' ); $self->assert_equals( 'Close', $menubar->{'-menu'}[1]->{'-submenu'}[0]{'-label'} ); } sub test_edit_value { my $self = $_[0]; my $value = new Lire::Config::StringSpec( 'name' => 'string' )->instance(); my $ui = $self->{'ui'}; my $ok_sub = sub { my $dialog = $_[1]; $self->assert_str_equals( 'My title', $dialog->title() ); my $widget = $dialog->getobj( 'widget' ); $self->assert_isa( 'Lire::UI::Widget', $widget ); $self->assert_str_equals( $value, $widget->{'value'} ); my $buttons = $dialog->getobj( 'buttons' ); $buttons->{'-buttons'}[1]{'-onpress'}->(); }; $self->{'driver'}->add_event_loop_handler( $ok_sub ); $self->assert_num_equals( 1, $ui->edit_value_dialog( $value, 'My title' ) ); my $cancel_sub = sub { my $dialog = $_[1]; $self->assert_str_equals( 'Editing string', $dialog->title() ); my $buttons = $dialog->getobj( 'buttons' ); $buttons->{'-buttons'}[0]{'-onpress'}->(); }; $self->{'driver'}->add_event_loop_handler( $cancel_sub ); $self->assert_num_equals( 0, $ui->edit_value_dialog( $value ) ); return; } 1;