line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Fennec; |
2
|
137
|
|
|
137
|
|
81321
|
use strict; |
|
137
|
|
|
|
|
966
|
|
|
137
|
|
|
|
|
3531
|
|
3
|
137
|
|
|
137
|
|
842
|
use warnings; |
|
137
|
|
|
|
|
483
|
|
|
137
|
|
|
|
|
3886
|
|
4
|
|
|
|
|
|
|
|
5
|
137
|
|
|
137
|
|
29113
|
BEGIN { require Fennec::Runner } |
6
|
|
|
|
|
|
|
|
7
|
137
|
|
|
137
|
|
50978
|
use Fennec::Test; |
|
137
|
|
|
|
|
347
|
|
|
137
|
|
|
|
|
5731
|
|
8
|
137
|
|
|
137
|
|
844
|
use Fennec::Util qw/inject_sub require_module verbose_message/; |
|
137
|
|
|
|
|
247
|
|
|
137
|
|
|
|
|
2736
|
|
9
|
137
|
|
|
137
|
|
94454
|
use Carp qw/croak carp/; |
|
137
|
|
|
|
|
244
|
|
|
137
|
|
|
|
|
25630
|
|
10
|
|
|
|
|
|
|
our $VERSION = '2.018'; |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
sub defaults { |
13
|
|
|
|
|
|
|
( |
14
|
|
|
|
|
|
|
utils => [ |
15
|
|
|
|
|
|
|
'Test::More', |
16
|
|
|
|
|
|
|
'Test::Warn', |
17
|
|
|
|
|
|
|
'Test::Exception', |
18
|
|
|
|
|
|
|
'Test::Workflow', |
19
|
|
|
|
|
|
|
'Mock::Quick', |
20
|
|
|
|
|
|
|
'Child', |
21
|
|
|
|
|
|
|
], |
22
|
|
|
|
|
|
|
parallel => defined $ENV{'FENNEC_PARALLEL'} ? $ENV{'FENNEC_PARALLEL'} : 3, |
23
|
|
|
|
|
|
|
runner_class => 'Fennec::Runner', |
24
|
|
|
|
|
|
|
with_tests => [], |
25
|
|
|
|
|
|
|
Child => ['child'], |
26
|
274
|
50
|
50
|
274
|
0
|
5178
|
debug => $ENV{'FENNEC_DEBUG'} || 0, |
27
|
|
|
|
|
|
|
); |
28
|
|
|
|
|
|
|
} |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
sub _setup_class { |
31
|
137
|
|
|
137
|
|
334
|
my $class = shift; |
32
|
137
|
|
|
|
|
512
|
my ( $runner, $importer, $load ) = @_; |
33
|
137
|
100
|
|
|
|
534
|
return unless $load; |
34
|
|
|
|
|
|
|
|
35
|
2
|
|
|
|
|
6
|
require_module $load; |
36
|
|
|
|
|
|
|
|
37
|
137
|
|
|
137
|
|
928
|
no strict 'refs'; |
|
137
|
|
|
|
|
349
|
|
|
137
|
|
|
|
|
45543
|
|
38
|
2
|
|
|
|
|
9380
|
*{"$importer\::CLASS"} = \$load; |
|
2
|
|
|
|
|
10
|
|
39
|
2
|
|
|
1
|
|
8
|
*{"$importer\::class"} = sub { $load }; |
|
2
|
|
|
|
|
8
|
|
|
1
|
|
|
|
|
37
|
|
40
|
|
|
|
|
|
|
} |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
sub import { |
43
|
137
|
|
|
137
|
|
80648
|
my $class = shift; |
44
|
137
|
|
|
|
|
389
|
my $importer = caller; |
45
|
|
|
|
|
|
|
|
46
|
137
|
|
|
|
|
383
|
my %defaults = $class->defaults; |
47
|
137
|
|
50
|
|
|
838
|
$defaults{runner_class} ||= 'Fennec::Runner'; |
48
|
137
|
|
|
|
|
611
|
my %params = ( %defaults, @_ ); |
49
|
|
|
|
|
|
|
|
50
|
137
|
50
|
0
|
|
|
572
|
$ENV{FENNEC_SEED} ||= $params{seed} if $params{seed}; |
51
|
137
|
50
|
0
|
|
|
539
|
$ENV{FENNEC_DEBUG} ||= $params{debug} if $params{debug}; |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
my ( $runner, $runner_init ) = $class->_get_runner( |
54
|
|
|
|
|
|
|
$importer, |
55
|
|
|
|
|
|
|
$defaults{runner_class}, |
56
|
|
|
|
|
|
|
$defaults{runner_params}, |
57
|
137
|
|
|
|
|
993
|
); |
58
|
|
|
|
|
|
|
|
59
|
137
|
|
|
|
|
1011
|
verbose_message("Entering build stage: $importer\n"); |
60
|
|
|
|
|
|
|
|
61
|
137
|
|
|
|
|
264
|
push @{$runner->test_classes} => $importer; |
|
137
|
|
|
|
|
1262
|
|
62
|
|
|
|
|
|
|
|
63
|
137
|
|
|
|
|
1192
|
my $meta = $class->_init_meta( $importer, %params ); |
64
|
|
|
|
|
|
|
|
65
|
137
|
|
|
|
|
842
|
$class->_setup_class( $runner, $importer, $params{class} ); |
66
|
137
|
|
|
|
|
653
|
$class->_process_deps( $runner, $params{skip_without} ); |
67
|
135
|
|
|
|
|
520
|
$class->_set_isa( $importer, 'Fennec::Test', $meta->base ); |
68
|
135
|
|
|
|
|
5018
|
$class->_load_utils( $importer, %params ); |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
# Intercept Mock::Quick mocks |
71
|
135
|
|
|
|
|
789
|
my $wfmeta = $importer->TEST_WORKFLOW; |
72
|
135
|
50
|
33
|
|
|
1037
|
if ( $wfmeta && grep { $_ eq 'Mock::Quick' } @{$defaults{utils} || []}) { |
|
813
|
50
|
|
|
|
1670
|
|
|
135
|
|
|
|
|
701
|
|
73
|
|
|
|
|
|
|
my $intercept = sub { |
74
|
24
|
|
|
24
|
|
68
|
my ($code) = @_; |
75
|
24
|
|
|
|
|
91
|
my @caller = caller; |
76
|
|
|
|
|
|
|
|
77
|
24
|
|
|
|
|
304
|
my $store = $wfmeta->control_store; |
78
|
24
|
100
|
|
|
|
165
|
return push @$store => $code->() if $store; |
79
|
|
|
|
|
|
|
|
80
|
10
|
|
33
|
|
|
60
|
my $layer = $wfmeta->peek_layer || $wfmeta->root_layer; |
81
|
10
|
|
|
|
|
40
|
$layer->add_control($code); |
82
|
135
|
|
|
|
|
798
|
}; |
83
|
137
|
|
|
137
|
|
1060
|
no strict 'refs'; |
|
137
|
|
|
|
|
369
|
|
|
137
|
|
|
|
|
27204
|
|
84
|
135
|
|
|
24
|
|
535
|
*{"$importer\::QINTERCEPT"} = sub{ $intercept }; |
|
135
|
|
|
|
|
691
|
|
|
24
|
|
|
|
|
2190
|
|
85
|
|
|
|
|
|
|
} |
86
|
|
|
|
|
|
|
|
87
|
135
|
|
|
|
|
1103
|
$class->_with_tests( $importer, $params{with_tests} ); |
88
|
135
|
|
|
|
|
977
|
$class->init( %params, importer => $importer, meta => $meta ); |
89
|
|
|
|
|
|
|
|
90
|
135
|
50
|
33
|
|
|
951
|
if ($ENV{FENNEC_DEBUG} || $params{debug}) { |
91
|
0
|
|
|
|
|
0
|
require Time::HiRes; |
92
|
0
|
|
|
|
|
0
|
my $collector; |
93
|
|
|
|
|
|
|
my $debug = sub { |
94
|
0
|
|
|
0
|
|
0
|
my $msg = pop; |
95
|
|
|
|
|
|
|
|
96
|
0
|
|
|
|
|
0
|
my ($sec, $ms) = Time::HiRes::gettimeofday(); |
97
|
0
|
|
|
|
|
0
|
my $line = sprintf( |
98
|
|
|
|
|
|
|
"FENNEC_DEBUG_CUSTOM:PID:%d\0SEC:%d\0MSEC:%d\0MESSAGE:%s\n", |
99
|
|
|
|
|
|
|
$$, |
100
|
|
|
|
|
|
|
$sec, |
101
|
|
|
|
|
|
|
$ms, |
102
|
|
|
|
|
|
|
$msg |
103
|
|
|
|
|
|
|
); |
104
|
0
|
|
0
|
|
|
0
|
$collector ||= Fennec::Runner->new->collector; |
105
|
0
|
|
|
|
|
0
|
$collector->diag($line); |
106
|
0
|
|
|
|
|
0
|
}; |
107
|
137
|
|
|
137
|
|
1232
|
no strict 'refs'; |
|
137
|
|
|
|
|
532
|
|
|
137
|
|
|
|
|
24967
|
|
108
|
0
|
|
|
|
|
0
|
*{"$importer\::fennec_debug"} = $debug; |
|
0
|
|
|
|
|
0
|
|
109
|
|
|
|
|
|
|
} |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
$class->_export_done_testing( |
112
|
135
|
|
|
|
|
724
|
$importer, |
113
|
|
|
|
|
|
|
$runner, |
114
|
|
|
|
|
|
|
$runner_init, |
115
|
|
|
|
|
|
|
); |
116
|
|
|
|
|
|
|
|
117
|
135
|
100
|
33
|
|
|
1264
|
$class->after_import({ |
118
|
|
|
|
|
|
|
importer => $importer, |
119
|
|
|
|
|
|
|
runner => $runner, |
120
|
|
|
|
|
|
|
meta => $meta, |
121
|
|
|
|
|
|
|
wf_meta => $wfmeta, |
122
|
|
|
|
|
|
|
layer => $wfmeta->peek_layer || $wfmeta->root_layer, |
123
|
|
|
|
|
|
|
}) if $class->can('after_import'); |
124
|
|
|
|
|
|
|
|
125
|
135
|
|
|
|
|
1115
|
verbose_message("Entering primary stage: $importer\n"); |
126
|
|
|
|
|
|
|
} |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
sub init { |
129
|
135
|
|
|
135
|
0
|
299
|
my $class = shift; |
130
|
135
|
|
|
|
|
784
|
my %params = @_; |
131
|
135
|
|
|
|
|
332
|
my $importer = $params{importer}; |
132
|
135
|
|
|
|
|
288
|
my $meta = $params{meta}; |
133
|
|
|
|
|
|
|
|
134
|
135
|
|
|
|
|
446
|
my $wfmeta = $importer->TEST_WORKFLOW; |
135
|
135
|
100
|
|
|
|
629
|
$wfmeta->test_sort( $meta->test_sort ) |
136
|
|
|
|
|
|
|
if $meta->test_sort; |
137
|
|
|
|
|
|
|
|
138
|
137
|
|
|
137
|
|
866
|
no strict 'refs'; |
|
137
|
|
|
|
|
229
|
|
|
137
|
|
|
|
|
59769
|
|
139
|
135
|
|
|
|
|
280
|
my $stash = \%{"$importer\::"}; |
|
135
|
|
|
|
|
533
|
|
140
|
135
|
|
|
|
|
1018
|
delete $stash->{$_} for qw/run_tests done_testing/; |
141
|
|
|
|
|
|
|
} |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
sub _get_runner { |
144
|
137
|
|
|
137
|
|
273
|
my $class = shift; |
145
|
137
|
|
|
|
|
711
|
my ( $importer, $runner_class, $runner_params ) = @_; |
146
|
|
|
|
|
|
|
|
147
|
137
|
|
|
|
|
662
|
require_module $runner_class; |
148
|
137
|
|
|
|
|
738
|
my $runner_init = $runner_class->is_initialized; |
149
|
|
|
|
|
|
|
|
150
|
137
|
50
|
66
|
|
|
1101
|
croak "Fennec cannot be used in package 'main' when the test is used with Fennec::Finder" |
151
|
|
|
|
|
|
|
if $runner_init && $importer eq 'main'; |
152
|
|
|
|
|
|
|
|
153
|
137
|
100
|
|
|
|
494
|
if ($runner_init) { |
154
|
48
|
|
|
|
|
624
|
my $runner = $runner_class->new; |
155
|
48
|
50
|
|
|
|
794
|
carp "Runner is already initialized, but it is not a $runner_class" |
156
|
|
|
|
|
|
|
unless $runner->isa($runner_class); |
157
|
|
|
|
|
|
|
|
158
|
48
|
50
|
|
|
|
863
|
carp "Runner is already initialized, ignoring 'runner_params'" |
159
|
|
|
|
|
|
|
if $runner_params; |
160
|
|
|
|
|
|
|
|
161
|
48
|
|
|
|
|
221
|
return ( $runner, $runner_init ); |
162
|
|
|
|
|
|
|
} |
163
|
|
|
|
|
|
|
|
164
|
89
|
50
|
|
|
|
301
|
my $runner = $runner_class->new( |
165
|
|
|
|
|
|
|
parallel => 0, |
166
|
|
|
|
|
|
|
$runner_params ? (%$runner_params) : (), |
167
|
|
|
|
|
|
|
); |
168
|
|
|
|
|
|
|
|
169
|
89
|
|
|
|
|
32798
|
require Fennec::EndRunner; |
170
|
89
|
|
|
|
|
602
|
Fennec::EndRunner->set_pid($$); |
171
|
89
|
|
|
|
|
286
|
Fennec::EndRunner->set_runner($runner); |
172
|
|
|
|
|
|
|
|
173
|
89
|
|
|
|
|
322
|
return ( $runner, $runner_init ); |
174
|
|
|
|
|
|
|
} |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
sub _process_deps { |
177
|
137
|
|
|
137
|
|
252
|
my $class = shift; |
178
|
137
|
|
|
|
|
443
|
my ( $runner, $deps ) = @_; |
179
|
|
|
|
|
|
|
|
180
|
137
|
100
|
66
|
|
|
591
|
return unless $deps && @$deps; |
181
|
|
|
|
|
|
|
|
182
|
2
|
|
|
|
|
3
|
for my $require (@$deps) { |
183
|
2
|
50
|
|
|
|
2
|
unless ( eval { require_module $require; 1 } ) { |
|
2
|
|
|
|
|
7
|
|
|
0
|
|
|
|
|
0
|
|
184
|
2
|
|
|
|
|
13
|
$runner->_skip_all(1); |
185
|
2
|
|
|
|
|
5
|
$runner->collector->skip("'$require' is not installed"); |
186
|
2
|
|
|
|
|
6
|
$runner->collector->finish; |
187
|
2
|
|
|
|
|
654
|
exit 0; |
188
|
|
|
|
|
|
|
} |
189
|
|
|
|
|
|
|
} |
190
|
|
|
|
|
|
|
} |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
sub _init_meta { |
193
|
137
|
|
|
137
|
|
347
|
my $class = shift; |
194
|
137
|
|
|
|
|
709
|
my ( $importer, %params ) = @_; |
195
|
|
|
|
|
|
|
|
196
|
137
|
|
|
|
|
42741
|
require Fennec::Meta; |
197
|
|
|
|
|
|
|
|
198
|
137
|
|
|
|
|
1032
|
my $meta = Fennec::Meta->new( |
199
|
|
|
|
|
|
|
%params, |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
# Well, this is confusing. |
202
|
|
|
|
|
|
|
fennec => $class, |
203
|
|
|
|
|
|
|
class => $importer, |
204
|
|
|
|
|
|
|
); |
205
|
|
|
|
|
|
|
|
206
|
137
|
|
|
1503
|
|
1023
|
inject_sub( $importer, 'FENNEC', sub { $meta } ); |
|
1503
|
|
|
|
|
9728
|
|
207
|
|
|
|
|
|
|
|
208
|
137
|
|
|
|
|
495
|
return $meta; |
209
|
|
|
|
|
|
|
} |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
sub _set_isa { |
212
|
135
|
|
|
135
|
|
387
|
my $class = shift; |
213
|
135
|
|
|
|
|
418
|
my ( $importer, @bases ) = @_; |
214
|
|
|
|
|
|
|
|
215
|
135
|
|
|
|
|
381
|
for my $base (@bases) { |
216
|
270
|
100
|
|
|
|
926
|
next unless $base; |
217
|
137
|
|
|
137
|
|
852
|
no strict 'refs'; |
|
137
|
|
|
|
|
302
|
|
|
137
|
|
|
|
|
33600
|
|
218
|
135
|
|
|
|
|
599
|
require_module $base; |
219
|
135
|
|
|
|
|
1904
|
push @{"$importer\::ISA"} => $base |
220
|
135
|
50
|
|
|
|
400
|
unless grep { $_ eq $base } @{"$importer\::ISA"}; |
|
0
|
|
|
|
|
0
|
|
|
135
|
|
|
|
|
1228
|
|
221
|
|
|
|
|
|
|
} |
222
|
|
|
|
|
|
|
} |
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
sub _load_utils { |
225
|
135
|
|
|
135
|
|
2656
|
my $class = shift; |
226
|
135
|
|
|
|
|
873
|
my ( $importer, %params ) = @_; |
227
|
|
|
|
|
|
|
|
228
|
135
|
|
|
|
|
424
|
my $utils = $params{utils}; |
229
|
135
|
50
|
33
|
|
|
1156
|
return unless $utils && @$utils; |
230
|
|
|
|
|
|
|
|
231
|
135
|
|
|
|
|
358
|
for my $util (@$utils) { |
232
|
813
|
|
|
|
|
2960
|
require_module $util; |
233
|
813
|
|
100
|
|
|
2464102
|
my $args = $params{$util} || []; |
234
|
813
|
|
|
|
|
2446
|
my $code = "package $importer; $util\->import(\@\$args); 1"; |
235
|
813
|
50
|
|
|
|
46873
|
eval $code || die $@; |
236
|
|
|
|
|
|
|
} |
237
|
|
|
|
|
|
|
} |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
sub _with_tests { |
240
|
135
|
|
|
135
|
|
326
|
my $class = shift; |
241
|
135
|
|
|
|
|
406
|
my ( $importer, $classes ) = @_; |
242
|
|
|
|
|
|
|
|
243
|
135
|
100
|
66
|
|
|
828
|
return unless $classes && @$classes; |
244
|
|
|
|
|
|
|
|
245
|
2
|
|
|
|
|
7
|
$importer->TEST_WORKFLOW->root_layer->merge_in( undef, @$classes ); |
246
|
|
|
|
|
|
|
} |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
sub _export_done_testing { |
249
|
135
|
|
|
135
|
|
396
|
my $class = shift; |
250
|
135
|
|
|
|
|
382
|
my ( $importer, $runner, $runner_init ) = @_; |
251
|
|
|
|
|
|
|
|
252
|
135
|
100
|
|
|
|
549
|
if ($runner_init) { |
253
|
137
|
|
|
137
|
|
18350
|
no strict 'refs'; |
|
137
|
|
|
|
|
271
|
|
|
137
|
|
|
|
|
6871
|
|
254
|
137
|
|
|
137
|
|
835
|
no warnings 'redefine'; |
|
137
|
|
|
|
|
427
|
|
|
137
|
|
|
|
|
14414
|
|
255
|
47
|
|
|
|
|
325
|
*{"$importer\::done_testing"} = sub { |
256
|
47
|
100
|
|
47
|
|
505
|
$importer->FENNEC->post(@_) if @_; |
257
|
47
|
|
|
|
|
600
|
return 1; |
258
|
47
|
|
|
|
|
216
|
}; |
259
|
|
|
|
|
|
|
} |
260
|
|
|
|
|
|
|
else { |
261
|
137
|
|
|
137
|
|
901
|
no strict 'refs'; |
|
137
|
|
|
|
|
272
|
|
|
137
|
|
|
|
|
4681
|
|
262
|
137
|
|
|
137
|
|
725
|
no warnings 'redefine'; |
|
137
|
|
|
|
|
247
|
|
|
137
|
|
|
|
|
17019
|
|
263
|
88
|
|
|
|
|
195
|
my $has_run = 0; |
264
|
88
|
|
|
|
|
472
|
*{"$importer\::done_testing"} = sub { |
265
|
77
|
50
|
|
77
|
|
568
|
croak "done_testing() called more than once!" |
266
|
|
|
|
|
|
|
if $has_run++; |
267
|
|
|
|
|
|
|
|
268
|
77
|
|
|
|
|
604
|
Fennec::EndRunner->set_runner(undef); |
269
|
|
|
|
|
|
|
|
270
|
77
|
100
|
|
|
|
287
|
$importer->FENNEC->post(@_) if @_; |
271
|
77
|
|
|
|
|
453
|
$runner->run(); |
272
|
|
|
|
|
|
|
|
273
|
18
|
|
|
|
|
3012
|
1; |
274
|
88
|
|
|
|
|
408
|
}; |
275
|
|
|
|
|
|
|
} |
276
|
|
|
|
|
|
|
} |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
1; |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
__END__ |