Stories
Slash Boxes
Comments
NOTE: use Perl; is on undef hiatus. You can read content, but you can't post it. More info will be forthcoming forthcomingly.

All the Perl that's Practical to Extract and Report

use Perl Log In

Log In

[ Create a new account ]

Shlomi Fish (918)

Shlomi Fish
  shlomif@iglu.org.il
http://www.shlomifish.org/
AOL IM: ShlomiFish (Add Buddy, Send Message)
Yahoo! ID: shlomif2 (Add User, Send Message)
Jabber: ShlomiFish@jabber.org

I'm a hacker of Perl, C, Shell, and occasionally other languages. Perl is my favourite language by far. I'm a member of the Israeli Perl Mongers, and contribute to and advocate open-source technologies. Technorati Profile [technorati.com]

Journal of Shlomi Fish (918)

Tuesday November 21, 2006
09:30 AM

Test::More Inheritance+Export Regression

[ #31675 ]

For WWW-Form, it was decided that the test scripts should use Test::More, but if it isn't available on the system (say because of an older Perl, then the test script will exit immediately with an empty plan. To do that I wrote the following code in a module called CondTestMore.pm (short for "Conditional Test::More"):

# This is an assisting module. It makes sure Test::More is present, and if not
# gracefully exists. Otherwise it behaves the same as Test::More.
#

package CondTestMore;

use vars qw(@ISA);

@ISA=qw(Test::More);

BEGIN
{
    eval {
       require Test::More;
    };
    if ($@)
    {
        warn "You don't have Test::More. Terminating";
        print "1..0\n";
        exit 0;
    }
}

1;

This worked fine at the time. However, recently someone on the IRC asked me why CondTestMore did not work anymore. I tested it with perl-5.8.8 and it indeed didn't work. It still worked with perl-5.8.7 and other versions however. A closer inspection showed that the problem was caused by recent versions of Test::More.

As it turned out Test::More converted to using Test::Builder::Module, from which in turn inherits from the "Exporter" module, and supplies its own import function, which looks like this:

sub import {
    my($class) = shift;

    my $test = $class->builder;

    my $caller = caller;

    $test->exported_to($caller);

    $class->import_extra(\@_);
    my(@imports) = $class->_strip_imports(\@_);

    $test->plan(@_);

    $class->$_export_to_level(1, $class, @imports);
}

Pretty funky, no? Well, Since CondTestMore inherits from Test::More it broke the Exporter logic, and so the ok() is() etc. methods were not exported. After playing a bit with my Perl code, I eventually was able to implement CondTestMore like this, so it will work with the newer Test::More:

package CondTestMore;

BEGIN
{
    eval {
        require Test::More;
    };
    if ($@)
    {
        warn "You don't have Test::More. Terminating";
        print "1..0\n";
        exit 0;
    }
    Test::More->import();
    @ISA = qw(Test::More);
    *EXPORT = \@Test::More::EXPORT;
}

1;

Here, I import the Test::More symbols into the CondTestMore package, and also make CondTestMore's @EXPORT point there, so Test::Builder::Module will like it this way. This seems to work for what I need to do.

So it's a regression, but I'm not sure anyone was supposed to inherit from Test::More in this way.

The Fine Print: The following comments are owned by whoever posted them. We are not responsible for them in any way.
 Full
 Abbreviated
 Hidden
More | Login | Reply
Loading... please wait.
  • As you'll likely have to bundle this module with the distribution, have you thought of bundling Test::More itself? That seems like less work to me.

    • Hi. I knew you were going to suggest that before I read your post here, because I thought about it too earlier. Well, this idea did not cross the minds of the WWW::Form originator and me when we first implemented "CondTestMore". However, now that I think of it, I believe it would be sub-optimal because bundling Test::More and all of its dependencies (like Test::Builder) will increase the size of the WWW::Form distribution considerably. So I guess we'll stick with CondTestMore for the time being.

      I shoul

      • Okay, so instead of adding one line to your Makefile.PL or a few kilobytes to the distribution size, you want to maintain your own code that doesn't do as much, takes more work to maintain, has no other users, and increases your testing burden by adding an entirely new test path, when there is one really good way to solve this problem (mark Test::More as a dependency in your build file) and one decent way to solve this problem (bundle Test::More).

        I have some weird hobbies too, but ... wow. Good luck with

        • Actually, the Makefile.PL [cpan.org] does specify a dependency on Test::More. We just still want to have CondTestMore in case a user on an older perl installation that doesn't have Test::More, tries to build it from the source without using CPAN.pm/CPANPLUS.pm.