Implement the tick event
This makes our tests less flaky, shorter, and more readable. fixes #2988
This commit is contained in:
@ -47,6 +47,8 @@ our @EXPORT = qw(
|
||||
wait_for_unmap
|
||||
$x
|
||||
kill_all_windows
|
||||
events_for
|
||||
listen_for_binding
|
||||
);
|
||||
|
||||
=head1 NAME
|
||||
@ -900,6 +902,86 @@ sub kill_all_windows {
|
||||
cmd '[title=".*"] kill';
|
||||
}
|
||||
|
||||
=head2 events_for($subscribecb, [ $rettype ], [ $eventcbs ])
|
||||
|
||||
Helper function which returns an array containing all events of type $rettype
|
||||
which were generated by i3 while $subscribecb was running.
|
||||
|
||||
Set $eventcbs to subscribe to multiple event types and/or perform your own event
|
||||
aggregation.
|
||||
|
||||
=cut
|
||||
sub events_for {
|
||||
my ($subscribecb, $rettype, $eventcbs) = @_;
|
||||
|
||||
my @events;
|
||||
$eventcbs //= {};
|
||||
if (defined($rettype)) {
|
||||
$eventcbs->{$rettype} = sub { push @events, shift };
|
||||
}
|
||||
my $subscribed = AnyEvent->condvar;
|
||||
my $flushed = AnyEvent->condvar;
|
||||
$eventcbs->{tick} = sub {
|
||||
my ($event) = @_;
|
||||
if ($event->{first}) {
|
||||
$subscribed->send($event);
|
||||
} else {
|
||||
$flushed->send($event);
|
||||
}
|
||||
};
|
||||
my $i3 = i3(get_socket_path(0));
|
||||
$i3->connect->recv;
|
||||
$i3->subscribe($eventcbs)->recv;
|
||||
$subscribed->recv;
|
||||
# Subscription established, run the callback.
|
||||
$subscribecb->();
|
||||
# Now generate a tick event, which we know we’ll receive (and at which point
|
||||
# all other events have been received).
|
||||
my $nonce = int(rand(255)) + 1;
|
||||
$i3->send_tick($nonce);
|
||||
|
||||
my $tick = $flushed->recv;
|
||||
$tester->is_eq($tick->{payload}, $nonce, 'tick nonce received');
|
||||
return @events;
|
||||
}
|
||||
|
||||
=head2 listen_for_binding($cb)
|
||||
|
||||
Helper function to evaluate whether sending KeyPress/KeyRelease events via XTEST
|
||||
triggers an i3 key binding or not. Expects key bindings to be configured in the
|
||||
form “bindsym <binding> nop <binding>”, e.g. “bindsym Mod4+Return nop
|
||||
Mod4+Return”.
|
||||
|
||||
is(listen_for_binding(
|
||||
sub {
|
||||
xtest_key_press(133); # Super_L
|
||||
xtest_key_press(36); # Return
|
||||
xtest_key_release(36); # Return
|
||||
xtest_key_release(133); # Super_L
|
||||
xtest_sync_with_i3;
|
||||
},
|
||||
),
|
||||
'Mod4+Return',
|
||||
'triggered the "Mod4+Return" keybinding');
|
||||
|
||||
=cut
|
||||
|
||||
sub listen_for_binding {
|
||||
my ($cb) = @_;
|
||||
my $triggered = AnyEvent->condvar;
|
||||
my @events = events_for(
|
||||
$cb,
|
||||
'binding');
|
||||
|
||||
$tester->is_eq(scalar @events, 1, 'Received precisely one event');
|
||||
$tester->is_eq($events[0]->{change}, 'run', 'change is "run"');
|
||||
# We look at the command (which is “nop <binding>”) because that is easier
|
||||
# than re-assembling the string representation of $event->{binding}.
|
||||
my $command = $events[0]->{binding}->{command};
|
||||
$command =~ s/^nop //g;
|
||||
return $command;
|
||||
}
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Michael Stapelberg <michael@i3wm.org>
|
||||
|
@ -20,8 +20,6 @@ our @EXPORT = qw(
|
||||
xtest_key_release
|
||||
xtest_button_press
|
||||
xtest_button_release
|
||||
listen_for_binding
|
||||
start_binding_capture
|
||||
binding_events
|
||||
);
|
||||
|
||||
@ -256,86 +254,6 @@ sub import {
|
||||
|
||||
=cut
|
||||
|
||||
my $i3;
|
||||
our @binding_events;
|
||||
|
||||
=head2 start_binding_capture()
|
||||
|
||||
Captures all binding events sent by i3 in the C<@binding_events> symbol, so
|
||||
that you can verify the correct number of binding events was generated.
|
||||
|
||||
my $pid = launch_with_config($config);
|
||||
start_binding_capture;
|
||||
# …
|
||||
sync_with_i3;
|
||||
is(scalar @i3test::XTEST::binding_events, 2, 'Received exactly 2 binding events');
|
||||
|
||||
=cut
|
||||
|
||||
sub start_binding_capture {
|
||||
# Store a copy of each binding event so that we can count the expected
|
||||
# events in test cases.
|
||||
$i3 = i3(get_socket_path());
|
||||
$i3->connect()->recv;
|
||||
$i3->subscribe({
|
||||
binding => sub {
|
||||
my ($event) = @_;
|
||||
@binding_events = (@binding_events, $event);
|
||||
},
|
||||
})->recv;
|
||||
}
|
||||
|
||||
=head2 listen_for_binding($cb)
|
||||
|
||||
Helper function to evaluate whether sending KeyPress/KeyRelease events via
|
||||
XTEST triggers an i3 key binding or not (with a timeout of 0.5s). Expects key
|
||||
bindings to be configured in the form “bindsym <binding> nop <binding>”, e.g.
|
||||
“bindsym Mod4+Return nop Mod4+Return”.
|
||||
|
||||
is(listen_for_binding(
|
||||
sub {
|
||||
xtest_key_press(133); # Super_L
|
||||
xtest_key_press(36); # Return
|
||||
xtest_key_release(36); # Return
|
||||
xtest_key_release(133); # Super_L
|
||||
},
|
||||
),
|
||||
'Mod4+Return',
|
||||
'triggered the "Mod4+Return" keybinding');
|
||||
|
||||
=cut
|
||||
|
||||
sub listen_for_binding {
|
||||
my ($cb) = @_;
|
||||
my $triggered = AnyEvent->condvar;
|
||||
my $i3 = i3(get_socket_path());
|
||||
$i3->connect()->recv;
|
||||
$i3->subscribe({
|
||||
binding => sub {
|
||||
my ($event) = @_;
|
||||
return unless $event->{change} eq 'run';
|
||||
# We look at the command (which is “nop <binding>”) because that is
|
||||
# easier than re-assembling the string representation of
|
||||
# $event->{binding}.
|
||||
$triggered->send($event->{binding}->{command});
|
||||
},
|
||||
})->recv;
|
||||
|
||||
my $t;
|
||||
$t = AnyEvent->timer(
|
||||
after => 0.5,
|
||||
cb => sub {
|
||||
$triggered->send('timeout');
|
||||
}
|
||||
);
|
||||
|
||||
$cb->();
|
||||
|
||||
my $recv = $triggered->recv;
|
||||
$recv =~ s/^nop //g;
|
||||
return $recv;
|
||||
}
|
||||
|
||||
=head2 set_xkb_group($group)
|
||||
|
||||
Changes the current XKB group from the default of 1 to C<$group>, which must be
|
||||
|
Reference in New Issue
Block a user