#!/usr/bin/env perl use strict; use warnings; use 5.010; 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 [1 of 2] - test/ok/png'); SendKeys('{DEL}'); test_win_title($win, 'feh [1 of 1] - test/ok/jpg'); 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();