line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Test::Steering::Wheel; |
2
|
|
|
|
|
|
|
|
3
|
5
|
|
|
5
|
|
80841
|
use warnings; |
|
5
|
|
|
|
|
10
|
|
|
5
|
|
|
|
|
224
|
|
4
|
5
|
|
|
5
|
|
33
|
use strict; |
|
5
|
|
|
|
|
17
|
|
|
5
|
|
|
|
|
143
|
|
5
|
5
|
|
|
5
|
|
30
|
use Carp; |
|
5
|
|
|
|
|
10
|
|
|
5
|
|
|
|
|
322
|
|
6
|
5
|
|
|
5
|
|
5807
|
use TAP::Harness; |
|
5
|
|
|
|
|
88899
|
|
|
5
|
|
|
|
|
177
|
|
7
|
5
|
|
|
5
|
|
51
|
use Scalar::Util qw(refaddr); |
|
5
|
|
|
|
|
13
|
|
|
5
|
|
|
|
|
759
|
|
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
=head1 NAME |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
Test::Steering::Wheel - Execute tests and renumber the resulting TAP. |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
=head1 VERSION |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
This document describes Test::Steering::Wheel version 0.02 |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
=cut |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
our $VERSION = '0.02'; |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
=head1 SYNOPSIS |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
use Test::Steering::Wheel; |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
my $wheel = Test::Steering::Wheel->new; |
26
|
|
|
|
|
|
|
$wheel->include_tests( 'xt/vms/*.t' ) if $^O eq 'VMS'; |
27
|
|
|
|
|
|
|
$wheel->include_tests( 'xt/windows/*.t' ) if $^O =~ 'MSWin32'; |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
=head1 DESCRIPTION |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
Behind the scenes in L is a singleton instance of |
32
|
|
|
|
|
|
|
C. |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
See L for more information. |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
=head1 INTERFACE |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
=head2 C<< new >> |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
Create a new C. |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
=over |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
=item C<< add_prefix >> |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
=item C<< announce >> |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
=item C<< defaults >> |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
=item C<< harness >> |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
=back |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
=cut |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
{ |
57
|
|
|
|
|
|
|
my %DEFAULTS; |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
BEGIN { |
60
|
5
|
|
|
5
|
|
47
|
%DEFAULTS = ( |
61
|
|
|
|
|
|
|
add_prefix => 0, |
62
|
|
|
|
|
|
|
announce => 0, |
63
|
|
|
|
|
|
|
defaults => {}, |
64
|
|
|
|
|
|
|
harness => 'TAP::Harness', |
65
|
|
|
|
|
|
|
); |
66
|
|
|
|
|
|
|
|
67
|
5
|
|
|
|
|
23
|
for my $method ( keys %DEFAULTS ) { |
68
|
5
|
|
|
5
|
|
40
|
no strict 'refs'; |
|
5
|
|
|
|
|
8
|
|
|
5
|
|
|
|
|
435
|
|
69
|
17
|
|
|
|
|
7620
|
*{ __PACKAGE__ . '::' . $method } = sub { |
70
|
58
|
|
|
58
|
|
97
|
my $self = shift; |
71
|
58
|
50
|
|
|
|
335
|
croak "$method may not be set" if @_; |
72
|
58
|
|
|
|
|
410
|
return $self->{$method}; |
73
|
17
|
|
|
|
|
84
|
}; |
74
|
|
|
|
|
|
|
} |
75
|
|
|
|
|
|
|
} |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
sub new { |
78
|
16
|
|
|
16
|
1
|
36660
|
my $class = shift; |
79
|
16
|
50
|
|
|
|
121
|
croak "Must supply an even number of arguments" if @_ % 1; |
80
|
16
|
|
|
|
|
201
|
my %args = ( %DEFAULTS, @_ ); |
81
|
|
|
|
|
|
|
|
82
|
16
|
|
|
|
|
88
|
my @bad = grep { !exists $DEFAULTS{$_} } keys %args; |
|
61
|
|
|
|
|
164
|
|
83
|
16
|
50
|
|
|
|
74
|
croak "Illegal option(s): ", join ', ', sort @bad if @bad; |
84
|
|
|
|
|
|
|
|
85
|
16
|
|
|
|
|
164
|
return bless { _test_number_adjust => 0, %args }, $class; |
86
|
|
|
|
|
|
|
} |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
# Documentation lower down |
89
|
|
|
|
|
|
|
sub option_names { |
90
|
3
|
|
|
3
|
1
|
32
|
my $class = shift; |
91
|
2
|
|
|
|
|
18
|
return sort keys %DEFAULTS; |
92
|
|
|
|
|
|
|
} |
93
|
|
|
|
|
|
|
} |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
# Output demultiplexer. Handles output associated with multiple parsers. |
96
|
|
|
|
|
|
|
# If parsers output sequentially no buffering is done. If, however, |
97
|
|
|
|
|
|
|
# output from multiple parsers is interleaved output from the first |
98
|
|
|
|
|
|
|
# encountered will be echoed directly and output from all the others |
99
|
|
|
|
|
|
|
# will be buffered. |
100
|
|
|
|
|
|
|
# |
101
|
|
|
|
|
|
|
# After a parser finishes (calls $done) the next parser to generate |
102
|
|
|
|
|
|
|
# output will have its buffer flushed and will start output directly. |
103
|
|
|
|
|
|
|
# |
104
|
|
|
|
|
|
|
# The upshot of all this is that we output from multiple parsers doing |
105
|
|
|
|
|
|
|
# the minimum amount of buffering necessary to keep per-parser output |
106
|
|
|
|
|
|
|
# ordered. |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
sub _output_demux { |
109
|
14
|
|
|
15
|
|
1024
|
my ( $self, $printer, $complete ) = @_; |
110
|
14
|
|
|
|
|
32
|
my $current_id = undef; |
111
|
14
|
|
|
|
|
37
|
my %queue_for = (); |
112
|
14
|
|
|
|
|
29
|
my @completed = (); |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
my $finish = sub { |
115
|
31
|
|
|
31
|
|
1978
|
while ( my $job = shift @completed ) { |
116
|
4
|
|
|
|
|
24
|
my ( $parser, $buffered ) = @$job; |
117
|
4
|
|
|
|
|
23
|
$printer->( $parser, @$_ ) for @$buffered; |
118
|
4
|
|
|
|
|
22
|
$complete->( $parser ); |
119
|
|
|
|
|
|
|
} |
120
|
14
|
|
|
|
|
89
|
}; |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
return ( |
123
|
|
|
|
|
|
|
# demux |
124
|
|
|
|
|
|
|
sub { |
125
|
88
|
|
|
88
|
|
2305
|
my ( $parser, $type, $line ) = @_; |
126
|
88
|
|
|
|
|
363
|
my $id = refaddr $parser; |
127
|
|
|
|
|
|
|
|
128
|
88
|
100
|
|
|
|
311
|
unless ( defined $current_id ) { |
129
|
|
|
|
|
|
|
# Our chance to take over... |
130
|
18
|
100
|
|
|
|
105
|
if ( $self->announce ) { |
131
|
1
|
|
|
|
|
15
|
my $name = $self->_name_for_parser( $parser ); |
132
|
1
|
|
|
|
|
94
|
print STDERR "# Running $name\n"; |
133
|
|
|
|
|
|
|
} |
134
|
18
|
100
|
|
|
|
104
|
if ( my $buffered = delete $queue_for{$id} ) { |
135
|
1
|
|
|
|
|
5
|
$printer->( $parser, @$_ ) for @$buffered; |
136
|
|
|
|
|
|
|
} |
137
|
18
|
|
|
|
|
74
|
$current_id = $id; |
138
|
|
|
|
|
|
|
} |
139
|
|
|
|
|
|
|
|
140
|
88
|
100
|
|
|
|
274
|
if ( $current_id == $id ) { |
141
|
87
|
|
|
|
|
299
|
$printer->( $parser, $type, $line ); |
142
|
|
|
|
|
|
|
} |
143
|
|
|
|
|
|
|
else { |
144
|
1
|
|
|
|
|
2
|
push @{ $queue_for{$id} }, [ $type, $line ]; |
|
1
|
|
|
|
|
8
|
|
145
|
|
|
|
|
|
|
} |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
}, |
148
|
|
|
|
|
|
|
# done |
149
|
|
|
|
|
|
|
sub { |
150
|
21
|
|
|
21
|
|
855
|
my $parser = shift; |
151
|
21
|
|
|
|
|
259
|
my $id = refaddr $parser; |
152
|
21
|
100
|
66
|
|
|
507
|
if ( defined $current_id && $current_id == $id ) { |
153
|
|
|
|
|
|
|
# Finished the current one so allow another to |
154
|
|
|
|
|
|
|
# take over |
155
|
17
|
|
|
|
|
67
|
$complete->( $parser ); |
156
|
17
|
|
|
|
|
107
|
undef $current_id; |
157
|
|
|
|
|
|
|
# Flush any others that have completed in the mean time |
158
|
17
|
|
|
|
|
56
|
$finish->(); |
159
|
|
|
|
|
|
|
} |
160
|
|
|
|
|
|
|
else { |
161
|
|
|
|
|
|
|
# Add to completed list |
162
|
4
|
|
|
|
|
37
|
push @completed, [ $parser, delete $queue_for{$id} ]; |
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
}, |
165
|
|
|
|
|
|
|
# finish |
166
|
14
|
|
|
|
|
201
|
$finish, |
167
|
|
|
|
|
|
|
); |
168
|
|
|
|
|
|
|
} |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
sub _name_for_parser { |
171
|
51
|
|
|
51
|
|
157
|
my $self = shift; |
172
|
51
|
|
|
|
|
392
|
my $parser = shift; |
173
|
51
|
|
|
|
|
198
|
my $id = refaddr $parser; |
174
|
51
|
100
|
|
|
|
304
|
return $self->{parser_name}->{$id} unless @_; |
175
|
20
|
|
|
|
|
184
|
return $self->{parser_name}->{$id} = shift; |
176
|
|
|
|
|
|
|
} |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
# Like ok |
179
|
|
|
|
|
|
|
sub _output_result { |
180
|
22
|
|
|
22
|
|
45
|
my ( $self, $ok, $description ) = @_; |
181
|
22
|
100
|
|
|
|
2191
|
printf( "%sok %d %s\n", |
182
|
|
|
|
|
|
|
$ok ? '' : 'not ', |
183
|
|
|
|
|
|
|
++$self->{_test_number_adjust}, $description ); |
184
|
|
|
|
|
|
|
} |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
# Output additional test failures if our subtest had problems. |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
sub _parser_postmortem { |
189
|
20
|
|
|
20
|
|
41
|
my ( $self, $parser ) = @_; |
190
|
|
|
|
|
|
|
|
191
|
20
|
|
|
|
|
86
|
my $test = $self->_name_for_parser( $parser ); |
192
|
|
|
|
|
|
|
|
193
|
20
|
|
|
|
|
45
|
my @errs = (); |
194
|
|
|
|
|
|
|
|
195
|
20
|
|
|
|
|
70
|
push @errs, "$test: Parse error: $_" for $parser->parse_errors; |
196
|
|
|
|
|
|
|
|
197
|
20
|
|
|
|
|
177
|
my ( $wait, $exit ) = ( $parser->wait, $parser->exit ); |
198
|
20
|
100
|
66
|
|
|
328
|
push @errs, "$test: Non-zero status: exit=$exit, wait=$wait" |
199
|
|
|
|
|
|
|
if $exit || $wait; |
200
|
|
|
|
|
|
|
|
201
|
20
|
100
|
|
|
|
63
|
if ( @errs ) { |
202
|
2
|
|
|
|
|
14
|
$self->_output_result( 0, $_ ) for @errs; |
203
|
|
|
|
|
|
|
} |
204
|
|
|
|
|
|
|
else { |
205
|
18
|
|
|
|
|
93
|
$self->_output_result( 1, "$test done" ); |
206
|
|
|
|
|
|
|
} |
207
|
|
|
|
|
|
|
} |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
sub _load { |
210
|
13
|
|
|
13
|
|
22
|
my $class = shift; |
211
|
13
|
50
|
33
|
2
|
|
2575
|
unless ( $INC{$class} || eval "use $class; 1" ) { |
|
2
|
|
|
|
|
15
|
|
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
47
|
|
212
|
0
|
|
|
|
|
0
|
croak "Can't load $class: $@"; |
213
|
|
|
|
|
|
|
} |
214
|
13
|
|
|
|
|
126
|
return $class; |
215
|
|
|
|
|
|
|
} |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
=head2 C<< include_tests >> |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
Run one or more tests. Wildcards will be expanded. |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
include_tests( 'xt/vms/*.t' ) if $^O eq 'VMS'; |
222
|
|
|
|
|
|
|
include_tests( 'xt/windows/*.t' ) if $^O =~ 'MSWin32'; |
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
=cut |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
sub include_tests { |
227
|
13
|
|
|
13
|
1
|
31192
|
my ( $self, @tests ) = @_; |
228
|
|
|
|
|
|
|
|
229
|
13
|
|
|
|
|
35
|
my %options = ( verbosity => -9, %{ $self->defaults } ); |
|
13
|
|
|
|
|
52
|
|
230
|
13
|
|
|
|
|
29
|
my @real_tests = (); |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
# Split options hashes from tests |
233
|
13
|
100
|
|
|
|
33
|
for my $t ( |
|
21
|
|
|
|
|
341
|
|
234
|
20
|
100
|
|
|
|
882
|
map { 'ARRAY' eq ref $_ ? $_ : [ $_, $_ ] } |
235
|
|
|
|
|
|
|
map { ref $_ ? $_ : glob $_ } @tests |
236
|
|
|
|
|
|
|
) { |
237
|
21
|
50
|
|
|
|
96
|
if ( 'HASH' eq ref $t ) { |
238
|
0
|
|
|
|
|
0
|
%options = ( %options, %$t ); |
239
|
|
|
|
|
|
|
} |
240
|
|
|
|
|
|
|
else { |
241
|
21
|
|
|
|
|
158
|
push @real_tests, |
242
|
21
|
|
|
|
|
38
|
grep { !$self->{_seen}->{ $_->[1] }++ } $t; |
243
|
|
|
|
|
|
|
} |
244
|
|
|
|
|
|
|
} |
245
|
|
|
|
|
|
|
|
246
|
13
|
|
|
|
|
61
|
my $harness = _load( $self->harness )->new( \%options ); |
247
|
13
|
|
|
|
|
51798
|
my $add_prefix = $self->add_prefix; |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
my $printer = sub { |
250
|
84
|
|
|
84
|
|
149
|
my ( $parser, $type, $line ) = @_; |
251
|
84
|
100
|
|
|
|
1345
|
print "TAP version 13\n" unless $self->{_started}++; |
252
|
84
|
100
|
|
|
|
214
|
if ( $type eq 'test' ) { |
253
|
80
|
|
|
|
|
704
|
$line =~ s/(\d+)/$1 + $self->{_test_number_adjust}/e; |
|
80
|
|
|
|
|
351
|
|
254
|
80
|
100
|
|
|
|
222
|
if ( $add_prefix ) { |
255
|
10
|
|
|
|
|
35
|
my $name = $self->_name_for_parser( $parser ); |
256
|
10
|
|
|
|
|
63
|
$line =~ s/(\d+)[ \t]*(\S+)/$1: $2/; |
257
|
10
|
|
|
|
|
61
|
$line =~ s/(\d+)/$1 $name/; |
258
|
|
|
|
|
|
|
} |
259
|
|
|
|
|
|
|
} |
260
|
84
|
|
|
|
|
2266
|
print $line; |
261
|
13
|
|
|
|
|
149
|
}; |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
my $complete = sub { |
264
|
20
|
|
|
20
|
|
42
|
my $parser = shift; |
265
|
20
|
|
|
|
|
69
|
my $tests_run = $parser->tests_run; |
266
|
20
|
|
|
|
|
146
|
$self->{_test_number_adjust} += $parser->tests_run; |
267
|
13
|
|
|
|
|
112
|
}; |
268
|
|
|
|
|
|
|
|
269
|
13
|
|
|
|
|
454
|
my ( $demux, $done, $finish ) |
270
|
|
|
|
|
|
|
= $self->_output_demux( $printer, $complete ); |
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
$harness->callback( |
273
|
|
|
|
|
|
|
made_parser => sub { |
274
|
20
|
|
|
20
|
|
402646
|
my ( $parser, $test_desc ) = @_; |
275
|
|
|
|
|
|
|
|
276
|
20
|
|
|
|
|
570
|
$self->_name_for_parser( $parser, $test_desc->[1] ); |
277
|
|
|
|
|
|
|
|
278
|
20
|
|
|
|
|
498
|
$parser->callback( plan => sub { } ); |
|
18
|
|
|
|
|
143752
|
|
279
|
20
|
|
|
|
|
1267
|
$parser->callback( version => sub { } ); |
|
2
|
|
|
|
|
23738
|
|
280
|
|
|
|
|
|
|
$parser->callback( |
281
|
|
|
|
|
|
|
test => sub { |
282
|
80
|
|
|
|
|
30280
|
my $test = shift; |
283
|
80
|
|
|
|
|
237
|
my $raw = $test->as_string; |
284
|
80
|
|
|
|
|
2891
|
$demux->( $parser, 'test', "$raw\n" ); |
285
|
|
|
|
|
|
|
} |
286
|
20
|
|
|
|
|
559
|
); |
287
|
|
|
|
|
|
|
$parser->callback( |
288
|
|
|
|
|
|
|
ELSE => sub { |
289
|
4
|
|
|
|
|
5885
|
my $result = shift; |
290
|
4
|
|
|
|
|
38
|
$demux->( $parser, 'raw', $result->raw . "\n" ); |
291
|
|
|
|
|
|
|
} |
292
|
20
|
|
|
|
|
491
|
); |
293
|
|
|
|
|
|
|
$parser->callback( |
294
|
|
|
|
|
|
|
EOF => sub { |
295
|
20
|
|
|
|
|
22040
|
$done->( $parser ); |
296
|
20
|
|
|
|
|
112
|
$self->_parser_postmortem( $parser ); |
297
|
|
|
|
|
|
|
} |
298
|
20
|
|
|
|
|
588
|
); |
299
|
|
|
|
|
|
|
} |
300
|
13
|
|
|
|
|
180
|
); |
301
|
|
|
|
|
|
|
|
302
|
13
|
|
|
|
|
324
|
my $aggregator = $harness->runtests( @real_tests ); |
303
|
13
|
|
|
|
|
10693
|
$finish->(); |
304
|
|
|
|
|
|
|
} |
305
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
=head2 C |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
Output the trailing plan. |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
=cut |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
sub end_plan { |
313
|
14
|
|
|
14
|
1
|
461
|
my $self = shift; |
314
|
14
|
100
|
|
|
|
103
|
if ( my $plan = $self->{_test_number_adjust} ) { |
315
|
13
|
|
|
|
|
613
|
print "1..$plan\n"; |
316
|
13
|
|
|
|
|
669
|
$self->{_test_number_adjust} = 0; |
317
|
|
|
|
|
|
|
} |
318
|
|
|
|
|
|
|
} |
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
=head2 C<< tests_run >> |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
Get a list of tests that have been run. |
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
my @tests = $wheel->tests_run(); |
325
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
=cut |
327
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
sub tests_run { |
329
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
330
|
0
|
0
|
|
|
|
0
|
return sort keys %{ $self->{_seen} || {} }; |
|
0
|
|
|
|
|
0
|
|
331
|
|
|
|
|
|
|
} |
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
=head2 C<< option_names >> |
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
Get the names of the supported options to C. Used by L |
336
|
|
|
|
|
|
|
to validate its arguments. |
337
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
=cut |
339
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
1; |
341
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
__END__ |