File Coverage

blib/lib/Test/Kantan.pm
Criterion Covered Total %
statement 68 102 66.6
branch 6 16 37.5
condition 0 11 0.0
subroutine 22 36 61.1
pod 8 19 42.1
total 104 184 56.5


line stmt bran cond sub pod time code
1             package Test::Kantan;
2 3     3   3253 use 5.010_001;
  3         11  
  3         122  
3 3     3   14 use strict;
  3         5  
  3         89  
4 3     3   23 use warnings;
  3         4  
  3         145  
5              
6             our $VERSION = "0.39";
7              
8 3     3   2583 use parent qw(Exporter);
  3         1195  
  3         17  
9              
10 3     3   3083 use Try::Tiny;
  3         5377  
  3         200  
11              
12 3     3   1732 use Test::Kantan::State;
  3         11  
  3         106  
13 3     3   2250 use Test::Kantan::Builder;
  3         10  
  3         120  
14 3     3   2187 use Test::Kantan::Caller;
  3         8  
  3         89  
15 3     3   1670 use Test::Kantan::Suite;
  3         7  
  3         94  
16 3     3   1792 use Test::Kantan::Expect;
  3         10  
  3         112  
17              
18 3     3   24 use Test::Deep::NoTest qw(ignore);
  3         5  
  3         19  
19 3     3   8958 use Module::Spy 0.03 qw(spy_on);
  3         6651  
  3         384  
20              
21             our @EXPORT = (
22             qw(Feature Scenario Given When Then),
23             qw(subtest done_testing setup teardown),
24             qw(describe context it),
25             qw(before_each after_each),
26             qw(expect ok diag ignore spy_on),
27             qw(skip_all),
28             );
29              
30 3     3   2501 my $HAS_DEVEL_CODEOBSERVER = !$ENV{KANTAN_NOOBSERVER} && eval "use Devel::CodeObserver 0.11; 1;";
  3         41472  
  3         50  
31              
32             our $Level = 0;
33              
34             if (Test::Builder->can('new')) {
35             # Replace some Test::Builder methods with mine.
36              
37 3     3   21 no warnings 'redefine';
  3         6  
  3         4359  
38              
39             *Test::Builder::ok = sub {
40             my ($self, $ok, $msg) = @_;
41             Test::Kantan->builder->ok(
42             value => $ok,
43             message => $msg,
44             caller => Test::Kantan::Caller->new(
45             $Test::Builder::Level
46             ),
47             );
48             };
49              
50             *Test::Builder::subtest = sub {
51             my $self = shift;
52             goto \&Test::Kantan::subtest;
53             };
54              
55             *Test::Builder::diag = sub {
56             my ($self, $message) = @_;
57              
58             Test::Kantan->builder->diag(
59             message => $message,
60             cutoff => 1024,
61             caller => Test::Kantan::Caller->new($Test::Builder::Level),
62             );
63             };
64              
65             *Test::Builder::note = sub {
66             my ($self, $message) = @_;
67              
68             Test::Kantan->builder->diag(
69             message => $message,
70             cutoff => 1024,
71             caller => Test::Kantan::Caller->new($Test::Builder::Level),
72             );
73             };
74              
75             *Test::Builder::done_testing = sub {
76             my ($self, $message) = @_;
77              
78             Test::Kantan->builder->done_testing()
79             };
80             }
81              
82             our $BUILDER = Test::Kantan::Builder->new();
83 9     9 0 86 sub builder { $BUILDER }
84              
85             # -------------------------------------------------------------------------
86             # DSL functions
87              
88             our $CURRENT = our $ROOT = Test::Kantan::Suite->new(root => 1, title => 'Root');
89             our $FINISHED;
90             our $RAN_TEST;
91              
92             sub skip_all {
93 0     0 1 0 my ($reason) = @_;
94 0   0     0 $reason //= '';
95 0         0 print "1..0 # SKIP ${reason}\n";
96 0         0 exit 0;
97             }
98              
99             sub setup(&) {
100 0     0 1 0 my ($code) = @_;
101 0         0 $CURRENT->add_trigger('setup' => $code);
102             }
103 0     0 1 0 sub before_each { goto \&setup }
104              
105             sub teardown(&) {
106 0     0 1 0 my ($code) = @_;
107 0         0 $CURRENT->add_trigger('teardown' => $code);
108             }
109 0     0 1 0 sub after_each { goto \&teardown }
110              
111             sub _step {
112 0     0   0 my ($tag, $title) = @_;
113 0 0       0 @_==2 or Carp::confess "Invalid arguments";
114              
115 0         0 my $last_state = $CURRENT->{last_state};
116 0         0 $CURRENT->{last_state} = $tag;
117 0 0 0     0 if ($last_state && $last_state eq $tag) {
118 0         0 $tag = 'And';
119             }
120 0         0 builder->reporter->step(sprintf("%5s %s", $tag, $title));
121             }
122              
123 0     0 0 0 sub Given { _step('Given', @_) }
124 0     0 0 0 sub When { _step('When', @_) }
125 0     0 0 0 sub Then { _step('Then', @_) }
126              
127             sub _suite {
128 3     3   8 my ($env_key, $tag, $title, $code) = @_;
129              
130 3 50       12 if (defined($env_key)) {
131 0         0 my $filter = $ENV{$env_key};
132 0 0 0     0 if (defined($filter) && length($filter) > 0 && $title !~ /$filter/) {
      0        
133 0         0 builder->reporter->step("SKIP: ${title}");
134 0         0 return;
135             }
136             }
137              
138 3         109 my $suite = Test::Kantan::Suite->new(
139             title => $title,
140             parent => $CURRENT,
141             );
142             {
143 3         16 local $CURRENT = $suite;
  3         8  
144 3 50       9 builder->subtest(
145             title => defined($tag) ? "${tag} ${title}" : $title,
146             code => $code,
147             suite => $suite,
148             );
149             }
150 3         29 $RAN_TEST++;
151             }
152              
153 0     0 0 0 sub Feature { _suite('KANTAN_FILTER_FEATURE', 'Feature', @_) }
154 0     0 0 0 sub Scenario { _suite('KANTAN_FILTER_SCENARIO', 'Scenario', @_) }
155              
156             # Test::More compat
157 0     0 0 0 sub subtest { _suite('KANTAN_FILTER_SUBTEST', undef, @_) }
158              
159             # BDD compat
160 2     2 0 46 sub describe { _suite( undef, undef, @_) }
161 0     0 0 0 sub context { _suite( undef, undef, @_) }
162 1     1 0 21 sub it { _suite( undef, undef, @_) }
163              
164             sub expect {
165 2     2 1 21 my $stuff = shift;
166 2         14 Test::Kantan::Expect->new(
167             stuff => $stuff,
168             builder => Test::Kantan->builder
169             );
170             }
171              
172             sub ok(&) {
173 1     1 1 138 my $code = shift;
174              
175 1 50       6 if ($HAS_DEVEL_CODEOBSERVER) {
176 1         14 state $observer = Devel::CodeObserver->new();
177 1         18 my ($retval, $result) = $observer->call($code);
178              
179 1         462 my $builder = Test::Kantan->builder;
180 1         12 $builder->ok(
181             value => $retval,
182             caller => Test::Kantan::Caller->new(
183             $Test::Kantan::Level
184             ),
185             );
186 1         3 for my $pair (@{$result->dump_pairs}) {
  1         106  
187 1         478 my ($code, $dump) = @$pair;
188              
189 1         10 $builder->diag(
190             message => sprintf("%s => %s", $code, $dump),
191             caller => Test::Kantan::Caller->new(
192             $Test::Kantan::Level
193             ),
194             cutoff => $builder->reporter->cutoff,
195             );
196             }
197 1         11 return !!$retval;
198             } else {
199 0         0 my $retval = $code->();
200 0         0 my $builder = Test::Kantan->builder;
201 0         0 $builder->ok(
202             value => $retval,
203             caller => Test::Kantan::Caller->new(
204             $Test::Kantan::Level
205             ),
206             );
207             }
208             }
209              
210             sub diag {
211 0     0 1 0 my ($msg, $cutoff) = @_;
212              
213 0         0 Test::Kantan->builder->diag(
214             message => $msg,
215             cutoff => $cutoff,
216             caller => Test::Kantan::Caller->new(
217             $Test::Kantan::Level
218             ),
219             );
220             }
221              
222             sub done_testing {
223 2     2 0 21 builder->done_testing
224             }
225              
226             END {
227 3 100   3   6 if ($RAN_TEST) {
228 1 50       4 unless (builder->finished) {
229 0         0 die "You need to call `done_testing` before exit";
230             }
231             }
232             }
233              
234              
235             1;
236             __END__