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   418359 use strict;
  5         11  
  5         197  
4 5     5   21 use warnings;
  5         13  
  5         261  
5              
6 5     5   25 use Exporter;
  5         6  
  5         296  
7              
8             our @ISA = ( qw{ Exporter } );
9              
10 5     5   2572 use PPIx::Regexp;
  5         15  
  5         207  
11 5     5   28 use PPIx::Regexp::Constant qw{ INFINITY };
  5         4  
  5         201  
12 5     5   2245 use PPIx::Regexp::Dumper;
  5         10  
  5         141  
13 5     5   27 use PPIx::Regexp::Element;
  5         7  
  5         79  
14 5     5   15 use PPIx::Regexp::Tokenizer;
  5         7  
  5         108  
15 5     5   20 use PPIx::Regexp::Util qw{ __choose_tokenizer_class __instance };
  5         7  
  5         278  
16 5     5   21 use Scalar::Util qw{ looks_like_number refaddr };
  5         7  
  5         195  
17 5     5   1652 use Test::More 0.88;
  5         225868  
  5         40  
18              
19             our $VERSION = '0.091_01';
20              
21 5     5   1358 use constant ARRAY_REF => ref [];
  5         8  
  5         15896  
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 652 my ( $expect ) = @_;
83 8 100       28 defined $expect or $expect = 0;
84 8         19 $obj = undef;
85 8         14 $parse = undef;
86 8         30 _pause();
87 8         156 $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         52 local $Test::Builder::Level = $Test::Builder::Level + 1;
91 8         145 return is( $result, $expect,
92             "Should be $expect leftover cache contents" );
93             }
94              
95             sub choose {
96 4710     4710 1 3085396 my @args = @_;
97 4710         9361 $obj = $parse;
98 4710         10664 return navigate( @args );
99             }
100              
101             sub klass {
102 4403     4403 1 172269 my ( $class ) = @_;
103 4403   66     12414 $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         5836 local $Test::Builder::Level = $Test::Builder::Level + 1;
107 4403 100       6659 if ( defined $class ) {
108 4341 50       11910 my $rslt = isa_ok( $obj, $class )
109             or diag " Instead, $kind $nav isa $result";
110 4341         1466977 return $rslt;
111             } else {
112 62   50     377 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 37591 unshift @_, 'content';
119 3609         10639 goto &_method_result;
120             }
121              
122             sub count {
123 1392     1392 1 78500 my ( @args ) = @_;
124 1392         1998 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         2138 local $Test::Builder::Level = $Test::Builder::Level + 1;
128 1392 100       6579 if ( ARRAY_REF eq ref $parse ) {
    100          
    50          
129 203         240 $result = @{ $parse };
  203         371  
130 203         783 return is( $result, $expect, "Expect $expect tokens" );
131             } elsif ( ARRAY_REF eq ref $obj ) {
132 565         528 $result = @{ $obj };
  565         864  
133 565         1857 return is( $result, $expect, "Expect $expect tokens" );
134             } elsif ( $obj->can( 'children' ) ) {
135 624         1661 $result = $obj->children();
136 624         2132 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 7 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         2 local $Test::Builder::Level = $Test::Builder::Level + 1;
150 1 50 33     12 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         5 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 1945 my ( $opt, @args ) = _parse_constructor_args( { test => 1 }, @_ );
167 5 50 0     18 if ( $opt->{test} ) {
    0          
    0          
    0          
168 5         17 my ( $expect, $name ) = splice @args, -2;
169 5         67 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         35 local $Test::Builder::Level = $Test::Builder::Level + 1;
173 5         15 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 79 my @args = @_;
189 19 100       37 @args < 3 and unshift @args, $obj;
190 19         24 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         29 local $Test::Builder::Level = $Test::Builder::Level + 1;
194 19 100 66     98 if ( ! defined $left && ! defined $right ) {
    50 33        
    50 33        
    0 0        
    0 0        
195 11         21 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         21 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 12078 unshift @_, 'error';
211 19         60 goto &_method_result;
212             }
213              
214             sub false {
215 52     52 1 24294 my ( $method, $args ) = @_;
216 52 100       181 ARRAY_REF eq ref $args
217             or $args = [ $args ];
218 52         89 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         87 local $Test::Builder::Level = $Test::Builder::Level + 1;
222 52 50       248 if ( $obj->can( $method ) ) {
223 52         81 $result = $obj->$method( @{ $args } );
  52         178  
224 52         113 my $fmtd = _format_args( $args );
225 52         203 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 1314 $obj = $parse = $result = undef;
234 2         8 _pause();
235 2         36 $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         9 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 1603 my ( $want ) = @_;
244 1081 100       1911 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 36667 my @args = @_;
259 4765         5751 my $scalar = 1;
260             @args > 1
261             and ARRAY_REF eq ref $args[-1]
262 601         3052 and @{ $args[-1] } == 0
263 4765 100 100     20546 and $array{$args[-2]}
      100        
      100        
264             and $scalar = 0;
265 4765         7153 my @nav = ();
266 4765         8270 while ( @args ) {
267 8483 100       18665 if ( __instance( $args[0], 'PPIx::Regexp::Element' ) ) {
    100          
268 9         16 $obj = shift @args;
269             } elsif ( ARRAY_REF eq ref $obj ) {
270 1571         2472 my $inx = shift @args;
271 1571         2718 push @nav, $inx;
272 1571         3508 $obj = $obj->[$inx];
273             } else {
274 6903         8270 my $method = shift @args;
275 6903         8069 my $args = shift @args;
276 6903 100       13032 ARRAY_REF eq ref $args
277             or $args = [ $args ];
278 6903         9000 push @nav, $method, $args;
279 6903 50       20323 $obj->can( $method ) or return;
280 6903 100 100     14865 if ( @args || $scalar ) {
281 6341 100       6207 $obj = $obj->$method( @{ $args } ) or return;
  6341         14823  
282             } else {
283 562         676 $obj = [ $obj->$method( @{ $args } ) ];
  562         1699  
284             }
285             }
286             }
287 4692         8914 $nav = __quote( @nav );
288 4692         37098 $nav =~ s/ ' ( \w+ ) ' , /$1 =>/smxg;
289 4692         11383 $nav =~ s/ \[ \s+ \] /[]/smxg;
290 4692         5911 $result = $obj;
291 4692         12319 return $obj;
292             }
293              
294             }
295              
296             sub parse { ## no critic (RequireArgUnpacking)
297 307     307 1 708859 my ( $opt, $regexp, @args ) = _parse_constructor_args(
298             { test => 1 }, @_ );
299 307         621 $initial_class = 'PPIx::Regexp';
300 307         458 $kind = 'element';
301 307         1748 $result = $obj = $parse = PPIx::Regexp->new( $regexp, @args );
302 307         834 $nav = '';
303 307 100       858 $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         542 local $Test::Builder::Level = $Test::Builder::Level + 1;
307 306         1090 return isa_ok( $parse, 'PPIx::Regexp' );
308             }
309              
310             sub ppi { ## no critic (RequireArgUnpacking)
311 1     1 1 619 my @args = @_;
312 1         3 my $expect = pop @args;
313 1         2 $result = undef;
314 1 50       7 defined $obj and $result = $obj->ppi()->content();
315 1         17 my $safe;
316 1 50       2 if ( defined $result ) {
317 1         4 ($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         2 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 123140 my ( $min, $max, $name ) = @_;
329 282 50       1664 defined $name
330             or $name = sprintf q<%s '%s'>, ref $obj, $obj->content();
331 282         480 local $Test::Builder::Level = $Test::Builder::Level + 1;
332 282         918 my @width = $obj->raw_width();
333 282   33     875 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 30953 %replace_characters = @_;
339 2         5 return;
340             }
341              
342             sub result {
343 2     2 1 1650 return $result;
344             }
345              
346             sub tokenize { ## no critic (RequireArgUnpacking)
347 206     206 1 681299 my ( $opt, $regexp, @args ) = _parse_constructor_args(
348             { test => 1, tokens => 1 }, @_ );
349 206         433 my %args = @args;
350 206         789 $initial_class = __choose_tokenizer_class( $regexp, \%args );
351 206         327 $kind = 'token';
352 206         1287 $obj = $initial_class->new( $regexp, @args );
353 206 100 100     819 if ( $obj && $opt->{tokens} ) {
354 203         622 $parse = [ $obj->tokens() ];
355             } else {
356 3         7 $parse = [];
357             }
358 206         441 $result = $parse;
359 206         384 $nav = '';
360 206 100       414 $opt->{test} or return;
361 205         289 local $Test::Builder::Level = $Test::Builder::Level + 1;
362 205         711 return isa_ok( $obj, 'PPIx::Regexp::Tokenizer' );
363             }
364              
365             sub true { ## no critic (RequireArgUnpacking)
366 47     47 1 18769 my ( $method, $args ) = @_;
367 47 100       172 ARRAY_REF eq ref $args
368             or $args = [ $args ];
369 47         119 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         73 local $Test::Builder::Level = $Test::Builder::Level + 1;
373 47 50       226 if ( $obj->can( $method ) ) {
374 47         57 $result = $obj->$method( @{ $args } );
  47         452  
375 47         117 my $fmtd = _format_args( $args );
376 47         205 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 495678 my ( $method, $args, $want, $name ) = @_;
385 1081 100       3399 ARRAY_REF eq ref $args
386             or $args = [ $args ];
387              
388 1081   66     2437 my $invocant = $obj || $initial_class;
389 1081   66     2726 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         1639 local $Test::Builder::Level = $Test::Builder::Level + 1;
393 1081 50       4887 if ( ! $invocant->can( $method ) ) {
394 0         0 return ok( undef, "$class->$method() exists" );
395             }
396              
397             $result = ARRAY_REF eq ref $want ?
398 3         17 [ $invocant->$method( @{ $args } ) ] :
399 1081 100       2327 $invocant->$method( @{ $args } );
  1078         3885  
400              
401 1081         2757 my $fmtd = _format_args( $args );
402 1081 100       2776 my $answer = format_want( $want, bare => ref $want ? 0 : 1 );
403 1081 50       2482 defined $name
404             or $name = "${class}->$method$fmtd is $answer";
405 1081 100       1753 if ( ref $result ) {
406 5         22 return is_deeply( $result, $want, $name );
407             } else {
408 1076         2412 return is( $result, $want, $name );
409             }
410             }
411              
412             sub width {
413 282     282 1 332185 my ( $min, $max, $name ) = @_;
414 282 50       1746 defined $name
415             or $name = sprintf q<%s '%s'>, ref $obj, $obj->content();
416 282         466 local $Test::Builder::Level = $Test::Builder::Level + 1;
417 282         977 my @width = $obj->width();
418 282   33     888 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   4059 my ( $args, %opt ) = @_;
424 2261 100       4600 ARRAY_REF eq ref $args
425             or $args = [ $args ];
426 2261         2447 my @rslt;
427 2261         2066 foreach my $arg ( @{ $args } ) {
  2261         3307  
428 1145 100       3419 if ( ! defined $arg ) {
    100          
429 277         438 push @rslt, 'undef';
430             } elsif ( looks_like_number( $arg ) ) {
431 631         1143 push @rslt, $arg;
432             } else {
433 237         335 push @rslt, $arg;
434 237         448 $rslt[-1] =~ s/ ' /\\'/smxg;
435 237         548 $rslt[-1] = "'$rslt[-1]'";
436             }
437             }
438 2261         3817 my $string = join ', ', @rslt;
439 2261 100       5445 $opt{bare} and return $string;
440 1185 100       2922 @rslt or return '()';
441 64         174 return "( $string )";
442             }
443              
444             sub _method_result { ## no critic (RequireArgUnpacking)
445 3628     3628   7809 my ( $method, @args ) = @_;
446 3628         5741 my $expect = pop @args;
447 3628         5574 $result = undef;
448 3628 100       17568 defined $obj and $result = $obj->$method();
449 3628         4376 my $safe;
450 3628 100       5508 if ( defined $result ) {
451 3564         11091 ($safe = $result) =~ s/([\\'])/\\$1/smxg;
452 3564         5801 $safe = "'$safe'";
453             } else {
454 64         115 $safe = 'undef';
455             }
456 3628         10399 @_ = _replace_characters( $result, $expect, "$kind $nav $method $safe" );
457 3628         11014 goto &is;
458             }
459              
460             sub _parse_constructor_args {
461 518     518   1413 my ( $opt, @args ) = @_;
462 518         1048 my @rslt = ( $opt );
463 518         1124 foreach my $arg ( @args ) {
464 581 100 66     2456 if ( $arg =~ m/ \A - -? (no)? (\w+) \z /smx &&
465             exists $opt->{$2} ) {
466 4         15 $opt->{$2} = !$1;
467             } else {
468 577         1117 push @rslt, $arg;
469             }
470             }
471 518         1634 return @rslt;
472             }
473              
474             sub _pause {
475 10 50   10   18 if ( eval { require Time::HiRes; 1 } ) { # Cargo cult programming.
  10         101  
  10         34  
476 10         1001770 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         141 return;
481             }
482              
483             # quote a string.
484             sub __quote {
485 11445     11445   243599 my @args = @_;
486 11445         11079 my @rslt;
487 11445         13157 foreach my $item ( @args ) {
488 21231 50       26502 if ( __instance( $item, 'PPIx::Regexp::Element' ) ) {
489 0         0 $item = $item->content();
490             }
491 21231 100       45184 if ( ! defined $item ) {
    100          
    100          
492 24         64 push @rslt, 'undef';
493             } elsif ( ARRAY_REF eq ref $item ) {
494 6751         6999 push @rslt, join( ' ', '[', __quote( @{ $item } ), ']' );
  6751         8809  
495             } elsif ( looks_like_number( $item ) ) {
496 7697         10767 push @rslt, $item;
497             } else {
498 6759         12079 $item =~ s/ ( [\\'] ) /\\$1/smxg;
499 6759         11883 push @rslt, "'$item'";
500             }
501             }
502 11445         36271 return join( ', ', @rslt );
503             }
504              
505             sub _replace_characters {
506 3628     3628   7208 my @arg = @_;
507 3628 100       7224 if ( keys %replace_characters ) {
508 12         15 foreach ( @arg ) {
509             $_ = join '',
510             # The following assumes I will never want to replace 0.
511 36 100       157 map { $replace_characters{$_} || $_ }
  391         705  
512             split qr<>;
513             }
514             }
515             wantarray
516 3628 50       5899 or return join '', @arg;
517 3628         9351 return @arg;
518             }
519              
520             1;
521              
522             __END__