Failed compilations can be partially successful
Apparently Perl doesn't clean up after a failed compile. However far it got sticks around. I didn't discover this myself, but here's an example:
eval <<'HERE';
package Weird;
use strict;
sub foo { print "hi\n" }
sub bar { print "$bar\n" }
1;
HERE
print "\$@ -> $@";
Weird::foo();
Weird::bar();
The Weird
package won't compile all the way because it has a strict
violation in Weird::bar()
. Here's the output, which shows that Weird::foo()
was defined and sticks around:
$@ -> Global symbol "$bar" requires explicit package name at (eval 1) line 4. hi Variable "$bar" is not imported at (eval 1) line 4. Undefined subroutine &Weird::bar called at test.pl line 14.
I'd never really thought about this because it was never much of a problem for me.
That could have implications for templating systems that embed Perl directly. They could compile a subroutine that was placed in the template, stick it in the package namespace, and then hit a syntax error later.
But other than taking up a little extra memory before erroring out, I'm not sure that has any practical issues.
It becomes a problem if you later use
Weird->can("foo")
as an indicator of whether theWeird
package loaded successfully.This is part of the reason Test::Most can die on fail. Years ago I was struggling to figure out a problem where some perfectly sensible code was mysteriously failing a test, but the there appeared to be nothing wrong with the code. As it turns out, at the top of my test, use_ok was also failing, but so many passing tests scrolled past that I didn't see that. I only saw a very mysterious failure at the end. Another programmer and I wasted a lot of time trying to figure out what was wrong, but didn't realize that Perl doesn't clean up after itself in this case.
That's part of the reason I advocate simply to use a module instead of use_ok, and with dying on test failure, you have another stopgap measure to help trap that (the latter argument being less persuasive, I admit).
That's why I check the return value of
use_ok()
before I continue. :)Sure it has practical issues. This is how I found out about the issue. :)
I like that you can tell Test::Most to die on fail, but don't like that it will still run the subsequent test.
See this pseudo-code where the "run" function dies on all errors:
lives_ok { run("mount server:/abc /mnt/abc") "Mounting";
lives_ok { run("dd if=/dev/zero of=/mnt/abc/file count=1M") } "dd";
This will still run the dd and only abort after that. I haven't figured out a good way to deal with that except for adding an "or die ..." after every critical test.
I like that you can tell Test::Most to die on fail, but don't like that it will still run the subsequent test.
See this pseudo-code where the "run" function dies on all errors:
lives_ok { run("mount server:/abc /mnt/abc") "Mounting";
lives_ok { run("dd if=/dev/zero of=/mnt/abc/file count=1M") } "dd";
This will still run the dd and only abort after that. I haven't figured out a good way to deal with that except for adding an "or die ..." after every critical test.