File Coverage

blib/lib/Test/Mini/Runner.pm
Criterion Covered Total %
statement 88 90 97.7
branch 9 14 64.2
condition 4 9 44.4
subroutine 24 25 96.0
pod 12 14 85.7
total 137 152 90.1


line stmt bran cond sub pod time code
1              
2             package Test::Mini::Runner;
3 4     4   719 use 5.006;
  4         13  
4 4     4   19 use strict;
  4         8  
  4         79  
5 4     4   19 use warnings;
  4         33  
  4         129  
6              
7 4     4   4279 use Getopt::Long;
  4         40805  
  4         19  
8 4     4   594 use Try::Tiny;
  4         6  
  4         210  
9 4     4   2800 use MRO::Compat;
  4         12356  
  4         107  
10 4     4   551 use Test::Mini::TestCase;
  4         8  
  4         105  
11 4     4   19 use List::Util qw/ shuffle /;
  4         6  
  4         1991  
12              
13             sub new {
14 11     11 1 2616 my ($class, %args) = @_;
15              
16             my %argv = (
17             verbose => $ENV{TEST_MINI_VERBOSE} || 0,
18             filter => $ENV{TEST_MINI_FILTER} || '',
19             logger => $ENV{TEST_MINI_LOGGER} || 'Test::Mini::Logger::TAP',
20 11   50     325 seed => $ENV{TEST_MINI_SEED} || int(rand(64_000_000)),
      50        
      50        
      33        
21             );
22              
23 11         42 GetOptions(\%argv, qw/ verbose=s filter=s logger=s seed=i /);
24 11         2975 return bless { %argv, %args, exit_code => 0 }, $class;
25             }
26              
27             # @group Attribute Accessors
28              
29             # @return Logger verbosity.
30             sub verbose {
31 10     10 1 15 my $self = shift;
32 10         49 return $self->{verbose};
33             }
34              
35             # @return Test name filter.
36             sub filter {
37 10     10 1 13 my $self = shift;
38 10         66 return $self->{filter};
39             }
40              
41             # @return Logger instance.
42             sub logger {
43 210     210 1 270 my $self = shift;
44 210         859 return $self->{logger};
45             }
46              
47             # @return Randomness seed.
48             sub seed {
49 10     10 1 15 my $self = shift;
50 10         29 return $self->{seed};
51             }
52              
53             # @return Exit code, representing the status of the test run.
54             sub exit_code {
55 20     20 1 27 my $self = shift;
56 20         79 return $self->{exit_code};
57             }
58              
59             # @group Test Run Hooks
60              
61             # Begins the test run.
62             # Loads and instantiates the test output logger, then dispatches to
63             # {#run_test_suite} (passing the {#filter} and {#seed}, as appropriate).
64             #
65             # @return The result of the {#run_test_suite} call.
66             sub run {
67 3     3 1 6 my ($self) = @_;
68 3         10 my $logger = $self->logger;
69             try {
70 3 50   3   265 eval "require $logger;" or die $@;
71             }
72             catch {
73 0 0   0   0 eval "require Test::Mini::Logger::$logger;" or die $@;
74 3         27 };
75              
76 3         66 $logger = $logger->new(verbose => $self->verbose);
77 3         7 $self->{logger} = $logger;
78              
79 3         9 return $self->run_test_suite(filter => $self->filter, seed => $self->seed);
80             }
81              
82             # Runs the test suite.
83             # Finds subclasses of {Test::Mini::TestCase}, and dispatches to
84             # {#run_test_case} with the name of each test case and a list test methods to
85             # be run.
86             #
87             # @param [Hash] %args
88             # @option %args [String] filter Test name filter.
89             # @option %args [String] seed Randomness seed.
90             # @return The value of {#exit_code}.
91             sub run_test_suite {
92 10     10 1 25 my ($self, %args) = @_;
93 10         20 $self->logger->begin_test_suite(%args);
94              
95 10         24 srand($args{seed});
96 10         14 my @testcases = @{ mro::get_isarev('Test::Mini::TestCase') };
  10         48  
97              
98             # Since mro::get_isarev is guaranteed to never shrink, we should "double
99             # check" our testcases, to make sure that they actually are *still*
100             # subclasses of Test::Mini::TestCase.
101             # @see http://search.cpan.org/dist/perl-5.12.2/ext/mro/mro.pm#mro::get_isarev($classname)
102 10         27 @testcases = grep { $_->isa('Test::Mini::TestCase') } @testcases;
  9         78  
103              
104 10 100       28 $self->{exit_code} = 255 unless @testcases;
105              
106 10         47 for my $tc (shuffle @testcases) {
107 4     4   18 no strict 'refs';
  4         8  
  4         1971  
108 9 100       12 my @tests = grep { /^test.+/ && defined &{"$tc\::$_"}} keys %{"$tc\::"};
  224         530  
  54         254  
  9         100  
109 9         29 $self->run_test_case($tc, grep { $_ =~ qr/$args{filter}/ } @tests);
  54         264  
110             }
111              
112 10         24 $self->logger->finish_test_suite($self->exit_code);
113 10         34 return $self->exit_code;
114             }
115              
116             # Runs tests in a test case.
117             #
118             # @param [Class] $tc The test case to run.
119             # @param [Array] @tests A list of tests to be run.
120             sub run_test_case {
121 9     9 0 28 my ($self, $tc, @tests) = @_;
122 9         31 $self->logger->begin_test_case($tc, @tests);
123              
124 9 100       18 $self->{exit_code} = 127 unless @{[
125 9         15 (@tests, grep { $_->isa($tc) } @{ mro::get_isarev($tc) })
  0         0  
  9         50  
126             ]};
127              
128 9         51 $self->run_test($tc, $_) for shuffle @tests;
129              
130 9         22 $self->logger->finish_test_case($tc, @tests);
131 9         33 return scalar @tests;
132             }
133              
134             # Runs a specific test.
135             #
136             # @param [Class] $tc The test case owning the test method.
137             # @param [String] $test The name of the test method to be run.
138             # @return [Integer] The number of assertions called by the test.
139             sub run_test {
140 54     54 1 96 my ($self, $tc, $test) = @_;
141 54         108 $self->logger->begin_test($tc, $test);
142              
143 54         239 my $instance = $tc->new(name => $test);
144 54         181 my $assertions = $instance->run($self);
145              
146 54         128 $self->logger->finish_test($tc, $test, $assertions);
147 54         266 return $assertions;
148             }
149              
150             # @group Callbacks
151              
152             # Callback for passing tests.
153             #
154             # @param [Class] $tc The test case owning the test method.
155             # @param [String] $test The name of the passing test.
156             sub pass {
157 50     50 1 76 my ($self, $tc, $test) = @_;
158 50         108 $self->logger->pass($tc, $test);
159             }
160              
161             # Callback for skipped tests.
162             #
163             # @param [Class] $tc The test case owning the test method.
164             # @param [String] $test The name of the skipped test.
165             # @param [Test::Mini::Exception::Skip] $e The exception object.
166             sub skip {
167 1     1 1 3 my ($self, $tc, $test, $e) = @_;
168 1         3 $self->logger->skip($tc, $test, $e);
169             }
170              
171             # Callback for failing tests.
172             #
173             # @param [Class] $tc The test case owning the test method.
174             # @param [String] $test The name of the failed test.
175             # @param [Test::Mini::Exception::Assert] $e The exception object.
176             sub fail {
177 1     1 0 2 my ($self, $tc, $test, $e) = @_;
178 1 50       4 $self->{exit_code} = 1 unless $self->{exit_code};
179 1         2 $self->logger->fail($tc, $test, $e);
180             }
181              
182             # Callback for dying tests.
183             #
184             # @param [Class] $tc The test case owning the test method.
185             # @param [String] $test The name of the test with an error.
186             # @param [Test::Mini::Exception] $e The exception object.
187             sub error {
188 2     2 1 4 my ($self, $tc, $test, $e) = @_;
189 2 50       6 $self->{exit_code} = 1 unless $self->{exit_code};
190 2         4 $self->logger->error($tc, $test, $e);
191             }
192              
193             1;
194              
195             __END__