File Coverage

blib/lib/Test/Kantan/Builder.pm
Criterion Covered Total %
statement 90 121 74.3
branch 15 32 46.8
condition 3 5 60.0
subroutine 23 26 88.4
pod 0 8 0.0
total 131 192 68.2


line stmt bran cond sub pod time code
1             package Test::Kantan::Builder;
2 4     4   708 use strict;
  4         7  
  4         171  
3 4     4   23 use warnings;
  4         9  
  4         96  
4 4     4   18 use utf8;
  4         7  
  4         27  
5 4     4   177 use 5.010_001;
  4         11  
  4         122  
6 4     4   4463 use Module::Load;
  4         4498  
  4         42  
7 4     4   192 use Try::Tiny;
  4         7  
  4         267  
8 4     4   21 use File::Spec;
  4         6  
  4         86  
9 4     4   19 use File::Path;
  4         8  
  4         219  
10              
11 4     4   22 use Test::Kantan::State;
  4         8  
  4         97  
12              
13             # Do not call this interface directly from your code.
14             # After release TB2 and TB2 is good enough to me, I will replace this part with TB2.
15              
16 4     4   18 use Moo;
  4         31  
  4         28  
17              
18             has color => ( is => 'lazy' );
19             has state => ( is => 'lazy' );
20             has reporter => ( is => 'ro', 'builder' => '_build_reporter' );
21             has finished => ( is => 'rw', default => sub { 0 } );
22             has pid => (is => 'ro', default => sub { $$ });
23             has message_dir => (is => 'ro', 'builder' => '_build_message_dir' );
24              
25 4     4   1688 no Moo;
  4         9  
  4         22  
26              
27             sub _build_color {
28 3 50   3   1712 $ENV{KANTAN_COLOR} || -t *STDOUT;
29             }
30              
31             sub _build_state {
32 28     28   2398 Test::Kantan::State->new();
33             }
34              
35             sub _build_message_dir {
36 28     28   154 my $self = shift;
37 28         79 my $time = time;
38 28         1799 File::Spec->catfile(File::Spec->tmpdir, "kantan.$$.${time}");
39             }
40              
41             sub _build_reporter {
42 3     3   73 my $self = shift;
43              
44 3         9 my $reporter_class = do {
45 3   50     30 my $s = $ENV{KANTAN_REPORTER} || 'Spec';
46 3 50       21 my $klass = ($s =~ s/\A\+// ? $s : "Test::Kantan::Reporter::${s}");
47 3         17 Module::Load::load $klass;
48 3         50 $klass;
49             };
50 3         23 my $reporter = $reporter_class->new(
51             color => $self->color,
52             state => $self->state,
53             );
54 3         39 $reporter->start;
55 3         99 return $reporter;
56             }
57              
58             sub ok {
59 28     28 0 116 my ($self, %args) = @_;
60 28 50       98 return if $self->care_child(\%args);
61              
62 28         100 my $caller = param(\%args, 'caller');
63 28         67 my $value = param(\%args, 'value');
64 28         101 my $description = param(\%args, 'description', {optional => 1});
65              
66 28 100       88 if ($value) {
67 16         378 $self->state->passed();
68 16         98 $self->reporter->pass(
69             caller => $caller,
70             description => $description,
71             );
72 16         662 return 1;
73             } else {
74 12         318 $self->state->failed();
75 12         63 $self->reporter->fail(
76             caller => $caller,
77             description => $description,
78             );
79 12         515 return 0;
80             }
81             }
82              
83             sub care_child {
84 29     29 0 45 my ($self, $args) = @_;
85 29 50       192 return if $$ eq $self->pid;
86 0         0 (my $meth = [caller(1)]->[3]) =~ s/.*:://;
87              
88 0         0 $self->push_child_message($meth, $args);
89             }
90              
91             sub exception {
92 0     0 0 0 my ($self, %args) = @_;
93 0 0       0 return if $self->care_child(\%args);
94 0         0 my $message = param(\%args, 'message');
95              
96 0         0 $self->state->failed();
97 0         0 $self->reporter->exception(
98             message => $message,
99             );
100             }
101              
102             sub param {
103 96     96 0 141 my ($args, $key, $opts) = @_;
104              
105 96 50 66     266 if (exists $opts->{default} && not exists $args->{$key}) {
106 0         0 $args->{$key} = $opts->{default};
107             }
108              
109 96 100       230 if (exists $args->{$key}) {
110 72         243 delete $args->{$key};
111             } else {
112 24 50       54 if ($opts->{optional}) {
113 24         53 return undef;
114             } else {
115 0         0 Carp::confess "Missing mandatory parameter: ${key}";
116             }
117             }
118             }
119              
120             sub diag {
121 1     1 0 6 my ($self, %args) = @_;
122 1 50       4 return if $self->care_child(\%args);
123 1         5 my $message = param(\%args, 'message');
124 1         10 my $cutoff = param(\%args, 'cutoff', { default => $self->reporter->cutoff });
125 1         4 my $caller = param(\%args, 'caller');
126              
127 1         8 $self->reporter->diag(
128             message => $message,
129             cutoff => $cutoff,
130             caller => $caller,
131             );
132             }
133              
134             sub subtest {
135 3     3 0 11 my ($self, %args) = @_;
136 3         11 my $title = param(\%args, 'title');
137 3         8 my $code = param(\%args, 'code');
138 3         7 my $suite = param(\%args, 'suite');
139              
140 3         20 my $guard = $self->reporter->suite($title);
141              
142 3         53 $suite->parent->call_trigger('setup');
143             try {
144 3     3   110 $code->();
145             } catch {
146 0     0   0 $self->exception(message => $_);
147 3         33 };
148              
149 3 50       162 if (-d $self->message_dir) {
150 0         0 require Storable;
151 0         0 for my $fname (glob($self->message_dir . "/*")) {
152 0 0       0 open my $fh, '<', $fname
153             or die;
154 0         0 my $dat = Storable::thaw(do { local $/; <$fh> });
  0         0  
  0         0  
155 0         0 close $fh;
156 0         0 unlink $fname;
157              
158 0         0 my ($method, $args) = @$dat;
159 0         0 $self->$method(%$args);
160             }
161 0         0 rmdir $self->message_dir;
162             }
163              
164 3         12 $suite->parent->call_trigger('teardown');
165             }
166              
167             sub done_testing {
168 2     2 0 4 my ($self) = @_;
169 2 50       17 return if $self->{finished}++;
170              
171 2         14 $self->reporter->finalize();
172              
173             # Test::Pretty was loaded
174 2 50       146 if (Test::Pretty->can('_subtest')) {
175             # Do not run Test::Pretty's finalization
176 0         0 $Test::Pretty::NO_ENDING=1;
177             }
178             }
179              
180             sub push_child_message {
181 0     0 0 0 my ($self, $type, $args) = @_;
182              
183 0         0 require Time::HiRes;
184 0         0 require Storable;
185              
186 0         0 mkdir $self->message_dir;
187              
188 0         0 my $fname = File::Spec->catfile($self->message_dir, "$$." . Time::HiRes::time());
189 0 0       0 open my $fh, '>>', $fname
190             or die "$fname: $!";
191 0         0 print {$fh} Storable::nfreeze([$type, $args]) . "\n";
  0         0  
192 0         0 close $fh;
193             }
194              
195             sub DESTROY {
196 25     25   560 my $self = shift;
197 25 50       116 if ($$ == $self->pid) {
198 25         3480 File::Path::rmtree($self->message_dir); # 為念
199             }
200             }
201              
202             1;
203