File Coverage

blib/lib/Test/Structure.pm
Criterion Covered Total %
statement 45 45 100.0
branch 4 12 33.3
condition 1 3 33.3
subroutine 11 11 100.0
pod 4 4 100.0
total 65 75 86.6


line stmt bran cond sub pod time code
1             package Test::Structure;
2 2     2   57177 use warnings;
  2         4  
  2         63  
3 2     2   11 use strict;
  2         4  
  2         75  
4 2     2   2005 use PPI;
  2         373970  
  2         76  
5 2     2   2126 use File::Spec::Functions;
  2         1562  
  2         179  
6              
7             my $CLASS = __PACKAGE__;
8              
9 2     2   10 use base 'Test::Builder::Module';
  2         4  
  2         1523  
10              
11             =head1 NAME
12              
13             Test::Structure - Test for the structure of a package
14              
15             =head1 VERSION
16              
17             Version 0.04
18              
19             =cut
20              
21             our $VERSION = '0.04';
22              
23             =head1 SYNOPSIS
24              
25             Have you ever wished that you could build tests based on the structure of a package, not
26             how a package acts. Ya me either, but I've bumped in to a situation where I needed it.
27              
28             use Test::Structure tests => 5;
29              
30             require_ok( 'My::Package' );
31             has_includes( 'My::Package', qw{My::Other::Package Some::Other::Package} );
32             has_subs( 'My::Package', qw{this that} );
33             has_commetns( 'My;::Package' );
34             has_pod( 'My::Package' );
35            
36             =head1 EXPORT
37              
38             =cut
39              
40             our @EXPORT = qw{ has_includes
41             has_subs
42             has_comments
43             has_pod
44             };
45             # PRIVATE: take My::Package and build the right path for it
46 4     4   90 sub _pkg2path { catfile( split /::/, shift ) . '.pm' };
47              
48             # PRIVATE: build up a PPI::Document for the given package
49             sub _doc {
50 4     4   10 my $pkg = shift;
51 4         500 eval sprintf q{require %s}, $pkg;
52 4   33     23 my $doc = PPI::Document->new( $INC{Test::Structure::_pkg2path($pkg)} || $pkg );
53 4         374223 $doc;
54             }
55              
56             =head2 has_includes
57              
58             =cut
59              
60             sub has_includes ($@) {
61 1     1 1 577 my $pkg = shift;
62 1         8 my $tb = $CLASS->builder;
63 1         9 my $doc = Test::Structure::_doc($pkg);
64 5         27712 my %inc = map{ $_->module => 1 }
  1         12  
65 1         5 @{ $doc->find('PPI::Statement::Include') } ;
66 1         35 my @missing = grep{ ! $inc{$_} } @_ ;
  2         8  
67 1 0       10 $tb->ok(! scalar( @missing ) )
    50          
68             || $tb->diag( sprintf qq{Package %s is missing the following package%s%s},
69             $pkg,
70             (scalar(@missing)>1) ? 's' : '',
71             join qq{\n - }, '', @missing
72             );
73             }
74              
75             =head2 has_subs
76              
77             =cut
78              
79             sub has_subs {
80 1     1 1 6332 my $pkg = shift;
81 1         14 my $tb = $CLASS->builder;
82 1         19 my $doc = Test::Structure::_doc($pkg);
83 6         141 my %subs = map {$_->name => 1}
  6         29112  
84 1         6 grep{ !$_->isa('PPI::Statement::Scheduled')}
85 1         4 @{$doc->find('PPI::Statement::Sub')};
86              
87 1         67 my @missing = grep{ ! $subs{$_} } @_ ;
  6         18  
88 1 0       53 $tb->ok(! scalar( @missing ) )
    50          
89             || $tb->diag( sprintf qq{Package %s does not define the following sub%s%s},
90             $pkg,
91             (scalar(@missing)>1) ? 's' : '',
92             join qq{\n - }, '', @missing
93             );
94             }
95              
96              
97             =head2 has_pod
98              
99             =cut
100              
101             sub has_pod ($) {
102 1     1 1 9093 my $pkg = shift;
103 1         14 my $tb = $CLASS->builder;
104 1 50       16 $tb->ok( Test::Structure::_doc($pkg)->find_any('PPI::Token::Pod'), sprintf q{Package %s has POD.}, $pkg )
105             || $tb->diag( sprintf q{Package %s does not seem to have any POD.}, $pkg );
106             }
107              
108             =head2 has_comments
109              
110             =cut
111              
112             sub has_comments ($) {
113 1     1 1 6912 my $pkg = shift;
114 1         19 my $tb = $CLASS->builder;
115 1 50       18 $tb->ok( Test::Structure::_doc($pkg)->find_any('PPI::Token::Comment'), sprintf q{Package %s has comments.}, $pkg )
116             || $tb->diag( sprintf q{Package %s does not seem to have any comments.}, $pkg );
117             }
118              
119             =head1 AUTHOR
120              
121             notbenh, C<< >>
122              
123             =head1 BUGS
124              
125             Please report any bugs or feature requests to C, or through
126             the web interface at L. I will be notified, and then you'll
127             automatically be notified of progress on your bug as I make changes.
128              
129              
130              
131              
132             =head1 SUPPORT
133              
134             You can find documentation for this module with the perldoc command.
135              
136             perldoc Test::Structure
137              
138              
139             You can also look for information at:
140              
141             =over 4
142              
143             =item * RT: CPAN's request tracker
144              
145             L
146              
147             =item * AnnoCPAN: Annotated CPAN documentation
148              
149             L
150              
151             =item * CPAN Ratings
152              
153             L
154              
155             =item * Search CPAN
156              
157             L
158              
159             =back
160              
161              
162             =head1 ACKNOWLEDGEMENTS
163              
164              
165             =head1 LICENSE AND COPYRIGHT
166              
167             Copyright 2010 notbenh.
168              
169             This program is free software; you can redistribute it and/or modify it
170             under the terms of either: the GNU General Public License as published
171             by the Free Software Foundation; or the Artistic License.
172              
173             See http://dev.perl.org/licenses/ for more information.
174              
175              
176             =cut
177              
178             1;