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   118983 use 5.012;
  34         128  
3 34     34   199 use strict;
  34         84  
  34         858  
4 34     34   220 use warnings;
  34         84  
  34         1196  
5 34     34   14688 use Data::Dumper; # DEBUG
  34         165414  
  34         2776  
6              
7 34     34   257 use Carp qw(croak);
  34         73  
  34         1831  
8 34     34   31455 use Keyword::Declare; # {debug=>1};
  34         4220020  
  34         356  
9 34     34   26045 use List::Util::MaybeXS qw(all);
  34         21830  
  34         2596  
10 34     34   289 use Scalar::Util qw(looks_like_number reftype);
  34         80  
  34         1986  
11              
12 34     34   226 use vars;
  34         81  
  34         965  
13 34     34   197 use Import::Into;
  34         77  
  34         908  
14              
15 34     34   3478 use parent 'Exporter';
  34         2507  
  34         277  
16             our @EXPORT = qw( skip_these skip_next );
17              
18             our $VERSION = '0.001004'; # TRIAL
19              
20 34     34   3297 use constant { true => !!1, false => !!0 };
  34         77  
  34         14072  
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 104010 my ($hrOpts, $should_shift) = _opts($_[0]);
143 25 100       102 shift if $should_shift;
144 25 50       90 croak 'Need an options hash reference' unless ref $hrOpts eq 'HASH';
145 25         123 foreach(@_) {
146 40 100       133 if(_is_testnum) {
147 30         215 $hrOpts->{skip}->{$_} = true;
148             } else {
149 10         1201 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 46937 my ($hrOpts, $should_shift) = _opts($_[0]);
165 14 100       55 shift if $should_shift;
166 14 50       83 croak 'Need an options hash reference' unless ref $hrOpts eq 'HASH';
167 14         69 $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   5906 my $self = shift;
182 42         137 my $target = caller;
183 42         285 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       939 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         24 $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   261 no strict 'refs';
  34         75  
  34         2558  
  39         106  
203             croak "Test::OnlySome: ${target}::skip() not defined - I can't function! (Missing `use Test::More`?)"
204 39 100       82 unless (defined &{ $target . '::skip' });
  39         900  
205             }
206              
207             # Copy symbols listed in @EXPORT first. Ignore @_, which we are
208             # going to use for our own purposes below.
209 35         4720 $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   273 no strict 'refs';
  34         74  
  34         2575  
  35         110  
216 35         103 *{ $target . '::__TOS_all' } = \&all;
  35         185  
217             }
218              
219             # Create the variables we need in the target package
220 35         448 vars->import::into($target, qw($TEST_NUMBER_OS $TEST_ONLYSOME));
221              
222             # Initialize the variables unless they already have been
223 35         9126 my $hrTOS;
224             {
225 34     34   449 no strict 'refs';
  34         75  
  34         12514  
  35         94  
226 35         120 ${ $target . '::TEST_NUMBER_OS' } = 1 # tests start at 1, not 0
227 35 50       99 unless ${ $target . '::TEST_NUMBER_OS' };
  35         271  
228 35         108 ${ $target . '::TEST_ONLYSOME' } = {}
229 35 50       78 unless 'HASH' eq ref ${ $target . '::TEST_ONLYSOME' };
  35         169  
230 35         79 $hrTOS = ${ $target . '::TEST_ONLYSOME' };
  35         101  
231             };
232              
233 35 50       167 $hrTOS->{n} = 1 unless $hrTOS->{n};
234 35 50       148 $hrTOS->{skip} = {} unless $hrTOS->{skip};
235 35 50       433 $hrTOS->{verbose} = 0 unless $hrTOS->{verbose};
236              
237             # Check the arguments. Numeric arguments are tests to skip.
238 35         185 my $curr_keyword = '';
239 35         110 foreach(@_) {
240 35 100       111 if(/^skip$/) { $curr_keyword='skip'; next; }
  10         25  
  10         29  
241 25 50       61 if(/^verbose$/) { $curr_keyword='verbose'; next; }
  0         0  
  0         0  
242              
243 25 50       67 if ( $curr_keyword eq 'verbose' ) {
244 0         0 $hrTOS->{verbose} = !!$_;
245 0         0 next;
246             }
247              
248 25 50 33     87 if ( $curr_keyword eq 'skip' && _is_testnum ) {
249             #print STDERR "TOS skipping $_\n";
250 25         89 $hrTOS->{skip}->{$_} = true;
251 25         57 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       126 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         107  
327 0 50 50 251   0 keyword os(String? $debug_var, Var? $opts_name, Num? $N,
  0         0  
  0         0  
  35         573  
  251         24117925  
  251         1060  
  251         872  
328 0         0 Block|Statement $controlled)
  35         286  
  251         57545  
329 0         0 {
  251         13112  
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         10147  
  251         767  
332 0         0 # # TODO make this more robust.
  251         34664  
333 0         0  
  251         27164  
334             if(length($debug_var)) {
335 0         0 no strict 'refs';
  0         0  
  251         6216  
  251         651  
336 0         0 $debug_var =~ s/^['"]|['"]$//g; # $debug_var comes with quotes
  251         29006  
337 0         0 ${$debug_var} = {opts_var_name => $opts_name, code => $controlled,
  251         10062  
338             n => $N};
339 0         0 #print STDERR "# Stashed $controlled into `$debug_var`\n";
  0         0  
  251         5769  
  251         614  
340 0         0 #print STDERR Carp::ret_backtrace(); #join "\n", caller(0);
  251         69463  
341 0         0 }
  251         52563  
342              
343 0         0 # Get the options
  251         6351  
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       2510  
349 34     34   1570974 croak "Need options as a scalar variable - got $hrOptsName"
  34     34   86  
  34         12559  
  34         263  
  34         77  
  34         5327  
350 0         0 unless defined $hrOptsName && substr($hrOptsName, 0, 1) eq '$';
  18         156  
351 0         0  
  0         0  
  18         372  
  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       2095  
359             =head2 unimport
360              
361             Removes the L keyword definition.
362              
363 0 0 0     0 =cut
  251 50 33     2993  
364              
365 0     0   0 sub unimport {
  0         0  
366 0 0 0     0 unkeyword os;
  251 100       1446  
  0 0       0  
  0         0  
367 34         328 }
  35         315  
  0         0  
368 34     34   1208502  
  35         1604  
369 34     34   290 # }}}2
  34         10304  
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   2162 my $optsVarName = shift or croak 'Need an options-var name';
384 251 50       1364 my $code = shift or croak 'Need code';
385 251         1662 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         577 my $W = '->';
391 251         526 my $L = '{';
392 251         525 my $R = '}';
393              
394 251 100       1141 $N = "$optsVarName$W$L n $R // 1" unless $N;
395              
396 251         1815 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         3529 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   302 my $arg = shift // $_;
427 65   100     661 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   202 my $target = caller(1) or croak 'Could not find caller';
441 39         371 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       175 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         91  
  34         3357  
  19         52  
  19         34  
  19         114  
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   54 my $target = caller(1) or croak 'Could not find caller';
462 34     34   231 return do { no strict 'refs'; ${ "$target" . '::TEST_NUMBER_OS' } };
  34         81  
  34         11518  
  14         121  
  14         56  
  14         93  
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   8 my $kit = shift;
478             #print STDERR "Invoked from Test::Kit module $kit\n";
479              
480 3         9 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         43 $callpkg = caller($level);
487 21 50       1324 last unless $callpkg;
488 21 100       53 last if $callpkg eq $kit;
489             } #for levels
490              
491 3 50 33     23 if($callpkg && ($callpkg eq $kit)) {
492 3         7 ++$level;
493 3         10 $callpkg = caller($level);
494 3 50       265 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: #