File Coverage

lib/Mail/AuthenticationResults/Header/Base.pm
Criterion Covered Total %
statement 236 237 98.3
branch 126 140 92.8
condition 24 30 80.0
subroutine 32 33 96.9
pod 20 20 100.0
total 438 460 95.4


line stmt bran cond sub pod time code
1             package Mail::AuthenticationResults::Header::Base;
2             # ABSTRACT: Base class for modelling parts of the Authentication Results Header
3              
4             require 5.008;
5 28     28   215 use strict;
  28         55  
  28         769  
6 28     28   133 use warnings;
  28         47  
  28         1125  
7             our $VERSION = '2.20210915'; # VERSION
8 28     28   172 use Scalar::Util qw{ weaken refaddr };
  28         51  
  28         1589  
9 28     28   16736 use JSON;
  28         342093  
  28         153  
10 28     28   3843 use Carp;
  28         59  
  28         1743  
11 28     28   10676 use Clone qw{ clone };
  28         61731  
  28         1745  
12              
13 28     28   9963 use Mail::AuthenticationResults::Header::Group;
  28         70  
  28         778  
14 28     28   10564 use Mail::AuthenticationResults::FoldableHeader;
  28         72  
  28         72361  
15              
16              
17 232     232   2058 sub _HAS_KEY{ return 0; }
18 34     34   2420 sub _HAS_VALUE{ return 0; }
19 253     253   712 sub _HAS_CHILDREN{ return 0; }
20             sub _ALLOWED_CHILDREN{ # uncoverable subroutine
21             # does not run in Base as HAS_CHILDREN returns 0
22 0     0   0 return 0; # uncoverable statement
23             }
24              
25              
26             sub new {
27 1788     1788 1 28282 my ( $class ) = @_;
28 1788         2520 my $self = {};
29 1788         2714 bless $self, $class;
30 1788         3033 return $self;
31             }
32              
33              
34             sub set_key {
35 345     345 1 8477 my ( $self, $key ) = @_;
36 345 100       738 croak 'Does not have key' if ! $self->_HAS_KEY();
37 341 100       666 croak 'Key cannot be undefined' if ! defined $key;
38 339 100       676 croak 'Key cannot be empty' if $key eq q{};
39 337 100       840 croak 'Invalid characters in key' if $key =~ /"/;
40 335 100       621 croak 'Invalid characters in key' if $key =~ /\n/;
41 333 100       601 croak 'Invalid characters in key' if $key =~ /\r/;
42 331         696 $self->{ 'key' } = $key;
43 331         609 return $self;
44             }
45              
46              
47             sub key {
48 1083     1083 1 2514 my ( $self ) = @_;
49 1083 100       1868 croak 'Does not have key' if ! $self->_HAS_KEY();
50 1077 100       2044 return q{} if ! defined $self->{ 'key' }; #5.8
51 1073         2493 return $self->{ 'key' };
52             }
53              
54              
55             sub safe_set_value {
56 18     18 1 2335 my ( $self, $value ) = @_;
57              
58 18 100       50 $value = q{} if ! defined $value;
59              
60 18         42 $value =~ s/\t/ /g;
61 18         36 $value =~ s/\n/ /g;
62 18         36 $value =~ s/\r/ /g;
63 18         34 $value =~ s/\(/ /g;
64 18         26 $value =~ s/\)/ /g;
65 18         26 $value =~ s/\\/ /g;
66 18         24 $value =~ s/"/ /g;
67 18         31 $value =~ s/;/ /g;
68 18         46 $value =~ s/^\s+//;
69 18         51 $value =~ s/\s+$//;
70              
71             #$value =~ s/ /_/g;
72              
73 18         58 $self->set_value( $value );
74 18         57 return $self;
75             }
76              
77              
78             sub set_value {
79 345     345 1 9928 my ( $self, $value ) = @_;
80 345 100       806 croak 'Does not have value' if ! $self->_HAS_VALUE();
81 341 100       732 croak 'Value cannot be undefined' if ! defined $value;
82             #croak 'Value cannot be empty' if $value eq q{};
83 338 100       814 croak 'Invalid characters in value' if $value =~ /"/;
84 335 100       651 croak 'Invalid characters in value' if $value =~ /\n/;
85 332 100       633 croak 'Invalid characters in value' if $value =~ /\r/;
86 329         709 $self->{ 'value' } = $value;
87 329         710 return $self;
88             }
89              
90              
91             sub value {
92 1398     1398 1 13845 my ( $self ) = @_;
93 1398 100       2409 croak 'Does not have value' if ! $self->_HAS_VALUE();
94 1397 100       2762 return q{} if ! defined $self->{ 'value' }; # 5.8
95 1344         3380 return $self->{ 'value' };
96             }
97              
98              
99             sub stringify {
100 451     451 1 17065 my ( $self, $value ) = @_;
101 451         684 my $string = $value;
102 451 100       769 $string = q{} if ! defined $string; #5.8;
103              
104 451 100       1184 if ( $string =~ /[\s\t \(\);=]/ ) {
105 34         87 $string = '"' . $string . '"';
106             }
107              
108 451         1279 return $string;
109             }
110              
111              
112             sub children {
113 3002     3002 1 9894 my ( $self ) = @_;
114 3002 100       4874 croak 'Does not have children' if ! $self->_HAS_CHILDREN();
115 3000 100       7808 return [] if ! defined $self->{ 'children' }; #5.8
116 1167         2582 return $self->{ 'children' };
117             }
118              
119              
120             sub orphan {
121 19     19 1 5080 my ( $self, $parent ) = @_;
122 19 100       125 croak 'Child does not have a parent' if ! exists $self->{ 'parent' };
123 11         20 delete $self->{ 'parent' };
124 11         21 return;
125             }
126              
127              
128             sub copy_children_from {
129 1     1 1 41 my ( $self, $object ) = @_;
130 1         3 for my $original_entry (@{$object->children()}) {
  1         2  
131 1         41 my $entry = clone $original_entry;
132 1 50       9 $entry->orphan if exists $entry->{ 'parent' };;
133 1         4 $self->add_child( $entry );
134             }
135             }
136              
137              
138             sub add_parent {
139 680     680 1 995 my ( $self, $parent ) = @_;
140 680 100       1338 return if ( ref $parent eq 'Mail::AuthenticationResults::Header::Group' );
141 340 100       639 croak 'Child already has a parent' if exists $self->{ 'parent' };
142 336 50       656 croak 'Cannot add parent' if ! $parent->_ALLOWED_CHILDREN( $self ); # uncoverable branch true
143             # Does not run as test is also done in add_child before add_parent is called.
144 336         560 $self->{ 'parent' } = $parent;
145 336         939 weaken $self->{ 'parent' };
146 336         450 return;
147             }
148              
149              
150             sub parent {
151 649     649 1 824 my ( $self ) = @_;
152 649         1058 return $self->{ 'parent' };
153             }
154              
155              
156             sub remove_child {
157 16     16 1 4214 my ( $self, $child ) = @_;
158 16 50       39 croak 'Does not have children' if ! $self->_HAS_CHILDREN();
159 16 50       37 croak 'Cannot add child' if ! $self->_ALLOWED_CHILDREN( $child );
160 16 50       65 croak 'Cannot add a class as its own parent' if refaddr $self == refaddr $child; # uncoverable branch true
161             # Does not run as there are no ALLOWED_CHILDREN results which permit this
162              
163 16         24 my @children;
164 16         20 my $child_removed = 0;
165 16         23 foreach my $mychild ( @{ $self->{ 'children' } } ) {
  16         35  
166 39 100       83 if ( refaddr $child == refaddr $mychild ) {
167 16 100       34 if ( ref $self ne 'Mail::AuthenticationResults::Header::Group' ) {
168 10         31 $child->orphan();
169             }
170 16         22 $child_removed = 1;
171             }
172             else {
173 23         40 push @children, $mychild;
174             }
175             }
176 16         29 my $children = $self->{ 'children' };
177              
178 16 50       22 croak 'Not a child of this class' if ! $child_removed;
179              
180 16         29 $self->{ 'children' } = \@children;
181              
182 16         60 return $self;
183             }
184              
185              
186             sub add_child {
187 754     754 1 39746 my ( $self, $child ) = @_;
188 754 100       1465 croak 'Does not have children' if ! $self->_HAS_CHILDREN();
189 725 100       1500 croak 'Cannot add child' if ! $self->_ALLOWED_CHILDREN( $child );
190 700 50       1947 croak 'Cannot add a class as its own parent' if refaddr $self == refaddr $child; # uncoverable branch true
191             # Does not run as there are no ALLOWED_CHILDREN results which permit this
192              
193 700         1661 $child->add_parent( $self );
194 696         794 push @{ $self->{ 'children' } }, $child;
  696         1569  
195              
196 696         1254 return $child;
197             }
198              
199              
200             sub ancestor {
201 230     230 1 312 my ( $self ) = @_;
202              
203 230         306 my $depth = 0;
204 230         437 my $ancestor = $self->parent();
205 230         304 my $eldest = $self;
206 230         449 while ( defined $ancestor ) {
207 410         485 $eldest = $ancestor;
208 410         630 $ancestor = $ancestor->parent();
209 410         766 $depth++;
210             }
211              
212 230         410 return ( $eldest, $depth );
213             }
214              
215              
216             sub as_string_prefix {
217 230     230 1 360 my ( $self, $header ) = @_;
218              
219 230         429 my ( $eldest, $depth ) = $self->ancestor();
220              
221 230         307 my $indents = 1;
222 230 50       695 if ( $eldest->can( 'indent_by' ) ) {
223 230         484 $indents = $eldest->indent_by();
224             }
225              
226 230         365 my $eol = "\n";
227 230 50       581 if ( $eldest->can( 'eol' ) ) {
228 230         412 $eol = $eldest->eol();
229             }
230              
231 230         328 my $indent = ' ';
232 230         274 my $added = 0;
233 230 50       573 if ( $eldest->can( 'indent_on' ) ) {
234 230 100       511 if ( $eldest->indent_on( ref $self ) ) {
235 81         235 $header->space( $eol );
236 81         300 $header->space( ' ' x ( $indents * $depth ) );
237 81         125 $added = 1;
238             }
239             }
240 230 100       662 $header->space( ' ' ) if ! $added;
241              
242 230         375 return $indent;
243             }
244              
245             sub _as_hashref {
246 23     23   34 my ( $self ) = @_;
247              
248 23         45 my $type = lc ref $self;
249 23         86 $type =~ s/^(.*::)//;
250 23         48 my $hashref = { 'type' => $type };
251              
252 23 100       49 $hashref->{'key'} = $self->key() if $self->_HAS_KEY();
253 23 50       47 $hashref->{'value'} = $self->value() if $self->_HAS_VALUE();
254 23 100       43 if ( $self->_HAS_CHILDREN() ) {
255 17         19 my @children = map { $_->_as_hashref() } @{ $self->children() };
  14         56  
  17         43  
256 17         30 $hashref->{'children'} = \@children;
257             }
258 23         53 return $hashref;
259             }
260              
261              
262             sub as_json {
263 1     1 1 11 my ( $self ) = @_;
264 1         18 my $J = JSON->new();
265 1         8 $J->canonical();
266 1         5 return $J->encode( $self->_as_hashref() );
267             }
268              
269              
270             sub as_string {
271 72     72 1 8079 my ( $self ) = @_;
272 72         267 my $header = Mail::AuthenticationResults::FoldableHeader->new();
273 72         237 $self->build_string( $header );
274 72         170 return $header->as_string();
275             }
276              
277              
278             sub build_string {
279 213     213 1 345 my ( $self, $header ) = @_;
280              
281 213 100       449 if ( ! $self->key() ) {
282 2         4 return;
283             }
284              
285 211         447 $header->string( $self->stringify( $self->key() ) );
286 211 100       472 if ( $self->value() ) {
    100          
    50          
287 191         543 $header->assignment( '=' );
288 191         321 $header->string( $self->stringify( $self->value() ) );
289             }
290             elsif ( $self->value() eq '0' ) {
291 2         7 $header->assignment( '=' );
292 2         5 $header->string( '0' );
293             }
294             elsif ( $self->value() eq q{} ) {
295             # special case none here
296 18 100       51 if ( $self->key() ne 'none' ) {
297 16         58 $header->assignment( '=' );
298 16         53 $header->string( '""' );
299             }
300             }
301 211 50       507 if ( $self->_HAS_CHILDREN() ) { # uncoverable branch false
302             # There are no classes which run this code without having children
303 211         312 foreach my $child ( @{$self->children()} ) {
  211         383  
304 159         412 $child->as_string_prefix( $header );
305 159         362 $child->build_string( $header );
306             }
307             }
308 211         388 return;
309             }
310              
311              
312             sub search {
313 1169     1169 1 1851 my ( $self, $search ) = @_;
314              
315 1169         2077 my $group = Mail::AuthenticationResults::Header::Group->new();
316              
317 1169         1450 my $match = 1;
318              
319 1169 100       2037 if ( exists( $search->{ 'key' } ) ) {
320 746 100       1433 if ( $self->_HAS_KEY() ) {
321 542 100 100     1476 if ( ref $search->{ 'key' } eq 'Regexp' && $self->key() =~ m/$search->{'key'}/ ) {
    100          
322 1   50     5 $match = $match && 1; # uncoverable statement
323             # $match is always 1 at this point, left this way for consistency
324             }
325             elsif ( lc $search->{ 'key' } eq lc $self->key() ) {
326 78   50     287 $match = $match && 1; # uncoverable statement
327             # $match is always 1 at this point, left this way for consistency
328             }
329             else {
330 463         639 $match = 0;
331             }
332             }
333             else {
334 204         264 $match = 0;
335             }
336             }
337              
338 1169 100       2040 if ( exists( $search->{ 'value' } ) ) {
339 671 50       1058 $search->{ 'value' } = '' if ! defined $search->{ 'value' };
340 671 100       1257 if ( $self->_HAS_VALUE() ) {
341 652 100 100     1815 if ( ref $search->{ 'value' } eq 'Regexp' && $self->value() =~ m/$search->{'value'}/ ) {
    100          
342 1   50     5 $match = $match && 1;
343             }
344             elsif ( lc $search->{ 'value' } eq lc $self->value() ) {
345 153   100     375 $match = $match && 1;
346             }
347             else {
348 498         676 $match = 0;
349             }
350             }
351             else {
352 19         45 $match = 0; # uncoverable statement
353             # There are no code paths with the current classes which end up here
354             }
355             }
356              
357 1169 100       2006 if ( exists( $search->{ 'authserv_id' } ) ) {
358 87 100       155 if ( $self->_HAS_VALUE() ) {
359 82 100       172 if ( lc ref $self eq 'mail::authenticationresults::header' ) {
360 16   50     24 my $authserv_id = eval{ $self->value()->value() } || q{};
361 16 100 100     87 if ( ref $search->{ 'authserv_id' } eq 'Regexp' && $authserv_id =~ m/$search->{'authserv_id'}/ ) {
    100          
362 2   50     10 $match = $match && 1;
363             }
364             elsif ( lc $search->{ 'authserv_id' } eq lc $authserv_id ) {
365 3   50     14 $match = $match && 1;
366             }
367             else {
368 11         21 $match = 0;
369             }
370             }
371             else {
372 66         85 $match = 0;
373             }
374             }
375             else {
376 5         7 $match = 0; # uncoverable statement
377             # There are no code paths with the current classes which end up here
378             }
379             }
380              
381 1169 100       1824 if ( exists( $search->{ 'isa' } ) ) {
382 389 100 100     1718 if ( lc ref $self eq 'mail::authenticationresults::header::' . lc $search->{ 'isa' } ) {
    100          
383 111   100     348 $match = $match && 1;
384             }
385             elsif ( lc ref $self eq 'mail::authenticationresults::header' && lc $search->{ 'isa' } eq 'header' ) {
386 5   100     15 $match = $match && 1;
387             }
388             else {
389 273         404 $match = 0;
390             }
391             }
392              
393 1169 100       1880 if ( exists( $search->{ 'has' } ) ) {
394 33         39 foreach my $query ( @{ $search->{ 'has' } } ) {
  33         51  
395 38 100       42 $match = 0 if ( scalar @{ $self->search( $query )->children() } == 0 );
  38         70  
396             }
397             }
398              
399 1169 100       1790 if ( $match ) {
400 158         397 $group->add_child( $self );
401             }
402              
403 1169 100       2165 if ( $self->_HAS_CHILDREN() ) {
404 953         1098 foreach my $child ( @{$self->children()} ) {
  953         1545  
405 1022         2179 my $childfound = $child->search( $search );
406 1022 100       1243 if ( scalar @{ $childfound->children() } ) {
  1022         1443  
407 187         362 $group->add_child( $childfound );
408             }
409             }
410             }
411              
412 1169         2042 return $group;
413             }
414              
415             1;
416              
417             __END__