File Coverage

blib/lib/Assert/Refute/Report.pm
Criterion Covered Total %
statement 209 213 98.1
branch 96 114 84.2
condition 42 65 64.6
subroutine 33 33 100.0
pod 23 23 100.0
total 403 448 89.9


line stmt bran cond sub pod time code
1             package Assert::Refute::Report;
2              
3 58     58   466894 use 5.006;
  58         276  
4 58     58   301 use strict;
  58         109  
  58         1210  
5 58     58   297 use warnings;
  58         135  
  58         3439  
6             our $VERSION = '0.1501';
7              
8             =head1 NAME
9              
10             Assert::Refute::Report - Contract execution class for Assert::Refute suite
11              
12             =head1 DESCRIPTION
13              
14             This class represents one specific application of contract.
15             It is mutable, but can only changed in one way
16             (there is no undo of tests and diagnostic messages).
17             Eventually a C locks it completely, leaving only
18             L for inspection.
19              
20             See L for contract I.
21              
22             =head1 SYNOPSIS
23              
24             my $c = Assert::Refute::Report->new;
25             $c->refute ( $cond, $message );
26             $c->refute ( $cond2, $message2 );
27             # .......
28             $c->done_testing; # no more refute after this
29              
30             $c->get_count; # how many tests were run
31             $c->is_passing; # did any of them fail?
32             $c->get_tap; # return printable summary in familiar format
33              
34             =cut
35              
36             # Now this module is the CORE of Assert::Refute.
37             # There are 3 things for which performance matters:
38             # 1) new()
39             # 2) refute( 0, ... )
40             # 3) done_testing()
41             # The rest can wait.
42              
43 58     58   424 use Carp;
  58         139  
  58         3795  
44 58     58   455 use Scalar::Util qw(blessed);
  58         168  
  58         3503  
45              
46 58     58   20007 use Assert::Refute::Build qw(to_scalar);
  58         165  
  58         3346  
47              
48             # Always add basic testing primitives to the arsenal
49 58     58   25460 use Assert::Refute::T::Basic qw();
  58         186  
  58         173199  
50              
51             my $ERROR_DONE = "done_testing was called, no more changes may be added";
52              
53             =head1 METHODS
54              
55             =head3 new
56              
57             Assert::Refute::Report->new();
58              
59             No arguments are currently supported.
60              
61             =cut
62              
63             sub new {
64 226     226 1 22308 bless {
65             fail => {},
66             count => 0,
67             }, shift;
68             };
69              
70             =head2 RUNNING PRIMITIVES
71              
72             =head3 plan( tests => $n )
73              
74             Plan to run exactly n tests.
75             This is not required, and L (see below)
76             is needed at the end anyway.
77              
78             =head3 plan( skip_all => $reason )
79              
80             Plan to run no tests at all.
81             As of current, this does not prevent any future checks from being run.
82              
83             In both cases,
84             dies if there's already a plan, or tests are being run, or done_testing
85             was seen.
86              
87             If plan is not fullfilled by the time of C call,
88             a message indicating plan violation will be added,
89             and the report will become unconditionally failing.
90              
91             =cut
92              
93             sub plan {
94 9     9 1 44 my ($self, $todo, @args) = @_;
95              
96             $self->_croak( $ERROR_DONE )
97 9 50       39 if $self->{done};
98              
99             $self->_croak( "plan(): already defined" )
100 9 50       26 if defined $self->{plan_tests};
101             $self->_croak( "plan(): testing already started" )
102 9 50       25 if $self->{count} > 0;
103              
104 9 100       29 if ($todo eq 'tests') {
    50          
105 8 50 33     106 $self->_croak( "plan(): usage: plan tests => n")
      33        
106             unless @args == 1 and defined $args[0] and $args[0] =~ /^\d+$/;
107 8         26 $self->{plan_tests} = $args[0];
108             } elsif ($todo eq 'skip_all') {
109 1 50 33     9 $self->_croak( "plan(): usage: plan skip_all => reason")
      33        
110             unless @args == 1 and defined $args[0] and length $args[0];
111 1         2 $self->{plan_skip} = $args[0];
112 1         11 $self->{plan_tests} = 0;
113             # TODO should we lock report?
114             } else {
115 0         0 $self->_croak( "Unknown 'plan $todo ...' command" );
116             };
117              
118 9         62 return $self;
119             };
120              
121             =head3 refute( $condition, $message )
122              
123             An inverted assertion. That is, it B if C<$condition> is B.
124              
125             Returns inverse of first argument.
126             Dies if L was called.
127              
128             See L for more detailed discussion.
129              
130             =cut
131              
132             sub refute {
133 413     413 1 1142 my ($self, $cond, $msg) = @_;
134              
135             $self->_croak( $ERROR_DONE )
136 413 100       1116 if $self->{done};
137              
138 412         760 my $n = ++$self->{count};
139 412 100       1171 $self->{name}{$n} = $msg if defined $msg;
140 412         655 delete $self->{log}; # log is a shortcut to $self->{messages}{$n}
141             # see do_log()
142              
143             # Pass, return ASAP
144 412 100       1681 return $n unless $cond;
145              
146             # Test failed!
147 152         349 $self->{fail}{$n} = $cond;
148 152         327 $self->{fail_count}++;
149 152         418 return 0;
150             };
151              
152             =head3 diag
153              
154             diag "Message", \%reference, ...;
155              
156             Add human-readable diagnostic message to report.
157             References are auto-explained via L.
158              
159             =head3 note
160              
161             diag "Message", \%reference, ...;
162              
163             Add human-readable notice message to report.
164             References are auto-explained via L.
165              
166             =cut
167              
168             sub diag {
169 120     120 1 1228 my $self = shift;
170              
171 120         294 $self->do_log( 0, -1, join " ", map { to_scalar($_) } @_ );
  132         382  
172             };
173              
174             sub note {
175 3     3 1 1251 my $self = shift;
176              
177 3         11 $self->do_log( 0, 1, join " ", map { to_scalar($_) } @_ );
  4         14  
178             };
179              
180             =head3 done_testing
181              
182             Stop testing.
183             After this call, no more writes (including done_testing)
184             can be performed on this contract.
185             This happens by default at the end of C block.
186              
187             Dies if called for a second time, I an argument is given.
188              
189             A true argument is considered to be the exception
190             that interrupted the contract execution,
191             resulting in an unconditionally failed contract.
192              
193             A false argument just avoids dying and is equivalent to
194              
195             $report->done_testing
196             unless $report->is_done;
197              
198             Returns self.
199              
200             =cut
201              
202             sub done_testing {
203 196     196 1 2431 my ($self, $exception) = @_;
204              
205 196 100       690 if ($exception) {
    100          
206             # Record a totally failing contract.
207 11         23 delete $self->{done};
208 11         31 $self->{has_error} = $exception;
209             } elsif ($self->{done}) {
210             # A special case - done_testing(0) means "tentative stop"
211 4 100       14 return $self if defined $exception;
212 3         11 $self->_croak( $ERROR_DONE );
213             };
214              
215             # Any post-mortem messages go to a separate bucket
216 192   100     1117 $self->{log} = $self->{messages}{ -1 } ||= [];
217              
218 192 100       517 if ($self->{has_error}) {
219 11         40 $self->diag( "Looks like contract was interrupted by", $self->{has_error} );
220             };
221              
222 192 100       489 if (defined $self->{plan_tests}) {
223             # Check plan
224 9 100       25 if ($self->{count} != $self->{plan_tests}) {
225 3         17 my $bad_plan = "Looks like you planned $self->{plan_tests}"
226             ." tests but ran $self->{count}";
227 3   33     21 $self->{has_error} ||= $bad_plan;
228 3         11 $self->diag( $bad_plan );
229             };
230             };
231              
232 192 100       497 if ($self->{fail_count}) {
233 92         574 $self->diag(
234             "Looks like $self->{fail_count} tests out of $self->{count} have failed");
235 92         265 my $ctx = $self->context;
236 92         386 foreach (keys %$ctx) {
237 1         4 $self->diag("context: $_:", $ctx->{$_});
238             };
239             };
240              
241 192         478 $self->{done}++;
242 192         422 return $self;
243             };
244              
245             =head3 context()
246              
247             Get execution context hash with arbitrary user data.
248              
249             Upon failure, the hash content is going to be appended to the log at diag level.
250              
251             =cut
252              
253             sub context {
254 97     97 1 1755 my $self = shift;
255 97   100     575 return $self->{context} ||= {};
256             };
257              
258             =head3 set_context( \%hash )
259              
260             Set the context hash.
261              
262             Only plain (not blessed) hash is allowed as argument.
263              
264             =cut
265              
266             sub set_context {
267 3     3 1 11 my ($self, $hash) = @_;
268              
269 3 100       14 $self->_croak( "argument must be a HASH reference" )
270             unless ref $hash eq 'HASH';
271              
272 2         5 $self->{context} = $hash;
273 2         36 return $self;
274             };
275              
276             =head2 TESTING PRIMITIVES
277              
278             L comes with a set of basic checks
279             similar to that of L, all being wrappers around
280             L discussed above.
281             They are available as both prototyped functions (if requested) I
282             methods in contract execution object and its descendants.
283              
284             The list is as follows:
285              
286             C, C, C, C, C, C,
287             C, C, C, C, C,
288             C, C, C, C, C, C.
289              
290             See L for more details.
291              
292             Additionally, I checks defined using L
293             will be added to L as methods
294             unless explicitly told otherwise.
295              
296             =head3 subcontract( "Message" => $specification, @arguments ... )
297              
298             Execute a previously defined group of tests and fail loudly if it fails.
299              
300             $specification may be one of:
301              
302             =over
303              
304             =item * code reference - will be executed in C block, with a I
305             L passed as argument;
306              
307             =item * L instance - apply() will be called;
308              
309             =item * L instance implying a previously executed test.
310              
311             =back
312              
313             B<[NOTE]> that the message comes first, unlike in C or other
314             test conditions, and is required.
315              
316             =cut
317              
318             sub subcontract {
319 48     48 1 125 my ($self, $msg, $sub, @args) = @_;
320              
321             $self->_croak( $ERROR_DONE )
322 48 50       158 if $self->{done};
323 48 50       94 $self->_croak( "Name is required for subcontract" )
324             unless $msg;
325              
326 48         76 my $rep;
327 48 100 66     316 if ( blessed $sub and $sub->isa( "Assert::Refute::Contract" ) ) {
    50 33        
    100          
328 8         31 $rep = $sub->apply(@args);
329             } elsif (blessed $sub and $sub->isa( "Assert::Refute::Report" ) ) {
330 0 0       0 $self->_croak("pre-executed subcontract cannot take args")
331             if @args;
332 0 0       0 $self->_croak("pre-executed subcontract must be finished")
333             unless $sub->is_done;
334 0         0 $rep = $sub;
335             } elsif (UNIVERSAL::isa( $sub, 'CODE' )) {
336 39         190 $rep = Assert::Refute::Report->new;
337 39         74 local $Assert::Refute::DRIVER = $rep;
338             eval {
339 39         120 $sub->($rep, @args);
340 38         118 $rep->done_testing(0);
341 38         108 1;
342 39 100       63 } or do {
343 1   50     56 $rep->done_testing( $@ || "Execution interrupted" );
344             };
345             } else {
346 1         5 $self->_croak("subcontract must be a contract definition or execution log");
347             };
348              
349 47         144 $self->{subcontract}{ $self->get_count + 1 } = $rep;
350 47         112 $self->refute( !$rep->is_passing, "$msg (subtest)" );
351             };
352              
353             =head2 QUERYING PRIMITIVES
354              
355             =head3 is_done
356              
357             Tells whether done_testing was seen.
358              
359             =cut
360              
361             sub is_done {
362 74     74 1 145 my $self = shift;
363 74   100     496 return $self->{done} || 0;
364             };
365              
366              
367             =head3 is_passing
368              
369             Tell whether the contract is passing or not.
370              
371             =cut
372              
373             sub is_passing {
374 136     136 1 253 my $self = shift;
375              
376 136   100     1654 return !$self->{fail_count} && !$self->{has_error};
377             };
378              
379             =head3 get_count
380              
381             How many tests have been executed.
382              
383             =cut
384              
385             sub get_count {
386 138     138 1 704 my $self = shift;
387 138         487 return $self->{count};
388             };
389              
390             =head3 get_fail_count
391              
392             How many tests failed
393              
394             =cut
395              
396             sub get_fail_count {
397 2     2 1 25 my $self = shift;
398 2   100     32 return $self->{fail_count} || 0;
399             };
400              
401             =head3 get_tests
402              
403             Returns a list of test ids, preserving order.
404              
405             =cut
406              
407             sub get_tests {
408 2     2 1 6 my $self = shift;
409 2         12 return 1 .. $self->{count};
410             };
411              
412             =head3 get_result( $id )
413              
414             Returns result of test denoted by $id, dies if such test was never performed.
415             The result is false for passing tests and whatever the reason for failure was
416             for failing ones.
417              
418             =cut
419              
420             sub get_result {
421 11     11 1 36 my ($self, $n) = @_;
422              
423             return $self->{fail}{$n} || 0
424 11 100 50     94 if exists $self->{fail}{$n};
425              
426 2 100 66     21 return 0 if $n =~ /^[1-9]\d*$/ and $n<= $self->{count};
427              
428 1         6 $self->_croak( "Test $n has never been performed" );
429             };
430              
431             =head3 get_result_details ($id)
432              
433             Returns a hash containing information about a test:
434              
435             =over
436              
437             =item * number - the number of test (this is equal to argument);
438              
439             =item * name - name of the test (if any);
440              
441             =item * ok - whether the test was successful;
442              
443             =item * reason - the reason for test failing, if it failed;
444             Undefined for "ok" tests.
445              
446             =item * diag - diagnostic messages as one array, without leading C<#>;
447              
448             =item * log - any log messages that followed the test (see get_log for format)
449              
450             =item * subcontract - if test was a subcontract, contains the report.
451              
452             =back
453              
454             Returns empty hash for nonexistent tests, and dies if test number is not integer.
455              
456             As a special case, tests number 0 and -1 represent the output before any
457             tests and postmortem output, respectively.
458             These only contains the C and C fields.
459              
460             See also L.
461              
462             B<[EXPERIMENTAL]>. Name and meaning may change in the future.
463              
464             =cut
465              
466             sub get_result_details {
467 38     38 1 12203 my ($self, $n) = @_;
468              
469 38 50 33     246 $self->_croak( "Bad test number $n, must be nonnegatine integer" )
470             unless defined $n and $n =~ /^(?:[0-9]+|-1)$/;
471              
472             # Process messages, return if premature(0) or post-mortem (n+1)
473 38         89 my @messages;
474 38 100       105 if (my $array = $self->{messages}{$n} ) {
475 9         28 @messages = @$array;
476             };
477              
478 38         96 my %ret = ( number => $n );
479              
480 38 100       80 if ($n >= 1) {
481             # a real test - add some information
482 32         98 my $reason = $self->{fail}{$n};
483 32         46 my @diag;
484              
485 32 100 100     135 if (ref $reason eq 'ARRAY') {
    100          
486 4         20 push @diag, [ 0, -1, to_scalar($_) ] for @$reason;
487             } elsif ( $reason and $reason ne 1 ) {
488 5         17 push @diag, [ 0, -1, to_scalar($reason) ];
489             };
490              
491 32         72 $ret{ok} = !$reason;
492 32         63 $ret{name} = $self->{name}{$n};
493 32         53 $ret{reason} = $reason;
494 32         77 $ret{log} = [@diag, @messages];
495 32         64 $ret{subcontract} = $self->{subcontract}{$n};
496             } else {
497             # leading or trailing messages
498 6         15 $ret{log} = \@messages,
499             };
500              
501             # Strip extra trash from internal log format
502 38         60 $ret{diag} = [ map { $_->[2] } grep { $_->[1] < 0 } @{ $ret{log} } ];
  23         57  
  23         60  
  38         104  
503              
504 38         224 return \%ret;
505             };
506              
507             =head3 get_error
508              
509             Return last error that was recorded during contract execution,
510             or false if there was none.
511              
512             =cut
513              
514             sub get_error {
515 95     95 1 166 my $self = shift;
516 95   100     631 return $self->{has_error} || '';
517             };
518              
519             =head3 get_tap( $level )
520              
521             Return a would-be Test::More script output for current contract.
522              
523             The level parameter allows to adjust verbosity level.
524             The default is 0 which includes passing tests,
525             but not notes and/or debugging messages.
526              
527             B<[NOTE]> that C is higher than C.
528              
529             =over
530              
531             =item * -3 - something totally horrible, like C
532              
533             =item * -2 - a failing test
534              
535             =item * -1 - a diagnostic message, think C
536              
537             =item * 0 - a passing test
538              
539             =item * 1+ - a normally ignored verbose message, think L
540              
541             =back
542              
543             =cut
544              
545             my %padding; # cache level => leading spaces mapping
546             my $tab = ' ';
547              
548             sub get_tap {
549 78     78 1 6661 my ($self, $verbosity) = @_;
550              
551 78   100     423 $verbosity ||= 0;
552              
553 78         235 my $mess = $self->get_log( $verbosity );
554              
555 78         131 my @str;
556 78         194 foreach (@$mess) {
557 466         1039 my ($indent, $level, $mess) = @$_;
558 466 50       1005 next if $level > $verbosity;
559              
560 466         861 my $pad = ' ' x $indent;
561             $pad .= exists $padding{$level}
562             ? $padding{$level}
563 466 100       1108 : ($padding{$level} = _get_padding( $level ));
564 466         2758 $mess =~ s/\s*$//s;
565              
566 466         1276 foreach (split /\n/, $mess) {
567 541         1503 push @str, "$pad$_";
568             };
569             };
570              
571 78         862 return join "\n", @str, '';
572             };
573              
574             sub _get_padding {
575 78     78   158 my $level = shift;
576              
577 78 100       246 return '#' x $level . '# ' if $level > 0;
578 77 100       243 return '# ' if $level == -1;
579 51         174 return '';
580             };
581              
582             =head3 get_sign
583              
584             Produce a terse pass/fail summary (signature)
585             as a string of numbers and letters.
586              
587             The format is C<"t(\d+|N)*[rdE]">.
588              
589             =over
590              
591             =item * C is always present at the start;
592              
593             =item * a number stands for a series of passing tests;
594              
595             =item * C stands for a I failing test;
596              
597             =item * C stands for a contract that is still Bunning;
598              
599             =item * C stands for a an Bxception during execution;
600              
601             =item * C stands for a contract that is Bone.
602              
603             =back
604              
605             The format is still evolving.
606             Capital letters are used to represent failure,
607             and it is likely to stay like that.
608              
609             The numeric notation was inspired by Forsyth-Edwards notation (FEN) in chess.
610              
611             =cut
612              
613             sub get_sign {
614 89     89 1 1397 my $self = shift;
615              
616 89         231 my @t = ("t");
617              
618 89         158 my $streak;
619 89         290 foreach (1 .. $self->{count}) {
620 224 100       537 if ( $self->{fail}{$_} ) {
621 93 100       292 push @t, $streak if $streak;
622 93         467 $streak = 0;
623 93         213 push @t, "N"; # for "not ok"
624             } else {
625 131         256 $streak++;
626             };
627             };
628 89 100       267 push @t, $streak if $streak;
629              
630 89 100       264 my $d = $self->get_error ? 'E' : $self->{done} ? 'd' : 'r';
    100          
631 89         548 return join '', @t, $d;
632             };
633              
634             =head2 DEVELOPMENT PRIMITIVES
635              
636             Generally one should not touch these methods unless
637             when subclassing to build a new test backend.
638              
639             When extending this module,
640             please try to stick to C, C, and C
641             to avoid clash with test names.
642              
643             This is weird and probably has to be fixed at some point.
644              
645             =head3 do_run( $code, @list )
646              
647             Run given CODEREF, passing self as both first argument I
648             current_contract().
649             Report object is locked afterwards via L call.
650              
651             Returns self.
652              
653             Example usage is
654              
655             Assert::Refute::Report->new->run( sub {
656             like $this, qr/.../;
657             can_ok $that, qw(foo bar frobnicate);
658             } );
659              
660             =cut
661              
662             sub do_run {
663 58     58 1 152 my ($self, $code, @args) = @_;
664 58         121 local $Assert::Refute::DRIVER = $self;
665             eval {
666 58         190 $code->($self, @args);
667 55         226 $self->done_testing(0);
668 55         159 1;
669 58 100       102 } || do {
670 3   33     39 $self->done_testing(
671             $@ || Carp::shortmess( 'Contract execution interrupted' ) );
672             };
673 58         209 return $self;
674             };
675              
676             =head3 do_log( $indent, $level, $message )
677              
678             Append a message to execution log.
679              
680             See L for level descriptions.
681              
682             =cut
683              
684             sub do_log {
685 123     123 1 485 my ($self, $indent, $level, $mess) = @_;
686              
687             $self->_croak( $ERROR_DONE )
688 123 100       417 if $self->{done};
689              
690 121   50     423 $self->{log} ||= $self->{messages}{ $self->{count} } ||= [];
      66        
691 121         235 push @{ $self->{log} }, [$indent, $level, $mess];
  121         511  
692              
693 121         320 return $self;
694             };
695              
696             =head3 get_log
697              
698             Return log messages "as is" as array reference
699             containing triads of (indent, level, message).
700              
701             B<[CAUTION]> This currently returns reference to internal structure,
702             so be careful not to spoil it.
703             This MAY change in the future.
704              
705             =cut
706              
707             sub get_log {
708 94     94 1 191 my ($self, $verbosity) = @_;
709 94 50       242 $verbosity = 9**9**9 unless defined $verbosity;
710              
711 94         157 my @mess;
712              
713             # output plan if there was plan
714 94 100       289 if (defined $self->{plan_tests}) {
715             push @mess, _plan_to_tap( $self->{plan_tests}, $self->{plan_skip} )
716 8 50       39 unless $verbosity < 0;
717             };
718              
719 94         333 foreach my $n ( 0 .. $self->{count}, -1 ) {
720             # Report test details.
721             # Only append the logs for
722             # premature (0) and postmortem (-1) messages
723 393 100       814 if ($n > 0) {
724 205         406 my $reason = $self->{fail}{$n};
725 205 100       502 my ($level, $prefix) = $reason ? (-2, "not ok") : (0, "ok");
726 205 100       596 my $name = $self->{name}{$n} ? "$n - $self->{name}{$n}" : $n;
727 205         602 push @mess, [ 0, $level, "$prefix $name" ];
728              
729 205 100       536 if ($self->{subcontract}{$n}) {
730             push @mess, map {
731 87         222 [ $_->[0]+1, $_->[1], $_->[2] ];
732 16         33 } @{ $self->{subcontract}{$n}->get_log( $verbosity ) };
  16         65  
733             };
734              
735 205 100 100     853 if (ref $reason eq 'ARRAY') {
    100          
736             push @mess, map {
737 7         21 [ 0, -1, to_scalar( $_ ) ]
  21         49  
738             } @$reason;
739             } elsif ($reason and $reason ne 1) {
740 70         232 push @mess, [ 0, -1, to_scalar( $reason ) ];
741             };
742             };
743              
744             # and all following diags
745 393 100       1068 if (my $rest = $self->{messages}{$n} ) {
746 101         236 push @mess, grep { $_->[1] <= $verbosity } @$rest;
  81         326  
747             };
748             };
749              
750 94 100 100     559 if (!defined $self->{plan_tests} and $self->{done}) {
751 81 50       360 push @mess, _plan_to_tap( $self->get_count )
752             unless $verbosity < 0;
753             };
754              
755 94         251 return \@mess;
756             };
757              
758             sub _plan_to_tap {
759 89     89   215 my ($n, $skip) = @_;
760              
761 89         205 my $line = "1..".$n;
762 89 100       266 $line .= " # SKIP $skip"
763             if defined $skip;
764 89         300 return [ 0, 0, $line ];
765             };
766              
767             sub _croak {
768 10     10   29 my ($self, $mess) = @_;
769              
770 10   50     27 $mess ||= "Something terrible happened";
771 10         30 $mess =~ s/\n+$//s;
772              
773 10         74 my $fun = (caller 1)[3];
774 10         107 $fun =~ s/(.*)::/${1}->/;
775              
776 10         1489 croak "$fun(): $mess";
777             };
778              
779             =head2 DEPRECATED METHODS
780              
781             =over
782              
783             =item set_result
784              
785             Was used inside refute() prior to 0.10. This is no more the case.
786             This function just dies and will be removed completely in 0.15.
787              
788             =back
789              
790             =cut
791              
792             sub set_result {
793 1     1 1 6 my $self = shift;
794 1         3 $self->_croak( "set_result() is removed, use refute() instead" );
795             };
796              
797             =head1 LICENSE AND COPYRIGHT
798              
799             This module is part of L suite.
800              
801             Copyright 2017-2018 Konstantin S. Uvarin. C<< >>
802              
803             This program is free software; you can redistribute it and/or modify it
804             under the terms of the the Artistic License (2.0). You may obtain a
805             copy of the full license at:
806              
807             L
808              
809             =cut
810              
811             1; # End of Assert::Refute::Report