PageRenderTime 71ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/Test-Unit-Lite-0.1201/lib/Test/Unit/Lite.pm

#
Perl | 1240 lines | 1016 code | 215 blank | 9 comment | 35 complexity | 5dc52eb1e1a4846a8803930071af6121 MD5 | raw file
Possible License(s): AGPL-1.0
  1. #!/usr/bin/perl -c
  2. package Test::Unit::Lite;
  3. =head1 NAME
  4. Test::Unit::Lite - Unit testing without external dependencies
  5. =head1 SYNOPSIS
  6. Bundling the L<Test::Unit::Lite> as a part of package distribution:
  7. perl -MTest::Unit::Lite -e bundle
  8. Running all test units:
  9. perl -MTest::Unit::Lite -e all_tests
  10. Using as a replacement for Test::Unit:
  11. package FooBarTest;
  12. use Test::Unit::Lite; # unnecessary if module isn't directly used
  13. use base 'Test::Unit::TestCase';
  14. sub new {
  15. my $self = shift()->SUPER::new(@_);
  16. # your state for fixture here
  17. return $self;
  18. }
  19. sub set_up {
  20. # provide fixture
  21. }
  22. sub tear_down {
  23. # clean up after test
  24. }
  25. sub test_foo {
  26. my $self = shift;
  27. my $obj = ClassUnderTest->new(...);
  28. $self->assert_not_null($obj);
  29. $self->assert_equals('expected result', $obj->foo);
  30. $self->assert(qr/pattern/, $obj->foobar);
  31. }
  32. sub test_bar {
  33. # test the bar feature
  34. }
  35. =head1 DESCRIPTION
  36. This framework provides lighter version of L<Test::Unit> framework. It
  37. implements some of the L<Test::Unit> classes and methods needed to run test
  38. units. The L<Test::Unit::Lite> tries to be compatible with public API of
  39. L<Test::Unit>. It doesn't implement all classes and methods at 100% and only
  40. those necessary to run tests are available.
  41. The L<Test::Unit::Lite> can be distributed as a part of package distribution,
  42. so the package can be distributed without dependency on modules outside
  43. standard Perl distribution. The L<Test::Unit::Lite> is provided as a single
  44. file.
  45. =head2 Bundling the L<Test::Unit::Lite> as a part of package distribution
  46. The L<Test::Unit::Lite> framework can be bundled to the package distribution.
  47. Then the L<Test::Unit::Lite> module is copied to the F<inc> directory of the
  48. source directory for the package distribution.
  49. =cut
  50. use 5.006;
  51. use strict;
  52. use warnings;
  53. our $VERSION = '0.1201';
  54. use Carp ();
  55. use File::Spec ();
  56. use File::Basename ();
  57. use File::Copy ();
  58. use File::Path ();
  59. use Symbol ();
  60. # Can't use Exporter 'import'. Compatibility with Perl 5.6
  61. use Exporter ();
  62. BEGIN { *import = \&Exporter::import };
  63. our @EXPORT = qw{ bundle all_tests };
  64. # Copy this module to inc subdirectory of the source distribution
  65. sub bundle {
  66. -f 'Makefile.PL' or -f 'Build.PL'
  67. or die "Cannot find Makefile.PL or Build.PL in current directory\n";
  68. my $src = __FILE__;
  69. my $dst = "inc/Test/Unit/Lite.pm";
  70. my @src = split m"/", $src;
  71. my @dst = split m"/", $dst;
  72. my $srcfile = File::Spec->catfile(@src);
  73. my $dstfile = File::Spec->catfile(@dst);
  74. die "Cannot bundle to itself: $srcfile\n" if $srcfile eq $dstfile;
  75. print "Copying $srcfile -> $dstfile\n";
  76. my $dstdir = File::Basename::dirname($dstfile);
  77. -d $dstdir or File::Path::mkpath([$dstdir], 0, 0777 & ~umask);
  78. File::Copy::cp($srcfile, $dstfile) or die "Cannot copy $srcfile to $dstfile: $!\n";
  79. }
  80. sub all_tests {
  81. Test::Unit::TestRunner->new->start('Test::Unit::Lite::AllTests');
  82. }
  83. {
  84. package Test::Unit::TestCase;
  85. use Carp ();
  86. our $VERSION = $Test::Unit::Lite::VERSION;
  87. our %Seen_Refs = ();
  88. our @Data_Stack;
  89. my $DNE = bless [], 'Does::Not::Exist';
  90. sub new {
  91. my ($class) = @_;
  92. $class = ref $class if ref $class;
  93. my $self = {};
  94. return bless $self => $class;
  95. }
  96. sub set_up { }
  97. sub tear_down { }
  98. sub list_tests {
  99. my ($self) = @_;
  100. my $class = ref $self || $self;
  101. my @tests;
  102. my %seen_isa;
  103. my $list_base_tests;
  104. $list_base_tests = sub {
  105. my ($class) = @_;
  106. foreach my $isa (@{ *{ Symbol::qualify_to_ref("${class}::ISA") } }) {
  107. next unless $isa->isa(__PACKAGE__);
  108. $list_base_tests->($isa) unless $seen_isa{$isa};
  109. $seen_isa{$isa} = 1;
  110. push @tests, grep { /^test_/ } keys %{ *{ Symbol::qualify_to_ref("${class}::") } };
  111. };
  112. };
  113. $list_base_tests->($class);
  114. my %uniq_tests = map { $_ => 1 } @tests;
  115. @tests = sort keys %uniq_tests;
  116. return wantarray ? @tests : [ @tests ];
  117. }
  118. sub __croak {
  119. my ($default_message, $custom_message) = @_;
  120. $default_message = '' unless defined $default_message;
  121. $custom_message = '' unless defined $custom_message;
  122. my $n = 1;
  123. my ($file, $line) = (caller($n++))[1,2];
  124. my $caller;
  125. $n++ while (defined( $caller = caller($n) ) and not eval { $caller->isa('Test::Unit::TestSuite') });
  126. my $sub = (caller($n))[3] || '::';
  127. $sub =~ /^(.*)::([^:]*)$/;
  128. my ($test, $unit) = ($1, $2);
  129. my $message = "$file:$line - $test($unit)\n$default_message\n$custom_message";
  130. chomp $message;
  131. no warnings 'once';
  132. local $Carp::Internal{'Test::Unit::TestCase'} = 1;
  133. Carp::confess("$message\n");
  134. }
  135. sub fail {
  136. my ($self, $msg) = @_;
  137. $msg = '' unless defined $msg;
  138. __croak $msg;
  139. }
  140. sub assert {
  141. my $self = shift;
  142. my $arg1 = shift;
  143. if (ref $arg1 eq 'Regexp') {
  144. my $arg2 = shift;
  145. my $msg = shift;
  146. __croak "'$arg2' did not match /$arg1/", $msg unless $arg2 =~ $arg1;
  147. }
  148. else {
  149. my $msg = shift;
  150. __croak "Boolean assertion failed", $msg unless $arg1;
  151. }
  152. }
  153. sub assert_null {
  154. my ($self, $arg, $msg) = @_;
  155. __croak "$arg is defined", $msg unless not defined $arg;
  156. }
  157. sub assert_not_null {
  158. my ($self, $arg, $msg) = @_;
  159. __croak "<undef> unexpected", $msg unless defined $arg;
  160. }
  161. sub assert_equals {
  162. my ($self, $arg1, $arg2, $msg) = @_;
  163. if (not defined $arg1 and not defined $arg2) {
  164. return;
  165. }
  166. __croak "expected value was undef; should be using assert_null?", $msg unless defined $arg1;
  167. __croak "expected '$arg1', got undef", $msg unless defined $arg2;
  168. if ($arg1 =~ /^[+-]?(\d+\.\d+|\d+\.|\.\d+|\d+)([eE][+-]?\d+)?$/ and
  169. $arg2 =~ /^[+-]?(\d+\.\d+|\d+\.|\.\d+|\d+)([eE][+-]?\d+)?$/)
  170. {
  171. local $^W;
  172. __croak "expected $arg1, got $arg2", $msg unless $arg1 == $arg2;
  173. }
  174. else {
  175. __croak "expected '$arg1', got '$arg2'", $msg unless $arg1 eq $arg2;
  176. }
  177. }
  178. sub assert_not_equals {
  179. my ($self, $arg1, $arg2, $msg) = @_;
  180. if (not defined $arg1 and not defined $arg2) {
  181. __croak "both args were undefined", $msg;
  182. }
  183. if (not defined $arg1 xor not defined $arg2) {
  184. # pass
  185. }
  186. elsif ($arg1 =~ /^[+-]?(\d+\.\d+|\d+\.|\.\d+|\d+)([eE][+-]?\d+)?$/ and
  187. $arg2 =~ /^[+-]?(\d+\.\d+|\d+\.|\.\d+|\d+)([eE][+-]?\d+)?$/)
  188. {
  189. local $^W;
  190. __croak "$arg1 and $arg2 should differ", $msg unless $arg1 != $arg2;
  191. }
  192. else {
  193. __croak "'$arg1' and '$arg2' should differ", $msg unless $arg1 ne $arg2;
  194. }
  195. }
  196. sub assert_num_equals {
  197. my ($self, $arg1, $arg2, $msg) = @_;
  198. __croak "expected value was undef; should be using assert_null?", $msg unless defined $arg1;
  199. __croak "expected '$arg1', got undef", $msg unless defined $arg2;
  200. no warnings 'numeric';
  201. __croak "expected $arg1, got $arg2", $msg unless $arg1 == $arg2;
  202. }
  203. sub assert_num_not_equals {
  204. my ($self, $arg1, $arg2, $msg) = @_;
  205. __croak "expected value was undef; should be using assert_null?", $msg unless defined $arg1;
  206. __croak "expected '$arg1', got undef", $msg unless defined $arg2;
  207. no warnings 'numeric';
  208. __croak "$arg1 and $arg2 should differ", $msg unless $arg1 != $arg2;
  209. }
  210. sub assert_str_equals {
  211. my ($self, $arg1, $arg2, $msg) = @_;
  212. __croak "expected value was undef; should be using assert_null?", $msg unless defined $arg1;
  213. __croak "expected '$arg1', got undef", $msg unless defined $arg2;
  214. __croak "expected '$arg1', got '$arg2'", $msg unless "$arg1" eq "$arg2";
  215. }
  216. sub assert_str_not_equals {
  217. my ($self, $arg1, $arg2, $msg) = @_;
  218. __croak "expected value was undef; should be using assert_null?", $msg unless defined $arg1;
  219. __croak "expected '$arg1', got undef", $msg unless defined $arg2;
  220. __croak "'$arg1' and '$arg2' should differ", $msg unless "$arg1" ne "$arg2";
  221. }
  222. sub assert_matches {
  223. my ($self, $arg1, $arg2, $msg) = @_;
  224. __croak "arg 1 to assert_matches() must be a regexp", $msg unless ref $arg1 eq 'Regexp';
  225. __croak "expected '$arg1', got undef", $msg unless defined $arg2;
  226. __croak "$arg2 didn't match /$arg1/", $msg unless $arg2 =~ $arg1;
  227. }
  228. sub assert_does_not_match {
  229. my ($self, $arg1, $arg2, $msg) = @_;
  230. __croak "arg 1 to assert_does_not_match() must be a regexp", $msg unless ref $arg1 eq 'Regexp';
  231. __croak "expected '$arg1', got undef", $msg unless defined $arg2;
  232. __croak "$arg2 matched /$arg1/", $msg unless $arg2 !~ $arg1;
  233. }
  234. sub assert_deep_equals {
  235. my ($self, $arg1, $arg2, $msg) = @_;
  236. __croak 'Both arguments were not references', $msg unless ref $arg1 and ref $arg2;
  237. local @Data_Stack = ();
  238. local %Seen_Refs = ();
  239. __croak $self->_format_stack(@Data_Stack), $msg unless $self->_deep_check($arg1, $arg2);
  240. }
  241. sub assert_deep_not_equals {
  242. my ($self, $arg1, $arg2, $msg) = @_;
  243. __croak 'Both arguments were not references', $msg unless ref $arg1 and ref $arg2;
  244. local @Data_Stack = ();
  245. local %Seen_Refs = ();
  246. __croak $self->_format_stack(@Data_Stack), $msg if $self->_deep_check($arg1, $arg2);
  247. }
  248. sub _deep_check {
  249. my $self = shift;
  250. my ($e1, $e2) = @_;
  251. if ( ! defined $e1 || ! defined $e2 ) {
  252. return 1 if !defined $e1 && !defined $e2;
  253. push @Data_Stack, { vals => [$e1, $e2] };
  254. return 0;
  255. }
  256. return 1 if $e1 eq $e2;
  257. if ( ref $e1 && ref $e2 ) {
  258. my $e2_ref = "$e2";
  259. return 1 if defined $Seen_Refs{$e1} && $Seen_Refs{$e1} eq $e2_ref;
  260. $Seen_Refs{$e1} = $e2_ref;
  261. }
  262. if (ref $e1 eq 'ARRAY' and ref $e2 eq 'ARRAY') {
  263. return $self->_eq_array($e1, $e2);
  264. }
  265. elsif (ref $e1 eq 'HASH' and ref $e2 eq 'HASH') {
  266. return $self->_eq_hash($e1, $e2);
  267. }
  268. elsif (ref $e1 eq 'REF' and ref $e2 eq 'REF') {
  269. push @Data_Stack, { type => 'REF', vals => [$e1, $e2] };
  270. my $ok = $self->_deep_check($$e1, $$e2);
  271. pop @Data_Stack if $ok;
  272. return $ok;
  273. }
  274. elsif (ref $e1 eq 'SCALAR' and ref $e2 eq 'SCALAR') {
  275. push @Data_Stack, { type => 'REF', vals => [$e1, $e2] };
  276. return $self->_deep_check($$e1, $$e2);
  277. }
  278. else {
  279. push @Data_Stack, { vals => [$e1, $e2] };
  280. return 0;
  281. }
  282. }
  283. sub _eq_array {
  284. my $self = shift;
  285. my($a1, $a2) = @_;
  286. return 1 if $a1 eq $a2;
  287. my $ok = 1;
  288. my $max = $#$a1 > $#$a2 ? $#$a1 : $#$a2;
  289. for (0..$max) {
  290. my $e1 = $_ > $#$a1 ? $DNE : $a1->[$_];
  291. my $e2 = $_ > $#$a2 ? $DNE : $a2->[$_];
  292. push @Data_Stack, { type => 'ARRAY', idx => $_, vals => [$e1, $e2] };
  293. $ok = $self->_deep_check($e1,$e2);
  294. pop @Data_Stack if $ok;
  295. last unless $ok;
  296. }
  297. return $ok;
  298. }
  299. sub _eq_hash {
  300. my $self = shift;
  301. my($a1, $a2) = @_;
  302. return 1 if $a1 eq $a2;
  303. my $ok = 1;
  304. my $bigger = keys %$a1 > keys %$a2 ? $a1 : $a2;
  305. foreach my $k (keys %$bigger) {
  306. my $e1 = exists $a1->{$k} ? $a1->{$k} : $DNE;
  307. my $e2 = exists $a2->{$k} ? $a2->{$k} : $DNE;
  308. push @Data_Stack, { type => 'HASH', idx => $k, vals => [$e1, $e2] };
  309. $ok = $self->_deep_check($e1, $e2);
  310. pop @Data_Stack if $ok;
  311. last unless $ok;
  312. }
  313. return $ok;
  314. }
  315. sub _format_stack {
  316. my $self = shift;
  317. my @Stack = @_;
  318. my $var = '$FOO';
  319. my $did_arrow = 0;
  320. foreach my $entry (@Stack) {
  321. my $type = $entry->{type} || '';
  322. my $idx = $entry->{'idx'};
  323. if( $type eq 'HASH' ) {
  324. $var .= "->" unless $did_arrow++;
  325. $var .= "{$idx}";
  326. }
  327. elsif( $type eq 'ARRAY' ) {
  328. $var .= "->" unless $did_arrow++;
  329. $var .= "[$idx]";
  330. }
  331. elsif( $type eq 'REF' ) {
  332. $var = "\${$var}";
  333. }
  334. }
  335. my @vals = @{$Stack[-1]{vals}}[0,1];
  336. my @vars = ();
  337. ($vars[0] = $var) =~ s/\$FOO/ \$a/;
  338. ($vars[1] = $var) =~ s/\$FOO/ \$b/;
  339. my $out = "Structures begin differing at:\n";
  340. foreach my $idx (0..$#vals) {
  341. my $val = $vals[$idx];
  342. $vals[$idx] = !defined $val ? 'undef' :
  343. $val eq $DNE ? 'Does not exist'
  344. : "'$val'";
  345. }
  346. $out .= "$vars[0] = $vals[0]\n";
  347. $out .= "$vars[1] = $vals[1]";
  348. return $out;
  349. }
  350. BEGIN { $INC{'Test/Unit/TestCase.pm'} = __FILE__; }
  351. }
  352. {
  353. package Test::Unit::Result;
  354. our $VERSION = $Test::Unit::Lite::VERSION;
  355. sub new {
  356. my ($class) = @_;
  357. my $self = {
  358. 'messages' => [],
  359. 'errors' => 0,
  360. 'failures' => 0,
  361. 'passes' => 0,
  362. };
  363. return bless $self => $class;
  364. }
  365. sub messages {
  366. my ($self) = @_;
  367. return $self->{messages};
  368. }
  369. sub errors {
  370. my ($self) = @_;
  371. return $self->{errors};
  372. }
  373. sub failures {
  374. my ($self) = @_;
  375. return $self->{failures};
  376. }
  377. sub passes {
  378. my ($self) = @_;
  379. return $self->{passes};
  380. }
  381. sub add_error {
  382. my ($self, $test, $message, $runner) = @_;
  383. $self->{errors}++;
  384. my $result = {test => $test, type => 'ERROR', message => $message};
  385. push @{$self->messages}, $result;
  386. $runner->print_error($result) if defined $runner;
  387. }
  388. sub add_failure {
  389. my ($self, $test, $message, $runner) = @_;
  390. $self->{failures}++;
  391. my $result = {test => $test, type => 'FAILURE', message => $message};
  392. push @{$self->messages}, $result;
  393. $runner->print_failure($result) if defined $runner;
  394. }
  395. sub add_pass {
  396. my ($self, $test, $message, $runner) = @_;
  397. $self->{passes}++;
  398. my $result = {test => $test, type => 'PASS', message => $message};
  399. push @{$self->messages}, $result;
  400. $runner->print_pass($result) if defined $runner;
  401. }
  402. BEGIN { $INC{'Test/Unit/Result.pm'} = __FILE__; }
  403. }
  404. {
  405. package Test::Unit::TestSuite;
  406. our $VERSION = $Test::Unit::Lite::VERSION;
  407. sub empty_new {
  408. my ($class, $name) = @_;
  409. my $self = {
  410. 'name' => defined $name ? $name : 'Test suite',
  411. 'units' => [],
  412. };
  413. return bless $self => $class;
  414. }
  415. sub new {
  416. my ($class, $test) = @_;
  417. my $self = {
  418. 'name' => 'Test suite',
  419. 'units' => [],
  420. };
  421. if (defined $test and not ref $test) {
  422. # untaint $test
  423. $test =~ /([A-Za-z0-9:-]*)/;
  424. $test = $1;
  425. eval "use $test;";
  426. die if $@;
  427. }
  428. elsif (not defined $test) {
  429. $test = $class;
  430. }
  431. if (defined $test and $test->isa('Test::Unit::TestSuite')) {
  432. $class = ref $test ? ref $test : $test;
  433. $self->{name} = $test->name if ref $test;
  434. $self->{units} = $test->units if ref $test;
  435. }
  436. elsif (defined $test and $test->isa('Test::Unit::TestCase')) {
  437. $class = ref $test ? ref $test : $test;
  438. $self->{units} = [ $test ];
  439. }
  440. else {
  441. require Carp;
  442. Carp::croak(sprintf("usage: %s->new([CLASSNAME | TEST])\n", __PACKAGE__));
  443. }
  444. return bless $self => $class;
  445. }
  446. sub name {
  447. return $_[0]->{name};
  448. }
  449. sub units {
  450. return $_[0]->{units};
  451. }
  452. sub add_test {
  453. my ($self, $unit) = @_;
  454. if (not ref $unit) {
  455. # untaint $unit
  456. $unit =~ /([A-Za-z0-9:-]*)/;
  457. $unit = $1;
  458. eval "use $unit;";
  459. die if $@;
  460. return unless $unit->isa('Test::Unit::TestCase');
  461. }
  462. return push @{ $self->{units} }, ref $unit ? $unit : $unit->new;
  463. }
  464. sub count_test_cases {
  465. my ($self) = @_;
  466. my $plan = 0;
  467. foreach my $unit (@{ $self->units }) {
  468. $plan += scalar @{ $unit->list_tests };
  469. }
  470. return $plan;
  471. }
  472. sub run {
  473. my ($self, $result, $runner) = @_;
  474. die "Undefined result object" unless defined $result;
  475. foreach my $unit (@{ $self->units }) {
  476. foreach my $test (@{ $unit->list_tests }) {
  477. my $unit_test = (ref $unit ? ref $unit : $unit) . '::' . $test;
  478. my $add_what;
  479. my $e = '';
  480. eval {
  481. $unit->set_up;
  482. };
  483. if ($@) {
  484. $e = "$@";
  485. $add_what = 'add_error';
  486. }
  487. else {
  488. eval {
  489. $unit->$test;
  490. };
  491. if ($@) {
  492. $e = "$@";
  493. $add_what = 'add_failure';
  494. }
  495. else {
  496. $add_what = 'add_pass';
  497. };
  498. };
  499. eval {
  500. $unit->tear_down;
  501. };
  502. if ($@) {
  503. $e .= "$@";
  504. $add_what = 'add_error';
  505. };
  506. $result->$add_what($unit_test, $e, $runner);
  507. }
  508. }
  509. return;
  510. }
  511. BEGIN { $INC{'Test/Unit/TestSuite.pm'} = __FILE__; }
  512. }
  513. {
  514. package Test::Unit::TestRunner;
  515. our $VERSION = $Test::Unit::Lite::VERSION;
  516. sub new {
  517. my ($class, $fh_out, $fh_err) = @_;
  518. $fh_out = \*STDOUT unless defined $fh_out;
  519. $fh_err = \*STDERR unless defined $fh_err;
  520. _autoflush($fh_out);
  521. _autoflush($fh_err);
  522. my $self = {
  523. 'suite' => undef,
  524. 'fh_out' => $fh_out,
  525. 'fh_err' => $fh_err,
  526. };
  527. return bless $self => $class;
  528. }
  529. sub fh_out {
  530. my ($self) = @_;
  531. return $self->{fh_out};
  532. }
  533. sub fh_err {
  534. my ($self) = @_;
  535. return $self->{fh_err};
  536. }
  537. sub result {
  538. my ($self) = @_;
  539. return $self->{result};
  540. }
  541. sub _autoflush {
  542. my ($fh) = @_;
  543. my $old_fh = select $fh;
  544. $| = 1;
  545. select $old_fh;
  546. }
  547. sub suite {
  548. my ($self) = @_;
  549. return $self->{suite};
  550. }
  551. sub print_header {
  552. }
  553. sub print_error {
  554. my ($self, $result) = @_;
  555. print { $self->fh_out } "E";
  556. }
  557. sub print_failure {
  558. my ($self, $result) = @_;
  559. print { $self->fh_out } "F";
  560. }
  561. sub print_pass {
  562. my ($self, $result) = @_;
  563. print { $self->fh_out } ".";
  564. }
  565. sub print_footer {
  566. my ($self, $result) = @_;
  567. printf { $self->fh_out } "\nTests run: %d", $self->suite->count_test_cases;
  568. if ($result->errors) {
  569. printf { $self->fh_out } ", Errors: %d", $result->errors;
  570. }
  571. if ($result->failures) {
  572. printf { $self->fh_out } ", Failures: %d", $result->failures;
  573. }
  574. print { $self->fh_out } "\n";
  575. if ($result->errors) {
  576. print { $self->fh_out } "\nERRORS!!!\n\n";
  577. foreach my $message (@{ $result->messages }) {
  578. if ($message->{type} eq 'ERROR') {
  579. printf { $self->fh_out } "%s\n%s:\n\n%s\n",
  580. '-' x 78,
  581. $message->{test},
  582. $message->{message};
  583. }
  584. }
  585. printf { $self->fh_out } "%s\n", '-' x 78;
  586. }
  587. if ($result->failures) {
  588. print { $self->fh_out } "\nFAILURES!!!\n\n";
  589. foreach my $message (@{ $result->messages }) {
  590. if ($message->{type} eq 'FAILURE') {
  591. printf { $self->fh_out } "%s\n%s:\n\n%s\n",
  592. '-' x 78,
  593. $message->{test},
  594. $message->{message};
  595. }
  596. }
  597. printf { $self->fh_out } "%s\n", '-' x 78;
  598. }
  599. }
  600. sub start {
  601. my ($self, $test) = @_;
  602. my $result = Test::Unit::Result->new;
  603. # untaint $test
  604. $test =~ /([A-Za-z0-9:-]*)/;
  605. $test = $1;
  606. eval "use $test;";
  607. die if $@;
  608. if ($test->isa('Test::Unit::TestSuite')) {
  609. $self->{suite} = $test->suite;
  610. }
  611. elsif ($test->isa('Test::Unit::TestCase')) {
  612. $self->{suite} = Test::Unit::TestSuite->empty_new;
  613. $self->suite->add_test($test);
  614. }
  615. else {
  616. die "Unknown test $test\n";
  617. }
  618. $self->print_header;
  619. $self->suite->run($result, $self);
  620. $self->print_footer($result);
  621. }
  622. BEGIN { $INC{'Test/Unit/TestRunner.pm'} = __FILE__; }
  623. }
  624. {
  625. package Test::Unit::HarnessUnit;
  626. our $VERSION = $Test::Unit::Lite::VERSION;
  627. use base 'Test::Unit::TestRunner';
  628. sub print_header {
  629. my ($self) = @_;
  630. print { $self->fh_out } "STARTING TEST RUN\n";
  631. printf { $self->fh_out } "1..%d\n", $self->suite->count_test_cases;
  632. }
  633. sub print_error {
  634. my ($self, $result) = @_;
  635. printf { $self->fh_out } "not ok %s %s\n", $result->{type}, $result->{test};
  636. print { $self->fh_err } join("\n# ", split /\n/, "# " . $result->{message}), "\n";
  637. }
  638. sub print_failure {
  639. my ($self, $result) = @_;
  640. printf { $self->fh_out } "not ok %s %s\n", $result->{type}, $result->{test};
  641. print { $self->fh_err } join("\n# ", split /\n/, "# " . $result->{message}), "\n";
  642. }
  643. sub print_pass {
  644. my ($self, $result) = @_;
  645. printf { $self->fh_out } "ok %s %s\n", $result->{type}, $result->{test};
  646. }
  647. sub print_footer {
  648. }
  649. BEGIN { $INC{'Test/Unit/HarnessUnit.pm'} = __FILE__; }
  650. }
  651. {
  652. package Test::Unit::Debug;
  653. our $VERSION = $Test::Unit::Lite::VERSION;
  654. BEGIN { $INC{'Test/Unit/Debug.pm'} = __FILE__; }
  655. }
  656. {
  657. package Test::Unit::Lite::AllTests;
  658. our $VERSION = $Test::Unit::Lite::VERSION;
  659. use base 'Test::Unit::TestSuite';
  660. use Cwd ();
  661. use File::Find ();
  662. use File::Basename ();
  663. use File::Spec ();
  664. sub suite {
  665. my $class = shift;
  666. my $suite = Test::Unit::TestSuite->empty_new('All Tests');
  667. my $cwd = ${^TAINT} ? do { local $_=Cwd::getcwd; /(.*)/; $1 } : '.';
  668. my $dir = File::Spec->catdir($cwd, 't', 'tlib');
  669. my $depth = scalar File::Spec->splitdir($dir);
  670. push @INC, $dir;
  671. File::Find::find({
  672. wanted => sub {
  673. my $path = File::Spec->canonpath($File::Find::name);
  674. return unless $path =~ s/(Test)\.pm$/$1/;
  675. my @path = File::Spec->splitdir($path);
  676. splice @path, 0, $depth;
  677. return unless scalar @path > 0;
  678. my $class = join '::', @path;
  679. return unless $class;
  680. return if $class =~ /^Test::Unit::/;
  681. return if @ARGV and $class !~ $ARGV[0];
  682. $suite->add_test($class);
  683. },
  684. no_chdir => 1,
  685. }, $dir || '.');
  686. return $suite;
  687. }
  688. BEGIN { $INC{'Test/Unit/Lite/AllTests.pm'} = __FILE__; }
  689. }
  690. 1;
  691. __END__
  692. =for readme stop
  693. =head1 FUNCTIONS
  694. =over
  695. =item bundle
  696. Copies L<Test::Unit::Lite> modules into F<inc> directory. Creates missing
  697. subdirectories if needed. Silently overwrites previous module if was
  698. existing.
  699. =item all_tests
  700. Creates new test runner for L<Test::Unit::Lite::AllTests> suite which searches
  701. for test units in F<t/tlib> directory.
  702. =back
  703. =head1 CLASSES
  704. =head2 L<Test::Unit::TestCase>
  705. This is a base class for single unit test module. The user's unit test
  706. module can override the default methods that are simple stubs.
  707. The MESSAGE argument is optional and is included to the default error message
  708. when the assertion is false.
  709. =over
  710. =item new
  711. The default constructor which just bless an empty anonymous hash reference.
  712. =item set_up
  713. This method is called at the start of each test unit processing. It is empty
  714. method and can be overridden in derived class.
  715. =item tear_down
  716. This method is called at the end of each test unit processing. It is empty
  717. method and can be overridden in derived class.
  718. =item list_tests
  719. Returns the list of test methods in this class and base classes.
  720. =item fail([MESSAGE])
  721. Immediate fail the test.
  722. =item assert(ARG [, MESSAGE])
  723. Checks if ARG expression returns true value.
  724. =item assert_null(ARG [, MESSAGE])
  725. =item assert_not_null(ARG [, MESSAGE])
  726. Checks if ARG is defined or not defined.
  727. =item assert_equals(ARG1, ARG2 [, MESSAGE])
  728. =item assert_not_equals(ARG1, ARG2 [, MESSAGE])
  729. Checks if ARG1 and ARG2 are equals or not equals. If ARG1 and ARG2 look like
  730. numbers then they are compared with '==' operator, otherwise the string 'eq'
  731. operator is used.
  732. =item assert_num_equals(ARG1, ARG2 [, MESSAGE])
  733. =item assert_num_not_equals(ARG1, ARG2 [, MESSAGE])
  734. Force numeric comparison.
  735. =item assert_str_equals(ARG1, ARG2 [, MESSAGE])
  736. =item assert_str_not_equals(ARG1, ARG2 [, MESSAGE])
  737. Force string comparison.
  738. =item assert(qr/PATTERN/, ARG [, MESSAGE])
  739. =item assert_matches(qr/PATTERN/, ARG [, MESSAGE])
  740. =item assert_does_not_match(qr/PATTERN/, ARG [, MESSAGE])
  741. Checks if ARG matches PATTER regexp.
  742. =item assert_deep_equals(ARG1, ARG2 [, MESSAGE])
  743. =item assert_deep_not_equals(ARG1, ARG2 [, MESSAGE])
  744. Check if reference ARG1 is a deep copy of reference ARG2 or not. The
  745. references can be deep structure. If they are different, the message will
  746. display the place where they start differing.
  747. =back
  748. =head2 L<Test::Unit::TestSuite>
  749. This is a base class for test suite, which groups several test units.
  750. =over
  751. =item empty_new([NAME])
  752. Creates a fresh suite with no tests.
  753. =item new([CLASS | TEST])
  754. Creates a test suite from unit test name or class. If a test suite is
  755. provided as the argument, it merely returns that suite. If a test case is
  756. provided, it extracts all test case methods (see
  757. L<Test::Unit::TestCase>->list_test) from the test case into a new test suite.
  758. =item name
  759. Contains the name of the current test suite.
  760. =item units
  761. Contains the list of test units.
  762. =item add_test([TEST_CLASSNAME | TEST_OBJECT])
  763. Adds the test object to a suite.
  764. =item count_test_cases
  765. Returns the number of test cases in this suite.
  766. =item run
  767. Runs the test suite and output the results as TAP report.
  768. =back
  769. =head2 L<Test::Unit::TestRunner>
  770. This is the test runner which outputs text report about finished test suite.
  771. =over
  772. =item new([$fh_out [, $fh_err]])
  773. The constructor for whole test framework. Its optional parameters are
  774. filehandles for standard output and error messages.
  775. =item fh_out
  776. Contains the filehandle for standard output.
  777. =item fh_err
  778. Contains the filehandle for error messages.
  779. =item suite
  780. Contains the test suite object.
  781. =item print_header
  782. Called before running test suite.
  783. =item print_error
  784. Called after error was occurred on C<set_up> or C<tear_down> method.
  785. =item print_failure
  786. Called after test unit is failed.
  787. =item print_pass
  788. Called after test unit is passed.
  789. =item print_footer
  790. Called after running test suite.
  791. =item start(TEST_SUITE)
  792. Starts the test suite.
  793. =back
  794. =head2 L<Test::Unit::Result>
  795. This object contains the results of test suite.
  796. =over
  797. =item new
  798. Creates a new object.
  799. =item messages
  800. Contains the array of result messages. The single message is a hash which
  801. contains:
  802. =over
  803. =item test
  804. the test unit name,
  805. =item type
  806. the type of message (PASS, ERROR, FAILURE),
  807. =item message
  808. the text of message.
  809. =back
  810. =item errors
  811. Contains the number of collected errors.
  812. =item failures
  813. Contains the number of collected failures.
  814. =item passes
  815. Contains the number of collected passes.
  816. =item add_error(TEST, MESSAGE)
  817. Adds an error to the report.
  818. =item add_failure(TEST, MESSAGE)
  819. Adds an failure to the report.
  820. =item add_pass(TEST, MESSAGE)
  821. Adds a pass to the report.
  822. =back
  823. =head2 L<Test::Unit::HarnessUnit>
  824. This is the test runner which outputs in the same format that
  825. L<Test::Harness> expects (Test Anything Protocol). It is derived
  826. from L<Test::Unit::TestRunner>.
  827. =head2 L<Test::Unit::Debug>
  828. The empty class which is provided for compatibility with original
  829. L<Test::Unit> framework.
  830. =head2 L<Test::Unit::Lite::AllTests>
  831. The test suite which searches for test units in F<t/tlib> directory.
  832. =head1 COMPATIBILITY
  833. L<Test::Unit::Lite> should be compatible with public API of L<Test::Unit>.
  834. The L<Test::Unit::Lite> also has some known incompatibilities:
  835. =over 2
  836. =item *
  837. The test methods are sorted alphabetically.
  838. =item *
  839. It implements new assertion method: B<assert_deep_not_equals>.
  840. =item *
  841. Does not support B<ok>, B<assert>(CODEREF, @ARGS) and B<multi_assert>.
  842. =back
  843. C<Test::Unit::Lite> is compatible with L<Test::Assert> assertion functions.
  844. =head1 EXAMPLES
  845. =head2 t/tlib/SuccessTest.pm
  846. This is the simple unit test module.
  847. package SuccessTest;
  848. use strict;
  849. use warnings;
  850. use base 'Test::Unit::TestCase';
  851. sub test_success {
  852. my $self = shift;
  853. $self->assert(1);
  854. }
  855. 1;
  856. =head2 t/all_tests.t
  857. This is the test script for L<Test::Harness> called with "make test".
  858. #!/usr/bin/perl
  859. use strict;
  860. use warnings;
  861. use File::Spec;
  862. use Cwd;
  863. BEGIN {
  864. unshift @INC, map { /(.*)/; $1 } split(/:/, $ENV{PERL5LIB}) if defined $ENV{PERL5LIB} and ${^TAINT};
  865. my $cwd = ${^TAINT} ? do { local $_=getcwd; /(.*)/; $1 } : '.';
  866. unshift @INC, File::Spec->catdir($cwd, 'inc');
  867. unshift @INC, File::Spec->catdir($cwd, 'lib');
  868. }
  869. use Test::Unit::Lite;
  870. local $SIG{__WARN__} = sub { require Carp; Carp::confess("Warning: $_[0]") };
  871. Test::Unit::HarnessUnit->new->start('Test::Unit::Lite::AllTests');
  872. =head2 t/test.pl
  873. This is the optional script for calling test suite directly.
  874. #!/usr/bin/perl
  875. use strict;
  876. use warnings;
  877. use File::Basename;
  878. use File::Spec;
  879. use Cwd;
  880. BEGIN {
  881. chdir dirname(__FILE__) or die "$!";
  882. chdir '..' or die "$!";
  883. unshift @INC, map { /(.*)/; $1 } split(/:/, $ENV{PERL5LIB}) if defined $ENV{PERL5LIB} and ${^TAINT};
  884. my $cwd = ${^TAINT} ? do { local $_=getcwd; /(.*)/; $1 } : '.';
  885. unshift @INC, File::Spec->catdir($cwd, 'inc');
  886. unshift @INC, File::Spec->catdir($cwd, 'lib');
  887. }
  888. use Test::Unit::Lite;
  889. local $SIG{__WARN__} = sub { require Carp; Carp::confess("Warning: $_[0]") };
  890. all_tests;
  891. This is perl equivalent of shell command line:
  892. perl -Iinc -Ilib -MTest::Unit::Lite -w -e all_tests
  893. =head1 SEE ALSO
  894. L<Test::Unit>, L<Test::Assert>.
  895. =head1 TESTS
  896. The L<Test::Unit::Lite> was tested as a L<Test::Unit> replacement for following
  897. distributions: L<Test::C2FIT>, L<XAO::Base>, L<Exception::Base>.
  898. =for readme continue
  899. =head1 AUTHOR
  900. Piotr Roszatycki <dexter@cpan.org>
  901. =head1 LICENSE
  902. Copyright (c) 2007-2009, 2012 by Piotr Roszatycki <dexter@cpan.org>.
  903. This program is free software; you can redistribute it and/or modify it under
  904. the same terms as Perl itself.
  905. See L<http://www.perl.com/perl/misc/Artistic.html>