From 976a0195d415ca73b0c15d54a84d0286375faf72 Mon Sep 17 00:00:00 2001 From: Chad Granum Date: Sat, 21 Nov 2015 18:05:33 -0800 Subject: [PATCH 01/10] Move to_tap logic into formatter --- lib/Test/Stream/Event.pm | 15 +- lib/Test/Stream/Event/Bail.pm | 10 -- lib/Test/Stream/Event/Diag.pm | 18 --- lib/Test/Stream/Event/Exception.pm | 9 -- lib/Test/Stream/Event/Note.pm | 13 -- lib/Test/Stream/Event/Ok.pm | 48 +------ lib/Test/Stream/Event/Plan.pm | 19 --- lib/Test/Stream/Event/Subtest.pm | 33 ----- lib/Test/Stream/Formatter/TAP.pm | 217 ++++++++++++++++++++++++++++- 9 files changed, 227 insertions(+), 155 deletions(-) diff --git a/lib/Test/Stream/Event.pm b/lib/Test/Stream/Event.pm index 239bd15..09abfe0 100644 --- a/lib/Test/Stream/Event.pm +++ b/lib/Test/Stream/Event.pm @@ -32,11 +32,21 @@ sub init { sub causes_fail { 0 } -sub to_tap {()}; sub update_state {()}; sub terminate {()}; sub global {()}; +sub to_tap { + my $self = shift; + my ($num) = @_; + + carp 'Use of $event->to_tap is deprecated'; + + require Test::Stream::Formatter::TAP; + my $formatter = Test::Stream::Formatter::TAP->new; + $formatter->event_tap($self, $num); +} + 1; __END__ @@ -139,6 +149,9 @@ ensure the event is seen and understood. =item @output = $e->to_tap($num) +B<***DEPRECATED***> This will be removed in the near future. See +L for TAP production. + This is where you get the chance to produce TAP output. The input argument C<$num> will either be the most recent test number, or undefined. The output should be a list of arrayrefs, each arrayref should have exactly 2 values: diff --git a/lib/Test/Stream/Event/Bail.pm b/lib/Test/Stream/Event/Bail.pm index ab70d98..a2ef676 100644 --- a/lib/Test/Stream/Event/Bail.pm +++ b/lib/Test/Stream/Event/Bail.pm @@ -2,19 +2,9 @@ package Test::Stream::Event::Bail; use strict; use warnings; -use Test::Stream::Formatter::TAP qw/OUT_STD/; - use base 'Test::Stream::Event'; use Test::Stream::HashBase accessors => [qw/reason/]; -sub to_tap { - my $self = shift; - return [ - OUT_STD, - "Bail out! " . $self->reason . "\n", - ]; -} - sub update_state { my $self = shift; my ($state) = @_; diff --git a/lib/Test/Stream/Event/Diag.pm b/lib/Test/Stream/Event/Diag.pm index 66f10c8..4085fb7 100644 --- a/lib/Test/Stream/Event/Diag.pm +++ b/lib/Test/Stream/Event/Diag.pm @@ -7,7 +7,6 @@ use Test::Stream::HashBase accessors => [qw/message/]; use Carp qw/confess/; -use Test::Stream::Formatter::TAP qw/OUT_TODO OUT_ERR/; sub init { $_[0]->SUPER::init(); @@ -19,23 +18,6 @@ sub init { } } -sub to_tap { - my $self = shift; - - my $msg = $self->{+MESSAGE}; - return unless $msg; - - $msg = "# $msg" unless $msg eq "\n"; - - chomp($msg); - $msg =~ s/\n/\n# /g; - - return [ - ($self->{+DEBUG}->no_diag ? OUT_TODO : OUT_ERR), - "$msg\n", - ]; -} - 1; __END__ diff --git a/lib/Test/Stream/Event/Exception.pm b/lib/Test/Stream/Event/Exception.pm index a04c666..58d17f7 100644 --- a/lib/Test/Stream/Event/Exception.pm +++ b/lib/Test/Stream/Event/Exception.pm @@ -2,18 +2,9 @@ package Test::Stream::Event::Exception; use strict; use warnings; -use Test::Stream::Formatter::TAP qw/OUT_ERR/; - use base 'Test::Stream::Event'; use Test::Stream::HashBase accessors => [qw/error/]; -sub to_tap { - my $self = shift; - return [ - OUT_ERR, $self->{+ERROR} - ]; -} - sub update_state { my $self = shift; my ($state) = @_; diff --git a/lib/Test/Stream/Event/Note.pm b/lib/Test/Stream/Event/Note.pm index 3c993f0..696688a 100644 --- a/lib/Test/Stream/Event/Note.pm +++ b/lib/Test/Stream/Event/Note.pm @@ -2,8 +2,6 @@ package Test::Stream::Event::Note; use strict; use warnings; -use Test::Stream::Formatter::TAP qw/OUT_STD/; - use base 'Test::Stream::Event'; use Test::Stream::HashBase accessors => [qw/message/]; @@ -17,17 +15,6 @@ sub init { } } -sub to_tap { - my $self = shift; - - chomp(my $msg = $self->{+MESSAGE}); - return unless $msg; - $msg = "# $msg" unless $msg =~ m/^\n/; - $msg =~ s/\n/\n# /g; - - return [OUT_STD, "$msg\n"]; -} - 1; __END__ diff --git a/lib/Test/Stream/Event/Ok.pm b/lib/Test/Stream/Event/Ok.pm index 6ec0200..21ca8bd 100644 --- a/lib/Test/Stream/Event/Ok.pm +++ b/lib/Test/Stream/Event/Ok.pm @@ -28,51 +28,6 @@ sub init { $self->debug->throw("'$name' is not a valid name, names must not contain '#' or newlines.") } -sub to_tap { - my $self = shift; - my ($num) = @_; - - my $name = $self->{+NAME}; - my $debug = $self->{+DEBUG}; - my $skip = $debug->{skip}; - my $todo = $debug->{todo}; - - my $out = ""; - $out .= "not " unless $self->{+PASS}; - $out .= "ok"; - $out .= " $num" if defined $num; - $out .= " - $name" if $name; - - if (defined $skip && defined $todo) { - $out .= " # TODO & SKIP"; - $out .= " $todo" if length $todo; - } - elsif (defined $todo) { - $out .= " # TODO"; - $out .= " $todo" if length $todo; - } - elsif (defined $skip) { - $out .= " # skip"; - $out .= " $skip" if length $skip; - } - - my @out = [OUT_STD, "$out\n"]; - - if ($self->{+DIAG} && @{$self->{+DIAG}}) { - my $diag_handle = $debug->no_diag ? OUT_TODO : OUT_ERR; - - for my $diag (@{$self->{+DIAG}}) { - chomp(my $msg = $diag); - - $msg = "# $msg" unless $msg =~ m/^\n/; - $msg =~ s/\n/\n# /g; - push @out => [$diag_handle, "$msg\n"]; - } - } - - return @out; -} - sub default_diag { my $self = shift; @@ -185,6 +140,9 @@ This generates the default diagnostics string: =item @sets = $e->to_tap($num) +B<***DEPRECATED***> This will be removed in the near future. See +L for TAP production. + Generate the tap stream for this object. C<@sets> containes 1 or more arrayrefs that identify the IO handle to use, and the string that should be sent to it. diff --git a/lib/Test/Stream/Event/Plan.pm b/lib/Test/Stream/Event/Plan.pm index e044c6e..575b649 100644 --- a/lib/Test/Stream/Event/Plan.pm +++ b/lib/Test/Stream/Event/Plan.pm @@ -5,7 +5,6 @@ use warnings; use base 'Test::Stream::Event'; use Test::Stream::HashBase accessors => [qw/max directive reason/]; -use Test::Stream::Formatter::TAP qw/OUT_STD/; use Carp qw/confess/; my %ALLOWED = ( @@ -37,24 +36,6 @@ sub init { } } -sub to_tap { - my $self = shift; - - my $max = $self->{+MAX}; - my $directive = $self->{+DIRECTIVE}; - my $reason = $self->{+REASON}; - - return if $directive && $directive eq 'NO PLAN'; - - my $plan = "1..$max"; - if ($directive) { - $plan .= " # $directive"; - $plan .= " $reason" if defined $reason; - } - - return [OUT_STD, "$plan\n"]; -} - sub update_state { my $self = shift; my ($state) = @_; diff --git a/lib/Test/Stream/Event/Subtest.pm b/lib/Test/Stream/Event/Subtest.pm index b3a18a2..f5691a7 100644 --- a/lib/Test/Stream/Event/Subtest.pm +++ b/lib/Test/Stream/Event/Subtest.pm @@ -5,8 +5,6 @@ use warnings; use Scalar::Util qw/blessed/; use Carp qw/confess/; -use Test::Stream::Formatter::TAP qw/OUT_STD/; - use base 'Test::Stream::Event::Ok'; use Test::Stream::HashBase accessors => [qw/subevents buffered/]; @@ -16,37 +14,6 @@ sub init { $self->{+SUBEVENTS} ||= []; } -sub to_tap { - my $self = shift; - my ($num) = @_; - - my ($ok, @diag) = $self->SUPER::to_tap($num); - - return ( - $ok, - @diag - ) unless $self->{+BUFFERED}; - - if ($ENV{HARNESS_IS_VERBOSE}) { - $_->[1] =~ s/^/ /mg for @diag; - } - - $ok->[1] =~ s/\n/ {\n/; - - my $count = 0; - my @subs = map { - $count++ if $_->isa('Test::Stream::Event::Ok'); - map { $_->[1] =~ s/^/ /mg; $_ } $_->to_tap($count); - } @{$self->{+SUBEVENTS}}; - - return ( - $ok, - @diag, - @subs, - [OUT_STD(), "}\n"], - ); -} - 1; __END__ diff --git a/lib/Test/Stream/Formatter/TAP.pm b/lib/Test/Stream/Formatter/TAP.pm index 5deffba..a876493 100644 --- a/lib/Test/Stream/Formatter/TAP.pm +++ b/lib/Test/Stream/Formatter/TAP.pm @@ -11,10 +11,22 @@ sub OUT_STD() { 0 } sub OUT_ERR() { 1 } sub OUT_TODO() { 2 } +use Scalar::Util qw/blessed/; + use Test::Stream::Exporter qw/import exports/; exports qw/OUT_STD OUT_ERR OUT_TODO/; no Test::Stream::Exporter; +my %CONVERTERS = ( + 'Test::Stream::Event::Ok' => \&_ok_event, + 'Test::Stream::Event::Note' => \&_note_event, + 'Test::Stream::Event::Diag' => \&_diag_event, + 'Test::Stream::Event::Bail' => \&_bail_event, + 'Test::Stream::Event::Exception' => \&_exception_event, + 'Test::Stream::Event::Subtest' => \&_subtest_event, + 'Test::Stream::Event::Plan' => \&_plan_event, +); + _autoflush(\*STDOUT); _autoflush(\*STDERR); @@ -56,18 +68,12 @@ if ($^C) { sub write { my ($self, $e, $num) = @_; - return if $self->{+NO_DIAG} && $e->isa('Test::Stream::Event::Diag'); - return if $self->{+NO_HEADER} && $e->isa('Test::Stream::Event::Plan'); - - $num = undef if $self->{+NO_NUMBERS}; - my @tap = $e->to_tap($num); + my @tap = $self->event_tap($e, $num) or return; my $handles = $self->{+HANDLES}; my $nesting = $e->nested || 0; my $indent = ' ' x $nesting; - return if $nesting && $e->isa('Test::Stream::Event::Bail'); - local($\, $", $,) = (undef, ' ', ''); for my $set (@tap) { no warnings 'uninitialized'; @@ -99,6 +105,176 @@ sub _autoflush { select $old_fh; } +sub event_tap { + my $self = shift; + my ($e, $num) = @_; + + # Optimization for the most common case of an 'ok' event + my $is_ok = index("$e", 'Test::Stream::Event::Ok=' ) == 0; + my $converter = $is_ok ? \&_ok_event : $CONVERTERS{blessed($e)}; + + $num = undef if $self->{+NO_NUMBERS}; + + # Legacy Support for $e->to_tap + unless ($converter) { + my $legacy = $e->can('to_tap') or return; + return if $legacy == \&Test::Stream::Event::to_tap; + warn "'$e' implements 'to_tap'. to_tap methods on events are deprecated.\n"; + return $e->to_tap($num); + } + + return $self->$converter($e, $num); +} + +sub _ok_event { + my $self = shift; + my ($e, $num) = @_; + + # We use direct hash access for performance. OK events are so common we + # need this to be fast. + my $name = $e->{name}; + my $debug = $e->{debug}; + my $skip = $debug->{skip}; + my $todo = $debug->{todo}; + + my $out = ""; + $out .= "not " unless $e->{pass}; + $out .= "ok"; + $out .= " $num" if defined $num; + $out .= " - $name" if $name; + + if (defined $skip && defined $todo) { + $out .= " # TODO & SKIP"; + $out .= " $todo" if length $todo; + } + elsif (defined $todo) { + $out .= " # TODO"; + $out .= " $todo" if length $todo; + } + elsif (defined $skip) { + $out .= " # skip"; + $out .= " $skip" if length $skip; + } + + my @out = [OUT_STD, "$out\n"]; + + if ($e->{diag} && @{$e->{diag}}) { + my $diag_handle = $debug->no_diag ? OUT_TODO : OUT_ERR; + + for my $diag (@{$e->{diag}}) { + chomp(my $msg = $diag); + + $msg = "# $msg" unless $msg =~ m/^\n/; + $msg =~ s/\n/\n# /g; + push @out => [$diag_handle, "$msg\n"]; + } + } + + return @out; +} + +sub _note_event { + my $self = shift; + my ($e, $num) = @_; + + chomp(my $msg = $e->message); + return unless $msg; + $msg = "# $msg" unless $msg =~ m/^\n/; + $msg =~ s/\n/\n# /g; + + return [OUT_STD, "$msg\n"]; +} + +sub _diag_event { + my $self = shift; + my ($e, $num) = @_; + return if $self->{+NO_DIAG}; + + my $msg = $e->message or return; + + $msg = "# $msg" unless $msg eq "\n"; + + chomp($msg); + $msg =~ s/\n/\n# /g; + + return [ + ($e->debug->no_diag ? OUT_TODO : OUT_ERR), + "$msg\n", + ]; +} + +sub _bail_event { + my $self = shift; + my ($e, $num) = @_; + + return if $e->nested; + + return [ + OUT_STD, + "Bail out! " . $e->reason . "\n", + ]; +} + +sub _exception_event { + my $self = shift; + my ($e, $num) = @_; + return [ OUT_ERR, $e->error ]; +} + +sub _subtest_event { + my $self = shift; + my ($e, $num) = @_; + + my ($ok, @diag) = $self->_ok_event($e, $num); + + return ( + $ok, + @diag + ) unless $e->buffered; + + if ($ENV{HARNESS_IS_VERBOSE}) { + $_->[1] =~ s/^/ /mg for @diag; + } + + $ok->[1] =~ s/\n/ {\n/; + + my $count = 0; + my @subs = map { + $count++ if $_->isa('Test::Stream::Event::Ok'); + map { $_->[1] =~ s/^/ /mg; $_ } $self->event_tap($_, $count); + } @{$e->subevents}; + + return ( + $ok, + @diag, + @subs, + [OUT_STD(), "}\n"], + ); +} + +sub _plan_event { + my $self = shift; + my ($e, $num) = @_; + + return if $self->{+NO_HEADER}; + + my $max = $e->max; + my $directive = $e->directive; + my $reason = $e->reason; + + return if $directive && $directive eq 'NO PLAN'; + + my $plan = "1..$max"; + if ($directive) { + $plan .= " # $directive"; + $plan .= " $reason" if defined $reason; + } + + return [OUT_STD, "$plan\n"]; +} + + + 1; __END__ @@ -182,6 +358,33 @@ This directly modifies the stored filehandles, it does not create new ones. Write an event to the console. +=item Test::Stream::Formatter::TAP->register_event($pkg, sub { ... }); + +In general custom events are not supported. There are however occasions where +you might want to write a custom event type that results in TAP output. In +order to do this you use the C class method. + + package My::Event; + use Test::Stream::Formatter::TAP qw/OUT_STD OUT_ERR/; + + use base 'Test::Stream::Event'; + use Test::Stream::HashBase accessors => [qw/pass name diag note/]; + + Test::Stream::Formatter::TAP->register_event( + __PACKAGE__, + sub { + my $self = shift; + my ($e, $num) = @_; + return ( + [OUT_STD, "ok $num - " . $e->name . "\n"], + [OUT_ERR, "# " . $e->name . " " . $e->diag . "\n"], + [OUT_STD, "# " . $e->name . " " . $e->note . "\n"], + ); + } + ); + + 1; + =back =head1 SOURCE From 7c8e5a48f85f0143bca32eaffe35008881991fd8 Mon Sep 17 00:00:00 2001 From: Chad Granum Date: Sun, 22 Nov 2015 13:17:53 -0800 Subject: [PATCH 02/10] Add event registration to TAP formatter --- lib/Test/Stream/Formatter/TAP.pm | 11 +++++++++++ t/modules/Formatter/TAP.t | 21 ++++++++++++--------- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/lib/Test/Stream/Formatter/TAP.pm b/lib/Test/Stream/Formatter/TAP.pm index a876493..d09bf95 100644 --- a/lib/Test/Stream/Formatter/TAP.pm +++ b/lib/Test/Stream/Formatter/TAP.pm @@ -12,6 +12,7 @@ sub OUT_ERR() { 1 } sub OUT_TODO() { 2 } use Scalar::Util qw/blessed/; +use Carp qw/croak/; use Test::Stream::Exporter qw/import exports/; exports qw/OUT_STD OUT_ERR OUT_TODO/; @@ -27,6 +28,16 @@ my %CONVERTERS = ( 'Test::Stream::Event::Plan' => \&_plan_event, ); +sub register_event { + my $class = shift; + my ($type, $convert) = @_; + croak "Event type is a required argument" unless $type; + croak "Event type '$type' already registered" if $CONVERTERS{$type}; + croak "The second argument to register_event() must be a code reference" + unless $convert && ref($convert) eq 'CODE'; + $CONVERTERS{$type} = $convert; +} + _autoflush(\*STDOUT); _autoflush(\*STDERR); diff --git a/t/modules/Formatter/TAP.t b/t/modules/Formatter/TAP.t index 2559897..dca8053 100644 --- a/t/modules/Formatter/TAP.t +++ b/t/modules/Formatter/TAP.t @@ -42,15 +42,18 @@ ok($layers->{utf8}, "Now utf8"); use base 'Test::Stream::Event'; use Test::Stream::HashBase accessors => [qw/pass name diag note/]; - sub to_tap { - my $self = shift; - my ($num) = @_; - return ( - [OUT_STD, "ok $num - " . $self->name . "\n"], - [OUT_ERR, "# " . $self->name . " " . $self->diag . "\n"], - [OUT_STD, "# " . $self->name . " " . $self->note . "\n"], - ); - } + Test::Stream::Formatter::TAP->register_event( + __PACKAGE__, + sub { + my $self = shift; + my ($e, $num) = @_; + return ( + [OUT_STD, "ok $num - " . $e->name . "\n"], + [OUT_ERR, "# " . $e->name . " " . $e->diag . "\n"], + [OUT_STD, "# " . $e->name . " " . $e->note . "\n"], + ); + } + ); } my ($std, $err); From 0ce937e83a71d00037d4982bc3f59421d263cbae Mon Sep 17 00:00:00 2001 From: Chad Granum Date: Sun, 22 Nov 2015 13:33:18 -0800 Subject: [PATCH 03/10] Hide warnings for deprecated to_tap in event tests Eventually these will be completely removed, at the same time to_tap methods are removed. --- t/modules/Event.t | 4 +- t/modules/Event/Bail.t | 12 +-- t/modules/Event/Diag.t | 58 +++++++------- t/modules/Event/Exception.t | 12 +-- t/modules/Event/Note.t | 58 +++++++------- t/modules/Event/Ok.t | 147 ++++++++++++++++++++---------------- t/modules/Event/Plan.t | 48 +++++++----- t/modules/Event/Subtest.t | 51 +++++++------ 8 files changed, 216 insertions(+), 174 deletions(-) diff --git a/t/modules/Event.t b/t/modules/Event.t index e5ae64d..e47837d 100644 --- a/t/modules/Event.t +++ b/t/modules/Event.t @@ -25,6 +25,8 @@ ok(!$one->causes_fail, "Events do not cause failures by default"); ok(!$one->$_, "$_ is false by default") for qw/update_state terminate global/; -is([$one->to_tap()], [], "to_tap is an empty list by default"); +warns { + is([$one->to_tap()], [], "to_tap is an empty list by default"); +}; done_testing; diff --git a/t/modules/Event/Bail.t b/t/modules/Event/Bail.t index a2d5c37..4220c54 100644 --- a/t/modules/Event/Bail.t +++ b/t/modules/Event/Bail.t @@ -11,11 +11,13 @@ my $bail = Test::Stream::Event::Bail->new( ok($bail->causes_fail, "balout always causes fail."); -is( - [$bail->to_tap(1)], - [[OUT_STD, "Bail out! evil\n" ]], - "Got tap" -); +warns { + is( + [$bail->to_tap(1)], + [[OUT_STD, "Bail out! evil\n" ]], + "Got tap" + ); +}; is($bail->terminate, 255, "Bail will cause the test to exit."); is($bail->global, 1, "Bail is global, everything should bail"); diff --git a/t/modules/Event/Diag.t b/t/modules/Event/Diag.t index c3a10b2..ab8a85d 100644 --- a/t/modules/Event/Diag.t +++ b/t/modules/Event/Diag.t @@ -10,32 +10,34 @@ my $diag = Test::Stream::Event::Diag->new( message => 'foo', ); -is( - [$diag->to_tap(1)], - [[OUT_ERR, "# foo\n"]], - "Got tap" -); +warns { + is( + [$diag->to_tap(1)], + [[OUT_ERR, "# foo\n"]], + "Got tap" + ); -$diag->set_message("foo\n"); -is( - [$diag->to_tap(1)], - [[OUT_ERR, "# foo\n"]], - "Only 1 newline" -); + $diag->set_message("foo\n"); + is( + [$diag->to_tap(1)], + [[OUT_ERR, "# foo\n"]], + "Only 1 newline" + ); -$diag->debug->set_todo('todo'); -is( - [$diag->to_tap(1)], - [[OUT_TODO, "# foo\n"]], - "Got tap in todo" -); + $diag->debug->set_todo('todo'); + is( + [$diag->to_tap(1)], + [[OUT_TODO, "# foo\n"]], + "Got tap in todo" + ); -$diag->set_message("foo\nbar\nbaz"); -is( - [$diag->to_tap(1)], - [[OUT_TODO, "# foo\n# bar\n# baz\n"]], - "All lines have proper prefix" -); + $diag->set_message("foo\nbar\nbaz"); + is( + [$diag->to_tap(1)], + [[OUT_TODO, "# foo\n# bar\n# baz\n"]], + "All lines have proper prefix" + ); +}; $diag = Test::Stream::Event::Diag->new( debug => Test::Stream::DebugInfo->new(frame => [__PACKAGE__, __FILE__, __LINE__]), @@ -51,10 +53,12 @@ $diag = Test::Stream::Event::Diag->new( like($diag->message, qr/^HASH\(.*\)$/, "stringified the input value"); -$diag->set_message(""); -is([$diag->to_tap], [], "no tap with an empty message"); +warns { + $diag->set_message(""); + is([$diag->to_tap], [], "no tap with an empty message"); -$diag->set_message("\n"); -is([$diag->to_tap], [[OUT_ERR, "\n"]], "newline on its own is unchanged"); + $diag->set_message("\n"); + is([$diag->to_tap], [[OUT_ERR, "\n"]], "newline on its own is unchanged"); +}; done_testing; diff --git a/t/modules/Event/Exception.t b/t/modules/Event/Exception.t index e48daa7..e523d40 100644 --- a/t/modules/Event/Exception.t +++ b/t/modules/Event/Exception.t @@ -11,11 +11,13 @@ my $exception = Test::Stream::Event::Exception->new( ok($exception->causes_fail, "Exception events always cause failure"); -is( - [$exception->to_tap(1)], - [[OUT_ERR, "evil at lake_of_fire.t line 6\n" ]], - "Got tap" -); +warns { + is( + [$exception->to_tap(1)], + [[OUT_ERR, "evil at lake_of_fire.t line 6\n" ]], + "Got tap" + ); +}; require Test::Stream::State; my $state = Test::Stream::State->new; diff --git a/t/modules/Event/Note.t b/t/modules/Event/Note.t index 739a9f6..3ef9925 100644 --- a/t/modules/Event/Note.t +++ b/t/modules/Event/Note.t @@ -12,25 +12,27 @@ my $note = Test::Stream::Event::Note->new( message => 'foo', ); -is( - [$note->to_tap(1)], - [[OUT_STD, "# foo\n"]], - "Got tap" -); - -$note->set_message("foo\n"); -is( - [$note->to_tap(1)], - [[OUT_STD, "# foo\n"]], - "Only 1 newline" -); - -$note->set_message("foo\nbar\nbaz"); -is( - [$note->to_tap(1)], - [[OUT_STD, "# foo\n# bar\n# baz\n"]], - "All lines have proper prefix" -); +warns { + is( + [$note->to_tap(1)], + [[OUT_STD, "# foo\n"]], + "Got tap" + ); + + $note->set_message("foo\n"); + is( + [$note->to_tap(1)], + [[OUT_STD, "# foo\n"]], + "Only 1 newline" + ); + + $note->set_message("foo\nbar\nbaz"); + is( + [$note->to_tap(1)], + [[OUT_STD, "# foo\n# bar\n# baz\n"]], + "All lines have proper prefix" + ); +}; $note = Test::Stream::Event::Note->new( debug => Test::Stream::DebugInfo->new(frame => [__PACKAGE__, __FILE__, __LINE__]), @@ -46,13 +48,15 @@ $note = Test::Stream::Event::Note->new( like($note->message, qr/^HASH\(.*\)$/, "stringified the input value"); -$note->set_message(""); -is([$note->to_tap], [], "no tap with an empty message"); - -$note->set_message("\n"); -is([$note->to_tap], [], "newline on its own is not shown"); - -$note->set_message("\nxxx"); -is([$note->to_tap], [[OUT_STD, "\n# xxx\n"]], "newline starting"); +warns { + $note->set_message(""); + is([$note->to_tap], [], "no tap with an empty message"); + + $note->set_message("\n"); + is([$note->to_tap], [], "newline on its own is not shown"); + + $note->set_message("\nxxx"); + is([$note->to_tap], [[OUT_STD, "\n# xxx\n"]], "newline starting"); +}; done_testing; diff --git a/t/modules/Event/Ok.t b/t/modules/Event/Ok.t index 4ba5502..70645fd 100644 --- a/t/modules/Event/Ok.t +++ b/t/modules/Event/Ok.t @@ -27,11 +27,13 @@ tests Passing => sub { is($ok->effective_pass, 1, "effective pass"); is($ok->diag, undef, "no diag"); - is( - [$ok->to_tap(4)], - [[OUT_STD, "ok 4 - the_test\n"]], - "Got tap for basic ok" - ); + warns { + is( + [$ok->to_tap(4)], + [[OUT_STD, "ok 4 - the_test\n"]], + "Got tap for basic ok" + ); + }; my $state = Test::Stream::State->new; $ok->update_state($state); @@ -53,13 +55,15 @@ tests Failing => sub { is($ok->name, 'the_test', "got name"); is($ok->effective_pass, 0, "effective pass"); - is( - [$ok->to_tap(4)], - [ - [OUT_STD, "not ok 4 - the_test\n"], - ], - "Got tap for failing ok" - ); + warns { + is( + [$ok->to_tap(4)], + [ + [OUT_STD, "not ok 4 - the_test\n"], + ], + "Got tap for failing ok" + ); + }; is( $ok->default_diag, @@ -67,37 +71,39 @@ tests Failing => sub { "default diag" ); - $ok->set_diag([ $ok->default_diag ]); - is( - [$ok->to_tap(4)], - [ - [OUT_STD, "not ok 4 - the_test\n"], - [OUT_ERR, "# Failed test 'the_test'\n# at foo.t line 42.\n"], - ], - "Got tap for failing ok with diag" - ); - - $ENV{HARNESS_IS_VERBOSE} = 0; - $ok->set_diag([ $ok->default_diag ]); - is( - [$ok->to_tap(4)], - [ - [OUT_STD, "not ok 4 - the_test\n"], - [OUT_ERR, "\n# Failed test 'the_test'\n# at foo.t line 42.\n"], - ], - "Got tap for failing ok with diag non verbose harness" - ); + warns { + $ok->set_diag([ $ok->default_diag ]); + is( + [$ok->to_tap(4)], + [ + [OUT_STD, "not ok 4 - the_test\n"], + [OUT_ERR, "# Failed test 'the_test'\n# at foo.t line 42.\n"], + ], + "Got tap for failing ok with diag" + ); - $ENV{HARNESS_ACTIVE} = 0; - $ok->set_diag([ $ok->default_diag ]); - is( - [$ok->to_tap(4)], - [ - [OUT_STD, "not ok 4 - the_test\n"], - [OUT_ERR, "# Failed test 'the_test'\n# at foo.t line 42.\n"], - ], - "Got tap for failing ok with diag no harness" - ); + $ENV{HARNESS_IS_VERBOSE} = 0; + $ok->set_diag([ $ok->default_diag ]); + is( + [$ok->to_tap(4)], + [ + [OUT_STD, "not ok 4 - the_test\n"], + [OUT_ERR, "\n# Failed test 'the_test'\n# at foo.t line 42.\n"], + ], + "Got tap for failing ok with diag non verbose harness" + ); + + $ENV{HARNESS_ACTIVE} = 0; + $ok->set_diag([ $ok->default_diag ]); + is( + [$ok->to_tap(4)], + [ + [OUT_STD, "not ok 4 - the_test\n"], + [OUT_ERR, "# Failed test 'the_test'\n# at foo.t line 42.\n"], + ], + "Got tap for failing ok with diag no harness" + ); + }; my $state = Test::Stream::State->new; $ok->update_state($state); @@ -126,14 +132,16 @@ tests fail_with_diag => sub { "Got diag" ); - is( - [$ok->to_tap(4)], - [ - [OUT_STD, "not ok 4 - the_test\n"], - [OUT_ERR, "# xxx\n"], - ], - "Got tap for failing ok" - ); + warns { + is( + [$ok->to_tap(4)], + [ + [OUT_STD, "not ok 4 - the_test\n"], + [OUT_ERR, "# xxx\n"], + ], + "Got tap for failing ok" + ); + }; my $state = Test::Stream::State->new; $ok->update_state($state); @@ -163,14 +171,16 @@ tests "Failing TODO" => sub { "Got diag" ); - is( - [$ok->to_tap(4)], - [ - [OUT_STD, "not ok 4 - the_test # TODO A Todo\n"], - [OUT_TODO, "# Failed (TODO) test 'the_test'\n# at foo.t line 42.\n"], - ], - "Got tap for failing ok" - ); + warns { + is( + [$ok->to_tap(4)], + [ + [OUT_STD, "not ok 4 - the_test # TODO A Todo\n"], + [OUT_TODO, "# Failed (TODO) test 'the_test'\n# at foo.t line 42.\n"], + ], + "Got tap for failing ok" + ); + }; my $state = Test::Stream::State->new; $ok->update_state($state); @@ -195,13 +205,15 @@ tests skip => sub { is($ok->effective_pass, 1, "effective pass"); is($ok->diag, undef, "no diag"); - is( - [$ok->to_tap(4)], - [ - [OUT_STD, "ok 4 - the_test # skip A Skip\n"], - ], - "Got tap for skip" - ); + warns { + is( + [$ok->to_tap(4)], + [ + [OUT_STD, "ok 4 - the_test # skip A Skip\n"], + ], + "Got tap for skip" + ); + }; my $state = Test::Stream::State->new; $ok->update_state($state); @@ -262,6 +274,11 @@ describe to_tap => sub { case pass => sub { $pass = 1 }; case fail => sub { $pass = 0 }; + around_all hide_warnings => sub { + local $SIG{__WARN__} = sub { 1 }; + $_[0]->(); + }; + tests name_and_number => sub { my $ok = Test::Stream::Event::Ok->new(debug => $dbg, pass => $pass, name => 'foo'); my @tap = $ok->to_tap(7); diff --git a/t/modules/Event/Plan.t b/t/modules/Event/Plan.t index 7a263c3..071a4e7 100644 --- a/t/modules/Event/Plan.t +++ b/t/modules/Event/Plan.t @@ -13,11 +13,13 @@ my $plan = Test::Stream::Event::Plan->new( max => 100, ); -is( - [$plan->to_tap(1)], - [[OUT_STD, "1..100\n"]], - "Got tap" -); +warns { + is( + [$plan->to_tap(1)], + [[OUT_STD, "1..100\n"]], + "Got tap" + ); +}; ok(!$plan->global, "regular plan is not a global event"); my $state = Test::Stream::State->new; $plan->update_state($state); @@ -27,11 +29,13 @@ is($plan->terminate, undef, "No terminate for normal plan"); $plan->set_max(0); $plan->set_directive('SKIP'); $plan->set_reason('foo'); -is( - [$plan->to_tap(1)], - [[OUT_STD, "1..0 # SKIP foo\n"]], - "Got tap for skip_all" -); +warns { + is( + [$plan->to_tap(1)], + [[OUT_STD, "1..0 # SKIP foo\n"]], + "Got tap for skip_all" + ); +}; ok($plan->global, "plan is global on skip all"); $state = Test::Stream::State->new; $plan->update_state($state); @@ -57,11 +61,13 @@ $plan = Test::Stream::Event::Plan->new( directive => 'skip_all', ); is($plan->directive, 'SKIP', "Change skip_all to SKIP"); -is( - [$plan->to_tap], - [[OUT_STD, "1..0 # SKIP\n"]], - "SKIP without reason" -); +warns { + is( + [$plan->to_tap], + [[OUT_STD, "1..0 # SKIP\n"]], + "SKIP without reason" + ); +}; $plan = Test::Stream::Event::Plan->new( debug => Test::Stream::DebugInfo->new(frame => [__PACKAGE__, __FILE__, __LINE__]), @@ -70,11 +76,13 @@ $plan = Test::Stream::Event::Plan->new( ); is($plan->directive, 'NO PLAN', "Change no_plan to 'NO PLAN'"); ok(!$plan->global, "NO PLAN is not global"); -is( - [$plan->to_tap], - [], - "NO PLAN" -); +warns { + is( + [$plan->to_tap], + [], + "NO PLAN" + ); +}; like( dies { diff --git a/t/modules/Event/Subtest.t b/t/modules/Event/Subtest.t index 43960c1..b260c3c 100644 --- a/t/modules/Event/Subtest.t +++ b/t/modules/Event/Subtest.t @@ -15,23 +15,27 @@ my $one = $st->new( isa_ok($one, $st, 'Test::Stream::Event::Ok'); is($one->subevents, [], "subevents is an arrayref"); -is( - [$one->to_tap(5)], - [ - [OUT_STD, "ok 5 - foo {\n"], - [OUT_STD, "}\n"], - ], - "Got Buffered TAP output" -); +warns { + is( + [$one->to_tap(5)], + [ + [OUT_STD, "ok 5 - foo {\n"], + [OUT_STD, "}\n"], + ], + "Got Buffered TAP output" + ); +}; $one->set_buffered(0); -is( - [$one->to_tap(5)], - [ - [OUT_STD, "ok 5 - foo\n"], - ], - "Got Unbuffered TAP output" -); +warns { + is( + [$one->to_tap(5)], + [ + [OUT_STD, "ok 5 - foo\n"], + ], + "Got Unbuffered TAP output" + ); +}; $dbg = Test::Stream::DebugInfo->new(frame => [__PACKAGE__, __FILE__, __LINE__, 'xxx']); $one = $st->new( @@ -51,7 +55,7 @@ $one = $st->new( ], ); -{ +warns { local $ENV{HARNESS_IS_VERBOSE}; is( [$one->to_tap(5)], @@ -68,9 +72,9 @@ $one = $st->new( ], "Got Buffered TAP output (non-verbose)" ); -} +}; -{ +warns { local $ENV{HARNESS_IS_VERBOSE} = 1; is( [$one->to_tap(5)], @@ -87,9 +91,9 @@ $one = $st->new( ], "Got Buffered TAP output (verbose)" ); -} +}; -{ +warns { local $ENV{HARNESS_IS_VERBOSE}; $one->set_buffered(0); is( @@ -101,9 +105,9 @@ $one = $st->new( ], "Got Unbuffered TAP output (non-verbose)" ); -} +}; -{ +warns { local $ENV{HARNESS_IS_VERBOSE} = 1; $one->set_buffered(0); is( @@ -115,7 +119,6 @@ $one = $st->new( ], "Got Unbuffered TAP output (verbose)" ); -} - +}; done_testing; From 77f7327947ca826a2ef37e4be130c64750abcaef Mon Sep 17 00:00:00 2001 From: Chad Granum Date: Sun, 22 Nov 2015 14:40:28 -0800 Subject: [PATCH 04/10] Port to_tap tests into TAP.t --- t/modules/Formatter/TAP.t | 434 +++++++++++++++++++++++++++++++++++++- 1 file changed, 429 insertions(+), 5 deletions(-) diff --git a/t/modules/Formatter/TAP.t b/t/modules/Formatter/TAP.t index dca8053..7db8b7c 100644 --- a/t/modules/Formatter/TAP.t +++ b/t/modules/Formatter/TAP.t @@ -1,10 +1,7 @@ -use strict; -use warnings; - -use Test::Stream qw/Core Compare/; +use Test::Stream -V1, -SpecTester, '!UTF8', Compare => '*'; use PerlIO; -use Test::Stream::Formatter::TAP; +use Test::Stream::Formatter::TAP qw/OUT_STD OUT_ERR OUT_TODO/; ok(my $one = Test::Stream::Formatter::TAP->new, "Created a new instance"); isa_ok($one, 'Test::Stream::Formatter::TAP'); @@ -126,4 +123,431 @@ $it->write($_, 1) for $ok, $diag, $plan, $bail; is($std, "ok - xxx\n", "Only got the 'ok'"); is($err, "", "no diag"); +describe events => sub { + my $fmt = Test::Stream::Formatter::TAP->new; + my $dbg; + before_each dbg => sub { + $dbg = Test::Stream::DebugInfo->new( + frame => ['main_foo', 'foo.t', 42, 'main_foo::flubnarb'], + ); + }; + + tests bail => sub { + my $bail = Test::Stream::Event::Bail->new( + debug => $dbg, + reason => 'evil', + ); + + is( + [$fmt->event_tap($bail, 1)], + [[OUT_STD, "Bail out! evil\n" ]], + "Got tap" + ); + }; + + tests diag => sub { + my $diag = Test::Stream::Event::Diag->new( + debug => $dbg, + message => 'foo', + ); + + is( + [$fmt->event_tap($diag, 1)], + [[OUT_ERR, "# foo\n"]], + "Got tap" + ); + + $diag->set_message("foo\n"); + is( + [$fmt->event_tap($diag, 1)], + [[OUT_ERR, "# foo\n"]], + "Only 1 newline" + ); + + $diag->debug->set_todo('todo'); + is( + [$fmt->event_tap($diag, 1)], + [[OUT_TODO, "# foo\n"]], + "Got tap in todo" + ); + + $diag->set_message("foo\nbar\nbaz"); + is( + [$fmt->event_tap($diag, 1)], + [[OUT_TODO, "# foo\n# bar\n# baz\n"]], + "All lines have proper prefix" + ); + + $diag->debug->set_todo(undef); + $diag->set_message(""); + is([$fmt->event_tap($diag)], [], "no tap with an empty message"); + + $diag->set_message("\n"); + is([$fmt->event_tap($diag)], [[OUT_ERR, "\n"]], "newline on its own is unchanged"); + }; + + tests exception => sub { + my $exception = Test::Stream::Event::Exception->new( + debug => $dbg, + error => "evil at lake_of_fire.t line 6\n", + ); + + is( + [$fmt->event_tap($exception, 1)], + [[OUT_ERR, "evil at lake_of_fire.t line 6\n" ]], + "Got tap" + ); + }; + + tests note => sub { + my $note = Test::Stream::Event::Note->new( + debug => $dbg, + message => 'foo', + ); + + is( + [$fmt->event_tap($note, 1)], + [[OUT_STD, "# foo\n"]], + "Got tap" + ); + + $note->set_message("foo\n"); + is( + [$fmt->event_tap($note, 1)], + [[OUT_STD, "# foo\n"]], + "Only 1 newline" + ); + + $note->set_message("foo\nbar\nbaz"); + is( + [$fmt->event_tap($note, 1)], + [[OUT_STD, "# foo\n# bar\n# baz\n"]], + "All lines have proper prefix" + ); + + $note->set_message(""); + is([$fmt->event_tap($note)], [], "no tap with an empty message"); + + $note->set_message("\n"); + is([$fmt->event_tap($note)], [], "newline on its own is not shown"); + + $note->set_message("\nxxx"); + is([$fmt->event_tap($note)], [[OUT_STD, "\n# xxx\n"]], "newline starting"); + }; + + describe ok => sub { + my $pass; + case pass => sub { $pass = 1 }; + case fail => sub { $pass = 0 }; + + tests name_and_number => sub { + my $ok = Test::Stream::Event::Ok->new(debug => $dbg, pass => $pass, name => 'foo'); + my @tap = $fmt->event_tap($ok, 7); + is( + \@tap, + [ + [OUT_STD, ($pass ? 'ok' : 'not ok') . " 7 - foo\n"], + ], + "Got expected output" + ); + }; + + tests no_number => sub { + my $ok = Test::Stream::Event::Ok->new(debug => $dbg, pass => $pass, name => 'foo'); + my @tap = $fmt->event_tap($ok, ); + is( + \@tap, + [ + [OUT_STD, ($pass ? 'ok' : 'not ok') . " - foo\n"], + ], + "Got expected output" + ); + }; + + tests no_name => sub { + my $ok = Test::Stream::Event::Ok->new(debug => $dbg, pass => $pass); + my @tap = $fmt->event_tap($ok, 7); + is( + \@tap, + [ + [OUT_STD, ($pass ? 'ok' : 'not ok') . " 7\n"], + ], + "Got expected output" + ); + }; + + tests skip_and_todo => sub { + $dbg->set_todo('a'); + $dbg->set_skip('b'); + + my $ok = Test::Stream::Event::Ok->new(debug => $dbg, pass => $pass); + my @tap = $fmt->event_tap($ok, 7); + is( + \@tap, + [ + [OUT_STD, ($pass ? 'ok' : 'not ok') . " 7 # TODO & SKIP a\n"], + ], + "Got expected output" + ); + + $dbg->set_todo(""); + + @tap = $fmt->event_tap($ok, 7); + is( + \@tap, + [ + [OUT_STD, ($pass ? 'ok' : 'not ok') . " 7 # TODO & SKIP\n"], + ], + "Got expected output" + ); + }; + + tests skip => sub { + $dbg->set_skip('b'); + + my $ok = Test::Stream::Event::Ok->new(debug => $dbg, pass => $pass); + my @tap = $fmt->event_tap($ok, 7); + is( + \@tap, + [ + [OUT_STD, ($pass ? 'ok' : 'not ok') . " 7 # skip b\n"], + ], + "Got expected output" + ); + + $dbg->set_skip(""); + + @tap = $fmt->event_tap($ok, 7); + is( + \@tap, + [ + [OUT_STD, ($pass ? 'ok' : 'not ok') . " 7 # skip\n"], + ], + "Got expected output" + ); + }; + + tests todo => sub { + $dbg->set_todo('b'); + + my $ok = Test::Stream::Event::Ok->new(debug => $dbg, pass => $pass); + my @tap = $fmt->event_tap($ok, 7); + is( + \@tap, + [ + [OUT_STD, ($pass ? 'ok' : 'not ok') . " 7 # TODO b\n"], + ], + "Got expected output" + ); + + $dbg->set_todo(""); + + @tap = $fmt->event_tap($ok, 7); + is( + \@tap, + [ + [OUT_STD, ($pass ? 'ok' : 'not ok') . " 7 # TODO\n"], + ], + "Got expected output" + ); + }; + + tests empty_diag_array => sub { + my $ok = Test::Stream::Event::Ok->new(debug => $dbg, pass => $pass, diag => []); + my @tap = $fmt->event_tap($ok, 7); + is( + \@tap, + [ + [OUT_STD, ($pass ? 'ok' : 'not ok') . " 7\n"], + ], + "Got expected output (No diag)" + ); + + $ok = Test::Stream::Event::Ok->new(debug => $dbg, pass => $pass); + @tap = $fmt->event_tap($ok, 7); + is( + \@tap, + [ + [OUT_STD, ($pass ? 'ok' : 'not ok') . " 7\n"], + ], + "Got expected output (No diag)" + ); + }; + + tests diag => sub { + my $ok = Test::Stream::Event::Ok->new( + debug => $dbg, + pass => 0, + name => 'the_test', + diag => ['xxx'], + ); + + is( + [$fmt->event_tap($ok, 4)], + [ + [OUT_STD, "not ok 4 - the_test\n"], + [OUT_ERR, "# xxx\n"], + ], + "Got tap for failing ok" + ); + }; + }; + + tests plan => sub { + my $plan = Test::Stream::Event::Plan->new( + debug => $dbg, + max => 100, + ); + + is( + [$fmt->event_tap($plan, 1)], + [[OUT_STD, "1..100\n"]], + "Got tap" + ); + + $plan->set_max(0); + $plan->set_directive('SKIP'); + $plan->set_reason('foo'); + is( + [$fmt->event_tap($plan, 1)], + [[OUT_STD, "1..0 # SKIP foo\n"]], + "Got tap for skip_all" + ); + + $plan = Test::Stream::Event::Plan->new( + debug => $dbg, + max => 0, + directive => 'skip_all', + ); + is( + [$fmt->event_tap($plan)], + [[OUT_STD, "1..0 # SKIP\n"]], + "SKIP without reason" + ); + + $plan = Test::Stream::Event::Plan->new( + debug => $dbg, + max => 0, + directive => 'no_plan', + ); + is( + [$fmt->event_tap($plan)], + [], + "NO PLAN" + ); + }; + + tests subtest => sub { + my $st = 'Test::Stream::Event::Subtest'; + + my $one = $st->new( + debug => $dbg, + pass => 1, + buffered => 1, + name => 'foo', + ); + + is( + [$fmt->event_tap($one, 5)], + [ + [OUT_STD, "ok 5 - foo {\n"], + [OUT_STD, "}\n"], + ], + "Got Buffered TAP output" + ); + + $one->set_buffered(0); + is( + [$fmt->event_tap($one, 5)], + [ + [OUT_STD, "ok 5 - foo\n"], + ], + "Got Unbuffered TAP output" + ); + + $one = $st->new( + debug => $dbg, + pass => 0, + buffered => 1, + name => 'bar', + diag => [ 'bar failed' ], + subevents => [ + Test::Stream::Event::Ok->new(debug => $dbg, name => 'first', pass => 1), + Test::Stream::Event::Ok->new(debug => $dbg, name => 'second', pass => 0, diag => ["second failed"]), + Test::Stream::Event::Ok->new(debug => $dbg, name => 'third', pass => 1), + + Test::Stream::Event::Diag->new(debug => $dbg, message => 'blah blah'), + + Test::Stream::Event::Plan->new(debug => $dbg, max => 3), + ], + ); + + { + local $ENV{HARNESS_IS_VERBOSE}; + is( + [$fmt->event_tap($one, 5)], + [ + [OUT_STD, "not ok 5 - bar {\n"], + [OUT_ERR, "# bar failed\n"], + [OUT_STD, " ok 1 - first\n"], + [OUT_STD, " not ok 2 - second\n"], + [OUT_ERR, " # second failed\n"], + [OUT_STD, " ok 3 - third\n"], + [OUT_ERR, " # blah blah\n"], + [OUT_STD, " 1..3\n"], + [OUT_STD, "}\n"], + ], + "Got Buffered TAP output (non-verbose)" + ); + } + + { + local $ENV{HARNESS_IS_VERBOSE} = 1; + is( + [$fmt->event_tap($one, 5)], + [ + [OUT_STD, "not ok 5 - bar {\n"], + [OUT_ERR, " # bar failed\n"], + [OUT_STD, " ok 1 - first\n"], + [OUT_STD, " not ok 2 - second\n"], + [OUT_ERR, " # second failed\n"], + [OUT_STD, " ok 3 - third\n"], + [OUT_ERR, " # blah blah\n"], + [OUT_STD, " 1..3\n"], + [OUT_STD, "}\n"], + ], + "Got Buffered TAP output (verbose)" + ); + } + + { + local $ENV{HARNESS_IS_VERBOSE}; + $one->set_buffered(0); + is( + [$fmt->event_tap($one, 5)], + [ + # In unbuffered TAP the subevents are rendered outside of this. + [OUT_STD, "not ok 5 - bar\n"], + [OUT_ERR, "# bar failed\n"], + ], + "Got Unbuffered TAP output (non-verbose)" + ); + } + + { + local $ENV{HARNESS_IS_VERBOSE} = 1; + $one->set_buffered(0); + is( + [$fmt->event_tap($one, 5)], + [ + # In unbuffered TAP the subevents are rendered outside of this. + [OUT_STD, "not ok 5 - bar\n"], + [OUT_ERR, "# bar failed\n"], + ], + "Got Unbuffered TAP output (verbose)" + ); + } + }; +}; + done_testing; From 1bfdda71a70ad8cdcbb6dd8b747376567525724d Mon Sep 17 00:00:00 2001 From: Chad Granum Date: Mon, 23 Nov 2015 15:09:16 -0800 Subject: [PATCH 05/10] Remove unnecessary optimization --- lib/Test/Stream/Formatter/TAP.pm | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/Test/Stream/Formatter/TAP.pm b/lib/Test/Stream/Formatter/TAP.pm index d09bf95..c9989d1 100644 --- a/lib/Test/Stream/Formatter/TAP.pm +++ b/lib/Test/Stream/Formatter/TAP.pm @@ -11,7 +11,6 @@ sub OUT_STD() { 0 } sub OUT_ERR() { 1 } sub OUT_TODO() { 2 } -use Scalar::Util qw/blessed/; use Carp qw/croak/; use Test::Stream::Exporter qw/import exports/; @@ -120,9 +119,7 @@ sub event_tap { my $self = shift; my ($e, $num) = @_; - # Optimization for the most common case of an 'ok' event - my $is_ok = index("$e", 'Test::Stream::Event::Ok=' ) == 0; - my $converter = $is_ok ? \&_ok_event : $CONVERTERS{blessed($e)}; + my $converter = $CONVERTERS{ref($e)}; $num = undef if $self->{+NO_NUMBERS}; From bd53460ffaaba4479415c53314c72996a5fc90e1 Mon Sep 17 00:00:00 2001 From: Chad Granum Date: Mon, 23 Nov 2015 16:44:19 -0800 Subject: [PATCH 06/10] Break out Skip into an event type * Add Test::Stream::Event::Skip * Add ctx->skip * deprecate debug->skip * Fix tests that expect Ok's for Skips. --- lib/Test/Stream/Compare/EventMeta.pm | 8 ++- lib/Test/Stream/Context.pm | 8 ++- lib/Test/Stream/DebugInfo.pm | 28 +++++++- lib/Test/Stream/Event/Ok.pm | 5 -- lib/Test/Stream/Event/Skip.pm | 95 ++++++++++++++++++++++++++++ lib/Test/Stream/Formatter/TAP.pm | 21 +++++- lib/Test/Stream/Plugin/Core.pm | 4 +- lib/Test/Stream/Workflow/Task.pm | 9 ++- lib/Test/Stream/Workflow/Unit.pm | 1 - t/behavior/TesterBundle.t | 7 +- t/modules/Compare/EventMeta.t | 15 ++++- t/modules/DebugInfo.t | 6 +- t/modules/Event/Ok.t | 3 +- t/modules/Event/Skip.t | 18 ++++++ t/modules/Formatter/TAP.t | 8 ++- t/modules/Plugin/Core.t | 6 +- t/modules/Workflow/Task.t | 11 ++-- t/modules/Workflow/Unit.t | 6 -- 18 files changed, 214 insertions(+), 45 deletions(-) create mode 100644 lib/Test/Stream/Event/Skip.pm create mode 100644 t/modules/Event/Skip.t diff --git a/lib/Test/Stream/Compare/EventMeta.pm b/lib/Test/Stream/Compare/EventMeta.pm index 51d8d8d..02cbefc 100644 --- a/lib/Test/Stream/Compare/EventMeta.pm +++ b/lib/Test/Stream/Compare/EventMeta.pm @@ -5,16 +5,22 @@ use warnings; use base 'Test::Stream::Compare::Meta'; use Test::Stream::HashBase; +use Carp qw/carp/; + sub get_prop_file { $_[1]->debug->file } sub get_prop_line { $_[1]->debug->line } sub get_prop_package { $_[1]->debug->package } sub get_prop_subname { $_[1]->debug->subname } -sub get_prop_skip { $_[1]->debug->skip } sub get_prop_todo { $_[1]->debug->todo } sub get_prop_trace { $_[1]->debug->trace } sub get_prop_tid { $_[1]->debug->tid } sub get_prop_pid { $_[1]->debug->pid } +sub get_prop_skip { + carp "Use of 'skip' property is deprecated"; + $_[1]->debug->_skip; # Private no-warning version until removed +} + 1; __END__ diff --git a/lib/Test/Stream/Context.pm b/lib/Test/Stream/Context.pm index 858080e..59a2b0d 100644 --- a/lib/Test/Stream/Context.pm +++ b/lib/Test/Stream/Context.pm @@ -15,7 +15,7 @@ my %LOADED = ( require "Test/Stream/Event/$_.pm"; my $pkg = "Test::Stream::Event::$_"; ( $pkg => $pkg, $_ => $pkg ) - } qw/Ok Diag Note Plan Bail Exception Waiting/ + } qw/Ok Diag Note Plan Bail Exception Waiting Skip/ ); # Stack is ok to cache. @@ -322,6 +322,12 @@ sub ok { $self->{+HUB}->send($e); } +sub skip { + my $self = shift; + my ($name, $reason) = @_; + $self->send_event('Skip', name => $name, reason => $reason); +} + sub note { my $self = shift; my ($message) = @_; diff --git a/lib/Test/Stream/DebugInfo.pm b/lib/Test/Stream/DebugInfo.pm index 7e17933..f61f000 100644 --- a/lib/Test/Stream/DebugInfo.pm +++ b/lib/Test/Stream/DebugInfo.pm @@ -4,18 +4,42 @@ use warnings; use Test::Stream::Util qw/get_tid/; -use Carp qw/confess/; +use Carp qw/confess carp/; use Test::Stream::HashBase( - accessors => [qw/frame todo skip detail pid tid parent_todo/], + accessors => [qw/frame detail pid tid skip todo parent_todo/], ); +BEGIN { + my $set = \&set_skip; + my $get = \&skip; + + my $new_set = sub { + carp "Use of 'skip' attribute for DebugInfo is deprecated"; + $set->(@_); + }; + + my $new_get = sub { + carp "Use of 'skip' attribute for DebugInfo is deprecated"; + $get->(@_); + }; + + no strict 'refs'; + no warnings 'redefine'; + *set_skip = $new_set; + *skip = $new_get; + *_skip = $get; +} + sub init { confess "Frame is required" unless $_[0]->{+FRAME}; $_[0]->{+PID} ||= $$; $_[0]->{+TID} ||= get_tid(); + + $_[0]->alert("Use of 'skip' attribute for DebugInfo is deprecated") + if defined $_[0]->{+SKIP}; } sub snapshot { bless {%{$_[0]}}, __PACKAGE__ }; diff --git a/lib/Test/Stream/Event/Ok.pm b/lib/Test/Stream/Event/Ok.pm index 21ca8bd..cbb721b 100644 --- a/lib/Test/Stream/Event/Ok.pm +++ b/lib/Test/Stream/Event/Ok.pm @@ -2,13 +2,8 @@ package Test::Stream::Event::Ok; use strict; use warnings; -use Scalar::Util qw/blessed/; use Carp qw/confess/; -use Test::Stream::Formatter::TAP qw/OUT_STD OUT_TODO OUT_ERR/; - -use Test::Stream::Event::Diag(); - use base 'Test::Stream::Event'; use Test::Stream::HashBase accessors => [qw/pass effective_pass name diag allow_bad_name/]; diff --git a/lib/Test/Stream/Event/Skip.pm b/lib/Test/Stream/Event/Skip.pm new file mode 100644 index 0000000..1d6ab69 --- /dev/null +++ b/lib/Test/Stream/Event/Skip.pm @@ -0,0 +1,95 @@ +package Test::Stream::Event::Skip; +use strict; +use warnings; + +use base 'Test::Stream::Event::Ok'; +use Test::Stream::HashBase accessors => [qw/reason/]; + +sub init { + my $self = shift; + $self->SUPER::init; + + $self->{+PASS} = 0; + $self->{+EFFECTIVE_PASS} = 1; +} + +sub update_state { $_[1]->bump(1) } + +sub causes_fail { 0 } + +1; + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Test::Stream::Event::Skip - Skip event type + +=head1 DESCRIPTION + +Skip events bump test counts just like L events, but +they can never fail. + +=head1 SYNOPSIS + + use Test::Stream::Context qw/context/; + use Test::Stream::Event::Skip; + + my $ctx = context(); + my $event = $ctx->skip($name, $reason); + +or: + + my $ctx = debug(); + my $event = $ctx->send_event( + 'Skip', + name => $name, + reason => $reason, + ); + +=head1 ACCESSORS + +=over 4 + +=item $reason = $e->reason + +The original true/false value of whatever was passed into the event (but +reduced down to 1 or 0). + +=back + +=head1 SOURCE + +The source code repository for Test::Stream can be found at +F. + +=head1 MAINTAINERS + +=over 4 + +=item Chad Granum Eexodist@cpan.orgE + +=back + +=head1 AUTHORS + +=over 4 + +=item Chad Granum Eexodist@cpan.orgE + +=back + +=head1 COPYRIGHT + +Copyright 2015 Chad Granum Eexodist7@gmail.comE. + +This program is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. + +See F + +=cut diff --git a/lib/Test/Stream/Formatter/TAP.pm b/lib/Test/Stream/Formatter/TAP.pm index c9989d1..0287c85 100644 --- a/lib/Test/Stream/Formatter/TAP.pm +++ b/lib/Test/Stream/Formatter/TAP.pm @@ -19,6 +19,7 @@ no Test::Stream::Exporter; my %CONVERTERS = ( 'Test::Stream::Event::Ok' => \&_ok_event, + 'Test::Stream::Event::Skip' => \&_skip_event, 'Test::Stream::Event::Note' => \&_note_event, 'Test::Stream::Event::Diag' => \&_diag_event, 'Test::Stream::Event::Bail' => \&_bail_event, @@ -142,8 +143,8 @@ sub _ok_event { # need this to be fast. my $name = $e->{name}; my $debug = $e->{debug}; - my $skip = $debug->{skip}; my $todo = $debug->{todo}; + my $skip = $debug->{skip}; # Deprecated my $out = ""; $out .= "not " unless $e->{pass}; @@ -181,6 +182,24 @@ sub _ok_event { return @out; } +sub _skip_event { + my $self = shift; + my ($e, $num) = @_; + + my $name = $e->name; + my $debug = $e->debug; + my $skip = $e->reason; + my $todo = $debug->todo; + + my $out = "ok"; + $out .= " $num" if defined $num; + $out .= " - $name" if $name; + $out .= " # skip"; + $out .= " $skip" if length $skip; + + return([OUT_STD, "$out\n"]); +} + sub _note_event { my $self = shift; my ($e, $num) = @_; diff --git a/lib/Test/Stream/Plugin/Core.pm b/lib/Test/Stream/Plugin/Core.pm index e495b56..35d5d94 100644 --- a/lib/Test/Stream/Plugin/Core.pm +++ b/lib/Test/Stream/Plugin/Core.pm @@ -177,9 +177,7 @@ sub skip { my ($why, $num) = @_; $num ||= 1; my $ctx = context(); - $ctx->debug->set_skip($why); - $ctx->ok(1, "skipped test") for 1 .. $num; - $ctx->debug->set_skip(undef); + $ctx->skip("skipped test", $why) for 1 .. $num; $ctx->release; no warnings 'exiting'; last SKIP; diff --git a/lib/Test/Stream/Workflow/Task.pm b/lib/Test/Stream/Workflow/Task.pm index 4d93d59..78b68c3 100644 --- a/lib/Test/Stream/Workflow/Task.pm +++ b/lib/Test/Stream/Workflow/Task.pm @@ -114,11 +114,16 @@ sub run { my $unit = $self->{+UNIT}; my $ctx = $unit->context; + my $meta = $unit->meta; + + my $skip; + $skip = $meta->{skip} if $meta && defined $meta->{skip}; + $skip ||= $ctx->debug->_skip; # Private accessor for deprecated thing, just until it goes away # Skip? - if ($ctx->debug->skip) { + if ($skip) { $self->{+STAGE} = STAGE_COMPLETE(); - $ctx->ok(1, $self->{+UNIT}->name); + $ctx->skip($unit->name, $skip); return; } diff --git a/lib/Test/Stream/Workflow/Unit.pm b/lib/Test/Stream/Workflow/Unit.pm index fedefe1..137d0cb 100644 --- a/lib/Test/Stream/Workflow/Unit.pm +++ b/lib/Test/Stream/Workflow/Unit.pm @@ -148,7 +148,6 @@ sub debug { return Test::Stream::DebugInfo->new( frame => [@$self{qw/package file start_line name/}], - skip => $self->meta->{skip}, detail => "in block '$self->{+NAME}' defined in $self->{+FILE} (Approx) lines $self->{+START_LINE} -> $self->{+END_LINE}", $hub->debug_todo, ); diff --git a/t/behavior/TesterBundle.t b/t/behavior/TesterBundle.t index 90a51c5..7a9ef6d 100644 --- a/t/behavior/TesterBundle.t +++ b/t/behavior/TesterBundle.t @@ -72,7 +72,6 @@ like( prop package => __PACKAGE__; prop subname => 'Test::Stream::Plugin::Core::ok'; prop trace => 'at ' . __FILE__ . ' line ' . $base; - prop skip => undef; prop todo => undef; }; }, @@ -88,11 +87,9 @@ like( event Ok => sub { field effective_pass => 1; prop todo => 'foo'; - prop skip => undef; }; - event Ok => sub { - field effective_pass => 1; - prop skip => 'blah'; + event Skip => sub { + field reason => 'blah'; prop todo => undef; }; end; diff --git a/t/modules/Compare/EventMeta.t b/t/modules/Compare/EventMeta.t index 70c2f1e..a955e9d 100644 --- a/t/modules/Compare/EventMeta.t +++ b/t/modules/Compare/EventMeta.t @@ -10,15 +10,24 @@ is($one->get_prop_file($Ok), 'foo.t', "file"); is($one->get_prop_line($Ok), 42, "line"); is($one->get_prop_package($Ok), 'Foo', "package"); is($one->get_prop_subname($Ok), 'foo', "subname"); -is($one->get_prop_skip($Ok), undef, "skip (unset)"); is($one->get_prop_todo($Ok), undef, "todo (unset)"); is($one->get_prop_trace($Ok), 'at foo.t line 42', "trace"); is($one->get_prop_pid($Ok), $$, "pid"); is($one->get_prop_tid($Ok), get_tid, "tid"); +like( + warning { is($one->get_prop_skip($Ok), undef, "skip (unset)") }, + qr/Use of 'skip' property is deprecated/, + "Got skip warning" +); + $Ok->debug->set_todo('a'); -$Ok->debug->set_skip('b'); is($one->get_prop_todo($Ok), 'a', "todo (set)"); -is($one->get_prop_skip($Ok), 'b', "skip (set)"); + +# Deprecated +warns { + $Ok->debug->set_skip('b'); + is($one->get_prop_skip($Ok), 'b', "skip (set)"); +}; done_testing; diff --git a/t/modules/DebugInfo.t b/t/modules/DebugInfo.t index ee1eeca..a236d15 100644 --- a/t/modules/DebugInfo.t +++ b/t/modules/DebugInfo.t @@ -53,7 +53,11 @@ ok($one->no_diag, "no diag"); ok($one->no_fail, "no fail"); $one->set_todo(undef); -$one->set_skip(1); +like( + warning { $one->set_skip(1) }, + qr/Use of 'skip' attribute for DebugInfo is deprecated/, + "Got expected warning for deprecated 'skip' attribute" +); ok($one->no_diag, "no diag"); ok($one->no_fail, "no fail"); diff --git a/t/modules/Event/Ok.t b/t/modules/Event/Ok.t index 70645fd..cff769d 100644 --- a/t/modules/Event/Ok.t +++ b/t/modules/Event/Ok.t @@ -191,9 +191,10 @@ tests "Failing TODO" => sub { $dbg->set_todo(undef); }; +# This is deprecated tests skip => sub { local $ENV{HARNESS_ACTIVE} = 1; - $dbg->set_skip('A Skip'); + warns { $dbg->set_skip('A Skip') }; my $ok = Test::Stream::Event::Ok->new( debug => $dbg, pass => 1, diff --git a/t/modules/Event/Skip.t b/t/modules/Event/Skip.t new file mode 100644 index 0000000..d355441 --- /dev/null +++ b/t/modules/Event/Skip.t @@ -0,0 +1,18 @@ +use Test::Stream -V1; +use strict; +use warnings; + +use Test::Stream::Event::Skip; +use Test::Stream::DebugInfo; + +my $skip = Test::Stream::Event::Skip->new( + debug => Test::Stream::DebugInfo->new(frame => [__PACKAGE__, __FILE__, __LINE__]), + name => 'skip me', + reason => 'foo', +); + +isa_ok($skip, 'Test::Stream::Event::Skip'); +is($skip->name, 'skip me', "set name"); +is($skip->reason, 'foo', "got skip reason"); + +done_testing; diff --git a/t/modules/Formatter/TAP.t b/t/modules/Formatter/TAP.t index 7db8b7c..ebea3e7 100644 --- a/t/modules/Formatter/TAP.t +++ b/t/modules/Formatter/TAP.t @@ -276,9 +276,10 @@ describe events => sub { ); }; + # Deprecated tests skip_and_todo => sub { $dbg->set_todo('a'); - $dbg->set_skip('b'); + warns { $dbg->set_skip('b') }; my $ok = Test::Stream::Event::Ok->new(debug => $dbg, pass => $pass); my @tap = $fmt->event_tap($ok, 7); @@ -302,8 +303,9 @@ describe events => sub { ); }; + # Deprecated tests skip => sub { - $dbg->set_skip('b'); + warns { $dbg->set_skip('b') }; my $ok = Test::Stream::Event::Ok->new(debug => $dbg, pass => $pass); my @tap = $fmt->event_tap($ok, 7); @@ -315,7 +317,7 @@ describe events => sub { "Got expected output" ); - $dbg->set_skip(""); + warns { $dbg->set_skip("") }; @tap = $fmt->event_tap($ok, 7); is( diff --git a/t/modules/Plugin/Core.t b/t/modules/Plugin/Core.t index e83b645..8ce0ba5 100644 --- a/t/modules/Plugin/Core.t +++ b/t/modules/Plugin/Core.t @@ -405,11 +405,9 @@ like( array { event Ok => sub { call pass => 1; - prop skip => undef; }; - event Ok => sub { - call pass => 1; - prop skip => 'oops'; + event Skip => sub { + call reason => 'oops'; } for 1 .. 5; end; }, diff --git a/t/modules/Workflow/Task.t b/t/modules/Workflow/Task.t index e310cba..2d73fe7 100644 --- a/t/modules/Workflow/Task.t +++ b/t/modules/Workflow/Task.t @@ -115,15 +115,14 @@ $unit->{'~~MOCK~CONTROL~~'}->add( context => $new_ctx ); $one->reset; $unit->name('bob'); -$debug->set_skip('foo'); +warns { $debug->set_skip('foo') }; is( intercept { $one->run }, array { - event Ok => sub { - call name => 'bob'; - call pass => 1; - prop skip => 'foo'; + event Skip => sub { + call name => 'bob'; + call reason => 'foo'; }; end; }, @@ -132,7 +131,7 @@ is( is($one->stage, $one->STAGE_COMPLETE, "stage set to complete after skip"); $one->reset; -$debug->set_skip(undef); +warns { $debug->set_skip(undef) }; $unit->primary(undef); is( diff --git a/t/modules/Workflow/Unit.t b/t/modules/Workflow/Unit.t index 60cbc12..5b791b6 100644 --- a/t/modules/Workflow/Unit.t +++ b/t/modules/Workflow/Unit.t @@ -68,12 +68,6 @@ like( "got a todo event" ); -{ - local $unit->meta->{skip} = "this is a skip"; - my $ctx = $unit->context; - is($ctx->debug->skip, 'this is a skip', "skip is set"); -} - like( dies { CLASS->new() }, qr/name is a required attribute/, From 6b83a0f29747a4f719d5de8349f3970fc610e63c Mon Sep 17 00:00:00 2001 From: Chad Granum Date: Sun, 6 Dec 2015 09:53:56 -0800 Subject: [PATCH 07/10] Deprecate DebugInfo's todo capabilities --- lib/Test/Stream/DebugInfo.pm | 59 +++++++++++++++++++++++------------- t/modules/DebugInfo.t | 25 +++++++-------- 2 files changed, 51 insertions(+), 33 deletions(-) diff --git a/lib/Test/Stream/DebugInfo.pm b/lib/Test/Stream/DebugInfo.pm index f61f000..d931960 100644 --- a/lib/Test/Stream/DebugInfo.pm +++ b/lib/Test/Stream/DebugInfo.pm @@ -11,24 +11,27 @@ use Test::Stream::HashBase( ); BEGIN { - my $set = \&set_skip; - my $get = \&skip; - - my $new_set = sub { - carp "Use of 'skip' attribute for DebugInfo is deprecated"; - $set->(@_); - }; - - my $new_get = sub { - carp "Use of 'skip' attribute for DebugInfo is deprecated"; - $get->(@_); - }; - - no strict 'refs'; - no warnings 'redefine'; - *set_skip = $new_set; - *skip = $new_get; - *_skip = $get; + for my $attr (SKIP, TODO, PARENT_TODO) { + my $set = __PACKAGE__->can("set_$attr"); + my $get = __PACKAGE__->can($attr); + + my $new_set = sub { + carp "Use of '$attr' attribute for DebugInfo is deprecated"; + $set->(@_); + }; + + my $new_get = sub { + carp "Use of '$attr' attribute for DebugInfo is deprecated"; + $get->(@_); + }; + + no strict 'refs'; + no warnings 'redefine'; + *{"set_$attr"} = $new_set; + *{"$attr"} = $new_get; + *{"_$attr"} = $get; + *{"_set_$attr"} = $set; + } } sub init { @@ -38,8 +41,10 @@ sub init { $_[0]->{+PID} ||= $$; $_[0]->{+TID} ||= get_tid(); - $_[0]->alert("Use of 'skip' attribute for DebugInfo is deprecated") - if defined $_[0]->{+SKIP}; + for my $attr (SKIP, TODO, PARENT_TODO) { + next unless defined $_[0]->{$attr}; + $_[0]->alert("Use of '$attr' attribute for DebugInfo is deprecated") + } } sub snapshot { bless {%{$_[0]}}, __PACKAGE__ }; @@ -71,13 +76,25 @@ sub line { $_[0]->{+FRAME}->[2] } sub subname { $_[0]->{+FRAME}->[3] } sub no_diag { + my $self = shift; + $self->alert("Use of the 'no_diag' method is deprecated"); + $self->_no_diag(@_); +} + +sub no_fail { + my $self = shift; + $self->alert("Use of the 'no_fail' method is deprecated"); + $self->_no_fail(@_); +} + +sub _no_diag { my $self = shift; return defined($self->{+TODO}) || defined($self->{+SKIP}) || defined($self->{+PARENT_TODO}); } -sub no_fail { +sub _no_fail { my $self = shift; return defined($self->{+TODO}) || defined($self->{+SKIP}); diff --git a/t/modules/DebugInfo.t b/t/modules/DebugInfo.t index a236d15..3d545be 100644 --- a/t/modules/DebugInfo.t +++ b/t/modules/DebugInfo.t @@ -40,25 +40,26 @@ my $snap = $one->snapshot; is($snap, $one, "identical"); ok($snap != $one, "Not the same instance"); -ok(!$one->no_diag, "yes diag"); -ok(!$one->no_fail, "yes fail"); -$one->set_parent_todo(1); -ok($one->no_diag, "no diag"); -ok(!$one->no_fail, "yes fail"); +ok(!$one->_no_diag, "yes diag"); +ok(!$one->_no_fail, "yes fail"); -$one->set_parent_todo(0); -$one->set_todo(1); -ok($one->no_diag, "no diag"); -ok($one->no_fail, "no fail"); +$one->_set_parent_todo(1); +ok($one->_no_diag, "no diag"); +ok(!$one->_no_fail, "yes fail"); -$one->set_todo(undef); +$one->_set_parent_todo(0); +$one->_set_todo(1); +ok($one->_no_diag, "no diag"); +ok($one->_no_fail, "no fail"); + +$one->_set_todo(undef); like( warning { $one->set_skip(1) }, qr/Use of 'skip' attribute for DebugInfo is deprecated/, "Got expected warning for deprecated 'skip' attribute" ); -ok($one->no_diag, "no diag"); -ok($one->no_fail, "no fail"); +ok($one->_no_diag, "no diag"); +ok($one->_no_fail, "no fail"); done_testing; From 6a1c48a5117860fab671c64537ebb6af00bf4acf Mon Sep 17 00:00:00 2001 From: Chad Granum Date: Sun, 6 Dec 2015 09:55:49 -0800 Subject: [PATCH 08/10] Add 'todo' fields for Diag and Ok events --- lib/Test/Stream/Compare/EventMeta.pm | 14 +++++++++++++- lib/Test/Stream/Event/Diag.pm | 5 +---- lib/Test/Stream/Event/Ok.pm | 8 +++++--- lib/Test/Stream/Formatter/TAP.pm | 9 +++++---- lib/Test/Stream/Plugin/Subtest.pm | 3 ++- t/modules/Compare/EventMeta.t | 8 ++++---- 6 files changed, 30 insertions(+), 17 deletions(-) diff --git a/lib/Test/Stream/Compare/EventMeta.pm b/lib/Test/Stream/Compare/EventMeta.pm index 02cbefc..fa0c9b0 100644 --- a/lib/Test/Stream/Compare/EventMeta.pm +++ b/lib/Test/Stream/Compare/EventMeta.pm @@ -11,11 +11,23 @@ sub get_prop_file { $_[1]->debug->file } sub get_prop_line { $_[1]->debug->line } sub get_prop_package { $_[1]->debug->package } sub get_prop_subname { $_[1]->debug->subname } -sub get_prop_todo { $_[1]->debug->todo } sub get_prop_trace { $_[1]->debug->trace } sub get_prop_tid { $_[1]->debug->tid } sub get_prop_pid { $_[1]->debug->pid } +sub get_prop_todo { + my $self = shift; + my ($thing) = @_; + + unless ($thing->can('todo')) { + my $type = ref($thing); + carp "Use of 'todo' property is deprecated for '$type'"; + return $thing->debug->_todo; # deprecated + } + + return $thing->todo || $thing->debug->_todo; +} + sub get_prop_skip { carp "Use of 'skip' property is deprecated"; $_[1]->debug->_skip; # Private no-warning version until removed diff --git a/lib/Test/Stream/Event/Diag.pm b/lib/Test/Stream/Event/Diag.pm index 4085fb7..482dd74 100644 --- a/lib/Test/Stream/Event/Diag.pm +++ b/lib/Test/Stream/Event/Diag.pm @@ -3,10 +3,7 @@ use strict; use warnings; use base 'Test::Stream::Event'; -use Test::Stream::HashBase accessors => [qw/message/]; - -use Carp qw/confess/; - +use Test::Stream::HashBase accessors => [qw/message todo/]; sub init { $_[0]->SUPER::init(); diff --git a/lib/Test/Stream/Event/Ok.pm b/lib/Test/Stream/Event/Ok.pm index cbb721b..624d748 100644 --- a/lib/Test/Stream/Event/Ok.pm +++ b/lib/Test/Stream/Event/Ok.pm @@ -5,7 +5,9 @@ use warnings; use Carp qw/confess/; use base 'Test::Stream::Event'; -use Test::Stream::HashBase accessors => [qw/pass effective_pass name diag allow_bad_name/]; +use Test::Stream::HashBase accessors => [ + qw/pass effective_pass name diag allow_bad_name todo diag_todo/ +]; sub init { my $self = shift; @@ -15,7 +17,7 @@ sub init { # Do not store objects here, only true or false $self->{+PASS} = $self->{+PASS} ? 1 : 0; - $self->{+EFFECTIVE_PASS} = $self->{+PASS} || $self->{+DEBUG}->no_fail || 0; + $self->{+EFFECTIVE_PASS} = ($self->{+PASS} || $self->{+TODO} || $self->{+DEBUG}->_no_fail) ? 1 : 0; return if $self->{+ALLOW_BAD_NAME}; my $name = $self->{+NAME} || return; @@ -31,7 +33,7 @@ sub default_diag { my $name = $self->{+NAME}; my $dbg = $self->{+DEBUG}; my $pass = $self->{+PASS}; - my $todo = defined $dbg->todo; + my $todo = defined($self->{+TODO} || $dbg->_todo); my $msg = $todo ? "Failed (TODO)" : "Failed"; my $prefix = $ENV{HARNESS_ACTIVE} && !$ENV{HARNESS_IS_VERBOSE} ? "\n" : ""; diff --git a/lib/Test/Stream/Formatter/TAP.pm b/lib/Test/Stream/Formatter/TAP.pm index 0287c85..f07e07a 100644 --- a/lib/Test/Stream/Formatter/TAP.pm +++ b/lib/Test/Stream/Formatter/TAP.pm @@ -143,7 +143,8 @@ sub _ok_event { # need this to be fast. my $name = $e->{name}; my $debug = $e->{debug}; - my $todo = $debug->{todo}; + my $todo = $e->{todo}; + $todo = $debug->{todo} unless defined $todo; # $debug->todo is deprecated my $skip = $debug->{skip}; # Deprecated my $out = ""; @@ -168,7 +169,7 @@ sub _ok_event { my @out = [OUT_STD, "$out\n"]; if ($e->{diag} && @{$e->{diag}}) { - my $diag_handle = $debug->no_diag ? OUT_TODO : OUT_ERR; + my $diag_handle = ($todo || $e->diag_todo || $debug->_no_diag) ? OUT_TODO : OUT_ERR; for my $diag (@{$e->{diag}}) { chomp(my $msg = $diag); @@ -189,7 +190,7 @@ sub _skip_event { my $name = $e->name; my $debug = $e->debug; my $skip = $e->reason; - my $todo = $debug->todo; + my $todo = $e->todo || $debug->_todo; my $out = "ok"; $out .= " $num" if defined $num; @@ -225,7 +226,7 @@ sub _diag_event { $msg =~ s/\n/\n# /g; return [ - ($e->debug->no_diag ? OUT_TODO : OUT_ERR), + (($e->todo || $e->debug->_no_diag) ? OUT_TODO : OUT_ERR), "$msg\n", ]; } diff --git a/lib/Test/Stream/Plugin/Subtest.pm b/lib/Test/Stream/Plugin/Subtest.pm index 4bc2299..645e75d 100644 --- a/lib/Test/Stream/Plugin/Subtest.pm +++ b/lib/Test/Stream/Plugin/Subtest.pm @@ -66,7 +66,7 @@ sub _subtest { $hub->listen(sub { push @events => $_[1] }); $hub->format(undef) if $buffered; - my $no_diag = $ctx->debug->no_diag; + my $no_diag = $parent->get_todo || $parent->parent_todo || $ctx->debug->_no_diag; $hub->set_parent_todo($no_diag) if $no_diag; my ($ok, $err, $finished); @@ -107,6 +107,7 @@ sub _subtest { name => $name, buffered => $buffered, subevents => \@events, + $parent->_fast_todo, ); $e->set_diag([ diff --git a/t/modules/Compare/EventMeta.t b/t/modules/Compare/EventMeta.t index a955e9d..4a2f12f 100644 --- a/t/modules/Compare/EventMeta.t +++ b/t/modules/Compare/EventMeta.t @@ -21,12 +21,12 @@ like( "Got skip warning" ); -$Ok->debug->set_todo('a'); -is($one->get_prop_todo($Ok), 'a', "todo (set)"); - # Deprecated warns { - $Ok->debug->set_skip('b'); + $Ok->debug->set_todo('a'); + is($one->get_prop_todo($Ok), 'a', "todo (set)"); + + $Ok->debug->set_skip('b'); is($one->get_prop_skip($Ok), 'b', "skip (set)"); }; From e69b5d0b6844a2a64f10d91d22fc08a3a40a42ac Mon Sep 17 00:00:00 2001 From: Chad Granum Date: Sun, 6 Dec 2015 09:57:24 -0800 Subject: [PATCH 09/10] Use event todo instead of debuginfo todo --- lib/Test/Stream/Context.pm | 17 ++++++++++++----- lib/Test/Stream/Hub.pm | 16 ++++++++++++++++ lib/Test/Stream/Workflow/Unit.pm | 3 +-- t/modules/Context.t | 6 +++--- t/modules/Event/Ok.t | 8 ++------ t/modules/Formatter/TAP.t | 27 ++++++++++++++++++++------- 6 files changed, 54 insertions(+), 23 deletions(-) diff --git a/lib/Test/Stream/Context.pm b/lib/Test/Stream/Context.pm index 59a2b0d..1d2b57d 100644 --- a/lib/Test/Stream/Context.pm +++ b/lib/Test/Stream/Context.pm @@ -195,7 +195,7 @@ sub context { frame => [$pkg, $file, $line, $sub], pid => $$, tid => get_tid(), - $hub->debug_todo, + $hub->_debug_todo, }, 'Test::Stream::DebugInfo' ); @@ -305,21 +305,23 @@ sub ok { my $self = shift; my ($pass, $name, $diag) = @_; + my $hub = $self->{+HUB}; + my $e = bless { debug => bless( {%{$self->{+DEBUG}}}, 'Test::Stream::DebugInfo'), pass => $pass, name => $name, + $hub->_fast_todo, }, 'Test::Stream::Event::Ok'; $e->init; - return $self->{+HUB}->send($e) if $pass; + return $hub->send($e) if $pass; $diag ||= []; unshift @$diag => $e->default_diag; - $e->set_diag($diag); - $self->{+HUB}->send($e); + $hub->send($e); } sub skip { @@ -337,7 +339,12 @@ sub note { sub diag { my $self = shift; my ($message) = @_; - $self->send_event('Diag', message => $message); + my $hub = $self->{+HUB}; + $self->send_event( + 'Diag', + message => $message, + todo => $hub->get_todo || $hub->parent_todo, + ); } sub plan { diff --git a/lib/Test/Stream/Hub.pm b/lib/Test/Stream/Hub.pm index 56d8489..f04b720 100644 --- a/lib/Test/Stream/Hub.pm +++ b/lib/Test/Stream/Hub.pm @@ -73,6 +73,11 @@ sub inherit { } sub debug_todo { + carp "The Hub->debug_todo method is deprecated"; + $_[0]->_debug_todo; +} + +sub _debug_todo { my ($self) = @_; my $array = $self->{+_TODO}; pop @$array while @$array && !defined $array->[-1]; @@ -82,6 +87,17 @@ sub debug_todo { ) } +sub _fast_todo { + my ($self) = @_; + my $array = $self->{+_TODO}; + pop @$array while @$array && !defined $array->[-1]; + my $todo = @$array ? ${$array->[-1]} : undef; + return ( + diag_todo => $todo || $self->{+PARENT_TODO}, + todo => $todo, + ) +} + sub meta { my $self = shift; my ($key, $default) = @_; diff --git a/lib/Test/Stream/Workflow/Unit.pm b/lib/Test/Stream/Workflow/Unit.pm index 137d0cb..4a37c98 100644 --- a/lib/Test/Stream/Workflow/Unit.pm +++ b/lib/Test/Stream/Workflow/Unit.pm @@ -147,9 +147,8 @@ sub debug { my $hub = $stack->top; return Test::Stream::DebugInfo->new( - frame => [@$self{qw/package file start_line name/}], + frame => [@$self{qw/package file start_line name/}], detail => "in block '$self->{+NAME}' defined in $self->{+FILE} (Approx) lines $self->{+START_LINE} -> $self->{+END_LINE}", - $hub->debug_todo, ); } diff --git a/t/modules/Context.t b/t/modules/Context.t index 4881301..20efd4c 100644 --- a/t/modules/Context.t +++ b/t/modules/Context.t @@ -175,15 +175,15 @@ is(@$events, 1, "1 event"); is($events, [$e], "Hub saw the event"); pop @$events; -# Test todo +# Test todo (deprecated) my ($dbg1, $dbg2); my $todo = Test::Stream::Sync->stack->top->set_todo("Here be dragons"); wrap { $dbg1 = shift->debug }; $todo = undef; wrap { $dbg2 = shift->debug }; -is($dbg1->todo, 'Here be dragons', "Got todo in context created with todo in place"); -is($dbg2->todo, undef, "no todo in context created after todo was removed"); +is($dbg1->_todo, 'Here be dragons', "Got todo in context created with todo in place"); +is($dbg2->_todo, undef, "no todo in context created after todo was removed"); # Test hooks diff --git a/t/modules/Event/Ok.t b/t/modules/Event/Ok.t index cff769d..df2f30e 100644 --- a/t/modules/Event/Ok.t +++ b/t/modules/Event/Ok.t @@ -92,7 +92,7 @@ tests Failing => sub { ], "Got tap for failing ok with diag non verbose harness" ); - + $ENV{HARNESS_ACTIVE} = 0; $ok->set_diag([ $ok->default_diag ]); is( @@ -153,11 +153,11 @@ tests fail_with_diag => sub { tests "Failing TODO" => sub { local $ENV{HARNESS_ACTIVE} = 1; local $ENV{HARNESS_IS_VERBOSE} = 1; - $dbg->set_todo('A Todo'); my $ok = Test::Stream::Event::Ok->new( debug => $dbg, pass => 0, name => 'the_test', + todo => 'A Todo', ); isa_ok($ok, 'Test::Stream::Event'); is($ok->pass, 0, "got pass"); @@ -187,8 +187,6 @@ tests "Failing TODO" => sub { is($state->count, 1, "Added to the count"); is($state->failed, 0, "failed count unchanged"); is($state->is_passing, 1, "still passing"); - - $dbg->set_todo(undef); }; # This is deprecated @@ -221,8 +219,6 @@ tests skip => sub { is($state->count, 1, "Added to the count"); is($state->failed, 0, "failed count unchanged"); is($state->is_passing, 1, "still passing"); - - $dbg->set_todo(undef); }; tests init => sub { diff --git a/t/modules/Formatter/TAP.t b/t/modules/Formatter/TAP.t index ebea3e7..0395dbe 100644 --- a/t/modules/Formatter/TAP.t +++ b/t/modules/Formatter/TAP.t @@ -132,6 +132,20 @@ describe events => sub { ); }; + my $set_todo; + case deprecated_todo => sub { + $set_todo = sub { + my ($e, $msg) = @_; + $e->debug->_set_todo($msg); + }; + }; + case new_todo => sub { + $set_todo = sub { + my ($e, $msg) = @_; + $e->set_todo($msg); + }; + }; + tests bail => sub { my $bail = Test::Stream::Event::Bail->new( debug => $dbg, @@ -164,7 +178,7 @@ describe events => sub { "Only 1 newline" ); - $diag->debug->set_todo('todo'); + $diag->$set_todo('todo'); is( [$fmt->event_tap($diag, 1)], [[OUT_TODO, "# foo\n"]], @@ -178,7 +192,7 @@ describe events => sub { "All lines have proper prefix" ); - $diag->debug->set_todo(undef); + $diag->$set_todo(undef); $diag->set_message(""); is([$fmt->event_tap($diag)], [], "no tap with an empty message"); @@ -278,10 +292,10 @@ describe events => sub { # Deprecated tests skip_and_todo => sub { - $dbg->set_todo('a'); warns { $dbg->set_skip('b') }; my $ok = Test::Stream::Event::Ok->new(debug => $dbg, pass => $pass); + $ok->$set_todo('a'); my @tap = $fmt->event_tap($ok, 7); is( \@tap, @@ -291,7 +305,7 @@ describe events => sub { "Got expected output" ); - $dbg->set_todo(""); + $ok->$set_todo(""); @tap = $fmt->event_tap($ok, 7); is( @@ -330,9 +344,8 @@ describe events => sub { }; tests todo => sub { - $dbg->set_todo('b'); - my $ok = Test::Stream::Event::Ok->new(debug => $dbg, pass => $pass); + $ok->$set_todo('b'); my @tap = $fmt->event_tap($ok, 7); is( \@tap, @@ -342,7 +355,7 @@ describe events => sub { "Got expected output" ); - $dbg->set_todo(""); + $ok->$set_todo(""); @tap = $fmt->event_tap($ok, 7); is( From f8098b7f98aec98af16a3bf8b741e5bc44d2191c Mon Sep 17 00:00:00 2001 From: Chad Granum Date: Mon, 7 Dec 2015 19:45:24 -0800 Subject: [PATCH 10/10] Changes from review --- lib/Test/Stream/Formatter/TAP.pm | 32 ++++++++++++++++---------------- lib/Test/Stream/Workflow/Task.pm | 8 ++++---- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/lib/Test/Stream/Formatter/TAP.pm b/lib/Test/Stream/Formatter/TAP.pm index f07e07a..d739091 100644 --- a/lib/Test/Stream/Formatter/TAP.pm +++ b/lib/Test/Stream/Formatter/TAP.pm @@ -127,7 +127,13 @@ sub event_tap { # Legacy Support for $e->to_tap unless ($converter) { my $legacy = $e->can('to_tap') or return; + + # Prevent infinite recursion. If an event subclasses 'Event' it has a + # to_tap method that brings it back here. We only call to_tap if they + # actually provided a custom one. This mess will go away at the end of + # the deprecation cycle. return if $legacy == \&Test::Stream::Event::to_tap; + warn "'$e' implements 'to_tap'. to_tap methods on events are deprecated.\n"; return $e->to_tap($num); } @@ -141,11 +147,9 @@ sub _ok_event { # We use direct hash access for performance. OK events are so common we # need this to be fast. - my $name = $e->{name}; - my $debug = $e->{debug}; - my $todo = $e->{todo}; - $todo = $debug->{todo} unless defined $todo; # $debug->todo is deprecated - my $skip = $debug->{skip}; # Deprecated + my ($name, $debug, $todo) = @{$e}{qw/name debug todo/}; + $todo = $debug->{todo} unless defined $todo; # $debug->todo is deprecated + my $skip = $debug->{skip}; # Deprecated my $out = ""; $out .= "not " unless $e->{pass}; @@ -187,16 +191,15 @@ sub _skip_event { my $self = shift; my ($e, $num) = @_; - my $name = $e->name; - my $debug = $e->debug; - my $skip = $e->reason; - my $todo = $e->todo || $debug->_todo; + my $name = $e->name; + my $reason = $e->reason; + my $todo = $e->todo || $e->debug->_todo; my $out = "ok"; $out .= " $num" if defined $num; $out .= " - $name" if $name; $out .= " # skip"; - $out .= " $skip" if length $skip; + $out .= " $reason" if length $reason; return([OUT_STD, "$out\n"]); } @@ -286,13 +289,12 @@ sub _plan_event { return if $self->{+NO_HEADER}; - my $max = $e->max; my $directive = $e->directive; - my $reason = $e->reason; - return if $directive && $directive eq 'NO PLAN'; - my $plan = "1..$max"; + my $reason = $e->reason; + + my $plan = "1.." . $e->max; if ($directive) { $plan .= " # $directive"; $plan .= " $reason" if defined $reason; @@ -301,8 +303,6 @@ sub _plan_event { return [OUT_STD, "$plan\n"]; } - - 1; __END__ diff --git a/lib/Test/Stream/Workflow/Task.pm b/lib/Test/Stream/Workflow/Task.pm index 78b68c3..92dca6b 100644 --- a/lib/Test/Stream/Workflow/Task.pm +++ b/lib/Test/Stream/Workflow/Task.pm @@ -113,12 +113,12 @@ sub run { return unless $self->should_run; my $unit = $self->{+UNIT}; - my $ctx = $unit->context; + my $ctx = $unit->context; my $meta = $unit->meta; + my $skip = $meta ? $meta->{skip} : undef; - my $skip; - $skip = $meta->{skip} if $meta && defined $meta->{skip}; - $skip ||= $ctx->debug->_skip; # Private accessor for deprecated thing, just until it goes away + # Private accessor for deprecated thing, just until it goes away + $skip ||= $ctx->debug->_skip; # Skip? if ($skip) {