•Re: When -w and use strict aren't enough...
by merlyn (Sage) on Nov 04, 2003 at 13:43 UTC
|
without having to write a test suite that exercises every code branch, which isn't always (or even usually) possible.
Quite the contrary. In a well-maintained system, a test suite that tests every code branch is mandatory. And as they say, "you can pay me now, or you can pay me later" with respect to testing.
Your code should be designed so that testing every branch is possible.
If you're writing code that's hard to test, you can't test it, and therefore
it's quite possible that some bug will show up in the future. Bad code, Bad code, what you gonna do?
Read Test::Tutorial. Learn how to write tests, and you'll gradually start writing code that can always be tested.
| [reply] |
|
| [reply] |
|
| [reply] |
Re: When -w and use strict aren't enough...
by Abigail-II (Bishop) on Nov 04, 2003 at 14:21 UTC
|
If you leave the parenthesis off, like this:
if ($mday == 1 && $month == 1) {
handelNewYear; # Typo in function name.
}
then the code won't compile under 'use strict'.
Leaving parens off isn't always possible without writing
uncommon idiom, but in many cases you can leave the parens
off, and it'll capture many mistyped sub names.
Abigail | [reply] [d/l] |
|
| [reply] |
Re: When -w and use strict aren't enough...
by Ovid (Cardinal) on Nov 04, 2003 at 14:43 UTC
|
Just as a new Perl programmer might get tired of hearing "use strict" or "use CGI", you're going to get tired of hearing "write tests" if you have a problem which testing tends to solve. Use Devel::Cover to develop a code coverage profile and you have a good start on writing your tests. I'll even help:
use strict;
use warnings;
use Test::More 'no_plan';
my $module = 'Foo.pm';
use_ok($module) or die;
can_ok($module, 'handleNewYear');
Then, just fill in "can_ok" stubs for your functions. As you uncover bugs, write a test that exploits them. It's not quite the same as test driven development, but I'm scratching my head trying to think of ways to get people to test who otherwise wouldn't :)
| [reply] [d/l] |
Re: When -w and use strict aren't enough...
by adrianh (Chancellor) on Nov 04, 2003 at 13:55 UTC
|
But it would be nice if there was a way to catch such cases...
Well, you've answered your own question when you said:
"there could be autoloads providing the subroutine, or it could have been dynamically generated at runtime in an eval, or something. "
The flexibility of Perl comes with a price. This is one of them.
However, I would strongly disagree when you said:
without having to write a test suite that exercises every code branch, which isn't always (or even usually) possible.
If you can't test your code then something is wrong with it. Fix the design so you can test it. If you have problems doing this, then post a SOPW - I'm sure somebody could help ;-)
Seriously, 100% test coverage is an attainable goal with surprisingly little effort.
| [reply] |
|
| [reply] |
|
| [reply] |
|
|
|
Re: When -w and use strict aren't enough...
by pg (Canon) on Nov 04, 2003 at 17:00 UTC
|
So as merly and everyone else have pointed out, at the end of the day, you have to have test cases cover all braches. Brach could mean different things for different testing phases. For the unit testing that you should do, branch means each logic branch of all your scripts.
On the other hand, I agree that it would be nice, if Perl can help you to avoid some of those pitfalls.
Now, how many times have you run into nasty problems by misspelling your hash keys? (In this case -w and strict does not help) But in this in this case Perl provides a great tool: Hash::Util:
foo.pm:
package foo;
use Hash::Util;
use strict;
use warnings;
sub new {
my $self = {};
$self->{XBCDE} = 1;
$self->{AXCDE} = 2;
$self->{ABXDE} = 3;
$self->{ABCXE} = 4;
$self->{ABCDX} = 5;
bless($self);
Hash::Util::lock_keys(%{$self});
return $self;
}
sub bar_1 {
my $self = shift;
$self->{AXCDE} = 10;
}
sub bar_2 {
my $self = shift;
print $self->{AXCDE};
}
sub bar_3 {
my $self = shift;
$self->{XXXXX} = 10;
}
sub bar_4 {
my $self = shift;
print $self->{XXXXX};
}
1;
foo.pl:
use foo;
use strict;
use warnings;
my $foo = new foo;
$foo->bar_1; #okay as the key exists
$foo->bar_2; #okay as the key exists
$foo->bar_3; #no good, comment out this, and try for the second time
$foo->bar_4; #no good, comment out this, and try for the third time
| [reply] [d/l] |
Re: When -w and use strict aren't enough...
by tilly (Archbishop) on Nov 04, 2003 at 22:19 UTC
|
There is a way to do what you want, but you probably don't want to do it. Here goes:
my $handleNewYear = sub {
# do something really useful
};
# ... lotsa logic...
if (1==$mday && 1==$month) {
$handelNewYear->();
}
All that I have done is stored the subroutine in a variable. Do that with all of your subroutines and all of your typos in subroutines become typos in variable names which strict.pm catches.
You may note that I also reversed the order of your == comparisons. The reason for doing that is so that if you type = instead of == some day, Perl will complain because you can't assign to a constant. This is a useful habit in many C-like languages. | [reply] [d/l] |
|
I read this thread earlier today and I have to admit that I skimmed over the bit about == comparisons and then just now I was reading about the back door attempt on the Linux kernel and way down there in the comments (sorry I can't see a way to link directly to it) are two comments by "legobuff" and "Mr_Z" on the exact same topic. A real world example how a simple change in coding practice can potentially make a profound difference (presuming of course some-one writes the auditing tools). ++tilly its a good meme to spread.
-- Do not seek to follow in the footsteps of the wise. Seek what they sought. -Basho
| [reply] |
|
This intrigues me.
but
Why do you say "Probably don't want to..."?
because
"it's too much work"?
or because
"it's dangerous/bad/ugly"?
| [reply] |
|
Don't know, but one downside (upside?) is that your functions are no longer accessible from outside the package. That can easily be fixed by doing one of the following for exportable functions:
*handleNewYear = my $handleNewYear = sub {
# do something really useful
};
sub handleNewYear {
# do something really useful
}
my $handleNewYear = \&handleNewYear;
| [reply] [d/l] [select] |
|
| [reply] |
Re: When -w and use strict aren't enough...
by fletcher_the_dog (Friar) on Nov 04, 2003 at 18:40 UTC
|
Even if there wasn't AUTOLOAD and eval, perl's loose typing makes it impossible to check method names at compile time. Consider this snippet:
sub foo{
my $thing = shift;
print $thing->to_xml;
}
$thing could be anything, there is no way at compile time for perl to know if $thing has a "to_xml" method | [reply] [d/l] |
Re: When -w and use strict aren't enough...
by bl0rf (Pilgrim) on Nov 05, 2003 at 01:16 UTC
|
if( $line =~ m!sub\s+(\S+){ eval "sub $1 {}" }
Then the second script will store every sub called
in an array, it will check %main:: and CORE:: to see
whether the subroutines have been, or will be, declared
at any point in your original script.
I hope my advice helps.
-Jacob
Eat Perl, live well.
My site
| [reply] [d/l] |
Re: When -w and use strict aren't enough...
by dada (Chaplain) on Nov 06, 2003 at 12:18 UTC
|
RMGir, meet B::Xref. B::Xref, meet RMGir :-)
I've published elsewhere a little script which parses the output of B::Xref to catch unused subs.
if you just change the last four lines to:
foreach my $sub (keys %subused) {
next if exists $subdef{ $sub };
print "UNDEFINED SUB: $subused{ $sub } $sub\n";
}
you have something that will catch your handelNewYear error :-)
cheers,
Aldo
King of Laziness, Wizard of Impatience, Lord of Hubris
| [reply] [d/l] |
|
Thanks!
I think both the unused and undeclared options look pretty useful.
Your post is a reply to Warnings for unused subs, an interesting thred I'd missed.
PS: I liked that side trip to Re: Re: ESMTP, linefeed and <CRLF> before you fixed your link; it made me wonder if I'd accidentally gotten decaf this morning :)
| [reply] |
Re: When -w and use strict aren't enough...
by graff (Chancellor) on Nov 17, 2003 at 04:58 UTC
|
A while back, someone posted an SoPW about having trouble maintaining someone else's complicated perl app (lots of separate perl files, lots of subs, etc), and it lead me to write and post this simple-minded tool, based on an idea that had worked pretty well for me when I had the same problem handling packages in C: scan all the source code files and build a listing that shows where subs are declared, and where they're called.
Of course, Perl is a bit tougher to parse than C, so my perl version of the tool is "less deterministic"... Still, I wonder if something like this might help in your case, at least to give a decent starting point for the diagnostics that you really want. Basically, it's a matter of comparing the sub calls against the sub declarations to see if there are any "outliers". | [reply] |