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   346 use strict;
  4         5  
  4         156  
3 4     4   15 use warnings;
  4         9  
  4         78  
4 4     4   15 use utf8;
  4         5  
  4         20  
5 4     4   126 use 5.010_001;
  4         12  
  4         141  
6 4     4   199598 use Module::Load;
  4         3318  
  4         33  
7 4     4   156 use Try::Tiny;
  4         5  
  4         220  
8 4     4   14 use File::Spec;
  4         5  
  4         62  
9 4     4   12 use File::Path;
  4         6  
  4         162  
10              
11 4     4   18 use Test::Kantan::State;
  4         4  
  4         69  
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   15 use Moo;
  4         22  
  4         20  
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   1416 no Moo;
  4         4  
  4         18  
26              
27             sub _build_color {
28 3 50   3   1247 $ENV{KANTAN_COLOR} || -t *STDOUT;
29             }
30              
31             sub _build_state {
32 61     61   2529 Test::Kantan::State->new();
33             }
34              
35             sub _build_message_dir {
36 61     61   218 my $self = shift;
37 61         86 my $time = time;
38 61         2363 File::Spec->catfile(File::Spec->tmpdir, "kantan.$$.${time}");
39             }
40              
41             sub _build_reporter {
42 3     3   45 my $self = shift;
43              
44 3         4 my $reporter_class = do {
45 3   50     25 my $s = $ENV{KANTAN_REPORTER} || 'Spec';
46 3 50       16 my $klass = ($s =~ s/\A\+// ? $s : "Test::Kantan::Reporter::${s}");
47 3         19 Module::Load::load $klass;
48 3         39 $klass;
49             };
50 3         19 my $reporter = $reporter_class->new(
51             color => $self->color,
52             state => $self->state,
53             );
54 3         30 $reporter->start;
55 3         103 return $reporter;
56             }
57              
58             sub ok {
59 61     61 0 150 my ($self, %args) = @_;
60 61 50       116 return if $self->care_child(\%args);
61              
62 61         120 my $caller = param(\%args, 'caller');
63 61         86 my $value = param(\%args, 'value');
64 61         157 my $description = param(\%args, 'description', {optional => 1});
65              
66 61 100       106 if ($value) {
67 39         883 $self->state->passed();
68 39         154 $self->reporter->pass(
69             caller => $caller,
70             description => $description,
71             );
72 39         869 return 1;
73             } else {
74 22         474 $self->state->failed();
75 22         93 $self->reporter->fail(
76             caller => $caller,
77             description => $description,
78             );
79 22         536 return 0;
80             }
81             }
82              
83             sub care_child {
84 62     62 0 68 my ($self, $args) = @_;
85 62 50       347 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 195     195 0 223 my ($args, $key, $opts) = @_;
104              
105 195 50 66     437 if (exists $opts->{default} && not exists $args->{$key}) {
106 0         0 $args->{$key} = $opts->{default};
107             }
108              
109 195 100       275 if (exists $args->{$key}) {
110 171         308 delete $args->{$key};
111             } else {
112 24 50       49 if ($opts->{optional}) {
113 24         37 return undef;
114             } else {
115 0         0 Carp::confess "Missing mandatory parameter: ${key}";
116             }
117             }
118             }
119              
120             sub diag {
121 1     1 0 5 my ($self, %args) = @_;
122 1 50       5 return if $self->care_child(\%args);
123 1         4 my $message = param(\%args, 'message');
124 1         9 my $cutoff = param(\%args, 'cutoff', { default => $self->reporter->cutoff });
125 1         4 my $caller = param(\%args, 'caller');
126              
127 1         9 $self->reporter->diag(
128             message => $message,
129             cutoff => $cutoff,
130             caller => $caller,
131             );
132             }
133              
134             sub subtest {
135 3     3 0 12 my ($self, %args) = @_;
136 3         11 my $title = param(\%args, 'title');
137 3         7 my $code = param(\%args, 'code');
138 3         7 my $suite = param(\%args, 'suite');
139              
140 3         21 my $guard = $self->reporter->suite($title);
141              
142 3         83 $suite->parent->call_trigger('setup');
143             try {
144 3     3   147 $code->();
145             } catch {
146 0     0   0 $self->exception(message => $_);
147 3         26 };
148              
149 3 50       180 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         18 $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         18 $self->reporter->finalize();
172              
173             # Test::Pretty was loaded
174 2 50       76 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 58     58   441 my $self = shift;
197 58 50       224 if ($$ == $self->pid) {
198 58         5144 File::Path::rmtree($self->message_dir); # 為念
199             }
200             }
201              
202             1;
203