File Coverage

blib/lib/Test/Unit/GTestRunner/Worker.pm
Criterion Covered Total %
statement 9 9 100.0
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 12 12 100.0


line stmt bran cond sub pod time code
1             #! /bin/false
2              
3             # vim: set autoindent shiftwidth=4 tabstop=8:
4             # $Id: Worker.pm,v 1.23 2006/05/12 12:42:14 guido Exp $
5              
6             # Copyright (C) 2004-2006 Guido Flohr ,
7             # all rights reserved.
8              
9             # This program is free software; you can redistribute it and/or modify
10             # it under the terms of the GNU General Public License as published by
11             # the Free Software Foundation; either version 2, or (at your option)
12             # any later version.
13              
14             # This program is distributed in the hope that it will be useful,
15             # but WITHOUT ANY WARRANTY; without even the implied warranty of
16             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17             # Library General Public License for more details.
18              
19             # You should have received a copy of the GNU General Public License
20             # along with this program; if not, write to the Free Software Foundation,
21             # Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22              
23             package Test::Unit::GTestRunner::Worker;
24              
25 1     1   7 use strict;
  1         2  
  1         56  
26              
27 1     1   8 use constant DEBUG => 0;
  1         2  
  1         67  
28              
29 1     1   6 use base qw (Test::Unit::TestRunner);
  1         2  
  1         385008  
30              
31             use Locale::TextDomain qw (Test-Unit-GTestRunner);
32             use Test::Unit::Loader;
33             use Storable qw (nfreeze);
34             use MIME::Base64 qw (encode_base64);
35             use IO::Handle;
36              
37             sub new {
38             my $class = shift;
39            
40             my $self = bless {}, $class;
41            
42             # We have to dup stdout to a new filehandle, and redirect it then
43             # to stderr. Otherwise, misbehaving test cases that print on
44             # stdout, will disturb our communication with the parent.
45             my $io = $self->{__pipe} = IO::Handle->new;
46             unless ($io->fdopen (fileno STDOUT, 'w')) {
47             $self->__sendWarning (__x ("Standard output cannot be "
48             . "duplicated: {err}.",
49             err => $!));
50             $self->__sendMessage ("terminated");
51             exit 1;
52             }
53            
54             $io->autoflush (1);
55            
56             unless (tie *STDOUT, 'Test::Unit::GTestRunner::TiedHandle',
57             sub { $self->__sendMessage (@_) }) {
58             $self->__sendWarning (__x ("Standard output cannot be tied: {err}.",
59             err => $!));
60             }
61            
62             unless (tie *STDERR, 'Test::Unit::GTestRunner::TiedHandle',
63             sub { $self->__sendMessage (@_) }) {
64             $self->__sendWarning (__x ("Standard error cannot be tied: {err}.",
65             err => $!));
66             }
67            
68             return $self;
69             }
70              
71             sub waitCommand {
72             my $self = shift;
73            
74             return 1;
75             }
76              
77             sub start {
78             my ($self, @suite_names) = @_;
79            
80             my $result = $self->{__my_result} = $self->create_test_result;
81              
82             my @suites;
83             my @selected_tests;
84            
85             foreach my $suite_name (@suite_names) {
86             my @test_numbers;
87             if ($suite_name =~ s/::([0-9\s,]+)$//) {
88             @test_numbers = split /\s*,\s*/, $1;
89             }
90             push @suites, $suite_name;
91             push @selected_tests, \@test_numbers;
92             }
93            
94             my $suite = eval {
95             package GTestRunnerSuite;
96             use base qw (Test::Unit::TestSuite);
97             *GTestRunnerSuite::include_tests = sub { @suites };
98            
99             package Test::Unit::GTestRunner;
100             Test::Unit::Loader::load ('GTestRunnerSuite');
101             };
102             if ($@) {
103             my $reply_queue = $self->{__my_reply_queue};
104            
105             $self->__sendMessage ("abort $@");
106            
107             exit 1;
108             }
109            
110             my $count = 0;
111             foreach my $test_numbers (@selected_tests) {
112             if (@{$test_numbers}) {
113             # Ouch. But the Test::Unit API gives us no other chance.
114             $suite->{_Tests}->[$count]->{_Tests} =
115             [@{$suite->{_Tests}->[$count]->{_Tests}}[@{$test_numbers}]];
116             }
117             ++$count;
118             }
119            
120             $result->add_listener ($self);
121             $self->{__my_suite} = $suite;
122            
123             eval {
124             $suite->run ($result, $self);
125             };
126             if ($@) {
127             $self->__sendMessage ("warning $@");
128             }
129            
130             $self->__sendMessage ("terminated");
131            
132             exit 0;
133             }
134              
135             # These are callbacks from Test::Unit::Result.
136             sub start_test {
137             my ($self, $test) = @_;
138            
139             my $name = $test->name;
140            
141             my $test_case = $test;
142             $test_case =~ s/=.*//;
143            
144             $self->__sendMessage ("start ${test_case}::$name");
145            
146             return 1;
147             }
148              
149             # These are callbacks from Test::Unit::Result.
150             sub end_test {
151             my ($self, $test) = @_;
152            
153             my $name = $test->name;
154            
155             $self->__sendMessage ("end $name");
156            
157             return 1;
158             }
159              
160             sub add_failure {
161             my ($self, $test, $failure) = @_;
162            
163             my $name = $test->name;
164            
165             # FIXME: Any clean/cleaner way for this?
166             my $packet = {
167             package => $failure->{'-package'},
168             file => $failure->file,
169             line => $failure->line,
170             text => $failure->text,
171             };
172            
173             my $obj = encode_base64 nfreeze $packet;
174            
175             $self->__sendMessage ("failure $name $obj");
176            
177             return 1;
178             }
179              
180             sub add_error {
181             my ($self, $test, $failure) = @_;
182            
183             my $name = $test->name;
184            
185             # FIXME: Any clean/cleaner way for this?
186             my $packet = {
187             package => $failure->{'-package'},
188             file => $failure->file,
189             line => $failure->line,
190             text => $failure->text,
191             };
192            
193             # FIXME: This is definetely not the right way!
194             # It will break if the file contains more than one packages.
195             if ($packet->{package} eq 'Error::subs') {
196             $packet->{package} = $packet->{file};
197             $packet->{package} =~ s/\//::/g;
198             $packet->{package} =~ s/.pm//g;
199             }
200            
201             my $obj = encode_base64 nfreeze $packet;
202            
203             $self->__sendMessage ("error $name $obj");
204            
205             return 1;
206             }
207              
208             sub add_pass {
209             my ($self, $test, $failure) = @_;
210            
211             my $name = $test->name;
212            
213             $self->__sendMessage ("success $name");
214            
215             return 1;
216             }
217              
218             sub _print {
219             my ($self, @args) = @_;
220            
221             print @args;
222             }
223              
224             sub __sendMessage {
225             my ($self, $message) = @_;
226            
227             my $length = 1 + length $message;
228             $length = $length & 0xffff_ffff;
229             $length = sprintf "%08x", $length;
230              
231             warn ">>> REPLY: $message\n" if DEBUG;
232              
233             $self->{__pipe}->print ("$length $message\n");
234             }
235              
236             sub __sendWarning {
237             my ($self, $warning) = @_;
238            
239             $self->__sendMessage ("warning $warning");
240             }
241              
242             package Test::Unit::GTestRunner::TiedHandle;
243              
244             use strict;
245              
246             use Storable qw (nfreeze);
247             use MIME::Base64 qw (encode_base64);
248              
249             sub TIEHANDLE {
250             my ($class, $callback) = @_;
251            
252             bless { __callback => $callback }, $class;
253             }
254              
255             sub WRITE {
256             my ($self, $buffer, $length, $offset) = @_;
257            
258             my $string = substr $buffer, $length, $offset;
259            
260             $self->PRINT ($string) or return;
261            
262             return length $string;
263             }
264              
265             sub PRINT {
266             my ($self, @strings) = @_;
267              
268             return if $self->{__closed};
269              
270             my $encoded = encode_base64 join $,, @strings, $\;
271            
272             $self->{__callback}->("print $encoded");
273             }
274              
275             sub PRINTF {
276             my ($self, $fmt, @args) = @_;
277            
278             $self->PRINT (sprintf $fmt, @args);
279             }
280              
281             sub CLOSE {
282             shift->{__closed} = 1;
283             }
284              
285             # POSIX stderr is read/write!
286             sub READ { return }
287             sub READLINE { return }
288             sub GETC { return }
289              
290             sub UNTIE {}
291             sub DESTROY {}
292              
293             sub BINMODE {}
294             sub OPEN {}
295             sub EOF {}
296             sub FILENO { 1 }
297             sub SEEK { return }
298             sub TELL { return }
299              
300             1;
301              
302             =head1 NAME
303              
304             Test::Unit::GTestRunner::Worker - Worker class for GTestRunner
305              
306             =head1 SYNOPSIS
307              
308             use Test::Unit::GTestRunner::Worker;
309              
310             Test::Unit::GTestRunner::Worker->new->start ($my_testcase_class);
311              
312             =head1 DESCRIPTION
313              
314             This class is not intended for direct usage. Instead,
315             Test::Unit::GTestRunner(3pm) executes Perl code that uses
316             Test::Unit::GTestRunner::Worker(3pm), so that the testing is
317             executed in separate process.
318              
319             Feedback about running tests is printed on standard output,
320             see the source for details of the protocol.
321              
322             =head1 AUTHOR
323              
324             Copyright (C) 2004-2006, Guido Flohr Eguido@imperia.netE, all
325             rights reserved. See the source code for details.
326              
327             This software is contributed to the Perl community by Imperia
328             (L).
329              
330             =head1 ENVIRONMENT
331              
332             The package is internationalized with libintl-perl, hence the
333             environment variables "LANGUAGE", "LANG", "LC_MESSAGES", and
334             "LC_ALL" will influence the language in which messages are presented.
335              
336             =head1 SEE ALSO
337              
338             Test::Unit::GTestRunner(3pm), Test::Unit::TestRunner(3pm),
339             Test::Unit(3pm), perl(1)
340              
341             =cut
342              
343             #Local Variables:
344             #mode: perl
345             #perl-indent-level: 4
346             #perl-continued-statement-offset: 4
347             #perl-continued-brace-offset: 0
348             #perl-brace-offset: -4
349             #perl-brace-imaginary-offset: 0
350             #perl-label-offset: -4
351             #cperl-indent-level: 4
352             #cperl-continued-statement-offset: 2
353             #tab-width: 8
354             #End: