File Coverage

blib/lib/Test/OnlySome.pm
Criterion Covered Total %
statement 158 191 82.7
branch 39 70 55.7
condition 11 26 42.3
subroutine 30 32 93.7
pod 2 2 100.0
total 240 321 74.7


line stmt bran cond sub pod time code
1             package Test::OnlySome;
2 34     34   100980 use 5.012;
  34         229  
3 34     34   182 use strict;
  34         75  
  34         1232  
4 34     34   172 use warnings;
  34         67  
  34         1759  
5 34     34   12665 use Data::Dumper; # DEBUG
  34         128645  
  34         2516  
6              
7 34     34   239 use Carp qw(croak);
  34         87  
  34         1725  
8 34     34   26953 use Keyword::Declare; # {debug=>1};
  34         2736452  
  34         392  
9 34     34   21842 use List::Util::MaybeXS qw(all);
  34         18703  
  34         2264  
10 34     34   229 use Scalar::Util qw(looks_like_number);
  34         67  
  34         1573  
11              
12 34     34   199 use vars;
  34         71  
  34         923  
13 34     34   179 use Import::Into;
  34         69  
  34         818  
14              
15 34     34   2879 use parent 'Exporter';
  34         2184  
  34         229  
16             our @EXPORT = qw( skip_these skip_next );
17              
18             our $VERSION = '0.001003';
19              
20 34     34   2948 use constant { true => !!1, false => !!0 };
  34         67  
  34         12586  
21              
22             # TODO move $TEST_NUMBER_OS into the options structure.
23              
24             # Docs, including osprove and T::OS::RerunFailed example {{{3
25              
26             =head1 NAME
27              
28             Test::OnlySome - Skip individual tests in a *.t file
29              
30             =head1 INSTALLATION
31              
32             Easiest: install C if you don't have it - see
33             L. Then run
34             C.
35              
36             Manually: clone or untar into a working directory. Then, in that directory,
37              
38             perl Makefile.PL
39             make
40             make test
41              
42             ... and if all the tests pass,
43              
44             make install
45              
46             If some of the tests fail, please check the issues and file a new one if
47             no one else has reported the problem yet.
48              
49             =head1 SYNOPSIS
50              
51             Suppose you are testing a C. If it succeeded last
52             time, you don't want to take the time to test it again. In your test file
53             (e.g., C):
54              
55             use Test::More tests => 2;
56             use Test::OnlySome::RerunFailed; # rerun only failed tests
57             os ok(long_running_function()); # "os" marks tests that might be skipped
58             os ok(0, 'fails');
59              
60             At the command line, supposing the function passes the test:
61              
62             $ osprove -lv
63             ...
64             ok 1 - passes
65             not ok 2 - fails
66             ...
67             Result: FAIL
68              
69             This creates C<.onlysome.yml>, which holds the test results from C.
70             Then, re-run:
71              
72             $ osprove -lv
73             ...
74             ok 1 # skip Test::OnlySome: you asked me to skip this
75             not ok 2 - fails
76             ...
77              
78             Since test 1 passed the first time, it was skipped the second time.
79              
80             You don't have to use L. You can directly
81             use C, and you can decide in some other way which tests
82             you want to skip.
83              
84             The argument to L can be a statement or block, and it doesn't have to
85             be a L test. You can wrap long-running tests in functions,
86             and apply L to those functions.
87              
88             Please note that L can take a C argument, e.g., if there
89             are multiple tests in a block. The whole block will be skipped if and only
90             if all the tests in that block are skipped. Otherwise, the whole block
91             will be rerun. The moral? Use a C of 1 for all tests run under
92             L and you won't be surprised.
93              
94             =head1 MARKING TESTS
95              
96             You can pick which tests to skip using implicit or explicit configuration.
97             Explicit configuration uses a hashref:
98              
99             my $opts = { skip => { 2=>true } };
100              
101             os $opts ok(1, 'This will run'); # Single statement OK
102              
103             os $opts { # Block also OK
104             ok(0, 'This will be skipped'); # Skipped since it's test 2
105             };
106              
107             Implicit configuration uses a hashref in the package variable C<$TEST_ONLYSOME>,
108             which Test::OnlySome creates in your package when you C it:
109              
110             $TEST_ONLYSOME->{skip} = { 2=>true };
111             os ok(1, 'Test 1'); # This one runs
112             os ok(0, 'Test 2 - should be skipped'); # Skipped since it's test 2
113              
114             =cut
115              
116             # }}}3
117             # Forward declarations of internal subs {{{3
118             sub _gen;
119             sub _is_testnum;
120             sub _opts;
121             sub _nexttestnum;
122             sub _escapekit;
123             sub _printtrace;
124             # }}}3
125             # Caller-facing routines {{{1
126              
127             =head1 EXPORTS
128              
129             =head2 skip_these
130              
131             A convenience function to fill in C<< $hashref_options->{skip} >>.
132              
133             skip_these $hashref_options, 1, 2;
134             # Skip tests 1 and 2
135             skip_these 1, 2;
136             # If you are using implicit configuration
137              
138             =cut
139              
140             sub skip_these {
141 25     25 1 93483 my ($hrOpts, $should_shift) = _opts($_[0]);
142 25 100       82 shift if $should_shift;
143 25 50       85 croak 'Need an options hash reference' unless ref $hrOpts eq 'HASH';
144 25         77 foreach(@_) {
145 40 100       99 if(_is_testnum) {
146 30         127 $hrOpts->{skip}->{$_} = true;
147             } else {
148 10         1048 croak "'$_' is not a valid test number";
149             }
150             }
151             } #skip_these()
152              
153             =head2 skip_next
154              
155             Another convenience function: Mark the next test to be skipped. Example:
156              
157             skip_next;
158             os ok(0, 'This one will be skipped');
159              
160             =cut
161              
162             sub skip_next {
163 14     14 1 43560 my ($hrOpts, $should_shift) = _opts($_[0]);
164 14 100       49 shift if $should_shift;
165 14 50       53 croak 'Need an options hash reference' unless ref $hrOpts eq 'HASH';
166 14         53 $hrOpts->{skip}->{_nexttestnum()} = true;
167             } #skip_next()
168              
169             # }}}1
170             # Importer, and keyword definitions {{{1
171              
172             =head2 import
173              
174             The C sub defines the keywords so that they will be exported (!).
175             This is per L.
176              
177             =cut
178              
179 0         0 sub import {
180 42     42   5212 my $self = shift;
181 42         123 my $target = caller;
182 42         207 my $level = 1;
183              
184             #print STDERR "$self import into $target\n";
185             #_printtrace();
186              
187             # Special-case imports from Test::Kit, since Test::Kit doesn't know how
188             # to copy the custom keyword from its fake package to the ultimate caller.
189 42 100       791 if($target =~ m{^Test::Kit::Fake::(.*)::\Q$self\E$}) {
190 3         9 ($target, $level) = _escapekit($1);
191             #print STDERR "$self real target = $target at level $level\n";
192 3         23 $self->import::into($target); # Import into the real target
193 3         147 return; # *** EXIT POINT ***
194             }
195              
196             # Sanity check - e.g., `perl -MTest::OnlySome -E `os ok(1);` will
197             # die because skip() isn't defined. However, we don't require
198             # Test::More because there might be other packages that you are
199             # using that provide skip().
200             {
201 34     34   226 no strict 'refs';
  34         76  
  34         2262  
  39         113  
202             croak "Test::OnlySome: ${target}::skip() not defined - I can't function! (Missing `use Test::More`?)"
203 39 100       74 unless (defined &{ $target . '::skip' });
  39         713  
204             }
205              
206             # Copy symbols listed in @EXPORT first. Ignore @_, which we are
207             # going to use for our own purposes below.
208 35         4291 $self->export_to_level($level);
209              
210             # Put List::Util::all() in the caller's package so we can use it in
211             # the generated code. Otherwise, the caller would have to use
212             # List::Util manually.
213             {
214 34     34   177 no strict 'refs';
  34         59  
  34         2208  
  35         98  
215 35         97 *{ $target . '::__TOS_all' } = \&all;
  35         178  
216             }
217              
218             # Create the variables we need in the target package
219 35         426 vars->import::into($target, qw($TEST_NUMBER_OS $TEST_ONLYSOME));
220              
221             # Initialize the variables unless they already have been
222 35         7981 my $hrTOS;
223             {
224 34     34   288 no strict 'refs';
  34         62  
  34         10682  
  35         86  
225 35         114 ${ $target . '::TEST_NUMBER_OS' } = 1 # tests start at 1, not 0
226 35 50       72 unless ${ $target . '::TEST_NUMBER_OS' };
  35         179  
227 35         95 ${ $target . '::TEST_ONLYSOME' } = {}
228 35 50       70 unless 'HASH' eq ref ${ $target . '::TEST_ONLYSOME' };
  35         183  
229 35         70 $hrTOS = ${ $target . '::TEST_ONLYSOME' };
  35         100  
230             };
231              
232 35 50       172 $hrTOS->{n} = 1 unless $hrTOS->{n};
233 35 50       160 $hrTOS->{skip} = {} unless $hrTOS->{skip};
234 35 50       417 $hrTOS->{verbose} = 0 unless $hrTOS->{verbose};
235              
236             # Check the arguments. Numeric arguments are tests to skip.
237 35         179 my $curr_keyword = '';
238 35         114 foreach(@_) {
239 35 100       106 if(/^skip$/) { $curr_keyword='skip'; next; }
  10         25  
  10         30  
240 25 50       61 if(/^verbose$/) { $curr_keyword='verbose'; next; }
  0         0  
  0         0  
241              
242 25 50       59 if ( $curr_keyword eq 'verbose' ) {
243 0         0 $hrTOS->{verbose} = !!$_;
244 0         0 next;
245             }
246              
247 25 50 33     93 if ( $curr_keyword eq 'skip' && _is_testnum ) {
248             #print STDERR "TOS skipping $_\n";
249 25         106 $hrTOS->{skip}->{$_} = true;
250 25         69 next;
251             }
252              
253 0 0       0 croak "Test::OnlySome: I can't understand argument '$_'" .
254             ($curr_keyword ? " to keyword '$curr_keyword'" : '');
255             } # foreach arg
256              
257 35 50       127 if($hrTOS->{verbose}) {
258 0         0 my $msg = "# Test::OnlySome $VERSION loading\nConfig:\n" .
259             Dumper($hrTOS);
260 0         0 $msg =~ s/^/# /gm;
261 0         0 print STDERR $msg;
262             }
263              
264             # `os` keyword - mark each test-calling statement this way {{{2
265              
266             =head2 os
267              
268             Keyword C marks a statement that should be excuted Bnly Bome of
269             the time. Example:
270              
271             os 'main::debug' $hrOpts ok 1,'Something';
272             # Run "ok 1,'Something'" if hashref $hrOpts indicates.
273             # Save debug information into $main::debug.
274              
275             Syntax:
276              
277             os ['debug::variable::name'] [$hashref_options] [test_count]
278              
279             =over
280              
281             =item *
282              
283             C<$debug::variable::name> will be assigned at compilation time. If specified,
284             the given package variable will be filled in with the L
285             parse of the os invocation.
286              
287             =item *
288              
289             C<$hashref_options> will be accessed at runtime. If it is not given,
290             L will be used instead.
291              
292             =item *
293              
294             C must be a numeric literal, if present. If it is given,
295             it will be used instead of the number of tests specified in
296             C<< $hashref_options->{n} >>.
297              
298             =back
299              
300             =head3 Cautions
301              
302             =over
303              
304             =item *
305              
306             The given statement or block will be run in its own lexical scope,
307             not in the caller's scope.
308              
309             =item *
310              
311             If you use C<< test_count>1 >>, the whole block will be skipped only if
312             every test in the block is marked to be skipped. So, for example,
313              
314             os 2 { ok(1); ok(0); }
315              
316             will still run the C even if it was marked to be skipped if
317             the C was not marked to be skipped.
318              
319             =back
320              
321             I recommend that, when using L, you always use
322             C<< test_count == 1 >>.
323              
324             =cut
325 35         129  
326 35 50 50     582 keyword os(String? $debug_var, Var? $opts_name, Num? $N,
327 35         268 Block|Statement $controlled)
328             {
329              
330             # At this point, caller() is in Keyword::Declare.
331 251     251   21414487 #my $target = caller(2); # Skip past Keyword::Declare's code.
  251         813  
  251         559  
  251         579  
  251         519  
  251         463  
332             # # TODO make this more robust.
333              
334             if(defined $debug_var) {
335             no strict 'refs';
336             $debug_var =~ s/^['"]|['"]$//g; # $debug_var comes with quotes
337 251 50       972 ${$debug_var} = {opts_var_name => $opts_name, code => $controlled,
338 34     34   1287816 n => $N};
  34         83  
  34         7254  
339 251         737 #print STDERR "# Stashed $controlled into `$debug_var`\n";
340 251         1613 #print STDERR Carp::ret_backtrace(); #join "\n", caller(0);
  251         1268  
341             }
342              
343             # Get the options
344             my $hrOptsName = $opts_name || '$TEST_ONLYSOME';
345              
346             # print STDERR "os: Options in $hrOptsName\n";
347 251   100     1306 # _printtrace();
348              
349             croak "Need options as a scalar variable - got $hrOptsName"
350             unless defined $hrOptsName && substr($hrOptsName, 0, 1) eq '$';
351              
352 251 50 33     1986 return _gen($hrOptsName, $controlled, $N);
353             } # os() }}}2
354              
355 251         1279 } # import()
356 35         362  
357             # Unimport {{{2
358 34     34   232  
359             =head2 unimport
360              
361             Removes the L keyword definition.
362 0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
363             =cut
364              
365 0     0   0 sub unimport {
  0         0  
366 0 0 0     0 unkeyword os;
  0         0  
367 0         0 }
368 0 0   34   0  
  34         1062580  
369 34     34   248 # }}}2
  34         69  
  34         4072  
  34         8594  
370 0         0 # }}}1
371 0         0 # Implementation of keywords (macro), and internal helpers {{{1
  0         0  
372              
373             =head1 INTERNALS
374              
375             =head2 _gen
376              
377             This routine generates source code that, at runtime, will execute a given
378 0   0     0 only-some test.
379              
380             =cut
381              
382             sub _gen {
383 0 0 0 251   0 my $optsVarName = shift or croak 'Need an options-var name';
  251 50       900  
384 251 50       893 my $code = shift or croak 'Need code';
385 251         583 my $N = shift;
386 0         0  
387 34         244 # Syntactic parts, so I don't have to disambiguate interpolation in the
388             # qq{} below from hash access in the generated code. Instead of
389             # $foo->{bar}, interpolations below use $foo$W$L bar $R.
390 251         524 my $W = '->';
391 251         567 my $L = '{';
392 251         582 my $R = '}';
393              
394 251 100       1202 $N = "$optsVarName$W$L n $R // 1" unless $N;
395              
396 251         1525 my $replacement = qq[
397             {
398             my \$__ntests = $N;
399             my \$__first_test_num = \$TEST_NUMBER_OS;
400             \$TEST_NUMBER_OS += \$__ntests;
401             my \$__skips = $optsVarName$W$L skip $R;
402             my \@__x=(\$__first_test_num .. (\$__first_test_num+\$__ntests-1));
403             # print STDERR 'Tests: ', join(', ', \@__x), "\\n";
404              
405             SKIP: {
406             skip 'Test::OnlySome: you asked me to skip this', \$__ntests
407             if __TOS_all { \$__skips$W$L \$_ $R } \@__x;
408              
409             $code
410             }
411             }
412             ];
413              
414             #print STDERR "$replacement\n"; # DEBUG
415 251         1055 return $replacement;
416              
417             } #_gen()
418              
419             =head2 _is_testnum
420              
421             Return True if the provided parameter, or C<$_>, is a valid test number.
422              
423             =cut
424              
425             sub _is_testnum {
426 65   66 65   274 my $arg = shift // $_;
427 65   100     643 return ($arg && !ref($arg) && looks_like_number($arg) && $arg >= 1);
428             } #_is_testnum()
429              
430             # `os`, skip*() helpers {{{2
431              
432             =head2 _opts
433              
434             Returns the appropriate options hashref, and an indication of whether
435             the caller should C (true for explicit config). Call as C<_opts($_[0])>.
436              
437             =cut
438              
439             sub _opts {
440 39 50   39   177 my $target = caller(1) or croak 'Could not find caller';
441 39         316 my $arg = shift;
442              
443             # print STDERR "_opts: Options in ", (ref $arg eq 'HASH' ?
444             # 'provided hashref' : "\$${target}::TEST_ONLYSOME\n");
445             # _printtrace();
446              
447 39 100       193 return ($arg, true) if ref $arg eq 'HASH';
448              
449             # Implicit config: find the caller's package and get $TEST_ONLYSOME
450 34     34   394 return do { no strict 'refs'; (${ "$target" . '::TEST_ONLYSOME' }, false) };
  34         71  
  34         3059  
  19         28  
  19         46  
  19         110  
451              
452             } #_opts()
453              
454             =head2 _nexttestnum
455              
456             Gets the caller's current C<$TEST_NUMBER_OS> value.
457              
458             =cut
459              
460             sub _nexttestnum {
461 14 50   14   47 my $target = caller(1) or croak 'Could not find caller';
462 34     34   202 return do { no strict 'refs'; ${ "$target" . '::TEST_NUMBER_OS' } };
  34         76  
  34         10262  
  14         107  
  14         48  
  14         91  
463             } #_nexttestnum()
464              
465             # }}}2
466             # `use` helpers {{{2
467              
468             =head2 _escapekit
469              
470             Find the caller that is using a Test::Kit package to use this module. This
471             helps us import the keyword into the right module.
472              
473             =cut
474              
475             sub _escapekit {
476             # Find the real target package, in case we were called from Test::Kit
477 3     3   9 my $kit = shift;
478             #print STDERR "Invoked from Test::Kit module $kit\n";
479              
480 3         6 my $level;
481              
482             my $callpkg;
483              
484             # Find the caller of $kit, and import directly there.
485 3         5 for($level=0; 1; ++$level) {
486 21         41 $callpkg = caller($level);
487 21 50       884 last unless $callpkg;
488 21 100       45 last if $callpkg eq $kit;
489             } #for levels
490              
491 3 50 33     21 if($callpkg && ($callpkg eq $kit)) {
492 3         7 ++$level;
493 3         9 $callpkg = caller($level);
494 3 50       230 return ($callpkg, $level) if $callpkg;
495             }
496              
497 0           die "Could not find the module that invoked Test::Kit module $kit";
498             } #_escapekit()
499              
500             =head2 _printtrace
501              
502             Print a full stack trace
503              
504             =cut
505              
506             sub _printtrace {
507             # Print full stack trace
508 0     0     my @callers;
509 0           for(my $i=0; 1; ++$i) {
510             ## 0 1 2 3 4
511             #my ($package, $filename, $line, $subroutine, $hasargs,
512             ## 5 6 7 8 9 10
513             #$wantarray, $evaltext, $is_require, $hints, $bitmask, $hinthash)
514             #= caller($i);
515 0           push @callers, [caller($i)];
516 0 0         last unless $callers[-1]->[0];
517             }
518 0           print Dumper(\@callers), "\n";
519             }
520              
521             # }}}2
522             # }}}1
523             # More docs {{{3
524             =head1 VARIABLES
525              
526             =head2 C<$TEST_NUMBER_OS>
527              
528             Exported into the caller's package. A sequential numbering of tests that
529             have been run under L.
530              
531             =head2 C<$TEST_ONLYSOME>
532              
533             Exported into the caller's package. A hashref of options, of the same format
534             as an explicit-config hashref. Keys are:
535              
536             =over
537              
538             =item * C
539              
540             The number of tests in each L call.
541              
542             =item * C
543              
544             A hashref of tests to skip. That hashref is keyed by test number; any truthy
545             value indicates that the L call beginning with that test number
546             should be skipped.
547              
548             B The test numbers used by L are B those run under L.
549             For example:
550              
551             skip_these 2;
552             os ok(1); # os's test 1
553             ok(0); # oops - not skipped - no "os"
554             os ok(0); # this one is skipped - os's test 2
555              
556             =back
557              
558             =head1 AUTHOR
559              
560             Christopher White, C<< >>
561              
562             =head1 BUGS
563              
564             Please report any bugs or feature requests on GitHub, at
565             L.
566              
567             =head1 SUPPORT
568              
569             You can find documentation for this module with the perldoc command.
570              
571             perldoc Test::OnlySome
572              
573             You can also look for information at:
574              
575             =over 4
576              
577             =item * The GitHub repository
578              
579             L
580              
581             =item * AnnoCPAN: Annotated CPAN documentation
582              
583             L
584              
585             =item * CPAN Ratings
586              
587             L
588              
589             =item * Search CPAN
590              
591             L
592              
593             =item * RT: CPAN's request tracker
594              
595             L
596              
597             =back
598              
599             This module is versioned with L,
600             but in the backward-compatible Perl format. So version C<0.001003> is
601             semantic version C<0.1.3>.
602              
603             =cut
604              
605             # }}}3
606             # License {{{3
607              
608             =head1 LICENSE AND COPYRIGHT
609              
610             Copyright 2018 Christopher White.
611              
612             This program is distributed under the MIT (X11) License:
613             L
614              
615             Permission is hereby granted, free of charge, to any person
616             obtaining a copy of this software and associated documentation
617             files (the "Software"), to deal in the Software without
618             restriction, including without limitation the rights to use,
619             copy, modify, merge, publish, distribute, sublicense, and/or sell
620             copies of the Software, and to permit persons to whom the
621             Software is furnished to do so, subject to the following
622             conditions:
623              
624             The above copyright notice and this permission notice shall be
625             included in all copies or substantial portions of the Software.
626              
627             THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
628             EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
629             OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
630             NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
631             HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
632             WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
633             FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
634             OTHER DEALINGS IN THE SOFTWARE.
635              
636             =cut
637              
638             # }}}3
639             1;
640              
641             # vi: set fdm=marker fdl=2: #