Permalink
Browse files

Abstract the regression test sequence helper into POE::Test::Sequence.

  • Loading branch information...
rcaputo committed Jul 12, 2014
1 parent 65cf8fc commit 31396d74dad0c1b552b8f468968f1a9fa976b169
Showing with 164 additions and 88 deletions.
  1. +1 −0 MANIFEST
  2. +117 −0 lib/POE/Test/Sequence.pm
  3. +46 −88 t/90_regression/whjackson-followtail.t
View
@@ -59,6 +59,7 @@ lib/POE/Resource/Sessions.pm
lib/POE/Resource/Signals.pm
lib/POE/Resources.pm
lib/POE/Session.pm
+lib/POE/Test/Sequence.pm
lib/POE/Wheel.pm
lib/POE/Wheel/Curses.pm
lib/POE/Wheel/FollowTail.pm
View
@@ -0,0 +1,117 @@
+package POE::Test::Sequence;
+
+use warnings;
+use strict;
+
+use Carp qw(croak);
+
+sub new {
+ my ($class, %args) = @_;
+
+ my $sequence = delete $args{sequence};
+ croak "sequence required" unless defined $sequence;
+
+ return bless {
+ sequence => $sequence,
+ test_count => scalar( @$sequence ),
+ }, $class;
+}
+
+sub next {
+ my ($self, $event, $parameter) = @_;
+
+ my $expected_result = shift @{ $self->{sequence} };
+ unless (defined $expected_result) {
+ Test::More::fail(
+ "Got an unexpected result ($event, $parameter). Time to bye."
+ );
+ exit;
+ }
+
+ my $next_action = pop @$expected_result;
+
+ Test::More::note "Testing (@$expected_result)";
+
+ Test::More::is_deeply( [ $event, $parameter ], $expected_result );
+
+ return $next_action // sub { undef };
+}
+
+sub test_count {
+ return $_[0]{test_count};
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+POE::Test::Sequence - POE test helper to verify a sequence of events
+
+=head1 SYNOPSIS
+
+ Sorry, there isn't a synopsis at this time.
+
+ However, see t/90_regression/whjackson-followtail.t in POE's test
+ suite for a full example.
+
+=head1 DESCRIPTION
+
+POE::Test::Sequence is a test helper that abstracts a lot of the
+tedious trickery needed to verify the relative ordering of events.
+
+With this module, one can test the sequence of events without
+necessarily relying on specific times elapsing between them.
+
+=head2 new
+
+Create a new sequence object. Takes named parameter pairs, currently
+just "sequence", which references an array of steps. Each step is an
+array reference containing the expected event, a required parameter to
+that event, and a code reference for the optional next step to take
+after testing for that event.
+
+ my $sequence = POE::Test::Sequence->new(
+ sequence => [
+ [ got_idle_event => 0, sub { append_to_log("text") } ],
+ ...,
+ ]
+ );
+
+next() uses the first two step elements to verify that steps are
+occurring in the order in which they should. The third element is
+returned by next() and is suitable for use as a goto() target. See
+the next() method for more details.
+
+=head2 next
+
+The next() method requires an event name and a scalar parameter.
+These are compared to the first two elements of the next sequence step
+to make sure events are happening in the order in which they should.
+
+ sub handle_start_event {
+ goto $sequence->next("got_start_event", 0);
+ }
+
+=head2 test_count
+
+test_count() returns the number of test steps in the sequence object.
+It's intended to be used for test planning.
+
+ use Test::More;
+ my $sequence = POE::Test::Sequence->new( ... );
+ plan tests => $sequence->test_count();
+
+=head1 BUGS
+
+None known.
+
+=head1 AUTHORS & LICENSING
+
+Please see L<POE> for more information about authors, contributors,
+and POE's licensing.
+
+=cut
+
+# vim: ts=2 sw=2 filetype=perl expandtab
@@ -17,6 +17,7 @@ sub POE::Kernel::ASSERT_DEFAULT () { 1 }
use Test::More;
use POE qw(Wheel::FollowTail);
+use POE::Test::Sequence;
use constant LOG => 'test_log';
use constant OLD_LOG => 'test_log.1';
@@ -34,114 +35,72 @@ use constant OLD_LOG => 'test_log.1';
unlink LOG, OLD_LOG;
}
-my @expected_results = (
- [ got_start_event => 0, sub {
- $_[HEAP]{wheel} = POE::Wheel::FollowTail->new(
- InputEvent => 'input_event',
- ResetEvent => 'reset_event',
- IdleEvent => 'idle_event',
- Filename => LOG,
- PollInterval => 1,
- );
- }
- ],
- [ got_idle_event => 0, sub { append_to_log("a") } ],
- [ did_log_append => "a", sub { undef } ],
- [ got_reset_event => 0, sub { undef } ], # Initial open is a reset.
- [ got_input_event => "a", sub { undef} ],
- [ got_idle_event => 0, sub {
- append_to_log("b");
- roll_log();
- append_to_log("c");
- }
- ],
- [ did_log_append => "b", sub { undef } ],
- [ did_log_roll => 0, sub { undef } ],
- [ did_log_append => "c", sub { undef } ],
- [ got_input_event => "b", sub { undef } ],
- [ got_reset_event => 0, sub { undef } ],
- [ got_input_event => "c", sub { append_to_log("d") } ],
- [ did_log_append => "d", sub { undef } ],
- [ got_input_event => "d", sub { delete $_[HEAP]{wheel} } ],
- [ got_stop_event => 0, sub {
- # Clean up test log files, if we can.
- unlink LOG or die "unlink failed: $!";
- unlink OLD_LOG or die "unlink failed: $!";
- }
+my $sequence = POE::Test::Sequence->new(
+ sequence => [
+ [ got_start_event => 0, sub {
+ $_[HEAP]{wheel} = POE::Wheel::FollowTail->new(
+ InputEvent => 'input_event',
+ ResetEvent => 'reset_event',
+ IdleEvent => 'idle_event',
+ Filename => LOG,
+ PollInterval => 1,
+ );
+ }
+ ],
+ [ got_idle_event => 0, sub { append_to_log("a") } ],
+ [ did_log_append => "a", undef ],
+ [ got_reset_event => 0, undef ], # Initial open is a reset.
+ [ got_input_event => "a", undef ],
+ [ got_idle_event => 0, sub {
+ append_to_log("b");
+ roll_log();
+ append_to_log("c");
+ }
+ ],
+ [ did_log_append => "b", undef ],
+ [ did_log_roll => 0, undef ],
+ [ did_log_append => "c", undef ],
+ [ got_input_event => "b", undef ],
+ [ got_reset_event => 0, undef ],
+ [ got_input_event => "c", sub { append_to_log("d") } ],
+ [ did_log_append => "d", undef ],
+ [ got_input_event => "d", sub { delete $_[HEAP]{wheel} } ],
+ [ got_stop_event => 0, sub {
+ # Clean up test log files, if we can.
+ unlink LOG or die "unlink failed: $!";
+ unlink OLD_LOG or die "unlink failed: $!";
+ }
+ ],
],
);
-plan tests => scalar @expected_results;
+plan tests => $sequence->test_count();
POE::Session->create(
inline_states => {
- _start => \&handle_start_event,
- _stop => \&handle_stop_event,
- input_event => \&handle_input_event,
- reset_event => \&handle_reset_event,
- idle_event => \&handle_idle_event,
+ _start => sub { goto $sequence->next("got_start_event", 0) },
+ _stop => sub { goto $sequence->next("got_stop_event", 0) },
+ input_event => sub { goto $sequence->next("got_input_event", $_[ARG0]) },
+ reset_event => sub { goto $sequence->next("got_reset_event", 0) },
+ idle_event => sub { goto $sequence->next("got_idle_event", 0) },
}
);
POE::Kernel->run();
exit;
-#
-# subs
-#
-
-sub test_event {
- my ($event, $parameter) = @_;
- my $expected_result = shift @expected_results;
- unless (defined $expected_result) {
- fail("Got an unexpected result ($event, $parameter). Time to bye.");
- exit;
- }
-
- my $next_action = pop @$expected_result;
-
- note "Testing (@$expected_result)";
-
- is_deeply( [ $event, $parameter ], $expected_result );
-
- return $next_action;
-}
-
-sub handle_reset_event {
- my $next_action = test_event("got_reset_event", 0);
- goto $next_action;
-}
-
-sub handle_idle_event {
- my $next_action = test_event("got_idle_event", 0);
- goto $next_action;
-}
-
-sub handle_input_event {
- my $next_action = test_event("got_input_event", $_[ARG0]);
- goto $next_action;
-}
-
-sub handle_start_event {
- my $next_action = test_event("got_start_event", 0);
- goto $next_action;
-}
-
-sub handle_stop_event {
- my $next_action = test_event("got_stop_event", 0);
- goto $next_action;
-}
+# Helpers.
sub roll_log {
- test_event did_log_roll => 0;
+ $sequence->next("did_log_roll", 0);
rename LOG, OLD_LOG or die "rename failed: $!";
return;
}
sub append_to_log {
my ($line) = @_;
- test_event did_log_append => $line;
+ $sequence->next("did_log_append", $line);
open my $fh, '>>', LOG or die "open failed: $!";
print {$fh} "$line\n";
@@ -150,5 +109,4 @@ sub append_to_log {
return;
}
-
1;

0 comments on commit 31396d7

Please sign in to comment.