Blame t/01-basic.t

Packit 985e12
use strict;
Packit 985e12
use warnings;
Packit 985e12
Packit 985e12
use Test::More 0.88;
Packit 985e12
Packit 985e12
use Devel::StackTrace;
Packit 985e12
Packit 985e12
sub get_file_name { File::Spec->canonpath( ( caller(0) )[1] ) }
Packit 985e12
my $test_file_name = get_file_name();
Packit 985e12
Packit 985e12
# Test all accessors
Packit 985e12
{
Packit 985e12
    my $trace = foo();
Packit 985e12
Packit 985e12
    my @f = ();
Packit 985e12
    while ( my $f = $trace->prev_frame ) { push @f, $f; }
Packit 985e12
Packit 985e12
    my $cnt = scalar @f;
Packit 985e12
    is(
Packit 985e12
        $cnt, 4,
Packit 985e12
        'Trace should have 4 frames'
Packit 985e12
    );
Packit 985e12
Packit 985e12
    @f = ();
Packit 985e12
    while ( my $f = $trace->next_frame ) { push @f, $f; }
Packit 985e12
Packit 985e12
    $cnt = scalar @f;
Packit 985e12
    is(
Packit 985e12
        $cnt, 4,
Packit 985e12
        'Trace should have 4 frames'
Packit 985e12
    );
Packit 985e12
Packit 985e12
    is(
Packit 985e12
        $f[0]->package, 'main',
Packit 985e12
        'First frame package should be main'
Packit 985e12
    );
Packit 985e12
Packit 985e12
    is(
Packit 985e12
        $f[0]->filename, $test_file_name,
Packit 985e12
        "First frame filename should be $test_file_name"
Packit 985e12
    );
Packit 985e12
Packit 985e12
    is( $f[0]->line, 1009, 'First frame line should be 1009' );
Packit 985e12
Packit 985e12
    is(
Packit 985e12
        $f[0]->subroutine, 'Devel::StackTrace::new',
Packit 985e12
        'First frame subroutine should be Devel::StackTrace::new'
Packit 985e12
    );
Packit 985e12
Packit 985e12
    is( $f[0]->hasargs, 1, 'First frame hasargs should be true' );
Packit 985e12
Packit 985e12
    ok(
Packit 985e12
        !$f[0]->wantarray,
Packit 985e12
        'First frame wantarray should be false'
Packit 985e12
    );
Packit 985e12
Packit 985e12
    my $trace_text = <<"EOF";
Packit 985e12
Trace begun at $test_file_name line 1009
Packit 985e12
main::baz(1, 2) called at $test_file_name line 1005
Packit 985e12
main::bar(1) called at $test_file_name line 1001
Packit 985e12
main::foo at $test_file_name line 13
Packit 985e12
EOF
Packit 985e12
Packit 985e12
    is( $trace->as_string, $trace_text, 'trace text' );
Packit 985e12
}
Packit 985e12
Packit 985e12
# Test constructor params
Packit 985e12
{
Packit 985e12
    my $trace = SubTest::foo( ignore_class => 'Test' );
Packit 985e12
Packit 985e12
    my @f = ();
Packit 985e12
    while ( my $f = $trace->prev_frame ) { push @f, $f; }
Packit 985e12
Packit 985e12
    my $cnt = scalar @f;
Packit 985e12
Packit 985e12
    is( $cnt, 1, 'Trace should have 1 frame' );
Packit 985e12
Packit 985e12
    is(
Packit 985e12
        $f[0]->package, 'main',
Packit 985e12
        'The package for this frame should be main'
Packit 985e12
    );
Packit 985e12
Packit 985e12
    $trace = Test::foo( ignore_class => 'Test' );
Packit 985e12
Packit 985e12
    @f = ();
Packit 985e12
    while ( my $f = $trace->prev_frame ) { push @f, $f; }
Packit 985e12
Packit 985e12
    $cnt = scalar @f;
Packit 985e12
Packit 985e12
    is( $cnt, 1, 'Trace should have 1 frame' );
Packit 985e12
    is(
Packit 985e12
        $f[0]->package, 'main',
Packit 985e12
        'The package for this frame should be main'
Packit 985e12
    );
Packit 985e12
}
Packit 985e12
Packit 985e12
# 15 - stringification overloading
Packit 985e12
{
Packit 985e12
    my $trace = baz();
Packit 985e12
Packit 985e12
    my $trace_text = <<"EOF";
Packit 985e12
Trace begun at $test_file_name line 1009
Packit 985e12
main::baz at $test_file_name line 99
Packit 985e12
EOF
Packit 985e12
Packit 985e12
    my $t = "$trace";
Packit 985e12
    is( $t, $trace_text, 'trace text' );
Packit 985e12
}
Packit 985e12
Packit 985e12
# 16-18 - frame_count, frame, reset_pointer, frames methods
Packit 985e12
{
Packit 985e12
    my $trace = foo();
Packit 985e12
Packit 985e12
    is(
Packit 985e12
        $trace->frame_count, 4,
Packit 985e12
        'Trace should have 4 frames'
Packit 985e12
    );
Packit 985e12
Packit 985e12
    my $f = $trace->frame(2);
Packit 985e12
Packit 985e12
    is(
Packit 985e12
        $f->subroutine, 'main::bar',
Packit 985e12
        q{Frame 2's subroutine should be 'main::bar'}
Packit 985e12
    );
Packit 985e12
Packit 985e12
    $trace->next_frame;
Packit 985e12
    $trace->next_frame;
Packit 985e12
    $trace->reset_pointer;
Packit 985e12
Packit 985e12
    $f = $trace->next_frame;
Packit 985e12
    is(
Packit 985e12
        $f->subroutine, 'Devel::StackTrace::new',
Packit 985e12
        'next_frame should return first frame after call to reset_pointer'
Packit 985e12
    );
Packit 985e12
Packit 985e12
    my @f = $trace->frames;
Packit 985e12
    is(
Packit 985e12
        scalar @f, 4,
Packit 985e12
        'frames method should return four frames'
Packit 985e12
    );
Packit 985e12
Packit 985e12
    is(
Packit 985e12
        $f[0]->subroutine, 'Devel::StackTrace::new',
Packit 985e12
        q{first frame's subroutine should be Devel::StackTrace::new}
Packit 985e12
    );
Packit 985e12
Packit 985e12
    is(
Packit 985e12
        $f[3]->subroutine, 'main::foo',
Packit 985e12
        q{last frame's subroutine should be main::foo}
Packit 985e12
    );
Packit 985e12
}
Packit 985e12
Packit 985e12
# Not storing references
Packit 985e12
{
Packit 985e12
    my $obj = RefTest->new;
Packit 985e12
Packit 985e12
    my $trace = $obj->{trace};
Packit 985e12
Packit 985e12
    my $call_to_trace = ( $trace->frames )[1];
Packit 985e12
Packit 985e12
    my @args = $call_to_trace->args;
Packit 985e12
Packit 985e12
    is(
Packit 985e12
        scalar @args, 1,
Packit 985e12
        'Only one argument should have been passed in the call to trace()'
Packit 985e12
    );
Packit 985e12
Packit 985e12
    like(
Packit 985e12
        $args[0], qr/RefTest=HASH/,
Packit 985e12
        q{Actual object should be replaced by string 'RefTest=HASH'}
Packit 985e12
    );
Packit 985e12
}
Packit 985e12
Packit 985e12
# Storing references
Packit 985e12
{
Packit 985e12
    my $obj = RefTest2->new;
Packit 985e12
Packit 985e12
    my $trace = $obj->{trace};
Packit 985e12
Packit 985e12
    my $call_to_trace = ( $trace->frames )[1];
Packit 985e12
Packit 985e12
    my @args = $call_to_trace->args;
Packit 985e12
Packit 985e12
    is(
Packit 985e12
        scalar @args, 1,
Packit 985e12
        'Only one argument should have been passed in the call to trace()'
Packit 985e12
    );
Packit 985e12
Packit 985e12
    isa_ok( $args[0], 'RefTest2' );
Packit 985e12
}
Packit 985e12
Packit 985e12
# Storing references (deprecated interface 1)
Packit 985e12
{
Packit 985e12
    my $obj = RefTestDep1->new;
Packit 985e12
Packit 985e12
    my $trace = $obj->{trace};
Packit 985e12
Packit 985e12
    my $call_to_trace = ( $trace->frames )[1];
Packit 985e12
Packit 985e12
    my @args = $call_to_trace->args;
Packit 985e12
Packit 985e12
    is(
Packit 985e12
        scalar @args, 1,
Packit 985e12
        'Only one argument should have been passed in the call to trace()'
Packit 985e12
    );
Packit 985e12
Packit 985e12
    isa_ok( $args[0], 'RefTestDep1' );
Packit 985e12
}
Packit 985e12
Packit 985e12
# No ref to Exception::Class::Base object without refs
Packit 985e12
if ( $Exception::Class::VERSION && $Exception::Class::VERSION >= 1.09 )
Packit 985e12
{
Packit 985e12
    ## no critic (ErrorHandling::RequireCheckingReturnValueOfEval)
Packit 985e12
    eval {
Packit 985e12
        Exception::Class::Base->throw(
Packit 985e12
            error      => 'error',
Packit 985e12
            show_trace => 1,
Packit 985e12
        );
Packit 985e12
    };
Packit 985e12
    my $exc = $@;
Packit 985e12
    eval { quux($exc) };
Packit 985e12
Packit 985e12
    ok( !$@, 'create stacktrace with no refs and exception object on stack' );
Packit 985e12
}
Packit 985e12
Packit 985e12
{
Packit 985e12
    sub FooBar::some_sub { return Devel::StackTrace->new }
Packit 985e12
Packit 985e12
    my $trace = eval { FooBar::some_sub('args') };
Packit 985e12
Packit 985e12
    my $f = ( $trace->frames )[2];
Packit 985e12
Packit 985e12
    is( $f->subroutine, '(eval)', 'subroutine is (eval)' );
Packit 985e12
Packit 985e12
    my @args = $f->args;
Packit 985e12
Packit 985e12
    is( scalar @args, 0, 'no args given to eval block' );
Packit 985e12
}
Packit 985e12
Packit 985e12
{
Packit 985e12
    {
Packit 985e12
        package    #hide
Packit 985e12
            FooBarBaz;
Packit 985e12
Packit 985e12
        sub func2 {
Packit 985e12
            return Devel::StackTrace->new( ignore_package => qr/^FooBar/ );
Packit 985e12
        }
Packit 985e12
        sub func1 { FooBarBaz::func2() }
Packit 985e12
    }
Packit 985e12
Packit 985e12
    my $trace = FooBarBaz::func1('args');
Packit 985e12
Packit 985e12
    my @f = $trace->frames;
Packit 985e12
Packit 985e12
    is( scalar @f, 1, 'check regex as ignore_package arg' );
Packit 985e12
}
Packit 985e12
Packit 985e12
## no critic (Modules::ProhibitMultiplePackages)
Packit 985e12
{
Packit 985e12
    package    #hide
Packit 985e12
        StringOverloaded;
Packit 985e12
Packit 985e12
    use overload q{""} => sub {'overloaded'};
Packit 985e12
}
Packit 985e12
Packit 985e12
{
Packit 985e12
    my $o = bless {}, 'StringOverloaded';
Packit 985e12
Packit 985e12
    my $trace = baz($o);
Packit 985e12
Packit 985e12
    unlike(
Packit 985e12
        $trace->as_string, qr/\boverloaded\b/,
Packit 985e12
        'overloading is ignored by default'
Packit 985e12
    );
Packit 985e12
}
Packit 985e12
Packit 985e12
{
Packit 985e12
    my $o = bless {}, 'StringOverloaded';
Packit 985e12
Packit 985e12
    my $trace = respect_overloading($o);
Packit 985e12
Packit 985e12
    like(
Packit 985e12
        $trace->as_string, qr/\boverloaded\b/,
Packit 985e12
        'overloading is ignored by default'
Packit 985e12
    );
Packit 985e12
}
Packit 985e12
Packit 985e12
{
Packit 985e12
    package    #hide
Packit 985e12
        BlowOnCan;
Packit 985e12
Packit 985e12
    sub can { die 'foo' }
Packit 985e12
}
Packit 985e12
Packit 985e12
{
Packit 985e12
    my $o = bless {}, 'BlowOnCan';
Packit 985e12
Packit 985e12
    my $trace = baz($o);
Packit 985e12
Packit 985e12
    like(
Packit 985e12
        $trace->as_string, qr/BlowOnCan/,
Packit 985e12
        'death in overload::Overloaded is ignored'
Packit 985e12
    );
Packit 985e12
}
Packit 985e12
Packit 985e12
{
Packit 985e12
    my $trace = max_arg_length('abcdefghijklmnop');
Packit 985e12
Packit 985e12
    my $trace_text = <<"EOF";
Packit 985e12
Trace begun at $test_file_name line 1021
Packit 985e12
main::max_arg_length('abcdefghij...') called at $test_file_name line 307
Packit 985e12
EOF
Packit 985e12
Packit 985e12
    is( $trace->as_string, $trace_text, 'trace text' );
Packit 985e12
Packit 985e12
    my $trace_text_1 = <<"EOF";
Packit 985e12
Trace begun at $test_file_name line 1021
Packit 985e12
main::max_arg_length('abc...') called at $test_file_name line 307
Packit 985e12
EOF
Packit 985e12
Packit 985e12
    is(
Packit 985e12
        $trace->as_string( { max_arg_length => 3 } ),
Packit 985e12
        $trace_text_1,
Packit 985e12
        'trace text, max_arg_length = 3',
Packit 985e12
    );
Packit 985e12
}
Packit 985e12
Packit 985e12
SKIP:
Packit 985e12
{
Packit 985e12
    skip 'Test only runs on Linux', 1
Packit 985e12
        unless $^O eq 'linux';
Packit 985e12
Packit 985e12
    my $frame = Devel::StackTrace::Frame->new(
Packit 985e12
        [ 'Foo', 'foo/bar///baz.pm', 10, 'bar', 1, 1, q{}, 0 ],
Packit 985e12
        []
Packit 985e12
    );
Packit 985e12
Packit 985e12
    is( $frame->filename, 'foo/bar/baz.pm', 'filename is canonicalized' );
Packit 985e12
}
Packit 985e12
Packit 985e12
{
Packit 985e12
    my $obj = RefTest4->new();
Packit 985e12
Packit 985e12
    my $trace = $obj->{trace};
Packit 985e12
Packit 985e12
    ok(
Packit 985e12
        ( !grep { ref $_ } map { @{ $_->{args} } } @{ $trace->{raw} } ),
Packit 985e12
        'raw data does not contain any references when unsafe_ref_capture not set'
Packit 985e12
    );
Packit 985e12
Packit 985e12
    is(
Packit 985e12
        $trace->{raw}[1]{args}[1], 'not a ref',
Packit 985e12
        'non-refs are preserved properly in raw data as well'
Packit 985e12
    );
Packit 985e12
}
Packit 985e12
Packit 985e12
{
Packit 985e12
    my $trace = overload_no_stringify( CodeOverload->new() );
Packit 985e12
Packit 985e12
    ## no critic (ErrorHandling::RequireCheckingReturnValueOfEval)
Packit 985e12
    eval { $trace->as_string() };
Packit 985e12
Packit 985e12
    is(
Packit 985e12
        $@, q{},
Packit 985e12
        'no error when respect_overload is true and object overloads but does not stringify'
Packit 985e12
    );
Packit 985e12
}
Packit 985e12
Packit 985e12
{
Packit 985e12
    my $trace = Filter::foo();
Packit 985e12
Packit 985e12
    my @frames = $trace->frames();
Packit 985e12
    is( scalar @frames, 2, 'frame_filtered trace has just 2 frames' );
Packit 985e12
    is(
Packit 985e12
        $frames[0]->subroutine(), 'Devel::StackTrace::new',
Packit 985e12
        'first subroutine'
Packit 985e12
    );
Packit 985e12
    is(
Packit 985e12
        $frames[1]->subroutine(), 'Filter::bar',
Packit 985e12
        'second subroutine (skipped Filter::foo)'
Packit 985e12
    );
Packit 985e12
}
Packit 985e12
Packit 985e12
{
Packit 985e12
    my $trace = FilterAllFrames::a_foo();
Packit 985e12
Packit 985e12
    my @frames = $trace->frames();
Packit 985e12
    is(
Packit 985e12
        scalar @frames, 2,
Packit 985e12
        'after filtering whole list of frames, got just 2 frames'
Packit 985e12
    );
Packit 985e12
    is(
Packit 985e12
        $frames[0]->subroutine(), 'FilterAllFrames::a_bar',
Packit 985e12
        'first subroutine'
Packit 985e12
    );
Packit 985e12
    is(
Packit 985e12
        $frames[1]->subroutine(), 'FilterAllFrames::a_foo',
Packit 985e12
        'second subroutine'
Packit 985e12
    );
Packit 985e12
}
Packit 985e12
Packit 985e12
done_testing();
Packit 985e12
Packit 985e12
# This means I can move these lines down without constantly fiddling
Packit 985e12
# with the checks for line numbers in the tests.
Packit 985e12
Packit 985e12
#line 1000
Packit 985e12
sub foo {
Packit 985e12
    bar( @_, 1 );
Packit 985e12
}
Packit 985e12
Packit 985e12
sub bar {
Packit 985e12
    baz( @_, 2 );
Packit 985e12
}
Packit 985e12
Packit 985e12
sub baz {
Packit 985e12
    Devel::StackTrace->new( @_ ? @_[ 0, 1 ] : () );
Packit 985e12
}
Packit 985e12
Packit 985e12
sub quux {
Packit 985e12
    Devel::StackTrace->new();
Packit 985e12
}
Packit 985e12
Packit 985e12
sub respect_overloading {
Packit 985e12
    Devel::StackTrace->new( respect_overload => 1 );
Packit 985e12
}
Packit 985e12
Packit 985e12
sub max_arg_length {
Packit 985e12
    Devel::StackTrace->new( max_arg_length => 10 );
Packit 985e12
}
Packit 985e12
Packit 985e12
sub overload_no_stringify {
Packit 985e12
    return Devel::StackTrace->new( respect_overload => 1 );
Packit 985e12
}
Packit 985e12
Packit 985e12
{
Packit 985e12
    package    #hide
Packit 985e12
        Test;
Packit 985e12
Packit 985e12
    sub foo {
Packit 985e12
        trace(@_);
Packit 985e12
    }
Packit 985e12
Packit 985e12
    sub trace {
Packit 985e12
        Devel::StackTrace->new(@_);
Packit 985e12
    }
Packit 985e12
}
Packit 985e12
Packit 985e12
{
Packit 985e12
    package    #hide
Packit 985e12
        SubTest;
Packit 985e12
Packit 985e12
    use base qw(Test);
Packit 985e12
Packit 985e12
    sub foo {
Packit 985e12
        trace(@_);
Packit 985e12
    }
Packit 985e12
Packit 985e12
    sub trace {
Packit 985e12
        Devel::StackTrace->new(@_);
Packit 985e12
    }
Packit 985e12
}
Packit 985e12
Packit 985e12
{
Packit 985e12
    package    #hide
Packit 985e12
        RefTest;
Packit 985e12
Packit 985e12
    sub new {
Packit 985e12
        my $self = bless {}, shift;
Packit 985e12
Packit 985e12
        $self->{trace} = trace($self);
Packit 985e12
Packit 985e12
        return $self;
Packit 985e12
    }
Packit 985e12
Packit 985e12
    sub trace {
Packit 985e12
        Devel::StackTrace->new();
Packit 985e12
    }
Packit 985e12
}
Packit 985e12
Packit 985e12
{
Packit 985e12
    package    #hide
Packit 985e12
        RefTest2;
Packit 985e12
Packit 985e12
    sub new {
Packit 985e12
        my $self = bless {}, shift;
Packit 985e12
Packit 985e12
        $self->{trace} = trace($self);
Packit 985e12
Packit 985e12
        return $self;
Packit 985e12
    }
Packit 985e12
Packit 985e12
    sub trace {
Packit 985e12
        Devel::StackTrace->new( unsafe_ref_capture => 1 );
Packit 985e12
    }
Packit 985e12
}
Packit 985e12
Packit 985e12
{
Packit 985e12
    package    #hide
Packit 985e12
        RefTestDep1;
Packit 985e12
Packit 985e12
    sub new {
Packit 985e12
        my $self = bless {}, shift;
Packit 985e12
Packit 985e12
        $self->{trace} = trace($self);
Packit 985e12
Packit 985e12
        return $self;
Packit 985e12
    }
Packit 985e12
Packit 985e12
    sub trace {
Packit 985e12
        Devel::StackTrace->new( no_refs => 0 );
Packit 985e12
    }
Packit 985e12
}
Packit 985e12
Packit 985e12
{
Packit 985e12
    package    #hide
Packit 985e12
        RefTest4;
Packit 985e12
Packit 985e12
    sub new {
Packit 985e12
        my $self = bless {}, shift;
Packit 985e12
Packit 985e12
        $self->{trace} = trace( $self, 'not a ref' );
Packit 985e12
Packit 985e12
        return $self;
Packit 985e12
    }
Packit 985e12
Packit 985e12
    sub trace {
Packit 985e12
        Devel::StackTrace->new();
Packit 985e12
    }
Packit 985e12
}
Packit 985e12
Packit 985e12
{
Packit 985e12
    package    #hide
Packit 985e12
        CodeOverload;
Packit 985e12
Packit 985e12
    use overload '&{}' => sub {'foo'};
Packit 985e12
Packit 985e12
    sub new {
Packit 985e12
        my $class = shift;
Packit 985e12
        return bless {}, $class;
Packit 985e12
    }
Packit 985e12
}
Packit 985e12
Packit 985e12
{
Packit 985e12
    package    #hide
Packit 985e12
        Filter;
Packit 985e12
Packit 985e12
    sub foo {
Packit 985e12
        bar();
Packit 985e12
    }
Packit 985e12
Packit 985e12
    sub bar {
Packit 985e12
        return Devel::StackTrace->new(
Packit 985e12
            frame_filter => sub { $_[0]{caller}[3] ne 'Filter::foo' } );
Packit 985e12
    }
Packit 985e12
}
Packit 985e12
Packit 985e12
{
Packit 985e12
    package    #hide
Packit 985e12
        FilterAllFrames;
Packit 985e12
Packit 985e12
    sub a_foo { b_foo() }
Packit 985e12
    sub b_foo { a_bar() }
Packit 985e12
    sub a_bar { b_bar() }
Packit 985e12
Packit 985e12
    sub b_bar {
Packit 985e12
        my $stacktrace = Devel::StackTrace->new();
Packit 985e12
        $stacktrace->frames( only_a_frames( $stacktrace->frames() ) );
Packit 985e12
        return $stacktrace;
Packit 985e12
    }
Packit 985e12
Packit 985e12
    sub only_a_frames {
Packit 985e12
        my @frames = @_;
Packit 985e12
        return grep { $_->subroutine() =~ /^FilterAllFrames::a/ } @frames;
Packit 985e12
    }
Packit 985e12
}