Thanks everyone for your thoughts on a cli test case.
Marcus wrote:
> There is a ShellTestCase in shell_tester.php. It's a
bit lightweight.
> If you extend it with features, let me know and we can
roll them back
> into SimpleTest.
Here's what I've knocked together so far:
First a simple script to test the new test case:
fwrite(STDOUT, "what is your pet type?n");
$reply = trim(fgets(STDIN));
if('exit' == $reply) {
exit(0);
}
if('Norwegian Blue' == $reply) {
fwrite(STDERR, "he doesn't look at all
welln");
exit(1);
} else {
fwrite(STDOUT, "that's a nice $replyn");
exit(0);
}
The test:
SimpleTestOptions::ignore('InteractiveShellTestCase');
class TestOfInteractiveShellTestCase extends
InteractiveShellTestCase {
function testExecute() {
$this->execute('whoami');
$this->assertEqual($this->getStdout(),
`whoami`);
}
function testPetshopWhenPetIsNorwegianBlue() {
$this->execute(
'php petshop.php',
'/path/to/petshop-dir/');
$this->enter("Norwegian Bluen");
$this->enter("exitn");
$this->assertPattern('/what is your pet
type?/',
$this->getStdout()); $this->assertPattern('/he
doesn't look at all
well/', $this->getStderr()); }
function testPetshopWhenPetIsGannet() {
$this->execute(
'php petshop.php',
'/path/to/petshop-dir/');
$this->enter("gannetn");
$this->enter("exitn");
$this->assertPattern('/what is your pet
type?/',
$this->getStdout()); $this->assertPattern('/that's a
nice gannet/',
$this->getStdout());
$this->assertEqual($this->getStderr(), '');
}
function testScriptOutputIsCached() {
$this->execute(
'php petshop.php',
'/path/to/petshop-dir/');
$this->enter("Norwegian Bluen");
$this->enter("exitn");
$this->assertEqual($this->getStdout(),
$this->getStdout());
$this->assertEqual($this->getStderr(),
$this->getStderr());
}
}
The test case class:
class InteractiveShellTestCase extends UnitTestCase {
var $_fdmap = array(
0 => array("pipe", "r"),
1 => array("pipe", "w"),
2 => array("pipe", "w"));
var $_process;
var $_pipes;
function after($method) {
parent::after($method);
unset($this->_stdout);
unset($this->_stderr);
if(is_resource($this->_process)) {
$this->enter("exitn");
fclose($this->_pipes[0]);
fclose($this->_pipes[1]);
fclose($this->_pipes[2]);
proc_close($this->_process);
}
}
function execute($shell_command, $cwd = null) {
$this->_process = proc_open(
$shell_command,
$this->_fdmap,
$this->_pipes,
$cwd);
}
function enter($input) {
fwrite($this->_pipes[0], $input);
}
function getStdout() {
if( !isset($this->_stdout)) {
$this->_stdout =
stream_get_contents($this->_pipes[1]);
}
return $this->_stdout;
}
function getStderr() {
if( !isset($this->_stderr)) {
$this->_stderr =
stream_get_contents($this->_pipes[2]);
}
return $this->_stderr;
}
}
To recap, I specifically need to test interactive shell
scripts (not
supported by the current ShellTestCase). Tests need to
manipulate the
script by sending input and reading output while the
manipulated script
runs through various logical paths.
I've never used proc_open before in my life so I could have
got the
following completely wrong...
It appears that you cannot send an input, read the output,
send another
input, read the next output, and so on, in sequence. You can
write any
number of inputs to the executed script STDIN, but you can
only get
its STDOUT (and STDERR) output back in one big, amalgamated
chunk with
stream_get_contents. That's not bad but it could fall down
in more
complex cases. Imagine trying to reconstruct a conversation
where,
rather than a sequential dialogue, you have a list of
comments made by
person A in one file and everything from person B in
another. You can't
tell which comment is a reply to which other comment (well,
a human
brain probably could do it by context but try defining
"context" in
code: basically that's everything you ever experienced in
your
entire life..). Is there a way to get the output back in
bits?
It appears that, if the executed script has more fgets()
calls than
there are client fwrites to executed STDIN, php will hang
(not
timeout) while executed waits for input which never arrives.
Therefore,
if every interactive dialogue in executed has an exit
option, and you
always add an extra $this->enter("exitn") call
in tests when you're
done defining the "normal" list of entries, you're
covered. I think...
You may not always be able to predict how many inputs
executed will
ask for, depending how complex is the script.
Finally, to merge this with ShellTestCase, perhaps another
object should
be pulled out, encapsulating the proc_open process.
Noel
------------------------------------------------------------
-------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and
take
control of your XML. No limits. Just data. Click to get it
now.
http://sourcefor
ge.net/powerbar/db2/
_______________________________________________
Simpletest-support mailing list
Simpletest-support lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/simp
letest-support
|