1#!perl -w
2
3use strict;
4use Test::More;
5use File::Spec::Functions;
6
7if (eval { require HTML::Entities }) {
8    plan tests => 92;
9} else {
10    plan skip_all => "SVN::Notify::Alternative requires HTML::Entities";
11}
12
13use_ok 'SVN::Notify::Alternative' or die;
14
15my $ext = $^O eq 'MSWin32' ? '.bat' : '';
16
17my $dir = catdir curdir, 't', 'scripts';
18$dir = catdir curdir, 't', 'bin' unless -d $dir;
19
20my %args = (
21    svnlook    => catfile($dir, "testsvnlook$ext"),
22    sendmail   => catfile($dir, "testsendmail$ext"),
23    repos_path => 'tmp',
24    revision   => '111',
25    to         => 'test@example.com',
26    handler    => 'Alternative',
27);
28
29##############################################################################
30# Basic Functionality.
31##############################################################################
32
33ok my $notifier = SVN::Notify->new(%args), 'Construct new alt notifier';
34isa_ok $notifier, 'SVN::Notify::Alternative';
35isa_ok $notifier, 'SVN::Notify';
36ok $notifier->prepare, 'Prepare alt notifier';
37ok $notifier->execute, 'Execute the alt notifier';
38
39my $email = get_output();
40my $mime_count = ($email =~ s/MIME-Version/MIME-Version/g);
41is $mime_count, 1, 'There should be only one MIME-Version header';
42
43my ($bound) = $email
44    =~ m{Content-Type: multipart/alternative; boundary="([^"]+)"};
45ok $bound, 'There should be a multiplart/alternative header';
46
47my $bound_count = ($email =~ s/--$bound/--$bound/g);
48is $bound_count, 3, 'There should be three instances of the boundary';
49like $email, qr{--$bound--\s+$},
50    'The message should end with the final boundary';
51
52like $email, qr{Content-Type: text/plain; charset=UTF-8},
53    'There should be a plain text content-type';
54
55like $email, qr{Content-Type: text/html; charset=UTF-8},
56    'There should be an HTML content-type';
57
58# Make sure we have headers for each of the four kinds of changes.
59for my $header (
60    'Log Message',
61    'Modified Paths',
62    'Added Paths',
63    'Removed Paths',
64    'Property Changed',
65) {
66    like $email, qr/^$header/m, $header;
67    like $email, qr{^<h3>$header</h3>}m, "HTML $header";
68}
69
70##############################################################################
71# Try with diff.
72##############################################################################
73ok $notifier = SVN::Notify->new(
74    %args,
75    with_diff => 1,
76), 'Construct new colordiff alt notifier';
77isa_ok $notifier, 'SVN::Notify::Alternative';
78isa_ok $notifier, 'SVN::Notify';
79ok $notifier->prepare, 'Prepare alt notifier';
80ok $notifier->execute, 'Execute the alt notifier';
81
82$email = get_output();
83
84($bound) = $email
85    =~ m{Content-Type: multipart/alternative; boundary="([^"]+)"};
86ok $bound, 'There should be a multiplart/alternative header';
87
88$bound_count = ($email =~ s/--$bound/--$bound/g);
89is $bound_count, 3, 'There should be three instances of the boundary';
90like $email, qr{--$bound--\s+$},
91    'The message should end with the final boundary';
92
93like $email, qr{Content-Type: text/plain; charset=UTF-8},
94    'There should be a plain text content-type';
95
96like $email, qr{Content-Type: text/html; charset=UTF-8},
97    'There should be an HTML content-type';
98
99like $email, qr{^Modified: trunk/Params-CallbackRequest/Changes}m,
100    'The diff should be embedded in the plain text mesage';
101
102like $email,
103    qr{^<a id="trunkParamsCallbackRequestChanges">Modified: trunk/Params-CallbackRequest/Changes}m,
104    'The diff should be embedded in the HTML message';
105
106##############################################################################
107# Try with ColorDiff.
108##############################################################################
109ok $notifier = SVN::Notify->new(
110    %args,
111    alternatives => ['HTML::ColorDiff'],
112    with_diff    => 1,
113), 'Construct new colordiff alt notifier';
114isa_ok $notifier, 'SVN::Notify::Alternative';
115isa_ok $notifier, 'SVN::Notify';
116ok $notifier->prepare, 'Prepare alt notifier';
117ok $notifier->execute, 'Execute the alt notifier';
118
119$email = get_output();
120
121($bound) = $email
122    =~ m{Content-Type: multipart/alternative; boundary="([^"]+)"};
123ok $bound, 'There should be a multiplart/alternative header';
124
125$bound_count = ($email =~ s/--$bound/--$bound/g);
126is $bound_count, 3, 'There should be three instances of the boundary';
127like $email, qr{--$bound--\s+$},
128    'The message should end with the final boundary';
129
130like $email, qr{Content-Type: text/plain; charset=UTF-8},
131    'There should be a plain text content-type';
132
133like $email, qr{Content-Type: text/html; charset=UTF-8},
134    'There should be an HTML content-type';
135
136like $email, qr{^Modified: trunk/Params-CallbackRequest/Changes}m,
137    'The diff should be embedded in the HTML mesage';
138
139like $email,
140    qr{^<div class="modfile"><h4>Modified: trunk/Params-CallbackRequest/Changes}m,
141    'The diff should be embedded in the HTML message';
142
143##############################################################################
144# Try with multiple alternatives.
145##############################################################################
146ok $notifier = SVN::Notify->new(
147    %args,
148    alternatives => ['HTML', 'HTML::ColorDiff'],
149    with_diff    => 1,
150), 'Construct new colordiff alt notifier';
151isa_ok $notifier, 'SVN::Notify::Alternative';
152isa_ok $notifier, 'SVN::Notify';
153ok $notifier->prepare, 'Prepare alt notifier';
154ok $notifier->execute, 'Execute the alt notifier';
155
156$email = get_output();
157
158($bound) = $email
159    =~ m{Content-Type: multipart/alternative; boundary="([^"]+)"};
160ok $bound, 'There should be a multiplart/alternative header';
161
162$bound_count = ($email =~ s/--$bound/--$bound/g);
163is $bound_count, 4, 'There should be four instances of the boundary';
164like $email, qr{--$bound--\s+$},
165    'The message should end with the final boundary';
166
167like $email, qr{Content-Type: text/plain; charset=UTF-8},
168    'There should be a plain text content-type';
169
170like $email, qr{Content-Type: text/html; charset=UTF-8},
171    'There should be an HTML content-type';
172
173like $email, qr{^Modified: trunk/Params-CallbackRequest/Changes}m,
174    'The diff should be embedded in the HTML mesage';
175
176like $email,
177    qr{^<div class="modfile"><h4>Modified: trunk/Params-CallbackRequest/Changes}m,
178    'The diff should be embedded in the HTML message';
179
180like $email,
181    qr{^<div class="modfile"><h4>Modified: trunk/Params-CallbackRequest/Changes}m,
182    'The diff should be embedded in the HTML::ColorDiff message';
183
184##############################################################################
185# Try with attach_diff.
186##############################################################################
187ok $notifier = SVN::Notify->new(
188    %args,
189    attach_diff => 1,
190), 'Construct new colordiff alt notifier';
191isa_ok $notifier, 'SVN::Notify::Alternative';
192isa_ok $notifier, 'SVN::Notify';
193ok $notifier->prepare, 'Prepare alt notifier';
194ok $notifier->execute, 'Execute the alt notifier';
195
196$email = get_output();
197
198($bound) = $email
199    =~ m{Content-Type: multipart/alternative; boundary="([^"]+)"};
200ok $bound, 'There should be a multiplart/alternative header';
201
202$bound_count = ($email =~ s/--$bound/--$bound/g);
203is $bound_count, 3, 'There should be three instances of the alt boundary';
204like $email, qr{--$bound--\s+$},
205    'The message should end with the final alt boundary';
206
207my ($mbound) = $email
208    =~ m{Content-Type: multipart/mixed; boundary="([^"]+)"};
209ok $mbound, 'There should be a multipart/mixed header';
210$bound_count = ($email =~ s/--$mbound/--$mbound/g);
211is $bound_count, 3, 'There should be three instances of the mixed boundary';
212like $email, qr{--$mbound--\n--$bound--\s+$},
213    'The message should end with the final mixed and alt boundaries';
214
215like $email, qr{Content-Type: text/plain; charset=UTF-8},
216    'There should be a plain text content-type';
217
218like $email, qr{Content-Type: text/html; charset=UTF-8},
219    'There should be an HTML content-type';
220
221like $email, qr{^Modified: trunk/Params-CallbackRequest/Changes}m,
222    'The diff should be embedded in the plain text mesage';
223
224like $email, qr{--$bound\nContent-Type: multipart/mixed; boundary="$mbound"},
225    'The multipart/mixed header should come after an alt boundary';
226
227like $email, qr{--$mbound\nContent-Type: text/html; charset=UTF-8},
228    'The multipart message should be the HTML format';
229
230like $email,
231    qr{--$mbound\nContent-Disposition: attachment; filename=r111-theory\.diff},
232    'The diff should be attached to the message';
233
234my $attach_count = ( $email
235        =~ s/Content-Disposition: attachment/Content-Disposition: attachment/g
236    )
237;
238
239is $attach_count, 1, 'The attachment should be attached only once';
240
241##############################################################################
242# Try max_diff_length
243#############################################################################
244ok $notifier = SVN::Notify->new(
245    %args,
246    with_diff       => 1,
247    max_diff_length => 1024,
248), 'Construct new colordiff alt notifier';
249
250isa_ok $notifier, 'SVN::Notify::Alternative';
251isa_ok $notifier, 'SVN::Notify';
252ok $notifier->prepare, 'Prepare alt notifier';
253ok $notifier->execute, 'Execute the alt notifier';
254
255# Check the output.
256$email = get_output();
257like $email, qr{Use Apache::RequestRec for mod_perl 2},
258    'Check for the last diff line';
259unlike $email, qr{ BEGIN }, 'Check for missing extra line';
260like $email, qr{Diff output truncated at 1024 characters.},
261    'Check for truncation message';
262
263##############################################################################
264# Try using the Trac filter.
265##############################################################################
266SKIP: {
267    eval 'require Text::Trac';
268    skip 'Text::Trac did not load', 7 if $@;
269
270    ok $notifier = SVN::Notify->new(
271        %args,
272        filters => ['Trac'],
273    ), 'Construct Trac-filtered alt notifier';
274
275    isa_ok $notifier, 'SVN::Notify::Alternative';
276    isa_ok $notifier, 'SVN::Notify';
277    ok $notifier->prepare, 'Prepare alt notifier';
278    ok $notifier->execute, 'Execute the alt notifier';
279
280    # Check the output.
281    $email = get_output();
282    my ($bound) = $email
283        =~ m{Content-Type: multipart/alternative; boundary="([^"]+)"};
284    my @parts = split "--$bound", $email;
285    my $text = $parts[1];
286    use utf8;
287    like $text,
288        qr/^Did this, that, and the «other»\. And then I did some more\. Some\nit was done on a second line\. “Go figure”\. r1234\n/m,
289        'Should have plain text log message in the plain text part';
290    my $html = $parts[2];
291    like $html,
292        qr{<p>\s*Did this, that, and the «other»[.] And then I did some more[.] Some\nit was done on a second line[.] “Go figure”[.] <a class="changeset" href="/changeset/1234">r1234</a>\s*</p>}ms,
293        'Check for Trac formatting in the HTML part';
294}
295
296##############################################################################
297# Functions.
298##############################################################################
299
300sub get_output {
301    my $outfile = catfile qw(t data output.txt);
302    open CAP, "<$outfile" or die "Cannot open '$outfile': $!\n";
303    binmode CAP, 'utf8' if SVN::Notify::PERL58();
304    return join '', <CAP>;
305}
306