#!/usr/bin/perl # # usage: t.rules/run [--verbose] [--tests=BOUNCE_MESSAGE,FOO,BAR] [file ...] # # TODO: Generate TAP output use strict; use warnings; use Getopt::Long; Getopt::Long::Configure( qw(bundling no_getopt_compat permute no_auto_abbrev no_ignore_case) ); my %opt = ( ); GetOptions( 'tests|t=s' => \$opt{'tests'}, 'verbose|v' => \$opt{'verbose'}, 'debug|D' => \$opt{'debug'}, ); my $USE_EXTERNAL_SA = 0; my $spamtest; if (!$USE_EXTERNAL_SA) { use lib 'lib'; use lib 'blib/lib'; use Mail::SpamAssassin; create_spamtest(); } my $verbose = $opt{'verbose'}; $opt{'tests'} ||= join " ", ; my $testsfailed = 0; if (@ARGV) { foreach my $f (@ARGV) { test_msg($f, $1); } } else { main(); } if (!$USE_EXTERNAL_SA) { $spamtest->finish(); } exit $testsfailed; # --------------------------------------------------------------------------- sub main { foreach my $rule (split(/[\s,]/, $opt{'tests'})) { $rule =~ s/^t.rules\///; chomp $rule; my $ruledir="t.rules/$rule"; next unless -d $ruledir; warn "\nRunning tests for $rule:\n" if $verbose; foreach my $f (<$ruledir/*>) { (-f $f) and test_msg($f); } } } # --------------------------------------------------------------------------- sub test_msg { my ($f) = @_; ($f =~ /\/([^\/]+)\/[^\/]+$/) or warn "cannot find rule in '$f'"; my $rule = $1; # if the filename starts with "fp", we want a _miss_ for the named rule my $want_hit = 1; if ($f =~ /\/fp/i) { $want_hit = 0; } # TODO: read file, find "Config: " synthetic headers, add them to --cf or # recreate $spamtest object with those in place. my $testsline; if ($USE_EXTERNAL_SA) { my $dbg = ''; $opt{debug} and $dbg = '-D'; open (IN, "./spamassassin --cf='use_bayes 0' --cf='use_awl 0' $dbg -Lt < $f 2>&1 |") or warn "sa failed"; open (LOG, ">o.log") or die; while () { print LOG; /check: tests=(.*)$/ and $testsline = $1; /check: subtests=(.*)$/ and $testsline .= ",$1"; } close IN; close LOG; } else { open (STDIN, "<$f") or warn "cannot open $f"; my $mail = $spamtest->parse(); my $status = $spamtest->check($mail); $testsline = $status->get_names_of_tests_hit().",".$status->get_names_of_subtests_hit(); $mail->finish(); $status->finish(); close STDIN; } if ($testsline =~ /(?:[ ,]|^)\Q$rule\E(?:[ ,]|$)/) { if ($want_hit) { pass($rule, $f, "$testsline"); } else { fail($rule, $f, "want=n got=y: $testsline"); } } else { if ($want_hit) { fail($rule, $f, "want=y got=n: $testsline"); } else { pass($rule, $f, "$testsline"); } } } # --------------------------------------------------------------------------- sub fail { my ($rule, $f, $err) = @_; print "NOT ok on $f for $rule: $err\n"; $testsfailed++; } sub pass { my ($rule, $f, $err) = @_; if (!$verbose) { print "ok on $f\n" } else { print "ok on $f for $rule: $err\n" } } # --------------------------------------------------------------------------- sub create_spamtest { $spamtest->finish() if $spamtest; $spamtest = new Mail::SpamAssassin( { rules_filename => 'rules', site_rules_filename => 'rules/local.cf', userprefs_filename => '', local_tests_only => 1, debug => $opt{debug}, dont_copy_prefs => 1, post_config_text => "use_learner 0\nuse_auto_whitelist 0\n", require_rules => 1, } ); $spamtest->init(1); } # ---------------------------------------------------------------------------