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