aboutsummaryrefslogtreecommitdiffstats
path: root/testing/lib/Test/Irssi/Test.pm
diff options
context:
space:
mode:
Diffstat (limited to 'testing/lib/Test/Irssi/Test.pm')
-rw-r--r--testing/lib/Test/Irssi/Test.pm308
1 files changed, 308 insertions, 0 deletions
diff --git a/testing/lib/Test/Irssi/Test.pm b/testing/lib/Test/Irssi/Test.pm
new file mode 100644
index 0000000..cd0a6f9
--- /dev/null
+++ b/testing/lib/Test/Irssi/Test.pm
@@ -0,0 +1,308 @@
+use strictures 1;
+use MooseX::Declare;
+
+class Test::Irssi::Test {
+
+ use POE;
+ use Test::Irssi;
+ use Test::Irssi::Driver;
+ use feature qw/say/;
+ use Data::Dump qw/dump/;
+
+ has 'parent'
+ => (
+ is => 'ro',
+ isa => 'Test::Irssi',
+ required => 1,
+ );
+
+ has 'name'
+ => (
+ is => 'ro',
+ isa => 'Str',
+ required => 1,
+ );
+
+ has 'description'
+ => (
+ is => 'rw',
+ isa => 'Str',
+ default => '',
+ );
+
+ has 'states'
+ => (
+ is => 'ro',
+ isa => 'ArrayRef',
+ traits => [qw/Array/],
+ default => sub { [] },
+ lazy => 1,
+ handles => {
+ add_state => 'push',
+ state_count => 'count',
+ get_state => 'get',
+ },
+ );
+
+ has 'results'
+ => (
+ is => 'ro',
+ isa => 'ArrayRef',
+ default => sub { [] },
+ );
+
+ has 'complete'
+ => (
+ is => 'rw',
+ isa => 'Bool',
+ default => 0,
+ );
+
+
+ has '_next_state'
+ => (
+ is => 'rw',
+ isa => 'Int',
+ default => 0,
+ traits => [qw/Counter/],
+ handles => {
+ _increment_state_counter => 'inc',
+ _clear_state => 'reset',
+ },
+ );
+
+ # TODO: should only be valid when complete is set.
+ sub passed {
+ my $self = shift;
+ my $pass = 0;
+ foreach my $result (@{$self->results}) {
+ $pass = $result;
+ }
+ return $pass and $self->complete;
+ }
+
+ sub failed {
+ my $self = shift;
+ return not $self->passed;
+ }
+
+
+ sub details {
+ my ($self) = shift;
+ my $state_count = $self->state_count;
+ for (0..$state_count-1) {
+ my $state = $self->states->[$_];
+ my $result = $self->results->[$_];
+ say( "#\t" . $state->{type} . " - " . $state->{desc} . " "
+ . " = " .( $result?"ok":"not ok"));
+ }
+ }
+ ############# API FUNCTIONS ##########################################
+
+
+ method add_input_sequence(Str $input) {
+ $self->add_state({type => 'command',
+ of => 'input',
+ input => $input,
+ desc => 'input'});
+
+ $self->log("Adding $input as input");
+ }
+
+ method add_delay (Num $delay) {
+ $self->add_state({type => 'command',
+ of => 'delay',
+ desc => 'delay',
+ delay => $delay });
+ $self->log("Adding $delay as delay");
+
+ }
+
+ method add_keycode(Str $code) {
+ my $input = $self->translate_keycode($code);
+ $self->add_state({type => 'command',
+ desc => 'input',
+ input => $input });
+ $self->log("Adding $input ($code) as input");
+
+ }
+ sub add_diag {
+ my ($self, $diag) = @_;
+ $self->add_state({type => 'command',
+ of => 'diag',
+ desc => $diag });
+ }
+
+ sub add_pattern_match {
+ my ($self, $pattern, $constraints, $desc) = @_;
+ $self->add_state({type => 'test',
+ of => 'pattern',
+ pattern => $pattern,
+ constraints => $constraints,
+ desc => $desc});
+
+ $self->log("Adding $pattern as output match ");
+ }
+
+ sub test_cursor_position {
+ my ($self, $x, $y, $desc) = @_;
+ $self->add_state({type => 'test',
+ of => 'cursor',
+ x => $x,
+ y => $y,
+ desc => $desc });
+ $self->log("Adding cursor [$x, $y] test ");
+
+ }
+
+ sub add_evaluation_function {
+ my ($self, $coderef, $desc) = @_;
+ $self->add_state({type => 'test',
+ of => 'function',
+ code => $coderef,
+ desc => $desc});
+ }
+
+
+ ############# END OF API FUNCTIONS ####################################
+
+
+
+ method translate_keycode(Str $code) {
+ my $seq = '';
+ if ($code =~ m/M-([a-z])/i) {
+ $seq = "\x1b" . $1;
+ } elsif ($code =~ m/C-([a-z])/i) {
+ $seq = chr ( ord(lc $1) - 64 );
+ }
+ return $seq;
+ }
+
+ method this_state {
+ return $self->_next_state - 1;
+ }
+
+ sub check_output {
+ my ($self, $data) = @_;
+
+ my ($pattern, $constraints) = ($data->{pattern}, $data->{constraints});
+
+ my $ok = 0;
+ my $line = '';
+ if ($constraints eq 'prompt') {
+ $line = $self->parent->get_prompt_line;
+ } elsif ($constraints eq 'window_sbar') {
+ $line = $self->parent->get_window_statusbar_line;
+ } elsif ($constraints eq 'window') {
+ # NOTE: not actually a line.
+ $line = $self->parent->get_window_contents;
+ } elsif ($constraints eq 'topic') {
+ $line = $self->parent->get_topic_line;
+ }
+
+ $self->log("Testing pattern against: '$line'");
+
+ if ($line =~ m/$pattern/) {
+ $self->log("Pattern $pattern passed");
+ $self->results->[$self->this_state] = 1;
+ } else {
+ $self->log("Pattern $pattern failed");
+ $self->results->[$self->this_state] = 0;;
+ }
+ }
+
+ sub get_next_state {
+ my ($self) = @_;
+ my $item = $self->get_state($self->_next_state);
+ $self->_increment_state_counter;
+
+ return $item;
+ }
+
+ sub evaluate_test {
+ my ($self) = @_;
+
+ while (my $state = $self->get_next_state) {
+
+ $self->log("Evaluating Test: " . dump($state));
+
+ my $type = $state->{type};
+
+ if ($type eq 'command') {
+ my $subtype = $state->{of};
+
+ if ($subtype eq 'diag') {
+ if ($self->parent->generate_tap) {
+ say STDOUT '#' . $state->{desc};
+ }
+ }
+ if ($subtype eq 'input') {
+ $self->parent->inject_text($state->{input});
+ $self->log("input: ". $state->{input});
+ }
+ if ($subtype eq 'delay') {
+ $self->log("inserting delay");
+ $self->parent->apply_delay($state->{delay});
+ $self->results->[$self->this_state] = 1;
+ return;
+ }
+
+ # all commands are considered to succeed.
+ $self->results->[$self->this_state] = 1;
+
+ } elsif ($type eq 'test') {
+
+ my $test_type = $state->{of};
+
+ if ($test_type eq 'pattern') {
+ my $pattern = $state->{pattern};
+ $self->check_output($state);
+ }
+ if ($test_type eq 'cursor') {
+ my ($curs_x, $curs_y) = $self->parent->get_cursor_position;
+
+ my $ret = 0;
+ if ($state->{x} == $curs_x and $state->{y} == $curs_y) {
+ $ret = 1;
+ }
+
+ $self->results->[$self->this_state] = $ret;
+
+ }
+
+ if ($test_type eq 'function') {
+ # code evaluation
+ my @args = ($self, $self->parent, $self->parent->vt);
+ my $ret = $state->{code}->(@args);
+ $ret //= 0; # ensure that undef failures are
+ # marked as such.
+ $self->results->[$self->this_state] = $ret;
+ }
+ } else {
+ # wtf?
+ }
+ }
+
+ $poe_kernel->post(IrssiTestDriver => 'test_complete');
+
+ $self->complete(1);
+
+ $self->log("Test Execution Finished");
+ }
+
+ sub resume_from_timer {
+ my ($self) = @_;
+ $self->log("Resuming after timeout");
+ $self->evaluate_test;
+ }
+ sub log {
+ my ($self, $msg) = @_;
+ $self->parent->_logfile_fh->say($msg);
+ }
+
+ sub _all { $_ || return 0 for @_; 1 }
+}
+
+
+
+ __END__