Skip to content

Commit e2d315c

Browse files
authored
Merge pull request #41 from cpan-authors/koan.toddr.bot/fix-preproc-engine-bugs
fix: fix bugs in preprocessing/engine modules and add 44 tests
2 parents 6a9b4d2 + eb83ba4 commit e2d315c

4 files changed

Lines changed: 201 additions & 16 deletions

File tree

lib/Razor2/Engine/VR8.pm

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@ sub new {
1616
rm => $args{RM},
1717
}, $class;
1818

19-
die unless $self;
20-
2119
return $self;
2220

2321
}

lib/Razor2/Preproc/Manager.pm

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ sub preproc {
3636
my $lengths = { '1_orig' => length($$bodyref) } if $dolength;
3737

3838
#-- $self->{rm}->{log}->log(12, "before_deBase64:");
39-
if ( exists $$self{deBase64} && $self->{deBase64}->isit($bodyref) ) {
39+
if ( exists $self->{deBase64} && $self->{deBase64}->isit($bodyref) ) {
4040
$self->{deBase64}->doit($bodyref);
4141
}
4242

@@ -47,7 +47,7 @@ sub preproc {
4747

4848
#-- $self->{rm}->{log}->log(12, "before_deQP:");
4949
my $isQP;
50-
if ( exists $$self{deQP} && ( $isQP = $self->{deQP}->isit($bodyref) ) ) {
50+
if ( exists $self->{deQP} && ( $isQP = $self->{deQP}->isit($bodyref) ) ) {
5151
$self->{deQP}->doit($bodyref);
5252
}
5353

@@ -57,18 +57,18 @@ sub preproc {
5757
$lengths->{'3_after_deQP'} = length($$bodyref) if $dolength;
5858

5959
#-- $self->{rm}->{log}->log(12, "before_deHTML:");
60-
if ( exists $$self{deHTML} && $self->{deHTML}->isit($bodyref) ) {
60+
if ( exists $self->{deHTML} && $self->{deHTML}->isit($bodyref) ) {
6161
$self->{deHTML}->doit($bodyref);
6262
}
6363

6464
#-- $self->{rm}->{log}->log(12, "after_deHTML:");
6565

66-
if ( exists $$self{deHTML_comment} && $self->{deHTML_comment}->isit($bodyref) ) {
66+
if ( exists $self->{deHTML_comment} && $self->{deHTML_comment}->isit($bodyref) ) {
6767
$self->{deHTML_comment}->doit($bodyref);
6868
}
6969

7070
#-- $self->{rm}->{log}->log(12, "before_deNewline:");
71-
if ( exists $$self{deNewline} ) {
71+
if ( exists $self->{deNewline} ) {
7272
$self->{deNewline}->doit($bodyref);
7373
}
7474

@@ -87,13 +87,9 @@ sub preproc {
8787

8888
sub log2file {
8989
my ( $self, $msgref, $mailid ) = @_;
90-
my $len = length($$msgref);
9190
my $fh = File::Temp->new(TEMPLATE => "razor_debug_XXXXXX", TMPDIR => 1, SUFFIX => ".$mailid");
92-
my $fn = $fh->filename;
93-
if ($fh) {
94-
print $fh $$msgref;
95-
close $fh;
96-
}
91+
print $fh $$msgref;
92+
close $fh;
9793
}
9894

9995
1;

lib/Razor2/Preproc/deBase64.pm

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,11 @@ sub extract_base64 {
3636

3737
if ( $$text =~ /Content-Transfer-Encoding: base64(.*)$/si ) {
3838
my $rhs = $1;
39-
$rhs =~ /\r?\n\r?\n([^=]*)/s; # match to end of data or '='
40-
return $1 . "==";
39+
if ( $rhs =~ /\r?\n\r?\n([^=]*)/s ) {
40+
return $1 . "==";
41+
}
4142
}
42-
return undef;
43+
return;
4344
}
4445

4546
1;

t/manager.t

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
#!perl
2+
3+
use strict;
4+
use warnings;
5+
6+
use Test::More;
7+
8+
# --- Razor2::Preproc::Manager ---
9+
10+
use_ok('Razor2::Preproc::Manager');
11+
12+
{
13+
my $mgr = Razor2::Preproc::Manager->new;
14+
isa_ok( $mgr, 'Razor2::Preproc::Manager' );
15+
16+
# Default constructor creates all standard preprocessors
17+
ok( exists $mgr->{deBase64}, "default manager has deBase64" );
18+
ok( exists $mgr->{deQP}, "default manager has deQP" );
19+
ok( exists $mgr->{deHTML}, "default manager has deHTML" );
20+
ok( exists $mgr->{deNewline},"default manager has deNewline" );
21+
ok( !exists $mgr->{deHTML_comment}, "default manager omits deHTML_comment" );
22+
}
23+
24+
{
25+
# Selective preprocessor exclusion
26+
my $mgr = Razor2::Preproc::Manager->new( no_deBase64 => 1, no_deQP => 1 );
27+
ok( !exists $mgr->{deBase64}, "no_deBase64 disables deBase64" );
28+
ok( !exists $mgr->{deQP}, "no_deQP disables deQP" );
29+
ok( exists $mgr->{deHTML}, "deHTML still enabled" );
30+
ok( exists $mgr->{deNewline},"deNewline still enabled" );
31+
}
32+
33+
{
34+
# Opt-in deHTML_comment
35+
my $mgr = Razor2::Preproc::Manager->new( deHTML_comment => 1 );
36+
ok( exists $mgr->{deHTML_comment}, "deHTML_comment enabled via opt-in" );
37+
}
38+
39+
# --- preproc() pipeline tests ---
40+
41+
{
42+
# Plain text message: headers stripped, body returned
43+
my $mgr = Razor2::Preproc::Manager->new;
44+
my $text = "Subject: Test\nContent-Type: text/plain\n\nHello World\n";
45+
$mgr->preproc( \$text );
46+
47+
is( $text, "Hello World", "preproc strips headers and trailing newline" );
48+
}
49+
50+
{
51+
# Base64 message: decode + strip headers
52+
my $mgr = Razor2::Preproc::Manager->new;
53+
my $text = "Content-Type: text/plain\nContent-Transfer-Encoding: base64\n\nSGVsbG8gV29ybGQ=\n";
54+
$mgr->preproc( \$text );
55+
56+
like( $text, qr/Hello World/, "preproc decodes base64 body" );
57+
unlike( $text, qr/Content-Type/, "preproc removes headers from base64 message" );
58+
}
59+
60+
{
61+
# Quoted-printable message: decode + strip headers
62+
my $mgr = Razor2::Preproc::Manager->new;
63+
my $text = "Content-Transfer-Encoding: quoted-printable\n\nHello=20World\n";
64+
$mgr->preproc( \$text );
65+
66+
like( $text, qr/Hello World/, "preproc decodes quoted-printable body" );
67+
}
68+
69+
{
70+
# HTML message: tags stripped + headers stripped
71+
my $mgr = Razor2::Preproc::Manager->new;
72+
my $text = "Content-Type: text/html\n\n<HTML><BODY>Hello World</BODY></HTML>\n";
73+
$mgr->preproc( \$text );
74+
75+
like( $text, qr/Hello World/, "preproc strips HTML tags from body" );
76+
unlike( $text, qr/<HTML>/, "preproc removes HTML tags" );
77+
}
78+
79+
{
80+
# HTML comments stripped when deHTML_comment is enabled
81+
my $mgr = Razor2::Preproc::Manager->new( deHTML_comment => 1 );
82+
my $text = "Content-Type: text/html\n\n<HTML><!-- junk -->Real content</HTML>\n";
83+
$mgr->preproc( \$text );
84+
85+
unlike( $text, qr/junk/, "preproc removes HTML comments when enabled" );
86+
like( $text, qr/Real content/, "preproc preserves non-comment content" );
87+
}
88+
89+
{
90+
# Length tracking with dolength flag
91+
my $mgr = Razor2::Preproc::Manager->new;
92+
my $text = "Subject: Test\n\nBody content\n";
93+
my $lengths = $mgr->preproc( \$text, 1 );
94+
95+
ok( defined $lengths, "preproc returns length hash when dolength is set" );
96+
ok( ref $lengths eq 'HASH', "lengths is a hashref" );
97+
ok( exists $lengths->{'1_orig'}, "lengths has 1_orig" );
98+
ok( exists $lengths->{'5_after_header_removal'}, "lengths has 5_after_header_removal" );
99+
ok( $lengths->{'1_orig'} > $lengths->{'5_after_header_removal'},
100+
"original length > body-only length" );
101+
}
102+
103+
{
104+
# Without dolength, returns undef
105+
my $mgr = Razor2::Preproc::Manager->new;
106+
my $text = "Subject: Test\n\nBody\n";
107+
my $result = $mgr->preproc( \$text );
108+
109+
ok( !defined $result, "preproc returns undef without dolength" );
110+
}
111+
112+
{
113+
# Pipeline with all preprocessors disabled
114+
my $mgr = Razor2::Preproc::Manager->new(
115+
no_deBase64 => 1,
116+
no_deQP => 1,
117+
no_deHTML => 1,
118+
no_deNewline => 1,
119+
);
120+
my $text = "Subject: Test\n\nBody content";
121+
$mgr->preproc( \$text );
122+
123+
is( $text, "Body content", "preproc with all preprocessors disabled still strips headers" );
124+
}
125+
126+
# --- Razor2::Engine::VR8 ---
127+
128+
use_ok('Razor2::Engine::VR8');
129+
130+
{
131+
my $vr8 = Razor2::Engine::VR8->new;
132+
isa_ok( $vr8, 'Razor2::Engine::VR8' );
133+
ok( exists $vr8->{whiplash}, "VR8 has whiplash engine" );
134+
isa_ok( $vr8->{whiplash}, 'Razor2::Signature::Whiplash' );
135+
}
136+
137+
{
138+
# Signature for text with URLs
139+
my $vr8 = Razor2::Engine::VR8->new;
140+
my $text = "Check out http://www.example.com/page for great deals!";
141+
my $sigs = $vr8->signature( \$text );
142+
143+
ok( defined $sigs, "VR8 signature returns result for text with URL" );
144+
ok( ref $sigs eq 'ARRAY', "VR8 signature returns arrayref" );
145+
ok( @$sigs > 0, "VR8 produces at least one signature" );
146+
147+
# VR8 returns base64-encoded signatures (hextobase64 output)
148+
for my $sig (@$sigs) {
149+
ok( defined $sig && length($sig) > 0, "signature is non-empty" );
150+
}
151+
}
152+
153+
{
154+
# Deterministic signatures
155+
my $vr8 = Razor2::Engine::VR8->new;
156+
my $text = "Visit http://spam.example.net/offer today!";
157+
my $sigs1 = $vr8->signature( \$text );
158+
my $sigs2 = $vr8->signature( \$text );
159+
is_deeply( $sigs1, $sigs2, "VR8 signatures are deterministic" );
160+
}
161+
162+
{
163+
# No URLs = no signatures
164+
my $vr8 = Razor2::Engine::VR8->new;
165+
my $text = "This is plain text with no URLs at all.";
166+
my $sigs = $vr8->signature( \$text );
167+
168+
ok( !defined $sigs, "VR8 returns undef for text without URLs" );
169+
}
170+
171+
# --- Razor2::Client::Engine ---
172+
173+
use_ok('Razor2::Client::Engine');
174+
175+
{
176+
my @engines = Razor2::Client::Engine::supported_engines();
177+
ok( scalar @engines >= 2, "supported_engines returns at least 2 engines" );
178+
ok( ( grep { $_ == 4 } @engines ), "engine 4 is supported" );
179+
ok( ( grep { $_ == 8 } @engines ), "engine 8 is supported" );
180+
}
181+
182+
{
183+
# Scalar context returns hashref
184+
my $engines = Razor2::Client::Engine::supported_engines();
185+
ok( ref $engines eq 'HASH', "supported_engines returns hashref in scalar context" );
186+
ok( $engines->{4}, "engine 4 in hashref" );
187+
ok( $engines->{8}, "engine 8 in hashref" );
188+
}
189+
190+
done_testing;

0 commit comments

Comments
 (0)