On 20/07/06, chromatic <[EMAIL PROTECTED]> wrote:
On Wednesday 19 July 2006 18:10, Fergal Daly wrote:
> On 20/07/06, chromatic <[EMAIL PROTECTED]> wrote:
> > On Thu, Jul 20, 2006 at 12:39:11AM +0100, Fergal Daly wrote:
> > > Simple question. Given this code:
> > >
> > > sub foo {
> > > my $thing;
> > > is($thing->x(), "x"); # line 4
> > > is($thing->y(), "y");
> > > }
> > >
> > > $t1 = Thing->new(1);
> > > foo($t1); # line 9
> > > $t2 = Thing->new(2);
> > > foo($t2);
> I'm talking about line numbers so adding a name is not relevant.
>
> Whether I add $T::B::L or not, I don't get any useful output. If you
> disagree please show me your fixed version.
sub foo :TestHelper
{
# this was just a typo; it's not part of my fix
my $thing = shift;
is($thing->x(), "x", 'checking x attribute'); # line 4
is($thing->y(), "y", 'checking y attribute');
}
Wrong!!
This problem has two parts. You want two pieces of information to debug a
failing test within foo(). The first is "Which object had the failure". The
second is "Which test within the function failed?"
Funnily enough your fixed version only provides 1 of these, it will
tell you that the failure was "checking attribute x" and it will also
point to line 4 (the line where that test runs). If you had
incremented $T::B::L at the start then it would have pointed to line 9
where foo() is called and we'd actually have enough info.
So, you got it wrong when I presume you were being careful. If that's
not a clear demonstration that something could be a whole lot better
then I don't know what is.
Apart from that, I said "adding a name is not relevant". The whole
point of my argument is that T::B is deficient when it comes to sub
routines but could be made perfectly adequate by giving stack traces
instead of just a single line.
Another point is that even when $T::L::B is set correctly, this
technique will only cope with 1 single sub call. If you foo() made 2
calls to bar() we would need 3 pieces of information to figure things
out and the maximum your fix can provide is 2.
There already exist two long-accepted, well-understood, coded, tested, and
debugged ways to answer both questions. I don't see the value in adding a
third, especially when it's not substantially better than either and can be
wrong in other circumstances!
What circumstances? Example please.
Without stack traces, here's the only way I know to use subroutines
safely in test scripts.
sub foo {
my ($thing, $name) = @_;
is($thing->x(), "x", "checking x in $name"); # line 4
is($thing->y(), "y", "checking y in $name");
}
$t1 = Thing->new(1);
foo($t1, "thing 1"); # line 9
$t2 = Thing->new(2);
foo($t2, "thing 2");
this technique will work in arbitrarily nested code as long as you
pass a name into every subroutine and combine it with more specific
detail in each layer., that a lot of work to do just to reclaim your
ablity to use subroutines. You end with test names like
"checking z in checking x in thing 1"
Basically the test name becomes a hand-built stack trace!
> > That boiler plate code tells Test::Builder *where* to report the call of
> > the test.
> What's your point?
Your patch relies on $Level too, as it calls the caller() *method* within
Test::Builder. If someone has not set it correctly, your patch will report
the wrong information.
Someone? Who? If there's a bug in one of the Test::XXX modules then
yes the stack trace could be wong but that's a bug that needs to be
fixed and is not a problem with my patch.
The test script author should not even need to know about $T::L::B.
> There's no guessing involved, the method is extremely straight forward
> and always gets the right answer. By that I mean that it always finds
> the spot where test script jumped into the test library.
sub an_extra_level
{
ok( $_[0], $_[1], $_[2] );
}
sub another_extra_level
{
an_extra_level( @_ );
}
sub yet_another_extra_level
{
another_extra_level( @_ );
}
sub still_more_extra_levels
{
yet_another_extra_level( @_ );
}
still_more_extra_levels( $have, $want, $diagnostic );
Where do you start debugging that?
With a stack trace it's pretty easy. Without a stack trace? I'd be
inserting print statements everywhere.
What good does a stack trace do in a loop?
None. What good is a line number in a loop? I'm not claiming to solve
that. Named nestable blocks are the only way to solve the loop problem
nicely (you've can also solve it by hand by constrcucting complex
names like above).
> The problem is that a single position in the test script is not always
> enough information to figure out what actually failed,
That's why there are test descriptions too.
But some people don't like having to provide names and as I pointed
out above unless you are prepared to do all the work to embed what is
effectively a stack trace in your names then names don't save you
either,
F