File Coverage

inc/My/Module/Test.pm
Criterion Covered Total %
statement 256 285 89.8
branch 92 126 73.0
condition 33 68 48.5
subroutine 41 42 97.6
pod 22 24 91.6
total 444 545 81.4


line stmt bran cond sub pod time code
1             package My::Module::Test;
2              
3 5     5   262349 use strict;
  5         45  
  5         137  
4 5     5   24 use warnings;
  5         13  
  5         133  
5              
6 5     5   24 use Exporter;
  5         9  
  5         271  
7              
8             our @ISA = ( qw{ Exporter } );
9              
10 5     5   2688 use PPIx::Regexp;
  5         18  
  5         235  
11 5     5   33 use PPIx::Regexp::Constant qw{ INFINITY };
  5         11  
  5         233  
12 5     5   2635 use PPIx::Regexp::Dumper;
  5         14  
  5         160  
13 5     5   36 use PPIx::Regexp::Element;
  5         12  
  5         128  
14 5     5   28 use PPIx::Regexp::Tokenizer;
  5         11  
  5         162  
15 5     5   33 use PPIx::Regexp::Util qw{ __choose_tokenizer_class __instance };
  5         19  
  5         360  
16 5     5   37 use Scalar::Util qw{ looks_like_number refaddr };
  5         10  
  5         244  
17 5     5   2144 use Test::More 0.88;
  5         200732  
  5         43  
18              
19             our $VERSION = '0.087_01';
20              
21 5     5   1676 use constant ARRAY_REF => ref [];
  5         12  
  5         20084  
22              
23             our @EXPORT_OK = qw{
24             builder
25             cache_count
26             choose
27             klass
28             cmp_ok
29             content
30             count
31             diag
32             different
33             done_testing
34             dump_result
35             equals
36             error
37             fail
38             false
39             finis
40             format_want
41             invocant
42             is
43             navigate
44             note
45             ok
46             parse
47             pass
48             plan
49             ppi
50             raw_width
51             result
52             replace_characters
53             skip
54             tokenize
55             true
56             value
57             width
58             INFINITY
59             };
60              
61             our @EXPORT = @EXPORT_OK; ## no critic (ProhibitAutomaticExportation)
62              
63             push @EXPORT_OK, qw{ __quote };
64              
65             my (
66             $initial_class, # For static methods; set by parse() or tokenize()
67             $kind, # of thing; set by parse() or tokenize()
68             $nav, # Navigation used to get to current object, as a
69             # string.
70             $obj, # Current object:
71             # PPIx::Regexp::Tokenizer if set by tokenize(),
72             # PPIx::Regexp if set by parse(), or
73             # PPIx::Regexp::Element if set by navigate().
74             $parse, # Result of parse:
75             # array ref if set by tokenize(), or
76             # PPIx::Regexp object if set by parse()
77             %replace_characters, # Troublesome characters replaced in output
78             # before testing
79             $result, # Operation result.
80             );
81              
82             sub builder {
83 1     1 1 111 return Test::More->builder();
84             }
85              
86             sub cache_count {
87 8     8 1 825 my ( $expect ) = @_;
88 8 100       31 defined $expect or $expect = 0;
89 8         25 $obj = undef;
90 8         16 $parse = undef;
91 8         48 _pause();
92 8         203 $result = PPIx::Regexp->__cache_size();
93             # cperl does not seem to like goto &xxx; it throws a deep recursion
94             # error if you do it enough times.
95 8         71 $Test::Builder::Level = $Test::Builder::Level + 1;
96 8         134 return is( $result, $expect,
97             "Should be $expect leftover cache contents" );
98             }
99              
100             sub choose {
101 4683     4683 1 21323670 my @args = @_;
102 4683         9016 $obj = $parse;
103 4683         10235 return navigate( @args );
104             }
105              
106             sub klass {
107 4381     4381 1 965330 my ( $class ) = @_;
108 4381   66     11626 $result = ref $obj || $obj;
109             # cperl does not seem to like goto &xxx; it throws a deep recursion
110             # error if you do it enough times.
111 4381         5717 $Test::Builder::Level = $Test::Builder::Level + 1;
112 4381 100       7365 if ( defined $class ) {
113 4319 50       15401 my $rslt = isa_ok( $obj, $class, "$kind $nav" )
114             or diag " Instead, $kind $nav isa $result";
115 4319         7195180 return $rslt;
116             } else {
117 62   50     592 return is( ref $obj || undef, $class, "Class of $kind $nav" );
118             }
119             }
120              
121             sub content { ## no critic (RequireArgUnpacking)
122             # For some reason cperl seems to have no problem with this
123 3591     3591 1 252055 unshift @_, 'content';
124 3591         11603 goto &_method_result;
125             }
126              
127             sub count {
128 1382     1382 1 340011 my ( @args ) = @_;
129 1382         2821 my $expect = pop @args;
130             # cperl does not seem to like goto &xxx; it throws a deep recursion
131             # error if you do it enough times.
132 1382         2439 $Test::Builder::Level = $Test::Builder::Level + 1;
133 1382 100       7421 if ( ARRAY_REF eq ref $parse ) {
    100          
    50          
134 202         307 $result = @{ $parse };
  202         485  
135 202         893 return is( $result, $expect, "Expect $expect tokens" );
136             } elsif ( ARRAY_REF eq ref $obj ) {
137 559         851 $result = @{ $obj };
  559         1121  
138 559         2131 return is( $result, $expect, "Expect $expect tokens" );
139             } elsif ( $obj->can( 'children' ) ) {
140 621         1770 $result = $obj->children();
141 621         2648 return is( $result, $expect, "Expect $expect children" );
142             } else {
143 0         0 $result = $obj->can( 'children' );
144 0         0 return ok( $result, ref( $obj ) . "->can( 'children')" );
145             }
146             }
147              
148             sub different {
149 1     1 1 18 my @args = @_;
150 1 50       5 @args < 3 and unshift @args, $obj;
151 1         5 my ( $left, $right, $name ) = @args;
152             # cperl does not seem to like goto &xxx; it throws a deep recursion
153             # error if you do it enough times.
154 1         3 $Test::Builder::Level = $Test::Builder::Level + 1;
155 1 50 33     18 if ( ! defined $left && ! defined $right ) {
    50 33        
    50 33        
    0 0        
    0 0        
156 0         0 return ok( undef, $name );
157             } elsif ( ! defined $left || ! defined $right ) {
158 0         0 return ok( 1, $name );
159             } elsif ( ref $left && ref $right ) {
160 1         11 return ok( refaddr( $left ) != refaddr( $right ), $name );
161             } elsif ( ref $left || ref $right ) {
162 0         0 return ok( 1, $name );
163             } elsif ( looks_like_number( $left ) && looks_like_number( $right ) ) {
164 0         0 return ok( $left != $right, $name );
165             } else {
166 0         0 return ok( $left ne $right, $name );
167             }
168             }
169              
170             sub dump_result {
171 5     5 1 4864 my ( $opt, @args ) = _parse_constructor_args( { test => 1 }, @_ );
172 5 50 0     13 if ( $opt->{test} ) {
    0          
    0          
    0          
173 5         14 my ( $expect, $name ) = splice @args, -2;
174 5         27 my $got = PPIx::Regexp::Dumper->new( $obj, @args )->string();
175             # cperl does not seem to like goto &xxx; it throws a deep
176             # recursion error if you do it enough times.
177 5         38 $Test::Builder::Level = $Test::Builder::Level + 1;
178 5         18 return is( $got, $expect, $name );
179             } elsif ( __instance( $result, 'PPIx::Regexp::Tokenizer' ) ||
180             __instance( $result, 'PPIx::Regexp::Element' ) ) {
181 0         0 diag( PPIx::Regexp::Dumper->new( $obj, @args )->string() );
182 0         0 } elsif ( eval { require YAML; 1; } ) {
  0         0  
183 0         0 diag( "Result dump:\n", YAML::Dump( $result ) );
184 0         0 } elsif ( eval { require Data::Dumper; 1 } ) {
  0         0  
185 0         0 diag( "Result dump:\n", Data::Dumper::Dumper( $result ) );
186             } else {
187 0         0 diag( "Result dump unavailable.\n" );
188             }
189 0         0 return;
190             }
191              
192             sub equals {
193 19     19 1 139 my @args = @_;
194 19 100       50 @args < 3 and unshift @args, $obj;
195 19         35 my ( $left, $right, $name ) = @args;
196             # cperl does not seem to like goto &xxx; it throws a deep recursion
197             # error if you do it enough times.
198 19         30 $Test::Builder::Level = $Test::Builder::Level + 1;
199 19 100 66     113 if ( ! defined $left && ! defined $right ) {
    50 33        
    50 33        
    0 0        
    0 0        
200 11         30 return ok( 1, $name );
201             } elsif ( ! defined $left || ! defined $right ) {
202 0         0 return ok( undef, $name );
203             } elsif ( ref $left && ref $right ) {
204 8         32 return ok( refaddr( $left ) == refaddr( $right ), $name );
205             } elsif ( ref $left || ref $right ) {
206 0         0 return ok( undef, $name );
207             } elsif ( looks_like_number( $left ) && looks_like_number( $right ) ) {
208 0         0 return ok( $left == $right, $name );
209             } else {
210 0         0 return ok( $left eq $right, $name );
211             }
212             }
213              
214             sub error { ## no critic (RequireArgUnpacking)
215 19     19 0 86857 unshift @_, 'error';
216 19         73 goto &_method_result;
217             }
218              
219             sub false {
220 52     52 1 41358 my ( $method, $args ) = @_;
221 52 100       190 ARRAY_REF eq ref $args
222             or $args = [ $args ];
223 52         97 my $class = ref $obj;
224             # cperl does not seem to like goto &xxx; it throws a deep recursion
225             # error if you do it enough times.
226 52         78 $Test::Builder::Level = $Test::Builder::Level + 1;
227 52 50       259 if ( $obj->can( $method ) ) {
228 52         78 $result = $obj->$method( @{ $args } );
  52         164  
229 52         112 my $fmtd = _format_args( $args );
230 52         239 return ok( ! $result, "$class->$method$fmtd is false" );
231             } else {
232 0         0 $result = undef;
233 0         0 return ok( undef, "$class->$method() exists" );
234             }
235             }
236              
237             sub finis {
238 2     2 1 11074 $obj = $parse = $result = undef;
239 2         11 _pause();
240 2         52 $result = PPIx::Regexp::Element->__parent_keys();
241             # cperl does not seem to like goto &xxx; it throws a deep recursion
242             # error if you do it enough times.
243 2         11 $Test::Builder::Level = $Test::Builder::Level + 1;
244 2         37 return is( $result, 0, 'Should be no leftover objects' );
245             }
246              
247             sub format_want {
248 1078     1078 1 1751 my ( $want ) = @_;
249 1078 100       3968 return _format_args( $want, bare => ref $want ? 0 : 1 );
250             }
251              
252             sub invocant {
253 0     0 1 0 return $obj;
254             }
255              
256             {
257              
258             my %array = map { $_ => 1 } qw{
259             children delimiters finish schildren start tokens type
260             };
261              
262             sub navigate {
263 4738     4738 1 80378 my @args = @_;
264 4738         5995 my $scalar = 1;
265             @args > 1
266             and ARRAY_REF eq ref $args[-1]
267 595         3511 and @{ $args[-1] } == 0
268 4738 100 100     21910 and $array{$args[-2]}
      100        
      100        
269             and $scalar = 0;
270 4738         7850 my @nav = ();
271 4738         8855 while ( @args ) {
272 8443 100       21758 if ( __instance( $args[0], 'PPIx::Regexp::Element' ) ) {
    100          
273 9         26 $obj = shift @args;
274             } elsif ( ARRAY_REF eq ref $obj ) {
275 1562         2611 my $inx = shift @args;
276 1562         2630 push @nav, $inx;
277 1562         3887 $obj = $obj->[$inx];
278             } else {
279 6872         9651 my $method = shift @args;
280 6872         8673 my $args = shift @args;
281 6872 100       15676 ARRAY_REF eq ref $args
282             or $args = [ $args ];
283 6872         10190 push @nav, $method, $args;
284 6872 50       22729 $obj->can( $method ) or return;
285 6872 100 100     17621 if ( @args || $scalar ) {
286 6316 100       6380 $obj = $obj->$method( @{ $args } ) or return;
  6316         16498  
287             } else {
288 556         859 $obj = [ $obj->$method( @{ $args } ) ];
  556         2305  
289             }
290             }
291             }
292 4665         9491 $nav = __quote( @nav );
293 4665         36970 $nav =~ s/ ' ( \w+ ) ' , /$1 =>/smxg;
294 4665         13894 $nav =~ s/ \[ \s+ \] /[]/smxg;
295 4665         6738 $result = $obj;
296 4665         15167 return $obj;
297             }
298              
299             }
300              
301             sub parse { ## no critic (RequireArgUnpacking)
302 305     305 1 1093363 my ( $opt, $regexp, @args ) = _parse_constructor_args(
303             { test => 1 }, @_ );
304 305         756 $initial_class = 'PPIx::Regexp';
305 305         574 $kind = 'element';
306 305         1954 $result = $obj = $parse = PPIx::Regexp->new( $regexp, @args );
307 305         1296 $nav = '';
308 305 100       1285 $opt->{test} or return;
309             # cperl does not seem to like goto &xxx; it throws a deep recursion
310             # error if you do it enough times.
311 304         740 $Test::Builder::Level = $Test::Builder::Level + 1;
312 304         776 return isa_ok( $parse, 'PPIx::Regexp',
313             _replace_characters( $regexp ) );
314             }
315              
316             sub ppi { ## no critic (RequireArgUnpacking)
317 1     1 1 1712 my @args = @_;
318 1         3 my $expect = pop @args;
319 1         3 $result = undef;
320 1 50       7 defined $obj and $result = $obj->ppi()->content();
321 1         25 my $safe;
322 1 50       4 if ( defined $result ) {
323 1         6 ($safe = $result) =~ s/([\\'])/\\$1/smxg;
324             } else {
325 0         0 $safe = 'undef';
326             }
327             # cperl does not seem to like goto &xxx; it throws a deep recursion
328             # error if you do it enough times.
329 1         3 $Test::Builder::Level = $Test::Builder::Level + 1;
330 1         6 return is( $result, $expect, "$kind $nav ppi() content '$safe'" );
331             }
332              
333             sub raw_width {
334 282     282 1 470496 my ( $min, $max, $name ) = @_;
335 282 50       1569 defined $name
336             or $name = sprintf q<%s '%s'>, ref $obj, $obj->content();
337 282         559 $Test::Builder::Level = $Test::Builder::Level + 1;
338 282         1253 my @width = $obj->raw_width();
339 282   33     1101 return is( $width[0], $min, "$name raw minimum witdh" ) && is(
340             $width[1], $max, "$name raw maximum width" );
341             }
342              
343             sub replace_characters {
344 2     2 0 211487 %replace_characters = @_;
345 2         6 return;
346             }
347              
348             sub result {
349 2     2 1 4010 return $result;
350             }
351              
352             sub tokenize { ## no critic (RequireArgUnpacking)
353 205     205 1 836710 my ( $opt, $regexp, @args ) = _parse_constructor_args(
354             { test => 1, tokens => 1 }, @_ );
355 205         557 my %args = @args;
356 205         876 $initial_class = __choose_tokenizer_class( $regexp, \%args );
357 205         610 $kind = 'token';
358 205         1214 $obj = $initial_class->new( $regexp, @args );
359 205 100 100     1165 if ( $obj && $opt->{tokens} ) {
360 202         938 $parse = [ $obj->tokens() ];
361             } else {
362 3         8 $parse = [];
363             }
364 205         577 $result = $parse;
365 205         606 $nav = '';
366 205 100       693 $opt->{test} or return;
367 204         481 $Test::Builder::Level = $Test::Builder::Level + 1;
368 204         598 return isa_ok( $obj, 'PPIx::Regexp::Tokenizer',
369             _replace_characters( $regexp ) );
370             }
371              
372             sub true { ## no critic (RequireArgUnpacking)
373 47     47 1 36198 my ( $method, $args ) = @_;
374 47 100       165 ARRAY_REF eq ref $args
375             or $args = [ $args ];
376 47         90 my $class = ref $obj;
377             # cperl does not seem to like goto &xxx; it throws a deep recursion
378             # error if you do it enough times.
379 47         80 $Test::Builder::Level = $Test::Builder::Level + 1;
380 47 50       257 if ( $obj->can( $method ) ) {
381 47         59 $result = $obj->$method( @{ $args } );
  47         146  
382 47         105 my $fmtd = _format_args( $args );
383 47         204 return ok( $result, "$class->$method$fmtd is true" );
384             } else {
385 0         0 $result = undef;
386 0         0 return ok( undef, "$class->$method() exists" );
387             }
388             }
389              
390             sub value { ## no critic (RequireArgUnpacking)
391 1078     1078 1 1759283 my ( $method, $args, $want, $name ) = @_;
392 1078 100       3506 ARRAY_REF eq ref $args
393             or $args = [ $args ];
394              
395 1078   66     2844 my $invocant = $obj || $initial_class;
396 1078   66     3511 my $class = ref $obj || $obj || $initial_class;
397             # cperl does not seem to like goto &xxx; it throws a deep recursion
398             # error if you do it enough times.
399 1078         1766 $Test::Builder::Level = $Test::Builder::Level + 1;
400 1078 50       5328 if ( ! $invocant->can( $method ) ) {
401 0         0 return ok( undef, "$class->$method() exists" );
402             }
403              
404             $result = ARRAY_REF eq ref $want ?
405 3         17 [ $invocant->$method( @{ $args } ) ] :
406 1078 100       2754 $invocant->$method( @{ $args } );
  1075         4392  
407              
408 1078         16120 my $fmtd = _format_args( $args );
409 1078 100       3372 my $answer = format_want( $want, bare => ref $want ? 0 : 1 );
410 1078 50       3645 defined $name
411             or $name = "${class}->$method$fmtd is $answer";
412 1078 100       2114 if ( ref $result ) {
413 5         40 return is_deeply( $result, $want, $name );
414             } else {
415 1073         2630 return is( $result, $want, $name );
416             }
417             }
418              
419             sub width {
420 282     282 1 1161875 my ( $min, $max, $name ) = @_;
421 282 50       1485 defined $name
422             or $name = sprintf q<%s '%s'>, ref $obj, $obj->content();
423 282         532 $Test::Builder::Level = $Test::Builder::Level + 1;
424 282         886 my @width = $obj->width();
425 282   33     1078 return is( $width[0], $min, "$name minimum witdh" ) && is(
426             $width[1], $max, "$name maximum width" );
427             }
428              
429             sub _format_args {
430 2255     2255   4592 my ( $args, %opt ) = @_;
431 2255 100       5016 ARRAY_REF eq ref $args
432             or $args = [ $args ];
433 2255         2905 my @rslt;
434 2255         2335 foreach my $arg ( @{ $args } ) {
  2255         4109  
435 1142 100       3979 if ( ! defined $arg ) {
    100          
436 277         645 push @rslt, 'undef';
437             } elsif ( looks_like_number( $arg ) ) {
438 629         1472 push @rslt, $arg;
439             } else {
440 236         447 push @rslt, $arg;
441 236         490 $rslt[-1] =~ s/ ' /\\'/smxg;
442 236         599 $rslt[-1] = "'$rslt[-1]'";
443             }
444             }
445 2255         4478 my $string = join ', ', @rslt;
446 2255 100       6531 $opt{bare} and return $string;
447 1182 100       3733 @rslt or return '()';
448 64         224 return "( $string )";
449             }
450              
451             sub _method_result { ## no critic (RequireArgUnpacking)
452 3610     3610   9295 my ( $method, @args ) = @_;
453 3610         5943 my $expect = pop @args;
454 3610         5317 $result = undef;
455 3610 100       17961 defined $obj and $result = $obj->$method();
456 3610         4838 my $safe;
457 3610 100       6466 if ( defined $result ) {
458 3546         10721 ($safe = $result) =~ s/([\\'])/\\$1/smxg;
459 3546         6673 $safe = "'$safe'";
460             } else {
461 64         320 $safe = 'undef';
462             }
463 3610         11114 @_ = _replace_characters( $result, $expect, "$kind $nav $method $safe" );
464 3610         11632 goto &is;
465             }
466              
467             sub _parse_constructor_args {
468 515     515   1644 my ( $opt, @args ) = @_;
469 515         1175 my @rslt = ( $opt );
470 515         1259 foreach my $arg ( @args ) {
471 578 100 66     2734 if ( $arg =~ m/ \A - -? (no)? (\w+) \z /smx &&
472             exists $opt->{$2} ) {
473 4         17 $opt->{$2} = !$1;
474             } else {
475 574         1647 push @rslt, $arg;
476             }
477             }
478 515         1821 return @rslt;
479             }
480              
481             sub _pause {
482 10 50   10   25 if ( eval { require Time::HiRes; 1 } ) { # Cargo cult programming.
  10         1666  
  10         3396  
483 10         1002121 Time::HiRes::sleep( 0.1 ); # Something like this is
484             } else { # in PPI's
485 0         0 sleep 1; # t/08_regression.t, and
486             } # who am I to argue?
487 10         180 return;
488             }
489              
490             # quote a string.
491             sub __quote {
492 11387     11387   18154 my @args = @_;
493 11387         11779 my @rslt;
494 11387         15929 foreach my $item ( @args ) {
495 21135 50       33797 if ( __instance( $item, 'PPIx::Regexp::Element' ) ) {
496 0         0 $item = $item->content();
497             }
498 21135 100       54459 if ( ! defined $item ) {
    100          
    100          
499 24         44 push @rslt, 'undef';
500             } elsif ( ARRAY_REF eq ref $item ) {
501 6720         8567 push @rslt, join( ' ', '[', __quote( @{ $item } ), ']' );
  6720         10685  
502             } elsif ( looks_like_number( $item ) ) {
503 7663         12880 push @rslt, $item;
504             } else {
505 6728         13670 $item =~ s/ ( [\\'] ) /\\$1/smxg;
506 6728         15525 push @rslt, "'$item'";
507             }
508             }
509 11387         40874 return join( ', ', @rslt );
510             }
511              
512             sub _replace_characters {
513 4118     4118   8953 my @arg = @_;
514 4118 100       9463 if ( keys %replace_characters ) {
515 14         25 foreach ( @arg ) {
516             $_ = join '',
517             # The following assumes I will never want to replace 0.
518 38 100       648 map { $replace_characters{$_} || $_ }
  403         1037  
519             split qr<>;
520             }
521             }
522             wantarray
523 4118 100       9453 or return join '', @arg;
524 3610         10836 return @arg;
525             }
526              
527             1;
528              
529             __END__