=head1 VERSION
-Version 1.00
+Version 1.11
=cut
-our $VERSION = '1.00';
+our $VERSION = '1.11';
=head1 DESCRIPTION
=cut
-# All these modules are required at configure time.
+use File::Spec ();
+use Scalar::Util ();
-BEGIN {
- require File::Spec;
- require Scalar::Util;
+use Fcntl (); # F_SETFD
+use POSIX (); # SIGKILL
- require Fcntl; # F_SETFD
- require POSIX; # SIGKILL
-}
+use version ();
use base qw/Test::Valgrind::Carp/;
-use Test::Valgrind::Report;
-
=head1 METHODS
=head2 C<< new search_dirs => \@search_dirs, valgrind => [ $valgrind | \@valgrind ], min_version => $min_version, no_def_supp => $no_def_supp, extra_supps => \@extra_supps >>
=cut
-my $build_version = sub {
- require version;
- version->new($_[0]);
-};
-
sub new {
my $class = shift;
$class = ref($class) || $class;
my %args = @_;
my @paths;
- my $vg = delete $args{vg};
+ my $vg = delete $args{valgrind};
if (defined $vg and not ref $vg) {
@paths = ($vg);
} else {
$class->_croak('Empty valgrind candidates list') unless @paths;
my $min_version = delete $args{min_version};
- defined and not ref and $_ = $build_version->($_) for $min_version;
+ defined and not ref and $_ = version->new($_) for $min_version;
my ($valgrind, $version);
for (@paths) {
my $ver = qx/$_ --version/;
if ($ver =~ /^valgrind-(\d+(\.\d+)*)/) {
if ($min_version) {
- $version = $build_version->($1);
+ $version = version->new($1);
next if $version < $min_version;
} else {
$version = $1;
my ($self) = @_;
my $version = $self->{version};
- $self->{version} = $version = $build_version->($version) unless ref $version;
+ $self->{version} = $version = version->new($version) unless ref $version;
return $version;
}
Runs the command C<$command> through C<valgrind> with the tool C<$tool>, which will report to the action C<$action>.
+If the command is a L<Test::Valgrind::Command::Aggregate> object, the action and the tool will be initialized once before running all the aggregated commands.
+
=cut
sub run {
my $self = shift;
- $self->start(@_);
+ my %args = @_;
+
+ $self->start(%args);
my $guard = bless sub { $self->finish } => 'Test::Valgrind::Session::Guard';
- $self->report(Test::Valgrind::Report->new_diag(
+ $self->_run($args{command});
+}
+
+sub _run {
+ my ($self, $cmd) = @_;
+
+ if ($cmd->isa('Test::Valgrind::Command::Aggregate')) {
+ $self->_run($_) for $cmd->commands;
+ return;
+ }
+
+ $self->command($cmd);
+
+ $self->report($self->report_class->new_diag(
'Using valgrind ' . $self->version . ' located at ' . $self->valgrind
));
my @supp_args;
if ($self->do_suppressions) {
push @supp_args, '--gen-suppressions=all';
- } else {
- my @supps;
- if (not $self->no_def_supp) {
- my $def_supp = $self->def_supp_file;
- if (defined $def_supp and not -e $def_supp) {
- $self->report(Test::Valgrind::Report->new_diag("Generating suppressions..."));
- require Test::Valgrind::Suppressions;
- Test::Valgrind::Suppressions->generate(
- tool => $self->tool,
- command => $self->command,
- target => $def_supp,
- );
- $self->_croak('Couldn\'t generate suppressions') unless -e $def_supp;
- $self->report(Test::Valgrind::Report->new_diag("Suppressions for this perl stored in $def_supp"));
- }
+ } elsif (not $self->no_def_supp) {
+ my $def_supp = $self->def_supp_file;
+ if (defined $def_supp and not -e $def_supp) {
+ $self->report($self->report_class->new_diag(
+ "Generating suppressions..."
+ ));
+ require Test::Valgrind::Suppressions;
+ Test::Valgrind::Suppressions->generate(
+ tool => $self->tool,
+ command => $self->command,
+ target => $def_supp,
+ );
+ $self->_croak('Couldn\'t generate suppressions') unless -e $def_supp;
+ $self->report($self->report_class->new_diag(
+ "Suppressions for this perl stored in $def_supp"
+ ));
+ }
+ for ($self->suppressions) {
+ next unless -e $_;
+ $self->report($self->report_class->new_diag("Using suppression file $_"));
+ push @supp_args, "--suppressions=$_";
}
- push @supp_args, '--suppressions=' . $_ for $self->suppressions;
}
pipe my $vrdr, my $vwtr or $self->_croak("pipe(\$vrdr, \$vwtr): $!");
my @args = (
$self->valgrind,
- '--log-fd=' . fileno($vwtr),
$self->tool->args($self),
@supp_args,
+ $self->parser->args($self, $vwtr),
$self->command->args($self),
);
-# $self->report(Test::Valgrind::Report->new_diag("@args"));
+# $self->report($self->report_class->new_diag("@args"));
exec { $args[0] } @args or $self->_croak("exec @args: $!");
}
close $vwtr or $self->_croak("close(\$vwtr): $!");
- $self->tool->parse($self, $vrdr);
+ $self->parser->parse($self, $vrdr);
$self->{exit_code} = (waitpid($pid, 0) == $pid) ? $? >> 8 : 255;
Read-only accessor for the C<tool> associated to the current run.
+=head2 C<parser>
+
+Read-only accessor for the C<parser> associated to the current tool.
+
=head2 C<command>
Read-only accessor for the C<command> associated to the current run.
my @members;
BEGIN {
- @members = qw/action tool command/;
+ @members = qw/action tool command parser/;
for (@members) {
eval "sub $_ { \@_ <= 1 ? \$_[0]->{$_} : (\$_[0]->{$_} = \$_[1]) }";
die if $@;
sub do_suppressions { $_[0]->action->do_suppressions }
+=head2 C<parser_class>
+
+Calls C<< ->tool->parser_class >> with the current session object as the unique argument.
+
+=cut
+
+sub parser_class { $_[0]->tool->parser_class($_[0]) }
+
=head2 C<report_class>
-Calls C<< ->action->report_class >> with the current session object as the sole argument.
+Calls C<< ->tool->report_class >> with the current session object as the unique argument.
=cut
=head2 C<def_supp_file>
Returns an absolute path to the default suppression file associated to the current session.
-C<undef> will be returned as soon as any of C<< ->tool->suppressions_tag >> or C<< ->tool->suppressions_tag >> are also C<undef>.
+
+C<undef> will be returned as soon as any of C<< ->command->suppressions_tag >> or C<< ->tool->suppressions_tag >> are also C<undef>.
Otherwise, the file part of the name is builded by joining those two together, and the directory part is roughly F<< File::HomeDir->my_home / .perl / Test-Valgrind / suppressions / $VERSION >>.
=cut
my %args = @_;
- for (@members) {
+ for (qw/action tool command/) {
my $base = 'Test::Valgrind::' . ucfirst;
my $value = $args{$_};
$self->_croak("Invalid $_") unless Scalar::Util::blessed($value)
delete @{$self}{qw/last_status exit_code/};
$self->tool->start($self);
+ $self->parser($self->parser_class->new)->start($self);
$self->action->start($self);
return;
sub abort {
my $self = shift;
+
$self->action->abort($self, @_);
}
=cut
sub report {
- my $self = shift;
- $self->action->report($self, @_);
+ my ($self, $report) = @_;
+
+ return unless defined $report;
+
+ for my $handler (qw/tool command/) {
+ $report = $self->$handler->filter($self, $report);
+ return unless defined $report;
+ }
+
+ $self->action->report($self, $report);
}
=head2 C<finish>
my ($self) = @_;
my $action = $self->action;
+
$action->finish($self);
+ $self->parser->finish($self);
$self->tool->finish($self);
my $status = $action->status($self);
=head1 SEE ALSO
-L<Test::Valgrind>, L<Test::Valgrind::Action>, L<Test::Valgrind::Tool>, L<Test::Valgrind::Command>.
+L<Test::Valgrind>, L<Test::Valgrind::Action>, L<Test::Valgrind::Command>, L<Test::Valgrind::Tool>, L<Test::Valgrind::Parser>.
L<version>, L<File::HomeDir>.