in reply to Pre-empting STDIN during Testing
Using this approach, you can inject on the fly, interleave injections and reads, and also simulate EOF input conditions.
The following code, which should work back to Perl 5.6, shows one way to do it.
#! perl use warnings; use strict; use File::Temp qw( tempfile ); # this function encapsulates the technique. # it returns a function that can be used to # inject input into the targeted file handle sub inject_input { my $target_fh = shift; my ($temp_fh, $temp_fn) = tempfile(); my $temp_fd = fileno $temp_fh; local *SAVED; local *TARGET = $target_fh; local *INJECT; open SAVED, "<&TARGET" or die "can't remember target"; open TARGET, "<&=$temp_fd" or die "can't redirect target"; open INJECT, "+>>$temp_fn" or die "can't open injector"; unlink $temp_fn; # we don't need the directory entry any more select((select(INJECT), $| = 1)[0]); my $saved_fh = *SAVED; my $inject_fh = *INJECT; return sub { if (@_) { print $inject_fh @_; } else { seek $inject_fh, 0, 0 or die "can't seek"; # rewind my $injected_output = do { local $/; <$inject_fh> }; close $temp_fh or die "can't close temp file handle"; local (*SAVED, *TARGET, *INJECT) = ($saved_fh, $target_fh, $inject_fh); open TARGET, "<&SAVED" or die "can't restore target"; close SAVED or die "can't close SAVED"; close INJECT or die "can't close INJECT"; return $injected_output; } } }
Here is an example of how to use the function:
# let us inject input into STDIN my $injector = inject_input(*STDIN); # the resulting injector takes a string to inject $injector->("1234\n"); # inject 1234 print "r: ", scalar <STDIN>; # read 1234 back in # now we can inject 5678, a, and b # we can read them back in via a loop $injector->("5678\n"); # inject 5678 $injector->("a\n", "b\n"); # inject a and b while (<>) { print "R: $_"; } # after the read loop reaches the EOF, we # can still inject more input and read it $injector->("we're outta here\n"); print "r: ", <>; # when we are done, we call the injector with # no arguments; this will close down the injection # apparatus, restore STDIN to its pre-injection # condition, and return a copy of what was injected # for flight-recording purposes print "\n\nwe injected:\n\n", $injector->(); # now STDIN is restored print "\n\nEnter text by hand:\n"; while (<>) { print "You entered: $_"; } # actual output follows: __END__ r: 1234 R: 5678 R: a R: b r: we're outta here we injected: 1234 5678 a b we're outta here Enter text by hand: blah You entered: blah blah You entered: blah blah You entered: blah
I hope this helps.
Cheers,
Tom
Tom Moertel : Blog / Talks / CPAN / LectroTest / PXSL / Coffee / Movie Rating Decoder
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re^2: Pre-empting STDIN during Testing
by jkeenan1 (Deacon) on Feb 15, 2005 at 14:13 UTC |