File Coverage

blib/lib/Test/More/Fork.pm
Criterion Covered Total %
statement 79 79 100.0
branch 18 18 100.0
condition 3 3 100.0
subroutine 17 17 100.0
pod 2 2 100.0
total 119 119 100.0


line stmt bran cond sub pod time code
1             package Test::More::Fork;
2 6     6   641166 use strict;
  6         18  
  6         696  
3 6     6   36 use warnings;
  6         6  
  6         672  
4              
5             #{{{ POD
6              
7             =pod
8              
9             =head1 NAME
10              
11             Test::More::Fork - Test forking capabilities hacked on to Test::More
12              
13             =head1 DESCRIPTION
14              
15             Test::More::Fork allows you to run tests seperately. This is useful for
16             returning to a known or pristine state between tests. Test::Seperate seperates
17             tests into different forked processes. You can do whatever you want in a test
18             set without fear that something you do will effect a test in another set.
19              
20             This is a better option than local when dealing with complex meta-structures
21             and testing class-construction in disperate conditions.
22              
23             =head1 SYNOPSYS
24              
25             # Should be used in place of Test::More, will import all of the functions
26             # from Test::More, and accept all the same arguments.
27             use Test::More::Fork tests => 5;
28              
29             ok( 1, "Runs in the main process" );
30             # ok 1 - Runs in the main process
31              
32             fork_tests {
33             ok( 1, "Runs in a forked process"
34             } "Forked tests were run", 1;
35             # ok 2 - Runs in a forked process
36             # ok 3 - Forked tests were run
37             # ok 4 - verify test count
38              
39             #message and coutn are optional:
40             fork_tests { ok( 1, "another test" )};
41             # ok 5 - another test
42              
43             #create your own test that is safe to run in a forked process:
44             fork_sub 'new_sub' => sub { ... };
45              
46             =head1 EXPORTED FUNCTIONS
47              
48             See the docs for L, all functions exported by Test::More are
49             exported by Test::More::Fork as well.
50              
51             =over 4
52              
53             =cut
54              
55             #}}}
56              
57 6     6   36 use base 'Test::More';
  6         84  
  6         8256  
58 6     6   56766 use Data::Dumper;
  6         18  
  6         1122  
59              
60             our @EXPORT = ( 'fork_tests', 'fork_sub', @Test::More::EXPORT );
61             our $VERSION = "0.007";
62             our $CHILD;
63             our $SEPERATOR = 'EODATA';
64              
65             pipe( READ, WRITE ) || die( $! );
66              
67             =item fork_sub $name => sub { ... }
68              
69             Create a new sub defined in both the current package and Test::More::Fork. This
70             sub will be safe to run in a forked test.
71              
72             =cut
73              
74             sub fork_sub {
75 178     178 1 2834 my ( $sub, $code ) = @_;
76             my $new = sub {
77 6     6   42 no strict 'refs';
  6         18  
  6         1632  
78 107 100   107   56461 goto &$code unless $CHILD;
79              
80 17         234 push @$CHILD => {
81             'caller' => [ caller()],
82             'sub' => $sub,
83             'params' => [@_],
84             };
85 17         1397 "$sub() delayed";
86 178         722 };
87             {
88 6     6   36 no strict 'refs';
  6         12  
  6         852  
  178         244  
89 178         698 *$sub = $new;
90 178         488 my ( $caller ) = caller();
91 178 100       6540 return if $caller eq __PACKAGE__;
92 10         20 *{ $caller . '::' . $sub } = $new;
  10         62  
93             }
94             }
95              
96             BEGIN {
97 6     6   24 for my $sub ( @Test::More::EXPORT ) {
98 6     6   36 no strict 'refs';
  6         12  
  6         288  
99 168         198 fork_sub $sub => \&{'Test::More::' . $sub}
  168         642  
100             }
101             }
102              
103             =item fork_tests( sub { ... }, $message, $count )
104              
105             Forks, then runs the provided sub in a child process.
106              
107             $message and $count are optional, and each add an extra test to the count.
108              
109             =cut
110              
111             sub fork_tests(&;$$) {
112 20     20 1 12355 my ($sub, $message, $count) = @_;
113              
114 20 100       25394 if ( my $pid = fork()) {
115 15         819 my $data = _read();
116 15         126102 waitpid( $pid, 0 );
117 15         265 my $out = !$?;
118 15         147 my $tests = _run_tests( $data );
119 14 100       173 Test::More::ok( $out, $message ) if $message;
120 14 100       4733 Test::More::is( @$tests, $count, "Verify test count" ) if $count;
121             }
122             else {
123 5         509 $CHILD = [];
124 5         170 eval { $sub->() };
  5         392  
125 5 100       726 if ( $@ ) {
126 1         55 _write( $@ . $SEPERATOR );
127             }
128             else {
129 4         263 _write( Dumper( $CHILD ) . $SEPERATOR );
130             }
131 5         2808 exit;
132             }
133             }
134              
135             sub _run_tests {
136 31     31   5687 my $data = shift;
137 31 100       1239 die( $data ) unless( $data =~ m/^\$VAR1/ );
138 30         99 my $tests = _deserialize_data( $data );
139 30         292 for my $test ( @$tests ) {
140 35         527 my $caller = $test->{ 'caller' };
141 35         62 my $sub = $test->{ 'sub' };
142 35         61 my $params = $test->{ params };
143 6     6   42 no strict 'refs';
  6         18  
  6         2088  
144 35         340 my $tb = Test::More->builder;
145 35         808 my $number = $tb->current_test;
146 35         427 eval { &$sub( @$params ) };
  35         380  
147 35         14191 my @summary = $tb->summary;
148 35 100 100     1144 if ( $tb->current_test != $number && !$summary[$number] ) {
149 5         170 Test::More::diag( "Problem at: " . $caller->[1] . " line: " . $caller->[2] );
150             }
151 35 100       543 Test::More::diag $@ if $@;
152             }
153 30         232 return $tests;
154             }
155              
156             sub _deserialize_data {
157 36     36   1554 my $data = shift;
158 6     6   42 no strict;
  6         12  
  6         876  
159 36         409 $data =~ s/$SEPERATOR//;
160 36         6710 return eval $data;
161             }
162              
163             sub _read {
164 15     15   1088 local $/ = $SEPERATOR;
165 15         6616798 my $data = ;
166 15         248 return $data;
167             }
168              
169             sub _write {
170 5     5   3010 print WRITE $_ for @_;
171             }
172              
173             1;
174              
175             __END__