File Coverage

blib/lib/Test/Class/Moose/Load.pm
Criterion Covered Total %
statement 66 66 100.0
branch 9 10 90.0
condition n/a
subroutine 22 22 100.0
pod 1 1 100.0
total 98 99 98.9


line stmt bran cond sub pod time code
1             package Test::Class::Moose::Load;
2              
3             # ABSTRACT: Load L<Test::Class::Moose> classes automatically.
4              
5 45     45   9796564 use strict;
  45         57677  
  45         1646  
6 44     44   8691 use warnings;
  44         74220  
  44         2231  
7 43     43   21259 use namespace::autoclean;
  43         595287  
  43         498  
8              
9             our $VERSION = '1.00';
10              
11 41     41   9519 use File::Find;
  41         39510  
  41         3275  
12 41     41   6630 use File::Spec;
  41         72075  
  41         24897  
13              
14             # Override to get your own filter
15             sub is_test_class {
16 387     387 1 8161 my ( undef, $file, undef ) = @_;
17              
18             # By default, we only care about .pm files
19 387 100       73126 if ( $file =~ /\.pm$/ ) {
20 196         1114 return 1;
21             }
22 203         41475 return;
23             }
24              
25             my %Added_to_INC;
26              
27             sub _load {
28 196     196   90193 my ( $class, $file, $dir ) = @_;
29              
30 196         1416 $file =~ s{\.pm$}{}; # remove .pm extension
31 185         524 $file =~ s{\\}{/}g; # to make win32 happy
32 185         425 $dir =~ s{\\}{/}g; # to make win32 happy
33 185         2826 $file =~ s/^\Q$dir\E//;
34 185         2684 my $_package = join '::', grep {$_} File::Spec->splitdir($file);
  579         1702  
35              
36             # untaint that puppy!
37 185         1399 my ($package) = $_package =~ /^([[:word:]]+(?:::[[:word:]]+)*)$/;
38              
39             # Filter out bad classes (mainly this means things in .svn and similar)
40 185 50       576 return unless defined $package;
41              
42 185 100       944 unshift @INC => $dir unless $Added_to_INC{$dir}++;
43              
44             {
45 185         415 local $SIG{__DIE__} = sub {
46 17     17   164531 undef $SIG{__DIE__};
47 17         186 require Carp;
48 17         68 local $Carp::CarpLevel = $Carp::CarpLevel + 1;
49 17         6591 Carp::confess(@_);
50 185         1435 };
51              
52             # either "require" it or "use" it with no import list. Otherwise, this
53             # module will inherit from Test::Class::Moose and break everything.
54              
55             ## no critic (BuiltinFunctions::ProhibitStringyEval, ErrorHandling::RequireCheckingReturnValueOfEval)
56 41     41   21642 eval "use $package ()";
  40     37   463638  
  40     1   1203  
  37     1   21570  
  37     1   227845  
  37     1   1147  
  185     1   16717  
  1     1   23  
  1     1   9  
  1     1   2  
  1     1   23  
  1     1   8  
  1         2  
  1         20  
  1         8  
  1         3  
  1         23  
  1         9  
  1         3  
  1         22  
  1         10  
  1         2  
  1         20  
57             }
58 185 100       15475 die $@ if $@;
59             }
60              
61             sub import {
62 38     38   556 my ( $class, @directories ) = @_;
63              
64 38         176 foreach my $dir (@directories) {
65 82         2131 $dir = File::Spec->catdir( split /\//, $dir );
66             find(
67             { no_chdir => 1,
68             wanted => sub {
69 376     376   1762 my @args = ( $File::Find::name, $dir );
70 376 100       3087 if ( $class->is_test_class(@args) ) {
71 185         899 $class->_load(@args);
72             }
73             },
74             },
75 82         12375 $dir
76             );
77             }
78             }
79              
80             1;
81              
82             __END__
83              
84             =pod
85              
86             =encoding UTF-8
87              
88             =head1 NAME
89              
90             Test::Class::Moose::Load - Load L<Test::Class::Moose> classes automatically.
91              
92             =head1 VERSION
93              
94             version 1.00
95              
96             =head1 SYNOPSIS
97              
98             use Test::Class::Moose::Load qw(t/tests t/lib);
99             Test::Class::Moose::Runner->new->runtests;
100              
101             =head1 DESCRIPTION
102              
103             Note: This helper module was blatantly stolen from L<Test::Class::Load>.
104             However, since your author is the person who originally wrote that code, he
105             doesn't feel too bad.
106              
107             Without a loader, you would have to manually load each test class in your test
108             file. This would look something like this:
109              
110             #!/usr/bin/perl -T
111              
112             use strict;
113             use warnings;
114              
115             use Test::Class::Moose::Runner;
116              
117             use lib 't/tests';
118              
119             use MyTest::Foo;
120             use MyTest::Foo::Bar;
121             use MyTest::Foo::Baz;
122              
123             Test::Class::Moose::Runner->new->runtests;
124              
125             This causes a problem, though. When you're writing a test class, it's easy to
126             forget to add it to the helper script. Then you run your huge test suite and
127             see that all tests pass, even though you don't notice that it didn't run your
128             new test class. Or you delete a test class and you forget to remove it from
129             the helper script.
130              
131             L<Test::Class::Moose::Load> automatically finds and loads your test classes for
132             you. There is no longer a need to list them individually.
133              
134             =head1 EXPORT
135              
136             None.
137              
138             =head1 BASIC USAGE
139              
140             Using L<Test::Class::Moose::Load> is as simple as this:
141              
142             #!/usr/bin/perl -T
143              
144             use strict;
145             use warnings;
146              
147             use Test::Class::Moose::Runner;
148             use Test::Class::Moose::Load 't/tests';
149              
150             Test::Class::Moose::Runner->new(\%args)->runtests;
151              
152             That will search through all files in the C<t/tests> directory and
153             automatically load anything which ends in C<.pm>. You should only put test
154             classes in those directories.
155              
156             If you have test classes in more than one directory, that's OK. Just list all
157             of them in the import list.
158              
159             use Test::Class::Moose::Load qw<
160             t/customer
161             t/order
162             t/inventory
163             >;
164             Test::Class::Moose::Runner->runtests;
165              
166             =head1 ADVANCED USAGE
167              
168             Here's some examples of advanced usage of L<Test::Class::Moose::Load>.
169              
170             =head2 FILTER LOADED CLASSES
171              
172             You can redefine the filtering criteria, that is, decide what classes are
173             picked up and what others are not. You do this simply by subclassing
174             L<Test::Class::Moose::Load> overriding the C<is_test_class()> method. You might
175             want to do this to only load modules which inherit from L<Test::Class::Moose>,
176             or anything else for that matter.
177              
178             =over 4
179              
180             =item B<is_test_class>
181              
182             $is_test_class = $class->is_test_class( $file, $directory )
183              
184             Returns true if C<$file> in C<$directory> should be considered a test class and
185             be loaded by L<Test::Class::Moose::Load>. The default filter simply returns
186             true if C<$file> ends with C<.pm>
187              
188             =back
189              
190             For example:
191              
192             use strict;
193             use warnings;
194              
195             package My::Loader;
196             use base qw( Test::Class::Moose::Load );
197              
198             # Overriding this selects what test classes
199             # are considered by T::C::Load
200             sub is_test_class {
201             my ( $class, $file, $dir ) = @_;
202              
203             # return unless it's a .pm (the default)
204             return unless $class->SUPER::is_test_class( $file, $dir );
205              
206             # and only allow .pm files with "Good" in their filename
207             return $file =~ m{Good};
208             }
209              
210             1;
211              
212             =head2 CUSTOMIZING TEST RUNS
213              
214             One problem with this style of testing is that you run I<all> of the tests
215             every time you need to test something. If you want to run only one test class,
216             it's problematic. The easy way to do this is to change your helper script by
217             deleting the C<runtests> call:
218              
219             #!/usr/bin/perl -T
220              
221             use strict;
222             use warnings;
223              
224             use Test::Class::Moose::Load 't/tests';
225              
226             Then, just make sure that all of your test classes inherit from your own base
227             class which runs the tests for you. It might looks something like this:
228              
229             package My::Test::Class::Moose;
230              
231             use strict;
232             use warnings;
233              
234             use Test::Class::Moose::Runner;
235              
236             use base 'Test::Class::Moose';
237              
238             INIT { Test::Class::Moose::Runner->new->runtests } # here's the magic!
239              
240             1;
241              
242             Then you can run an individual test class by using the C<prove> utility, tell
243             it the directory of the test classes and the name of the test package you wish
244             to run:
245              
246             prove -lv -It/tests Some::Test::Class::Moose
247              
248             You can even automate this by binding it to a key in C<vim>:
249              
250             noremap ,t :!prove -lv -It/tests %<CR>
251              
252             Then you can just type C<,t> ('comma', 'tee') and it will run the tests for
253             your test class or the tests for your test script (if you're using a
254             traditional L<Test::More> style script).
255              
256             Of course, you can still run your helper script with C<prove>, C<make test> or
257             C<./Build test> to run all of your test classes.
258              
259             If you do that, you'll have to make sure that the C<-I> switches point to your
260             test class directories.
261              
262             =head1 SECURITY
263              
264             L<Test::Class::Moose::Load> is taint safe. Because we're reading the class
265             names from the directory structure, they're marked as tainted when running
266             under taint mode. We use the following ultra-paranoid bit of code to untaint
267             them. Please file a bug report if this is too restrictive.
268              
269             my ($package) = $_package =~ /^([[:word:]]+(?:::[[:word:]]+)*)$/;
270              
271             =head1 ACKNOWLEDGMENTS
272              
273             Thanks to David Wheeler for the idea and Adrian Howard for
274             L<Test::Class::Moose>.
275              
276             =head1 BUGS
277              
278             Please report any bugs or feature requests to
279             C<bug-test-class-load@rt.cpan.org>, or through the web interface at
280             L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Test-Class-Load>. I will be
281             notified, and then you'll automatically be notified of progress on your bug as
282             I make changes.
283              
284             Bugs may be submitted at L<https://github.com/Test-More/test-class-moose/issues>.
285              
286             =head1 SOURCE
287              
288             The source code repository for Test-Class-Moose can be found at L<https://github.com/Test-More/test-class-moose>.
289              
290             =head1 AUTHORS
291              
292             =over 4
293              
294             =item *
295              
296             Curtis "Ovid" Poe <ovid@cpan.org>
297              
298             =item *
299              
300             Dave Rolsky <autarch@urth.org>
301              
302             =item *
303              
304             Chad Granum <exodist@cpan.org>
305              
306             =back
307              
308             =head1 COPYRIGHT AND LICENSE
309              
310             This software is copyright (c) 2012 - 2025 by Curtis "Ovid" Poe.
311              
312             This is free software; you can redistribute it and/or modify it under
313             the same terms as the Perl 5 programming language system itself.
314              
315             The full text of the license can be found in the
316             F<LICENSE> file included with this distribution.
317              
318             =cut