I added short_backtrace() that parallels quell_backtrace() in
assert.pm.  It causes a short version of the stacktrace to be printed
that filters out Test::Unit calls.  If no calls are left, it prints the
whole stack.

I didn't add it to the Unit.pm interface but it probably should be.

I don't really like how assert.pm handles the flags so if you want to
change it feel free.

-Kevin Connor
Interwoven

###########################################################
SHORT STACKTRACE:

C:\perl\Test-Unit-0.13\examples>perl  -I. ..\TestRunner.pl
testcase_fail_example

..F
Time:  0 wallclock secs ( 0.01 usr +  0.00 sys =  0.01 CPU)

!!!FAILURES!!!
Test Results:
Run: 2 Failures: 1 Errors: 0
There was 1 failure:
1) test_fail2(testcase_fail_example): Born to lose ...
Level 2: in package 'testcase_fail_example', file
'testcase_fail_example.pm', at
 line '18', sub 'Test::Unit::Assert::assert'
Level 14: in package 'main', file '..\TestRunner.pl', at line '4', sub
'Test::Un
it::TestRunner::start'
Test was not successful.

###########################################################
FULL STACKTRACE:
C:\perl\Test-Unit-0.13\examples>perl  -I. ..\TestRunner.pl
testcase_fail_example

..F
Time:  0 wallclock secs ( 0.00 usr +  0.00 sys =  0.00 CPU)

!!!FAILURES!!!
Test Results:
Run: 2 Failures: 1 Errors: 0
There was 1 failure:
1) test_fail2(testcase_fail_example): Born to lose ...
Level 1: in package 'Test::Unit::Assert', file
'c:\iw-home\iw-perl\site\lib/Test
/Unit/Assert.pm', at line '9', sub 'Test::Unit::Assert::fail'
Level 2: in package 'testcase_fail_example', file
'testcase_fail_example.pm', at
 line '18', sub 'Test::Unit::Assert::assert'
Level 3: in package 'Test::Unit::TestCase', file
'c:\iw-home\iw-perl\site\lib/Te
st/Unit/TestCase.pm', at line '65', sub
'testcase_fail_example::test_fail2'
Level 4: in package 'Test::Unit::TestCase', file
'c:\iw-home\iw-perl\site\lib/Te
st/Unit/TestCase.pm', at line '45', sub 'Test::Unit::TestCase::run_test'
Level 5: in package 'Test::Unit::TestCase', file
'c:\iw-home\iw-perl\site\lib/Te
st/Unit/TestCase.pm', at line '44', sub '(eval)'
Level 6: in package 'Test::Unit::TestResult', file
'c:\iw-home\iw-perl\site\lib/
Test/Unit/TestResult.pm', at line '100', sub
'Test::Unit::TestCase::run_bare'
Level 7: in package 'Test::Unit::TestResult', file
'c:\iw-home\iw-perl\site\lib/
Test/Unit/TestResult.pm', at line '110', sub
'Test::Unit::TestResult::__ANON__'
Level 8: in package 'Test::Unit::TestResult', file
'c:\iw-home\iw-perl\site\lib/
Test/Unit/TestResult.pm', at line '109', sub '(eval)'
Level 9: in package 'Test::Unit::TestResult', file
'c:\iw-home\iw-perl\site\lib/
Test/Unit/TestResult.pm', at line '100', sub
'Test::Unit::TestResult::run_protec
ted'
Level 10: in package 'Test::Unit::TestCase', file
'c:\iw-home\iw-perl\site\lib/T
est/Unit/TestCase.pm', at line '36', sub 'Test::Unit::TestResult::run'
Level 11: in package 'Test::Unit::TestSuite', file
'c:\iw-home\iw-perl\site\lib/
Test/Unit/TestSuite.pm', at line '157', sub 'Test::Unit::TestCase::run'
Level 12: in package 'Test::Unit::TestRunner', file
'c:\iw-home\iw-perl\site\lib
/Test/Unit/TestRunner.pm', at line '58', sub
'Test::Unit::TestSuite::run'
Level 13: in package 'Test::Unit::TestRunner', file
'c:\iw-home\iw-perl\site\lib
/Test/Unit/TestRunner.pm', at line '196', sub
'Test::Unit::TestRunner::do_run'
Level 14: in package 'main', file '..\TestRunner.pl', at line '4', sub
'Test::Un
it::TestRunner::start'

Test was not successful.
package Test::Unit::Exception;
use strict;
use constant DEBUG => 0;

sub new {
    my $class = shift;
    my ($message) = @_;
    
    $message = '' unless defined($message);
    $message = ref($class) . ": " . $message . "\n";

    my $i = 0;
    my $stacktrace = '';
    my ($pack, $file, $line, $subname, $hasargs, $wantarray);
    
    while (($pack, $file, $line, $subname, 
            $hasargs, $wantarray) = caller(++$i)) {
        $stacktrace .= "Level $i: in package '$pack', file '$file', at line '$line', 
sub '$subname'\n";
    }
    
    bless { _message => $message, _stacktrace => $stacktrace }, $class;
}

sub stacktrace {
    my $self = shift;
    return $self->{_stacktrace};
}

sub get_message {
    my $self = shift;
    return $self->{_message};
}

sub hide_backtrace {
    my $self = shift;
    $self->{_hide_backtrace} = 1;
}

sub short_backtrace {
    my $self = shift;
    $self->{_short_backtrace} = 1;
}

sub to_string {
    my $self = shift;
    if ($self->{_hide_backtrace})
    {
        return $self->get_message();
    }
    elsif ($self->{_short_backtrace})
    {
        my $short_stacktrace = join "\n",
                        grep {$_ !~ /package \'Test\:\:Unit/} 
                        split "\n", $self->stacktrace();
        $short_stacktrace = $self->stacktrace() if ($short_stacktrace eq "");
            return $self->get_message() . $short_stacktrace;
    }
    return $self->get_message() . $self->stacktrace();
}

1;
__END__

=head1 NAME

    Test::Unit::Exception - unit testing framework exception class

=head1 SYNOPSIS

    # this class is not intended to be used directly 

=head1 DESCRIPTION

    This class is used by the framework to communicate the result
    of assertions, which will throw an instance of a subclass
    of this class in case of errors or failures.

=head1 AUTHOR

    Copyright (c) 2000 Christian Lemburg, <[EMAIL PROTECTED]>.

    All rights reserved. This program is free software; you can
    redistribute it and/or modify it under the same terms as
    Perl itself.

    Thanks go to the other PerlUnit framework people: 
    Brian Ewins, Cayte Lindner, J.E. Fritz, Zhon Johansen.

    Thanks for patches go to:
    Matthew Astley.

=head1 SEE ALSO

    - Test::Unit::Assert
    - Test::Unit::ExceptionError
    - Test::Unit::ExceptionFailure

=cut
package Test::Unit::Assert;
use strict;
use constant DEBUG => 0;

sub assert {
    my $self = shift;
    print ref($self) . "::assert() called\n" if DEBUG;
    my ($condition, $message) = @_;
    $self->fail($message) unless $condition;
}

sub fail {
    my $self = shift;
    print ref($self) . "::fail() called\n" if DEBUG;
    my ($message) = @_;
    my $ex = Test::Unit::ExceptionFailure->new($message);
    $ex->hide_backtrace() unless $self->get_backtrace_on_fail();
    $ex->short_backtrace() if $self->get_short_backtrace_on_fail();
    die $ex;
}

sub quell_backtrace {
    my $self = shift;
    $self->{_no_backtrace_on_fail} = 1;
    $self->{_short_backtrace_on_fail} = 0;
}

sub short_backtrace {
    my $self = shift;
    $self->{_short_backtrace_on_fail} = 1;
    $self->{_no_backtrace_on_fail} = 0;
}

sub get_short_backtrace_on_fail {
    my $self = shift;
    return $self->{_short_backtrace_on_fail};
}

sub get_backtrace_on_fail {
    my $self = shift;
    return $self->{_no_backtrace_on_fail} ? 0 : 1;
}



1;
__END__

=head1 NAME

    Test::Unit::Assert - unit testing framework assertion class

=head1 SYNOPSIS

    # this class is not intended to be used directly, 
    # normally you get the functionality by subclassing from 
    # Test::Unit::TestCase

    use Test::Unit::TestCase;
   
    # more code here ...
    
    $self->assert($your_condition_here, $your_optional_message_here);

    # NOTE: if you want to use regexes in comparisons, do it like this:

    $self->assert(scalar("foo" =~ /bar/), $your_optional_message_here);

=head1 DESCRIPTION

    This class is used by the framework to assert boolean conditions
    that determine the result of a given test. The optional message
    will be displayed if the condition fails. Normally, it is not
    used directly, but you get the functionality by subclassing from 
    Test::Unit::TestCase.

    There is one problem with assert(): the arguments to assert() are
    evaluated in list context, e.g. making a failing regex "pull" the
    message into the place of the first argument. Since this is ususally
    just plain wrong, please use scalar() to force the regex comparison
    to yield a useful boolean value. I currently do not see a way around
    this, since function prototypes don't work for object methods, and
    any other tricks (counting argument number, and complaining if there
    is only one argument and it looks like a string, etc.) don't appeal
    to me. Thanks to Matthew Astley for noting this effect. 

    The procedural interface to this framework, Test::Unit, does not have
    this problem, as it exports a "normal" assert() function, and that can
    and does use a function prototype to correct the problem.


=head1 AUTHOR

    Copyright (c) 2000 Christian Lemburg, <[EMAIL PROTECTED]>.

    All rights reserved. This program is free software; you can
    redistribute it and/or modify it under the same terms as
    Perl itself.

    Thanks go to the other PerlUnit framework people: 
    Brian Ewins, Cayte Lindner, J.E. Fritz, Zhon Johansen.

    Thanks for patches go to:
    Matthew Astley, David Esposito.

=head1 SEE ALSO

    - Test::Unit::TestCase
    - Test::Unit::Exception
    - The framework self-testing suite (Test::Unit::tests::AllTests)

=cut

Reply via email to