summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_winconsoleio.py
diff options
context:
space:
mode:
authorSteve Dower <steve.dower@microsoft.com>2016-10-03 16:04:58 (GMT)
committerSteve Dower <steve.dower@microsoft.com>2016-10-03 16:04:58 (GMT)
commit312cef7452dcc8bb97ca6b20999d5db567406692 (patch)
treee3f305b6012ccfffa5ed6ea4895eabee6bd99c7b /Lib/test/test_winconsoleio.py
parent7fe091df42e25db5b6c7d955bffd0ff8db053f1f (diff)
downloadcpython-312cef7452dcc8bb97ca6b20999d5db567406692.zip
cpython-312cef7452dcc8bb97ca6b20999d5db567406692.tar.gz
cpython-312cef7452dcc8bb97ca6b20999d5db567406692.tar.bz2
Issue #28217: Adds _testconsole module to test console input. Fixes some issues found by the tests.
Diffstat (limited to 'Lib/test/test_winconsoleio.py')
-rw-r--r--Lib/test/test_winconsoleio.py70
1 files changed, 62 insertions, 8 deletions
diff --git a/Lib/test/test_winconsoleio.py b/Lib/test/test_winconsoleio.py
index ec26f06..f2cccbc 100644
--- a/Lib/test/test_winconsoleio.py
+++ b/Lib/test/test_winconsoleio.py
@@ -1,12 +1,4 @@
'''Tests for WindowsConsoleIO
-
-Unfortunately, most testing requires interactive use, since we have no
-API to read back from a real console, and this class is only for use
-with real consoles.
-
-Instead, we validate that basic functionality such as opening, closing
-and in particular fileno() work, but are forced to leave real testing
-to real people with real keyborads.
'''
import io
@@ -16,6 +8,8 @@ import sys
if sys.platform != 'win32':
raise unittest.SkipTest("test only relevant on win32")
+from _testconsole import write_input
+
ConIO = io._WindowsConsoleIO
class WindowsConsoleIOTests(unittest.TestCase):
@@ -83,5 +77,65 @@ class WindowsConsoleIOTests(unittest.TestCase):
f.close()
f.close()
+ def assertStdinRoundTrip(self, text):
+ stdin = open('CONIN$', 'r')
+ old_stdin = sys.stdin
+ try:
+ sys.stdin = stdin
+ write_input(
+ stdin.buffer.raw,
+ (text + '\r\n').encode('utf-16-le', 'surrogatepass')
+ )
+ actual = input()
+ finally:
+ sys.stdin = old_stdin
+ self.assertEqual(actual, text)
+
+ def test_input(self):
+ # ASCII
+ self.assertStdinRoundTrip('abc123')
+ # Non-ASCII
+ self.assertStdinRoundTrip('ϼўТλФЙ')
+ # Combining characters
+ self.assertStdinRoundTrip('A͏B ﬖ̳AA̝')
+ # Non-BMP
+ self.assertStdinRoundTrip('\U00100000\U0010ffff\U0010fffd')
+
+ def test_partial_reads(self):
+ # Test that reading less than 1 full character works when stdin
+ # contains multibyte UTF-8 sequences
+ source = 'ϼўТλФЙ\r\n'.encode('utf-16-le')
+ expected = 'ϼўТλФЙ\r\n'.encode('utf-8')
+ for read_count in range(1, 16):
+ stdin = open('CONIN$', 'rb', buffering=0)
+ write_input(stdin, source)
+
+ actual = b''
+ while not actual.endswith(b'\n'):
+ b = stdin.read(read_count)
+ actual += b
+
+ self.assertEqual(actual, expected, 'stdin.read({})'.format(read_count))
+ stdin.close()
+
+ def test_partial_surrogate_reads(self):
+ # Test that reading less than 1 full character works when stdin
+ # contains surrogate pairs that cannot be decoded to UTF-8 without
+ # reading an extra character.
+ source = '\U00101FFF\U00101001\r\n'.encode('utf-16-le')
+ expected = '\U00101FFF\U00101001\r\n'.encode('utf-8')
+ for read_count in range(1, 16):
+ stdin = open('CONIN$', 'rb', buffering=0)
+ write_input(stdin, source)
+
+ actual = b''
+ while not actual.endswith(b'\n'):
+ b = stdin.read(read_count)
+ actual += b
+
+ self.assertEqual(actual, expected, 'stdin.read({})'.format(read_count))
+ stdin.close()
+
+
if __name__ == "__main__":
unittest.main()