line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Test2::Harness::Renderer::EventStream; |
2
|
23
|
|
|
23
|
|
135152
|
use strict; |
|
23
|
|
|
|
|
25
|
|
|
23
|
|
|
|
|
552
|
|
3
|
23
|
|
|
23
|
|
90
|
use warnings; |
|
23
|
|
|
|
|
23
|
|
|
23
|
|
|
|
|
1017
|
|
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
our $VERSION = '0.000013'; |
6
|
|
|
|
|
|
|
|
7
|
23
|
|
|
23
|
|
92
|
use Test2::Util::HashBase qw/color verbose jobs slots parallel clear out_std watch colors graph_colors counter/; |
|
23
|
|
|
|
|
23
|
|
|
23
|
|
|
|
|
157
|
|
8
|
23
|
|
|
23
|
|
18793
|
use Term::ANSIColor(); |
|
23
|
|
|
|
|
112669
|
|
|
23
|
|
|
|
|
621
|
|
9
|
23
|
|
|
23
|
|
116
|
use List::Util qw/first shuffle/; |
|
23
|
|
|
|
|
24
|
|
|
23
|
|
|
|
|
1844
|
|
10
|
23
|
|
|
23
|
|
93
|
use Scalar::Util qw/blessed/; |
|
23
|
|
|
|
|
23
|
|
|
23
|
|
|
|
|
846
|
|
11
|
23
|
|
|
23
|
|
531
|
use Time::HiRes qw/sleep/; |
|
23
|
|
|
|
|
1001
|
|
|
23
|
|
|
|
|
220
|
|
12
|
23
|
|
|
23
|
|
10879
|
use Test2::Util::Term qw/term_size/; |
|
23
|
|
|
|
|
531148
|
|
|
23
|
|
|
|
|
137
|
|
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
my @DEFAULT_GRAPH_COLORS = qw{ |
15
|
|
|
|
|
|
|
blue yellow cyan magenta |
16
|
|
|
|
|
|
|
bright_blue bright_yellow bright_cyan bright_magenta |
17
|
|
|
|
|
|
|
}; |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
my %DEFAULT_COLORS = ( |
20
|
|
|
|
|
|
|
blob => 'bold bright_black on_white', |
21
|
|
|
|
|
|
|
tag => 'bold bright_white', |
22
|
|
|
|
|
|
|
mark => 'bold bright_white', |
23
|
|
|
|
|
|
|
diag => 'yellow', |
24
|
|
|
|
|
|
|
stderr => 'yellow', |
25
|
|
|
|
|
|
|
fail => 'bold red', |
26
|
|
|
|
|
|
|
failed => 'bold red', |
27
|
|
|
|
|
|
|
parser => 'magenta', |
28
|
|
|
|
|
|
|
unknown => 'magenta', |
29
|
|
|
|
|
|
|
pass => 'green', |
30
|
|
|
|
|
|
|
passed => 'bold green', |
31
|
|
|
|
|
|
|
reset => 'reset', |
32
|
|
|
|
|
|
|
skip => 'bold white on_blue', |
33
|
|
|
|
|
|
|
skipall => 'bold white on_blue', |
34
|
|
|
|
|
|
|
todo => 'bold black on_bright_yellow', |
35
|
|
|
|
|
|
|
file => 'bold bright_white', |
36
|
|
|
|
|
|
|
); |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
my %EXTENDED_COLORS = ( |
39
|
|
|
|
|
|
|
%DEFAULT_COLORS, |
40
|
|
|
|
|
|
|
plan => 'cyan', |
41
|
|
|
|
|
|
|
note => 'blue', |
42
|
|
|
|
|
|
|
stdout => 'blue', |
43
|
|
|
|
|
|
|
); |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
BEGIN { |
46
|
23
|
|
|
23
|
|
3359
|
for my $sig (qw/INT TERM/) { |
47
|
|
|
|
|
|
|
my $old = $SIG{$sig} || sub { |
48
|
|
|
|
|
|
|
$SIG{$sig} = 'DEFAULT'; |
49
|
|
|
|
|
|
|
kill $sig, $$; |
50
|
46
|
|
50
|
|
|
439
|
}; |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
$SIG{$sig} = sub { |
53
|
0
|
0
|
|
|
|
0
|
print STDOUT Term::ANSIColor::color('reset') if -t STDOUT; |
54
|
0
|
0
|
|
|
|
0
|
print STDERR Term::ANSIColor::color('reset') if -t STDERR; |
55
|
0
|
|
|
|
|
0
|
$old->(); |
56
|
46
|
|
|
|
|
59917
|
}; |
57
|
|
|
|
|
|
|
} |
58
|
|
|
|
|
|
|
} |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
END { |
61
|
23
|
50
|
|
23
|
|
4776527
|
print STDOUT Term::ANSIColor::color('reset') if -t STDOUT; |
62
|
23
|
50
|
|
|
|
430
|
print STDERR Term::ANSIColor::color('reset') if -t STDERR; |
63
|
|
|
|
|
|
|
} |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
sub init { |
66
|
100
|
|
|
100
|
0
|
206690
|
my $self = shift; |
67
|
100
|
|
|
|
|
255
|
$self->{+JOBS} = {}; |
68
|
100
|
|
|
|
|
220
|
$self->{+SLOTS} = []; |
69
|
100
|
|
|
|
|
119
|
$self->{+CLEAR} = 0; |
70
|
|
|
|
|
|
|
|
71
|
100
|
|
66
|
|
|
337
|
my $fh = $self->{+OUT_STD} ||= do { |
72
|
84
|
50
|
|
|
|
17956
|
open( my $out, '>&', STDOUT ) or die "Can't dup STDOUT: $!"; |
73
|
|
|
|
|
|
|
|
74
|
84
|
|
|
|
|
372
|
my $old = select $out; |
75
|
84
|
|
|
|
|
237
|
$| = 1; |
76
|
84
|
|
|
|
|
200
|
select $old; |
77
|
|
|
|
|
|
|
|
78
|
84
|
|
|
|
|
325
|
$out; |
79
|
|
|
|
|
|
|
}; |
80
|
|
|
|
|
|
|
|
81
|
100
|
|
|
|
|
192
|
$self->{+COUNTER} = 0; |
82
|
|
|
|
|
|
|
|
83
|
100
|
|
|
|
|
261
|
my $is_term = -t $fh; |
84
|
100
|
50
|
|
|
|
270
|
$self->{+COLOR} = $is_term ? 1 : 0 unless defined $self->{+COLOR}; |
|
|
100
|
|
|
|
|
|
85
|
100
|
50
|
|
|
|
386
|
$self->{+WATCH} = $is_term ? 1 : 0 unless defined $self->{+WATCH}; |
|
|
100
|
|
|
|
|
|
86
|
100
|
50
|
66
|
|
|
737
|
if (($is_term || $self->{+COLOR} || $self->{+WATCH}) && $^O eq 'MSWin32') { |
|
|
|
66
|
|
|
|
|
87
|
0
|
0
|
|
|
|
0
|
eval { require Win32::Console::ANSI } and Win32::Console::ANSI->import; |
|
0
|
|
|
|
|
0
|
|
88
|
|
|
|
|
|
|
} |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
my $colors = |
91
|
|
|
|
|
|
|
$self->{+COLOR} > 1 ? \%EXTENDED_COLORS |
92
|
100
|
100
|
|
|
|
295
|
: $self->{+COLOR} ? \%DEFAULT_COLORS |
|
|
50
|
|
|
|
|
|
93
|
|
|
|
|
|
|
: {}; |
94
|
|
|
|
|
|
|
|
95
|
100
|
100
|
|
|
|
219
|
my $graph_colors = $self->{+COLOR} ? [@DEFAULT_GRAPH_COLORS] : []; |
96
|
|
|
|
|
|
|
|
97
|
100
|
|
50
|
|
|
453
|
$self->{+COLORS} ||= {map { $_ => eval { Term::ANSIColor::color($colors->{$_}) } || '' } grep {$colors->{$_}} keys %$colors, 'reset'}; |
|
34
|
|
100
|
|
|
430
|
|
|
126
|
|
|
|
|
361
|
|
98
|
100
|
50
|
100
|
|
|
586
|
$self->{+GRAPH_COLORS} ||= [map { eval { Term::ANSIColor::color($_) } || '' } grep {$_} @$graph_colors]; |
|
16
|
|
|
|
|
129
|
|
|
16
|
|
|
|
|
22
|
|
|
16
|
|
|
|
|
15
|
|
99
|
|
|
|
|
|
|
} |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
sub paint { |
102
|
918
|
|
|
918
|
|
19987
|
my $self = shift; |
103
|
918
|
|
|
|
|
1918
|
my $string = ""; |
104
|
|
|
|
|
|
|
|
105
|
918
|
|
|
|
|
1871
|
my $colors = $self->{+COLORS}; |
106
|
918
|
|
|
|
|
1394
|
my $graph = $self->{+GRAPH_COLORS}; |
107
|
918
|
|
|
|
|
1341
|
my $jobs = $self->{+JOBS}; |
108
|
|
|
|
|
|
|
|
109
|
918
|
100
|
|
|
|
2127
|
if ($self->{+CLEAR}) { |
110
|
2
|
|
|
|
|
5
|
$string .= "\e[K"; |
111
|
2
|
|
|
|
|
4
|
$self->{+CLEAR}--; |
112
|
|
|
|
|
|
|
} |
113
|
|
|
|
|
|
|
|
114
|
918
|
|
|
|
|
2423
|
for my $i (@_) { |
115
|
23162
|
100
|
|
|
|
27918
|
unless (ref($i)) { |
116
|
8730
|
|
|
|
|
6042
|
$string .= $i; |
117
|
8730
|
|
|
|
|
7206
|
next; |
118
|
|
|
|
|
|
|
} |
119
|
|
|
|
|
|
|
|
120
|
14432
|
|
|
|
|
17219
|
my ($c, $s, $r) = @$i; |
121
|
14432
|
100
|
|
|
|
21469
|
$r = 1 if @$i < 3; |
122
|
14432
|
100
|
|
|
|
22022
|
if ($c =~ m/^\d+$/) { |
123
|
2172
|
100
|
50
|
|
|
3591
|
$string .= $graph->[$jobs->{$c}->{slot} % @$graph] || '' if @$graph |
124
|
|
|
|
|
|
|
} |
125
|
|
|
|
|
|
|
else { |
126
|
12260
|
|
100
|
|
|
32005
|
$string .= $colors->{lc($c)} || ''; |
127
|
|
|
|
|
|
|
} |
128
|
14432
|
|
|
|
|
9889
|
$string .= $s; |
129
|
14432
|
100
|
100
|
|
|
42615
|
$string .= $colors->{reset} || '' if $r; |
130
|
|
|
|
|
|
|
} |
131
|
|
|
|
|
|
|
|
132
|
918
|
|
|
|
|
2336
|
my $fh = $self->{+OUT_STD}; |
133
|
|
|
|
|
|
|
|
134
|
918
|
|
|
|
|
199955
|
print $fh $string; |
135
|
|
|
|
|
|
|
} |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
sub encoding { |
138
|
323
|
|
|
323
|
|
1958
|
my $self = shift; |
139
|
323
|
|
|
|
|
668
|
my ($enc) = @_; |
140
|
|
|
|
|
|
|
|
141
|
323
|
|
|
|
|
687
|
my $fh = $self->{+OUT_STD}; |
142
|
|
|
|
|
|
|
# https://rt.perl.org/Public/Bug/Display.html?id=31923 |
143
|
|
|
|
|
|
|
# If utf8 is requested we use ':utf8' instead of ':encoding(utf8)' in |
144
|
|
|
|
|
|
|
# order to avoid the thread segfault. |
145
|
323
|
50
|
|
|
|
2374
|
if ($enc =~ m/^utf-?8$/i) { |
146
|
323
|
|
|
|
|
1904
|
binmode($fh, ":utf8"); |
147
|
|
|
|
|
|
|
} |
148
|
|
|
|
|
|
|
else { |
149
|
0
|
|
|
|
|
0
|
binmode($fh, ":encoding($enc)"); |
150
|
|
|
|
|
|
|
} |
151
|
|
|
|
|
|
|
} |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
sub summary { |
154
|
26
|
|
|
26
|
0
|
3625
|
my $self = shift; |
155
|
26
|
|
|
|
|
115
|
my ($results) = @_; |
156
|
|
|
|
|
|
|
|
157
|
26
|
|
|
|
|
93
|
my @fail = grep {!$_->passed} @$results; |
|
434
|
|
|
|
|
1440
|
|
158
|
|
|
|
|
|
|
|
159
|
26
|
100
|
|
|
|
217
|
if (@fail) { |
160
|
2
|
|
|
|
|
8
|
$self->paint("\n", ['failed', "=== FAILURE SUMMARY ===\n", 0]); |
161
|
2
|
|
|
|
|
4
|
$self->paint(map { " * " . $_->name . "\n" } @fail); |
|
4
|
|
|
|
|
202
|
|
162
|
|
|
|
|
|
|
} |
163
|
|
|
|
|
|
|
else { |
164
|
24
|
|
|
|
|
230
|
$self->paint("\n", ['passed', "=== ALL TESTS SUCCEEDED ===\n", 0]); |
165
|
|
|
|
|
|
|
} |
166
|
|
|
|
|
|
|
|
167
|
26
|
|
|
|
|
251
|
$self->paint(['reset', '', 0], "\n"); |
168
|
|
|
|
|
|
|
} |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
sub listen { |
171
|
54
|
|
|
54
|
0
|
106
|
my $self = shift; |
172
|
54
|
|
|
19785
|
|
332
|
sub { $self->process(@_) }; |
|
19785
|
|
|
|
|
35263
|
|
173
|
|
|
|
|
|
|
} |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
sub init_job { |
176
|
611
|
|
|
611
|
0
|
2970
|
my $self = shift; |
177
|
611
|
|
|
|
|
698
|
my ($j) = @_; |
178
|
|
|
|
|
|
|
|
179
|
611
|
|
|
|
|
1159
|
my $jobs = $self->{+JOBS}; |
180
|
611
|
|
|
|
|
712
|
my $slots = $self->{+SLOTS}; |
181
|
|
|
|
|
|
|
|
182
|
611
|
|
|
|
|
628
|
my $slot; |
183
|
611
|
|
|
|
|
3602
|
for my $s (0 .. @$slots) { |
184
|
613
|
100
|
|
|
|
1807
|
$slot = $s unless defined $slots->[$s]; |
185
|
613
|
100
|
|
|
|
1511
|
last if defined $slot; |
186
|
|
|
|
|
|
|
} |
187
|
|
|
|
|
|
|
|
188
|
611
|
|
|
|
|
1744
|
$slots->[$slot] = $j; |
189
|
|
|
|
|
|
|
|
190
|
611
|
|
|
|
|
4459
|
return $jobs->{$j} = {slot => $slot}; |
191
|
|
|
|
|
|
|
} |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
sub end_job { |
194
|
605
|
|
|
605
|
|
5162
|
my $self = shift; |
195
|
605
|
|
|
|
|
1261
|
my ($j) = @_; |
196
|
|
|
|
|
|
|
|
197
|
605
|
|
|
|
|
3422
|
my $job = delete $self->{+JOBS}->{$j}; |
198
|
605
|
|
|
|
|
7236
|
$self->{+SLOTS}->[$job->{slot}] = undef; |
199
|
|
|
|
|
|
|
} |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
sub update_state { |
202
|
19787
|
|
|
19787
|
|
15397
|
my $self = shift; |
203
|
19787
|
|
|
|
|
14697
|
my ($j, $event) = @_; |
204
|
|
|
|
|
|
|
|
205
|
19787
|
|
|
|
|
18785
|
$self->{+COUNTER}++; |
206
|
|
|
|
|
|
|
|
207
|
19787
|
|
|
|
|
21732
|
my $jobs = $self->{+JOBS}; |
208
|
19787
|
|
66
|
|
|
43562
|
my $job = $jobs->{$j} ||= $self->init_job($j); |
209
|
19787
|
|
|
|
|
18859
|
$job->{counter}++; |
210
|
|
|
|
|
|
|
|
211
|
19787
|
100
|
|
|
|
77923
|
$self->encoding($event->encoding) if $event->isa('Test2::Event::Encoding'); |
212
|
|
|
|
|
|
|
} |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
sub pick_renderer { |
215
|
19246
|
|
|
19246
|
|
116336
|
my $self = shift; |
216
|
19246
|
|
|
|
|
14775
|
my ($event) = @_; |
217
|
|
|
|
|
|
|
|
218
|
19246
|
|
100
|
|
|
29449
|
my $n = $event->nested || 0; |
219
|
|
|
|
|
|
|
|
220
|
19246
|
100
|
|
|
|
75744
|
return 'render' if $n < 0; |
221
|
|
|
|
|
|
|
|
222
|
19230
|
100
|
|
|
|
25337
|
if ($n == 0) { |
223
|
4973
|
100
|
|
|
|
10382
|
return 'render' unless $event->subtest_id; |
224
|
2002
|
100
|
|
|
|
8249
|
return 'render_subtest' unless $event->in_subtest; |
225
|
|
|
|
|
|
|
} |
226
|
|
|
|
|
|
|
|
227
|
14265
|
100
|
|
|
|
20586
|
return 'render_orphan' unless $event->in_subtest; |
228
|
14257
|
100
|
|
|
|
47144
|
return 'preview' if $self->{+WATCH}; |
229
|
|
|
|
|
|
|
|
230
|
14249
|
|
|
|
|
27727
|
return; |
231
|
|
|
|
|
|
|
} |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
sub process { |
234
|
19791
|
|
|
19791
|
|
17861
|
my $self = shift; |
235
|
19791
|
|
|
|
|
15200
|
my ($j, $event) = @_; |
236
|
|
|
|
|
|
|
|
237
|
19791
|
|
|
|
|
33731
|
my $job_id = $j->id; |
238
|
19791
|
|
|
|
|
55668
|
$self->update_state($job_id, $event); |
239
|
|
|
|
|
|
|
|
240
|
19791
|
|
|
|
|
19349
|
my $job = $self->{+JOBS}->{$job_id}; |
241
|
|
|
|
|
|
|
|
242
|
19791
|
|
|
|
|
46521
|
my $is_end = $event->isa('Test2::Event::ProcessFinish'); |
243
|
|
|
|
|
|
|
|
244
|
19791
|
100
|
100
|
|
|
61904
|
if ($event->isa('Test2::Event::ProcessStart') && !$self->{+VERBOSE}) { |
245
|
603
|
|
|
|
|
1808
|
$job->{start} = $event; |
246
|
|
|
|
|
|
|
} |
247
|
|
|
|
|
|
|
else { |
248
|
19188
|
|
|
|
|
29256
|
my @to_print = $self->_process($job_id, $event, $is_end); |
249
|
19188
|
100
|
|
|
|
36760
|
$self->paint(@to_print) if @to_print; |
250
|
|
|
|
|
|
|
} |
251
|
|
|
|
|
|
|
|
252
|
19791
|
|
|
|
|
29460
|
$self->do_watch; |
253
|
|
|
|
|
|
|
|
254
|
19791
|
100
|
|
|
|
56733
|
$self->end_job($job_id) if $is_end; |
255
|
|
|
|
|
|
|
} |
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
sub _process { |
258
|
19190
|
|
|
19190
|
|
28166
|
my $self = shift; |
259
|
19190
|
|
|
|
|
20477
|
my ($j, $event, $is_end) = @_; |
260
|
19190
|
|
|
|
|
17977
|
my $job = $self->{+JOBS}->{$j}; |
261
|
|
|
|
|
|
|
|
262
|
19190
|
100
|
|
|
|
21773
|
my $meth = $self->pick_renderer($event) or return; |
263
|
4949
|
100
|
|
|
|
32281
|
my @to_print = $self->$meth($j, $event) or return; |
264
|
864
|
100
|
|
|
|
7038
|
my @start = $job->{start} ? $self->render($j, delete $job->{start}) : (); |
265
|
|
|
|
|
|
|
|
266
|
864
|
100
|
|
|
|
7841
|
return (@start, @to_print) unless $is_end; |
267
|
|
|
|
|
|
|
|
268
|
605
|
100
|
|
|
|
4295
|
my @errors = $self->_plan_errors($event->result->events, 0) or return @to_print; |
269
|
2
|
|
|
|
|
444
|
my @tree = $self->tree($j, $event); |
270
|
|
|
|
|
|
|
|
271
|
2
|
|
|
|
|
11
|
@errors = map {( |
272
|
4
|
|
|
|
|
47
|
['tag', '['], ['fail',' PLAN '], ['tag', ']'], |
273
|
|
|
|
|
|
|
' ', @tree, ' ', |
274
|
|
|
|
|
|
|
['fail', $_], |
275
|
|
|
|
|
|
|
"\n", |
276
|
|
|
|
|
|
|
)} @errors; |
277
|
|
|
|
|
|
|
|
278
|
2
|
|
|
|
|
47
|
return (@start, @errors, @to_print); |
279
|
|
|
|
|
|
|
} |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
sub do_watch { |
282
|
19791
|
|
|
19791
|
|
15883
|
my $self = shift; |
283
|
19791
|
100
|
|
|
|
29707
|
return unless $self->{+WATCH}; |
284
|
4
|
100
|
|
|
|
12
|
return if $self->{+VERBOSE}; |
285
|
|
|
|
|
|
|
|
286
|
2
|
|
|
|
|
4
|
my $jobs = $self->{+JOBS}; |
287
|
|
|
|
|
|
|
|
288
|
2
|
|
|
|
|
5
|
my $size = length($self->{+COUNTER}); |
289
|
|
|
|
|
|
|
|
290
|
2
|
|
|
|
|
9
|
$self->paint(" Events Seen: ", $self->{+COUNTER}, "\r"); |
291
|
2
|
|
|
|
|
4
|
$self->{+CLEAR} = 1; |
292
|
|
|
|
|
|
|
} |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
sub _tag { |
295
|
21368
|
|
|
21368
|
|
22280
|
my $self = shift; |
296
|
21368
|
|
|
|
|
18927
|
my ($event) = @_; |
297
|
|
|
|
|
|
|
|
298
|
21368
|
100
|
|
|
|
36223
|
return if $event->no_display; |
299
|
|
|
|
|
|
|
|
300
|
21364
|
100
|
|
|
|
90358
|
return ("LAUNCH", 'file') |
301
|
|
|
|
|
|
|
if $event->isa('Test2::Event::ProcessStart'); |
302
|
|
|
|
|
|
|
|
303
|
20158
|
100
|
|
|
|
45873
|
if ($event->isa('Test2::Event::ParserSelect')) { |
304
|
605
|
100
|
|
|
|
2509
|
return unless $self->{+VERBOSE}; |
305
|
2
|
|
|
|
|
14
|
return ('PARSER', 'parser_select'); |
306
|
|
|
|
|
|
|
} |
307
|
|
|
|
|
|
|
|
308
|
19553
|
100
|
|
|
|
42828
|
if ($event->isa('Test2::Event::Subtest')) { |
309
|
2061
|
100
|
|
|
|
4665
|
return ("FAILED", 'failed') if $event->causes_fail; |
310
|
|
|
|
|
|
|
|
311
|
2057
|
|
100
|
|
|
7950
|
my $n = $event->nested || 0; |
312
|
2057
|
100
|
100
|
|
|
15362
|
return unless $self->{+VERBOSE} || $n < 0; |
313
|
|
|
|
|
|
|
|
314
|
18
|
|
|
|
|
21
|
my ($plan) = (grep { $_->isa('Test2::Event::Plan') } @{$event->subevents})[0]; |
|
34
|
|
|
|
|
118
|
|
|
18
|
|
|
|
|
38
|
|
315
|
18
|
100
|
66
|
|
|
66
|
if ($plan && $plan->directive && $plan->directive eq 'SKIP') { |
|
|
|
66
|
|
|
|
|
316
|
4
|
|
|
|
|
71
|
return ("SKIP!!", 'skipall'); |
317
|
|
|
|
|
|
|
} |
318
|
|
|
|
|
|
|
|
319
|
14
|
|
|
|
|
105
|
return ("PASSED", 'passed'); |
320
|
|
|
|
|
|
|
} |
321
|
|
|
|
|
|
|
|
322
|
17492
|
100
|
|
|
|
37299
|
if ($event->isa('Test2::Event::ProcessFinish')) { |
323
|
1202
|
100
|
|
|
|
2688
|
return ("NOTEST", "skipall") unless $event->result->ran_tests; |
324
|
1126
|
50
|
|
|
|
1878
|
return ("PASSED", 'passed') if $event->result->passed; |
325
|
0
|
|
|
|
|
0
|
return ("FAILED", 'failed'); |
326
|
|
|
|
|
|
|
} |
327
|
|
|
|
|
|
|
|
328
|
16290
|
100
|
|
|
|
31995
|
if ($event->isa('Test2::Event::Plan')) { |
329
|
2692
|
100
|
|
|
|
5958
|
if ($event->directive eq 'SKIP') { |
330
|
80
|
|
|
|
|
693
|
return ("SKIP!!", 'skipall'); |
331
|
|
|
|
|
|
|
} |
332
|
2612
|
100
|
|
|
|
12232
|
return unless $self->{+VERBOSE}; |
333
|
10
|
|
|
|
|
34
|
return (" PLAN ", 'plan'); |
334
|
|
|
|
|
|
|
} |
335
|
|
|
|
|
|
|
|
336
|
13598
|
100
|
|
|
|
27967
|
if ($event->isa('Test2::Event::Encoding')) { |
337
|
325
|
100
|
|
|
|
916
|
return unless $self->{+VERBOSE}; |
338
|
2
|
|
|
|
|
10
|
return ('ENCODE', 'encoding'); |
339
|
|
|
|
|
|
|
} |
340
|
|
|
|
|
|
|
|
341
|
13273
|
100
|
100
|
|
|
69898
|
if ($event->isa('Test2::Event::UnknownStdout') || $event->isa('Test2::Event::UnknownStderr')) { |
342
|
8
|
50
|
|
|
|
21
|
return unless defined $event->output; |
343
|
|
|
|
|
|
|
|
344
|
8
|
100
|
|
|
|
64
|
return ("STDERR", 'stderr') if $event->isa('Test2::Event::UnknownStderr'); |
345
|
4
|
50
|
|
|
|
14
|
return (" DIAG ", 'diag') if $event->diagnostics; |
346
|
|
|
|
|
|
|
|
347
|
4
|
100
|
|
|
|
27
|
return unless $self->{+VERBOSE}; |
348
|
2
|
|
|
|
|
12
|
return ("STDOUT", 'stdout'); |
349
|
|
|
|
|
|
|
} |
350
|
|
|
|
|
|
|
|
351
|
13265
|
100
|
100
|
|
|
65597
|
if ($event->isa('Test2::Event::UnexpectedProcessExit') || $event->isa('Test2::Event::TimeoutReset')) { |
352
|
132
|
|
|
|
|
321
|
return ("PARSER", 'parser'); |
353
|
|
|
|
|
|
|
} |
354
|
|
|
|
|
|
|
|
355
|
13133
|
100
|
|
|
|
20311
|
if ($event->increments_count) { |
356
|
12403
|
100
|
|
|
|
36056
|
if ($self->{+VERBOSE}) { |
357
|
24
|
100
|
66
|
|
|
108
|
return (" OK ", 'skip') if $event->can('reason') && defined $event->reason; |
358
|
22
|
100
|
100
|
|
|
129
|
return ("NOT OK", 'todo') if $event->can('todo') && defined $event->todo; |
359
|
|
|
|
|
|
|
# The event is a failure but something overrode that - this would |
360
|
|
|
|
|
|
|
# be a failure inside a subtest marked as todo. |
361
|
20
|
50
|
66
|
|
|
126
|
return ("NOT OK", 'todo') if !$event->pass && $event->effective_pass; |
362
|
20
|
100
|
|
|
|
691
|
return (" OK ", 'pass') unless $event->causes_fail; |
363
|
|
|
|
|
|
|
} |
364
|
|
|
|
|
|
|
|
365
|
12383
|
100
|
|
|
|
16411
|
return ("NOT OK", 'fail') if $event->causes_fail; |
366
|
12375
|
|
|
|
|
36391
|
return; |
367
|
|
|
|
|
|
|
} |
368
|
|
|
|
|
|
|
|
369
|
730
|
100
|
|
|
|
3674
|
if ($event->can('message')) { |
370
|
710
|
100
|
|
|
|
1297
|
return (" DIAG ", 'diag') if $event->diagnostics; |
371
|
404
|
100
|
|
|
|
1672
|
return unless $self->{+VERBOSE}; |
372
|
2
|
|
|
|
|
11
|
return (" NOTE ", 'note'); |
373
|
|
|
|
|
|
|
} |
374
|
|
|
|
|
|
|
|
375
|
20
|
100
|
100
|
|
|
101
|
return unless $self->{+VERBOSE} || $event->diagnostics; |
376
|
14
|
100
|
|
|
|
73
|
return ("PARSER", 'parser') if $event->isa('Test2::Event::ParseError'); |
377
|
|
|
|
|
|
|
|
378
|
10
|
100
|
66
|
|
|
24
|
return unless defined $event->summary && $event->summary =~ /\S/; |
379
|
|
|
|
|
|
|
|
380
|
8
|
|
|
|
|
115
|
return (" ???? ", 'unknown'); |
381
|
|
|
|
|
|
|
} |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
sub tag { |
384
|
19805
|
|
|
19805
|
|
21723
|
my $self = shift; |
385
|
19805
|
|
|
|
|
13892
|
my ($event) = @_; |
386
|
|
|
|
|
|
|
|
387
|
19805
|
|
|
|
|
23386
|
my ($val, $color) = $self->_tag($event); |
388
|
|
|
|
|
|
|
|
389
|
19805
|
100
|
|
|
|
69440
|
return unless $val; |
390
|
|
|
|
|
|
|
return ( |
391
|
1477
|
|
|
|
|
9199
|
['tag', '['], |
392
|
|
|
|
|
|
|
[$color, $val], |
393
|
|
|
|
|
|
|
['tag', ']'], |
394
|
|
|
|
|
|
|
); |
395
|
|
|
|
|
|
|
} |
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
sub tree { |
398
|
3524
|
|
|
3524
|
|
4398
|
my $self = shift; |
399
|
3524
|
|
|
|
|
3839
|
my ($j, $event) = @_; |
400
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
# Get mark |
402
|
3524
|
|
|
|
|
4302
|
my $mark = '+'; |
403
|
3524
|
100
|
|
|
|
5227
|
if (!$event) { |
404
|
2
|
|
|
|
|
4
|
$mark = '|'; |
405
|
|
|
|
|
|
|
} |
406
|
|
|
|
|
|
|
else { |
407
|
3522
|
|
100
|
|
|
8057
|
my $n = $event->nested || 0; |
408
|
3522
|
100
|
|
|
|
22036
|
$mark = '_' if $event->isa('Test2::Event::ProcessStart'); |
409
|
3522
|
100
|
100
|
|
|
11222
|
$mark = '=' if $event->isa('Test2::Event::Subtest') && $n < 0; |
410
|
3522
|
100
|
|
|
|
9933
|
$mark = '=' if $event->isa('Test2::Event::ProcessFinish'); |
411
|
|
|
|
|
|
|
} |
412
|
|
|
|
|
|
|
|
413
|
3524
|
|
|
|
|
3872
|
my $jobs = $self->{+JOBS}; |
414
|
3524
|
|
|
|
|
4132
|
my $slots = $self->{+SLOTS}; |
415
|
|
|
|
|
|
|
|
416
|
3524
|
|
|
|
|
2938
|
my @marks; |
417
|
3524
|
|
|
|
|
7602
|
for my $s (@$slots) { |
418
|
3542
|
100
|
|
|
|
6328
|
if (!defined($s)) { |
419
|
12
|
|
|
|
|
13
|
push @marks => (' ', ' '); |
420
|
12
|
|
|
|
|
15
|
next; |
421
|
|
|
|
|
|
|
} |
422
|
|
|
|
|
|
|
|
423
|
3530
|
100
|
100
|
|
|
9160
|
unless ($jobs->{$s}->{counter} > 1 || $j == $s) { |
424
|
10
|
|
|
|
|
19
|
push @marks => ([$s, ':'], ' '); |
425
|
10
|
|
|
|
|
12
|
next; |
426
|
|
|
|
|
|
|
} |
427
|
|
|
|
|
|
|
|
428
|
3520
|
100
|
100
|
|
|
16365
|
if ($s == $j && $mark ne '|') { |
429
|
3504
|
100
|
|
|
|
11384
|
push @marks => ([$mark eq '+' ? $s : 'mark', $mark], ' '); |
430
|
|
|
|
|
|
|
} |
431
|
|
|
|
|
|
|
else { |
432
|
16
|
|
|
|
|
30
|
push @marks => ([$s, '|'], ' '); |
433
|
|
|
|
|
|
|
} |
434
|
|
|
|
|
|
|
} |
435
|
3524
|
|
|
|
|
3283
|
pop @marks; |
436
|
3524
|
|
|
|
|
6538
|
return @marks; |
437
|
|
|
|
|
|
|
} |
438
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
sub painted_length { |
440
|
1479
|
|
|
1479
|
0
|
5780
|
my $self = shift; |
441
|
1479
|
100
|
|
|
|
2276
|
my $str = join '' => map { ref($_) ? $_->[1] : $_ } @_; |
|
8836
|
|
|
|
|
14115
|
|
442
|
1479
|
|
|
|
|
3041
|
return length($str); |
443
|
|
|
|
|
|
|
} |
444
|
|
|
|
|
|
|
|
445
|
|
|
|
|
|
|
sub event_summary { |
446
|
1477
|
|
|
1477
|
|
1797
|
my $self = shift; |
447
|
1477
|
|
|
|
|
1505
|
my ($event, $start) = @_; |
448
|
|
|
|
|
|
|
|
449
|
1477
|
|
|
|
|
2864
|
my ($val, $color) = $self->_tag($event); |
450
|
|
|
|
|
|
|
|
451
|
1477
|
|
|
|
|
7161
|
my $summary = $event->summary; |
452
|
|
|
|
|
|
|
|
453
|
1477
|
|
|
|
|
7343
|
$summary =~ s/^[\n\r]+//g; |
454
|
1477
|
50
|
|
|
|
6191
|
my @lines = grep {defined $_ && length $_} split /[\n\r]+/, $summary; |
|
3317
|
|
|
|
|
12179
|
|
455
|
1477
|
50
|
|
|
|
3004
|
@lines = ('') unless @lines; |
456
|
|
|
|
|
|
|
|
457
|
1477
|
|
|
|
|
3226
|
my $len = $self->painted_length(@$start) + 1; |
458
|
1477
|
|
|
|
|
7582
|
my $term_size = term_size(); |
459
|
|
|
|
|
|
|
|
460
|
1477
|
|
|
|
|
7162323
|
my @blob; |
461
|
1477
|
100
|
|
|
|
2907
|
if (grep { $term_size <= $len + length($_) } @lines) { |
|
3317
|
|
|
|
|
7485
|
|
462
|
51
|
|
|
|
|
305
|
@lines = ( ['blob', '----- START -----'] ); |
463
|
51
|
|
|
|
|
314
|
@blob = ( |
464
|
|
|
|
|
|
|
[$color, $summary], |
465
|
|
|
|
|
|
|
"\n", |
466
|
|
|
|
|
|
|
@$start, |
467
|
|
|
|
|
|
|
['blob', '------ END ------'], |
468
|
|
|
|
|
|
|
"\n", |
469
|
|
|
|
|
|
|
); |
470
|
|
|
|
|
|
|
} |
471
|
|
|
|
|
|
|
else { |
472
|
1426
|
|
|
|
|
2150
|
@lines = map { [$color, $_] } @lines; |
|
3266
|
|
|
|
|
10251
|
|
473
|
|
|
|
|
|
|
} |
474
|
|
|
|
|
|
|
|
475
|
1477
|
|
|
|
|
11608
|
return (\@lines, \@blob); |
476
|
|
|
|
|
|
|
} |
477
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
sub render { |
479
|
19803
|
|
|
19803
|
|
16554
|
my $self = shift; |
480
|
19803
|
|
|
|
|
21519
|
my ($j, $event, @nest) = @_; |
481
|
|
|
|
|
|
|
|
482
|
|
|
|
|
|
|
# If there is no tag then we do not render it. |
483
|
19803
|
100
|
|
|
|
25477
|
my @tag = $self->tag($event) or return; |
484
|
1475
|
|
|
|
|
3193
|
my @tree = $self->tree($j, $event); |
485
|
1475
|
|
|
|
|
3881
|
my @start = (@tag, ' ', @tree, ' ', @nest); |
486
|
|
|
|
|
|
|
|
487
|
1475
|
|
|
|
|
3730
|
my ($summary, $blob) = $self->event_summary($event, \@start); |
488
|
|
|
|
|
|
|
|
489
|
1475
|
|
|
|
|
1669
|
my @out; |
490
|
1475
|
|
|
|
|
10943
|
push @out => (@start, $_, "\n") for @$summary; |
491
|
1475
|
100
|
|
|
|
4115
|
push @out => @$blob if @$blob; |
492
|
|
|
|
|
|
|
|
493
|
1475
|
|
|
|
|
13192
|
return @out; |
494
|
|
|
|
|
|
|
} |
495
|
|
|
|
|
|
|
|
496
|
|
|
|
|
|
|
sub render_orphan { |
497
|
6
|
|
|
6
|
0
|
1749
|
my $self = shift; |
498
|
6
|
|
|
|
|
9
|
my ($j, $event) = @_; |
499
|
|
|
|
|
|
|
|
500
|
|
|
|
|
|
|
# If there is no tag then we do not render it. |
501
|
6
|
100
|
|
|
|
17
|
my @tag = $self->tag($event) or return; |
502
|
4
|
|
|
|
|
22
|
my @tree = $self->tree($j, $event); |
503
|
4
|
|
|
|
|
108
|
my @start = (@tag, ' ', @tree, ' ', [$j, ("> " x $event->nested)]); |
504
|
|
|
|
|
|
|
|
505
|
4
|
|
|
|
|
199
|
my ($summary, $blob) = $self->event_summary($event, \@start); |
506
|
|
|
|
|
|
|
|
507
|
4
|
|
|
|
|
12
|
my @out; |
508
|
4
|
|
|
|
|
17
|
push @out => (@start, $_, "\n") for @$summary; |
509
|
4
|
100
|
|
|
|
11
|
push @out => @$blob if @$blob; |
510
|
|
|
|
|
|
|
|
511
|
4
|
|
|
|
|
36
|
return @out; |
512
|
|
|
|
|
|
|
} |
513
|
|
|
|
|
|
|
|
514
|
|
|
|
|
|
|
sub preview { |
515
|
6
|
|
|
6
|
0
|
1784
|
my $self = shift; |
516
|
6
|
|
|
|
|
8
|
my ($j, $event) = @_; |
517
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
# If there is no tag then we do not render it. |
519
|
6
|
100
|
|
|
|
17
|
my @tag = $self->tag($event) or return; |
520
|
4
|
|
|
|
|
21
|
my @tree = $self->tree($j, $event); |
521
|
4
|
|
|
|
|
27
|
my @start = (@tag, ' ', @tree, ' ', [$j, ("> " x $event->nested)]); |
522
|
|
|
|
|
|
|
|
523
|
4
|
|
|
|
|
208
|
my ($summary) = $self->event_summary($event, \@start); |
524
|
|
|
|
|
|
|
|
525
|
4
|
|
|
|
|
15
|
$self->{+CLEAR} = 2; |
526
|
4
|
|
|
|
|
33
|
return (@start, $summary->[-1], "\r"); |
527
|
|
|
|
|
|
|
} |
528
|
|
|
|
|
|
|
|
529
|
|
|
|
|
|
|
sub render_subtest { |
530
|
1988
|
|
|
1988
|
0
|
2226
|
my $self = shift; |
531
|
1988
|
|
|
|
|
1921
|
my ($j, $event) = @_; |
532
|
|
|
|
|
|
|
|
533
|
1988
|
|
|
|
|
3490
|
my @out = $self->render($j, $event); |
534
|
|
|
|
|
|
|
|
535
|
1988
|
|
|
|
|
1651
|
my @todo = @{$event->subevents}; |
|
1988
|
|
|
|
|
4013
|
|
536
|
1988
|
|
|
|
|
6415
|
my @stack = ($event); |
537
|
|
|
|
|
|
|
|
538
|
1988
|
|
|
|
|
3950
|
while (my $e = shift @todo) { |
539
|
14253
|
|
|
|
|
11402
|
my $nest = ""; |
540
|
|
|
|
|
|
|
|
541
|
14253
|
100
|
|
|
|
19336
|
if ($e->subtest_id) { |
542
|
53
|
|
|
|
|
256
|
unshift @todo => @{$e->subevents}; |
|
53
|
|
|
|
|
216
|
|
543
|
53
|
|
|
|
|
215
|
push @stack => $e; |
544
|
|
|
|
|
|
|
|
545
|
53
|
|
|
|
|
163
|
$nest = '| ' x ($e->nested - 1); |
546
|
53
|
|
|
|
|
247
|
$nest .= "+-"; |
547
|
|
|
|
|
|
|
} |
548
|
|
|
|
|
|
|
else { |
549
|
14200
|
|
|
|
|
37352
|
$nest = '| ' x $e->nested; |
550
|
|
|
|
|
|
|
} |
551
|
|
|
|
|
|
|
|
552
|
14253
|
100
|
50
|
|
|
51830
|
if (!@todo || (($todo[0]->in_subtest || '') ne ($e->in_subtest || '') && !$e->subtest_id)) { |
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
66
|
|
|
|
|
553
|
2041
|
|
|
|
|
4567
|
push @out => $self->render($j, $e, [$j, $nest]); |
554
|
|
|
|
|
|
|
|
555
|
2041
|
|
|
|
|
4376
|
my @tree = $self->tree($j, $e); |
556
|
|
|
|
|
|
|
|
557
|
2041
|
50
|
|
|
|
3864
|
if (my $st = pop @stack) { |
558
|
|
|
|
|
|
|
push @out => ( |
559
|
|
|
|
|
|
|
['tag', '['], ['fail', ' PLAN '], ['tag', ']'], |
560
|
|
|
|
|
|
|
' ', @tree, ' ', |
561
|
|
|
|
|
|
|
[$j, $nest], |
562
|
|
|
|
|
|
|
['fail', $_], |
563
|
|
|
|
|
|
|
"\n", |
564
|
2041
|
|
100
|
|
|
3946
|
) for $self->_plan_errors($st->subevents, ($st->nested || 0) + 1); |
565
|
|
|
|
|
|
|
} |
566
|
|
|
|
|
|
|
|
567
|
2041
|
50
|
66
|
|
|
7657
|
if (@out && $self->{+VERBOSE}) { |
568
|
4
|
|
|
|
|
15
|
my $n2 = '| ' x ($e->nested - 1); |
569
|
4
|
|
|
|
|
56
|
push @out => ( |
570
|
|
|
|
|
|
|
" ", @tree, " ", |
571
|
|
|
|
|
|
|
[$j, "$n2^"], |
572
|
|
|
|
|
|
|
"\n", |
573
|
|
|
|
|
|
|
); |
574
|
|
|
|
|
|
|
} |
575
|
|
|
|
|
|
|
} |
576
|
|
|
|
|
|
|
else { |
577
|
12212
|
|
|
|
|
79294
|
push @out => $self->render($j, $e, [$j, $nest]); |
578
|
|
|
|
|
|
|
} |
579
|
|
|
|
|
|
|
} |
580
|
|
|
|
|
|
|
|
581
|
1988
|
|
|
|
|
5455
|
return @out; |
582
|
|
|
|
|
|
|
} |
583
|
|
|
|
|
|
|
|
584
|
|
|
|
|
|
|
sub _plan_errors { |
585
|
2642
|
|
|
2642
|
|
20949
|
my $self = shift; |
586
|
2642
|
|
|
|
|
2605
|
my $events = shift; |
587
|
2642
|
|
|
|
|
1806
|
my $nested = shift; |
588
|
|
|
|
|
|
|
|
589
|
2642
|
|
|
|
|
2710
|
my @errors; |
590
|
|
|
|
|
|
|
|
591
|
2642
|
50
|
66
|
|
|
5797
|
unless ($nested || grep { $_->isa('Test2::Event::ProcessStart') } @{$events}) { |
|
19182
|
|
|
|
|
43525
|
|
|
601
|
|
|
|
|
1823
|
|
592
|
0
|
|
|
|
|
0
|
push @errors => 'No process start event was seen!'; |
593
|
0
|
|
|
|
|
0
|
return; |
594
|
|
|
|
|
|
|
} |
595
|
|
|
|
|
|
|
|
596
|
2642
|
100
|
100
|
|
|
2249
|
my @plans = grep { ($_->nested || 0) == $nested && $_->isa('Test2::Event::Plan') } @{$events}; |
|
33435
|
|
|
|
|
152310
|
|
|
2642
|
|
|
|
|
3136
|
|
597
|
|
|
|
|
|
|
|
598
|
2642
|
50
|
|
|
|
17036
|
unless (@plans) { |
599
|
0
|
|
|
|
|
0
|
push @errors => 'No plan was ever set.'; |
600
|
0
|
|
|
|
|
0
|
return; |
601
|
|
|
|
|
|
|
} |
602
|
|
|
|
|
|
|
|
603
|
2642
|
50
|
|
|
|
4401
|
push @errors => 'Multiple plans were set.' |
604
|
|
|
|
|
|
|
if @plans > 1; |
605
|
|
|
|
|
|
|
|
606
|
2642
|
100
|
66
|
|
|
11844
|
push @errors => 'Plan must come before or after all testing, not in the middle.' |
607
|
|
|
|
|
|
|
unless $plans[0] == $events->[0] || $plans[0] == $events->[-1]; |
608
|
|
|
|
|
|
|
|
609
|
2642
|
|
|
|
|
9542
|
my $max = ($plans[0]->sets_plan)[0]; |
610
|
|
|
|
|
|
|
|
611
|
2642
|
100
|
100
|
|
|
12067
|
my $total = grep { ($_->nested || 0) == $nested && $_->increments_count } @{$events}; |
|
33435
|
|
|
|
|
148088
|
|
|
2642
|
|
|
|
|
3084
|
|
612
|
2642
|
50
|
|
|
|
28103
|
return if $max == $total; |
613
|
0
|
|
|
|
|
|
push @errors => "Planned to run $max test(s) but ran $total."; |
614
|
|
|
|
|
|
|
|
615
|
0
|
|
|
|
|
|
return @errors; |
616
|
|
|
|
|
|
|
} |
617
|
|
|
|
|
|
|
|
618
|
|
|
|
|
|
|
1; |
619
|
|
|
|
|
|
|
|
620
|
|
|
|
|
|
|
__END__ |