File Coverage

lib/Mail/AuthenticationResults/Header/Base.pm
Criterion Covered Total %
statement 235 236 98.3
branch 126 140 92.8
condition 24 30 80.0
subroutine 32 33 96.9
pod 20 20 100.0
total 437 459 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   226 use strict;
  28         56  
  28         793  
6 28     28   134 use warnings;
  28         43  
  28         1144  
7             our $VERSION = '2.20210914'; # VERSION
8 28     28   155 use Scalar::Util qw{ weaken refaddr };
  28         54  
  28         1607  
9 28     28   19640 use JSON;
  28         376504  
  28         167  
10 28     28   3975 use Carp;
  28         54  
  28         1810  
11 28     28   13770 use Clone qw{ clone };
  28         67253  
  28         1881  
12              
13 28     28   11629 use Mail::AuthenticationResults::Header::Group;
  28         72  
  28         820  
14 28     28   11633 use Mail::AuthenticationResults::FoldableHeader;
  28         84  
  28         75840  
15              
16              
17 232     232   2144 sub _HAS_KEY{ return 0; }
18 34     34   2482 sub _HAS_VALUE{ return 0; }
19 253     253   717 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 30966 my ( $class ) = @_;
28 1788         2577 my $self = {};
29 1788         2847 bless $self, $class;
30 1788         3297 return $self;
31             }
32              
33              
34             sub set_key {
35 345     345 1 8943 my ( $self, $key ) = @_;
36 345 100       753 croak 'Does not have key' if ! $self->_HAS_KEY();
37 341 100       714 croak 'Key cannot be undefined' if ! defined $key;
38 339 100       621 croak 'Key cannot be empty' if $key eq q{};
39 337 100       833 croak 'Invalid characters in key' if $key =~ /"/;
40 335 100       692 croak 'Invalid characters in key' if $key =~ /\n/;
41 333 100       617 croak 'Invalid characters in key' if $key =~ /\r/;
42 331         766 $self->{ 'key' } = $key;
43 331         571 return $self;
44             }
45              
46              
47             sub key {
48 1083     1083 1 2532 my ( $self ) = @_;
49 1083 100       1861 croak 'Does not have key' if ! $self->_HAS_KEY();
50 1077 100       2104 return q{} if ! defined $self->{ 'key' }; #5.8
51 1073         2440 return $self->{ 'key' };
52             }
53              
54              
55             sub safe_set_value {
56 18     18 1 2532 my ( $self, $value ) = @_;
57              
58 18 100       52 $value = q{} if ! defined $value;
59              
60 18         51 $value =~ s/\t/ /g;
61 18         39 $value =~ s/\n/ /g;
62 18         30 $value =~ s/\r/ /g;
63 18         33 $value =~ s/\(/ /g;
64 18         34 $value =~ s/\)/ /g;
65 18         31 $value =~ s/\\/ /g;
66 18         21 $value =~ s/"/ /g;
67 18         34 $value =~ s/;/ /g;
68 18         48 $value =~ s/^\s+//;
69 18         54 $value =~ s/\s+$//;
70              
71             #$value =~ s/ /_/g;
72              
73 18         57 $self->set_value( $value );
74 18         63 return $self;
75             }
76              
77              
78             sub set_value {
79 345     345 1 10487 my ( $self, $value ) = @_;
80 345 100       892 croak 'Does not have value' if ! $self->_HAS_VALUE();
81 341 100       718 croak 'Value cannot be undefined' if ! defined $value;
82             #croak 'Value cannot be empty' if $value eq q{};
83 338 100       859 croak 'Invalid characters in value' if $value =~ /"/;
84 335 100       658 croak 'Invalid characters in value' if $value =~ /\n/;
85 332 100       651 croak 'Invalid characters in value' if $value =~ /\r/;
86 329         651 $self->{ 'value' } = $value;
87 329         696 return $self;
88             }
89              
90              
91             sub value {
92 1398     1398 1 9780 my ( $self ) = @_;
93 1398 100       2454 croak 'Does not have value' if ! $self->_HAS_VALUE();
94 1397 100       2760 return q{} if ! defined $self->{ 'value' }; # 5.8
95 1344         3418 return $self->{ 'value' };
96             }
97              
98              
99             sub stringify {
100 451     451 1 16896 my ( $self, $value ) = @_;
101 451         623 my $string = $value;
102 451 100       747 $string = q{} if ! defined $string; #5.8;
103              
104 451 100       1223 if ( $string =~ /[\s\t \(\);=]/ ) {
105 34         87 $string = '"' . $string . '"';
106             }
107              
108 451         1210 return $string;
109             }
110              
111              
112             sub children {
113 3002     3002 1 11064 my ( $self ) = @_;
114 3002 100       4809 croak 'Does not have children' if ! $self->_HAS_CHILDREN();
115 3000 100       7735 return [] if ! defined $self->{ 'children' }; #5.8
116 1167         2520 return $self->{ 'children' };
117             }
118              
119              
120             sub orphan {
121 19     19 1 5348 my ( $self, $parent ) = @_;
122 19 100       128 croak 'Child does not have a parent' if ! exists $self->{ 'parent' };
123 11         24 delete $self->{ 'parent' };
124 11         17 return;
125             }
126              
127              
128             sub copy_children_from {
129 1     1 1 38 my ( $self, $object ) = @_;
130 1         4 for my $original_entry ($object->children()->@*) {
131 1         35 my $entry = clone $original_entry;
132 1 50       9 $entry->orphan if exists $entry->{ 'parent' };;
133 1         3 $self->add_child( $entry );
134             }
135             }
136              
137              
138             sub add_parent {
139 680     680 1 1044 my ( $self, $parent ) = @_;
140 680 100       1359 return if ( ref $parent eq 'Mail::AuthenticationResults::Header::Group' );
141 340 100       715 croak 'Child already has a parent' if exists $self->{ 'parent' };
142 336 50       613 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         547 $self->{ 'parent' } = $parent;
145 336         1307 weaken $self->{ 'parent' };
146 336         466 return;
147             }
148              
149              
150             sub parent {
151 649     649 1 919 my ( $self ) = @_;
152 649         945 return $self->{ 'parent' };
153             }
154              
155              
156             sub remove_child {
157 16     16 1 4416 my ( $self, $child ) = @_;
158 16 50       46 croak 'Does not have children' if ! $self->_HAS_CHILDREN();
159 16 50       40 croak 'Cannot add child' if ! $self->_ALLOWED_CHILDREN( $child );
160 16 50       60 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         21 my @children;
164 16         28 my $child_removed = 0;
165 16         37 foreach my $mychild ( @{ $self->{ 'children' } } ) {
  16         41  
166 39 100       92 if ( refaddr $child == refaddr $mychild ) {
167 16 100       37 if ( ref $self ne 'Mail::AuthenticationResults::Header::Group' ) {
168 10         38 $child->orphan();
169             }
170 16         28 $child_removed = 1;
171             }
172             else {
173 23         43 push @children, $mychild;
174             }
175             }
176 16         23 my $children = $self->{ 'children' };
177              
178 16 50       34 croak 'Not a child of this class' if ! $child_removed;
179              
180 16         31 $self->{ 'children' } = \@children;
181              
182 16         62 return $self;
183             }
184              
185              
186             sub add_child {
187 754     754 1 40806 my ( $self, $child ) = @_;
188 754 100       1478 croak 'Does not have children' if ! $self->_HAS_CHILDREN();
189 725 100       1626 croak 'Cannot add child' if ! $self->_ALLOWED_CHILDREN( $child );
190 700 50       1978 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         1714 $child->add_parent( $self );
194 696         840 push @{ $self->{ 'children' } }, $child;
  696         1647  
195              
196 696         1286 return $child;
197             }
198              
199              
200             sub ancestor {
201 230     230 1 311 my ( $self ) = @_;
202              
203 230         299 my $depth = 0;
204 230         409 my $ancestor = $self->parent();
205 230         300 my $eldest = $self;
206 230         445 while ( defined $ancestor ) {
207 410         497 $eldest = $ancestor;
208 410         665 $ancestor = $ancestor->parent();
209 410         709 $depth++;
210             }
211              
212 230         405 return ( $eldest, $depth );
213             }
214              
215              
216             sub as_string_prefix {
217 230     230 1 354 my ( $self, $header ) = @_;
218              
219 230         454 my ( $eldest, $depth ) = $self->ancestor();
220              
221 230         302 my $indents = 1;
222 230 50       717 if ( $eldest->can( 'indent_by' ) ) {
223 230         484 $indents = $eldest->indent_by();
224             }
225              
226 230         330 my $eol = "\n";
227 230 50       532 if ( $eldest->can( 'eol' ) ) {
228 230         410 $eol = $eldest->eol();
229             }
230              
231 230         340 my $indent = ' ';
232 230         284 my $added = 0;
233 230 50       573 if ( $eldest->can( 'indent_on' ) ) {
234 230 100       519 if ( $eldest->indent_on( ref $self ) ) {
235 81         190 $header->space( $eol );
236 81         281 $header->space( ' ' x ( $indents * $depth ) );
237 81         125 $added = 1;
238             }
239             }
240 230 100       647 $header->space( ' ' ) if ! $added;
241              
242 230         353 return $indent;
243             }
244              
245             sub _as_hashref {
246 23     23   31 my ( $self ) = @_;
247              
248 23         49 my $type = lc ref $self;
249 23         96 $type =~ s/^(.*::)//;
250 23         81 my $hashref = { 'type' => $type };
251              
252 23 100       56 $hashref->{'key'} = $self->key() if $self->_HAS_KEY();
253 23 50       46 $hashref->{'value'} = $self->value() if $self->_HAS_VALUE();
254 23 100       48 if ( $self->_HAS_CHILDREN() ) {
255 17         20 my @children = map { $_->_as_hashref() } @{ $self->children() };
  14         37  
  17         35  
256 17         44 $hashref->{'children'} = \@children;
257             }
258 23         59 return $hashref;
259             }
260              
261              
262             sub as_json {
263 1     1 1 15 my ( $self ) = @_;
264 1         30 my $J = JSON->new();
265 1         19 $J->canonical();
266 1         6 return $J->encode( $self->_as_hashref() );
267             }
268              
269              
270             sub as_string {
271 72     72 1 8416 my ( $self ) = @_;
272 72         313 my $header = Mail::AuthenticationResults::FoldableHeader->new();
273 72         242 $self->build_string( $header );
274 72         188 return $header->as_string();
275             }
276              
277              
278             sub build_string {
279 213     213 1 355 my ( $self, $header ) = @_;
280              
281 213 100       448 if ( ! $self->key() ) {
282 2         3 return;
283             }
284              
285 211         430 $header->string( $self->stringify( $self->key() ) );
286 211 100       555 if ( $self->value() ) {
    100          
    50          
287 191         504 $header->assignment( '=' );
288 191         337 $header->string( $self->stringify( $self->value() ) );
289             }
290             elsif ( $self->value() eq '0' ) {
291 2         6 $header->assignment( '=' );
292 2         7 $header->string( '0' );
293             }
294             elsif ( $self->value() eq q{} ) {
295             # special case none here
296 18 100       52 if ( $self->key() ne 'none' ) {
297 16         54 $header->assignment( '=' );
298 16         37 $header->string( '""' );
299             }
300             }
301 211 50       501 if ( $self->_HAS_CHILDREN() ) { # uncoverable branch false
302             # There are no classes which run this code without having children
303 211         280 foreach my $child ( @{$self->children()} ) {
  211         406  
304 159         404 $child->as_string_prefix( $header );
305 159         358 $child->build_string( $header );
306             }
307             }
308 211         404 return;
309             }
310              
311              
312             sub search {
313 1169     1169 1 1942 my ( $self, $search ) = @_;
314              
315 1169         1987 my $group = Mail::AuthenticationResults::Header::Group->new();
316              
317 1169         1454 my $match = 1;
318              
319 1169 100       2027 if ( exists( $search->{ 'key' } ) ) {
320 746 100       1829 if ( $self->_HAS_KEY() ) {
321 542 100 100     1486 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     325 $match = $match && 1; # uncoverable statement
327             # $match is always 1 at this point, left this way for consistency
328             }
329             else {
330 463         649 $match = 0;
331             }
332             }
333             else {
334 204         272 $match = 0;
335             }
336             }
337              
338 1169 100       2025 if ( exists( $search->{ 'value' } ) ) {
339 671 50       1101 $search->{ 'value' } = '' if ! defined $search->{ 'value' };
340 671 100       1252 if ( $self->_HAS_VALUE() ) {
341 652 100 100     1701 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     372 $match = $match && 1;
346             }
347             else {
348 498         678 $match = 0;
349             }
350             }
351             else {
352 19         34 $match = 0; # uncoverable statement
353             # There are no code paths with the current classes which end up here
354             }
355             }
356              
357 1169 100       2449 if ( exists( $search->{ 'authserv_id' } ) ) {
358 87 100       155 if ( $self->_HAS_VALUE() ) {
359 82 100       175 if ( lc ref $self eq 'mail::authenticationresults::header' ) {
360 16   50     23 my $authserv_id = eval{ $self->value()->value() } || q{};
361 16 100 100     74 if ( ref $search->{ 'authserv_id' } eq 'Regexp' && $authserv_id =~ m/$search->{'authserv_id'}/ ) {
    100          
362 2   50     9 $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         18 $match = 0;
369             }
370             }
371             else {
372 66         81 $match = 0;
373             }
374             }
375             else {
376 5         13 $match = 0; # uncoverable statement
377             # There are no code paths with the current classes which end up here
378             }
379             }
380              
381 1169 100       1888 if ( exists( $search->{ 'isa' } ) ) {
382 389 100 100     1660 if ( lc ref $self eq 'mail::authenticationresults::header::' . lc $search->{ 'isa' } ) {
    100          
383 111   100     323 $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         415 $match = 0;
390             }
391             }
392              
393 1169 100       1899 if ( exists( $search->{ 'has' } ) ) {
394 33         36 foreach my $query ( @{ $search->{ 'has' } } ) {
  33         56  
395 38 100       40 $match = 0 if ( scalar @{ $self->search( $query )->children() } == 0 );
  38         63  
396             }
397             }
398              
399 1169 100       1798 if ( $match ) {
400 158         394 $group->add_child( $self );
401             }
402              
403 1169 100       2092 if ( $self->_HAS_CHILDREN() ) {
404 953         1128 foreach my $child ( @{$self->children()} ) {
  953         1578  
405 1022         2274 my $childfound = $child->search( $search );
406 1022 100       1189 if ( scalar @{ $childfound->children() } ) {
  1022         1456  
407 187         362 $group->add_child( $childfound );
408             }
409             }
410             }
411              
412 1169         2143 return $group;
413             }
414              
415             1;
416              
417             __END__