leriksen has asked for the wisdom of the Perl Monks concerning the following question:

I have been seeking advice on writing test case that work across platforms in Testing for read() failures on different platforms

adrianh gave me a really good solution, but I now have a new problem that puzzles me.

adrianh's idea was to overload CORE::GLOBAL::read(), but I am getting a strange behaviour - instead of returning to my calling code, it croaks directly.

Here's the code in the File.t file

... $file = File->new('t/file7.test'); eval { # declare as local so default is restored on block exit local *CORE::GLOBAL::read = sub (*\$$;$) { return undef }; # method that calls read() # the above causes that to fail, and so should # croak with a nice message $file->header(); }; # expected error message returned by the # croak in File::header() like($@, qr(Error in reading file header)); ...

And File::header() looks like this

package File; ... sub header { my ( $self ) = @_; my $seek_rc = $self->{FH}->seek($self->{Header}->{OFFSET}, SEEK_SE +T ); if ($seek_rc == 0) { croak( 'Cannot seek to absolute file position on opened file handl +e - ', $! ); } my $length = $self->{FH}->read(my $header, $self->{Header}->{Lengt +h}); # check if read() had an error croak( "Error in reading file header - $!") # pathological test unless defined $length; croak( 'Error in reading file header - Mismatch between expected l +ength (', $self->{Header}->{Length}, ") and returned length ($length +) byte count") unless $length == $self->{Header}->{_Length}; $header =~ s/(?:\015+)?\012.*$/\n/; # remove any garbage at end +of header and replace with \n return $header; } ...

So if the read() returns undef, I expect the croak() message to appear with the $! reason for failure.

Instead, I don't get my croak() message , all I get is $! populated with 'Bad file descriptor'. $@ is empty (that is , $@ eq '').

So why aren't I croak()'ing ?

>perl -v This is perl, v5.8.3 built for i686-linux

use brain;

Replies are listed 'Best First'.
Re: Overloaded *CORE:: function not behaving correctly
by broquaint (Abbot) on Jul 29, 2004 at 02:53 UTC
    You have to override *CORE::GLOBAL:: functions at compile-time so when the parser sees them they're pointing to the right bit of code e.g
    BEGIN { *CORE::GLOBAL::glob = sub { "glob overriden" }; } print glob('a pattern'), "\n"; *CORE::GLOBAL::join = sub { print "n/a" }; print join(' ', qw/ join not overridden /), "\n"; __output__ glob overriden join not overridden
    HTH

    _________
    broquaint

      OK, both ysth and broquaint seem to be in agreement - you cant do it on the fly (ie like I did with a block-scope and a local operator) a CORE:: function. Looks like a separate test file that uses the BEGIN style is required

      Does anyone know why this is so (the design decision, not the fact), and where the pre-compile requirement is documented ?

      update s/can/cant/

      use brain;

        I believe this is so that builtins aren't looked up every time they are called, which is almost certainly for speed reasons. Where the fact that this 'builtin overriding behaviour needs to be implemented at compile-time' is documented, I'm not sure. It might be documented in the 3rd Camel, but I can't seem to find hide or hair of it in the standard docs. A patch to the Overriding Built-in Functions section of perlsub is probably needed.
        HTH

        _________
        broquaint

Re: Overloaded *CORE:: function not behaving correctly
by ysth (Canon) on Jul 29, 2004 at 02:26 UTC
    IIRC, to overload core functions, you need to do it before the calling code (in this case, IO::Handle I'm guessing, since you are calling it as a method call, and only IO::Handle::read is actually trying to call the core function) is compiled.

    Back up a little, and separate your two apparent issues. Verify that your overloading routine is actually called with a print statement in it. Check if croak is behaving correctly without the overloading and without the eval. Add things to the pot one at a time, so you can see what exact circumstances contribute to the failure you are seeing.

    Apologies if you've already done this; if so, it's not clear from your description of the problem.