File Coverage

blib/lib/Test/Spec/Example.pm
Criterion Covered Total %
statement 50 79 63.2
branch 4 18 22.2
condition 4 11 36.3
subroutine 15 16 93.7
pod 0 8 0.0
total 73 132 55.3


line stmt bran cond sub pod time code
1             package Test::Spec::Example;
2              
3             # Purpose: represents an `it` block
4              
5 14     14   92 use strict;
  14         67  
  14         389  
6 14     14   73 use warnings;
  14         28  
  14         359  
7              
8             ########################################################################
9             # NO USER-SERVICEABLE PARTS INSIDE.
10             ########################################################################
11              
12 14     14   69 use Carp ();
  14         23  
  14         205  
13 14     14   62 use Scalar::Util ();
  14         31  
  14         4003  
14              
15             sub new {
16 122     122 0 1156 my ($class, $args) = @_;
17              
18 122 50 33     516 if (!$args || ref($args) ne 'HASH') {
19 0         0 Carp::croak "usage: $class->new(\\%args)";
20             }
21              
22 122         250 my $self = bless {}, $class;
23 122         247 foreach my $attr ( qw/name description code builder context/ ) {
24 610   33     1463 $self->{$attr} = $args->{$attr} || Carp::croak "$attr missing";
25             }
26              
27 122         392 Scalar::Util::weaken($self->{context});
28              
29 122         271 return $self;
30             }
31              
32 122     122 0 755 sub name { shift->{name} }
33 119     119 0 547 sub description { shift->{description} }
34 122     122 0 530 sub code { shift->{code} }
35 0     0 0 0 sub builder { shift->{builder} }
36 122     122 0 318 sub context { shift->{context} }
37              
38             # Build a stack from the starting context
39             # down to the current context
40             sub stack {
41 122     122 0 263 my ($self) = @_;
42              
43 122         328 my $ctx = $self->context;
44              
45 122         268 my @ancestors = $ctx;
46 122         365 while ( $ctx = $ctx->parent ) {
47 222         476 push @ancestors, $ctx;
48             }
49              
50 122         462 return reverse(@ancestors);
51             }
52              
53             sub run {
54 122     122 0 271 my ($self) = @_;
55              
56             # clobber Test::Builder's ok() method just like Test::Class does,
57             # but without screwing up underscores.
58 14     14   90 no warnings 'redefine';
  14         26  
  14         6652  
59 122         297 my $orig_builder_ok = \&Test::Builder::ok;
60             local *Test::Builder::ok = sub {
61 121     121   199167 my ($builder,$test,$desc) = splice(@_,0,3);
62 121   66     684 $desc ||= $self->description;
63 121         244 local $Test::Builder::Level = $Test::Builder::Level+1;
64 121         450 $orig_builder_ok->($builder, $test, $desc, @_);
65 122         794 };
66              
67             # Run the test
68 122         370 eval { $self->_runner($self->stack) };
  122         469  
69              
70             # And trap any errors
71 122 50       1394 if (my $err = $@) {
72 0         0 my $builder = $self->builder;
73 0         0 my $description = $self->description;
74              
75             # eval in case stringification overload croaks
76 0   0     0 chomp($err = eval { $err . '' } || 'unknown error');
77 0         0 my ($file,$line);
78 0 0       0 ($file,$line) = ($1,$2) if ($err =~ s/ at (.+?) line (\d+)\.\Z//);
79              
80             # disable ok()'s diagnostics so we can generate a custom TAP message
81 0         0 my $old_diag = $builder->no_diag;
82 0         0 $builder->no_diag(1);
83             # make sure we can restore no_diag
84 0         0 eval { $builder->ok(0, $description) };
  0         0  
85 0         0 my $secondary_err = $@;
86             # no_diag needs a defined value, so double-negate it to get either '' or 1
87 0         0 $builder->no_diag(!!$old_diag);
88              
89 0 0       0 unless ($builder->no_diag) {
90             # emulate Test::Builder::ok's diagnostics, but with more details
91 0         0 my ($msg,$diag_fh);
92 0 0       0 if ($builder->in_todo) {
93 0         0 $msg = "Failed (TODO)";
94 0         0 $diag_fh = $builder->todo_output;
95             }
96             else {
97 0         0 $msg = "Failed";
98 0         0 $diag_fh = $builder->failure_output;
99             }
100 0 0       0 print {$diag_fh} "\n" if $ENV{HARNESS_ACTIVE};
  0         0  
101 0         0 print {$builder->failure_output} qq[# $msg test '$description' by dying:\n];
  0         0  
102 0         0 print {$builder->failure_output} qq[# $err\n];
  0         0  
103 0 0       0 print {$builder->failure_output} qq[# at $file line $line.\n] if defined($file);
  0         0  
104             }
105 0 0       0 die $secondary_err if $secondary_err;
106             }
107             }
108              
109             sub _runner {
110 344     344   833 my ($self, $ctx, @remainder) = @_;
111              
112             # This recursive closure essentially does this
113             # $outer->contextualize {
114             # $outer->before_each
115             # $inner->contextualize {
116             # $inner->before_each
117             # $anon->contextualize {
118             # $anon->before_each (no-op)
119             # execute test
120             # $anon->after_each (no-op)
121             # }
122             # $inner->after_each
123             # }
124             # $outer->after_each
125             # }
126             #
127             return $ctx->contextualize(sub {
128 344     344   940 $ctx->_run_before_all_once;
129 344         749584 $ctx->_run_before('each');
130 344 100       993 if ( @remainder ) {
131 222         483 $self->_runner(@remainder);
132             }
133             else {
134 122         409 $ctx->_in_anonymous_context($self->code, $self);
135             }
136 344         1685 $ctx->_run_after('each');
137             # "after 'all'" only happens during context destruction (DEMOLISH).
138             # This is the only way I can think to make this work right
139             # in the case that only specific test methods are run.
140             # Otherwise, the global teardown would only happen when you
141             # happen to run the last test of the context.
142 344         1738 }, $self);
143             }
144              
145             1;