diff options
Diffstat (limited to 'tests')
51 files changed, 4251 insertions, 0 deletions
diff --git a/tests/PexpectTestCase.py b/tests/PexpectTestCase.py new file mode 100644 index 0000000..f6dff60 --- /dev/null +++ b/tests/PexpectTestCase.py @@ -0,0 +1,36 @@ + +''' +PEXPECT LICENSE + + This license is approved by the OSI and FSF as GPL-compatible. + http://opensource.org/licenses/isc-license.txt + + Copyright (c) 2012, Noah Spurrier <noah@noah.org> + PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY + PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE + COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES. + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +''' + +import unittest +import sys +import os + +class PexpectTestCase(unittest.TestCase): + def setUp(self): + self.PYTHONBIN = sys.executable + self.original_path = os.getcwd() + newpath = os.path.join (os.environ['PROJECT_PEXPECT_HOME'], 'tests') + os.chdir (newpath) + print '\n', self.id(), + unittest.TestCase.setUp(self) + def tearDown(self): + os.chdir (self.original_path) + diff --git a/tests/README b/tests/README new file mode 100644 index 0000000..295632b --- /dev/null +++ b/tests/README @@ -0,0 +1,18 @@ + +The best way to run these tests is from the directory above this one. Source +the test.env environment file. This will make sure that you are using the +correct pexpect.py file otherwise Python might try to import a different +version if it is already installed in this environment. Then run the testall.py +script in the tools/ directory. This script will automatically build a test +suite from all the test scripts in the tests/ directory. This allows you to add +new test scripts simply by dropping them in the tests/ directory. You don't +have to register the test or do anything else to integrate it into the test +suite. + +For example, this is the normal set of commands you would use to run all tests +in the tests/ directory: + + $ cd /home/user/pexpect_dev/ + $ . test.env + $ ./tools/testall.py + diff --git a/tests/TESTDATA.txt b/tests/TESTDATA.txt new file mode 100644 index 0000000..adb9c01 --- /dev/null +++ b/tests/TESTDATA.txt @@ -0,0 +1,8 @@ +This is test data. + One + 2 + THREE + IV + ..... + 110 +This is the end of test data: END diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100755 index 0000000..f717d82 --- /dev/null +++ b/tests/__init__.py @@ -0,0 +1,25 @@ + +''' +PEXPECT LICENSE + + This license is approved by the OSI and FSF as GPL-compatible. + http://opensource.org/licenses/isc-license.txt + + Copyright (c) 2012, Noah Spurrier <noah@noah.org> + PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY + PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE + COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES. + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +''' + +# __init__.py +# The mere presence of this file makes the dir a package. +pass + diff --git a/tests/adhoc.py b/tests/adhoc.py new file mode 100755 index 0000000..8567a71 --- /dev/null +++ b/tests/adhoc.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python +''' +PEXPECT LICENSE + + This license is approved by the OSI and FSF as GPL-compatible. + http://opensource.org/licenses/isc-license.txt + + Copyright (c) 2012, Noah Spurrier <noah@noah.org> + PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY + PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE + COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES. + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +''' +import pexpect +import time + +p = pexpect.spawn ('./a.out') +print p.exitstatus +p.expect (pexpect.EOF) +print p.before +time.sleep(1) +print 'exitstatus:', p.exitstatus +print 'isalive',p.isalive() +print 'exitstatus',p.exitstatus +print 'isalive',p.isalive() +print 'exitstatus',p.exitstatus + diff --git a/tests/bambi.vt b/tests/bambi.vt new file mode 100644 index 0000000..853f099 --- /dev/null +++ b/tests/bambi.vt @@ -0,0 +1,417 @@ +[?25l +[1;24r +[2J +[10;1H The +[10;1H The Adventures +[10;1H The Adventures of +[10;1H The Adventures of BAMBI +[16;1H +[15;1H Number +[15;1H Number One : +[15;1H Number One : BAMBI +[15;1H Number One : BAMBI versus +[15;1H Number One : BAMBI versus GODZILLA +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[16;1H +[2J +[23;5H ,| *./[24;5H\|(/|/[1;1H +[22;38H /|[23;38H |/`|',[24;38H/| \|/[1;1H +[23;65H \/_,| /| /,[24;65H /<|\\/\|/|\[1;1H +[15;1H _^_ +[16;1H o / .\ +[17;1H \,--------; __o +[18;1H / .:::. . / +[19;1H \___________/ +[20;1H |\ |\ +[21;1H | > | \ +[22;1H / / | \ +[15;2H _^_ +[16;2H o / .\ +[17;2H \,--------; __o +[18;2H / .:::. . / +[19;2H \___________/ +[20;2H \| |\ +[21;2H \ | \ +[22;2H / \ / | +[15;3H _^_ +[16;3H o / .\ +[17;3H \,--------; __o +[18;3H / .:::. . / +[19;3H \___________/ +[20;3H \\ \| +[21;3H \\ \ +[22;3H | \ |\ +[15;4H _^_ +[16;4H o / .\ +[17;4H \,--------; __o +[18;4H / .:::. . / +[19;4H \___________/ +[20;4H \\ \| +[21;4H >\ \ +[22;4H / | /| +[15;5H _^_ +[16;5H o / .\ +[17;5H \,--------; __o +[18;5H / .:::.. . / +[19;5H \___________/ +[20;5H |\ |\ +[21;5H | > | \ +[22;5H / / | \ +[15;6H _^_ +[16;6H o / .\ +[17;6H \,--------; __o +[18;6H / .:::.. . / +[19;6H \___________/ +[20;6H \| |\ +[21;6H \ | \ +[22;6H / \ / | +[15;18H +[16;18H +[17;18H--,_^_ +[18;18H. .\ +[19;18H__--___o +[17;18H--_ +[18;18H. \ +[19;18H__ \/| +[20;18H|\( .| +[21;18H| \\ / +[22;18H | " +[17;18H--_ +[18;18H. \ +[19;18H__ \/| +[20;18H|\( .| +[21;18H| \\ / +[22;18H | " +[17;18H--_ +[18;18H. \ +[19;18H__ \/| +[20;18H|\( .| +[21;18H| \\ / +[22;18H | " +[17;18H--_ +[18;18H. \ +[19;18H__ \/| +[20;18H|\( .| +[21;18H| \\ / +[22;18H | " +[17;18H--,_^_ +[18;18H. .\ +[19;18H__--___o +[20;18H|\ +[21;18H| \ +[22;18H | +[15;7H _^_ +[16;7H o / .\ +[17;7H \,--------; __o +[18;7H / .:::.. . / +[19;7H \___________/ +[20;7H \\ \| +[21;7H \\ \ +[22;7H | \ |\ +[15;8H _^_ +[16;8H o / .\ +[17;8H \,--------; __o +[18;8H / .:::.. . / +[19;8H \___________/ +[20;8H \\ \| +[21;8H >\ \ +[22;8H / | /| +[15;9H _^_ +[16;9H o / .\ +[17;9H \,--------; __o +[18;9H / .:::.. . / +[19;9H \___________/ +[20;9H |\ |\ +[21;9H | > | \ +[22;9H / / | \ +[15;10H _^_ +[16;10H o / .\ +[17;10H \,--------; __o +[18;10H / .:::.. . / +[19;10H \___________/ +[20;10H \| |\ +[21;10H \ | \ +[22;10H / \ / | +[15;11H _^_ +[16;11H o / .\ +[17;11H \,--------; __o +[18;11H / .:::.. . / +[19;11H \___________/ +[20;11H \\ \| +[21;11H \\ \ +[22;11H | \ |\ +[15;12H _^_ +[16;12H o / .\ +[17;12H \,--------; __o +[18;12H / .:::.. . / +[19;12H \___________/ +[20;12H \\ \| +[21;12H >\ \ +[22;12H / | /| +[15;13H _^_ +[16;13H o / .\ +[17;13H \,--------; __o +[18;13H / .:::.. . / +[19;13H \___________/ +[20;13H |\ |\ +[21;13H | > | \ +[22;13H / / | \ +[15;14H _^_ +[16;14H o / .\ +[17;14H \,--------; __o +[18;14H / .:::.. . / +[19;14H \___________/ +[20;14H \| |\ +[21;14H \ | \ +[22;14H / \ / | +[15;15H _^_ +[16;15H o / .\ +[17;15H \,--------; __o +[18;15H / .:::.. . / +[19;15H \___________/ +[20;15H \\ \| +[21;15H \\ \ +[22;15H | \ |\ +[15;16H _^_ +[16;16H o / .\ +[17;16H \,--------; __o +[18;16H / .:::.. . / +[19;16H \___________/ +[20;16H \\ \| +[21;16H >\ \ +[22;16H / | /| +[15;17H _^_ +[16;17H o / .\ +[17;17H \,--------; __o +[18;17H / .:::.. . / +[19;17H \___________/ +[20;17H |\ |\ +[21;17H | > | \ +[22;17H / / | \ +[15;29H +[16;29H +[17;29H--,_^_ +[18;29H. .\ +[19;29H__--___o +[17;29H--_ +[18;29H. \ +[19;29H__ \/| +[20;29H|\( .| +[21;29H| \\ / +[22;29H| \" +[17;29H--_ +[18;29H. \ +[19;29H__ \/| +[20;29H|\( .| +[21;29H| \\ / +[22;29H| \" +[17;29H--,_^_ +[18;29H. .\ +[19;29H__--___o +[20;29H|\ +[21;29H| \ +[22;29H| \ +[17;29H--,_^_ +[18;29H. .\ +[19;29H__--___o +[20;29H|\ +[21;29H| \ +[22;29H| \ +[17;29H--_ +[18;29H. \ +[19;29H__ \/| +[20;29H|\( .| +[21;29H| \\ / +[22;29H| \" +[17;29H--_ +[18;29H. \ +[19;29H__ \/| +[20;29H|\( .| +[21;29H| \\ / +[22;29H| \" +[17;29H--_ +[18;29H. \ +[19;29H__ \/| +[20;29H|\( .| +[21;29H| \\ / +[22;29H| \" +[17;29H--,_^_ +[18;29H. .\ +[19;29H__--___o +[20;29H|\ +[21;29H| \ +[22;29H| \ +[15;18H _^_ +[16;18H o / .\ +[17;18H \,--------; __o +[18;18H / .:::.. . / +[19;18H \___________/ +[20;18H \| |\ +[21;18H \ | \ +[22;18H / \ / | +[15;19H _^_ +[16;19H o / .\ +[17;19H \,--------; __o +[18;19H / .:::.. . / +[19;19H \___________/ +[20;19H \\ \| +[21;19H \\ \ +[22;19H | \ |\ +[15;20H _^_ +[16;20H o / .\ +[17;20H \,--------; __o +[18;20H / .:::.. . / +[19;20H \___________/ +[20;20H \\ \| +[21;20H >\ \ +[22;20H / | /| +[15;21H _^_ +[16;21H o / .\ +[17;21H \,--------; __o +[18;21H / .:::.. . / +[19;21H \___________/ +[20;21H |\ |\ +[21;21H | > | \ +[22;21H / / | \ +[15;22H _^_ +[16;22H o / .\ +[17;22H \,--------; __o +[18;22H / .:::.. . / +[19;22H \___________/ +[20;22H \| |\ +[21;22H \ | \ +[22;22H / \ / | +[15;23H _^_ +[16;23H o / .\ +[17;23H \,--------; __o +[18;23H / .:::.. . / +[19;23H \___________/ +[20;23H \\ \| +[21;23H \\ \ +[22;23H | \ |\ +[15;24H _^_ +[16;24H o / .\ +[17;24H \,--------; __o +[18;24H / .:::.. . / +[19;24H \___________/ +[20;24H \\ \| +[21;24H >\ \ +[22;24H / | /| +[15;24H +[16;24H o +[17;24H \,----------,_^_ +[18;24H / .:::.. . .\ +[19;24H \___________--___o +[20;24H \\ \| +[21;24H >\ \ +[22;24H / | /| +[15;24H +[16;24H o +[17;24H \,----------_ +[18;24H / .:::.. . \ +[19;24H \___________ \/| +[20;24H \\ \|( .| +[21;24H >\ \ \ / +[22;24H / | /| " +[1;15r +[1;10H`' `.__________________________________/M +[1;10H( / ([1;54H/M +[1;10H(-.___[1;55H)M +[1;11H/ \/[1;55H)M +[1;12H_______.--'[1;54H\M +[1;23H,____________/[1;53H\M +[1;37H( / )M +[1;37H( ) /M +[1;37H\ \ )M +[1;36H( )M +[1;36H( ( /M +[1;36H\ ( )M +[1;35H( \ )M +[1;35H( ( /M +[1;16r +[1;35H\ ( ) )M +[1;17r +[1;34H( ( / )M +[1;18r +[1;34H( \ ) /M +[1;19r +[1;34H\ ( ) )M +[1;20r +[1;33H( ) )M +[1;21r +[1;33H( ) /M +[1;22r +[1;33H\ / )M +[1;24r +[1;32H( ) ) +[23;25H / > | \ +[1;1H +[1;1H +[10;1H T[10;1H T[10;1H T +[10;1H T H[10;1H T H[10;1H T H +[10;1H T H E[10;1H T H E[10;1H T H E [10;1H T H E +[10;1H T H E E[10;1H T H E E[10;1H T H E E +[10;1H T H E E N[10;1H T H E E N[10;1H T H E E N +[10;1H T H E E N D[10;1H T H E E N D +[11;1H =============== +[22;1H +[?25h diff --git a/tests/depricated_test_filedescriptor.py b/tests/depricated_test_filedescriptor.py new file mode 100755 index 0000000..f5223f4 --- /dev/null +++ b/tests/depricated_test_filedescriptor.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python +''' +PEXPECT LICENSE + + This license is approved by the OSI and FSF as GPL-compatible. + http://opensource.org/licenses/isc-license.txt + + Copyright (c) 2012, Noah Spurrier <noah@noah.org> + PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY + PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE + COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES. + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +''' +import pexpect +import unittest +import PexpectTestCase +import sys +import os + +class ExpectTestCase(PexpectTestCase.PexpectTestCase): + def setUp(self): + print self.id() + PexpectTestCase.PexpectTestCase.setUp(self) + + def test_fd (self): + fd = os.open ('TESTDATA.txt', os.O_RDONLY) + s = pexpect.spawn (fd) + s.expect ('This is the end of test data:') + s.expect (pexpect.EOF) + assert s.before == ' END\n' + + def test_maxread (self): + fd = os.open ('TESTDATA.txt', os.O_RDONLY) + s = pexpect.spawn (fd) + s.maxread = 100 + s.expect('2') + s.expect ('This is the end of test data:') + s.expect (pexpect.EOF) + assert s.before == ' END\n' + + def test_fd_isalive (self): + fd = os.open ('TESTDATA.txt', os.O_RDONLY) + s = pexpect.spawn (fd) + assert s.isalive() + os.close (fd) + assert not s.isalive() + + def test_fd_isatty (self): + fd = os.open ('TESTDATA.txt', os.O_RDONLY) + s = pexpect.spawn (fd) + assert not s.isatty() + os.close(fd) + +### def test_close_does_not_close_fd (self): +### '''Calling close() on a pexpect.spawn object should not +### close the underlying file descriptor. +### ''' +### fd = os.open ('TESTDATA.txt', os.O_RDONLY) +### s = pexpect.spawn (fd) +### try: +### s.close() +### self.fail('Expected an Exception.') +### except pexpect.ExceptionPexpect, e: +### pass + +if __name__ == '__main__': + unittest.main() + +suite = unittest.makeSuite(ExpectTestCase, 'test') + +#fout = open('delete_me_1','wb') +#fout.write(the_old_way) +#fout.close +#fout = open('delete_me_2', 'wb') +#fout.write(the_new_way) +#fout.close diff --git a/tests/echo_wait.py b/tests/echo_wait.py new file mode 100755 index 0000000..db940de --- /dev/null +++ b/tests/echo_wait.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python +''' +PEXPECT LICENSE + + This license is approved by the OSI and FSF as GPL-compatible. + http://opensource.org/licenses/isc-license.txt + + Copyright (c) 2012, Noah Spurrier <noah@noah.org> + PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY + PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE + COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES. + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +''' +import signal, time, struct, fcntl, termios, os, sys + +# a dumb PAM will print the password prompt first then set ECHO +# False. What it should do it set ECHO False first then print the +# prompt. Otherwise, if we see the password prompt and type out +# password real fast before it turns off ECHO then some or all of +# our password might be visibly echod back to us. Sounds unlikely? +# It happens. + +print "fake password:" +sys.stdout.flush() +time.sleep(3) +attr = termios.tcgetattr(sys.stdout) +attr[3] = attr[3] & ~termios.ECHO +termios.tcsetattr(sys.stdout, termios.TCSANOW, attr) +time.sleep(12) +attr[3] = attr[3] | termios.ECHO +termios.tcsetattr(sys.stdout, termios.TCSANOW, attr) +time.sleep(2) diff --git a/tests/exit1.py b/tests/exit1.py new file mode 100755 index 0000000..4e07377 --- /dev/null +++ b/tests/exit1.py @@ -0,0 +1,24 @@ +''' +PEXPECT LICENSE + + This license is approved by the OSI and FSF as GPL-compatible. + http://opensource.org/licenses/isc-license.txt + + Copyright (c) 2012, Noah Spurrier <noah@noah.org> + PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY + PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE + COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES. + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +''' +import os, sys + +print "Hello" +sys.stdout.flush() +os._exit(1) diff --git a/tests/exit667.c b/tests/exit667.c new file mode 100644 index 0000000..962b9fd --- /dev/null +++ b/tests/exit667.c @@ -0,0 +1,26 @@ +/* + PEXPECT LICENSE + + This license is approved by the OSI and FSF as GPL-compatible. + http://opensource.org/licenses/isc-license.txt + + Copyright (c) 2012, Noah Spurrier <noah@noah.org> + PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY + PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE + COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES. + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +*/ + +#include <stdio.h> +int main () +{ + printf ("Hello world!\n"); + exit(7); +} diff --git a/tests/getch.py b/tests/getch.py new file mode 100755 index 0000000..53ff2c7 --- /dev/null +++ b/tests/getch.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python +''' +PEXPECT LICENSE + + This license is approved by the OSI and FSF as GPL-compatible. + http://opensource.org/licenses/isc-license.txt + + Copyright (c) 2012, Noah Spurrier <noah@noah.org> + PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY + PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE + COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES. + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +''' +import sys, tty, termios +def getch(): + fd = sys.stdin.fileno() + old_settings = termios.tcgetattr(fd) + try: + tty.setraw(sys.stdin.fileno()) + ch = sys.stdin.read(1) + finally: + termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) + return ch + +#for i in range(256): +# Current Python unicode support was too hard to figure out. +# This only tests the true ASCII characters now: +for i in range(126): + c = getch() + a = ord(c) # chr(a) + print a + diff --git a/tests/globe.vt b/tests/globe.vt new file mode 100644 index 0000000..85dc78d --- /dev/null +++ b/tests/globe.vt @@ -0,0 +1,690 @@ +[H[J _-o#&&*''''?d:>b\_ + _o/"`'' '',, dMF9MMMMMHo_ + .o&#' `"MbHMMMMMMMMMMMHo. + .o"" ' vodM*$&&HMMMMMMMMMM?. + ,' $M&ood,~'`(&##MMMMMMH\ + / ,MMMMMMM#b?#bobMMMMHMMML + & ?MMMMMMMMMMMMMMMMM7MMM$R*Hk + ?$. :MMMMMMMMMMMMMMMMMMM/HMMM|`*L +| |MMMMMMMMMMMMMMMMMMMMbMH' T, +$H#: `*MMMMMMMMMMMMMMMMMMMMb#}' `? +]MMH# ""*""""*#MMMMMMMMMMMMM' - +MMMMMb_ |MMMMMMMMMMMP' : +HMMMMMMMHo `MMMMMMMMMT . +?MMMMMMMMP 9MMMMMMMM} - +-?MMMMMMM |MMMMMMMMM?,d- ' + :|MMMMMM- `MMMMMMMT .M|. : + .9MMM[ &MMMMM*' `' . + :9MMk `MMM#" - + &M} ` .- + `&. . + `~, . ./ + . _ .- + '`--._,dd###pp=""' +[H _v->#H#P? "':o<>\_ + .,dP` `'' "'-o.+H6&MMMHo_ + oHMH9' `?&bHMHMMMMMMHo. + oMP"' ' ooMP*#&HMMMMMMM?. + ,M* - `*MSdob//`^&##MMMH\ + d*' .,MMMMMMH#o>#ooMMMMMb + HM- :HMMMMMMMMMMMMMMM&HM[R\ + d"Z\. 9MMMMMMMMMMMMMMMMM[HMM|: +-H - MMMMMMMMMMMMMMMMMMMbMP' : +:??Mb# `9MMMMMMMMMMMMMMMMMMH#! . +: MMMMH#, "*""""`#HMMMMMMMMMMH - +||MMMMMM6\. {MMMMMMMMMH' : +:|MMMMMMMMMMHo `9MMMMMMMM' . +. HMMMMMMMMMMP' !MMMMMMMM ` +- `#MMMMMMMMM HMMMMMMM*,/ : + : ?MMMMMMMF HMMMMMM',P' : + . HMMMMR' {MMMMP' ^' - + : `HMMMT iMMH' .' + -.`HMH . + -:*H . ' + -`\,, . .- + ' . _ .-` + '`~\.__,obb#q==~''' +[H .ovr:HMM#?:`' >b\_ + .,:&Hi' `' "' \\|&bSMHo_ + oHMMM#*} `?&dMMMMMMHo. + .dMMMH"'''' ,oHH*&&9MMMM?. + ,MMM*' `*M\bd<|"*&#MH\ + dHH?' :MMMMMM#bd#odMML + H' |\ `dMMMMMMMMMMMMMM9Mk + JL/"7+,. `MMMMMMMMMMMMMMMH9ML +-`Hp ' |MMMMMMMMMMMMMMMMHH|: +: \\#M#d? `HMMMMMMMMMMMMMMMMH. +. JMMMMM##, ``*""'"*#MMMMMMMMH +-. ,MMMMMMMM6o_ |MMMMMMMM': +: |MMMMMMMMMMMMMb\ TMMMMMMT : +. ?MMMMMMMMMMMMM' :MMMMMM|.` +- ?HMMMMMMMMMM: HMMMMMM\|: + : 9MMMMMMMMH' `MMMMMP.P. + . `MMMMMMT'' HMMM*''- + - TMMMMM' MM*' - + '. HMM# - + -. `9M: .' + -. `b,, . . ' + '-\ ., .-` + '-:b~\\_,oddq==--" +[H _oo##'9MMHb':'-,o_ + .oH":HH$' ""' "' -\7*R&o_ + .oHMMMHMH#9: "\bMMMMHo. + dMMMMMM*""'`' .oHM"H9MM?. + ,MMMMMM' "HLbd<|?&H\ + JMMH#H' |MMMMM#b>bHb + :MH ."\ `|MMMMMMMMMMMM& + .:M:d-"|:b.. 9MMMMMMMMMMMMM+ +: "*H| - &MMMMMMMMMMMMMH: +. `LvdHH#d? `?MMMMMMMMMMMMMb +: iMMMMMMH#b `"*"'"#HMMMMMM +. . ,MMMMMMMMMMb\. {MMMMMH +- |MMMMMMMMMMMMMMHb, `MMMMM| +: |MMMMMMMMMMMMMMH' &MMMM, +- `#MMMMMMMMMMMM |MMMM6- + : `MMMMMMMMMM+ ]MMMT/ + . `MMMMMMMP" HMM*` + - |MMMMMH' ,M#'- + '. :MMMH| .- + . |MM - + ` . `#?.. . ..' + -. _. .- + '-|.#qo__,,ob=~~-'' +[H _ooppH[`MMMD::--\_ + _oHMR":&M&. ""' "' /&\\_ + oHMMMMMHMMH#9, `"<MMHo. + oHMMMMMMMM*""'`` .dMP#M?. + .dMMMMMMMM* `H\do?&\ + -iMMMHH#H' &MMMHb#? + : ZMM' 7-. `{MMMMMMMMH + . .M6_d|"`$|v.. 9MMMMMMMMML +- `'*H# : |MMMMMMMMMM: +: *\\dHM#dd. ?MMMMMMMMMb +- |MMMMMMM##\ `"*""?HMMM +: . |MMMMMMMMMMMo\. {MMM +. {MMMMMMMMMMMMMMMHo. `MMM +- ?MMMMMMMMMMMMMMM*' -MMP +: `#MMMMMMMMMMMMT dMM' + - |MMMMMMMMMMH' -MMT + : `MMMMMMMM"' JMP + - MMMMMMH' ,H? + '. HMMM#' : + . ?MM- . ' + -. *M:.. .- + - . _. .- + '-.~-dHb__\ov+~~-` +[H .oo>#&H6?*MMH:-.._ + .oHMMMR:"&MZ\ `"' " |$-_ + ..dMMMMMMMMdMMM#9\ `'HHo. + . ,dMMMMMMMMMMM"`' ` ?MP?. + . |MMMMMMMMMMM' `"$b&\ + - |MMMMHH##M' HMMH? + - TTMM| >.. \MMMMMH + : |MM\,#-""$~b\. `MMMMMM+ +. ``"H&# - &MMMMMM| +: *\v,#MHddc. `9MMMMMb +. MMMMMMMM##\ `"":HM +- . .HMMMMMMMMMMRo_. |M +: |MMMMMMMMMMMMMMMM#\ :M +- `HMMMMMMMMMMMMMMM' |T +: `*HMMMMMMMMMMMM' H' + : MMMMMMMMMMM| |T + . MMMMMMMM?' ./ + `. MMMMMMH' ./ + -. |MMMH#' . + . `MM* . ' + -. #M: . . .- + ` . ., .- + '-.-~ooHH__,,v~--` +[H _ood>H&H&Z?#M#b-\. + .\HMMMMMR?`\M6b."`' ''``v. + .. .MMMMMMMMMMHMMM#&. ``~o. + . ,HMMMMMMMMMMMM*"'-` &b. + . .MMMMMMMMMMMMH' `"&\ + - RMMMMM#H##R' 4Mb + - |7MMM' ?:: `|MMb + / HMM__#|`"\>?v.. `MMML +. `"'#Hd| ` 9MMM: +- |\,\?HH#bbL `9MMb +: !MMMMMMMH#b, `""T +. . ,MMMMMMMMMMMbo. | +: 4MMMMMMMMMMMMMMMHo | +: ?MMMMMMMMMMMMMMM? : +-. `#MMMMMMMMMMMM: .- + : |MMMMMMMMMM? . + - JMMMMMMMT' : + `. MMMMMMH' - + -. |MMM#*` - + . HMH' . ' + -. #H:. .- + ` . .\ .- + '-..-+oodHL_,--/-` +[H _,\?dZkMHF&$*q#b.. + .//9MMMMMMM?:'HM\\"`-''`.. + ..` :MMMMMMMMMMHMMMMH?_ `-\ + . .dMMMMMMMMMMMMMM'"'" `\. + . |MMMMMMMMMMMMMR \\ + - T9MMMMMHH##M" `? + : (9MMM' !':. &k + .: HMM\_?p "":-b\. `ML +- "'"H&#, : |M| +: ?\,\dMH#b#. 9b +: |MMMMMMM##, `* +: . +MMMMMMMMMMMo_ - +: HMMMMMMMMMMMMMM#, : +: 9MMMMMMMMMMMMMH' . +: . *HMMMMMMMMMMP .' + : MMMMMMMMMH' . + - :MMMMMMM'` . + `. 9MMMMM*' - + -. {MMM#' : + - |MM" .' + `. &M'.. . ..' + ' . ._ .- + '-. -voboo#&:,-.-` +[H _oo:\bk99M[<$$+b\. + .$*"MMMMMMMM[:"\Mb\?^" . + . '` HMMMMMMMMMMHMMMM+?. `. + . .HMMMMMMMMMMMMMMP"'' . + . `MMMMMMMMMMMMMM| -`. + - `&MMMMMMHH##H: : + : `(*MMM} `|\ | + : `- ?MMb__#|""`|+v.. \ +. `''*H#b - :| +: `*\v,#M#b#, \ +. 9MMMMMMHb. : +: . #MMMMMMMMMb\ - +- .HMMMMMMMMMMMMb : +: `MMMMMMMMMMMMH . +-: . `#MMMMMMMMMP ' + : ]MMMMMMMH' : + - ,MMMMMM?' . + `: HMMMMH" - + -. .HMM#* .- + `. .HH*' . + `-. &R". .- + -. ._ .- + '-. .voodoodc?..-` +[H _\oo\?ddk9MRbS>v\_ + ..:>*""MMMMMMMMM:?|H?$?-. + ..- - "HMMMMMMMMMMHMMMH\_-. + . dMMMMMMMMMMMMMMT" . + . TMMMMMMMMMMMMMM `. + - `&HMMMMMM#H#H: . + - `\7HMMH |\. . + : ` HMM\_?c`""+?\.. : +- "``#&#| . - +: `?,\#MHdb. . +: |MMMMMH#. : +: . ,HMMMMMMMb, - +: ' 4MMMMMMMMMMH` +: . 9MMMMMMMMMT- +:.` `#MMMMMMMH ' + : ' HMMMMMH': + - |MMMMH" - + `: |MMMH*' .' + '? dMM#' . + \. .dH" .' + -. ,M'- ..' + ` . .. ..-` + '-. .\ooooboo<^.-` +[H _o,:o?\?dM&MHcc~,. + ..^':&#""HMMMMMMMM$:?&&?. + .` -` 'HMMMMMMMMMHMMMp\. + . ' |MMMMMMMMMMMMMM"' . + . `9MMMMMMMMMMMMM -. + - `*9MMMMMHH##[ . + - `\Z9MMM `~\ . + : '| ?MMb_?p""-?v.. : +- `"'*&#, - . +: `?,oHH#? . +-- |MMMMH,: +: . |MMMMMM6, +: - |MMMMMMMM +? HMMMMMMP +-- . ' |HMMMMM' + :.` . ' JMMMM+ + \ ,MMMP: + : |MMH?: + -:\. dM#" . + \ ,H*' .' + -. d':..' + ` . .,.- + '-.. .\oooodov~^-` +[H _o\:,??\??MR9#cb\_ + .v/''':&#""#HMMMMMMM$?*d\. + ..~' - -` `"#MMMMMMMMMMMHv. + .-' HMMMMMMMMMMMR!. + : `9MMMMMMMMMMM| -. + . `*9MMMMMH##| . + - `(#MMH `:, . + : '| `HMb_>/"|\,.: +.' `"'#&b - . +: ?\oHH?. +: !MMM& +: . . HMMMM +/. - -MMMMM +\`. 9MMMP +:. . . - |MMM' + \... ' .MMT + &. .dMP + \, .HM* + \. `\. ,H&' + `- `| - ,&': + `. ,/\ ' + '-.. _.- + "---.._\o,oov+--'" +[H _,d?,:?o?:?HM>#b\_ + ..H*"''`'H#*"**MMMMMM6$$v_ + v//" - `` `'#MMMMMMMMHo. + /"` |MMMMMMMMMM:. + ,> `HMMMMMMMMH:. + : `#HMMMMHH\ - + ' `Z#MM, `,: + : '\ ?HH_>:`\, +: "'*&| `: +. <\Hb +: MM +: . iMM +Mb\. {MM +::.`- - !MP +`&. . . - :M' + 9H, \ ' |T + HM? ,P + *ML ?? + :&. `o .d' + ': |T /" + -. .<'' + `... ..- + "`-=.,_,,,oov-~.-` +[H _,oc>?_:b?o?HH#b\_ + .v/99*""" '*H#""*HMMMMMZ,_ + oH* /" - ' "`#MMMMM#o. + ./*>- `MMMMMMMb + ,b/' `#MMMMMMM\ + :' ``HMMMMb: + /- `|&MH `\ + / `-. |Hb??\ +,- ' "`&,. +1 \} +!. T +$,. . 1 +?`M??. M +?.::| '\ - ? + M?&. . . - ,' + 9MMH\ .. ' ` . + HMMM#. :' + 9#MMb .. + -:"# `b. .- + . ` {! / + - ,-' + ' . .- + ```^==\_.,,,ov--\-` +[H _\o##??,:io??$#b\_ + .oH#"H9*""" "`#H*"*#MMMHo_ + oHMM- -' - '' ``*HMMHo. + dM#S>-` ?MMMM?. + ,&&,/' "#MMMH\ + d?-" `*HMMb + H? "ZHb: + /: \ H?L +|:| . `*: +:?: \ +>" : +M|\,_ | +!|":HH?-'. : +:^'_:?"\ `-- - . +- |ML?b . .. - - + :HMMMMH\ \ ` : + >MMMMMM#. . + ^M*HMMM| - + `. `"#+ `?v .` + . `- +?' - + ` . ..' + - . .- + "`\b=p?.._\\vv---` +[H _,o#bH\??::?o?cbo_ + .o#MH#**SH""' "`*H#"*#MHo_ + oHMMMH^ ^" - ` '*HHo. + .dMMM#">>- `HM?. + ,MH:R_o/ `*MH\ + dMM' ' "ML + HMR! ' `#k + d&'. -. `L +:M :: ` `- +/| !| - +k.$-" : +}9R:!,,_. . +\::\':`*M#\-'. - +: "''..:"!`\ '- - ` +- ,HMb.H| . _ - .' + : ,MMMMMMMb. .. . + .`HMMMMMMMM? . + `.`9M#*HMMMM : + -.' "##* `b, . + . ` ,/' .' + ` . ..' + - . ..- + "`*#d##c.._\v----` +[H _,o#&oHb?\o::d?>\_ + .oHHMMM#**$M""` "`*HH"#&o_ + oHMMMMMMD' .'' - ' ``bo. + .dMMMMMH*'/|- `\b. + ,MMMM?T|_o/ `\\ + dMMMMP '' `| + HMMMH& - `\ + /MH7' : -- : +-:MM {. . . +:i?' .!& . +:{, o| ' : +-T?9M\:-'o,_ . +: \?::``"`?9MHo./.. - +. '"`'^ _.`"!"^. `- - ` +- ,bMM?.M\ . . - . .' + : .oMMMMMMMMb. .. ` . + . `HMMMMMMMMMMb - + - 9MH*#HMMMMH .' + '. ' `"*##' `b. : + . ` .d'' .' + -. . ' + -. .-` + "`*##H###:._\--.-` +[H _oo#H&d#b?\b:_>>\_ + .oHMMMMMMH*"*9R"'-``*#P\-_ + oHMMMMMMMMM$ ." ' `^- + .dMMMMMMMMH*",?- '\. + ,MMMMMMM:?}.,d' `. + dMMMMMMMH /'' : + HMMMMMMM&' - - + dPTMMP>' : -. : +|? -MM} .\ . +J' ::*' -$L . +: ?b .,H- ' : +- |6.&MP:: !.,_. - +: `\:: "' "`:"MM#,-^, - : +- ````:' _.:"?``\ `- . +: .?bMML.]# - _ ` . .' + - .o#MMMMMMMMH\ \. . . + - `HMMMMMMMMMMMH : + `. `HMM#*#MMMMMH' - + -. ' ``##*' i+ : + - `' v/' .' + `- ..' + ' . .- + "`*##HMH##:__,-.-` +[H _oo##Mbb&bo??o_>\_ + .oHMMMMMMMMM**#?M*' "?*&.. + oHMMMMMMMMMMMM4 `" - `. + .dMMMMMMMMMMMM#"\?.- . + ,MMMMMMMMMM}"9:_,d' -. + dMMMMMMMMMMM| ^'' . + &MMMMMMMMMMH\ - . + :{M*"MMMPT"' : `-. : +.'M' 'MMM. -T, . . +- k i:?'' -|& . +: ` -o& .,H- " : +- `M:`HMP|:'!.o._. . +: "<:::'<^ '"``9MH#,-^ . - +- '''``''._.`"?`^| ^ - : +: ?#dMM_.M? . . - ..' + : ,ddMMMMMMMMMb. .. ' . + . TMMMMMMMMMMMMM, : + - ?MMH**#MMMMMH' : + '. ' "`##*' &. : + -. `' ,~" .' + -. ..' + ` . .- + ```*##HMMMH#<:,..-` +[H _,dd#HMb&dHo?\?:\_ + .oHMMMMMMMMMMMH***9P'`"\v. + oHMMMMMMMMMMMMMMM> `' -. + .dMMMMMMMMMMMMMMMH*'|~-' . + ,MMMMMMMMMMMMM6>`H._,& -. + dMMMMMMMMMMMMMMM| `" . + H*MMMMMMMMMMMMMH&. - . + d' HMM""&MMMPT'' :. `.- +,' MP `TMMM, |: . - +| #: ? *" : &L : +! `' /?H ,#r `' : +. ?M: HMM^<~->,o._ : +: `9:::'`*-``':`9MHb,|-, ' : +. `"''':' :_ ""!"^. `| : +`. _dbHM6_|H. . . ' .' + \ _odHMMMMMMMMH, .. ` : + `- |MMMMMMMMMMMMM| : + `. 9MMH**#MMMMMH' : + -. ' "?##" d : + . ' ,/" .' + `.. ..' + ` . .- + '`"#HHMMMMM#<>..-` +[H _oo##bHMb&d#bd,>\_ + .oHMMMMMMMMMMMMMM***9R"-.. + oHMMMMMMMMMMMMMMMMMH\ ? `-. + .dMMMMMMMMMMMMMMMMMMM#".}-' . + ,MMMMMMMMMMMMMMMMM6/`H _o} -. + dMMMMMMMMMMMMMMMMMMML `'' . + HbP*HMMMMMMMMMMMMMMM*: - , + dMH' `MMMP'"HMMMR'T" : : +|H' -MR' `?MMMb P, . . +1& *| |.`*" .-`&| . +M' " |\&| .,#~ "' : +T :HL.|HMH\c~`|v,\_ : +| `"|:::':`-`` '"MM#\-'. -: +% ``'``'`' :_ '?'`| ``. : +||, ,#dMM?.M? . .` - + ?\ .,odMMMMMMMMM? \ ` : + / |MMMMMMMMMMMMM: .' + `. TMMH#*9MMMMM* : + -. ` "*#*' ,: . + . ` .v'' .' + `. ..' + '- . .- + "`\+HHMMMMMMHr~.-` +[H _,,>#b&HMHd&&bb>\_ + _oHMMMMMMMMMMMMMMMMH**H:. + oHMMMMMMMMMMMMMMMMMMMM#v`? `. + .dMMMMMMMMMMMMMMMMMMMMMMH*`+| . + ,MMMMMMMMMMMMMMMMMMMMMb|?+.,H -. + ddHMMMMMMMMMMMMMMMMMMMMMb `' . + HMMkZ**HMMMMMMMMMMMMMMMMH\ - . : + dTMMM* `9MMMP'"*MMMMPT"` .. : +|M6H'' 4MP' `"HMMM| !|. . . +1MHp' #L $ *"' .-:&. . +MMM' " q:H. .o#-``' : +MM' ?H?.|MMH::::-o,_. - +M[ `*?:::'|` `"`:9MH\~-. ` +&M. ""'`'^'.:.`?'`. '| -: +`M|d, .dbHM[.1? .. : + 9||| . _obMMMMMMMMH, . : + H.^ MMMMMMMMMMMM} - + \ |MMH#*HMMMMH' .' + . ` `#*' ,:- + ` '' .-'. + `. .- + '- . .-` + '`\bqHMMMMMMHHb--` +[H .,:,#&6dHHHb&##o\_ + .oHHMMMMMMMMMMMMMMMMMH*\,. + oHMMMMMMMMMMMMMMMMMMMMMMHb:'-. + .dMMMMMMMMMMMMMMMMMMMMMMMMMH|\/' . + ,&HMMMMMMMMMMMMMMMMMMMMMMM/"&.,d. -. + dboMMHMMMMMMMMMMMMMMMMMMMMMML `' . + HMHMMM$Z***MMMMMMMMMMMMMMMMMM|.- . + dMM}MMMM#' `9MMMH?"`MMMMR'T' _ : +|MMMbM#'' |MM" ``MMMH. <_ . +dMMMM#& *&. .?`*" .'&: . +MMMMMH- `' -v/H .dD "' ' : +MMMM* `*M: 4MM*::-!v,_ : +MMMM `*?::" "'``"?9Mb::. : +&MMM, `"'"'|"._ "?`| - : +`MMM}.H ,#dM[_H ..: + 9MMi`M: . .ooHMMMMMMM, .. + 9Mb `- 1MMMMMMMMMM| : + ?M |MM#*#MMMM* . + -. ` |#"' ,' + . -" v` + -. .- + - . . ` + '-*#d#HHMMMMHH#"-' +[H _,<_:&S6dHHHb&bb\_ + .odHMMMMMMMMMMMMMMMMMMM}-_ + .oHMMMMMMMMMMMMMMMMMMMMMMMM#d:. + ?9MMMMMMMMMMMMMMMMMMMMMMMMMMMH-$ . + ,::dHMMMMMMMMMMMMMMMMMMMMMMMMH:\.?? -. + dMdboHMMHMMMMMMMMMMMMMMMMMMMMMMH, ' . + HMMMM7MMMb$R***MMMMMMMMMMMMMMMMMH\ - . + dMMMMM/MMMMM* `$MMMM*'"*MMMM?&' . : +|MMMMMMb1H*' HMP' '9MMM| &. . . +dMMMMMMM##~` `#\ |.`*" .-9. : +9MMMMMMMM* ` |v7? .,H `' ` : +SMMMMMMH' '9M_-MMH::-\v_ : +:HMMMMM `\_:"'|'`':9Mv\. +-|MMMMM, ""`'`':.`?\ \ +`:MMMMM}.d} .?bM6,| | + :?MMM6 M| . .,oHMMMMM| / + .?MMM- `' &MMMMMMMM|. + -`HM- HMH#*MMM?: + '. ' `#*:` + - -'/ + ` . . ' + ` . . ` + '--##HH#HMMMHH#""` +[H _o,d_?dZdoHHHb#b\_ + .vdMMMMMMMMMMMMMMMMMMMMH\. + .,HHMMMMMMMMMMMMMMMMMMMMMMMMH&,. + /?RMMMMMMMMMMMMMMMMMMMMMMMMMMMMH|.. + ,\?>`T#RMMMMMMMMMMMMMMMMMMMMMMMM6`\|/ + dMMbd#ooHMMMHMMMMMMMMMMMMMMMMMMMMMH,`' ' + HMMMMMMMTMMMMb$ZP**HMMMMMMMMMMMMMMMM|. : + dMMMMMMMM}$MMMMMH' `HMMMH?"`MMMM?T' . : +|MMMMMMMMMMoMH*'' `MM? ``MMM| +\ . +1MMMMMMMMMMMb#/ ?#? |`#" -T: : +*'HMMMMMMMMMM*' " ~?& .?} ' ' . +- 4MMMMMMMMP" `M? HMTc:\\.: +: `MMMMMMM[ "#:::`>`"?M{ +. |MMMMMMH. ``'``'_`:- +- |MMMMMMM|.dD ,#Mb\' + : *MMMMM: iM| . _oHMMMM: + . ?MMMM' "' ,MMMMMMP + : `HMH JM#*MMT + -. ' ` #' + . / + -. - .' + -. . ` + '--=&&MH##HMHH#""" +[H .-:?,Z?:&$dHH##b\_ + ,:bqRMMMMMMMMMMMMMMMMMHo. + .?HHHMMMMMMMMMMMMMMMMMMMMMMMHo. + -o/*M9MMMMMMMMMMMMMMMMMMMMMMMMMMMv + .:H\b\'|?#HHMMMMMMMMMMMMMMMMMMMMMM6?Z\ + .?MMMHbdbbodMMMMHMMMMMMMMMMMMMMMMMMMM\': + :MMMMMMMMMMM7MMMMb?6P**#MMMMMMMMMMMMMMM_ : + \MMMMMMMMMMMMb^MMMMMM? `*MMMM*"`MMMR<' . - +.1MMMMMMMMMMMMMb]M#"" 9MR' `?MMb \. : +-MMMMMMMMMMMMMMMH##|` *&. |`*' .\ . +-?""*MMMMMMMMMMMMM' ' |?b ,}" : +: MMMMMMMMMMH' `M_|M}r\? +. `MMMMMMMMM' `$_:`'"H +- TMMMMMMMM, '"``:: +: {MMMMMMMM| oH| .#M- + : `9MMMMMM' .MP . ,oMMT + . HMMMMP' `' ,MMMP + - `MMH' HH9* + '. ` ` .' + - . ' + ` . - .- + ` . .- + ' -==pHMMH##HH#""" +[H _..-:b&::&?&&##bo_ + ...?-#&9MMMMMMMMMMMMMMMHo_ + .. .1&#MMHMMMMMMMMMMMMMMMMMMMHo. + . .o/##R9MMMMMMMMMMMMMMMMMMMMMMMM?. + .- |MSd?|'`$?#HMMMMMMMMMMMMMMMMMMMMMH\ + - dMMMMHbd##oodMMMM#MMMMMMMMMMMMMMMMMH: + - JMMMMMMMMMMMMM7HMMMH$SR***MMMMMMMMMMMMb> + : {MMMMMMMMMMMMMMM`9MMMMMH' ``HMMM?"*MM[| : +- |MMMMMMMMMMMMMMMMM<MH*'' `MM' 'HM? |. +: `MMMMMMMMMMMMMMMMMM##H-' `#, ` |`? /| +. ?"""?HMMMMMMMMMMMMMH' " v& .}? +- |MMMMMMMMMMMP' `H:&H& +i `9MMMMMMMMMT `|?"? +: MMMMMMMMMH "`\ +: MMMMMMMMMH-.dH ,| + : ?MMMMMMM? {M' . .dT + . ?MMMMMR' `' ,MP + - `HMM#' .&* + '. ' `. + - . ' + `.. .- + -. .- + '-.==p##HMMHp&#""" +[H _v---:?&?:?&?&#b\_ + ..' i: #M$MMMMMMMMMMMMMHo_ + .. -]M#HMHMMMMMMMMMMMMMMMMMHo. + . ooP*&6&MMMMMMMMMMMMMMMMMMMMM?. + . - &Rbbd-/`?:##HMMMMMMMMMMMMMMMMMH? + - ,HMMMMM#od#boodMMMMHMMMMMMMMMMMMMMb + - iMMMMMMMMMMMMMMM[*MMMH&$R***MMMMMMMMMb + : |MMMMMMMMMMMMMMMMML"MMMMMM' ``MMMP"HMM: +. HMMMMMMMMMMMMMMMMMMb/MH"" `MR *M,| +: TMMMMMMMMMMMMMMMMMMMMd#&` `D. ?|\ +. `*"'"*HMMMMMMMMMMMMMMP' ' -d,J +: |MMMMMMMMMMMMP' ||M +M, ?MMMMMMMMMM| `\? +&| HMMMMMMMMM} `` +`L .MMMMMMMMMMP ,d| : + *. ?MMMMMMMF' .MP / + | TMMMMMM' `"' / + `. `MMMP' ./ + -. ` . + . . ' + - . .- + -\ ..- + '-..=p####HMH&=""" +[H _vo~^'':&b::d,#b\_ + ..`" `:v +9P]MMMMMMMMMMHo_ + ,- ?Mb#MMMMMMMMMMMMMMMMMHo. + . " ,ooM*&&&HMMMMMMMMMMMMMMMMHb. + . - 99Soo?|'`*?##HMMMMMMMMMMMMMH\ + - .HMMMMMM#od#boodMMMMHMMMMMMMMMMb + - :MMMMMMMMMMMMMMMM67HMMH&$R**HMMMMMb + : .MMMMMMMMMMMMMMMMMMM/HMMMMM| `9MM'HL +: {MMMMMMMMMMMMMMMMMMMM\MM*'' `H[ `9| +| `HMMMMMMMMMMMMMMMMMMMMb##| `F. :? +H `"*"'"`#MMMMMMMMMMMMMMM? ' k +M. MMMMMMMMMMMMM"' H +MMH. `HMMMMMMMMMM: | +&MM| `MMMMMMMMMM, - +`MM| dMMMMMMMMMM|.oH : + 9ML `HMMMMMMM? dH' - + Hi |MMMMMMP "' .' + T. `MMM#' - + `. ` .` + ` - + `.. . ..' + ... .- + '-. //######M#b~"" +[H _ooq=""''$b$_&?b\_ + .-`^" "'o |&M:MMMMMMMMHo_ + o/' -$Mb#MMMMMMMMMMMMMMHo. + /' .ooHP*&R&MMMMMMMMMMMMMM?. + .' `MRbod?|'`+?##9MMMMMMMMMH\ + .` .,MMMMMMH#od##obdMMMMHMMMMMMb + - ?MMMMMMMMMMMMMMMMM$HMMH$ZP*HMMb + ? |MMMMMMMMMMMMMMMMMMM|9MMMMP "M6\ +.- dMMMMMMMMMMMMMMMMMMMMb]M*' |R | +1| `HMMMMMMMMMMMMMMMMMMMMMd#| ?,: +MH, ``*""'"*#MMMMMMMMMMMMMM* '` +MM6_ |MMMMMMMMMMMMH" : +MMMMMb. "MMMMMMMMMMT - +&MMMMM' |MMMMMMMMMH ` +!MMMMb .HMMMMMMMMM+.?& : + TMMMM *MMMMMMMP dH' . : + 9MM' `MMMMMMP' "' . + 9ML `MMM#' - + `H ` : + `\. .' + `-\ . .- + ' ._ .-` + '-\. ,b#####p&**^` diff --git a/tests/interact.py b/tests/interact.py new file mode 100755 index 0000000..c37c6d9 --- /dev/null +++ b/tests/interact.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python +''' +PEXPECT LICENSE + + This license is approved by the OSI and FSF as GPL-compatible. + http://opensource.org/licenses/isc-license.txt + + Copyright (c) 2012, Noah Spurrier <noah@noah.org> + PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY + PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE + COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES. + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +''' +import pexpect +p = pexpect.spawn('cat') +p.interact() diff --git a/tests/pexpectTest.py b/tests/pexpectTest.py new file mode 100755 index 0000000..62ac422 --- /dev/null +++ b/tests/pexpectTest.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python +''' +PEXPECT LICENSE + + This license is approved by the OSI and FSF as GPL-compatible. + http://opensource.org/licenses/isc-license.txt + + Copyright (c) 2012, Noah Spurrier <noah@noah.org> + PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY + PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE + COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES. + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +''' + +import os, time, pexpect, sys + +def getProcessResults(cmd, timeLimit=20): + ''' + executes 'cmd' as a child process and returns the child's output, + the duration of execution, and the process exit status. Aborts if + child process does not generate output for 'timeLimit' seconds. + ''' + output = "" + startTime = time.time() + child = pexpect.spawn(cmd, timeout=10) + child.logfile = sys.stdout + + while 1: + try: + # read_nonblocking will add to 'outout' one byte at a time + # newlines can show up as '\r\n' so we kill any '\r's which + # will mess up the formatting for the viewer + output += child.read_nonblocking(timeout=timeLimit).replace("\r","") + except pexpect.EOF, e: + print str(e) + # process terminated normally + break + except pexpect.TIMEOUT, e: + print str(e) + output += "\nProcess aborted by FlashTest after %s seconds.\n" % timeLimit + print child.isalive() + child.kill(9) + break + + endTime = time.time() + child.close(force=True) + + duration = endTime - startTime + exitStatus = child.exitstatus + + return (output, duration, exitStatus) + +cmd = "./ticker.py" + +result, duration, exitStatus = getProcessResults(cmd) + +print "result: %s" % result +print "duration: %s" % duration +print "exit-status: %s" % exitStatus + diff --git a/tests/platform_tests/CSIGNALTEST/test.c b/tests/platform_tests/CSIGNALTEST/test.c new file mode 100644 index 0000000..86bcc17 --- /dev/null +++ b/tests/platform_tests/CSIGNALTEST/test.c @@ -0,0 +1,90 @@ +/* I built this with "gcc -lutil test.c -otest" */ +#include <sys/types.h> /* include this before any other sys headers */ +#include <sys/wait.h> /* header for waitpid() and various macros */ +#include <signal.h> /* header for signal functions */ +#include <stdio.h> /* header for fprintf() */ +#include <unistd.h> /* header for fork() */ +#ifdef LINUX +#include <pty.h> +#else +#include <util.h> /* header for forkpty, compile with -lutil */ +#endif + +void sig_chld(int); /* prototype for our SIGCHLD handler */ + +int main() +{ + struct sigaction act; + int pid; + int fdm; + char slave_name [20]; + + + /* Assign sig_chld as our SIGCHLD handler. + We don't want to block any other signals in this example + We're only interested in children that have terminated, not ones + which have been stopped (eg user pressing control-Z at terminal). + Finally, make these values effective. If we were writing a real + application, we would save the old value instead of passing NULL. + */ + act.sa_handler = sig_chld; + sigemptyset(&act.sa_mask); + act.sa_flags = SA_NOCLDSTOP; + if (sigaction(SIGCHLD, &act, NULL) < 0) + { + fprintf(stderr, "sigaction failed\n"); + return 1; + } + + /* Do the Fork thing. + */ + pid = forkpty (&fdm, slave_name, NULL, NULL); + /* pid = fork(); */ + + switch (pid) + { + case -1: + fprintf(stderr, "fork failed\n"); + return 1; + break; + + case 0: /* Child process. */ + printf ("This child output will cause trouble.\n"); + _exit(7); + break; + + default: /* Parent process. */ + sleep(1); + printf ("Child pid: %d\n", pid); + sleep(10); /* let child finish -- crappy way to avoid race. */ + break; + } + + return 0; +} + +void sig_chld(int signo) +{ + int status, wpid, child_val; + + printf ("In sig_chld signal handler.\n"); + + /* Wait for any child without blocking */ + wpid = waitpid (-1, & status, WNOHANG); + printf ("\tWaitpid found status for pid: %d\n", wpid); + if (wpid < 0) + { + fprintf(stderr, "\twaitpid failed\n"); + return; + } + printf("\tWaitpid status: %d\n", status); + + if (WIFEXITED(status)) /* did child exit normally? */ + { + child_val = WEXITSTATUS(status); + printf("\tchild exited normally with status %d\n", child_val); + } + printf ("End of sig_chld.\n"); +} + + diff --git a/tests/platform_tests/README b/tests/platform_tests/README new file mode 100644 index 0000000..c4b0564 --- /dev/null +++ b/tests/platform_tests/README @@ -0,0 +1,4 @@ +These are tests that are not yet pyunit tests +or are not intended to be pyunit tests. +Anything not part of the Python unittest framework +should go here. diff --git a/tests/platform_tests/pexqa.py b/tests/platform_tests/pexqa.py new file mode 100644 index 0000000..0ba1412 --- /dev/null +++ b/tests/platform_tests/pexqa.py @@ -0,0 +1,39 @@ +import os, sys +import select +import signal +import traceback +import time +import re +import struct +from types import * +import posix + +import pty +import tty +import termios +import fcntl +class s: + def __init__(self, command, args=None, timeout=30): + + self.pid = self.child_fd = None + try: + #self.pid, self.child_fd = posix.forkpty() + self.pid, self.child_fd = pty.fork() + except OSError, e: + raise Exception('pty fork() failed: ' + str(e)) + + if self.pid == 0: # Child + os.execvp(command, args) + + # Parent + + +print '1' +x = s('ls', ['ls']) +time.sleep(5) +print '2' +result = os.read (x.child_fd, 5555) +print '3' +print result +print '4' + diff --git a/tests/platform_tests/test.py b/tests/platform_tests/test.py new file mode 100755 index 0000000..f80263b --- /dev/null +++ b/tests/platform_tests/test.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python +import signal, os, time, errno, pty + +def signal_handler (signum, frame): + print 'Signal handler called with signal:', signum + print 'signal.SIGCHLD=', signal.SIGKILL + +# First thing we do is set up a handler for SIGCHLD. +signal.signal (signal.SIGCHLD, signal.SIG_IGN) + +print 'PART 1 -- Test signal handling with empty pipe.' +# Create a child process for us to kill. +try: + pid, fd = pty.fork() +except Exception, e: + print str(e) + +if pid == 0: +# os.write (sys.stdout.fileno(), 'This is a test.\n This is a test.') + time.sleep(10000) + +print 'Sending SIGKILL to child pid:', pid +os.kill (pid, signal.SIGKILL) + +# SIGCHLD should interrupt sleep. +# Note that this is a race. +# It is possible that the signal handler will get called +# before we try to sleep, but this has not happened yet. +# But in that case we can only tell by order of printed output. +print 'Entering sleep...' +try: + time.sleep(10) +except: + print 'sleep was interrupted by signal.' + +# Just for fun let's see if the process is alive. +try: + os.kill(pid, 0) + print 'Child is alive. This is ambiguous because it may be a Zombie.' +except OSError, e: + print 'Child appears to be dead.' + +print 'PART 2 -- Test signal handling with full pipe.' +# Create a child process for us to kill. +try: + pid, fd = pty.fork() +except Exception, e: + print str(e) + +if pid == 0: + os.write (sys.stdout.fileno(), 'This is a test.\n This is a test.') + time.sleep(10000) + +print 'Sending SIGKILL to child pid:', pid +os.kill (pid, signal.SIGKILL) + +# SIGCHLD should interrupt sleep. +# Note that this is a race. +# It is possible that the signal handler will get called +# before we try to sleep, but this has not happened yet. +# But in that case we can only tell by order of printed output. +print 'Entering sleep...' +try: + time.sleep(10) +except: + print 'sleep was interrupted by signal.' + +# Just for fun let's see if the process is alive. +try: + os.kill(pid, 0) + print 'Child is alive. This is ambiguous because it may be a Zombie.' +except OSError, e: + print 'Child appears to be dead.' + diff --git a/tests/platform_tests/test2.py b/tests/platform_tests/test2.py new file mode 100755 index 0000000..9611f39 --- /dev/null +++ b/tests/platform_tests/test2.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python +import signal, os, time, errno + +def signal_handler (signum, frame): + print 'Signal handler called with signal:', signum + print 'signal.SIGCHLD=', signal.SIGKILL + +# Create a child process for us to kill. +pid = os.fork() +if pid == 0: + time.sleep(10000) + +#signal.signal (signal.SIGCHLD, signal.SIG_IGN) +signal.signal (signal.SIGCHLD, signal_handler) + +print 'Sending SIGKILL to child pid:', pid +os.kill (pid, signal.SIGKILL) + +# SIGCHLD should interrupt sleep. +# Note that this is a race. +# It is possible that the signal handler will get called +# before we try to sleep, but this has not happened yet. +# But in that case we can only tell by order of printed output. +interrupted = 0 +try: + time.sleep(10) +except: + print 'sleep was interrupted by signal.' + interrupted = 1 + +if not interrupted: + print 'ERROR. Signal did not interrupt sleep.' +else: + print 'Signal interrupted sleep. This is good.' + +# Let's see if the process is alive. +try: + os.kill(pid, 0) + print 'Child is alive. This is ambiguous because it may be a Zombie.' +except OSError, e: + print 'Child appears to be dead.' + diff --git a/tests/platform_tests/test_badfork.py b/tests/platform_tests/test_badfork.py new file mode 100755 index 0000000..c0768a4 --- /dev/null +++ b/tests/platform_tests/test_badfork.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python +import pexpect +import pyunit + +def main (): + pid, fd = fooork ('aThelaDSjd','-i') + print 'pid', pid + print 'fd', fd + Xexpect(fd, 'bash.*#',10) + os.write(fd, 'scp -P 6666 *.py noah@gw.tiered.com:pexpect/\n') + Xexpect(fd, 'bash.*#',10) + os.write(fd, 'exit\n') + print _my_read (fd, 1000, 5) + sys.exit (1) + diff --git a/tests/platform_tests/test_control_terminal.py b/tests/platform_tests/test_control_terminal.py new file mode 100755 index 0000000..9598fd7 --- /dev/null +++ b/tests/platform_tests/test_control_terminal.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python + +import termios, fcntl, struct, os, sys + +def getwinsize(): + s = struct.pack("HHHH", 0, 0, 0, 0) + x = fcntl.ioctl(sys.stdout.fileno(), termios.TIOCGWINSZ, s) + rows, cols = struct.unpack("HHHH", x)[:2] + return rows, cols + +def setwinsize(r,c): + # Assume ws_xpixel and ws_ypixel are zero. + s = struct.pack("HHHH", r,c,0,0) + x = fcntl.ioctl(sys.stdout.fileno(), termios.TIOCSWINSZ, s) +print 'stdin tty:', os.ttyname(0) +print 'stdout tty:', os.ttyname(1) +print 'controlling terminal:', os.ctermid() +print 'winsize %d,%d' % getwinsize() +print 'ENDTEST' diff --git a/tests/platform_tests/test_handler.py b/tests/platform_tests/test_handler.py new file mode 100755 index 0000000..d9239b6 --- /dev/null +++ b/tests/platform_tests/test_handler.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python +import signal, os, time, errno, pty, sys, fcntl, tty +GLOBAL_SIGCHLD_RECEIVED = 0 + +def nonblock (fd): + # if O_NDELAY is set read() returns 0 (ambiguous with EOF). + # if O_NONBLOCK is set read() returns -1 and sets errno to EAGAIN + original_flags = fcntl.fcntl (fd, fcntl.F_GETFL, 0) + flags = original_flags | os.O_NONBLOCK + fcntl.fcntl(fd, fcntl.F_SETFL, flags) + return original_flags + +def signal_handler (signum, frame): + print '<HANDLER>' + global GLOBAL_SIGCHLD_RECEIVED + status = os.waitpid (-1, os.WNOHANG) + if status[0] == 0: + print 'No process for waitpid:', status + else: + print 'Status:', status + print 'WIFEXITED(status):', os.WIFEXITED(status[1]) + print 'WEXITSTATUS(status):', os.WEXITSTATUS(status[1]) + GLOBAL_SIGCHLD_RECEIVED = 1 + +def main (): + signal.signal (signal.SIGCHLD, signal_handler) + pid, fd = pty.fork() + if pid == 0: + os.write (sys.stdout.fileno(), 'This is a test.\nThis is a test.') + time.sleep(10000) + nonblock (fd) + tty.setraw(fd) #STDIN_FILENO) + print 'Sending SIGKILL to child pid:', pid + time.sleep(2) + os.kill (pid, signal.SIGKILL) + + print 'Entering to sleep...' + try: + time.sleep(2) + except: + print 'Sleep interrupted' + try: + os.kill(pid, 0) + print '\tChild is alive. This is ambiguous because it may be a Zombie.' + except OSError, e: + print '\tChild appears to be dead.' +# print str(e) + print + print 'Reading from master fd:', os.read (fd, 1000) + + + +if __name__ == '__main__': + main () diff --git a/tests/platform_tests/test_killed_pid.py b/tests/platform_tests/test_killed_pid.py new file mode 100755 index 0000000..ff2fe5e --- /dev/null +++ b/tests/platform_tests/test_killed_pid.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python +import os, time, signal +import expyct + +e = expyct.expyct ('/bin/sh', '-i') +print 'pid,fd:', e.pid, e.fd +print 'isAlive:', e.isAlive() +# Treat it brusquely. +print 'sending SIGKILL...' +os.kill (e.pid, signal.SIGKILL) +time.sleep (1) +print os.read(e.fd, 1000) +print 'isAlive:', e.isAlive() +e.expect('\#') +e.send ('ls -la /\n') +r,m,i = e.expect ('\#') +print r diff --git a/tests/platform_tests/test_middle_buffer.py b/tests/platform_tests/test_middle_buffer.py new file mode 100755 index 0000000..ccb8302 --- /dev/null +++ b/tests/platform_tests/test_middle_buffer.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python2 +import expyct +import time + +e = expyct.expyct ('/bin/sh -i') +e.timeout=60 +e.expect(['#', '\$']) +e.send ('ls -la /\n') + +i = e.expect (['foo','(d[aeiou]v)']) +print '\nRead before match>%s<' % e.before +print 'Matched:>%s<' % e.matched +print 'index:', i + +i = e.expect(['#', '\$']) +print '\nRead before match>%s<' % e.before +print 'Matched:>%s<' % e.matched +print 'index:', i +e.send('exit\n') +print 'Sent exit' +time.sleep(2) +print 'isAlive:', e.isAlive() + +# This should test timeout... +i = e.expect ('#####') +print '\nRead before match>%s<' % e.before +print 'Matched:>%s<' % e.matched +print 'index:', i + + diff --git a/tests/platform_tests/test_read.py b/tests/platform_tests/test_read.py new file mode 100755 index 0000000..1e16ed4 --- /dev/null +++ b/tests/platform_tests/test_read.py @@ -0,0 +1,35 @@ +import os, sys + +filename = os.tmpnam() +print 'filename:', filename + +fd_out = os.open(filename, os.O_CREAT | os.O_WRONLY) +print 'fd_out:', fd_out +os.write (fd_out, 'This is a test.\n') +os.close(fd_out) +print +print 'testing read on good fd...' +fd_in = os.open (filename, os.O_RDONLY) +print 'fd_in:', fd_in +while 1: + data_in = os.read(fd_in, 1) + print 'data_in:', data_in + if data_in == '': + print 'data_in was empty' + break #sys.exit(1) +os.close(fd_in) +print +print +print 'testing read on closed fd...' +fd_in = os.open ('test_read.py', os.O_RDONLY) +print 'fd_in:', fd_in +while 1: + data_in = os.read(fd_in, 1) + print 'data_in:', data_in + if data_in == '': + print 'data_in was empty' + break +os.close(fd_in) +d = os.read(fd_in, 1) # fd_in should be closed now... +if s == '': + print 'd is empty. good.' diff --git a/tests/platform_tests/test_signals.py b/tests/platform_tests/test_signals.py new file mode 100755 index 0000000..cd1a6da --- /dev/null +++ b/tests/platform_tests/test_signals.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python +import signal, os, time, errno, pty, sys +GLOBAL_SIGCHLD_RECEIVED = 0 + +def signal_handler (signum, frame): + print '<HANDLER>' + global GLOBAL_SIGCHLD_RECEIVED + status = os.waitpid (-1, os.WNOHANG) + print 'WIFEXITED(status):', os.WIFEXITED(status) + print 'WEXITSTATUS(status):', os.WEXITSTATUS(status) + GLOBAL_SIGCHLD_RECEIVED = 1 + +def main (): +# sig_test ('SIG_IGN', 'ptyfork', 'yes') + sig_test ('handler', 'ptyfork', 'yes') +# sig_test ('SIG_IGN', 'ptyfork', 'no') +# sig_test ('handler', 'ptyfork', 'no') +# sig_test ('SIG_IGN', 'osfork', 'yes') +# sig_test ('handler', 'osfork', 'yes') +# sig_test ('SIG_IGN', 'osfork', 'no') +# sig_test ('handler', 'osfork', 'no') + +def sig_test (sig_handler_type, fork_type, child_output): + print 'Testing with:' + print '\tsig_handler_type:', sig_handler_type + print '\tfork_type:', fork_type + print '\tchild_output:', child_output + + if sig_handler_type == 'SIG_IGN': + signal.signal (signal.SIGCHLD, signal.SIG_IGN) + else: + signal.signal (signal.SIGCHLD, signal_handler) + pid = -1 + fd = -1 + if fork_type == 'ptyfork': + pid, fd = pty.fork() + else: + pid = os.fork() + + if pid == 0: + if child_output == 'yes': + os.write (sys.stdout.fileno(), 'This is a test.\nThis is a test.') + time.sleep(10000) + + #print 'Sending SIGKILL to child pid:', pid + time.sleep(2) + os.kill (pid, signal.SIGKILL) + + #print 'Entering to sleep...' + try: + time.sleep(2) + except: + pass + try: + os.kill(pid, 0) + print '\tChild is alive. This is ambiguous because it may be a Zombie.' + except OSError, e: + print '\tChild appears to be dead.' +# print str(e) + print + +if __name__ == '__main__': + main () diff --git a/tests/qa.py b/tests/qa.py new file mode 100755 index 0000000..eb11946 --- /dev/null +++ b/tests/qa.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python +''' +PEXPECT LICENSE + + This license is approved by the OSI and FSF as GPL-compatible. + http://opensource.org/licenses/isc-license.txt + + Copyright (c) 2012, Noah Spurrier <noah@noah.org> + PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY + PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE + COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES. + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +''' +import commands +import signal + +signal.signal(signal.SIGCHLD, signal.SIG_IGN) +print commands.getoutput('/bin/ls -l') + diff --git a/tests/sigwinch_report.py b/tests/sigwinch_report.py new file mode 100755 index 0000000..26030cb --- /dev/null +++ b/tests/sigwinch_report.py @@ -0,0 +1,46 @@ +''' +PEXPECT LICENSE + + This license is approved by the OSI and FSF as GPL-compatible. + http://opensource.org/licenses/isc-license.txt + + Copyright (c) 2012, Noah Spurrier <noah@noah.org> + PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY + PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE + COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES. + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +''' +import signal, time, struct, fcntl, termios, os, sys + +def getwinsize(): + '''This returns the window size of the child tty. + The return value is a tuple of (rows, cols). + ''' + if 'TIOCGWINSZ' in dir(termios): + TIOCGWINSZ = termios.TIOCGWINSZ + else: + TIOCGWINSZ = 1074295912L # Assume + s = struct.pack('HHHH', 0, 0, 0, 0) + x = fcntl.ioctl(sys.stdout.fileno(), TIOCGWINSZ, s) + return struct.unpack('HHHH', x)[0:2] + +def handler(signum, frame): + print 'signal' + sys.stdout.flush() + print 'SIGWINCH:', getwinsize () + sys.stdout.flush() + +print "setting handler for SIGWINCH" +signal.signal(signal.SIGWINCH, handler) + +while 1: + sys.stdout.flush() + time.sleep(1) + diff --git a/tests/swapcase_echo.py b/tests/swapcase_echo.py new file mode 100755 index 0000000..344cfaf --- /dev/null +++ b/tests/swapcase_echo.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python +''' +PEXPECT LICENSE + + This license is approved by the OSI and FSF as GPL-compatible. + http://opensource.org/licenses/isc-license.txt + + Copyright (c) 2012, Noah Spurrier <noah@noah.org> + PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY + PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE + COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES. + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +''' +import sys, time +while True: + x = raw_input () + time.sleep(1) # without this delay the test would fail about 75% of the time. Why? + print x.swapcase() + sys.stdout.flush() diff --git a/tests/test_ansi.py b/tests/test_ansi.py new file mode 100755 index 0000000..4ac7b9a --- /dev/null +++ b/tests/test_ansi.py @@ -0,0 +1,133 @@ +#!/usr/bin/env python +''' +PEXPECT LICENSE + + This license is approved by the OSI and FSF as GPL-compatible. + http://opensource.org/licenses/isc-license.txt + + Copyright (c) 2012, Noah Spurrier <noah@noah.org> + PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY + PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE + COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES. + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +''' + +import ANSI +import unittest +import PexpectTestCase + +write_target = 'I\'ve got a ferret sticking up my nose. \n' +\ +'(He\'s got a ferret sticking up his nose.) \n' +\ +'How it got there I can\'t tell \n' +\ +'But now it\'s there it hurts like hell \n' +\ +'And what is more it radically affects my sense of smell. \n' +\ +'(His sense of smell.) ' + +write_text = 'I\'ve got a ferret sticking up my nose.\n' + \ +'(He\'s got a ferret sticking up his nose.)\n' + \ +'How it got there I can\'t tell\n' + \ +'But now it\'s there it hurts like hell\n' + \ +'And what is more it radically affects my sense of smell.\n' + \ +'(His sense of smell.)\n' + \ +'I can see a bare-bottomed mandril.\n' + \ +'(Slyly eyeing his other nostril.)\n' + \ +'If it jumps inside there too I really don\'t know what to do\n' + \ +'I\'ll be the proud posessor of a kind of nasal zoo.\n' + \ +'(A nasal zoo.)\n' + \ +'I\'ve got a ferret sticking up my nose.\n' + \ +'(And what is worst of all it constantly explodes.)\n' + \ +'"Ferrets don\'t explode," you say\n' + \ +'But it happened nine times yesterday\n' + \ +'And I should know for each time I was standing in the way.\n' + \ +'I\'ve got a ferret sticking up my nose.\n' + \ +'(He\'s got a ferret sticking up his nose.)\n' + \ +'How it got there I can\'t tell\n' + \ +'But now it\'s there it hurts like hell\n' + \ +'And what is more it radically affects my sense of smell.\n' + \ +'(His sense of smell.)' + +tetris_target=' XX XXXX XX \n' +\ +' XXXXXX XXXXXXXX XX \n' +\ +' XXXXXX XXXXXXXX XX \n' +\ +' XX XX XX XXXX XX \n' +\ +' XXXXXX XXXX XXXX XX \n' +\ +' XXXXXXXXXX XXXX XX \n' +\ +' XX XXXXXX XX XX \n' +\ +' XXXXXX XX XX \n' +\ +' XXXX XXXXXX XX XX \n' +\ +' XXXXXX XXXX XX XX \n' +\ +' XX XX XXXX XX XX \n' +\ +' XX XX XX XX XX \n' +\ +' XX XX XXXX XXXX XX \n' +\ +' XXXXXXXX XXXX XXXX XX \n' +\ +' XXXXXXXXXXXXXX XXXXXXXX \n' +\ +' XX XXXXXXXX XX XX \n' +\ +' XXXXXXXXXXXXXX XX XX \n' +\ +' XX XXXX XXXXXX XX \n' +\ +' XXXXXX XXXXXXXX \n' +\ +' XXXXXXXXXX XX XX \n' +\ +' XXXXXXXXXXXXXXXXXXXXXXXX \n' +\ +' \n' +\ +' J->LEFT K->ROTATE L->RIGHT SPACE->DROP P->PAUSE Q->QUIT \n' +\ +' ' + +torture_target='+--------------------------------------------------------------------------------+\n' +\ +'|a`opqrs` This is the `srqpo`a |\n' +\ +'|VT100 series Torture Test Demonstration. |\n' +\ +'|VT100 series Torture Test Demonstration. |\n' +\ +'|This is a normal line __________________________________________________y_ |\n' +\ +'|This is a bold line (normal unless the Advanced Video Option is installed) |\n' +\ +'|This line is underlined _ " " " " " " _y_ |\n' +\ +'|This is a blinking line _ " " " " " " _y_ |\n' +\ +'|This is inverse video _ (underlined if no AVO and cursor is underline) _y_ |\n' +\ +'|Normal gjpqy Underline Blink Underline+Blink gjpqy |\n' +\ +'|Bold gjpqy Underline Blink Underline+Blink gjpqy |\n' +\ +'|Inverse Underline Blink Underline+Blink |\n' +\ +'|Bold+Inverse Underline Blink Underline+Blink |\n' +\ +'|This is double width |\n' +\ +'|This is double height |\n' +\ +'|This is double height |\n' +\ +'|_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ioy |\n' +\ +'|_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ioy |\n' +\ +'|_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ioy |\n' +\ +'|`abcdefghijklmnopqrstuvwxyz{|}~ lqwqk |\n' +\ +'|`abcdefghijklmnopqrstuvwxyz{|}~ tqnqu |\n' +\ +'|`abcdefghijklmnopqrstuvwxyz{|}~ tqnqu |\n' +\ +'|`abcdefghijklmnopqrstuvwxyz{|}~ mqvqj |\n' +\ +'| This test created by Joe Smith, 8-May-85 |\n' +\ +'| |\n' +\ +'+--------------------------------------------------------------------------------+\n' + +class ansiTestCase (PexpectTestCase.PexpectTestCase): + def test_write (self): + s = ANSI.ANSI (6,65) + s.fill('.') + s.cursor_home() + for c in write_text: + s.write (c) + assert str(s) == write_target + def test_torturet (self): + s = ANSI.ANSI (24,80) + sample_text = open ('torturet.vt').read() + for c in sample_text: + s.process (c) + assert s.pretty() == torture_target, 'processed: \n' + s.pretty() + '\nexpected:\n' + torture_target + def test_tetris (self): + s = ANSI.ANSI (24,80) + tetris_text = open ('tetris.data').read() + for c in tetris_text: + s.process (c) + assert str(s) == tetris_target + +if __name__ == '__main__': + unittest.main() + +suite = unittest.makeSuite(ansiTestCase,'test') + diff --git a/tests/test_command_list_split.py b/tests/test_command_list_split.py new file mode 100755 index 0000000..2213b45 --- /dev/null +++ b/tests/test_command_list_split.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python +''' +PEXPECT LICENSE + + This license is approved by the OSI and FSF as GPL-compatible. + http://opensource.org/licenses/isc-license.txt + + Copyright (c) 2012, Noah Spurrier <noah@noah.org> + PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY + PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE + COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES. + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +''' +import pexpect +import unittest +import PexpectTestCase +class SplitCommandLineTestCase(PexpectTestCase.PexpectTestCase): + def testSplitSizes(self): + assert len(pexpect.split_command_line(r'')) == 0 + assert len(pexpect.split_command_line(r'one')) == 1 + assert len(pexpect.split_command_line(r'one two')) == 2 + assert len(pexpect.split_command_line(r'one two')) == 2 + assert len(pexpect.split_command_line(r'one two')) == 2 + assert len(pexpect.split_command_line(r'one\ one')) == 1 + assert len(pexpect.split_command_line('\'one one\'')) == 1 + assert len(pexpect.split_command_line(r'one\"one')) == 1 + assert len(pexpect.split_command_line(r'This\' is a\'\ test')) == 3 + +if __name__ == '__main__': + unittest.main() + +suite = unittest.makeSuite(SplitCommandLineTestCase,'test') diff --git a/tests/test_constructor.py b/tests/test_constructor.py new file mode 100755 index 0000000..8a98c28 --- /dev/null +++ b/tests/test_constructor.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python +''' +PEXPECT LICENSE + + This license is approved by the OSI and FSF as GPL-compatible. + http://opensource.org/licenses/isc-license.txt + + Copyright (c) 2012, Noah Spurrier <noah@noah.org> + PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY + PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE + COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES. + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +''' +import pexpect +import unittest +import time +import PexpectTestCase + +class TestCaseConstructor(PexpectTestCase.PexpectTestCase): + def test_constructor (self): + '''This tests that the constructor will work and give + the same results for different styles of invoking __init__(). + This assumes that the root directory / is static during the test. + ''' + p1 = pexpect.spawn('/bin/ls -l /bin') + p2 = pexpect.spawn('/bin/ls' ,['-l', '/bin']) + p1.expect (pexpect.EOF) + p2.expect (pexpect.EOF) + assert (p1.before == p2.before) + + def test_named_parameters (self): + '''This tests that named parameters work. + ''' + p = pexpect.spawn ('/bin/ls',timeout=10) + p = pexpect.spawn (timeout=10, command='/bin/ls') + p = pexpect.spawn (args=[], command='/bin/ls') + +if __name__ == '__main__': + unittest.main() + +suite = unittest.makeSuite(TestCaseConstructor,'test') + diff --git a/tests/test_ctrl_chars.py b/tests/test_ctrl_chars.py new file mode 100755 index 0000000..c679609 --- /dev/null +++ b/tests/test_ctrl_chars.py @@ -0,0 +1,109 @@ +#!/usr/bin/env python +''' +PEXPECT LICENSE + + This license is approved by the OSI and FSF as GPL-compatible. + http://opensource.org/licenses/isc-license.txt + + Copyright (c) 2012, Noah Spurrier <noah@noah.org> + PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY + PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE + COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES. + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +''' +import pexpect +import unittest +import PexpectTestCase +import time +import os + +class TestCtrlChars(PexpectTestCase.PexpectTestCase): + + def test_control_chars (self): + + '''FIXME: Python unicode was too hard to figure out, so + this tests only the true ASCII characters. This is lame + and should be fixed. I'm leaving this script here as a + placeholder so that it will remind me to fix this one day. + This is what it used to do: + This tests that we can send all 256 8-bit ASCII characters + to a child process.''' + + # FIXME: Getting this to support Python's Unicode was + # too hard, so I disabled this. I should fix this one day. + return 0 + child = pexpect.spawn('python getch.py') + try: + for i in range(256): +# child.send(unicode('%d'%i, encoding='utf-8')) + child.send(chr(i)) + child.expect ('%d\r\n' % i) + except Exception, e: + msg = "Did not echo character value: " + str(i) + "\n" + msg = msg + str(e) + self.fail(msg) + + def test_sendintr (self): + try: + child = pexpect.spawn('python getch.py') + child.sendintr() + child.expect ('3\r\n') + except Exception, e: + msg = "Did not echo character value: 3\n" + msg = msg + str(e) + self.fail(msg) + + def test_bad_sendcontrol_chars (self): + + '''This tests that sendcontrol will return 0 for an unknown char. ''' + + child = pexpect.spawn('python getch.py') + retval = child.sendcontrol('1') + assert retval == 0, "sendcontrol() should have returned 0 because there is no such thing as ctrl-1." + + def test_sendcontrol(self): + + '''This tests that we can send all special control codes by name. + ''' + + child = pexpect.spawn('python getch.py') + #child.delaybeforesend = 0.1 + for i in 'abcdefghijklmnopqrstuvwxyz': + child.sendcontrol(i) + child.expect ('[0-9]+\r\n') + #print child.after + + child.sendcontrol('@') + child.expect ('0\r\n') + #print child.after + child.sendcontrol('[') + child.expect ('27\r\n') + #print child.after + child.sendcontrol('\\') + child.expect ('28\r\n') + #print child.after + child.sendcontrol(']') + child.expect ('29\r\n') + #print child.after + child.sendcontrol('^') + child.expect ('30\r\n') + #print child.after + child.sendcontrol('_') + child.expect ('31\r\n') + #print child.after + child.sendcontrol('?') + child.expect ('127\r\n') + #print child.after + +if __name__ == '__main__': + unittest.main() + +suite = unittest.makeSuite(TestCtrlChars,'test') + diff --git a/tests/test_destructor.py b/tests/test_destructor.py new file mode 100755 index 0000000..d6b176c --- /dev/null +++ b/tests/test_destructor.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python +''' +PEXPECT LICENSE + + This license is approved by the OSI and FSF as GPL-compatible. + http://opensource.org/licenses/isc-license.txt + + Copyright (c) 2012, Noah Spurrier <noah@noah.org> + PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY + PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE + COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES. + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +''' +import pexpect +import unittest +import PexpectTestCase +import gc +import time + +class TestCaseDestructor(PexpectTestCase.PexpectTestCase): + def test_destructor (self): + p1 = pexpect.spawn('%s hello_world.py' % self.PYTHONBIN) + p2 = pexpect.spawn('%s hello_world.py' % self.PYTHONBIN) + p3 = pexpect.spawn('%s hello_world.py' % self.PYTHONBIN) + p4 = pexpect.spawn('%s hello_world.py' % self.PYTHONBIN) + fd_t1 = (p1.child_fd,p2.child_fd,p3.child_fd,p4.child_fd) + p1.expect(pexpect.EOF) + p2.expect(pexpect.EOF) + p3.expect(pexpect.EOF) + p4.expect(pexpect.EOF) + p1.kill(9) + p2.kill(9) + p3.kill(9) + p4.kill(9) + p1 = None + p2 = None + p3 = None + p4 = None + gc.collect() + time.sleep(3) # Some platforms are slow at gc... Solaris! + + p1 = pexpect.spawn('%s hello_world.py' % self.PYTHONBIN) + p2 = pexpect.spawn('%s hello_world.py' % self.PYTHONBIN) + p3 = pexpect.spawn('%s hello_world.py' % self.PYTHONBIN) + p4 = pexpect.spawn('%s hello_world.py' % self.PYTHONBIN) + fd_t2 = (p1.child_fd,p2.child_fd,p3.child_fd,p4.child_fd) + p1.kill(9) + p2.kill(9) + p3.kill(9) + p4.kill(9) + del (p1) + del (p2) + del (p3) + del (p4) + gc.collect() + time.sleep(3) + + p1 = pexpect.spawn('%s hello_world.py' % self.PYTHONBIN) + p2 = pexpect.spawn('%s hello_world.py' % self.PYTHONBIN) + p3 = pexpect.spawn('%s hello_world.py' % self.PYTHONBIN) + p4 = pexpect.spawn('%s hello_world.py' % self.PYTHONBIN) + fd_t3 = (p1.child_fd,p2.child_fd,p3.child_fd,p4.child_fd) + + assert (fd_t1 == fd_t2 == fd_t3), "pty file descriptors not properly garbage collected (fd_t1,fd_t2,fd_t3)=(%s,%s,%s)" % (str(fd_t1),str(fd_t2),str(fd_t3)) + + +if __name__ == '__main__': + unittest.main() + +suite = unittest.makeSuite(TestCaseDestructor,'test') + diff --git a/tests/test_dotall.py b/tests/test_dotall.py new file mode 100755 index 0000000..46577da --- /dev/null +++ b/tests/test_dotall.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python +''' +PEXPECT LICENSE + + This license is approved by the OSI and FSF as GPL-compatible. + http://opensource.org/licenses/isc-license.txt + + Copyright (c) 2012, Noah Spurrier <noah@noah.org> + PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY + PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE + COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES. + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +''' +import pexpect +import unittest +import os +import re +import PexpectTestCase + +testdata = 'BEGIN\nHello world\nEND' +class TestCaseDotall(PexpectTestCase.PexpectTestCase): + def test_dotall (self): + p = pexpect.spawn('echo "%s"' % testdata) + i = p.expect (['BEGIN(.*)END', pexpect.EOF]) + assert i==0, 'DOTALL does not seem to be working.' + + def test_precompiled (self): + p = pexpect.spawn('echo "%s"' % testdata) + pat = re.compile('BEGIN(.*)END') # This overrides the default DOTALL. + i = p.expect ([pat, pexpect.EOF]) + assert i==1, 'Precompiled pattern to override DOTALL does not seem to be working.' + +if __name__ == '__main__': + unittest.main() + +suite = unittest.makeSuite(TestCaseDotall,'test') + diff --git a/tests/test_expect.py b/tests/test_expect.py new file mode 100755 index 0000000..7075aa0 --- /dev/null +++ b/tests/test_expect.py @@ -0,0 +1,424 @@ +#!/usr/bin/env python +''' +PEXPECT LICENSE + + This license is approved by the OSI and FSF as GPL-compatible. + http://opensource.org/licenses/isc-license.txt + + Copyright (c) 2012, Noah Spurrier <noah@noah.org> + PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY + PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE + COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES. + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +''' +import pexpect +import unittest +import commands +import sys, time +import PexpectTestCase +#import pdb + +# Many of these test cases blindly assume that sequential directory +# listings of the /bin directory will yield the same results. +# This may not be true, but seems adequate for testing now. +# I should fix this at some point. + +FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.' for x in range(256)]) +def hex_dump(src, length=16): + result=[] + for i in xrange(0, len(src), length): + s = src[i:i+length] + hexa = ' '.join(["%02X"%ord(x) for x in s]) + printable = s.translate(FILTER) + result.append("%04X %-*s %s\n" % (i, length*3, hexa, printable)) + return ''.join(result) + +class ExpectTestCase (PexpectTestCase.PexpectTestCase): + + def test_expect_basic (self): + p = pexpect.spawn('cat') + p.sendline ('Hello') + p.sendline ('there') + p.sendline ('Mr. Python') + p.expect ('Hello') + p.expect ('there') + p.expect ('Mr. Python') + p.sendeof () + p.expect (pexpect.EOF) + + def test_expect_exact_basic (self): + p = pexpect.spawn('cat') + p.sendline ('Hello') + p.sendline ('there') + p.sendline ('Mr. Python') + p.expect_exact ('Hello') + p.expect_exact ('there') + p.expect_exact ('Mr. Python') + p.sendeof () + p.expect_exact (pexpect.EOF) + + def test_expect_ignore_case(self): + '''This test that the ignorecase flag will match patterns + even if case is different using the regex (?i) directive. + ''' + p = pexpect.spawn('cat') + p.sendline ('HELLO') + p.sendline ('there') + p.expect ('(?i)hello') + p.expect ('(?i)THERE') + p.sendeof () + p.expect (pexpect.EOF) + + def test_expect_ignore_case_flag(self): + '''This test that the ignorecase flag will match patterns + even if case is different using the ignorecase flag. + ''' + p = pexpect.spawn('cat') + p.ignorecase = True + p.sendline ('HELLO') + p.sendline ('there') + p.expect ('hello') + p.expect ('THERE') + p.sendeof () + p.expect (pexpect.EOF) + + def test_expect_order (self): + '''This tests that patterns are matched in the same order as given in the pattern_list. + + (Or does it? Doesn't it also pass if expect() always chooses + (one of the) the leftmost matches in the input? -- grahn) + ''' + p = pexpect.spawn('cat') + self._expect_order(p) + + def test_expect_order_exact (self): + '''Like test_expect_order(), but using expect_exact(). + ''' + p = pexpect.spawn('cat') + p.expect = p.expect_exact + self._expect_order(p) + + def _expect_order (self, p): + p.sendline ('1234') + p.sendline ('abcd') + p.sendline ('wxyz') + p.sendline ('7890') + p.sendeof () + index = p.expect (['1234','abcd','wxyz',pexpect.EOF,'7890']) + assert index == 0, "index="+str(index) + index = p.expect (['1234','abcd','wxyz',pexpect.EOF,'7890']) + assert index == 0, "index="+str(index) + index = p.expect ([pexpect.EOF,pexpect.TIMEOUT,'wxyz','abcd','1234']) + assert index == 3, "index="+str(index) + index = p.expect (['54321',pexpect.TIMEOUT,'1234','abcd','wxyz',pexpect.EOF], timeout=5) + assert index == 3, "index="+str(index) + index = p.expect (['54321',pexpect.TIMEOUT,'1234','abcd','wxyz',pexpect.EOF], timeout=5) + assert index == 4, "index="+str(index) + index = p.expect (['54321',pexpect.TIMEOUT,'1234','abcd','wxyz',pexpect.EOF], timeout=5) + assert index == 4, "index="+str(index) + index = p.expect ([pexpect.EOF,'abcd','wxyz','7890']) + assert index == 3, "index="+str(index) + index = p.expect ([pexpect.EOF,'abcd','wxyz','7890']) + assert index == 3, "index="+str(index) + + def test_waitnoecho (self): + + ''' This tests that we can wait on a child process to set echo mode. + For example, this tests that we could wait for SSH to set ECHO False + when asking of a password. This makes use of an external script + echo_wait.py. ''' + + p1 = pexpect.spawn('%s echo_wait.py' % self.PYTHONBIN) + start = time.time() + p1.waitnoecho(timeout=10) + end_time = time.time() - start + assert end_time < 10 and end_time > 2, "waitnoecho did not set ECHO off in the expected window of time." + + # test that we actually timeout and return False if ECHO is never set off. + p1 = pexpect.spawn('cat') + start = time.time() + retval = p1.waitnoecho(timeout=4) + end_time = time.time() - start + assert end_time > 3, "waitnoecho should have waited longer than 2 seconds. retval should be False, retval=%d"%retval + assert retval==False, "retval should be False, retval=%d"%retval + + # This one is mainly here to test default timeout for code coverage. + p1 = pexpect.spawn('%s echo_wait.py' % self.PYTHONBIN) + start = time.time() + p1.waitnoecho() + end_time = time.time() - start + assert end_time < 10, "waitnoecho did not set ECHO off in the expected window of time." + + def test_expect_echo (self): + '''This tests that echo can be turned on and off. + ''' + p = pexpect.spawn('cat', timeout=10) + self._expect_echo(p) + + def test_expect_echo_exact (self): + '''Like test_expect_echo(), but using expect_exact(). + ''' + p = pexpect.spawn('cat', timeout=10) + p.expect = p.expect_exact + self._expect_echo(p) + + def _expect_echo (self, p): + p.sendline ('1234') # Should see this twice (once from tty echo and again from cat). + index = p.expect (['1234','abcd','wxyz',pexpect.EOF,pexpect.TIMEOUT]) + assert index == 0, "index="+str(index)+"\n"+p.before + index = p.expect (['1234','abcd','wxyz',pexpect.EOF]) + assert index == 0, "index="+str(index) + p.setecho(0) # Turn off tty echo + p.sendline ('abcd') # Now, should only see this once. + p.sendline ('wxyz') # Should also be only once. + index = p.expect ([pexpect.EOF,pexpect.TIMEOUT,'abcd','wxyz','1234']) + assert index == 2, "index="+str(index) + index = p.expect ([pexpect.EOF,'abcd','wxyz','7890']) + assert index == 2, "index="+str(index) + p.setecho(1) # Turn on tty echo + p.sendline ('7890') # Should see this twice. + index = p.expect ([pexpect.EOF,'abcd','wxyz','7890']) + assert index == 3, "index="+str(index) + index = p.expect ([pexpect.EOF,'abcd','wxyz','7890']) + assert index == 3, "index="+str(index) + p.sendeof() + + def test_expect_index (self): + '''This tests that mixed list of regex strings, TIMEOUT, and EOF all + return the correct index when matched. + ''' + #pdb.set_trace() + p = pexpect.spawn('cat') + self._expect_index(p) + + def test_expect_index_exact (self): + '''Like test_expect_index(), but using expect_exact(). + ''' + p = pexpect.spawn('cat') + p.expect = p.expect_exact + self._expect_index(p) + + def _expect_index (self, p): + p.setecho(0) + p.sendline ('1234') + index = p.expect (['abcd','wxyz','1234',pexpect.EOF]) + assert index == 2, "index="+str(index) + p.sendline ('abcd') + index = p.expect ([pexpect.TIMEOUT,'abcd','wxyz','1234',pexpect.EOF]) + assert index == 1, "index="+str(index) + p.sendline ('wxyz') + index = p.expect (['54321',pexpect.TIMEOUT,'abcd','wxyz','1234',pexpect.EOF], timeout=5) + assert index == 3, "index="+str(index) # Expect 'wxyz' + p.sendline ('$*!@?') + index = p.expect (['54321',pexpect.TIMEOUT,'abcd','wxyz','1234',pexpect.EOF], timeout=5) + assert index == 1, "index="+str(index) # Expect TIMEOUT + p.sendeof () + index = p.expect (['54321',pexpect.TIMEOUT,'abcd','wxyz','1234',pexpect.EOF], timeout=5) + assert index == 5, "index="+str(index) # Expect EOF + + def test_expect (self): + the_old_way = commands.getoutput('ls -l /bin') + p = pexpect.spawn('ls -l /bin') + the_new_way = '' + while 1: + i = p.expect (['\n', pexpect.EOF]) + the_new_way = the_new_way + p.before + if i == 1: + break + the_new_way = the_new_way[:-1] + the_new_way = the_new_way.replace('\r','\n') + # For some reason I get an extra newline under OS X evey once in a while. + # I found it by looking through the hex_dump(). + assert the_old_way == the_new_way, hex_dump(the_new_way) + "\n" + hex_dump(the_old_way) + + def test_expect_exact (self): + the_old_way = commands.getoutput('ls -l /bin') + p = pexpect.spawn('ls -l /bin') + the_new_way = '' + while 1: + i = p.expect_exact (['\n', pexpect.EOF]) + the_new_way = the_new_way + p.before + if i == 1: + break + the_new_way = the_new_way[:-1] + the_new_way = the_new_way.replace('\r','\n') + assert the_old_way == the_new_way, repr(the_old_way) + '\n' + repr(the_new_way) + p = pexpect.spawn('echo hello.?world') + i = p.expect_exact('.?') + assert p.before == 'hello' and p.after == '.?' + + def test_expect_eof (self): + the_old_way = commands.getoutput('/bin/ls -l /bin') + p = pexpect.spawn('/bin/ls -l /bin') + p.expect(pexpect.EOF) # This basically tells it to read everything. Same as pexpect.run() function. + the_new_way = p.before + the_new_way = the_new_way.replace('\r','') # Remember, pty line endings are '\r\n'. + the_new_way = the_new_way[:-1] + assert the_old_way == the_new_way + + def test_expect_timeout (self): + p = pexpect.spawn('ed', timeout=10) + i = p.expect(pexpect.TIMEOUT) # This tells it to wait for timeout. + assert p.after == pexpect.TIMEOUT + + def test_unexpected_eof (self): + p = pexpect.spawn('ls -l /bin') + try: + p.expect('_Z_XY_XZ') # Probably never see this in ls output. + except pexpect.EOF, e: + pass + else: + self.fail ('Expected an EOF exception.') + + def _before_after(self, p): + p.timeout = 5 + + p.expect('>>> ') + self.assertEqual(p.after, '>>> ') + self.assert_(p.before.startswith('Python ')) + + p.sendline('range(4*3)') + + p.expect('5') + self.assertEqual(p.after, '5') + self.assert_(p.before.startswith('range(4*3)')) + + p.expect('>>> ') + self.assertEqual(p.after, '>>> ') + self.assert_(p.before.startswith(', 6, 7, 8')) + + def test_before_after(self): + '''This tests expect() for some simple before/after things. + ''' + p = pexpect.spawn(self.PYTHONBIN) + self._before_after(p) + + def test_before_after_exact(self): + '''This tests some simple before/after things, for + expect_exact(). (Grahn broke it at one point.) + ''' + p = pexpect.spawn(self.PYTHONBIN) + # mangle the spawn so we test expect_exact() instead + p.expect = p.expect_exact + self._before_after(p) + + def _ordering(self, p): + p.timeout = 5 + p.expect('>>> ') + + p.sendline('range(4*3)') + self.assertEqual(p.expect(['5,', '5,']), 0) + p.expect('>>> ') + + p.sendline('range(4*3)') + self.assertEqual(p.expect(['7,', '5,']), 1) + p.expect('>>> ') + + p.sendline('range(4*3)') + self.assertEqual(p.expect(['5,', '7,']), 0) + p.expect('>>> ') + + p.sendline('range(4*5)') + self.assertEqual(p.expect(['2,', '12,']), 0) + p.expect('>>> ') + + p.sendline('range(4*5)') + self.assertEqual(p.expect(['12,', '2,']), 1) + + def test_ordering(self): + '''This tests expect() for which pattern is returned + when many may eventually match. I (Grahn) am a bit + confused about what should happen, but this test passes + with pexpect 2.1. + ''' + p = pexpect.spawn(self.PYTHONBIN) + self._ordering(p) + + def test_ordering_exact(self): + '''This tests expect_exact() for which pattern is returned + when many may eventually match. I (Grahn) am a bit + confused about what should happen, but this test passes + for the expect() method with pexpect 2.1. + ''' + p = pexpect.spawn(self.PYTHONBIN) + # mangle the spawn so we test expect_exact() instead + p.expect = p.expect_exact + self._ordering(p) + + def _greed(self, p): + p.timeout = 5 + p.expect('>>> ') + p.sendline('import time') + p.expect('>>> ') + # the newline and sleep will (I hope) guarantee that + # pexpect is fed two distinct batches of data, + # "foo\r\n" + "bar\r\n". + foo_then_bar = 'print "f"+"o"+"o" ; time.sleep(3); print "b"+"a"+"r"' + + p.sendline(foo_then_bar) + self.assertEqual(p.expect(['foo\r\nbar']), 0) + p.expect('>>> ') + + p.sendline(foo_then_bar) + self.assertEqual(p.expect(['\r\nbar']), 0) + p.expect('>>> ') + + p.sendline(foo_then_bar) + self.assertEqual(p.expect(['foo\r\nbar', 'foo', 'bar']), 1) + p.expect('>>> ') + + p.sendline(foo_then_bar) + self.assertEqual(p.expect(['foo', 'foo\r\nbar', 'foo', 'bar']), 0) + p.expect('>>> ') + + p.sendline(foo_then_bar) + self.assertEqual(p.expect(['bar', 'foo\r\nbar']), 1) + p.expect('>>> ') + + # If the expect works as if we rematch for every new character, + # 'o\r\nb' should win over 'oo\r\nba'. The latter is longer and + # matches earlier in the input, but isn't satisfied until the 'a' + # arrives. + # However, pexpect doesn't do that (version 2.1 didn't). + p.sendline(foo_then_bar) + self.assertEqual(p.expect(['oo\r\nba', 'o\r\nb']), 0) + p.expect('>>> ') + + # distinct patterns, but both suddenly match when the 'r' arrives. + p.sendline(foo_then_bar) + self.assertEqual(p.expect(['foo\r\nbar', 'ar']), 0) + p.expect('>>> ') + + p.sendline(foo_then_bar) + self.assertEqual(p.expect(['ar', 'foo\r\nbar']), 1) + p.expect('>>> ') + + def test_greed(self): + p = pexpect.spawn(self.PYTHONBIN) + self._greed(p) + + def test_greed_exact(self): + p = pexpect.spawn(self.PYTHONBIN) + # mangle the spawn so we test expect_exact() instead + p.expect = p.expect_exact + self._greed(p) + +if __name__ == '__main__': + unittest.main() + +suite = unittest.makeSuite(ExpectTestCase,'test') + +#fout = open('delete_me_1','wb') +#fout.write(the_old_way) +#fout.close +#fout = open('delete_me_2', 'wb') +#fout.write(the_new_way) +#fout.close + diff --git a/tests/test_filedescriptor.py b/tests/test_filedescriptor.py new file mode 100755 index 0000000..9eb553b --- /dev/null +++ b/tests/test_filedescriptor.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python +''' +PEXPECT LICENSE + + This license is approved by the OSI and FSF as GPL-compatible. + http://opensource.org/licenses/isc-license.txt + + Copyright (c) 2012, Noah Spurrier <noah@noah.org> + PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY + PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE + COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES. + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +''' +import fdpexpect, pexpect +import unittest +import PexpectTestCase +import sys +import os + +class ExpectTestCase(PexpectTestCase.PexpectTestCase): + def setUp(self): + print self.id() + PexpectTestCase.PexpectTestCase.setUp(self) + + def test_fd (self): + fd = os.open ('TESTDATA.txt', os.O_RDONLY) + s = fdpexpect.fdspawn (fd) + s.expect ('This is the end of test data:') + s.expect (pexpect.EOF) + assert s.before == ' END\n' + + def test_maxread (self): + fd = os.open ('TESTDATA.txt', os.O_RDONLY) + s = fdpexpect.fdspawn (fd) + s.maxread = 100 + s.expect('2') + s.expect ('This is the end of test data:') + s.expect (pexpect.EOF) + assert s.before == ' END\n' + + def test_fd_isalive (self): + fd = os.open ('TESTDATA.txt', os.O_RDONLY) + s = fdpexpect.fdspawn (fd) + assert s.isalive() + os.close (fd) + assert not s.isalive(), "Should not be alive after close()" + + def test_fd_isatty (self): + fd = os.open ('TESTDATA.txt', os.O_RDONLY) + s = fdpexpect.fdspawn (fd) + assert not s.isatty() + #os.close(fd) + s.close() + +### def test_close_does_not_close_fd (self): +### '''Calling close() on a fdpexpect.fdspawn object should not +### close the underlying file descriptor. +### ''' +### fd = os.open ('TESTDATA.txt', os.O_RDONLY) +### s = fdpexpect.fdspawn (fd) +### try: +### s.close() +### self.fail('Expected an Exception.') +### except pexpect.ExceptionPexpect, e: +### pass + +if __name__ == '__main__': + unittest.main() + +suite = unittest.makeSuite(ExpectTestCase, 'test') + +#fout = open('delete_me_1','wb') +#fout.write(the_old_way) +#fout.close +#fout = open('delete_me_2', 'wb') +#fout.write(the_new_way) +#fout.close diff --git a/tests/test_interact.py b/tests/test_interact.py new file mode 100755 index 0000000..bbdb681 --- /dev/null +++ b/tests/test_interact.py @@ -0,0 +1,81 @@ +#!/usr/bin/env python +''' +PEXPECT LICENSE + + This license is approved by the OSI and FSF as GPL-compatible. + http://opensource.org/licenses/isc-license.txt + + Copyright (c) 2012, Noah Spurrier <noah@noah.org> + PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY + PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE + COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES. + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +''' +import pexpect +import unittest +import commands +import sys, os, time, tty +import PexpectTestCase +import thread +import threading + +def start_interact (p): + p.interact() + +class InteractTestCase (PexpectTestCase.PexpectTestCase): + + def test_interact_thread (self): + # I can't believe this actually works... + # Note that I had to add a delay in the swapcase_echo.py script. + # I'm not sure why this helped. + p = pexpect.spawn('%s swapcase_echo.py' % self.PYTHONBIN) + mode = tty.tcgetattr(p.STDIN_FILENO) + t = threading.Thread (target=start_interact, args=(p,)) + t.start() + #thread.start_new_thread (start_interact, (p,)) + time.sleep(1) + p.sendline ('Hello') + #time.sleep(1) + try: + p.expect ('hELLO', timeout=4) + except Exception, e: + p.close(force = False) + tty.tcsetattr(p.STDIN_FILENO, tty.TCSAFLUSH, mode) + print str(p) + raise e + p.close(force = True) + tty.tcsetattr(p.STDIN_FILENO, tty.TCSAFLUSH, mode) +# def test_interact_thread (self): +# # I can't believe this actually works... +# p = pexpect.spawn('%s swapcase_echo.py' % self.PYTHONBIN) +# mode = tty.tcgetattr(p.STDIN_FILENO) +# thread.start_new_thread (start_interact, (p,)) +# time.sleep(1) +# p.sendline ('Hello') +# time.sleep(2) +# p.close(force = False) +# tty.tcsetattr(p.STDIN_FILENO, tty.TCSAFLUSH, mode) + + def test_interact (self): + p = pexpect.spawn('%s interact.py' % self.PYTHONBIN) + p.sendline ('Hello') + p.sendline ('there') + p.sendline ('Mr. Python') + p.expect ('Hello') + p.expect ('there') + p.expect ('Mr. Python') + p.sendeof () + p.expect (pexpect.EOF) + +if __name__ == '__main__': + unittest.main() + +suite = unittest.makeSuite(InteractTestCase,'test') + diff --git a/tests/test_isalive.py b/tests/test_isalive.py new file mode 100755 index 0000000..4c7e85e --- /dev/null +++ b/tests/test_isalive.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python +''' +PEXPECT LICENSE + + This license is approved by the OSI and FSF as GPL-compatible. + http://opensource.org/licenses/isc-license.txt + + Copyright (c) 2012, Noah Spurrier <noah@noah.org> + PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY + PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE + COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES. + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +''' +import pexpect +import unittest +import sys, os, time +import PexpectTestCase + +class IsAliveTestCase(PexpectTestCase.PexpectTestCase): + + def test_expect_wait (self): + '''This tests that calling wait on a finished process works as expected. + ''' + p = pexpect.spawn('sleep 3') + if not p.isalive(): + self.fail ('Child process is not alive. It should be.') + time.sleep(1) + p.wait() + if p.isalive(): + self.fail ('Child process is not dead. It should be.') + p = pexpect.spawn('sleep 3') + if not p.isalive(): + self.fail ('Child process is not alive. It should be.') + p.kill(9) + time.sleep(1) + try: + p.wait() + except pexpect.ExceptionPexpect, e: + pass + else: + self.fail ('Should have raised ExceptionPython because you can\'t call wait on a dead process.') + + def test_expect_isalive_dead_after_normal_termination (self): + p = pexpect.spawn('ls') + p.expect(pexpect.EOF) + time.sleep(1) # allow kernel status time to catch up with state. + if p.isalive(): + self.fail ('Child process is not dead. It should be.') + + def test_expect_isalive_dead_after_SIGINT (self): + p = pexpect.spawn('cat', timeout=5) + if not p.isalive(): + self.fail ('Child process is not alive. It should be.') + p.terminate() + # Solaris is kind of slow. + # Without this delay then p.expect(...) will not see + # that the process is dead and it will timeout. + time.sleep(1) + p.expect(pexpect.EOF) + if p.isalive(): + self.fail ('Child process is not dead. It should be.') + + def test_expect_isalive_dead_after_SIGKILL (self): + p = pexpect.spawn('cat', timeout=3) + if not p.isalive(): + self.fail ('Child process is not alive. It should be.') + p.kill(9) + # Solaris is kind of slow. + # Without this delay then p.expect(...) will not see + # that the process is dead and it will timeout. + time.sleep(1) + p.expect(pexpect.EOF) + if p.isalive(): + self.fail ('Child process is not dead. It should be.') + +### Some platforms allow this. Some reset status after call to waitpid. + def test_expect_isalive_consistent_multiple_calls (self): + + '''This tests that multiple calls to isalive() return same value. + ''' + + p = pexpect.spawn('cat') + if not p.isalive(): + self.fail ('Child process is not alive. It should be.') + if not p.isalive(): + self.fail ('Second call. Child process is not alive. It should be.') + p.kill(9) + p.expect(pexpect.EOF) + if p.isalive(): + self.fail ('Child process is not dead. It should be.') + if p.isalive(): + self.fail ('Second call. Child process is not dead. It should be.') + +if __name__ == '__main__': + unittest.main() + +suite = unittest.makeSuite(IsAliveTestCase, 'test') + diff --git a/tests/test_log.py b/tests/test_log.py new file mode 100755 index 0000000..c3af9a7 --- /dev/null +++ b/tests/test_log.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python +''' +PEXPECT LICENSE + + This license is approved by the OSI and FSF as GPL-compatible. + http://opensource.org/licenses/isc-license.txt + + Copyright (c) 2012, Noah Spurrier <noah@noah.org> + PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY + PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE + COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES. + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +''' +import pexpect +import unittest +import os +import tempfile +import PexpectTestCase + +class TestCaseLog(PexpectTestCase.PexpectTestCase): + + def test_log (self): + log_message = 'This is a test.' + filename = tempfile.mktemp() + mylog = open (filename, 'w') + p = pexpect.spawn('echo', [log_message]) + p.logfile = mylog + p.expect (pexpect.EOF) + p.logfile = None + mylog.close() + lf = open(filename).read() + lf = lf[:-2] + os.unlink (filename) + assert lf == log_message + + def test_log_logfile_read (self): + log_message = 'This is a test.' + filename = tempfile.mktemp() + mylog = open (filename, 'w') + p = pexpect.spawn('cat') + p.logfile_read = mylog + p.sendline(log_message) + p.sendeof() + p.expect (pexpect.EOF) + p.logfile = None + mylog.close() + lf = open(filename).read() + lf = lf[:-2] + os.unlink (filename) + lf = lf.replace(chr(4),'') + assert lf == 'This is a test.\r\nThis is a test.', "The read log file has bad data. Note logfile_read should only record what we read from child and nothing else.\n" + repr(lf) + + def test_log_logfile_send (self): + log_message = 'This is a test.' + filename = tempfile.mktemp() + mylog = open (filename, 'w') + p = pexpect.spawn('cat') + p.logfile_send = mylog + p.sendline(log_message) + p.sendeof() + p.expect (pexpect.EOF) + p.logfile = None + mylog.close() + lf = open(filename).read() + lf = lf[:-2] + os.unlink (filename) + assert lf == log_message, "The send log file has bad data. Note logfile_send should only record what we sent to child and nothing else." + + def test_log_send_and_received (self): + + '''The logfile should have the test message three time -- once for the + data we sent. Once for the data that cat echos back as characters are + typed. And once for the data that cat prints after we send a linefeed + (sent by sendline). ''' + + log_message = 'This is a test.' + filename = tempfile.mktemp() + mylog = open (filename, 'w') + p = pexpect.spawn('cat') + p.logfile = mylog + p.sendline(log_message) + p.sendeof() + p.expect (pexpect.EOF) + p.logfile = None + mylog.close() + lf = open(filename).read() + os.unlink (filename) + lf = lf.replace(chr(4),'') + assert lf == 'This is a test.\nThis is a test.\r\nThis is a test.\r\n', repr(lf) + +if __name__ == '__main__': + unittest.main() + +suite = unittest.makeSuite(TestCaseLog,'test') + diff --git a/tests/test_misc.py b/tests/test_misc.py new file mode 100755 index 0000000..61abfde --- /dev/null +++ b/tests/test_misc.py @@ -0,0 +1,217 @@ +#!/usr/bin/env python +''' +PEXPECT LICENSE + + This license is approved by the OSI and FSF as GPL-compatible. + http://opensource.org/licenses/isc-license.txt + + Copyright (c) 2012, Noah Spurrier <noah@noah.org> + PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY + PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE + COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES. + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +''' +import pexpect +import unittest +import PexpectTestCase +import time +import os +import re + +class TestCaseMisc(PexpectTestCase.PexpectTestCase): + + def test_isatty (self): + child = pexpect.spawn('cat') + assert child.isatty(), "Not returning True. Should always be True." + def test_read (self): + child = pexpect.spawn('cat') + child.sendline ("abc") + child.sendeof() + assert child.read(0) == '', "read(0) did not return ''" + assert child.read(1) == 'a', "read(1) did not return 'a'" + assert child.read(1) == 'b', "read(1) did not return 'b'" + assert child.read(1) == 'c', "read(1) did not return 'c'" + assert child.read(2) == '\r\n', "read(2) did not return '\\r\\n'" + assert child.read() == 'abc\r\n', "read() did not return 'abc\\r\\n'" + def test_readline (self): + '''See the note in test_readlines() for an explaination as to why + I allow line3 and line4 to return multiple patterns. + Basically, this is done to handle a valid condition on slow systems. + ''' + child = pexpect.spawn('cat') + child.sendline ("abc") + child.sendline ("123") + child.sendeof() + line1 = child.readline(0) + line2 = child.readline() + line3 = child.readline(2) + line4 = child.readline(1) + line5 = child.readline() + assert line1 == '', "readline(0) did not return ''. Returned: " + repr(line1) + assert line2 == 'abc\r\n', "readline() did not return 'abc\\r\\n'. Returned: " + repr(line2) + assert ( (line3 == 'abc\r\n' or line3 == '123\r\n'), + "readline(2) did not return 'abc\\r\\n'. Returned: " + + repr(line3) ) + assert ( (line4 == '123\r\n' or line4 == 'abc\r\n'), + "readline(1) did not return '123\\r\\n'. Returned: " + + repr(line4) ) + assert line5 == '123\r\n', "readline() did not return '123\\r\\n'. Returned: " + repr(line5) + def test_iter (self): + '''See the note in test_readlines() for an explaination as to why + I allow line3 and line4 to return multiple patterns. + Basically, this is done to handle a valid condition on slow systems. + ''' + child = pexpect.spawn('cat') + child.sendline ("abc") + child.sendline ("123") + child.sendeof() + # Don't use ''.join() because we want to test the ITERATOR. + page = "" + for line in child: + page = page + line + assert ( (page == 'abc\r\nabc\r\n123\r\n123\r\n' or + page == 'abc\r\n123\r\nabc\r\n123\r\n') , + "iterator did not work. page=%s"%repr(page) ) + def test_readlines(self): + '''Note that on some slow or heavily loaded systems that the lines + coming back from 'cat' may come even after the EOF. + We except to see two copies of the lines we send 'cat'. + The first line is the TTY echo, the second line is from 'cat'. + Usually 'cat' will respond with 'abc' before we have a chance to + send the second line, '123'. If this does not happen then the + lines may appear out of order. This is technically not an error. + That's just the nature of asynchronous communication. + This is why the assert will allow either of the two possible + patterns to be returned by lineslined(). The (lame) alternative is + to put a long sleep between the two sendline() calls, but then + I have to make assumptions about how fast 'cat' can reply. + ''' + child = pexpect.spawn('cat') + child.sendline ("abc") + child.sendline ("123") + child.sendeof() + page = child.readlines() + page = ''.join(page) + assert ( (page == 'abc\r\nabc\r\n123\r\n123\r\n' or + page == 'abc\r\n123\r\nabc\r\n123\r\n'), + "readlines() did not work. page=%s"%repr(page) ) + def test_write (self): + child = pexpect.spawn('cat') + child.write('a') + child.write('\r') + assert child.readline() == 'a\r\n', "write() did not work" + def test_writelines (self): + child = pexpect.spawn('cat') + child.writelines(['abc','123','xyz','\r']) + child.sendeof() + line = child.readline() + assert line == 'abc123xyz\r\n', "writelines() did not work. line=%s"%repr(line) + def test_eof(self): + child = pexpect.spawn('cat') + child.sendeof() + try: + child.expect ('the unexpected') + except: + pass + assert child.eof(), "child.eof() did not return True" + def test_terminate(self): + child = pexpect.spawn('cat') + child.terminate(force=1) + assert child.terminated, "child.terminated is not True" + def test_bad_child_pid(self): + child = pexpect.spawn('cat') + child.terminate(force=1) + child.terminated = 0 # Force invalid state to test code + try: + child.isalive() + except pexpect.ExceptionPexpect, e: + pass + else: + self.fail ("child.isalive() should have raised a pexpect.ExceptionPexpect") + child.terminated = 1 # Force back to valid state so __del__ won't complain + def test_bad_arguments (self): + '''This tests that we get a graceful error when passing bad arguments.''' + try: + p = pexpect.spawn(1) + except pexpect.ExceptionPexpect, e: + pass + else: + self.fail ("pexpect.spawn(1) should have raised a pexpect.ExceptionPexpect.") + try: + p = pexpect.spawn('ls', '-la') # should really use pexpect.spawn('ls', ['-ls']) + except TypeError, e: + pass + else: + self.fail ("pexpect.spawn('ls', '-la') should have raised a TypeError.") + try: + p = pexpect.spawn('cat') + p.close() + p.read_nonblocking(size=1, timeout=3) + except ValueError, e: + pass + else: + self.fail ("read_nonblocking on closed spawn object should have raised a ValueError.") + def test_isalive(self): + child = pexpect.spawn('cat') + assert child.isalive(), "child.isalive() did not return True" + child.sendeof() + child.expect(pexpect.EOF) + assert not child.isalive(), "child.isalive() did not return False" + def test_bad_type_in_expect(self): + child = pexpect.spawn('cat') + try: + child.expect({}) # We don't support dicts yet. Should give TypeError + except TypeError, e: + pass + else: + self.fail ("child.expect({}) should have raised a TypeError") + def test_winsize(self): + child = pexpect.spawn('cat') + child.setwinsize(10,13) + assert child.getwinsize()==(10,13), "getwinsize() did not return (10,13)" + def test_env(self): + default = pexpect.run('env') + userenv = pexpect.run('env', env={'foo':'pexpect'}) + assert default!=userenv, "'default' and 'userenv' should be different" + assert 'foo' in userenv and 'pexpect' in userenv, "'foo' and 'pexpect' should be in 'userenv'" + def test_cwd (self): # This assumes 'pwd' and '/tmp' exist on this platform. + default = pexpect.run('pwd') + tmpdir = pexpect.run('pwd', cwd='/tmp') + assert default!=tmpdir, "'default' and 'tmpdir' should be different" + assert ('tmp' in tmpdir), "'tmp' should be returned by 'pwd' command" + def test_which (self): + p = os.defpath + ep = os.environ['PATH'] + os.defpath = ":/tmp" + os.environ['PATH'] = ":/tmp" + wp = pexpect.which ("ticker.py") + assert wp == 'ticker.py', "Should return a string. Returned %s" % wp + os.defpath = "/tmp" + os.environ['PATH'] = "/tmp" + wp = pexpect.which ("ticker.py") + assert wp == None, "Executable should not be found. Returned %s" % wp + os.defpath = p + os.environ['PATH'] = ep + def test_searcher_re (self): + ss = pexpect.searcher_re ([re.compile('this'),re.compile('that'),re.compile('and'),re.compile('the'),re.compile('other')]) + assert ss.__str__() == 'searcher_re:\n 0: re.compile("this")\n 1: re.compile("that")\n 2: re.compile("and")\n 3: re.compile("the")\n 4: re.compile("other")' + ss = pexpect.searcher_re ([pexpect.TIMEOUT,re.compile('this'),re.compile('that'),re.compile('and'),pexpect.EOF,re.compile('other')]) + assert ss.__str__() == 'searcher_re:\n 0: TIMEOUT\n 1: re.compile("this")\n 2: re.compile("that")\n 3: re.compile("and")\n 4: EOF\n 5: re.compile("other")' + def test_searcher_string (self): + ss = pexpect.searcher_string (['this','that','and','the','other']) + assert ss.__str__() == 'searcher_string:\n 0: "this"\n 1: "that"\n 2: "and"\n 3: "the"\n 4: "other"', repr(ss.__str__()) + ss = pexpect.searcher_string (['this',pexpect.EOF,'that','and','the','other',pexpect.TIMEOUT]) + assert ss.__str__() == 'searcher_string:\n 0: "this"\n 1: EOF\n 2: "that"\n 3: "and"\n 4: "the"\n 5: "other"\n 6: TIMEOUT' + +if __name__ == '__main__': + unittest.main() + +suite = unittest.makeSuite(TestCaseMisc,'test') + diff --git a/tests/test_missing_command.py b/tests/test_missing_command.py new file mode 100755 index 0000000..fea9218 --- /dev/null +++ b/tests/test_missing_command.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python +''' +PEXPECT LICENSE + + This license is approved by the OSI and FSF as GPL-compatible. + http://opensource.org/licenses/isc-license.txt + + Copyright (c) 2012, Noah Spurrier <noah@noah.org> + PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY + PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE + COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES. + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +''' +import pexpect +import unittest +import PexpectTestCase + +class MissingCommandTestCase (PexpectTestCase.PexpectTestCase): + def testMissingCommand(self): + try: + i = pexpect.spawn ('ZXQYQZX') + except Exception: + pass + else: + self.fail('Expected an Exception.') + +if __name__ == '__main__': + unittest.main() + +suite = unittest.makeSuite(MissingCommandTestCase,'test') + diff --git a/tests/test_performance.py b/tests/test_performance.py new file mode 100755 index 0000000..50bb12f --- /dev/null +++ b/tests/test_performance.py @@ -0,0 +1,91 @@ +#!/usr/bin/env python +''' +PEXPECT LICENSE + + This license is approved by the OSI and FSF as GPL-compatible. + http://opensource.org/licenses/isc-license.txt + + Copyright (c) 2012, Noah Spurrier <noah@noah.org> + PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY + PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE + COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES. + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +''' + +import unittest, time +import pexpect +import PexpectTestCase + +# This isn't exactly a unit test, but it fits in nicely with the rest of the tests. + +class PerformanceTestCase (PexpectTestCase.PexpectTestCase): + + '''Testing the performance of expect, with emphasis on wading through long + inputs. ''' + + def plain_range(self, n): + e = pexpect.spawn('python') + self.assertEqual(e.expect('>>>'), 0) + e.sendline('for n in range(1, %d+1): print n' % n) + self.assertEqual(e.expect(r'\.{3}'), 0) + e.sendline('') + self.assertEqual(e.expect(['inquisition', '%d' % n]), 1) + + def window_range(self, n): + e = pexpect.spawn('python') + self.assertEqual(e.expect('>>>'), 0) + e.sendline('for n in range(1, %d+1): print n' % n) + self.assertEqual(e.expect(r'\.{3}'), 0) + e.sendline('') + self.assertEqual(e.expect(['inquisition', '%d' % n], searchwindowsize=10), 1) + + def exact_range(self, n): + e = pexpect.spawn('python') + self.assertEqual(e.expect_exact(['>>>']), 0) + e.sendline('for n in range(1, %d+1): print n' % n) + self.assertEqual(e.expect_exact(['...']), 0) + e.sendline('') + self.assertEqual(e.expect_exact(['inquisition', '%d' % n],timeout=520), 1) + + def ewin_range(self, n): + e = pexpect.spawn('python') + self.assertEqual(e.expect_exact(['>>>']), 0) + e.sendline('for n in range(1, %d+1): print n' % n) + self.assertEqual(e.expect_exact(['...']), 0) + e.sendline('') + self.assertEqual(e.expect_exact(['inquisition', '%d' % n], searchwindowsize=10), 1) + + def faster_range(self, n): + e = pexpect.spawn('python') + self.assertEqual(e.expect('>>>'), 0) + e.sendline('range(1, %d+1)' % n) + self.assertEqual(e.expect(['inquisition', '%d' % n]), 1) + + def test_100000(self): + start_time = time.time() + self.plain_range (100000) + print "100000 calls to plain_range:", (time.time() - start_time) + start_time = time.time() + self.window_range(100000) + print "100000 calls to window_range:", (time.time() - start_time) + start_time = time.time() + self.exact_range (100000) + print "100000 calls to exact_range:", (time.time() - start_time) + start_time = time.time() + self.ewin_range (100000) + print "100000 calls to ewin_range:", (time.time() - start_time) + start_time = time.time() + self.faster_range(100000) + print "100000 calls to faster_range:", (time.time() - start_time) + +if __name__ == "__main__": + unittest.main() + +suite = unittest.makeSuite(PerformanceTestCase,'test') diff --git a/tests/test_run.py b/tests/test_run.py new file mode 100755 index 0000000..261bcb0 --- /dev/null +++ b/tests/test_run.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python +''' +PEXPECT LICENSE + + This license is approved by the OSI and FSF as GPL-compatible. + http://opensource.org/licenses/isc-license.txt + + Copyright (c) 2012, Noah Spurrier <noah@noah.org> + PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY + PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE + COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES. + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +''' +import pexpect +import unittest +import commands +import sys +import PexpectTestCase + +# TODO Many of these test cases blindly assume that sequential +# TODO listing of the /bin directory will yield the same results. +# TODO This may not always be true, but seems adequate for testing for now. +# TODO I should fix this at some point. + +def timeout_callback (d): +# print d["event_count"], + if d["event_count"]>5: + return 1 + return 0 + +class ExpectTestCase(PexpectTestCase.PexpectTestCase): + def test_run_exit (self): + (data, exitstatus) = pexpect.run ('python exit1.py', withexitstatus=1) + assert exitstatus == 1, "Exit status of 'python exit1.py' should be 1." + + def test_run (self): + the_old_way = commands.getoutput('ls -l /bin') + (the_new_way, exitstatus) = pexpect.run ('ls -l /bin', withexitstatus=1) + the_new_way = the_new_way.replace('\r','')[:-1] + assert the_old_way == the_new_way + assert exitstatus == 0 + + def test_run_callback (self): # TODO it seems like this test could block forever if run fails... + pexpect.run("cat", timeout=1, events={pexpect.TIMEOUT:timeout_callback}) + + def test_run_bad_exitstatus (self): + (the_new_way, exitstatus) = pexpect.run ('ls -l /najoeufhdnzkxjd', withexitstatus=1) + assert exitstatus != 0 + +if __name__ == '__main__': + unittest.main() + +suite = unittest.makeSuite(ExpectTestCase,'test') + diff --git a/tests/test_run_out_of_pty.py b/tests/test_run_out_of_pty.py new file mode 100755 index 0000000..b6b9e6c --- /dev/null +++ b/tests/test_run_out_of_pty.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python +''' +PEXPECT LICENSE + + This license is approved by the OSI and FSF as GPL-compatible. + http://opensource.org/licenses/isc-license.txt + + Copyright (c) 2012, Noah Spurrier <noah@noah.org> + PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY + PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE + COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES. + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +''' +import pexpect +import unittest +import commands +import sys +import PexpectTestCase + +class ExpectTestCase(PexpectTestCase.PexpectTestCase): + # This takes too long to run and isn't all that interesting of a test. + def OFF_test_run_out_of_pty (self): + '''This assumes that the tested platform has < 10000 pty devices. + This test currently does not work under Solaris. + Under Solaris it runs out of file descriptors first and + ld.so starts to barf: + ld.so.1: pt_chmod: fatal: /usr/lib/libc.so.1: Too many open files + ''' + plist=[] + for count in range (0,10000): + try: + plist.append (pexpect.spawn('ls -l')) + except pexpect.ExceptionPexpect, e: + for c in range (0,count): + plist[c].close() + return + except Exception, e: + self.fail ('Expected ExceptionPexpect. ' + str(e)) + self.fail ('Could not run out of pty devices. This may be OK.') + +if __name__ == '__main__': + unittest.main() + +suite = unittest.makeSuite(ExpectTestCase,'test') + diff --git a/tests/test_screen.py b/tests/test_screen.py new file mode 100755 index 0000000..714f85e --- /dev/null +++ b/tests/test_screen.py @@ -0,0 +1,191 @@ +#!/usr/bin/env python +''' +PEXPECT LICENSE + + This license is approved by the OSI and FSF as GPL-compatible. + http://opensource.org/licenses/isc-license.txt + + Copyright (c) 2012, Noah Spurrier <noah@noah.org> + PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY + PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE + COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES. + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +''' + +import screen +import unittest +import PexpectTestCase + +fill1_target='XXXXXXXXXX\n' + \ +'XOOOOOOOOX\n' + \ +'XO::::::OX\n' + \ +'XO:oooo:OX\n' + \ +'XO:o..o:OX\n' + \ +'XO:o..o:OX\n' + \ +'XO:oooo:OX\n' + \ +'XO::::::OX\n' + \ +'XOOOOOOOOX\n' + \ +'XXXXXXXXXX' +fill2_target = 'XXXXXXXXXXX\n' + \ +'XOOOOOOOOOX\n' + \ +'XO:::::::OX\n' + \ +'XO:ooooo:OX\n' + \ +'XO:o...o:OX\n' + \ +'XO:o.+.o:OX\n' + \ +'XO:o...o:OX\n' + \ +'XO:ooooo:OX\n' + \ +'XO:::::::OX\n' + \ +'XOOOOOOOOOX\n' + \ +'XXXXXXXXXXX' +put_target = '\\.3.5.7.9/\n' + \ +'.........2\n' + \ +'3.........\n' + \ +'.........4\n' + \ +'5...\\/....\n' + \ +'..../\\...6\n' + \ +'7.........\n' + \ +'.........8\n' + \ +'9.........\n' + \ +'/2.4.6.8.\\' +scroll_target = '\\.3.5.7.9/\n' + \ +'\\.3.5.7.9/\n' + \ +'\\.3.5.7.9/\n' + \ +'\\.3.5.7.9/\n' + \ +'5...\\/....\n' + \ +'..../\\...6\n' + \ +'/2.4.6.8.\\\n' + \ +'/2.4.6.8.\\\n' + \ +'/2.4.6.8.\\\n' + \ +'/2.4.6.8.\\' +insert_target = 'ZXZZZZZZXZ\n' +\ +'.........2\n' +\ +'3.........\n' +\ +'.........4\n' +\ +'Z5...\\/...\n' +\ +'..../Z\\...\n' +\ +'7.........\n' +\ +'.........8\n' +\ +'9.........\n' +\ +'ZZ/2.4.6ZZ' +get_region_target = ['......', '.\\/...', './\\...', '......'] + +class screenTestCase (PexpectTestCase.PexpectTestCase): + def make_screen_with_put (self): + s = screen.screen(10,10) + s.fill ('.') + for r in range (1,s.rows + 1): + if r % 2: + s.put_abs (r, 1, str(r)) + else: + s.put_abs (r, s.cols, str(r)) + for c in range (1,s.cols + 1): + if c % 2: + s.put_abs (1, c, str(c)) + else: + s.put_abs (s.rows, c, str(c)) + s.put_abs(1,1, '\\') + s.put_abs(1,s.cols, '/') + s.put_abs(s.rows,1,'/') + s.put_abs(s.rows, s.cols, '\\') + s.put_abs(5,5,'\\') + s.put_abs(5,6,'/') + s.put_abs(6,5,'/') + s.put_abs(6,6,'\\') + return s + + def test_fill (self): + s = screen.screen (10,10) + s.fill_region (10,1,1,10,'X') + s.fill_region (2,2,9,9,'O') + s.fill_region (8,8,3,3,':') + s.fill_region (4,7,7,4,'o') + s.fill_region (6,5,5,6,'.') + assert str(s) == fill1_target + + s = screen.screen (11,11) + s.fill_region (1,1,11,11,'X') + s.fill_region (2,2,10,10,'O') + s.fill_region (9,9,3,3,':') + s.fill_region (4,8,8,4,'o') + s.fill_region (7,5,5,7,'.') + s.fill_region (6,6,6,6,'+') + assert str(s) == fill2_target + def test_put (self): + s = self.make_screen_with_put() + assert str(s) == put_target + def test_get_region (self): + s = self.make_screen_with_put() + r = s.get_region (4,4,7,9) + assert r == get_region_target + + def test_cursor_save (self): + s = self.make_screen_with_put() + s.cursor_home (5,5) + c = s.get() + s.cursor_save() + s.cursor_home() + s.cursor_forward() + s.cursor_down() + s.cursor_unsave() + assert s.cur_r == 5 and s.cur_c == 5 + assert c == s.get() + def test_scroll (self): + s = self.make_screen_with_put() + s.scroll_screen_rows (1,4) + s.scroll_down(); s.scroll_down(); s.scroll_down() + s.scroll_down(); s.scroll_down(); s.scroll_down() + s.scroll_screen_rows (7,10) + s.scroll_up(); s.scroll_up(); s.scroll_up() + s.scroll_up(); s.scroll_up(); s.scroll_up() + assert str(s) == scroll_target + def test_insert (self): + s = self.make_screen_with_put() + s.insert_abs (10,1,'Z') + s.insert_abs (1,1,'Z') + s.insert_abs (1,1,'Z') + s.insert_abs (1,1,'Z') + s.insert_abs (1,1,'Z') + s.insert_abs (1,1,'Z') + s.insert_abs (10,1,'Z') + s.insert_abs (1,1,'Z') + s.insert_abs (1,1,'Z') + s.insert_abs (5,1,'Z') + s.insert_abs (6,6,'Z') + s.cursor_home (1,1) # Also test relative insert. + s.insert ('Z') + s.insert ('Z') + s.insert ('Z') + s.insert ('Z') + s.insert_abs (1,8,'X') + s.insert_abs (1,2,'X') + s.insert_abs (10,9,'Z') + s.insert_abs (10,9,'Z') + assert str(s) == insert_target + # def test_write (self): + # s = screen.screen (6,65) + # s.fill('.') + # s.cursor_home() + # for c in write_text: + # s.write (c) + # print str(s) + # assert str(s) == write_target + # def test_tetris (self): + # s = screen.screen (24,80) + # tetris_text = open ('tetris.data').read() + # for c in tetris_text: + # s.write (c) + # assert str(s) == tetris_target + +if __name__ == '__main__': + unittest.main() + +suite = unittest.makeSuite(screenTestCase,'test') + + diff --git a/tests/test_timeout_pattern.py b/tests/test_timeout_pattern.py new file mode 100755 index 0000000..606b045 --- /dev/null +++ b/tests/test_timeout_pattern.py @@ -0,0 +1,86 @@ +#!/usr/bin/env python +''' +PEXPECT LICENSE + + This license is approved by the OSI and FSF as GPL-compatible. + http://opensource.org/licenses/isc-license.txt + + Copyright (c) 2012, Noah Spurrier <noah@noah.org> + PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY + PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE + COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES. + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +''' +import pexpect +import unittest +import sys, os, time +import PexpectTestCase + +class Exp_TimeoutTestCase(PexpectTestCase.PexpectTestCase): + def test_matches_exp_timeout (self): + '''This tests that we can raise and catch TIMEOUT. + ''' + try: + raise pexpect.TIMEOUT("TIMEOUT match test") + except pexpect.TIMEOUT: + pass + #print "Correctly caught TIMEOUT when raising TIMEOUT." + else: + self.fail('TIMEOUT not caught by an except TIMEOUT clause.') + + def test_pattern_printout (self): + '''Verify that a TIMEOUT returns the proper patterns it is trying to match against. + Make sure it is returning the pattern from the correct call.''' + try: + p = pexpect.spawn('cat') + p.sendline('Hello') + p.expect('Hello') + p.expect('Goodbye',timeout=5) + except pexpect.TIMEOUT, expTimeoutInst: + assert p.match_index == None + else: + self.fail("Did not generate a TIMEOUT exception.") + + def test_exp_timeout_notThrown (self): + '''Verify that a TIMEOUT is not thrown when we match what we expect.''' + try: + p = pexpect.spawn('cat') + p.sendline('Hello') + p.expect('Hello') + except pexpect.TIMEOUT: + self.fail("TIMEOUT caught when it shouldn't be raised because we match the proper pattern.") + + def test_stacktraceMunging (self): + '''Verify that the stack trace returned with a TIMEOUT instance does not contain references to pexpect.''' + try: + p = pexpect.spawn('cat') + p.sendline('Hello') + p.expect('Goodbye',timeout=5) + except pexpect.TIMEOUT, e: + if e.get_trace().count("pexpect.py") != 0: + self.fail("The TIMEOUT get_trace() referenced pexpect.py. It should only reference the caller.\n"+e.get_trace()) + + def test_correctStackTrace (self): + '''Verify that the stack trace returned with a TIMEOUT instance correctly handles function calls.''' + def nestedFunction (spawnInstance): + spawnInstance.expect("junk", timeout=3) + + try: + p = pexpect.spawn('cat') + p.sendline('Hello') + nestedFunction(p) + except pexpect.TIMEOUT, e: + if e.get_trace().count("nestedFunction") == 0: + self.fail("The TIMEOUT get_trace() did not show the call to the nestedFunction function.\n" + str(e) + "\n" + e.get_trace()) + +if __name__ == '__main__': + unittest.main() + +suite = unittest.makeSuite(Exp_TimeoutTestCase,'test') diff --git a/tests/test_winsize.py b/tests/test_winsize.py new file mode 100755 index 0000000..4888641 --- /dev/null +++ b/tests/test_winsize.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python +''' +PEXPECT LICENSE + + This license is approved by the OSI and FSF as GPL-compatible. + http://opensource.org/licenses/isc-license.txt + + Copyright (c) 2012, Noah Spurrier <noah@noah.org> + PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY + PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE + COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES. + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +''' +import pexpect +import unittest +import PexpectTestCase +import time +import sys, os, signal + +class TestCaseWinsize(PexpectTestCase.PexpectTestCase): + + def test_winsize (self): + ''' + This tests that the child process can set and get the windows size. + This makes use of an external script sigwinch_report.py. + ''' + p1 = pexpect.spawn('%s sigwinch_report.py' % self.PYTHONBIN) + time.sleep(10) + p1.setwinsize (11,22) + time.sleep(3) + index = p1.expect ([pexpect.TIMEOUT, 'SIGWINCH: \(([0-9]*), ([0-9]*)\)'], timeout=30) + if index == 0: + self.fail ("TIMEOUT -- this platform may not support sigwinch properly.\n" + str(p1)) + r = p1.match.group(1) + c = p1.match.group(2) + assert (r=="11" and c=="22") + time.sleep(1) + p1.setwinsize (24,80) + index = p1.expect ([pexpect.TIMEOUT, 'SIGWINCH: \(([0-9]*), ([0-9]*)\)'], timeout=10) + if index == 0: + self.fail ("TIMEOUT -- this platform may not support sigwinch properly.\n" + str(p1)) + r = p1.match.group(1) + c = p1.match.group(2) + assert (r=="24" and c=="80") + p1.close() + +# def test_parent_resize (self): +# pid = os.getpid() +# p1 = pexpect.spawn('%s sigwinch_report.py' % self.PYTHONBIN) +# time.sleep(10) +# p1.setwinsize (11,22) +# os.kill (pid, signal.SIGWINCH) + +if __name__ == '__main__': + unittest.main() + +suite = unittest.makeSuite(TestCaseWinsize,'test') + + diff --git a/tests/tetris.data b/tests/tetris.data new file mode 100644 index 0000000..06b6ce6 --- /dev/null +++ b/tests/tetris.data @@ -0,0 +1,3 @@ +[2J +[24;1H J->LEFT K->ROTATE L->RIGHT SPACE->DROP P->PAUSE Q->QUIT +[1;28HXX[1;36HXXXXXXXX[1;50HXX[2;28HXX[2;50HXX[3;28HXX[3;50HXX[4;28HXX[4;50HXX[5;28HXX[5;50HXX[6;28HXX[6;50HXX[7;28HXX[7;50HXX[8;28HXX[8;50HXX[9;28HXX[9;50HXX[10;28HXX[10;50HXX[11;28HXX[11;50HXX[12;28HXX[12;50HXX[13;28HXX[13;50HXX[14;28HXX[14;50HXX[15;28HXX[15;50HXX[16;28HXX[16;50HXX[17;28HXX[17;50HXX[18;28HXX[18;50HXX[19;28HXX[19;50HXX[20;28HXX[20;50HXX[21;28HXXXXXXXXXXXXXXXXXXXXXXXX[1;36H [2;36HXXXXXXXX[21;50HXX[2;36H [3;36HXXXXXXXX[21;50HXX[3;36H [4;36HXXXXXXXX[21;50HXX[4;36H [5;36HXXXXXXXX[21;50HXX[5;34HXX[5;42H [21;50HXX[5;34H [6;34HXXXXXXXX[21;50HXX[6;32HXX[6;40H [21;50HXX[6;30HXX[6;38H [21;50HXX[6;30H [7;30HXXXXXXXX[21;50HXX[21;50HXX[21;50HXX[21;50HXX[7;30H [8;30HXXXXXXXX[21;50HXX[8;30H [20;30HXXXXXXXX[21;50HXX[1;36HXXXXXX[2;36HXX[21;50HXX[1;36H [2;38HXXXX[3;36HXX[21;50HXX[2;36H [2;42HXX[3;36H XX[21;50HXX[2;38H [3;40HXXXX[4;38HXX[21;50HXX[3;38H [3;44HXX[4;38H XX[21;50HXX[3;40H [3;46HXX[4;40H XX[21;50HXX[3;42H [3;48HXX[4;42H XX[21;50HXX[21;50HXX[21;50HXX[21;50HXX[21;50HXX[21;50HXX[21;50HXX[3;44H [4;46HXXXX[5;44HXX[21;50HXX[4;44H [5;46HXXXX[6;44HXX[21;50HXX[5;44H [6;44H [19;44HXXXXXX[20;44HXX[21;50HXX[1;36HXXXXXX[2;36HXX[21;50HXX[1;36H [2;38HXXXX[3;36HXX[21;50HXX[2;36H [2;42HXX[3;36H XX[21;50HXX[2;38H [2;44HXX[3;38H XX[21;50HXX[2;40H [3;42HXXXX[4;40HXX[21;50HXX[2;42HXX[3;40H [3;44H [4;40H XXXX[21;50HXX[2;42H XX[3;40HXX[3;44HXX[4;42H [21;50HXX[2;44H [3;40H [4;40HXXXXXX[21;50HXX[3;44H [4;40H [17;44HXX[18;40HXXXXXX[21;50HXX[1;36HXXXX[21;50HXX[1;36H [1;40HXX[2;36HXXXX[21;50HXX[1;36HXX[1;40H [2;34HXX[2;38H [21;50HXX[1;36H [2;34H [2;38HXX[3;34HXXXX[21;50HXX[2;34HXX[2;38H [3;32HXX[3;36H [21;50HXX[2;32HXX[2;36H [3;30HXX[3;34H [21;50HXX[21;50HXX[2;32H [3;30H [3;34HXX[4;30HXXXX[21;50HXX[21;50HXX[3;32H [4;30H [18;32HXXXX[19;30HXXXX[21;50HXX[1;36HXXXXXX[2;36HXX[21;50HXX[1;36H [1;42HXX[2;36H XX[21;50HXX[1;38H [2;40HXXXX[3;38HXX[21;50HXX[2;38H [2;44HXX[3;38H XX[21;50HXX[2;40H [2;46HXX[3;40H XX[21;50HXX[2;42H [2;48HXX[3;42H XX[21;50HXX[2;44H [3;46HXXXX[4;44HXX[21;50HXX[21;50HXX[21;50HXX[3;44H [4;44H [15;44HXXXXXX[16;44HXX[21;50HXX[1;36HXXXXXXXX[21;50HXX[1;34HXX[1;42H [21;50HXX[1;34H [2;34HXXXXXXXX[21;50HXX[2;32HXX[2;40H [21;50HXX[2;30HXX[2;38H [21;50HXX[21;50HXX[21;50HXX[21;50HXX[21;50HXX[2;30H [3;30HXXXXXXXX[21;50HXX[3;30H [17;30HXXXXXXXX[21;50HXX[1;38HXXXX[21;50HXX[1;38H [16;36HXXXX[17;38HXXXX[21;50HXX[21;50HXX[1;36HXXXX[21;50HXX[1;36H [1;40HXX[21;50HXX[2;38HXXXX[21;50HXX[1;38H [1;42HXX[2;38H [2;42HXX[21;50HXX[1;40H [1;44HXX[2;40H [2;44HXX[21;50HXX[1;42H [1;46HXX[2;42H [2;46HXX[21;50HXX[1;44H [3;44HXXXX[21;50HXX[2;44H [3;44H [13;44HXXXX[14;44HXXXX[21;50HXX[1;36HXXXXXX[2;40HXX[21;50HXX[1;34HXX[1;40H [2;38HXX [21;50HXX[1;34H [2;34HXXXX[3;38HXX[21;50HXX[2;32HXX[2;38H [3;36HXX [21;50HXX[2;30HXX[2;36H [3;34HXX [21;50HXX[21;50HXX[21;50HXX[21;50HXX[2;30H [3;34H [15;30HXXXXXX[16;34HXX[21;50HXX[1;36HXXXXXXXX[21;50HXX[1;36H [1;44HXX[21;50HXX[1;38H [2;38HXXXXXXXX[21;50HXX[1;40HXX[2;38H [2;42H [3;40HXX[4;40HXX[21;50HXX[1;40H [5;40HXX[21;50HXX[2;40H [3;38HXX[3;42HXXXX[4;40H [5;40H [21;50HXX[2;40HXX[3;38H [3;42H [4;40HXX[5;40HXX[21;50HXX[2;40H [6;40HXX[21;50HXX[3;40H [4;40H [5;40H [6;40H [13;40HXX[14;40HXX[15;40HXX[16;40HXX[21;50HXX[1;36HXXXXXX[2;38HXX[21;50HXX[1;34HXX[1;40H [2;36HXX [21;50HXX[1;32HXX[1;38H [2;34HXX [21;50HXX[1;32H [21;50HXX[1;36H [2;36HXX[3;34HXX[21;50HXX[1;32HXX [2;32HXX[2;36H [3;32HXX [21;50HXX[2;30HXX[3;32H [21;50HXX[1;32H [2;30H [2;34H [3;30HXXXXXX[21;50HXX[2;32H [3;30H [13;32HXX[14;30HXXXXXX[21;50HXX[1;36HXXXXXXXX[21;50HXX[1;36H [1;44HXX[21;50HXX[1;38H [1;42H [2;40HXX[3;40HXX[21;50HXX[1;40H XX[2;40H XX[3;40H XX[21;50HXX[4;42HXX[21;50HXX[1;42H [2;40HXX[2;44HXXXX[3;42H [4;42H [21;50HXX[2;40H [2;48HXX[21;50HXX[1;44HXX[2;42H [2;46H [3;44HXX[4;44HXX[21;50HXX[1;44H [5;44HXX[21;50HXX[2;44H [3;44H [4;44H [5;44H [9;44HXX[10;44HXX[11;44HXX[12;44HXX[21;50HXX[1;36HXXXXXX[2;36HXX[21;50HXX[1;36H [1;40H [2;36H XXXX[21;50HXX[1;36HXX [2;36HXX[2;40H [21;50HXX[1;34HXX[1;38HXX[2;36H [21;50HXX[1;34H [2;34HXXXXXX[21;50HXX[1;36HXX [2;32HXX[2;38H [21;50HXX[1;32HXXXX [2;32H [2;36H [3;34HXX[21;50HXX[1;30HXX[1;34H [2;32HXX [3;32HXX [21;50HXX[1;30H [2;30HXX[4;32HXX[21;50HXX[2;30H [3;32H [4;32H [10;30HXXXX[11;32HXX[12;32HXX[21;50HXX[1;36HXXXXXX[2;40HXX[21;50HXX[1;36H [1;40H [2;38HXX [21;50HXX[1;36HXX[1;40HXX[2;38H [21;50HXX[1;38H [2;36HXXXXXX[21;50HXX[1;36H XX[2;36H [2;40H [3;36HXXXX[21;50HXX[1;38H [2;38H [3;36H [13;38HXX[14;38HXX[15;36HXXXX[21;50HXX[1;36HXXXXXX[2;36HXX[21;50HXX[1;36H [1;42HXX[2;36H XX[21;50HXX[1;38H [2;40HXXXX[3;38HXX[21;50HXX[1;40HXX[2;38H [2;42H [3;38H XXXX[21;50HXX[1;40H XX[2;40H XX[3;40H [3;44HXX[21;50HXX[1;42H XX[2;40HXX[2;44HXX[3;42H [21;50HXX[1;44H XX[2;40H [2;46HXX[21;50HXX[1;46H [2;42H [3;42HXXXXXX[21;50HXX[2;42HXXXX [3;42H [3;46H [4;44HXX[21;50HXX[2;42H [3;44H [4;44H [6;42HXXXX[7;44HXX[8;44HXX[21;50HXX[1;38HXXXX[21;50HXX[1;36HXX[1;40H [2;36HXX[21;50HXX[1;34HXX[1;38H [2;34HXX [21;50HXX[1;34H [2;36HXX[3;34HXX[21;50HXX[1;34HXX[2;34H [2;38HXX[3;34H [21;50HXX[1;32HXX[1;36H [2;34HXX[2;38H [21;50HXX[1;32H [2;32HXX[2;36H [3;32HXX[21;50HXX[1;32HXX [2;30HXX[2;34H [3;30HXX [21;50HXX[1;32H [2;30H [3;32HXX[4;30HXX[21;50HXX[2;32H [3;30H [4;30H [7;32HXX[8;30HXXXX[9;30HXX[21;50HXX[1;36HXXXX[21;50HXX[21;50HXX[1;36H [1;40HXX[21;50HXX[21;50HXX[2;38HXXXX[21;50HXX[1;38H [1;42HXX[2;38H [2;42HXX[21;50HXX[21;50HXX[1;40H [1;44HXX[2;40H [2;44HXX[21;50HXX[21;50HXX[1;42H [3;42HXXXX[21;50HXX[2;42H [3;42H [4;42HXXXX[5;42HXXXX[21;50HXX[1;36HXXXX[21;50HXX[1;36H [1;40HXX[2;40HXX[21;50HXX[1;36HXX[1;40H [2;40H [21;50HXX[1;36H [1;40HXX[2;40HXX[21;50HXX[1;40H [2;38HXX[3;40HXX[21;50HXX[1;38H [2;38H [3;40H [10;38HXX[11;38HXXXX[12;40HXX[21;50HXX[1;36HXXXXXX[2;40HXX[21;50HXX[1;36H [2;40H [9;36HXXXXXX[10;40HXX[21;50HXX[21;50HXX[1;38HXXXX[21;50HXX[1;36HXX[1;40H [2;36HXX[21;50HXX[1;34HXX[1;38H [2;34HXX [21;50HXX[1;34H [2;36HXX[3;34HXX[21;50HXX[1;34HXX[2;34H [2;38HXX[3;34H [21;50HXX[1;32HXX[1;36H [2;34HXX[2;38H [21;50HXX[1;32H [2;34H [6;32HXXXX[7;34HXXXX[21;50HXX[1;36HXXXXXX[2;40HXX[21;50HXX[1;36H [1;42HXX[2;40H XX[21;50HXX[1;38H [1;42H [2;40HXX [21;50HXX[1;40H XX[2;40H XX[21;50HXX[1;40HXX[1;44HXX[2;42H [21;50HXX[1;42H [2;40HXXXXXX[21;50HXX[1;40H XX[2;40H [2;46HXX[21;50HXX[1;42H XX[2;42H [2;46H [3;42HXXXX[21;50HXX[21;50HXX[1;38HXXXX[21;50HXX[1;36HXX[1;40H [2;36HXX[21;50HXX[1;36H [2;38HXX[3;36HXX[21;50HXX[1;36HXX [2;34HXX[2;38H [3;34HXX [21;50HXX[1;34HXX[2;34H [2;38HXX[3;34H [21;50HXX[1;32HXX[1;36H [2;34HXX[2;38H [21;50HXX[1;32H [2;32HXX[2;36H [3;32HXX[21;50HXX[1;34H [2;32H [3;34HXX[4;32HXX[21;50HXX[2;32HXX [3;30HXX[3;34H [4;30HXX [21;50HXX[2;32H [3;30H [4;30H XX[5;30HXXXX[6;30HXX[21;50HXX[1;36HXXXXXX[2;40HXX[21;50HXX[1;36H [1;42HXX[2;40H XX[21;50HXX[1;38H [1;42H [2;40HXX [21;50HXX[1;40H XX[2;40H XX[21;50HXX[21;50HXX[1;38HXXXX[21;50HXX[21;50HXX[1;36HXX[1;40H [2;36HXX[21;50HXX[1;36H [2;36H [4;38HXX[5;36HXXXX[6;36HXX[21;50HXX[1;36HXXXX[21;50HXX[21;50HXX[1;34HXX[1;38H [21;50HXX[2;34HXXXX[21;50HXX[21;50HXX[1;32HXX[1;36H [2;32HXX[2;36H [21;50HXX[21;50HXX[1;30HXX[1;34H [2;30HXX[2;34H [21;50HXX[1;30H [3;30HXXXX[21;50HXX[21;50HXX[1;36HXXXX[21;50HXX[1;36H [1;40HXX[21;50HXX[21;50HXX[21;50HXX[21;50HXX[2;38HXXXX[21;50HXX[21;50HXX[21;50HXX[21;50HXX[21;50HXX[1;38H [3;38HXXXX[21;50HXX[21;50HXX[21;50HXX[21;50HXX[21;50HXX diff --git a/tests/ticker.py b/tests/ticker.py new file mode 100755 index 0000000..5ecc1c2 --- /dev/null +++ b/tests/ticker.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python +''' +PEXPECT LICENSE + + This license is approved by the OSI and FSF as GPL-compatible. + http://opensource.org/licenses/isc-license.txt + + Copyright (c) 2012, Noah Spurrier <noah@noah.org> + PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY + PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE + COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES. + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +''' + +import time, sys + +for i in range(5): + print "tick" + time.sleep(1) + +sys.exit(0) diff --git a/tests/torturet.vt b/tests/torturet.vt new file mode 100644 index 0000000..65f965b --- /dev/null +++ b/tests/torturet.vt @@ -0,0 +1,61 @@ +\<>[H[1;2;3;4qPrEM1\[?4h[0m +[H[J[7m#6(0a`opqrs`(B This is the (0`srqpo`a(B[1m +#3VT100 series Torture Test Demonstration. +#4VT100 series Torture Test Demonstration. +#6[1;5m Watch the blinking lights [4;24r[0m +[0q[1q[0q[2q[0q[3q[0q[4q[0q +[0q[1q[0q[2q[0q[3q[0q[4q[0q +[0q[1q[0q[2q[0q[3q[0q[4q[0q +PrEM0\[4;1H[J[24;1H + +This file is a VT100-series Torture Test. It demonstrates all the visual +attributes of the VT100 terminal. + +The top line is double-width/single-height with inverse-video line-drawing +characters. The 2nd and 3rd lines are double-width/double-height in bold +inverse video. They also show the limited scrolling region. + +The remaining lines will show NORMAL, BOLD, BLINK, INVERSE, and all 16 +combinations of those 4 attributes. They show that there is a difference +between an underscore character and the underline attribute, and that +lower-case decenders go below the underline. + +A window pane is drawn in the lower right to show how the line-drawing set +can be used. At the lower left is the character set double-wide/double-high +to show the dot-matrix used. Upper-case characters are 8 by 7 in a 10 by 10 +character cell, with 1 blank row on top and 2 on the bottom. The underline +attribute uses the first bottom blank row, lower-case decenders use both. + + + +[0mThis is a normal line __________________________________________________y_ +[1mThis is a bold line (normal unless the Advanced Video Option is installed) +[0;4mThis line is underlined _ " " " " " " _y_ +[0;5mThis is a blinking line _ " " " " " " _y_ +[0;7mThis is inverse video _ (underlined if no AVO and cursor is underline) _y_ +[0mNormal gjpqy [4mUnderline[0;0m [5m Blink [4mUnderline+Blink gjpqy[0m +[1mBold gjpqy [4mUnderline[0;1m [5m Blink [4mUnderline+Blink gjpqy[0m +[7mInverse [4mUnderline[0;7m [5m Blink [4mUnderline+Blink[0;7m +[1mBold+Inverse [4mUnderline[0;1;7m [5m Blink [4mUnderline+Blink[0m +PrEM1\[A +#6This is double [1mwidth[0m +#3This is double [1mheight[0m +#4This is double [1mheight[0m +#6[7;4m_[0;7mABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ioy +#3[7;4m_[0;7mABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ioy +#4[7;4m_[0;7mABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ioy[3A +[0m[CA[CC[CE[CG[CI[CK[CM[CO[CQ[CS[CU[CW[CY[C0[C2[C4[C6[C8[Ci[Cy +[4m_[0m[CB[CD[CF[CH[CJ[CL[CN[CP[CR[CT[CV[CX[CZ[C1[C3[C5[C7[C9[Co +[4m_[0m[CB[CD[CF[CH[CJ[CL[CN[CP[CR[CT[CV[CX[CZ[C1[C3[C5[C7[C9[Co +(0#6[7m`abcdefghijklmnopqrstuvwxyz{|}~[0m lqwqk +#3[7m`abcdefghijklmnopqrstuvwxyz{|}~[0m tqnqu +#4[7m`abcdefghijklmnopqrstuvwxyz{|}~[0m tqnqu[3A[0m +[Ca[Cc[Ce[Cg[Ci[Ck[Cm[Co[Cq[Cs[Cu[Cw[Cy[C{[C} +`[Cb[Cd[Cf[Ch[Cj[Cl[Cn[Cp[Cr[Ct[Cv[Cx[Cz[C|[C~ +`[Cb[Cd[Cf[Ch[Cj[Cl[Cn[Cp[Cr[Ct[Cv[Cx[Cz[C|[C~(B +#6[7m`abcdefghijklmnopqrstuvwxyz{|}~(0[0m mqvqj[A(B +[0m[Ca[Cc[Ce[Cg[Ci[Ck[Cm[Co[Cq[Cs[Cu[Cw[Cy[C{[C} +PrEM0\ $PrEM0 works on GIGI [A[1;7m + This test created by Joe Smith, 8-May-85 [0m +[1;r[22;1H + |