Re: Testing output to STDOUT and STDERR

2004-02-10 Thread A. Pagaltzis
* Adriano R. Ferreira [EMAIL PROTECTED] [2004-02-09 01:56]:
 While writing tests for some of my code, I was faced with the issue
 of capturing what the code sends to STDOUT and STDERR. As I have not
 found a module to make it easy, I wrote a trivial code to do it. It
 is used like this:
 
   use Test::More tests = 2;
   use Seize qw(seize release);
 
   my ($out, $err);
 
   seize \$out, \$err; # from here on, STDOUT and STDERR are seized
 
   print 1\n;
   warn 2\n;
   print 3\n;
   eval { die 4\n; }
 
   release; # here STDOUT and STDERR are released
 
   is($out, 1\n3\n);
   is($err, 2\n3\n);
 
 My doubt is if this deserves a module: maybe it would be better
 to use idioms commonly employed to this kind of task. Maybe
 there is some module I am overlooking that already does that.

For Perl 5.8 (and 5.6 with IO::String? I think it works there)
it's trivial:

use Test::More tests = 2;
use Carp;

sub string_fh {
open my $fh, '', $_[0]
or croak Couldn't open scalar as filehandle: $!\n;
return $fh;
}

my ($out, err);

{
local STDOUT, STDERR;
*STDOUT = string_fh \$out;
*STDERR = string_fh \$err;

print 1\n;
warn 2\n;
print 3\n;
eval { die 4\n; }
}

is($out, 1\n3\n);
is($err, 2\n3\n);

I believe this is a lot more robust than a tie() solution as
well. But it isn't really modularizable due to the local() and
there's not much anyway to stick in a module. Another approach I
only have the time to sketch here:

use Test::More tests = 2;
use Carp;

sub redir_fh {
my ($fh, $mode, $file);

my $saved_fh;
# dup $fh in here

open $fh, $mode, $file
# not sure this msg makes sense..
or croak Couldn't dup $fh to $file: $!\n;

return bless [ $fh, $saved_fh ], 'RestoreHandle';
}

sub RestoreHandle::DESTROY {
# use $self to dup the original FH back into the used one
}

my ($out, err);

{
my $s_out = redir_fh \*STDOUT, '', \$out;
my $s_err = redir_fh \*STDERR, '', \$err;

print 1\n;
warn 2\n;
print 3\n;
eval { die 4\n; }

}
# $s_* went out of scope here..

is($out, 1\n3\n);
is($err, 2\n3\n);

which uses lexical variables to implement dynamic scoping. :)

-- 
Regards,
Aristotle
 
If you can't laugh at yourself, you don't take life seriously enough.


Re: Testing output to STDOUT and STDERR

2004-02-10 Thread khemir nadim

Andy Lester [EMAIL PROTECTED] wrote in message
news:[EMAIL PROTECTED]
  Because:
  a) I wasn't happy with the API
  b) I'm a lazy SOB and couldn't find the time to sort it out

 I'll be glad to help with the second part.  Mail me the parts and I'll
 bundle it up all nice for ya.

Hi, I also have a lot of stuff to bundle! I can even arrange to produce
unbundled code so you can practice your bundling skills. You can make a
reputation as Lester the Bundler.

;-)

Nadim.




Re: Testing output to STDOUT and STDERR

2004-02-10 Thread Andy Lester
 Hi, I also have a lot of stuff to bundle! I can even arrange to produce
 unbundled code so you can practice your bundling skills. You can make a
 reputation as Lester the Bundler.

It's not like I need practice in make a distro.  I just wanna help along
the stuff that I think sounds useful...

xoa

-- 
Andy Lester = [EMAIL PROTECTED] = www.petdance.com = AIM:petdance


Re: Testing output to STDOUT and STDERR

2004-02-09 Thread Sam Vilain
On Mon, 09 Feb 2004 14:00, Andy Lester wrote;

While writing tests for some of my code, I was faced with the issue
of capturing what the code sends to STDOUT and STDERR. As I have not
found a module to make it easy, I wrote a trivial code to do it. It
is used like this:
   I'm not sure what you're actually trying to test.  If you're testing
   test modules, look at Test::Builder::Tester.

No, something that ties STDOUT so that code can print to it, and you
can test that the right thing was printed; I've had to do this before,
and ended up not going through the CPAN ropes for this module:

{
package Capture;

sub new {
my $class = shift;
my $self = { stdout =  };
bless $self, $class;
return $self;
}

sub capture_print {
my $self = shift;
$self-{so} = tie(*STDOUT, __PACKAGE__, \$self-{stdout})
or die failed to tie STDOUT; $!;
}

sub release_stdout {
my $self = shift;
delete $self-{so};
untie(*STDOUT);
return $self-{stdout};
}

sub TIEHANDLE {
my $class = shift;
my $ref = shift;
return bless({ stdout = $ref }, $class);
}

sub PRINT {
my $self = shift;
${$self-{stdout}} .= join('', map { defined $_?$_:} @_); 
}

sub PRINTF {
my ($self) = shift;
print STDERR OUCH @_\n;
my ($fmt) = shift;
${$self-{stdout}} .= sprintf($fmt, @_)
if (@_);
}

sub glob {
return \*STDOUT;
}
}

Though, I must say that I prefer his API.  The above was really just a
quick hack based on what I'd extracted out of the ePerl code base.

I'd call it something like IO::Capture if I were to CPAN it.
IO::Seize isn't quite right, but seize is definitely a good Perlish
name for the function.

Note that php has a built-in function to do just this.
-- 
Sam Vilain, sam /\T vilain |T net, PGP key ID: 0x05B52F13
(include my PGP key ID in personal replies to avoid spam filtering)

  Time is an illusion perpetrated by the manufacturers of space.
GRAFFITI





RE: Testing output to STDOUT and STDERR

2004-02-09 Thread Orton, Yves
Title: RE: Testing output to STDOUT and STDERR





 Though, I must say that I prefer his API. The above was really just a
 quick hack based on what I'd extracted out of the ePerl code base.
 
 I'd call it something like IO::Capture if I were to CPAN it.
 IO::Seize isn't quite right, but seize is definitely a good Perlish
 name for the function.
 
 Note that php has a built-in function to do just this.


Its worth noting that this approach wont actually grab everything on the tied filehandles. There are enough ways to bypass the tie that you have to do a lot more than that to get the majority, and even then there is stuff that will still bypass it.

Its very annoying actually that there isnt a reliable and clean way to intercept STDOUT/STDERR properly. (IMO)


Yves








Re: Testing output to STDOUT and STDERR

2004-02-09 Thread Adrian Howard
On Monday, February 9, 2004, at 06:27  pm, Kineticode Billing wrote:

On Feb 9, 2004, at 10:20 AM, Adrian Howard wrote:
[snip]
Cool. Why isn't this on CPAN?
Because:
a) I wasn't happy with the API
b) I'm a lazy SOB and couldn't find the time to sort it out
The new year's resolution may have helped with (b), but Adriano's 
solution looks better anyway :-)

Adrian



Re: Testing output to STDOUT and STDERR

2004-02-09 Thread Adrian Howard
On Monday, February 9, 2004, at 08:27  pm, Andy Lester wrote:

Because:
a) I wasn't happy with the API
b) I'm a lazy SOB and couldn't find the time to sort it out
I'll be glad to help with the second part.  Mail me the parts and I'll
bundle it up all nice for ya.
If you want to play it's at http://www.quietstars.com/perl/

However I still don't think that API is good, and Adriano's solution 
looks like something more generally useful - so I'm not sure that a 
nice bundle is a good idea :-)

Adrian



Re: Testing output to STDOUT and STDERR

2004-02-09 Thread Sam Vilain
On Tue, 10 Feb 2004 00:57, Orton, Yves wrote;

   Its worth noting that this approach wont actually grab everything
   on the tied filehandles.  There are enough ways to bypass the tie
   that you have to do a lot more than that to get the majority, and
   even then there is stuff that will still bypass it.

Yes, that is worth noting; but I'd consider all code that bypasses the
tie to be bugs or an inappropriate test case :-).

I'm just a little curious about the ways that this could happen; see
if you can add to this list.

  a) something grabs the file handle number via fileno(STDOUT) - or
 has a hardcoded `1' for STDOUT - and prints to that directly
 using stdio (now, wouldn't that have to be XS code?)

  b) something uses syswrite(STDOUT)

  c) something written via system() prints to STDOUT

  d) something has already DUP'ed the file handle (ie open FOO,
 STDOUT) and prints to it normally

   Its very annoying actually that there isnt a reliable and clean
   way to intercept STDOUT/STDERR properly. (IMO)

Other than fork and IPC, which bites and doesn't play well with the
test suites... try forking in the middle of a Test::Builder run.
-- 
Sam Vilain, sam /\T vilain |T net, PGP key ID: 0x05B52F13
(include my PGP key ID in personal replies to avoid spam filtering)

Activity is the politician's substitute for achievement.
 - anon.



Testing output to STDOUT and STDERR

2004-02-08 Thread Adriano R. Ferreira
While writing tests for some of my code, I was faced with the issue
of capturing what the code sends to STDOUT and STDERR. As I have not
found a module to make it easy, I wrote a trivial code to do it. It
is used like this:
use Test::More tests = 2;
use Seize qw(seize release);
	my ($out, $err);

	seize \$out, \$err; # from here on, STDOUT and STDERR are seized

print 1\n;
warn 2\n;
print 3\n;
eval { die 4\n; }
	release; # here STDOUT and STDERR are released

is($out, 1\n3\n);
is($err, 2\n3\n);
My doubt is if this deserves a module: maybe it would be better to use
idioms commonly employed to this kind of task. Maybe there is some module
I am overlooking that already does that.
If it is worthy, there's a bunch of things I would appreciate some
feedback on:
* does it make sense the use of 'seize' and 'release' as above
  (I am not an English native speaker and I am not sure).
* What would be a sensible name: IO::Seize, Test::Stdout?
* It is necessary that I understand better the interaction of the
  code being tested and how Test:: modules and Test::Harness works
* It would be better to make it a real Test:: module?


--
Adriano


Re: Testing output to STDOUT and STDERR

2004-02-08 Thread Andy Lester
 While writing tests for some of my code, I was faced with the issue
 of capturing what the code sends to STDOUT and STDERR. As I have not
 found a module to make it easy, I wrote a trivial code to do it. It
 is used like this:

I'm not sure what you're actually trying to test.  If you're testing
test modules, look at Test::Builder::Tester.

xoa

-- 
Andy Lester = [EMAIL PROTECTED] = www.petdance.com = AIM:petdance


Re: Testing output to STDOUT and STDERR

2004-02-08 Thread Adriano R. Ferreira
The thing I want to test is the output of my piece of code to STDOUT
and STDERR. The kind of code I am writing is just like the output
of a compiler which outputs to STDOUT and sends warnings to STDERR.
Of course, there won't be warnings when the input is correct.
In the tests for this code, I would like not only to test the
successful cases but also the bad cases. So I found this need
to watch STDOUT and STDERR.
One of the things I am not confident at is the interplay with
modules like Test::More. Where they send their output: STDERR?
Adriano.

On Sun, 8 Feb 2004 19:00:02 -0600, Andy Lester [EMAIL PROTECTED] wrote:

While writing tests for some of my code, I was faced with the issue
of capturing what the code sends to STDOUT and STDERR. As I have not
found a module to make it easy, I wrote a trivial code to do it. It
is used like this:
I'm not sure what you're actually trying to test.  If you're testing
test modules, look at Test::Builder::Tester.
xoa

--
Oasis Comunicacao e Tecnologia Ltda.


Re: Testing output to STDOUT and STDERR

2004-02-08 Thread Lincoln A. Baxter
On Sun, 2004-02-08 at 20:00, Andy Lester wrote:
  While writing tests for some of my code, I was faced with the issue
  of capturing what the code sends to STDOUT and STDERR. As I have not
  found a module to make it easy, I wrote a trivial code to do it. It
  is used like this:
 
 I'm not sure what you're actually trying to test.  If you're testing
 test modules, look at Test::Builder::Tester.
 
 xoa

I think he is trying to do what this should do on the command line but
which does not always work:

ksh$ perl -Mblib t/test.t 21  somefile

Where the 21 does not succeed in concatentating 2 to 1. (probably
because 2 or 1 is the tty), in which case I am not sure this would work
either.

I think this could possibly be useful... post the code, or a link to the
code.  You might consider combine() and separate() instead of seize and
release?  Not really happy with these names either...

Lincoln




Re: Testing output to STDOUT and STDERR

2004-02-08 Thread David Wheeler
On Feb 8, 2004, at 5:52 PM, Adriano R. Ferreira wrote:

If it is worthy, there's a bunch of things I would appreciate some
feedback on:
* does it make sense the use of 'seize' and 'release' as above
  (I am not an English native speaker and I am not sure).
I like them. They're quirky.

* What would be a sensible name: IO::Seize, Test::Stdout?
The latter, I think.

* It is necessary that I understand better the interaction of the
  code being tested and how Test:: modules and Test::Harness works
If you're tie'ing off STDOUT and STDERR, it should be fine.

* It would be better to make it a real Test:: module?
Perhaps:

  stdout_is(print STDOUT hello, hello, 'print hello to STDOUT');

You might want to look at the TieOut module that comes with 
ExtUtils::MakeMaker. I myself have a version of it in the App::Info 
distribution, in t/lib:

  http://search.cpan.org/src/DWHEELER/App-Info-0.25/t/lib/TieOut.pm

Regards,

David