@@ -10,6 +10,9 @@ my $builder = $class->new
create_makefile_pl => 'traditional',
dist_author => 'Eirik Berg Hanssen <ebhanssen@cpan.org>',
dist_version_from => 'lib/Test/Trap.pm',
+ configure_requires =>
+ { 'Module::Build' => 0,
+ },
requires =>
{ 'base' => 0, # core ...
'constant' => 0, # core ...
@@ -1,5 +1,19 @@
Revision history for Test-Trap
+0.2.5 Sun Nov 16 18:31:42 CET 2014
+ This release localizes $! (ERRNO) for internal operations that
+ change it, as suggested by Felipe Gasper. For the same
+ operations, it also localizes $^E (extended OS error).
+ Library files:
+ - Localize $! and $^E for internal operations that change them.
+ Tests:
+ - Check that bare test blocks leave $!, %!, and $^E unchanged,
+ but that blocks that modify $! and $^E still do so.
+ Also:
+ - Added Module::Build to the configure_requires.
+ - Fix emacs mode line on t/14-leaks.t.
+ - Better comments in lib/Test/Trap/Builder.pm.
+
0.2.4 Sun Mar 30 10:02:16 CEST 2014
This release fixes a memory leak with the default tempfile
backend layer implementation for trapping output. The
@@ -4,7 +4,7 @@
"Eirik Berg Hanssen <ebhanssen@cpan.org>"
],
"dynamic_config" : 1,
- "generated_by" : "Module::Build version 0.38, CPAN::Meta::Converter version 2.110440",
+ "generated_by" : "Module::Build version 0.4003, CPAN::Meta::Converter version 2.133380",
"license" : [
"perl_5"
],
@@ -16,49 +16,49 @@
"prereqs" : {
"configure" : {
"requires" : {
- "Module::Build" : "0.38"
+ "Module::Build" : "0"
}
},
"runtime" : {
"requires" : {
- "Carp" : 0,
- "Data::Dump" : 0,
- "Exporter" : 0,
- "File::Temp" : 0,
- "IO::Handle" : 0,
- "Test::Builder" : 0,
- "Test::More" : 0,
+ "Carp" : "0",
+ "Data::Dump" : "0",
+ "Exporter" : "0",
+ "File::Temp" : "0",
+ "IO::Handle" : "0",
+ "Test::Builder" : "0",
+ "Test::More" : "0",
"Test::Tester" : "0.107",
- "base" : 0,
- "constant" : 0,
- "lib" : 0,
+ "base" : "0",
+ "constant" : "0",
+ "lib" : "0",
"perl" : "v5.6.2",
- "strict" : 0,
- "version" : 0,
- "warnings" : 0
+ "strict" : "0",
+ "version" : "0",
+ "warnings" : "0"
}
}
},
"provides" : {
"Test::Trap" : {
"file" : "lib/Test/Trap.pm",
- "version" : "v0.2.4"
+ "version" : "v0.2.5"
},
"Test::Trap::Builder" : {
"file" : "lib/Test/Trap/Builder.pm",
- "version" : "v0.2.4"
+ "version" : "v0.2.5"
},
"Test::Trap::Builder::PerlIO" : {
"file" : "lib/Test/Trap/Builder/PerlIO.pm",
- "version" : "v0.2.4"
+ "version" : "v0.2.5"
},
"Test::Trap::Builder::SystemSafe" : {
"file" : "lib/Test/Trap/Builder/SystemSafe.pm",
- "version" : "v0.2.4"
+ "version" : "v0.2.5"
},
"Test::Trap::Builder::TempFile" : {
"file" : "lib/Test/Trap/Builder/TempFile.pm",
- "version" : "v0.2.4"
+ "version" : "v0.2.5"
}
},
"release_status" : "stable",
@@ -67,5 +67,5 @@
"http://dev.perl.org/licenses/"
]
},
- "version" : "v0.2.4"
+ "version" : "v0.2.5"
}
@@ -4,9 +4,9 @@ author:
- 'Eirik Berg Hanssen <ebhanssen@cpan.org>'
build_requires: {}
configure_requires:
- Module::Build: 0.38
+ Module::Build: 0
dynamic_config: 1
-generated_by: 'Module::Build version 0.38, CPAN::Meta::Converter version 2.110440'
+generated_by: 'Module::Build version 0.4003, CPAN::Meta::Converter version 2.133380'
license: perl
meta-spec:
url: http://module-build.sourceforge.net/META-spec-v1.4.html
@@ -15,19 +15,19 @@ name: Test-Trap
provides:
Test::Trap:
file: lib/Test/Trap.pm
- version: v0.2.4
+ version: v0.2.5
Test::Trap::Builder:
file: lib/Test/Trap/Builder.pm
- version: v0.2.4
+ version: v0.2.5
Test::Trap::Builder::PerlIO:
file: lib/Test/Trap/Builder/PerlIO.pm
- version: v0.2.4
+ version: v0.2.5
Test::Trap::Builder::SystemSafe:
file: lib/Test/Trap/Builder/SystemSafe.pm
- version: v0.2.4
+ version: v0.2.5
Test::Trap::Builder::TempFile:
file: lib/Test/Trap/Builder/TempFile.pm
- version: v0.2.4
+ version: v0.2.5
requires:
Carp: 0
Data::Dump: 0
@@ -46,4 +46,4 @@ requires:
warnings: 0
resources:
license: http://dev.perl.org/licenses/
-version: v0.2.4
+version: v0.2.5
@@ -1,4 +1,4 @@
-# Note: this file was auto-generated by Module::Build::Compat version 0.3800
+# Note: this file was auto-generated by Module::Build::Compat version 0.4003
require 5.006002;
use ExtUtils::MakeMaker;
WriteMakefile
@@ -1,6 +1,6 @@
package Test::Trap::Builder::PerlIO;
-use version; $VERSION = qv('0.2.4');
+use version; $VERSION = qv('0.2.5');
use strict;
use warnings;
@@ -30,7 +30,7 @@ Test::Trap::Builder::PerlIO - Output layer backend using PerlIO::scalar
=head1 VERSION
-Version 0.2.4
+Version 0.2.5
=head1 DESCRIPTION
@@ -1,6 +1,6 @@
package Test::Trap::Builder::SystemSafe;
-use version; $VERSION = qv('0.2.4');
+use version; $VERSION = qv('0.2.5');
use strict;
use warnings;
@@ -16,11 +16,15 @@ sub import {
if (tied *$globref or $fileno < 0) {
$self->Exception("SystemSafe only works with real file descriptors; aborting");
}
- my ($fh, $file) = tempfile( UNLINK => 1 ); # XXX: Test?
+ my ($fh, $file) = do {
+ local ($!, $^E);
+ tempfile( UNLINK => 1 ); # XXX: Test?
+ };
my ($fh_keeper, $autoflush_keeper);
my $Die = $self->ExceptionFunction;
for my $buffer ($self->{$name}) {
$self->Teardown($_) for sub {
+ local ($!, $^E);
if ($pid == $$) {
# this process opened it, so it gets to collect the contents:
local $/;
@@ -44,8 +48,11 @@ sub import {
};
}
binmode $fh; # superfluous?
- open $fh_keeper, ">&$fileno"
- or $self->Exception("Cannot dup '$fileno' for $name: '$!'");
+ {
+ local ($!, $^E);
+ open $fh_keeper, ">&$fileno"
+ or $self->Exception("Cannot dup '$fileno' for $name: '$!'");
+ }
$autoflush_keeper = $globref->autoflush;
_close_reopen( $self->ExceptionFunction, $globref, $fileno, ">>$file",
sub {
@@ -61,6 +68,7 @@ sub import {
sub _close_reopen {
my ($Die, $glob, $fno_want, $what, $err) = @_;
+ local ($!, $^E);
close *$glob;
my @fh;
while (1) {
@@ -94,7 +102,7 @@ Test::Trap::Builder::SystemSafe - "Safe" output layer backend using File::Temp
=head1 VERSION
-Version 0.2.4
+Version 0.2.5
=head1 DESCRIPTION
@@ -1,6 +1,6 @@
package Test::Trap::Builder::TempFile;
-use version; $VERSION = qv('0.2.4');
+use version; $VERSION = qv('0.2.5');
use strict;
use warnings;
@@ -13,13 +13,17 @@ sub import {
my $self = shift;
my ($name, $fileno, $globref) = @_;
my $pid = $$;
- my ($fh, $file) = tempfile( UNLINK => 1 ); # XXX: Test?
+ my ($fh, $file) = do {
+ local ($!, $^E);
+ tempfile( UNLINK => 1 ); # XXX: Test?
+ };
# make an alias to $self->{$name}, so that the closure does not hold $self:
for my $buffer ($self->{$name}) {
$self->Teardown($_) for sub {
# if the file is opened by some other process, that one should deal with it:
return unless $pid == $$;
local $/;
+ local ($!, $^E);
$buffer .= <$fh>;
close $fh;
unlink $file;
@@ -29,6 +33,7 @@ sub import {
local *$globref;
{
no warnings 'io';
+ local ($!, $^E);
open *$globref, '>>', $file;
}
binmode *$globref; # must write as we read.
@@ -47,7 +52,7 @@ Test::Trap::Builder::TempFile - Output layer backend using File::Temp
=head1 VERSION
-Version 0.2.4
+Version 0.2.5
=head1 DESCRIPTION
@@ -1,6 +1,6 @@
package Test::Trap::Builder;
-use version; $VERSION = qv('0.2.4');
+use version; $VERSION = qv('0.2.5');
use strict;
use warnings;
@@ -142,6 +142,7 @@ BEGIN { # Test callback registration and test method generation:
);
# backwards compatibility -- don't use these:
@argspec{ qw( object all indexed ) } = @argspec{ qw( trap entirety element ) };
+ # stringifying the CODE refs, that we may easily check if we have a specific one:
my %isname = ( $argspec{name} => 1 );
my %iselement = ( $argspec{element} => 1 );
my %takesarg = ( $argspec{predicate} => 1 );
@@ -352,7 +353,7 @@ sub layer_implementation {
next;
}
my ($name, $arg) =
- /^ ( [^\(]+ ) # meth: anything but '('
+ /^ ( [^\(]+ ) # layer name: anything but '('
(?: # begin optional group
\( # literal '('
( [^\)]* ) # arg: anything but ')'
@@ -376,7 +377,7 @@ Test::Trap::Builder - Backend for building test traps
=head1 VERSION
-Version 0.2.4
+Version 0.2.5
=head1 SYNOPSIS
@@ -1,6 +1,6 @@
package Test::Trap;
-use version; $VERSION = qv('0.2.4');
+use version; $VERSION = qv('0.2.5');
use strict;
use warnings;
@@ -301,7 +301,7 @@ Test::Trap - Trap exit codes, exceptions, output, etc.
=head1 VERSION
-Version 0.2.4
+Version 0.2.5
=head1 SYNOPSIS
@@ -14,7 +14,7 @@ BEGIN {
local $@;
eval qq{ use $pkg };
if (exists &{"$pkg\::import"}) {
- plan tests => 1 + 6*10 + 5*3 + 1; # 10 runtests; 3 inner_tests
+ plan tests => 1 + 6*10 + 5*3 + 13; # 10 runtests; 3 inner_tests; another bunch ...
}
else {
plan skip_all => "$backend backend not supported; skipping";
@@ -165,4 +165,31 @@ trap {
};
unlike $T->stderr, qr/, \S+ line 1\./, 'No "<$f> line ..." stuff, please';
+# test the $! handling:
+my $errnum = 11; # "Resource temporarily unavailable" locally -- sounds good :-P
+my $errstring = do { local $! = $errnum; "$!" };
+my $erros = do { local $! = $errnum; $^E };
+my ($errsym) = do { local $! = $errnum; grep { $!{$_} } keys %! };
+for my $case ([Bare => sub { return 42 }], [Dying => sub { die 42 }], [Exiting => sub { exit 42 }]) {
+ my ($type, $code);
+ local $! = $errnum;
+ trap { $code->() };
+ my ($sym) = grep { $!{$_} } keys %!;
+ is $!+0, $errnum, "$type trap doesn't change errno (remains $errnum/$errstring)";
+ is $^E, $erros, "$type trap doesn't change extended OS error (remains $erros)";
+ is $sym, $errsym, "$type trap doesn't change the error symbol (remains $errsym)";
+}
+
+{
+ local $! = $errnum;
+ trap {
+ $! = 0;
+ $^E = '';
+ };
+ my ($sym) = grep { $!{$_} } keys %!;
+ is $!+0, 0, "Errno-unsetting trap unsets errno (it's not localized)";
+ is $^E, '', "Errno-unsetting trap unsets extended OS error (it's not localized)";
+ is $sym, undef, "Errno-unsetting trap unsets the error symbol (it's not localized)";
+}
+
1;
@@ -2,7 +2,7 @@
# -*- mode: cperl ; compile-command: "cd .. ; ./Build ; prove -vb t/04-*.t" -*-
BEGIN { $_ = defined && /(.*)/ && $1 for @ENV{qw/ TMPDIR TEMP TMP /} } # taint vs tempfile
-use Test::More tests => 6;
+use Test::More tests => 9;
use strict;
use warnings;
@@ -22,6 +22,14 @@ BEGIN {
use_ok( 'Test::Trap' );
}
+# test the $! handling:
+my $errnum = 11; # "Resource temporarily unavailable" locally -- sounds good :-P
+my $errstring = do { local $! = $errnum; "$!" };
+my $erros = do { local $! = $errnum; $^E };
+my ($errsym) = do { local $! = $errnum; grep { $!{$_} } keys %! };
+
+$! = $errnum;
+
trap { exit };
is( $trap->exit, 0, "Trapped the first exit");
trap {
@@ -34,6 +42,11 @@ trap {
};
like( $trap->stderr, qr/^Subroutine (?:CORE::GLOBAL::)?exit redefined at \Q${\__FILE__} line/, 'Override warning' );
+my ($sym) = grep { $!{$_} } keys %!;
+is $!+0, $errnum, "These traps don't change errno (remains $errnum/$errstring)";
+is $^E, $erros, "These traps don't change extended OS error (remains $erros)";
+is $sym, $errsym, "These traps don't change the error symbol (remains $errsym)";
+
$ready_for_exit++;
exit;
@@ -1,5 +1,5 @@
#!perl -T
-# -*- mode: cperl ; compile-command: "cd .. ; ./Build ; prove -vb t/13-*.t" -*-
+# -*- mode: cperl ; compile-command: "cd .. ; ./Build ; prove -vb t/14-*.t" -*-
BEGIN {
$_ = defined && /(.*)/ && $1 for @ENV{qw/ TMPDIR TEMP TMP /}; # taint vs tempfile