root/ext/Test/lib/Test.pm

Revision 19677, 21.2 kB (checked in by lwall, 10 months ago)

[Test.pm] typo

  • Property svn:mime-type set to text/plain; charset=UTF-8
  • Property svn:eol-style set to native
Line 
1
2# this is needed by v6.pm (perl6-in-perl5)
3use v6-alpha;
4
5module Test-0.0.8;
6
7#if substr($*PROGRAM_NAME, -2) eq '.t' {
8#    my $script = slurp($*PROGRAM_NAME);
9#    my $comp = lc $?COMPILER;
10#    if $script ~~ /^^ '#?' 'pugs' ':'/ {       # s/b $comp
11#       my $fud = $*PROGRAM_NAME;
12#       $fud ~~ s/t$/fud/ or die "oops";
13#       my $fudge;
14#       for 0..10 -> $x {
15#           $fudge = '../' x $x ~ 'util/fudge';
16#           last if $fudge ~~ :f;
17#       }
18#       system("$fudge $comp $*PROGRAM_NAME >$fud");
19#       try {
20#           evalfile $fud;
21#       }
22#       say "# Fudged!";
23#       fail;
24#       exit(1);
25#       abort();
26#       kill -9, $*PID;
27#       die "Fudged";
28#    }
29#}
30
31### CONSTANTS
32
33# some options available through the environment
34$Test::ALWAYS_CALLER = %*ENV<TEST_ALWAYS_CALLER>;
35
36### GLOBALS
37
38# globals to keep track of our tests
39$Test::num_of_tests_run    = 0;
40$Test::num_of_tests_failed = 0;
41$Test::num_of_tests_badpass = 0;
42$Test::num_of_tests_planned;
43
44$Test::todo_next_test = False;
45
46# a Junction to hold our FORCE_TODO tests.  It's actually a string so
47# Test.pm doesn't require back to implement Junction.
48$Test::force_todo_test_junction = '';
49
50# for running the test suite multiple times in the same process
51$Test::testing_started = 1;
52
53### FUNCTIONS
54
55# Compare numeric values with approximation
56
57sub approx (Num $a, Num $b) returns Bool is export {
58    my $EPSILON = 0.00001;
59    (abs($a - $b) < $EPSILON);
60}
61
62## plan
63
64sub plan (Int $number_of_tests) returns Void is export {
65    $Test::testing_started = 1;
66    $Test::num_of_tests_planned = $number_of_tests;
67    say "1..$number_of_tests";
68}
69
70sub force_todo (*@todo_tests) returns Void is export {
71     $Test::force_todo_test_junction = join ' ', '', @todo_tests, '';
72}
73
74## ok
75
76sub ok (Bool $cond, Str $desc?, :$todo, :$depends) returns Bool is export {
77    Test::proclaim($cond, $desc, $todo, :$depends);
78}
79
80## is
81
82sub is (Str $got, Str $expected, Str $desc?, :$todo, :$depends) returns Bool is export {
83    my $test := $got eq $expected;
84    Test::proclaim($test, $desc, $todo, $got, $expected, $depends);
85}
86
87## is_deeply
88sub is_deeply(Any $got, Any $expected, Str $desc?, :$todo, :$depends) returns Bool is export {
89    # hack for now
90    my $got_perl = $got.perl;
91    my $expected_perl = $expected.perl;
92    my $test := ($got_perl eq $expected_perl);
93    Test::proclaim($test, $desc, $todo, $got_perl, $expected_perl, $depends);
94}
95
96## is_approx   Approximately compare two Nums
97
98sub is_approx(Num $got, Num $expected, Str $desc?, :$todo, :$depends) returns Bool is export {
99    my $test := Test::approx($got, $expected);
100    Test::proclaim($test, $desc, $todo, $got, $expected, $depends);
101}
102
103## isnt
104
105sub isnt (Str $got, Str $expected, Str $desc?, :$todo, :$depends) returns Bool is export {
106    my $test := not($got eq $expected);
107    Test::proclaim($test, "Should not match: $desc", $todo, $got, $expected, $depends, :negate);
108}
109
110## like
111
112sub like (Str $got, Rule $expected, Str $desc?, :$todo, :$depends) returns Bool is export {
113    my $test := $got ~~ $expected;
114    Test::proclaim($test, $desc, $todo, $got, $expected, $depends);
115}
116
117## unlike
118
119sub unlike (Str $got, Rule $expected, Str $desc?, :$todo, :$depends) returns Bool is export {
120    my $test := not($got ~~ $expected);
121    Test::proclaim($test, $desc, $todo, $got, $expected, $depends, :negate);
122}
123
124# eval_ok eval_is - removed.
125
126## eval_dies_ok
127
128sub eval_dies_ok (Str $code, Str $desc?, :$todo, :$depends) returns Bool is export {
129    eval $code;
130    if (defined $!) {
131        &Test::ok.nextwith(1, $desc, :$todo);
132    }
133    else {
134        Test::proclaim(undef, $desc, $todo, "No exception thrown", :$depends);
135    }
136}
137
138## cmp_ok
139
140sub cmp_ok (Str $got, Code &compare_func, Str $expected, Str $desc?, :$todo, :$depends) returns Bool is export {
141    my $test := compare_func($got, $expected);
142    Test::proclaim($test, $desc, $todo, $got, "&compare_func.name() $expected", $depends);
143}
144
145## isa_ok
146
147sub isa_ok (Any|Junction|Pair $ref is rw, Str $expected_type, Str $desc?, :$todo, :$depends) returns Bool is export {
148    my $out := defined($desc) ?? $desc !! "The object is-a '$expected_type'";
149    my $test := $ref.isa($expected_type);
150    Test::proclaim($test, $out, $todo, ~($ref.WHAT), $expected_type, $depends);
151        # Note: the above $ref.WHAT is being cast to a Str because a .defined
152        # on the result of plain .WHAT would be false, which causes
153        # report_failure() to display "undef" for "Actual:" even when
154        # the "actual" contains a valid package name; the Str cast makes "Actual:" work.
155        # At least that .defined matter is the case with Pugs r18102.
156}
157
158## use_ok
159
160sub use_ok (Str $module, :$todo, :$depends) is export {
161    my $caller = caller().package;
162
163    eval "package $caller; require $module";
164
165    #try {
166    #    &::($module)::import.nextwith();
167    #};
168
169    if ($!) {
170        Test::proclaim(undef, "require $module;", $todo, "Import error when loading $module: $!", :$depends);
171    }
172    else {
173        &Test::ok.nextwith(1, "$module imported OK", :$todo, :$depends);
174    }
175}
176
177## throws ok
178
179sub throws_ok (Code &code, Any $match, Str $desc?, :$todo, :$depends) returns Bool is export {
180    try &code;
181    if ($!) {
182        &Test::ok.nextwith($! ~~ $match, $desc, :$todo, :$depends);
183    }
184    else {
185        Test::proclaim(undef, $desc, $todo, "No exception thrown", :$depends);
186    }
187}
188
189## dies_ok
190
191sub dies_ok (Code &code, Str $desc?, :$todo, :$depends) returns Bool is export {
192    try &code;
193    if ($!) {
194        &Test::ok.nextwith(1, $desc, :$todo);
195    }
196    else {
197        Test::proclaim(undef, $desc, $todo, "No exception thrown", :$depends);
198    }
199}
200
201## lives ok
202
203sub lives_ok (Code &code, Str $desc?, :$todo, :$depends) returns Bool is export {
204    try &code;
205    if ($!) {
206        Test::proclaim(undef, $desc, $todo, "An exception was thrown : $!", :$depends);
207    }
208    else {
209        &Test::ok.nextwith(1, $desc, :$todo, :$depends);
210    }
211}
212
213## misc. test utilities
214
215sub version_lt (Str $version1, Str $version2) returns Bool {
216    my @num1 = split '.', $version1;
217    my @num2 = split '.', $version2;
218    #warn ">>> compare $version1 <=> $version2\n";
219    for each(@num1; @num2) -> $a, $b {
220        next if $a == $b;
221        return True if $a < $b;
222        return False;
223    }
224    return False;
225}
226
227sub todo (Str $reason = "fix", *%deadline) returns Bool is export {
228    #warn "!!!", %deadline;
229    return if ! $?COMPILER.defined;
230    my $spec_ver = %deadline{lc($?COMPILER)} // %deadline<by> // "Christmas";
231    if (!$spec_ver.defined or $spec_ver eq '1' or $spec_ver gt '9' or Test::version_lt($?VERSION, $spec_ver)) {
232        $Test::todo_next_test = "$reason by $spec_ver" // True;
233        return True;
234    }
235    return False;
236}
237
238multi sub skip (Str $reason?, :$depends) returns Bool is export {
239    Test::proclaim(1, "", "skip $reason", :$depends);
240}
241
242multi sub skip (Int $count, Str $reason, :$depends) returns Bool is export {
243    for (1 .. $count) {
244        # Hack -- PIL2JS doesn't support multisubs correctly yet
245        if $*OS eq "browser" {
246            Test::proclaim(1, "", "skip $reason", :$depends);
247        } else {
248            Test::skip $reason, :$depends;
249        }
250    }
251}
252
253sub skip_rest (Str $reason?, :$depends) returns Bool is export {
254    Test::skip($Test::num_of_tests_planned - $Test::num_of_tests_run, $reason // "", :$depends);
255}
256
257sub pass (Str $desc?) returns Bool is export {
258    Test::proclaim(1, $desc);
259}
260
261sub flunk (Str $desc?, :$todo, :$depends) returns Bool is export {
262    Test::proclaim(0, $desc, $todo, :$depends);
263}
264
265sub diag (Str $diag) is export {
266    for (split("\n", $diag)) -> $line {
267        if ($diag ~~ m:P5/Failed \(TODO.*?\) test/) {
268            $*OUT.say("# $line");
269        } else {
270            $*ERR.say("# $line");   # we need warn to work with prove6
271        }
272    }
273}
274
275## 'private' subs
276
277sub proclaim (Bool $cond, Str $desc? is copy, $todo?, Str $got?, Str $expected?, $depends?, $negate?) returns Bool {
278    $Test::testing_started = 1;
279    $Test::num_of_tests_run++;
280
281    # $context is now the raw TODO, so we have to check it
282    my $context;
283
284    # Check if we have to forcetodo this test
285    # because we're preparing for a release.
286    $context = "TODO for release"
287        if index($Test::force_todo_test_junction, ' '~$Test::num_of_tests_run~' ') >= 0;
288
289    #warn "todo_next_test: $Test::todo_next_test";
290    if $Test::todo_next_test {
291        $context =  "TODO " ~ ($todo.isa('Str') ?? $todo !!  $Test::todo_next_test // '');
292        $Test::todo_next_test = False;
293    } elsif $todo {
294        if (substr($todo, 0, 4) eq 'skip') {
295            $context = $todo;
296        }
297        else {
298            $context =  "TODO" ~ ($todo.isa('Str') ?? " $todo" !! '');
299            if ( $cond ) {
300                $Test::num_of_tests_badpass ++;
301            }
302        }
303    }
304
305    if ( $depends ) {
306        $context ~= " (depends on $depends working)";
307    }
308
309    my $out = $desc.defined ?? " - $desc" !! "";
310    $out = "$out <pos:$?CALLER::CALLER::POSITION>" if $Test::ALWAYS_CALLER;
311    # message like "test #1 # TODO" confuse the harness. Escape desc #s.
312    $out ~~ s:P5:g/#/\\#/;
313
314    my $context_out = $context.defined ?? " # $context" !! "";
315
316    say(($cond ?? "ok " !! "not ok "), $Test::num_of_tests_run, $out, $context_out);
317
318    Test::report_failure($context, $got, $expected, $negate) unless $cond;
319
320    return $cond;
321}
322
323sub report_failure (Str $todo?, Str $got?, Str $expected?, Bool $negate?) returns Bool {
324    if ($todo) {
325        Test::diag("  Failed ($todo) test ($?CALLER::CALLER::CALLER::POSITION)");
326    }
327    else {
328        Test::diag("  Failed test ($?CALLER::CALLER::CALLER::POSITION)");
329        $Test::num_of_tests_failed++;
330    }
331    my $wanted = $negate ?? "Unwanted" !! "Expected";
332
333    # As PIL2JS doesn't support junctions yet, skip the junction part when
334    # running under PIL2JS.
335    if (index('&Test::is &Test::isnt &Test::cmp_ok &Test::isa_ok &Test::is_deeply &Test::todo_is &Test::todo_isnt &Test::todo_cmp_ok &Test::todo_eval_is &Test::todo_isa_ok ', &?CALLER::CALLER::ROUTINE.name ~ ' ') >= 0) {
336        Test::diag("  $wanted: '" ~ ($expected.defined ?? $expected !! "undef") ~ "'");
337        Test::diag("    Actual: '" ~ ($got.defined ?? $got !! "undef") ~ "'");
338    }
339    else {
340        Test::diag("    Actual: " ~ ($got.defined ?? $got !! "undef"));
341    }
342}
343
344
345sub test_ends {
346    #XXX this fixes an extremely strange bug
347    # my $nr = $Test::num_of_tests_run;        #AAA
348    return() unless $Test::testing_started;
349    if (!defined($Test::num_of_tests_run)) {   #BBB
350    # if (!defined($Test::num_of_tests_run)) returned true when running t/operators/precedence.t
351    # even though $Test::num_of_tests_run was defined and equal to 49 at the top of this sub
352    # the bug only occurs when Test.pm is precompiled
353    # for the full story see the IRC conversation beginning at
354    # http://moritz.faui2k3.org/irclog/out.pl?channel=perl6;date=2007-05-14#id_l267
355    # r16289 of this file is the one that was being tested.
356    # my fix was to comment the line marked BBB and uncomment the lines marked AAA
357    # -rhr
358    # if (!defined($nr)) {                    #AAA
359        say("1..$Test::num_of_tests_run");
360    }
361    elsif ($Test::num_of_tests_planned != $Test::num_of_tests_run) {
362        $*ERR.say("# Looks like you planned $Test::num_of_tests_planned tests, but ran $Test::num_of_tests_run");
363    }
364
365    if ($Test::num_of_tests_failed) {
366        $*ERR.say("# Looks like you failed $Test::num_of_tests_failed tests of $Test::num_of_tests_run");
367    }
368    if ($Test::num_of_tests_badpass) {
369        $*ERR.say("# Looks like $Test::num_of_tests_badpass tests of $Test::num_of_tests_run passed unexpectedly");
370    }
371    $Test::num_of_tests_run    = 0;
372    $Test::num_of_tests_failed = 0;
373    $Test::num_of_tests_badpass = 0;
374    $Test::num_of_tests_planned = undef;
375    $Test::force_todo_test_junction = undef;
376    $Test::testing_started = 0;
377}
378
379END { Test::test_ends() }
380
381=pod
382
383=head1 NAME
384
385Test - Test support module for perl6
386
387=head1 SYNOPSIS
388
389  use v6-alpha;
390  require Test;
391
392  plan 10;
393  force_todo(1, 3 .. 5, 9);
394
395  use_ok('Some::Module');
396  use_ok('Some::Other::Module', todo => 1);
397
398  ok(2 + 2 == 4, '2 and 2 make 4');
399  is(2 + 2, 4, '2 and 2 make 4');
400  isa_ok([1, 2, 3], 'List');
401
402  ok(2 + 2 == 5, '2 and 2 make 5', :todo(1));
403  is(2 + 2, 5, desc => '2 and 2 make 5', todo => 1);
404  is_approx(pi(), 3.141562, 'approximate compare');
405  isa_ok({'one' => 1}, 'Hash', :todo(1));
406
407  use_ok('My::Module');
408
409  pass('This test passed');
410  flunk('This test failed');
411
412  skip('skip this test for now');
413
414  flunk('this fails, but might work soon', :todo(1));
415
416  diag('some misc comments and documentation');
417
418  # TODO the next test with respect to the "deadline" specified.
419  todo :pugs<6.2.13>, :foo<1.23>;
420  is foo, bar, '...';
421
422=head1 DESCRIPTION
423
424This module was built to facilitate the Pugs test suite. It has the
425distinction of being the very first module written for Pugs.
426
427It provides a simple set of common test utility functions, and is
428an implementation of the TAP protocol.
429
430This module, like Pugs, is a work in progress. As new features are
431added to Pugs, new test functions will be defined to facilitate the
432testing of those features. For more information see the FUTURE PLANS
433section of this document.
434
435=head1 FUNCTIONS
436
437  plan (Int $number_of_tests) returns Void
438
439All tests need a plan. A plan is simply the number of tests which are
440expected to run. This should be specified at the very top of your tests.
441
442  force_todo (*@todo_tests) returns Void
443
444If you have some tests which you would like to force into being TODO tests
445then you can pass them through this function. This is primarily a release
446tool, but can be useful in other contexts as well.
447
448=head2 Testing Functions
449
450=head3 use_ok
451
452  use_ok (Str $module, Bool :$todo, Str :$depends) returns Bool
453
454=head3 ok
455
456  ok (Bool $cond, Str $desc?, Bool :$todo, Str :$depends) returns Bool
457
458=head3 is
459
460=head3 isnt
461
462  is   (Str $got, Str $expected, Str $desc?, Bool :$todo, Str :$depends) returns Bool
463  isnt (Str $got, Str $expected, Str $desc?, Bool :$todo, Str :$depends) returns Bool
464
465=head3 like
466
467=head3 unlike
468
469  like   (Str $got, Rule $expected, Str $desc?, Bool :$todo, Str :$depends) returns Bool is export
470  unlike (Str $got, Rule $expected, Str $desc?, Bool :$todo, Str :$depends) returns Bool is export
471
472These functions should work with most reg-exps, but given that they are still a
473somewhat experimental feature in Pugs, it is suggested you don't try anything
474too funky.
475
476=head3 cmp_ok
477
478  cmp_ok (Str $got, Code &compare_func, Str $expected, Str $desc?, Bool :$todo, Str :$depends) returns Bool
479
480This function will compare C<$got> and C<$expected> using C<&compare_func>. This will
481eventually allow Test::More-style cmp_ok() though the following syntax:
482
483  cmp_ok('test', &infix:<gt>, 'me', '... testing gt on two strings');
484
485However the C<< &infix:<gt> >> is currently not implemented, so you will have to wait
486a little while. Until then, you can just write your own functions like this:
487
488  cmp_ok('test', sub ($a, $b) { ?($a gt $b) }, 'me', '... testing gt on two strings');
489  isa_ok ($ref, Str $expected_type, Str $desc?, Bool :$todo, Str :$depends) returns Bool
490
491This function currently on checks with WHAT() since we do not yet have
492object support. Once object support is created, we will add it here, and
493maintain backwards compatibility as well.
494
495=head3 eval_dies_ok
496
497  eval_dies_ok (Str $code, Str $desc?,                Bool :$todo, Str :$depends) returns Bool
498
499This is the function to use if you have a piece of code that would otherwise
500failed to be parsed. If the code parses, but may die at run time, consider
501using C<dies_ok> or C<lives_ok>, which have lower overhead.
502
503C<eval> a string - unsuccessful or failure was expected.
504
505The C<eval> does not occur in the context of the caller.
506Non-global lexicals will not be accessible, and the package will be different.
507
508=head3 throws_ok
509
510  throws_ok (Code &code, Any $expected, Str $desc?, Bool :$todo, Str :$depends) returns Bool
511
512This function takes a block of code and runs it. It then smart-matches (C<~~>) any C<$!>
513value with the C<$expected> value.
514
515=head3 dies_ok
516
517=head3 lives_ok
518
519  dies_ok  (Code &code, Str $desc?, Bool :$todo, Str :$depends) returns Bool
520  lives_ok (Code &code, Str $desc?, Bool :$todo, Str :$depends) returns Bool
521
522These functions both take blocks of code, and test whether they live or die using C<try>
523
524The code must at least be parsable. If the code might not parse, wrap it in C<eval>.
525
526=head3 is_approx
527
528  is_approx (Num $got, Num $expected, Str $desc?, Bool :$todo, Str :$depends) returns Bool
529
530Similar to is(), but compares approximately, to account for floating point
531precision errors.
532
533=head3 is_deeply
534
535 is_deeply(Any $got, Any $expected, Str $desc?, :$todo, :$depends) returns Bool
536
537Similar to is(), except that if $this and $that are references, it
538does a deep comparison walking each data structure to see if they are
539equivalent. 
540
541=begin is_deeply_comment
542
543The plan currently is to implement this as a mutually recursive multi-
544sub which will be able to handle structures of arbitrary depth and of
545an arbitrary type. The function signatures will likely look something
546like this:
547
548  multi sub is_deeply (Array @got, Array @expected, Str $desc?) returns Bool;
549  multi sub is_deeply (List  $got, List  $expected, Str $desc?) returns Bool;
550  multi sub is_deeply (Hash  %got, Hash  %expected, Str $desc?) returns Bool;
551  multi sub is_deeply (Pair  $got, Pair  $expected, Str $desc?) returns Bool;
552
553Because these functions will be mutually recursive, they will easily be
554able handle arbitrarily complex data structures automatically (at least
555that is what I hope).
556
557=end is_deeply_comment
558
559=head2 Misc. Functions
560
561=head3 todo
562
563  todo (*%deadline) returns Bool is export
564
565If and only if the deadline has been hit (or passed), the next one test will
566be marked as TODO.
567
568For example:
569
570   todo :pugs<6.28.0>;
571   is($got, $expected, $desc);
572
573The call to the C<todo> function will mark the next one test as TODO if
574and only if the current compiler's $?COMPILER holds a string whose lowercase
575version equals to 'pugs' and $?VERSION holds a value less than '6.28.0'.
576The C<todo> functuion will perform partial ordering comparison between version
577numbers.
578
579More implementation-specific deadlines can be appended to a single C<todo> call:
580
581  todo :pugs<6.28.0>, :p6p5<0.011>, :parrot<0.45>;
582
583=head3 skip
584
585  skip (Str $reason?) returns Bool
586  skip (Int $count, Str $reason?) returns Bool
587
588If for some reason a test is to be skipped, you can use this
589function to do so.
590
591=head3 pass
592
593=head3 flunk
594
595  pass (Str $desc?) returns Bool
596
597Sometimes what you need to test does not fit into one of the standard
598testing functions. In that case, you can use the rather blunt pass()
599functions and its compliment the flunk() function.
600
601  flunk (Str $desc?, Bool :$todo) returns Bool
602
603This is the opposite of pass()
604
605=head3 diag
606
607  diag (Str $diag)
608
609This will print each string with a '#' character appended to it, this is
610ignored by the TAP protocol.
611
612=head1 Common options
613
614=head2 :todo
615
616Sometimes a test is broken because something is not implemented yet. So
617in order to still allow that to be tested, and those tests to knowingly
618fail, we provide the C<todo> function to TODO the next one test according
619to a given deadline. (See below.)
620
621Take the Pugs implementation. When TODOing failing tests before
622the Pugs release (say, 6.2.12), the following form of todo should be used:
623
624    todo :pugs<6.2.13>;  # version of the next point release
625
626By doing this, temporarily TODO'd tests can get unTODO'd automatically once
627the the release is done (and the version number gets updated).
628
629The version number fed to C<todo> is optional. If omitted,
630the corresponding tests won't get expired unless we unTODO them manually.
631
632It is also possible to use the C<force_todo()> function to do large scale
633TODO-ing of tests.
634
635=head2 :depends
636
637The C<:depends("string")> parameter to most of the functions is a way to
638provide more context in the case of a failure.  It should refer to another file
639or test which must be made to pass before this test can pass (or before an
640implementation could be started).  This is most useful when writing modules and
641you find there is some language feature missing, or core bug that needs to be
642sorted out before you can continue.
643
644=head1 FUTURE PLANS
645
646This module is still a work in progress. As Pugs grows, so will it's
647testing needs. This module will be the code support for those needs. The
648following is a list of future features planned for this module.
649
650- better error handling for cmp_ok
651
652The error handling capabilities need to be expanded more to handle the
653error reporting needs of the cmp_ok() function.
654
655=head1 ENVIRONMENT
656
657Setting the environment variable TEST_ALWAYS_CALLER to force Test.pm to always
658append the caller information to the test's C<$desc>.
659
660=head1 SEE ALSO
661
662The Perl 5 Test modules
663
664- Test
665
666- Test::More
667
668Information about the TAP protocol can be found in the Test::Harness
669distribution.
670
671=head1 AUTHORS
672
673Audrey Tang <autrijus@autrijus.org>
674
675Benjamin Smith
676
677Norman Nunley
678
679Steve Peters
680
681Stevan Little <stevan@iinteractive.com>
682
683Brian Ingerson <ingy@cpan.org>
684
685Jesse Vincent <jesse@bestpractical.com>
686
687Yuval Kogman <nothingmuch@woobling.org>
688
689Darren Duncan <perl@DarrenDuncan.net>
690
691Nathan Gray <kolibrie@graystudios.org>
692
693Max Maischein <corion@cpan.org>
694
695Ingo Blechschmidt <iblech@web.de>
696
697Gaal Yahas <gaal@forum2.org>
698
699Mark Stosberg
700
701Simon Sun <dolmens@gmail.com>
702
703Cosimo Streppone <cosimo@cpan.org>
704
705=head1 COPYRIGHT
706
707Copyright (c) 2005, 2006. Audrey Tang. All rights reserved.
708
709This program is free software; you can redistribute it and/or modify it
710under the same terms as Perl itself.
711
712See http://www.perl.com/perl/misc/Artistic.html
713
714=cut
Note: See TracBrowser for help on using the browser.