package ExtUtils::MakeMaker::Coverage; use warnings; use strict; use base 'Object::Accessor'; =head1 NAME ExtUtils::MakeMaker::Coverage - add a Makefile target to determine test coverage using Devel::Cover =head1 VERSION Version 0.05 =cut our $VERSION = '0.05'; =head1 SYNOPSIS This module adds an additional target to the Makefile generated by C. The target, C, calls C, the command-line script to generate test coverage statistics, to clean up any data from a previous run. It then runs the tests, as if C was run, then calls C again to generate the coverage statistics. # In Makefile.PL use ExtUtils::MakeMaker; use ExtUtils::MakeMaker::Coverage; ... # if you already have a MY::postamble... sub MY::postamble { testcover(); ... } # if you wish to tweak the testcover target that will be written, # alter it's configuration. $conf = ExtUtils::MakeMaker::Coverage->config; In your shell > perl Makefile.PL > make > make testcover =head1 METHODS =cut sub import { my $class = shift; my $caller = caller; my $arg = shift || ''; no strict 'refs'; *{$caller . "::testcover"} = \&{$class . "::testcover"}; *{"MY::postamble"} = \&{$class . "::testcover"}; } =head2 testcover This method is exported for use when there already is a MY::postamble in the Makefile.PL. In that case, adding a call to the testcover method will add the necessary Makefile steps. =cut sub testcover { ### our base object my $obj = __PACKAGE__->config; ### make a list of things to cover my $to_cover = join ",", map { s/cover_//; "-coverage,$_" } grep { /^cover/ && $obj->$_ } $obj->ls_accessors; ### make a list of patterns to ignore my $ignore = ref $obj->ignore ? join(',', map { "+ignore,$_" } @{$obj->ignore}) : ''; ### what files to run coverage on my $files = ref $obj->files ? join(' ', @{$obj->files}) : '$(TEST_FILES)'; ### what type of reporting tool to use my $report = $obj->format ? "-report " . $obj->format : ''; ### the path to the cover binary to use my $bin = $obj->binary; ### basic make fragment, this includes the coverable parts my $make_frag = qq[\n COVER = $bin coverclean: \$(COVER) -delete testcover: coverclean pure_all HARNESS_PERL_SWITCHES='-MDevel::Cover=$to_cover]; ### did you provide an ignore list? if so, add it to the make frag ### (dont forget the trailing "' ', or just add the trailing "' " if ### there are no ignore patterns $make_frag .= $ignore ? ",$ignore' " : "' "; ### add the invocation to test, where the files to test are ### determined by our config $make_frag .= q[PERL_DL_NONLAZY=1 $(FULLPERLRUN) ] . q["-MExtUtils::Command::MM" "-e" ] . q["test_harness($(TEST_VERBOSE), '$(INST_LIB)',] . q['$(INST_ARCHLIB)')" ] . $files; ### add the proper report format $make_frag .= qq[\n \$(COVER) $report \n]; return $make_frag; } =head2 config This method returns the internal config object used by this package to create the C target for the Makefile. You can change parts of the C target by setting accessors of this object =over 4 =item binary The value to use for the C binary. Defaults to C. =item format The output format to use for C. Defaults to none, using C's default settings. Consult C for documentation on its C<-report> switch. =item ignore An array ref of patterns to ignore when generating the coverage report. Defaults to an empty list. Consult C for documentation on its C<-ignore> switch. =item files An array ref of test files to run for this coverage reprort. Defaults to the C<$(TESTFILES)> variable as defined in your C. Consult C for details. =item cover_statement Boolean indicating whether to run coverage on statements. Defaults to true. Consult C for documentation on its C<-coverage> switch. =item cover_branch Boolean indicating whether to run coverage on branches. Defaults to true. Consult C for documentation on its C<-coverage> switch. =item cover_subroutine Boolean indicating whether to run coverage on subroutines. Defaults to true. Consult C for documentation on its C<-coverage> switch. =item cover_condition Boolean indicating whether to run coverage on conditions. Defaults to true. Consult C for documentation on its C<-coverage> switch. =item cover_pod Boolean indicating whether to run coverage on POD. Defaults to true. Consult C for documentation on its C<-coverage> switch. Example: $config = ExtUtils::MakeMaker::Coverage->config; $config->pod(0); # disable pod coverage $config->files(['t/1.t', 't/2.t']); # use these test files only $config->ignore(['SCCS']); # ignore files with these # patterns in their path =back =cut { my %conf = ( binary => 'cover', format => '', ignore => '', files => '', cover_statement => 1, cover_branch => 1, cover_subroutine => 1, cover_condition => 1, cover_pod => 1, ); ### create a base object my $obj = __PACKAGE__->new; ### set all accessors $obj->mk_accessors( keys %conf ); ### initialize them for my $meth ( keys %conf ) { $obj->$meth( $conf{$meth} ); } ### accessor to return the base object sub config { return $obj } } 1; # End of ExtUtils::MakeMaker::Coverage __END__ =head1 NOTES This is alpha quality code in terms of features. For this module to be usable for as many modules as possible, the following additional features are needed. =over =item BSD make From my testing, if you run the testcover step using a BSD make, you will get coverage statistics for the test scripts. This is not at all useful. gmake is suggested until this issue is resolved. =item nmake I have not tested this enough with nmake. I have done some initial changes to make it work, but it requires more refactoring to get to where I'd like to see it. Expect full support in a release or two. =back =head1 AUTHOR Steve Peters, C<< >> =head1 BUGS Please report any bugs or feature requests to C, or through the web interface at L. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes. =head1 ACKNOWLEDGEMENTS =over =item Paul Johnson For developing C and enduring my many questions on IRC. =item Andy Lester For helping to make me a test-infected Perl programmer. =item Jos Boumans For making many of the changes for the 0.05 release, including the testcover script. =back =head1 SEE ALSO =over =item L =item L =back =head1 COPYRIGHT & LICENSE Copyright 2005 Steve Peters, All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut