line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Test2::Harness::Renderer::EventStream; |
2
|
23
|
|
|
23
|
|
113947
|
use strict; |
|
23
|
|
|
|
|
46
|
|
|
23
|
|
|
|
|
601
|
|
3
|
23
|
|
|
23
|
|
72
|
use warnings; |
|
23
|
|
|
|
|
24
|
|
|
23
|
|
|
|
|
1027
|
|
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
our $VERSION = '0.000012'; |
6
|
|
|
|
|
|
|
|
7
|
23
|
|
|
23
|
|
69
|
use Test2::Util::HashBase qw/color verbose jobs slots parallel clear out_std watch colors graph_colors counter/; |
|
23
|
|
|
|
|
24
|
|
|
23
|
|
|
|
|
178
|
|
8
|
23
|
|
|
23
|
|
18011
|
use Term::ANSIColor(); |
|
23
|
|
|
|
|
117923
|
|
|
23
|
|
|
|
|
704
|
|
9
|
23
|
|
|
23
|
|
178
|
use List::Util qw/first shuffle/; |
|
23
|
|
|
|
|
24
|
|
|
23
|
|
|
|
|
2134
|
|
10
|
23
|
|
|
23
|
|
90
|
use Scalar::Util qw/blessed/; |
|
23
|
|
|
|
|
45
|
|
|
23
|
|
|
|
|
922
|
|
11
|
23
|
|
|
23
|
|
481
|
use Time::HiRes qw/sleep/; |
|
23
|
|
|
|
|
935
|
|
|
23
|
|
|
|
|
179
|
|
12
|
23
|
|
|
23
|
|
11638
|
use Test2::Util::Term qw/term_size/; |
|
23
|
|
|
|
|
105024
|
|
|
23
|
|
|
|
|
141
|
|
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
|
|
3086
|
for my $sig (qw/INT TERM/) { |
47
|
|
|
|
|
|
|
my $old = $SIG{$sig} || sub { |
48
|
|
|
|
|
|
|
$SIG{$sig} = 'DEFAULT'; |
49
|
|
|
|
|
|
|
kill $sig, $$; |
50
|
46
|
|
50
|
|
|
498
|
}; |
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
|
|
|
|
|
54946
|
}; |
57
|
|
|
|
|
|
|
} |
58
|
|
|
|
|
|
|
} |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
END { |
61
|
23
|
50
|
|
23
|
|
4718180
|
print STDOUT Term::ANSIColor::color('reset') if -t STDOUT; |
62
|
23
|
50
|
|
|
|
401
|
print STDERR Term::ANSIColor::color('reset') if -t STDERR; |
63
|
|
|
|
|
|
|
} |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
sub init { |
66
|
100
|
|
|
100
|
0
|
179679
|
my $self = shift; |
67
|
100
|
|
|
|
|
296
|
$self->{+JOBS} = {}; |
68
|
100
|
|
|
|
|
186
|
$self->{+SLOTS} = []; |
69
|
100
|
|
|
|
|
193
|
$self->{+CLEAR} = 0; |
70
|
|
|
|
|
|
|
|
71
|
100
|
|
66
|
|
|
358
|
my $fh = $self->{+OUT_STD} ||= do { |
72
|
84
|
50
|
|
|
|
23027
|
open( my $out, '>&', STDOUT ) or die "Can't dup STDOUT: $!"; |
73
|
|
|
|
|
|
|
|
74
|
84
|
|
|
|
|
380
|
my $old = select $out; |
75
|
84
|
|
|
|
|
268
|
$| = 1; |
76
|
84
|
|
|
|
|
233
|
select $old; |
77
|
|
|
|
|
|
|
|
78
|
84
|
|
|
|
|
306
|
$out; |
79
|
|
|
|
|
|
|
}; |
80
|
|
|
|
|
|
|
|
81
|
100
|
|
|
|
|
250
|
$self->{+COUNTER} = 0; |
82
|
|
|
|
|
|
|
|
83
|
100
|
|
|
|
|
241
|
my $is_term = -t $fh; |
84
|
100
|
50
|
|
|
|
322
|
$self->{+COLOR} = $is_term ? 1 : 0 unless defined $self->{+COLOR}; |
|
|
100
|
|
|
|
|
|
85
|
100
|
50
|
|
|
|
409
|
$self->{+WATCH} = $is_term ? 1 : 0 unless defined $self->{+WATCH}; |
|
|
100
|
|
|
|
|
|
86
|
100
|
50
|
66
|
|
|
735
|
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
|
|
|
|
364
|
: $self->{+COLOR} ? \%DEFAULT_COLORS |
|
|
50
|
|
|
|
|
|
93
|
|
|
|
|
|
|
: {}; |
94
|
|
|
|
|
|
|
|
95
|
100
|
100
|
|
|
|
254
|
my $graph_colors = $self->{+COLOR} ? [@DEFAULT_GRAPH_COLORS] : []; |
96
|
|
|
|
|
|
|
|
97
|
100
|
|
50
|
|
|
570
|
$self->{+COLORS} ||= {map { $_ => eval { Term::ANSIColor::color($colors->{$_}) } || '' } grep {$colors->{$_}} keys %$colors, 'reset'}; |
|
34
|
|
100
|
|
|
399
|
|
|
126
|
|
|
|
|
471
|
|
98
|
100
|
50
|
100
|
|
|
642
|
$self->{+GRAPH_COLORS} ||= [map { eval { Term::ANSIColor::color($_) } || '' } grep {$_} @$graph_colors]; |
|
16
|
|
|
|
|
128
|
|
|
16
|
|
|
|
|
20
|
|
|
16
|
|
|
|
|
12
|
|
99
|
|
|
|
|
|
|
} |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
sub paint { |
102
|
880
|
|
|
880
|
|
24632
|
my $self = shift; |
103
|
880
|
|
|
|
|
1974
|
my $string = ""; |
104
|
|
|
|
|
|
|
|
105
|
880
|
|
|
|
|
1598
|
my $colors = $self->{+COLORS}; |
106
|
880
|
|
|
|
|
1736
|
my $graph = $self->{+GRAPH_COLORS}; |
107
|
880
|
|
|
|
|
1407
|
my $jobs = $self->{+JOBS}; |
108
|
|
|
|
|
|
|
|
109
|
880
|
100
|
|
|
|
1890
|
if ($self->{+CLEAR}) { |
110
|
2
|
|
|
|
|
5
|
$string .= "\e[K"; |
111
|
2
|
|
|
|
|
5
|
$self->{+CLEAR}--; |
112
|
|
|
|
|
|
|
} |
113
|
|
|
|
|
|
|
|
114
|
880
|
|
|
|
|
3143
|
for my $i (@_) { |
115
|
22554
|
100
|
|
|
|
27674
|
unless (ref($i)) { |
116
|
8502
|
|
|
|
|
5611
|
$string .= $i; |
117
|
8502
|
|
|
|
|
7519
|
next; |
118
|
|
|
|
|
|
|
} |
119
|
|
|
|
|
|
|
|
120
|
14052
|
|
|
|
|
16441
|
my ($c, $s, $r) = @$i; |
121
|
14052
|
100
|
|
|
|
25409
|
$r = 1 if @$i < 3; |
122
|
14052
|
100
|
|
|
|
23024
|
if ($c =~ m/^\d+$/) { |
123
|
2134
|
100
|
50
|
|
|
2972
|
$string .= $graph->[$jobs->{$c}->{slot} % @$graph] || '' if @$graph |
124
|
|
|
|
|
|
|
} |
125
|
|
|
|
|
|
|
else { |
126
|
11918
|
|
100
|
|
|
28775
|
$string .= $colors->{lc($c)} || ''; |
127
|
|
|
|
|
|
|
} |
128
|
14052
|
|
|
|
|
10079
|
$string .= $s; |
129
|
14052
|
100
|
100
|
|
|
40148
|
$string .= $colors->{reset} || '' if $r; |
130
|
|
|
|
|
|
|
} |
131
|
|
|
|
|
|
|
|
132
|
880
|
|
|
|
|
1235
|
my $fh = $self->{+OUT_STD}; |
133
|
|
|
|
|
|
|
|
134
|
880
|
|
|
|
|
249521
|
print $fh $string; |
135
|
|
|
|
|
|
|
} |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
sub encoding { |
138
|
323
|
|
|
323
|
|
2070
|
my $self = shift; |
139
|
323
|
|
|
|
|
541
|
my ($enc) = @_; |
140
|
|
|
|
|
|
|
|
141
|
323
|
|
|
|
|
624
|
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
|
|
|
|
2367
|
if ($enc =~ m/^utf-?8$/i) { |
146
|
323
|
|
|
|
|
1694
|
binmode($fh, ":utf8"); |
147
|
|
|
|
|
|
|
} |
148
|
|
|
|
|
|
|
else { |
149
|
0
|
|
|
|
|
0
|
binmode($fh, ":encoding($enc)"); |
150
|
|
|
|
|
|
|
} |
151
|
|
|
|
|
|
|
} |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
sub summary { |
154
|
26
|
|
|
26
|
0
|
3221
|
my $self = shift; |
155
|
26
|
|
|
|
|
70
|
my ($results) = @_; |
156
|
|
|
|
|
|
|
|
157
|
26
|
|
|
|
|
92
|
my @fail = grep {!$_->passed} @$results; |
|
434
|
|
|
|
|
1399
|
|
158
|
|
|
|
|
|
|
|
159
|
26
|
100
|
|
|
|
128
|
if (@fail) { |
160
|
2
|
|
|
|
|
12
|
$self->paint("\n", ['failed', "=== FAILURE SUMMARY ===\n", 0]); |
161
|
2
|
|
|
|
|
3
|
$self->paint(map { " * " . $_->name . "\n" } @fail); |
|
4
|
|
|
|
|
167
|
|
162
|
|
|
|
|
|
|
} |
163
|
|
|
|
|
|
|
else { |
164
|
24
|
|
|
|
|
166
|
$self->paint("\n", ['passed', "=== ALL TESTS SUCCEEDED ===\n", 0]); |
165
|
|
|
|
|
|
|
} |
166
|
|
|
|
|
|
|
|
167
|
26
|
|
|
|
|
245
|
$self->paint(['reset', '', 0], "\n"); |
168
|
|
|
|
|
|
|
} |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
sub listen { |
171
|
54
|
|
|
54
|
0
|
87
|
my $self = shift; |
172
|
19731
|
|
|
19731
|
|
40186
|
sub { $self->process(@_) } |
173
|
54
|
|
|
|
|
463
|
}; |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
sub init_job { |
176
|
611
|
|
|
611
|
0
|
2811
|
my $self = shift; |
177
|
611
|
|
|
|
|
844
|
my ($j) = @_; |
178
|
|
|
|
|
|
|
|
179
|
611
|
|
|
|
|
1061
|
my $jobs = $self->{+JOBS}; |
180
|
611
|
|
|
|
|
930
|
my $slots = $self->{+SLOTS}; |
181
|
|
|
|
|
|
|
|
182
|
611
|
|
|
|
|
1660
|
my $slot; |
183
|
611
|
|
|
|
|
3487
|
for my $s (0 .. @$slots) { |
184
|
613
|
100
|
|
|
|
2033
|
$slot = $s unless defined $slots->[$s]; |
185
|
613
|
100
|
|
|
|
1843
|
last if defined $slot; |
186
|
|
|
|
|
|
|
} |
187
|
|
|
|
|
|
|
|
188
|
611
|
|
|
|
|
1386
|
$slots->[$slot] = $j; |
189
|
|
|
|
|
|
|
|
190
|
611
|
|
|
|
|
3818
|
return $jobs->{$j} = {slot => $slot}; |
191
|
|
|
|
|
|
|
} |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
sub end_job { |
194
|
605
|
|
|
605
|
|
4010
|
my $self = shift; |
195
|
605
|
|
|
|
|
1271
|
my ($j) = @_; |
196
|
|
|
|
|
|
|
|
197
|
605
|
|
|
|
|
1618
|
my $job = delete $self->{+JOBS}->{$j}; |
198
|
605
|
|
|
|
|
4150
|
$self->{+SLOTS}->[$job->{slot}] = undef; |
199
|
|
|
|
|
|
|
} |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
sub update_state { |
202
|
19733
|
|
|
19733
|
|
15427
|
my $self = shift; |
203
|
19733
|
|
|
|
|
16262
|
my ($j, $event) = @_; |
204
|
|
|
|
|
|
|
|
205
|
19733
|
|
|
|
|
18476
|
$self->{+COUNTER}++; |
206
|
|
|
|
|
|
|
|
207
|
19733
|
|
|
|
|
17235
|
my $jobs = $self->{+JOBS}; |
208
|
19733
|
|
66
|
|
|
40951
|
my $job = $jobs->{$j} ||= $self->init_job($j); |
209
|
19733
|
|
|
|
|
20668
|
$job->{counter}++; |
210
|
|
|
|
|
|
|
|
211
|
19733
|
100
|
|
|
|
83273
|
$self->encoding($event->encoding) if $event->isa('Test2::Event::Encoding'); |
212
|
|
|
|
|
|
|
} |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
sub pick_renderer { |
215
|
19192
|
|
|
19192
|
|
115637
|
my $self = shift; |
216
|
19192
|
|
|
|
|
14184
|
my ($event) = @_; |
217
|
|
|
|
|
|
|
|
218
|
19192
|
|
100
|
|
|
34331
|
my $n = $event->nested || 0; |
219
|
|
|
|
|
|
|
|
220
|
19192
|
100
|
|
|
|
77964
|
return 'render' if $n < 0; |
221
|
|
|
|
|
|
|
|
222
|
19176
|
100
|
|
|
|
28034
|
if ($n == 0) { |
223
|
4973
|
100
|
|
|
|
10851
|
return 'render' unless $event->subtest_id; |
224
|
2002
|
100
|
|
|
|
9019
|
return 'render_subtest' unless $event->in_subtest; |
225
|
|
|
|
|
|
|
} |
226
|
|
|
|
|
|
|
|
227
|
14211
|
100
|
|
|
|
21615
|
return 'render_orphan' unless $event->in_subtest; |
228
|
14203
|
100
|
|
|
|
48123
|
return 'preview' if $self->{+WATCH}; |
229
|
|
|
|
|
|
|
|
230
|
14195
|
|
|
|
|
31716
|
return; |
231
|
|
|
|
|
|
|
} |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
sub process { |
234
|
19737
|
|
|
19737
|
|
16985
|
my $self = shift; |
235
|
19737
|
|
|
|
|
16402
|
my ($j, $event) = @_; |
236
|
|
|
|
|
|
|
|
237
|
19737
|
|
|
|
|
36314
|
my $job_id = $j->id; |
238
|
19737
|
|
|
|
|
61812
|
$self->update_state($job_id, $event); |
239
|
|
|
|
|
|
|
|
240
|
19737
|
|
|
|
|
20447
|
my $job = $self->{+JOBS}->{$job_id}; |
241
|
|
|
|
|
|
|
|
242
|
19737
|
|
|
|
|
47607
|
my $is_end = $event->isa('Test2::Event::ProcessFinish'); |
243
|
|
|
|
|
|
|
|
244
|
19737
|
100
|
100
|
|
|
66452
|
if ($event->isa('Test2::Event::ProcessStart') && !$self->{+VERBOSE}) { |
245
|
603
|
|
|
|
|
2720
|
$job->{start} = $event; |
246
|
|
|
|
|
|
|
} |
247
|
|
|
|
|
|
|
else { |
248
|
19134
|
|
|
|
|
28743
|
my @to_print = $self->_process($job_id, $event, $is_end); |
249
|
19134
|
100
|
|
|
|
33765
|
$self->paint(@to_print) if @to_print; |
250
|
|
|
|
|
|
|
} |
251
|
|
|
|
|
|
|
|
252
|
19737
|
|
|
|
|
27877
|
$self->do_watch; |
253
|
|
|
|
|
|
|
|
254
|
19737
|
100
|
|
|
|
61900
|
$self->end_job($job_id) if $is_end; |
255
|
|
|
|
|
|
|
} |
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
sub _process { |
258
|
19136
|
|
|
19136
|
|
25905
|
my $self = shift; |
259
|
19136
|
|
|
|
|
18176
|
my ($j, $event, $is_end) = @_; |
260
|
19136
|
|
|
|
|
17043
|
my $job = $self->{+JOBS}->{$j}; |
261
|
|
|
|
|
|
|
|
262
|
19136
|
100
|
|
|
|
24405
|
my $meth = $self->pick_renderer($event) or return; |
263
|
4949
|
100
|
|
|
|
36001
|
my @to_print = $self->$meth($j, $event) or return; |
264
|
826
|
100
|
|
|
|
4059
|
my @start = $job->{start} ? $self->render($j, delete $job->{start}) : (); |
265
|
|
|
|
|
|
|
|
266
|
826
|
100
|
|
|
|
11292
|
return (@start, @to_print) unless $is_end; |
267
|
|
|
|
|
|
|
|
268
|
605
|
100
|
|
|
|
2743
|
my @errors = $self->_plan_errors($event->result->events, 0) or return @to_print; |
269
|
2
|
|
|
|
|
321
|
my @tree = $self->tree($j, $event); |
270
|
|
|
|
|
|
|
|
271
|
2
|
|
|
|
|
9
|
@errors = map {( |
272
|
4
|
|
|
|
|
32
|
['tag', '['], ['fail',' PLAN '], ['tag', ']'], |
273
|
|
|
|
|
|
|
' ', @tree, ' ', |
274
|
|
|
|
|
|
|
['fail', $_], |
275
|
|
|
|
|
|
|
"\n", |
276
|
|
|
|
|
|
|
)} @errors; |
277
|
|
|
|
|
|
|
|
278
|
2
|
|
|
|
|
28
|
return (@start, @errors, @to_print); |
279
|
|
|
|
|
|
|
} |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
sub do_watch { |
282
|
19737
|
|
|
19737
|
|
17115
|
my $self = shift; |
283
|
19737
|
100
|
|
|
|
32979
|
return unless $self->{+WATCH}; |
284
|
4
|
100
|
|
|
|
14
|
return if $self->{+VERBOSE}; |
285
|
|
|
|
|
|
|
|
286
|
2
|
|
|
|
|
4
|
my $jobs = $self->{+JOBS}; |
287
|
|
|
|
|
|
|
|
288
|
2
|
|
|
|
|
5
|
my $size = length($self->{+COUNTER}); |
289
|
|
|
|
|
|
|
|
290
|
2
|
|
|
|
|
8
|
$self->paint(" Events Seen: ", $self->{+COUNTER}, "\r"); |
291
|
2
|
|
|
|
|
4
|
$self->{+CLEAR} = 1; |
292
|
|
|
|
|
|
|
} |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
sub _tag { |
295
|
21272
|
|
|
21272
|
|
20957
|
my $self = shift; |
296
|
21272
|
|
|
|
|
14947
|
my ($event) = @_; |
297
|
|
|
|
|
|
|
|
298
|
21272
|
100
|
|
|
|
37538
|
return if $event->no_display; |
299
|
|
|
|
|
|
|
|
300
|
21268
|
100
|
|
|
|
93079
|
return ("LAUNCH", 'file') |
301
|
|
|
|
|
|
|
if $event->isa('Test2::Event::ProcessStart'); |
302
|
|
|
|
|
|
|
|
303
|
20062
|
100
|
|
|
|
49724
|
if ($event->isa('Test2::Event::ParserSelect')) { |
304
|
605
|
100
|
|
|
|
2617
|
return unless $self->{+VERBOSE}; |
305
|
2
|
|
|
|
|
12
|
return ('PARSER', 'parser_select'); |
306
|
|
|
|
|
|
|
} |
307
|
|
|
|
|
|
|
|
308
|
19457
|
100
|
|
|
|
46153
|
if ($event->isa('Test2::Event::Subtest')) { |
309
|
2061
|
100
|
|
|
|
4637
|
return ("FAILED", 'failed') if $event->causes_fail; |
310
|
|
|
|
|
|
|
|
311
|
2057
|
|
100
|
|
|
8820
|
my $n = $event->nested || 0; |
312
|
2057
|
100
|
100
|
|
|
16429
|
return unless $self->{+VERBOSE} || $n < 0; |
313
|
|
|
|
|
|
|
|
314
|
18
|
|
|
|
|
19
|
my ($plan) = (grep { $_->isa('Test2::Event::Plan') } @{$event->subevents})[0]; |
|
34
|
|
|
|
|
99
|
|
|
18
|
|
|
|
|
29
|
|
315
|
18
|
100
|
66
|
|
|
57
|
if ($plan && $plan->directive && $plan->directive eq 'SKIP') { |
|
|
|
66
|
|
|
|
|
316
|
4
|
|
|
|
|
60
|
return ("SKIP!!", 'skipall'); |
317
|
|
|
|
|
|
|
} |
318
|
|
|
|
|
|
|
|
319
|
14
|
|
|
|
|
85
|
return ("PASSED", 'passed'); |
320
|
|
|
|
|
|
|
} |
321
|
|
|
|
|
|
|
|
322
|
17396
|
100
|
|
|
|
39618
|
if ($event->isa('Test2::Event::ProcessFinish')) { |
323
|
1202
|
50
|
|
|
|
4322
|
return ("PASSED", 'passed') if $event->result->passed; |
324
|
0
|
|
|
|
|
0
|
return ("FAILED", 'failed'); |
325
|
|
|
|
|
|
|
} |
326
|
|
|
|
|
|
|
|
327
|
16194
|
100
|
|
|
|
32580
|
if ($event->isa('Test2::Event::Plan')) { |
328
|
2650
|
100
|
|
|
|
5909
|
return unless $self->{+VERBOSE}; |
329
|
10
|
|
|
|
|
22
|
return (" PLAN ", 'plan'); |
330
|
|
|
|
|
|
|
} |
331
|
|
|
|
|
|
|
|
332
|
13544
|
100
|
|
|
|
27607
|
if ($event->isa('Test2::Event::Encoding')) { |
333
|
325
|
100
|
|
|
|
1319
|
return unless $self->{+VERBOSE}; |
334
|
2
|
|
|
|
|
15
|
return ('ENCODE', 'encoding'); |
335
|
|
|
|
|
|
|
} |
336
|
|
|
|
|
|
|
|
337
|
13219
|
100
|
100
|
|
|
70601
|
if ($event->isa('Test2::Event::UnknownStdout') || $event->isa('Test2::Event::UnknownStderr')) { |
338
|
8
|
50
|
|
|
|
20
|
return unless defined $event->output; |
339
|
|
|
|
|
|
|
|
340
|
8
|
100
|
|
|
|
57
|
return ("STDERR", 'stderr') if $event->isa('Test2::Event::UnknownStderr'); |
341
|
4
|
50
|
|
|
|
13
|
return (" DIAG ", 'diag') if $event->diagnostics; |
342
|
|
|
|
|
|
|
|
343
|
4
|
100
|
|
|
|
23
|
return unless $self->{+VERBOSE}; |
344
|
2
|
|
|
|
|
16
|
return ("STDOUT", 'stdout'); |
345
|
|
|
|
|
|
|
} |
346
|
|
|
|
|
|
|
|
347
|
13211
|
100
|
100
|
|
|
66907
|
if ($event->isa('Test2::Event::UnexpectedProcessExit') || $event->isa('Test2::Event::TimeoutReset')) { |
348
|
132
|
|
|
|
|
792
|
return ("PARSER", 'parser'); |
349
|
|
|
|
|
|
|
} |
350
|
|
|
|
|
|
|
|
351
|
13079
|
100
|
|
|
|
22372
|
if ($event->increments_count) { |
352
|
12349
|
100
|
|
|
|
37214
|
if ($self->{+VERBOSE}) { |
353
|
24
|
100
|
66
|
|
|
75
|
return (" OK ", 'skip') if $event->can('reason') && defined $event->reason; |
354
|
22
|
100
|
100
|
|
|
104
|
return ("NOT OK", 'todo') if $event->can('todo') && defined $event->todo; |
355
|
|
|
|
|
|
|
# The event is a failure but something overrode that - this would |
356
|
|
|
|
|
|
|
# be a failure inside a subtest marked as todo. |
357
|
20
|
50
|
66
|
|
|
111
|
return ("NOT OK", 'todo') if !$event->pass && $event->effective_pass; |
358
|
20
|
100
|
|
|
|
674
|
return (" OK ", 'pass') unless $event->causes_fail; |
359
|
|
|
|
|
|
|
} |
360
|
|
|
|
|
|
|
|
361
|
12329
|
100
|
|
|
|
17004
|
return ("NOT OK", 'fail') if $event->causes_fail; |
362
|
12321
|
|
|
|
|
38386
|
return; |
363
|
|
|
|
|
|
|
} |
364
|
|
|
|
|
|
|
|
365
|
730
|
100
|
|
|
|
3737
|
if ($event->can('message')) { |
366
|
710
|
100
|
|
|
|
1544
|
return (" DIAG ", 'diag') if $event->diagnostics; |
367
|
404
|
100
|
|
|
|
2109
|
return unless $self->{+VERBOSE}; |
368
|
2
|
|
|
|
|
12
|
return (" NOTE ", 'note'); |
369
|
|
|
|
|
|
|
} |
370
|
|
|
|
|
|
|
|
371
|
20
|
100
|
100
|
|
|
99
|
return unless $self->{+VERBOSE} || $event->diagnostics; |
372
|
14
|
100
|
|
|
|
62
|
return ("PARSER", 'parser') if $event->isa('Test2::Event::ParseError'); |
373
|
|
|
|
|
|
|
|
374
|
10
|
100
|
66
|
|
|
23
|
return unless defined $event->summary && $event->summary =~ /\S/; |
375
|
|
|
|
|
|
|
|
376
|
8
|
|
|
|
|
101
|
return (" ???? ", 'unknown'); |
377
|
|
|
|
|
|
|
} |
378
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
sub tag { |
380
|
19751
|
|
|
19751
|
|
25604
|
my $self = shift; |
381
|
19751
|
|
|
|
|
13846
|
my ($event) = @_; |
382
|
|
|
|
|
|
|
|
383
|
19751
|
|
|
|
|
21852
|
my ($val, $color) = $self->_tag($event); |
384
|
|
|
|
|
|
|
|
385
|
19751
|
100
|
|
|
|
74968
|
return unless $val; |
386
|
|
|
|
|
|
|
return ( |
387
|
1439
|
|
|
|
|
9739
|
['tag', '['], |
388
|
|
|
|
|
|
|
[$color, $val], |
389
|
|
|
|
|
|
|
['tag', ']'], |
390
|
|
|
|
|
|
|
); |
391
|
|
|
|
|
|
|
} |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
sub tree { |
394
|
3486
|
|
|
3486
|
|
5270
|
my $self = shift; |
395
|
3486
|
|
|
|
|
4016
|
my ($j, $event) = @_; |
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
# Get mark |
398
|
3486
|
|
|
|
|
4116
|
my $mark = '+'; |
399
|
3486
|
100
|
|
|
|
6294
|
if (!$event) { |
400
|
2
|
|
|
|
|
5
|
$mark = '|'; |
401
|
|
|
|
|
|
|
} |
402
|
|
|
|
|
|
|
else { |
403
|
3484
|
|
100
|
|
|
7958
|
my $n = $event->nested || 0; |
404
|
3484
|
100
|
|
|
|
19746
|
$mark = '_' if $event->isa('Test2::Event::ProcessStart'); |
405
|
3484
|
100
|
100
|
|
|
11426
|
$mark = '=' if $event->isa('Test2::Event::Subtest') && $n < 0; |
406
|
3484
|
100
|
|
|
|
9415
|
$mark = '=' if $event->isa('Test2::Event::ProcessFinish'); |
407
|
|
|
|
|
|
|
} |
408
|
|
|
|
|
|
|
|
409
|
3486
|
|
|
|
|
4677
|
my $jobs = $self->{+JOBS}; |
410
|
3486
|
|
|
|
|
3827
|
my $slots = $self->{+SLOTS}; |
411
|
|
|
|
|
|
|
|
412
|
3486
|
|
|
|
|
3660
|
my @marks; |
413
|
3486
|
|
|
|
|
7196
|
for my $s (@$slots) { |
414
|
3504
|
100
|
|
|
|
6301
|
if (!defined($s)) { |
415
|
12
|
|
|
|
|
16
|
push @marks => (' ', ' '); |
416
|
12
|
|
|
|
|
15
|
next; |
417
|
|
|
|
|
|
|
} |
418
|
|
|
|
|
|
|
|
419
|
3492
|
100
|
100
|
|
|
8328
|
unless ($jobs->{$s}->{counter} > 1 || $j == $s) { |
420
|
10
|
|
|
|
|
17
|
push @marks => ([$s, ':'], ' '); |
421
|
10
|
|
|
|
|
9
|
next; |
422
|
|
|
|
|
|
|
} |
423
|
|
|
|
|
|
|
|
424
|
3482
|
100
|
100
|
|
|
15109
|
if ($s == $j && $mark ne '|') { |
425
|
3466
|
100
|
|
|
|
11838
|
push @marks => ([$mark eq '+' ? $s : 'mark', $mark], ' '); |
426
|
|
|
|
|
|
|
} |
427
|
|
|
|
|
|
|
else { |
428
|
16
|
|
|
|
|
32
|
push @marks => ([$s, '|'], ' '); |
429
|
|
|
|
|
|
|
} |
430
|
|
|
|
|
|
|
} |
431
|
3486
|
|
|
|
|
3862
|
pop @marks; |
432
|
3486
|
|
|
|
|
7311
|
return @marks; |
433
|
|
|
|
|
|
|
} |
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
sub painted_length { |
436
|
1441
|
|
|
1441
|
0
|
5066
|
my $self = shift; |
437
|
1441
|
100
|
|
|
|
2378
|
my $str = join '' => map { ref($_) ? $_->[1] : $_ } @_; |
|
8608
|
|
|
|
|
15136
|
|
438
|
1441
|
|
|
|
|
3086
|
return length($str); |
439
|
|
|
|
|
|
|
} |
440
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
sub event_summary { |
442
|
1439
|
|
|
1439
|
|
1745
|
my $self = shift; |
443
|
1439
|
|
|
|
|
1469
|
my ($event, $start) = @_; |
444
|
|
|
|
|
|
|
|
445
|
1439
|
|
|
|
|
2269
|
my ($val, $color) = $self->_tag($event); |
446
|
|
|
|
|
|
|
|
447
|
1439
|
|
|
|
|
6707
|
my $summary = $event->summary; |
448
|
|
|
|
|
|
|
|
449
|
1439
|
|
|
|
|
6084
|
$summary =~ s/^[\n\r]+//g; |
450
|
1439
|
50
|
|
|
|
6505
|
my @lines = grep {defined $_ && length $_} split /[\n\r]+/, $summary; |
|
3279
|
|
|
|
|
10981
|
|
451
|
1439
|
50
|
|
|
|
3260
|
@lines = ('') unless @lines; |
452
|
|
|
|
|
|
|
|
453
|
1439
|
|
|
|
|
4581
|
my $len = $self->painted_length(@$start) + 1; |
454
|
1439
|
|
|
|
|
6254
|
my $term_size = term_size(); |
455
|
|
|
|
|
|
|
|
456
|
1439
|
|
|
|
|
6412
|
my @blob; |
457
|
1439
|
100
|
|
|
|
2145
|
if (grep { $term_size <= $len + length($_) } @lines) { |
|
3279
|
|
|
|
|
6103
|
|
458
|
51
|
|
|
|
|
196
|
@lines = ( ['blob', '----- START -----'] ); |
459
|
51
|
|
|
|
|
231
|
@blob = ( |
460
|
|
|
|
|
|
|
[$color, $summary], |
461
|
|
|
|
|
|
|
"\n", |
462
|
|
|
|
|
|
|
@$start, |
463
|
|
|
|
|
|
|
['blob', '------ END ------'], |
464
|
|
|
|
|
|
|
"\n", |
465
|
|
|
|
|
|
|
); |
466
|
|
|
|
|
|
|
} |
467
|
|
|
|
|
|
|
else { |
468
|
1388
|
|
|
|
|
1518
|
@lines = map { [$color, $_] } @lines; |
|
3228
|
|
|
|
|
5568
|
|
469
|
|
|
|
|
|
|
} |
470
|
|
|
|
|
|
|
|
471
|
1439
|
|
|
|
|
4341
|
return (\@lines, \@blob); |
472
|
|
|
|
|
|
|
} |
473
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
sub render { |
475
|
19749
|
|
|
19749
|
|
17643
|
my $self = shift; |
476
|
19749
|
|
|
|
|
20647
|
my ($j, $event, @nest) = @_; |
477
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
# If there is no tag then we do not render it. |
479
|
19749
|
100
|
|
|
|
25182
|
my @tag = $self->tag($event) or return; |
480
|
1437
|
|
|
|
|
3411
|
my @tree = $self->tree($j, $event); |
481
|
1437
|
|
|
|
|
5175
|
my @start = (@tag, ' ', @tree, ' ', @nest); |
482
|
|
|
|
|
|
|
|
483
|
1437
|
|
|
|
|
4060
|
my ($summary, $blob) = $self->event_summary($event, \@start); |
484
|
|
|
|
|
|
|
|
485
|
1437
|
|
|
|
|
1663
|
my @out; |
486
|
1437
|
|
|
|
|
7962
|
push @out => (@start, $_, "\n") for @$summary; |
487
|
1437
|
100
|
|
|
|
6342
|
push @out => @$blob if @$blob; |
488
|
|
|
|
|
|
|
|
489
|
1437
|
|
|
|
|
10057
|
return @out; |
490
|
|
|
|
|
|
|
} |
491
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
sub render_orphan { |
493
|
6
|
|
|
6
|
0
|
1781
|
my $self = shift; |
494
|
6
|
|
|
|
|
8
|
my ($j, $event) = @_; |
495
|
|
|
|
|
|
|
|
496
|
|
|
|
|
|
|
# If there is no tag then we do not render it. |
497
|
6
|
100
|
|
|
|
14
|
my @tag = $self->tag($event) or return; |
498
|
4
|
|
|
|
|
19
|
my @tree = $self->tree($j, $event); |
499
|
4
|
|
|
|
|
26
|
my @start = (@tag, ' ', @tree, ' ', [$j, ("> " x $event->nested)]); |
500
|
|
|
|
|
|
|
|
501
|
4
|
|
|
|
|
198
|
my ($summary, $blob) = $self->event_summary($event, \@start); |
502
|
|
|
|
|
|
|
|
503
|
4
|
|
|
|
|
10
|
my @out; |
504
|
4
|
|
|
|
|
15
|
push @out => (@start, $_, "\n") for @$summary; |
505
|
4
|
100
|
|
|
|
11
|
push @out => @$blob if @$blob; |
506
|
|
|
|
|
|
|
|
507
|
4
|
|
|
|
|
28
|
return @out; |
508
|
|
|
|
|
|
|
} |
509
|
|
|
|
|
|
|
|
510
|
|
|
|
|
|
|
sub preview { |
511
|
6
|
|
|
6
|
0
|
1806
|
my $self = shift; |
512
|
6
|
|
|
|
|
8
|
my ($j, $event) = @_; |
513
|
|
|
|
|
|
|
|
514
|
|
|
|
|
|
|
# If there is no tag then we do not render it. |
515
|
6
|
100
|
|
|
|
15
|
my @tag = $self->tag($event) or return; |
516
|
4
|
|
|
|
|
23
|
my @tree = $self->tree($j, $event); |
517
|
4
|
|
|
|
|
29
|
my @start = (@tag, ' ', @tree, ' ', [$j, ("> " x $event->nested)]); |
518
|
|
|
|
|
|
|
|
519
|
4
|
|
|
|
|
200
|
my ($summary) = $self->event_summary($event, \@start); |
520
|
|
|
|
|
|
|
|
521
|
4
|
|
|
|
|
23
|
$self->{+CLEAR} = 2; |
522
|
4
|
|
|
|
|
37
|
return (@start, $summary->[-1], "\r"); |
523
|
|
|
|
|
|
|
} |
524
|
|
|
|
|
|
|
|
525
|
|
|
|
|
|
|
sub render_subtest { |
526
|
1988
|
|
|
1988
|
0
|
2213
|
my $self = shift; |
527
|
1988
|
|
|
|
|
2434
|
my ($j, $event) = @_; |
528
|
|
|
|
|
|
|
|
529
|
1988
|
|
|
|
|
3874
|
my @out = $self->render($j, $event); |
530
|
|
|
|
|
|
|
|
531
|
1988
|
|
|
|
|
1920
|
my @todo = @{$event->subevents}; |
|
1988
|
|
|
|
|
4425
|
|
532
|
1988
|
|
|
|
|
7671
|
my @stack = ($event); |
533
|
|
|
|
|
|
|
|
534
|
1988
|
|
|
|
|
5133
|
while (my $e = shift @todo) { |
535
|
14199
|
|
|
|
|
10384
|
my $nest = ""; |
536
|
|
|
|
|
|
|
|
537
|
14199
|
100
|
|
|
|
20743
|
if ($e->subtest_id) { |
538
|
53
|
|
|
|
|
289
|
unshift @todo => @{$e->subevents}; |
|
53
|
|
|
|
|
268
|
|
539
|
53
|
|
|
|
|
252
|
push @stack => $e; |
540
|
|
|
|
|
|
|
|
541
|
53
|
|
|
|
|
195
|
$nest = '| ' x ($e->nested - 1); |
542
|
53
|
|
|
|
|
331
|
$nest .= "+-"; |
543
|
|
|
|
|
|
|
} |
544
|
|
|
|
|
|
|
else { |
545
|
14146
|
|
|
|
|
39878
|
$nest = '| ' x $e->nested; |
546
|
|
|
|
|
|
|
} |
547
|
|
|
|
|
|
|
|
548
|
14199
|
100
|
50
|
|
|
52749
|
if (!@todo || (($todo[0]->in_subtest || '') ne ($e->in_subtest || '') && !$e->subtest_id)) { |
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
66
|
|
|
|
|
549
|
2041
|
|
|
|
|
4790
|
push @out => $self->render($j, $e, [$j, $nest]); |
550
|
|
|
|
|
|
|
|
551
|
2041
|
|
|
|
|
4435
|
my @tree = $self->tree($j, $e); |
552
|
|
|
|
|
|
|
|
553
|
2041
|
50
|
|
|
|
4156
|
if (my $st = pop @stack) { |
554
|
|
|
|
|
|
|
push @out => ( |
555
|
|
|
|
|
|
|
['tag', '['], ['fail', ' PLAN '], ['tag', ']'], |
556
|
|
|
|
|
|
|
' ', @tree, ' ', |
557
|
|
|
|
|
|
|
[$j, $nest], |
558
|
|
|
|
|
|
|
['fail', $_], |
559
|
|
|
|
|
|
|
"\n", |
560
|
2041
|
|
100
|
|
|
4167
|
) for $self->_plan_errors($st->subevents, ($st->nested || 0) + 1); |
561
|
|
|
|
|
|
|
} |
562
|
|
|
|
|
|
|
|
563
|
2041
|
50
|
66
|
|
|
8199
|
if (@out && $self->{+VERBOSE}) { |
564
|
4
|
|
|
|
|
7
|
my $n2 = '| ' x ($e->nested - 1); |
565
|
4
|
|
|
|
|
30
|
push @out => ( |
566
|
|
|
|
|
|
|
" ", @tree, " ", |
567
|
|
|
|
|
|
|
[$j, "$n2^"], |
568
|
|
|
|
|
|
|
"\n", |
569
|
|
|
|
|
|
|
); |
570
|
|
|
|
|
|
|
} |
571
|
|
|
|
|
|
|
} |
572
|
|
|
|
|
|
|
else { |
573
|
12158
|
|
|
|
|
86788
|
push @out => $self->render($j, $e, [$j, $nest]); |
574
|
|
|
|
|
|
|
} |
575
|
|
|
|
|
|
|
} |
576
|
|
|
|
|
|
|
|
577
|
1988
|
|
|
|
|
6653
|
return @out; |
578
|
|
|
|
|
|
|
} |
579
|
|
|
|
|
|
|
|
580
|
|
|
|
|
|
|
sub _plan_errors { |
581
|
2642
|
|
|
2642
|
|
17897
|
my $self = shift; |
582
|
2642
|
|
|
|
|
2615
|
my $events = shift; |
583
|
2642
|
|
|
|
|
1730
|
my $nested = shift; |
584
|
|
|
|
|
|
|
|
585
|
2642
|
|
|
|
|
2160
|
my @errors; |
586
|
|
|
|
|
|
|
|
587
|
2642
|
50
|
66
|
|
|
5680
|
unless ($nested || grep { $_->isa('Test2::Event::ProcessStart') } @{$events}) { |
|
19128
|
|
|
|
|
44604
|
|
|
601
|
|
|
|
|
1617
|
|
588
|
0
|
|
|
|
|
0
|
push @errors => 'No process start event was seen!'; |
589
|
0
|
|
|
|
|
0
|
return; |
590
|
|
|
|
|
|
|
} |
591
|
|
|
|
|
|
|
|
592
|
2642
|
100
|
100
|
|
|
2299
|
my @plans = grep { ($_->nested || 0) == $nested && $_->isa('Test2::Event::Plan') } @{$events}; |
|
33327
|
|
|
|
|
164642
|
|
|
2642
|
|
|
|
|
3327
|
|
593
|
|
|
|
|
|
|
|
594
|
2642
|
50
|
|
|
|
18444
|
unless (@plans) { |
595
|
0
|
|
|
|
|
0
|
push @errors => 'No plan was ever set.'; |
596
|
0
|
|
|
|
|
0
|
return; |
597
|
|
|
|
|
|
|
} |
598
|
|
|
|
|
|
|
|
599
|
2642
|
50
|
|
|
|
4873
|
push @errors => 'Multiple plans were set.' |
600
|
|
|
|
|
|
|
if @plans > 1; |
601
|
|
|
|
|
|
|
|
602
|
2642
|
100
|
66
|
|
|
12601
|
push @errors => 'Plan must come before or after all testing, not in the middle.' |
603
|
|
|
|
|
|
|
unless $plans[0] == $events->[0] || $plans[0] == $events->[-1]; |
604
|
|
|
|
|
|
|
|
605
|
2642
|
|
|
|
|
7484
|
my $max = ($plans[0]->sets_plan)[0]; |
606
|
|
|
|
|
|
|
|
607
|
2642
|
100
|
100
|
|
|
11028
|
my $total = grep { ($_->nested || 0) == $nested && $_->increments_count } @{$events}; |
|
33327
|
|
|
|
|
164472
|
|
|
2642
|
|
|
|
|
3592
|
|
608
|
2642
|
50
|
|
|
|
27752
|
return if $max == $total; |
609
|
0
|
|
|
|
|
|
push @errors => "Planned to run $max test(s) but ran $total."; |
610
|
|
|
|
|
|
|
|
611
|
0
|
|
|
|
|
|
return @errors; |
612
|
|
|
|
|
|
|
} |
613
|
|
|
|
|
|
|
|
614
|
|
|
|
|
|
|
1; |
615
|
|
|
|
|
|
|
|
616
|
|
|
|
|
|
|
__END__ |