PaxHeader/Test-Unit-0.28000755 000765 000024 00000000210 15113573111 015270 xustar00rjbsstaff000000 000000 30 mtime=1764685385.436789708 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/000755 000765 000024 00000000000 15113573111 013400 5ustar00rjbsstaff000000 000000 Test-Unit-0.28/PaxHeader/TkTestRunner.pl000644 000765 000024 00000000152 07400720502 020312 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/TkTestRunner.pl000644 000765 000024 00000000147 07400720502 016345 0ustar00rjbsstaff000000 000000 #!/usr/bin/perl -w use strict; use Test::Unit::TkTestRunner; Test::Unit::TkTestRunner::main(@ARGV); Test-Unit-0.28/PaxHeader/TestLister.pl000755 000765 000024 00000000152 07403173761 020023 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/TestLister.pl000755 000765 000024 00000000762 07403173761 016061 0ustar00rjbsstaff000000 000000 #!/usr/bin/perl -w use strict; use Getopt::Long; use Test::Unit::Loader; my %opts = (); GetOptions(\%opts, 'help', 'testcases'); usage() if $opts{help}; foreach my $test (@ARGV) { my $suite = Test::Unit::Loader::load($test); print join '', @{ $suite->list($opts{testcases}) }; } sub usage { die < [ ... ] Options: --testcases, -t List testcases contained in (sub)suites --help, -h Tests can be package names or file names. EOF } Test-Unit-0.28/PaxHeader/ChangeLog000644 000765 000024 00000000210 15113573044 017121 xustar00rjbsstaff000000 000000 30 mtime=1764685348.549121814 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/ChangeLog000644 000765 000024 00000145664 15113573044 015177 0ustar00rjbsstaff000000 000000 2025-12-02 Ricardo Signes * lib/Test/Unit.pm: version 0.28 * replace tabs with spaces in a bunch of places * no functional changes 2024-06-27 Ricardo Signes * lib/Test/Unit.pm: version 0.27 * lib/Test/Unit/Assert.pm: sort keys when deep-comparing hashes to avoid hash randomization causing test failures sporadically * lib/Test/Unit/Procedural.pm: fix a typo * t/tlib/AssertTest.pm: fix a test that failed on perl v5.30 due to a bug in perl v5.30! 2024-06-26 Ricardo Signes * lib/Test/Unit.pm: version 0.26 * lib/Test/Unit/TestCase.pm: the "defined ARRAY" syntax, removed in v5.22.0, has now been removed from this library * t/try_examples.t: was adjusted to pass on Darwin * t/tlib/AssertTest.pm: tests were updated to work with whatever qr// stringification is in play 2005-10-15 Matthew Astley * doc/release-checklist, doc/TODO, ChangeLog: updates for release * lib/Test/Unit.pm: version 0.25 * MANIFEST: add licence and class-diagram files, remove old example; keep in "make manifest" generated order * t/tlib/AssertTest.pm (test_fail_assert_not_null): extra check, for SF bug #610499 * lib/Test/Unit/Assert.pm (assert_deep_equals): fix comparisons of cyclic structures (thanks flacoste, SF patch #678422), comparisons of undefs (thanks flacoste, Debian BTS #249678), comparison of SCALAR refs * t/tlib/AssertTest.pm (test_assert_deep_equals): add modified test from SF bug #1012115; modified test from flacoste's SF patch #678422; more tests on SCALAR refs, and improve the regexp 2005-08-19 Matthew Astley * doc/TODO: notes on HarnessUnit, UnitHarness; more on stuff I'd like to do later * examples/README: minor update 2005-08-03 Matthew Astley * doc/class-diagram.{dia,txt,png}: first stab at a UML class diagram, see how it goes 2005-08-01 Matthew Astley * lib/Test/Unit.pm, lib/Test/Unit/TkTestRunner.pm, lib/Test/Unit/TestRunner.pm: put links to COPYING.* in Test::Unit; move copyright notices from testrunner modules to Test::Unit * lib/Test/Unit/, t/tlib/AllTests.pm: set AUTHOR POD sections to the same boilerplate, in files that don't appear to be single-author -- as described in the top level AUTHORS file * AUTHORS: update authors list with SF ids and what I found while boilerplating the PODs; add explicit copy of the Perl licence, taken from Debian perl-base package v5.8.4-2 * COPYING.Artistic, COPYING.GPL-2: licences copied from Debian base-files package v3.0.12 2005-07-31 Matthew Astley * lib/Test/Unit/Assert.pm (is_numeric): change the test to match only lone numbers. fix SF bug#1014540 *** NB. this causes assert_equals to switch from assert_num_equals to assert_str_equals in some cases * t/tlib/AssertTest.pm (test_numericness, test_assert_equals): tests for new is_numeric * lib/Test/Unit/TkTestRunner.pm: make "Show..." dialog text expand with window and include annotations. fixes SF bug#1018619 * t/try_examples.t: clear out useless 'use lib's; remove dup $^O check; fix RT bug#3963 (thanks ILYAM); improve skipping of untested items * examples/tester.png: update screenshot of Tk test runner; mark as binary * examples/tester.pl: remove old Tk code - Test::SuiteWrapper went away 2000-02-21 2005-07-30 Matthew Astley * t/try_examples.t: Fix SF bug#908422 (track changing testing output format); Thanks: dholland, eksiegerman [aka. SF bug#1245490, RT bug#2244] * .cvsignore: ignore build stuff -- other changes Adam made since REL_0_24, but aren't mentioned already. I list them partly so I know where my towel is: * AUTHORS: Adam became maintainer * doc/TODO: updated * lib/Test/Unit/Decorator.pm: some minor change I've not investigated * lib/Test/Unit/Procedural.pm: fix bug spotted by Matthias Ferber (and Ken) in run() (which is usually overridden) [SF bug#760491, RT bug#3058] * lib/Test/Unit/Runner.pm: improve filtering, POD * lib/Test/Unit/TestCase.pm: POD for filtering * t/tlib/RunnerTest.pm: new test for T:U:TestRunner, just tests filtering; uses the new t/tlib/FilteredSuite.pm 2002-06-20 Adam Spiers * lib/Test/Unit/TestCase.pm: document new filtering via coderefs * MANIFEST, lib/Test/Unit/Test.pm, lib/Test/Unit/TestSuite.pm, t/tlib/AllTests.pm, t/tlib/FilteredSuite.pm: - remove ALL filtering hack, and instead allow filtering via coderefs: sub filter {{ foo_tests => sub { my $method = shift; return $method =~ /foo/; }, everything => sub { 1 }, # method lists still work another_token => [ qw/test_method1 test_method2/ ], }} - add tests for filtering mechanism 2002-06-14 Adam Spiers * lib/Test/Unit.pm: version 0.24 * ChangeLog: new stuff for 0.24 * MANIFEST: 'make manifest' revealed more missing files, though none of them crucial * AUTHORS: change Adam's email address * lib/Test/Unit/TestRunner.pm: Don't die if the run was unsuccessful; we might want to reuse the runner for another run. * MANIFEST: argh! 0.23's MANIFEST was missing several crucial files. 2002-06-13 Adam Spiers * lib/Test/Unit/Runner/Terminal.pm: forgot to update the pod * .cvsignore: ignore tarballs * doc/release-checklist: typo * README, doc/release-checklist: cut down on the poor maintainer's workload * Changes: deprecate this file * ChangeLog: new stuff for 0.23 * lib/Test/Unit.pm: version 0.23 * doc/TODO: mention that Attribute::Handlers probably won't work * t/tlib/TestTest.pm, lib/Test/Unit/Error.pm, lib/Test/Unit/Exception.pm, lib/Test/Unit/Result.pm, lib/Test/Unit/TestCase.pm: Rework the exception handling mechanisms of run_protected/run_bare so that run-time exceptions in set_up or tear_down no longer halt the framework, and neither do user-defined exceptions thrown in the test methods themselves (where the framework only used to handle straight-forward exceptions where $@ was a scalar, I think). Some assumptions about Error.pm internals have had to be made, unfortunately. * lib/Test/Unit/Procedural.pm: remove spurious 'use' line 2002-06-12 Adam Spiers * lib/Test/Unit/Debug.pm: allow debugging to a file with debug_to_file 2002-06-10 Adam Spiers * lib/Test/Unit/Runner/Terminal.pm: use \e[4A\r instead of \e[4F, which not all terminals support * lib/Test/Unit/Runner/Terminal.pm: Ahem. Forgot to change package name. * lib/Test/Unit/TkTestRunner.pm: check that something is selected when the user clicks 'Show...' * lib/Test/Unit/TkTestRunner.pm: disable broken rerun button * MANIFEST, lib/Test/Unit/Listener.pm, lib/Test/Unit/Runner.pm, lib/Test/Unit/Runner/Terminal.pm, lib/Test/Unit/TestRunner.pm, lib/Test/Unit/TestSuite.pm: - new start_suite/end_suite events sent to listeners, to track where current test is in the suite hierarchy ($runner->suites_running) - new T::U::Runner::Terminal runner which uses terminal escape sequences to show which suites/tests are currently being run - result object now stored in the runner * lib/Test/Unit/TkTestRunner.pm: clean up of code style * lib/Test/Unit/Listener.pm: pseudo-document the parameters for the listener interface 2002-05-23 Adam Spiers * doc/TODO, lib/Test/Unit/TestCase.pm: (poorly) document @TESTS and the filtering mechanism * lib/Test/Unit.pm: version 0.22 * ChangeLog: get this uptodate by merging auto-generated entries with existing ones * lib/Test/Unit/TestSuite.pm: allow 'ALL' as a magic test name which matches all methods in this class, e.g. package MyTest37; use base qw(Test::Unit::TestCase); ... sub filter {{ skip_thirty_seven => [ 'ALL' ], slow => [ qw(test_I_am_slow test_I_am_slow_too) ], }} * lib/Test/Unit/Assert.pm, t/tlib/AssertTest.pm: assert_(str|num)(_not)?_equals now fail with undef parameters, to avoid tests passing by accident. The user should either use assert_null/assert_not_null, or check for undef before the assertion. 2002-05-23 Adam Spiers * lib/Test/Unit/TestSuite.pm: allow 'ALL' as a magic test name which matches all methods in this class, e.g. package MyTest37; use base qw(Test::Unit::TestCase); ... sub filter {{ skip_thirty_seven => [ 'ALL' ], slow => [ qw(test_I_am_slow test_I_am_slow_too) ], }} * lib/Test/Unit/Assert.pm, t/tlib/AssertTest.pm: assert_(str|num)(_not)?_equals now fail with undef parameters, to avoid tests passing by accident. The user should either use assert_null/assert_not_null, or check for undef before the assertion. 2002-05-14 Adam Spiers * lib/Test/Unit/TestCase.pm: bit more debugging 2002-03-26 Adam Spiers * lib/Test/Unit.pm: version 0.21 * lib/Test/Unit/Assert.pm, t/tlib/AssertTest.pm: avoid UNIVERSAL::isa, which is buggy with 5.6.0 (see perldelta) 2002-03-18 Adam Spiers * t/tlib/AssertTest.pm: update boolean assertion tests for new failure message * doc/TODO: do_run should be public * lib/Test/Unit/Assertion/Boolean.pm: slightly nicer default assertion failure message 2002-03-04 Adam Spiers * lib/Test/Unit/Test.pm, lib/Test/Unit/TestCase.pm: avoid namespace clashes in TestCase objects (thanks to jonasbn for pointing this problem out) * README: update the prerequisites 2002-02-20 Adam Spiers * lib/Test/Unit/Assert.pm: reintroduce caveat about $self->assert($foo =~ /$bar/) 2002-02-12 Adam Spiers * lib/Test/Unit/Assert.pm, t/tlib/AssertTest.pm: make $self->assert([1]); work 2002-02-05 Adam Spiers * lib/Test/Unit/Assert.pm, t/tlib/AssertTest.pm: assert_deep_equals takes references 'A' and 'B', not 'got' and 'expected' 2002-02-04 Adam Spiers * t/tlib/AllTests.pm, t/tlib/AssertTest.pm, t/tlib/ExceptionChecker.pm, t/tlib/TestObject.pm, t/tlib/WillDie.pm: - factor out exception checking into ExceptionChecker - move TestObject class into separate file - tests for test-case methods which die ( they pass but I am still getting funny results from my real-world test-cases )-: * doc/TODO: @TESTS needs testing 2002-01-29 Adam Spiers * lib/Test/Unit/HarnessUnit.pm, lib/Test/Unit/Runner.pm, lib/Test/Unit/TkTestRunner.pm: factor create_test_result * lib/Test/Unit/Assert.pm, t/tlib/AssertTest.pm: - new assert_deep_equals for comparing deep structures, mostly ripped out of Test::More - some tests weren't getting run because of identical hash keys when I should have been using arrays (doh!) 2002-01-23 Adam Spiers * doc/TODO: need to document @TESTS 2002-01-09 Adam Spiers * lib/Test/Unit/TestRunner.pm: missed a rename from output() to annotations() 2002-01-08 Adam Spiers * MANIFEST, lib/Test/Unit/Assert.pm, lib/Test/Unit/Assertion/CodeRef.pm, lib/Test/Unit/Assertion/Exception.pm, lib/Test/Unit/Assertion/Regexp.pm, t/assert.t, t/tlib/AssertTest.pm: - Fix breakage where coderef assertions were not failing. Coderef assertions are now expected to throw Test::Unit::Failures ($self->fail() is a convenient way of doing this; see updated docs). - New tests for assert(). - New multi_assert() for using multiple argument sets with one assertion (plus tests). - New assert_raises() for asserting that a coderef raises a particular class of exception (plus tests). * t/tlib/TestTest.pm: the famous scalar/regexp problem 2001-12-20 Adam Spiers * lib/Test/Unit/Assertion.pm: whitespace 2001-12-19 Adam Spiers * lib/Test/Unit/TestCase.pm: missed a print -> annotate change in the pod * t/tlib/AssertTest.pm: 3 more tests for ok() 2001-12-18 Adam Spiers * lib/Test/Unit/Loader.pm: fix problem with symbol tables containing symbol tables * lib/Test/Unit/TestCase.pm, lib/Test/Unit/TestRunner.pm: rename print() to annotate() 2001-12-11 Adam Spiers * lib/Test/Unit/Assert.pm, t/tlib/AssertTest.pm: - Add new assert_matches() and assert_does_not_match() assertions, as requested by Matthias Ferber, and new tests for them of course. - Start testing for the correct messages in T::U::Failure objects (see check_exception()). In particular this tests that the optional MESSAGE args are processed correctly when reporting failures. - Improved behaviour of assert_equals() and assert_not_equals() with undefined parameters. - Added more stringent tests for assert_equals() and assert_not_equals(). Some of these are possibly debatable. I think the assert_equals() matrix should be retired in favour of the check_failures() style tests used to check assert_not_equals(), since the latter also check the failure message and originating file/line (added a #FIXME for this). - Fixed reversed got/expected message with $self->ok(sub { 2 + 2 }, 4); Spotted this as a bonus of the new check_exception(), yay. * lib/Test/Unit/TestRunner.pm, t/try_examples.t: autoflush TestRunner's output stream 2001-12-07 Adam Spiers * lib/Test/Unit/TestRunner.pm: Don't need that \n *either*. Doh! * lib/Test/Unit/TestRunner.pm: don't need that \n either 2001-12-06 Adam Spiers * lib/Test/Unit/TestCase.pm: document print() 2001-12-05 Adam Spiers * doc/TODO, lib/Test/Unit/Exception.pm, lib/Test/Unit/Result.pm, lib/Test/Unit/TestCase.pm, lib/Test/Unit/TestRunner.pm: can now call $self->print("debugging stuff") within test case methods and if the test fails or "errors" you get to see all the debugging accumulated from the above calls 2001-12-04 Adam Spiers * doc/TODO: ideas from Test::More * doc/TODO: $Error::Depth bug fixed (I think) * lib/Test/Unit/Assert.pm: We seem to have obtained an extra 2 stack frames somewhere along the line. This makes the new, more stringent exception checking tests in AssertTest.pm pass. * t/tlib/AssertTest.pm: - Added hairiness to failure/error testing, so it now doesn't just check that the exception was raised, but also checks that its file() and line() methods point correctly to the source of the failed assertion. - Refactored duplicated code from check_failures() and check_errors() into check_exceptions() * lib/Test/Unit/TestCase.pm: tiny cosmetic tweak * TestLister.pl, lib/Test/Unit/TestCase.pm, lib/Test/Unit/TestSuite.pm: simple but pretty script for listing suite structure rather than running it * examples/fail_example.pm, lib/Test/Unit/Debug.pm: missed a few DEBUGs in fail_example.pm * Makefile.PL, doc/TODO: require base.pm version 1, so that a warning is generated for buggy base.pms * lib/Test/Unit.pm: link to AUTHORS file * TestRunner.pl: example usage of debugging * lib/Test/Unit/Loader.pm: avoid warning * AUTHORS: Kevin was listed twice 2001-12-03 Piers Cawley * AUTHORS: Added the list of Authors who've written code for PerlUnit. Almost certainly incomplete. Add your details please. 2001-12-03 Adam Spiers * lib/Test/Unit/HarnessUnit.pm: don't need that \n * doc/TODO: fixed * lib/Test/Unit/HarnessUnit.pm, lib/Test/Unit/Loader.pm, lib/Test/Unit/Result.pm, lib/Test/Unit/Setup.pm, lib/Test/Unit/Test.pm, lib/Test/Unit/TestCase.pm, lib/Test/Unit/TestRunner.pm, lib/Test/Unit/TestSuite.pm, lib/Test/Unit/UnitHarness.pm, t/all_tests.t, t/tlib/ListenerTest.pm, MANIFEST, lib/Test/Unit/Assert.pm, lib/Test/Unit/Debug.pm, lib/Test/Unit/Decorator.pm, lib/Test/Unit/Exception.pm: All debugging now happens through a simple unified debugging class Test::Unit::Debug. This allows the user to turn debugging on/off dynamically, still on a per-package basis, but in a more convenient way. Also eliminates the problem with `make test' failing when DEBUG is "compiled in". * doc/TODO: more jobs * t/tlib/TestTest.pm: should have a name * t/tlib/TestTest.pm: give inner classes names to avoid warnings in debugging 2001-11-30 Adam Spiers * lib/Test/Unit/TestCase.pm: this could come in handy when overriding list_tests() 2001-11-30 Piers Cawley * lib/Test/Unit.pm: Added a feedback section to Test::Unit's pod, suggesting that users join perlunit-users and generally give us some feedback. 2001-11-29 Adam Spiers * lib/Test/Unit/Loader.pm: forgot to put this die() in * MANIFEST, Makefile.PL, lib/Test/Unit.pm, lib/Test/Unit/Loader.pm, lib/Test/Unit/Procedural.pm, lib/Test/Unit/Test.pm, lib/Test/Unit/TestRunner.pm, lib/Test/Unit/TestSuite.pm, lib/Test/Unit/Warning.pm, t/tlib/AllTests.pm, t/tlib/InheritedSuite/OverrideNew.pm, t/tlib/InheritedSuite/OverrideNewName.pm, t/tlib/InheritedSuite/Simple.pm, t/tlib/InheritedSuite/TestNames.pm, t/tlib/SuiteTest.pm: some major improvements: - fixed the existing suite-building API, extended it, documented it fully, added/improved tests for it - reintroduced Test/Unit.pm, this time as a placeholder for $VERSION and some introductory pod containing pointers to the other modules - massive refactoring of Test::Unit::Loader - factored out Test::Unit::Suite::_warning into Test::Unit::Warning, so it could be used elsewhere [I think he meant Test::Unit::TestSuite::_warning -- mca, trying to prevent confusion] - fixed NoTestCaseClass test * examples/fail_example.pm, t/try_examples.t: add a couple of comments now I know what this Decorator/Setup business is about * t/try_examples.t: skip properly, don't just mark as TODO because they aren't TODO * lib/Test/Unit/Decorator.pm: whitespace * lib/Test/Unit/Setup.pm: don't want those prototypes * lib/Test/Unit/UnitHarness.pm: - @ISA = ('Exporter') line was overriding use base lines - whitespace now matches conventions we decided on * t/all_tests.t, t/assert.t, t/try_examples.t: these should be executable 2001-11-28 Adam Spiers * examples/README: get this up to date (ish) * lib/Test/Unit/Loader.pm: - get_package_name_from_file() never worked before (missing assignment to $filename). - remove dependency on FileHandle; this saves us a bit of code bloat if we're not using UnitHarness. * t/try_examples.t: I think this is right for fail_example.pm, maybe ... * examples/fail_example.pm: fail_example_testsuite_setup package needs to come second, otherwise Test::Unit::Loader::get_package_name_from_file returns the wrong suite. * t/tlib/ActiveTestTest.pm, t/tlib/Success.pm: - refactoring: no point having more than one Success test case - it should really have at least one successful test in it * lib/Test/Unit/Loader.pm: fix the pod * lib/Test/Unit/Loader.pm: - more suitable variable names - don't need no strict 'refs' - cosmetics * lib/Test/Unit/TestRunner.pm: TestRunner can run test cases *and* test suites * lib/Test/Unit/HarnessUnit.pm: missing use * doc/TODO: copyright stuff 2001-11-27 Adam Spiers * doc/TODO, lib/Test/Unit/TestSuite.pm: Allow test suites to be derived from Test::Unit::TestSuite! This turned out to be a relatively small change, and paves the way for vast improvements IMO. The old API should still work perfectly. * MANIFEST, README, doc/TODO, examples/patch100132, examples/patch100132-1, examples/patch100132-2, lib/Test/Unit.pm, lib/Test/Unit/Procedural.pm: renamed Test::Unit to Test::Unit::Procedural * lib/Test/Unit/Test.pm, lib/Test/Unit/TestRunner.pm: get the versioning uptodate and CPAN-compliant * TestRunner.pl, TkTestRunner.pl: there's no reason why these shouldn't be executable 2001-11-16 Adam Spiers * doc/TODO: done that * lib/Test/Unit/Loader.pm, t/tlib/AllTests.pm, t/tlib/BadSuite/BadUse.pm, t/tlib/BadSuite/SyntaxError.pm, t/tlib/BadSuitesTest.pm: - might as well have some debugging in Loader if we have DEBUG - fix misleading error when a suite has a bad dependency - add tests for correct runner error message in above bad dependency case, and for a straightforward syntax error 2001-11-15 Piers Cawley * MANIFEST: Added doc/TODO 2001-11-15 Adam Spiers * lib/Test/Unit/Test.pm: forgot to test DEBUG * doc/TODO: done some work on runner state and filtering * lib/Test/Unit/TestSuite.pm: only add tests via add_test() * MANIFEST, lib/Test/Unit/HarnessUnit.pm, lib/Test/Unit/Runner.pm, lib/Test/Unit/Test.pm, lib/Test/Unit/TestCase.pm, lib/Test/Unit/TestRunner.pm, lib/Test/Unit/TestSuite.pm, lib/Test/Unit/TkTestRunner.pm, lib/Test/Unit/UnitHarness.pm: - add new Runner base class which is an appropriate place for runner state common between all runners - very basic example of its usage: filter tokens - add something like this to your test case sub filter {{ 'slow' => [ 'test_a_slow_one', 'test_another_slow_one' ], 'really_slow' => [ 'test_wow_really_slow' ], }} then you can filter out slow tests via my $runner = new Test::Unit::TestRunner(); $runner->filter(qw/slow really_slow/); $runner->start($class); * lib/Test/Unit/TestRunner.pm: - tidy up output a bit - use T::U::Loader for loading main suite * doc/TODO: done that * t/all_tests.t, t/assert.t, t/tlib/ActiveTestTest.pm, t/tlib/AllTests.pm, t/tlib/AssertTest.pm, t/tlib/InheritedInheritedTestCase.pm, t/tlib/InheritedTestCase.pm, t/tlib/ListenerTest.pm, t/tlib/NoTestCaseClass.pm, t/tlib/NoTestCases.pm, t/tlib/OneTestCase.pm, t/tlib/OverrideTestCase.pm, t/tlib/Success.pm, t/tlib/SuiteTest.pm, t/tlib/TestAssertionCodeRef.pm, t/tlib/TestTest.pm, t/tlib/TornDown.pm, t/tlib/WasRun.pm, t/try_examples.t, MANIFEST, README, lib/Test/Unit/Assert.pm, lib/Test/Unit/TestCase.pm, lib/Test/Unit/TestRunner.pm, lib/Test/Unit/TestSuite.pm, lib/Test/Unit/TkTestRunner.pm, lib/Test/Unit/Tutorial.pm: move lib/Test/Unit/tests/*.pm to t/tlib * doc/TODO, doc/consensus.txt: moved some stuff to TODO * doc/consensus.txt: removing stuff about new assertion mechanism, this is now in HEAD and documented (Test::Unit::Assert*) * doc/TODO, doc/consensus.txt: new doc/TODO 2001-11-14 Adam Spiers * lib/Test/Unit/Assertion/Boolean.pm: get optional messages working just like with assert_str_equals etc. 2001-11-13 Adam Spiers * lib/Test/Unit/Assert.pm: - add support to ok() for optional comments - make ok() raise error not failure with bad args - fix assert_num_equals ditching optional comment * lib/Test/Unit/Assertion/Regexp.pm: making debugging more readable * lib/Test/Unit/Assertion/Boolean.pm: - fix typo which was hiding optional failure comment - making debugging more readable * lib/Test/Unit/Exception.pm: improve legibility of failures * lib/Test/Unit/Assert.pm: - finish ok() wrapper, and add tests for it - some refactoring into new check_failures() in T/U/tests/AssertTest.pm 2001-11-12 Adam Spiers * Makefile.PL: need 5.005 for qr//, thanks to Quinn Weaver for pointing that out 2001-11-12 Piers Cawley * lib/Test/Unit/Assertion.pm, lib/Test/Unit/Assertion/Boolean.pm, lib/Test/Unit/Assertion/CodeRef.pm, lib/Test/Unit/Assertion/Regexp.pm, lib/Test/Unit/Decorator.pm, lib/Test/Unit/Error.pm, lib/Test/Unit/Exception.pm, lib/Test/Unit/ExceptionError.pm, lib/Test/Unit/ExceptionFailure.pm, lib/Test/Unit/Failure.pm, lib/Test/Unit/HarnessUnit.pm, lib/Test/Unit/InnerClass.pm, lib/Test/Unit/Listener.pm, lib/Test/Unit/Loader.pm, lib/Test/Unit/Result.pm, lib/Test/Unit/Setup.pm, lib/Test/Unit/Test.pm, lib/Test/Unit/TestCase.pm, lib/Test/Unit/TestDecorator.pm, lib/Test/Unit/TestFailure.pm, lib/Test/Unit/TestListener.pm, lib/Test/Unit/TestLoader.pm, lib/Test/Unit/TestResult.pm, lib/Test/Unit/TestRunner.pm, lib/Test/Unit/TestSetup.pm, lib/Test/Unit/TestSuite.pm, lib/Test/Unit/TkTestRunner.pm, lib/Test/Unit/UnitHarness.pm, t/all_tests.t, t/assert.t, t/try_examples.t, .cvsignore, ChangeLog, Changes, MANIFEST, MANIFEST.SKIP, Makefile.PL, examples/README, examples/fail_example.pm, examples/patch100132, examples/procedural-adding-suites-example.pl, examples/procedural-another-package-example.pl, examples/procedural-fail-example.pl, examples/procedural-ok-example.pl, lib/Test/Unit.pm, lib/Test/Unit/Assert.pm: Merged changes from PDC_REFACTOR branch. * Makefile.PL, lib/Test/Unit/TestCase.pm: Tidied up some formatting in Test::Unit::TestCase and added a dependency to Makefile.PL 2001-11-12 Adam Spiers * doc/consensus.txt: coding style 2001-11-07 Adam Spiers * lib/Test/Unit/Assert.pm: ok(): support more cases * lib/Test/Unit/Assert.pm: oops, ok() needs to reverse order of got/expected args * ChangeLog: Bring ChangeLog uptodate for this branch. Hmm, maybe we should just let CVS and rcs2log do the hard work as far as change logs are concerned. * doc/consensus.txt: - only edit consensus.txt in HEAD - consensus on use vs. require * lib/Test/Unit/Exception.pm: cosmetics in failure output * lib/Test/Unit/Assert.pm: - cosmetics in failure output - add missing require (thanks to Hans Donner ) - add a controversial but very convenient and harmless alias: &ok -> &assert_equals * .cvsignore: New file. * .cvsignore: cvs-ignore Makefile * doc/consensus.txt: deal with broken base.pm issue 2001-10-31 Piers Cawley * MANIFEST: Tidied up the MANIFEST so make tardist works. * MANIFEST, t/try_examples.t: Fixed t/try_examples.t to recognize a passing test. 2001-10-30 Piers Cawley * lib/Test/Unit/TestRunner.pm, lib/Test/Unit/UnitHarness.pm, Makefile.PL: Tidied up output of TestRunner Added prerequisites to Makefile.PL Removed some dependencies on Test::Unit::InnerClass 2001-10-26 Adam Spiers * lib/Test/Unit/tests/AssertTest.pm: fix barewords error 2001-10-25 Adam Spiers * doc/consensus.txt: todo: check for broken Error.pms 2001-09-07 pdcawley * ChangeLog: Added some stuff in the ChangeLog * lib/Test/Unit/Result.pm: More doc fixes. * lib/Test/Unit/Result.pm, lib/Test/Unit/TestCase.pm: Doctored Test::Unit::Result again, so that if $test->run_bare *does* return false we actually add a failure instead of just leaving things up in the air (causes a problem with test harnesses if we don't) * lib/Test/Unit/Assert.pm, lib/Test/Unit/TestCase.pm, lib/Test/Unit/tests/AssertTest.pm, ChangeLog: Tidied up the documentation in Test::Unit::Assert. Made sure that Test::Unit::TestCase::run_bare returns true if it doesn't throw an exception. * lib/Test/Unit/TestCase.pm: An attempt at improving the documentation. * lib/Test/Unit/Setup.pm: New file. * Changes, MANIFEST, examples/README, examples/fail_example.pm, lib/Test/Unit/Setup.pm, lib/Test/Unit/TestSetup.pm: Renamed Test::Unit::TestSetup to Test::Unit::Setup * lib/Test/Unit/Listener.pm, lib/Test/Unit/tests/ListenerTest.pm: New file. * MANIFEST, lib/Test/Unit/HarnessUnit.pm, lib/Test/Unit/Listener.pm, lib/Test/Unit/TestListener.pm, lib/Test/Unit/TestRunner.pm, lib/Test/Unit/TkTestRunner.pm, lib/Test/Unit/UnitHarness.pm, lib/Test/Unit/tests/AllTests.pm, lib/Test/Unit/tests/ListenerTest.pm, lib/Test/Unit/tests/TestListenerTest.pm: Renamed Test::Unit::TestListener to Test::Unit::Listener * lib/Test/Unit/Decorator.pm: New file. * MANIFEST, lib/Test/Unit/Decorator.pm, lib/Test/Unit/TestDecorator.pm, lib/Test/Unit/TestSetup.pm: Renamed Test::Unit::TestDecorator to Test::Unit::Decorator * lib/Test/Unit/Loader.pm: New file. * ChangeLog, MANIFEST, lib/Test/Unit/HarnessUnit.pm, lib/Test/Unit/Loader.pm, lib/Test/Unit/TestListener.pm, lib/Test/Unit/TestLoader.pm, lib/Test/Unit/TkTestRunner.pm: Renamed Test::Unit::TestLoader to Test::Unit::Loader 2001-09-07 Piers Cawley * lib/Test/Unit/TestCase.pm (run_bare): Made sure it returns true if it doesn't throw an exception. * lib/Test/Unit/tests/AssertTest.pm (test_fail_assert_not_equals): (test_success_assert_not_equals): Added tests for assert_not_equals. * lib/Test/Unit/Assert.pm Doc fixes. (assert_not_equals): Aadded the option to assert that things aren't equal. Also added appropriate (assert_(str|num)_not_equals) methods. 2001-09-02 Piers Cawley * lib/Test/Unit/Loader.pm (load): Improved the error message when a file can be found, but has a syntax error. * lib/Test/Unit/TestFailure.pm: Removed. * lib/Test/Unit/InnerClass.pm: Removed * lib/Test/Unit/tests/AssertTest.pm Switched to a ResultsMatrix style of testing. Seems to work quite well... * lib/Test/Unit/Assert.pm (is_numeric): Got rid of warnings when the argument isn't numeric. * t/all_tests.t: * t/assert_test.t: Got rid of C since blib should be handling that. * lib/Test/Unit/tests/TestTest.pm: Basic refactoring to use Class::Inner. (make_dummy_testcase): New helper method to make anonymous classes used in many of the tests. * lib/Test/Unit/Assertion/Boolean.pm (do_assertion): Switched to a slightly more sensible way of generating failure messages. * lib/Test/Unit/Loader.pm (load): Changed the order in which we call C and C. * lib/Test/Unit/TestResult.pm: Removed dependency on Test::Unit::TestFailure. * lib/Test/Unit/ExceptionError.pm (make_from_error_simple): Fixed things up slightly. This method maybe needs a leading underscore; Framework users should probably never see it... * lib/Test/Unit/Assertion.pm (fail): Fixed things to put appropriate information into the thrown exception. * lib/Test/Unit/Assert.pm: General refactoring work to get things working with the CPAN modules. (assert): Now, when an exception is generated, we try and get the appropriate caller information for setting -line and -file. Which is nice. (assert_equals): Fixed to use try/catch. Fixed a nasty bug with @_ getting silently emptied via try, so now, before we call try, we copy @_ to @args and use that inside the closure, otherwise assert_equals would always return true. (assert_str_equals,assert_num_equals,assert_null,assert_not_null): All now set $Error::Depth correctly. * lib/Test/Unit/Exception.pm (stringify): Tidied up stringification. (failed_test, thrown_exception): We now conform to the Test::Unit::TestFailure interface. Which means that we can get rid of Test::Unit::TestFailure itself. Which is nice. * lib/Test/Unit.pm: Switched to using Devel::Symdump, Class::Inner and Error (assert): Moved to the try/catch style. (create_suite): Vaguely major refactoring. Switched to using Devel::Symdump and Class::Inner instead of the hand rolled symbol table manipulation and Test::Unit::InnerClass 2001-08-31 Piers Cawley * lib/Test/Unit.pm: Fixed a silly typo induced bug. * MANIFEST, MANIFEST.SKIP, Makefile.PL, examples/patch100132, examples/procedural-adding-suites-example.pl, examples/procedural-another-package-example.pl, examples/procedural-fail-example.pl, examples/procedural-ok-example.pl, lib/Test/Unit.pm, lib/Test/Unit/Assertion.pm, lib/Test/Unit/Assertion/Boolean.pm, lib/Test/Unit/Assertion/CodeRef.pm, lib/Test/Unit/Assertion/Regexp.pm, lib/Test/Unit/Exception.pm, lib/Test/Unit/ExceptionError.pm, lib/Test/Unit/HarnessUnit.pm, lib/Test/Unit/InnerClass.pm, lib/Test/Unit/Test.pm, lib/Test/Unit/TestCase.pm, lib/Test/Unit/TestDecorator.pm, lib/Test/Unit/TestFailure.pm, lib/Test/Unit/TestLoader.pm, lib/Test/Unit/TestResult.pm, lib/Test/Unit/TestRunner.pm, lib/Test/Unit/TestSetup.pm, lib/Test/Unit/TestSuite.pm, t/try_examples.t: Beginnings of a major refactoring. 1. Replace Test::Unit::InnerClass with Class::Inner 2. Use Error.pm as the basis for exception handling and try/catch/... in place of eval. 3. Use Devel::Symdump in place of hand rolled symbol table manipulation. 4. Also includes an attempt at an 'assert_equals' that does the right thing in most cases. Tries to make reasonable guesses about numeric or string comparison, and can make use of object based equality things. 5. Started to port jUnit tests that make sense in the context of PerlUnit. TODO: Need to get the procedural Test::Unit working. Or abandon it. However, it does do some stuff that Test::More and friends don't (no plan testing that actually produces a sensible 'test count') Write more tests. (Patches welcome) * t/assert.t: Calls the (too) simple set of tests for Test::Unit::Assert and friends. * t/assert.t: New file. 2001-08-30 Piers Cawley * lib/Test/Unit/Assert.pm: Removed some warnings when called with 'undef'. Also added a stringification of undef to when reporting failures... 2001-06-18 Christian Lemburg * Changes, MANIFEST, examples/README, examples/fail_example.pm, lib/Test/Unit.pm, lib/Test/Unit/TestDecorator.pm, lib/Test/Unit/TestResult.pm, lib/Test/Unit/TestSetup.pm: added TestSetup and TestDecorator by Kevin Connor 2001-05-05 Christian Lemburg * README, Changes: for version 0.14 * t/try_examples.t: do not assume order of tests will be constant * lib/Test/Unit/Assertion/Boolean.pm: fix for problem with use base and older perls * lib/Test/Unit/Assert.pm: document Piers additions * lib/Test/Unit.pm: new version, updated team member list 2001-04-27 Matthew Astley * t/try_examples.t: add redirection warning for Win32 2001-04-09 Matthew Astley * doc/consensus.txt: wittering about packaging, plus my vague plan for things I fancy doing * t/try_examples.t: checks STDOUT & STDERR together, from invoking the examples doesn't look at return codes 2001-03-19 Piers Cawley * lib/Test/Unit.pm, lib/Test/Unit/InnerClass.pm, lib/Test/Unit/TestSuite.pm, lib/Test/Unit/UnitHarness.pm: Redid Test::Unit::InnerClass to be more 'classlike'. (ie, calling Test::Unit::InnerClass::make_inner_class as a class method rather than as a direct subroutine call) Added Test::Unit::InnerClass::make_inner_class_with_coderefs Instead of taking an extension_text argument, takes a hash of coderefs and uses the keys as method names. Lets you do closure magic and the like when creating inner classes. Moved Test::Unit::InnerClass::make_inner_class to T::U::IC::make_inner_class_with_text. The make_inner_class subroutine now looks at $_[2] to determine whether to dispatch to the _with_text version of the method or the _with_coderefs version. Modified all the clients of Test::Unit::InnerClass to do proper Class based method dispatch. Modified Test::Unit::tests::TestTest to create some of its inner classes using the 'hash of coderefs' approach. Didn't do the documentation yet. 2001-03-17 Christian Lemburg * Makefile.PL: take version number for distribution file from lib/Test/Unit.pm * doc/release-checklist: changed to take distribution file version number from lib/Test/Unit.pm * doc/release-checklist: more documentation on release procedure * doc/release-checklist: added documentation on release procedure and explanation of version number stuff * lib/Test/Unit.pm: Added version number again, it has to be in the module, added explanation 2001-03-08 Piers Cawley * MANIFEST.SKIP, Makefile.PL, lib/Test/Unit/Assert.pm, lib/Test/Unit/Assertion.pm, lib/Test/Unit/Assertion/Boolean.pm, lib/Test/Unit/Assertion/CodeRef.pm, lib/Test/Unit/Assertion/Regexp.pm, lib/Test/Unit/Exception.pm, lib/Test/Unit/TestFailure.pm, lib/Test/Unit/TestRunner.pm, MANIFEST: Merged the pdc_coderefassert branch. 2001-03-07 Adam Spiers * lib/Test/Unit/TestCase.pm: add missing use 2001-03-06 Piers Cawley * doc/consensus.txt: Added some commentary * lib/Test/Unit/Assert.pm: Stopped Test::Unit::Assert::normalize_assert from dying when passed an object that can't 'do_assertion'. Instead treats it as the argument for Test::Unit::Assertion::Boolean::new. (Came across this bug while testing some of my 'real' code). This should also mean that, if you package Foo; use overload bool => sub {...} Then assertion will continue to work properly. I've added a test for the simple case -- T:U:t:TestTest::test_assert_with_non_assertion_object (essentially it's always going to be true in this instance), but not for the case where 'bool' is overridden. I'll leave that as an exercise for the interested reader (plus I'm not sure how to make inner classes do overrides). 2001-03-06 Matthew Astley * doc/consensus.txt: updates 2001-03-05 Piers Cawley * lib/Test/Unit/Assert.pm, lib/Test/Unit/Assertion.pm: Added some appropriate 'require's to these class files. * Makefile.PL, lib/Test/Unit/Assertion.pm, lib/Test/Unit/Assertion/Boolean.pm, lib/Test/Unit/Assertion/CodeRef.pm, lib/Test/Unit/Assertion/Regexp.pm: Added a bunch of documentation to T::U::Assertion and its subclasses. Removed the dependency on B::Deparse (I think. If someone who hasn't got this installed could test it...) 2001-03-05 Adam Spiers * t/fail.t: Removing to avoid misguided fails on `make test'. Brian can resurrect it if he wants when he resurfaces. * lib/Test/Unit/TestResult.pm: slightly more informative debug message in run() 2001-03-02 Piers Cawley * lib/Test/Unit/Assertion/Regexp.pm: Corrected a typo. * lib/Test/Unit/Assertion.pm, lib/Test/Unit/Assertion/Boolean.pm, lib/Test/Unit/Assertion/CodeRef.pm, lib/Test/Unit/Assertion/Regexp.pm: New file. * lib/Test/Unit/Assert.pm, lib/Test/Unit/Assertion.pm, lib/Test/Unit/Assertion/Boolean.pm, lib/Test/Unit/Assertion/CodeRef.pm, lib/Test/Unit/Assertion/Regexp.pm: Reified assertions. Added assertion classes for coderefs, regular expressions and booleans. Now Test::Unit::Assert::assert takes the first argument, the assertion, creates an appropriate assertion object, and calls the object's do_assertion method. This seems to be a win. Check out T::U::tests::SuiteTest and the 'basic_assertion' method. This is possibly using a coderef for the sake of it, but it's one way of testing it hard... If you check out T::U::tests::TestTest you'll see a big win on the regexp front. Instead of $self->assert(scalar("foo" =~ /bar/), "Should not match"); we have $self->assert(qr/bar/, "foo"); (I haven't worked out how to name such an assertion, but the default error message for that would look like: 'foo' did not match /(?-xism:bar)/ which is pretty useful already) 2001-02-28 Matthew Astley * doc/consensus.txt: append * lib/Test/Unit/TestCase.pm: Use the class 'isa' not the global one * doc/consensus.txt, lib/Test/Unit/TestCase.pm: fix exceptions that look like object names 2001-02-27 Matthew Astley * doc/consensus.txt: First cut should mention most current issues 2001-02-27 Piers Cawley * Makefile.PL: Added the B::Deparse prerequisite. * MANIFEST, lib/Test/Unit/Assert.pm, lib/Test/Unit/Exception.pm, lib/Test/Unit/TestFailure.pm, lib/Test/Unit/TestRunner.pm: Added an option to call assert with a coderef (currently using the coderef_assert method, but if this is accepted we'll make the 'assert' method DTRT.) Taken advantage of this to tidy up the kind of error reporting that gets done. Which is nice. Still needs a pile of work done, but I think it's a start. 2001-02-27 Christian Lemburg * lib/Test/Unit/TestCase.pm, lib/Test/Unit/TestSuite.pm: patch by Piers Cawley to fix overriden tests 2001-02-22 Adam Spiers * lib/Test/Unit/Exception.pm: fixed small bug where new() was assumed to be always used as an instance method and never as a class method * lib/Test/Unit/InnerClass.pm: - slightly improve legibility and remove need for no strict 'refs' - die with helpful error if compilation of inner class fails * lib/Test/Unit/HarnessUnit.pm: - make runner output more concise and legible - do not exit(-1) on failures, as that breaks TestHarness - output $exception->to_string() rather than $exception->stacktrace() to avoid hiding valuable error messages - standardise whitespace * lib/Test/Unit/TestListener.pm: fix trivial braino in croak message 2001-02-22 Matthew Astley * doc/release-checklist: Stash consensus reached so far on the mailing list 2001-02-20 Matthew Astley * lib/Test/Unit/Assert.pm, lib/Test/Unit/Exception.pm, lib/Test/Unit/ExceptionError.pm, lib/Test/Unit/ExceptionFailure.pm, lib/Test/Unit/HarnessUnit.pm, lib/Test/Unit/InnerClass.pm, lib/Test/Unit/Test.pm, lib/Test/Unit/TestCase.pm, lib/Test/Unit/TestFailure.pm, lib/Test/Unit/TestListener.pm, lib/Test/Unit/TestLoader.pm, lib/Test/Unit/TestResult.pm, lib/Test/Unit/TestRunner.pm, lib/Test/Unit/TestSuite.pm, lib/Test/Unit/TkTestRunner.pm, lib/Test/Unit/Tutorial.pm, lib/Test/Unit/UnitHarness.pm, lib/Test/Unit.pm: Fixes Bug#133287: Remove indentation from pod 2001-02-17 Christian Lemburg * README, Changes, Makefile.PL: version 0.13 * lib/Test/Unit.pm: removed misleading version info * lib/Test/Unit.pm: make people aware of message arg * examples/procedural-fail-example.pl: show that procedural interface can handle regex problem * lib/Test/Unit.pm: added function prototype for assert() * lib/Test/Unit/Assert.pm: added documentation about regex in boolean context * lib/Test/Unit/TkTestRunner.pm: make the GUI adhere to hide of stacktrace, too - patch by David Esposito * lib/Test/Unit/Assert.pm: mention optional message arg to assert - variant of patch by David Esposito * lib/Test/Unit/Assert.pm, lib/Test/Unit/TestCase.pm: corrected patch to hide backtrace 2001-02-06 Christian Lemburg * Changes, Makefile.PL, README, lib/Test/Unit.pm, lib/Test/Unit/Assert.pm, lib/Test/Unit/Exception.pm, lib/Test/Unit/TestCase.pm: added patch by Matthew Astley to quell backtrace on failed tests 2000-07-09 Christian Lemburg * lib/Test/Unit/TestCase.pm: Eliminated two blanks in pod documentation that caused problems 2000-05-07 Christian Lemburg * Changes, MANIFEST, README, test.pl: moved to standard CPAN style * examples/README: corrected typo * examples/Experimental/Sample.pm, examples/README, examples/patch100132, examples/patch100132-1, examples/patch100132-2: added explanation of examples, added reply to patch100132 2000-04-22 Christian Lemburg * lib/Test/Unit.pm, lib/Test/Unit/Assert.pm, lib/Test/Unit/Exception.pm, lib/Test/Unit/ExceptionError.pm, lib/Test/Unit/ExceptionFailure.pm, lib/Test/Unit/HarnessUnit.pm, lib/Test/Unit/InnerClass.pm, lib/Test/Unit/Test.pm, lib/Test/Unit/TestCase.pm, lib/Test/Unit/TestFailure.pm, lib/Test/Unit/TestListener.pm, lib/Test/Unit/TestLoader.pm, lib/Test/Unit/TestResult.pm, lib/Test/Unit/TestRunner.pm, lib/Test/Unit/TestSuite.pm, lib/Test/Unit/TkTestRunner.pm, lib/Test/Unit/Tutorial.pm, lib/Test/Unit/UnitHarness.pm: added and/or modified documentation * lib/Test/Unit/TestResult.pm, lib/Test/Unit/HarnessUnit.pm, lib/Test/Unit/InnerClass.pm, lib/Test/Unit/Test.pm, lib/Test/Unit/TestSuite.pm, lib/Test/Unit/Assert.pm, lib/Test/Unit/Exception.pm, lib/Test/Unit/ExceptionError.pm, lib/Test/Unit/ExceptionFailure.pm, lib/Test/Unit/Tutorial.pm: added documentation * lib/Test/Unit/TestCase.pm, lib/Test/Unit.pm: modified documentation * lib/Test/Unit.pm: added documentation 2000-03-06 Christian Lemburg * lib/Test/Unit/TestCase.pm: Fixed bug in POD * lib/Test/Unit/TestCase.pm: better documentation * lib/Test/Unit.pm: removed useless paranoid reload avoidance code 2000-03-05 Christian Lemburg * lib/Test/Unit/Tutorial.pm: container for tutorial on unit testing with framework * examples/procedural-adding-suites-example.pl: example for procedural API test suite composition feature * README: procedural API can now compose test suites, too * lib/Test/Unit.pm: added procedural API test suites composing feature add_suite() 2000-03-04 Christian Lemburg * README, examples/procedural-another-package-example.pl: added inter-package suite creation and run features to Procedural API * lib/Test/Unit.pm: added inter-package suite creation and run features * lib/Test/Unit/Exception.pm: changed stacktrace to begin at level of caller of Exception->new() * lib/Test/Unit/TestCase.pm: fixed run_bare() debug output to say it comes from run_bare, not _run_bare * lib/Test/Unit/HarnessUnit.pm, lib/Test/Unit/TestCase.pm: removed useless middleman _run() * lib/Test/Unit.pm: exported names will be seen on multiple uses, added filehandle arg to run_suite * lib/Test/Unit/TestRunner.pm: removed _run method, changed exit() to die() and return for ending run 2000-02-29 Christian Lemburg * lib/Test/Unit/TestCase.pm: first start at some documentation * lib/Test/Unit/Test.pm, lib/Test/Unit/TestSuite.pm: enlarged Test interface (name, to_string), TestSuite run() returns result * lib/Test/Unit/TestSuite.pm: fixed bug in eval subroutine run_test in warning() - missing right curly 2000-02-27 Brian Ewins * lib/Test/Unit/TkTestRunner.pm: Fixed copyright notice 2000-02-27 Christian Lemburg * README, examples/procedural-fail-example.pl, examples/procedural-ok-example.pl: removed use lib from procedural API examples, use -I on commandline instead 2000-02-26 Christian Lemburg * lib/Test/Unit/TestRunner.pm: TestRunner now also uses Benchmark for timing info * examples/procedural-fail-example.pl: show we also can handle messages ... has not been advertised yet ... * README, examples/procedural-fail-example.pl, examples/procedural-ok-example.pl, lib/Test/Unit.pm: first cut at a procedural API wrapper, with examples (see README) * lib/Test/Unit/Exception.pm: nicer output again * lib/Test/Unit/Exception.pm, lib/Test/Unit/TestFailure.pm: modified stringifying methods and their interplay for nicer output on errors * lib/Test/Unit/Test.pm, lib/Test/Unit/TestCase.pm: Test inherits from Assert now, so TestCase and TestSuite can now assert() 2000-02-25 Christian Lemburg * lib/Test/Unit/InnerClass.pm: removed use of constant module to avoid warnings when reloading in test 2000-02-25 Brian Ewins * lib/Test/Unit/TkTestRunner.pm: Fixed the File and About dialogs. 2000-02-24 Christian Lemburg * lib/Test/Unit/Exception.pm: separated to_string(), get_message(), and stacktrace() 2000-02-24 Brian Ewins * lib/Test/Unit/TkTestRunner.pm: Whoops forgot line to set the number of planned tests in progress bar... * TkTestRunner.pl, lib/Test/Unit/TestLoader.pm, lib/Test/Unit/TkTestRunner.pm, lib/Test/Unit/UnitHarness.pm: Many updates to GUI, now nearer to JUnit. Private stub exceptions/testcases used in UnitHarness to complete wrapping. 2000-02-23 Christian Lemburg * MANIFEST, README, lib/Test/Unit/InnerClass.pm, lib/Test/Unit/TestCase.pm, lib/Test/Unit/TestSuite.pm, lib/Test/Unit/UnitHarness.pm: fixed make_inner_class(), put it in own module, changed calls, added testcase 2000-02-23 Brian Ewins * lib/Test/Unit/HarnessUnit.pm, lib/Test/Unit/TkTestRunner.pm, lib/Test/Unit/UnitHarness.pm, t/fail.t: Lots of GUI bug fixes. Doh! * lib/Test/Unit/TestLoader.pm, lib/Test/Unit/TkTestRunner.pm: Bugfixes in GUI and Loader now recognizes arbitrary .pm's * lib/Test/Unit/TestLoader.pm, lib/Test/Unit/TkTestRunner.pm, lib/Test/Unit/UnitHarness.pm: Nicer looking but still incomplete GUI with all-new 'ArrayBar' widget. Support for '.t' tests added to TestLoader, so now GUI supports them again. Display of .t fails should be improved next... GUI shows progress correctly *except* when dealing with .t tests because 'plan()' method isnt implemented in TestRunner. Exception details dialog added. Currently the code to collect these details for .t tests (ie the 'verbose' output between ok/not ok messages) is not collected. 2000-02-22 Christian Lemburg * lib/Test/Unit/TestSuite.pm: fixed extraction of test suite to work across whole inheritance tree * lib/Test/Unit/TestResult.pm: deleted useless sanity check method clone_listeners * lib/Test/Unit/TestSuite.pm: resolved overloading of constructor by introducing string constructor empty_new * lib/Test/Unit/TestRunner.pm: deleted sub extract_class_name and changed suite method test to can() 2000-02-22 Brian Ewins * t/all_tests.t, lib/Test/Unit/HarnessUnit.pm, lib/Test/Unit/TestLoader.pm: Fleshed out HarnessUnit and implemented (sortof) tests for it. TestLoader was updated to recognize classes with a suite method. 2000-02-22 Christian Lemburg * lib/Test/Unit/TestCase.pm, lib/Test/Unit/TestResult.pm, lib/Test/Unit/TestRunner.pm, lib/Test/Unit/TestSuite.pm, README, test.pl: added TestSuite tests - 21 tests running OK 2000-02-21 Brian Ewins * README, TkTestRunner.pl, lib/Test/SuiteWrapper.pm, lib/Test/Unit/HarnessUnit.pm, lib/Test/Unit/TestListener.pm, lib/Test/Unit/TestLoader.pm, lib/Test/Unit/TestResult.pm, lib/Test/Unit/TestRunner.pm, lib/Test/Unit/TkTestRunner.pm, lib/Test/Unit/UnitHarness.pm: Integrated TkTestRunner. Added partial TestLoader and fleshed out TestListener. 2000-02-21 Christian Lemburg * lib/Test/Unit.pm: Deleted Unit.pm - it has been splitted to separate class files * MANIFEST, README, TestRunner.pl, lib/Test/Unit/Assert.pm, lib/Test/Unit/Exception.pm, lib/Test/Unit/ExceptionError.pm, lib/Test/Unit/ExceptionFailure.pm, lib/Test/Unit/Test.pm, lib/Test/Unit/TestCase.pm, lib/Test/Unit/TestFailure.pm, lib/Test/Unit/TestListener.pm, lib/Test/Unit/TestResult.pm, lib/Test/Unit/TestRunner.pm, lib/Test/Unit/TestSuite.pm, test.pl: Running first version, separate class files, CPAN style method names 2000-02-20 Brian Ewins * Changes, MANIFEST, Makefile.PL, examples/tester.pl, examples/tester.png, lib/Test/SuiteWrapper.pm, lib/Test/Unit.pm, test.pl: A work area for the new 'Test::Unit'. This currently contains: - standard CPAN bundling - Christian's test.pl and new Unit.pm (as lib/Test/Unit.pm) - my own 'Test::SuiteWrapper.pm', which works on test::harness tests; - examples/tester.pl - a Tk gui for using SuiteWrapper. - examples/tester.png - a screenshot. oooh. Test-Unit-0.28/PaxHeader/AUTHORS000644 000765 000024 00000000152 10273475041 016424 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/AUTHORS000644 000765 000024 00000005044 10273475041 014460 0ustar00rjbsstaff000000 000000 # PerlUnit was originally written as a port of Kent Beck and Erich # Gamma's xUnit testing framework by Christian Lemburg and Brian # Ewins, and is now maintained by Adam Spiers and the rest of the # PerlUnit team. # # The following is an alphabetical list of all the people who've # contributed code and effort to making PerlUnit what it is today. # Where possible we have included their Sourceforge usernames and # preferred email addresses. # # The use of this database for anything other than PerlUnit # development is strictly forbidden. (Passive distribution with the # PerlUnit source code package is naturally allowed) Adam Spiers adamspiers Brian Ewins ba22a Cayte Linder cayte Christian Lemburg clemburg David Esposito davide J.E. Fritz jefritz Kevin Connor wallisalviar Matthew Astley mca1001 (was mca-gdl) Michael Schwern/Test::More project for the deep structure comparison routines Piers Cawley pdcawley Zhon Johansen zhon As far as copyright years go (as if anyone cares), this may serve as a vague starting guide for who put together the bulk of the project: 2000 ba22a, clemburg 2001 clemburg, pdcawley 2002 adamspiers, pdcawley Where specific files in the project have been contributed by one person and that person has claimed the copyright, I have left their authorship. The rest of the files have moved over to a more boilerplate style crediting the PerlUnit Development Team and referring to the Test::Unit docs and this file. This is simply for maintenance sanity. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself: ------------------------------------------------------------------------------ Perl copyright: ------------------------------------------------------------------------------ Copyright 1989-2001, Larry Wall All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of either: a) the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version, or b) the "Artistic License" which comes with Perl. ------------------------------------------------------------------------------ The GNU GPL version 2 is included here in the file COPYING.GPL-2 . You may use version 1 instead, but it has been superceded for good reasons... The Artistic License is included here in the file COPYING.Artistic Test-Unit-0.28/PaxHeader/Changes000644 000765 000024 00000000152 07502137435 016652 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/Changes000644 000765 000024 00000004035 07502137435 014705 0ustar00rjbsstaff000000 000000 ****************************************************************************** * Due to lack of time, this file has been deprecated in favour of the * automatically generated ChangeLog file. Sorry. ****************************************************************************** Revision history for Perl extension Test::Unit. 0.14 - lots of changes and additions: Piers Cawley fixed a bad bug that caused inherited tests to be called on the parent class instead of the inheriting class. Piers Cawley also put in a lot of new functionality for regular expression assertions and coderef assertions. Matthew Astley fixed the POD documentation. Matthew Astley and Adam Spiers fixed a number of smaller things. Greatly improved formatting of failure reports. Version number is now (hopefully) handled correctly for CPAN. Kevin Connor ported Setup and TestDecorator to Perl. 0.13 - patched the patch from 0.12, added patches by David Esposito, (documentation for optional message arg to assert(), make TkTestRunner use to_string() for exception display), added documentation on problems in using assert() with regexes and messages, fixed these problems for the procedural style interface (where they can be solved) 0.12 - added patch by Matthew Astley (method to quell backtrace on failed tests, see Test::Unit::TestCase). 0.11 - fixed bugs in self tests that caused failed tests under HPUX and Solaris 0.1 - much revised and extended due to PerlUnit effort (see http://sourceforge.net/project?group_id=2653) - INCOMPATIBLE CHANGES: old interface style is discontinued (if you want support for this, use the old 0.06 version) - resembles JUnit approach much more closely - adapters to Test::Harness style tests - GUI test runner using Tk - stack traces for errors and failures - object-oriented implementation approach supporting test inheritance and test specialization 0.06 - first CPAN release 0.05 - initial release version 0.01 - 0.04 - development versions Test-Unit-0.28/PaxHeader/MANIFEST000644 000765 000024 00000000210 15113573111 016473 xustar00rjbsstaff000000 000000 30 mtime=1764685385.463484799 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/MANIFEST000644 000765 000024 00000004070 15113573111 014532 0ustar00rjbsstaff000000 000000 AUTHORS ChangeLog Changes COPYING.Artistic COPYING.GPL-2 doc/class-diagram.dia doc/class-diagram.png doc/class-diagram.txt doc/consensus.txt doc/release-checklist doc/TODO examples/Experimental/Sample.pm examples/fail_example.pm examples/patch100132 examples/patch100132-1 examples/patch100132-2 examples/README examples/tester.png lib/Test/Unit.pm lib/Test/Unit/Assert.pm lib/Test/Unit/Assertion.pm lib/Test/Unit/Assertion/Boolean.pm lib/Test/Unit/Assertion/CodeRef.pm lib/Test/Unit/Assertion/Exception.pm lib/Test/Unit/Assertion/Regexp.pm lib/Test/Unit/Debug.pm lib/Test/Unit/Decorator.pm lib/Test/Unit/Error.pm lib/Test/Unit/Exception.pm lib/Test/Unit/Failure.pm lib/Test/Unit/HarnessUnit.pm lib/Test/Unit/Listener.pm lib/Test/Unit/Loader.pm lib/Test/Unit/Procedural.pm lib/Test/Unit/Result.pm lib/Test/Unit/Runner.pm lib/Test/Unit/Runner/Terminal.pm lib/Test/Unit/Setup.pm lib/Test/Unit/Test.pm lib/Test/Unit/TestCase.pm lib/Test/Unit/TestRunner.pm lib/Test/Unit/TestSuite.pm lib/Test/Unit/TkTestRunner.pm lib/Test/Unit/Tutorial.pm lib/Test/Unit/UnitHarness.pm lib/Test/Unit/Warning.pm Makefile.PL MANIFEST This list of files README t/all_tests.t t/assert.t t/tlib/ActiveTestTest.pm t/tlib/AllTests.pm t/tlib/AssertTest.pm t/tlib/BadSuite/BadUse.pm t/tlib/BadSuite/SyntaxError.pm t/tlib/BadSuitesTest.pm t/tlib/ExceptionChecker.pm t/tlib/FilteredSuite.pm t/tlib/InheritedInheritedTestCase.pm t/tlib/InheritedSuite/OverrideNew.pm t/tlib/InheritedSuite/OverrideNewName.pm t/tlib/InheritedSuite/Simple.pm t/tlib/InheritedSuite/TestNames.pm t/tlib/InheritedTestCase.pm t/tlib/ListenerTest.pm t/tlib/NoTestCaseClass.pm t/tlib/NoTestCases.pm t/tlib/OneTestCase.pm t/tlib/OverrideTestCase.pm t/tlib/RunnerTest.pm t/tlib/Success.pm t/tlib/SuiteTest.pm t/tlib/TestAssertionCodeRef.pm t/tlib/TestObject.pm t/tlib/TestTest.pm t/tlib/TornDown.pm t/tlib/WasRun.pm t/tlib/WillDie.pm t/try_examples.t TestLister.pl TestRunner.pl TkTestRunner.pl META.yml Module YAML meta-data (added by MakeMaker) META.json Module JSON meta-data (added by MakeMaker) Test-Unit-0.28/PaxHeader/COPYING.Artistic000644 000765 000024 00000000152 10273474152 020172 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/COPYING.Artistic000644 000765 000024 00000013737 10273474152 016236 0ustar00rjbsstaff000000 000000 The "Artistic License" Preamble The intent of this document is to state the conditions under which a Package may be copied, such that the Copyright Holder maintains some semblance of artistic control over the development of the package, while giving the users of the package the right to use and distribute the Package in a more-or-less customary fashion, plus the right to make reasonable modifications. Definitions: "Package" refers to the collection of files distributed by the Copyright Holder, and derivatives of that collection of files created through textual modification. "Standard Version" refers to such a Package if it has not been modified, or has been modified in accordance with the wishes of the Copyright Holder as specified below. "Copyright Holder" is whoever is named in the copyright or copyrights for the package. "You" is you, if you're thinking about copying or distributing this Package. "Reasonable copying fee" is whatever you can justify on the basis of media cost, duplication charges, time of people involved, and so on. (You will not be required to justify it to the Copyright Holder, but only to the computing community at large as a market that must bear the fee.) "Freely Available" means that no fee is charged for the item itself, though there may be fees involved in handling the item. It also means that recipients of the item may redistribute it under the same conditions they received it. 1. You may make and give away verbatim copies of the source form of the Standard Version of this Package without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. 2. You may apply bug fixes, portability fixes and other modifications derived from the Public Domain or from the Copyright Holder. A Package modified in such a way shall still be considered the Standard Version. 3. You may otherwise modify your copy of this Package in any way, provided that you insert a prominent notice in each changed file stating how and when you changed that file, and provided that you do at least ONE of the following: a) place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or placing the modifications on a major archive site such as uunet.uu.net, or by allowing the Copyright Holder to include your modifications in the Standard Version of the Package. b) use the modified Package only within your corporation or organization. c) rename any non-standard executables so the names do not conflict with standard executables, which must also be provided, and provide a separate manual page for each non-standard executable that clearly documents how it differs from the Standard Version. d) make other distribution arrangements with the Copyright Holder. 4. You may distribute the programs of this Package in object code or executable form, provided that you do at least ONE of the following: a) distribute a Standard Version of the executables and library files, together with instructions (in the manual page or equivalent) on where to get the Standard Version. b) accompany the distribution with the machine-readable source of the Package with your modifications. c) give non-standard executables non-standard names, and clearly document the differences in manual pages (or equivalent), together with instructions on where to get the Standard Version. d) make other distribution arrangements with the Copyright Holder. 5. You may charge a reasonable copying fee for any distribution of this Package. You may charge any fee you choose for support of this Package. You may not charge a fee for this Package itself. However, you may distribute this Package in aggregate with other (possibly commercial) programs as part of a larger (possibly commercial) software distribution provided that you do not advertise this Package as a product of your own. You may embed this Package's interpreter within an executable of yours (by linking); this shall be construed as a mere form of aggregation, provided that the complete Standard Version of the interpreter is so embedded. 6. The scripts and library files supplied as input to or produced as output from the programs of this Package do not automatically fall under the copyright of this Package, but belong to whoever generated them, and may be sold commercially, and may be aggregated with this Package. If such scripts or library files are aggregated with this Package via the so-called "undump" or "unexec" methods of producing a binary executable image, then distribution of such an image shall neither be construed as a distribution of this Package nor shall it fall under the restrictions of Paragraphs 3 and 4, provided that you do not represent such an executable image as a Standard Version of this Package. 7. C subroutines (or comparably compiled subroutines in other languages) supplied by you and linked into this Package in order to emulate subroutines and variables of the language defined by this Package shall not be considered part of this Package, but are the equivalent of input as in Paragraph 6, provided these subroutines do not change the language in any way that would cause it to fail the regression tests for the language. 8. Aggregation of this Package with a commercial distribution is always permitted provided that the use of this Package is embedded; that is, when no overt attempt is made to make this Package's interfaces visible to the end user of the commercial distribution. Such use shall not be construed as a distribution of this Package. 9. The name of the Copyright Holder may not be used to endorse or promote products derived from this software without specific prior written permission. 10. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. The End Test-Unit-0.28/PaxHeader/t000755 000765 000024 00000000210 15113573111 015533 xustar00rjbsstaff000000 000000 30 mtime=1764685385.275860042 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/t/000755 000765 000024 00000000000 15113573111 013643 5ustar00rjbsstaff000000 000000 Test-Unit-0.28/PaxHeader/README000644 000765 000024 00000000152 07502137752 016241 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/README000644 000765 000024 00000005627 07502137752 014304 0ustar00rjbsstaff000000 000000 NAME Test::Unit::* - a unit testing framework for Perl DESCRIPTION Test::Unit::* is a sophisticated unit testing framework for Perl that is derived from the JUnit testing framework for Java by Kent Beck and Erich Gamma. While this framework is originally intended to support unit testing in an object-oriented development paradigm (with support for inheritance of tests etc.), Test::Unit::Procedural is intended to provide a simpler interface to the framework that is more suitable for use in a scripting style environment. Therefore, Test::Unit::Procedural does not provide much support for an object-oriented approach to unit testing - if you want that, please have a look at Test::Unit::TestCase (also included in this install). A short tutorial on the object-oriented approach can be found in the documentation of Test::Unit::TestCase (the test base class). The Test::Unit self-test suite (contained in t/tlib) is a good example of this approach. There is also a GUI based interface to the testing framework. The "TkTestRunner.pl" script shows how to invoke it. The testing framework also features adapters for tests in the Test::Harness style to tests in the unit testing framework style and vice versa - see Test::Unit::HarnessUnit and Test::Unit::UnitHarness. An example of this approach is the self-test of the unit testing framework that you start with the 'make test' command (see t/all_tests.t). PREREQUISITES Class::Inner, Devel::Symdump and Error.pm are required. A new-ish version of base.pm (> 1.0) is required to avoid the problem where earlier versions failed to compile in the parent class. The Tk module is needed for the GUI. INSTALLATION Once you have installed the prerequisites, just perform the usual incantation (replacing 'x.yy' with the current version): gunzip Test-Unit-x.yy.tar.gz tar -xvf Test-Unit-x.yy.tar cd Test-Unit-x.yy perl Makefile.PL make make test make install AUTHOR Copyright (c) 2000, 2001 Christian Lemburg, . All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. Thanks go to the other PerlUnit framework people: Brian Ewins, Cayte Lindner, J.E. Fritz, Zhon Johansen, Piers Cawley, Adam Spiers Thanks for patches go to: Matthew Astley, David Esposito. SEE ALSO - Test::Unit::TestCase (included in this install) - the README file in the examples directory - Refactoring -- Improving The Design Of Existing Code. Martin Fowler. Addison-Wesley, 1999. - http://www.xProgramming.com/ EXAMPLES Use TestRunner.pl like this (lib adjusted for this directory): perl -w -I./lib -I./t/tlib TestRunner.pl AllTests Use TkTestRunner like this: perl -w -I./lib -I./t/tlib TkTestRunner.pl AllTests Test-Unit-0.28/PaxHeader/COPYING.GPL-2000644 000765 000024 00000000152 10273474152 017171 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/COPYING.GPL-2000644 000765 000024 00000043110 10273474152 015221 0ustar00rjbsstaff000000 000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. Test-Unit-0.28/PaxHeader/examples000755 000765 000024 00000000210 15113573111 017106 xustar00rjbsstaff000000 000000 30 mtime=1764685385.273822586 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/examples/000755 000765 000024 00000000000 15113573111 015216 5ustar00rjbsstaff000000 000000 Test-Unit-0.28/PaxHeader/META.yml000644 000765 000024 00000000210 15113573111 016613 xustar00rjbsstaff000000 000000 30 mtime=1764685385.335052673 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/META.yml000644 000765 000024 00000001053 15113573111 014650 0ustar00rjbsstaff000000 000000 --- abstract: unknown author: - unknown build_requires: ExtUtils::MakeMaker: '0' configure_requires: ExtUtils::MakeMaker: '0' dynamic_config: 1 generated_by: 'ExtUtils::MakeMaker version 7.76, CPAN::Meta::Converter version 2.150010' license: unknown meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: Test-Unit no_index: directory: - t - inc requires: Class::Inner: '0' Devel::Symdump: '0' Error: '0' base: '1' version: '0.28' x_serialization_backend: 'CPAN::Meta::YAML version 0.020' Test-Unit-0.28/PaxHeader/lib000755 000765 000024 00000000210 15113573111 016036 xustar00rjbsstaff000000 000000 30 mtime=1764685385.260756645 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/lib/000755 000765 000024 00000000000 15113573111 014146 5ustar00rjbsstaff000000 000000 Test-Unit-0.28/PaxHeader/Makefile.PL000644 000765 000024 00000000152 07403164645 017334 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/Makefile.PL000644 000765 000024 00000000755 07403164645 015374 0ustar00rjbsstaff000000 000000 use ExtUtils::MakeMaker; # See lib/ExtUtils/MakeMaker.pm for details of how to influence # the contents of the Makefile that is written. require 5.005; WriteMakefile( 'NAME' => 'Test::Unit', 'VERSION_FROM' => 'lib/Test/Unit.pm', # finds $VERSION 'PREREQ_PM' => { Class::Inner => 0, Devel::Symdump => 0, Error => 0, base => 1, }, ); Test-Unit-0.28/PaxHeader/doc000755 000765 000024 00000000210 15113573111 016035 xustar00rjbsstaff000000 000000 30 mtime=1764685385.274169794 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/doc/000755 000765 000024 00000000000 15113573111 014145 5ustar00rjbsstaff000000 000000 Test-Unit-0.28/PaxHeader/TestRunner.pl000644 000765 000024 00000000152 07403156701 020022 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/TestRunner.pl000644 000765 000024 00000000413 07403156701 016051 0ustar00rjbsstaff000000 000000 #!/usr/bin/perl -w use strict; use Test::Unit::Debug qw(debug_pkgs); use Test::Unit::TestRunner; # Uncomment and edit to debug individual packages. #debug_pkgs(qw/Test::Unit::TestCase/); my $testrunner = Test::Unit::TestRunner->new(); $testrunner->start(@ARGV); Test-Unit-0.28/PaxHeader/META.json000644 000765 000024 00000000207 15113573111 016771 xustar00rjbsstaff000000 000000 29 mtime=1764685385.43547421 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/META.json000644 000765 000024 00000001715 15113573111 015025 0ustar00rjbsstaff000000 000000 { "abstract" : "unknown", "author" : [ "unknown" ], "dynamic_config" : 1, "generated_by" : "ExtUtils::MakeMaker version 7.76, CPAN::Meta::Converter version 2.150010", "license" : [ "unknown" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : 2 }, "name" : "Test-Unit", "no_index" : { "directory" : [ "t", "inc" ] }, "prereqs" : { "build" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "configure" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "runtime" : { "requires" : { "Class::Inner" : "0", "Devel::Symdump" : "0", "Error" : "0", "base" : "1" } } }, "release_status" : "stable", "version" : "0.28", "x_serialization_backend" : "JSON::PP version 4.16" } Test-Unit-0.28/doc/PaxHeader/class-diagram.dia000644 000765 000024 00000000152 10273776502 021315 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/doc/class-diagram.dia000644 000765 000024 00001520420 10273776502 017352 0ustar00rjbsstaff000000 000000 #A4# #Test::Unit::Failure# ## ## #Test::Unit::Assert# ## ## #assert# ## ## ## #normalize_assertion# ## ## ## #assert_raises# ## ## ## #do_assertion# ## ## ## #multi_assert# ## ## ## #is_numeric# ## ## ## #assert_equals# ## ## ## #ok# ## ## ## #assert_not_equals# ## ## ## #assert_deep_equals# ## ## ## #_deep_check# ## ## ## #_eq_array# ## ## ## #_eq_hash# ## ## ## #_format_stack# ## ## ## #fail# ## ## ## #error# ## ## ## #quell_backtrace# ## ## ## #get_backtrace_on_fail# ## ## ## #Test::Unit::Procedural# ## ## #add_to_suites# ## ## ## #assert# ## ## ## #create_suite# ## ## ## #run_suite# ## ## ## #add_suite# ## ## ## #Test::Unit::Error# ## ## #make_new_from_error# ## ## ## #Test::Unit::Result# ## ## #_Listeners# ## ## ## #_Errors# ## ## ## #_Failures# ## ## ## #_Run_tests# ## ## ## #_Stop# ## ## ## #new# ## ## ## #tell_listeners# ## ## ## #add_error# ## ## ## #add_failure# ## ## ## #add_pass# ## ## ## #add_listener# ## ## ## #listeners# ## ## ## #end_test# ## ## ## #error_count# ## ## ## #errors# ## ## ## #failure_count# ## ## ## #failures# ## ## ## #run# ## ## ## #run_protected# ## ## ## #run_count# ## ## ## #run_count_inc# ## ## ## #should_stop# ## ## ## #start_test# ## ## ## #stop# ## ## ## #was_successful# ## ## ## #to_string# ## ## ## #Test::Unit::Loader# ## ## #obj_load# ## ## ## #compile# ## ## ## #compile_class# ## ## ## #compile_file# ## ## ## #load# ## ## ## #load_test# ## ## ## #load_test_suite# ## ## ## #load_test_case# ## ## ## #extract_testcases# ## ## ## #load_test_harness_test# ## ## ## #load_test_dir# ## ## ## #get_package_name_from_file# ## ## ## #Test::Unit::Runner::Terminal# ## ## #_last_test# ## ## ## #start_suite# ## ## ## #end_suite# ## ## ## #start_test# ## ## ## #end_test# ## ## ## #add_error# ## ## ## #add_failure# ## ## ## #add_pass# ## ## ## #_update_status# ## ## ## #print_result# ## ## ## #Test::Unit::Assertion# ## ## #fail# ## ## ## #do_assertion# ## ## ## #new# ## ## ## #Test::Unit::UnitHarness# ## ## #_Name# ## ## ## #_Names# ## ## ## #new# ## ## ## #run# ## ## ## #name# ## ## ## #names# ## ## ## #add_test# ## ## ## #add_test_method# ## ## ## #count_test_cases# ## ## ## #to_string# ## ## ## #warning# ## ## ## #Test::Unit::TkTestRunner# ## ## #frame# ## ## ## #number_of_errors# ## ## ## #number_of_failures# ## ## ## #failure_list# ## ## ## #failed_tests# ## ## ## #exceptions# ## ## ## #planned# ## ## ## #suite_name# ## ## ## #suite_label# ## ## ## #suite_field# ## ## ## #add_text_listener# ## ## ## #run# ## ## ## #progress_bar# ## ## ## #failure_label# ## ## ## #quit_button# ## ## ## #rerun_button# ## ## ## #show_error_button# ## ## ## #status_line_box# ## ## ## #runs# ## ## ## #status_line# ## ## ## #listbox# ## ## ## #number_of_runs# ## ## ## #runner# ## ## ## #result# ## ## ## #start_time# ## ## ## #finish_time# ## ## ## #run_time# ## ## ## #new# ## ## ## #about# ## ## ## #add_error# ## ## ## #add_failure# ## ## ## #append_failure# ## ## ## #plan# ## ## ## #choose_file# ## ## ## #create_punit_menu# ## ## ## #create_menus# ## ## ## #create_ui# ## ## ## #end_test# ## ## ## #get_test# ## ## ## #is_error_selected# ## ## ## #load_frame_icon# ## ## ## #main# ## ## ## #rerun# ## ## ## #reset# ## ## ## #run# ## ## ## #run_failed# ## ## ## #run_suite# ## ## ## #show_error_trace# ## ## ## #show_info# ## ## ## #show_status# ## ## ## #start# ## ## ## #start_test# ## ## ## #add_pass# ## ## ## #update# ## ## ## #add_to_history# ## ## ## #Test::Unit::Assertion::CodeRef# ## ## #new# ## ## ## #do_assertion# ## ## ## #to_string# ## ## ## #Test::Unit::HarnessUnit# ## ## #_Print_stream# ## ## ## #new# ## ## ## #print_stream# ## ## ## #_print# ## ## ## #start_test# ## ## ## #not_ok# ## ## ## #ok# ## ## ## #add_error# ## ## ## #add_failure# ## ## ## #add_pass# ## ## ## #end_test# ## ## ## #do_run# ## ## ## #main# ## ## ## #run# ## ## ## #start# ## ## ## #Test::Unit::Assertion::Exception# ## ## #new# ## ## ## #do_assertion# ## ## ## #to_string# ## ## ## #Test::Unit::Setup# ## ## #run# ## ## ## #set_up# ## ## ## #tear_down# ## ## ## #Test::Unit::Runner# ## ## #_result# ## ## ## #_suites_running# ## ## ## #_filter# ## ## ## #create_test_result# ## ## ## #result# ## ## ## #start_suite# ## ## ## #end_suite# ## ## ## #suites_running# ## ## ## #filter# ## ## ## #reset_filter# ## ## ## #Test::Unit::Assertion::Boolean# ## ## #new# ## ## ## #do_assertion# ## ## ## #to_string# ## ## ## #Test::Unit::UnitHarness::Exception# ## ## #stacktrace# ## ## ## #new# ## ## ## #stacktrace# ## ## ## #Test::Unit::TestCase# ## ## #__PACKAGE__ . "_annotations# ## ## ## #__PACKAGE__ . "_name# ## ## ## #new# ## ## ## #annotate# ## ## ## #annotations# ## ## ## #count_test_cases# ## ## ## #create_result# ## ## ## #name# ## ## ## #run# ## ## ## #run_bare# ## ## ## #run_test# ## ## ## #set_up# ## ## ## #tear_down# ## ## ## #to_string# ## ## ## #make_test_from_coderef# ## ## ## #list_tests# ## ## ## #get_matching_methods# ## ## ## #list# ## ## ## #Test::Unit::TestSuite# ## ## #_Name# ## ## ## #_Tests# ## ## ## #empty_new# ## ## ## #new# ## ## ## #suite# ## ## ## #name# ## ## ## #names# ## ## ## #list# ## ## ## #add_test# ## ## ## #count_test_cases# ## ## ## #run# ## ## ## #filter_test# ## ## ## #test_at# ## ## ## #test_count# ## ## ## #tests# ## ## ## #to_string# ## ## ## #add_warning# ## ## ## #Test::Unit::Exception# ## ## #_hide_backtrace# ## ## ## #throw_new# ## ## ## #stacktrace# ## ## ## #get_message# ## ## ## #hide_backtrace# ## ## ## #stringify# ## ## ## #to_string# ## ## ## #failed_test# ## ## ## #thrown_exception# ## ## ## #Test::Unit::Test# ## ## #count_test_cases# ## ## ## #run# ## ## ## #name# ## ## ## #to_string# ## ## ## #filter_method# ## ## ## #filter# ## ## ## #_find_sym# ## ## ## #MODIFY_CODE_ATTRIBUTES# ## ## ## #Test::Unit::Listener# ## ## #new# ## ## ## #start_suite# ## ## ## #start_test# ## ## ## #add_error# ## ## ## #add_failure# ## ## ## #end_test# ## ## ## #Test::Unit::Decorator# ## ## #_fTest# ## ## ## #new# ## ## ## #basic_run# ## ## ## #count_test_cases# ## ## ## #run# ## ## ## #to_string# ## ## ## #get_test# ## ## ## #Test::Unit::Assertion::Regexp# ## ## #new# ## ## ## #do_assertion# ## ## ## #to_string# ## ## ## #Test::Unit::TestRunner# ## ## #_Print_stream# ## ## ## #new# ## ## ## #print_stream# ## ## ## #_print# ## ## ## #add_error# ## ## ## #add_failure# ## ## ## #add_pass# ## ## ## #do_run# ## ## ## #end_test# ## ## ## #main# ## ## ## #print_result# ## ## ## #print_errors# ## ## ## #print_failures# ## ## ## #print_header# ## ## ## #run# ## ## ## #run_and_wait# ## ## ## #start# ## ## ## #start_test# ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## #Error# ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## #Test::Unit::Warning# ## ## #_message# ## ## ## #run_test# ## ## ## #new# ## ## ## #Test::Unit::UnitHarness::TestCase# ## ## #run_test# ## ## ## #(c) 2005 PerlUnit project <http://perlunit.sf.net/> Class diagram generated by autodia <http://droogs.org/autodia> and some tweaking, for "v0.24 plus bugfixes and filtering", the CVS "HEAD" version 2005-07-01# #See doc/class-diagram.txt for caveats!# Test-Unit-0.28/doc/PaxHeader/TODO000644 000765 000024 00000000152 10324276751 016615 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/doc/TODO000644 000765 000024 00000020557 10324276751 014657 0ustar00rjbsstaff000000 000000 PerlUnit TODO ============= Here's our roadmap. It should give you an idea of what is planned, and in some cases when it's planned for and/or who's going to do it. Only update this file on the main branch! See also doc/consensus.txt. * Before release 1.0 None of these are big jobs, but Adam thinks they should all be done before 1.0 if we want the framework to gain respect and widespread usage; after all, many people will check out PerlUnit for the first time when they hear 1.0 being announced, and first impressions count for a lot. ** Rename Test::Unit::HarnessUnit and Test::Unit::UnitHarness Not sure what to yet, but we want to get these big API changes out of the way before we bump the version number. *** HarnessUnit "A Test::Unit::Runner which outputs Test::Harness-style output" Used for most of our self-tests. *** UnitHarness "A makeover of Test::Harness to allow its tests to be retrofitted as unit tests". Seems to need some work, but is neat for running t/*.t What uses it? I can't see anything here, but we may have real live (and quiet) users. It's referenced from T:U:Loader, but only used for certain inputs. ** Get working build on 5.7.2 and 5.8.0 Now seems happy on Debian 5.8.4-2, and I'll cheerfully let the cpan-testers find out about the others. ** Rename do_run to run_suite in the runners. Is this to match T:U:Procedural and T:U:TkTestRunner ? ** Tidy up copyrights, credits, and licensing We had copyrights, licenses, and out of date author attributions in pretty much every file in the distribution. Tidied up 2005-07 mca. > It would be good to move all the copyrights and credits into one or > two files (COPYING or LICENSE or AUTHORS, say), There are still some single-author files: T:U:Assertion* T:U:Decorator T:U:Setup T:U:Tutorial > and then to change the licensing/credit bits and pieces in all the > other files into something which refers to that one file, and also > states that none of the files should be distributed separately, only > as an entire package, thereby preventing the copyright-containing > file from being disassociated from the others. Well I've done a chunk of that. It's not clear that the project licences need or seek to prevent dissociation of files from the project. * Document stuff better ** TestRunner::do_run should be public Requested by Matthias Ferber, so that suites can be dynamically generated by providing parameters. ** Filtering mechanism is poorly documented. ** Test::Unit::Tutorial is AWOL ** examples are old and sparse Useful stuff has been on the lists... ** class diagram We have one at doc/class-diagram.* Dunno if it's much good. Notes include specific TODOs at the bottom. * Nice to have before 1.0 Some of these could be left until after 1.0. Adam thinks it makes sense to do them before the release, however; none of them are big jobs. ** @TESTS isn't tested. ** Pinch more assertions from Test::More I don't think there's even any particular reason against importing them directly from Test::More. No point in duplicating code across CPAN modules without good reason. I like these ones: *** use_ok(), require_ok(), eq_set() import straight in *** is_deeply() either import or write using FreezeThaw::cmpStr or Data::Compare or whatever *** eq_array(), eq_hash() Hmm. Test::Unit::Assertion::Array / Test::Unit::Assertion::Hash? *** Easier assertion-set extensibility mca: I extend test cases by having a standard (for me) superclass, into which I pile assorted stuff. It would be nice to provide such functionality easily and without kinking everyone's inheritance tree. Also, may need to avoid bloating the standard assertions set. The overhead for the compiler is small, but the learning curve ends up looking much steeper than it needs to be. Options... - provide "simple" and "hedgehog (bristling)" versions of TestCase - use import options to determine assertion set - leave them all in, but split the documentation - spread them into Piers' T:U:A:* structure... need to investigate ** Rethink how the tests are split up between the t/*.t. Currently we have t/all_tests.t, which is clearly a misnomer, and we have some tests for the assertion code being run from that rather than from t/assert.t. ** Test::Unit::Loader working with whole directories. Test::Unit::Loader::load_test_dir() needs to be finished. * After 1.0 No harm done if they end up being done before 1.0 though, of course. ** Test filtering Piers suggested the beautiful idea of using Attribute::Handlers so you could do things like: sub test_something : todo {...} sub test_something : skip_if() {...} sub test_something : skip {...} Adam needs this for work ASAP, and will probably implement it very soon. There is already a primitive filtering mechanism in place which is controlled by the filter() and filter_method() methods. Update: Adam met up with Piers a few months ago and together they figured out that Attribute::Handlers may be unusable due to its magic happening in the BEGIN phase, whereas all user test code gets compiled at run-time via Test::Unit::Loader. Hmm. ** Tests to add *** PerlUnit selftests **** die errors that look like variable names [mca] A test that fails with an error like die '$lotsofdollars'; and make sure it gets wrapped into an ExceptionError **** doing the right OOP thing in constructors and isa() checks Possibly a test that overrides the 'isa' method so Piers' fix to my patch (back to using $exception->isa(C) instead of UNIVERSAL::isa($exception,C)) can be exercised. Also Adam has patched some of the PerlUnit constructors to allow passing a classname instead of being invoked as a method. **** check for broken Error.pm overloading of exceptions [as] Older Error.pms don't do boolean overload, so eval { ... }; if ($@) { ... } could break. We should check for that. *** Generic tests for users to include Matthew wrote some. Whether anyone else wants them remains to be seen. The potentially useful ones: **** test_SubsAllNeedTests Checks all subs in a module are tested. Take the code and put it somewhere else. **** test_PodChecker Look the sourcecode up in %INC and run it through the Pod::Checker (which spits out stuff to STDOUT regardless). **** test_HaveWarnings Check $^W .. a bit cheeky. I was actually after a check for strictness, after forgetting to use it in some module I broke off, but this is either tricky or impossible. [Impossible I believe. That's kind of the point of lexical scope after all -- pdc] *** Test coverage tests There was a big thread on this but it's someone else's turn to write about that. 8-) -- mca Current thinking is to keep test-coverage tests away from the executed tests, mainly so you can have a script which draws a pretty chart of how well your code is tested. Adam has some code for this. * Personal TODO lists Moved here from doc/consensus.txt. ** Matthew tktestrunner: ctrl-q, file menu shortcut assert_deep_equals patches: check Test::More for updates can we do that direct use linkage? do I need to backport the patches we have? move the scripts somewhere so they get installed in a bin/ put version numbers in all modules (my or our or oldestyle?) as below, - if derived from CVS, with a note somewhere about bumping CVS versions if files take non-linear routes somewhere - cd src/Test-Unit; grep -rL VERSION lib/ | grep -v CVS/ *** integrate Debianisations and credit the relevant folks /usr/share/doc/libtest-unit-perl/changelog.Debian.gz note, dropped from Debian unstable: http://bugs.debian.org/279805 http://bugs.debian.org/317416 *** update top-level README *** Periodic checks (should go in doc/release-checklist, or better yet in an installation test) Search for Test::* and check they still exist Search for 'package' ... UnitHarness contains >1 http://www.cpan.org/modules/04pause.html says: Please make sure all your *.pm files contain a $VERSION variable that conforms to the CPAN rules, i.e. the complete computation of $VERSION must take place on the one first line within the module that assigns to it. You can test if this is the case by running perl -MExtUtils::MakeMaker -le 'print MM->parse_version(shift)' 'file' *** Find a neat way to run unit-tested programs without the suite It's convenient for medium sized projects to stick the test subs in the classes they test, but then you have a run-time dependence on perlunit. **** Local Variables: **** mode: outline **** End: Test-Unit-0.28/doc/PaxHeader/release-checklist000644 000765 000024 00000000152 10324276751 021437 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/doc/release-checklist000644 000765 000024 00000015105 10324276751 017472 0ustar00rjbsstaff000000 000000 This is out of date in places. I haven't investigated which places. Note that there are multiple bug trackers, listed here in what mca considers the order of preference, http://sourceforge.net/tracker/?group_id=2653&atid=102653 http://rt.cpan.org/NoAuth/Bugs.html?Dist=Test-Unit http://bugs.debian.org/libtest-unit-perl Also note use of ChangeLog instead of Changes, and parts of doc/TODO ------------------------------------------------- The procedure should be: ------------------------------------------------- Prerequisites: Make sure all the tests run OK. Make sure all the examples run OK. 1. Commit new files in src/Test-Unit 2. lib/Test/Unit.pm - put in the new $VERSION for the distribution 3. MANIFEST if files are to be added to the tarball ("make manifest" will add new files and tell you, but check they're not local cruft from your working copy. Get a clean checkout of the working copy to ensure no files are missing, or that you have removed deleted files from MANIFEST.) 4. cvs rtag -r HEAD REL_0_14 releasemodule (with the $VERSION number from above) 5. make clean ; perl Makefile.PL ; make tardist 6. upload to incoming as per Sourceforge docs 7. notify current CPAN maintainer to get an upload ------------------------------------------------- Explanation on version number synchronization: ------------------------------------------------- The CPAN module will decide to upgrade a module when the version number of the module installed locally is less than the highest version number of any version of the module it can find on CPAN. It will find out the distribution file this module is in, and then install this distribution file. This can lead to surprising results for distribution files that contain multiple modules. Take this common situation: package Foo-0.22.tar.gz contains modules Foo, Foo::Bar, and Foo::Baz. Now, something changes in Foo::Bar, and Foo::Bar gets a new version number. The module author happily uploads Foo-0.23.tar.gz to CPAN. Now, will the CPAN module use Foo-0.23.tar.gz to upgrade package Foo if you tell it "install Foo"? No. CPAN will look at the version number for Foo, determine it has not changed compared to the locally installed version, and do nothing. You have to tell it "install Foo::Bar" to get the new distribution file, which is bad, since nobody will know she has to do that. The solution is to make sure any time a distribution file gets upgraded, its top level module should get a new, higher version number. This way, things will work like people expect them to work. Please note that any module on CPAN should have a version number, even if it is contained in a package with many other modules. This ensures that people can require a certain version of any module in a given distribution file. ------------------------------------------------- References ------------------------------------------------- Date: Wed, 21 Feb 2001 14:06:35 +0000 From: Matthew Astley To: perlunit-devel@lists.sourceforge.net Subject: Re: [Perlunit-devel] CVS tags / release procedure Message-ID: <20010221140635.P25661@grantadesign.com> References: <20010220215614.H25661@grantadesign.com> <000901c09bf0$a1641140$9f0010ac@aixonix.de> <20010221130709.A9412@thelonious.new.ox.ac.uk> <20010220215614.H25661@grantadesign.com> <000901c09bf0$a1641140$9f0010ac@aixonix.de> In-Reply-To: <000901c09bf0$a1641140$9f0010ac@aixonix.de>; from lemburg@aixonix.de on Wed, Feb 21, 2001 at 11:25:36AM +0100 On Wed, Feb 21, 2001 at 11:25:36AM +0100, Christian Lemburg wrote: > OK so far, I suggest to replace the manual tar with > "make clean ; perl Makefile.PL ; make tardist" > (your perl will do the Right CPAN Thing for you). [revised] Commit new files in src/Test-Unit-0.1 including - Changes (section for release at the top) - Makefile.PL (set new $VERSION) - README (Version numbers on installation commands .. surely we could put something generic in here?) - MANIFEST if files are to be added to the tarball cvs rtag -r HEAD REL_0_14 releasemodule cvs exp -r REL_0_14 -d Test-Unit-n.nn src/Test-Unit-0.1 make clean ; perl Makefile.PL ; make tardist (upload to incoming as per Sourceforge docs) As for the CPAN stuff, is this complicated? Presumably the significant changes are documented in ExtUtils::MakeMaker? Also, since there's filtering via MANIFEST, is there any need to 'export' instead of running from a checked out working copy? Could Makefile.PL enquire of CVS or the top of the Changes file which version we're releasing? I'm thinking about reducing the number of things that need trivial tweaks before making a release. > > I'm left thinking that it could be handy to tag files as development > > only, so for example I could drop my GenericTests.pm into place but > > tag it as mine/not for release. It's rather hard for someone to commit > > on a patch, I think? So we've a solution to this separate problem, but perhaps we should hold off the feature creep until we've got more tests in? (any bright ideas for ways to tie the docs to the tests so the can fail a test when we tweak things? I'm just about to digress hugely so I'll save it for another post) > > * tag release stuff as STABLE or similar, then do > > > > cvs rtag -r STABLE REL_0_14 releasemodule [patches commands above, nb. "-r HEAD" instead of "-r STABLE"] > > > > and export that. > > That would be my preferred option. Would suit me too, since ATM we've no way to backtrace to a release. Only thing is, if you can release a checked out copy, the export is a little wasteful. Matthew #8-) From: "Christian Lemburg" To: "Matthew Astley" , References: <20010220215614.H25661@grantadesign.com> <000901c09bf0$a1641140$9f0010ac@aixonix.de> <20010221130709.A9412@thelonious.new.ox.ac.uk> <20010220215614.H25661@grantadesign.com> <000901c09bf0$a1641140$9f0010ac@aixonix.de> <20010221140635.P25661@grantadesign.com> Subject: Re: [Perlunit-devel] CVS tags / release procedure Date: Wed, 21 Feb 2001 15:58:34 +0100 > Also, since there's filtering via MANIFEST, is there any need to > 'export' instead of running from a checked out working copy? Could > Makefile.PL enquire of CVS or the top of the Changes file which > version we're releasing? No. You can just run from a checked out working copy. At least that was what I did until now. Cheers, Christian _______________________________________________ Perlunit-devel mailing list Perlunit-devel@lists.sourceforge.net http://lists.sourceforge.net/lists/listinfo/perlunit-devel Test-Unit-0.28/doc/PaxHeader/class-diagram.txt000644 000765 000024 00000000152 10273776634 021405 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/doc/class-diagram.txt000644 000765 000024 00000012340 10273776634 017436 0ustar00rjbsstaff000000 000000 -*- outline -*- (this mark tells Emacs to use '*' heading levels) * Comments on the class diagrams Diagram is in early stages so - there are probably better ways to carve it up - there are bugs in it, take it as an overview Please let me know if it's helpful -- mca1001 I've coloured parts of the full diagram, to try to show where to start. And starting may be all you need. ** Classes to interact with directly (yellow) These classes have fairly thorough POD and are intended as the main interfaces for "the user". Test::Unit::Procedural is all you need for simple work, but reduces flexibility. You don't need it at all for the explicit object oriented approach. Test::Unit::TestCase is what you inherit you tests from, if you take the explicit OO approach. Test::Unit::TestSuite can be used to put your TestCases together in groups or trees, and make it easier to manage more complex OO test systems. ** Test runners (green) One of these will be used to manage the running of your test suite. They all do basically the same thing, but their outputs are different: interactive GUI, terminal and Test::Harness linkage. Generally, an instance will be made for you by whatever script you use to kick off the test run, e.g. TestRunner.pl or TkTestRunner.pl ** Things you'll probably see (red) If something die()s during your test - any sort of error - this is caught and wrapped as a Test::Unit::Error object. When a test assertion fails, an instance of Test::Unit::Failure is created and "thrown". These objects then percolate into the depths of the mechanism, to be collected and reported later. I'm being vague, to spare you the details. Test::Unit::Assert isn't for use explicitly in your code, but the manpage contains a handy breakdown of the various assert methods you can use. * Construction of class diagram ** Generate the bulk of the diagram I fired up "autodia" aka. "autodial" with cd $PROJDIR autodia.pl -d lib/ -rC dia-gnome autodia.out.xml & Then I started moving boxes around. Don't worry, they are joined together! It helps to set the "autoroute" property on the connectors... use the "group properties..." dialog? I didn't get as far as hacking the template to fix this. ...shuffle boxes until they're close to the relevant thing and you have a big tangle of class usage. Time to simplify. Probably easier if you crib my layout. [later] It doesn't list inheritance outside the codebase...? Or just not for "use base". And not for Test::Unit::TestSuite, Test::Unit::Warning... argh. ** Remove stuff that isn't helping There are dependencies in there which don't need to be graphed. List of class/what uses it, plus rough notes: base used by many classes Config Test::Unit::UnitHarness Error base class for Test::Unit::Exception, so left on the diagram also used by Test::Unit::Procedural Test::Unit::Assertion::Exception Test::Unit::Assert Test::Unit::Result Test::Unit::TestCase File::Basename Test::Unit::TkTestRunner Tk, Tk::BrowseEntry Test::Unit::TkTestRunner Tk::ROText Tk::ArrayBar (?) should be TkTestRunner Tk::DialogBox Tk::ArrayBar (?) Tk::Derived Tk::ArrayBar Tk::Canvas Tk::ArrayBar Devel::Symdump > what's this all about, then? Test::Unit::Procedural Test::Unit::TestCase Filehandle Test::Unit::Loader Test::Unit::UnitHarness Benchmark > candidate for moving to Test::Unit::Runner Test::Unit::TestRunner Test::Unit::TkTestRunner Exporter > (list incomplete) > may be useful to know... Test::Unit::Debug Test::Unit::Procedural Test::Unit::UnitHarness Class::Inner > was split off this project at some point? Test::Unit::Procedural Test::Unit::UnitHarness Test::Unit::TestCase Tk:ArrayBar -> is part of Test::Unit::TkTestRunner, interesting in its own right, but not relevant here Test::Unit::Debug used by many things, but basically dull Test::Unit::Assertion::CodeRef Test::Unit::Assert Test::Unit::Assertion::Exception Test::Unit::TestSuite Test::Unit::Result Test::Unit::Test Test::Unit::TestCase Test::Unit::UnitHarness Test::Unit::Loader Test::Unit::Loader > used by many things; headed towards "scary" > looks like it should be used by the Runner instead? Test::Unit::Listener Test::Unit::TestSuite Test::Unit::HarnessUnit Test::Unit::TkTestRunner Test::Unit::TestRunner uses Test::Unit::UnitHarness Test::Unit::TestSuite Test::Unit::Warning mundane helper class Test::Unit::TestSuite Test::Unit::Loader Test::Unit::Tutorial contains no code Test::Unit contains only constants Test::Unit::TestRunner Test::Unit::TkTestRunner ** TO DO Filter method & members: some detail is obsolete, should be hidden, takes up too much space. Ensure all classes are shown. Mark presence of/need for docs, level of detail, position on learning parabola. Um, I'm just about to add more stuff. Doh. Check uses & inheritance lines are correct and significant. How tedious. It would be nice to cover all the classes with at least some explanation of what they are and how they fit in, but there's no point duplicating POD material. Maybe break out the relevant parts into another diagram that shows the examples too? A similar diagram (sequence diagram?) for how the tests are loaded, built into suites, run and reported. Test-Unit-0.28/doc/PaxHeader/consensus.txt000644 000765 000024 00000000152 07374754713 020720 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/doc/consensus.txt000644 000765 000024 00000011647 07374754713 016762 0ustar00rjbsstaff000000 000000 -*- outline -*- * Intro We were wondering how we should go about keeping track of the consensuses (sp?) we reached on the perlunit-devel mailing list. Matthew was all for a cumbersome set of tags so we could grep the list for "points". Christian suggested a simple text file in CVS which we modify as appropriate. This is a compromise - a simple text file marked up for use with emacs' "outline-mode". Most of the active developers use emacs. Issues currently being discussed on the list can be kept track of here by listing any suggestions made or conclusions which were reached. Once it's decided what needs to be done, the details should be moved to doc/TODO and someone will get on with implementing them. Please only update this file on the main branch! ** Links back to the mailing list Might be handy for those with local archives, but dropping message-ids in this file will make a mess IMHO -- mca * Coding conventions If in doubt, conform to the style shown in the existing code. ** use vs. require After a discussion on perlunit-devel in March 2001, subject 'Towards sensible failure messages', we settled on use rather than require, except where we only want to load a module if we need it, of course. ** whitespace No hard tabs, 4 column indent level. * Auto-adding tests, Test::Unit::TestSuite->new() ** interaction with inheritance Broken in v0.13, it will take SUPER::test_foo if test_foo is an inheritted method in the class being scanned. Fixed by Piers. ** regexps to pull functions called /^test/ I think current consensus is to change the default to /^test[_A-Z]/ but make it configurable. I seem to have lost that thread -- mca * Debug methods Not much agreement yet, here are some of the suggestions ** $self->debug() A dead/unused patch from Matthew, the idea was a default debug in the base T:U:TestCase class and methods to override it. Messy and inconvenient. ** $self->listener->debug($@) Some say listeners are Java-ish. Others say that they're good anyway. 9-) Arguments are headed towards something like debug( level => 123, user => "simple message", developer => "complicated message" ); or some variation on the theme. This all looks rather verbose so far though. 8-( ** clever things with caller() one vote for [MCA] (provided you can override it) one vote against? [PDC] * Documentation ** Where? Where should it be kept? At the moment it lives almost entirely in POD and mailing list/message board format, and so is inaccessible. A pod2html pass of released software should probably be served on the website. Matthew's (almost finished) cvspublish.pl script could do most of this but is probably overkill. Also it doesn't grok MANIFEST files. There is a documentation manager on SF. The front door is not too friendly and there is no back door to the data inside it. ** API & PerlUnit overview Current favourite is to point at the JUnit docs. There is in 'src/api' a set of basic perl modules containing the essence of the structure, but they're getting old. Also, the SF message boards have some knowledge which needs distilling. * Namespace pollution ** classes used during self-tests We're going to try to avoid it while generating "inner classes" or whatever, for the self-tests. ** keys in the TestCase object hash [not yet discussed] T:U::TestCase::new is biting into namespace belonging to classes inherited from T:U::TestCase .. currently it only takes _name ... I'm wondering whether we should go to '__' prefix in the C tradition for "magic things", since the perlunit user shouldn't need to mess with this? -- mca Not sure I understand what you're getting at here. The PITA approach would be to name all the keys used only by T:U::TestCase as 'Test::Unit::TestCase::keyname', which is a pain to work with, but probably the best practice. See the discussion in Damian Conway's Object Oriented Perl. -- pdc * TODO lists Moved to doc/TODO. * Packaging [mca: Christian has SourceForge and CPAN packaging pretty much wrapped up *cough*, this is documented in another file in this directory] ** Debian GNU/Linux [mca: Since I use perlunit for production work, I'm tempted to roll a package if it's not too tricky. There is a stack of reading to do first though (I'm not an official Debian developer) Relevant bit from /usr/doc/dh-make-perl/README dh-make-perl will create the files required to build a debian source package out of a perl package. This works for most simple packages and is also useful for getting started with packaging perl modules. There is an override mechanism in place to handle most of the little changes that may be needed for some modules (this hasn't been tested much, though). Using this program is no excuse for not reading the debian developer documentation, including the policy, the perl policy, the packaging manual and so on. See also http://www.uk.debian.org/devel/ ] ** RedHat [mca: I made a RH package a long time ago... don't remember how] Test-Unit-0.28/doc/PaxHeader/class-diagram.png000644 000765 000024 00000000152 10273776772 021355 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/doc/class-diagram.png000644 000765 000024 00000533542 10273776772 017422 0ustar00rjbsstaff000000 000000 PNG  IHDR|B5sBITO pHYsjw IDATxw\?I Xb,(((%-X&vQQĨ *AD1(P{Gn}хyc53k0 b̘1߿[?[]ׯ-,,zڋ~Gzzѣ{ i-Zx⮶ѣ ={VWW޽@ @#i7 }#3gСC{ڋ~AZZ }v@ _< =@t(F D)..޲efUUUO@ Z@ P\\|Qyyv@ 4@ g~ΝӧO=@t+(F >&(Ǐ7m$//)/%~H~1 sXoDRO~Z@ }.ݟXs5k|q3Vx#"hW@ Dhࡡ;8qɓ5kddd=: `„ d%|>˖-"C;wtK$F̙k֬yf̘q4O(_ښTK.رc!!!Ç?p%Kdddy޼y3qD{{tQ};B}}'OrrrMO'MիW^YXX >ǏJJJIII)/~3lذ#FdeeAd &OѣGgddL<999ǏWjnnnhhXXX(̜qB`{} @ _fff'E(T'Kײ6-sEUUU 233WX!##3jԨk׮y^~ Sկ3y ''GX0l ?YVV\PBLy/SNUhmmV#0O mjj* ==^D@ |jٳgĵHFÇ'Offfׯ_x]hW_ """11y*G,,,xI&4-ZAs"MMMkυ#FZi8A =#Bb 3;9O~ꕙ̘1c^~1M2 WfҦO ++;l0 edd<ᆆRRRx6rVVǏ1Q3⨥tǏ ???ѣGϟ?;w5s2DSS sq ! 4? "sww9x`pppzI;gddL8QaKjMKkkZwR uttg(F`K8Ν;B8vuxC7NQQQMMΝ; ߿9sʬYO%AVVVWWw…o޼;/>pSSqvtV;oܸQaoǕǏy<^}}}QE4xXHy@ 8"뤤ox<'' H333//6ҒliiVTT^|! dVUUI8KGdrϟҊ_0pOwSu"bJ?.* zFFFl6[D;}\777wP0 Q<))|h2555uuuO;@3 F@۷ܹsbe(--}}A򤥥ܹ믿0`ɓCCC:z{{^zUV^+Nj2dȖ-[Am;Y7>}?ܸqcٔhNК)駟>} 444^ D7AJ~~Q(O>ݻÇgŊ3𤯾 ðb1mkiiױΝ#Λ7o֭xjǙ;wU~CCÈ#߿d|&FFO/(//PA ׯ_srrLfpp0ͮ!gv횏7n055ů555kkkɩuuu_3f̈uMM~]TTdjj\WWp>|d2o߾M={vbb"˥U(IIqsE?^NrKKjs}'Os?ڵk }}}"]x@Ɔ8/^ŋu݄ mQfee•wqtR֜?? &) i{ŋ/Ȋ/33nqpf^mm {nO<хOٳgÆ C~'KK͛7 [rss8,έU^^>{;w._`085OSرٳKieʔ[P#}ڰzݺuꖕAqƉWTTXYY'eee)/,r\999qR?~T>|ػw#JKKqA(l6[YYRV $<<h3@tBTWWkjj K)//'Ktuu7 dlTYYAOYYfY;yyyQO<򺕴4/x544K"Kjjj7KÇ׭[_ V8aaaͣt"KR:>n铳ڼyӾKJJٳv#GU@ КKd444 JKKD!۷od#rssɒ\ੂܺu899,`+W\QQIRX.22,u떽f wrrzի]\\lmm$im޽=zH!\yGɤwd]#%%elllbb~v[$#)|>۶;w\fǏgDWfccc=<|رT6f_|jOOOOOO|+0777aŅYG =Ž R>|ӻ~:nhh{iϟ_\\Lðuuua+eb^jhhXYY)N1cΞ=p.]4t|a5N~~ӧʸ\nqqqHH|O rȑyyy---#G$ٳmmmWvZSSSyyiMM0xogBv7 dl<- &&& im mEkYp_Z!\yG?PRRr򼽽Ǐ$W<'Nkmm-//߻wʕ+eMAmcfbb(@`:555%%2ccc***<== arrrNNѣGcbbaaa?޹s'.ikk8qDBBB`` … GWWWb5 +i Akh##ϟ?gff111ׯ_700ӻx?H~AFF0̺u:tؘرeҤI'Ofٵk֬rJii3,,,p[6ařL&^HZZyzznė ܹseeeɾgsss4ܸ9sѣGog=HV!!!Ç)lrkpB$"h8MMM|>h ,KEEnllTTT`V__O[8"-ޫ@4? ϯ~bСCWXپ!$6|{I&]vظSt*4E4۠ +WJƬ6(FЗ=@ 2FH  @ Ad{@ ?)@t.zzzhчA4@ 2ZZZDJKK;F>{@ }|ۊҎ;ӎ ]Z@ @H@hqXztYnN/iL q2L>҂_g&'''''w7oެ0׷{,"@?x`޼yZZZ ŋY;Op״74qFqy-'GlWPZZz@uugqq1͎dz=y򤭭ԩSGSq ف'N`ٔ"yyyRRR:#.@h?o۶mÆ UUUx񢾾~w:@ $%% É\lH!emmk.ƍ𜡡{챱 ܸqɓ'ӳ_xAV[XX(##C>5j7ȝ;wf̘>}zLLL@t/ڸo5kV/CB z->8>}ݹ;7fϞM9Ve$?сΥceeehh`J?9RAAPVV6}tMMM6=~'O<OVBUUU]]~xÏ]WYѥ@_r'gYYYa^:|pyyy99aÆ޽Op8FߴiSHH$Zjjjmf``{ r*7GK_PIIiǎyyy S\\rJUUU999ڤ߿訢FEE988(+++++/ZR/3+Vhkkˏ3#MoݺXNNdV# ]&۷o{MMM X\C|>LMMJd](Ba5MIIqrrt̙޽ N8 ͛333I@[)aw-[L[[[AAaĉ HCюIxS!w!Z75m|#633s񇃃CBB{==='''ԩS^_p1k֬Ç}7D/2wgϞbQ899%&&^zekk9B FСCh(emmm ;j*>>999~~~&L$HMMͨQ9[)--cvTWWgffvR.{E8`ى\.WmqEDDX;v(++Ū۶mO?$^pgLMM8ÇL۷ɦ}}}\n~~EΟ?/fY)"M2 ɓ'_v1gϞ֏?&2N8Q*x]h}% >|ڵ }} 1k*goox/^ ԚXZZWWWs8^?~xYf=Z[[ Opss MMM$ d2 n D!(yY__/L.Gttt(_eeeu'NZƎ[RR@3y0f{AƔTPo(I]d@,>pCnMcB/X JJJyP?%Z2uԐ{WVVm⩅+VOosssE& BtC| D\8!,. &m ]&22 ݻ/_aŋW\)LȺ#ԅם88i{YS\\,,O;*E+ \|_)7OY=|݆Z/}̙w;At7hD rӧO(Izz4HV<^|~nnnvv3gƎ+fMMj]RWW\k` wFGGAXYתeE#ve6 IDAT,Ą.TTTd2>}>}:aSNU)))N[S|^'N111˗/`j^RRBxCIT#Gh[o7o,_ֶ,At7hD~͛7?~rl ߼y3m~d2')))cccgeeDښؓ0a.YYY=zHXYIu3NNN,iYTTTljj߄D]FKHH… Æ STT~eei ua2%%%T| `M"##ɒ[nם88!899=~x...QQQm%X)aB ^ݻwG)tH*m.nHiږG,Ͽ}Ν;׬Ycb :dbbbcccM&##Cd vvv.))rEEEw:qD{?Cy%Ɍp8555VVV@Ȕ ܥgϞ?|GGG;88`pmő722:}tYY-.. mwYx51 9{,_ ]&֭[+**N>mjjJ'>r0%~S򼽽Ǐ􂂂= tuu= :qp Z`hիW_vԴFZ Ü_N1M+7`OY!Ai[&&&X<hƒ#%)))))I"pnܸ= 4g̘.##cll|ܹW3|}}L?}DdXtaO< IO2E^^~}۷o=.agii)//?`;;8 m `V\\d2 D-Y(iYxce FIICJVVVu"_nٲPdM߼y3cƌ 01%%l<\ A!mW^mڴIAAA__Y,СC[ZZh8ᩐ; bma!-X8셐袢7n`}ɪ*""eeeyzz/^HKK uuuVð?~:770>>>::G+@4?О>I~~>7Ыmx{{!ICy??ݻw#qz"LΖVZk.bgWWW(mmm'NHHH ą....\,`cbb<==1 믿"[nw;(F@,--CCCkjj\njjڵkwލ]@?6l ;K^2++kΙ3gC]lپ}>}JVVV{$S\\vJKKܹxΝswwx{{8qf======eϜ9J.|||N:U]]k&>yyy)))SS{uw I@3B_쒻Ǐy<^}}}jii^Cx̙3UTTTTTf͚yСq)**ߔ\|vqW#ا}$r4Hgj;n$W^ =&&{@H BvگY %*++gϞdɒ%K̞=?TTT :z#G3(~e!@1"SzC,doB``a СCwԄ'~###?hen:x`EE]v? 3|#G9;;_~H} 䔒B$bbbf̘<`sܾ}w/_%''gff*%/?\8dȐ\"ω'낂Ai ޶IIIG%{EBMMͶm oߞ+++ 8-+V0 Z˖-\gff۷m߾}YYY~۩S_ 6Mqrʔ)@kS,]TKKK^^~„ ݣd`7o,ZHCCC^^~ĉ<w>%=x'O GȨX7>^DVG##nU[88'',}G ߏaǫ%g`p" H"Ixҥr |[^Ajj*"}_>>999~~~&L>|ڵ }} ,~ǎ_?bmO?ᙋLMM8ÇL۷aM#wIIIqanZ`mKdKMM>\ZZrsss/^E={vbb"œZ bxYeE֝vw󭊀C@ݼy322R _pǯWZ|rggg޽{>>[/(\]]E%h߷-[۷o'f=)aX[[mAƍGwqq"2 |>Y:g2ű6w\q w.00pϞ=>% ]xM4םvw󭊀C@#@#B?~-paK.%䚚 b.7n\qq1!)((tp\`s\rܜ2 U;/TYd {;hoU@w3(FӃ b~ahjj⓲gΜ;v,.t"ѡb"yEEE 2$++ ű%mo߾]XXW_]x)sfŠ@h >|w)S ջw9߼y3eǏ3̛7oR19O0L RRRrA \EEE]!.g߽{7vFB.$f^Нr"A4?@a2d8gX[[RMLL֯_ "##nݺeoo/'d%*DN6~0aA,,,veaa!-m;o|o B"722:}tYY-.. a666gϞdᅣ$..pB%~655͛7ˋ^x왱Ç9N}}}tt޵k 4!iwHę3g lNW^544aBB:Z$pWvZSSSyy)ycDrqoo~ּmjjJL w]`jj&2rx< >%`w>^DVY;aDv-ܿ tQQэ70 uwwwww0رcðf|?~bu۷5??'((}EZZZUUfhhkbb"8znn7'>>>::[hD@cחd_ӧOb~a?eyy~wo߾|,]TSSSVVvذa'͛3f;::R6 ()..vvvf2 CMMΎI333BfnnNyoȑ.cm֭[/$V0,..R^^~vvvqqqFYYY222?CHQ__/wpNNN߿xhbb""}zjӦM 7o,믿eee lRXXHdr EQQQGGg0hV,9x 1cpA#dTKTA/",ƇԽ4&EVZTQQg#6YONN9zhLLWTT '666,,;w0-##? !!!00BL ,XVb&|غukUhD/O>x"|u~G|2tJXE/DǏ/..;zh``ߓ'O(K믥;v|2ڵkIIID_~0A sN"AWhDg rk׮ݽ{70wܞuE@;!̝;ԩSdznooO>0{l?? .ϟoffve pHqȉoU9sfҥJJJ666w! B>Azw@;+)؅X/x7= q^7VpHq{qh:v@ z_:thGxyy+Wk}4sst`OB@@ 2viDoF @ $@ @ $B 31C Erqq춁D (F DΝ;sԩjOOOOOb<[XXۓ'O'NPWWdggzxxxsιGEE}z"gΜ!w111*** Xpa^^Ė5D(TTT0 ]]]___"yccÇoڴIҎ<\C*E$Sq Fu),Z=dnܸqܹ|Fַ~BAA]nn.pA"T Onv'Jϟ?UUUyyB2:$B2</22RVVv bM<~ڰ6 //_~122b0^R˗/Ғ333 D?3g =z$8;~Ǐ bA4PXl൰$~𡝝a666=Caw܁F!33s߾}}233kHVX`00 knn>pȑ#_.o:::0`NNN)))Q!6aׯ)N*N"LeeS(O-CpppOFth?0ɼnÆ v tmmmO;ҏ`0h!4t%BOTc6h 7VVV_AA-ZZZMMMX,իW !29~ۉ6m"@hhh ܬ[VV'_ 77T )//' Lp***KGdeey<9˕'U~ #µk޽{,B@w (~P@#:HEZZ#J n_l6[XY}}~mmmp͛7([)++\rŊ;vعsgGj>.]Yns_7 aРAvvvp;;;===>~߾}&GoAK b!n?? z$U@ z (ommmN:rH]]%?oot7g@+**655 *͛7?~?6瓃B]uuuDDDyy9ͼUVq\$77xt%l 󃔊HKKF=cXV8?)EFF%nݲA@@˗/-ZDIo"""ȒH[x nݚ5kqdggϟ?G" M>;,,rƍ6d '~ '~666gϞ%E>}ӏaءCLLL"##Y,Vccclliddd(َ;*|DDCXXX]]ILLݻSUU!'n[ZZJKKⵃ3g0 .ĉZ[[ݻrJ"ÇzzzAAA 4 $$$K) <888b544\zаR1cƜ={6##]tiСJ qf͚u Ibh t'@w?}` tQQqGR8qð_U7oor ~wr6clllll,`X?3qVԩSK/%hD@yJJe*;;;3Lfgg7=c uuuccs Fʂr ~EEEeee'bx䉰ݬϜ9C䗖а!fA_K.Ԕ6lɯRyfƌ>Ў}= Dwᶔ޿O.I^j![zuaa074W_|zT(濯q@th.Kv 8|˗/?}aÆ={P~ٳg"xtff v܉>||Rο,Ptm:::kO]\@@{ɀD8`@kkk[[`q%''GH(aÆ]x?w\//ݻwVt!?@ @ }"#"2\?p@8̙3'22dڵE_~ ڵT-@ @ @3D"##'0555222K,a0=۷ee@ :o]f9~ŋ䣹 ߿pF}3f899 Z!M.9|7@|#_(F DjڵsY`Y^VV{$)^QQ?hhh- :tٲe{)%Ǔ!K|$5C  _6nll-,,rn޼YZZ:wgϞb͝;ԩSN:+r/^IKK^".@.?>uԢ"KRRR872^ _lVRs] ;ѓ.fDDw}Qxh _$//O9&+7! DF.ėG]d ]o 殑x( PRR/h&3Jl!%%EGD?-@ SL366\|d2 & HRRR5qAOQK͛7.\PTTT.(ŬK||<_ǿ}vرJJJ.]2a ͛7Yvgzv.**hmmDBt^~=dEEŞv3@QQȜ[_O9|p III)k0''0baٺN-G<*DMdҤIɓ'c6f~| iljj*bW077<Ȧ}fJ novvBg+++-[6p@eeoLJ6[`^rx/֛~fLԉgӦMW^mjjT q* %HIIZ9::(5x<$|hvv6ܓ.R zܸqBNd"HhBK5%KSN3 155Aj&@ n>^tQ***\\\m{ aaaWs̜>}zO{s >o<H>*Q+spD6`%$$0~mbb |4{# U'%+Ynŵ{ԯp aŋEyfEE׷kC @ ,(xUPP7o^MM \N绺׫nܸ򖖖-[ 8d:u ikks\ +((0c¤I&1 mm+V@b:/"SPPprr! :`@~7 MMM__۷kjj?)ݚ:rȖ Z[[L!]O A hKR---&M"JM4 w2VDX'vho}K8ҦO ++;l0 edd<ᆆRRRYYY ?~V/PvZZnݒW8l"($ N/=zs333Ӛs2DSS*z W5f̘ׯ_ k.h y GQQэ70 rpp(**uwwwwwË&&&rܓ'O>|ݻxjTTTVV֕+WEȜ?,߿///aAAA9OVVօ aǎ&{BK Z 㣣5-@&M:p@RRRSSY~a:6m۶.'sĉݻwWVV]v?~f9r~{ٶm[]]]AA? ;qFaK80CCø?>|"yN:wqQ\.)ґ"U$XXQQh5*&$bנ +zh؈[ "e)qPa}g5gvgg),++w\x48B֮][XXxi@,GFF4N27o޺uL&۹syKݫ{SK[VUI}wޕd cǎeVx ɿ2D[[Wiվ W-۾l͛+V?yL&[|9Utfgg22ã,YaÆ'O_K,߅u…3gJ~aѢEbڵk|rDDě7oϟlec㏜L8G߲eKRRìYᅬ-4AT ŋѣG뫫Çz;;f566Vߗׯ|kkkf:''SIΝ\R]@_HbX 0۷oϧ\Yk<#{v5(;FBP~GNR*((6mZeeeǥ7U(ؽʓ:t"_paDD6P 7ťЪ Te˗߾}zjffdAAA9s?>mڴ+W^Z~wu [lYdL&;t*T !!!G$ۏ4AT}ѣG =zԽ{c2ӛ7o hllx=---YO e,f933ؘ|YFF{|˗3gԩ9LMM]]]ϝ;`%g$꒯񈩩쯱;d@SS6 sZj̙ _ߎNjС-(OO>Q0Iam22e 34*^^^ƍc\YYw^;;;H4h N^~뫩ٲeM6nɓ'l200fH2@F9sAMMqɓ'w͛ V2?|pMM޽{?I-zB۴iWʼn#]Q8|}dU՝L&{򥚚Zvv6KJ8'Rݛ asN5}Ujz=P @ k$Z $$DSyyϝ;wA2d۶mP'o޴iX,D"Ѿ}jRwss{3 Էﻺ>z#C^srػw/Y[[ی Hԯ_?vX0oZ[[ 4ZZZ6m aOu|w|g޼yw 4>|w ITjP *JKKΥnD"3e#"|}}9wu41 RiEE/QQQ}QWWLMܣG$9::ˑ#G~7Ż_xQ,2k!߿O?-**ڲe˺uNށh%ճg)S :aرK,:33s111b8==ٙT^^+_sֳ֭ݳ G]?bWZf͚tB(4;paaa\\3=oqqq~~~ZZZEE=W0!dĈڵcnvL5 ~8pۖ-[hƁP7oի˗/9ؽ}V$skkk3mkLVPPP,h.U.J߼ySeUЈ}zDDŋbKhh(!ѣGIIIW^#DFF0… |@STϞ=mllbcc}}},,,ttt*** GMqttܸq3D"QSSc+J@heaa1h J}daaѿHD4hי۷oӧaSh]@ܼyW^/_T0T*}捡a[|||̂ϟ_oB]^^3D";;;(..N[[(!Zτ)S0 h=5{lDw*$11Q[[, h@@j9rl( Ph@ʫ*++[]  222bccG%Hv)'NH f6M6"<<իWfܿu떎KDDǏY%%%3fe'8$02W'h@(K.xbʕ:::y1O13&''ҥ IDATwM*㏄;;;O>ˑ#G~7Ż㏑f={6ЀPRLc.Y>233ڷo/ӝM幹5nݚ}9bCʋ0..@(BBBB V\\&J ?$$$tޝ2bĈ{N<ޅ>DuDOOoC UɎ;RSSBu}('D\۷"HSS)7k֌]f2iV]8ܝ3!&8l>d&^z%''+ϭHw hPEIII;v;?y#Y444@uuY4J?l|--[ETTRw Cu4@ MM~~>)@S445m۶]n]QQ(A׮]C̚5(66vɒ%K.?U-ܐo_kH:FA|-êK:á\rƍ~~~[l655?~IdlC^n0wPfvD0ޱcۥR)fվl1&&fڴi.ׯ_744db;vܲeآ۷9s\r> :cǎ->>>lƍ| W^}Qصk}aꫯG :>22Ύ-n߾_evvvt_|#?w\ӯ_?:?O.]ѣGW^n޼Iׯ_g>>>?3[J:tッ \2g: >>^SS-.[ɓlgϞv㽼5.\8n8H !.\жnݺ{nتU'N}YRR[:uٳWp>L E6mZLL [[j[,++n͛ҥKJIHHPSSc// OOO!}-O9[s玿?ennNWPPakkKO RSS+**7onbbB1c7|^x+++mmmBHDDD6m~wu((( 33?PޫWJKKFl2“Jϟ?'XXX0{f/ofggBBP(d>p/_\ YYYEEEeӷo-[{L&311i޼9!dʕ#Gd/OܹVCCr5###c^@HԲeKB+^x)))ƄٳgO:5##;*//OKK#X[[kiiB?^x_ŋӧ3b}ED"ydC:tHWW2yժGv-Y2{gάܵ+#74Y}/2}/Xrd߾Jޯ捻/կ||E߸ÜSk"P^^Ǯa>Yfff~~~Bi߾=`cc9 آ3U__S>]lݺ5|z|3\]]9r755t:޽[l׮'`Ĉ2-r^sssNw$Ct> BH9ӭsB |Ӻuk9A---NAѣ 9hт NΝ"}10\BʙАS]lӦ `ffƩO?m۶-Oom֬~###Nt脐^zYXXN:[8[ZZr@@tB_Z$0tв2hooOo5114s !<>|˗/wNiѢnݺURRbmm\...L%Lqqq;2̿vvvL˗/={Icٳ's%$$1o Ӥc/s cz6eҤI{Nz;zrî7gr:JLLܱc߉l",@U ?~ۧOiiiSԩS2LCCC&UVV޼y3(n@DbaaAӧ!۷|GZZZg cccީS'B(+)J+++ !W^eՕ@T )T\F@!B)88xذa{;h@|LoܸqӧOKҲru޿{GM{CHm>2l;CwҥKN8p/:ujݺuk׮#t"GwᅮZݿ ial\TZJ𡎖V;GУGKF$$&eeM2Ғ9C=<!ׯݛ%='gKssqYٌQ H'OݳS'zR"k7772"qp#:zH^42OFٳ',,-9r [7n̙3bnn۷wؑ-}ׯM矜FQttP+Wp[tww߸q#?`"`???0c :̙3􌭿ˡCb֭cƌIMMeSLaed}t}\\\ÇmMMMϜ9C7we~~~h7n/^b ( 9OQQQlwׯ>SXL?S"3gűc6-З#!$88Ғ-8qaaaA_K>-2dloķiӆ-޽{ www?d2ٸqYfٓ-޹so>h[l۶%KB8a„gϞOtMѣGO: aÆ͞=_b3[tk.:>00նw\eeĉ[nl1..|۷߸q-r>NZ\\'M4`fVֶm~Hhkk?`~~~7DvvOǯ^ё-WsfzbO?œ'Oӹsgx_~8|0]_Ν;ϛ74iRYY[>|vZ:_m޼9[;;-=xݻײeKCCCB?lkkDFFolؘ@'X"))-0`ҤIl~=طo8p`͚5666#F`IL}o>/22 8ϒcބ ζG#./w =PZVP8}}Gϟj2#77mmf6wo;;V!G.]m:-=ڷomk1<|7\sNݝ ;]!$%6zSչ 4i2s5u ?}퍌b˖-"ޝG]\\d2[dg{aNGu8tH_ ]p%,]]]N#!ƆNquu533cPSSS haaA4k֌S'|BS?266p899t۔ƴ;!DOOSݡ6[lIX[[sС~XGGyq \2LCCCKK"/++l=]]m,,b'}]]=@t@{''"+*r_&d7kf?ݎBVEe%'zcxֻ ֶL63/ϫKc[M(d9Gaw,sj7IR1!}J]Ν`Èݝ o߾1cƌ3FAիlS\СC @FFFT@wP\ǎ_ 7DZn:['0|pΏ-RTq}s| jii)K.]tQ0qDN!SL?<==$}~ Ѿ};PsLLv67G1ǯ\Գ n8r钋]GggBmg"6rѣQ cWPP```P}\-^xw"[n Ϟ=+t´$ !tzKK559?p3R離"cH&FJDky>ifh||?AR䔕wu 6:fm L5Av儡Cͩ_D" ^6zuB,_iTx E;h:ty:cYx19<_X߻|ݡNK4R7ɝ;wN<D J *h@4vqfPNܹs۶mNf2ݸq~֖^&{w=z7߿z2rHz۷oEssszBӧ";vتU+^r2dq~- |w:/Soߞ-s"۷/=trrrBB[䌳vڵhgg%ɉ'xwww+++X:`ԨQ &2X[[1bė_~IOtE0a#?ѣGNRZZJB IĄغu+:'x ܾ}{N1j/^Lo5cLMM9s\v8 XXXsQQVVV|]*HAǪbs @ܻwTUYYsEP.?cPPYoN>4pIR {{L3P@;vl֭@儅ihhݻy> ޸q#I___HwPow-Y3x:v2Рܼy֭[|gUP4@=Yr%=YN>]QQ铚1^NNNnn.Y@ЀwBpڴiLᅲd۶m7+qᐐlܸ hxGtttVC2^^^ZZZ7+`3USR5FFF|gvR7޽{9P!RE'OW2ՕTVyy`NNNBʚ5k譏= Cm4TR1{Rٳg溺|'tBarr2[$?~TWQQQ9+nZ\\9Z[[{yy5DrMu;v,߉(;FhxFFF͚52d]!@}S[8ͮ]"""x4@ѲeKGGGhN8q%OmXj)4}J݀ ; Vtt͛7}dgϦH5o|ԩ sݻ7̱@޺uBP wP˗/[ҒDƍ|'R7o޼111it\\T*mc6mTMZjCP֭۷oY:gggSSS> P[n;_|E@SVZZ M6ahjjd2P].\^/_|Էp8q">>,Lz;v/\i&fݻ[lWXh":ۛnv/\O?eqqq˖-O<lEWWנ :~رlqڴi}[LJJ5kw^+++xCE={~ӧOѣk7n8:~ƍ|gϞݶmt۷oϟ?-J$vߟQ4|\MMM:Yf666rBB.6bll tMNfhhHq귴'ӣD"N NeeelyV555NPWW>{8VݻP>ey3>>Dj+VGpvvNNNfϟ?(GСCbbblllݙhww*!tobَńlkV4fWzrssۼys> sHS6yd uŋJ}44RIII׮]#tI&ղܮ];@ƭW^%&&'&&ѣO2kfYFCC6 lVaĈx|edddggfРAJ݀633300; xǎ#5RTTﯯߢE/2ԩ!Ɔfn:t(:||r mB[ taE DGGצfBȋ/vŹ}*Oɧo߾YN2E__hǎ??@S'x_˗/oӦzT<L׮]NguB'!o$INNNeeem322# F h7!ڄXL2+OɦNg4a_N=z4s"]JJ{r1a___ܿp-[B>|ϟ?⢦֬YÇd;2Á11wﶲruudǝԚ7o>vؼ>6sAzY4eÆ Sa@U7ԓٳgNNN]t15F >\o;v-Y(sss,!@PQ|P4|\QQQ(~^|w'uF޽{-Z߿?߉={~XSZYYch@Һv3 4f,_|144T!Y@ZnsNQ( v8GGGvlh,a^)uzɒ%|={fddwJ°<hĔ\fffFFƤINDU$&&}H _uǎMLL>VV&44TCC,7aaah@{iaaNDU( .HSw ӧO+u:33͛7...|'UT "ȑ#h@+?ԩY(SPFJ݀K(/))|#4Jeee'O~۷oˇdݻwBΝ{uvӱcDze2&gdoo_\\>~޴j h8222"## !VԔH$U f$??Bf/rrrA6mNQ300-,,; ƍӨVFFD"Q 9!111.]JIIQWW6l+!d#,X`…F9x`fkC ihlw MYΤ ګW;*d\4!={gffo^,+A"ETZ/B]t q !wΤ)++SubРAiii5;ֹsgKKA]~r>}wP[nd2P:J=44"zzz1c''Pmmmz؇@fÃYnӦMLLLvvիWϟ߀7b&fbbUP5kV)S0 h=ןӧOO|'Ј) p4-; ,##=P5DŽ ?wMz@ ; ijjҩ-SjI(e|[>zhm}M_|eL&cG/T&ݽ{7))믿:Tބo߆*++evGa 3w\v4!PA_~enE"˗ !{а%w׾:j(]]'Np*}2۷''Z,_'[sm2;X,^fMxxxnnneeeHHȺu^~͉gfCBBeBHhhhPPPQQWDDĊ+nܸN#&%%߿)))0>}zB=yarr2YoƌSĉcbbn޼7BfΜvƍTBȇXoذp zrqq9sLmrVx%&&&,,ܹsN:|IU"""z1}7rvQSS>}ŋzŋb%44ȑ# .4117o5!d#1G`v0`u…y}̙3Cݻ777Bȳg!$ٓ3y/@zRD"!H ̯III3Qp{ɓ'OLLL>}tJGz9eʔC,-[466fYϏcǎ]dM/ggg=٫u֊'BGGي }̏u@Cm۶K.IR[ɓׯ_gV21>>+V !^zѢE)|WTTBz'::̭Yvvv!!!oߦW*8"!0YƄ5>>!,߿KKKK]]Q&بh"449z@ ׯX&=yo߾ZZZZZZKNN/ԲZz3gƍWcaaa}YmKńSNU˗iF~}qqqee%\VVV\\\EEEY.,,$??W*8L&۳gOVVT*ݰaCu1JkڵNNNRӧOBa|||m̙!hmvA޼|R4?h7aeeeZZZN1b߹fŊÇk.O0ܼ~j֭[o߾yzٳgNNN]t1W^nnn7o~Ac󩭭w"M1!4y@{9h0!TD$AW^^wJG;ǧTT*Ԭ^ǎ433۱cnj3)7`@#VTT$ uttNx~YOOO;;;3id$Çw""###66vԨQIII111iii&L -))1csJ6l;/ !pȐ!|G;n8hFeeew"͛7BfΜQ8ꪬ/sҥuuu]]]f}uؑJ|QV222 Ɏ5{l4>w}oꕃFgϞ666QQQ7nheeayYcǎ|!B8ؙi,,,όy\~~~s@{322\2~xvL&۳gԩS9QQQ}QWG6*RWW#ߟYtRB޽{߼ychhHquuuuu%Bڴimffv())믿<<< j H$ @Rsc^vttܶm[ee%)@w?3N{~>t&BH$D1 ~֭[XXV==rDzz,3@7uT@]eH$JMM-**mիWq[vь3N1dt-@ӗY#\]]ݻK>SN|gݸqʊ,7h@4s;#c@պv튩`'''ooo9oe2ٞ={N?1w*4eee|g5|gtjn@3SywLQ"ܹ3//oڴiAAA??BHRR!͛xq~<== !%%%3f޹sX,8qI=%(nݺJMMuww?+߹4Vz266; MQQQpBAAӓ͛` 5OKK#ݾ}_~/^...G,*ɓ:t; P]|gʌ h~'S>}4={VYY٦MNۛ j߾X,^@ "=wvvѣY?3vZXZZJi>}z^^N)T޴4T*رc;w s|? H072k޼9&RitpGQgBShh6eg`;nݪ<}BOmddw7oB07*((; >Sy7k֬z{6 BL07@266;F Sy͛ϝ;,aÆYYYرD+VmMǤIpt}P6sh@@0VIw Mҩ=cƌy=|FEEZGQVV_RRRׯ_wJNͷp}vĈ]vݺuUimllbbb&L`ggommݭLMaZhi[zz[|||.];w.&QVe?<.z}qdbQ\&wE!PRA0ɲM*{2M3 ^1(+U4\1M0 ԄQYtDvÙ0s|vOw$ IDATTj+W;  BakkkaaP($iiit{>zjggg:oݺ;|y7kBϺz˗ :u*U n7y7LFa888y&̙3t3U#BHs_~/@k7 366VlaÆ[zz];hР g^rXL3FNBHu<^ wwww: ckڒ%KHf!maaAw0!z ":4[&nz#Pwsuu---uqqŋMLLFu!dZNDycw9yfޣGLLL.]0?ŋs]!FFF ۿ/''$ A1D}ʕ\½@KSUUu>%>>^&q]B}{ILL U\:'{h DtX,^f͛'B\WBNO0SAxXy'OVUUEDD8;;ws!:f۶m˖-{g!UIÇ^bÇ}`ZZɓ-[uVPhmm7@!nڴBb۶m ę/B$ˆ?99yeemcc#XXXILL1c7o^TTG}4k,ؿ~8mڴ}Ҽ6czzz>&5ѹ2˖-xO'pСZ._?_bq/Buqρ^|ܾ}D"177 4it\.2^$ۜD 'N$E6lؽ{׭[jժ/X  ,PB[RTD!EWሥTWW׏=L|1s?Lbllv HNN8ph'?%Gx<Dn^^^̶b]/E:LLL433c]օ @ ߔ֯oyG{_r<==U}L?>Gk6LE$BiiirO󙙙:lF &@aa!xzzr333Sڞl͛0dUt y<^CCb]/E:dj5j(8u:R)u{#d0MRU'1lذ۷o+m[tttPw3gr]Eo7eʔ+Wr]z2/={6Uq  ę-[t4ХK Hq̙򏖵MF2!JGg+QC%@ H$Evak~uFzgr߸qΝ;j!'݇u}ܑ#G~g@裏 ?޺u+h22#F\|9;;{ƌd|?9s&mP^^NOꐷN=a„\&35v޽pСW^y%55u…{}7YEvK^^^gϞ3FRZ nݺqիWرC7WWכ7oj!Cdeek.] POO.O?DO OJJܹsɌہN6166IJJrqqqssTϾ}O>k֬ٳg۷Kwmqq筬sP+++N!H֮#G>}QWTT/::7HLL#f{۰aoɓ'/_ï4iU Piii@fffhxJrrʕ+ge֭[u!HOOo̙Ǐ纐^mԩ&Lu!./SRRׅ tBCR@:Ν;s=x𠚩P!NޮA: j%%%dDkkK.!-u Ko7dmmm&&&OKFF}bbbdddVؽ{AO9s U ֮][SSC^Fuv芊Ҽ޼ymfTcǎ8H*틊*++c]6nxi+`BHx7u ^EsxI&&&\WB輼Gfff|իW;;;?~5֮]{]^^~֭wy竺P($AiiiWOMM}}} +++00;vXTsnѣ1i]w>޽{G>wDDĜ9sBCC(p? q:t(IguEW:u!;999۫=[nϑj74hP\\\aaaPPٳg\ȨPܦ)R__ë"P/gݫ[غuknn.aТ;Pejj.!-a@9x(oXdISSS~}7(nXGGG _ؘ̫SsP$+ UAAAVJ䟂˗g̘A;wwww!Յo#_2vd\ EyE Ot5WguE̽ʌ3'w @ )S@B}y@OŅ;n5g{!B=L_~GYd }啈w}>:k,Vt۷G/^͛t͛7Gǎԩt\q]VΝٳ>޼ytz>*HXt#G^|wseJ7HLL t 6G'M„ tO?>ZVV꿰nc ---GÇY X!#""裊IPNN>5B:aaavvvOzo /0dFmr?~<}tȑ!/k ҃ZGGGV}Yss3;qD+w3g=dnݺ0FZYYw}}}a˗/Q}}}Vcƌw}YVCvA/ɓnnnYAs4h?|.>jkk fff}3C '2ƎjG.^},?66ѣGb |I@ZZڂ D˴fffhxJrrʕ+߆D:}ٲe֭Sի#F(..9rd k n޼yԩS'L CH;w̌utݻU&444$%%*B=Gfddp]E7e=Qy! ۴iSUUX,޼ysJJKC@@ֶD"۲e >SA!{n!ѩjY!w}_s]B}ӧ򲳳 CCC-[v@;;;:ȷ~K2u֥:t,`LoM>>̶sUXWd2QݹAHw$ :wߵaӇt$BOOτ333m62w666tؾ}D"!oN0* 0Ð &0"- BPKMM./j;.\Ʈ!ysw4440L&cšz`rjIIIAAA}tv;ӳ)))ę RYzuWա13>Pq̺"-JGGu#Gy{{s]B.D{ B[_|Emm- 8pƍ}QUUVUU}Gt 6sǎc^Y++th ŋݖV{GG޽KNNܹ1cVXA7Xl#x{ٽzjLL ~۶m%~']wwۯ]^_ fv޽ߴiZ֖~V8F!RYYʑVj׮]?v< &T*=L7` Xr9z bn@uuuݣCX޴nhh(<(tJ9H$MMMXZZ$FO@w;vh'6lpĉ3fp] Bi7|hLF^GcihhHOOgfIJv]v-\^r޽{z-DyHHCX222|}}  ###5?!;r?+{ҥ?g =: ̜9Zk7f;+++&*<;wlڴĄ>ɽ>?o޼Z(--s0ytǤ|k{$}ohiTB߫GI=IIIjɓӧO ԍz@{NGQy8ʛe8;;/]T Ч{" Bakkkaa!PyD=:J$^EEEVVD;wH$-[(H;vʼnD"HKK۸qӧ &&UZZo߾2T}M69rn憤G]i 77]v={ʕ+};x yee(o&̙3Cjh#G9rft#lmmgѣgΜu3] `#}|||||v|| yʹa3%¾ܫ&Xjܽ{իK.Ōnf̘$Zwmii ę0/ѩugfWMT;E>{Xd }v:MBߜлUׯ?rȊ+<<<=}߸!A!D$&&r]B}Fy Qޠ- 1gΜO>|!BIWޟ̟?zCi/\/BaG"n߾ 'ׅ fΜ /p]LYY>QMMMg.!TWWd2GGG _3gU Τ@WTTdeeT*ݱcǦMb͛SRRs .ϛ7X[[3]ʼnD"DGBBBLLLcccii} --mƍO&=3zzz${Pqƕ+W[BCC 8 !8Pw$Bk^p|ի?.   E 55?%=cxjnn2es=ZXX4jԨ3fp]B!Г$BXуj kk^z X:Ԕ9 @ 8{aeeĉ8qℷ7ץ!B=vS8H`\\ieȨ?aEA Ξ={>'Hx!B@4oX޳>IcMt;|?'YzH IDATYqq u!i>Ht_l7--MQ*&Dbv^,:'RFU{d_~et-X \nݺJvB hؿSşԓ |ʕ+LI*== /ܸq.\u! 2*8>?d@\j֯_?晱9=kٍTWW &P__kȢs"""D)S8qhdd4p@P|3Qr4,,}N4얬Hl+URD333Uk]pA  ~Mi~SNC;v Nx>khhHb*r„ {USzRBO*J@# tu &Ifff\f5޼yt y<^CCb]/E:dj5j(8u \>qDx<4iɓ'YTT...O_Rih>F*@#M_ޅ/]d0G_3goooz<M~WdR rwwR(СCD H$T"Y_P?ڵkl+_i.^cy嗙Sƪ>|8a!P/hӌ<==Yzƈ# ;;[&?y4;;߿?]s@077KId&áCrCOXEvKiٳgm4B%a=x`8wi+W!CT4 revhTJ˸U~WL&۽{.N8U}wdy;vtUD4:v @? @y/̙3,88YPQQFrkkk111db"H]vp_dsBBBsssdddEEE^^P(\hѠAy<_v- `ʔ)LW|>={l@!.^X__uqʣY\nh݉\nY)ߘѭ#>|'ܽ{BP#\WBu/QjNPͭa.7Pܬ0[GEEE!N!:&ʛ;v3}:OOOčs@ZZڂ 4?ؘY$ d:AU+vdooS[[[MMM333CBBE˔(]'׷iڴi=_N255%Kr}}t'/rMOO .7Z/'UW ДMII ׅ vDYr |􌺕֭[^?D`_Wg⺐>K'Й4BOˋLD^/nrH4''Wr]B!P'."觟~}6ׅޫ$q4B6n8/Muuu!ԻK.p]}YVR$ ׅ 0B-ZZ&1kbАμGwd,##>11122 ꃖ.]u—BqKy7űuuu"Hij!Yvxt55l"x7_>tƚi/Qުro VUެn`|N3f̕+W.!fHosR \)q_?SB}(oUggg5ҧ&0[=zonnL&kmm}322rΝ;;U B}YBtŸeeS.5cj9R]] *bZكiy!S<""[暚N B&#<< ;!AVX(+,bcs|Ҧ9WV]s-&.^GҚt73m"pЖ-'"Y_JꓞjիWwUHwXZZ]ѱÖ̜"ZPPЪUR)3f ɤ wwwIA!DE/D*x#3s`PP|&}ܹ~Ui?>4g.LG^no8V@U9+WEjVROzi=HKK[`וhVSS̐kS|}}nj~hLƚ_DKJJ ş5$ٳgr}}tRt#F>}LJZ8/I}BؔZƦBg0i53Bt2@#i׿ȯH78qέrrrY0d!or];N"xiii׮] f;>>^,GFFZ[[1RRR޽;k,@ HS߿...ΝsqqayiҤ1cЧEGGog & MKd2Y[[xCCCzz:`w744\w޷zó222|}}###<xzzr]xo ou}WLVox<tFITV'}vDbnn،JJJ%]N711HޡҴr ,̤|Xkkk[WWGOg!Jw%~m;;]vpkkkfEO!mdA8A~=### &VB73mY:SƊ3YcccE 0>EqVH60PwГkjji7oO!_/޺uO?577믿Ǐk~aaad}h?G'#B[ցƄBI111䞊5VYY3j(Xp?x>>>6+ TguK_5YB!]A*988>}K̤7:::yTSS# e2Y}}}AA>~~?=P\ GffUHF]ޞz8F=T4fR׶mLLLȳ^z=3!!L__^uccc"Ms!}Lj=NG_]]eQyyq7)(pU p=x+Ngvg{WTHH$1fH|W55vY >?~֪a]EP !zĥ}z"++l'$$Đ6nxirٕH$qqq[ly!T*ݱcG\\yȡ4''B!d2YW?/J݌\3#K.VMōګ?pK/d GH_\ v>,}w>,~(|9&7őaaG^rs'Mb.7vs! uK7j_ p/1&P$1I бLܠ/1Lˎ;>|8zsb ͍B@_\_)?S葻xǎӧMVXgmaҌ0t@Se"Ke23&ꬰ0[[]vq]↯oDy[XXЫa7zNQhh(Ț8DR^^NciHL B&Yɩ0b!ԞRS_/MMWXx*.N*WXssc\JJ~܋ݝȡ«WǍᯆԯjccu3k֬(ohj`7zrt!$BV }HM ,8r{0b!Ԟ {$[gfb=,w?}jIppSKK?33W\\]S3F.paMx8'_!9 ԥmll4YAS3 ġ>H15w9E޽[WWwdx<yG!ZǁM܄zDѳ툐%B=#pp\]]ATVV[D[:͍LC: Hua7z6\;<% .M/[RRj*GetE"|}q^B!cry'̲wٴi Y[W$,͛W[[ rܹz݄HǪ %%ݻf>|8\\\ez D+IHBJ]|u!Z&(;?gnnrԴM"\l--HK&@_ߒonW)ďЮ}lSccV8I?@j$.wq 4h㹮q>P LHH0j]&->>DOOnJYYY%%%֒CtW/ԋL/׵ Ә(oڼiӢ`*EO2~yaϴ))/رJ q 7aԄ 2???=HKK[`A\RZ4333$$ZLYY[AAĉmmmwܡobRr\__?==CU͛.\u51+p$:[ѣ6TJ&Q¤kH&1I઺jhnfYN'=Q|7:.KMIٞZ^Yٵv;;;|cG:]j/R<o8Sϟؿxx'OuE!6c##c#)$8|h2zLj$NS]"?-°qTP| UhLtWWLMW^J5cPXTTu-\PIPN X"8hzLgff2'z :y򤪗+**ƍBdwk qP/URR~G>}]ꫯ@zb7Bp]RTTTL&kkk#/ڵk…&L`&[oD?<$$t>&33;ƌcggWðaú@ݻwBk:pEEEVV(oDBwرiӦ*,&&,}bbbG~efHw~{\#/#ڡ̠ 򢽾~pp0Y! L*9^">)r|?<2~F.xsBj=KJJ:zhffsppҥKI^`AJJ iv .: BD~ᇾt7ߺuw!0dee;qĄ{T<|hh嫯jeeB4tTHu4He}iϞvZcs3egoܽKo;~.`WȒj.:oB{1g(5kuM慠vww_p|,nT(**277 trr:x𠳳s```~t|q  -WTy̙SH~"̟Ϸad,3oeE´/4k/\brs'M"{ܹN8A1Hgtw}}}AA%aR矿w9ٽ{ ; IDAT0=%ٓI( ӦJVs V1}^}Ո@IKK(o _ؘ%Y8A"xv&goIQ^f,X \|ƚ\vQQQ=z}a4oB%X`6BLeT-b"T__ fN0p8zFti x"PTTt.?\No&C2NtqIX ~}l&=ۢ_?z7O0m:|Ip0m*!5`W\\]Scom}LD w.eggu!Z)SN84228p PV6VDxՉٳ~d[H֮"&&&\… H oJWr9F W,㧟~400 'ڜ:uc|2ass{>?bQ777fлi8_uM\ULDHyGu-=HKK'%O4333$$ZP_v#F9Rvvv~7@O8p„ ׯ_777oiicXOP͛7=<< RRRfCbŋcǎ555x"Y_t(;ZdȩSt}bذa'NpvvV,cȐ!ׯ_pɉm&Mty//k׮M4)??t^TT$\\\BdaP5I1cN81c 8iuؔ啕\);;;M!]w% I7o3g7kM\.gF6y]I&IR04{;DijllH$@"466*URp5 um+())7nܸs2/=z4sb^{)_fZ>*nC`Gu±c>u3;vh7dOKFFFuu\.߹sgՆ!#FlLF8٤ yu*@\Mf*k-p!\~!V]/%rYf[)5S8 ellk+sb5plW\!Pg~ƍWA';vLy!PQ}EEEF "RRRΝkllLf8pڴiMRR~7}Yf͞=; `߾}^nϟ?oeeE+ZYYw YEv&NNN9rGaJM<955|e|</<<VVSN{'O$=ϝ;w C!U5///;;044455СC999`oo_XX  I6_nݺYfVX1{ln ON͂z=`ȑN*N}饗H!Cm )nh-)X$kWKd]?~}!@{{{'=L?<$Wѓw^XXXAAA/F'999:tŅBPqrrڶm[_MPGď8`kiY(JSSŭaa72ٮÇEoÇŏϙcmalӛȰ09eg_++ 0-o򋋗;8@Vtx6HXUhA<T|7SrPqAV򊚉Hܿ_*޹s'((HSX*> '''lccgq]Ɩ-[4OU QbxΝ:"+)ݻwB &;wݎ|iӢ5e o AEⷚ+w#SpB}iEE C:,-.bܶ^mbll׬H O$~䐇?~ @6pV###  'O6m3CQQQ&+:z`=x5622~Z!/3fz[M7>^,GFFZ[[D%K8;;'$$477GFFxwΚ5gQF,$$Hs/K A\?a%*%C;:%DKDPx(otPhmmp͛7zjSSǏaÆ%$$x{{d2Cm֭[٥k#HzO>ݝZ>_ čaNJw`9s](tc ]0q"j޴i U%H lmn )OMx}zeemcc#}uuK/?d6gg~$۷|r@kbذafW}b. 2I*x`ees5 yEEeg/_/~VE 쭭 ^ 8>$(k?ܾ=, nC )?z"Re榦ݽlӁ/N>e 閾d2C"&uvS8TEyGGGoiӦΛ7/**ƆyTI___`'ecc\e$bKdia`BL"F矹.qcҥOM 4i9cK,ijj"c人:kkkHJJ%۪xyym۶ĄAѹׂ\binNN|۵k?Uwll,=}(z066fGmQ4VZE~I+$BzSzꮪ33ҒB8`Ǽ;zhܫW< 88_EIMA(F I+N.I RA=mǎ QQQaÆ7:)ZpNN/\[:99>.ǩB} @S[[w^񤔾t+W444Ì3<+b.i/Io?Bbg ę7nh,`ֻ@ Y_E۷VZ L&kmm rrr$ Q]]-wٓe SX/DDD 0@OOG!RYYYd;--mƍO.-----mii!۷/**WJJ_|QTT$HlC5X;w˭G^BiB&>^L.dsuM\.ߙe =KJJ:zhff&~ᇾBwqM]O%M@\, VqjZE_:uܦbqiuBQqDP(-esEEQYB?o7"7Ǽrs}Nr|lvKK͛7Bdw||<~ "5>>=44tϞ=2???h>>>άb&&&wܡ堫;~x"=@r'%3x~'H,>xޓ'9uul 9R\^^f--iyy_ԩԸTPDBBxL С̻w b/]ug`0nz̘1-:ut7eLQޥdwEEE߾}n9#Xk⚚ mZZZ~.!_G.^Z嗷 BDҠ T::RUE%t֬WٕfAA#rXٳYf|r֭:::/^ _rOGŝ>};XL<^n݆ 3pUˈ([FF7` zA n| U(O;::vj nmmM|SQQC 2dϷ;wMǔ$p-8匔eİz555!J ^&(4HTUU~˂lbiiollabV^-]/ &qF6<Vw"vÇȼmlNj3,9#,?Ñ˂~MMMZ/׿mmmb9Լy44471Ǩ`%3a0@^+..̕\rA &RbccʦL쌯h?HtY\]]ar'_dƌ?/ n`0@IuݺuKtY*7nH߀ hϞx'>8ۗq+$~}_r&Jn.O!fH2 X~***rssG `nno>KKK +pr'LQgr̚ejlu,_ rTٌHHhħ>..0r]رc9!ӦYQBQSS 23@٘gݿ;byv ս]J9;"==@OfdСCw% mܸH"1XrD\~v,?=ʕ+MLL.}EuvSGyt7)1dF7mҳg|˗';|͂< ?;e8HxtWhcmm@ID#xd] ߟ/P&%݌n |ٴ4[KK`, ?;e8Hx9Uss1cdt R.0M1!jj=UڬZQ999!wwwp8;w>}رcgE~sa\"j$遲xQٍ&ONrr+>`=TQQQQZ"}U"L[(v=s̺:߽{EV) EY[[K FE:ԩS\͛g`ГVPVt9!!C'Ҽ536<{vYppV O%GZ";;I&oׯ'bHwfff7oޜ0aySN&$$P*%|aܹswO?KFR~volllt8AAA]u4 D([ZByhi88 ޠ(or-j-;kkv]uJd$ j$%W__k׮YfZy~Woߎx%Erew srzRsr+*TU݇ dk'6wĈohk:k3%#cgذ0is 䈲G@b2DLwXX۷W eKKK,]!sڵqơK}ga5U444`0~~Ab$'N nbhH\~V֒=!7fXΝ@Yf1Bs̡@% $>Ot㚚455)W=2JvP$i >z{,Q'Hr OJJ 445;z Ht>}ܻwzׯׯ_]rHJJRUUt` Bp8;v Mw#X,ybcDDٳ;:  =LYY٤I Bw-J@SSٹ"Ν;^"T]]]퓒(7) ¿Ž{BiiitB3OON?Qgr̚ejlu,_ rTٌHHhħ>..0r]رc9!ӦY(d<`WV67'EbqGCS+33[  y#F[7!DA9r{w72dG 4So@UUUƳg(IwW=IkkkAAAss3݅(G]HJJ:th``uO~0OSSĉPܹsΝtWAb[[[9;Q3|}Cٱ.?eyPbO蒊 y%;/8q RSOBmZoHJUY~KI63#wG271Iz?436YP0a(5jg \N@EEEM ^rEy#GlllaғZ[G^Z$8  w"bA FJJg̘o߾'O8::Rz&$$?"}6a'?<ʻ ҿ?_ 駛 ? oV̞8!4Vz,͂j +8<0]Spl--0!2C/N)Aܬ 7۹sg g``0o<2p;$$ ߿DD61/pL&3::!Y!} CQQÇgOOOSSӤ 6P:to@( OnjA567pJDml}POLěޫRQ,-tvt3Ǎ~$)6GF15Ҳ ;vǔiittBgܹcoeYP yg P||9s]xpҢE\%S\\lgg;j(k=DKKod0{씔OOO&Ivr/_G溻s p''ѣÖ/<ܬI;44^]ƛb360>rcs Z[vPN;!$/h3 J8Jx{>qےw+}8SSS}w#}>}.K.EIoMF_E' xSEE3y'N̟:{Iw4?d~HGuCF|kB޽{¨[B| H$N1-)777??!؅Xf.9 tvvѣG/^TRR˥KX,2J!g6mlljժ#RRR\| (8PXTTw('Oxxxhhh]z!mkkNl }V˷īzzz(F9994(‑ڔu떫۷ۭ_`0MLL쨞.mQ MMGϟ'cƌYhԩSg̘Af^~2o߾&&&<!d2 @ ߿BMMM./"fgff RO?566nܸRxx555wfJE mnn .ϿvZ~~… e.1|pxv):௿7o{YNJf&BH$.dIǻGD''مlvsKKZ^^BP(xqqqER?AΏ?Fyyyۭ_m0@"Xvtvk>~СCB7Zr>;+II_OJOWUQ {4(edކcMÆ]_Rʽn 4%pƍoxrpp8p?@LM6a""XDL]gTXL|v9JAjj*чx$.a ?322s#G N>-HN>M>C)Ҕd@%r qdBt=SH׼}gu׬n3zyQk9<{ Ǿ~{Dy63c1ݔC1 tux7"֛8oONY [~֭tWhsij(I__H&:::!''''''⭖h"b!ozX@ b+n[[qYZZG}O2„ Ǐy<###35")MJSGGG?~Ȑ!_5jԈ#Kwq ' /=*y?QޭB(?,*jx{YP@y>{ˡC{O$)paÁFNv#bCYY%\Q'F%WWSGoc> G A7x$ -*Dy"Gy7**kyy..!!Y-ҁ ,--sss/d;VTTXZZcz}(o-v#"=XobLAwԄk{]\\E 0SN~ QVC.0(sΥ@v֭[Lbqkk+vP<}4**jܹ2vٹsǎK‚Z@Bly؅#v蒀O@ Czx&"!_C>.puY4c%?%ҥ)𚛳<;߿_>nfPޣG:ZZ.d^ B  CQ{ҪXvmvv6gG) xxpA2 H\YԬZ[S~S]HII)// ?~PD̸sG,_u>}Bg͊zNw>uqp@mD]ڏ߿ĉ544kjjlvkk+J&%$$DEE!:Ì7n<|)B ć%IGGS _4DHDеJKzED³QK_ط/*)յcJ^ n1}E]͸q,"$]]][&(mmmb:K|khhPR߿&qѣuuu!###]__O<Ƈ?3,! @AL}kN>@3PTl3ڻ.CdZXޫ::cP̅ rs)WX8eA#n龾䅁D^1 "GVVɤ @UV}P!d?y A!x$2ʬ*nܸA\$$B:(H[%hdJ$@!P:5k{C~"£Gz{{] gϞ똥W#>BP nd^ P3T@w!D򨩩9u_~8>4++olީ!DuX~;>` B\|/L`0x, mǏo߾a m,+S!> +-- {7~3!-[dff"ÉP*Htm۶%''#dtG^x1))f \PJJq˗/3^솼nhbyyyY:>>=44tϞ=D|ҥKY,>!abunݺE ?n޼iee5fLFee (Ad`{_֬ ϝûX^[SxMM\<%g{3c[ qzuzeRwuрa zŭ6CvwGtO,Y,%2fN !TTTtM+Q2tX,PIIɒ%KGw-afXl2]Yn !g!BЎT=p@ FZZUz%KX)z/^]Fsԩ۷o]H(X,nmm%@#ȕõk|}}] C/^Qfff˖-x~G5;;;P\\\mm"WP^999|>&&&Bp|>ٲe+L"(**,Y4**cԴl2===P||Ǐ'LbmmNډ:;;fϟ?ihEoWʻ͛7Ǐ]JrSN^%RT̙)IeĵVb8D 99 PL;&&wg())ӓ3+v]^}捵5D2W+**֮]V1% Ɍe%j%^V'O7jn#Gnޓ'9uunP`;^hԧO~ʊBD"HII3e˖{"Ս7Jg666԰V<LI Z)8#pE!Q!>}Bg͊z.xY^4(edD []x? @NmJKK P("rt@*>/OO2{_~$vڿmmm" aIm,+J }F"TAD"(o*yVVs?tA{w+&S HLLT tVVD"QUUDK>x=>y3{|K?n\+~FiѪ >$uss>4SQi a@1ihh(:44!`0 nЅ٫G3{Qă-B5454A|7 KA'Џ?f0 ֯^b}.Ο??2zD"444 ݵ(o2!/uPL8f"ƆhnٲeѢE!!!uHwJǃwqq%`0']ɺ'q  o߮pB ؾ +W?s#߿_'YYY ,\pԩ!@ zX,nii!_vM(vjxGC$Ç9BbbbUUD"_;uj\\\ڵk8ꫯƌڰaB6m4@Q^^N\Cp8aaaaaaBp޽?cmm-H$:x޽{9>!e˖LPxx8 GaaǷo^\\,8m۶det3 "[x@'БEݻwO4 !jժ/^XXX]qqqDN;tmQxd7%FXF7By󦕕q2{%%NNӵ5}ȐР= !!C߾=r.Γ'x7m3BOƻ3K$, ΎƍO88 H-Z~zqssS+3QިmvGQxd7>ƛ'N$|+Vppp BFi7ʛ>Аlnn @@oPA IDATl:ԩS\͛g [M1sܸG0 xxtF>FI&==WwpAB}}yMM ! G'КQFyuрl$򱃵k"B(lryqgj2mZcs3MH0Sn?P@D!IHQ 4%ׯ_?X ɉ妦N4 n*Ϟ= @.#!.2ٔ}d>`wI|$ ==̞WZZ:{lx9F U33^P(TSofff( )=toɥWUUug13##㽧 S tdddII U@ìlVrz~ :*HJJ"tX,nyADr9_eܹC =>xٳt/BΝ;~9 Q>NJf&z>(4Eb3g>\ - bUhqFy2`t h#566:u @ ʕ3fhkkO>=##P>ӧO1cUÇ) [M0d>}B=9ׯ_]ww{Eb1Lخm?ri`0Ãmoe %dff薖 ]@QL͛y?==]tBg9uuڷ/c\N~~N~;Ev-/OauA8H@=|*@7n\jjaBL&ӽMuuuKkkkb1"Bs@SSSss3TUU522 Bm*kkkjj766Md2\.ljjj޼y7LfDDD>}&ǫ; 0oVUUXYY_)^? ZZZ666x6066fXdS P2llljFٰl Rb544t?ȑ#/###oΝ;- }'XFII 3???jnn+:99 Muuuzׯoܸqɒ%񝜜WBazz: ,++×ݻ焳X,JŜD9ν{?@QF322&/^xؿE9..0rС w0JOG GA ==ؤI<_r#Gǧ}V\I6ܹ3m@.dsΝ;v Ώ=ܿl__VZZJIվ~'s#L&2!3gΕ+W ;F6>YA%&&$[nݽ{7ޡ,**", " o>gΜxyرe˖f@@@nn.ƧAMoo 9qDc,X@6CBBΟ?O6UTT( ( ׯ}||?yRSS]]]?455,Bhx wwlwkz TAf "<&НqFccczWׯBO)׊@`nn~5_}D^>#ƔgΜ//Q:::GWB_}~LzuTT#鲙ƛӧOwtt$R[]lWIjjj2R9N,}鲔_~RfSL ǟwMu_קӦMw (p:;;|xs֭111dSz_/r}!4}tWe]׮]_GRM6Q`A͝;Kq.\3JeIbd矯޷o]\#xMM5\c))~#78@fv4ŋGBMC,((0v+i{"355e2 (̌P>567m XjX,&SԤfmMMD"khhPͺRNfƻOP(D@зpPdV{Nޙ S͙L}F,|Z`0::Tg)UA8H'bPWw8=?ˋ݌Azm``/tͦ@˗+zΝjnURRIƍ[hU&HW`g=-)YwMKWsHE"ԐP ].NJf&BH$vprFB("!!<&ԄՅ;vX)ނ57_rPIEH,>x̶Ç+߼A^Ϟxy=,**>5uˡCwN)$,4)g ?qXHD*r߆ ᡆ 5; I'"~hRדo>zdej9f<!22"b(Gp0`_'^q67>}@9T\jꆐCe COMu2$4(hOl,RUE%t֬x,``mf6m؅ӧ!/owGeJF3l嬬Uh@@ɀDkj<{vaG22wTL3|!!dbhix"%\1cƘ&'']ٳ tJJ %sɧc ʪy/oܿ] ,-JFsǏ\++[BOCE={m$t__%ct1m?rd;C?iiOo.)!E7?B'r\E@narFs/[&=QL 8(g`G1DAkP$L<~PCs&S"w!$зp644]^^IܧO7/^ڋ$2D$N#}v uuqPCP BRUQ c(z9;d"` ,*mh//w6] tNN t=I\``B_NJJ{eYtW9ʊB:++ [JJJ.P'O~M^^z@[n @9dgg_r֭[.\z2@@~[n ܶm"ì\.ǣ @'*%@\~r 1bą MFwQ=f }uEEH$@M<ƍӧÝ $bq7}mD@۷lg\x 4P+x'g\Q+{ }?(CC>B=RRRzdɒǏ]=<<\2i$Kw1ba;P``BO ɓ7n \ *>б@|fԈbE4Lfcccnn;}e(ӧU ή&$$ŋt@opt?Nw6 }޽{eeetWm۶1 ]lj'z}ƍ:o } Bz!SSSC< aaadgϞ;|w<99daܹxݻw|9eʔÇW^QnxZbLKK&_5?22MoooYSSsAE,--fnnիWɦʕ+'N())!Æ 'য়~0`|aRRǛΝ{8p9svjmm%SN:t(,..ZJWWl>},\Q[[K6}}}&É/^ܜlfeedpxǏzl1bdyϞ=x?ޞl>x 99lRvJLL| trr ;ܹ tuu%EEEO_&/_uٴ|~.K6ǏA6>_t)!/566ods~~~dxy׏l޽{_n:BBBaa!\UUE6=<<ƏO6\ ,!nݺ|2Zf EEEd500lD;w'O7nTUU%X{{?gϞf9y#Fcǎ/_nhhH6㏬,innxbTTTuu5%x Ӈl奦M]]UVcccСCNJ6[[[wڅ3gGΝ;wشi\RRÇ'@@6 F6KJJN8zAcc;V\Gvzjnn.ٴ\h~!ooo)_[XX촴4i``b LL &Ç2e wϝ;l?l|wxgx0PH6M'/^:u Oyr͛7MMMb =Ɖb⭁4j(|Mw6l؀OoܸOǎK@ {{{|kk|}e}/^M|@9 tAAԔ29 |J9'>...;0 :33ߌ?2>}48h |]YYI)`ҥ֭[xWWW:)) 511'uuuGC@_|Ν;dS,薖}}} tQQA]]2믿O?2>y$ >.//|r=//ɓds innOkjj(ǟ;w.>;ۗ2tR~~>TUU'|>r'gϞttt(?( 2 @za:'''!!l=2>s 75>~ ';888P&/^? tcc#SL'ЅxCCC:-- Ϙ1@Kǎ9@lJu謬,|E@'$$wh؅ w)ϟM===|-O?~w011L^C6|>> {xxh{,BhӦMx)))dsܸq t\\\cc#0`>&c+++E"щ'BCC ۷\\\(褤$*1>r 4=‚2r GH$'rch{e G@ ]7 &_W u+s/w}@W_}U7N 4hE^^ 6~~~ =^`A߾}o/^((( @˗+?,++ h L@/_VVV]Ed``gU@UUU]7ө IDATLΘ1ԩS>}:vt˜R^{XKNݻ>?aݻtRkkkk u >ׯX*r]hfff- ຐ111?]ɷx#<==sss 322F%,Pr0//JFɭvjN%_6RT~ ,_<''y.77ƍC ~]zˋZZ;\qe^@5ҥK\Wr]E>7d??zyyM2%99Yz8<֖H$R(GGGD+i[%)QԦ3BH=|\_zcǎr]B:9sF*N8N6$<z Cɵ#FhUV uʿ/U;B!4B[HHH  п666۷o'mLMMs7|s„ 'N;x`/J/Auʿ/U;B!%!ޢHVKϜ9s̙-^!PhBS~mo뢦+X|W %^7ou!P{d2St/yEXXG}u3ɼ@]7U BG gϞ[i]g٠ ##Ǐ:i_(!5uuu*D7o3f ׅ\Lg6_lYnn[ܹM~O>>}:svAuG@#ӦOr]:4Y4# pj $!I\W8ߺu̙3cǎ%'N|oAoF^SSSXXH`kzzzfff3*vHi^u!ŦQ|2&%kh^@/^ڵk\WB_74C dM Xiii@ZPຊV466~+W亐V/#G***N:Q"*B^kll~w.{ Jgvv;w&LЁ}"7BЈc.Uto> >ulh֭\WB!#####s]4۷ozTVVMMM\:/// T A>|8ЫW>7.!y!,XB4уƍ\W8i&^!M'JtURR7|I!lll...\עA&&.$$(55uҤI2y'O ?O8СCEEƔ Q*(ib3utt p1U 濌䢢"mm%K$&&>}Z,ݻwE"QZZٻ=%%ߟ!R'8F<%,3f6]oD3z^^^&M:u*X[[655'';vD"f:-B[={ %^/0771}$??֭?Ғy?3Oyf-[=z<?~әϞ=Oaaaz .=zyڣG/nW_ݽ{y:zhk(MMM|>$$뱱t{L橛ۊ++WgcƌaFEEmfnn<N><۸q#~ӦM@'O6l@_n=ٳ?}:U |w@oݺO> E4!PyBN"ꖞuN9򇐚 :ujPP'+WܹsرcLˤk44jNn8bt!Pt krܤ!5߬B|DFFfff.X֖*//_xubb{H7c$111uuu!!!^&c V4%&@#QٙPU6ACIQtF7}̙^ne$BnYуcǎ%I gee!^{}p3^(oW˿ ~,xE_rfr=Ԍ&;p@oذaΝ\WSM֗3Qd(M2tfcqr9~,ʼypMv ^@+YB\a>611ם˝cbb(oz庢eq%f8B!>!7M_hu;gX!p1LEAWEvӯ W#R8FFfii)ի~~~QQQd(֞h-nfiijlA(**7o^cc#WD);;={<|Ȑ!]GlR)j$++o&$$kC ٳ.qɉ_"ܺu֛H]Mu+k͚5rdoWl1QcEѯH۷Wg)!MuK$={?~RSSģG@LLLTTԋ/cӧO8u3_~%?3{Z󺡥/y[*J,)77'OZZZի-PD555qqqvLD;g`֬Y YQQq 60!uK8_mYX;)"J$ccc(OkգG޽pug$B7hff}={VUUX,Ҙ5FFF̲qss]bqHH9} ϝ;9>655566Ңo/GHk4VPۥћ)EQAԱ'OXi߾}yN":u*7haa߫WcǎÇ z*.,,N('&&5j;vS>8b7FH(oU"m6L4)99zӦM7zٳg̟9)5G'ҏKKK}}}{I֌ҧpq -i@GWWU~k 5t~u쬓z֞1cFg=6cƌ͛7@@@Sdڴid3go)ܿ\[}BBBx=޹sgMM U 7VΝ; V PH?vrrڽ{wss3ӧp! أYK:y[#xi: =1(N䍢fsY~3lG_JSLQmða=́Ey3 ,3goٲl~G7:3$BrdAooo>_J"dFҗ]6lssNf#v /Dz<fgĉ7o9r$+ŀ΢Jtgձجڵk$i驨ZE˧t>}zpw }ԩ'Ovuue׮]ĺDaaaG=r~[#ԭz4 3$ =y#Hbccb+**ի~~~~p}w3v;v|\ׂz;.WpsF@GylP%4[Ib6>4UMM͎; x}A꩓m-VpklhGh6񨷯}}}#""puNf;' ps^@[[[p]"-&oXǎe52|^zmܸ'(&f8zFȢA֭[/ٳg\W=ǣ(1D3pGPx뭷"""p!Pgsguccccmd,is<ꇙ~ٳ'hii$4B4B)BO?oKDDU!8Fu?g'Bu ^%ISSU xG~Ihԕ/H${쉎.//K.766~WG& E"U ΄z-}ٳB:XzRIOOرcC=|'|~zە+W֭[ףG?r۶mk֬qvv?~H$=z]TT~!vڵfffcƌ\UUt[SSC:u*k/8y{׮]{íǃ JHHѣ{7p@B+++R{W]] clll'MļƍMMM-Z,KJJ񱲲oBBB B\/))a6GYf͚5*NJJJ233***߿_SS#H:tRWW׏?x555SLquuݺu޼yʪ`׿mÆ 8tТEH&Ν;'Mtxb+y.\ ߮|3gѣGttt%. }Q||<9qHz t=l0aaaիױc7oBKybd7u#hLmMLLf̘A9r䧟~ZjL&ۿiiIT|y[ٙΞ=ŋ/~/^TB~ bcc {E?{l@@СCW\y~u-߿yy94:СCLimmmhhϞ= V%Zyb?LrRƏ?~x撯<իj͍Ԑ|;VL+dbUL?~-]|}]SS}=˖- ,5%"Mh+Lyf&ً#uj8}RP( V>IKKIne"HGGe4 K|-,,q&--M:;v۶mY|||*9)J0m:===za"b1Dv^%... jÇwU///kAH溸ܸqcС\עAG.y=mi,V6{V2|KV#!B]hnPڳg5UhPhB%zzz׮]㺐xY}}-ׅ;+.B\WN ݷn!22dٲe\Eb?yׯ B{ضm[ssscc#FO?]nU $''z_FGGs]"*FyJr; + \ LGqO?۷ap] B p ()) H$bx`ggwU???"5\ Յ0[ZZ^%11޽{~~~dҳ]FFFQQѼyH$bNٳC d$c!Bm۶?0a￿~BH=zid˽tRKKˢ,r͚5@rҹ/tѵk=D1r@۷>ٯ4%%ߟ4=uT!O?3gu@#^ 4iԩS\˗/+ Cas[0 0ND֭[3gNuccc822}BCC.!B%q?wvv;wncc%KuQH|7O<Ẋijj 纐033[bUhCq]EGdCP>ٳ'Ut>t„ \4Qxx͛9s4559::s]-Z̙3\wz⺐6kjj]]] igϞ#??B:݂ >}u!u??^準QYY%011⺐!7>jZ 0[D?~ՉjiiM6;###33S7n |,]:oדS66Qc,NJ:/߃K.$Bl:ѣGofjii7~{1zСtӧOKR橇G߾}YYYtcҙ[w-,,d5nF<`GGGiMM˗YQFyyy"yjhhKgE38yxy#d✜橶6k7ʘ666C :u;3x>}0Ox7͕6V[@ {…ϟ?oWikkW&eee٬PHF-C8IPGGV&˶뭭eccF;ig[ P4}oz ~~#rsO:VW/{2Y?|!꺻;3ݲz @wɓ'z 4B|kUkUhp 4^q 4lqB!Шϗ^&B!P7oΝ۽{7U Yz Bu3g:ŋ?~u!!ԑ ry֮ 64H$=cʔP A QZZkU4B7ovveggbPѣի/f`zk><|P(亐!āq.]u$.tStn1j@#B!+"yThƍ \WB! z?ՅƊ@dddff lmm9~Ʀ.]kU.dii СEyxN]zC@AA;0SS#,Hcc(/\xuO(#vQy&6663mm{uT,n Hef,X0ƒ9ekkGǾ,a.:6qIļ+z!^NN͛7%lmm'OpBVӧObWWטKZZZZZZz{{Z GψrryS$H7;u*cӦo. o211q~^^f۶.. 6矏\\efܺ%g}Y<|{/08x 렶֒%3fOHkkk-Y2=1,81̨QKر#{ȪUlmXӧ`͚w4?d8zb8F!.eee&&&3gttt3g/_ܩE"QaǏ]ݝOL()yʴٸ{ J6@ۗ #7lG|22nō䈵~SS3_?=M_W~W/gut;gθ\| j.@O?TXXp]B7u6 H$׮]355{{hOO)W5u6x_~u%K[񚳳vDDLLv\Ey׭qwwΞE}@YԡAA~4.*z,6m?""[XL0mG.gNyzRt9ڵ;Fwds+&&_~IJJS+W233;Uc^^^zXhQaa3g.ݧM}RiUU9BTjkk{at~~>ׅt <}455B… ~~~O{eRԨf/^ԛ߂T*HN2:mlljn3Wa)%3jjB=Ǡܼ):`x=c6B}vy0EF`llL3.o󸬬wo x޼IcyZZZI3ѳꯨ|4Lw`P+2O!XY ccCU^u,^BHsZ:V뾯#ӧOgnܸndɒ0OףG@qqqqqQZ.^XRR/ٳ.x54Yuuurr&,'*Bjh;;;gg炂`sssFF}dӧO<"o={&3d.x5gh&$77W H,[[[s]BH$%%zxŋ*L4iҤI0k֬'O"--)S:tBWWrV^/v _" k첲2??`' {~ffc _w=.jkv3l@5kv9;M:F]8!1˂CzF3 Bcu$B:z޾Lx"K fgḺ:qHH~Rᮁ!"DHii==_qbq}Lz%s8F!.I҆^TVV&pY^/^LM ee&&=Mfy.K8BJJJ233D"QFFFQQѼycbbBBBRSSW;RRR&OQA~'r>R%( &  Hmݻ7Q7m۶~ZPwq̙###mm%K8p`Ȑ!b5&&&,,ݻZIIɵk&O2a҃+pԉ}f]qqYI˸e\F&05ug[ 6Uر#ȃ .&&Ntss"7UU077ik=oۧ7nɓ']^233Nz9kkkCCæ2ss3gӎ;D[[D*me9)B"8zF A j֌y5tX jMMMZ_  u!Kfr] j5?tO[o`͚5:\ѹ ܹsŊ\Ws]BVbb,-͸MO?]亐n:4|盞\&tJ(% Bi"?6:~!BB\b333333UD&۷ TpԕRiCCwMJ:_VV!Mꌪj+@n*z%%%%)))ŋ~iͅdϞ=?4::CEEE1t$$$l۶۬n7o|%D""$I$ :D%%))e?ED/((cQQ^ˤqJJ:B8F֭[ȈKMMMNNݻwLYf%$$@aaa~~ҥKɷ|֬Y R4,,M;zڵk}||!++t)))__SNuG'#v\\rj䴢ZKLOL<{tXj?p"QQZk@JJH҃N{@`꿎v`8d˲.!XQ&&&ͥQQQd;NGG9s_~ƌŊm0`@ ɘSL`8`*8Z^^vv֙9S9wWkkKCC沲 &3g'';忥2/PWieMF4UFY6JګLIibzֲu j!$>tٳg|ڊ"2v횩KN8144͛#G:tppp~)LG]ںq^>n;v7`ܸQ7@V1cu}2V}I+.ʖelG!>tرckjjӘ2b611;wP(#WEFFY\\\ee|f!i@8::ڵKOOO 0I`8.MFcǎ G6lMUU/M5`h41##<--{U_ڼ~ G G:^;{ NƟ 0Rwd@c}:qDmHR\ndd+W̞=[۫뵽-['Џ=x o}(`CS^1͒Ie2 lß>B+Q:*<m[}|v+WNաr)! :;;km/uܼzj:Bz̤1ʹyiAӨ߿~~J6VUT9v8{R^=o'MCk23θҋ`Q;sv}N;adb! O5xh4͛7oԩ^ꢶv^B!]ΟN%M }|Ɔ@ٱg?ٜy󈅮 ,Tͳ95!kNrd[ɴLD[tw>fnJ}&&ii0C#D=Dۭ!`W"ߒHo`:@Wvx_j0PTPPTQG-`' U%5t㛢\0xኅ~;C-T*++x?y&N&⬭3 Æ KNN˗/wrrD\.5..nСb8&&'W)JE"ѪUNp8Jp8taHHHH7UV@T~F$_jqcc _"VGG,/OFeqqR,9@P|=АMowr.Tk8..r0S:dT0$m Ha=yWP%B2+cPp8~~~ׯg2_rE,s\2jj8#pHf᪦C!z,٬؈%KyKdȧYYy>>cc#vq8V~~^G;9ّbDzŋ888Θ1O?v޻w.%bw涶^E).....ɓO?©m7l۶̙3_|?7+LWUUQWV@llի1 =,b!4Fz,!!A~M?z{{[soX[r~LUL&J`hM-u}4-cf8r䈗ה)Se2yMN֗譯B!JZZ@#g&Myyy2s?ˣ~N8A_QEEEiӦ3ߚ|/+Bi L&xx\6LB.\hdd4vX=zٳ菱fdd8;;ZZZȑ#s̙7o^HHH``#GzhmMm6##7o֗HC!4ץD( J#_xy 񀥭!s@)SdRٙ3ū?HDq~4Ui:TKByBBTTTTT:~Vqŋk%R|ŴH&uvv7Pvvݾ}hm:L)166zߚ5}CCr|SF t D'z^6d 5sLwq /3oɭF&Fb"b#OxjfzRYy4kB!B=zHEvw```yy9vqq!CXFR))@"_uvOO?#wpܷzFFF?3le|Ya0:{Qh׆]%qf9ԀePWSgfafamo?A۫@Ȕ7dffnڴߟlwld#=?)oظ12 VTT={Vzuukj2 XFo#XX-waMIe O>}zmuvv@&L@q@2ec% __Ogg{Jy&&'' eSwJ6/)oTƂLyX[ 56ܼr؛OQ]So÷`t³gIMM ܹS A=yahhH7nnniiit;(觏}W0qD>_SScggWXX?G 0v3HyJ F>ݽ{^|&)1c˖R8q_ZSSGaaml"s-PPP.^~=~x- D(Ϟ껔48sx O>|W#Ե+++.KE"B[nhǔ<!BLy#.^xa BG8d2SbqTP }&w+Τ_Mg!Z}}Sbbb@*DUVݹsɓ'r>rqqqÆ BhQZ5 /x0`JaPX.lokUp ^?D^V^^f^[s۵'쯪SSGS6@^VcO*O=~h׍T0\*RpTvTvzE}!wJKK߿/J-ZtY1Xd +,,{+Wb;dtU 6|Xf---Y,VMM5~4\TVVH$JNNNNN~D"IMMݺuׯK={D"rdee%$$\v RRR!GIJJzT*ݽ{wbb PU~SY)ɹF=.GJJH$[z˅¶[#G.&%|R$ON>|ŋ䜊۹S))G[Rٞ=SSD+jHbZri@i o_GU~~~*S{S]Ɛn40J7Y&D-m-ۺ&Hꧢ2;9~=_~^?͙3G۫MaaaFFJ@=hii Tzƍ655ZQo SoNNNYYY>>>;v` xի998lܸ^\\hbb XGLyݕ{z# V ed[1Malr/wpdJUM X|6nÏ)OyO{ZJؐaꮨT֛wO J"Sd4i Ri6j2Y, 142!5۷oGGG1Q, ϞvqqIMM OJJ7ocƛ7oZZZR?AC59܏?PVVvС+V`3:ڵ;/>݃vuuLN>|Gٕ;Unr{hڵRܔV:\ɔ)89\ʹX4cJSǶϏo3fѐ! M 4+\Bzj^'d{---HwH$YXX,[ؘ1.Sd … k֬3f 'XGNy[Ygd6rGۊn С d[pJqri>yH%z}t/B###R?|cc͛-XGb```b#mu=b33ݪ[ȩj`%BV\U z7l6;""fCH[[A.<<O8;!WR}*d2Yǻ޼TPJqETӚl\~9\nݞ,!݇)oBHbNe$z,V[[$N #HQ)oLFٓX]]k׮Lr)))dkCGoAPU0^ H[D"Qu;qPAL ".,6+"6"xI%O}1eWXF 뭔7oDh?AH!9]OPݰ>Hi_{sݍ Qٔ!c>8 ] "b J%b?v]$}tƪ0R8ܽ{7//O۫M[ׯ_oDH6QA-Jir)5%Hvɔ T!c,#XHV11(.Im-mujOAvTwUdD 1R8?~ƍs*)F@@ѸеkJRsssFk,DL74JOPB U%B0a4}:Gvɩ}DϦ*Ȉ bbٳuDHnwύ7~s?s =כ2"A!jB&[H%BF8D8HoW9HL@C6d2"%Hp򁊱삩SG]de%BP;-*"7}t]"|1!A]OPnXDZDL\wc. $agSS%$c~~^~o1BW11hX"DHa{b4(WYȓo"]@M?Q \&v8(]ijgDÐ oW\)//ZPMMMڪ@ ! ~vrSPoy󦶗8@d2ICE3g~W~χ^/o, :sj7NOVg6d+!fhhF7n[wF6&&MziAAA_Lާ%?cq'OBDhQTPHŴ-m-3ūcn&Tr!pN{w)ĭȸHa]A'!3'..Xɮ?^cTz]׿nnnBdL6;}g"{qmiNyʻbjӒm+Wh<{FL&Ưkjjr޽{bUQdgg_tb"wyȑII?${{}׮YYyy5ٍam#Tix<uï2''ˏ9sr)))@_|˗/Ga``0qK.imhKLL7nܴiȔPXfbcge]%{PXx{R]]ݻ3Fɓ]2JStL[)Q:KAvWWO]=~UP75-ඃ/WPG޽{Tz`ϟ l6;666++ʕ+bݝ@YYYyyyaa!GQ999 /_.sRRRBB^Fre~aaޞcjj)mذ/zl6r)eHvcX333)o賘69n/XM!BY ۛvvvXXXX[[GEE1cvhbbR?'2}h@KLL8qbDDŚ>}zBB~u&n#ٍam#4]/ƴ$I6=A?dl ]vT*rcǎ}APP?,**rssYfG]~̤/ )..ҐSAAӨ-_}jōam#>ИFH CCC,9(觿ꫯСC Tf̘'N555vvvXfF}L=7o^FL2 FC*HM4dbgV\I=g)x!4hݻO[bǸLA;BC]~޼yo{8BS dn\"umқs@~纝w*ʿ%H/K}BDD z- tc ͌Ջ47=d|7ǁCoXKBΞ=+ɖ-[Fm@ݮr۷o^HZʛLv_>qyzt& inr|7^tN8qbggt҅ J³g9: YYy ]W^.,/܂o|7=&M굔7쮯sQRNQ5DUH/b^EoSpڵ򶶶P|c!/Ȕ7dfmڴPX-VwYw#Rd?ǕO!݌:::ڴ^C 33sӦMBP(SEVS!HyO0|滑N͔7^z#c#[Y/&wȔ7L0uP<ѕo7BH(My:&'s!F:7SdԄzMOHQflGhSvuuMNNs!F: o昖x7滑 dꁛ[ZZZT1rnkDXTT̙3@}CLy#B淿-@#=% BhpUY"!2%H B!wK@d+c3<ҫ_͘7c8z7QnEa+ÌL ].D.nU_/VD;cq!B>%B:Cߝp\&8qݪ7idJ &LU YlWbq!d2Y{w- ]PSS'ޡbP^"$ Xԝ_x9j(jXXYuvt9Jd?ֲ 8SI>}nz{)ofB)oZssŋWTTI={N'&%rOmnn,>Vyl>-}j:t[?wfߙţwoٿ"%8̘7܎A {U&:MR={ 77w׮]YYYrSRR!ֽ7sڵٽ;fF,Y]"+Wbq {@xx;y,3TD}VИP dJr 7H%R+Z XD{aè^~~°gϞY[[bwww.3ovv5BҔwKKK]]P(TsFлy{O! oc&jtI7W ӓacc͛7---BJׂn߾UDC׸?z30]=) ZZڨ \,Hq7,iEK˖-322266%KZJ۫ǎyWO! $s N!QÐ c'N*%BFYzmс^޸q@HX"D:(33OϴB .'N?C!B=H.;pz|+T&B!B7>z^T/, ˅m nQK9Fa^T8/_"MH|%O:j8B! S&IT0ٍwUEUʈVjau3fcL2XyyEs#7t-)3{Rc]wW5AEMʻ)##CSJ~~&7fo=b@Qf wݽ{wƌƞ_{B40)oFrBF˅glu&Q_9r򔷣K?fM#݌/obY3575`*[n*z&b믿x^SH$JNNNNN~N|3v~r\V(>sʕҾ[ dʛo]nPhqPXmmmIK˄nd7cSnilyx0a,ꩫg*Ł++.#jpHY@|' )_IM 3f^z:4z!C=/k~jddaΞ=˘Di_~ J8!E6V3V0^7`1)o3 e!FFF!mÐ7} ԃ,_F |7mڛV,C=P:LyZ'''VЌJI|3ⷾ).....ɓO?\.Ƽw IDAT۶m;s_|xbzxE?~رK.U\0c*U'LLL~׽o:M.72G^Ͽ9{/u&QSyhmDJ4cD7h~|6Jg  NtʛwGDD$$$888@hh(⒚&Mo}w=~Νw.ZCS^1͖J2bhۣ\JNǏ'%%Zjҥ UM|AtŒo]n⦑[11ӧ{Pѽ#lr9&Q_듐J4v:=vX27S{=)i---iUonXw&MzA^^^PPuܹsׯ_9sf^^ySSSEEr\.EEEiӦКL_zΝK.MJJrvvV`T&&&bXÇ0~hHGmMΞSsa@ 5,"=_C۫+4۷o7FGG1&͘z} .H$G~ѣ++++juֹ744(ȑ#qqq}КL;u'OL>Sq\MS-\vΝ6h PvtS~vZOy׋wyJ%U3!`;^#}Xݝɔw[s۵'쯪"3 Bh` Su345fd|NC7Q~ OPm9YeXS`mg]V\6-plٽiw`d 621"[xT[DxwiׄqfjƁӃk2!RMMMkkkd2Ygg'} RSSөS?c<Ϛ5Rt@ /2;;n߾}qqq Q?Sm/Do777k{*+EAidd J/_djmEf*ψDV-{y`zcc 4--S,nͽ>M!..#7 @k[aaa? il_*(6 9`4lqDGS:33ɭ&]'N\>|SW||&O0z_ƍ|uáCMlVlo͉8'h޼ S׬Ih +Vr JUpGo? T'??umL*# ,GSr.(*No!]?nhhgcc<|SN7F7MLLȔwTTԳg϶lB܍^XXVRR3kkkzx||>>&Lرchf<~W֭۶mW7O **UFXU eeԞ1cn]"s#Kf.hŢqU |ons!ۻ=^)vJL [7oV,G7GDx}0P3gH R_[odgaCoرcoOTVVPy<Duׯ_@yyyyyy[[[AAAyy#G?N%_xAΩ妤477K={D"Uɕ5$11jZZ%400„}:,"+++!!ڵkw9H%ss?_XQ%B'';*%c1ٳի#8+rdfmڴ{osOj>u?TQw2Ov zG֭[|CUꩫg**??4hxx!*_Oro,@h K'N?~< y[ Q5R z%bD"9\ʹ*!`] 0aTg ;KHg)-2RƖ7ZZnO~UCCsYbB,ޢ!IU}DaHHڵk߿?}t2wQ*HnW)T:\ɔ)SD"9\ʹd0LwIg˩_2DJdJdaalYcPH? F=꫕.Yј1Nԟb,"CUFFF}}=U3!nnniii/. cHጕ0pUU#Fr +]o6`"Gry{{_=j(mEGGGm/AStqL )H*?_xO-X"DC*HYYYk{}n?~ yZ&Rj*!9\ʹtOz` /*^,٬95B˗/ 4c󟵽BBٳJ!BwZ&u16~񝪧[$V/߹nݢS\~NERHã B!ԥ$eUuUe?+wn42 D9\xŃI+WBרx^VW!B"SުA[ҰjǏ+֮M-~SY]MM UQ\ u7͊^|wVVvݡN~s}wnjEɨT YlW2 yy7-?W_7mFX[\~Mf0ݍ7 &QS޹w:GTW@ss[ssۭ[yrOmnn%ad}Կi/^LL< H@*8'FxK'X<ޥW^3FX `o\*OyD6*t;amM:daˀj.QqG=D)al=aX#{Xm7f2HyԴ3 Rt݉.\?*]ʂF===}˖->XGLyTWxl6+66bɒ`7ύ{{xr/wpɩȬ7c5o݂3WX9Vɮ8HrxQ]L8FĉөX caQ팕Affw[K[c]cZ)atf>5f:sܭ[gR2*(nDőz^CFɰ6#MR⦛q۷oSCsqq/`Y' UtPwkk?<-- 0Ly,Ka,AUhÆ]|~Xӧ;:::+55ufQQAe죦 Y'"_x9~(BqaQS ScCV2ζcUFS*͈9 eW+صTbDi7IMn>+9s:PNW3QGLyZZjdqѢYͭ] vmT*3':O7׿n+'$䃵kw޿_>}CꟐcjjXMv @'6T1٭V3oS[,2L)o&-n5~džCXϺ~WjS)_Q>zh~~ٳHK7UCmrㇾlG)mnhhVgz>h.Dwũs}z4++?7QG$;7덍lcaQll,J{zG!&m&dʛdaaM7)S|…5k֌3C?&]l;YϏ>}:5&֑NQfXԉbیFa3R/Ȯ8Mq8}DeG޺q݇%B>m'Cd[t&ϟ͛7S[T)J{1&֑~a[@'H-^XKЂ^l숈ޚ UGG~^ B HŘF!BhF!B7laPX.lokn̈f#BiNyD,*KmS:DU)ob6)o jauG{>!Z4BFm7imVR MMM4-)o*<|vcOɳc])4iqw#Mn,f5k7l0:o EH?s}~6R[rrrsbbbuu5t]n jz݀n}4]Sތ7 r⯿zч'o7[P/"Sތ/msObMZHy٨֮].Uϫ؆la.05em=G^Vdɣ'w>w2л;..*Un515*)iq g?>^]^M*JZ9KoM34%J@PHu_npL.Tk8..r0S*(._^D!**(=HTjbCC6cҏ?7oFss_r))Ǩ֕ :::ٞ\ Z}4^XAqD)Ej}1[[ˆfT~F,XD:!!G~ύ}tVج[,m,,:;:Doik6c̙}gΜj=ܚܭ"(*årϜ9^~^R#J%RQhѱv;GGT\\իm/ GU Cߴ/<^ehȶut;L LM_Xx',lVIɓg*?hnllē'BEEwe2y|uܹ>~ƍ16펌  lVlo J`"#~sYYy>>'Lc)8x֧N]:[Ě@NNѼy?& `5)xG6lؠDxݛvr/cf>t_cƼ~|߲^8t??<͇ܷtŴ49m-muj#233 B!Kc.\(pfUaYMY,*ц ۋ/ǏE?瘚t*Qɕ9EeokkV[[dgccAXUCcB={PO*!8qڰ{T"515)Pњ8;pb ,ȐD3 3)mZдiAZZ#s㍇S'B!?jhh.+Cf)AP]5 ԩ'Hk|tMDdŊvc#2v tb޼F'$wp0Aw𷬿/ &%9)L*+<_6dw1یy>5kh{!ڴnݺ7n>= ZlѣG(!cwwZ?W9.\(2773sIIq2N RI--mC\kc/`D͞EZaGGD">*666bYJw #P;;ۏir~)Ǐ2޷:SXl֜9>v4!;͟BJT;(}j``ٳJHUFFCPM[&`q YFzf2D۫@!lV>X [ݼyO IDAT۶mB+V!B!5@dnS"umjYq\Nv^TsλEwwlUKT[!!B.'ТJѵk!2VRK9FݟΊc5;|vKc ˅ra{[[?akєͭcɣ5]xm*prB!L&ko~ݺEo)K"O jjr޽`R6k悙..<17 $'VuYqٴiJj,6> t{ztM?߿-(H]L!7c>NG^6SJDFGi[hQ謷iӦ+WQryiii|||QZZZLyu=٠#^n,`#]p.w S4:-Wљ,.px8;_O]*L1\*&rEUo/?/Ԑ#7H4lذ&m/(m/!W|}=R3]E~ HLyh.y3֦ym/?/7o i.z3ɣYoprB!dgL>1Ftc=TmKF}fCŢOGO!_l:E^`N/Y-[BW/_@G'NtKkj ociKT0ߍB!k2l 0ñN B޽SHM4^۫@! rUmcc]IhQTP!8r~=pNc)^T8ptvNv `eg7sLz72.6/6_75iɌ]s@!jܹs[ZZjkk?sǂ1dȐ(9AQAՂjg7g  $Y*vT^plk;';ccQ#ύzbGB;p9s&Mn:رb QAAmmolb(8 8-۝Bo}y[-l,FqPRT9!ܹsE" ?{&7#M['.I6 nYr ,ndzE"M5t ˖.KNNf{ l1bĭ[jkkҘiӦq8Lnz!C bA]]}BB͛ 22ܹsϞ=c{\ eˀk0zhPMytlwষ\!}G!3_$tlh!_O!UԧgϞ /P1bĉ֭ҝeQ4`GBH1)_|.%$$`ۣ@!d)$4[CnU@K$aPQWDʕ*_,n#Bur)8 3O"^F࡙3ƛlm។A'W'd*3Ow??"B;,X ~y^@*J+ CcCyx_𕡱a/&g-S``]|@~jFo[2J~%% "BQ|TB.r *Cc*!jSUUU]]ۣ@!Gmllnݺ҈O"$G|"KuiC it*lL%D(***++c{Hݻӷzks%;"?gϞ=z_ׯ__~=o155woѻ[x1~ѢEUUUn||ĉ,_lb gggz7++ȑ#W_}Es}z7""W^ bbbZt eiYX[0x,v!#ep'ss @2$I "tǏ>qIqk/tud7$e1KJoؐJ~YX|ΊJv@nWRIB\AAAAAۣ@!Q= }X\&syMw726"OH~ @2"h}vEEۣ@DF BPjj(Y1eHl9ݾv{丑W^%(IVt*%0 )R^^Nf/#Bu6'''I Fr[-mYLVDSQkqa ӿmO00P$BT 2jL"DL"D ׁV2y5r e۬U?9<ܖ{ZtR]]ݕ+W4773g :Ly==ӧw͐BIcA*$pTw1cƴN+*((>|8ۣ@H!//2GeD"_jTcccv$žhΝ .`{PV$g{ WwߞYA(xsl6DiӦEGG=mR\\lhh@M,'$$Hm-ȀJOO'?=[WWWs;g;MiDSCC@H%C} --- lBeffbC2zW[l!Bj;d7@ZP.\vR-Un8Bu~!00Q RUQ@d;qU =U@>DݬBGSY4+;/{ݱݫwxOfnIdw2Ł ?wogBH^}o!6i;ʛL=}ӏȐmF  f$3dd@~{kB!s/BQ~A~dA`]^>^¦ B]<]uWf$3dd7qvsz\%7kgi$(ib׈Nz-!tw}R7XXSUSɯJ!2d[I8%@0oE)O=yґw:gc鴴Rg3w\lN-zK%.BhU@S5itwLb xb^FTqLZB:dGNK}w;9,m$qdґ^>ڷcu%\ -StUWWBg hY7KEqAǩSOS?mUE9AHU:s]æ1Nұ z;^ /ҵOkdZO?1wj!Pא?C &&dH&CƆTLv߽f7GUKOvg\zFfѳ '{LpS[Hhh fpGpFPc[utQ`_8INہT*mmW/WOh#OM9^׼e s Χ~J~3[R. + ?XAc}wK[´봲o//˟)Ԥ>i۩ESL9{A!5К2sL66]iV\_Kݽ]CU^QR]xx!7GBm=}=H$ :G"rwvf3\jmFƮ!P4ZQr9`8t됕Ճ;=|d CU^QR]}%/J.kl<^ՆSQVAʝ?\u0ͧVrm]ZI4MFƮ!Pϑ4j֕\0uGq Z}fEa!>aa`W,DE'Msf>fٶe=&X(:ߟ~rdr@x|jUN+Wd}Q}ە!+--(oԶ+~'(ݜ9OXmٺ1g=;OznZSrZLw jW ^^r%lXߪ]; 9Uwpөcc㦍#d|x 'Pr ۜm52v-!zVD"p)eZUrid11cEٓU >Cm322b{!T%?xOFw@x(!LMMBv }%C:s[nB!t@||(onԗȌn ݱn=yL_f B!3GyȌn6#QT__ܒ} 큠 *[[[ FE-Y]WW@Bi(o'a\<]ȌnF涒nm]t~l=c===cPQ݇^m׿4b•Bu+*-c0#F8;z,l_u>lf֭X@#u{"=}=wowˬ -BiǏgqOʟ|Ƨ)\-=*Jo9,x|HUlB錷z h$\E꽟D=~zؽzKY;Z^Z^-ޱrǎ;?|8D,=){Ռfi37fZj-Ugݻ~//B!A hDB}mAIbZP.\vb]Xri;EwJH?nZVWyE %ޭf.ǁq*rwF3 7׋Kq<8\:}iovOC9::= BjU@ gYܐ%|~ 9?;x>+;/vb@R]#%>|pXvQɫO>_5zw%OA~U!UL-L--M'_0P$=}=3K3s/Sdgg= BD!XzBR:#KƆLJs 9=%%1V,8:ڹkw߭ooW2!t$BE ջ|9"c t)FReH5ۭT-8 ܒ,8:8Xbbn"HK*2_oޯ|^e,X˴ld36Җ=/-޸بSm׉PP]ͼm⚚rhEETp(#J[q=j*IJ*z>*nCd`a y{xv즷fF8t${${*ƅ)V*jȘ={6ۣh//d{*111Wtӳ+ǣz-x<^DDCT<^dqC" $rK1B]K.]2snx*zcc'O= ]sĉ+o'L0kƃtUmmmdd6 TT<%?#KwXYFRk`ɥB!\=wϻ=ʓ'Sjjɓ;P= ]sΝ6HMO>mM'b-P{.|Aݽ{wԨQpBHgdeeaؔ,}[l7G566A..R)!X@DL{۽{l!B*z6]WTWɣE)C_} QT*=1*Ԧud>^R*6ߟH$:<߿*W2iitJ~SSSRRի;sȏV SdImii~vv6}I`>KMMMNN}*QތFt6(IoG326d2x>>qIqk=z=ܻ^j%\ɯכ4d_rMBwo{ӗ_9GsFF0,dϳan޼9zhCCCj贴4777.&RG:8*~떖&&&%%%044tM6K?noo奯SPrkGUw^xwRSSdBM hQsbg;1W^e40Ă Nu͙ǑXs:q 9ZDUL-L--M}I_~9粑H}}}$PWJHH=|iiygΜ)++'JWZU__tRAOliiyܹ˗/GEEM0իT7ޠ;&%%566*  DҁnFh䴲%l޻6D]յ_QQDwkaA)Ԕ#t7%@'>rS/@֮o?[Wlnw'St̤o|G4 ,u G_;wjd;rH!'v(X<~x5jTll.rSK$X W#{Z.;~ƴش4P8~x. ;w:t(477g# 5% ݻw2@7#?-}TF{U0 kU@Q{ST64w/$Ƽk bo}֘cp·>}kԄQ^>^gO# 9KC_dŲeDKZ;7aQx%r NLJz*GX0h xy=|pNN Y=ũ ''?zz IDATƃ&MƊ+]vQ ?CSu@7#?wmdb*~?ӧڵkd8SO&2LMct5Z,{==={̙B} 'aaBW Fy)GX2ydCCC///pss;v5k6۶msuu𰴴Tt;wM4)222<<|Νm>*H==qƙ؄EFFRGWZehh8cb/_nff-߈8m{߻6D?1MrV\onڴ~r_ O>7#4r:e&8OXtYrrr~'H$uU]?n18:zXu)woAAw ݇^ÇG&ȠUPwv-ooW2DI۷uuu]60q5???OOOw+ޫW͛7SU8BS< $_sV!4޾oa{,)gaB!_ C;rJW!B!jZ"ZD/Lewtn|pkIB/aTzd둗2SCfJd<ঃs;|qGGGG4ѣGsa{ "HIXm۶ˆt_MZP.(+  s +3#EB8:^;- <챳|;g;Uܟscތqvsܘ?7̄+Q?4x(bx߷77mb%׈і|vr`NN76 4#끰%%\[R;'֡zܽz7C213ٱrGQ^QLb -J%V-&g2>`zSo\Ax x y)%~`E߾}Ҥ{D kD",}} .\tˆtdybana/B@̄8_kN_ ]x~y~FO-##F}W̲Jv6}ޗČqvۏg>n?:nڸI˓p3@P!Xp}anIăBH}nppٱrǍK7"kWV<0 R$b "macAOA)|G::ƆxNQɵk.//,A^Y.0bջ;;FI6 H$J~w nh`B!mԪ&sG|2~kĥ2Lテ^ײet@|Ebv0uKWӅ|v"߈404P[H\ :!zԮH=¸bclQ00e\hd3T`8`F9г(Qu\J>W^yel!P]](v{IhETZZL$[n5Q66\C.*Ϯ|K.;t#%#ٌ  xK,{cǎݾ}Y*qƆsRYzMMM ֌m@oO>rigghvǏSO1pǏGFFQ{2SJ~e%R,, P @D*rXSb>]jn|5~ CS?|L=~zؽz7=N~ ?kg[K˩+wP]$HCAJ 깽L2Bm۶;vȑ#o߾%K|>|EIIIu;; ӇfYYy;;;F38zhDDu_6BgL `d^ѠUL"DZ CU[rabsgStG"xx?ۘʘcbmm"JRH0m uD"QQ\]]bcc`p:99(:x2Zb򫢪iKDH#C14=wZzoeL2  Rܹs 8=T4aƃ+WtRSRR"""?#XlnnN~„ 999pv0UF%?T$UI"D \}$K͌I2 0 FFFlDל>}z*6600?AN}k<==[###7n'|螘X__O}\W<#ӧO/\P9 $&nK̘o̘ /bZJI.אթ^@+B}C][˫(7 3ȌYgUU/OZdlb\r/Ч"35PwCCm̓wB^|)ף^\R6x f9r/[LB7mg!t0Fd1B:(oFF˄&|aqa)HEyEՂoO52߽feݳ:6 ]R̦&f&d7-}9~nyLƸo51.a: # *V6 AqD"/YI:F:|ppȍvwkffzzz..'3O|n} I'Sbq qG9{#Ɉӏ#4r2xxKeng|}צ31:۰a>U/]7ї0yB뱱_)%'!(y*I1:nZI!macAftZFi`h@'SY(2Su[%91YWCcw'ȹLr[P!2ֲq)5)y=z.޸بU9.[q/EB'X;XcN|BOedX=kzΒJaqa9Qm &wi)H+c_uV  C42)5ףk:DD͌q!< qy斑1}tBH%tOGY2&&|PO_<^ wiHr.ӷ "1Up{TBH ,s!cޕ$N(5r r<%BHu,֭[4jD!Qތn:رcQQQpјōPo !B헛m۶cǎ9r s.\GFDDPg | !yZD,m*_,y.EK[6(ڼGdW=Tz'b8{lXXۣ@7jԨ9sDEEQQt^7 }]vmNN8tOFH[ȏݫwS={{y<> G]FIPRn|"r0gRzݿѫ+/a~ ?kg[K"=i_<y$lXXGw"03Kvvvlu Qd.7xyy99970!m ?ʻr aQ†%/zvrsks20~=:I>K[Knd{njq:Zkd*!j(bÐBKDO_ojԣۏ:q q6}ޗd/I wC5:܉snݦ&Mֹ܀&s}}}}}}`рYu{Ç>;7vNlPTPhl({UFA`&Yp8H5L"t0&f̔S#@¢99J~YHMZөPC20P5% vNv&ƢBdY铧!F ` Bj#se͙3ё`P7gɏ`Ek%=hat]Y)iG +/adYd$YоA!ɏ` ՋR˨DH"m} {ˎ;n\85$ +6їp92\wch#J1F6n8a///BH% ׁ`EkD_Om0C?.q9نjf(T̻p8^h{w.ihhP 1Ba۫ !5:%H6TǒvWBчAaRE3K6mb{JMM>}QnCD%B)׿= U-Z?\hAHkDBPϞ=;rAH)L"$2d=$cF"S0!lllV^ ;vcƌn bJ*GLyDg:x𠅅D"quuH$;v`{DiHI@dP F}^hCba*! ջ|(o=b,m,M-L[-dwv_cC Lr[Xй u ?4ydh)L 'Npvvr[n}뭷BA7km&n`*aQ3;kWօSFAvg܎`by迁rh`)ĉo̘1l T*N8>>>W\a{PiNntsjFyG'D9:ٝ;[א&A~ٳg= Գ޽8<|6l6co) ?}]HNN>|BH;,Y hBgquu-/g&2(nJ, #r:&11ݝQ RUh:Sxx~ 0_93{o/]Wa2 g9ہ27f654ύ71jBԉŁ&`hPr[,v_sSsx k Ft***BD~7$ ZɯW T #ʛJF7`LwwØx^7|dP3qmҿ<@C6OIIa{iQn 8.Mfttw7%91ɘedt{wՉ5ANFr8j0Zo *C!AH=zŋl!m#r]<\vqҍ6OGetFMptpG)Dn by }#OffMW?|ehl*/[GxV*2,dX@w6ubqT6$A!)򦳻]<]~kp8 /ʛJFtwջI,# d$|dP'qmҿیCFtXss3˥,BݟJѷhdcf9KrbR,#I r2p> š.aUM%1ӧOg{ !T:И9K$9Ƞ5AOF8HRF= rewݝb2`BJJJɉ>|Mq{z~#ɓ'dv 8޽[W|qI[[>}лbd{ 緌>}C !wʪ]KKKjl;;;U^|ESSSzѣG< _YnݺU[[KّkK$˗/ݪ{ FA޻w޵"\rE,ӻnnnnmm[C rR{Gm###@HƎ; z{ްdÆ% j^F]!'PYlC|>1[PP0|ڵkn޽̙ӻIII6mwʊw?oлzzzd /ȠwLr .\@~!XYYI7oޯJ[[lw'OLx^{l Hț~޽{GCBB ~o6{ҥcǒ˝Ӌݿ\2(_>|=>ދ IDATBuO8֖|͍1Fݻ]r^wqq!wcbb RRRȊL /p]%o.|Y|f4 gXn݊+2PXX(H]zr2rH{w]6uT@H11=푠ٻ~+ۣ@݋D" |dIs5]J٭N|m"c%JTzd둗2T w{Ȕac>CR?`v6vAru[Խ~ww0>HQ@t===緰 ?!wJR\J(p8off&9880J^sƽzR>[[[[[aÆ*"BjROH"TBnHa|H,fTH!&j\p%߿-U%lnrO<.["F\;^^jck_K<ʙ+1s] u 7U+,ԩSOnz4hХKTX hk)CZ.(z%Y[Wl-/-%Wz;Vx1ٝ*T6)4K(o>cbL=o?;$,J(.(}J~e%R,,X D7#LF!<==[t-ŨɤRsCZ,Ȣ_I 8 K.+;+ f:q WU/{'Ί ZSXKi(9AQAT s (o rݕ=e&>OacB!]~4YKc2^=~ K/\,Yr12VP2 ճWe[2)4H6[""r0v"m} I'm>8|ܵ?:QLA! Lu?OOO>k]썌!G&|"K8wR8Hv~ẙML7? )ZJԉ񯎧6ݡud__iI:tF*81hѡk)rr}q#E,]r1 +IioRoDArkӱ(oݕPG:M6 rsYY#=iӦ믌U*Z*` *QYG-;-+-46Y.A]$f:WSSSIIIKK AݗJQJ*b !B=ټyphB!TC,B!j,JArs%;' 1\ P)pqqϭ꾰TJ{C(o~ CS?|LvgJ2v1JI#\.b ΨΎ큠gah;ʻ((Hs.UZ.;w^^GOTݫwS_$eTb}]ɯ46}#3r%ByWGySc]㙬3VUX$ޓ'5>؜_-ޱrǎ;?| XWi t A5U57/$'e¢b`|c}micija"l!3r%Byן/cW[˫(7 KO?>o@?~'Ŗk2x>>nצf.I+=i4ua!V'~)%V^$R,+24317q]wyx |L[Jaqad\ɬ]YN]1vٝ+(%B=(oFDKQT lkz *m!7~w[Q3;:!zd)QJ1k֬w}7 큠6bDlu2OOO.XP7%?ʛQ?e;c_uV ѓFxXƥTwgwtdD0R*~ohCGH]RR߮]|>ܻwopGM9luSWjC}YaX$ ^B@LbLc}#.UڎI{a$B!^ 95r A}Yn/B!ywpQB!A 4BHH$Qzr '3Oҷ(7WKnCZ;Xt0~.uĉEsΉ'EݸqN8QYYX-""[笯߰af<|Y[[=[d CX@#;傢pܘ?7^P.(-WFΌ[$ܽfeݳ:/{Q^QLbCq/ホ Q QVvVf@ Vv6jrJrrebK$ ӬǏX㧻vzҥ{66f.դRxGaX@t*YJ#[8g٦jAn2l0i6K26 ݽo웣ۏZynegE/K.}ܴq˓'Q&SQ(ݖsR ڳgOhhhiJff+(tDQޔچhWS0͇RRY ^W\ɍfO37fZ ܓZPM&YZY}yl}M=3J-UA&V=207mξQDH#3pwB=MJJJQ&/O?S`" ZO68ER#+3>}K\84x(Rn7=ǁqf;9YQVQ~<8+;J~e%R,,XL=-^=8:ڹkw߭gN-^|Έ$?I:;B˫(oKK򆯢d4k,>W?|EmM$ryw=2~2T>9"ln5 it"dwәaqaJ,pSER6Җ=P%IRdw2zpwB=^Q _zg.q˘VIa 2;kWօSFzw2~RQR$b 9Hü{3NGV$IQ3lmKΈ\]lllbccB!y.uޥE#Hb=g уG&IrHl(9I&YQ]iNIӧOB?A0?g JQ _EEY?ی$pIr5*se263}Jd0qaJ T쥼%FI{ip/|U.0WlGdWeQT %(ibv=5=?JQތf%2&I X$EvLF^#Ii_JK^vRn۶mjEy\0BH+ܼY:zlC@'O^ܢܑnn@s8#mz-:,С_'i;Okãݾ}_}FE}.sѣGzxx̙3eee@KҎZT$igϞ]TTtԩٳ4NEEEqqo@rrree%UL+z(ٰFHwK3_gb'smȸ h\3̛7ˋQt_W{!Fo]ȒD"K:t=|O?}Νocht̕+W޽ ǏQF)Z,ymj/D"GX#{ZY7n z{Ν~~~Cf eR0S?IJ}&'g xyTss(+v~\ɹ |jUN_yekMWWG0661Wt̠AI$Dɡژ5! >kAզ999T߀6Zzܹs+]v_/J^&ά5]v,F.S><MRdJEd7S*UAFyy݂ N booXpvԵW 311y7Lԝܹ*rAQ^Qx|D,9`zSͭwmikYMBr-_lqNWVw+;/~ ](<4scfSCSx31P#I3sk MUdH$$,JذdCx|8=7ytYgQیHgĞrc)gIz/R"2ʛ^]$\F;2K<өQ>iM';ݿ SD*V#^xytɳgOVt~F_s>}4yg~fڴiӦM۝߿vv'P1bDQQԩSOnfΜ9sfd_&i,ۡØ1|}悙txJ~%X;X_,'FEOFuR7#$S*$㾩hLT;cvruz-vO2׆Bk8HR\]Ξ=mgg@BDcQ$']?1/}ܩ:#[XJ2zS*;,וD(ɵhp8X=k\pppFFB!h,ʛDv @0oE>T͈ɔb)M-LɸoJBHM񯎧6ݡuGݗ1݆Q~㮡(oub)e)钛7oFE|@zԒjٳ˗/_72Qwt(oݕPtXOO,q(oPrǎMHb{ =Ez4~Z}}ӧOO2w?9Ҹwk!u),U5B۷/9Dt}xi`8233 RAHwX>(B 螮ꐧX|$:챳{exxT0͖/ULn,`` {\]]MLBliD"jKdI˴[e7Dr3JGy_/W w{Ȕacd j`}p꾀N ~+T b:q smN s +3#MLvQWGTPb:ƽn>(lF%DYY!;C.~ܵۅu<.;(}decz'#duMMMW_m۶ѱHM&?{gՕ-U2@PT™A4Nk'4^1NQ4DZ[.SC x Z"2@U}?Nٜ( dO~aW;}a}M=]W,RوĤ A3a 4b-!d"dYuttu먲@[B_ZR ʽĐQߗ]#Z6-Bxr1H}2+_~=@.%Kf%%54HV\`lW{z zzz k|оe ]WU*ȮLwRٌ0U|KR[!UW%V#,ZJCDB# $X𱠵8vPXh_R٘1CuvG K̶NTTȽ{ʪ`{&IӈIIBucaaYYYa --m5}!uKW6}L*MlС 4b-!a"dSoՁb >;U}!qV_vPAa}wܴvE*'LqT.]^.?:fPIWWPGSYY }; MPWq^5**Zt(k-)ĂOC4(_|ń mꔷo*dm_xEG'J2W@!tMt]m,Z*UBLX XKu.7*ƨG#V >y- g6CbR/F`9thu| ԧHw#ɚA._ş}YPPдi]6---22ӽݻrʮ$MR4BUT@! %}6׺ #/tttz%,Xe׮]dʕuuuyyyΝ{ ά`޼y@x+VH$ /^>>nnno-[`ڵ֭[@eT2|۶mQQQKII9q℟eZZdee͙3zj,E* ZfرfffA:Ŕ)S"##Ν\^^oXXX9kiѴw=|͚5B93{{{sNHRL&ꏅ ƍ1O? ={6̛7o֭G^paƌΐ>~xzx}}}UUH$b M62ٳg3\z!= K.d/-3AWO>X\P ch Ƃ8kF:aֽ'ٲeSiuF9k;Çv D}ɓ',=;}tS; ::Z* 껑 U,d/ sV,js&aZ3.0YCV\\\̙D^9W!*o33j>mqqq0zh (1: O8  B/VUV1_wa2LCvNjM'QHT"zb!JD%p8̵Im~Zcl7{=T0J.PmtCJ^.o39rȑzV!22ښ`hMMR)_{uW.\!œEz9倴E:@?t.3M7 ӷbZh$̉X1k\BT;}ʽ֕[ƭF w|7I+wE$BA;;;;;;mg G8]N fccb LKpeψV$ՉzoDwʕ[LsLZ'd/_p\~q~~c;0!==R.W:(Wy|Imu-Vf'!kvHmC^)53Z2%E- [Lņz/P9 H0eMAAqpѣgy<#>pߚަܔ3jjjb/UDqH 66CC"3߼yw;;K});gL4d7772D*۷O,Xr߾}$<<\ 0.J QZ۴[GG~,987l..` \ûm˷h; zSX̞=R G~{eh:|gϪ/A>9's>S0VWoO9"'NvBb~ iX+z7+N#bˆUL`6slXLBtФ z aLLLwd M[o`L/&edފa-Y!0᛼ѻ'w},Ytn=-kyGύ+SԀ`Btrk,5IgVVk} 12LOXYY%˿{8jU@MFᬱcw`l۷6썲W ?.oWc] WQ'9]1v!dfWB. 6m!wݷoҥK5eeewޕ+Wv,[! dU9dWq#PBhiՔb,y!Aq ,:C8(AD DHò>O*-[XXX0%QߍtE1!b D܁>00pĈnnnpw#G"HADP>z^ Qߍt X@#hrm ]@գj8껑. *L[)0n#[zX K,w5nKhS@4DÒ`օL*ؗ$i>h$sQNZX3H': - K*)-F &˜w5{/׿Uޯߞ3Tuf3@wB +{P9@G˴iewXL1~P h>ʬYzZGeBag@wB'f/goXILIGA:*o\~if;7E4 =~UbUUZB5265fތe:Q cƌyyyBkT*۳TbqDTR"jl|yb!i!W;RZQ HƴLO?7OwY~oݯgUcԬ*Bڅo} U`??d;0"pߖ2tFO9 ښ)0gWgTVUY%˯]cB].]mg¢̳g/gf=zTAf"QHTeիȵkï] ؘ0{{ YY~(ǟ[t=?_G^mDwA fRC6Zy%h7,]:{=!!38kpeFŷv!*o]P[[Ƽ؇mOPTT*oZ YU` AT55W255qr;rCmSFA^3ʛ3 rk[ qC#"B[7*&SSSinTTԽ{RRR,--%HE* Zf 1n9(C0nxoT|k ZMgnj#H={foooddDdC` e߯ *oFRyWUUD"Li&[[[FRmtkUޝIA QyC[6:thRR;wg.[__Ϛ?;;8u+ACG a.ϜǨS9's>S] -]"'N c!C/Y!ۓfN _{nƸ?uᅰ{_[=跸Mqq).( F8#dXϱt\|41CիUA+'ZRqp8˗/'G|M:7ܽ{7}DOWdΎD\\]s̚ӻ󎓓57oӏ֯_ϴR@ `?x`zLJ8w|ժU TGMN0Ы300`}O2E_A2IO5ʊwoJ| A珟t-u9 Ut]EP?OZDݕ(')t^^щ2P*cc󎎎jw}WYkkkO8qĉj͛,S?QF&VsVOOOJ\I$@fl`bbh"- ,) E"QEX;}bqml,Ξ|V Ò%$+W.066$n`xAnZ#zG͒ѓGscbH&u)zvNvGQ_Oڃ&G+ɨr&a4qR*Dz/N"<|Xkll5eQQ!RRcb{7!eYYsZ^z{_: hmy!!77ǧ20"=FOhM7=9OZ3*oE$=VNYߠU޹66CCrq|1cJ$McjjlbbA}w&BX,+((OJJjhhXr13\""C8xTjIA:Qy7VUՈD1{'7gLL%Ɉ#bcc=z͛73m=HAΜ9*~JKs˕ W;ϟ>w0qvwsdÆHHJzx{{wB:o"TJee% .ggK_>$$f@!ғӗu@Y q̙ )#OwI!cbb_@@@ttT*e-555W\155e"a(2Dz,#K.v]} >D.={h;  v tDHQ__\>tЋ/ޚ</44Pd$m hUVgEj.] ,3466ڵǬ!NNNtkA.K_# מ0kkkCw'5lVH2|6L\\PhMҒ$ +E¢ Q AMc L-L^caqAq`Dn0 c_Fin\3+<ѐ?{l[la -bbbhJBB*oL+D::_HN7yӴY$ތt?/֭[322nݺA/Q@Mq R l--PފgRu7#>tWWWΟ?ԨQ[lvFqH,L&{8HOXYY%˿*DaCW^^7?x\q.Dxmz8KLA}9ADCQQQ666:::7nċHǸvZFF*((vZL[>|X&9eˁgp/ H\=d3f3%Ty#h@`6o țqP,;w }Am\Ӻu̡3ZoM*oAǏ_joF$i; @Y֮ v_4qP 0foohDDy}d!fu/Y00"qB!8=?_GMÜ]UU|+k(#D'{n^^&B5a, } 탽Lܬ/?쳠iӦ;6--ǐ㣧N] 4$==j޽+W9ג~M9Ϲyywk.߸iU H'a/?b K:ettMLLpwwevAmKT9s5,gccCF:|ՙ2a1a] ҿ &BK_`fFƴ^P(y𡞞-#dT...۷o߶mw^JJ%KE$d;66to޼G2,66%Y3gee1^z5ЈD e ,z;, )D`oKKKNV'˱ X@#3f˗/9sF) HKT7oޜ}86䮓/%/\Uj5ku߀o ##COtUfY0;@TdWQáÔIN@y8 HjD L2cӦCCwi; +::Q*߀X=zSNeiSSSܹ3s̩Sm4h*_*辕Z---* B}7SXX8`?Ϻ/^(Gk!*Cbo#]Z}/|o@wCH,k׮oh'O~76qnO4vq+uj… UUYϟT͚ 0Hü&t˥~* 'N,zCd7{6܈oRڿZ}Qbp8~G;\\\Җvn.n jtߪ,ߪߊSaÌ?~v ;aXp)z˗k;D ޽7m...666x̙3AV|.q)gPjVVeVfMhFZg-v&ȫ1vƿo\zy=N:h"*v.})ɇBCCvZiK.)֑2XQo3s[.x)zZf gW 0--mr95Y"##?7FM@*D::_HFOqҥ'Oh; F TS|w!-P Y.nq5_ $Mlnz!GFMCY l--nA4ݻyyyf̘D ))ٟuQѽibO?=y JJD//^,,)}[|&(WjV5:YpUpb #:7#fkj*D--v5V# G_7 pUQVyߐ䱱܆xx پ=D ˦WoD:QQSS/qUoULvi[8aL&{%?8??_Qɬ핆hr$IŘJ\W_ugvHRM iPؤXF,Q6a֒YdvwC ڿ͂`bfBYp F#*' oX^.`aaZWНllX [JKLdcfZ-0y󪫫e׮]dʕ|>_*YBBŋ/yT), uuuB… aaaZ(D0GGGA>2z" _bcc5rqzѓU=OEUI} }+:z͛%'7o֭ysL''#ׯQN;UWcV:d81NW3-m ! Mxjj۷mۦK~~~iiiT=Reqrr5kÇcccr }$sc*,aI  _ܹe"T|# L?elwii2Bgg]Fo m4qss*˷LXqzi-\.a8m"{{{[XXA[߳gU5xf2HcccchhL/ǜ"C:L}P4  _#D e̴E7;Kc4h}]UoU#Tp5[8ygb"dHOO?~ynjnn\y!!!6mUT1j,JSS*$g"4UDح҂M=LϛiX}}}$LQ1j-JS*$gE!wyhLWW>\.<9o{8}wPj@Q tN*{PD!**Jv@& tJ M#v*G H'y󦶳055gӦ?>%hu&BU@E Hۼy;vh; @ɜu"AO$*D*nՐCCWŭb܁QH$;i$CcCIeUUrZ޵ fgAy5_h)S"# L:}>A/QyP5P[[QhU@E DHF=m=AW%*oDBO]f *o///k#wm-" t+Dqq F=vmu;w!ctuuJeKyy ^P(LNN>{lff&}QyGEEm߾{ERRRN8GW%ޞd~FgMvk׮'O\ndee>w\Q4"hwwwsssmgPO$ޣV?-F6aF4i$mgNA^P5- k# hA/{ァ,5AOOH<==ݻwСC[{ΝJUĀ}!bxDMFɚ6..]]]BaeeU^^[CP  vUA66oެ\ 99k\ZRA`CcCX;X66FA֯__TTheetAPy#øq㔫 dNĺq^M&N1TBTۨFA`ԩ/ˠAo/Uw>Nd)rqw䷺rs [Z&CX1-(Wy`\.TUVx|B_&Q  ,s9sٳgNNN?3lذ1c|'ׯ_ٿʻɖ-ZZ >cbyX\w$.HiHJJ?ZW !RlϞSjV  a*oDTfh~Hܑ;3Zo;g;@7 /K/uÇ_~iggGN]ݻwc׭[w}l2+V6m5jݷo5008vwuE~[o!!!eee;wܶmCPPi'<|X8mG7avmu{< fccb %#N.;y2o>Uj…mehh$̙Jfzu?> RyCx漍6-p);g5ք XZoAuuubXY… 8GQ` `:8_1@sRy*U<[(C.~˗oXp@az4t+ccwFGG_zÉc\oWpEZQZ׃Ƞ*mg<\GW/OG:-/1"=@ZZS ,X@]>LY3335X5g9Ν;nnn}Qppq8ΩSHRR/?b KGG??DTfp!55W255nm*{+m kQyK={<|رfiؒK.UTTDFFݷMJJǏ̙X GI,--UHgXRR" E"QXX~{%K^ZZe O2Gz*5Éc6:-p8%ܹ@#p57dm'ңZ:pvZ0ȺHY }g~W.\JSNݰaCpp0S((Vy/Y2>E9s,X_hd4E4BՐP.WO_ˊquu ++a8*# srr>|gcccgg8eKD |ҥKm_DEEݻw/%%eҤI2CãyzzZ ?|pll,^YY\TT>j}``#ɓ|󍁁=<<\\\oK2f _vuX!b4 ޫW74>~.k?z[e " utt@KKnZ)s&{ <6yP֥k-`.ʻn޽ӦMd`nn񚚚hwii鰦OB[+ѣ5\аkjjjbby N Tu9K65` H6lxضmS0m!*Ǐxۇ ]ܠ¿ G͝>}:yɓǍAAAuuu6m SRU,y&к̘YӲq@xo~Oۙ lqݽ]HT^'z{HNy9uԢEdJ;D})ɇBCCvZK.3gΘ 2[nd͠ɓ'3c}}=}jz8=JWp8MSSѕwr>>ڹzIbLzE/qVV{3V}Ѯŋeeei+Wh;ׇ? h)n66Uvv޳~όoWݚ@FR%[ .aI?~ѣGk; ˗/_ie˖7|3888((hرt|YxL8""*))ArccCTo_D>02#WX1_OOC/7j==8mghv<8J~}m=ߺrXGGu6%1Ъff@wi<8s8sL& DDflaή]_5pt#؛1uT?y5|XO#Ϭ#Yٶ=+|V\Lwo>777V>,ӑ&;;HMMe*b:Dck֬zzzwuuX֕;w/*jرdt~Hmii hll0`۷7o<~x"  3ϞGVp=*C3:^NWW'**d"lŘ|?̶s~XYY5#} myMhw݋:FFh31ҧ# gWbaqUeߊ-7޾zգq;}e'e# IDATc<5N^Wƿ̘?|iuq3;^i!'ebGya>ԇ  Z_zb=F|~mްy n16 ,BBB袐U 3]? L4b~~ߠk ?h}vĈMMMŋ))>m駟֒]֥Awppw̙Cպu&ELؑc̕p\n.^;IYhct[/=Ytrے7l ɦL=((HVynxFۄCbglV Qs[Yˍ H'gAԳ5ex#xh0 %|#7Z;X􎷩y6}9V4s7&x.iߒ+vƟ@']5/V. A4gС{y˗cbb^mbbOi c*#6R Vdmm^nA:*h"D4"={n2"HwisZ&uYɋ*ryW]  :NڦIٿiO?$*JD/_^,Q?`2 A{c   Hϰnݺ? "aQfr峗2 dNĺq^*DML QR/@~VΚ5AWA&l["mwa*=bee\. "Mh.S`#004hin4" L9s:uR"yr>WR"F(,* V icDhdw$ȝwgLY4ٰgφ=N!Ti;!<|X 06vc"ܼ9H=U~ L ۷lWޖgÇbcSeeϙ3{X@#Mvvkv?yWz$xH@`?@"`iN Ⴧk; х&'Çl'XX5rР5 D*ܶ@kXmmggvHLoEGydMߺ9dw亲[Th+DDϟ&BADt$9ZfkZZ#vvoʰaC$k*" ---X@#Z\}A㧍WY[8g; HFP1,!96ڜ rpYշRB<*V h ̦ϛ^[]ʤ}+-2$Ms#ŁVԋj4Id  H&&&L) y~)E& 3TGWGUNHT(;%{eʢ6GXϱa1aGfqyaq㩤S }  tʛDƷB#O8lWw|F 346|^H~M*U/\eIdl7{=ܼ|S%*xF<>wo# t+~agUބ'Ol9 m N9u`ˁgX1^Cizf7-)hц&ISO{+>>3@=VH~iShoU4ߺr˸y[G۔?^^?k8AAǘ1cp r OB[o_=i$:,vneo5-pan _{ fo-&-~7Omf?{|}/fرY:&g^P=W ۾8:3mŐ{o?p40~#ǓFy{9&>?5߬_ [;[H 0[Y.^DQFxY/ !Jޘ|l1s;tz(Aۑ `͚5OJ܈ ݝYD=Tޫlhh0Y@Qvdq@[MвW{1Y@HQ޺ۑ `4Fi|(V"V+m볅fQGY{~#ܤnRcPэOjQ<Љ=x ''gѥ-YZQ(+"3d^+ "^W]6FV"+-"zbc5jMTR9?,<љ*If.)rPY]ÁwߍU®JE%s<=X! ໱9\=]e%2W<&V~G@T]]=m4sEWjQ7n}g`_rGyz>o<[{[>{ 8]n"bה wVHn _9D$I_X9434DڕzO# (55~Ҥ>.Wo(o~_N;D/>ʛ*]\?,$2ܔ1^9(z=6mگT6,[? zIȼv4,,(4tD||r%%BL>o^D[jAfMD7X(ggGsEekۭٗ Eygv窭zjVVVƇ$F^9{׫VRS|rwM r%ƈ2RuJˈHݨޗoǻW9~F.ҴZE޸9-Z[Tɓ_hZ"ZpMa'._/;|\8_\|k8jȐ ´Ĵ3ϜJ;%,qt%^:ED2YoſJd?|Pe\z^&`s,ugd\̹hZ00p99M$Fc> _!/S rJ.erUJx&w7=F.%#@h ڪKeMzrp_XK~&sύ%q!""FVkcSR"3~&zXYe^vgV NP8gm!nWFx s$p8.0zqtHd,“pn,z?k4\ɹHDcD&/,u[ʕsv1Ep)Z?c|==4}QZ 3H7uo?ߘ:/TJ7(®K&u4ױyILL4@'wСsj4֭;yyEaÆ vv6cmRW^oyieex l/^z3{ɓD4v3_|_LD^~oĉ#-ED /LnL |ӯzIn\b^{'#+k+{9Yb1v9-gҗ- %% ;"bځc!ZĒkk+*d2FfO!H%**o2rig\?iI($@sV̖CL]K -bI޲eU_~VҐ!| 8Ə$"~8J' /$zykZA*Q𙂢7YH*#EI(H$X= h$JCB!Xz"zO}.]2,,Fcc#iVcs麚-5MFѓ7ac=ҼZ6mWgϿР]هGpnK]HGvB(dɣYbjtk2(h]jܧɉlYp)2EQ^QXlFIݞR"G:1//uz ʆe C"C('=g̉Tɾ|HV"+-;\Ά͙'DLhLoQ҆ gJ®JE%s<=2d^+ wcs [*딱b: 9;;>GV_н]:8;h,0tana^f^yiu7끁n}'gϞ8qb˽چPo3#Gy;;1ӂ/秢fj U=6|Р,b]wQw3=4*4Z`(hiii3&?m*Dl:Gy*[#E||Zxoܸ믿\{T*MJZ3~>.jҏ0۔3Mf "~Yl(z2w9 SIIIqq'|{>+8ϥrtQZ⤥yxx,^xӦMiiiX@teznѣGCCCR =jFРһ.1񨡦LVݹȣNupZ? h򼼼p":uKn޼i "*+S&"Zu롵kwJ))w'"QQ(*7lHڰ!֭;ꄄ}*!)%%Y}}Cvv>'9"-[ﭩ '7ܩrH$C8ֆ4@ ;foo?a"=zބ 70113iib OIӧkH+I;vX\\gݼY~Fҥ12\&74 w_P,sJ[ '`aIF8q-CmZѨt iޏ-d[FvgWܮ "V{bV^uuGuxE݄KfnooOD3f:q/ \^XBRu^?5*/WRSS/կ/Oze峺}y2-e駉Hzh_¾JEe}M*+-#"uz_¾﮺_ua`Nz??\jNڐtkڝ]DPߐ'">Y"1V!Dtp{jd%|*DT%OHɸ>pucW̥~f[srr***xVoo*LAcTT5; }DMOBBJAAS֭{_h ejϟ* ۿ52UTTٳW^V4OsQRPP<2$ʻf9lW|"rG' IDATfBnbݎn5Ok?͉`nY|dnQ7"233wѯ_?++'N+>;uvrr zoٲ{S×_"!C&o™݉h敍jgg^fggKD64a[S :_nnR۩SVZh$H(! VpQh3!L 98 W)y4M &&ԩSD4c a?8nWf͍\üy^^l>N\,= XYY=ĈSTMIz&~Mmz3!Oẗ́fbnFXS7]n#y݄nxBBBD[Ə+Lb0OVQަ<]*ʦ鎀hj,0{7-SZ'"r&Dv: Ӧ1tQf<-wG@tt,H mǕn#y݄n mUIUUѣG}.`NR0Iyye2O!#QޏJ-nEgn,,(oQzl8f͎ӧ/Y6Ytvipt/RLLF3zhφ {9yCnn'~G|app_ a:ʕ+_~e,**ZW}}}Y󫯾ڽ{7kСC|s/hѢ7|5ʢIIIO?5]]]eΟ?ϚfZf k644 gM25VZw(((r?~5'LyfĉkjjX{Yŋ'NJ_ݻ57̙SZZʚK,Yt)kd2>RRRʚɟ9kzzzfff_~Ixȶff敖wf=9..uYJJƜ9So(8uBsWZd:![x'L4rD14ih4u2Qݬ(Q#BGIR.mœs1T!DTW]u0}Ol-(*0#wwիWv$"D2}t~7u=%gQ*9`ѡLR[[˚}wph짞z :="0aBYsݻwuu};8:: 6kmm-_ ', i(=l0~Y9h L6aBu>}?o zTtD󻸸M;cƌDNDEEEq{+6@T옘!!(g{РzI61vwn)+ Ө5SUJUH"{Q3ΔI]9Kxx{d,V0$Vv?ξƋDtk ׺;Qeꔼ1å揚*OupAe2vYCV9#BGՍ7(b:9PTDklT7899_KѾk;~|`UU-k c7nس>zf%^Vv7<|lPpLaWAA͛山af;f3m$;sX؅΍ѓY݆57](*CQ|z(LfgjܵZfngqV;H`| @m(ʛÿEPTFQޢl)64b.gdq `jT>Po/څ(o#Y<$0Gye 6m$g$+EhQfQF uCs_kbHwg2/@Q9І ,FyVݹ)S & hKŢ(%%SXxnaE|7O/)(>>YxX0xIoh4*}W׉n7./W\EnnR1Q7%9sy~S;A*tanaZbڙgN*Y^v,fi1(RSa "ܟp#Dv>QrsR9i9K+/!zPx>45%&#N9E/ (/ ~[2\&W57YUDͫP0Еx{{L>""&qd۶K~ ={իVWWTTd'!!#^UU{UVVVfmj9M '[~C[%5tdu@ODUA"ʳbP0e(oWW*+u3ݝn>DI64dd* .uTJ"43rduLOD3REكG MڐtkPCZ]D"1w;65Y\üy^^|wNubX0x'X=S&9 2猳$BCÍP)U6ܟ(Pw/wVyH"DhvmD?b#GA\xIzaB|W-mM?Tt>RTODh1HFS;YĠT|!Knݺ]eXS"h`4O"$.}P(ɭ87%b vAM5?Dv[T@'>`/01H:)/bD;D(SņiԚ9K8:%oLvpTJdd% ?^Pы=}m&wfNzFN<ˣ Ѱ$BB1?ĈA22"M?]]Eyݢ&"-*R MlqP`'4( jnwO=e4?\-j"۲B, D4f hnB4`WmYŒW|%3 Q?#x-u;:;~CUܮp]8ur*`5M rrgpQ^n 鉢 ơBA 2]]]e2!۸'z̨LWVkoOU(*,qcR⛌0DT͟YQQED{{;w%,lL||tgj+Zpt˖uueb{p`QD$DyGthGy[[[̝7'ÃY -79dB3! zj1ӧB*8t&|wyb/rs Jս{~~Rw>D7Dy?6Q:MV\PLZf+k+o?ߘч+DX`Zxuu,֛bh*Ɉ u&uCo h***<<<226M:Eļk9жMo|n37KcH$Xt|FwHw`Z14qKHN*"A#ZRJ<~‚A7=zHKK3YtuH"/ϢC!#05P&rEyEEyEj<1b9smĬֽ*ŜE%@џDȇ9:09"JeCXѣk s g˿Wr|X1CsSe,VDDCg A\;*|JvQF "vYe%BL1/¡O+΂ ۳".p)ՕԼiQ Ц][vSiи)B|h"5WOW!NXN ;,&.&C 5'nNց," Ԕ94T3^8"tD^=f9~ّrsÃ>#'@C}`B*tg9giQ Ц &Io|nS4JxznT.09gho+{x [TΜyu)MGUG KUBB!@ >_Fc舢T".2 9sH7De5^|0!C!`BT' R1%4冎61hk.dQ[IENDB`Test-Unit-0.28/lib/PaxHeader/Test000755 000765 000024 00000000210 15113573111 016755 xustar00rjbsstaff000000 000000 30 mtime=1764685385.266317263 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/lib/Test/000755 000765 000024 00000000000 15113573111 015065 5ustar00rjbsstaff000000 000000 Test-Unit-0.28/lib/Test/PaxHeader/Unit000755 000765 000024 00000000210 15113573111 017674 xustar00rjbsstaff000000 000000 30 mtime=1764685385.275694167 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/lib/Test/Unit/000755 000765 000024 00000000000 15113573111 016004 5ustar00rjbsstaff000000 000000 Test-Unit-0.28/lib/Test/PaxHeader/Unit.pm000644 000765 000024 00000000210 15113573055 020313 xustar00rjbsstaff000000 000000 30 mtime=1764685357.557198878 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/lib/Test/Unit.pm000644 000765 000024 00000006252 15113573055 016356 0ustar00rjbsstaff000000 000000 =head1 NAME Test::Unit - the PerlUnit testing framework =head1 SYNOPSIS This package provides only the project version number, copyright texts, and a framework overview in POD format. =head1 DESCRIPTION This framework is intended to support unit testing in an object-oriented development paradigm (with support for inheritance of tests etc.) and is derived from the JUnit testing framework for Java by Kent Beck and Erich Gamma. To start learning how to use this framework, see L and L. (There will also eventually be a tutorial in L. However C is the procedural style interface to a sophisticated unit testing framework for Perl that. Test::Unit is intended to provide a simpler interface to the framework that is more suitable for use in a scripting style environment. Therefore, Test::Unit does not provide much support for an object-oriented approach to unit testing. =head1 COPYRIGHT Copyright (c) 2000-2002, 2005 the PerlUnit Development Team (see the F file included in this distribution). All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. That is, under the terms of either of: =over 4 =item * The GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version. The text of version 2 is included in the PerlUnit distribution package as F. =item * The "Artistic License" which comes with Perl. The text of this is included in the PerlUnit distribution package as F. =back =head1 SEE ALSO =over 4 =item * L =item * L =item * L =back =head1 FEEDBACK The Perl Unit development team are humans. In part we develop stuff because it scratches our collective itch but we'd also really like to know if it scratches yours. Please subscribe to the perlunit-users mailing list at L and let us know what you love and hate about PerlUnit and what else you want to do with it. =cut package Test::Unit; use strict; use vars qw($VERSION); # NOTE: this version number has to be kept in sync with the # number in the distribution file name (the distribution file # is the tarball for CPAN release) because the CPAN module # decides to fetch the tarball by looking at the version of # this module if you say "install Test::Unit" in the CPAN # shell. "make tardist" should do this automatically. BEGIN { $VERSION = '0.28'; } # Constants for notices displayed to the user: use constant COPYRIGHT_SHORT => < <<'END_COPYRIGHT_NOTICE'; This is PerlUnit version $Test::Unit::VERSION. Copyright (C) 2000-2002, 2005 Christian Lemburg, Brian Ewins, et. al. PerlUnit is a Unit Testing framework based on JUnit. See http://c2.com/cgi/wiki?TestingFrameworks PerlUnit is free software, redistributable under the same terms as Perl. END_COPYRIGHT_NOTICE 1; __END__ Test-Unit-0.28/lib/Test/Unit/PaxHeader/Exception.pm000644 000765 000024 00000000152 10273475545 022265 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/lib/Test/Unit/Exception.pm000644 000765 000024 00000003375 10273475545 020326 0ustar00rjbsstaff000000 000000 package Test::Unit::Exception; use strict; use Carp; use Error; use base 'Error'; sub throw_new { my $self = shift; my $class = ref $self; $class->throw(%{$self || {}},@_); } sub stacktrace { my $self = shift; warn "Stacktrace is deprecated and no longer works" } sub get_message { my $self = shift; $self->text; } sub hide_backtrace { my $self = shift; $self->{_hide_backtrace} = 1; } sub stringify { my $self = shift; my $file = $self->file; my $line = $self->line; my $message = $self->text || 'Died'; my $object = $self->object; my $str = "$file:$line"; $str .= ' - ' . $object->to_string() if $object && $object->can('to_string'); $str .= "\n" . $message; return $str; } sub to_string { my $self = shift; $self->stringify; } sub failed_test { carp "Test::Unit::Exception::failed_test called"; return $_[0]->object; } sub thrown_exception { carp "Test::Unit::Exception::thrown_exception called"; return $_[0]->object; } 1; __END__ =head1 NAME Test::Unit::Exception - unit testing framework exception class =head1 SYNOPSIS This class is not intended to be used directly =head1 DESCRIPTION This class is used by the framework to communicate the result of assertions, which will throw an instance of a subclass of this class in case of errors or failures. =head1 AUTHOR Copyright (c) 2000-2002, 2005 the PerlUnit Development Team (see L or the F file included in this distribution). All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO =over 4 =item * L =item * L =item * L =back =cut Test-Unit-0.28/lib/Test/Unit/PaxHeader/Runner.pm000644 000765 000024 00000000152 10273475545 021600 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/lib/Test/Unit/Runner.pm000644 000765 000024 00000003671 10273475545 017640 0ustar00rjbsstaff000000 000000 package Test::Unit::Runner; =head1 NAME Test::Unit::Runner - abstract base class for test runners =head1 SYNOPSIS my $runner = Test::Unit::TestRunner->new(); $runner->filter(@filter_tokens); $runner->start(...); =head1 DESCRIPTION This class is a parent class of all test runners, and hence is not intended to be used directly. It provides functionality such as state (e.g. run-time options) available to all runner classes. =cut use strict; use Test::Unit::Result; use base qw(Test::Unit::Listener); sub create_test_result { my $self = shift; return $self->{_result} = Test::Unit::Result->new(); } sub result { shift->{_result} } sub start_suite { my $self = shift; my ($suite) = @_; push @{ $self->{_suites_running} }, $suite; } sub end_suite { my $self = shift; my ($suite) = @_; pop @{ $self->{_suites_running} }; } =head2 suites_running() Returns an array stack of the current suites running. When a new suite is started, it is pushed on the stack, and it is popped on completion. Hence the first element in the returned array is the top-level suite, and the last is the innermost suite. =cut sub suites_running { my $self = shift; return @{ $self->{_suites_running} || [] }; } =head2 filter([ @tokens ]) Set the runner's filter tokens to the given list. =cut sub filter { my $self = shift; $self->{_filter} = [ @_ ] if @_; return @{ $self->{_filter} || [] }; } =head2 reset_filter() Clears the current filter. =cut sub reset_filter { my $self = shift; $self->{_filter} = []; } 1; =head1 AUTHOR Copyright (c) 2000-2002, 2005 the PerlUnit Development Team (see L or the F file included in this distribution). All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO L, L, L =cut Test-Unit-0.28/lib/Test/Unit/PaxHeader/Procedural.pm000644 000765 000024 00000000210 15113572106 022407 xustar00rjbsstaff000000 000000 30 mtime=1764684870.436014119 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/lib/Test/Unit/Procedural.pm000644 000765 000024 00000013420 15113572106 020445 0ustar00rjbsstaff000000 000000 package Test::Unit::Procedural; use strict; use Test::Unit::TestSuite; use Test::Unit::TestRunner; use base 'Exporter'; use vars qw(@EXPORT); @EXPORT = qw(assert create_suite run_suite add_suite); # Helper classes use Devel::Symdump; use Class::Inner; # Exception handling use Error qw/:try/; use Test::Unit::Exception; use Test::Unit::Failure; # private my $test_suite = Test::Unit::TestSuite->empty_new("Test::Unit"); my %suites = (); %suites = ('Test::Unit' => $test_suite); sub add_to_suites { my $suite_holder = shift; if (not exists $suites{$suite_holder}) { my $test_suite = Test::Unit::TestSuite->empty_new($suite_holder); $suites{$suite_holder} = $test_suite; } } # public sub assert ($;$) { my($condition, $message) = @_; my($asserter,$file,$line) = caller(1); add_to_suites($asserter); try { $suites{$asserter}->assert($condition, $message); } catch Test::Unit::Exception with { my $e = shift; $e->throw_new( -package => $asserter, -file => $file, -line => $line); } } sub create_suite { my ($test_package_name) = @_; $test_package_name = caller() unless defined($test_package_name); add_to_suites($test_package_name); no strict 'refs'; my $set_up_func = sub {}; my $tear_down_func = sub {}; my $st = Devel::Symdump->new($test_package_name); my @set_up_candidates = grep /::set_up$/, $st->functions; $set_up_func = \&{$set_up_candidates[0]} if @set_up_candidates; my @tear_down_candidates = grep /::tear_down$/, $st->functions; $tear_down_func = \&{$tear_down_candidates[0]} if @tear_down_candidates; for my $test_method (grep /::test[^:]*$/, $st->functions) { my($method_name) = $test_method =~ /::(test[^:]*)/; my $subref = \&{$test_method}; my $test_case = Class::Inner->new (parent => 'Test::Unit::TestCase', methods => {set_up => $set_up_func, tear_down => $tear_down_func, $method_name => $subref, }, args => [$method_name],); $suites{$test_package_name}->add_test($test_case); } } sub run_suite { my ($test_package_name, $filehandle) = @_; $test_package_name = caller() unless defined($test_package_name); my $test_runner = Test::Unit::TestRunner->new($filehandle); $test_runner->do_run($suites{$test_package_name}); } sub add_suite { my ($to_be_added, $to_add_to) = @_; $to_add_to = caller() unless defined($to_add_to); die "Error: no suite '$to_be_added'" unless exists $suites{$to_be_added}; die "Error: no suite '$to_add_to'" unless exists $suites{$to_add_to}; $suites{$to_add_to}->add_test($suites{$to_be_added}); } 1; __END__ =head1 NAME Test::Unit::Procedural - Procedural style unit testing interface =head1 SYNOPSIS use Test::Unit::Procedural; # your code to be tested goes here sub foo { return 23 }; sub bar { return 42 }; # define tests sub test_foo { assert(foo() == 23, "Your message here"); } sub test_bar { assert(bar() == 42, "I will be printed if this fails"); } # set_up and tear_down are used to # prepare and release resources need for testing sub set_up { print "hello world\n"; } sub tear_down { print "leaving world again\n"; } # run your test create_suite(); run_suite(); =head1 DESCRIPTION Test::Unit::Procedural is the procedural style interface to a sophisticated unit testing framework for Perl that is derived from the JUnit testing framework for Java by Kent Beck and Erich Gamma. While this framework is originally intended to support unit testing in an object-oriented development paradigm (with support for inheritance of tests etc.), Test::Unit::Procedural is intended to provide a simpler interface to the framework that is more suitable for use in a scripting style environment. Therefore, Test::Unit::Procedural does not provide much support for an object-oriented approach to unit testing - if you want that, please have a look at L. You test a given unit (a script, a module, whatever) by using Test::Unit::Procedural, which exports the following routines into your namespace: =over 4 =item assert() used to assert that a boolean condition is true =item create_suite() used to create a test suite consisting of all methods with a name prefix of C =item run_suite() runs the test suite (text output) =item add_suite() used to add test suites to each other =back For convenience, C will automatically build a test suite for a given package. This will build a test case for each subroutine in the package given that has a name starting with C and pack them all together into one TestSuite object for easy testing. If you don't give a package name to C, the current package is taken as default. Test output is one status line (a "." for every successful test run, or an "F" for any failed test run, to indicate progress), one result line ("OK" or "!!!FAILURES!!!"), and possibly many lines reporting detailed error messages for any failed tests. Please remember, Test::Unit::Procedural is intended to be a simple and convenient interface. If you need more functionality, take the object-oriented approach outlined in L. =head1 AUTHOR Copyright (c) 2000-2002, 2005 the PerlUnit Development Team (see L or the F file included in this distribution). All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO =over 4 =item * L =item * the procedural style examples in the examples directory =back =cut Test-Unit-0.28/lib/Test/Unit/PaxHeader/TkTestRunner.pm000644 000765 000024 00000000210 15113572271 022722 xustar00rjbsstaff000000 000000 30 mtime=1764684985.966084524 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/lib/Test/Unit/TkTestRunner.pm000644 000765 000024 00000044532 15113572271 020770 0ustar00rjbsstaff000000 000000 #!/usr/bin/perl -w package Test::Unit::TkTestRunner; use strict; use base qw(Test::Unit::Runner); use Tk; use Tk::BrowseEntry; use Benchmark; use Test::Unit; # for copyright & version number use Test::Unit::Result; use Test::Unit::Loader; sub new { my $self = bless {}, shift; return $self; } sub about { my $self = shift; my $dialog = $self->{frame}->DialogBox( -title => 'About PerlUnit', -buttons => [ 'OK' ] ); my $text = $dialog->add("ROText"); #, -width => 80, -height => 20); $text->insert("end", Test::Unit::COPYRIGHT_NOTICE); $text->pack(); $dialog->Show(); } sub add_error { my $self = shift; $self->{number_of_errors} = $self->{result}->error_count(); $self->append_failure("Error", @_); $self->update(); } sub add_failure { my $self = shift; $self->{number_of_failures} = $self->{result}->failure_count(); $self->append_failure("Failure", @_); $self->update(); } sub append_failure { my ($self, $kind, $test, $exception)=@_; my $message = $test->name(); #bad juju!! if ($message) { $kind .= ":".substr($message, 0, 100); } $self->{failure_list}->insert("end", $message); push @{$self->{failed_tests}}, $test; push @{$self->{exceptions}}, $exception; } sub plan{ my $self = shift; $self->{planned} = shift; } sub choose_file { my $self = shift; my $name = $self->{suite_name}; my @types = ([ 'All Files', '*' ]); my $dir = undef; if (defined $name) { require File::Basename; my $sfx; ($name, $dir, $sfx) = File::Basename::fileparse($name, '\..*'); if (defined($sfx) && length($sfx)) { unshift(@types, [ 'Similar Files', [$sfx]]); $name .= $sfx; } } my $file = $self->{frame}->getOpenFile( -title => "Select test case", -initialdir => $dir, -initialfile => $name, -filetypes => \@types ); if (defined $file) { $file=~s/\/+/\//g; } $self->{suite_name} = $file; } sub create_punit_menu { my $self = shift; my $main_menu = $self->{frame}->Menu( -type => 'menubar', -menuitems => [ [ cascade => 'F~ile', -menuitems => [ [ command => 'O~pen', -command => sub { $self->choose_file() } ], [ command => 'Ex~it', -command => sub { $self->{frame}->destroy() } ], ], ], [ cascade => 'H~elp', -menuitems => [ [ command => 'A~bout PerlUnit', -command => sub { $self->about() } ], ], ], ], ); return $main_menu; } sub create_menus { my $self = shift; $self->{frame}->configure(-menu => $self->create_punit_menu()); } sub create_ui { my $self = shift; # Lay the window out.... my $mw = $self->{frame} = MainWindow->new( -title => 'Run Test Suite', -width => 200 ); # I need stretchy labels, Tk doesnt have them my $mklabel = sub { my (@args)=@_; $self->{$args[0]} = $args[2]; $mw->Entry( -textvariable => \$self->{$args[0]}, -justify => $args[1], -relief => 'flat', -state => 'disabled' ); }; $self->create_menus(); $self->{suite_label} = $mw->Label( -text => 'Enter the name of the TestCase:' ); $self->{suite_name} = "x"; $self->{suite_field} = $mw->BrowseEntry( -textvariable => \$self->{suite_name}, -choices => [], ); $self->{add_text_listener} = sub { $self->run_suite() }; $self->{run} = $mw->Button( -text => 'Run', -state => 'normal', -command => sub { $self->run_suite() } ); my $lab1 = $mw->Label(-text => "Runs:"); my $lab2 = &{$mklabel}('number_of_runs', 'right', 0); my $lab3 = $mw->Label(-text => "Errors:"); my $lab4 = &{$mklabel}('number_of_errors', 'right', 0); my $lab5 = $mw->Label(-text => "Failures:"); my $lab6 = &{$mklabel}('number_of_failures', 'right', 0); $self->{progress_bar} = $mw->ArrayBar( -width => 20, -length => 400, -colors => [ 'green', 'red', 'grey' ] ); $self->{failure_label} = $mw->Label( -text => 'Errors and Failures:', -justify => 'left' ); $self->{failure_list} = $mw->Scrolled('Listbox', -scrollbars => 'e'); $self->{failure_list}->insert("end", "", "", "", "", "", ""); $self->{quit_button} = $mw->Button( -text => 'Quit', -command => sub { $mw->destroy() } ); $self->{rerun_button} = $mw->Button( -text => 'ReRun', -state => 'normal', -command => sub { $self->rerun() } ); $self->{show_error_button} = $mw->Button( -text => 'Show...', -state => 'normal', -command => sub { $self->show_error_trace() } ); $self->{status_line_box}= &{$mklabel}('status_line', 'left', 'Status line'); $self->{status_line_box}->configure(-relief => 'sunken', -bg => 'grey'); # Bindings go here, so objects are already defined. $self->{failure_list}->bind('' => sub { $self->show_error_trace() }); # all geometry management BELOW this point. Otherwise bindings # wont work. $self->{suite_label}->form( -left => [ '%0' ], -top => [ '%0' ], -fill => 'x' ); $self->{run}->form( -right => [ '%100' ], -top => [ $self->{suite_label} ], ); $self->{suite_field}->form( -left => [ '%0' ], -right => [$self->{run}], -top => [$self->{suite_label}], -fill => 'x' ); $lab1->form(-left => ['%0'], -top => [$self->{suite_field}, 10]); $lab2->form(-left => [$lab1], -top => [$self->{suite_field}, 10], -fill => 'x'); $lab3->form(-left => [$lab2], -top => [$self->{suite_field}, 10]); $lab4->form(-left => [$lab3], -top => [$self->{suite_field}, 10], -fill => 'x'); $lab5->form(-left => [$lab4], -top => [$self->{suite_field}, 10]); $lab6->form(-left => [$lab5], -top => [$self->{suite_field}, 10], -fill => 'x'); $self->{progress_bar}->form(-left => [ '%0' ], -top => [$lab6, 10]); $self->{failure_label}->form( -left => [ '%0' ], -top => [$self->{progress_bar}, 10], -right => [ '%100' ] ); $self->{failure_list}->form( -left => [ '%0' ], -top => [$self->{failure_label}], -right => [ '%100' ], -fill => 'both' ); # this is in a wierd order 'cos Quit keeps trying to resize. $self->{quit_button}->form( -right => [ '%100' ], -bottom => [ '%100' ], -fill => 'none' ); $self->{show_error_button}->form( -right => [ '%100' ], -bottom => [$self->{quit_button}], -top => [$self->{failure_list}] ); # Rerun doesn't work yet. # $self->{rerun_button}->form( # -right => [$self->{show_error_button}], # -top => [$self->{failure_list}] # ); $self->{status_line_box}->form( -left => [ '%0' ], -right => [$self->{quit_button}], -bottom => [ '%100' ], -top => [$self->{show_error_button}], -fill => 'x' ); $self->reset(); return $mw; } sub end_test { my $self = shift; $self->{runs} = $self->{result}->run_count(); $self->update(); } sub get_test { my $self = shift; my $suite = Test::Unit::Loader->obj_load(shift); $self->{status_line}=""; return $suite; } sub is_error_selected { my $self = shift; ($self->{listbox}->curselection>=0)?1:0; } sub load_frame_icon { # not implemented } sub main { my $main = new Test::Unit::TkTestRunner()->start(@_); } sub rerun { # not implemented and not going to! my $self = shift; my $index = $self->{failure_list}->curselection; return if $index < 0; my $test = $self->{failed_tests}->[$index]; #if (! $test->isa("Test::Unit::TestCase")) { $self->show_status("Could not reload test."); #} # Not sure how to do this... } sub reset { my $self = shift; $self->{number_of_errors} = 0; $self->{number_of_failures} = 0; $self->{number_of_runs} = 0; $self->{planned} = 0; $self->{failure_list}->delete(0, "end"); $self->{exceptions} = []; $self->{failed_tests} = []; $self->{progress_bar}->value(0, 0, 1); } sub run { my $self = shift; $self->run_suite(); } sub run_failed { my $self = shift; # not implemented } sub run_suite { my $self = shift; my $suite; if (defined($self->{runner})) { $self->{result}->stop(); } else { $self->add_to_history(); $self->{run}->configure(-text => "Stop"); $self->show_info("Initializing..."); $self->reset(); $self->show_info("Load Test Case..."); eval { $suite = $self->get_test($self->{suite_name}); }; if ($@ or !$suite) { $suite = undef; $self->show_status("Could not load test!"); } if ($suite) { $self->{runner} = 1; $self->{planned} = $suite->count_test_cases(); $self->{result} = $self->create_test_result(); $self->{result}->add_listener($self); $self->show_info("Running..."); $self->{start_time} = new Benchmark(); $suite->run($self->{result}); if ($self->{result}->should_stop()) { $self->show_status("Stopped"); } else { $self->{finish_time} = new Benchmark(); $self->{run_time} = timediff($self->{finish_time}, $self->{start_time}); $self->show_info("Finished: ".timestr($self->{run_time}, 'nop')); } } $self->{runner} = undef; $self->{result} = undef; $self->{run}->configure(-text => "Run"); } } sub show_error_trace { # pop up a text dialog containing the details. my $self = shift; my $dialog = $self->{frame}->DialogBox( -title => 'Details', -buttons => [ 'OK' ] ); my $selected = $self->{failure_list}->curselection; return unless defined($selected) && $self->{exceptions}[$selected]; my $text = $dialog->add("Scrolled", "ROText", -width => 80, -height => 20) ->pack(-expand => 1, -fill => 'both'); $text->insert("end", $self->{exceptions}[$selected]->to_string()); my $e = $self->{exceptions}[$selected]; if ($e->object->annotations()) { foreach my $data ("\n\nAnnotations:\n", $e->object->annotations()) { $text->insert("end", $data); # third arg would be a tag } } $dialog->Show(); } sub show_info { my $self = shift; $self->{status_line} = shift; $self->{status_line_box}->configure(-bg => 'grey'); } sub show_status { my $self = shift; $self->{status_line} = shift; $self->{status_line_box}->configure(-bg => 'red'); } sub start { my $self = shift; my (@args)=@_; my $mw = $self->create_ui(); if (@args) { $self->{suite_name} = shift @args; } MainLoop; } sub start_test { my $self = shift; my $test = shift; $self->{number_of_runs} = $self->{result}->run_count(); $self->show_info("Running: " . $test->name()); } sub add_pass { my $self = shift; my ($test, $exception)=@_; $self->update(); } sub update { my $self = shift; my $result = $self->{result}; my $total = $result->run_count(); my $failures = $result->failure_count(); my $errors = $result->error_count(); my $passes = $total-$failures-$errors; my $bad = $failures+$errors; #$passes = $result->run_count(); my $todo = ($total>$self->{planned})?0:$self->{planned}-$total; $self->{progress_bar}->value($passes, $bad, $todo); # force entry into the event loop. # this makes it nearly like its threaded... #sleep 1; $self->{frame}->update(); } sub add_to_history { my $self = shift; my $new_item = $self->{suite_name}; my $h = $self->{suite_field}; my $choices = $h->cget('-choices'); my @choices = (); if (ref($choices)) { @choices=@{$h->cget('-choices')}; } elsif ($choices) { # extraordinarily bad - choices is a scalar if theres # only one, and undefined if there are none! @choices = ($h->cget('-choices')); } @choices = ($new_item, grep {$_ ne $new_item} @choices); if (@choices>10) { @choices=@choices[0..9]; } $h->configure(-choices => \@choices); } package Tk::ArrayBar; # progressbar doesnt cut it. # This expects a variable which is an array ref, and # a matching list of colours. Sortof like stacked progress bars. # Heavily - ie almost totally - based on the code in ProgressBar. use Tk; use Tk::Canvas; use Tk::ROText; use Tk::DialogBox; use Carp; use strict; use base qw(Tk::Derived Tk::Canvas); Construct Tk::Widget 'ArrayBar'; sub ClassInit { my ($class, $mw) = @_; $class->SUPER::ClassInit($mw); $mw->bind($class, '', [ '_layoutRequest', 1 ]); } sub Populate { my($c, $args) = @_; $c->ConfigSpecs( -width => [ PASSIVE => undef, undef, 0 ], '-length' => [ PASSIVE => undef, undef, 0 ], -padx => [ PASSIVE => 'padX', 'Pad', 0 ], -pady => [ PASSIVE => 'padY', 'Pad', 0 ], -colors => [ PASSIVE => undef, undef, undef ], -relief => [ SELF => 'relief', 'Relief', 'sunken' ], -value => [ METHOD => undef, undef, undef ], -variable => [ PASSIVE => undef, undef, [ 0 ] ], -anchor => [ METHOD => 'anchor', 'Anchor', 'w' ], -resolution => [ PASSIVE => undef, undef, 1.0 ], -highlightthickness => [ SELF => 'highlightThickness', 'HighlightThickness', 0 ], -troughcolor => [ PASSIVE => 'troughColor', 'Background', 'grey55' ], ); _layoutRequest($c, 1); $c->OnDestroy([ Destroyed => $c ]); } sub anchor { my $c = shift; my $var = \$c->{Configure}{'-anchor'}; my $old = $$var; if (@_) { my $new = shift; croak "bad anchor position \"$new\": must be n, s, w or e" unless $new =~ /^[news]$/; $$var = $new; } $old; } sub _layoutRequest { my $c = shift; my $why = shift; $c->afterIdle([ '_arrange', $c ]) unless $c->{layout_pending}; $c->{layout_pending} |= $why; } sub _arrange { my $c = shift; my $why = $c->{layout_pending}; $c->{layout_pending} = 0; my $w = $c->Width; my $h = $c->Height; my $bw = $c->cget('-borderwidth') + $c->cget('-highlightthickness'); my $x = abs(int($c->{Configure}{'-padx'})) + $bw; my $y = abs(int($c->{Configure}{'-pady'})) + $bw; my $value = $c->cget('-variable'); my $horz = $c->{Configure}{'-anchor'} =~ /[ew]/i ? 1 : 0; my $dir = $c->{Configure}{'-anchor'} =~ /[ne]/i ? -1 : 1; if ($w == 1 && $h == 1) { my $bw = $c->cget('-borderwidth'); $h = $c->pixels($c->cget('-length')) || 40; $w = $c->pixels($c->cget('-width')) || 20; ($w, $h) = ($h, $w) if $horz; $c->GeometryRequest($w, $h); $c->parent->update; $c->update; $w = $c->Width; $h = $c->Height; } $w -= $x*2; $h -= $y*2; my $length = $horz ? $w : $h; my $width = $horz ? $h : $w; # at this point we have the length and width of the # bar independent of orientation and padding. # blocks and gaps are not used. # unlike progressbar I need to redraw these each time. # actually resizing them might be better... my $colors = $c->{Configure}{'-colors'} || [ 'green', 'red', 'grey55' ]; $c->delete($c->find('all')); $c->createRectangle( 0, 0, $w+$x*2, $h+$y*2, -fill => $c->{Configure}{'-troughcolor'}, -width => 0, -outline => undef ); my $total; my $count_value = scalar(@$value)-1; foreach my $val (@$value) { $total += $val > 0 ? $val : 0; } # prevent div by zero and give a nice initial appearance. $total = $total ? $total : 1; my $curx = $x; my $cury = $y; foreach my $index (0..$count_value) { my $size = ($length*$value->[$index])/$total; my $ud = $horz?$width:$size; my $lr = $horz?$size:$width; $c->{cover}->[$index] = $c->createRectangle( $curx, $cury, $curx+$lr-1, $cury+$ud-1, -fill => $colors->[$index], -width => 1, -outline => 'black' ); $curx+=$horz?$lr:0; $cury+=$horz?0:$ud; } } sub value { my $c = shift; my $val = $c->cget('-variable'); if (@_) { $c->configure(-variable => [@_]); _layoutRequest($c, 2); } } sub Destroyed { my $c = shift; my $var = delete $c->{'-variable'}; untie $$var if defined($var) && ref($var); } 1; __END__ =head1 NAME Test::Unit::TkTestRunner - unit testing framework helper class =head1 SYNOPSIS use Test::Unit::TkTestRunner; Test::Unit::TkTestRunner::main($my_testcase_class); =head1 DESCRIPTION This class is the test runner for the GUI style use of the testing framework. It is used by simple command line tools like the F script provided. The class needs as arguments the names of the classes encapsulating the tests to be run. =head1 AUTHOR Copyright (c) 2000-2002, 2005 the PerlUnit Development Team (see L or the F file included in this distribution). All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO =over 4 =item * L =item * L =item * L =item * L =item * L =item * L =item * For further examples, take a look at the framework self test collection (t::tlib::AllTests). =back =cut Test-Unit-0.28/lib/Test/Unit/PaxHeader/UnitHarness.pm000644 000765 000024 00000000152 10273475544 022571 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/lib/Test/Unit/UnitHarness.pm000644 000765 000024 00000012405 10273475544 020624 0ustar00rjbsstaff000000 000000 # This is a makeover of Test::Harness to allow its tests # to be retrofitted as unit tests. package Test::Unit::UnitHarness; BEGIN {require 5.002;} use base qw(Test::Unit::Runner Test::Unit::Test Exporter); use Config; use Carp; use Class::Inner; use FileHandle; use Test::Unit::Debug qw(debug); use Test::Unit::TestCase; use Test::Unit::Exception; use strict; use vars qw($VERSION $verbose $switches $have_devel_corestack $curtest @EXPORT @EXPORT_OK); $have_devel_corestack = 0; $VERSION = "1.1502"; @EXPORT = qw(&runtests); @EXPORT_OK = qw($verbose $switches); $verbose = 0; $switches = "-w"; # class and object methods sub new { my $class = shift; my ($name) = @_; my @_Tests = (); my $self = { _Tests => \@_Tests, _Name => $name, _Names => [], }; bless $self, $class; debug(ref($self) . "::new($name) called\n"); return $self; } sub run { my $self = shift; my $result = shift; my $test = $self->{_Name}; my $fh = new FileHandle; my $next = 1; my $max = 0; my $message = ""; # pass -I flags to children my $old5lib = $ENV{PERL5LIB}; local($ENV{'PERL5LIB'}) = join($Config{path_sep}, @INC); if ($^O eq 'VMS') { $switches =~ s/-(\S*[A-Z]\S*)/"-$1"/g } $fh->open($test) or print "can't open $test. $!\n"; my $first = <$fh>; my $s = $switches; $s .= q[ "-T"] if $first =~ /^#!.*\bperl.*-\w*T/; $fh->close or print "can't close $test. $!\n"; my $cmd = "$^X $s $test|"; $cmd = "MCR $cmd" if $^O eq 'VMS'; $fh->open($cmd) or print "can't run $test. $!\n"; for my $line (<$fh>) { print $line if $verbose; if ($line =~ /^1\.\.([0-9]+)/) { # Not supported in Result - It's needed!!! #$result->plan($1); $next = 1; $max = $1; $message = ""; } elsif ($max && $line =~ /^(not\s+)?ok\b/) { my $this = $next; if ($line =~ /^not ok\s*(\d*)/) { $this = $1 if $1 > 0; my $testcase = new Test::Unit::TestCase("$test case $this"); $result->start_test($testcase); $result->add_failure( Test::Unit::UnitHarness::TestCase->new("$test case $this"), Test::Unit::UnitHarness::Exception->new($message) ); $result->end_test($testcase); $message = ""; } elsif ($line =~ /^ok\s*(\d*)/) { $this = $1 if $1; my $testcase = Test::Unit::UnitHarness::TestCase->new("$test case $this"); $result->start_test($testcase); $result->add_pass($testcase); $result->end_test($testcase); $message = ""; } $next++; } else { # this is the message, not the medium... # this wasnt part of the Test::Harness protocol, so it # must be output from the program. Collect this, it might # prove useful! $message .= $line; } } $fh->close; # must close to reap child resource values if ($^O eq 'VMS') { if (defined $old5lib) { $ENV{PERL5LIB} = $old5lib; } else { delete $ENV{PERL5LIB}; } } } sub name { my $self = shift; return $self->{_Name}; } sub names { my $self = shift; return $self->{_Names}; } sub add_test { croak "This is suite is not mutable."; } sub add_test_method { croak "This suite is not mutable."; } sub count_test_cases { return 0; } sub to_string { my $self = shift; return $self->{_Name}; } sub warning { my $self = shift; my ($message) = @_; return Class::Inner->new( parent => 'Test::Unit::TestCase', methods => { run_test => sub { (shift)->fail($message) } }, args => ['warning'], ); } package Test::Unit::UnitHarness::TestCase; use base qw(Test::Unit::TestCase); sub run_test { my $self = shift; my $class = ref($self); my $method = $self->name(); $self->fail("This test is not restartable"); } package Test::Unit::UnitHarness::Exception; use base qw(Test::Unit::Exception); use strict; sub new { my $class = shift; my ($message) = @_; my $stacktrace = ''; $message = '' unless defined($message); $stacktrace = $class . ": Output from external test\n" . $message . "\n"; bless { stacktrace => $stacktrace }, $class; } sub stacktrace { my $self = shift; return $self->{stacktrace}; } 1; __END__ =head1 NAME Test::Unit::UnitHarness - unit testing framework helper class =head1 SYNOPSIS This class is not intended to be used directly =head1 DESCRIPTION This is a makeover of Test::Harness to allow its tests to be retrofitted as unit tests. =head1 AUTHOR Copyright (c) 2000-2002, 2005 the PerlUnit Development Team (see L or the F file included in this distribution). All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO =over 4 =item * L =item * L =item * L =back =cut Test-Unit-0.28/lib/Test/Unit/PaxHeader/HarnessUnit.pm000644 000765 000024 00000000210 15113572076 022560 xustar00rjbsstaff000000 000000 30 mtime=1764684862.630457301 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/lib/Test/Unit/HarnessUnit.pm000644 000765 000024 00000005600 15113572076 020617 0ustar00rjbsstaff000000 000000 package Test::Unit::HarnessUnit; # this is a test runner which outputs in the same # format that Test::Harness expects. use strict; use base qw(Test::Unit::Runner); use Test::Unit::TestSuite; use Test::Unit::Loader; sub new { my $class = shift; my ($filehandle) = @_; # should really use the IO::Handle package here. # this is very ugly. $filehandle = \*STDOUT unless $filehandle; bless { _Print_stream => $filehandle }, $class; } sub print_stream { my $self = shift; return $self->{_Print_stream}; } sub _print { my $self = shift; my (@args) = @_; $self->{_Print_stream}->print( @args); } sub start_test { my $self=shift; my $test=shift; } sub not_ok { my $self = shift; my ($test, $exception) = @_; $self->_print("\nnot ok ERROR ", $test->name(), "\n$exception\n"); } sub ok { my $self = shift; my ($test) = @_; $self->_print("ok PASS " . $test->name() . "\n"); } sub add_error { my $self = shift; $self->not_ok(@_); } sub add_failure { my $self = shift; $self->not_ok(@_); } sub add_pass { my $self = shift; $self->ok(@_); } sub end_test { my $self = shift; my ($test) = @_; } sub do_run { my $self = shift; my ($suite) = @_; my $result = $self->create_test_result(); $result->add_listener($self); $suite->run($result, $self); } sub main { my $self = shift; my $a_test_runner = __PACKAGE__->new; $a_test_runner->start(@_); } sub run { my $self = shift; my ($class) = @_; my $a_test_runner = Test::Unit::TestRunner->new(); if ($class->isa("Test::Unit::Test")) { $a_test_runner->do_run($class, 0); } else { $a_test_runner->do_run(Test::Unit::TestSuite->new($class), 0); } } sub start { my $self = shift; my (@args) = @_; my $test_case = ""; my $wait = 0; my $suite = Test::Unit::Loader::load(@args); if ($suite) { my $count=$suite->count_test_cases(); $self->_print("STARTING TEST RUN\n1..$count\n"); $self->do_run($suite); exit(0); } else { $self->_print("Invalid argument to test runner: $args[0]\n"); exit(1); } } 1; __END__ =head1 NAME Test::Unit::HarnessUnit - unit testing framework helper class =head1 SYNOPSIS This class is not intended to be used directly =head1 DESCRIPTION This is a test runner which outputs in the same format that Test::Harness expects. =head1 AUTHOR Copyright (c) 2000-2002, 2005 the PerlUnit Development Team (see L or the F file included in this distribution). All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO =over 4 =item * L =item * L =item * L =back =cut Test-Unit-0.28/lib/Test/Unit/PaxHeader/TestCase.pm000644 000765 000024 00000000210 15113571503 022022 xustar00rjbsstaff000000 000000 30 mtime=1764684611.886430194 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/lib/Test/Unit/TestCase.pm000644 000765 000024 00000026454 15113571503 020073 0ustar00rjbsstaff000000 000000 package Test::Unit::TestCase; use strict; use base qw(Test::Unit::Test); use Test::Unit::Debug qw(debug); use Test::Unit::Failure; use Test::Unit::Error; use Test::Unit::Result; use Devel::Symdump; use Class::Inner; use Error qw/:try/; sub new { my $class = shift; my ($name) = @_; bless { __PACKAGE__ . '_name' => $name, __PACKAGE__ . '_annotations' => '', }, $class; } sub annotate { my $self = shift; $self->{__PACKAGE__ . '_annotations'} .= join '', @_; } sub annotations { $_[0]->{__PACKAGE__ . '_annotations'} } sub count_test_cases { my $self = shift; return 1; } sub create_result { my $self = shift; return Test::Unit::Result->new(); } sub name { my $self = shift; return $self->{__PACKAGE__ . '_name'}; } sub run { my $self = shift; debug(ref($self), "::run() called on ", $self->name, "\n"); my ($result, $runner) = @_; $result ||= create_result(); $result->run($self); return $result; } sub run_bare { my $self = shift; debug(" ", ref($self), "::run_bare() called on ", $self->name, "\n"); $self->set_up(); # Make sure tear_down happens if and only if set_up() succeeds. try { $self->run_test(); 1; } finally { $self->tear_down; }; } sub run_test { my $self = shift; debug(" ", ref($self) . "::run_test() called on ", $self->name, "\n"); my $method = $self->name(); if ($self->can($method)) { debug(" running `$method'\n"); $self->$method(); } else { $self->fail(" Method `$method' not found"); } } sub set_up { 1 } sub tear_down { 1 } sub to_string { my $self = shift; my $class = ref($self); return ($self->name() || "ANON") . "(" . $class . ")"; } sub make_test_from_coderef { my ($self, $coderef, @args) = @_; die "Need a coderef argument" unless $coderef; return Class::Inner->new(parent => ($self || ref $self), methods => {run_test => $coderef}, args => [ @args ]); } # Returns a list of the tests run by this class and its superclasses. # DO NOT OVERRIDE THIS UNLESS YOU KNOW WHAT YOU ARE DOING! sub list_tests { my $class = ref($_[0]) || $_[0]; my @tests = (); no strict 'refs'; if (@{"$class\::TESTS"}) { push @tests, @{"$class\::TESTS"}; } else { push @tests, $class->get_matching_methods(qr/::(test[^:]*)$/); } push @tests, map {$_->can('list_tests') ? $_->list_tests : () } @{"$class\::ISA"}; my %tests = map {$_ => ''} @tests; return keys %tests; } sub get_matching_methods { my $class = ref($_[0]) || $_[0]; my $re = $_[1]; my $st = Devel::Symdump->new($class); return map { /$re/ ? $1 : () } $st->functions(); } sub list { my $self = shift; my $show_testcases = shift; return $show_testcases ? [ ($self->name() || 'anonymous testcase') . "\n" ] : []; } 1; __END__ =head1 NAME Test::Unit::TestCase - unit testing framework base class =head1 SYNOPSIS package FooBar; use base qw(Test::Unit::TestCase); sub new { my $self = shift()->SUPER::new(@_); # your state for fixture here return $self; } sub set_up { # provide fixture } sub tear_down { # clean up after test } sub test_foo { my $self = shift; my $obj = ClassUnderTest->new(...); $self->assert_not_null($obj); $self->assert_equals('expected result', $obj->foo); $self->assert(qr/pattern/, $obj->foobar); } sub test_bar { # test the bar feature } =head1 DESCRIPTION Test::Unit::TestCase is the 'workhorse' of the PerlUnit framework. When writing tests, you generally subclass Test::Unit::TestCase, write C and C functions if you need them, a bunch of C test methods, then do $ TestRunner.pl My::TestCase::Class and watch as your tests fail/succeed one after another. Or, if you want your tests to work under Test::Harness and the standard perlish 'make test', you'd write a t/foo.t that looked like: use Test::Unit::HarnessUnit; my $r = Test::Unit::HarnessUnit->new(); $r->start('My::TestCase::Class'); =head2 How To Use Test::Unit::TestCase (Taken from the JUnit TestCase class documentation) A test case defines the "fixture" (resources need for testing) to run multiple tests. To define a test case: =over 4 =item 1 implement a subclass of TestCase =item 2 define instance variables that store the state of the fixture (I suppose if you are using Class::MethodMaker this is possible...) =item 3 initialize the fixture state by overriding C =item 4 clean-up after a test by overriding C. =back Implement your tests as methods. By default, all methods that match the regex C are taken to be test methods (see L and L). Note that, by default all the tests defined in the current class and all of its parent classes will be run. To change this behaviour, see L. By default, each test runs in its own fixture so there can be no side effects among test runs. Here is an example: package MathTest; use base qw(Test::Unit::TestCase); sub new { my $self = shift()->SUPER::new(@_); $self->{value_1} = 0; $self->{value_2} = 0; return $self; } sub set_up { my $self = shift; $self->{value_1} = 2; $self->{value_2} = 3; } For each test implement a method which interacts with the fixture. Verify the expected results with assertions specified by calling C<$self-Eassert()> with a boolean value. sub test_add { my $self = shift; my $result = $self->{value_1} + $self->{value_2}; $self->assert($result == 5); } Once the methods are defined you can run them. The normal way to do this uses reflection to implement C. It dynamically finds and invokes a method. For this the name of the test case has to correspond to the test method to be run. The tests to be run can be collected into a TestSuite. The framework provides different test runners, which can run a test suite and collect the results. A test runner either expects a method C as the entry point to get a test to run or it will extract the suite automatically. =head2 Writing Test Methods The return value of your test method is completely irrelevant. The various test runners assume that a test is executed successfully if no exceptions are thrown. Generally, you will not have to deal directly with exceptions, but will write tests that look something like: sub test_something { my $self = shift; # Execute some code which gives some results. ... # Make assertions about those results $self->assert_equals('expected value', $resultA); $self->assert_not_null($result_object); $self->assert(qr/some_pattern/, $resultB); } The assert methods throw appropriate exceptions when the assertions fail, which will generally stringify nicely to give you sensible error reports. L has more details on the various different C methods. L describes the Exceptions used within the C framework. =head2 Helper methods =over 4 =item make_test_from_coderef (CODEREF, [NAME]) Takes a coderef and an optional name and returns a Test case that inherits from the object on which it was called, which has the coderef installed as its C method. L has more details on how this is generated. =item list_tests Returns the list of test methods in this class and its parents. You can override this in your own classes, but remember to call C in there too. Uses C. =item get_matching_methods (REGEXP) Returns the list of methods in this class matching REGEXP. =item set_up =item tear_down If you don't have any setup or tear down code that needs to be run, we provide a couple of null methods. Override them if you need to. =item annotate (MESSAGE) You can accumulate helpful debugging for each testcase method via this method, and it will only be outputted if the test fails or encounters an error. =back =head2 How it All Works The PerlUnit framework is achingly complex. The basic idea is that you get to write your tests independently of the manner in which they will be run, either via a C type script, or through one of the provided TestRunners, the framework will handle all that for you. And it does. So for the purposes of someone writing tests, in the majority of cases the answer is 'It just does.'. Of course, if you're trying to extend the framework, life gets a little more tricky. The core class that you should try and grok is probably Test::Unit::Result, which, in tandem with whichever TestRunner is being used mediates the process of running tests, stashes the results and generally sits at the centre of everything. Better docs will be forthcoming. =head1 NOTES Here's a few things to remember when you're writing your test suite: Tests are run in 'random' order; the list of tests in your TestCase are generated automagically from its symbol table, which is a hash, so methods aren't sorted there. If you need to specify the test order, you can do one of the following: =over 4 =item * Set @TESTS our @TESTS = qw(my_test my_test_2); This is the simplest, and recommended way. =item * Override the C method to return an ordered list of methodnames =item * Provide a C method which returns a Test::Unit::TestSuite. =back However, even if you do manage to specify the test order, be careful, object data will not be retained from one test to another, if you want to use persistent data you'll have to use package lexicals or globals. (Yes, this is probably a bug). If you only need to restrict which tests are run, there is a filtering mechanism available. Override the C method in your testcase class to return a hashref whose keys are filter tokens and whose values are either arrayrefs of test method names or coderefs which take the method name as the sole parameter and return true if and only if it should be filtered, e.g. sub filter {{ slow => [ qw(my_slow_test my_really_slow_test) ], matching_foo => sub { my $method = shift; return $method =~ /foo/; } }} Then, set the filter state in your runner before the test run starts: # @filter_tokens = ( 'slow', ... ); $runner->filter(@filter_tokens); $runner->start(@args); This interface is public, but currently undocumented (see F). =head1 BUGS See note 1 for at least one bug that's got me scratching my head. There's bound to be others. =head1 AUTHOR Copyright (c) 2000-2002, 2005 the PerlUnit Development Team (see L or the F file included in this distribution). All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO =over 4 =item * L =item * L =item * L =item * L =item * L =item * For further examples, take a look at the framework self test collection (t::tlib::AllTests). =back =cut Test-Unit-0.28/lib/Test/Unit/PaxHeader/Tutorial.pm000644 000765 000024 00000000152 07374760233 022131 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/lib/Test/Unit/Tutorial.pm000644 000765 000024 00000002303 07374760233 020160 0ustar00rjbsstaff000000 000000 package Test::Unit::Tutorial; # this is only a container for the Test::Unit tutorial # to allow viewing tutorial-style documentation on # unit testing by way of the perldoc utility. 1; __END__ =head1 NAME Test::Unit::Tutorial - Tutorial on unit testing =head1 SYNOPSIS perldoc Test::Unit::Tutorial =head1 DESCRIPTION Here should be extensive documentation on what unit testing is, why it is useful, and how to do it with the Test::Unit collection of modules. Sorry for not implementing this yet. Please have a look at the examples in the examples directory and read the F file that came with this distribution. A short tutorial on how to use the unit testing framework is included in L. Further examples can be found by looking at the self test collection, starting in t::tlib::AllTests. =head1 AUTHOR Christian Lemburg Elemburg@acm.orgE =head1 SEE ALSO =over 4 =item * The module documentation for all modules in the Test::Unit tree. =item * I Martin Fowler. Addison-Wesley, 1999. =item * The JUnit (unit testing framework for Java) documentation. =item * http://www.xProgramming.com/ =back =cut Test-Unit-0.28/lib/Test/Unit/PaxHeader/Error.pm000644 000765 000024 00000000152 10273475547 021422 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/lib/Test/Unit/Error.pm000644 000765 000024 00000002355 10273475547 017460 0ustar00rjbsstaff000000 000000 package Test::Unit::Error; use strict; use base qw(Test::Unit::Exception); # This is a hack to effectively rebless an unknown user exception as a # Test::Unit::Error, which is nice because all Test::Unit::Exceptions # have nice stringify() methods. sub make_new_from_error { my $self = shift; my $ex = shift; my $object = shift; $self->new(%$ex, -object => $object); } 1; __END__ =head1 NAME Test::Unit::Error - unit testing framework exception class =head1 SYNOPSIS This class is not intended to be used directly =head1 DESCRIPTION This class is used by the framework to communicate the occurrence of run-time errors (that is, syntax errors and the like, not failed tests, as the latter are classified as failures) generated by user code. When such an error occurs, an instance of this class will be thrown and caught internally in the framework. =head1 AUTHOR Copyright (c) 2000-2002, 2005 the PerlUnit Development Team (see L or the F file included in this distribution). All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO =over 4 =item * L =item * L =back =cut Test-Unit-0.28/lib/Test/Unit/PaxHeader/Runner000755 000765 000024 00000000210 15113573111 021145 xustar00rjbsstaff000000 000000 30 mtime=1764685385.270351716 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/lib/Test/Unit/Runner/000755 000765 000024 00000000000 15113573111 017255 5ustar00rjbsstaff000000 000000 Test-Unit-0.28/lib/Test/Unit/PaxHeader/Decorator.pm000644 000765 000024 00000000152 07504367740 022251 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/lib/Test/Unit/Decorator.pm000644 000765 000024 00000002531 07504367740 020303 0ustar00rjbsstaff000000 000000 package Test::Unit::Decorator; use strict; use base qw(Test::Unit::Test); sub new { my $class = shift; my ($fTest) = @_; return bless { _fTest => $fTest }, $class; } sub basic_run { my $self = shift; my ($result) = @_; $self->{_fTest}->run($result); } sub count_test_cases() { my $self = shift; return $self->{_fTest}->count_test_cases(); } sub run { my $self = shift; my ($result) = @_; $self->basic_run($result); } sub to_string { my $self = shift; "$self->{_fTest}"; } sub get_test { my $self = shift; return $self->{_fTest}; } 1; __END__ =head1 NAME Test::Unit::Decorator - unit testing framework helper class =head1 SYNOPSIS # A Decorator for Tests. Use TestDecorator as the base class # for defining new test decorators. Test decorator subclasses # can be introduced to add behaviour before or after a test # is run. =head1 DESCRIPTION A Decorator for Tests. Use TestDecorator as the base class for defining new test decorators. Test decorator subclasses can be introduced to add behaviour before or after a test is run. =head1 AUTHOR Copyright (c) 2001 Kevin Connor All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO L =cut Test-Unit-0.28/lib/Test/Unit/PaxHeader/Assertion.pm000644 000765 000024 00000000152 07410440351 022260 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/lib/Test/Unit/Assertion.pm000644 000765 000024 00000003756 07410440351 020324 0ustar00rjbsstaff000000 000000 package Test::Unit::Assertion; use strict; use Carp; use Test::Unit::Failure; use overload '""' => 'to_string'; sub fail { my $self = shift; my($asserter, $file, $line) = caller(2); # We're always called from # within an Assertion... Test::Unit::Failure->throw(-object => $self, -file => $file, -line => $line, -text => join '', @_); } sub do_assertion { Carp::croak("$_[0] forgot to override do_assertion"); } sub new { Carp::croak("$_[0] forgot to override new"); } 1; __END__ =head1 NAME Test::Unit::Assertion - The abstract base class for assertions =head1 NAME Any assertion class that expects to plug into Test::Unit::Assert needs to implement this interface. =head2 Required methods =over 4 =item new Creates a new assertion object. Takes whatever arguments you desire. Isn't strictly necessary for the framework to work with this class but is generally considered a good idea. =item do_assertion This is the important one. If Test::Unit::Assert::assert is called with an object as its first argument then it does: $_[0]->do_assertion(@_[1 .. $#_]) || $self->fail("Assertion failed"); This means that C should return true if the assertion succeeds and false if it doesn't. Or, you can fail by throwing a Test::Unit::Failure object, which will get caught further up the stack and used to produce a sensible error report. Generally it's good practice for do_assertion to die with a meaningful error on assertion failure rather than just returning false. =back =head1 AUTHOR Copyright (c) 2001 Piers Cawley Epdcawley@iterative-software.comE. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO =over 4 =item * L =item * L =item * L =back Test-Unit-0.28/lib/Test/Unit/PaxHeader/Assert.pm000644 000765 000024 00000000210 15113572067 021556 xustar00rjbsstaff000000 000000 30 mtime=1764684855.638086193 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/lib/Test/Unit/Assert.pm000644 000765 000024 00000051606 15113572067 017624 0ustar00rjbsstaff000000 000000 package Test::Unit::Assert; use strict; use Test::Unit::Debug qw(debug); use Test::Unit::Failure; use Test::Unit::Error; use Test::Unit::Exception; use Test::Unit::Assertion::CodeRef; use Error qw/:try/; use Carp; sub assert { my $self = shift; my $assertion = $self->normalize_assertion(shift); $self->do_assertion($assertion, (caller($Error::Depth))[0 .. 2], @_); } sub normalize_assertion { my $self = shift; my $assertion = shift; if (!ref($assertion) || ref($assertion) =~ 'ARRAY') { debug((defined $assertion ? $assertion : '_undef_') . " normalized as boolean\n"); require Test::Unit::Assertion::Boolean; return Test::Unit::Assertion::Boolean->new($assertion); } # If we're this far, we must have a reference. if (eval {$assertion->isa('Regexp')}) { debug("$assertion normalized as Regexp\n"); require Test::Unit::Assertion::Regexp; return Test::Unit::Assertion::Regexp->new($assertion); } if (ref($assertion) eq 'CODE') { debug("$assertion normalized as coderef\n"); require Test::Unit::Assertion::CodeRef; return Test::Unit::Assertion::CodeRef->new($assertion); } # if (ref($assertion) eq 'SCALAR') { # debug("$assertion normalized as scalar ref\n"); # require Test::Unit::Assertion::Scalar; # return Test::Unit::Assertion::Scalar->new($assertion); # } if (ref($assertion) !~ /^(GLOB|LVALUE|REF|SCALAR)$/) { debug("$assertion already an object\n"); require Test::Unit::Assertion::Boolean; return $assertion->can('do_assertion') ? $assertion : Test::Unit::Assertion::Boolean->new($assertion); } else { die "Don't know how to normalize $assertion (ref ", ref($assertion), ")\n"; } } sub assert_raises { my $self = shift; require Test::Unit::Assertion::Exception; my $assertion = Test::Unit::Assertion::Exception->new(shift); my ($asserter, $file, $line) = caller($Error::Depth); my $exception = $self->do_assertion($assertion, (caller($Error::Depth))[0 .. 2], @_); } sub do_assertion { my $self = shift; my $assertion = shift; my $asserter = shift; my $file = shift; my $line = shift; debug("Asserting [$assertion] from $asserter in $file line $line\n"); my @args = @_; try { $assertion->do_assertion(@args) } catch Test::Unit::Exception with { my $e = shift; debug(" Caught $e, rethrowing from $asserter, $file line $line\n"); $e->throw_new(-package => $asserter, -file => $file, -line => $line, -object => $self); } } sub multi_assert { my $self = shift; my ($assertion, @argsets) = @_; my ($asserter, $file, $line) = caller($Error::Depth); foreach my $argset (@argsets) { try { $self->assert($assertion, @$argset); } catch Test::Unit::Exception with { my $e = shift; debug(" Caught $e, rethrowing from $asserter, $file line $line\n"); $e->throw_new(-package => $asserter, -file => $file, -line => $line, -object => $self); } } } sub is_numeric { my $str = shift; local $^W; return defined $str && ! ($str == 0 && $str !~ /^\s*[+-]?0(e0)?\s*$/i); } # First argument determines the comparison type. sub assert_equals { my $self = shift; my($asserter, $file, $line) = caller($Error::Depth); my @args = @_; try { if (! defined($args[0]) and ! defined($args[1])) { # pass } elsif (defined($args[0]) xor defined($args[1])) { $self->fail('one arg was not defined'); } elsif (is_numeric($args[0])) { $self->assert_num_equals(@args); } elsif (eval {ref($args[0]) && $args[0]->isa('UNIVERSAL')}) { require overload; if (overload::Method($args[0], '==')) { $self->assert_num_equals(@args); } else { $self->assert_str_equals(@args); } } else { $self->assert_str_equals(@args); } } catch Test::Unit::Exception with { my $e = shift; $e->throw_new(-package => $asserter, -file => $file, -line => $line, -object => $self); } } sub ok { # To make porting from Test easier my $self = shift; my @args = @_; local $Error::Depth = $Error::Depth + 1; if (@args == 1) { $self->assert($args[0]); # boolean assertion } elsif (@args >= 2 && @args <= 3) { if (ref($args[0]) eq 'CODE') { my $code = shift @args; my $expected = shift @args; $self->assert_equals($expected, $code->(), @args); } elsif (eval {$args[1]->isa('Regexp')}) { my $got = shift @args; my $re = shift @args; $self->assert($re, $got, @args); } else { my $got = shift @args; my $expected = shift @args; $self->assert_equals($expected, $got, @args); } } else { $self->error('ok() called with wrong number of args'); } } sub assert_not_equals { my $self = shift; my($asserter,$file,$line) = caller($Error::Depth); my @args = @_; try { if (! defined($args[0]) && ! defined($args[1])) { my $first = shift @args; my $second = shift @args; $self->fail(@args ? join('', @args) : 'both args were undefined'); } elsif (defined($args[0]) xor defined($args[1])) { # succeed } elsif (is_numeric($args[0])) { $self->assert_num_not_equals(@args); } elsif (eval {ref($args[0]) && $args[0]->isa('UNIVERSAL')}) { require overload; if (overload::Method($args[0], '==')) { $self->assert_num_not_equals(@args); } else { $self->assert_str_not_equals(@args); } } else { $self->assert_str_not_equals(@args); } } catch Test::Unit::Exception with { my $e = shift; $e->throw_new(-package => $asserter, -file => $file, -line => $line, -object => $self,); }; } # Shamelessly pinched from Test::More and adapted to Test::Unit. our %Seen_Refs = (); our @Data_Stack; my $DNE = bless [], 'Does::Not::Exist'; sub assert_deep_equals { my $self = shift; my $this = shift; my $that = shift; local $Error::Depth = $Error::Depth + 1; if (! ref $this || ! ref $that) { Test::Unit::Failure->throw( -text => @_ ? join('', @_) : 'Both arguments were not references' ); } local @Data_Stack = (); local %Seen_Refs = (); if (! $self->_deep_check($this, $that)) { Test::Unit::Failure->throw( -text => @_ ? join('', @_) : $self->_format_stack(@Data_Stack) ); } } sub _deep_check { my $self = shift; my ($e1, $e2) = @_; if ( ! defined $e1 || ! defined $e2 ) { return 1 if !defined $e1 && !defined $e2; push @Data_Stack, { vals => [$e1, $e2] }; return 0; } return 0 if ( (defined $e1 && $e1 eq $DNE) || (defined $e2 && $e2 eq $DNE )); return 1 if $e1 eq $e2; if ( ref $e1 && ref $e2 ) { my $e2_ref = "$e2"; return 1 if defined $Seen_Refs{$e1} && $Seen_Refs{$e1} eq $e2_ref; $Seen_Refs{$e1} = $e2_ref; } if (UNIVERSAL::isa($e1, 'ARRAY') and UNIVERSAL::isa($e2, 'ARRAY')) { return $self->_eq_array($e1, $e2); } elsif (UNIVERSAL::isa($e1, 'HASH') and UNIVERSAL::isa($e2, 'HASH')) { return $self->_eq_hash($e1, $e2); } elsif (UNIVERSAL::isa($e1, 'REF') and UNIVERSAL::isa($e2, 'REF')) { push @Data_Stack, { type => 'REF', vals => [$e1, $e2] }; my $ok = $self->_deep_check($$e1, $$e2); pop @Data_Stack if $ok; return $ok; } elsif (UNIVERSAL::isa($e1, 'SCALAR') and UNIVERSAL::isa($e2, 'SCALAR')) { push @Data_Stack, { type => 'REF', vals => [$e1, $e2] }; return $self->_deep_check($$e1, $$e2); } else { push @Data_Stack, { vals => [$e1, $e2] }; return 0; } } sub _eq_array { my $self = shift; my($a1, $a2) = @_; return 1 if $a1 eq $a2; my $ok = 1; my $max = $#$a1 > $#$a2 ? $#$a1 : $#$a2; for (0..$max) { my $e1 = $_ > $#$a1 ? $DNE : $a1->[$_]; my $e2 = $_ > $#$a2 ? $DNE : $a2->[$_]; push @Data_Stack, { type => 'ARRAY', idx => $_, vals => [$e1, $e2] }; $ok = $self->_deep_check($e1,$e2); pop @Data_Stack if $ok; last unless $ok; } return $ok; } sub _eq_hash { my $self = shift; my($a1, $a2) = @_; return 1 if $a1 eq $a2; my $ok = 1; my $bigger = keys %$a1 > keys %$a2 ? $a1 : $a2; foreach my $k (sort keys %$bigger) { my $e1 = exists $a1->{$k} ? $a1->{$k} : $DNE; my $e2 = exists $a2->{$k} ? $a2->{$k} : $DNE; push @Data_Stack, { type => 'HASH', idx => $k, vals => [$e1, $e2] }; $ok = $self->_deep_check($e1, $e2); pop @Data_Stack if $ok; last unless $ok; } return $ok; } sub _format_stack { my $self = shift; my @Stack = @_; my $var = '$FOO'; my $did_arrow = 0; foreach my $entry (@Stack) { my $type = $entry->{type} || ''; my $idx = $entry->{'idx'}; if( $type eq 'HASH' ) { $var .= "->" unless $did_arrow++; $var .= "{$idx}"; } elsif( $type eq 'ARRAY' ) { $var .= "->" unless $did_arrow++; $var .= "[$idx]"; } elsif( $type eq 'REF' ) { $var = "\${$var}"; } } my @vals = @{$Stack[-1]{vals}}[0,1]; my @vars = (); ($vars[0] = $var) =~ s/\$FOO/ \$a/; ($vars[1] = $var) =~ s/\$FOO/ \$b/; my $out = "Structures begin differing at:\n"; foreach my $idx (0..$#vals) { my $val = $vals[$idx]; $vals[$idx] = !defined $val ? 'undef' : $val eq $DNE ? "Does not exist" : "'$val'"; } $out .= "$vars[0] = $vals[0]\n"; $out .= "$vars[1] = $vals[1]\n"; return $out; } { my %assert_subs = ( str_equals => sub { my $str1 = shift; my $str2 = shift; defined $str1 or Test::Unit::Failure->throw( -text => @_ ? join('',@_) : "expected value was undef; should be using assert_null?" ); defined $str2 or Test::Unit::Failure->throw( -text => @_ ? join('',@_) : "expected '$str1', got undef" ); $str1 eq $str2 or Test::Unit::Failure->throw( -text => @_ ? join('',@_) : "expected '$str1', got '$str2'" ); }, str_not_equals => sub { my $str1 = shift; my $str2 = shift; defined $str1 or Test::Unit::Failure->throw( -text => @_ ? join('',@_) : "expected value was undef; should be using assert_not_null?" ); defined $str2 or Test::Unit::Failure->throw( -text => @_ ? join('',@_) : "expected a string ne '$str1', got undef" ); $str1 ne $str2 or Test::Unit::Failure->throw( -text => @_ ? join('',@_) : "'$str1' and '$str2' should differ" ); }, num_equals => sub { my $num1 = shift; my $num2 = shift; defined $num1 or Test::Unit::Failure->throw( -text => @_ ? join('',@_) : "expected value was undef; should be using assert_null?" ); defined $num2 or Test::Unit::Failure->throw( -text => @_ ? join('',@_) : "expected '$num1', got undef" ); # silence `Argument "" isn't numeric in numeric eq (==)' warnings local $^W; $num1 == $num2 or Test::Unit::Failure->throw( -text => @_ ? join('', @_) : "expected $num1, got $num2" ); }, num_not_equals => sub { my $num1 = shift; my $num2 = shift; defined $num1 or Test::Unit::Failure->throw( -text => @_ ? join('',@_) : "expected value was undef; should be using assert_not_null?" ); defined $num2 or Test::Unit::Failure->throw( -text => @_ ? join('',@_) : "expected a number != '$num1', got undef" ); # silence `Argument "" isn't numeric in numeric ne (!=)' warnings local $^W; $num1 != $num2 or Test::Unit::Failure->throw( -text => @_ ? join('', @_) : "$num1 and $num2 should differ" ); }, matches => sub { my $regexp = shift; eval { $regexp->isa('Regexp') } or Test::Unit::Error->throw( -text => "arg 1 to assert_matches() must be a regexp" ); my $string = shift; $string =~ $regexp or Test::Unit::Failure->throw (-text => @_ ? join('', @_) : "$string didn't match /$regexp/"); }, does_not_match => sub { my $regexp = shift; eval { $regexp->isa('Regexp') } or Test::Unit::Error->throw( -text => "arg 1 to assert_does_not_match() must be a regexp" ); my $string = shift; $string !~ $regexp or Test::Unit::Failure->throw (-text => @_ ? join('', @_) : "$string matched /$regexp/"); }, null => sub { my $arg = shift; !defined($arg) or Test::Unit::Failure->throw (-text => @_ ? join('',@_) : "$arg is defined"); }, not_null => sub { my $arg = shift; defined($arg) or Test::Unit::Failure->throw (-text => @_ ? join('', @_) : " unexpected"); }, ); foreach my $type (keys %assert_subs) { my $assertion = Test::Unit::Assertion::CodeRef->new($assert_subs{$type}); no strict 'refs'; *{"Test::Unit::Assert::assert_$type"} = sub { local $Error::Depth = $Error::Depth + 3; my $self = shift; $assertion->do_assertion(@_); }; } } sub fail { my $self = shift; debug(ref($self) . "::fail() called\n"); my($asserter,$file,$line) = caller($Error::Depth); my $message = join '', @_; Test::Unit::Failure->throw(-text => $message, -object => $self, -file => $file, -line => $line); } sub error { my $self = shift; debug(ref($self) . "::error() called\n"); my($asserter,$file,$line) = caller($Error::Depth); my $message = join '', @_; Test::Unit::Error->throw(-text => $message, -object => $self, -file => $file, -line => $line); } sub quell_backtrace { my $self = shift; carp "quell_backtrace deprecated"; } sub get_backtrace_on_fail { my $self = shift; carp "get_backtrace_on_fail deprecated"; } 1; __END__ =head1 NAME Test::Unit::Assert - unit testing framework assertion class =head1 SYNOPSIS # this class is not intended to be used directly, # normally you get the functionality by subclassing from # Test::Unit::TestCase use Test::Unit::TestCase; # more code here ... $self->assert($your_condition_here, $your_optional_message_here); # or, for regular expression comparisons: $self->assert(qr/some_pattern/, $result); # or, for functional style coderef tests: $self->assert(sub { $_[0] == $_[1] or $self->fail("Expected $_[0], got $_[1]"); }, 1, 2); # or, for old style regular expression comparisons # (strongly deprecated; see warning below) $self->assert(scalar("foo" =~ /bar/), $your_optional_message_here); # Or, if you don't mind us guessing $self->assert_equals('expected', $actual [, $optional_message]); $self->assert_equals(1,$actual); $self->assert_not_equals('not expected', $actual [, $optional_message]); $self->assert_not_equals(0,1); # Or, if you want to force the comparator $self->assert_num_equals(1,1); $self->assert_num_not_equals(1,0); $self->assert_str_equals('string','string'); $self->assert_str_not_equals('stringA', 'stringB'); # assert defined/undefined status $self->assert_null(undef); $self->assert_not_null(''); =head1 DESCRIPTION This class contains the various standard assertions used within the framework. With the exception of the C, all the assertion methods take an optional message after the mandatory fields. The message can either be a single string, or a list, which will get concatenated. Although you can specify a message, it is hoped that the default error messages generated when an assertion fails will be good enough for most cases. =head2 Methods =over 4 =item assert_equals(EXPECTED, ACTUAL [, MESSAGE]) =item assert_not_equals(NOTEXPECTED, ACTUAL [, MESSAGE]) The catch all assertions of (in)equality. We make a guess about whether to test for numeric or string (in)equality based on the first argument. If it looks like a number then we do a numeric test, if it looks like a string, we do a string test. If the first argument is an object, we check to see if the C<'=='> operator has been overloaded and use that if it has, otherwise we do the string test. =item assert_num_equals =item assert_num_not_equals Force numeric comparison with these two. =item assert_str_equals =item assert_str_not_equals Force string comparison =item assert_matches(qr/PATTERN/, STRING [, MESSAGE]) =item assert_does_not_match(qr/PATTERN/, STRING [, MESSAGE]) Assert that STRING does or does not match the PATTERN regex. =item assert_deep_equals(A, B [, MESSAGE ]) Assert that reference A is a deep copy of reference B. The references can be complex, deep structures. If they are different, the default message will display the place where they start differing. B This is NOT well-tested on circular references. Nor am I quite sure what will happen with filehandles. =item assert_null(ARG [, MESSAGE]) =item assert_not_null(ARG [, MESSAGE]) Assert that ARG is defined or not defined. =item assert(BOOLEAN [, MESSAGE]) Checks if the BOOLEAN expression returns a true value that is neither a CODE ref nor a REGEXP. Note that MESSAGE is almost non optional in this case, otherwise all the assertion has to go on is the truth or otherwise of the boolean. If you want to use the "old" style for testing regular expression matching, please be aware of this: the arguments to assert() are evaluated in list context, e.g. making a failing regex "pull" the message into the place of the first argument. Since this is usually just plain wrong, please use scalar() to force the regex comparison to yield a useful boolean value. =item assert(qr/PATTERN/, ACTUAL [, MESSAGE]) Matches ACTUAL against the PATTERN regex. If you omit MESSAGE, you should get a sensible error message. =item assert(CODEREF, @ARGS) Calls CODEREF->(@ARGS). Assertion fails if this returns false (or throws Test::Unit::Failure) =item assert_raises(EXCEPTION_CLASS, CODEREF [, MESSAGE]) Calls CODEREF->(). Assertion fails unless an exception of class EXCEPTION_CLASS is raised. =item multi_assert(ASSERTION, @ARGSETS) Calls $self->assert(ASSERTION, @$ARGSET) for each $ARGSET in @ARGSETS. =item ok(@ARGS) Simulates the behaviour of the L module. B =back =head1 AUTHOR Copyright (c) 2000-2002, 2005 the PerlUnit Development Team (see L or the F file included in this distribution). All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO =over 4 =item * L =item * L =item * L =item * L =item * L =item * L =item * The framework self-testing suite (L) =back =cut Test-Unit-0.28/lib/Test/Unit/PaxHeader/Test.pm000644 000765 000024 00000000152 10273475545 021246 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/lib/Test/Unit/Test.pm000644 000765 000024 00000006135 10273475545 017304 0ustar00rjbsstaff000000 000000 package Test::Unit::Test; use strict; use Carp; use Test::Unit::Debug qw(debug); use base qw(Test::Unit::Assert); sub count_test_cases { my $self = shift; my $class = ref($self); croak "call to abstract method ${class}::count_test_cases"; } sub run { my $self = shift; my $class = ref($self); croak "call to abstract method ${class}::run"; } sub name { my $self = shift; my $class = ref($self); croak "call to abstract method ${class}::name"; } sub to_string { my $self = shift; return $self->name(); } sub filter_method { my $self = shift; my ($token) = @_; my $filtered = $self->filter->{$token}; return unless $filtered; if (ref $filtered eq 'ARRAY') { return grep $self->name eq $_, @$filtered; } elsif (ref $filtered eq 'CODE') { return $filtered->($self->name); } else { die "Didn't understand filtering definition for token $token in ", ref($self), "\n"; } } my %filter = (); sub filter { \%filter } # use Attribute::Handlers; # sub Filter : ATTR(CODE) { # my ($pkg, $symbol, $referent, $attr, $data, $phase) = @_; # print "attr $attr (data $data) on $pkg\::*{$symbol}{NAME}\n"; # # return (); # } sub _find_sym { # pinched from Attribute::Handlers my ($pkg, $ref) = @_; my $type = ref($ref); no strict 'refs'; warn "type $type\n"; while (my ($name, $sym) = each %{$pkg."::"} ) { use Data::Dumper; # warn Dumper(*$sym); warn "name $name sym $sym (" . (*{$sym}{$type} || '?') . ") matches?\n"; return \$sym if *{$sym}{$type} && *{$sym}{$type} == $ref; } } sub MODIFY_CODE_ATTRIBUTES { my ($pkg, $subref, @attrs) = @_; my @bad = (); foreach my $attr (@attrs) { if ($attr =~ /^Filter\((.*)\)$/) { my @tokens = split /\s+|\s*,\s*/, $1; my $sym = _find_sym($pkg, $subref); if ($sym) { push @{ $filter{$_} }, *{$sym}{NAME} foreach @tokens; } else { warn "Couldn't find symbol for $subref in $pkg\n" unless $sym; push @bad, $attr; } } else { push @bad, $attr; } } return @bad; } 1; __END__ =head1 NAME Test::Unit::Test - unit testing framework abstract base class =head1 SYNOPSIS This class is not intended to be used directly =head1 DESCRIPTION This class is used by the framework to define the interface of a test. It is an abstract base class implemented by Test::Unit::TestCase and Test::Unit::TestSuite. Due to the nature of the Perl OO implementation, this class is not really needed, but rather serves as documentation of the interface. =head1 AUTHOR Copyright (c) 2000-2002, 2005 the PerlUnit Development Team (see L or the F file included in this distribution). All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO =over 4 =item * L =item * L =item * L =back =cut Test-Unit-0.28/lib/Test/Unit/PaxHeader/Warning.pm000644 000765 000024 00000000152 10273475542 021731 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/lib/Test/Unit/Warning.pm000644 000765 000024 00000001417 10273475542 017765 0ustar00rjbsstaff000000 000000 package Test::Unit::Warning; use strict; use base 'Test::Unit::TestCase'; =head1 NAME Test::Unit::Warning - helper TestCase for adding warnings to a suite =head1 DESCRIPTION Used by L and others to provide messages that come up when the suite runs. =cut sub run_test { my $self = shift; $self->fail($self->{_message}); } sub new { my $class = shift; my $self = $class->SUPER::new('warning'); $self->{_message} = shift; return $self; } 1; =head1 AUTHOR Copyright (c) 2000-2002, 2005 the PerlUnit Development Team (see L or the F file included in this distribution). All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut Test-Unit-0.28/lib/Test/Unit/PaxHeader/Assertion000755 000765 000024 00000000210 15113573111 021643 xustar00rjbsstaff000000 000000 30 mtime=1764685385.270699757 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/lib/Test/Unit/Assertion/000755 000765 000024 00000000000 15113573111 017753 5ustar00rjbsstaff000000 000000 Test-Unit-0.28/lib/Test/Unit/PaxHeader/Failure.pm000644 000765 000024 00000000152 10273475545 021716 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/lib/Test/Unit/Failure.pm000644 000765 000024 00000001544 10273475545 017753 0ustar00rjbsstaff000000 000000 package Test::Unit::Failure; use strict; use base qw(Test::Unit::Exception); 1; __END__ =head1 NAME Test::Unit::Failure - unit testing framework exception class =head1 SYNOPSIS This class is not intended to be used directly =head1 DESCRIPTION This class is used by the framework to communicate the result of assertions, which will throw an instance of this class in case of failures (that is, failed tests, not syntax errors and the like, these are classified as errors). =head1 AUTHOR Copyright (c) 2000-2002, 2005 the PerlUnit Development Team (see L or the F file included in this distribution). All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO =over 4 =item * L =item * L =back =cut Test-Unit-0.28/lib/Test/Unit/PaxHeader/Setup.pm000644 000765 000024 00000000152 07402737001 021413 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/lib/Test/Unit/Setup.pm000644 000765 000024 00000002463 07402737001 017451 0ustar00rjbsstaff000000 000000 package Test::Unit::Setup; use strict; use base qw(Test::Unit::Decorator); sub run { my $self = shift(); my($result) = @_; my $protectable = sub { $self->set_up(); $self->basic_run($result); $self->tear_down(); }; $result->run_protected($self, $protectable); } # Sets up the fixture. Override to set up additional fixture # state. sub set_up { print "Suite setup\n"; } # Tears down the fixture. Override to tear down the additional # fixture state. sub tear_down { print "Suite teardown\n"; } 1; __END__ =head1 NAME Test::Unit::Setup - unit testing framework helper class =head1 SYNOPSIS # A Decorator to set up and tear down additional fixture state. # Subclass Setup and insert it into your tests when you want # to set up additional state once before the tests are run. =head1 DESCRIPTION A Decorator to set up and tear down additional fixture state. Subclass Setup and insert it into your tests when you want to set up additional state once before the tests are run. =head1 AUTHOR Copyright (c) 2001 Kevin Connor All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO L, L =cut Test-Unit-0.28/lib/Test/Unit/PaxHeader/Result.pm000644 000765 000024 00000000210 15113572150 021564 xustar00rjbsstaff000000 000000 30 mtime=1764684904.844132963 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/lib/Test/Unit/Result.pm000644 000765 000024 00000013112 15113572150 017620 0ustar00rjbsstaff000000 000000 package Test::Unit::Result; use strict; use Test::Unit::Debug qw(debug); use Test::Unit::Error; use Test::Unit::Failure; use Error qw/:try/; sub new { my $class = shift; bless { _Failures => [], _Errors => [], _Listeners => [], _Run_tests => 0, _Stop => 0, }, $class; } sub tell_listeners { my $self = shift; my $method = shift; foreach (@{$self->listeners}) { $_->$method(@_); } } sub add_error { my $self = shift; debug($self . "::add_error() called\n"); my ($test, $exception) = @_; $exception->{-object} = $test; push @{$self->errors()}, $exception; $self->tell_listeners(add_error => @_); } sub add_failure { my $self = shift; debug($self . "::add_failure() called\n"); my ($test, $exception) = @_; $exception->{-object} = $test; push @{$self->failures()}, $exception; $self->tell_listeners(add_failure => @_); } sub add_pass { my $self = shift; debug($self . "::add_pass() called\n"); my ($test) = @_; $self->tell_listeners(add_pass => @_); } sub add_listener { my $self = shift; debug($self . "::add_listener() called\n"); my ($listener) = @_; push @{$self->listeners()}, $listener; } sub listeners { my $self = shift; return $self->{_Listeners}; } sub end_test { my $self = shift; my ($test) = @_; $self->tell_listeners(end_test => $test); } sub error_count { my $self = shift; return scalar @{$self->{_Errors}}; } sub errors { my $self = shift; return $self->{_Errors}; } sub failure_count { my $self = shift; return scalar @{$self->{_Failures}}; } sub failures { my $self = shift; return $self->{_Failures}; } sub run { my $self = shift; my ($test) = @_; debug(sprintf "%s::run(%s) called\n", $self, $test->name()); $self->start_test($test); # This closure may look convoluted, but it allows Test::Unit::Setup # to work cleanly. $self->run_protected( $test, sub { $test->run_bare() ? $self->add_pass($test) : $self->add_failure($test); } ); $self->end_test($test); } sub run_protected { my $self = shift; my $test = shift; my $protectable = shift; debug("$self\::run_protected($test, $protectable) called\n"); try { &$protectable(); } catch Test::Unit::Failure with { $self->add_failure($test, shift); } catch Error with { # *Any* exception which isn't a failure or # Test::Unit::Exception should get rebuilt and added to the # result as a Test::Unit::Error, so that the stringify() # method can be called on it for nice reporting. my $error = shift; $error = Test::Unit::Error->make_new_from_error($error) unless $error->isa('Test::Unit::Exception'); $self->add_error($test, $error); }; } sub run_count { my $self = shift; return $self->{_Run_tests}; } sub run_count_inc { my $self = shift; ++$self->{_Run_tests}; return $self->{_Run_tests}; } sub should_stop { my $self = shift; return $self->{_Stop}; } sub start_test { my $self = shift; my ($test) = @_; $self->run_count_inc(); $self->tell_listeners(start_test => $test); } sub stop { my $self = shift; $self->{_Stop} = 1; } sub was_successful { my $self = shift; return ($self->failure_count() == 0) && ($self->error_count() == 0); } sub to_string { my $self = shift; my $class = ref($self); debug($class . "::to_string() called\n"); } 1; __END__ =head1 NAME Test::Unit::Result - unit testing framework helper class =head1 SYNOPSIS This class is not intended to be used directly =head1 DESCRIPTION This class is used by the framework to record the results of tests, which will throw an instance of a subclass of Test::Unit::Exception in case of errors or failures. To achieve this, this class gets called with a test case as argument. It will call this test case's run method back and catch any exceptions thrown. It could be argued that Test::Unit::Result is the heart of the PerlUnit framework, since TestCase classes vary, and you can use one of several Test::Unit::TestRunners, but we always gather the results in a Test::Unit::Result object. This is the quintessential call tree of the communication needed to record the results of a given test: $aTestCase->run() { # creates result $aTestResult->run($aTestCase) { # catches exception and records it $aTestCase->run_bare() { # runs test method inside eval $aTestCase->run_test() { # calls method $aTestCase->name() # and propagates exception # method will call Assert::assert() # to cause failure if test fails on # test assertion # it finds this because $aTestCase is-a Assert } } } } Note too that, in the presence of Test::Unit::TestSuites, this call tree can get a little more convoluted, but if you bear the above in mind it should be apparent what's going on. =head1 AUTHOR Copyright (c) 2000-2002, 2005 the PerlUnit Development Team (see L or the F file included in this distribution). All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO =over 4 =item * L =item * L =item * L =back =cut Test-Unit-0.28/lib/Test/Unit/PaxHeader/Debug.pm000644 000765 000024 00000000152 10273475547 021357 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/lib/Test/Unit/Debug.pm000644 000765 000024 00000003440 10273475547 017411 0ustar00rjbsstaff000000 000000 package Test::Unit::Debug; =head1 NAME Test::Unit::Debug - framework debugging control =head1 SYNOPSIS package MyRunner; use Test::Unit::Debug qw(debug_to_file debug_pkg); debug_to_file('foo.log'); debug_pkg('Test::Unit::TestCase'); =cut use strict; use base 'Exporter'; use vars qw(@EXPORT_OK); @EXPORT_OK = qw(debug debug_to_file debug_pkg no_debug_pkg debug_pkgs no_debug_pkgs debugged); my %DEBUG = (); my $out = \*STDERR; =head1 ROUTINES =head2 debug_to_file($file) Switch debugging to C<$file>. =cut sub debug_to_file { my ($file) = @_; open(DEBUG, ">$file") or die "Couldn't open $file for writing"; $out = \*DEBUG; } =head2 debug_to_stderr() Switch debugging to STDERR (this is the default). =cut sub debug_to_stderr { $out = \*STDERR; } sub debug { my ($package, $filename, $line) = caller(); print $out @_ if $DEBUG{$package}; } =head2 debug_pkg($pkg) Enable debugging in package C<$pkg>. =cut sub debug_pkg { $DEBUG{$_[0]} = 1; } =head2 debug_pkgs(@pkgs) Enable debugging in the packages C<@pkgs>. =cut sub debug_pkgs { $DEBUG{$_} = 1 foreach @_; } =head2 debug_pkg($pkg) Enable debugging in package C<$pkg>. =cut sub no_debug_pkg { $DEBUG{$_[0]} = 0; } =head2 debug_pkgs(@pkgs) Disable debugging in the packages C<@pkgs>. =cut sub no_debug_pkgs { $DEBUG{$_} = 0 foreach @_; } sub debugged { my ($package, $filename, $line) = caller(); return $DEBUG{$_[0] || $package}; } =head1 AUTHOR Copyright (c) 2000-2002, 2005 the PerlUnit Development Team (see L or the F file included in this distribution). All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO L =cut 1; Test-Unit-0.28/lib/Test/Unit/PaxHeader/Loader.pm000644 000765 000024 00000000152 10273475545 021535 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/lib/Test/Unit/Loader.pm000644 000765 000024 00000012532 10273475545 017571 0ustar00rjbsstaff000000 000000 package Test::Unit::Loader; use strict; use FileHandle; use Test::Unit::Debug qw(debug); use Test::Unit::TestSuite; use Test::Unit::TestCase; use Test::Unit::UnitHarness; use Test::Unit::Warning; # should really do something in here about a local @INC. sub obj_load { shift; load(@_) } # Compiles a target. Returns the package if successful. sub compile { my $target = shift; debug("Test::Unit::Loader::compile($target) called\n"); if ($target =~ /^\w+(::\w+)*$/) { compile_class($target); return $target; } elsif ($target =~ /\.pm$/) { compile_file($target); # In this case I need to figure out what the class was I just loaded! return get_package_name_from_file($target); } else { return undef; } } sub compile_class { my $classname = shift; debug(" Test::Unit::Loader::compile_class($classname) called\n"); # Check if the package exists already. { no strict 'refs'; if (my @keys = grep { ! /::$/ } keys %{"$classname\::"}) { debug(" package $classname already exists (@keys); not compiling.\n"); return; } } # No? Try 'require'ing it eval "require $classname"; die $@ if $@; debug(" $classname compiled OK as class name\n"); } sub compile_file { my $file = shift; debug(" Test::Unit::Loader::compile_file($file) called\n"); eval qq{require "$file"}; die $@ if $@; debug(" $file compiled OK as filename\n"); } sub load { my $target = shift; debug("Test::Unit::Loader::load($target) called\n"); my $suite = load_test($target) || load_test_harness_test($target) || load_test_dir($target); return $suite if $suite; die "Couldn't load $target in any of the supported ways"; } sub load_test { my $target = shift; debug("Test::Unit::Loader::load_test($target) called\n"); my $package = compile($target); return unless $package; debug(" compile returned $package\n"); my $suite = load_test_suite($package) || load_test_case($package); die "`$target' was not a valid Test::Unit::Test\n" unless $suite; return $suite; } sub load_test_suite { my $package = shift; debug(" Test::Unit::Loader::load_test_suite($package) called\n"); if ($package->can("suite")) { debug(" $package has a suite() method\n"); return $package->suite(); } } sub load_test_case { my $package = shift; debug(" Test::Unit::Loader::load_test_case($package) called\n"); if ($package->isa("Test::Unit::TestCase")) { debug(" $package isa Test::Unit::TestCase\n"); return Test::Unit::TestSuite->new($package); } } sub extract_testcases { my $classname = shift; my @testcases = (); foreach my $method ($classname->list_tests()) { if ( my $a_class_instance = $classname->new($method) ) { push @testcases, $a_class_instance; } else { push @testcases, Test::Unit::Warning->new( "extract_testcases: Couldn't create a $classname object" ); } } push @testcases, Test::Unit::Warning->new("No tests found in $classname") unless @testcases; return @testcases; } sub load_test_harness_test { my $target = shift; foreach my $file ("$target", "$target.t", "t/$target", "t/$target.t" ) { if (-r $file) { # are the next 3 lines really necessary? open(FH, $file) or next; my $first = ; close(FH) or next; return Test::Unit::UnitHarness->new($file); } } return undef; } sub load_test_dir { my $test_dir = shift; if (-d $test_dir) { die "This is a test directory. I haven't implemented that.\n"; return Test::Unit::UnitHarness::new_dir($test_dir); } } # The next bit of code is a helper function which attempts # to identify the class we are trying to use from a '.pm' # file. If we've reached this point, we managed to 'require' # the file already, but we dont know the file the package was # loaded from. Somehow I feel this information is in perl # somwhere but if it is I dont know where... sub get_package_name_from_file { my $filename = shift; my $real_path = $INC{$filename}; die "Can't find $filename in @INC: $!" unless $real_path && open(FH, $real_path); while () { if (/^\s*package\s+([\w:]+)/) { close(FH); return $1; } } die "Can't find a package in $filename"; } 1; __END__ =head1 NAME Test::Unit::Loader - unit testing framework helper class =head1 SYNOPSIS This class is not intended to be used directly. =head1 DESCRIPTION This class is used by the framework to load test classes into the runtime environment. It handles test case and test suite classes (referenced either via their package names or the files containing them), Test::Harness style test files, and directory names. =head1 AUTHOR Copyright (c) 2000-2002, 2005 the PerlUnit Development Team (see L or the F file included in this distribution). All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO =over 4 =item * L =item * L =item * L =back =cut Test-Unit-0.28/lib/Test/Unit/PaxHeader/TestSuite.pm000644 000765 000024 00000000207 15113572002 022241 xustar00rjbsstaff000000 000000 29 mtime=1764684802.45605818 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/lib/Test/Unit/TestSuite.pm000644 000765 000024 00000020431 15113572002 020271 0ustar00rjbsstaff000000 000000 package Test::Unit::TestSuite; use strict; =head1 NAME Test::Unit::TestSuite - unit testing framework base class =cut use base 'Test::Unit::Test'; use Carp; use Test::Unit::Debug qw(debug); use Test::Unit::TestCase; use Test::Unit::Loader; use Test::Unit::Warning; =head1 SYNOPSIS package MySuite; use base qw(Test::Unit::TestSuite); sub name { 'My very own test suite' } sub include_tests { qw(MySuite1 MySuite2 MyTestCase1 ...) } This is the easiest way of building suites; there are many more. Read on ... =head1 DESCRIPTION This class provides the functionality for building test suites in several different ways. Any module can be a test suite runnable by the framework if it provides a C method which returns a C object, e.g. use Test::Unit::TestSuite; # more code here ... sub suite { my $class = shift; # Create an empty suite. my $suite = Test::Unit::TestSuite->empty_new("A Test Suite"); # Add some tests to it via $suite->add_test() here return $suite; } This is useful if you want your test suite to be contained in the module it tests, for example. Alternatively, you can have "standalone" test suites, which inherit directly from C, e.g.: package MySuite; use base qw(Test::Unit::TestSuite); sub new { my $class = shift; my $self = $class->SUPER::empty_new(); # Build your suite here return $self; } sub name { 'My very own test suite' } or if your C is going to do nothing more interesting than add tests from other suites and testcases via C, you can use the C method as shorthand: package MySuite; use base qw(Test::Unit::TestSuite); sub name { 'My very own test suite' } sub include_tests { qw(MySuite1 MySuite2 MyTestCase1 ...) } This is the easiest way of building suites. =head1 CONSTRUCTORS =head2 empty_new ([NAME]) my $suite = Test::Unit::TestSuite->empty_new('my suite name'); Creates a fresh suite with no tests. =cut sub empty_new { my $this = shift; my $classname = ref $this || $this; my $name = shift || ''; my $self = { _Tests => [], _Name => $name, }; bless $self, $classname; debug(ref($self), "::empty_new($name) called\n"); return $self; } =head2 new ([ CLASSNAME | TEST ]) If a test suite is provided as the argument, it merely returns that suite. If a test case is provided, it extracts all test case methods from the test case (see L) into a new test suite. If the class this method is being run in has an C method which returns an array of class names, it will also automatically add the tests from those classes into the newly constructed suite object. =cut sub new { my $class = shift; my $classname = shift || ''; # Avoid a warning debug("$class\::new($classname) called\n"); my $self = $class->empty_new(); if ($classname) { Test::Unit::Loader::compile_class($classname); if (eval { $classname->isa('Test::Unit::TestCase') }) { $self->{_Name} = "suite extracted from $classname"; my @testcases = Test::Unit::Loader::extract_testcases($classname); foreach my $testcase (@testcases) { $self->add_test($testcase); } } elsif (eval { $classname->can('suite') }) { return $classname->suite(); } else { my $error = "Class $classname was not a test case or test suite.\n"; #$self->add_warning($error); die $error; } } if ($self->can('include_tests')) { foreach my $test ($self->include_tests()) { $self->add_test($test); } } return $self; } =head1 METHODS =cut sub suite { my $class = shift; croak "suite() is not an instance method" if ref $class; $class->new(@_); } =head2 name() Returns the suite's human-readable name. =cut sub name { my $self = shift; croak "Override name() in subclass to set name\n" if @_; return $self->{_Name}; } =head2 names() Returns an arrayref of the names of all tests in the suite. =cut sub names { my $self = shift; my @test_list = @{$self->tests}; return [ map {$_->name} @test_list ] if @test_list; } =head2 list (SHOW_TESTCASES) Produces a human-readable indented lists of the suite and the subsuites it contains. If the first parameter is true, also lists any testcases contained in the suite and its subsuites. =cut sub list { my $self = shift; my $show_testcases = shift; my $first = ($self->name() || 'anonymous Test::Unit::TestSuite'); $first .= " - " . ref($self) unless ref($self) eq __PACKAGE__; $first .= "\n"; my @lines = ( $first ); foreach my $test (@{ $self->tests() }) { push @lines, map " $_", @{ $test->list($show_testcases) }; } return \@lines; } =head2 add_test (TEST_CLASSNAME | TEST_OBJECT) You can add a test object to a suite with this method, by passing either its classname, or the object itself as the argument. Of course, there are many ways of getting the object too ... # Get and add an existing suite. $suite->add_test('MySuite1'); # This is exactly equivalent: $suite->add_test(Test::Unit::TestSuite->new('MySuite1')); # So is this, provided MySuite1 inherits from Test::Unit::TestSuite. use MySuite1; $suite->add_test(MySuite1->new()); # Extract yet another suite by way of suite() method and add it to # $suite. use MySuite2; $suite->add_test(MySuite2->suite()); # Extract test case methods from MyModule::TestCase into a # new suite and add it to $suite. $suite->add_test(Test::Unit::TestSuite->new('MyModule::TestCase')); =cut sub add_test { my $self = shift; my ($test) = @_; debug('+ ', ref($self), "::add_test($test) called\n"); $test = Test::Unit::Loader::load_test($test) unless ref $test; croak "`$test' could not be interpreted as a Test::Unit::Test object" unless eval { $test->isa('Test::Unit::Test') }; push @{$self->tests}, $test; } sub count_test_cases { my $self = shift; my $count; $count += $_->count_test_cases for @{$self->tests}; return $count; } sub run { my $self = shift; my ($result, $runner) = @_; debug("$self\::run($result, ", $runner || 'undef', ") called\n"); $result ||= create_result(); $result->tell_listeners(start_suite => $self); $self->add_warning("No tests found in " . $self->name()) unless @{ $self->tests() }; for my $t (@{$self->tests()}) { if ($runner && $self->filter_test($runner, $t)) { debug(sprintf "+ skipping '%s'\n", $t->name()); next; } debug(sprintf "+ didn't skip '%s'\n", $t->name()); last if $result->should_stop(); $t->run($result, $runner); } $result->tell_listeners(end_suite => $self); return $result; } sub filter_test { my $self = shift; my ($runner, $test) = @_; debug(sprintf "checking whether to filter '%s'\n", $test->name); my @filter_tokens = $runner->filter(); foreach my $token (@filter_tokens) { my $filtered = $test->filter_method($token); debug(" - by token $token? ", $filtered ? 'yes' : 'no', "\n"); return 1 if $filtered; } return 0; } sub test_at { my $self = shift; my ($index) = @_; return $self->tests()->[$index]; } sub test_count { my $self = shift; return scalar @{$self->tests()}; } sub tests { my $self = shift; return $self->{_Tests}; } sub to_string { my $self = shift; return $self->name(); } sub add_warning { my $self = shift; $self->add_test(Test::Unit::Warning->new(join '', @_)); } 1; __END__ =head1 AUTHOR Copyright (c) 2000-2002, 2005 the PerlUnit Development Team (see L or the F file included in this distribution). All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO =over 4 =item * L =item * L =item * For further examples, take a look at the framework self test collection (t::tlib::AllTests). =back =cut Test-Unit-0.28/lib/Test/Unit/PaxHeader/Listener.pm000644 000765 000024 00000000152 10273475545 022114 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/lib/Test/Unit/Listener.pm000644 000765 000024 00000004012 10273475545 020142 0ustar00rjbsstaff000000 000000 package Test::Unit::Listener; use Test::Unit::Loader; use Carp; use strict; sub new { my $class = shift; croak "call to abstract constructor ${class}::new"; } sub start_suite { my $self = shift; my $class = ref($self); my ($suite) = @_; croak "call to abstract method ${class}::start_suite"; } sub start_test { my $self = shift; my $class = ref($self); my ($test) = @_; croak "call to abstract method ${class}::start_test"; } sub add_error { my $self = shift; my $class = ref($self); my ($test, $exception) = @_; croak "call to abstract method ${class}::add_error"; } sub add_failure { my $self = shift; my $class = ref($self); my ($test, $exception) = @_; croak "call to abstract method ${class}::add_failure"; } sub end_test { my $self = shift; my $class = ref($self); my ($test) = @_; croak "call to abstract method ${class}::end_test"; } 1; __END__ =head1 NAME Test::Unit::Listener - unit testing framework abstract base class =head1 SYNOPSIS This class is not intended to be used directly =head1 DESCRIPTION This class is used by the framework to define the interface of a test listener. It is an abstract base class implemented by the test runners. Due to the nature of the Perl OO implementation, this class is not really needed, but rather serves as documentation of the interface. Each of the add_ methods gets two arguments: C and C. The test is a Test::Unit::Test and the exception is a Test::Unit::Exception. Typically you want to display Cname()> and keep the rest as details. =head1 AUTHOR Copyright (c) 2000-2002, 2005 the PerlUnit Development Team (see L or the F file included in this distribution). All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO =over 4 =item * L =item * L =item * L =back =cut Test-Unit-0.28/lib/Test/Unit/PaxHeader/TestRunner.pm000644 000765 000024 00000000207 15113572177 022436 xustar00rjbsstaff000000 000000 29 mtime=1764684927.48624203 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/lib/Test/Unit/TestRunner.pm000644 000765 000024 00000013201 15113572177 020463 0ustar00rjbsstaff000000 000000 package Test::Unit::TestRunner; use strict; use base qw(Test::Unit::Runner); use Test::Unit; # for copyright & version number use Test::Unit::TestSuite; use Test::Unit::Loader; use Test::Unit::Result; use Benchmark; sub new { my $class = shift; my ($filehandle) = @_; $filehandle = \*STDOUT unless $filehandle; select((select($filehandle), $| = 1)[0]); bless { _Print_stream => $filehandle }, $class; } sub print_stream { my $self = shift; return $self->{_Print_stream}; } sub _print { my $self = shift; my (@args) = @_; $self->print_stream->print(@args); } sub add_error { my $self = shift; my ($test, $exception) = @_; $self->_print("E"); } sub add_failure { my $self = shift; my ($test, $exception) = @_; $self->_print("F"); } sub add_pass { # in this runner passes are ignored. } sub do_run { my $self = shift; my ($suite, $wait) = @_; my $result = $self->create_test_result(); $result->add_listener($self); my $start_time = new Benchmark(); $suite->run($result, $self); my $end_time = new Benchmark(); $self->print_result($result, $start_time, $end_time); if ($wait) { print " to continue"; # go to STDIN any case ; } $self->_print("\nTest was not successful.\n") unless $result->was_successful; return $result->was_successful; } sub end_test { } sub main { my $self = shift; my $a_test_runner = Test::Unit::TestRunner->new(); $a_test_runner->start(@_); } sub print_result { my $self = shift; my ($result, $start_time, $end_time) = @_; my $run_time = timediff($end_time, $start_time); $self->_print("\n", "Time: ", timestr($run_time), "\n"); $self->print_header($result); $self->print_errors($result); $self->print_failures($result); } sub print_errors { my $self = shift; my ($result) = @_; return unless my $error_count = $result->error_count(); my $msg = "\nThere " . ($error_count == 1 ? "was 1 error" : "were $error_count errors") . ":\n"; $self->_print($msg); my $i = 0; for my $e (@{$result->errors()}) { chomp(my $e_to_str = $e); $i++; $self->_print("$i) $e_to_str\n"); $self->_print("\nAnnotations:\n", $e->object->annotations()) if $e->object->annotations(); } } sub print_failures { my $self = shift; my ($result) = @_; return unless my $failure_count = $result->failure_count; my $msg = "\nThere " . ($failure_count == 1 ? "was 1 failure" : "were $failure_count failures") . ":\n"; $self->_print($msg); my $i = 0; for my $f (@{$result->failures()}) { chomp(my $f_to_str = $f); $self->_print("\n") if $i++; $self->_print("$i) $f_to_str\n"); $self->_print("\nAnnotations:\n", $f->object->annotations()) if $f->object->annotations(); } } sub print_header { my $self = shift; my ($result) = @_; if ($result->was_successful()) { $self->_print("\n", "OK", " (", $result->run_count(), " tests)\n"); } else { $self->_print("\n", "!!!FAILURES!!!", "\n", "Test Results:\n", "Run: ", $result->run_count(), ", Failures: ", $result->failure_count(), ", Errors: ", $result->error_count(), "\n"); } } sub run { my $self = shift; my ($class) = @_; my $a_test_runner = Test::Unit::TestRunner->new(); $a_test_runner->do_run(Test::Unit::TestSuite->new($class), 0); } sub run_and_wait { my $self = shift; my ($test) = @_; my $a_test_runner = Test::Unit::TestRunner->new(); $a_test_runner->do_run(Test::Unit::TestSuite->new($test), 1); } sub start { my $self = shift; my (@args) = @_; my $test = ""; my $wait = 0; for (my $i = 0; $i < @args; $i++) { if ($args[$i] eq "-wait") { $wait = 1; } elsif ($args[$i] eq "-v") { print Test::Unit::COPYRIGHT_SHORT; } else { $test = $args[$i]; } } if ($test eq "") { die "Usage: TestRunner.pl [-wait] name, where name is the name of the Test class\n"; } my $suite = Test::Unit::Loader::load($test); $self->do_run($suite, $wait); } sub start_test { my $self = shift; my ($test) = @_; $self->_print("."); } 1; __END__ =head1 NAME Test::Unit::TestRunner - unit testing framework helper class =head1 SYNOPSIS use Test::Unit::TestRunner; my $testrunner = Test::Unit::TestRunner->new(); $testrunner->start($my_test_class); =head1 DESCRIPTION This class is the test runner for the command line style use of the testing framework. It is used by simple command line tools like the F script provided. The class needs one argument, which is the name of the class encapsulating the tests to be run. =head1 OPTIONS =over 4 =item -wait wait for user confirmation between tests =item -v version info =back =head1 AUTHOR Copyright (c) 2000-2002, 2005 the PerlUnit Development Team (see L or the F file included in this distribution). All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO =over 4 =item * L =item * L =item * L =item * L =item * L =item * For further examples, take a look at the framework self test collection (t::tlib::AllTests). =back =cut Test-Unit-0.28/lib/Test/Unit/Assertion/PaxHeader/Exception.pm000644 000765 000024 00000000152 07416643311 024225 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/lib/Test/Unit/Assertion/Exception.pm000644 000765 000024 00000003507 07416643311 022263 0ustar00rjbsstaff000000 000000 package Test::Unit::Assertion::Exception; use strict; use base qw/Test::Unit::Assertion/; use Carp; use Error qw/:try/; use Test::Unit::Debug qw(debug); my $deparser; sub new { my $class = shift; my $exception_class = shift; croak "$class\::new needs an exception class" unless $exception_class; bless \$exception_class => $class; } sub do_assertion { my $self = shift; my $coderef = shift; my $exception_class = $$self; my $exception; try { &$coderef(); } catch $exception_class with { $exception = shift; }; if (! $exception || ! $exception->isa($$self)) { $self->fail(@_ ? $_[0] : "No $exception_class was raised"); } return $exception; # so that it can be stored in the test for the # user to get at. } sub to_string { my $self = shift; return "$$self exception assertion"; } 1; __END__ =head1 NAME Test::Unit::Assertion::Exception - A assertion for raised exceptions =head1 SYNOPSIS require Test::Unit::Assertion::Exception; my $assert_raised = Test::Unit::Assertion::Exception->new('MyException'); # This should succeed $assert_eq->do_assertion(sub { MyException->throw() }); # This should fail $assert_eq->do_assertion(sub { }); =head1 DESCRIPTION Although the SYNOPSIS shows how you'd use Test::Unit::Assertion::Exception directly, it is more sensibly used indirectly via C, which instantiates a C. =head1 AUTHOR Copyright (c) 2001 Piers Cawley Epdcawley@iterative-software.comE. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO =over 4 =item * L =item * L =back Test-Unit-0.28/lib/Test/Unit/Assertion/PaxHeader/CodeRef.pm000644 000765 000024 00000000152 07416643311 023576 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/lib/Test/Unit/Assertion/CodeRef.pm000644 000765 000024 00000006161 07416643311 021633 0ustar00rjbsstaff000000 000000 package Test::Unit::Assertion::CodeRef; use strict; use base qw/Test::Unit::Assertion/; use Carp; use Test::Unit::Debug qw(debug); my $deparser; sub new { my $class = shift; my $code = shift; croak "$class\::new needs a CODEREF" unless ref($code) eq 'CODE'; bless \$code => $class; } sub do_assertion { my $self = shift; my $possible_object = $_[0]; debug("Called do_assertion(" . ($possible_object || 'undef') . ")\n"); if (ref($possible_object) and ref($possible_object) ne 'Regexp' and eval { $possible_object->isa('UNIVERSAL') }) { debug(" [$possible_object] isa [" . ref($possible_object) . "]\n"); $possible_object->$$self(@_[1..$#_]); } else { debug(" asserting [$self]" . (@_ ? " on args " . join(', ', map { $_ || '' } @_) : '') . "\n"); $$self->(@_); } } sub to_string { my $self = shift; if (eval "require B::Deparse") { $deparser ||= B::Deparse->new("-p"); return join '', "sub ", $deparser->coderef2text($$self); } else { return "sub { # If you had a working B::Deparse, you'd know what was in # this subroutine. }"; } } 1; __END__ =head1 NAME Test::Unit::Assertion::CodeRef - A delayed evaluation assertion using a Coderef =head1 SYNOPSIS require Test::Unit::Assertion::CodeRef; my $assert_eq = Test::Unit::Assertion::CodeRef->new(sub { $_[0] eq $_[1] or Test::Unit::Failure->throw(-text => "Expected '$_[0]', got '$_[1]'\n"); }); $assert_eq->do_assertion('foo', 'bar'); Although this is how you'd use Test::Unit::Assertion::CodeRef directly, it is more usually used indirectly via Test::Unit::Test::assert, which instantiates a Test::Unit::Assertion::CodeRef when passed a Coderef as its first argument. =head1 IMPLEMENTS Test::Unit::Assertion::CodeRef implements the Test::Unit::Assertion interface, which means it can be plugged into the Test::Unit::TestCase and friends' C method with no ill effects. =head1 DESCRIPTION This class is used by the framework to allow us to do assertions in a 'functional' manner. It is typically used generated automagically in code like: $self->assert(sub { $_[0] == $_[1] or $self->fail("Expected $_[0], got $_[1]"); }, 1, 2); (Note that if Damian Conway's Perl6 RFC for currying ever comes to pass then we'll be able to do this as: $self->assert(^1 == ^2 || $self->fail("Expected ^1, got ^2"), 1, 2) which will be nice...) If you have a working B::Deparse installed with your perl installation then, if an assertion fails, you'll see a listing of the decompiled coderef (which will be sadly devoid of comments, but should still be useful) =head1 AUTHOR Copyright (c) 2001 Piers Cawley Epdcawley@iterative-software.comE. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO =over 4 =item * L =item * L =back Test-Unit-0.28/lib/Test/Unit/Assertion/PaxHeader/Boolean.pm000644 000765 000024 00000000152 07445364540 023654 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/lib/Test/Unit/Assertion/Boolean.pm000644 000765 000024 00000003051 07445364540 021704 0ustar00rjbsstaff000000 000000 package Test::Unit::Assertion::Boolean; use strict; # adding this fixes the 'Can't locate object method "fail" via package # "Test::Unit::Assertion::Boolean"' problem under perl 5.005 - Christian use Test::Unit::Assertion; use Test::Unit::Failure; use base 'Test::Unit::Assertion'; use overload 'bool' => sub {$ {$_[0]}}; sub new { my $class = shift; my $bool = shift; my $self = \$bool; bless $self, $class; } sub do_assertion { my $self = shift; $$self or $self->fail( @_ ? join('', @_) : "Boolean assertion failed"); } sub to_string { my $self = shift; ($$self ? 'TRUE' : 'FALSE') . ' boolean assertion'; } 1; __END__ =head1 NAME Test::Unit::Assertion::Boolean - A boolean assertion =head1 SYNOPSIS Pay no attention to the man behind the curtain. This is simply a boolean assertion that exists solely to rationalize the way Test::Unit::Assert::assert does its thing. You should never have to instantiate one of these directly. Ever. Go away. There's nothing to see here. =head1 AUTHOR Copyright (c) 2001 Piers Cawley Epdcawley@iterative-software.comE. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO Look, I've told you, there's nothing going on here. If you go looking at the listing of this module you'll see that it does almost nothing. Why on earth you're still reading at this point is something of a mystery to me. After all, if you're hacking on the Test::Unit source code you'll be able to use the Source. Test-Unit-0.28/lib/Test/Unit/Assertion/PaxHeader/Regexp.pm000644 000765 000024 00000000152 07416643311 023521 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/lib/Test/Unit/Assertion/Regexp.pm000644 000765 000024 00000004333 07416643311 021555 0ustar00rjbsstaff000000 000000 package Test::Unit::Assertion::Regexp; use strict; use Test::Unit::Assertion; use base qw/Test::Unit::Assertion/; sub new { my $class = shift; my $regex = shift; bless \$regex, $class; } sub do_assertion { my $self = shift; my $target = shift; $target =~ $$self or $self->fail(@_ ? $_[0] : "'$target' did not match /$$self/"); } sub to_string { my $self = shift; "/$$self/ regexp assertion"; } 1; __END__ =head1 NAME Test::Unit::Assertion::Regexp - Assertion with regex matching =head1 SYNOPSIS require Test::Unit::Assertion::Regexp; my $assert_re = Test::Unit::Assertion::Regexp->new(qr/a_pattern/); $assert_re->do_assertion('a_string'); This is rather more detail than the average user will need. Test::Unit::Assertion::Regexp objects are generated automagically by Test::Unit::Assert::assert when it is passed a regular expression as its first parameter. sub test_foo { ... $self->assert(qr/some_pattern/, $result); } If the assertion fails then the object throws an exception with details of the pattern and the string it failed to match against. Note that if you need to do a 'string does I match this pattern' type of assertion then you can do: $self->assert(qr/(?!some_pattern)/, $some_string) ie. Make use of the negative lookahead assertion. =head1 IMPLEMENTS Test::Unit::Assertion::Regexp implements the Test::Unit::Assertion interface, which means it can be plugged into the Test::Unit::TestCase and friends' C method with no ill effects. =head1 DESCRIPTION The class is used by the framework to provide sensible 'automatic' reports when a match fails. The old: $self->assert(scalar($foo =~ /pattern/), "$foo didn't match /.../"); seems rather clumsy compared to this. If the regexp assertion fails, then the user is given a sensible error message, with the pattern and the string that failed to match it... =head1 AUTHOR Copyright (c) 2001 Piers Cawley Epdcawley@iterative-software.comE. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO =over 4 =item * L =item * L =back Test-Unit-0.28/lib/Test/Unit/Runner/PaxHeader/Terminal.pm000644 000765 000024 00000000210 15113572161 023334 xustar00rjbsstaff000000 000000 30 mtime=1764684913.086052013 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/lib/Test/Unit/Runner/Terminal.pm000644 000765 000024 00000006223 15113572161 021375 0ustar00rjbsstaff000000 000000 package Test::Unit::Runner::Terminal; use strict; use base qw(Test::Unit::TestRunner); sub start_suite { my $self = shift; $self->SUPER::start_suite(@_); $self->_update_status; } sub end_suite { my $self = shift; $self->SUPER::end_suite(@_); $self->_update_status; } sub start_test { my $self = shift; my ($test) = @_; $self->{_last_test} = $test->name; $self->_update_status; } sub end_test { my $self = shift; my ($test) = @_; $self->{_last_test} = ''; $self->_update_status; } sub add_error { my $self = shift; my ($test, $exception) = @_; $self->_update_status; } sub add_failure { my $self = shift; my ($test, $exception) = @_; $self->_update_status; } sub add_pass { my $self = shift; my ($test) = @_; $self->_update_status; } sub _update_status { my $self = shift; my $result = $self->result; # \e[2A goes two lines up # \e[K clears to end of line # \e[J clears below # \e7 saves cursor position # \e8 restores cursor position my $template = <_print( sprintf $template, $result->run_count, $result->failure_count, $result->error_count, join(' -> ', map { $_->name || '?' } $self->suites_running), $self->{_last_test} || '', ); } sub print_result { my $self = shift; $self->_print("\e[J"); # clear status lines below $self->SUPER::print_result(@_); } 1; __END__ =head1 NAME Test::Unit::Runner::Terminal - unit testing framework helper class =head1 SYNOPSIS use Test::Unit::Runner::Terminal; my $testrunner = Test::Unit::Runner::Terminal->new(); $testrunner->start($my_test_class); =head1 DESCRIPTION This class is a test runner for the command line style use of the testing framework. It is similar to its parent class, Test::Unit::TestRunner, but it uses terminal escape sequences to continually update a more informative status report as the runner progresses through the tests than just a string of dots, E's and F's. The status report indicates the number of tests run, the number of failures and errors encountered, which test is currently being run, and where it lives in the suite hierarchy. The class needs one argument, which is the name of the class encapsulating the tests to be run. =head1 OPTIONS =over 4 =item -wait wait for user confirmation between tests =item -v version info =back =head1 AUTHOR Copyright (c) 2000-2002, 2005 the PerlUnit Development Team (see L or the F file included in this distribution). All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO =over 4 =item * L =item * L =item * L =item * L =item * L =item * For further examples, take a look at the framework self test collection (t::tlib::AllTests). =back =cut Test-Unit-0.28/examples/PaxHeader/Experimental000755 000765 000024 00000000210 15113573111 021543 xustar00rjbsstaff000000 000000 30 mtime=1764685385.272269463 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/examples/Experimental/000755 000765 000024 00000000000 15113573111 017653 5ustar00rjbsstaff000000 000000 Test-Unit-0.28/examples/PaxHeader/patch100132000644 000765 000024 00000000152 07400722057 020663 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/examples/patch100132000644 000765 000024 00000001132 07400722057 016711 0ustar00rjbsstaff000000 000000 #!/usr/bin/perl -w use strict; use Experimental::Sample; use Test::Unit::Procedural; use constant DEBUG => 0; # code to be tested will be somewhere around here # define tests, set_up and tear_down sub test_ok_1 { assert(23 == 23); } sub test_ok_2 { assert(42 == 42); } sub test_ok_3 { my $sample = new Experimental::Sample(); $sample->name( 'Joe' ); assert( 'Joe' eq $sample->name() ); } sub set_up { print "hello world\n" if DEBUG; } sub tear_down { print "leaving world again\n" if DEBUG; } # and run them create_suite( 'Experimental::Sample' ); create_suite; run_suite(); Test-Unit-0.28/examples/PaxHeader/patch100132-1000644 000765 000024 00000000152 07400722057 021021 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/examples/patch100132-1000644 000765 000024 00000001531 07400722057 017052 0ustar00rjbsstaff000000 000000 #!/usr/bin/perl -w use strict; use Experimental::Sample; use Test::Unit::Procedural; use constant DEBUG => 0; # code to be tested will be somewhere around here # define tests, set_up and tear_down sub test_ok_1 { assert(23 == 23); } sub test_ok_2 { assert(42 == 42); } sub test_ok_3 { my $sample = new Experimental::Sample(); $sample->name( 'Joe' ); assert( 'Joe' eq $sample->name() ); } sub set_up { print "hello world\n" if DEBUG; } sub tear_down { print "leaving world again\n" if DEBUG; } # and run them # This will not work, as the test methods were # defined in package main: # # create_suite( 'Experimental::Sample' ); # run_suite(); # # We need to create the default suite # (created from package main) to pick # our test methods up - they just use the # methods in Experimental::Sample ... create_suite(); run_suite(); Test-Unit-0.28/examples/PaxHeader/README000644 000765 000024 00000000152 10301431446 020043 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/examples/README000644 000765 000024 00000001030 10301431446 016066 0ustar00rjbsstaff000000 000000 This directory contains examples of the framework in use. It's a bit out of date now... tester.png: ----------- This is a screenshot of the GUI running (view with a PNG viewer, e.g., your favorite web browser). Also visible on the SF screenshot page. patch100132*, fail_example.pm ----------------------------- Very mysterious. They get used by 'make test' via t/try_examples.t though. fail_example.pm is supposed to be an example for TestDecorator and Setup. You can run it via: perl -I../lib/ ../TestRunner.pl fail_example Test-Unit-0.28/examples/PaxHeader/fail_example.pm000644 000765 000024 00000000152 07403166624 022163 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/examples/fail_example.pm000644 000765 000024 00000002370 07403166624 020216 0ustar00rjbsstaff000000 000000 package fail_example; # this is the test case to be decorated use strict; use Test::Unit::Debug qw(debug debugged); use Test::Unit::TestSuite; use base qw(Test::Unit::TestCase); sub test_ok { my $self = shift(); $self->assert(23 == 23); } sub test_fail { my $self = shift(); $DB::single = $DB::single; # avoid 'used only once' warning $DB::single = 1 if debugged(); #this breaks into the debugger $self->assert(scalar "born" =~ /loose/, "Born to lose ..."); } sub set_up { my $self = shift()->SUPER::set_up(@_); debug("hello world\n"); } sub tear_down { my $self = shift(); debug("leaving world again\n"); $self->SUPER::tear_down(@_); } sub suite { my $testsuite = Test::Unit::TestSuite->new(__PACKAGE__); my $wrapper = fail_example_testsuite_setup->new($testsuite); return $wrapper; } 1; package fail_example_testsuite_setup; # this suite will decorate fail_example with additional fixture use strict; use Test::Unit::Debug qw(debug); use base qw(Test::Unit::Setup); sub set_up { my $self = shift()->SUPER::set_up(@_); debug("fail_example_testsuite_setup\n"); } sub tear_down { my $self = shift(); debug("fail_example_testsuite_tear_down\n"); $self->SUPER::tear_down(@_); } 1; Test-Unit-0.28/examples/PaxHeader/patch100132-2000644 000765 000024 00000000152 07400722057 021022 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/examples/patch100132-2000644 000765 000024 00000002506 07400722057 017056 0ustar00rjbsstaff000000 000000 #!/usr/bin/perl -w use strict; use Experimental::Sample; use Test::Unit::Procedural; use constant DEBUG => 0; # code to be tested will be somewhere around here # define tests, set_up and tear_down sub test_ok_1 { assert(23 == 23); } sub test_ok_2 { assert(42 == 42); } sub test_ok_3 { my $sample = new Experimental::Sample(); $sample->name( 'Joe' ); assert( 'Joe' eq $sample->name() ); } sub set_up { print "hello world\n" if DEBUG; } sub tear_down { print "leaving world again\n" if DEBUG; } # and run them # This will not work, as the test methods were # defined in package main: # # create_suite( 'Experimental::Sample' ); # run_suite(); # # We need to create the default suite to pick # our test methods up - they just use the # methods in Experimental::Sample ... # # The other way is to define the tests in # package Experimental::Sample itself. # Then we can proceed as indicated above, # but we obviously need to run the suite # we created, not the default suite: sub Experimental::Sample::test_ok_1 { assert(23 == 23); } sub Experimental::Sample::test_ok_2 { assert(42 == 42); } sub Experimental::Sample::test_ok_3 { my $sample = new Experimental::Sample(); $sample->name( 'Joe' ); assert( 'Joe' eq $sample->name() ); } create_suite( 'Experimental::Sample' ); run_suite( 'Experimental::Sample' ); Test-Unit-0.28/examples/PaxHeader/tester.png000644 000765 000024 00000000152 10273172335 021206 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/examples/tester.png000644 000765 000024 00000151326 10273172335 017247 0ustar00rjbsstaff000000 000000 PNG  IHDRJ* pHYs  ~tIME6 IDATxy$]ތ]lب$8c Xn61S006-V@Ҙ;L#þYU ޫ꽌qq#3߫W%_fčI""N[ NB!&c" s9m2T] ۣ&Ҿ}˚㥇@7OUJ'DEEߞ;э/t?w)^w{}9ş- EJ_Dw}Ɲ!s5UHP>I[i_~W[ia#'}6$F`ZxN(җECE?ס%T릏3ؙT>u֪=Xkr6Sx2B.UDh#]#]#*DLQZlJS]^)_fR}!oÅ3'5sҙs!7}eUc%lVh`XK>:{.b3PW4 *8oRwxc5vӓŨ~f쿒Rz 5Y:/e WI%p$ BYI3niUi ǀThC  < SׄDt5* 2)_SgRV NNXj NP5/PSV*k"i FD¯MKmʻ]REy6M &D:_ǡm?к,yJnOX'71dA؈N,%x!\ɨZ}:Jҝv%3Ig:ƍ&\O%z0* "8, 8d/_l9_@LƜ~Mz{kiɷ^+ P[3Q5Fwr@qkAU"e{ݟ@T3 KL;yl![,~صrJX3$N~ju*ud01O9U|" \VpOOu*up^* 0ξd Y|ӅN uONEK5pUMHF+~l7OEᰋFD~kQ4H$PIF SJh5*B1Eʃv)и?->z?h{Aq|V ѵnY]~Zy7?ԧ>nZUnyvlwƽ(u^ڊj'ӡ'{@##z`LnJ?SEjTDT`DŽ6Zu-z A/FUIgI/:OXu yDR'ډvje$F)<0LR gH;?:)0aUqU{Iw "}b]*T/^҉t?QT3SZ HГ}iѻȌ.V9/9}`J PUY`n] Bx)GS.浱. `Ts?y>pu cUn2"uݹZ|}NGֳbz2\ fɮmqܩP(vM:;qVrJI #aDb2ک=h۹VspcVƬ1+1$NN۶NAGh``5NRdP:/B,U+c`5fY){4t/` JruÅSU^7~[*a-&W[t*B]k 9e^h:SdTi?'66>3lZcɃ=3RO݄CIot.W:%{=uGHς -3,"Ը 9<3+]>j>nEmص 6\v]];/b~$ LC ^{h %0 Q89 cN$طZ\/EX7uRWXڕktډSb:wG麮?bW @QH7Jk(ީ`OtPQ_2Хo({oS'knvDh:W/t _ ``P/^5 " |E7KޑI8HJpqݽǟO `sC[I쐩[:Dq 6}A1hcVH#V7KLrinE[w]]'?:w=f0iZDcb;BJ9T]V [bT\0uF7-,{U t:=et5@ 6MשZj.2(] kYv/xJfV$!FU@ ߟhCtm׵]RjeTj?w~0LSq}D E*|UtZq>ftP@ߠ Q dSq2eZݘ\8=t+Q*('$Pjݱufo !k8eu;>^a`Щh{a>j]nHxe T&H7N2>';_+0yPt ' $ޞ"Հ(NΜI_ԕݴ 0F0ҴYOh+] Dl@Y8)=Yeu;vQeyE iٺɻ9( &-p^A*Y/C(4sd,e`Nc/3co"ųYU CX4i?w(TWh# Hڈ4$55:4ZWj{ NgK ڈo6[z}ԮZmUn|^׭um9Y'ykcؗxyNAl FUc-Kc~o!"?neõkGs=? ;]: 9+-o5^\?3޽xx]vOНUA/?oW_^ǿr@ig跉'}@D~9xA.P Q ss 5 7IARaË <d +;%!pN{T-Va]i[~Ct]0k 0"sZ{tS5ߕדy&^I\z|>::zTiVׯzݶmm6JDWzߜ NTuo3F'ǀty?y)_EۿGA5\_wO- $v&m2;/w'| #H*~ ~ADt3)}}߼/W_y-~g^؏哉l ec Joם=59'/w+R鵔ޝf?:hRx*^N'rsVo~#d^&5;7T*TZw\$UVhWW`#ISkH1LEݝPHP A?lWAv^zXWC۶C^]9{7^;͞|>֕'+lbB, G;"b TZU{~OnYqlfooDw-;G&7/m(&;O YoGD^KwޝK.fԵA?O>&9;Ǟu͖biiOgw *EjWsa_3@bk] #"+-B:Id`O*ik^ԿUZ\kMK1i\6Ӑ1s^M{ZKqZ) (޸֝tkm>zufURD %#?yBQ&hݿ;c_}< W~<_~Ϲ92U/Az㶗U}-ycy{?~1}? y-П^+˿{k/_>;?yqc6{/"}CE/_/_ܯKD#?KK?g?@A~3>Ox;?'I5%EC-ئWqؖ/IFڟO5!~e(p*U9rݛ&5KLlnzI̩+L r ESQtR_t&Y2NT:鎏quv=VۃѶ:ua%s* {,I u7~c\Nkɭ'>u(\}t=Sx<9\[oJ`(Wٶǭڰ4x|`/T:HQ#zN:'rpaCȜM r wPA˸ӇCtL0 a7+lWMdYO?n_~O|{oΗyk^s_c//ʗ<糞%"/q꣪Wjl]vIŘ(wPU_?oyGiW׽55kaui_qk{׾;K_g+yV~AE y e|~AJNhFj.*P  ,kPvv5] Ҕ-k>/4Z,utlM[HwE¨M ^tRx֖Vg4V 7R!^|?}_'-Э^}YVՊ!: Ed xOAh J_! KVhץ}U[9 so[' oxY~D-oOD}10ƈhG}䇊/w|Stt~_o{+~W^ׯqM#bY"׽>Ӟ'ǿxϟe_i/?~^Rѱ{?_ "asyaH<:bCVf;rw|^|\}ڣ׮uŔ`zLn֐ǜޟHW|g% ւ=XR[; z>8K8C2CZXCmLcc[C/\%*lW- ?]/mϩ"R[LkUcuQ{%os:կ {= {Wc$4"1w9E$zSn}O;it˝4>h\} ׶G'/u:wՄo> 8h sw[?rx]_xnǭ@TQs\5@_Ynߗ pea\3ԻGǟ[VMO![|7V7S?_k?#o?_쯦}f;N/P [t]'G䔪>]EΟI۽czG<Ӟ""ׯoɋ^w}tjrF\¬mW柼7 }WOگWzu (ׯ9G)|wɞH9tU\r2;x$u;eol}CH|{{:nXLI;{/+tm(  S˓*NQW'n DBiHuQ/L }鵇}ʘ >6}wq[zY^#iF}krD" R U+.'p>M1Q֘ij[bUV4FS vuiM<çNa3sNQZ)*;sqR7Lݓ6o%7}]xvr4qy˟fƻOzGa}[}v5еׯs(& b-,lz H#[7H|o<)O˿>yE~|;}o{7 C>noÏ"c'>Oy~G|~{>?Y_i~K9||׻gO޷>~睾=\`(78 !g\AJ"foBcyo^"NOdG(F$5s9eʐqpxF9kqqSi F'TMОj/4%IHrk7$HIIMG˫PPOPFEX{w.S+И VSṯ1{އ\a'f Or~}of >]{{#\Pz>Z_;v-+wV=ic7eC|g}]/x3 o|+{Dxa78^ &Cؚ)d?,?3}m ૿?ÿ^qכ'w۫C]\'՗_x5'ﻋڋ?q"WVΔ<ТO̫g~+gn- ~{sG7[cl?bZ*c@G[W4D-,eyA538hIi Z཰B倭^Z;lجf˴%7ʾXGrbmÿ/G=r$1#u#vryOR0G'W~kGo{ !w| mbo,Lb:&]}[{Ò IDAT!qͻ^v8F2Ï >r5ĝ]rw!ҥK"sWG=5OV,!PYۣvb!=#%2 !P$:OyT4heB!IZEKjA)OgzBL(ie mB!Ebp|iR5@$Q%s%%Q?4\$#uB!#8QSu]q)FgA#XT!&ȿO[fSj\DJgkBixb Qɗ:-:}oOZ=IR BB!*-gx T#8A5gC06M;tB!d@h:Ot,c, UMUbRa1 Tr…/_?|2)B!ĊeQY*B9 OtF4巏&?c9 >!m= v?x^) xD:&[.9ץ]H@!dc%Vs7VEN ΂;V(®kگr B6…  ,cL> /tG: !PٖAJA\0jB5mԉ󦟏l6Rw@!b%7(SRp$֪ 6x;wy@!䌉φS59h͜S2hFDN .U@!$Dˍ.($LaD>qBNTleק7Hr) :Yh0%*CTk/G|;GT!l Vʢ,;5"8 [u(&Xp(;l=BvNr9͜趝5k4^#BQt {Ok& nfqI! aw֤ek ےl!rS71Ap"4WP} !+T}qgIiӀBޣ7O4uP&@! .h:?9^x^C^@! =r}~]ODUQa O70ՀBk;ͿQmS'_uӻ*77T6I !n{]kG?65ڥj۰؟ ?< ѡtrK.v!io9(?Ӌ^m5vF:SRnXnBotxFwqB!  CBDTa:պVٕttN`[IQGrŋyB3x# !^v~hoֱݠJڕv2$ySV@!3@FGl:eH361XV"޻t}BC#RGV3hWa\K#1̐BjT=9F@a}5@ 9 jֲꇻEu?v.2淕ӍpʪQB!@,G")aH .GN r n?:UVӹ [xtP}4rGB! ĵz?~ auIU%zXP"+ѕU$Lq I.\S5oqjw-؋/krGI/;! ;uېFd9 [?msikYI(5 5 D[]aQM… !3pOPQXH!`\3OVADs,UB^3P3 v<a&|&Gl/wb8gIW6ds'gb7sw?V V:'.,}!&| ]L}/@"g2BkhjUm(5t.[)%}3V~X Ň(YXn~3W?Xtɳ T 3lL!gE:"Q/F ! 3 Ϣ<_Z5Vhq;f-F77JvaP7@%'$Mm}7;DY6ROanUH!2;UOu@LR΂ `1ġsڗlNЉbbTW9m4 ܭl!f. 1@S8@YHbTо&ƸYѵh-D=Ó07l9oA;EB'KSށ1NnC2Y @S2u") G Erݨ蠝*B;QkSD^:斧c g}Bp5B v:(mLvĨ 1n;8E@ţ<S@V+8FP`nh4-mQ!D ަif d) )FkɢwlUQ <^[e_e󚷬ۿ7؏[&B^E+% !lݯ_]k@?!Q.RH(R%#*A:iC 67"߸.Ճaª!!')b@!|=@SV<@&B`/B!NEiN l Tn;Yw!NNRj J(B!*(?%,IoAT N?LX' S=Lop/(L;P %d(2_Ngj'0/8S#6 ; 2O^EdOE)1;EK):Mڠ}@w?_'wl;/_u} " O`#(_kL 0sb&#ԄsyA. ky{ܿH%cnSuMnPy,B!Uڞ}0кp k}xN\L0NLаa?A..kO \Qdm`cV;7dsNB$>60hx*mk4%DfFN,%}ꞨvmԲޗٲ?T [:ןHռfP#(rXً[$~|l9sruSx^02\DQ1*r +'Q5E@FLj"iUiL0J*B+$WǓœ'}GިrvtcfӨ-aP ,*PO' -{r^Y.(zɃV* lR#r'rE{ͳtW #2H%`**~"-@X"gtXܟT9E?٥Ӡ@95?I|iAF·'g, 1A8tT!6\T)z(ŌO!LBQyB qJAZ0 {-4҅F|1R1Z7H=w Tu !I:4LptB2H)]oqW/lnHA'K݅rh-8q 쇙QӐz"-ȟhSPѡ'|$dB{.]t G2 ۍ=4fW d_ tklΟ! wqǡ0rbp((?.!nTz.y4qmդ/^x*!иrŋ*`2=5v@·0*GED #N&}HW[!B}h 2GIM!0IB!|#*l8[@#GDm*%B!"0h^u(sԏ UAQ;x $?`ď9PBS`wҡAfѶGQPL p37壩B^ ;ߴ9Urzlo+ m$;56}1J\ Bv0؝Ɉ.H8Q3CRPŴW` h$Q5%w 39 T[B![pS0[&jFg<3 !7m @NQ90<˿",t;T/+.B!GΫ|Vd \Ԋ63K ^aB!dƦE|PX@r_hUmC({AA#AB]o$ ȃ墽nA%}BH{'6b e&m$1 ְ4h!!Bv4q2dYІ)|6e6iM= !57Pu)r*{'t!<]LBٱ=Ka7 /Irkf1 .\޹|2v{/Y,3]OH#L^>pu)o:HA .\܁?kn$tn$i$w%PSE&C\e((eP==_69I;U7c](ao7o}TxYmC0+x#*%5+In:v4 }g&نԃ~{|;ۛUJ2@4"R A/͞Cط*|#{`-b.pGG6oônowIⳒl/."'z%oĎTDH3H9)XT^"7mv:.6n:UdvcB!fac:lW%jLGISB!'ahʭ!'xH7]" DŽBHع]pc WV@T%!|^OH b!kvF@!QnyL ֜_)UB!{$슋)~ y}@&Z`^Ϫ'%3B!- pl!DG 'du B@!:gOenV/\?mS9AsC=rBȾ3 ;Tȑ3=j 7@Q3GB!ILG~7{PPDuJOP  BH$wQYW`bܿ Q DQ BAu`1멝E:!ea!7g )T/`z@!DlAp6_sF4!zhFU`6ɣB-B;l$!v~ڻ*~AOދa^p !˼dkzQF/|@x .%Jx]|6.eӦ5ŗ/9ۊ \_YE`MJ3lS8nJB^Є&*b˙ÍuT !N." *Pa#LdpbGNN!B{@>105kB\)a*v!F!Tjs@ ٔB(&<#B!l3@ݧRHPEٷtN!rFB!lVg &yw QGS(h_YUp@!d_~aZD׀?3,ThMB~OuAK:IɅ_B iN BP#s'74^BjMLMD!d]O0G}~0'k(}(E|bgH6J'B!*{U"Bſ3U[Zp&"Br5qҹ xLU$5B!đ_b_<^hXQg 4I0dBaz*CYKذ@F[N9X20Thf@!Hc.D*6`g7Au --%KUUBcn "~K-kl:-vI oB!d{6dk A: qc.)GsЪQtdSOB&d˟!.9 B0()Wc\|_%!COv`Gjky$.,;4iB9hC~&t8~ j^*2&bB!$iwɌ5@Icp6Me@!dߵvJc>f!NM* fv0\keT ˵O " MzAȾ %mioS0sΏ`!w s)I̓nC[;RDZ.&뜝ڿ@ĞucZie+G뷩}3)uO?9rSʅheD0D4ԘN6Nș!uSЌ4 ^~׺ ]  #$/ڝNlOWN+ VFfg=S> vAFf׈:έ([_ +`Fjr_. 5jJR N`Aw# d:dpB>١ 'jfЗѰPM|a淁d򪆓Bx yNоOȞԑH+FIk2mLiNzȾJaV-ݠTo?][T_3x\d@K-{a9R.fcu F{(潟 y}M׏w`: IDATB)+^{˽%)/'0u; t!t^C!ܬ aL7c8 xdCNB! LcaEI։RhmP;٠(CnFB!Q8CN`@Le@!d{,좄@-uM gB] k# 90!rHV jPhQ8F@ n-)3jEN;P c#aB!n@o[9O Gap$?SS15DLM蕋QtoB!g/n/.^FX0T#F͠ Alvou~$EB!7oTkZ̑tGiZreNKajq&Fw@!n-wޙ[o]$OgA&#ג^į͔TDFi͍Q]wśB xŷly뭷y睕v9Z~K= UȨ3 `u@!y*uF}bU:e6"\^KDTRc_ g<"Kr[A6!fъ@ὤ=B]ǐDu :~"QIG%jhh|N>"B,}&"'6Tˡ(J>MEI6^0w\{=~3q 2rn].HKhw$Ķhk(5:q6:3e*777B9Q'cNk`Wf > st(!Ƞ*[43mLy!{ %젢Q^@ dA-Y|& "OYbA`[~{>Bt\tP +yY/rGK@I4?n!YaRDB@6B!'(Ym nmHSLh.@ɩ(1.Y;!tHU$BP?(Ò? <-U4Sa؉dp.2ofyڡ5p?W-;.:P2Bٱ{ L c p_[`b/*#1H9$Xm/K#[=^0c1BH2 9.]$'4lz2(610?}0#@DzVAa09oB!$&=qHmmV(R";4*' )h^!HA&B@rѾQ"DQYo;jwDSQB{B/naB yGHzT<[<ۉ&u&vwBIun|dqC.`1pٔfH}B)BB]#r4~cuawZ&}#&J*g`˃B!7 [׭^i")/ncLU%`漎kFd3*Z´`heAxX VB!xQڢ"/QmӭX+1ks|hMДw#k2qo?5B!`0c:w컓znN095:ӈJgHn Rq#1H*B!{̃z޿b"i:6k#il6gY2 Bȉ3DUEVZͺ^`DHH[JB*wL X\H7Є(Nɻ5? !7gX vډ<;ZηXufXK!6!7:f<¸BB!l͟9C_kk*hMh<)Q ŞL B!$.@ ^~BմG纣t͗"ɞR= ro`}J;WYs*C=y'!rjA mMwԘsks؜@1 s0% u_B!HZ~`ZnBxx3ބIh4r+@LC7 'g5]|cXlgjݮq|aW<ێ3PH(,ZL!LRsI̹Ed*kVڪ=׮E[Hx- TvmniB5B9`WŪ5ǀNàZ: IHJ !B7A(25A`Bh%#u&7؃AD091vcյ !B]>;f#rjG#7]VOHC=cY8'6qGb@!dq]2N"onjGBz_O+'9Fw d̓Pi͹Zum_6@!pՁa@v!I^8ًwBԬrDjA4!®&ȯ$,~DW Ro%5E}L 0B f \(@@JbyO'd)$Pa!T'R <> Vc/"Km*fdwB9ˀ !,asVzVW5ؾ~qHhbHC8J`!1}٬|$#e@!&2Sp$$M-3 yV31T!w`wFht:lacyNJ0zVG 9M[,ND!d*,P/E's b}G3"p"R* JD"Bs]ȟHB!EZ+/m0װtdkyդr!C |{&lŻbάgŬZ8ie4T! t BBv$-u(Ԍ888G"YU@B1Qo83l{'d ބ5tfDv~VJĞ .&BJ b;(*B!;u^G)-vu_3XMd<^c|JB!d/y JN?jkfyߛl17#2HWBEUE@!IxoNK3ɊL &!:!,_W'PsbS8,[:r g2A*3 !WNm&Q6$#hP3we:!9‘U&miӠEz3|fB!䰔- <1x)&@+=Yd\H@ ! ǘES|fwYY`3(TDsfVo`m5K:"!=$n*(#p. 5sphFsɀBI;tGC+ i^4kZfЄ[@!R~C: vP!Pc)*kC+-C 0Un@!dߩvݍEh}N]8 U4)C[G%BA"fKB%+mih:~ 4Z!B 2Z[hF뼏b @LV1 m#xZ!}gvɢpۅѯb~ǿ-"]y ](B9`aNn0Fƅ*7l] F#9@!@ݯNT`!b>?c9M'R.BwfnN="Ο;RG 0D.!p}BH# l:7R٬)N1BV&ick}$[+K9){!S}raUC-}օ6;n^D*PY B!+p%nv VtXфUB! GeF}%L"XP9ǀ!}gka ת% S) 2' B!5?UPHJەԪ){B1fB![h}*OQ@7 9G&%uAgB!$vub{SzQ0@p5:"I! 1-͎]p Vq! Hł) ]44 !@BU ><*B R9"BnNOZƓQ=l8\j9CeBȁz I\l5z BKtBbP!!rނ>ȊGZQT u`oτ !y>zFt^& x4<fNo!B - S>`lE~lz ]{t6eB!~hmh*˻J&dbqnZrAskRڄq!Gk,nWԅ*bN9F I4yB! t1`JL(l>E@@"U(z eS\G r߯ۃX'p䦪@W 0y!Y`0̻Bk|a9 90| jrBȡ9ttYA N_, #:s7~B!7 6)Z;)NtB9hP/}kO0`UB! :۔vR&QxacT$ B r9lmDdV mZV dT^@!dZUo= UzD値S!3sM{6H!P.]txI'-vg䎟7Tqıs@!&;lk5! E}m"]n#!P T!]wummbFP jV:ʡB3B>p뭷p4](`+6Ă!0PDFZLѳABM!X}' >S2f\#auZ_~Qaf@3j!+W7K \g~.g54!(+UB!7O~U^Z [gw6}]21ghM{@!h!0/ܶADAU,B!$؈9T!V#Zq\T0$[75{!=p8="}a8;PC5B!tBQ'@nj^7@ ̺' 3"T>H!OcEu77f!n_VX DSM !@%2g #6@*$RM!B=0H : sZ.ˆylJMV@!piAJv*̬MFAᡛB޻jbwU o7'(%"!r9 zm`S~OZVV0DbDXj@!dؾ@U6v l,7fs!Ie.߳ј2lDDӄ) }BHhm IDAT Rb5 JS\J?IiՈ&Bj[Q߷;1r4?M 3kTSZomG!LlZXq[9J KN2,Zx+WxB9;V6y&$Esf玈@" UnΟlL!*< ^E0o!w1pvpBqAcwav B Š~?lL!䀹;J"VIP@!-M%#WfTB}1D.\1p vT v̮u;,*!::An|.B{F?vLtxrvE}vÂ|'Q *dB!B]TUr fK’R rоV vsl'H z?2OBk`@]?/Hp p$*0  rDϠ^Ijg&@T@(J$ը391zl " r:bnQ]$5iFYg;tS:E-! .^|پٿ>Z@A>d)PhjX,R:\_H rŀBڀ.\p™fGO=дSoa-ˮݺ  L HXTk )鄌0vA@h'e0`a(46؉vl%r$Yf{Y{^^>69{](Nb=t zXFW!$D5K>ߵpʔ?5 F?CLP2&D"aaޫ"|e ο64{vv:TxCj-S (DqD"K'hԂF]p/@\< ! Q8E"H$7lߊ40#{ϑHF£F02XK3?H$dXB.@%=p+RL2L$`dzB/%c09$ d( 6ՐH$ļ,7~ ,Ʉ;a Pw/iB!`{ɉD"H /ϑj 3azX50(X0 uןH$C-` w37wT6qY GO1J H$P[ P}8;1&f eP!u"ߐE"H$>&M_H$w *9]!QJj*#;#$D"*`\ Cp涻6'1H$& "削ް`PoH8.9 -"xp0D"H#*"cNE L(r cFH$cƇ~x.#{e3ئ0:-0pǀ$DM珐,8d#G\ mH H$9^xٳv\g 8%!Jqx B"\ۑО~s"H$zn5O@W˿`*lC 8jy$Db~O>x"$P%L!bTUKKSRK\at~w"H$ uh;YǴt9umZ Ǒ ;N>D"Po}k FeOggQKߡ-@2Hh= rFV<ǖH$ģچm[6x8Өy\$Dhx]nFR 5d *`U¡-(H$S &bZCv@*hjq@G$D"gNp5RJ{$=No:ϡr#GeH$GDe>b+B;B@ŐeH$Gpa5ڎuv"5F: ?vo?k/WtƼDΩw_ w!ԳSzپ+}.N/MfR o>ۉO>nyF~A h &r(u9>RQ r8P_lm r.WYm:ׇ?E饩^U,I V{92V(# tLyhKrA$ pN^oҀh>4Cʢ>Pl\}G]3ay}0`5ꉻ5_ʟnؾn?&@۶*8IJ/ RLA~؅ZfCC-8K]gw64@wyeyǐ$A.'eMxH`F{G圈}NAkfP!6kye.R7;~.3~~sͣ.jeZ\CRH<|NTV5 pNTS }NmF_e ~PV1"n5͠zT5:oΰJ% qOQX' B(v7*?3W` mCcEdh ZB7TIe .vQy ̺7'pq`gsGPDޙ+ޅF ޑ yJH.6MW>0?y$8†'j {!?RcYG6 lĮ,D4;v&A躏;uۭ/Cewǡv¿g> C5uM17r 9wqiNq؂>@&w~Z;^h@%vIU M[p?rtO~R#"ÿsW[V)ŋO >RʳgϞ7*~(ʯmO/ÊSV1HPL$aK]c1nrکD]!%'wVB"#*xqKQ@ә#9'FwB¥T5 ?x:ANBp^{ - '+a`!j@6<( H$*Ї!L><,9Q@)@H$ۤ 3E_R?PvNcn H$GK^ o#0*(G؟rʼn{$R}݆,_J)TD"M9g9( >@S`s="[v(:N_z]J9ND"H$"8?d(Mc.ʮGkʼn.f;HwfD;a4,4zz eį~q8_w"H$xv,VOO\_bmEw3pF7bBa)|ןÓ/.|}D"ŋgϞ=q6ΐٛԞd4޾#؟jith?_|/zWW<B+lsŦ0Ӫ gr]2[Fό>?As}>F'VgRƑdUұ?u k,*{2wTB"Tf ,@L.XT-\y<8$78r.wX<,ÿ|P2 PiG7tiϨL``Q ۘu.3fukOM~5er8Пwb,lWTW/";_ˋ[\I흭BBAX n.鮬X՜ַCr*69ϾϿ*>T|<_[b:d]wKPER(1Z(,g?׿~Og곟t<ڭJ"=GШlbXkiT%߼f`%9&.2N3^,5K;润8j_nݴj% ҮPX=Wi.˔ҹ$:sr.BTHBNd=ϗe=@a9z^(cSM ,:VʖLޑZ}O{ݟ wcSS*M{)ESDa}GEUKej4*?;]aHnЦ"blrhP5zڐەg|^>O?vw`7 j0nyt(&6_|_/?駿ɏ}F'GؘcRʨt/GIuw|l9[6Ҩa,̼r&6؍A!Q9+%a|?׼,$fn|<"r%$1>%'˱+Oٴë߼7/®ߵ}@?YT [\.^H4``QĎOe4CUNg6P'W. 5}8a5|^EhB3?~})Q7"Z_*)}(l?Sf:U,?qbY6WڍΚ{xh[8R S&Ŷ(T({bq<-c,}QQȀζ%Ző$"}F+KvgBV(@y4ε@W#А[bJrU{"mPQyoqh\Ԕ#;^iq~( >UTov˱/,:߬fYf`D(V6NhK#HT!܈I;B^FeoDƶ֢@ ZjRϾ^;\5\B7k? ONUjljC.!%d{1Xsgڜ"DYDx DuyFᨃRɸt{KN!Գ:8BoQ;6[*&Șn/!Wh'C+xZ'( ^:iL)ISy4;U]/mCIGR5W7 ۶R읗[ CŽ@ETW[k}zą2kv, m[ѭ1h#MĉtJ(6b=u˲EݭI/R[HY?$!#Br#)>$KiU.J %g\8Q-؀$6-uI*Ԉx .%HҙlTCS&*VR$9C۸YX(qXn%C3B7b_&/6š-ESǣv7w Pkc+yoƱ,[nh5zIv#L kN4IbK|k*9LX)= =wR0b٧J{*ct.,EyAoƓ#JyQHH:㦲[$iUmSoslrhf< Mlͨe=-ac(UKbqh[K|N/_~%H$3oe]E qÑ2l4=A5٫jřJ $wx`##0>Y1I2aRQZeX7`{' D?ů/RJL$8>\EHcD(&m)l߱Dh T8FD)=UCu y{g:x{8 p[8 VT)kPʱ_}/W??[knɹoH$WUh۴߃SZ`l% 5(*˙b u*We&.XfG`rэһz*[wCm,F+o ׯ^oy'|AD1`]UGsEK8|b[ _BA!1xx`>idbTzH D0C,}~VуNE o-uYtr-3.RPGMg)0,ey'e`QsPһNqTg3Q.Z7y!+blYrgK/D"{? No.E <cdsD*A1 G"^ƌ}n;}SwJ^ SIjd"CY{|M'~d͇g}uG:~ޥG``Xg0ޛ3'_@Ky:ABu9WWjlf6̀ H srmԥVIBk% 6!Xb9bG1vld9,࣏>*.r4[ ,&FJ9GPm[Bn<9 e8'c|vqJnȇ$Z.ճ݆}S`MuڗK2RB]gkfǩ;_3~%ufq>y޸`X7Ȫ-+D-F"6kՐP:.c›K^K t"m*U߳~ب$ >x$AOkF\W/eHeqd, g9%P#C\gHv={cȻ|*V!\mbcZaх%b3fwtEe|>>dS7) |Ѡܒkkm;2SJp qY`!-8(-A[5}92m!ˋ`)PwD:s.ߞrnHcIsL8znP*2X1qݜn94KloPw$BsovӠ\pOH>Zj^pQ>mS=̯U+Yu ,XMbXcإ DNDW@J9p](_(HV loX 1= 7{϶T0M;;gxg*npдOZj҂%MXYm2aq5TxPy5\Hl7`Nh$As>'J{NZ# ^f8b'2ڽCz[fɒqGg@QSC!'7Q|;(HR [%hzmm<(+]4S͋T4ŃǬy/-ͺ>>.et9h_L[n:JE!Vk{gß_?{Ź/Yܲݕ.m`Yz1_CsYW/6 IDAT1,C;֙ ]KA--/S~豍[}t`]h 6 v3VTKu}0^3$AyjKhhE:SnD=J{HuV1wh;o0_ ^.& +<ϟ?&`_DbJpTkM8ո9Ca)-lekK𰘱zsIz_wNJtSȾJC$Ctk?s8)m࣏>R]_IfV_IK6Hܰ=֦E4IE-)ܽƭoȾx5%0CEbd UHf`Y@}pnGaoZH$o#AP SC0"a<̽s 7M5-*mu3Q QF;+nv"\_Ä:w#!tk[{0rXJXK5z{#!xZ.3Ss-@'TVk;`4!ƌCS>ܻPi5IGy~; UyQϟ?fe/j}!hJI"$HXflQ :ؕ %O(Vq-WSIxw+X̧eo1D펛Ds?J ˎ鑏=s"WJʇ&\bj&bO 聶-XA;J@uQrjI͕l,H &xDÅv"ͫ`9k4]%U@`|(RIV x̤>hN㭃6H. ^-vzE}P8Zpzhr>- In^2Dc=F !j}b,hm |ᑓ*H$.CP,~,.@i.sp|u ?ȏFg_#@0,-=Քw=; (eh߰Hv;[g0y٘IJ7RDn2H<(n`[E$q67d€שjT{-x&BxNbz @Lq Cb .ucV3H$(JT(s0EUXX0e*g'etESK~m6T&fQ]j  |jCzU: DAA(^W+ W?5 fQVg!ti Pޘ;v+z'qq8ldyhi$5܀b.`z^{]'֠j@ :!}.#M"p7e>&6w~`(dMl|e"H$v*cߓ~oOYɻLsN֙~,m<4Hq#]_?dȶ?`D3jfm7c+NPi'/Ll\RfA"HD?u"7:@+t;":zM19ǡH}7qO}"D& ;r˰?}"H$0VrrGF1E4i`-Ma U6$hu0pq@ALWbZ(_D"أ hW`ICЗM3 zE٨t^oP5Sm[^THrbR!,*δ&\71=!HwA"H=.`"Qrvy ͤpw)ؤϰVxLi{|=ď${.V!g9׉D"<<3 ]"l5dog֝ɦT(zLHbn溥s%>}$iFj k !:s);\Du{ Є ZvAݘssıRX:u5Z]*D"1mـoNmmDܶxȋ:j"|`Zo"GNpEHػ<{蚱\Z,E+D"qGPVv.^r]uBжwNЛ]BZ~0-GeCNĮtωVM%[VaTDb/KPJ|C5=* ;u-1j4qNft1,:7ӺҰA_5gAmqH$D@r;kpQ1COB'RajoÅq1 8۔lĹb|}n]K`ҞD"H̒*C 0-U4;JNcC'H -=9w)MEXOPS#D:J/|4H$x2o62v ^ UGb{;o̘0:7ȾSt3aGM=T\惔D"q@)(G!E/% F=P HĹ>HbFWEofm#,FaшQvWv$a _u;̖O0z;@ ųA"H3CUL!8PGk~RCqj_B{: $⛪% 9`ӍTdfoOI\>$>@"E/ c ӵ} sfjxXHwNJtfUmwԩƞq`-ډSH$w(~e8BTaH*Ch1&nک曒UMj4թޤ։K0KD"qiv6b)t"r^Fn&ͯ== ]Xa(FIɔ2;ҧEA6]R@bvHȖz1AYC뇀-'#UD"إ W#[n*{oif'+1s._?\P1ţ#)BA޶7ꮬPP2n H$0e1q ;ʉ*VRJeKL}"L49i Sm"L#kc0a "I$o04T*7eЩ YD2Л󋛠 gaƕQO'c ȶLd{NiY04ՋP57/G8J;cmQ]oAm{&DX`=@"H\izQqƝЋt ١ #&J$"Tݲtn pc{qAy=PL {P d݇?L H$**1 ##23Y$]V&f L`_Ж-1.[P\ {@OW{@%!q"J(]B4HC H$88zbbE0uj@Qe+J?e'K.,%F>9JThΚg)QVV_2I0C!?5T5[xN2J&~O[n"4"hҾBFAQ G{r(dkjh(]@-X>ɐWz6cB- d#|_=8|V$”in6j`H(?g%ԶIlnH$W*zpIlkAc-ol橧,J(*c`3J}uNVc$H S"H$n4+ۡ-uw}6+8,P4l~9#wF Qy (@̘|fH$WH*zp6Pu43(}&DlU@F>˙͂G 3,0uk1;AjHвH6=츤: D"[v/Bo%S[mJ } rnܙ|EF3gK%,an'%DZC[ n+Lds[a˽\(c+Gm# VipBRs.7kE^Kh}ǫ0vgVb{aJ6)sOzN?hEMi1kNUM]D}sݾ::^ lVGIpm;0^žFٴqO@Lؖ^$Ćł630h/W@WX>q-e`^aȈD"F WjRO)y.ytbVQumw!(^NAkFMb]CTt :#K) XƮ$e$c)= $~B`RHquznaW{!E#DhG(ۺśc;|XߨtfH Pn#PM(YaviMV(J$\x/s9o~Z=O r]زq+QN`њ+2<$Sb`3YБF3/$aU،‡~or"H䷾bSvuBcU>)ua NPELNzg 0 at0JGP(U,q4mzyD"О|;V \{\Vn5M J(gA' p @! JM"5wQJZC'@TuB{ҷ7P Z-Cau՝.Bo}+_D"=C֞ф4273VKmS1?zZD/]g9Dפ #w%\9@`M 5 $3]~ÉD"1$[i#yX/qlP7@D[ce;ryUxbu! zg>^_><nH=]?JģUGMv9=g@ V n,,¯'ψO{2Cl?Bq)Pmq}CuPkEPz^xop0?bm!nznZb<- ٺzTAX h@G^`Mp/H@#NQ;bk9֮+oĴ$=H$S8tqH%ٱo;#,GTJJr ai[c\3g,11GX R`f~e?L& e>Fm&!# D⦰c2/Z]>▬iߢ=^1+Dڙيꐼ\MGPTGqkW2(fH8 ޴PmOT)I$D::|/:&jPԛϸ}J5* 14|l-fI f`| K|cP깦`X I H$68h oMTsJQM}qWz å"?IΙp.<-CQEF%\% JH22twgD"GW+BXqEt˦ذ`Y*frdSGή߆ђ~C<'k6Ȉr\$ ?,MC 5*)ZкFFU H$hc5Pgݯ اTs GG9׽,n"[+)] h ^<[B ƴ\T1+VYÅ%=H$3{7G|K6f.q!DGȑAXhAHBvGjv x;*ـsm#ry}Kni*2+!HVα* d_ F:v RoHgA$% \Mc XR0ޕ@"x`+J#4QX ib%ǀqm|tC 9Vg0cGu^5!\?޵Ct=mCO[a@YԲ$ >ߗ^D"v2+JPlU_Hs ST:zbثQ^b=*},#}VIjHSjƅ΅ ]J Hڀ_r.xn%Q A/)"otK"4tlLÒЪ>XY!2Hsh yte>%0LRHQL9B S-H$۩ m, I=*̀& Mi ":NEǔ*[l:E&gtm{a 2[ T Ļ ȵ]چ!vs nWi6lR&P3*7b(9=^q{*Q-QjI;L7H H{>yJ\zˡi0tz\Io]9s@5OD+k];.`~CjvPp6ac*TM kTN H$vrz(8O^ɱZc<@hF;bzK`N=:_qY ,S>X 7ՂD"xTrbq`)<ׇ'O^[3l.xas䦕,)EoE""GaO1sׇj0;BUR 3H$sEĶ:|5z3=p ltz,XG2( iۦ9 %`Ł;G\X_t$بGdΧg> 'w/7;a Y-^-]rQZ9'W+=r,9h &yUV8 lonвm`|+T"7va'MG،)]l D4`Kc^5}0TSPwooK%6 q^sAA#,xxjnrD`Hy*1aKޓ1(y CCj*ߩCMiF-Ϟ=˶DQ .5 }i[B(n-D̞㖌&Ct573{KȨ="$O+Qx PD"N`AASXJfme8 *mK$ qv^{&rePbC OTXDx¡d 6tGL?H$|JcEc]GჇxX!@5/WK$h[LC19Y.ܬ2Q+\9>'2.TIh4)U;)JOʐ_&'8L4΅A\x8{PPEpZJ} H$R L,fG{H;J.x:iD3SM\-qJY.gpS OD{[Vl3f"nH[-ẃXouNӣm6ݎj^Q]aj%qf f v/gVjK.Cs-kհ *Ha *-Ӥ$"c׷3h6P̤{|Il2R+H >}Іnĝ}lSn@fM&_єARs1Q q%apM $)dzgD-$ $/F6U5pΩc!JIRQSH<d[E] #GY#C4+B/hDu ve:efz>3 w~+B@sRuQ}(@ӑ@+vCD,zibztzӿvctQCRњhKDZjݼXp`t)eq)L$NY!C*cR\7 ,sr- ]#Ch]/KSvHpe6BNi ^Z9!ƽ TgD_( (Yθ=0շD"HR:~twqȜ0ލ^DoMZCz;Kj Y6*+'C @4z]WdʆgG{$阐Zaf"H$v p+)WCnp׀(n[hV1Fna VcJ ٨g_*H$}ڜl{3m )Q`P'+j\YtTzJa!>1]%В2)βA\I%siD&D"l?@c6{t-*w!M7% iZ$b+A+73 lʓvڔ@vZȸz_d0"ڙwD"q5SնkL6g߱D Opomy#uȮB]\YmԺ)eM]np7ZWGء@f%mZ VBxxxϟ|IMg"p^JS7`閾3KA&{:D%wQU' k4TNUxcչn oJ3,) 5:$03& |'gI/u@;k5"کJZ GP<|Y^1*D6 CEC$= $=(&LǻMղG[+0ү1в`p_Cj C*wE Ыb BmUAP[u`kpTXix9V(l=m%AuCDADP-\;F3NEzmD"HXFS!`r"8_ߠxв`.0ijM4e<6mߐ,ƌMFéLSe] =?8Ï-H$NP-˲ kT9oe s=48J ѓJ՛E2G2DJZa*e@l @-)Ej﹮FA8jBW8AkǬ@5o JgK^&;ҧ!0@L3"ia}$wR'H<@b0Q7DƳg^xx\Ai[/8*;y8ti IdF\>Cߟ@0+zFv꡸;.GR/>/~_嗟_G]zp]_h $Y&0;3NYg2Z`Tn ٞHR.Zj:"+R{&y?zϮjyɜI7Mu$Se,wkpṐ8\Xܱa~_r-wY@a Պ5sٍuS 5Fa1P!euS1 e k2BF(I#]X׶ԊŮOoWO:Dx֣ׄ R <wYP.5A@~`]Վf#X8[R?6v\ժk'%>ߙqEk)+E>n[ڢ>0肈\CX242ҫ?:[qM@3q6+2P*BT%B5U__ d0^D$reW1OowAh+ŢSPh" ""YKKNjkBx'r6P^ҕ>qPF`-Jna⨲=i0u:t.{Y^'WG0Y3-ޤUxr2bV,Lo`ߑUcRELЭyԚTk$\oVuDa]w `yi=/~2j[t!(`}LPn;bNjyJnB5J [> ) ZZ@ٱnK3^$yJe0soGa˝lꁁT0F[K~NDa|kdo=WmֵY/30U "ROL4=7hs)I-&?Ho |8T0YH3_ ot))lS]Ծ1m@dtG} Ldۮ~~*bfK}z Cͽ\f]C7w^V ΒN_e{˩Q4Ssl~Ȱ12|F{Ž` |'C\|- ѨЇ4./D۠ }ߘoj E~ oP$W\a+v״kT5ctD/ V#Y}kJ/co?c Ch\\Y2;_-({] JfV42 SLv 175(k8w{g)tx\#R-W.kbբA#~զ)K /}2F7Ͳbs z96mFfH4fT$0G/H/mEr,߹pGhUQfe]:!$!x,Ֆ*7Ұ`*S*Kɂ׷1;"Aُ1D.@n v}@= /t]S(rgbfG6L4o ˰`^U<.0M>(e_h\W-öQX|JXo}q{P©H07Gה%*’A5V>0(Z YB%u|}Q{F+e-CGSi ˉQ ̶rpD@lE@<}vcePn^Hd8Е%NNt B[Zڸ" #9ecaDfYc PD Yy%Wbѯ{5,I)E͖g 7po(Lh ڣʙ48wTkd00]O!+1 Ok &}M&]}&Hgр>uӝ{mK>IENDB`Test-Unit-0.28/examples/Experimental/PaxHeader/Sample.pm000644 000765 000024 00000000152 07105243406 023404 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/examples/Experimental/Sample.pm000644 000765 000024 00000000706 07105243406 021440 0ustar00rjbsstaff000000 000000 package Experimental::Sample; use strict; use vars qw($VERSION @ISA @EXPORT $SIGNPOST $test_suite); require Exporter; @ISA = qw(Exporter); sub new { my $pkg = shift; my $self = { @_ }; bless($self, $pkg); return $self; } # object methods - public sub name { my ( $self, $name ) = @_; if( defined( $name ) ){ $self->{name} = $name; } return $self->{name}; } 1; __END__ Test-Unit-0.28/t/PaxHeader/tlib000755 000765 000024 00000000210 15113573111 016465 xustar00rjbsstaff000000 000000 30 mtime=1764685385.275523501 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/t/tlib/000755 000765 000024 00000000000 15113573111 014575 5ustar00rjbsstaff000000 000000 Test-Unit-0.28/t/PaxHeader/try_examples.t000644 000765 000024 00000000210 15113572703 020514 xustar00rjbsstaff000000 000000 30 mtime=1764685251.258311326 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/t/try_examples.t000644 000765 000024 00000006271 15113572703 016560 0ustar00rjbsstaff000000 000000 #!/usr/bin/perl -w use strict; # using the standard built-in 'Test' module (assume nothing) use Test; foreach (qw(Makefile.PL Makefile examples lib t)) { die("Please run 'make test' from the top-level source directory\n". "(I can't see $_)\n") unless -e $_; } my %skip = map { ("examples/$_") => 1 } qw(. .. CVS Experimental README tester.png); my @examples = grep { ! $skip{$_} } glob("examples/*"); my %guru_checked = ( "examples/patch100132" => <<'EGC', ... Time: 0 wallclock secs ( 0.00 usr + 0.00 sys = 0.00 CPU) OK (3 tests) EGC "examples/patch100132-1" => <<'EGC', ... Time: 0 wallclock secs ( 0.00 usr + 0.00 sys = 0.00 CPU) OK (3 tests) EGC "examples/patch100132-2" => <<'EGC', ... Time: 0 wallclock secs ( 0.01 usr + 0.00 sys = 0.01 CPU) OK (3 tests) EGC "examples/fail_example.pm" => <<'EGC', Suite setup .F.Suite teardown Time: 0 wallclock secs ( 0.01 usr + 0.00 sys = 0.01 CPU) !!!FAILURES!!! Test Results: Run: 2, Failures: 1, Errors: 0 There was 1 failure: 1) examples/fail_example.pm:19 - test_fail(fail_example) Born to lose ... Test was not successful. EGC ); plan(tests => scalar(@examples)); foreach my $e (keys %guru_checked) { warn("Guru ".(defined $guru_checked{$e} ? 'answer' : 'excuse'). " exists for '$e' but there is no test file\n") unless grep { $_ eq $e } @examples; } warn("\n > The STDERR redirection may not work or may behave differently under\n". " > your OS '$^O'. That will probably cause this test to fail.\n") if grep { $^O eq $_ } (qw( cygwin MSWin32 )); # This will apply to various OSes. Is there a "capable of doing unix # redirections" flag somewhere? # Attempt to get hold of the correct perl to run the examples. I # think we want $ENV{FULLPERLRUN} when running "make test", but that # doesn't filter down to us. $ENV{PERL5LIB} is set correctly though. my $perl = $^X || "perl"; # warn "running examples with \$perl='$perl'\n under \@INC=(@INC)\n with PERL5LIB=$ENV{PERL5LIB}\n"; foreach my $e (@examples) { if (defined $guru_checked{$e}) { # get program output my $runner = $e =~ /\.pm$/ ? './TestRunner.pl ' : ''; my $cmd = "$perl -I examples $runner$e 2>&1"; # warn "cmd $cmd\n"; my $out = `$cmd`; foreach ($out, $guru_checked{$e}) { # mess about with start & end newlines s/^\n+//; $_ .= "\n" unless /\n$/; # bin the naughty carriage returns s/\r//g; # we can't assume the order of tests will be the same s/^[.F]+\n?Suite teardown$/TEST-RUN-SUMMARY/sm; s/::Load[0-9_]+Anonymous[0-9_]+/::LOAD_ANONYMOUS_CLASSNAME/; # indent lines with '# ' so they're comments if the test fails s/\n/\n# /g; # hide things that look like CPU usage s{Time:\s+[\d\.]+\s+wallclock secs \([\d\s\.]+usr\s+\+[\d\s\.]+sys\s+=[\d\s\.]+CPU\)} {TIME-SUMMARY}g; } ok($out, $guru_checked{$e}); } else { skip( (exists $guru_checked{$e} ? "Skip $e: not yet checked" : 0), "nothing", "data at \$guru_checked{$e}"); } } Test-Unit-0.28/t/PaxHeader/all_tests.t000644 000765 000024 00000000152 07402737001 017773 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/t/all_tests.t000644 000765 000024 00000000367 07402737001 016032 0ustar00rjbsstaff000000 000000 #!/usr/bin/perl -w use strict; use Test::Unit::Debug qw(debug_pkgs); use Test::Unit::HarnessUnit; #debug_pkgs(qw{Test::Unit::Result}); use lib 't/tlib', 'tlib'; my $testrunner = Test::Unit::HarnessUnit->new(); $testrunner->start("AllTests"); Test-Unit-0.28/t/PaxHeader/assert.t000644 000765 000024 00000000152 07416643311 017307 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/t/assert.t000644 000765 000024 00000000452 07416643311 015341 0ustar00rjbsstaff000000 000000 #!/usr/bin/perl -w use strict; use Test::Unit::HarnessUnit; use Test::Unit::Debug qw(debug_pkgs); #debug_pkgs(qw/Test::Unit::Assert/); #debug_pkgs(qw/Test::Unit::Assertion::CodeRef/); use lib 't/tlib', 'tlib'; my $testrunner = Test::Unit::HarnessUnit->new(); $testrunner->start("AssertTest"); Test-Unit-0.28/t/tlib/PaxHeader/NoTestCaseClass.pm000644 000765 000024 00000000152 07374760234 022116 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/t/tlib/NoTestCaseClass.pm000644 000765 000024 00000000113 07374760234 020142 0ustar00rjbsstaff000000 000000 package NoTestCaseClass; use strict; sub new { } sub testSuccess { } 1; Test-Unit-0.28/t/tlib/PaxHeader/RunnerTest.pm000644 000765 000024 00000000152 07504374516 021230 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/t/tlib/RunnerTest.pm000644 000765 000024 00000005050 07504374516 017261 0ustar00rjbsstaff000000 000000 package RunnerTest; use strict; use Test::Unit::TestRunner; use base 'Test::Unit::TestCase'; sub set_up { my $self = shift; open(DEVNULL, '>/dev/null') or die "Couldn't open(>/dev/null): $!"; $self->{runner} = Test::Unit::TestRunner->new(\*DEVNULL); } sub tear_down { my $self = shift; close(DEVNULL); } sub test_reset_filtering { my $self = shift; $self->{runner}->filter('random_token'); $self->{runner}->reset_filter; $self->assert(! $self->{runner}->start('FilteredSuite'), "run wasn't supposed to succeed"); my $result = $self->{runner}->result; $self->assert_num_equals(4, $result->run_count); $self->assert_num_equals(3, $result->error_count); $self->assert_num_equals(0, $result->failure_count); } sub test_filter_via_method_list { my $self = shift; $self->{runner}->filter('token_filtering_via_method_list'); $self->assert(! $self->{runner}->start('FilteredSuite'), "run wasn't supposed to succeed"); my $result = $self->{runner}->result; $self->assert_num_equals(2, $result->run_count); $self->assert_num_equals(1, $result->error_count); $self->assert_num_equals(0, $result->failure_count); } sub test_filter_via_sub { my $self = shift; $self->{runner}->filter('token_filtering_via_sub'); $self->assert(! $self->{runner}->start('FilteredSuite'), "run wasn't supposed to succeed"); my $result = $self->{runner}->result; $self->assert_num_equals(3, $result->run_count); $self->assert_num_equals(2, $result->error_count); $self->assert_num_equals(0, $result->failure_count); } sub test_filter_via_both { my $self = shift; $self->{runner}->filter( 'token_filtering_via_method_list', 'token_filtering_via_sub', 'nonexistent_token', # this has to be allowed ); $self->assert($self->{runner}->start('FilteredSuite'), "run wasn't supposed to fail"); my $result = $self->{runner}->result; $self->assert_num_equals(1, $result->run_count); $self->assert_num_equals(0, $result->error_count); $self->assert_num_equals(0, $result->failure_count); } sub test_filter_broken_token { my $self = shift; $self->{runner}->filter('broken_token'); eval { $self->{runner}->start('FilteredSuite'); }; my $exception = $@; # have to save $@ otherwise the assertion messes it up $self->assert_str_equals( "Didn't understand filtering definition for token broken_token in FilteredSuite\n", $exception ); } 1; Test-Unit-0.28/t/tlib/PaxHeader/AssertTest.pm000644 000765 000024 00000000207 15113572610 021207 xustar00rjbsstaff000000 000000 29 mtime=1764685192.32372216 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/t/tlib/AssertTest.pm000644 000765 000024 00000052060 15113572610 017242 0ustar00rjbsstaff000000 000000 package AssertTest; use strict; use ExceptionChecker; use TestObject; use Test::Unit::TestCase; use Test::Unit::Failure; use Test::Unit::Error; use Error qw/:try/; use Class::Inner; use vars qw/@ISA/; @ISA = qw(Test::Unit::TestCase ExceptionChecker); sub test_assert_equals { my $self = shift; my $o = TestObject->new(); $self->assert_equals($o, $o); $self->check_failures ("expected 'start o:MyClass=HASH(0x1404343f0) | any o:MyClass=HASH(0x1404343f0) e:start | any o:MyClass=HASH(0x1404343f0) e:in', got 'start o: e: | any o:start e: | any o:in e:'" => # A false-negative that burned me; problem with is_numeric # Test must be all on one line [ __LINE__, sub { shift->assert_equals("start o:MyClass=HASH(0x1404343f0) | any o:MyClass=HASH(0x1404343f0) e:start | any o:MyClass=HASH(0x1404343f0) e:in", "start o: e: | any o:start e: | any o:in e:"); } ], ); } # ...and the root of that problem in test_assert_equals sub test_numericness { my $self = shift; my %tests = ( 1 => 't', 0 => 't', '15e7' => 't', '15E7' => 't', "not 0" => 'f', "not 4" => 'f', " \n 5E2" => 't', " \t 0E0 " => 't', ); foreach my $str (keys %tests) { my $expect = $tests{$str}; my $actual = Test::Unit::Assert::is_numeric($str) ? 't' : 'f'; $self->fail("For string '$str', expect $expect but got $actual") unless $expect eq $actual; } if ($] gt '5.029001' && $] lt '5.031004') { # https://github.com/Perl/perl5/issues/17062 # skipping test, broken around v5.30 because of bug in perl } else { my $actual = Test::Unit::Assert::is_numeric('0xF00') ? 't' : 'f'; $self->fail("For string '0xF00', expect f but got $actual") unless 'f' eq $actual; } } sub test_assert { my $self = shift; $self->assert(1); $self->assert(1, 'should be true'); $self->assert(qr/foo/, 'foobar'); $self->assert(qr/foo/, 'foobar', 'should match /foo/'); my $coderef = sub { $_[0] eq $_[1] or $self->fail("$_[0] ne $_[1]"); }; $self->assert($coderef, 'a', 'a'); $self->assert([]); $self->assert([ 'foo', 7 ]); my $qr_string = "" . qr/foo/; # for use in tests below $self->check_failures( 'Boolean assertion failed' => [ __LINE__, sub { shift->assert(undef) } ], 'Boolean assertion failed' => [ __LINE__, sub { shift->assert(0) } ], 'Boolean assertion failed' => [ __LINE__, sub { shift->assert('') } ], 'bang' => [ __LINE__, sub { shift->assert(0, 'bang') } ], 'bang' => [ __LINE__, sub { shift->assert('', 'bang') } ], "'qux' did not match /$qr_string/" => [ __LINE__, sub { shift->assert(qr/foo/, 'qux') } ], 'bang' => [ __LINE__, sub { shift->assert(qr/foo/, 'qux', 'bang') } ], 'a ne b'=> [ __LINE__, sub { shift->assert($coderef, 'a', 'b') } ], ); } sub test_assert_str_equals { my $self = shift; my @pass = ( ['', ''], [0, 0], [1, 1], ['foo', 'foo'], ); foreach my $pair (@pass) { my ($expected, $got) = @$pair; $self->assert_str_equals($expected, $got); $self->assert_str_equals($expected, $got, 'failure message'); } $self->check_failures( 'expected value was undef; should be using assert_null?' => [ __LINE__, sub { shift->assert_str_equals(undef, undef) } ], 'expected value was undef; should be using assert_null?' => [ __LINE__, sub { shift->assert_str_equals(undef, 0) } ], 'expected value was undef; should be using assert_null?' => [ __LINE__, sub { shift->assert_str_equals(undef, '') } ], 'expected value was undef; should be using assert_null?' => [ __LINE__, sub { shift->assert_str_equals(undef, 'foo') } ], "expected '', got undef" => [ __LINE__, sub { shift->assert_str_equals('', undef) } ], "expected 'foo', got undef" => [ __LINE__, sub { shift->assert_str_equals('foo', undef) } ], "expected '', got '0'" => [ __LINE__, sub { shift->assert_str_equals('', 0) } ], "expected '0', got ''" => [ __LINE__, sub { shift->assert_str_equals(0, '') } ], "expected '0', got undef" => [ __LINE__, sub { shift->assert_str_equals(0, undef) } ], "expected '0', got '1'" => [ __LINE__, sub { shift->assert_str_equals(0, 1) } ], "expected '0', got '-0'" => [ __LINE__, sub { shift->assert_str_equals(0, '-0') } ], "expected '-0', got '0'" => [ __LINE__, sub { shift->assert_str_equals('-0', 0) } ], "expected 'foo', got 'bar'" => [ __LINE__, sub { shift->assert_str_equals('foo', 'bar') } ], ); } sub test_multi_assert { my $self = shift; my $assertion = sub { $_[0] =~ /1/ or Test::Unit::Failure->throw(-text => "first arg missing 1"); $_[1] eq 'cluck' or Test::Unit::Failure->throw(-text => "what? no chickens!?"); }; $self->multi_assert( $assertion, [ 1, 'cluck' ], [ 'el1te', 'cluck' ], ); $self->check_failures( 'first arg missing 1' => [ __LINE__, sub { shift->multi_assert($assertion, [ 2, 'cluck' ]) } ], 'what? no chickens!?' => [ __LINE__, sub { shift->multi_assert($assertion, [ 1, 'cluck' ], [ 1, 'moo' ]) } ], ); } sub test_assert_matches { my $self = shift; $self->assert_matches(qr/ob/i, 'fooBar'); $self->check_errors( 'arg 1 to assert_matches() must be a regexp' => [ __LINE__, sub { shift->assert_matches(1, 2) } ] ); } sub test_assert_does_not_match { my $self = shift; $self->assert_does_not_match(qr/ob/, 'fooBar'); $self->check_errors( 'arg 1 to assert_does_not_match() must be a regexp' => [ __LINE__, sub { shift->assert_does_not_match(1, 2) } ] ); } sub test_assert_equals_null { my $self = shift; $self->assert_equals(undef, undef); } # sub assertion_has_failed { # my $error = shift; # return eval {ref($error) && $error->isa('Test::Unit::Failure')}; # } # Not sure this has meaning in Perl # sub test_assert_null_not_equals_null { # my $self = shift; # eval { $self->assert_equals(undef, TestObject->new()) }; # $self->fail unless assertion_has_failed($@); # } @AssertTest::Exception::ISA = 'Error'; sub test_assert_raises { my $self = shift; $self->assert_raises( 'AssertTest::Exception', sub { AssertTest::Exception->throw(-text => 'boom'); } ); $self->assert_str_equals('boom', AssertTest::Exception->prior->{-text}); $self->assert_raises( 'Error::Simple', sub { die "bang"; } ); $self->assert_str_equals('bang', AssertTest::Exception->prior->{-text}); $self->check_failures( 'No AssertTest::Exception was raised' => [ __LINE__ + 1, sub { shift->assert_raises('AssertTest::Exception', sub {}) } ], 'zxc' => [ __LINE__ + 1, sub { shift->assert_raises('AssertTest::Exception', sub {}, 'zxc') } ], ); } sub test_ok_boolean { my $self = shift; $self->ok(1); $self->check_failures( 'Boolean assertion failed' => [ __LINE__, sub { shift->ok(0) } ], 'Boolean assertion failed' => [ __LINE__, sub { shift->ok('') } ], 'Boolean assertion failed' => [ __LINE__, sub { shift->ok(undef) } ], ); } sub test_ok_bad_args { my $self = shift; $self->check_errors( 'ok() called with wrong number of args' => [ __LINE__, sub { shift->ok() } ], 'ok() called with wrong number of args' => [ __LINE__, sub { shift->ok(1, 2, 3, 4) } ], ); } sub test_ok_equals { my $self = shift; foreach my $args ([0, 0], [2, 2], [1.34, 1.34], ['foo', 'foo'], ['', ''], [undef, undef], [sub {2+2}, 4], ['fixed', qr/x/]) { $self->ok(@$args); $self->ok(@$args, 'comment'); } } sub test_ok_not_equals { my $self = shift; my $adder = sub { 2+2 }; my $qr_string = "" . qr/x/; # To interpolate below in @checks my @checks = ( # interface is ok(GOT, EXPECTED); q{expected 1, got 0} => [ 0, 1 ], q{expected 0, got 1} => [ 1, 0 ], q{expected 3, got 2} => [ 2, 3 ], q{expected -57.001, got -57} => [ -57, -57.001 ], q{expected 'bar', got 'foo'} => [ 'foo', 'bar' ], q{expected '', got 'foo'} => [ 'foo', '' ], q{expected 'foo', got ''} => [ '', 'foo' ], q{expected 5, got 4} => [ $adder, 5 ], qq{'foo' did not match /$qr_string/} => [ 'foo', qr/x/ ], ); my @tests = (); while (@checks) { my $expected = shift @checks; my $args = shift @checks; push @tests, $expected => [ __LINE__, sub { shift->ok(@$args) } ]; push @tests, 'failure comment' => [ __LINE__, sub { shift->ok(@$args, 'failure comment') } ]; } $self->check_failures(@tests); } sub test_fail { my $self = shift; $self->check_failures( '' => [ __LINE__, sub { shift->fail() } ], 'failure message' => [ __LINE__, sub { shift->fail('failure message') } ], ); } sub test_succeed_assert_null { my $self = shift; $self->assert_null(undef); } sub test_fail_assert_null { my $self = shift; $self->check_failures( 'Defined is defined' => [ __LINE__, sub { shift->assert_null('Defined') } ], 'Weirdness' => [ __LINE__, sub { shift->assert_null('Defined', 'Weirdness') } ], ); } sub test_success_assert_not_equals { my $self = shift; $self->assert_not_equals(1, 0); $self->assert_not_equals(0, 1); $self->assert_not_equals(0, 1E10); $self->assert_not_equals(1E10, 0); $self->assert_not_equals(1, 2); $self->assert_not_equals('string', 1); $self->assert_not_equals(1, 'string'); $self->assert_not_equals('string', 0); # $self->assert_not_equals(0,'string'); # Numeric comparison done here.. # $self->assert_not_equals(0, ''); # Numeric comparison done here.. $self->assert_not_equals('', 0); $self->assert_not_equals(undef, 0); $self->assert_not_equals(0, undef); # $self->assert_not_equals(0, ''); FIXME $self->assert_not_equals(undef, ''); $self->assert_not_equals('', undef); } sub test_fail_assert_not_equals { my $self = shift; my @pairs = ( # Some of these are debatable, but at least including the tests # will alert us if any of the outcomes change. "0 and 0 should differ" => [ 0, 0 ], "0 and 0 should differ" => [ 0, '0' ], "0 and 0 should differ" => [ '0', 0 ], "0 and 0 should differ" => [ '0', '0' ], "1 and 1 should differ" => [ 1, 1 ], "1 and 1 should differ" => [ 1, '1' ], "1 and 1 should differ" => [ '1', 1 ], "1 and 1 should differ" => [ '1', '1' ], "0 and should differ" => [ 0, '' ], # Numeric comparison "0 and string should differ" => [ 0, 'string' ], # Numeric comparison "'' and '' should differ" => [ '', '' ], "both args were undefined" => [ undef, undef ], ); my @tests = (); while (@pairs) { my $expected = shift @pairs; my $pair = shift @pairs; push @tests, $expected => [ __LINE__, sub { shift->assert_not_equals(@$pair) } ]; push @tests, "$expected with comment", => [ __LINE__, sub { shift->assert_not_equals(@$pair, "$expected with comment") } ]; } $self->check_failures(@tests); } sub test_fail_assert_not_null { my $self = shift; $self->check_failures( ' unexpected' => [ __LINE__, sub { shift->assert_not_null(undef) } ], ' unexpected' => [ __LINE__, sub { shift->assert_not_null() } ], # nb. $self->assert_not_null(@emptylist, "message") is not # going to do what you expected! 'Weirdness' => [ __LINE__, sub { shift->assert_not_null(undef, 'Weirdness') } ] ); } sub test_succeed_assert_not_null { my $self = shift; $self->assert_not_null(TestObject->new); $self->assert_not_null(''); $self->assert_not_null('undef'); $self->assert_not_null(0); $self->assert_not_null(10); } sub test_assert_deep_equals { my $self = shift; $self->assert_deep_equals([], []); $self->assert_deep_equals({}, {}); $self->assert_deep_equals([ 0, 3, 5 ], [ 0, 3, 5 ]); my $hashref = { a => 2, b => 4 }; $self->assert_deep_equals($hashref, $hashref); $self->assert_deep_equals($hashref, { b => 4, a => 2 }); my $complex = { array => [ 1, $hashref, 3 ], undefined => undef, number => 3.2, string => 'hi mom', deeper => { and => [ even => [ qw(deeper wahhhhh) ], { foo => 11, bar => 12 } ], }, }; $self->assert_deep_equals( $complex, { array => [ 1, $hashref, 3 ], undefined => undef, number => 3.2, string => 'hi mom', deeper => { and => [ even => [ qw(deeper wahhhhh) ], { foo => 11, bar => 12 } ], }, }, ); my $differ = sub { my ($x, $y) = @_; qr/^Structures\ begin\ differing\ at: $ \n \S*\s* \$a .* = .* (?-x:$x) .* $ \n \S*\s* \$b .* = .* (?-x:$y)/mx; }; my %families; # key=test-purpose, value=assorted circular structures foreach my $key (qw(orig copy bad_copy)) { my %family = ( john => { name => 'John Doe', spouse => undef, children => [], }, jane => { name => 'Jane Doe', spouse => undef, children => [], }, baby => { name => 'Baby Doll', # spouse => undef, children => [], }, ); $family{john}{spouse} = $family{jane}; $family{jane}{spouse} = $family{john}; push @{$family{john}{children}}, $family{baby}; push @{$family{jane}{children}}, $family{baby}; $families{$key} = \%family; } $families{bad_copy}->{jane}{spouse} = $families{bad_copy}->{baby}; # was ->{john} # Breakage under test is infinite recursion, to memory exhaustion! # Jump through hoops to avoid killing people's boxes { my $old_isa = \&UNIVERSAL::isa; # Pick on isa() because it'll be called from any deep-ing code local $^W = 0; local *UNIVERSAL::isa = sub { die "Giving up on deep recursion for assert_deep_equals" if defined caller(500); return $old_isa->(@_); }; $self->assert_deep_equals($families{orig}, $families{copy}); } my ($H, $H2, $G) = qw(hello hello goodbye); my @pairs = ( 'Both arguments were not references' => [ undef, 0 ], 'Both arguments were not references' => [ 0, undef ], 'Both arguments were not references' => [ 0, 1 ], 'Both arguments were not references' => [ 0, '' ], 'Both arguments were not references' => [ '', 0 ], $differ->(qw/'ARRAY 'HASH/) => [ [], {} ], $differ->(qw/'ARRAY 'HASH/) => [ [1,2], {1,2} ], $differ->( "'ARRAY", " undef" ) => [ { 'test' => []}, { 'test' => undef } ], $differ->( "'ARRAY", 'not exist' ) => [ { 'test' => []}, {} ], $differ->( 'undef', "'ARRAY" ) => [ { 'test' => undef }, { 'test' => []} ], $differ->( "''", " undef" ) => [ [ '' ], [ undef ] ], $differ->( "'undef'", " undef" ) => [ [ 'undef' ], [ undef ] ], $differ->('not exist', "'3'") => [ [1,2], [1,2,3] ], $differ->("'3'", "not exist") => [ [1,2,3], [1,2] ], $differ->("'wahhhhh'", "'wahhhh'") => [ $complex, { array => [ 1, $hashref, 3 ], undefined => undef, number => 3.2, string => 'hi mom', deeper => { and => [ even => [ qw(deeper wahhhh) ], { foo => 11, bar => 12 } ], }, } ], $differ->( 'HASH', 'not exist') => [$families{orig}, $families{bad_copy}], # test may be fragile due to recursion ordering? $differ->("'3'", "'5'") => [ [ \$H, 3 ], [ \$H2, 5 ] ], $differ->("'hello'", "'goodbye'") => [ { world => \$H }, { world => \$G } ], $differ->("'hello'", "'goodbye'") => [ [ \$H, "world" ], [ \$G, "world" ] ], ); my @tests = (); while (@pairs) { my $expected = shift @pairs; my $pair = shift @pairs; push @tests, $expected, [ __LINE__, sub { shift->assert_deep_equals(@$pair) } ]; push @tests, "$expected with comment", [ __LINE__, sub { shift->assert_deep_equals(@$pair, "$expected with comment") } ]; } $self->check_failures(@tests); } # Key = assert_method # Value = [[@arg_list],undef/expected exception] # FIXME: These should probably be merged with the tests for assert_not_equals() # somehow, since the failures aren't currently tested for the correct message # via check_exception(), or originating file/line via check_file_and_line(). my %test_hash = ( assert_equals => { success => [ { args => [0,'foo'], name => "0 == 'foo'" }, { args => [1,'1.0'], name => "1 == '1.0'" }, { args => ['1.0', 1], name => "'1.0' == 1" }, { args => ['foo', 'foo'], name => 'foo eq foo' }, { args => ['0e0', 0], name => '0E0 == 0' }, { args => [0, 'foo'], name => "0 == 'foo'" }, { args => [undef, undef], name => "both undef" }, { args => [0, 0], name => "0 == 0" }, { args => [0, 0.0], name => "0 == 0.0" }, { args => [0.0, 0], name => "0.0 == 0" }, { args => [0.0, 0.0], name => "0.0 == 0.0" }, { args => ['', ''], name => "'' == ''" }, ], 'Test::Unit::Failure' => [ { args => [1,'foo'], name => "1 != 'foo'" }, { args => ['foo', 0], name => "'foo' ne 0" }, { args => ['foo', 1], name => "'foo' ne 1" }, { args => [0,1], name => "0 != 1" }, { args => ['foo', 'bar'], name => "'foo' ne 'bar'" }, { args => ['foo', undef], name => "'foo' ne undef" }, { args => [undef, 'foo'], name => "undef ne 'foo'" }, # { args => [0, ''], name => "0 ne ''" }, # numeric compare ], }, ); sub suite { my $self = shift; my $suite = Test::Unit::TestSuite->empty_new("Assertion Tests"); foreach my $test ($self->make_tests_from_matrix(\%test_hash)) { $suite->add_test($test); } foreach my $test ($self->list_tests) { no strict 'refs'; $suite->add_test($self->make_test_from_coderef(sub {my $self = shift; $self->$test(@_)},$test)); } return $suite; } sub make_tests_from_matrix { my $self = shift; my $matrix = shift; my @tests; foreach my $method_name (keys %$matrix) { # Build 'successful' tests. foreach my $spec (@{$matrix->{$method_name}{success}}) { push @tests, $self->make_test_from_coderef (sub { my $self = shift; $self->$method_name(@{$spec->{args}}); }, $spec->{name}); } foreach my $outcome (grep {$_ ne 'success'} keys %{$matrix->{$method_name}}) { foreach my $spec (@{$matrix->{$method_name}{$outcome}}) { push @tests, $self->make_test_from_coderef (sub { my $self = shift; try { $self->$method_name(@{$spec->{args}}); 0; } catch $outcome with { 1; } or Test::Unit::Failure->throw(-text => $spec->{name}, -object => $self); }, $spec->{name}); } } } return @tests; } 1; Test-Unit-0.28/t/tlib/PaxHeader/ExceptionChecker.pm000644 000765 000024 00000000210 15113572627 022333 xustar00rjbsstaff000000 000000 30 mtime=1764685207.263945027 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/t/tlib/ExceptionChecker.pm000644 000765 000024 00000005534 15113572627 020400 0ustar00rjbsstaff000000 000000 package ExceptionChecker; use strict; use warnings; use Test::Unit::Error; use Test::Unit::Failure; use Error qw(:try); sub check_failures { my $self = shift; $self->check_exceptions('Test::Unit::Failure', @_); } sub check_errors { my $self = shift; $self->check_exceptions('Test::Unit::Error', @_); } sub check_exceptions { my $self = shift; my ($exception_class, @tests) = @_; my ($asserter, $file, $line) = caller($Error::Depth + 1); # EVIL hack! Assumes check_exceptions # always called via check_{failures,errors}. # My brain hurts too much right now to think # of a better way. while (@tests) { my $expected = shift @tests; my $test_components = shift @tests; my ($test_code_line, $test) = @$test_components; my $exception; try { $self->$test(); } catch $exception_class with { $exception = shift; } catch Error::Simple with { $exception = shift; } otherwise { $exception = 0; }; try { $self->check_exception($exception_class, $expected, $exception); $self->check_file_and_line($exception, $file, $test_code_line); } catch Test::Unit::Failure with { my $failure = shift; $failure->throw_new( -package => $asserter, -file => $file, -line => $line, -object => $self ); } } } sub check_exception { my $self = shift; my ($exception_class, $expected, $exception) = @_; Test::Unit::Failure->throw( -text => "Didn't get $exception_class `$expected'", -object => $self, ) unless $exception; my $got = $exception->text(); Test::Unit::Failure->throw( -text => "Expected $exception_class `$expected', got `$got'", -object => $self, ) unless UNIVERSAL::isa($expected, 'Regexp') ? $got =~ /$expected/ : $got eq $expected; } sub check_file_and_line { my $self = shift; my ($exception, $expected_file, $test_code_line) = @_; if ($exception->file() ne $expected_file) { throw Test::Unit::Failure( -text => "failure's file() should have returned $expected_file" . " (line $test_code_line), not " . $exception->file(), -object => $self, ); } if ($exception->line() != $test_code_line) { throw Test::Unit::Failure( -text => "failure's line() should have returned " . "$test_code_line, not " . $exception->line(), -object => $self, ); } } 1; Test-Unit-0.28/t/tlib/PaxHeader/TestAssertionCodeRef.pm000644 000765 000024 00000000152 07374760234 023157 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/t/tlib/TestAssertionCodeRef.pm000644 000765 000024 00000000555 07374760234 021215 0ustar00rjbsstaff000000 000000 package TestAssertionCodeRef; use strict; use base qw(Test::Unit::TestCase); sub test_case_to_string { my $self = shift; $self->assert(sub { my $self = shift; $self->to_string eq shift; }, $self, "test_noy_to_string(" . ref($self) . ")"); } sub test_with_a_regex { my $self = shift; $self->assert(qr/foo/, 'foo'); $self->assert(qr/bar/, 'foo'); } 1; Test-Unit-0.28/t/tlib/PaxHeader/OverrideTestCase.pm000644 000765 000024 00000000152 07374760234 022333 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/t/tlib/OverrideTestCase.pm000644 000765 000024 00000000242 07374760234 020362 0ustar00rjbsstaff000000 000000 package OverrideTestCase; use strict; # Test class used in SuiteTest use base qw(OneTestCase); sub new { shift()->SUPER::new(@_); } sub test_case { } 1; Test-Unit-0.28/t/tlib/PaxHeader/FilteredSuite.pm000644 000765 000024 00000000152 07504364255 021666 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/t/tlib/FilteredSuite.pm000644 000765 000024 00000001404 07504364255 017716 0ustar00rjbsstaff000000 000000 package FilteredSuite; use base 'Test::Unit::TestCase'; sub filter {{ token_filtering_via_method_list => [ qw/test_filtered_method1 test_filtered_method2/ ], token_filtering_via_sub => sub { my ($method) = @_; return 1 if $method =~ /method3$/; }, broken_token => 'nonsense', }} sub test_filtered_method1 { my $self = shift; die "test_filtered_method1 should get filtered via method list"; } sub test_filtered_method2 { my $self = shift; die "test_filtered_method2 should get filtered via method list"; } sub test_filtered_method3 { my $self = shift; die "test_filtered_method3 should get filtered via sub"; } sub test_unfiltered_method1 { my $self = shift; $self->assert('trooooo'); } 1; Test-Unit-0.28/t/tlib/PaxHeader/BadSuite000755 000765 000024 00000000210 15113573111 020165 xustar00rjbsstaff000000 000000 30 mtime=1764685385.271213965 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/t/tlib/BadSuite/000755 000765 000024 00000000000 15113573111 016275 5ustar00rjbsstaff000000 000000 Test-Unit-0.28/t/tlib/PaxHeader/WasRun.pm000644 000765 000024 00000000152 07374760234 020337 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/t/tlib/WasRun.pm000644 000765 000024 00000000455 07374760234 016374 0ustar00rjbsstaff000000 000000 package WasRun; use strict; use base qw(Test::Unit::TestCase); sub new { my $self = shift()->SUPER::new(@_); $self->{_TornDown} = 0; return $self; } sub run_test { my $self = shift; $self->{_WasRun} = 1; } sub was_run { my $self = shift; return $self->{_WasRun}; } 1; Test-Unit-0.28/t/tlib/PaxHeader/NoTestCases.pm000644 000765 000024 00000000152 07374760234 021313 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/t/tlib/NoTestCases.pm000644 000765 000024 00000000420 07374760234 017340 0ustar00rjbsstaff000000 000000 package NoTestCases; use strict; use base qw(Test::Unit::TestCase); sub new { my $class = shift; my ($name) = @_; my $self = bless {}, $class; my $a_test_case = $self->SUPER::new($name); return bless $a_test_case, $class; } sub no_test_case { } 1; Test-Unit-0.28/t/tlib/PaxHeader/SuiteTest.pm000644 000765 000024 00000000152 07401526733 021044 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/t/tlib/SuiteTest.pm000644 000765 000024 00000012311 07401526733 017073 0ustar00rjbsstaff000000 000000 package SuiteTest; use strict; use base qw(Test::Unit::TestCase); use Test::Unit::Result; use Test::Unit::TestSuite; use TornDown; use WasRun; require Test::Unit::Assertion::CodeRef; my %method_hash = (runs => 'run_count', failures => 'failure_count', success => 'was_successful', errors => 'error_count',); sub new { my $self = shift()->SUPER::new(@_); $self->{_my_result} = undef; $self->{__default_assertion} = Test::Unit::Assertion::CodeRef->new(sub { my $arg_hash = shift; for (qw/runs failures errors/) { next unless exists $arg_hash->{$_}; my $method = $method_hash{$_}; my $expected = $arg_hash->{$_}; my $got = $self->result->$method(); $expected == $got or die "Expected $expected $_, got $got\n"; } if (exists $arg_hash->{'success'}) { my $method = $method_hash{'success'}; my $expected = $arg_hash->{'success'}; my $got = $self->result->$method(); $expected && $got || !$expected && !$got or die "Expected ", $expected ? 'success,' : 'failure,', ' got ', $got ? 'success.' : 'failure.', "\n"; } 1; }); return $self; } sub basic_assertion { my $self = shift; $self->{__default_assertion}->do_assertion(ref($_[0]) ? shift : {@_}); } sub result { my $self = shift; return $self->{_my_result}; } sub set_up { my $self = shift; $self->{_my_result} = Test::Unit::Result->new(); } sub suite { my $class = shift; my $suite = Test::Unit::TestSuite->empty_new("Suite Tests"); $suite->add_test(SuiteTest->new("test_no_test_case_class")); $suite->add_test(SuiteTest->new("test_no_test_cases")); $suite->add_test(SuiteTest->new("test_one_test_case")); $suite->add_test(SuiteTest->new("test_not_existing_test_case")); $suite->add_test(SuiteTest->new("test_inherited_tests")); $suite->add_test(SuiteTest->new("test_inherited_inherited_tests")); $suite->add_test(SuiteTest->new("test_shadowed_tests")); $suite->add_test(SuiteTest->new("test_complex_inheritance")); return $suite; } # test subs sub test_inherited_tests { my $self = shift; my $suite = Test::Unit::TestSuite->new("InheritedTestCase"); $suite->run($self->result()); $self->basic_assertion({success => 1, runs => 2}); $self->assert($self->result()->was_successful()); $self->assert(2 == $self->result->run_count); } sub test_complex_inheritance { my $self = shift; eval q{ package _SuperClass; use base qw(Test::Unit::TestCase); sub test_case { my $self = shift; $self->assert($self->override_this_method ); } sub override_this_method { 0 ; } package _SubClass; use base qw(_SuperClass); sub override_this_method { 1 ; } }; die $@ if $@; my $suite = Test::Unit::TestSuite->new("_SubClass"); my $result = $self->result; $suite->run($result); $self->assert($result->was_successful()); $self->assert(1 == $self->result->run_count); } sub test_inherited_inherited_tests { my $self = shift; my $suite = Test::Unit::TestSuite->new("InheritedInheritedTestCase"); $suite->run($self->result()); $self->basic_assertion(success => 1, runs => 3); $self->assert($self->result()->was_successful()); $self->assert(3 == $self->result()->run_count()); } sub test_no_test_case_class { my $self = shift; eval { my $suite = Test::Unit::TestSuite->new("NoTestCaseClass"); }; $self->assert_str_equals("Class NoTestCaseClass was not a test case or test suite.\n", "$@"); } sub test_no_test_cases { my $self = shift; my $t = Test::Unit::TestSuite->new("NoTestCases"); $t->run($self->result()); $self->basic_assertion(runs => 1, failures => 1, success => 0); $self->assert(1 == $self->result()->run_count()); # warning test $self->assert(1 == $self->result()->failure_count()); $self->assert(not $self->result()->was_successful()); } sub test_not_existing_test_case { my $self = shift; my $t = SuiteTest->new("not_existing_method"); $t->run($self->result()); $self->basic_assertion(runs => 1, failures => 1, errors => 0); $self->assert(1 == $self->result()->run_count()); $self->assert(1 == $self->result()->failure_count()); $self->assert(0 == $self->result()->error_count()); } sub test_one_test_case { my $self = shift; my $t = Test::Unit::TestSuite->new("OneTestCase"); $t->run($self->result()); $self->basic_assertion(runs => 1, failures => 0, errors => 0, success => 1); $self->assert(1 == $self->result()->run_count()); $self->assert(0 == $self->result()->failure_count()); $self->assert(0 == $self->result()->error_count()); $self->assert($self->result()->was_successful()); } sub test_shadowed_tests { my $self = shift; my $t = Test::Unit::TestSuite->new("OverrideTestCase"); $t->run($self->result()); $self->basic_assertion(runs => 1); $self->assert(1 == $self->result()->run_count()); } 1; Test-Unit-0.28/t/tlib/PaxHeader/ListenerTest.pm000644 000765 000024 00000000152 07402737001 021531 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/t/tlib/ListenerTest.pm000644 000765 000024 00000003736 07402737001 017573 0ustar00rjbsstaff000000 000000 package ListenerTest; # Test class used in SuiteTest use base qw(Test::Unit::TestCase Test::Unit::Listener); use Test::Unit::Result; sub new { my $self = shift()->SUPER::new(@_); $self->{_my_result} = 0; $self->{_my_start_count} = 0; $self->{_my_end_count} = 0; $self->{_my_failure_count} = 0; $self->{_my_error_count} = 0; return $self; } sub add_error { my $self = shift; my ($test, $t) = @_; $self->{_my_error_count}++; } sub add_failure { my $self = shift; my ($test, $t) = @_; $self->{_my_failure_count}++; } sub end_test { my $self = shift; my ($test) = @_; $self->{_my_end_count}++; } sub set_up { my $self = shift; $self->{_my_result} = Test::Unit::Result->new(); $self->{_my_result}->add_listener($self); $self->{_my_start_count} = 0; $self->{_my_end_count} = 0; $self->{_my_failure_count} = 0; } sub start_test { my $self = shift; $self->{_my_start_count}++; } sub add_pass { } # the tests sub make_dummy_testcase { my $self = shift; my $sub = pop; my $method_name = shift || 'run_test'; Class::Inner->new(parent => 'Test::Unit::TestCase', methods => { $method_name => $sub }, args => [ $method_name ]); } sub test_error { my $self = shift; my $test = $self->make_dummy_testcase(sub {die}); $test->run($self->{_my_result}); $self->assert(1 == $self->{_my_error_count}); $self->assert(1 == $self->{_my_end_count}); } sub test_failure { my $self = shift; my $test = $self->make_dummy_testcase(sub {shift->fail()}); $test->run($self->{_my_result}); $self->assert(1 == $self->{_my_failure_count}); $self->assert(1 == $self->{_my_end_count}); } sub test_start_stop { my $self = shift; my $test = $self->make_dummy_testcase(sub {}); $test->run($self->{_my_result}); $self->assert(1 == $self->{_my_start_count}); $self->assert(1 == $self->{_my_end_count}); } 1; Test-Unit-0.28/t/tlib/PaxHeader/OneTestCase.pm000644 000765 000024 00000000152 07374760234 021275 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/t/tlib/OneTestCase.pm000644 000765 000024 00000000260 07374760234 017324 0ustar00rjbsstaff000000 000000 package OneTestCase; # Test class used in SuiteTest use base qw(Test::Unit::TestCase); sub new { shift()->SUPER::new(@_); } sub no_test_case { } sub test_case { } 1; Test-Unit-0.28/t/tlib/PaxHeader/InheritedSuite000755 000765 000024 00000000210 15113573111 021412 xustar00rjbsstaff000000 000000 30 mtime=1764685385.274836252 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/t/tlib/InheritedSuite/000755 000765 000024 00000000000 15113573111 017522 5ustar00rjbsstaff000000 000000 Test-Unit-0.28/t/tlib/PaxHeader/Success.pm000644 000765 000024 00000000152 07401233023 020506 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/t/tlib/Success.pm000644 000765 000024 00000000220 07401233023 016531 0ustar00rjbsstaff000000 000000 package Success; use strict; use warnings; use base 'Test::Unit::TestCase'; sub test_success { my $self = shift; $self->assert(1); } 1; Test-Unit-0.28/t/tlib/PaxHeader/InheritedTestCase.pm000644 000765 000024 00000000152 07374760234 022467 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/t/tlib/InheritedTestCase.pm000644 000765 000024 00000000223 07374760234 020515 0ustar00rjbsstaff000000 000000 package InheritedTestCase; # Test class used in SuiteTest use base qw(OneTestCase); sub new { shift()->SUPER::new(@_); } sub test2 { } 1; Test-Unit-0.28/t/tlib/PaxHeader/InheritedInheritedTestCase.pm000644 000765 000024 00000000152 07374760234 024323 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/t/tlib/InheritedInheritedTestCase.pm000644 000765 000024 00000000242 07374760234 022352 0ustar00rjbsstaff000000 000000 package InheritedInheritedTestCase; # Test class used in SuiteTest use base qw(InheritedTestCase); sub new { shift()->SUPER::new(@_); } sub test3 { } 1; Test-Unit-0.28/t/tlib/PaxHeader/TestObject.pm000644 000765 000024 00000000152 07427575205 021167 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/t/tlib/TestObject.pm000644 000765 000024 00000000141 07427575205 017214 0ustar00rjbsstaff000000 000000 package TestObject; use strict; sub new { my $class = shift; bless [@_], $class; } 1; Test-Unit-0.28/t/tlib/PaxHeader/WillDie.pm000644 000765 000024 00000000152 07427575205 020452 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/t/tlib/WillDie.pm000644 000765 000024 00000000652 07427575205 016506 0ustar00rjbsstaff000000 000000 package WillDie; use Error; use base qw(Test::Unit::TestCase ExceptionChecker); sub test_dies { my $self = shift; $self->check_errors( 'Died' => [ __LINE__, sub { die; } ], 'BANG' => [ __LINE__, sub { die "BANG"; } ], ); } sub test_throws_error_simple { my $self = shift; $self->check_errors( 'BANG!' => [ __LINE__, sub { Error::Simple->throw("BANG!"); } ], ); } 1; Test-Unit-0.28/t/tlib/PaxHeader/TornDown.pm000644 000765 000024 00000000152 07374760234 020672 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/t/tlib/TornDown.pm000644 000765 000024 00000000603 07374760234 016722 0ustar00rjbsstaff000000 000000 package TornDown; use base qw(Test::Unit::TestCase); sub new { my $self = shift()->SUPER::new(@_); $self->{_TornDown} = 0; return $self; } sub tear_down { my $self = shift; $self->{_TornDown} = 1; } sub torn_down { my $self = shift; return $self->{_TornDown}; } sub run_test { my $self = shift; my $e = new Test::Unit::Error(); die $e; } 1; Test-Unit-0.28/t/tlib/PaxHeader/TestTest.pm000644 000765 000024 00000000152 07502136573 020673 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/t/tlib/TestTest.pm000644 000765 000024 00000016714 07502136573 016735 0ustar00rjbsstaff000000 000000 package TestTest; use strict; use base qw(Test::Unit::TestCase); use TornDown; use WasRun; use Test::Unit::Error; use Test::Unit::Failure; use Class::Inner; use Error qw/:try/; sub verify_error { my $self = shift; my ($test) = @_; my $result = $test->run(); $self->assert_num_equals(1, $result->run_count()); $self->assert_num_equals(0, $result->failure_count()); $self->assert_num_equals(1, $result->error_count()); $self->assert(! $result->was_successful()); } sub verify_failure { my $self = shift; my ($test) = @_; my $result = $test->run(); $self->assert_num_equals(1, $result->run_count()); $self->assert_num_equals(1, $result->failure_count()); $self->assert_num_equals(0, $result->error_count()); $self->assert(! $result->was_successful()); } sub verify_success { my $self = shift; my ($test) = @_; my $result = $test->run(); $self->assert_num_equals(1, $result->run_count()); $self->assert_num_equals(0, $result->failure_count()); $self->assert_num_equals(0, $result->error_count()); $self->assert($result->was_successful()); } # test subs sub make_dummy_testcase { my $self = shift; my $sub = pop; my $method_name = shift || 'run_test'; my $test_name = (caller(1))[3] . '_inner'; Class::Inner->new(parent => 'Test::Unit::TestCase', methods => { $method_name => $sub }, args => [ $test_name ]); } sub test_case_to_string { my $self = shift; $self->assert(qr"test_case_to_string\(TestTest\)", $self->to_string); $self->assert($self->to_string() eq "test_case_to_string(TestTest)"); } sub test_error { my $self = shift; my $error = $self->make_dummy_testcase( sub { Test::Unit::Error->throw(-object => $self); } ); $self->verify_error($error); } sub test_die { my $self = shift; my $fail = $self->make_dummy_testcase(sub { my $self = shift; die "died" }); $self->verify_error($fail); } sub test_fail { my $self = shift; my $fail = $self->make_dummy_testcase(sub { my $self = shift; fail() }); $self->verify_error($fail); } sub test_failure { my $self = shift; my $failure = $self->make_dummy_testcase( sub { my $self = shift; $self->assert(0); } ); $self->verify_failure($failure); } sub test_failure_exception { my $self = shift; try { $self->fail; } catch Test::Unit::Failure with { 1; } otherwise { $self->fail; } } sub test_run_and_tear_down_both_throw { my $self = shift; my $fails = Class::Inner->new( parent => 'TornDown', methods => { run_test => sub { throw Test::Unit::Error -object => $_[0]; }, tear_down => sub { my $self = shift; $self->SUPER; die "this tear_down dies"; }, }, args => [ 'test_run_and_tear_down_both_throw_inner' ], ); $self->verify_error($fails); $self->assert($fails->torn_down()); } sub test_run_and_tear_down_both_throw2 { my $self = shift; my $fails = Class::Inner->new( parent => 'TornDown', methods => { run_test => sub { die "this run_test dies"; }, tear_down => sub { my $self = shift; $self->SUPER; throw Test::Unit::Error -object => $_[0]; }, }, args => [ 'test_run_and_tear_down_both_throw2_inner' ], ); $self->verify_error($fails); $self->assert($fails->torn_down()); } sub test_runner_printing { my $self = shift; $self->assert("1.05" eq (1050 / 1000)); } sub test_setup_fails { my $self = shift; my $fails = Class::Inner->new( parent => 'Test::Unit::TestCase', methods => { set_up => sub { my $self = shift; throw Test::Unit::Error -object => $self; }, run_test => sub {}, }, args => [ 'test_setup_fails_inner' ], ); $self->verify_error($fails); } sub test_success { my $self = shift; my $success = $self->make_dummy_testcase(sub {shift->assert(1)}); $self->verify_success($success); } sub test_tear_down_after_error { my $self = shift; my $fails = Class::Inner->new( parent => 'TornDown', methods => { dummy => sub {} }, args => [ 'test_tear_down_after_error_inner' ], ); $self->verify_error($fails); $self->assert($fails->torn_down()); } sub test_tear_down_dies { my $self = shift; my $fails = Class::Inner->new( parent => 'Test::Unit::TestCase', methods => { tear_down => sub { die "this tear_down dies" }, run_test => {} }, args => [ 'test_tear_down_dies_inner' ], ); $self->verify_error($fails); } sub test_tear_down_fails { my $self = shift; my $fails = Class::Inner->new( parent => 'Test::Unit::TestCase', methods => { tear_down => sub { Test::Unit::Error->throw( -text => "this tear_down throws an Error" ); }, run_test => {} }, args => [ 'test_tear_down_fails_inner' ], ); $self->verify_error($fails); } sub test_set_up_dies_no_tear_down { my $self = shift; my $fails = Class::Inner->new( parent => 'TornDown', methods => { set_up => sub { die "this set_up dies" } }, args => [ 'test_set_up_dies_no_tear_down_inner' ], ); $self->verify_error($fails); $self->assert(! $fails->torn_down()); } sub test_set_up_throws_no_tear_down { my $self = shift; my $fails = Class::Inner->new( parent => 'TornDown', methods => { set_up => sub { Test::Unit::Error->throw( -text => "this set_up throws an Error" ); } }, args => [ 'test_set_up_throws_no_tear_down_inner' ], ); $self->verify_error($fails); $self->assert(! $fails->torn_down()); } sub test_was_not_successful { my $self = shift; my $failure = $self->make_dummy_testcase(sub { shift->fail }); $self->verify_failure($failure); } sub test_was_run { my $self = shift; my $test = WasRun->new("WasRun"); $test->run(); $self->assert($test->was_run()); } sub test_was_successful { my $self = shift; my $success = $self->make_dummy_testcase(sub { shift->assert(1) }); $self->verify_success($success); } sub test_assert_on_matching_regex { my $self = shift; my $matching_regex = $self->make_dummy_testcase (sub { my $self = shift; $self->assert(scalar('foo' =~ /foo/), 'foo matches foo (boolean)'); $self->assert(qr/foo/, 'foo', 'foo matches foo (Assertion::Regex)'); }); $self->verify_success($matching_regex); } sub test_assert_on_failing_regex { my $self = shift; my $matching_regex = $self->make_dummy_testcase (sub { my $self = shift; $self->assert(scalar("foo" =~ /bar/), "Should not have matched!"); $self->assert(qr/bar/, "foo"); }); $self->verify_failure($matching_regex); } sub test_assert_with_non_assertion_object { my $self = shift; my $obj = bless {}, 'NonExistentClass'; $self->assert($obj, "Object should eval to true"); } 1; Test-Unit-0.28/t/tlib/PaxHeader/ActiveTestTest.pm000644 000765 000024 00000000152 07401233023 022011 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/t/tlib/ActiveTestTest.pm000644 000765 000024 00000003415 07401233023 020045 0ustar00rjbsstaff000000 000000 package ActiveTestTest; use strict; use Test::Unit::TestCase (); use base 'Test::Unit::TestCase'; use Test::Unit::Result; use Test::Unit::TestSuite (); use Success; sub testActiveTest { my $self = shift; my $test = $self->create_active_test_suite; my $result = Test::Unit::Result->new; $test->run($result); $self->assert_equals(100, $result->run_count); $self->assert_equals(0, $result->failure_count); $self->assert_equals(0, $result->error_count); } # sub test_active_repeated_test { # my $self = shift; # my $test = Test::Unit::RepeatedTest($self->create_active_test_suite, 5); # my $result = Result->new; # $test->run($result); # $self->assert_equals(500, $result->run_count); # $self->assert_equals(0, $result->failure_count); # $self->assert_equals(0, $result->error_count); # } # sub test_active_repeated_test0 { # my $self = shift; # my $test = Test::Unit::RepeatedTest($self->create_active_test_suite, 0); # my $result = Result->new; # $test->run($result); # $self->assert_equals(0, $result->run_count); # $self->assert_equals(0, $result->failure_count); # $self->assert_equals(0, $result->error_count); # } # sub test_active_repeated_test1 { # my $self = shift; # my $test = Test::Unit::RepeatedTest($self->create_active_test_suite, 1); # my $result = Result->new; # $test->run($result); # $self->assert_equals(100, $result->run_count); # $self->assert_equals(0, $result->failure_count); # $self->assert_equals(0, $result->error_count); # } sub create_active_test_suite () { my $self = shift; my $suite = Test::Unit::TestSuite->new; for (1 .. 100) { $suite->add_test(Success->new("test_success")); } return $suite; } 1; Test-Unit-0.28/t/tlib/PaxHeader/AllTests.pm000644 000765 000024 00000000152 10273475542 020650 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/t/tlib/AllTests.pm000644 000765 000024 00000003712 10273475542 016704 0ustar00rjbsstaff000000 000000 package AllTests; use Test::Unit::TestSuite; use SuiteTest; use InheritedSuite::Simple; use InheritedSuite::TestNames; sub new { my $class = shift; return bless {}, $class; } sub suite { my $class = shift; my $suite = Test::Unit::TestSuite->empty_new("Framework Tests"); # We now add the various test cases and suites to this suite # in deliberately different ways, so as to implicitly test # the different interfaces by which one can add/construct tests. # Add test cases in 3 different ways. The first 3 extract all # test_* methods, and the last extracts only 1 method. $suite->add_test(Test::Unit::TestSuite->new('TestTest')); $suite->add_test('ListenerTest'); $suite->add_test('BadSuitesTest'); $suite->add_test('RunnerTest'); $suite->add_test('WillDie'); $suite->add_test(InheritedSuite::TestNames->new('test_names')); # Add test suites in 4 different ways. $suite->add_test(SuiteTest->suite()); $suite->add_test(InheritedSuite::Simple->new()); $suite->add_test('InheritedSuite::OverrideNew'); # $suite->add_test(Test::Unit::TestSuite->new('InheritedSuite::OverrideNewName')); return $suite; } 1; __END__ =head1 NAME AllTests - unit testing framework self tests =head1 SYNOPSIS # command line style use perl TestRunner.pl AllTests # GUI style use perl TkTestRunner.pl AllTests =head1 DESCRIPTION This class is used by the unit testing framework to encapsulate all the self tests of the framework. =head1 AUTHOR Copyright (c) 2000-2002, 2005 the PerlUnit Development Team (see L or the F file included in this distribution). All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO =over 4 =item * L =item * L =back =cut Test-Unit-0.28/t/tlib/PaxHeader/BadSuitesTest.pm000644 000765 000024 00000000152 07375231005 021631 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/t/tlib/BadSuitesTest.pm000644 000765 000024 00000001146 07375231005 017664 0ustar00rjbsstaff000000 000000 package BadSuitesTest; use strict; use Test::Unit::TestCase; use Test::Unit::TestRunner; use base 'Test::Unit::TestCase'; sub test_suite_with_syntax_error { my $self = shift; my $runner = Test::Unit::TestRunner->new(); eval { $runner->start('BadSuite::SyntaxError'); }; $self->assert(qr!^syntax error at .*/SyntaxError\.pm!, "$@"); } sub test_suite_with_bad_use { my $self = shift; my $runner = Test::Unit::TestRunner->new(); eval { $runner->start('BadSuite::BadUse'); }; $self->assert(qr!^Can't locate TestSuite/NonExistent\.pm in \@INC!, "$@"); } 1; Test-Unit-0.28/t/tlib/InheritedSuite/PaxHeader/TestNames.pm000644 000765 000024 00000000152 07401526733 023743 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/t/tlib/InheritedSuite/TestNames.pm000644 000765 000024 00000001357 07401526733 022002 0ustar00rjbsstaff000000 000000 package InheritedSuite::TestNames; # This class is probably overkill :-) use strict; use base 'Test::Unit::TestCase'; use InheritedSuite::Simple; use InheritedSuite::OverrideNew; use InheritedSuite::OverrideNewName; sub test_names { my $self = shift; my $simple = InheritedSuite::Simple->new(); $self->assert_str_equals('Simple inherited suite', $simple->name()); my $override_new = InheritedSuite::OverrideNew->new(); $self->assert_str_equals('Inherited suite overriding new()', $override_new->name()); my $override_new_name = InheritedSuite::OverrideNewName->new(); $self->assert_str_equals('Inherited suite overriding new() and name()', $override_new_name->name()); } 1; Test-Unit-0.28/t/tlib/InheritedSuite/PaxHeader/OverrideNew.pm000644 000765 000024 00000000152 07401526733 024271 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/t/tlib/InheritedSuite/OverrideNew.pm000644 000765 000024 00000000422 07401526733 022320 0ustar00rjbsstaff000000 000000 package InheritedSuite::OverrideNew; use strict; use base qw(Test::Unit::TestSuite); sub new { my $class = shift; my $self = $class->SUPER::empty_new('Inherited suite overriding new()'); $self->add_test(Test::Unit::TestSuite->new('Success')); return $self; } 1; Test-Unit-0.28/t/tlib/InheritedSuite/PaxHeader/OverrideNewName.pm000644 000765 000024 00000000152 07401526733 025072 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/t/tlib/InheritedSuite/OverrideNewName.pm000644 000765 000024 00000000460 07401526733 023123 0ustar00rjbsstaff000000 000000 package InheritedSuite::OverrideNewName; use strict; use base qw(Test::Unit::TestSuite); sub new { my $class = shift; my $self = $class->SUPER::empty_new(); $self->add_test(Test::Unit::TestSuite->new('Success')); return $self; } sub name { 'Inherited suite overriding new() and name()' } 1; Test-Unit-0.28/t/tlib/InheritedSuite/PaxHeader/Simple.pm000644 000765 000024 00000000152 07401526733 023271 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/t/tlib/InheritedSuite/Simple.pm000644 000765 000024 00000000265 07401526733 021325 0ustar00rjbsstaff000000 000000 package InheritedSuite::Simple; use strict; use base qw(Test::Unit::TestSuite); sub include_tests { 'Success' } sub name { 'Simple inherited suite' } 1; Test-Unit-0.28/t/tlib/BadSuite/PaxHeader/SyntaxError.pm000644 000765 000024 00000000152 07375231005 023106 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/t/tlib/BadSuite/SyntaxError.pm000644 000765 000024 00000000112 07375231005 021131 0ustar00rjbsstaff000000 000000 package BadSuite::SyntaxError; sub broken_method { my $self = } 1; Test-Unit-0.28/t/tlib/BadSuite/PaxHeader/BadUse.pm000644 000765 000024 00000000152 07375231005 021751 xustar00rjbsstaff000000 000000 57 LIBARCHIVE.xattr.com.apple.provenance=AQIAqPQzEp0BKlw 49 SCHILY.xattr.com.apple.provenance=3*\ Test-Unit-0.28/t/tlib/BadSuite/BadUse.pm000644 000765 000024 00000000073 07375231005 020002 0ustar00rjbsstaff000000 000000 package BadSuite::BadUse; use TestSuite::NonExistent; 1;