File Coverage

blib/lib/Mail/Action/Test.pm
Criterion Covered Total %
statement 218 218 100.0
branch n/a
condition n/a
subroutine 45 45 100.0
pod 0 18 0.0
total 263 281 93.5


line stmt bran cond sub pod time code
1             package Mail::Action::Test;
2              
3 1     1   640 use strict;
  1         2  
  1         36  
4 1     1   7 use warnings;
  1         2  
  1         32  
5              
6 1     1   5 use base 'Test::Class';
  1         5  
  1         1420  
7 1     1   49866 use Test::More;
  1         8141  
  1         11  
8 1     1   1438 use Test::Exception;
  1         3627  
  1         5  
9              
10 1     1   1334 use IO::File;
  1         12549  
  1         172  
11 1     1   1022 use Email::MIME;
  1         98660  
  1         53  
12 1     1   15 use Email::MIME::Modifier;
  1         4  
  1         21  
13 1     1   1314 use Test::MockObject;
  1         3827  
  1         9  
14              
15             # subclasses M::A to set a storage class
16 24     24 0 110 sub module { 'Mail::Action::WithStorage' }
17 12     12 0 61 sub request { 'Mail::Action::Request' }
18              
19             sub startup :Test( startup => 3 )
20             {
21 1     1 0 13107 my $self = shift;
22 1         33 my $module = $self->module();
23              
24 1     1   8 use_ok( 'Mail::Action' );
  1         1254  
  1         3  
  1         3  
  1         24  
25 1     1   959 use_ok( $module );
  1         125  
  1         3  
  1         2  
  1         23  
26 1         585 can_ok( $module, 'new' );
27              
28             # XXX: a bit of a hack here
29 2     2   13 Test::MockObject->fake_module( 'Mail::Mailer',
30 1         696 new => sub ($@) {$self->{mail}});
31 1     1   195 }
  1         3  
  1         14  
32              
33             sub setup :Test( setup )
34             {
35 11     11 0 12084 my $self = shift;
36 11         60 my $module = $self->module();
37 11         51 my $req = $self->request()->new( $self->message() );
38 11         223 $self->{ma} = $module->new( 'dir', Request => $req );
39 11         411 $self->{mail} = Test::MockObject->new();
40 1     1   496 }
  1         2  
  1         5  
41              
42             sub message
43             {
44 16     16 0 107 return <<'END_HERE';
45             From: me@home
46             To: you@house
47             Subject: Hi there
48              
49             Hello!
50              
51             Well, bye.
52             END_HERE
53              
54             }
55              
56             sub new_exception :Test
57             {
58 1     1 0 237 my $self = shift;
59 1         6 my $module = $self->module();
60 1     1   18 throws_ok { $module->new() } qr/No address directory provided/,
  1         60  
61             'new() should throw exception without address directory';
62 1     1   402 }
  1         3  
  1         6  
63              
64             sub new_from_text :Test( 2 )
65             {
66 1     1 0 221 my $self = shift;
67 1         4 my $module = $self->module();
68 1         7 can_ok( $module, 'message' );
69 1         719 my $ma = $module->new( 'dir', $self->message() );
70              
71 1         12 like( $ma->message->body(), qr/Hello!/,
72             'new() should set messsage from string given only two arguments' );
73 1     1   377 }
  1         3  
  1         5  
74              
75             sub new_from_fh: Test( 3 )
76             {
77 1     1 0 220 my $self = shift;
78 1         4 my $module = $self->module();
79 1         4 my $message = $self->message();
80 1         360 my $fh = IO::File->new_tmpfile();
81 1         34 my $pos = $fh->getpos();
82              
83 1         11 $fh->print( $message );
84 1         156 $fh->setpos( $pos );
85              
86 1         12 my $ma = $module->new( 'dir', $fh );
87 1         8 like( $ma->message->body(), qr/Hello!/,
88             'new() should set message body from filehandle, given two arguments' );
89              
90 1         789 $fh->setpos( $pos );
91 1         5 my %options = ( Filehandle => $fh );
92 1         8 $ma = $module->new( 'dir', %options );
93 1         43 like( $ma->message->body(), qr/Hello!/,
94             '... or from filehandle, when passed as Filehandle option' );
95              
96 1         577 $options{Filehandle} = $message;
97 1         7 $ma = $module->new( 'dir', %options );
98 1         14 like( $ma->message->body(), qr/Hello!/,
99             '... or from string, when passed as Filehandle option (yow!)' );
100 1     1   699 }
  1         4  
  1         6  
101              
102             sub new_with_storage :Test( 5 )
103             {
104 1     1 0 221 my $self = shift;
105 1         5 my $module = $self->module();
106 1         5 my %options = ( Filehandle => $self->message() );
107              
108 1         7 can_ok( $module, 'storage' );
109              
110 1         892 my $ma = $module->new( 'dir', %options );
111 1         10 like( $ma->storage(), qr/^ST:/,
112             'new() should default to storage_class() storage object' );
113              
114 1         649 is( $ma->storage(), 'ST: dir', '... passing address directory' );
115              
116 1         475 $options{Addresses} = 'addresses';
117 1         9 $ma = $module->new( 'dir', %options );
118 1         53 is( $ma->storage(), 'addresses', '... or Addresses option' );
119              
120 1         596 $options{Storage} = 'storage';
121 1         8 $ma = $module->new( 'dir', %options );
122 1         13 is( $ma->storage(), 'storage', '... preferring Storage option' );
123 1     1   531 }
  1         2  
  1         7  
124              
125             sub new_from_stdin :Test( 1 )
126             {
127 1     1 0 228 my $self = shift;
128 1         4 my $module = $self->module();
129 1         477 my $fh = IO::File->new_tmpfile();
130 1         15 my $pos = $fh->getpos();
131 1         5 $fh->print( $self->message() );
132 1         80 $fh->setpos( $pos );
133              
134 1         5 local *STDIN = $fh;
135 1         10 my $ma = $module->new( 'dir' );
136 1         9 like( $ma->message->body(), qr/Hello!/,
137             'new() should read from STDIN, given only one argument' );
138 1     1   415 }
  1         3  
  1         4  
139              
140             sub fetch_address :Test( 4 )
141             {
142 1     1 0 232 my $self = shift;
143 1         26 my $module = $self->module();
144              
145 1         6 can_ok( $module, 'fetch_address' );
146              
147 1         872 my $mock_store = Test::MockObject->new()
148             ->set_series( exists => 0, 1, 1 )
149             ->set_always( fetch => 'addy' );
150              
151 1         89 my $req = $self->request()->new( $self->message() );
152 1         27 my $ma = $module->new( 'dir', Storage => $mock_store, Request => $req );
153              
154 1         8 is( $ma->fetch_address(), undef,
155             'fetch_address() should return undef unless address exists' );
156 1         822 is( $ma->fetch_address(), 'addy',
157             '... or existing address, in scalar context' );
158              
159 1         576 is_deeply( [ $ma->fetch_address() ], [qw( addy alias )],
160             '... or address and alias, in list context' );
161 1     1   429 }
  1         2  
  1         4  
162              
163             sub command_help :Test( 4 )
164             {
165 1     1 0 250 my $self = shift;
166 1         6 my $module = $self->module();
167 1         7 can_ok( $module, 'command_help' );
168              
169 1         886 my $ma = $self->{ma};
170 1         4 my $mock_mail = $self->{mail};
171 1         20 $mock_mail->set_true( 'open' )
172             ->set_true( 'print' )
173             ->set_true( 'close' );
174              
175              
176 1         123 my $pod =<
177             =head1 FOO
178              
179             some text
180              
181             =head1 USING LISTS
182              
183             more text
184              
185             =head1 DIRECTIVES
186              
187             Yet More Text.
188              
189             =head1 CREDITS
190              
191             no one of consequence
192             END_HERE
193              
194 1         13 $ma->request->store_header( 'From', [ Email::Address->parse( 'some@here' ) ] );
195 1         7 $ma->command_help( $pod, 'USING LISTS', 'DIRECTIVES' );
196              
197 1         114 my ($method, $args) = $mock_mail->next_call();
198 1         35 is( $args->[1]{To}, 'some@here',
199             'command_help() should reply to sender' );
200 1         865 is( $args->[1]{Subject}, $self->module() . ' Help',
201             '... with appropriate subject' );
202 1         511 ($method, $args) = $mock_mail->next_call();
203 1         28 is( $args->[1],
204             "USING LISTS\n\n more text\n\nDIRECTIVES\n\n Yet More Text.",
205             '... with text extracted from passed-in POD' );
206 1     1   478 }
  1         2  
  1         6  
207              
208             sub process_body :Test( 8 )
209             {
210 1     1 0 281 my $self = shift;
211 1         8 my $module = $self->module();
212 1         4 my $ma = $self->{ma};
213              
214 1         8 can_ok( $module, 'process_body' );
215              
216 1         847 my $mock_store = Test::MockObject->new();
217 1         16 $mock_store->set_always( attributes => { foo => 1, bar => 1 } )
218             ->set_true( 'foo' )
219             ->set_true( 'bar' )
220             ->clear();
221              
222 1         129 $ma->message->body_set(
223             "Foo: foo\nCar: vroom\nbaR: b a r\n\nMy: friend\nhi\n-- \nFOO: moo"
224             );
225              
226 1         100 is_deeply( $ma->process_body( $mock_store ), [ '', 'My: friend', 'hi' ],
227             'process_body() should return message without directives or sig' );
228 1         853 my ($method, $args) = $mock_store->next_call( 2 );
229 1         27 is( $method, 'foo', '... calling directive found' );
230 1         1046 is( $args->[1], 'foo', '... passing directive value found' );
231 1         479 ($method, $args) = $mock_store->next_call();
232 1         27 isnt( $method, 'car', '... not calling unknown directive' );
233 1         619 is( $method, 'bar', '... lowercasing directive name' );
234 1         1285 is( $args->[1], 'b a r', '... passing entire directive value found' );
235              
236 1         616 $ma->message->body_set();
237 1         694 is_deeply( $ma->process_body( $mock_store ), [],
238             '... returning empty list with no body' );
239 1     1   656 }
  1         3  
  1         6  
240              
241             sub reply :Test( 6 )
242             {
243 1     1 0 313 my $self = shift;
244 1         9 my $module = $self->module();
245 1         382 my $ma = $self->{ma};
246 1         532 my $mock_mail = $self->{mail}->set_true(qw( open print close ));
247              
248 1         265 can_ok( $module, 'reply' );
249              
250 1         1195 $ma->reply( 'headers', 'body', 'lines' );
251 1         59 my ($method, $args) = $mock_mail->next_call();
252 1         27 is( $method, 'open', 'reply() should open a Mail::Mailer object' );
253 1         642 is( $args->[1], 'headers', '... passing headers' );
254              
255 1         787 ($method, $args) = $mock_mail->next_call();
256 1         33 is( $method, 'print', '... printing body' );
257 1         622 is( "@$args", "$mock_mail body lines", '... all lines passed' );
258 1         538 is( $mock_mail->next_call(), 'close', '... closing message' );
259 1     1   478 }
  1         3  
  1         6  
260              
261             sub find_command :Test( 5 )
262             {
263 1     1 0 205 my $self = shift;
264 1         6 my $module = $self->module();
265 1         3 my $ma = $self->{ma};
266              
267 1         7 can_ok( $module, 'find_command' );
268              
269 1         729 is( $ma->find_command(), undef,
270             'find_command() should return undef without a valid command' );
271 1         523 $ma->request->store_header( 'Subject', [ '*help*' ] );
272 1         5 is( $ma->find_command(), 'command_help',
273             '... or the name of the command sub, if it exists' );
274 1         503 $ma->request->store_header( 'Subject', [ '*hElP*' ] );
275 1         5 is( $ma->find_command(), 'command_help',
276             '... regardless of capitalization' );
277 1         551 $ma->request->store_header( 'Subject', [ '*drinkME*' ] );
278 1         5 is( $ma->find_command(), '',
279             '... or an empty string if command does not match' );
280 1     1   561 }
  1         2  
  1         5  
281              
282             sub copy_headers: Test( 4 )
283             {
284 1     1 0 242 my $self = shift;
285 1         5 my $module = $self->module();
286 1         4 my $ma = $self->{ma};
287 1         7 my $req = $ma->request();
288              
289 1         8 can_ok( $module, 'copy_headers' );
290              
291 1         713 $req->store_header( 'Subject', [ '*help*' ] );
292 1         17 $req->store_header( 'To', [ 'you@house' ] );
293 1         6 $req->store_header( 'From', [ 'me@home' ] );
294 1         6 $req->store_header( 'From ', [ 1 ] );
295 1         5 $req->store_header( 'Cc', [ 1 ] );
296 1         7 $req->store_header( 'Content-type', [ '' ] );
297              
298 1         5 my $result = $ma->copy_headers();
299              
300 1         9 isnt( $result, $ma->message()->{head},
301             'copy_headers() should make a new hash' );
302 1         575 is_deeply( $result,
303             { From => 'me@home', Subject => '*help*', To => 'you@house', Cc => 1,
304             'Content-type' => '', 'Delivered-to' => '' },
305             '... cleaning header names' );
306 1         2463 ok( ! exists $result->{'From '}, '... removing mbox From header' );
307 1     1   489 }
  1         3  
  1         5  
308              
309             package Mail::Action::WithStorage;
310              
311             @Mail::Action::WithStorage::ISA = 'Mail::Action';
312              
313             $INC{'Mail/Action/WithStorage.pm'} = 1;
314 20     20 0 57 sub storage_class { 'StorageTest' }
315 3     3 0 12 sub parse_alias { 'alias' }
316              
317             package StorageTest;
318              
319 17     17   71 sub new { 'ST: ' . $_[1] };
320              
321             1;