File Coverage

blib/lib/Test/OnlySome.pm
Criterion Covered Total %
statement 171 216 79.1
branch 44 78 56.4
condition 9 22 40.9
subroutine 30 32 93.7
pod 2 2 100.0
total 256 350 73.1


line stmt bran cond sub pod time code
1             package Test::OnlySome;
2 34     34   120358 use 5.012;
  34         128  
3 34     34   208 use strict;
  34         92  
  34         874  
4 34     34   170 use warnings;
  34         68  
  34         1186  
5 34     34   14646 use Data::Dumper; # DEBUG
  34         164637  
  34         2780  
6              
7 34     34   249 use Carp qw(croak);
  34         66  
  34         1855  
8 34     34   31910 use Keyword::Declare; # {debug=>1};
  34         4218697  
  34         371  
9 34     34   27382 use List::Util::MaybeXS qw(all);
  34         22430  
  34         2607  
10 34     34   276 use Scalar::Util qw(looks_like_number reftype);
  34         75  
  34         2043  
11              
12 34     34   230 use vars;
  34         74  
  34         961  
13 34     34   197 use Import::Into;
  34         81  
  34         907  
14              
15 34     34   3515 use parent 'Exporter';
  34         2601  
  34         275  
16             our @EXPORT = qw( skip_these skip_next );
17              
18             our $VERSION = '0.001005';
19              
20 34     34   3282 use constant { true => !!1, false => !!0 };
  34         82  
  34         14432  
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             sub _have;
125             # }}}3
126             # Caller-facing routines {{{1
127              
128             =head1 EXPORTS
129              
130             =head2 skip_these
131              
132             A convenience function to fill in C<< $hashref_options->{skip} >>.
133              
134             skip_these $hashref_options, 1, 2;
135             # Skip tests 1 and 2
136             skip_these 1, 2;
137             # If you are using implicit configuration
138              
139             =cut
140              
141             sub skip_these {
142 25     25 1 109111 my ($hrOpts, $should_shift) = _opts($_[0]);
143 25 100       106 shift if $should_shift;
144 25 50       98 croak 'Need an options hash reference' unless ref $hrOpts eq 'HASH';
145 25         113 foreach(@_) {
146 40 100       108 if(_is_testnum) {
147 30         208 $hrOpts->{skip}->{$_} = true;
148             } else {
149 10         1308 croak "'$_' is not a valid test number";
150             }
151             }
152             } #skip_these()
153              
154             =head2 skip_next
155              
156             Another convenience function: Mark the next test to be skipped. Example:
157              
158             skip_next;
159             os ok(0, 'This one will be skipped');
160              
161             =cut
162              
163             sub skip_next {
164 14     14 1 50540 my ($hrOpts, $should_shift) = _opts($_[0]);
165 14 100       60 shift if $should_shift;
166 14 50       54 croak 'Need an options hash reference' unless ref $hrOpts eq 'HASH';
167 14         68 $hrOpts->{skip}->{_nexttestnum()} = true;
168             } #skip_next()
169              
170             # }}}1
171             # Importer, and keyword definitions {{{1
172              
173             =head2 import
174              
175             The C sub defines the keywords so that they will be exported (!).
176             This is per L.
177              
178             =cut
179              
180 0         0 sub import {
181 42     42   6048 my $self = shift;
182 42         146 my $target = caller;
183 42         225 my $level = 1;
184              
185             #print STDERR "$self import into $target\n";
186             #_printtrace();
187              
188             # Special-case imports from Test::Kit, since Test::Kit doesn't know how
189             # to copy the custom keyword from its fake package to the ultimate caller.
190 42 100       986 if($target =~ m{^Test::Kit::Fake::(.*)::\Q$self\E$}) {
191 3         14 ($target, $level) = _escapekit($1);
192             #print STDERR "$self real target = $target at level $level\n";
193 3         27 $self->import::into($target); # Import into the real target
194 3         108 return; # *** EXIT POINT ***
195             }
196              
197             # Sanity check - e.g., `perl -MTest::OnlySome -E `os ok(1);` will
198             # die because skip() isn't defined. However, we don't require
199             # Test::More because there might be other packages that you are
200             # using that provide skip().
201             {
202 34     34   256 no strict 'refs';
  34         80  
  34         2552  
  39         118  
203             croak "Test::OnlySome: ${target}::skip() not defined - I can't function! (Missing `use Test::More`?)"
204 39 100       87 unless (defined &{ $target . '::skip' });
  39         835  
205             }
206              
207             # Copy symbols listed in @EXPORT first. Ignore @_, which we are
208             # going to use for our own purposes below.
209 35         4790 $self->export_to_level($level);
210              
211             # Put List::Util::all() in the caller's package so we can use it in
212             # the generated code. Otherwise, the caller would have to use
213             # List::Util manually.
214             {
215 34     34   210 no strict 'refs';
  34         78  
  34         2554  
  35         108  
216 35         106 *{ $target . '::__TOS_all' } = \&all;
  35         257  
217             }
218              
219             # Create the variables we need in the target package
220 35         461 vars->import::into($target, qw($TEST_NUMBER_OS $TEST_ONLYSOME));
221              
222             # Initialize the variables unless they already have been
223 35         9243 my $hrTOS;
224             {
225 34     34   376 no strict 'refs';
  34         75  
  34         11836  
  35         98  
226 35         124 ${ $target . '::TEST_NUMBER_OS' } = 1 # tests start at 1, not 0
227 35 50       84 unless ${ $target . '::TEST_NUMBER_OS' };
  35         201  
228 35         104 ${ $target . '::TEST_ONLYSOME' } = {}
229 35 50       77 unless 'HASH' eq ref ${ $target . '::TEST_ONLYSOME' };
  35         169  
230 35         79 $hrTOS = ${ $target . '::TEST_ONLYSOME' };
  35         104  
231             };
232              
233 35 50       184 $hrTOS->{n} = 1 unless $hrTOS->{n};
234 35 50       161 $hrTOS->{skip} = {} unless $hrTOS->{skip};
235 35 50       383 $hrTOS->{verbose} = 0 unless $hrTOS->{verbose};
236              
237             # Check the arguments. Numeric arguments are tests to skip.
238 35         165 my $curr_keyword = '';
239 35         112 foreach(@_) {
240 35 100       110 if(/^skip$/) { $curr_keyword='skip'; next; }
  10         25  
  10         32  
241 25 50       58 if(/^verbose$/) { $curr_keyword='verbose'; next; }
  0         0  
  0         0  
242              
243 25 50       78 if ( $curr_keyword eq 'verbose' ) {
244 0         0 $hrTOS->{verbose} = !!$_;
245 0         0 next;
246             }
247              
248 25 50 33     86 if ( $curr_keyword eq 'skip' && _is_testnum ) {
249             #print STDERR "TOS skipping $_\n";
250 25         82 $hrTOS->{skip}->{$_} = true;
251 25         51 next;
252             }
253              
254 0 0       0 croak "Test::OnlySome: I can't understand argument '$_'" .
255             ($curr_keyword ? " to keyword '$curr_keyword'" : '');
256             } # foreach arg
257              
258 35 50       137 if($hrTOS->{verbose}) {
259 0         0 my $msg = "# Test::OnlySome $VERSION loading\nConfig:\n" .
260             Dumper($hrTOS);
261 0         0 $msg =~ s/^/# /gm;
262 0         0 print STDERR $msg;
263             }
264              
265             # `os` keyword - mark each test-calling statement this way {{{2
266              
267             =head2 os
268              
269             Keyword C marks a statement that should be excuted Bnly Bome of
270             the time. Example:
271              
272             os 'main::debug' $hrOpts ok 1,'Something';
273             # Run "ok 1,'Something'" if hashref $hrOpts indicates.
274             # Save debug information into $main::debug.
275              
276             Syntax:
277              
278             os ['debug::variable::name'] [$hashref_options] [test_count]
279              
280             =over
281              
282             =item *
283              
284             C<$debug::variable::name> will be assigned at compilation time. If specified,
285             the given package variable will be filled in with the L
286             parse of the os invocation.
287              
288             =item *
289              
290             C<$hashref_options> will be accessed at runtime. If it is not given,
291             L will be used instead.
292              
293             =item *
294              
295             C must be a numeric literal, if present. If it is given,
296             it will be used instead of the number of tests specified in
297             C<< $hashref_options->{n} >>.
298              
299             =back
300              
301             =head3 Cautions
302              
303             =over
304              
305             =item *
306              
307             The given statement or block will be run in its own lexical scope,
308             not in the caller's scope.
309              
310             =item *
311              
312             If you use C<< test_count>1 >>, the whole block will be skipped only if
313             every test in the block is marked to be skipped. So, for example,
314              
315             os 2 { ok(1); ok(0); }
316              
317             will still run the C even if it was marked to be skipped if
318             the C was not marked to be skipped.
319              
320             =back
321              
322             I recommend that, when using L, you always use
323             C<< test_count == 1 >>.
324              
325             =cut
326 35         114  
327 0 50 50 251   0 keyword os(String? $debug_var, Var? $opts_name, Num? $N,
  0         0  
  0         0  
  35         592  
  251         24175843  
  251         1040  
  251         979  
328 0         0 Block|Statement $controlled)
  35         297  
  251         58057  
329 0         0 {
  251         13091  
330             # At this point, caller() is in Keyword::Declare.
331 0         0 #my $target = caller(2); # Skip past Keyword::Declare's code.
  0         0  
  251         10186  
  251         695  
332 0         0 # # TODO make this more robust.
  251         34409  
333 0         0  
  251         27282  
334             if(length($debug_var)) {
335 0         0 no strict 'refs';
  0         0  
  251         6209  
  251         653  
336 0         0 $debug_var =~ s/^['"]|['"]$//g; # $debug_var comes with quotes
  251         28732  
337 0         0 ${$debug_var} = {opts_var_name => $opts_name, code => $controlled,
  251         10700  
338             n => $N};
339 0         0 #print STDERR "# Stashed $controlled into `$debug_var`\n";
  0         0  
  251         5845  
  251         639  
340 0         0 #print STDERR Carp::ret_backtrace(); #join "\n", caller(0);
  251         70519  
341 0         0 }
  251         52711  
342              
343 0         0 # Get the options
  251         6520  
344             my $hrOptsName = length($opts_name) ? $opts_name : '$TEST_ONLYSOME';
345              
346             # print STDERR "os: Options in $hrOptsName\n";
347             # _printtrace();
348 0 0       0  
  251 100       2555  
349 34     34   1570727 croak "Need options as a scalar variable - got $hrOptsName"
  34     34   95  
  34         12807  
  34         277  
  34         95  
  34         5312  
350 0         0 unless defined $hrOptsName && substr($hrOptsName, 0, 1) eq '$';
  18         165  
351 0         0  
  0         0  
  18         376  
  18         116  
352             return _gen($hrOptsName, $controlled, length($N) ? $N : undef);
353             } # os() }}}2
354              
355             } # import()
356              
357             # Unimport {{{2
358 0 0       0  
  251 100       2079  
359             =head2 unimport
360              
361             Removes the L keyword definition.
362              
363 0 0 0     0 =cut
  251 50 33     2974  
364              
365 0     0   0 sub unimport {
  0         0  
366 0 0 0     0 unkeyword os;
  251 100       1468  
  0 0       0  
  0         0  
367 34         290 }
  35         354  
  0         0  
368 34     34   1210429  
  35         1741  
369 34     34   298 # }}}2
  34         10013  
370             # }}}1
371             # Implementation of keywords (macro), and internal helpers {{{1
372              
373             =head1 INTERNALS
374              
375             =head2 _gen
376              
377             This routine generates source code that, at runtime, will execute a given
378             only-some test.
379              
380             =cut
381              
382             sub _gen {
383 251 50   251   2250 my $optsVarName = shift or croak 'Need an options-var name';
384 251 50       1362 my $code = shift or croak 'Need code';
385 251         1699 my $N = shift;
386              
387             # 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         603 my $W = '->';
391 251         575 my $L = '{';
392 251         564 my $R = '}';
393              
394 251 100       1163 $N = "$optsVarName$W$L n $R // 1" unless $N;
395              
396 251         1852 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         3526 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   293 my $arg = shift // $_;
427 65   100     680 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   172 my $target = caller(1) or croak 'Could not find caller';
441 39         408 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       187 return ($arg, true) if ref $arg eq 'HASH';
448              
449             # Implicit config: find the caller's package and get $TEST_ONLYSOME
450 34     34   389 return do { no strict 'refs'; (${ "$target" . '::TEST_ONLYSOME' }, false) };
  34         89  
  34         3575  
  19         54  
  19         35  
  19         131  
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   53 my $target = caller(1) or croak 'Could not find caller';
462 34     34   248 return do { no strict 'refs'; ${ "$target" . '::TEST_NUMBER_OS' } };
  34         94  
  34         12087  
  14         119  
  14         45  
  14         88  
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         7 my $level;
481              
482             my $callpkg;
483              
484             # Find the caller of $kit, and import directly there.
485 3         7 for($level=0; 1; ++$level) {
486 21         44 $callpkg = caller($level);
487 21 50       967 last unless $callpkg;
488 21 100       60 last if $callpkg eq $kit;
489             } #for levels
490              
491 3 50 33     27 if($callpkg && ($callpkg eq $kit)) {
492 3         5 ++$level;
493 3         12 $callpkg = caller($level);
494 3 50       264 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: #