| home / programming / awperl2 / 1 | [previous] [next] |
|
|
throws_ok { $array[6] = "dog" } qr/out of range/,
"Bounds exception";
is_deeply(\@array, [ 42 ], "Array contents correct");
These work immediately. But an ugly truth emerges when we try another simple array operation:
lives_ok { push @array, 17 } "Push works";
This results in:
not ok 5 - Push works
# Failed test (t/03use.t at line 19)
# died: Can't locate object method "PUSH" via package
"Tie::Array::Bounded" (perhaps you forgot to load
"Tie::Array::Bounded"?) at t/03use.t line 19. # Looks
like you failed 1 tests of 5.
Inspecting perltie reveals that PUSH is one of several
methods it looks like we’re going to have to write. Do we really have
to write them all? Can’t we be lazier than that?
Yes, we can.8 The Tie::Array core module defines PUSH and friends in terms
of a handful of methods we have to write: FETCH, STORE, FETCHSIZE, and STORESIZE.
The only one we haven’t done yet is STORESIZE:
sub STORESIZE
{
my ($self, $size) = @_;
$self->_bound_check($size-1);
$#{$self->{array}} = $size - 1;
}
We need to add near the top of Bounded.pm:
8. Remember, if you find yourself doing something too rote
or boring, look for a way to get the computer to make it easier for you. Top
of the list of those ways would be finding code someone else already wrote to
solve the problem.
use base qw(Tie::Array);
to inherit all that array method goodness.
This is a big step to take, and if we didn’t have canned tests, we might won¬der what sort of unknown havoc could be wrought upon our module by a new base class if we misused it. However, our test suite allows us to determine that, in fact, nothing has broken.
Now we can add to 01load.t the methods FETCH, STORE, FETCHSIZE, and STORESIZE
in the can_ok test:
Example 3.3 Final Version of 01load.t
#!/usr/bin/perl
use strict;
use warnings;
use Test::More tests => 2;
use blib;
BEGIN { use_ok("Tie::Array::Bounded") }
can_ok("Tie::Array::Bounded", qw(TIEARRAY STORE FETCH STORESIZE
FETCHSIZE));
Because our tests pass, let’s add as many more as we can to test all the boundary conditions we can think of, leaving us with a final 03use.t file of:
Example 3.4 Final Version of 03use.t
#!/usr/bin/perl
use strict;
use warnings;
use Test::More tests => 15;
use Test::Exception; use
blib;
use Tie::Array::Bounded;
my $RANGE_EXCEP = qr/out of range/;
my @array;
tie @array, "Tie::Array::Bounded", upper => 5;
lives_ok { $array[0]
= 42 } "Store works";
is($array[0], 42, "Fetch works");
throws_ok { $array[6] = "dog" } $RANGE_EXCEP,
"Bounds exception";
is_deeply(\@array, [ 42 ], "Array contents correct");
lives_ok { push @array, 17 } "Push works";
is($array[1], 17, "Second
array element correct");
lives_ok { push @array, 2, 3 } "Push multiple elements works";
is_deeply(\@array,
[ 42, 17, 2, 3 ], "Array contents correct");
lives_ok { splice(@array, 4, 0, qw(apple banana)) }
"Splice works";
is_deeply(\@array, [ 42, 17, 2, 3, 'apple', 'banana' ],
"Array contents correct");
throws_ok { push @array, "excessive" } $RANGE_EXCEP,
"Push bounds exception"; is(scalar @array,
6,
"Size of array correct");
tie @array, "Tie::Array::Bounded", lower => 3, upper
throws_ok { $array[1] = "too small" } $RANGE_EXCEP,
"Lower bound check failure";
lives_ok { @array[3..6] = 3..6 } "Slice assignment
works"; throws_ok { push @array, "too
big" }
$RANGE_EXCEP, "Push bounds exception";
Tests are real programs, too. Because we test for the same exception repeatedly, we put its recognition pattern in a variable to be lazy.
Bounded.pm, although not exactly a model of efficiency (our internal array
contains unnecessary space allocated to the first $lower elements that will
never be used), is now due for documenting, and h2xs filled out some POD stubs
already. We’ll flesh it out to the final version you can see in the Appendix.
I’ll go into documentation more in Chapter 10.
Now we create 04pod.t to test that the POD is formatted correctly:
Example 3.5 Final Version of 04pod.t
#!/usr/bin/perl
use strict;
use warnings;
use Test::Pod tests => 1;
use blib;
use Tie::Array::Bounded;
pod_ok($INC{"Tie/Array/Bounded.pm"});
There’s just a little trick there to allow us to run this test from any directory, since all the others can be run with the current working directory set to either the parent directory or the t directory. We load the module itself and then get Perl to tell us where it found the file by looking it up in the %INC hash, which tracks such things (see its entry in perlvar).
With a final “make test”, we’re done:
Files=4, Tests=24, 2 wallclock secs ( 1.58 cusr + 0.24 csys = 1.82 CPU)
We have a whole 24 tests at our fingertips ready to be repeated any time we want.
You can get more help on how to use these modules from the module Test::Tutorial, which despite the module appellation contains no code, only documentation.
With only a bit more work, this module could have been submitted to CPAN. See
[TREGAR02] for full instructions.
| home / programming / awperl2 / 1 | [previous] [next] |
Created: March 27, 2003
Revised: March 24, 2004
URL: http://webreference.com/programming/awperl2/1