File Coverage

inc/My/Module/Test.pm
Criterion Covered Total %
statement 255 284 89.7
branch 91 126 72.2
condition 33 68 48.5
subroutine 40 41 97.5
pod 21 23 91.3
total 440 542 81.1


line stmt bran cond sub pod time code
1             package My::Module::Test;
2              
3 5     5   356198 use strict;
  5         6  
  5         157  
4 5     5   23 use warnings;
  5         11  
  5         181  
5              
6 5     5   16 use Exporter;
  5         5  
  5         262  
7              
8             our @ISA = ( qw{ Exporter } );
9              
10 5     5   2225 use PPIx::Regexp;
  5         15  
  5         188  
11 5     5   24 use PPIx::Regexp::Constant qw{ INFINITY };
  5         6  
  5         198  
12 5     5   2185 use PPIx::Regexp::Dumper;
  5         24  
  5         162  
13 5     5   25 use PPIx::Regexp::Element;
  5         6  
  5         80  
14 5     5   16 use PPIx::Regexp::Tokenizer;
  5         5  
  5         82  
15 5     5   14 use PPIx::Regexp::Util qw{ __choose_tokenizer_class __instance };
  5         6  
  5         232  
16 5     5   18 use Scalar::Util qw{ looks_like_number refaddr };
  5         6  
  5         187  
17 5     5   1618 use Test::More 0.88;
  5         222429  
  5         36  
18              
19             our $VERSION = '0.092';
20              
21 5     5   1350 use constant ARRAY_REF => ref [];
  5         7  
  5         15535  
22              
23             our @EXPORT_OK = qw{
24             cache_count
25             choose
26             klass
27             cmp_ok
28             content
29             count
30             diag
31             different
32             done_testing
33             dump_result
34             equals
35             error
36             fail
37             false
38             finis
39             format_want
40             invocant
41             is
42             navigate
43             note
44             ok
45             parse
46             pass
47             plan
48             ppi
49             raw_width
50             result
51             replace_characters
52             skip
53             tokenize
54             true
55             value
56             width
57             INFINITY
58             };
59              
60             our @EXPORT = @EXPORT_OK; ## no critic (ProhibitAutomaticExportation)
61              
62             push @EXPORT_OK, qw{ __quote };
63              
64             my (
65             $initial_class, # For static methods; set by parse() or tokenize()
66             $kind, # of thing; set by parse() or tokenize()
67             $nav, # Navigation used to get to current object, as a
68             # string.
69             $obj, # Current object:
70             # PPIx::Regexp::Tokenizer if set by tokenize(),
71             # PPIx::Regexp if set by parse(), or
72             # PPIx::Regexp::Element if set by navigate().
73             $parse, # Result of parse:
74             # array ref if set by tokenize(), or
75             # PPIx::Regexp object if set by parse()
76             %replace_characters, # Troublesome characters replaced in output
77             # before testing
78             $result, # Operation result.
79             );
80              
81             sub cache_count {
82 8     8 1 612 my ( $expect ) = @_;
83 8 100       21 defined $expect or $expect = 0;
84 8         13 $obj = undef;
85 8         12 $parse = undef;
86 8         24 _pause();
87 8         126 $result = PPIx::Regexp->__cache_size();
88             # cperl does not seem to like goto &xxx; it throws a deep recursion
89             # error if you do it enough times.
90 8         42 local $Test::Builder::Level = $Test::Builder::Level + 1;
91 8         84 return is( $result, $expect,
92             "Should be $expect leftover cache contents" );
93             }
94              
95             sub choose {
96 4710     4710 1 3033111 my @args = @_;
97 4710         9397 $obj = $parse;
98 4710         9423 return navigate( @args );
99             }
100              
101             sub klass {
102 4403     4403 1 166409 my ( $class ) = @_;
103 4403   66     11424 $result = ref $obj || $obj;
104             # cperl does not seem to like goto &xxx; it throws a deep recursion
105             # error if you do it enough times.
106 4403         6848 local $Test::Builder::Level = $Test::Builder::Level + 1;
107 4403 100       6633 if ( defined $class ) {
108 4341 50       12313 my $rslt = isa_ok( $obj, $class )
109             or diag " Instead, $kind $nav isa $result";
110 4341         1432540 return $rslt;
111             } else {
112 62   50     345 return is( ref $obj || undef, $class, "Class of $kind $nav" );
113             }
114             }
115              
116             sub content { ## no critic (RequireArgUnpacking)
117             # For some reason cperl seems to have no problem with this
118 3609     3609 1 36283 unshift @_, 'content';
119 3609         9695 goto &_method_result;
120             }
121              
122             sub count {
123 1392     1392 1 79387 my ( @args ) = @_;
124 1392         1991 my $expect = pop @args;
125             # cperl does not seem to like goto &xxx; it throws a deep recursion
126             # error if you do it enough times.
127 1392         2091 local $Test::Builder::Level = $Test::Builder::Level + 1;
128 1392 100       6219 if ( ARRAY_REF eq ref $parse ) {
    100          
    50          
129 203         373 $result = @{ $parse };
  203         398  
130 203         699 return is( $result, $expect, "Expect $expect tokens" );
131             } elsif ( ARRAY_REF eq ref $obj ) {
132 565         641 $result = @{ $obj };
  565         828  
133 565         2034 return is( $result, $expect, "Expect $expect tokens" );
134             } elsif ( $obj->can( 'children' ) ) {
135 624         1526 $result = $obj->children();
136 624         1919 return is( $result, $expect, "Expect $expect children" );
137             } else {
138 0         0 $result = $obj->can( 'children' );
139 0         0 return ok( $result, ref( $obj ) . "->can( 'children')" );
140             }
141             }
142              
143             sub different {
144 1     1 1 8 my @args = @_;
145 1 50       3 @args < 3 and unshift @args, $obj;
146 1         2 my ( $left, $right, $name ) = @args;
147             # cperl does not seem to like goto &xxx; it throws a deep recursion
148             # error if you do it enough times.
149 1         1 local $Test::Builder::Level = $Test::Builder::Level + 1;
150 1 50 33     11 if ( ! defined $left && ! defined $right ) {
    50 33        
    50 33        
    0 0        
    0 0        
151 0         0 return ok( undef, $name );
152             } elsif ( ! defined $left || ! defined $right ) {
153 0         0 return ok( 1, $name );
154             } elsif ( ref $left && ref $right ) {
155 1         6 return ok( refaddr( $left ) != refaddr( $right ), $name );
156             } elsif ( ref $left || ref $right ) {
157 0         0 return ok( 1, $name );
158             } elsif ( looks_like_number( $left ) && looks_like_number( $right ) ) {
159 0         0 return ok( $left != $right, $name );
160             } else {
161 0         0 return ok( $left ne $right, $name );
162             }
163             }
164              
165             sub dump_result {
166 5     5 1 1623 my ( $opt, @args ) = _parse_constructor_args( { test => 1 }, @_ );
167 5 50 0     13 if ( $opt->{test} ) {
    0          
    0          
    0          
168 5         11 my ( $expect, $name ) = splice @args, -2;
169 5         23 my $got = PPIx::Regexp::Dumper->new( $obj, @args )->string();
170             # cperl does not seem to like goto &xxx; it throws a deep
171             # recursion error if you do it enough times.
172 5         34 local $Test::Builder::Level = $Test::Builder::Level + 1;
173 5         14 return is( $got, $expect, $name );
174             } elsif ( __instance( $result, 'PPIx::Regexp::Tokenizer' ) ||
175             __instance( $result, 'PPIx::Regexp::Element' ) ) {
176 0         0 diag( PPIx::Regexp::Dumper->new( $obj, @args )->string() );
177 0         0 } elsif ( eval { require YAML; 1; } ) {
  0         0  
178 0         0 diag( "Result dump:\n", YAML::Dump( $result ) );
179 0         0 } elsif ( eval { require Data::Dumper; 1 } ) {
  0         0  
180 0         0 diag( "Result dump:\n", Data::Dumper::Dumper( $result ) );
181             } else {
182 0         0 diag( "Result dump unavailable.\n" );
183             }
184 0         0 return;
185             }
186              
187             sub equals {
188 19     19 1 70 my @args = @_;
189 19 100       38 @args < 3 and unshift @args, $obj;
190 19         31 my ( $left, $right, $name ) = @args;
191             # cperl does not seem to like goto &xxx; it throws a deep recursion
192             # error if you do it enough times.
193 19         24 local $Test::Builder::Level = $Test::Builder::Level + 1;
194 19 100 66     86 if ( ! defined $left && ! defined $right ) {
    50 33        
    50 33        
    0 0        
    0 0        
195 11         28 return ok( 1, $name );
196             } elsif ( ! defined $left || ! defined $right ) {
197 0         0 return ok( undef, $name );
198             } elsif ( ref $left && ref $right ) {
199 8         22 return ok( refaddr( $left ) == refaddr( $right ), $name );
200             } elsif ( ref $left || ref $right ) {
201 0         0 return ok( undef, $name );
202             } elsif ( looks_like_number( $left ) && looks_like_number( $right ) ) {
203 0         0 return ok( $left == $right, $name );
204             } else {
205 0         0 return ok( $left eq $right, $name );
206             }
207             }
208              
209             sub error { ## no critic (RequireArgUnpacking)
210 19     19 0 11448 unshift @_, 'error';
211 19         53 goto &_method_result;
212             }
213              
214             sub false {
215 52     52 1 20253 my ( $method, $args ) = @_;
216 52 100       133 ARRAY_REF eq ref $args
217             or $args = [ $args ];
218 52         75 my $class = ref $obj;
219             # cperl does not seem to like goto &xxx; it throws a deep recursion
220             # error if you do it enough times.
221 52         64 local $Test::Builder::Level = $Test::Builder::Level + 1;
222 52 50       215 if ( $obj->can( $method ) ) {
223 52         57 $result = $obj->$method( @{ $args } );
  52         142  
224 52         99 my $fmtd = _format_args( $args );
225 52         170 return ok( ! $result, "$class->$method$fmtd is false" );
226             } else {
227 0         0 $result = undef;
228 0         0 return ok( undef, "$class->$method() exists" );
229             }
230             }
231              
232             sub finis {
233 2     2 1 1165 $obj = $parse = $result = undef;
234 2         6 _pause();
235 2         39 $result = PPIx::Regexp::Element->__parent_keys();
236             # cperl does not seem to like goto &xxx; it throws a deep recursion
237             # error if you do it enough times.
238 2         12 local $Test::Builder::Level = $Test::Builder::Level + 1;
239 2         23 return is( $result, 0, 'Should be no leftover objects' );
240             }
241              
242             sub format_want {
243 1081     1081 1 1500 my ( $want ) = @_;
244 1081 100       2052 return _format_args( $want, bare => ref $want ? 0 : 1 );
245             }
246              
247             sub invocant {
248 0     0 1 0 return $obj;
249             }
250              
251             {
252              
253             my %array = map { $_ => 1 } qw{
254             children delimiters finish schildren start tokens type
255             };
256              
257             sub navigate {
258 4765     4765 1 32663 my @args = @_;
259 4765         5360 my $scalar = 1;
260             @args > 1
261             and ARRAY_REF eq ref $args[-1]
262 601         2915 and @{ $args[-1] } == 0
263 4765 100 100     21606 and $array{$args[-2]}
      100        
      100        
264             and $scalar = 0;
265 4765         6097 my @nav = ();
266 4765         7498 while ( @args ) {
267 8483 100       19077 if ( __instance( $args[0], 'PPIx::Regexp::Element' ) ) {
    100          
268 9         18 $obj = shift @args;
269             } elsif ( ARRAY_REF eq ref $obj ) {
270 1571         1873 my $inx = shift @args;
271 1571         2001 push @nav, $inx;
272 1571         3281 $obj = $obj->[$inx];
273             } else {
274 6903         7932 my $method = shift @args;
275 6903         7329 my $args = shift @args;
276 6903 100       12248 ARRAY_REF eq ref $args
277             or $args = [ $args ];
278 6903         8357 push @nav, $method, $args;
279 6903 50       20153 $obj->can( $method ) or return;
280 6903 100 100     15572 if ( @args || $scalar ) {
281 6341 100       5822 $obj = $obj->$method( @{ $args } ) or return;
  6341         13775  
282             } else {
283 562         654 $obj = [ $obj->$method( @{ $args } ) ];
  562         1734  
284             }
285             }
286             }
287 4692         8411 $nav = __quote( @nav );
288 4692         35891 $nav =~ s/ ' ( \w+ ) ' , /$1 =>/smxg;
289 4692         10801 $nav =~ s/ \[ \s+ \] /[]/smxg;
290 4692         5201 $result = $obj;
291 4692         11431 return $obj;
292             }
293              
294             }
295              
296             sub parse { ## no critic (RequireArgUnpacking)
297 307     307 1 690941 my ( $opt, $regexp, @args ) = _parse_constructor_args(
298             { test => 1 }, @_ );
299 307         593 $initial_class = 'PPIx::Regexp';
300 307         536 $kind = 'element';
301 307         1493 $result = $obj = $parse = PPIx::Regexp->new( $regexp, @args );
302 307         1024 $nav = '';
303 307 100       774 $opt->{test} or return;
304             # cperl does not seem to like goto &xxx; it throws a deep recursion
305             # error if you do it enough times.
306 306         553 local $Test::Builder::Level = $Test::Builder::Level + 1;
307 306         1047 return isa_ok( $parse, 'PPIx::Regexp' );
308             }
309              
310             sub ppi { ## no critic (RequireArgUnpacking)
311 1     1 1 589 my @args = @_;
312 1         2 my $expect = pop @args;
313 1         2 $result = undef;
314 1 50       5 defined $obj and $result = $obj->ppi()->content();
315 1         16 my $safe;
316 1 50       2 if ( defined $result ) {
317 1         3 ($safe = $result) =~ s/([\\'])/\\$1/smxg;
318             } else {
319 0         0 $safe = 'undef';
320             }
321             # cperl does not seem to like goto &xxx; it throws a deep recursion
322             # error if you do it enough times.
323 1         3 local $Test::Builder::Level = $Test::Builder::Level + 1;
324 1         4 return is( $result, $expect, "$kind $nav ppi() content '$safe'" );
325             }
326              
327             sub raw_width {
328 282     282 1 123363 my ( $min, $max, $name ) = @_;
329 282 50       1335 defined $name
330             or $name = sprintf q<%s '%s'>, ref $obj, $obj->content();
331 282         458 local $Test::Builder::Level = $Test::Builder::Level + 1;
332 282         872 my @width = $obj->raw_width();
333 282   33     987 return is( $width[0], $min, "$name raw minimum witdh" ) && is(
334             $width[1], $max, "$name raw maximum width" );
335             }
336              
337             sub replace_characters {
338 2     2 0 25591 %replace_characters = @_;
339 2         6 return;
340             }
341              
342             sub result {
343 2     2 1 1665 return $result;
344             }
345              
346             sub tokenize { ## no critic (RequireArgUnpacking)
347 206     206 1 666506 my ( $opt, $regexp, @args ) = _parse_constructor_args(
348             { test => 1, tokens => 1 }, @_ );
349 206         434 my %args = @args;
350 206         835 $initial_class = __choose_tokenizer_class( $regexp, \%args );
351 206         264 $kind = 'token';
352 206         1011 $obj = $initial_class->new( $regexp, @args );
353 206 100 100     811 if ( $obj && $opt->{tokens} ) {
354 203         633 $parse = [ $obj->tokens() ];
355             } else {
356 3         5 $parse = [];
357             }
358 206         405 $result = $parse;
359 206         438 $nav = '';
360 206 100       469 $opt->{test} or return;
361 205         406 local $Test::Builder::Level = $Test::Builder::Level + 1;
362 205         735 return isa_ok( $obj, 'PPIx::Regexp::Tokenizer' );
363             }
364              
365             sub true { ## no critic (RequireArgUnpacking)
366 47     47 1 15653 my ( $method, $args ) = @_;
367 47 100       141 ARRAY_REF eq ref $args
368             or $args = [ $args ];
369 47         75 my $class = ref $obj;
370             # cperl does not seem to like goto &xxx; it throws a deep recursion
371             # error if you do it enough times.
372 47         71 local $Test::Builder::Level = $Test::Builder::Level + 1;
373 47 50       200 if ( $obj->can( $method ) ) {
374 47         42 $result = $obj->$method( @{ $args } );
  47         351  
375 47         82 my $fmtd = _format_args( $args );
376 47         138 return ok( $result, "$class->$method$fmtd is true" );
377             } else {
378 0         0 $result = undef;
379 0         0 return ok( undef, "$class->$method() exists" );
380             }
381             }
382              
383             sub value { ## no critic (RequireArgUnpacking)
384 1081     1081 1 477985 my ( $method, $args, $want, $name ) = @_;
385 1081 100       3155 ARRAY_REF eq ref $args
386             or $args = [ $args ];
387              
388 1081   66     2255 my $invocant = $obj || $initial_class;
389 1081   66     2666 my $class = ref $obj || $obj || $initial_class;
390             # cperl does not seem to like goto &xxx; it throws a deep recursion
391             # error if you do it enough times.
392 1081         1610 local $Test::Builder::Level = $Test::Builder::Level + 1;
393 1081 50       4586 if ( ! $invocant->can( $method ) ) {
394 0         0 return ok( undef, "$class->$method() exists" );
395             }
396              
397             $result = ARRAY_REF eq ref $want ?
398 3         10 [ $invocant->$method( @{ $args } ) ] :
399 1081 100       2327 $invocant->$method( @{ $args } );
  1078         3384  
400              
401 1081         2688 my $fmtd = _format_args( $args );
402 1081 100       2521 my $answer = format_want( $want, bare => ref $want ? 0 : 1 );
403 1081 50       2494 defined $name
404             or $name = "${class}->$method$fmtd is $answer";
405 1081 100       1349 if ( ref $result ) {
406 5         19 return is_deeply( $result, $want, $name );
407             } else {
408 1076         2488 return is( $result, $want, $name );
409             }
410             }
411              
412             sub width {
413 282     282 1 331342 my ( $min, $max, $name ) = @_;
414 282 50       1443 defined $name
415             or $name = sprintf q<%s '%s'>, ref $obj, $obj->content();
416 282         496 local $Test::Builder::Level = $Test::Builder::Level + 1;
417 282         843 my @width = $obj->width();
418 282   33     994 return is( $width[0], $min, "$name minimum witdh" ) && is(
419             $width[1], $max, "$name maximum width" );
420             }
421              
422             sub _format_args {
423 2261     2261   3887 my ( $args, %opt ) = @_;
424 2261 100       9691 ARRAY_REF eq ref $args
425             or $args = [ $args ];
426 2261         2201 my @rslt;
427 2261         2054 foreach my $arg ( @{ $args } ) {
  2261         3162  
428 1145 100       3272 if ( ! defined $arg ) {
    100          
429 277         453 push @rslt, 'undef';
430             } elsif ( looks_like_number( $arg ) ) {
431 631         1188 push @rslt, $arg;
432             } else {
433 237         308 push @rslt, $arg;
434 237         370 $rslt[-1] =~ s/ ' /\\'/smxg;
435 237         565 $rslt[-1] = "'$rslt[-1]'";
436             }
437             }
438 2261         4052 my $string = join ', ', @rslt;
439 2261 100       5247 $opt{bare} and return $string;
440 1185 100       2615 @rslt or return '()';
441 64         132 return "( $string )";
442             }
443              
444             sub _method_result { ## no critic (RequireArgUnpacking)
445 3628     3628   7112 my ( $method, @args ) = @_;
446 3628         4401 my $expect = pop @args;
447 3628         5583 $result = undef;
448 3628 100       16146 defined $obj and $result = $obj->$method();
449 3628         3989 my $safe;
450 3628 100       5100 if ( defined $result ) {
451 3564         9769 ($safe = $result) =~ s/([\\'])/\\$1/smxg;
452 3564         4625 $safe = "'$safe'";
453             } else {
454 64         121 $safe = 'undef';
455             }
456 3628         8419 @_ = _replace_characters( $result, $expect, "$kind $nav $method $safe" );
457 3628         9672 goto &is;
458             }
459              
460             sub _parse_constructor_args {
461 518     518   1394 my ( $opt, @args ) = @_;
462 518         1034 my @rslt = ( $opt );
463 518         1050 foreach my $arg ( @args ) {
464 581 100 66     2219 if ( $arg =~ m/ \A - -? (no)? (\w+) \z /smx &&
465             exists $opt->{$2} ) {
466 4         11 $opt->{$2} = !$1;
467             } else {
468 577         1102 push @rslt, $arg;
469             }
470             }
471 518         1461 return @rslt;
472             }
473              
474             sub _pause {
475 10 50   10   17 if ( eval { require Time::HiRes; 1 } ) { # Cargo cult programming.
  10         79  
  10         26  
476 10         1001552 Time::HiRes::sleep( 0.1 ); # Something like this is
477             } else { # in PPI's
478 0         0 sleep 1; # t/08_regression.t, and
479             } # who am I to argue?
480 10         142 return;
481             }
482              
483             # quote a string.
484             sub __quote {
485 11445     11445   241387 my @args = @_;
486 11445         9548 my @rslt;
487 11445         12569 foreach my $item ( @args ) {
488 21231 50       24325 if ( __instance( $item, 'PPIx::Regexp::Element' ) ) {
489 0         0 $item = $item->content();
490             }
491 21231 100       44314 if ( ! defined $item ) {
    100          
    100          
492 24         37 push @rslt, 'undef';
493             } elsif ( ARRAY_REF eq ref $item ) {
494 6751         6444 push @rslt, join( ' ', '[', __quote( @{ $item } ), ']' );
  6751         8772  
495             } elsif ( looks_like_number( $item ) ) {
496 7697         10796 push @rslt, $item;
497             } else {
498 6759         10914 $item =~ s/ ( [\\'] ) /\\$1/smxg;
499 6759         11180 push @rslt, "'$item'";
500             }
501             }
502 11445         33587 return join( ', ', @rslt );
503             }
504              
505             sub _replace_characters {
506 3628     3628   6729 my @arg = @_;
507 3628 100       6120 if ( keys %replace_characters ) {
508 12         18 foreach ( @arg ) {
509             $_ = join '',
510             # The following assumes I will never want to replace 0.
511 36 100       165 map { $replace_characters{$_} || $_ }
  391         705  
512             split qr<>;
513             }
514             }
515             wantarray
516 3628 50       5206 or return join '', @arg;
517 3628         8357 return @arg;
518             }
519              
520             1;
521              
522             __END__