File Coverage

blib/lib/Test/Flatten.pm
Criterion Covered Total %
statement 92 110 83.6
branch 21 36 58.3
condition 7 9 77.7
subroutine 17 18 94.4
pod 1 1 100.0
total 138 174 79.3


line stmt bran cond sub pod time code
1             package Test::Flatten;
2              
3 7     7   128324 use strict;
  7         15  
  7         300  
4 7     7   36 use warnings;
  7         8  
  7         213  
5 7     7   32 use Test::More ();
  7         17  
  7         121  
6 7     7   30 use Test::Builder ();
  7         9  
  7         192  
7 7     7   7041 use Term::ANSIColor qw(colored);
  7         51789  
  7         3672  
8              
9             our $VERSION = '0.11';
10              
11             our $BORDER_COLOR = [qw|cyan bold|];
12             our $BORDER_CHAR = '-';
13             our $BORDER_LENGTH = 78;
14             our $CAPTION_COLOR = ['clear'];
15             our $NOTE_COLOR = ['yellow'];
16              
17             our $ORG_SUBTEST = Test::Builder->can('subtest');
18             our $ORG_TEST_MORE_SUBTEST = Test::More->can('subtest');
19              
20             $ENV{ANSI_COLORS_DISABLED} = 1 if $^O eq 'MSWin32';
21              
22             sub import {
23 7     7   55 my $class = caller(0);
24 7     7   61 no warnings qw(redefine prototype);
  7         11  
  7         349  
25 7     7   31 no strict 'refs';
  7         9  
  7         2378  
26 7         25 *Test::Builder::subtest = \&subtest;
27              
28             # backward campatibility
29 7         24 *{"$class\::subtest"} = Test::More->can('subtest');
  7         8389  
30             }
31              
32             my $TEST_DIFF = 0;
33             END {
34 7 50   7   811 if ($TEST_DIFF) {
35 0         0 my $builder = Test::More->builder;
36 0         0 _diag_plan($builder->{Curr_Test} - $TEST_DIFF, $builder->{Curr_Test});
37 0         0 Test::Builder::_my_exit(255); # report fail
38 0         0 undef $Test::Builder::Test; # disabled original END{} block
39             }
40             }
41              
42             sub subtest {
43 20     20 1 2993 my ($self, $caption, $test, @args) = @_;
44              
45 20         50 my $builder = Test::More->builder;
46 20 50       128 unless (ref $test eq 'CODE') {
47 0         0 $builder->croak("subtest()'s second argument must be a code ref");
48             }
49              
50             # copying original setting
51 20         58 my $current_test = $builder->{Curr_Test};
52 20         29 my $skip_all = $builder->{Skip_All};
53 20         29 my $have_plan = $builder->{Have_Plan};
54 20         24 my $no_plan = $builder->{No_Plan};
55 20         27 my $in_filter = $builder->{__in_filter__};
56              
57             ## this idea from http://d.hatena.ne.jp/tokuhirom/20111017/1318831330
58 20 100       70 if (my $filter = $ENV{SUBTEST_FILTER}) {
59 7 100 100     97 if ($caption =~ qr{$filter} || $in_filter) {
60 4         7 $builder->{__in_filter__} = 1;
61             }
62             else {
63 3         29 $builder->note(colored $NOTE_COLOR, "SKIP: $caption by SUBTEST_FILTER");
64 3         535 return;
65             }
66             }
67              
68 17         83 $builder->note(colored $BORDER_COLOR, $BORDER_CHAR x $BORDER_LENGTH);
69 17         3014 $builder->note(colored $CAPTION_COLOR, $caption);
70 17         2380 $builder->note(colored $BORDER_COLOR, $BORDER_CHAR x $BORDER_LENGTH);
71              
72             # reset
73 17         2307 $builder->{Have_Plan} = 0;
74              
75 7     7   38 no warnings 'redefine';
  7         9  
  7         227  
76 7     7   31 no strict 'refs';
  7         7  
  7         568  
77 17         53 local *{ref($builder).'::plan'} = _fake_plan(\my $tests, \my $is_skip_all);
  17         72  
78 17     1   49 local *{ref($builder).'::done_testing'} = sub {}; # temporary disabled
  17         48  
  1         523  
79              
80 7     7   75 use warnings;
  7         11  
  7         202  
81 7     7   27 use strict;
  7         8  
  7         3763  
82              
83 17         28 local $Test::Builder::Level = $Test::Builder::Level = 1;
84 17         20 my $is_passing = eval { $test->(@args); 1 };
  17         47  
  15         7277  
85 16         28 my $e = $@;
86              
87 16 50 66     54 die $e if $e && !eval { $e->isa('Test::Builder::Exception') };
  1         11  
88              
89 16 100 66     115 if ($is_skip_all) {
    50          
    50          
90 1         2 $builder->{Skip_All} = $skip_all;
91             }
92             elsif ($tests && $builder->{Curr_Test} != $current_test + $tests) {
93 0         0 _diag_plan($tests, $builder->{Curr_Test} - $current_test);
94 0         0 $TEST_DIFF = $builder->{Curr_Test} - $current_test - $tests;
95 0         0 $is_passing = $builder->is_passing(0);
96             }
97             elsif ($builder->{Curr_Test} == $current_test) {
98 0         0 $builder->croak("No tests run for subtest $caption");
99             }
100              
101             # restore
102 16         25 $builder->{Have_Plan} = $have_plan;
103 16         20 $builder->{No_Plan} = $no_plan;
104 16         24 $builder->{__in_filter__} = $in_filter;
105              
106 16         241 return $is_passing;
107             }
108              
109             sub _diag_plan {
110 0     0   0 my ($plan, $ran) = @_;
111 0 0       0 my $s = $plan == 1 ? '' : 's';
112 0         0 Test::More->builder->diag(sprintf 'Looks like you planned %d test%s but ran %d.',
113             $plan, $s, $ran,
114             );
115             }
116              
117             sub _fake_plan {
118 17     17   24 my ($tests, $is_skip_all) = @_;
119              
120             return sub {
121 4     4   54 my ($self, $cmd, $arg) = @_;
122 4 50       11 return unless $cmd;
123 4         5 local $Test::Builder::Level = $Test::Builder::Level + 2;
124 4 50       15 $self->croak("You tried to plan twice") if $self->{Have_Plan};
125              
126 4 100       15 if ($cmd eq 'no_plan') {
    100          
    50          
127 1         1 local $Test::Builder::Level = $Test::Builder::Level + 1;
128 1         10 $self->no_plan($arg);
129             }
130             elsif ($cmd eq 'skip_all') {
131 1         2 local $Test::Builder::Level = $Test::Builder::Level + 1;
132 1         1 $self->{Skip_All} = 1;
133 1 50       5 $self->note(join q{ }, 'SKIP:', $arg) unless $self->no_header;
134 1         147 $$is_skip_all = 1; # set flag
135 1         12 die bless {}, 'Test::Builder::Exception';
136             }
137             elsif ($cmd eq 'tests') {
138 2 50       4 if($arg) {
    0          
139 2         3 local $Test::Builder::Level = $Test::Builder::Level + 1;
140 2 50       11 unless ($arg =~ /^\+?\d+$/) {
141 0         0 $self->croak("Number of tests must be a positive integer. You gave it '$arg'");
142             }
143 2         3 $$tests = $arg; # set tests
144             }
145             elsif( !defined $arg ) {
146 0         0 $self->croak("Got an undefined number of tests");
147             }
148             else {
149 0         0 $self->croak("You said to run 0 tests");
150             }
151             }
152             else {
153 0         0 my @args = grep { defined } ( $cmd, $arg );
  0         0  
154 0         0 $self->croak("plan() doesn't understand @args");
155             }
156 3         11 return 1;
157 17         146 };
158             }
159              
160             1;
161             __END__