summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorJeff Quast <contact@jeffquast.com>2014-11-23 04:23:31 -0800
committerJeff Quast <contact@jeffquast.com>2014-11-23 04:23:31 -0800
commit01ea0ff440facd47894c076747488c28291a47cc (patch)
tree9a6a1f02e34f364ecfd9fed378a41ac6df8eb4eb /tests
parenta88e60f8403b1d25db1cca857009f3612a8f1e19 (diff)
parent00c8aaed9605c446844bbe379582753492a3627b (diff)
downloadpexpect-01ea0ff440facd47894c076747488c28291a47cc.tar.gz
Merge remote-tracking branch 'origin/master' into issue-104-cannot-exec-setuids
Conflicts: doc/history.rst
Diffstat (limited to 'tests')
-rwxr-xr-xtests/test_ansi.py59
-rw-r--r--tests/test_async.py51
-rwxr-xr-xtests/test_constructor.py10
-rwxr-xr-xtests/test_expect.py37
-rw-r--r--tests/test_repr.py26
-rwxr-xr-xtests/test_run.py38
-rwxr-xr-xtests/test_screen.py124
7 files changed, 318 insertions, 27 deletions
diff --git a/tests/test_ansi.py b/tests/test_ansi.py
index 516509c..a9d445e 100755
--- a/tests/test_ansi.py
+++ b/tests/test_ansi.py
@@ -21,6 +21,9 @@ PEXPECT LICENSE
from pexpect import ANSI
import unittest
from . import PexpectTestCase
+import sys
+
+PY3 = (sys.version_info[0] >= 3)
write_target = 'I\'ve got a ferret sticking up my nose. \n' +\
'(He\'s got a ferret sticking up his nose.) \n' +\
@@ -162,6 +165,62 @@ class ansiTestCase (PexpectTestCase.PexpectTestCase):
assert str(s) == ('test ')
assert s.state.memory == [s]
+ def test_utf8_bytes(self):
+ """Test that when bytes are passed in containing UTF-8 encoded
+ characters, where the encoding of each character consists of
+ multiple bytes, the characters are correctly decoded.
+ Incremental decoding is also tested."""
+ s = ANSI.ANSI(2, 10, encoding='utf-8')
+ # This is the UTF-8 encoding of the UCS character "HOURGLASS"
+ # followed by the UTF-8 encoding of the UCS character
+ # "KEYBOARD". These characters can't be encoded in cp437 or
+ # latin-1. The "KEYBOARD" character is split into two
+ # separate writes.
+ s.write(b'\xe2\x8c\x9b')
+ s.write(b'\xe2\x8c')
+ s.write(b'\xa8')
+ if PY3:
+ assert str(s) == u'\u231b\u2328 \n '
+ else:
+ assert unicode(s) == u'\u231b\u2328 \n '
+ assert str(s) == b'\xe2\x8c\x9b\xe2\x8c\xa8 \n '
+ assert s.dump() == u'\u231b\u2328 '
+ assert s.pretty() == u'+----------+\n|\u231b\u2328 |\n| |\n+----------+\n'
+ assert s.get_abs(1, 1) == u'\u231b'
+ assert s.get_region(1, 1, 1, 5) == [u'\u231b\u2328 ']
+
+ def test_unicode(self):
+ """Test passing in of a unicode string."""
+ s = ANSI.ANSI(2, 10, encoding="utf-8")
+ s.write(u'\u231b\u2328')
+ if PY3:
+ assert str(s) == u'\u231b\u2328 \n '
+ else:
+ assert unicode(s) == u'\u231b\u2328 \n '
+ assert str(s) == b'\xe2\x8c\x9b\xe2\x8c\xa8 \n '
+ assert s.dump() == u'\u231b\u2328 '
+ assert s.pretty() == u'+----------+\n|\u231b\u2328 |\n| |\n+----------+\n'
+ assert s.get_abs(1, 1) == u'\u231b'
+ assert s.get_region(1, 1, 1, 5) == [u'\u231b\u2328 ']
+
+ def test_decode_error(self):
+ """Test that default handling of decode errors replaces the
+ invalid characters."""
+ s = ANSI.ANSI(2, 10, encoding="ascii")
+ s.write(b'\xff') # a non-ASCII character
+ # In unicode, the non-ASCII character is replaced with
+ # REPLACEMENT CHARACTER.
+ if PY3:
+ assert str(s) == u'\ufffd \n '
+ else:
+ assert unicode(s) == u'\ufffd \n '
+ assert str(s) == b'? \n '
+ assert s.dump() == u'\ufffd '
+ assert s.pretty() == u'+----------+\n|\ufffd |\n| |\n+----------+\n'
+ assert s.get_abs(1, 1) == u'\ufffd'
+ assert s.get_region(1, 1, 1, 5) == [u'\ufffd ']
+
+
if __name__ == '__main__':
unittest.main()
diff --git a/tests/test_async.py b/tests/test_async.py
new file mode 100644
index 0000000..ce75572
--- /dev/null
+++ b/tests/test_async.py
@@ -0,0 +1,51 @@
+try:
+ import asyncio
+except ImportError:
+ asyncio = None
+
+import sys
+import unittest
+
+import pexpect
+from .PexpectTestCase import PexpectTestCase
+
+def run(coro):
+ return asyncio.get_event_loop().run_until_complete(coro)
+
+@unittest.skipIf(asyncio is None, "Requires asyncio")
+class AsyncTests(PexpectTestCase):
+ def test_simple_expect(self):
+ p = pexpect.spawn('cat')
+ p.sendline('Hello asyncio')
+ coro = p.expect(['Hello', pexpect.EOF] , async=True)
+ assert run(coro) == 0
+ print('Done')
+
+ def test_timeout(self):
+ p = pexpect.spawn('cat')
+ coro = p.expect('foo', timeout=1, async=True)
+ with self.assertRaises(pexpect.TIMEOUT):
+ run(coro)
+
+ p = pexpect.spawn('cat')
+ coro = p.expect(['foo', pexpect.TIMEOUT], timeout=1, async=True)
+ assert run(coro) == 1
+
+ def test_eof(self):
+ p = pexpect.spawn('cat')
+ p.sendline('Hi')
+ coro = p.expect(pexpect.EOF, async=True)
+ p.sendeof()
+ assert run(coro) == 0
+
+ p = pexpect.spawn('cat')
+ p.sendeof()
+ coro = p.expect('Blah', async=True)
+ with self.assertRaises(pexpect.EOF):
+ run(coro)
+
+ def test_expect_exact(self):
+ p = pexpect.spawn('%s list100.py' % sys.executable)
+ assert run(p.expect_exact(b'5', async=True)) == 0
+ assert run(p.expect_exact(['wpeok', b'11'], async=True)) == 1
+ assert run(p.expect_exact([b'foo', pexpect.EOF], async=True)) == 1
diff --git a/tests/test_constructor.py b/tests/test_constructor.py
index 60525a0..98c473a 100755
--- a/tests/test_constructor.py
+++ b/tests/test_constructor.py
@@ -28,11 +28,11 @@ class TestCaseConstructor(PexpectTestCase.PexpectTestCase):
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)
+ p1 = pexpect.spawn('uname -m -n -p -r -s -v')
+ p2 = pexpect.spawn('uname', ['-m', '-n', '-p', '-r', '-s', '-v'])
+ p1.expect(pexpect.EOF)
+ p2.expect(pexpect.EOF)
+ assert p1.before == p2.before
def test_named_parameters (self):
'''This tests that named parameters work.
diff --git a/tests/test_expect.py b/tests/test_expect.py
index 8ccb9c5..3f4c9d8 100755
--- a/tests/test_expect.py
+++ b/tests/test_expect.py
@@ -18,11 +18,13 @@ PEXPECT LICENSE
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
'''
+import multiprocessing
import unittest
import subprocess
import time
import signal
import sys
+import os
import pexpect
from . import PexpectTestCase
@@ -542,7 +544,40 @@ class ExpectTestCase (PexpectTestCase.PexpectTestCase):
signal.alarm(1)
p1.expect('END')
+ def test_stdin_closed(self):
+ '''
+ Ensure pexpect continues to operate even when stdin is closed
+ '''
+ class Closed_stdin_proc(multiprocessing.Process):
+ def run(self):
+ sys.__stdin__.close()
+ cat = pexpect.spawn('cat')
+ cat.sendeof()
+ cat.expect(pexpect.EOF)
+
+ proc = Closed_stdin_proc()
+ proc.start()
+ proc.join()
+ assert proc.exitcode == 0
+
+ def test_stdin_stdout_closed(self):
+ '''
+ Ensure pexpect continues to operate even when stdin and stdout is closed
+ '''
+ class Closed_stdin_stdout_proc(multiprocessing.Process):
+ def run(self):
+ sys.__stdin__.close()
+ sys.__stdout__.close()
+ cat = pexpect.spawn('cat')
+ cat.sendeof()
+ cat.expect(pexpect.EOF)
+
+ proc = Closed_stdin_stdout_proc()
+ proc.start()
+ proc.join()
+ assert proc.exitcode == 0
+
if __name__ == '__main__':
unittest.main()
-suite = unittest.makeSuite(ExpectTestCase,'test')
+suite = unittest.makeSuite(ExpectTestCase, 'test')
diff --git a/tests/test_repr.py b/tests/test_repr.py
new file mode 100644
index 0000000..ce618d4
--- /dev/null
+++ b/tests/test_repr.py
@@ -0,0 +1,26 @@
+""" Test __str__ methods. """
+import pexpect
+
+from . import PexpectTestCase
+
+
+class TestCaseMisc(PexpectTestCase.PexpectTestCase):
+
+ def test_str_spawnu(self):
+ """ Exercise spawnu.__str__() """
+ # given,
+ p = pexpect.spawnu('cat')
+ # exercise,
+ value = str(p)
+ # verify
+ assert isinstance(value, str)
+
+ def test_str_spawn(self):
+ """ Exercise spawn.__str__() """
+ # given,
+ p = pexpect.spawn('cat')
+ # exercise,
+ value = str(p)
+ # verify
+ assert isinstance(value, str)
+
diff --git a/tests/test_run.py b/tests/test_run.py
index 814b70a..c018b4d 100755
--- a/tests/test_run.py
+++ b/tests/test_run.py
@@ -22,14 +22,11 @@ PEXPECT LICENSE
import pexpect
import unittest
import subprocess
+import tempfile
import sys
+import os
from . 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.
-
unicode_type = str if pexpect.PY3 else unicode
def timeout_callback (d):
@@ -44,14 +41,24 @@ class RunFuncTestCase(PexpectTestCase.PexpectTestCase):
empty = b''
prep_subprocess_out = staticmethod(lambda x: x)
+ def setUp(self):
+ fd, self.rcfile = tempfile.mkstemp()
+ os.write(fd, b'PS1=GO: \n')
+ os.close(fd)
+ super(RunFuncTestCase, self).setUp()
+
+ def tearDown(self):
+ os.unlink(self.rcfile)
+ super(RunFuncTestCase, self).tearDown()
+
def test_run_exit (self):
(data, exitstatus) = self.runfunc('python exit1.py', withexitstatus=1)
assert exitstatus == 1, "Exit status of 'python exit1.py' should be 1."
def test_run (self):
- the_old_way = subprocess.Popen(args=['ls', '-l', '/bin'],
+ the_old_way = subprocess.Popen(args=['uname', '-m', '-n'],
stdout=subprocess.PIPE).communicate()[0].rstrip()
- (the_new_way, exitstatus) = self.runfunc('ls -l /bin', withexitstatus=1)
+ (the_new_way, exitstatus) = self.runfunc('uname -m -n', withexitstatus=1)
the_new_way = the_new_way.replace(self.cr, self.empty).rstrip()
self.assertEqual(self.prep_subprocess_out(the_old_way), the_new_way)
self.assertEqual(exitstatus, 0)
@@ -64,6 +71,23 @@ class RunFuncTestCase(PexpectTestCase.PexpectTestCase):
withexitstatus=1)
assert exitstatus != 0
+ def test_run_tuple_list (self):
+ events = [
+ # second match on 'abc', echo 'def'
+ ('abc\r\n.*GO:', 'echo "def"\n'),
+ # final match on 'def': exit
+ ('def\r\n.*GO:', 'exit\n'),
+ # first match on 'GO:' prompt, echo 'abc'
+ ('GO:', 'echo "abc"\n')
+ ]
+
+ (data, exitstatus) = pexpect.run(
+ 'bash --rcfile {0}'.format(self.rcfile),
+ withexitstatus=True,
+ events=events,
+ timeout=10)
+ assert exitstatus == 0
+
class RunUnicodeFuncTestCase(RunFuncTestCase):
runfunc = staticmethod(pexpect.runu)
cr = b'\r'.decode('ascii')
diff --git a/tests/test_screen.py b/tests/test_screen.py
index 3f0736b..2429e57 100755
--- a/tests/test_screen.py
+++ b/tests/test_screen.py
@@ -19,10 +19,14 @@ PEXPECT LICENSE
'''
+import sys
+
from pexpect import screen
import unittest
from . import PexpectTestCase
+PY3 = (sys.version_info[0] >= 3)
+
fill1_target='XXXXXXXXXX\n' + \
'XOOOOOOOOX\n' + \
'XO::::::OX\n' + \
@@ -76,6 +80,17 @@ insert_target = 'ZXZZZZZZXZ\n' +\
'ZZ/2.4.6ZZ'
get_region_target = ['......', '.\\/...', './\\...', '......']
+unicode_box_unicode_result = u'\u2554\u2557\n\u255A\u255D'
+unicode_box_pretty_result = u'''\
++--+
+|\u2554\u2557|
+|\u255A\u255D|
++--+
+'''
+unicode_box_ascii_bytes_result = b'??\n??'
+unicode_box_cp437_bytes_result = b'\xc9\xbb\n\xc8\xbc'
+unicode_box_utf8_bytes_result = b'\xe2\x95\x94\xe2\x95\x97\n\xe2\x95\x9a\xe2\x95\x9d'
+
class screenTestCase (PexpectTestCase.PexpectTestCase):
def make_screen_with_put (self):
s = screen.screen(10,10)
@@ -168,20 +183,101 @@ class screenTestCase (PexpectTestCase.PexpectTestCase):
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
+
+ def make_screen_with_box_unicode(self, *args, **kwargs):
+ '''Creates a screen containing a box drawn using double-line
+ line drawing characters. The characters are fed in as
+ unicode. '''
+ s = screen.screen (2,2,*args,**kwargs)
+ s.put_abs (1,1,u'\u2554')
+ s.put_abs (1,2,u'\u2557')
+ s.put_abs (2,1,u'\u255A')
+ s.put_abs (2,2,u'\u255D')
+ return s
+
+ def make_screen_with_box_cp437(self, *args, **kwargs):
+ '''Creates a screen containing a box drawn using double-line
+ line drawing characters. The characters are fed in as
+ CP437. '''
+ s = screen.screen (2,2,*args,**kwargs)
+ s.put_abs (1,1,b'\xc9')
+ s.put_abs (1,2,b'\xbb')
+ s.put_abs (2,1,b'\xc8')
+ s.put_abs (2,2,b'\xbc')
+ return s
+
+ def make_screen_with_box_utf8(self, *args, **kwargs):
+ '''Creates a screen containing a box drawn using double-line
+ line drawing characters. The characters are fed in as
+ UTF-8. '''
+ s = screen.screen (2,2,*args,**kwargs)
+ s.put_abs (1,1,b'\xe2\x95\x94')
+ s.put_abs (1,2,b'\xe2\x95\x97')
+ s.put_abs (2,1,b'\xe2\x95\x9a')
+ s.put_abs (2,2,b'\xe2\x95\x9d')
+ return s
+
+ def test_unicode_ascii (self):
+ # With the default encoding set to ASCII, we should still be
+ # able to feed in unicode strings and get them back out:
+ s = self.make_screen_with_box_unicode('ascii')
+ if PY3:
+ assert str(s) == unicode_box_unicode_result
+ else:
+ assert unicode(s) == unicode_box_unicode_result
+ # And we should still get something for Python 2 str(), though
+ # it might not be very useful
+ str(s)
+
+ assert s.pretty() == unicode_box_pretty_result
+
+ def test_decoding_errors(self):
+ # With strict error handling, it should reject bytes it can't decode
+ with self.assertRaises(UnicodeDecodeError):
+ self.make_screen_with_box_cp437('ascii', 'strict')
+
+ # replace should turn them into unicode replacement characters, U+FFFD
+ s = self.make_screen_with_box_cp437('ascii', 'replace')
+ expected = u'\ufffd\ufffd\n\ufffd\ufffd'
+ if PY3:
+ assert str(s) == expected
+ else:
+ assert unicode(s) == expected
+
+ def test_unicode_cp437 (self):
+ # Verify decoding from and re-encoding to CP437.
+ s = self.make_screen_with_box_cp437('cp437','strict')
+ if PY3:
+ assert str(s) == unicode_box_unicode_result
+ else:
+ assert unicode(s) == unicode_box_unicode_result
+ assert str(s) == unicode_box_cp437_bytes_result
+ assert s.pretty() == unicode_box_pretty_result
+
+ def test_unicode_utf8 (self):
+ # Verify decoding from and re-encoding to UTF-8.
+ s = self.make_screen_with_box_utf8('utf-8','strict')
+ if PY3:
+ assert str(s) == unicode_box_unicode_result
+ else:
+ assert unicode(s) == unicode_box_unicode_result
+ assert str(s) == unicode_box_utf8_bytes_result
+ assert s.pretty() == unicode_box_pretty_result
+
+ def test_no_bytes(self):
+ s = screen.screen(2, 2, encoding=None)
+ s.put_abs(1, 1, u'A')
+ s.put_abs(2, 2, u'D')
+
+ with self.assertRaises(TypeError):
+ s.put_abs(1, 2, b'B')
+
+ if PY3:
+ assert str(s) == u'A \n D'
+ else:
+ assert unicode(s) == u'A \n D'
+ # This will still work if it's limited to ascii
+ assert str(s) == b'A \n D'
if __name__ == '__main__':
unittest.main()