+ return $status;
+}
+
+=head2 C<import>
+
+ use Test::Valgrind %options;
+
+In the parent process, L</import> calls L</analyse> with the arguments it received itself - except that if no C<file> option was supplied, it tries to pick the first caller context that looks like a script.
+When the analysis ends, it exits with the status returned by the action (for the default TAP-generator action, it's the number of failed tests).
+
+In the child process, it just C<return>s so that the calling code is actually run under C<valgrind>, albeit two side-effects :
+
+=over 4
+
+=item *
+
+L<Perl::Destruct::Level> is loaded and the destruction level is set to C<3>.
+
+=item *
+
+Autoflush on C<STDOUT> is turned on.
+
+=back
+
+=cut
+
+# We use as little modules as possible in run mode so that they don't pollute
+# the analysis. Hence all the requires.
+
+my $run;
+
+sub import {
+ my $class = shift;
+ $class = ref($class) || $class;
+
+ if (@_ % 2) {
+ require Carp;
+ Carp::croak('Optional arguments must be passed as key => value pairs');
+ }
+ my %args = @_;
+
+ if (defined delete $args{run} or $run) {
+ require Perl::Destruct::Level;
+ Perl::Destruct::Level::set_destruct_level(3);
+ {
+ my $oldfh = select STDOUT;
+ $|++;
+ select $oldfh;
+ }
+ $run = 1;
+ return;
+ }
+
+ my $file = delete $args{file};
+ unless (defined $file) {
+ my ($next, $last_pm);
+ for (my $l = 0; 1; ++$l) {
+ $next = (caller $l)[1];
+ last unless defined $next;
+ next if $next =~ /^\s*\(\s*eval\s*\d*\s*\)\s*$/;
+ if ($next =~ /\.pmc?$/) {
+ $last_pm = $next;
+ } else {
+ $file = $next;
+ last;
+ }
+ }
+ $file = $last_pm unless defined $file;
+ }
+
+ unless (defined $file) {
+ require Test::Builder;
+ Test::Builder->new->diag('Couldn\'t find a valid source file');
+ return;
+ }
+
+ if ($file ne '-e') {
+ exit $class->analyse(
+ file => $file,
+ %args,
+ );
+ }
+
+ require File::Temp;
+ my $tmp = File::Temp->new;
+
+ require Filter::Util::Call;
+ Filter::Util::Call::filter_add(sub {
+ my $status = Filter::Util::Call::filter_read();
+ if ($status > 0) {
+ print $tmp $_;
+ } elsif ($status == 0) {
+ close $tmp;
+ my $code = $class->analyse(
+ file => $tmp->filename,
+ %args,
+ );
+ exit $code;
+ }
+ $status;
+ });