File Coverage

blib/lib/Test/Stream.pm
Criterion Covered Total %
statement 117 119 98.3
branch 49 56 87.5
condition 14 17 82.3
subroutine 14 14 100.0
pod 0 5 0.0
total 194 211 91.9


line stmt bran cond sub pod time code
1             package Test::Stream;
2 102     102   37014 use strict;
  102         114  
  102         2405  
3 102     102   303 use warnings;
  102         98  
  102         2266  
4 102     102   326 use vars qw/$VERSION/;
  102         98  
  102         5513  
5              
6             $Test::Stream::VERSION = '1.302027';
7             $VERSION = eval $VERSION;
8              
9 102     102   349 use Carp qw/croak/;
  102         113  
  102         5088  
10 102     102   344 use Scalar::Util qw/reftype/;
  102         101  
  102         7087  
11              
12 102     102   34926 use Test::Stream::Sync();
  102         172  
  102         2215  
13              
14 102     102   454 use Test::Stream::Util qw/try pkg_to_file/;
  102         99  
  102         420  
15              
16             sub default {
17 1     1 0 129 croak "No plugins or bundles specified (Maybe try '-Classic'?)"
18             }
19              
20             sub import {
21 122     122   1118 my $class = shift;
22 122         353 my @caller = caller;
23              
24 122 100       380 push @_ => $class->default unless @_;
25              
26 121         299 $class->load(\@caller, @_);
27              
28 119         82074 1;
29             }
30              
31             sub load {
32 157     157 0 194 my $class = shift;
33 157         153 my $caller = shift;
34              
35 157         152 my @order;
36             my %args;
37 0         0 my %skip;
38              
39 157         474 while (my $arg = shift @_) {
40 1759   100     5246 my $type = reftype($arg) || "";
41              
42 1759 100       2280 if ($type eq 'CODE') {
43 114         178 push @order => $arg;
44 114         257 next;
45             }
46              
47             # Strip off the '+', which may be combined with ':' or '-' at the
48             # start.
49 1645 100       2356 my $full = ($arg =~ s/^([!:-]?)\+/$1/) ? 1 : 0;
50              
51             # Disallowed plugin
52 1645 100       2190 if ($arg =~ m/^!(.*)$/) {
53 3 100       8 my $pkg = $full ? $1 : "Test::Stream::Plugin::$1";
54 3         4 $skip{$pkg}++;
55 3         6 next;
56             }
57              
58             # Bundle
59 1642 100       2301 if ($arg =~ m/^-(.*)$/) {
60 163 100       588 my $pkg = $full ? $1 : "Test::Stream::Bundle::$1";
61 163         470 my $file = pkg_to_file($pkg);
62 163         53385 require $file;
63 163         820 unshift @_ => $pkg->plugins;
64 163         687 next;
65             }
66              
67             # Local Bundle
68 1479 100       1798 if ($arg =~ m/^:(.*)$/) {
69 2 50       8 my $pkg = $full ? $1 : "Test::Stream::Bundle::$1";
70 2         6 my $file = pkg_to_file($pkg);
71              
72             local @INC = (
73             ($ENV{TS_LB_PATH} ? split(':', $ENV{TS_LB_PATH}) : ()),
74             't/lib',
75             'lib',
76             sub {
77 1     1   2 my ($me, $fname) = @_;
78 1 50       4 return unless $fname eq $file;
79 1         14 die "Could not load LOCAL PROJECT bundle '$pkg' (Do you need to set TS_LB_PATH?)\n";
80             },
81 2 50       23 @INC,
82             );
83              
84 2         355 require $file;
85 1         8 unshift @_ => $pkg->plugins;
86 1         9 next;
87             }
88              
89 1477 100       2345 if ($arg =~ m/^[a-z]/) {
90 7         12 my $method = "opt_$arg";
91              
92 7 100       62 die "'$arg' is not a valid option for '$class' (Did you intend to use the '" . ucfirst($arg) . "' plugin?) at $caller->[1] line $caller->[2].\n"
93             unless $class->can($method);
94              
95 6         18 $class->$method(list => \@_, order => \@order, args => \%args, skip => \%skip);
96 6         23 next;
97             }
98              
99             # Load the plugin
100 1470 100       2820 $arg = 'Test::Stream::Plugin::' . $arg unless $full;
101              
102             # Get the value
103 1470         1135 my $val;
104              
105             # Arg is specified
106 1470 100 66     5960 $val = shift @_ if @_ && (ref($_[0]) || ($_[0] && $_[0] eq '*'));
      66        
107              
108             # Special Cases
109 1470 50 100     2472 $val = $val eq '*' ? ['-all'] : [$val]
    100          
110             if defined($val) && !ref($val);
111              
112             # Make sure we only list it in @order once.
113 1470 100       2362 push @order => $arg unless $args{$arg};
114              
115             # Override any existing value, last wins.
116 1470 100       7142 $args{$arg} = $val if defined $val;
117             }
118              
119 155         243 for my $arg (@order) {
120 1578   100     6211 my $type = reftype($arg) || "";
121 1578 100       2705 if ($type eq 'CODE') {
122 114         348 $arg->($caller);
123 114         159 next;
124             }
125              
126 1464 100       2449 next if $skip{$arg};
127              
128 1460         1560 my $import = $args{$arg};
129 1460         1227 my $mod = $arg;
130              
131 1460         3302 my $file = pkg_to_file($mod);
132 1460 100       1624 unless (eval { require $file; 1 }) {
  1460         414251  
  1458         4202  
133 2   50     4 my $error = $@ || 'unknown error';
134 2         3 my $file = __FILE__;
135 2         2 my $line = __LINE__ - 3;
136 2         24 $error =~ s/ at \Q$file\E line $line.*//;
137 2         192 croak "Could not load Test::Stream plugin '$arg': $error";
138             }
139              
140 1458 100       11799 if ($mod->can('load_ts_plugin')) {
    50          
    0          
141 546         1594 $mod->load_ts_plugin($caller, @$import);
142             }
143             elsif (my $meta = Test::Stream::Exporter::Meta->get($mod)) {
144 912         2072 Test::Stream::Exporter::export_from($mod, $caller->[0], $import);
145             }
146             elsif (@$import) {
147 0         0 croak "Module '$mod' does it implement 'load_ts_plugin()', nor does it export using Test::Stream::Exporter."
148             }
149             }
150              
151 140         700 Test::Stream::Sync->loaded(1);
152             }
153              
154             sub opt_class {
155 5     5 0 16 shift;
156 5         12 my %params = @_;
157 5         6 my $list = $params{list};
158 5         3 my $args = $params{args};
159 5         6 my $order = $params{order};
160              
161 5         6 my $class = shift @$list;
162              
163 3         5 push @{$params{order}} => 'Test::Stream::Plugin::Class'
164 5 100       11 unless $args->{'Test::Stream::Plugin::Class'};
165              
166 5         13 $args->{'Test::Stream::Plugin::Class'} = [$class];
167             }
168              
169             sub opt_skip_without {
170 4     4 0 16 shift;
171 4         11 my %params = @_;
172 4         5 my $list = $params{list};
173 4         5 my $args = $params{args};
174 4         2 my $order = $params{order};
175              
176 4         5 my $class = shift @$list;
177              
178 3         6 push @{$params{order}} => 'Test::Stream::Plugin::SkipWithout'
179 4 100       9 unless $args->{'Test::Stream::Plugin::SkipWithout'};
180              
181 4   100     16 $args->{'Test::Stream::Plugin::SkipWithout'} ||= [];
182 4         3 push @{$args->{'Test::Stream::Plugin::SkipWithout'}} => $class;
  4         9  
183             }
184              
185             sub opt_srand {
186 2     2 0 16 shift;
187 2         7 my %params = @_;
188 2         2 my $list = $params{list};
189 2         2 my $args = $params{args};
190 2         3 my $order = $params{order};
191              
192 2         3 my $seed = shift @$list;
193              
194 1         2 push @{$params{order}} => 'Test::Stream::Plugin::SRand'
195 2 100       5 unless $args->{'Test::Stream::Plugin::SRand'};
196              
197 2         5 $args->{'Test::Stream::Plugin::SRand'} = [$seed];
198             }
199              
200             1;
201              
202             __END__