I stumbled across a strange issue in Inline::CPP.  Here's a test to
illustrate it:

# Break object instantiation such that accessors fetch bad data.

use strict;
use warnings;

use Test::More;

use Inline 'C++' => <<END;

class CStrTest {
    public:
        CStrTest( char* a );
        char* get_name();
    private:
        char* x;
};

CStrTest::CStrTest( char* a ) {
   x = a;
}

char* CStrTest::get_name() {
    return x;
}

END


note( 'Subtest: Testing object instantiated by Class->new() syntax.' );

subtest 'Object instantiated with Class->new() syntax.' => sub {
    plan tests => 4;

    my $obj1 = CStrTest->new( 'Honest' );
    my $obj2 = CStrTest->new( 'Lucky'  );
    isa_ok( $obj1, 'CStrTest', '$obj1' );
    isa_ok( $obj2, 'CStrTest', '$obj2' );
    is( $obj1->get_name, 'Honest', "get_name on \$obj1 (Honest)" );
    is( $obj2->get_name, 'Lucky',  "get_name on \$obj2 (Lucky)"  );

};


TODO: {

    local $TODO = 'Tests on new_ok() objects fail. Still investigating why.';

    note(
        'Subtest: Testing object instantiated by ' .
        'Test::More::new_ok() syntax.'
    );

    subtest 'Object instantiated with new_ok().' => sub {
        plan tests => 4;

        my $obj1 = new_ok( 'CStrTest', [ 'Mickey' ], '$obj1' );
        my $obj2 = new_ok( 'CStrTest', [ 'Donald' ], '$obj2' );
        is( $obj1->get_name, 'Mickey', "get_name on \$obj1 (Mickey)" );
        is( $obj2->get_name, 'Donald', "get_name on \$obj2 (Donald)" );
    };

}

done_testing();

__END__

And the output.....

# Subtest: Testing object instantiated by Class->new() syntax.
    1..4
    ok 1 - $obj1 isa CStrTest
    ok 2 - $obj2 isa CStrTest
    ok 3 - get_name on $obj1 (Honest)
    ok 4 - get_name on $obj2 (Lucky)
ok 1 - Object instantiated with Class->new() syntax.
# Subtest: Testing object instantiated by Test::More::new_ok() syntax.
    1..4
    ok 1 - $obj1 isa CStrTest
    ok 2 - $obj2 isa CStrTest
    not ok 3 - get_name on $obj1 (Mickey)
    #   Failed test 'get_name on $obj1 (Mickey)'
    #   at t/16charptr.t line 58.
    #          got: 'Donald'
    #     expected: 'Mickey'
    not ok 4 - get_name on $obj2 (Donald)
    #   Failed test 'get_name on $obj2 (Donald)'
    #   at t/16charptr.t line 59.
    #          got: ''
    #     expected: 'Donald'
    # Looks like you failed 2 tests of 4.
not ok 2 - Object instantiated with new_ok(). # TODO Tests on new_ok()
objects fail. Still investigating why.
#   Failed (TODO) test 'Object instantiated with new_ok().'
#   at t/16charptr.t line 60.
1..2

It looks to me like what's happening is that when the object is
instantiated using Test::More::use_ok(), the string passed in to the
constructor must be falling out of scope and being garbage-collected
so that the char* becomes invalid.  But this isn't happening when the
object is instantiated with Class->new() syntax.

That's just a hunch.  Here are some additional facts:  There is no
failure if we pass a basic data type instead of a pointer to a
c-string.  That's because when passing basic data types copies are
made, whereas when passing pointers around there is no additional copy
of the data pointed to.

I'm trying to decide if this is a Test::More::use_ok bug, a bug in my
test C++ code, a bug in Inline::CPP, a bug in the typemap for char*,
or a bug in Inline::C.

If anyone wishes to play with it, you can find it in my github repo:
g...@github.com:daoswald/Inline-CPP.git

Check out the 'cstr-test' branch.  The specific test is t/16charptr.t

Dave

-- 

David Oswald
daosw...@gmail.com

Reply via email to