File Coverage

blib/lib/Test/Pod/LinkCheck.pm
Criterion Covered Total %
statement 9 11 81.8
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             #
2             # This file is part of Test-Pod-LinkCheck
3             #
4             # This software is copyright (c) 2011 by Apocalypse.
5             #
6             # This is free software; you can redistribute it and/or modify it under
7             # the same terms as the Perl 5 programming language system itself.
8             #
9 3     3   51771 use strict; use warnings;
  3     3   3  
  3         101  
  3         15  
  3         5  
  3         137  
10             package Test::Pod::LinkCheck;
11             BEGIN {
12 3     3   61 $Test::Pod::LinkCheck::VERSION = '0.007';
13             }
14             BEGIN {
15 3     3   141 $Test::Pod::LinkCheck::AUTHORITY = 'cpan:APOCAL';
16             }
17              
18             # ABSTRACT: Tests POD for invalid links
19              
20             # Import the modules we need
21 3     3   2641 use Moose 1.01;
  0            
  0            
22             use Test::Pod 1.44 ();
23             use App::PodLinkCheck::ParseLinks 4;
24              
25             # setup our tests and etc
26             use Test::Builder 0.94;
27             my $Test = Test::Builder->new;
28              
29             # export our 2 subs
30             use parent qw( Exporter );
31             our @EXPORT_OK = qw( pod_ok all_pod_ok );
32              
33              
34             has 'check_cpan' => (
35             is => 'rw',
36             isa => 'Bool',
37             default => 1,
38             );
39              
40             {
41             use Moose::Util::TypeConstraints 1.01;
42              
43              
44             # TODO add CPANIDX?
45             has 'cpan_backend' => (
46             is => 'rw',
47             isa => enum( [ qw( CPANPLUS CPAN CPANSQLite ) ] ),
48             default => 'CPANPLUS',
49             trigger => \&_clean_cpan_backend,
50             );
51              
52             sub _clean_cpan_backend {
53             my( $self, $new, $old ) = @_;
54              
55             # Just clear the cpan cache
56             $self->_cache->{'cpan'} = {};
57             $self->_backend_err( 0 );
58             }
59             }
60              
61              
62             has 'cpan_backend_auto' => (
63             is => 'rw',
64             isa => 'Bool',
65             default => 1,
66             );
67              
68              
69             has 'cpan_section_err' => (
70             is => 'rw',
71             isa => 'Bool',
72             default => 0,
73             );
74              
75              
76             has 'verbose' => (
77             is => 'rw',
78             isa => 'Bool',
79             default => 0,
80             );
81              
82             # holds the cached results of link look-ups
83             has '_cache' => (
84             is => 'ro',
85             isa => 'HashRef',
86             default => sub { return {
87             'cpan' => {},
88             'man' => {},
89             'pod' => {},
90             'section' => {},
91             } },
92             );
93              
94             # is the backend good to use?
95             has '_backend_err' => (
96             is => 'rw',
97             isa => 'Bool',
98             default => 0,
99             trigger => \&_clean_backend_err,
100             );
101              
102             sub _clean_backend_err {
103             my( $self, $new, $old ) = @_;
104              
105             # Only clean if an error happened
106             if ( $new ) {
107             $self->_cache->{'cpan'} = {};
108             }
109             }
110              
111              
112             sub pod_ok {
113             my $self = shift;
114             my $file = shift;
115              
116             if ( ! ref $self ) { # Allow function call
117             $file = $self;
118             $self = __PACKAGE__->new;
119             }
120              
121             my $name = @_ ? shift : "LinkCheck test for $file";
122              
123             if ( ! -f $file ) {
124             $Test->ok( 0, $name );
125              
126             if ( $self->verbose ) {
127             $Test->diag( "Extra: " );
128             $Test->diag( " * '$file' does not exist?" );
129             }
130              
131             return 0;
132             }
133              
134             # Parse the POD!
135             my $parser = App::PodLinkCheck::ParseLinks->new( {} );
136             my $output;
137              
138             # Override some options that the podlinkcheck subclass "helpfully" set for us...
139             $parser->output_string( \$output );
140             $parser->complain_stderr( 0 );
141             $parser->no_errata_section( 0 );
142             $parser->no_whining( 0 );
143             $parser->parse_file( $file );
144              
145             # is POD well-formed?
146             if ( $parser->any_errata_seen ) {
147             $Test->ok( 0, $name );
148              
149             if ( $self->verbose ) {
150             $Test->diag( "Extra: " );
151             $Test->diag( " * Unable to parse POD in '$file'" );
152              
153             # TODO ugly, but there is no other way to get at it?
154             ## no critic ( ProhibitAccessOfPrivateData )
155             foreach my $l ( keys %{ $parser->{'errata'} } ) {
156             $Test->diag( " * errors seen in line $l:" );
157             $Test->diag( " * $_" ) for @{ $parser->{'errata'}{$l} };
158             }
159             }
160              
161             return 0;
162             }
163              
164             # Did we see POD in the file?
165             if ( $parser->doc_has_started ) {
166             my( $err, $diag ) = $self->_analyze( $parser );
167              
168             if ( scalar @$err > 0 ) {
169             $Test->ok( 0, $name );
170             $Test->diag( "Erroneous links: " );
171             $Test->diag( " * $_" ) for @$err;
172              
173             if ( $self->verbose and @$diag ) {
174             $Test->diag( "Extra: " );
175             $Test->diag( " * $_" ) for @$diag;
176             }
177              
178             return 0;
179             } else {
180             $Test->ok( 1, $name );
181              
182             if ( $self->verbose and @$diag ) {
183             $Test->diag( "Extra: " );
184             $Test->diag( " * $_" ) for @$diag;
185             }
186             }
187             } else {
188             $Test->ok( 1, $name );
189              
190             if ( $self->verbose ) {
191             $Test->diag( "Extra: " );
192             $Test->diag( " * There is no POD in '$file' ?" );
193             }
194             }
195              
196             return 1;
197             }
198              
199              
200             sub all_pod_ok {
201             my $self = shift;
202             my @files = @_ ? @_ : Test::Pod::all_pod_files();
203              
204             if ( ! defined $self or ! ref $self ) { # Allow function call
205             unshift( @files, $self ) if defined $self;
206             $self = __PACKAGE__->new;
207             }
208              
209             $Test->plan( tests => scalar @files );
210              
211             my $ok = 1;
212             foreach my $file ( @files ) {
213             $self->pod_ok( $file ) or undef $ok;
214             }
215              
216             return $ok;
217             }
218              
219             sub _analyze {
220             my( $self, $parser ) = @_;
221              
222             my $file = $parser->source_filename;
223             my $links = $parser->links_arrayref;
224             my $own_sections = $parser->sections_hashref;
225             my( @errors, @diag );
226              
227             foreach my $l ( @$links ) {
228             ## no critic ( ProhibitAccessOfPrivateData )
229             my( $type, $to, $section, $linenum, $column ) = @$l;
230             push( @diag, "$file:$linenum:$column - Checking link type($type) to(" . ( defined $to ? $to : '' ) . ") " .
231             "section(" . ( defined $section ? $section : '' ) . ")" ) if $self->verbose;
232              
233             # What kind of link?
234             if ( $type eq 'man' ) {
235             if ( ! $self->_known_manpage( $to ) ) {
236             push( @errors, "$file:$linenum:$column - Unknown link type(man) to($to)" );
237             }
238             } elsif ( $type eq 'pod' ) {
239             # do we have a to/section?
240             if ( defined $to ) {
241             if ( defined $section ) {
242             # Do we have this file installed?
243             if ( ! $self->_known_podlink( $to, $section ) ) {
244             # Is it a CPAN module?
245             my $res = $self->_known_cpan( $to );
246             if ( defined $res ) {
247             if ( $res ) {
248             # if true, treat cpan sections as errors because we can't verify if section exists
249             if ( $self->cpan_section_err ) {
250             push( @errors, "$file:$linenum:$column - Unable to verify link type(pod) to($to) section($section) because the module isn't installed" );
251             } else {
252             push( @diag, "$file:$linenum:$column - Unable to verify link type(pod) to($to) section($section) because the module isn't installed" );
253             }
254             } else {
255             push( @errors, "$file:$linenum:$column - Unknown link type(pod) to($to) section($section) - module doesn't exist in CPAN" );
256             }
257             } else {
258             push( @errors, "$file:$linenum:$column - Unknown link type(pod) to($to) section($section) - unable to check CPAN" );
259             }
260             }
261             } else {
262             # Is it a perlfunc reference?
263             if ( ! $self->_known_perlfunc( $to ) ) {
264             # Do we have this file installed?
265             if ( ! $self->_known_podfile( $to ) ) {
266             # Sometimes we find a manpage but not the pod...
267             if ( ! $self->_known_manpage( $to ) ) {
268             # Is it a CPAN module?
269             my $res = $self->_known_cpan( $to );
270             if ( defined $res ) {
271             if ( ! $res ) {
272             # Check for internal section
273             if ( exists $own_sections->{ $to } ) {
274             push( @diag, "$file:$linenum:$column - Link type(pod) to($to) looks like an internal section link - recommend 'L</$to>'" );
275             } else {
276             push( @errors, "$file:$linenum:$column - Unknown link type(pod) to($to) - module doesn't exist in CPAN" );
277             }
278             }
279             } else {
280             # Check for internal section
281             if ( exists $own_sections->{ $to } ) {
282             push( @diag, "$file:$linenum:$column - Link type(pod) to($to) looks like an internal section link - recommend 'L</$to>'" );
283             } else {
284             push( @errors, "$file:$linenum:$column - Unknown link type(pod) to($to) - unable to check CPAN" );
285             }
286             }
287             }
288             }
289             }
290             }
291             } else {
292             if ( defined $section ) {
293             if ( ! exists $own_sections->{ $section } ) {
294             push( @errors, "$file:$linenum:$column - Unknown link type(pod) to() section($section) - section doesn't exist!" );
295             }
296             } else {
297             # no to/section eh?
298             push( @errors, "$file:$linenum:$column - Malformed link type(pod) to() section()" );
299             }
300             }
301             } else {
302             # unknown type?
303             push( @errors, "$file:$linenum:$column - Unknown link type($type) to(" . ( defined $to ? $to : '' ) . ") section(" . ( defined $section ? $section : '' ) . ")" );
304             }
305             }
306              
307             return( \@errors, \@diag );
308             }
309              
310             sub _known_perlfunc {
311             my( $self, $func ) = @_;
312             my $cache = $self->_cache->{'func'};
313              
314             if ( ! exists $cache->{ $func } ) {
315             # TODO this sucks, but Pod::Perldoc can't do it because it expects to be ran in the console...
316             require Capture::Tiny;
317             $cache->{ $func } = Capture::Tiny::capture_merged( sub {
318             system( 'perldoc -f ' . $func );
319             } );
320              
321             # We need at least 5 newlines to guarantee a real perlfunc
322             # apoc@blackhole:~$ perldoc -f foobar
323             # No documentation for perl function `foobar' found
324             if ( ( $cache->{ $func } =~ tr/\n// ) > 5 ) {
325             $cache->{ $func } = 1;
326             } else {
327             $cache->{ $func } = 0;
328             }
329             }
330              
331             return $cache->{ $func };
332             }
333              
334             sub _known_manpage {
335             my( $self, $page ) = @_;
336             my $cache = $self->_cache->{'man'};
337              
338             if ( ! exists $cache->{ $page } ) {
339             my @manargs;
340             if ( $page =~ /(.+)\s*\((.+)\)$/ ) {
341             @manargs = ($2, $1);
342             } else {
343             @manargs = ($page);
344             }
345              
346             require Capture::Tiny;
347             $cache->{ $page } = Capture::Tiny::capture_merged( sub {
348             system( 'man', @manargs );
349             } );
350              
351             # We need at least 5 newlines to guarantee a real manpage
352             if ( ( $cache->{ $page } =~ tr/\n// ) > 5 ) {
353             $cache->{ $page } = 1;
354             } else {
355             $cache->{ $page } = 0;
356             }
357             }
358              
359             return $cache->{ $page };
360             }
361              
362             sub _known_podfile {
363             my( $self, $link ) = @_;
364             my $cache = $self->_cache->{'pod'};
365              
366             if ( ! exists $cache->{ $link } ) {
367             # Is it a plain POD file?
368             require Pod::Find;
369             my $filename = Pod::Find::pod_where( {
370             '-inc' => 1,
371             }, $link );
372             if ( defined $filename ) {
373             $cache->{ $link } = $filename;
374             } else {
375             # It might be a script...
376             require File::Spec;
377             require Config;
378             foreach my $dir ( split /\Q$Config::Config{'path_sep'}/o, $ENV{'PATH'} ) {
379             $filename = File::Spec->catfile( $dir, $link );
380             if ( -e $filename ) {
381             $cache->{ $link } = $filename;
382             last;
383             }
384             }
385             if ( ! exists $cache->{ $link } ) {
386             $cache->{ $link } = 0;
387             }
388             }
389             }
390              
391             return $cache->{ $link };
392             }
393              
394             sub _known_cpan {
395             my( $self, $module ) = @_;
396              
397             # Do we even check CPAN?
398             if ( ! $self->check_cpan ) {
399             return;
400             }
401              
402             # Did the backend encounter an error?
403             if ( $self->_backend_err ) {
404             return;
405             }
406              
407             # Sanity check - we use '.' as the actual cache placeholder...
408             if ( $module eq '.' ) {
409             return;
410             }
411              
412             # is the answer cached already?
413             if ( exists $self->_cache->{'cpan'}{ $module } ) {
414             return $self->_cache->{'cpan'}{ $module };
415             }
416              
417             # Select the backend?
418             if ( $self->cpan_backend eq 'CPANPLUS' ) {
419             return $self->_known_cpan_cpanplus( $module );
420             } elsif ( $self->cpan_backend eq 'CPAN' ) {
421             return $self->_known_cpan_cpan( $module );
422             } elsif ( $self->cpan_backend eq 'CPANSQLite' ) {
423             return $self->_known_cpan_cpansqlite( $module );
424             } else {
425             die "Unknown backend: " . $self->cpan_backend;
426             }
427             }
428              
429             sub _known_cpan_cpanplus {
430             my( $self, $module ) = @_;
431             my $cache = $self->_cache->{'cpan'};
432              
433             # init the backend ( and set some options )
434             if ( ! exists $cache->{'.'} ) {
435             eval {
436             # Wacky format so dzil will not autoprereq it
437             require 'CPANPLUS/Backend.pm'; require 'CPANPLUS/Configure.pm';
438              
439             my $cpanconfig = CPANPLUS::Configure->new;
440             $cpanconfig->set_conf( 'verbose' => 0 );
441             $cpanconfig->set_conf( 'no_update' => 1 );
442              
443             # ARGH, CPANIDX doesn't work well with this kind of search...
444             # TODO check if it's still true?
445             if ( $cpanconfig->get_conf( 'source_engine' ) =~ /CPANIDX/ ) {
446             $cpanconfig->set_conf( 'source_engine' => 'CPANPLUS::Internals::Source::Memory' );
447             }
448              
449             # silence CPANPLUS!
450             eval "no warnings 'redefine'; sub Log::Message::store { return }";
451             local $SIG{'__WARN__'} = sub { return };
452             $cache->{'.'} = CPANPLUS::Backend->new( $cpanconfig );
453             };
454             if ( $@ ) {
455             warn "Unable to load CPANPLUS - $@" if $self->verbose;
456             if ( $self->cpan_backend_auto ) {
457             $self->cpan_backend( 'CPAN' );
458             return $self->_known_cpan_cpan( $module );
459             } else {
460             $self->_backend_err( 1 );
461             return;
462             }
463             }
464             }
465              
466             my $result;
467             eval { local $SIG{'__WARN__'} = sub { return }; $result = $cache->{'.'}->parse_module( 'module' => $module ) };
468             if ( $@ ) {
469             warn "Unable to use CPANPLUS - $@" if $self->verbose;
470             if ( $self->cpan_backend_auto ) {
471             $self->cpan_backend( 'CPAN' );
472             return $self->_known_cpan_cpan( $module );
473             } else {
474             $self->_backend_err( 1 );
475             return;
476             }
477             }
478             if ( defined $result ) {
479             $cache->{ $module } = 1;
480             } else {
481             $cache->{ $module } = 0;
482             }
483              
484             return $cache->{ $module };
485             }
486              
487             sub _known_cpan_cpan {
488             my( $self, $module ) = @_;
489             my $cache = $self->_cache->{'cpan'};
490              
491             # init the backend ( and set some options )
492             if ( ! exists $cache->{'.'} ) {
493             eval {
494             # Wacky format so dzil will not autoprereq it
495             require 'CPAN.pm';
496              
497             # TODO this code stolen from App::PodLinkCheck
498             # not sure how far back this will work, maybe only 5.8.0 up
499             if ( ! $CPAN::Config_loaded && CPAN::HandleConfig->can( 'load' ) ) {
500             # fake $loading to avoid running the CPAN::FirstTime dialog -- is this the right way to do that?
501             local $CPAN::HandleConfig::loading = 1;
502             CPAN::HandleConfig->load;
503             }
504              
505             # figure out the access method
506             if ( defined $CPAN::META && %$CPAN::META ) {
507             # works already!
508             } elsif ( ! CPAN::Index->can('read_metadata_cache') ) {
509             # Argh, we can't use it...
510             die "Unable to use CPAN.pm metadata cache!";
511             } else {
512             # try the .cpan/Metadata even if CPAN::SQLite is installed, just in
513             # case the SQLite is not up-to-date or has not been used yet
514             local $CPAN::Config->{use_sqlite} = $CPAN::Config->{use_sqlite} = 0; # stupid used once warning...
515             CPAN::Index->read_metadata_cache;
516             if ( defined $CPAN::META && %$CPAN::META ) {
517             # yay, works!
518             } else {
519             die "Unable to use CPAN.pm metadata cache!";
520             }
521             }
522              
523             # Cache is ready
524             $cache->{'.'} = $CPAN::META->{'readwrite'}->{'CPAN::Module'};
525             };
526             if ( $@ ) {
527             warn "Unable to load CPAN - $@" if $self->verbose;
528             if ( $self->cpan_backend_auto ) {
529             $self->cpan_backend( 'CPANSQLite' );
530             return $self->_known_cpan_cpansqlite( $module );
531             } else {
532             $self->_backend_err( 1 );
533             return;
534             }
535             }
536             }
537              
538             if ( exists $cache->{'.'}{ $module } ) {
539             $cache->{ $module } = 1;
540             } else {
541             $cache->{ $module } = 0;
542             }
543              
544             return $cache->{ $module };
545             }
546              
547             sub _known_cpan_cpansqlite {
548             my( $self, $module ) = @_;
549             my $cache = $self->_cache->{'cpan'};
550              
551             # init the backend ( and set some options )
552             if ( ! exists $cache->{'.'} ) {
553             eval {
554             # Wacky format so dzil will not autoprereq it
555             require 'CPAN.pm'; require 'CPAN/SQLite.pm';
556              
557             # TODO this code stolen from App::PodLinkCheck
558             # not sure how far back this will work, maybe only 5.8.0 up
559             if ( ! $CPAN::Config_loaded && CPAN::HandleConfig->can( 'load' ) ) {
560             # fake $loading to avoid running the CPAN::FirstTime dialog -- is this the right way to do that?
561             local $CPAN::HandleConfig::loading = 1;
562             CPAN::HandleConfig->load;
563             }
564              
565             $cache->{'.'} = CPAN::SQLite->new;
566             };
567             if ( $@ ) {
568             warn "Unable to load CPANSQLite - $@" if $self->verbose;
569             if ( $self->cpan_backend_auto ) {
570             warn "Unable to use any CPAN backend, disabling searches!" if $self->verbose;
571             $self->check_cpan( 0 );
572             $self->cpan_section_err( 1 );
573             }
574              
575             $self->_backend_err( 1 );
576             return;
577             }
578             }
579              
580             my $result;
581             eval { local $SIG{'__WARN__'} = sub { return }; $result = $cache->{'.'}->query( 'mode' => 'module', name => $module, max_results => 1 ); };
582             if ( $@ ) {
583             warn "Unable to use CPANSQLite - $@" if $self->verbose;
584             if ( $self->cpan_backend_auto ) {
585             warn "Unable to use any CPAN backend, disabling searches!" if $self->verbose;
586             $self->check_cpan( 0 );
587             $self->cpan_section_err( 1 );
588             }
589              
590             $self->_backend_err( 1 );
591             return;
592             }
593             if ( $result ) {
594             $cache->{ $module } = 1;
595             } else {
596             $cache->{ $module } = 0;
597             }
598              
599             return $cache->{ $module };
600             }
601              
602             sub _known_podlink {
603             my( $self, $link, $section ) = @_;
604              
605             # First of all, does the file exists?
606             my $filename = $self->_known_podfile( $link );
607             return 0 if ! defined $filename;
608              
609             # Okay, get the sections in the file and see if the link matches
610             my $file_sections = $self->_known_podsections( $filename );
611             if ( defined $file_sections and exists $file_sections->{ $section } ) {
612             return 1;
613             } else {
614             return 0;
615             }
616             }
617              
618             sub _known_podsections {
619             my( $self, $filename ) = @_;
620             my $cache = $self->_cache->{'sections'};
621              
622             if ( ! exists $cache->{ $filename } ) {
623             # Okay, get the sections in the file
624             require App::PodLinkCheck::ParseSections;
625             my $parser = App::PodLinkCheck::ParseSections->new( {} );
626             $parser->parse_file( $filename );
627             $cache->{ $filename } = $parser->sections_hashref;
628             }
629              
630             return $cache->{ $filename };
631             }
632              
633             # from Moose::Manual::BestPractices
634             no Moose;
635             __PACKAGE__->meta->make_immutable;
636              
637             1;
638              
639              
640             __END__
641             =pod
642              
643             =for :stopwords Apocalypse cpan testmatrix url annocpan anno bugtracker rt cpants kwalitee
644             diff irc mailto metadata placeholders CPAN foo OO backend env CPANPLUS
645             CPANSQLite http
646              
647             =encoding utf-8
648              
649             =head1 NAME
650              
651             Test::Pod::LinkCheck - Tests POD for invalid links
652              
653             =head1 VERSION
654              
655             This document describes v0.007 of Test::Pod::LinkCheck - released April 21, 2011 as part of Test-Pod-LinkCheck.
656              
657             =head1 SYNOPSIS
658              
659             #!/usr/bin/perl
660             use strict; use warnings;
661              
662             use Test::More;
663              
664             eval "use Test::Pod::LinkCheck";
665             if ( $@ ) {
666             plan skip_all => 'Test::Pod::LinkCheck required for testing POD';
667             } else {
668             Test::Pod::LinkCheck->new->all_pod_ok;
669             }
670              
671             =head1 DESCRIPTION
672              
673             This module looks for any links in your POD and verifies that they point to a valid resource. It uses the L<Pod::Simple> parser
674             to analyze the pod files and look at their links. In a nutshell, it looks for C<LE<lt>FooE<gt>> links and makes sure that Foo
675             exists. It also recognizes section links, C<LE<lt>/SYNOPSISE<gt>> for example. Also, manpages are resolved and checked.
676              
677             This module does B<NOT> check "http" links like C<LE<lt>http://www.google.comE<gt>> in your pod. For that, please check
678             out L<Test::Pod::No404s>.
679              
680             Normally, you wouldn't want this test to be run during end-user installation because they might not have the modules installed! It is
681             HIGHLY recommended that this be used only for module authors' RELEASE_TESTING phase. To do that, just modify the synopsis to
682             add an env check :)
683              
684             This module normally uses the OO method to run tests, but you can use the functional style too. Just explicitly ask for the C<all_pod_ok> or
685             C<pod_ok> function to be imported when you use this module.
686              
687             #!/usr/bin/perl
688             use strict; use warnings;
689             use Test::Pod::LinkCheck qw( all_pod_ok );
690             all_pod_ok();
691              
692             =head1 ATTRIBUTES
693              
694             =head2 check_cpan
695              
696             If enabled, this module will check the CPAN module database to see if a link is a valid CPAN module or not. It uses the backend
697             defined in L</cpan_backend> to do the actual searching.
698              
699             If disabled, it will resolve links based on locally installed modules. If it isn't installed it will be an error!
700              
701             The default is: true
702              
703             =head2 cpan_backend
704              
705             Selects the CPAN backend to use for querying modules. The available ones are: CPANPLUS, CPAN, and CPANSQLite.
706              
707             The default is: CPANPLUS
708              
709             The backends were tested and verified against those versions. Older versions should work, but is untested!
710             CPANPLUS v0.9010
711             CPAN v1.9402
712             CPAN::SQLite v0.199
713              
714             =head2 cpan_backend_auto
715              
716             Enable to automatically try the CPAN backends to find an available one. It will try the backends in the order defined in L</cpan_backend>
717              
718             If no backend is available, it will disable the L</check_cpan> attribute and enable the L</cpan_section_err> attribute.
719              
720             The default is: true
721              
722             =head2 cpan_section_err
723              
724             If enabled, a link pointing to a CPAN module's specific section is treated as an error if it isn't installed.
725              
726             The default is: false
727              
728             =head2 verbose
729              
730             If enabled, this module will print extra diagnostics for the links it's checking.
731              
732             The default is: false
733              
734             =head1 METHODS
735              
736             =head2 pod_ok
737              
738             Accepts the filename to check, and an optional test name.
739              
740             This method will pass the test if there is no POD links present in the POD or if all links are not an error. Furthermore, if the POD was
741             malformed as reported by L<Pod::Simple>, the test will fail and not attempt to check the links.
742              
743             When it fails, this will show any failing links as diagnostics. Also, some extra information is printed if verbose is enabled.
744              
745             The default test name is: "LinkCheck test for FILENAME"
746              
747             =head2 all_pod_ok
748              
749             Accepts an optional array of files to check. By default it uses all POD files in your distribution.
750              
751             This method is what you will usually run. Every file is passed to the L</pod_ok> function. This also sets the
752             test plan to be the number of files.
753              
754             =head1 NOTES
755              
756             =head2 backend
757              
758             This module uses the L<CPANPLUS> and L<CPAN> modules as the backend to verify valid CPAN modules. Please make sure that the backend you
759             choose is properly configured before running this! This means the index is updated, permissions is set, and whatever else the backend
760             needs to properly function. If you don't want to use them please disable the L</check_cpan> attribute.
761              
762             If this module fails to check CPAN modules or the testsuite fails, it's probably because of the above reason.
763              
764             =head2 CPAN module sections
765              
766             One limitation of this module is that it can't check for valid sections on CPAN modules if they aren't installed. If you want that to be an
767             error, please enable the L</cpan_section_err> attribute.
768              
769             =head1 SEE ALSO
770              
771             Please see those modules/websites for more information related to this module.
772              
773             =over 4
774              
775             =item *
776              
777             L<App::PodLinkCheck|App::PodLinkCheck>
778              
779             =item *
780              
781             L<Pod::Checker|Pod::Checker>
782              
783             =item *
784              
785             L<Test::Pod::No404s|Test::Pod::No404s>
786              
787             =back
788              
789             =head1 SUPPORT
790              
791             =head2 Perldoc
792              
793             You can find documentation for this module with the perldoc command.
794              
795             perldoc Test::Pod::LinkCheck
796              
797             =head2 Websites
798              
799             The following websites have more information about this module, and may be of help to you. As always,
800             in addition to those websites please use your favorite search engine to discover more resources.
801              
802             =over 4
803              
804             =item *
805              
806             Search CPAN
807              
808             The default CPAN search engine, useful to view POD in HTML format.
809              
810             L<http://search.cpan.org/dist/Test-Pod-LinkCheck>
811              
812             =item *
813              
814             RT: CPAN's Bug Tracker
815              
816             The RT ( Request Tracker ) website is the default bug/issue tracking system for CPAN.
817              
818             L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Test-Pod-LinkCheck>
819              
820             =item *
821              
822             AnnoCPAN
823              
824             The AnnoCPAN is a website that allows community annonations of Perl module documentation.
825              
826             L<http://annocpan.org/dist/Test-Pod-LinkCheck>
827              
828             =item *
829              
830             CPAN Ratings
831              
832             The CPAN Ratings is a website that allows community ratings and reviews of Perl modules.
833              
834             L<http://cpanratings.perl.org/d/Test-Pod-LinkCheck>
835              
836             =item *
837              
838             CPAN Forum
839              
840             The CPAN Forum is a web forum for discussing Perl modules.
841              
842             L<http://cpanforum.com/dist/Test-Pod-LinkCheck>
843              
844             =item *
845              
846             CPANTS
847              
848             The CPANTS is a website that analyzes the Kwalitee ( code metrics ) of a distribution.
849              
850             L<http://cpants.perl.org/dist/overview/Test-Pod-LinkCheck>
851              
852             =item *
853              
854             CPAN Testers
855              
856             The CPAN Testers is a network of smokers who run automated tests on uploaded CPAN distributions.
857              
858             L<http://www.cpantesters.org/distro/T/Test-Pod-LinkCheck>
859              
860             =item *
861              
862             CPAN Testers Matrix
863              
864             The CPAN Testers Matrix is a website that provides a visual way to determine what Perls/platforms PASSed for a distribution.
865              
866             L<http://matrix.cpantesters.org/?dist=Test-Pod-LinkCheck>
867              
868             =item *
869              
870             CPAN Testers Dependencies
871              
872             The CPAN Testers Dependencies is a website that shows a chart of the test results of all dependencies for a distribution.
873              
874             L<http://deps.cpantesters.org/?module=Test::Pod::LinkCheck>
875              
876             =back
877              
878             =head2 Email
879              
880             You can email the author of this module at C<APOCAL at cpan.org> asking for help with any problems you have.
881              
882             =head2 Internet Relay Chat
883              
884             You can get live help by using IRC ( Internet Relay Chat ). If you don't know what IRC is,
885             please read this excellent guide: L<http://en.wikipedia.org/wiki/Internet_Relay_Chat>. Please
886             be courteous and patient when talking to us, as we might be busy or sleeping! You can join
887             those networks/channels and get help:
888              
889             =over 4
890              
891             =item *
892              
893             irc.perl.org
894              
895             You can connect to the server at 'irc.perl.org' and join this channel: #perl-help then talk to this person for help: Apocalypse.
896              
897             =item *
898              
899             irc.freenode.net
900              
901             You can connect to the server at 'irc.freenode.net' and join this channel: #perl then talk to this person for help: Apocal.
902              
903             =item *
904              
905             irc.efnet.org
906              
907             You can connect to the server at 'irc.efnet.org' and join this channel: #perl then talk to this person for help: Ap0cal.
908              
909             =back
910              
911             =head2 Bugs / Feature Requests
912              
913             Please report any bugs or feature requests by email to C<bug-test-pod-linkcheck at rt.cpan.org>, or through
914             the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Test-Pod-LinkCheck>. You will be automatically notified of any
915             progress on the request by the system.
916              
917             =head2 Source Code
918              
919             The code is open to the world, and available for you to hack on. Please feel free to browse it and play
920             with it, or whatever. If you want to contribute patches, please send me a diff or prod me to pull
921             from your repository :)
922              
923             L<http://github.com/apocalypse/perl-test-pod-linkcheck>
924              
925             git clone git://github.com/apocalypse/perl-test-pod-linkcheck.git
926              
927             =head1 AUTHOR
928              
929             Apocalypse <APOCAL@cpan.org>
930              
931             =head1 COPYRIGHT AND LICENSE
932              
933             This software is copyright (c) 2011 by Apocalypse.
934              
935             This is free software; you can redistribute it and/or modify it under
936             the same terms as the Perl 5 programming language system itself.
937              
938             The full text of the license can be found in the LICENSE file included with this distribution.
939              
940             =head1 DISCLAIMER OF WARRANTY
941              
942             BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
943             FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT
944             WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER
945             PARTIES PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND,
946             EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
947             IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
948             PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
949             SOFTWARE IS WITH YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME
950             THE COST OF ALL NECESSARY SERVICING, REPAIR, OR CORRECTION.
951              
952             IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
953             WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
954             REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE LIABLE
955             TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL, OR
956             CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
957             SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
958             RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
959             FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
960             SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
961             DAMAGES.
962              
963             =cut
964