spacer

Webref WebRef   Sitemap · Experts · Tools · Services · Newsletters · About i.com

home / programming / awperl / 1 To page 1To page 2current pageTo page 4
[previous] [next]

Sr Instructional Designer D2L-Moodle,Clearance
WSI Nationwide, Inc.
US-NJ-Fort Monmouth

Justtechjobs.com Post A Job | Post A Resume
Developer News
News Flash: Adobe Has iPhone Workaround
Adobe's Flash 10.1 Goes Mobile (Minus iPhone)
A Salute to Visionary CEOs


Perl Medic: Transforming Legacy Code. Chapter 3. Pt. 1

3.2.5 The Test::Builder Module

Did you spot that all these modules have a lot in common? Did you wonder how you’d add a Test:: module of your own, if you wanted to write one?

Then you’re already thinking lazily, and the testing guys are ahead of you. That common functionality lives in a superclass module called Test::Builder, seldom seen, but used to take the drudgery out of creating new test modules.

Suppose we want to write a module that checks whether mail messages conform to RFC 822 syntax.3 We’ll call it Test::MailMessage, and it will export a basic function, msg_ok(), that determines whether a message consists of an optional set of header lines, optionally followed by a blank line and any num¬ber of lines of text. (Yes, an empty message is legal according to this syntax. Unfortunately, too few people who have nothing to say avail themselves of this option.) Here’s the module:

Example 3.1 Using Test::Builder to Create Test::MailMessage

1 package Test::MailMessage; 2 use strict; 3 use warnings; 4 use Carp;
5 use Test::Builder;
6 use base qw(Exporter);
7 our @EXPORT = qw(msg_ok);
8
9 my $test = Test::Builder->new;
10
11 sub import 12
{

13 my $self = shift; 14 my $pack = caller;
15
16    $test->exported_to($pack);
17    $test->plan(@_);

3. http://www.faqs.org/rfcs/rfc822.html

18
19    $self->export_to_level(1, $self, 'msg_ok');
20 } 21
22 sub msg_ok
23 {
24 my $arg = shift;
25 my $tester = _new();
26      eval
27    {
28      if (defined(fileno($arg)))
29          {
30        while (<$arg>)
31       {
32          $tester->_validate($_);
33        }
34       }
35             elsif (ref $arg)
36       {
37         $tester->_validate($_) for @$arg;
38       }
39       else
40       {
41                for ($arg =~ /(.*\n)/g)
42        {
43                 $tester->_validate($_);
44        }
45      }
46    };
47    $test->ok(!$@, shift);
48    $test->diag($@) if $@;
49 } 50
51 sub _new
52 {
53    return bless { expect => "header" };
54 } 55
56 sub _validate
57 {
58      my ($self, $line) = @_;
59    return if $self->{expect} eq "body";

 

 

 

60

 

if ($self->{expect} eq "header/continuation")

61

 

{

62

 

/^\s+\S/ and return;

63

 

}

64

 

$self->{expect} = "body", return if /^$/;

65

 

/^\S+:/ or croak "Invalid header";

66

 

$self->{expect} = "header/continuation";

67

}

 

68

 

 

69

1;

 

In line 1 we put this module into its own package, and in lines 2 and 3 we set warnings and strictness to help development go smoothly. In lines 4 and 5 we load the Carp module so we can call croak(), and the Test::Builder module so we can create an instance of it. In lines 6 and 7 we declare this to be a subclass of the Exporter module, exporting to the caller the subroutine msg_ok(). (Note that this is not a subclass of Test::Builder.)

In line 9 we create a Test::Builder object that will do the boring part of testing for us. Lines 11 through 20 are copied right out of the Test::Builder docu¬mentation; the import() routine is what allows us to say how many tests we’re going to run when we use the module.

Lines 22 through 49 define the msg_ok() function itself. Its single argument specifies the mail message, either via a scalar containing the message, a reference to an array of lines in the message, or a filehandle from which the message can be read. Rather than read all of the lines from that filehandle into memory, we’re going to operate on them one at a time because it’s not necessary to have the whole message in memory. That’s why we create the object $tester in line 25 to handle each line: it will contain a memory of its current state.

Then we call the _validate() method of $tester with each line of the message. Because that method will croak() if the message is in error, we wrap those loops in an eval block. This allows us easily to skip superfluous scanning of a message after detecting an error.

Finally, we see whether an error occurred; if an exception was thrown by croak()inside the eval block, $@ will contain its text; otherwise $@ will be empty. The ok() method of the Test::Builder object we created is the same function we’re used to using in Test::Simple; it takes a true or false value, and an optional tag string, which we pass from our caller. If we had an exception, we pass its text to Test::Builder’s diag() method, which causes it to be out¬put as a comment during testing.

The _new() method in lines 50–53 is not called new() because it’s not really a proper constructor; it’s really just creating a state object, which is why we didn’t bother to make it inheritable. It starts out in life expecting to see a mail header.

Lines 56–70 validate a line of a message. Because anything goes in a message body, if that’s what we’re expecting we have nothing to do. Otherwise, if we’re expecting a header or header continuation line, then first we check for a continuation line (which starts with white space; this is how a long message header “overflows”). If we have a blank line (line 67), that separates the header from the body, so we switch to expecting body text.

Finally, we must at this point be expecting a header line, and one of those starts with non-white-space characters followed by a colon. If we don’t have that, the message is bogus; but if we do, the next line could be either a header line or a continuation of the current header (or the blank line separating head¬ers from the body).


home / programming / awperl / 1 To page 1To page 2current pageTo page 4
[previous] [next]

internet.commediabistro.comJusttechjobs.comGraphics.com

Search:

WebMediaBrands Corporate Info

Legal Notices, Licensing, Reprints, Permissions, Privacy Policy.
Advertise | Newsletters | Shopping | E-mail Offers | Freelance Jobs

webref The latest from WebReference.com Browse >
Building a Banking Application Home Page with OOP · Mixing Scripting Languages · Review: phpFox, a Social Networking CMS with all the Bells and Whistles
Sitemap · Experts · Tools · Services · Email a Colleague · Contact FREE Newsletters 
 The latest from internet.com
Enterprise 2.0: Social Networking in the Cloud · BroadSoft Marketplace Hastens Pace of Telephony Innovation · Review: HTC Hero for Sprint

Created: March 27, 2003
Revised: March 24, 2004

URL: http://webreference.com/programming/awperl/1