]> git.vpit.fr Git - perl/modules/Test-Valgrind.git/commitdiff
Factor the agnostic part of Test::Valgrind->import out to a new ->analyse
authorVincent Pit <vince@profvince.com>
Tue, 14 Apr 2009 14:20:38 +0000 (16:20 +0200)
committerVincent Pit <vince@profvince.com>
Tue, 14 Apr 2009 14:20:38 +0000 (16:20 +0200)
lib/Test/Valgrind.pm

index 4b33486fe3e34b5eeae8e74d0f2aa01b68dbbccb..601a949997f5991b7c7df4a0f17f402ba9d414d4 100644 (file)
@@ -39,9 +39,11 @@ Due to the nature of perl's memory allocator, this module can't track leaks of P
 This includes non-mortalized scalars and memory cycles. However, it can track leaks of chunks of memory allocated in XS extensions with C<Newx> and friends or C<malloc>.
 As such, it's complementary to the other very good leak detectors listed in the L</SEE ALSO> section.
 
 This includes non-mortalized scalars and memory cycles. However, it can track leaks of chunks of memory allocated in XS extensions with C<Newx> and friends or C<malloc>.
 As such, it's complementary to the other very good leak detectors listed in the L</SEE ALSO> section.
 
-=head1 CONFIGURATION
+=head1 METHODS
 
 
-You can pass parameters to C<import> as a list of key / value pairs, where valid keys are :
+=head2 C<analyse [ %options ]>
+
+Run a C<valgrind> analysis configured by C<%options> :
 
 =over 4
 
 
 =over 4
 
@@ -71,9 +73,11 @@ Defaults to L<Test::Valgrind::Action::Test>.
 
 =item *
 
 
 =item *
 
-C<< diag => $bool >>
+C<< file => $file >>
 
 
-If true, print the output of the test script as diagnostics.
+The file name of the script to analyse.
+
+Ignored if you supply your own custom C<command>, but mandatory otherwise.
 
 =item *
 
 
 =item *
 
@@ -82,7 +86,15 @@ C<< callers => $number >>
 Specify the maximum stack depth studied when valgrind encounters an error.
 Raising this number improves granularity.
 
 Specify the maximum stack depth studied when valgrind encounters an error.
 Raising this number improves granularity.
 
-Default is 12.
+Ignored if you supply your own custom C<tool>, otherwise defaults to C<12>.
+
+=item *
+
+C<< diag => $bool >>
+
+If true, print the output of the test script as diagnostics.
+
+Ignored if you supply your own custom C<action>, otherwise defaults to false.
 
 =item *
 
 
 =item *
 
@@ -90,60 +102,25 @@ C<< extra_supps => \@files >>
 
 Also use suppressions from C<@files> besides C<perl>'s.
 
 
 Also use suppressions from C<@files> besides C<perl>'s.
 
+Defaults to empty.
+
 =item *
 
 C<< no_def_supp => $bool >>
 
 If true, do not use the default suppression file.
 
 =item *
 
 C<< no_def_supp => $bool >>
 
 If true, do not use the default suppression file.
 
+Defaults to false.
+
 =back
 
 =cut
 
 =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 {
+sub analyse {
  shift;
 
  shift;
 
- if (@_ % 2) {
-  require Carp;
-  Carp::croak('Optional arguments must be passed as key => value pairs');
- }
  my %args = @_;
 
  my %args = @_;
 
- if (defined $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, $pm, $next);
- my $l = 0;
- while ($l < 1000) {
-  $next = (caller $l++)[1];
-  last unless defined $next;
-  next if $next eq '-e' or $next =~ /^\s*\(\s*eval\s*\d*\s*\)\s*$/ or !-f $next;
-  if ($next =~ /\.pm$/) {
-   $pm   = $next;
-  } else {
-   $file = $next;
-  }
- }
- unless (defined($file) or defined($file = $pm)) {
-  require Test::Builder;
-  Test::Builder->new->diag('Couldn\'t find a valid source file');
-  return;
- }
-
  my $instanceof = sub {
   require Scalar::Util;
   Scalar::Util::blessed($_[0]) && $_[0]->isa($_[1]);
  my $instanceof = sub {
   require Scalar::Util;
   Scalar::Util::blessed($_[0]) && $_[0]->isa($_[1]);
@@ -154,7 +131,7 @@ sub import {
   require Test::Valgrind::Command;
   $cmd = Test::Valgrind::Command->new(
    command => $cmd || 'PerlScript',
   require Test::Valgrind::Command;
   $cmd = Test::Valgrind::Command->new(
    command => $cmd || 'PerlScript',
-   file    => $file,
+   file    => delete $args{file},
    args    => [ '-MTest::Valgrind=run,1' ],
   );
  }
    args    => [ '-MTest::Valgrind=run,1' ],
   );
  }
@@ -164,7 +141,7 @@ sub import {
   require Test::Valgrind::Tool;
   $tool = Test::Valgrind::Tool->new(
    tool     => $tool || 'memcheck',
   require Test::Valgrind::Tool;
   $tool = Test::Valgrind::Tool->new(
    tool     => $tool || 'memcheck',
-   callers  => delete($args{callers}),
+   callers  => delete $args{callers},
   );
  }
 
   );
  }
 
@@ -173,7 +150,7 @@ sub import {
   require Test::Valgrind::Action;
   $action = Test::Valgrind::Action->new(
    action => $action || 'Test',
   require Test::Valgrind::Action;
   $action = Test::Valgrind::Action->new(
    action => $action || 'Test',
-   diag   => delete($args{diag}),
+   diag   => delete $args{diag},
   );
  }
 
   );
  }
 
@@ -186,7 +163,7 @@ sub import {
  };
  unless ($sess) {
   $action->abort($sess, $@);
  };
  unless ($sess) {
   $action->abort($sess, $@);
-  exit $action->status($sess);
+  return $action->status($sess);
  }
 
  eval {
  }
 
  eval {
@@ -204,7 +181,67 @@ sub import {
  my $status = $sess->status;
  $status = 255 unless defined $status;
 
  my $status = $sess->status;
  $status = 255 unless defined $status;
 
- exit $status;
+ return $status;
+}
+
+=head2 C<import [ %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 highest caller context that looks like a script.
+When the analyse finishes, it exists with the status that was returned.
+
+In the child process, it just C<return>s so that the calling code is actually run under C<valgrind>.
+
+=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, $pm, $next);
+ my $l = 0;
+ while ($l < 1000) {
+  $next = (caller $l++)[1];
+  last unless defined $next;
+  next if $next eq '-e' or $next =~ /^\s*\(\s*eval\s*\d*\s*\)\s*$/ or !-f $next;
+  if ($next =~ /\.pm$/) {
+   $pm   = $next;
+  } else {
+   $file = $next;
+  }
+ }
+ unless (defined($file) or defined($file = $pm)) {
+  require Test::Builder;
+  Test::Builder->new->diag('Couldn\'t find a valid source file');
+  return;
+ }
+
+ exit $class->analyse(
+  file => $file,
+  %args,
+ );
 }
 
 END {
 }
 
 END {