#!/usr/bin/env perl use strict; use warnings; use 5.010; no if $] >= 5.018, warnings => 'experimental::smartmatch'; use Cwd; use Test::More tests => 103; use Time::HiRes qw/sleep/; use X11::GUITest qw/:ALL/; my $win; my ( $width, $height ); my $pwd = getcwd(); $ENV{HOME} = 'test'; sub waitfor(&) { my ($sub) = @_; my $out; for ( 1 .. 40 ) { sleep(0.05); $out = &{$sub}; if ($out) { return $out; } } return 0; } sub feh_start { my ( $opts, $files ) = @_; my $id; $opts //= q{}; $files //= 'test/ok/png'; StartApp("feh ${opts} ${files}"); ($id) = WaitWindowViewable(qr{^feh}); if ( not $id ) { BAIL_OUT("Unable to start feh ${opts} ${files}"); } if ( not SetInputFocus($id) ) { BAIL_OUT("Unable to focus window"); } return $id; } sub feh_stop { SendKeys('{ESC}'); if ( not waitfor { not FindWindowLike(qr{^feh}) } ) { BAIL_OUT("Unclosed feh window still open, cannot continue"); } } sub test_no_win { my ($reason) = @_; if ( waitfor { not FindWindowLike(qr{^feh}) } ) { pass("Window closed ($reason)"); } else { fail("Window closed ($reason)"); BAIL_OUT("unclosed window still open, cannot continue"); } } sub test_win_title { my ( $win, $wtitle ) = @_; my $rtitle; if ( waitfor { GetWindowName($win) eq $wtitle } ) { pass("Window has title: $wtitle"); } else { $rtitle = GetWindowName($win); fail("Window has title: $wtitle"); diag("expected: $wtitle"); diag(" got: $rtitle"); } } sub slurp { my ($file) = @_; my $ret; local $/ = undef; open( my $fh, '<', $file ) or die("Can't open $file: $!"); $ret = <$fh>; close($fh) or die("Can't close $file: $!"); return ($ret); } if ( FindWindowLike(qr{^feh}) ) { BAIL_OUT('It appears you have an open feh window. Please close it.'); } for my $key (qw/q x {ESC}/) { feh_start(); SendKeys($key); test_no_win("$key pressed"); } $win = feh_start( q{}, 'test/ok/png' ); test_win_title( $win, 'feh [1 of 1] - test/ok/png' ); feh_stop(); $win = feh_start( q{}, 'test/ok/png test/ok/jpg test/ok/gif' ); test_win_title( $win, 'feh [1 of 3] - test/ok/png' ); SendKeys('{RIG}'); test_win_title( $win, 'feh [2 of 3] - test/ok/jpg' ); SendKeys('n'); test_win_title( $win, 'feh [3 of 3] - test/ok/gif' ); SendKeys('{SPA}'); test_win_title( $win, 'feh [1 of 3] - test/ok/png' ); SendKeys('{LEF}'); test_win_title( $win, 'feh [3 of 3] - test/ok/gif' ); SendKeys('p'); test_win_title( $win, 'feh [2 of 3] - test/ok/jpg' ); SendKeys('{BAC}'); test_win_title( $win, 'feh [1 of 3] - test/ok/png' ); SendKeys('p'); test_win_title( $win, 'feh [3 of 3] - test/ok/gif' ); SendKeys('{DEL}'); test_win_title( $win, 'feh [2 of 2] - test/ok/jpg' ); SendKeys('{DEL}'); test_win_title( $win, 'feh [1 of 1] - test/ok/png' ); SendKeys('{DEL}'); test_no_win("Removed all images from slideshow"); $win = feh_start( '--title \'feh %m %u/%l %n\'', 'test/ok/png test/ok/jpg test/ok/gif' ); test_win_title( $win, 'feh slideshow 1/3 png' ); SendKeys('{RIG}'); test_win_title( $win, 'feh slideshow 2/3 jpg' ); feh_stop(); feh_start( '--cycle-once', 'test/ok/png test/ok/jpg' ); for ( 1 .. 2 ) { SendKeys('{RIG}'); } test_no_win("--cycle-once -> window closed"); feh_start( '--cycle-once --slideshow-delay 0.5', 'test/ok/png test/ok/jpg test/ok/gif' ); sleep(1.5); test_no_win('cycle-once + slideshow-delay -> window closed'); $win = feh_start( '--cycle-once --slideshow-delay -0.01', 'test/ok/png test/ok/jpg test/ok/gif' ); test_win_title( $win, 'feh [1 of 3] - test/ok/png [Paused]' ); SendKeys('h'); test_no_win('cycle-once + negative delay + [h]'); $win = feh_start( q{}, 'test/ok/png test/ok/gif test/ok/gif test/ok/jpg' ); for ( 1 .. 2 ) { SendKeys('{END}'); test_win_title( $win, 'feh [4 of 4] - test/ok/jpg' ); } for ( 1 .. 2 ) { SendKeys('{HOM}'); test_win_title( $win, 'feh [1 of 4] - test/ok/png' ); } SendKeys('{PGU}'); test_win_title( $win, 'feh [4 of 4] - test/ok/jpg' ); SendKeys('{PGD}'); test_win_title( $win, 'feh [1 of 4] - test/ok/png' ); SendKeys('{PGD}'); test_win_title( $win, 'feh [2 of 4] - test/ok/gif' ); feh_stop(); $win = feh_start( '--slideshow-delay 1', 'test/ok/png test/ok/gif test/ok/jpg' ); sleep(1.7); test_win_title( $win, 'feh [3 of 3] - test/ok/jpg' ); SendKeys('h'); test_win_title( $win, 'feh [3 of 3] - test/ok/jpg [Paused]' ); SendKeys('{RIG}'); test_win_title( $win, 'feh [1 of 3] - test/ok/png [Paused]' ); SendKeys('h'); test_win_title( $win, 'feh [1 of 3] - test/ok/png' ); sleep(0.8); test_win_title( $win, 'feh [2 of 3] - test/ok/gif' ); feh_stop(); $win = feh_start( '--action3 ";echo foo" --action7 "echo foo" ' . '--action8 ";touch feh_test_%u_%l" --action9 "rm feh_test_%u_%l"', 'test/ok/png test/ok/gif test/ok/jpg' ); test_win_title( $win, 'feh [1 of 3] - test/ok/png' ); SendKeys('3'); test_win_title( $win, 'feh [1 of 3] - test/ok/png' ); SendKeys('7'); test_win_title( $win, 'feh [2 of 3] - test/ok/gif' ); SendKeys('8'); test_win_title( $win, 'feh [2 of 3] - test/ok/gif' ); ok( -e 'feh_test_2_3', 'feh action created file with correct format specifiers' ); SendKeys('9'); ok( waitfor { not -e 'feh_test_2_3' }, 'feh action removed file' ); test_win_title( $win, 'feh [3 of 3] - test/ok/jpg' ); feh_stop(); # .config/feh/keys # Action Unbinding + non-conflicting none/shift/control/meta modifiers $ENV{XDG_CONFIG_HOME} = 'test/config/keys'; $win = feh_start( '--action1 "touch a1" --action2 "touch a2" ' . '--action3 "touch a3" --action4 "touch a4" ' . '--action5 "touch a5" --action6 "touch a6" ', 'test/ok/png test/ok/jpg test/ok/pnm' ); test_win_title( $win, 'feh [1 of 3] - test/ok/png' ); SendKeys('6'); test_win_title( $win, 'feh [1 of 3] - test/ok/png' ); SendKeys('{RIG}'); test_win_title( $win, 'feh [1 of 3] - test/ok/png' ); SendKeys('a'); test_win_title( $win, 'feh [2 of 3] - test/ok/jpg' ); SendKeys('b'); test_win_title( $win, 'feh [3 of 3] - test/ok/pnm' ); SendKeys('c'); test_win_title( $win, 'feh [1 of 3] - test/ok/png' ); SendKeys('d'); test_win_title( $win, 'feh [3 of 3] - test/ok/pnm' ); SendKeys('e'); test_win_title( $win, 'feh [2 of 3] - test/ok/jpg' ); SendKeys('f'); test_win_title( $win, 'feh [1 of 3] - test/ok/png' ); SendKeys('1'); test_win_title( $win, 'feh [1 of 3] - test/ok/png' ); SendKeys('x'); ok( waitfor { -e 'a1' }, 'action 1 = X ok' ); SendKeys('X'); ok( waitfor { -e 'a2' }, 'action 2 = Shift+X ok' ); SendKeys('^(x)'); ok( waitfor { -e 'a3' }, 'action 3 = Ctrl+X ok' ); SendKeys('^(X)'); ok( waitfor { -e 'a4' }, 'action 4 = Ctrl+Shift+X ok' ); SendKeys('%(x)'); ok( waitfor { -e 'a5' }, 'action 5 = Alt+X ok' ); for my $f (qw(a1 a2 a3 a4 a5)) { unlink($f); } feh_stop(); $ENV{XDG_CONFIG_HOME} = 'test/config/themes'; $win = feh_start( '-Ttest_general', 'test/ok/png test/ok/jpg' ); SendKeys('1'); ok( waitfor { -e 'a1' }, 'theme: action 1 okay' ); unlink('a1'); feh_stop(); $win = feh_start( '-Ttest_general --action1 "touch c1"', 'test/ok/png test/ok/jpg' ); SendKeys('1'); ok( waitfor { -e 'c1' }, 'theme: commandline overrides theme' ); unlink('c1'); feh_stop(); $win = feh_start( '-Ttest_multiline', 'test/ok/png test/ok/jpg' ); SendKeys('1'); ok( waitfor { -e 'a1' }, 'multiline theme: first line ok' ); SendKeys('2'); ok( waitfor { -e 'a2' }, 'multiline theme: second line ok' ); SendKeys('3'); ok( waitfor { -e 'a3' }, 'multiline theme: last line ok' ); for my $f (qw(a1 a2 a3)) { unlink($f); } feh_stop(); delete $ENV{XDG_CONFIG_HOME}; $win = feh_start( q{}, 'test/ok/png ' x 100 ); test_win_title( $win, 'feh [1 of 100] - test/ok/png' ); SendKeys('{PGD}'); test_win_title( $win, 'feh [6 of 100] - test/ok/png' ); SendKeys('{PGD}'); test_win_title( $win, 'feh [11 of 100] - test/ok/png' ); SendKeys('{HOM PGU}'); test_win_title( $win, 'feh [96 of 100] - test/ok/png' ); feh_stop(); $win = feh_start( '--thumbnails -H 300 -W 310 --thumb-title "feh [%l] %f"', 'test/ok/png test/ok/gif test/ok/jpg' ); test_win_title( $win, 'feh [thumbnail mode]' ); ( $width, $height ) = ( GetWindowPos($win) )[ 2, 3 ]; is( $width, 310, 'thumbnail win: Set correct width' ); is( $height, 300, 'thumbnail win: Set correct height' ); MoveMouseAbs( 30, 30 ); ClickMouseButton(M_BTN1); ($win) = WaitWindowViewable(qr{test/ok/png$}); ok( $win, 'Thumbnail mode: Window opened' ); test_win_title( $win, 'feh [3] test/ok/png' ); SetInputFocus($win); SendKeys('x'); ok( waitfor { not FindWindowLike(qr{^ok/png$}) }, 'Thumbnail mode: closed' ); MoveMouseAbs( 90, 30 ); ClickMouseButton(M_BTN1); ($win) = WaitWindowViewable(qr{test/ok/gif$}); ok( $win, 'Thumbnail mode: Window opened' ); test_win_title( $win, 'feh [3] test/ok/gif' ); MoveMouseAbs( 150, 30 ); ClickMouseButton(M_BTN1); ($win) = WaitWindowViewable(qr{test/ok/jpg$}); ok( $win, 'Thumbnail mode: Other window opened' ); test_win_title( $win, 'feh [3] test/ok/jpg' ); feh_stop(); feh_start( '--multiwindow', 'test/ok/png test/ok/gif test/ok/jpg' ); ok( waitfor { FindWindowLike(qr{^feh - test/ok/png$}) }, 'multiwindow 1/3' ); ok( waitfor { FindWindowLike(qr{^feh - test/ok/gif$}) }, 'multiwindow 2/3' ); ok( waitfor { FindWindowLike(qr{^feh - test/ok/jpg$}) }, 'multiwindow 3/3' ); ($win) = FindWindowLike(qr{^feh - test/ok/gif$}); SetInputFocus($win); SendKeys('x'); ok( waitfor { not FindWindowLike(qr{^feh - test/ok/gif$}) }, 'win 1 closed' ); ok( FindWindowLike(qr{^feh - test/ok/png$}), 'multiwindow 1/2' ); ok( FindWindowLike(qr{^feh - test/ok/jpg$}), 'multiwindow 2/2' ); ($win) = FindWindowLike(qr{^feh - test/ok/jpg$}); SetInputFocus($win); SendKeys('x'); ok( waitfor { not FindWindowLike(qr{^feh - test/ok/jpg$}) }, 'win 2 closed' ); ($win) = FindWindowLike(qr{^feh - test/ok/png$}); SetInputFocus($win); SendKeys('x'); test_no_win('all multiwindows closed'); $win = feh_start( '--start-at test/ok/jpg', 'test/ok/png test/ok/gif test/ok/jpg' ); test_win_title( $win, 'feh [3 of 3] - test/ok/jpg' ); SendKeys('{RIG}'); test_win_title( $win, 'feh [1 of 3] - test/ok/png' ); feh_stop(); feh_start( '--caption-path .captions', 'test/ok/png' ); SendKeys('cFoo Bar Quux Moep~'); feh_stop(); ok( -d 'test/ok/.captions', 'autocreated captions directory' ); is( slurp('test/ok/.captions/png.txt'), 'Foo Bar Quux Moep', 'Correct caption saved' ); feh_start( '--caption-path .captions', 'test/ok/png' ); SendKeys('c'); SendKeys( '{BKS}' x length('Foo Bar Quux Moep') ); SendKeys('Foo Bar^(~)miep~'); feh_stop(); is( slurp('test/ok/.captions/png.txt'), "Foo Bar\nmiep", 'Caption with newline + correct backspace' ); unlink('test/ok/.captions/png.txt'); rmdir('test/ok/.captions'); $win = feh_start( '--filelist test/filelist', 'test/ok/png test/ok/gif test/ok/png test/ok/jpg' ); SendKeys('{DEL}'); test_win_title( $win, "feh [1 of 3] - ${pwd}/test/ok/gif" ); feh_stop(); is( slurp('test/filelist'), <<"EOF", 'Filelist saved' ); ${pwd}/test/ok/gif ${pwd}/test/ok/png ${pwd}/test/ok/jpg EOF $win = feh_start( '--filelist test/filelist', q{} ); test_win_title( $win, "feh [1 of 3] - ${pwd}/test/ok/gif" ); feh_stop(); unlink('test/filelist'); $win = feh_start('--geometry 423x232'); ( undef, undef, $width, $height ) = GetWindowPos($win); is( $width, 423, '--geometry: correct width' ); is( $height, 232, '--geometry: correct height' ); feh_stop(); $win = feh_start('--fullscreen'); ( undef, undef, $width, $height ) = GetWindowPos($win); ok( [ ( GetWindowPos($win) )[ 2, 3 ] ] ~~ [ GetScreenRes() ], 'fullscreen uses full screen size' ); feh_stop(); $win = feh_start( q{}, 'test/ok/png ' . 'test/fail/png ' x 7 . 'test/ok/gif' ); test_win_title( $win, 'feh [1 of 9] - test/ok/png' ); SendKeys('{RIG}'); test_win_title( $win, 'feh [2 of 2] - test/ok/gif' ); SendKeys('{LEF}'); test_win_title( $win, 'feh [1 of 2] - test/ok/png' ); SendKeys('{LEF}'); test_win_title( $win, 'feh [2 of 2] - test/ok/gif' ); feh_stop(); $win = feh_start(); ( undef, undef, $width, $height ) = GetWindowPos($win); is( $width, 16, 'correct default window width' ); is( $height, 16, 'correct default window height' ); ResizeWindow( $win, 25, 30 ); ( undef, undef, $width, $height ) = GetWindowPos($win); SKIP: { if ( not( [ $width, $height ] ~~ [ 25, 30 ] ) ) { skip( 'ResizeWindow failed', 2 ); } PressKey('w'); ok( waitfor { [ ( GetWindowPos($win) )[ 2, 3 ] ] ~~ [ 16, 16 ] }, 'w key resizes correctly' ); } feh_stop(); $win = feh_start( q{}, 'test/huge.png' ); ok( waitfor { ( GetWindowPos($win) )[2] == ( GetScreenRes() )[0] || ( GetWindowPos($win) )[3] == ( GetScreenRes() )[1]; }, 'Large window limited to screen size' ); feh_stop(); $win = feh_start( '--no-screen-clip', 'test/huge.png' ); ok( waitfor { [ ( GetWindowPos($win) )[ 2, 3 ] ] ~~ [ 4000, 3000 ]; }, 'disabled screen clip' ); feh_stop(); # GH-35 "Custom window title crashes feh on unloadable files" $win = feh_start( '--title "feh %h"', 'test/ok/png test/fail/png test/ok/jpg' ); SendKeys('{RIG}'); test_win_title( $win, 'feh 16' ); feh_stop();