Skip Menu |

This queue is for tickets about the Test-Kit CPAN distribution.

Report information
The Basics
Id: 89575
Status: resolved
Priority: 0/
Queue: Test-Kit

People
Owner: ovid [...] cpan.org
Requestors: kaoru [...] slackwise.net
Cc:
AdminCc:

Bug Information
Severity: Important
Broken in: 0.101
Fixed in: (no value)



Subject: A Test::Kit module only seems to work in "main"?
Some examples here: https://github.com/kaoru/test-kit-broken-examples/tree/master/02-main https://github.com/kaoru/test-kit-broken-examples/tree/master/03-packages Am I getting something wrong here? I've looked at the code for Test::Kit and it seems to try to use caller() to do the right thing and export everything into the right namespace... but I must admit I don't fully understand what it's doing!
I poked and prodded it in my usual semi-understanding way and came up with this diff... ###################################### --- /home/alex/perl5/perlbrew/perls/perl-5.16.3/lib/site_perl/5.16.3/Test/Kit.pm 2013-10-16 09:22:04.000000000 +0100 +++ 01-test-aggregate/lib/Test/Kit.pm 2013-10-17 14:23:29.000000000 +0100 @@ -103,7 +103,7 @@ and excluding. To do this, add a hashref after the module name with keys 'exclude', 'rename', or both. - use Test::Most + use Test::Most 'Test::Something' => { # or a scalar for just one exclude => [qw/ list of excluded functions/], @@ -122,7 +122,7 @@ sub import { my $class = shift; - my $callpack = caller(1); + my $callpack = $class->_get_callpack(); my $basic_functions = namespace::clean->get_functions($class); @@ -153,11 +153,44 @@ return 1; } +sub _get_callpack { + my $class = shift; + + my $callpack; + + # so, as far as I can tell, on Perl 5.14 and 5.16 at least, we have the + # following callstack... + # + # 1. Test::Kit::import, + # 2. MyTest::BEGIN + # 3. (eval) + # 4. (eval) + # 5. main::BEGIN + # 6. (eval) + # + # ... and we want to get the package name "MyTest" out of there. + # So, let's look for the first occurrence of BEGIN or something! + + my @begins = grep { m/::BEGIN$/ } + map { (caller($_))[3] } + 1 .. 10; + + if ($begins[0] && $begins[0] =~ m/^ (.+) ::BEGIN $/msx) { + $callpack = $1; + } + else { + die "Unable to determine callpack for some reason..."; + } + + return $callpack; +} + sub _setup_import { my ( $class, $features ) = @_; - my $callpack = caller(1); # this is the composed test package + my $callpack = $class->_get_callpack(); my $import = "$callpack\::import"; my $isa = "$callpack\::ISA"; + my $export = "$callpack\::EXPORT"; no strict 'refs'; if ( defined &$import ) { Carp::croak("Class $callpack must not define an &import method"); @@ -166,9 +199,20 @@ unshift @$isa => 'Test::Kit::Features'; *$import = sub { my ( $class, @args ) = @_; + @args = $class->BUILD(@args) if $class->can('BUILD'); @args = $class->_setup_features( $features, @args ); @_ = ( $class, @args ); + + no strict 'refs'; + @$export = keys %{ namespace::clean->get_functions($class) }; + + # HACK! + @$export = grep { $_ ne 'import' } @$export; + @$export = grep { $_ ne 'BEGIN' } @$export; + push @$export, '$TODO'; + # END HACK! + goto &Test::Builder::Module::import; }; } ###################################### There's really two changes here: 1. We call _get_callpack() instead of caller(1), which correctly gets the name of the class that is using Test::Kit in all cases. 2. We set @EXPORT on that class before goto'ing to Test::Builder::Module::import so that Test::Builder::Module::import() (which is really just Exporter::import()) actually exports some functions. Not sure if this is the expected behaviour or the nicest/cleanest/most-fitting-in implementation of those two fixes... but as far as I can tell it makes these cases work! Unfortunately it doesn't pass all the tests in the current test suite... basic.t is failing to compile (or rather, failing during BEGIN) and exceptions.t is catching a differently named exception now. Will look into those at some point, unless you want to jump in :-)
Subject: test-kit-kaoru-hack.diff
--- /home/alex/perl5/perlbrew/perls/perl-5.16.3/lib/site_perl/5.16.3/Test/Kit.pm 2013-10-16 09:22:04.000000000 +0100 +++ 01-test-aggregate/lib/Test/Kit.pm 2013-10-17 14:23:29.000000000 +0100 @@ -103,7 +103,7 @@ and excluding. To do this, add a hashref after the module name with keys 'exclude', 'rename', or both. - use Test::Most + use Test::Most 'Test::Something' => { # or a scalar for just one exclude => [qw/ list of excluded functions/], @@ -122,7 +122,7 @@ sub import { my $class = shift; - my $callpack = caller(1); + my $callpack = $class->_get_callpack(); my $basic_functions = namespace::clean->get_functions($class); @@ -153,11 +153,44 @@ return 1; } +sub _get_callpack { + my $class = shift; + + my $callpack; + + # so, as far as I can tell, on Perl 5.14 and 5.16 at least, we have the + # following callstack... + # + # 1. Test::Kit::import, + # 2. MyTest::BEGIN + # 3. (eval) + # 4. (eval) + # 5. main::BEGIN + # 6. (eval) + # + # ... and we want to get the package name "MyTest" out of there. + # So, let's look for the first occurrence of BEGIN or something! + + my @begins = grep { m/::BEGIN$/ } + map { (caller($_))[3] } + 1 .. 10; + + if ($begins[0] && $begins[0] =~ m/^ (.+) ::BEGIN $/msx) { + $callpack = $1; + } + else { + die "Unable to determine callpack for some reason..."; + } + + return $callpack; +} + sub _setup_import { my ( $class, $features ) = @_; - my $callpack = caller(1); # this is the composed test package + my $callpack = $class->_get_callpack(); my $import = "$callpack\::import"; my $isa = "$callpack\::ISA"; + my $export = "$callpack\::EXPORT"; no strict 'refs'; if ( defined &$import ) { Carp::croak("Class $callpack must not define an &import method"); @@ -166,9 +199,20 @@ unshift @$isa => 'Test::Kit::Features'; *$import = sub { my ( $class, @args ) = @_; + @args = $class->BUILD(@args) if $class->can('BUILD'); @args = $class->_setup_features( $features, @args ); @_ = ( $class, @args ); + + no strict 'refs'; + @$export = keys %{ namespace::clean->get_functions($class) }; + + # HACK! + @$export = grep { $_ ne 'import' } @$export; + @$export = grep { $_ ne 'BEGIN' } @$export; + push @$export, '$TODO'; + # END HACK! + goto &Test::Builder::Module::import; }; }
Updated my fix so that the current Test::Kit test suite also passes. https://github.com/kaoru/test-kit-broken-examples/commits/master https://github.com/kaoru/test-kit-broken-examples/commit/324f69055af1627cc0e279c785808e0d8b0ee0d7 - fixes basic.t https://github.com/kaoru/test-kit-broken-examples/commit/7861396fc3e852b4ca2954ca18df11d76c1e34a0 - fixes exceptions.t With all my tests still passing too. ================== Still probably needs some fixing and tidying up since it's entirely possible that half my changes were bad, confusing, no-op type changes that just happened to not break things too badly despite them being entirely wrong. The @EXPORT setting I think is good. The implementation of _get_callpack() could probably use some work by somebody who understands Perl call stacks better than me.
Hey Curtis, After seeing Matt Trout's talk on Import::Into at LPW on Saturday I realised it might be perfect for Test::Kit. I've started on a branch in my test-kit-broken-examples repo here: https://github.com/kaoru/test-kit-broken-examples/tree/import-into It allowed me to delete a whole load of my hacky and poorly thought through code! So far all my tests are passing, but parts of the original test suite are still failing because I didn't implement excluded functions yet. Will keep hacking on it. Let me know if you have any input :-) - Alex
Aaand now the full original Test::Kit test suite passes on my branch... https://github.com/kaoru/test-kit-broken-examples/tree/import-into Ok, so I did delete one of the exceptions.t tests... https://github.com/kaoru/test-kit-broken-examples/commit/73a6f36ecce629f2036f174fb9d65c6b1203829b But as I wrote in the commit message, I'm pretty sure it's not relevant anyway. Test::Kit no longer creates an import method in your class, it just causes your class to export things without an import method, or something... I think? It's late :-)
On Thu Dec 05 17:44:23 2013, KAORU wrote: Show quoted text
> But as I wrote in the commit message, I'm pretty sure it's not > relevant anyway. Test::Kit no longer creates an import method in your > class, it just causes your class to export things without an import > method, or something... I think? It's late :-)
Yeah it clearly was late, because that was clearly a load of rubbish. But I still think it doesn't ever export &import so I don't know quite what that test is trying to do.
Oh, I see it now... that test was rendered redundant by one of my earlier hacks! https://github.com/kaoru/test-kit-broken-examples/commit/8011d219caeb559a5fe86231cf3d7b152330e1cb#diff-d931e82b1b5f2afa8bae64265d1e72bfR221 If I remove that hack then my 03-packages test directory starts to fail: alex@yuzu:~/Documents/Git/stuff/test-kit-broken-examples$ git diff diff --git a/Kit.pm b/Kit.pm index 61bcf92..e9ece57 100644 --- a/Kit.pm +++ b/Kit.pm @@ -294,8 +294,6 @@ sub _setup_import { @$export = keys %{ namespace::clean->get_functions($class) }; # HACK! - @$export = grep { $_ ne 'import' } @$export; - @$export = grep { $_ ne 'BEGIN' } @$export; push @$export, '$TODO'; # END HACK! alex@yuzu:~/Documents/Git/stuff/test-kit-broken-examples$ cd 03-packages ; prove -l *.t bad.t ... Can't locate object method "_setup_features" via package "AnotherModule" at /home/alex/Documents/Git/stuff/test-kit-broken-examples/03-packages/lib/Test/Kit.pm line 290. BEGIN failed--compilation aborted at bad.t line 2. bad.t ... Dubious, test returned 255 (wstat 65280, 0xff00) No subtests run good.t .. ok If I remove the '$TODO' hack as well then t/compose.t from the original Test::Kit test suite starts to fail too. *shrug* Two step forwards, one step back! Will give it another look over sometime soon I'm sure.
Subject: Re: [rt.cpan.org #89575] A Test::Kit module only seems to work in "main"?
Date: Fri, 6 Dec 2013 02:18:29 -0800 (PST)
To: "bug-Test-Kit [...] rt.cpan.org" <bug-Test-Kit [...] rt.cpan.org>
From: Ovid <curtis_ovid_poe [...] yahoo.com>
Alex, This sounds awesome! I am, however, in New York at the moment, so I won't be able to look at this much until I get back. Looking forward to this, though!   Best, Ovid -- IT consulting, training, international recruiting        http://www.allaroundtheworld.fr/. Buy my book! - http://bit.ly/beginning_perl Live and work overseas - http://www.overseas-exile.com/ On Thursday, 5 December 2013, 18:31, Alex Balhatchet via RT <bug-Test-Kit@rt.cpan.org> wrote:       Queue: Test-Kit Show quoted text
>Ticket <URL: https://rt.cpan.org/Ticket/Display.html?id=89575 > > >Oh, I see it now... that test was rendered redundant by one of my earlier hacks! > >https://github.com/kaoru/test-kit-broken-examples/commit/8011d219caeb559a5fe86231cf3d7b152330e1cb#diff-d931e82b1b5f2afa8bae64265d1e72bfR221 > >If I remove that hack then my 03-packages test directory starts to fail: > >alex@yuzu:~/Documents/Git/stuff/test-kit-broken-examples$ git diff >diff --git a/Kit.pm b/Kit.pm >index 61bcf92..e9ece57 100644 >--- a/Kit.pm >+++ b/Kit.pm >@@ -294,8 +294,6 @@ sub _setup_import { >            @$export = keys %{ namespace::clean->get_functions($class) }; > >            # HACK! >-            @$export = grep { $_ ne 'import' } @$export; >-            @$export = grep { $_ ne 'BEGIN'  } @$export; >            push @$export, '$TODO'; >            # END HACK! > >alex@yuzu:~/Documents/Git/stuff/test-kit-broken-examples$ cd 03-packages ; prove -l *.t >bad.t ... Can't locate object method "_setup_features" via package "AnotherModule" at /home/alex/Documents/Git/stuff/test-kit-broken-examples/03-packages/lib/Test/Kit.pm line 290. >BEGIN failed--compilation aborted at bad.t line 2. >bad.t ... Dubious, test returned 255 (wstat 65280, 0xff00) >No subtests run >good.t .. ok  > > > >If I remove the '$TODO' hack as well then t/compose.t from the original Test::Kit test suite starts to fail too. > >*shrug* > >Two step forwards, one step back! Will give it another look over sometime soon I'm sure. > > >
Hey Ovid, Just moved flat which has given me some programming time while I wait for our internet connection to be installed ;-) I've written a new module Test::Kit2 based on the issues I found with Test::Kit and the fixes I hacked in place. It's not up on CPAN yet but you can take a look on Github: https://github.com/kaoru/Test-Kit2 There's still a few more tests I want to add before it wings its way to CPAN. If you have a chance, take a look and let me know what you think. Thanks, - Alex
Subject: Re: [rt.cpan.org #89575] A Test::Kit module only seems to work in "main"?
Date: Sat, 19 Apr 2014 09:02:42 -0700 (PDT)
To: "bug-Test-Kit [...] rt.cpan.org" <bug-Test-Kit [...] rt.cpan.org>
From: Ovid <curtis_ovid_poe [...] yahoo.com>
Hi Alex, Unlike you, I don't have tons of free time, so it's hard for me to keep up with my open source work. However, would you like to take over maintenance of Test::Kit? It might be the easiest way of resolving some issues. Cheers, Ovid  -- IT consulting, training, international recruiting        http://www.allaroundtheworld.fr/. Buy my book! - http://bit.ly/beginning_perl Live and work overseas - http://www.overseas-exile.com/ On Saturday, 19 April 2014, 12:49, Alex Balhatchet via RT <bug-Test-Kit@rt.cpan.org> wrote:       Queue: Test-Kit Show quoted text
>Ticket <URL: https://rt.cpan.org/Ticket/Display.html?id=89575 > > >Hey Ovid, > >Just moved flat which has given me some programming time while I wait for our internet connection to be installed ;-) > >I've written a new module Test::Kit2 based on the issues I found with Test::Kit and the fixes I hacked in place. It's not up on CPAN yet but you can take a look on Github: > >https://github.com/kaoru/Test-Kit2 > >There's still a few more tests I want to add before it wings its way to CPAN. > >If you have a chance, take a look and let me know what you think. > >Thanks, > >- Alex > > >
Show quoted text
> Unlike you, I don't have tons of free time, so it's hard for me to > keep up with my open source work.
I can imagine, hope AAtW is going well! Show quoted text
> However, would you like to take over > maintenance of Test::Kit? It might be the easiest way of resolving > some issues.
Sure, if you want to ship me COMAINT on Test::Kit I can re-brand Test::Kit2 as Test::Kit 2.0 and send it down the pipes to CPAN. Do you know of anybody using Test::Kit in the real world? Specifically in weird and/or wonderful ways? I'd love to get a second pair of eyes on it before I release it. Maybe I'll try the prepan.
I believe this is fully resolved in Test::Kit 2.0