| blib/lib/Mail/Box/Test.pm | |||
|---|---|---|---|
| Criterion | Covered | Total | % | 
| statement | 117 | 149 | 78.5 | 
| branch | 31 | 62 | 50.0 | 
| condition | 0 | 3 | 0.0 | 
| subroutine | 19 | 22 | 86.3 | 
| pod | 0 | 9 | 0.0 | 
| total | 167 | 245 | 68.1 | 
| line | stmt | bran | cond | sub | pod | time | code | 
|---|---|---|---|---|---|---|---|
| 1 | # Copyrights 2001-2019 by [Mark Overmeer]. | ||||||
| 2 | # For other contributors see ChangeLog. | ||||||
| 3 | # See the manual pages for details on the licensing terms. | ||||||
| 4 | # Pod stripped from pm file by OODoc 2.02. | ||||||
| 5 | # This code is part of distribution Mail-Box. Meta-POD processed with | ||||||
| 6 | # OODoc into POD and HTML manual-pages. See README.md | ||||||
| 7 | # Copyright Mark Overmeer. Licensed under the same terms as Perl itself. | ||||||
| 8 | |||||||
| 9 | package Mail::Box::Test; | ||||||
| 10 | 42 | 42 | 20845 | use vars '$VERSION'; | |||
| 42 | 265 | ||||||
| 42 | 3003 | ||||||
| 11 | $VERSION = '3.008'; | ||||||
| 12 | |||||||
| 13 | 42 | 42 | 231 | use base 'Exporter'; | |||
| 42 | 55 | ||||||
| 42 | 4368 | ||||||
| 14 | |||||||
| 15 | 42 | 42 | 227 | use strict; | |||
| 42 | 60 | ||||||
| 42 | 674 | ||||||
| 16 | 42 | 42 | 161 | use warnings; | |||
| 42 | 72 | ||||||
| 42 | 1508 | ||||||
| 17 | |||||||
| 18 | 42 | 42 | 18926 | use File::Copy 'copy'; | |||
| 42 | 196772 | ||||||
| 42 | 3178 | ||||||
| 19 | 42 | 42 | 272 | use List::Util 'first'; | |||
| 42 | 73 | ||||||
| 42 | 4750 | ||||||
| 20 | 42 | 42 | 17686 | use IO::File; # to overrule open() | |||
| 42 | 350931 | ||||||
| 42 | 7202 | ||||||
| 21 | 42 | 42 | 1724 | use File::Spec; | |||
| 42 | 79 | ||||||
| 42 | 4214 | ||||||
| 22 | 42 | 42 | 33251 | use File::Temp 'tempdir'; | |||
| 42 | 443117 | ||||||
| 42 | 2474 | ||||||
| 23 | 42 | 42 | 272 | use Cwd qw(getcwd); | |||
| 42 | 73 | ||||||
| 42 | 1527 | ||||||
| 24 | 42 | 42 | 26605 | use Sys::Hostname qw(hostname); | |||
| 42 | 37475 | ||||||
| 42 | 1961 | ||||||
| 25 | 42 | 42 | 27735 | use Test::More; | |||
| 42 | 2295794 | ||||||
| 42 | 350 | ||||||
| 26 | |||||||
| 27 | |||||||
| 28 | our @EXPORT = | ||||||
| 29 | qw/clean_dir copy_dir | ||||||
| 30 | unpack_mbox2mh unpack_mbox2maildir | ||||||
| 31 | compare_lists listdir | ||||||
| 32 | compare_message_prints reproducable_text | ||||||
| 33 | compare_thread_dumps | ||||||
| 34 | |||||||
| 35 | $folderdir | ||||||
| 36 | $workdir | ||||||
| 37 | $src $unixsrc $winsrc | ||||||
| 38 | $fn $unixfn $winfn | ||||||
| 39 | $cpy $cpyfn | ||||||
| 40 | $raw_html_data | ||||||
| 41 | $crlf_platform $windows | ||||||
| 42 | /; | ||||||
| 43 | |||||||
| 44 | our ($logfile, $folderdir); | ||||||
| 45 | our ($src, $unixsrc, $winsrc); | ||||||
| 46 | our ($fn, $unixfn, $winfn); | ||||||
| 47 | our ($cpy, $cpyfn); | ||||||
| 48 | our ($crlf_platform, $windows); | ||||||
| 49 | our $workdir; | ||||||
| 50 | |||||||
| 51 | BEGIN { | ||||||
| 52 | 42 | 42 | 19966 | $windows = $^O =~ m/mswin32/i; | |||
| 53 | 42 | 100 | $crlf_platform = $windows; | ||||
| 54 | |||||||
| 55 | 42 | 522 | $folderdir = File::Spec->catdir('t','folders'); | ||||
| 56 | 42 | 267 | $workdir = tempdir(CLEANUP => 1); | ||||
| 57 | |||||||
| 58 | |||||||
| 59 | 42 | 48904 | $logfile = File::Spec->catfile(getcwd(), 'run-log'); | ||||
| 60 | 42 | 138 | $unixfn = 'mbox.src'; | ||||
| 61 | 42 | 99 | $winfn = 'mbox.win'; | ||||
| 62 | 42 | 76 | $cpyfn = 'mbox.cpy'; | ||||
| 63 | |||||||
| 64 | 42 | 268 | $unixsrc = File::Spec->catfile($folderdir, $unixfn); | ||||
| 65 | 42 | 286 | $winsrc = File::Spec->catfile($folderdir, $winfn); | ||||
| 66 | 42 | 320 | $cpy = File::Spec->catfile($workdir, $cpyfn); | ||||
| 67 | |||||||
| 68 | 42 | 50 | 211 | ($src, $fn) = $windows ? ($winsrc, $winfn) : ($unixsrc, $unixfn); | |||
| 69 | |||||||
| 70 | # ensure to test the Perl Parser not the C-Parser (separate distribution) | ||||||
| 71 | 42 | 19936 | require Mail::Box::Parser::Perl; | ||||
| 72 | 42 | 762506 | Mail::Box::Parser->defaultParserType( 'Mail::Box::Parser::Perl' ); | ||||
| 73 | } | ||||||
| 74 | |||||||
| 75 | # | ||||||
| 76 | # CLEAN_DIR | ||||||
| 77 | # Clean a directory structure, typically created by unpack_mbox() | ||||||
| 78 | # | ||||||
| 79 | |||||||
| 80 | sub clean_dir($); | ||||||
| 81 | sub clean_dir($) | ||||||
| 82 | 11 | 11 | 0 | 105 | { my $dir = shift; | ||
| 83 | 11 | 46 | local *DIR; | ||||
| 84 | 11 | 50 | 403 | opendir DIR, $dir or return; | |||
| 85 | |||||||
| 86 | 0 | 0 | 0 | my @items = map { m/(.*)/ && "$dir/$1" } # untainted | |||
| 0 | 0 | ||||||
| 87 | grep !/^\.\.?$/, readdir DIR; | ||||||
| 88 | 0 | 0 | foreach (@items) | ||||
| 89 | 0 | 0 | 0 | { if(-d) { clean_dir $_ } | |||
| 0 | 0 | ||||||
| 90 | 0 | 0 | else { unlink $_ } | ||||
| 91 | } | ||||||
| 92 | |||||||
| 93 | 0 | 0 | closedir DIR; | ||||
| 94 | 0 | 0 | rmdir $dir; | ||||
| 95 | } | ||||||
| 96 | |||||||
| 97 | # | ||||||
| 98 | # COPY_DIR FROM, TO | ||||||
| 99 | # Copy directory to other place (not recursively), cleaning the | ||||||
| 100 | # destination first. | ||||||
| 101 | # | ||||||
| 102 | |||||||
| 103 | sub copy_dir($$) | ||||||
| 104 | 0 | 0 | 0 | 0 | { my ($orig, $dest) = @_; | ||
| 105 | |||||||
| 106 | 0 | 0 | clean_dir($dest); | ||||
| 107 | |||||||
| 108 | 0 | 0 | 0 | mkdir $dest | |||
| 109 | or die "Cannot create copy destination $dest: $!\n"; | ||||||
| 110 | |||||||
| 111 | 0 | 0 | 0 | opendir ORIG, $orig | |||
| 112 | or die "Cannot open directory $orig: $!\n"; | ||||||
| 113 | |||||||
| 114 | 0 | 0 | 0 | 0 | foreach my $name (map { !m/^\.\.?$/ && m/(.*)/ ? $1 : () } readdir ORIG) | ||
| 0 | 0 | ||||||
| 115 | 0 | 0 | { my $from = File::Spec->catfile($orig, $name); | ||||
| 116 | 0 | 0 | 0 | next if -d $from; | |||
| 117 | |||||||
| 118 | 0 | 0 | my $to = File::Spec->catfile($dest, $name); | ||||
| 119 | 0 | 0 | 0 | copy($from, $to) or die "Couldn't copy $from,$to: $!\n"; | |||
| 120 | } | ||||||
| 121 | |||||||
| 122 | 0 | 0 | close ORIG; | ||||
| 123 | } | ||||||
| 124 | |||||||
| 125 | # UNPACK_MBOX2MH | ||||||
| 126 | # Unpack an mbox-file into an MH-directory. | ||||||
| 127 | # This skips message-nr 13 for testing purposes. | ||||||
| 128 | # Blanks before "From" are removed. | ||||||
| 129 | |||||||
| 130 | sub unpack_mbox2mh($$) | ||||||
| 131 | 6 | 6 | 0 | 449 | { my ($file, $dir) = @_; | ||
| 132 | 6 | 26 | clean_dir($dir); | ||||
| 133 | |||||||
| 134 | 6 | 389 | mkdir $dir, 0700; | ||||
| 135 | 6 | 21 | my $count = 1; | ||||
| 136 | 6 | 10 | my $blank; | ||||
| 137 | |||||||
| 138 | 6 | 50 | 224 | open FILE, $file or die; | |||
| 139 | 6 | 241 | open OUT, '>', File::Spec->devnull; | ||||
| 140 | |||||||
| 141 | 6 | 143 | while( | ||||
| 142 | 20088 | 100 | 26788 | { if( /^From / ) | |||
| 143 | 270 | 5698 | { close OUT; | ||||
| 144 | 270 | 636 | undef $blank; | ||||
| 145 | 270 | 50 | 10863 | open OUT, ">$dir/".$count++ or die; | |||
| 146 | 270 | 100 | 902 | $count++ if $count==13; # skip 13 for test | |||
| 147 | 270 | 1040 | next; # from line not included in file. | ||||
| 148 | } | ||||||
| 149 | |||||||
| 150 | 19818 | 100 | 25049 | print OUT $blank | |||
| 151 | if defined $blank; | ||||||
| 152 | |||||||
| 153 | 19818 | 100 | 27351 | if( m/^\015?\012$/ ) | |||
| 154 | 2400 | 2769 | { $blank = $_; | ||||
| 155 | 2400 | 4707 | next; | ||||
| 156 | } | ||||||
| 157 | |||||||
| 158 | 17418 | 16579 | undef $blank; | ||||
| 159 | 17418 | 28222 | print OUT; | ||||
| 160 | } | ||||||
| 161 | |||||||
| 162 | 6 | 134 | close OUT; | ||||
| 163 | 6 | 77 | close FILE; | ||||
| 164 | } | ||||||
| 165 | |||||||
| 166 | # UNPACK_MBOX2MAILDIR | ||||||
| 167 | # Unpack an mbox-file into an Maildir-directory. | ||||||
| 168 | |||||||
| 169 | our @maildir_names = | ||||||
| 170 | ( '8000000.localhost.23:2,' | ||||||
| 171 | , '90000000.localhost.213:2,' | ||||||
| 172 | , '110000000.localhost.12:2,' | ||||||
| 173 | , '110000001.l.42:2,' | ||||||
| 174 | , '110000002.l.42:2,' | ||||||
| 175 | , '110000002.l.43:2,' | ||||||
| 176 | , '110000004.l.43:2,' | ||||||
| 177 | , '110000005.l.43:2,' | ||||||
| 178 | , '110000006.l.43:2,' | ||||||
| 179 | , '110000007.l.43:2,D' | ||||||
| 180 | , '110000008.l.43:2,DF' | ||||||
| 181 | , '110000009.l.43:2,DFR' | ||||||
| 182 | , '110000010.l.43:2,DFRS' | ||||||
| 183 | , '110000011.l.43:2,DFRST' | ||||||
| 184 | , '110000012.l.43:2,F' | ||||||
| 185 | , '110000013.l.43:2,FR' | ||||||
| 186 | , '110000014.l.43:2,FRS' | ||||||
| 187 | , '110000015.l.43:2,FRST' | ||||||
| 188 | , '110000016.l.43:2,DR' | ||||||
| 189 | , '110000017.l.43:2,DRS' | ||||||
| 190 | , '110000018.l.43:2,DRST' | ||||||
| 191 | , '110000019.l.43:2,FS' | ||||||
| 192 | , '110000020.l.43:2,FST' | ||||||
| 193 | , '110000021.l.43:2,R' | ||||||
| 194 | , '110000022.l.43:2,RS' | ||||||
| 195 | , '110000023.l.43:2,RST' | ||||||
| 196 | , '110000024.l.43:2,S' | ||||||
| 197 | , '110000025.l.43:2,ST' | ||||||
| 198 | , '110000026.l.43:2,T' | ||||||
| 199 | , '110000027.l.43:2,' | ||||||
| 200 | , '110000028.l.43:2,' | ||||||
| 201 | , '110000029.l.43:2,' | ||||||
| 202 | , '110000030.l.43:2,' | ||||||
| 203 | , '110000031.l.43:2,' | ||||||
| 204 | , '110000032.l.43:2,' | ||||||
| 205 | , '110000033.l.43:2,' | ||||||
| 206 | , '110000034.l.43:2,' | ||||||
| 207 | , '110000035.l.43:2,' | ||||||
| 208 | , '110000036.l.43:2,' | ||||||
| 209 | , '110000037.l.43:2,' | ||||||
| 210 | , '110000038.l.43' | ||||||
| 211 | , '110000039.l.43' | ||||||
| 212 | , '110000040.l.43' | ||||||
| 213 | , '110000041.l.43' | ||||||
| 214 | , '110000042.l.43' | ||||||
| 215 | ); | ||||||
| 216 | |||||||
| 217 | sub unpack_mbox2maildir($$) | ||||||
| 218 | 4 | 4 | 0 | 358 | { my ($file, $dir) = @_; | ||
| 219 | 4 | 17 | clean_dir($dir); | ||||
| 220 | |||||||
| 221 | 4 | 50 | 18 | die unless @maildir_names==45; | |||
| 222 | |||||||
| 223 | 4 | 50 | 292 | mkdir $dir or die; | |||
| 224 | 4 | 50 | 232 | mkdir File::Spec->catfile($dir, 'cur') or die; | |||
| 225 | 4 | 50 | 172 | mkdir File::Spec->catfile($dir, 'new') or die; | |||
| 226 | 4 | 50 | 165 | mkdir File::Spec->catfile($dir, 'tmp') or die; | |||
| 227 | 4 | 17 | my $msgnr = 0; | ||||
| 228 | |||||||
| 229 | 4 | 50 | 129 | open FILE, $file or die; | |||
| 230 | 4 | 149 | open OUT, '>', File::Spec->devnull; | ||||
| 231 | |||||||
| 232 | 4 | 13 | my $last_empty = 0; | ||||
| 233 | 4 | 7 | my $blank; | ||||
| 234 | |||||||
| 235 | 4 | 83 | while( | ||||
| 236 | 13392 | 100 | 18137 | { if( m/^From / ) | |||
| 237 | 180 | 3987 | { close OUT; | ||||
| 238 | 180 | 426 | undef $blank; | ||||
| 239 | 180 | 255 | my $now = time; | ||||
| 240 | 180 | 549 | my $hostname = hostname; | ||||
| 241 | |||||||
| 242 | 180 | 100 | 2170 | my $msgfile = File::Spec->catfile($dir | |||
| 243 | , ($msgnr > 40 ? 'new' : 'cur') | ||||||
| 244 | , $maildir_names[$msgnr++] | ||||||
| 245 | ); | ||||||
| 246 | |||||||
| 247 | 180 | 50 | 7661 | open OUT, ">", $msgfile or die "Create $msgfile: $!\n"; | |||
| 248 | 180 | 1037 | next; # from line not included in file. | ||||
| 249 | } | ||||||
| 250 | |||||||
| 251 | 13212 | 100 | 16823 | print OUT $blank | |||
| 252 | if defined $blank; | ||||||
| 253 | |||||||
| 254 | 13212 | 100 | 18673 | if( m/^\015?\012$/ ) | |||
| 255 | 1600 | 1825 | { $blank = $_; | ||||
| 256 | 1600 | 3167 | next; | ||||
| 257 | } | ||||||
| 258 | |||||||
| 259 | 11612 | 11007 | undef $blank; | ||||
| 260 | 11612 | 19113 | print OUT; | ||||
| 261 | } | ||||||
| 262 | |||||||
| 263 | 4 | 86 | close OUT; | ||||
| 264 | 4 | 46 | close FILE; | ||||
| 265 | } | ||||||
| 266 | |||||||
| 267 | # | ||||||
| 268 | # Compare two lists. | ||||||
| 269 | # | ||||||
| 270 | |||||||
| 271 | sub compare_lists($$) | ||||||
| 272 | 16 | 16 | 0 | 638 | { my ($first, $second) = @_; | ||
| 273 | #warn "[@$first]==[@$second]\n"; | ||||||
| 274 | 16 | 50 | 40 | return 0 unless @$first == @$second; | |||
| 275 | 16 | 44 | for(my $i=0; $i<@$first; $i++) | ||||
| 276 | 193 | 50 | 366 | { return 0 unless $first->[$i] eq $second->[$i]; | |||
| 277 | } | ||||||
| 278 | 16 | 72 | 1; | ||||
| 279 | } | ||||||
| 280 | |||||||
| 281 | # | ||||||
| 282 | # Compare the text of two messages, rather strict. | ||||||
| 283 | # On CRLF platforms, the Content-Length may be different. | ||||||
| 284 | # | ||||||
| 285 | |||||||
| 286 | sub compare_message_prints($$$) | ||||||
| 287 | 0 | 0 | 0 | 0 | { my ($first, $second, $label) = @_; | ||
| 288 | |||||||
| 289 | 0 | 0 | 0 | if($crlf_platform) | |||
| 290 | 0 | 0 | {   $first  =~ s/Content-Length: (\d+)/Content-Length: | ||||
| 291 | 0 | 0 | $second =~ s/Content-Length: (\d+)/Content-Length: | ||||
| 292 | } | ||||||
| 293 | |||||||
| 294 | 0 | 0 | is($first, $second, $label); | ||||
| 295 | } | ||||||
| 296 | |||||||
| 297 | # | ||||||
| 298 | # Strip message text down the things which are the same on all | ||||||
| 299 | # platforms and all situations. | ||||||
| 300 | # | ||||||
| 301 | |||||||
| 302 | sub reproducable_text($) | ||||||
| 303 | 0 | 0 | 0 | 0 | { my $text = shift; | ||
| 304 | 0 | 0 | my @lines = split /^/m, $text; | ||||
| 305 | 0 | 0 | foreach (@lines) | ||||
| 306 | 0 | 0 | {   s/((?:references|message-id|date|content-length)\: ).*/$1 | ||||
| 307 | 0 | 0 | s/boundary-\d+/boundary- | ||||
| 308 | } | ||||||
| 309 | 0 | 0 | join '', @lines; | ||||
| 310 | } | ||||||
| 311 | |||||||
| 312 | # | ||||||
| 313 | # Compare two outputs of thread details. | ||||||
| 314 | # On CRLF platforms, the reported sizes are ignored. | ||||||
| 315 | # | ||||||
| 316 | |||||||
| 317 | sub compare_thread_dumps($$$) | ||||||
| 318 | 6 | 6 | 0 | 18 | { my ($first, $second, $label) = @_; | ||
| 319 | |||||||
| 320 | 6 | 50 | 16 | if($crlf_platform) | |||
| 321 | 0 | 0 | { $first =~ s/^..../ /gm; | ||||
| 322 | 0 | 0 | $second =~ s/^..../ /gm; | ||||
| 323 | } | ||||||
| 324 | |||||||
| 325 | 6 | 20 | is($first, $second, $label); | ||||
| 326 | } | ||||||
| 327 | |||||||
| 328 | # | ||||||
| 329 | # List directory | ||||||
| 330 | # This removes '.' and '..' | ||||||
| 331 | # | ||||||
| 332 | |||||||
| 333 | sub listdir($) | ||||||
| 334 | 3 | 3 | 0 | 138 | { my $dir = shift; | ||
| 335 | 3 | 50 | 94 | opendir LISTDIR, $dir or return (); | |||
| 336 | 3 | 178 | my @entities = grep !/^\.\.?$/, readdir LISTDIR; | ||||
| 337 | 3 | 50 | closedir LISTDIR; | ||||
| 338 | 3 | 61 | @entities; | ||||
| 339 | } | ||||||
| 340 | |||||||
| 341 | # | ||||||
| 342 | # A piece of HTML text which is used in some tests. | ||||||
| 343 | # | ||||||
| 344 | |||||||
| 345 | our $raw_html_data = <<'TEXT'; | ||||||
| 346 | |||||||
| 347 | |||||||
| 348 |  | ||||||
| 349 | |||||||
| 350 | |||||||
| 351 | |||||||
| 352 | Life according to Brian | ||||||
| 353 | |||||||
| 354 | This is normal text, but not in a paragraph. New paragraph | ||||||
| 355 | in a bad way. | ||||||
| 356 | |||||||
| 357 | And this is just a continuation. When texts get long, they must be | ||||||
| 358 | auto-wrapped; and even that is working already. | ||||||
| 359 | |||||||
| 360 | Silly subsection at once | ||||||
| 361 | and another chapter | ||||||
| 362 | again a section | ||||||
| 363 | Normal paragraph, which contains an  | ||||||
| 364 | SRC=image.gif>, some | ||||||
| 365 | italics with linebreak | ||||||
| 366 | and code | ||||||
| 367 | |||||||
| 368 |  | ||||||
| 369 | And now for the preformatted stuff | ||||||
| 370 | it should stay as it was | ||||||
| 371 | even with strange blanks | ||||||
| 372 | and indentations | ||||||
| 373 | |||||||
| 374 | |||||||
| 375 | And back to normal text... | ||||||
| 376 |  | ||||||
| 377 |  | ||||||
| 378 |  | ||||||
| 379 |  | ||||||
| 380 |  | ||||||
| 381 | |||||||
| 382 |  | ||||||
| 383 | |||||||
| 384 | |||||||
| 385 | |||||||
| 386 | TEXT | ||||||
| 387 | |||||||
| 388 | 1; |