use 5.008001; use strict; use warnings; package Test::FailWarnings; # ABSTRACT: Add test failures if warnings are caught our $VERSION = '0.008'; # VERSION use Test::More 0.86; use Cwd qw/getcwd/; use File::Spec; use Carp; our $ALLOW_DEPS = 0; our @ALLOW_FROM = (); my $ORIG_DIR = getcwd(); # cache in case handler runs after a chdir sub import { my ( $class, @args ) = @_; croak("import arguments must be key/value pairs") unless @args % 2 == 0; my %opts = @args; $ALLOW_DEPS = $opts{'-allow_deps'}; if ( $opts{'-allow_from'} ) { @ALLOW_FROM = ref $opts{'-allow_from'} ? @{ $opts{'-allow_from'} } : $opts{'-allow_from'}; } $SIG{__WARN__} = \&handler; } sub handler { my $msg = shift; $msg = '' unless defined $msg; chomp $msg; my ( $package, $filename, $line ) = _find_source(); # shortcut if ignoring dependencies and warning did not # come from something local if ($ALLOW_DEPS) { $filename = File::Spec->abs2rel( $filename, $ORIG_DIR ) if File::Spec->file_name_is_absolute($filename); return if $filename !~ /^(?:t|xt|lib|blib)/; } return if grep { $package eq $_ } @ALLOW_FROM; if ( $msg !~ m/at .*? line \d/ ) { chomp $msg; $msg = "'$msg' at $filename line $line."; } else { $msg = "'$msg'"; } my $builder = Test::More->builder; $builder->ok( 0, "Test::FailWarnings should catch no warnings" ) or $builder->diag("Warning was $msg"); } sub _find_source { my $i = 1; while (1) { my ( $pkg, $filename, $line ) = caller( $i++ ); return caller( $i - 2 ) unless defined $pkg; next if $pkg =~ /^(?:Carp|warnings)/; return ( $pkg, $filename, $line ); } } 1; # vim: ts=4 sts=4 sw=4 et: __END__ =pod =encoding utf-8 =head1 NAME Test::FailWarnings - Add test failures if warnings are caught =head1 VERSION version 0.008 =head1 SYNOPSIS Test file: use strict; use warnings; use Test::More; use Test::FailWarnings; ok( 1, "first test" ); ok( 1 + "lkadjaks", "add non-numeric" ); done_testing; Output: ok 1 - first test not ok 2 - Test::FailWarnings should catch no warnings # Failed test 'Test::FailWarnings should catch no warnings' # at t/bin/main-warn.pl line 7. # Warning was 'Argument "lkadjaks" isn't numeric in addition (+) at t/bin/main-warn.pl line 7.' ok 3 - add non-numeric 1..3 # Looks like you failed 1 test of 3. =head1 DESCRIPTION This module hooks C<$SIG{__WARN__}> and converts warnings to L C calls. It is designed to be used with C, when you don't need to know the test count in advance. Just as with L, this does not catch warnings if other things localize C<$SIG{__WARN__}>, as this is designed to catch I warnings. =for Pod::Coverage handler =head1 USAGE =head2 Overriding C<$SIG{__WARN__}> On C, C<$SIG{__WARN__}> is replaced with C. use Test::FailWarnings; # global If you don't want global replacement, require the module instead and localize in whatever scope you want. require Test::FailWarnings; { local $SIG{__WARN__} = \&Test::FailWarnings::handler; # ... warnings will issue fail() here } When the handler reports on the source of the warning, it will look past any calling packages starting with C or C to try to detect the real origin of the warning. =head2 Allowing warnings from dependencies If you want to ignore failures from outside your own code, you can set C<$Test::FailWarnings::ALLOW_DEPS> to a true value. You can do that on the C line with C<< -allow_deps >>. use Test::FailWarnings -allow_deps => 1; When true, warnings will only be thrown if they appear to originate from a filename matching C<< qr/^(?:t|xt|lib|blib)/ >> =head2 Allowing warnings from specific modules If you want to white-list specific modules only, you can add their package names to C<@Test::NoWarnings::ALLOW_FROM>. You can do that on the C line with C<< -allow_from >>. use Test::FailWarnings -allow_from => [ qw/Annoying::Module/ ]; =head1 SEE ALSO =over 4 =item * L -- catches warnings and reports in an C block. Not (yet) friendly with C. =item * L -- a replacement for Test::NoWarnings that works with done_testing =item * L -- test for warnings without triggering failures from this modules =back =for :stopwords cpan testmatrix url annocpan anno bugtracker rt cpants kwalitee diff irc mailto metadata placeholders metacpan =head1 SUPPORT =head2 Bugs / Feature Requests Please report any bugs or feature requests through the issue tracker at L. You will be notified automatically of any progress on your issue. =head2 Source Code This is open source software. The code repository is available for public review and contribution under the terms of the license. L git clone https://github.com/dagolden/Test-FailWarnings.git =head1 AUTHOR David Golden =head1 COPYRIGHT AND LICENSE This software is Copyright (c) 2013 by David Golden. This is free software, licensed under: The Apache License, Version 2.0, January 2004 =cut