line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Spreadsheet::Compare::Reporter::XLSX; |
2
|
|
|
|
|
|
|
|
3
|
2
|
|
|
2
|
|
2223
|
use Mojo::Base 'Spreadsheet::Compare::Reporter', -signatures; |
|
2
|
|
|
|
|
13
|
|
|
2
|
|
|
|
|
41
|
|
4
|
2
|
|
|
2
|
|
388
|
use Spreadsheet::Compare::Common; |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
9
|
|
5
|
|
|
|
|
|
|
|
6
|
2
|
|
|
2
|
|
3022
|
use Excel::Writer::XLSX; |
|
2
|
|
|
|
|
366598
|
|
|
2
|
|
|
|
|
4103
|
|
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
my %format_defaults = ( |
9
|
|
|
|
|
|
|
fmt_head => 'bold 1 align left', |
10
|
|
|
|
|
|
|
fmt_headerr => 'bold 1 align left bg_color yellow', |
11
|
|
|
|
|
|
|
fmt_default => 'color black', |
12
|
|
|
|
|
|
|
fmt_left_odd => 'color blue', |
13
|
|
|
|
|
|
|
fmt_right_odd => 'color red', |
14
|
|
|
|
|
|
|
fmt_diff_odd => 'color green', |
15
|
|
|
|
|
|
|
fmt_left_even => 'color blue bg_color silver', |
16
|
|
|
|
|
|
|
fmt_right_even => 'color red bg_color silver', |
17
|
|
|
|
|
|
|
fmt_diff_even => 'color green bg_color silver', |
18
|
|
|
|
|
|
|
fmt_left_high => 'color blue bg_color yellow', |
19
|
|
|
|
|
|
|
fmt_right_high => 'color red bg_color yellow', |
20
|
|
|
|
|
|
|
fmt_diff_high => 'color black bg_color yellow', |
21
|
|
|
|
|
|
|
fmt_left_low => 'color blue bg_color lime', |
22
|
|
|
|
|
|
|
fmt_right_low => 'color red bg_color lime', |
23
|
|
|
|
|
|
|
fmt_diff_low => 'color black bg_color lime', |
24
|
|
|
|
|
|
|
); |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
has $_, $format_defaults{$_} for keys %format_defaults; |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
has report_filename => sub { |
29
|
|
|
|
|
|
|
( my $title = $_[0]->test_title ) =~ s/[^\w-]/_/g; |
30
|
|
|
|
|
|
|
return "$title.xlsx"; |
31
|
|
|
|
|
|
|
}; |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
34
|
28
|
|
|
28
|
1
|
48
|
sub add_stream ( $self, $name ) { |
|
28
|
|
|
|
|
49
|
|
|
28
|
|
|
|
|
56
|
|
|
28
|
|
|
|
|
45
|
|
35
|
|
|
|
|
|
|
|
36
|
28
|
100
|
|
|
|
140
|
$self->_open_wkb() unless $self->{wbk}; |
37
|
|
|
|
|
|
|
|
38
|
28
|
|
|
|
|
149
|
$self->{ws}{$name} = $self->{wbk}->add_worksheet($name); |
39
|
28
|
|
|
|
|
9904
|
$self->{ws}{$name}->add_write_handler( qr[\d], \&_write_with_infinity ); |
40
|
28
|
|
|
|
|
381
|
$self->{row}{$name} = 0; |
41
|
|
|
|
|
|
|
|
42
|
28
|
|
|
|
|
107
|
return $self; |
43
|
|
|
|
|
|
|
} |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
|
46
|
28
|
|
|
28
|
1
|
65
|
sub write_header ( $self, $name ) { |
|
28
|
|
|
|
|
45
|
|
|
28
|
|
|
|
|
55
|
|
|
28
|
|
|
|
|
43
|
|
47
|
|
|
|
|
|
|
|
48
|
28
|
|
|
|
|
159
|
$self->{ws}{$name}->write_row( $self->{row}{$name}++, 0, $self->header, $self->fmt_head ); |
49
|
28
|
|
|
|
|
2186
|
$self->{ws}{$name}->freeze_panes( 1, 0 ); |
50
|
|
|
|
|
|
|
|
51
|
28
|
|
|
|
|
696
|
return $self; |
52
|
|
|
|
|
|
|
} |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
|
55
|
7
|
|
|
7
|
1
|
24
|
sub mark_header ( $self, $name, $mask ) { |
|
7
|
|
|
|
|
19
|
|
|
7
|
|
|
|
|
23
|
|
|
7
|
|
|
|
|
23
|
|
|
7
|
|
|
|
|
18
|
|
56
|
|
|
|
|
|
|
|
57
|
7
|
|
|
|
|
58
|
my $smask = $self->strip_ignore($mask); |
58
|
7
|
|
|
|
|
54
|
my $off = $self->head_offset; |
59
|
7
|
|
|
|
|
77
|
my $rhead = $self->record_header; |
60
|
7
|
|
|
|
|
58
|
for my $col ( 0 .. $#$rhead ) { |
61
|
440
|
100
|
|
|
|
11710
|
$self->{ws}{$name}->write( 0, $col + $off, $rhead->[$col], $self->fmt_headerr ) |
62
|
|
|
|
|
|
|
if $smask->[$col]; |
63
|
|
|
|
|
|
|
} |
64
|
|
|
|
|
|
|
|
65
|
7
|
|
|
|
|
56
|
return $self; |
66
|
|
|
|
|
|
|
} |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
|
69
|
36
|
|
|
36
|
1
|
84
|
sub write_row ( $self, $name, $robj ) { |
|
36
|
|
|
|
|
73
|
|
|
36
|
|
|
|
|
93
|
|
|
36
|
|
|
|
|
78
|
|
|
36
|
|
|
|
|
107
|
|
70
|
36
|
|
|
|
|
263
|
my($fnorm) = $self->_get_fmt( $name, $robj->side ); |
71
|
36
|
|
|
|
|
453
|
$self->{ws}{$name}->write_row( $self->{row}{$name}++, 0, $self->output_record($robj), $fnorm ); |
72
|
36
|
|
|
|
|
5986
|
return $self; |
73
|
|
|
|
|
|
|
} |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
|
76
|
5366
|
|
|
5366
|
|
39624
|
sub _get_fmt ( $self, $name, $side ) { |
|
5366
|
|
|
|
|
8302
|
|
|
5366
|
|
|
|
|
8882
|
|
|
5366
|
|
|
|
|
9023
|
|
|
5366
|
|
|
|
|
7897
|
|
77
|
|
|
|
|
|
|
|
78
|
5366
|
100
|
33
|
|
|
35128
|
$self->{$name}{odd} ^= 1 |
|
|
|
66
|
|
|
|
|
79
|
|
|
|
|
|
|
if $name eq 'Additional' and $side eq 'right' |
80
|
|
|
|
|
|
|
or $side eq 'left'; |
81
|
|
|
|
|
|
|
|
82
|
5366
|
100
|
|
|
|
16096
|
my $oe = $self->{$name}{odd} ? 'odd' : 'even'; |
83
|
|
|
|
|
|
|
|
84
|
5366
|
|
33
|
|
|
28336
|
my $fnorm = $self->{format}{$side}{$oe} || $self->fmt_default; |
85
|
5366
|
|
33
|
|
|
18643
|
my $fhigh = $self->{format}{$side}{high} || $self->fmt_default; |
86
|
5366
|
|
33
|
|
|
15425
|
my $flow = $self->{format}{$side}{low} || $self->fmt_default; |
87
|
|
|
|
|
|
|
|
88
|
5366
|
|
|
|
|
17025
|
return ( $fnorm, $fhigh, $flow ); |
89
|
|
|
|
|
|
|
} |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
|
92
|
5330
|
|
|
5330
|
1
|
11198
|
sub write_fmt_row ( $self, $name, $robj ) { |
|
5330
|
|
|
|
|
9920
|
|
|
5330
|
|
|
|
|
9958
|
|
|
5330
|
|
|
|
|
7893
|
|
|
5330
|
|
|
|
|
7962
|
|
93
|
|
|
|
|
|
|
|
94
|
5330
|
|
|
|
|
23136
|
my $data = $self->output_record($robj); |
95
|
5330
|
|
|
|
|
19813
|
my $mask = $self->strip_ignore( $robj->limit_mask ); |
96
|
5330
|
|
|
|
|
37006
|
my $off = $self->head_offset; |
97
|
5330
|
|
|
|
|
33642
|
my $row = $self->{row}{$name}++; |
98
|
|
|
|
|
|
|
|
99
|
5330
|
|
|
|
|
18592
|
my( $fnorm, $fhigh, $flow ) = $self->_get_fmt( $name, $robj->side ); |
100
|
|
|
|
|
|
|
|
101
|
5330
|
|
|
|
|
19611
|
for my $col ( 0 .. $#$data ) { |
102
|
352180
|
|
|
|
|
23532924
|
my $idx = $col - $off; |
103
|
352180
|
50
|
|
|
|
704689
|
my $flag = $idx < 0 ? 0 : $mask->[$idx]; |
104
|
352180
|
100
|
|
|
|
1054798
|
$self->{ws}{$name}->write( |
|
|
100
|
|
|
|
|
|
105
|
|
|
|
|
|
|
$row, $col, $data->[$col], $flag |
106
|
|
|
|
|
|
|
? ( $flag == 1 ? $fhigh : $flow ) |
107
|
|
|
|
|
|
|
: $fnorm, |
108
|
|
|
|
|
|
|
); |
109
|
|
|
|
|
|
|
} |
110
|
|
|
|
|
|
|
|
111
|
5330
|
|
|
|
|
443287
|
return $self; |
112
|
|
|
|
|
|
|
} |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
|
115
|
7
|
|
|
7
|
|
20
|
sub _open_wkb ($self) { |
|
7
|
|
|
|
|
15
|
|
|
7
|
|
|
|
|
20
|
|
116
|
|
|
|
|
|
|
|
117
|
7
|
|
|
|
|
40
|
my $rfn = $self->report_fullname->stringify; |
118
|
7
|
|
|
|
|
390
|
INFO "opening report file $rfn"; |
119
|
|
|
|
|
|
|
|
120
|
7
|
50
|
|
|
|
125
|
$self->{wbk} = Excel::Writer::XLSX->new($rfn) |
121
|
|
|
|
|
|
|
or LOGDIE "could not create >>$rfn<<, $!"; |
122
|
|
|
|
|
|
|
|
123
|
7
|
|
|
|
|
5282
|
for my $fname ( keys %format_defaults ) { |
124
|
105
|
|
|
|
|
366
|
my( undef, $side, $fmt ) = split( /_/, $fname ); |
125
|
105
|
|
|
|
|
490
|
my $fobj = $self->{wbk}->add_format( split( /\s+/, $self->$fname ) ); |
126
|
105
|
100
|
|
|
|
11313
|
if ($fmt) { |
127
|
84
|
|
|
|
|
307
|
$self->{format}{$side}{$fmt} = $fobj; |
128
|
|
|
|
|
|
|
} |
129
|
|
|
|
|
|
|
else { |
130
|
21
|
|
|
|
|
63
|
$self->{$fname} = $fobj; |
131
|
|
|
|
|
|
|
} |
132
|
|
|
|
|
|
|
} |
133
|
|
|
|
|
|
|
|
134
|
7
|
|
|
|
|
32
|
return $self; |
135
|
|
|
|
|
|
|
} |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
|
138
|
7
|
|
|
7
|
1
|
20
|
sub save_and_close ($self) { |
|
7
|
|
|
|
|
17
|
|
|
7
|
|
|
|
|
17
|
|
139
|
|
|
|
|
|
|
|
140
|
7
|
50
|
|
|
|
41
|
if ( $self->header->@* ) { |
141
|
7
|
|
|
|
|
101
|
for my $name ( keys $self->{ws}->%* ) { |
142
|
28
|
|
|
|
|
3636
|
$self->{ws}{$name}->autofilter( 0, 0, $self->{row}{$name} - 1, $self->header->$#* ); |
143
|
|
|
|
|
|
|
} |
144
|
|
|
|
|
|
|
} |
145
|
|
|
|
|
|
|
|
146
|
7
|
50
|
|
|
|
1097
|
if ( $self->{wbk} ) { |
147
|
7
|
|
|
|
|
74
|
$self->{wbk}->close(); |
148
|
7
|
|
|
|
|
27394248
|
delete $self->{wbk}; |
149
|
|
|
|
|
|
|
} |
150
|
|
|
|
|
|
|
|
151
|
7
|
|
|
|
|
39267
|
return $self; |
152
|
|
|
|
|
|
|
} |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
|
155
|
2
|
|
|
2
|
1
|
7
|
sub write_summary ( $self, $summary, $filename ) { |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
6
|
|
|
2
|
|
|
|
|
11
|
|
|
2
|
|
|
|
|
5
|
|
156
|
|
|
|
|
|
|
|
157
|
2
|
50
|
|
|
|
26
|
$filename .= '.xlsx' unless $filename =~ /\.xlsx$/i; |
158
|
|
|
|
|
|
|
|
159
|
2
|
|
|
|
|
17
|
my $sfn = $self->report_fullname($filename)->stringify; |
160
|
|
|
|
|
|
|
|
161
|
2
|
|
|
|
|
183
|
INFO "opening summary file $sfn"; |
162
|
2
|
50
|
|
|
|
35
|
my $wbk = Excel::Writer::XLSX->new($sfn) |
163
|
|
|
|
|
|
|
or ERROR "could not create >>$sfn<<, $!"; |
164
|
|
|
|
|
|
|
|
165
|
2
|
|
|
|
|
1638
|
my $fhead = $wbk->add_format(qw/bold 1 align left/); |
166
|
2
|
|
|
|
|
350
|
my $head = $self->stat_head; |
167
|
|
|
|
|
|
|
|
168
|
2
|
|
|
|
|
18
|
for my $suite ( sort keys %$summary ) { |
169
|
3
|
|
|
|
|
18
|
my $ws = $wbk->add_worksheet($suite); |
170
|
3
|
|
|
|
|
1352
|
my $row = 0; |
171
|
3
|
|
|
|
|
22
|
$ws->write_row( $row++, 0, $head, $fhead ); |
172
|
3
|
|
|
|
|
3155
|
$ws->freeze_panes( 1, 0 ); |
173
|
3
|
|
|
|
|
65
|
for my $test ( @{ $summary->{$suite} } ) { |
|
3
|
|
|
|
|
13
|
|
174
|
14
|
|
|
|
|
48
|
my $result = $test->{result}; |
175
|
14
|
|
|
|
|
52
|
$result->{title} = $test->{title}; |
176
|
14
|
|
|
|
|
134
|
my $data = [ @$result{@$head} ]; |
177
|
14
|
|
|
|
|
56
|
$ws->write_row( $row, 0, $data ); |
178
|
14
|
50
|
|
|
|
9097
|
$ws->write_url( $row, $#$head, "external:$test->{report}", undef, $test->{title} ) if $test->{report}; |
179
|
14
|
|
|
|
|
2805
|
$row++; |
180
|
|
|
|
|
|
|
} |
181
|
|
|
|
|
|
|
} |
182
|
|
|
|
|
|
|
|
183
|
2
|
|
|
|
|
27
|
$wbk->close(); |
184
|
|
|
|
|
|
|
|
185
|
2
|
|
|
|
|
106779
|
return $self; |
186
|
|
|
|
|
|
|
} |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
my $qr_num = qr/^ |
189
|
|
|
|
|
|
|
(?:[+-]?) |
190
|
|
|
|
|
|
|
(?=[0-9]|\.[0-9]) |
191
|
|
|
|
|
|
|
[0-9]* |
192
|
|
|
|
|
|
|
(\.[0-9]*)? |
193
|
|
|
|
|
|
|
([Ee]([+-]?[0-9]+))? |
194
|
|
|
|
|
|
|
$/x; |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
sub _write_with_infinity { |
197
|
258655
|
|
|
258655
|
|
4860583
|
my $ws = shift; |
198
|
258655
|
100
|
100
|
|
|
2038520
|
return $ws->write_string(@_) if $_[2] =~ /$qr_num/ and $_[2]+0 =~ /Inf/; |
199
|
70144
|
|
|
|
|
161575
|
return; |
200
|
|
|
|
|
|
|
} |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
1; |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
=head1 NAME |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
Spreadsheet::Compare::Reporter::XLSX - XLSX Report Adapter for Spreadsheet::Compare |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
=head1 DESCRIPTION |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
Handles writing Spreadsheet::Compare reports in XLSX format. |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
=head1 ATTRIBUTES |
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
The format attributes have to be valid format strings used by L<Excel::Writer::XLSX>. |
217
|
|
|
|
|
|
|
(see L<Excel::Writer::XLSX/CELL FORMATTING>) |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
The defaults for the attributes are: |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
fmt_head => 'bold 1 align left', |
222
|
|
|
|
|
|
|
fmt_headerr => 'bold 1 align left bg_color yellow', |
223
|
|
|
|
|
|
|
fmt_default => 'color black', |
224
|
|
|
|
|
|
|
fmt_left_odd => 'color blue', |
225
|
|
|
|
|
|
|
fmt_right_odd => 'color red', |
226
|
|
|
|
|
|
|
fmt_diff_odd => 'color green', |
227
|
|
|
|
|
|
|
fmt_left_even => 'color blue bg_color silver', |
228
|
|
|
|
|
|
|
fmt_right_even => 'color red bg_color silver', |
229
|
|
|
|
|
|
|
fmt_diff_even => 'color green bg_color silver', |
230
|
|
|
|
|
|
|
fmt_left_high => 'color blue bg_color yellow', |
231
|
|
|
|
|
|
|
fmt_right_high => 'color red bg_color yellow', |
232
|
|
|
|
|
|
|
fmt_diff_high => 'color black bg_color yellow', |
233
|
|
|
|
|
|
|
fmt_left_low => 'color blue bg_color lime', |
234
|
|
|
|
|
|
|
fmt_right_low => 'color red bg_color lime', |
235
|
|
|
|
|
|
|
fmt_diff_low => 'color black bg_color lime', |
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
=head1 METHODS |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
see L<Spreadsheet::Compare::Reporter> |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
=cut |