jkeenan1 has asked for the wisdom of the Perl Monks concerning the following question:
I have a module whose constructor:
Here is the complete package:
package Woeisme; use strict; local $^W = 1; use vars qw ($VERSION ); $VERSION = 0.01; use Carp; my %default_values = ( SUBJECT => 'Subject (<= 44 characters) goes here', AUTHOR => { NAME => 'A. U. Thor', CPANID => 'AUTHOR', WEBSITE => 'http://a.galaxy.far.far.away/modules', EMAIL => 'a.u.thor@a.galaxy.far.far.away', }, ); sub new { my ($class, %parameters) = @_; my $self = ref($class) ? bless( \%default_values, ref($class) ) : bless( \%default_values, $class ); foreach my $param ( keys %parameters ) { if ( ref( $parameters{$param} ) eq 'HASH' ) { foreach ( keys( %{ $parameters{$param} } ) ) { $self->{$param}{$_} = $parameters{$param}{$_}; } } else { $self->{$param} = $parameters{$param}; } } $self->verify_values(); return ($self); } sub verify_values { my $self = shift; my (@errors); push( @errors, 'NAME is required' ) unless ( $self->{NAME} ); push( @errors, 'Module NAME contains illegal characters' ) unless ( $self->{NAME} and $self->{NAME} =~ m/^[\w:]+$/ ); push( @errors, 'SUBJECTs are limited to 44 characters' ) if ( length( $self->{SUBJECT} ) > 44 ); push( @errors, 'CPAN IDs are 3-9 characters' ) if ( $self->{AUTHOR}{CPANID} !~ m/^\w{3,9}$/ ); push( @errors, 'EMAIL addresses need to have an at sign' ) if ( $self->{AUTHOR}{EMAIL} !~ m/.*\@.*/ ); push( @errors, 'WEBSITEs should start with an "http:" or "https:"' + ) if ( $self->{AUTHOR}{WEBSITE} !~ m/https?:\/\/.*/ ); if (@errors) { croak( join "\n", @errors, '', $!); } } 1;
I'm interested in testing for the cases where bad data is passed to the constructor. Do the proper error messages then appear? Since the real-world module displaying this problem creates directories and files, I try to test each distinct error in its own environment: a temporary directory set up with File::Temp. I have written failsafe() as a wrapper around the creation of the tempdir, the call to the constructor and the test. Here is the test file:
# -*- perl -*- # t/001_load.t - check module loading and create testing directory use Test::More qw{no_plan}; BEGIN { use_ok( 'Woeisme' ); } BEGIN { use_ok( 'File::Temp', qw| tempdir |); } BEGIN { use_ok( 'Cwd' ); } my $object = Woeisme->new ( 'NAME' => 'ABC::XYZ', ); isa_ok ($object, 'Woeisme'); failsafe( [ 'NAME' => 'ABC::XYZ', 'SUBJECT' => '123456789012345678901234567890123456789012345', ], "^SUBJECTs are limited to 44 characters", "Constructor correctly failed due to SUBJECT > 44 characters"); failsafe( [ 'NAME' => 'GHI::DEF', 'AUTHOR' => { NAME => 'James E Keenan', CPANID => 'ABCDEFGHIJ', }, ], "^CPAN IDs are 3-9 characters", "Constructor correctly failed due to CPANID > 9 characters"); sub failsafe { my ($argslistref, $pattern, $message) = @_; my $odir = cwd(); my ($tdir, $mod); $tdir = tempdir( CLEANUP => 1); ok(chdir $tdir, 'changed to temp directory for testing'); local $@ = undef; eval { $mod = Woeisme->new (@$argslistref); }; like($@, qr/$pattern/, $message); local $@ = undef; ok(chdir $odir, 'changed back to original directory after testing') +; }
Since there's only a single test file, once I have maked the package I can test it with either make test or prove -vb t/001_load.t.
Now, here's the problem. If I comment out one or the other of the two failsafe blocks so as to test just one feature at a time, there is no problem. But if I test the two in succession, the like test in the second block fails. It fails only because the wrong message is generated. Instead of getting an error message which begins
CPAN IDs are 3-9 characters
... I'm getting one that first repeats the error message from the previous call to failsafe(), and only then displays the expected error message:
SUBJECTs are limited to 44 characters CPAN IDs are 3-9 characters
I'm getting an error message about the SUBJECT even though I haven't declared any new SUBJECT (and, hence, the subject from %default_values should still prevail -- and that one was less than 44 characters in length). If you sprinkled some print statements around, you'd see that the value of SUBJECT in the second set of tests is 123456789012345678901234567890123456789012345 -- but shouldn't that value have been wiped out (a) because the first constructor failed and (b) because the first set of tests was properly scoped.
Given that each set of tests is limited to the scope of failsafe() and that each set is taking place in its own tempdir, I cannot see any reason why, when I run both test blocks in succession, the value of SUBJECT in the first lingers into the second and eventually causes the wrong error message to print out, causing like to generate a false value.
Any ideas? Thanks in advance.
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: Wrong Error Message When Testing for Failure of Constructor
by davidrw (Prior) on Jul 22, 2005 at 02:31 UTC | |
by jkeenan1 (Deacon) on Jul 22, 2005 at 19:47 UTC | |
|
Re: Wrong Error Message When Testing for Failure of Constructor
by tlm (Prior) on Jul 22, 2005 at 02:31 UTC | |
by jkeenan1 (Deacon) on Jul 22, 2005 at 17:39 UTC | |
by tlm (Prior) on Jul 22, 2005 at 18:52 UTC | |
by jkeenan1 (Deacon) on Jul 23, 2005 at 00:02 UTC | |
by tlm (Prior) on Jul 24, 2005 at 01:22 UTC | |
| |
by jkeenan1 (Deacon) on Jul 22, 2005 at 19:45 UTC |