blob: 0d0b160d7645a55a1b1f3f90e4c23c4255b2cc30 [file] [log] [blame]
Andrew M. Kuchling2158df02001-10-22 15:26:09 +00001#
2# Test script for the curses module
3#
4# This script doesn't actually display anything very coherent. but it
Zachary Warebaf45c52014-10-17 13:59:18 -05005# does call (nearly) every method and function.
Andrew M. Kuchling2158df02001-10-22 15:26:09 +00006#
7# Functions not tested: {def,reset}_{shell,prog}_mode, getch(), getstr(),
Neal Norwitz88bbd732006-01-10 07:05:44 +00008# init_color()
9# Only called, not tested: getmouse(), ungetmouse()
Andrew M. Kuchling2158df02001-10-22 15:26:09 +000010#
11
Zachary Warebaf45c52014-10-17 13:59:18 -050012import os
Serhiy Storchaka514f9732016-06-18 22:08:11 +030013import string
Zachary Warebaf45c52014-10-17 13:59:18 -050014import sys
15import tempfile
16import unittest
17
18from test.support import requires, import_module, verbose
Andrew M. Kuchling2158df02001-10-22 15:26:09 +000019
20# Optionally test curses module. This currently requires that the
21# 'curses' resource be given on the regrtest command line using the -u
22# option. If not available, nothing after this line will be executed.
Larry Hastings9147a962014-05-04 04:41:18 -070023import inspect
Neal Norwitz9f39f682006-01-06 04:18:21 +000024requires('curses')
25
R. David Murraya21e4ca2009-03-31 23:16:50 +000026# If either of these don't exist, skip the tests.
27curses = import_module('curses')
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +030028import_module('curses.panel')
29import_module('curses.ascii')
Serhiy Storchakabdf9e0e2016-12-28 10:16:06 +020030import_module('curses.textpad')
R. David Murraya21e4ca2009-03-31 23:16:50 +000031
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +030032def requires_curses_func(name):
33 return unittest.skipUnless(hasattr(curses, name),
34 'requires curses.%s' % name)
Mark Dickinson945e2422010-02-21 13:42:03 +000035
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +030036term = os.environ.get('TERM')
37
38# If newterm was supported we could use it instead of initscr and not exit
39@unittest.skipIf(not term or term == 'unknown',
Zachary Warebaf45c52014-10-17 13:59:18 -050040 "$TERM=%r, calling initscr() may cause exit" % term)
41@unittest.skipIf(sys.platform == "cygwin",
42 "cygwin's curses mostly just hangs")
43class TestCurses(unittest.TestCase):
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +030044
Zachary Warebaf45c52014-10-17 13:59:18 -050045 @classmethod
46 def setUpClass(cls):
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +030047 if not sys.__stdout__.isatty():
Serhiy Storchaka53a00352016-05-22 18:16:20 +030048 # Temporary skip tests on non-tty
Serhiy Storchaka0a91e432016-05-22 18:23:36 +030049 raise unittest.SkipTest('sys.__stdout__ is not a tty')
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +030050 cls.tmp = tempfile.TemporaryFile()
51 fd = cls.tmp.fileno()
52 else:
53 cls.tmp = None
54 fd = sys.__stdout__.fileno()
55 # testing setupterm() inside initscr/endwin
56 # causes terminal breakage
57 curses.setupterm(fd=fd)
58
59 @classmethod
60 def tearDownClass(cls):
61 if cls.tmp:
62 cls.tmp.close()
63 del cls.tmp
Andrew M. Kuchling2158df02001-10-22 15:26:09 +000064
Zachary Warebaf45c52014-10-17 13:59:18 -050065 def setUp(self):
66 if verbose:
67 # just to make the test output a little more readable
68 print()
69 self.stdscr = curses.initscr()
70 curses.savetty()
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000071
Zachary Warebaf45c52014-10-17 13:59:18 -050072 def tearDown(self):
Andrew M. Kuchling2158df02001-10-22 15:26:09 +000073 curses.resetty()
Andrew M. Kuchling2158df02001-10-22 15:26:09 +000074 curses.endwin()
Zachary Warebaf45c52014-10-17 13:59:18 -050075
76 def test_window_funcs(self):
77 "Test the methods of windows"
78 stdscr = self.stdscr
79 win = curses.newwin(10,10)
80 win = curses.newwin(5,5, 5,5)
81 win2 = curses.newwin(15,15, 5,5)
82
83 for meth in [stdscr.addch, stdscr.addstr]:
Serhiy Storchaka08349052017-06-28 09:27:35 +030084 for args in [('a',), ('a', curses.A_BOLD),
Zachary Warebaf45c52014-10-17 13:59:18 -050085 (4,4, 'a'), (5,5, 'a', curses.A_BOLD)]:
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +030086 with self.subTest(meth=meth.__qualname__, args=args):
87 meth(*args)
Zachary Warebaf45c52014-10-17 13:59:18 -050088
89 for meth in [stdscr.box, stdscr.clear, stdscr.clrtobot,
90 stdscr.clrtoeol, stdscr.cursyncup, stdscr.delch,
91 stdscr.deleteln, stdscr.erase, stdscr.getbegyx,
92 stdscr.getbkgd, stdscr.getkey, stdscr.getmaxyx,
93 stdscr.getparyx, stdscr.getyx, stdscr.inch,
94 stdscr.insertln, stdscr.instr, stdscr.is_wintouched,
95 win.noutrefresh, stdscr.redrawwin, stdscr.refresh,
96 stdscr.standout, stdscr.standend, stdscr.syncdown,
97 stdscr.syncup, stdscr.touchwin, stdscr.untouchwin]:
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +030098 with self.subTest(meth=meth.__qualname__):
99 meth()
Zachary Warebaf45c52014-10-17 13:59:18 -0500100
101 stdscr.addnstr('1234', 3)
102 stdscr.addnstr('1234', 3, curses.A_BOLD)
103 stdscr.addnstr(4,4, '1234', 3)
104 stdscr.addnstr(5,5, '1234', 3, curses.A_BOLD)
105
106 stdscr.attron(curses.A_BOLD)
107 stdscr.attroff(curses.A_BOLD)
108 stdscr.attrset(curses.A_BOLD)
109 stdscr.bkgd(' ')
110 stdscr.bkgd(' ', curses.A_REVERSE)
111 stdscr.bkgdset(' ')
112 stdscr.bkgdset(' ', curses.A_REVERSE)
113
114 win.border(65, 66, 67, 68,
115 69, 70, 71, 72)
116 win.border('|', '!', '-', '_',
117 '+', '\\', '#', '/')
118 with self.assertRaises(TypeError,
119 msg="Expected win.border() to raise TypeError"):
120 win.border(65, 66, 67, 68,
121 69, [], 71, 72)
122
123 stdscr.clearok(1)
124
125 win4 = stdscr.derwin(2,2)
126 win4 = stdscr.derwin(1,1, 5,5)
127 win4.mvderwin(9,9)
128
129 stdscr.echochar('a')
130 stdscr.echochar('a', curses.A_BOLD)
131 stdscr.hline('-', 5)
132 stdscr.hline('-', 5, curses.A_BOLD)
133 stdscr.hline(1,1,'-', 5)
134 stdscr.hline(1,1,'-', 5, curses.A_BOLD)
135
136 stdscr.idcok(1)
137 stdscr.idlok(1)
138 stdscr.immedok(1)
139 stdscr.insch('c')
140 stdscr.insdelln(1)
141 stdscr.insnstr('abc', 3)
142 stdscr.insnstr('abc', 3, curses.A_BOLD)
143 stdscr.insnstr(5, 5, 'abc', 3)
144 stdscr.insnstr(5, 5, 'abc', 3, curses.A_BOLD)
145
146 stdscr.insstr('def')
147 stdscr.insstr('def', curses.A_BOLD)
148 stdscr.insstr(5, 5, 'def')
149 stdscr.insstr(5, 5, 'def', curses.A_BOLD)
150 stdscr.is_linetouched(0)
151 stdscr.keypad(1)
152 stdscr.leaveok(1)
153 stdscr.move(3,3)
154 win.mvwin(2,2)
155 stdscr.nodelay(1)
156 stdscr.notimeout(1)
157 win2.overlay(win)
158 win2.overwrite(win)
159 win2.overlay(win, 1, 2, 2, 1, 3, 3)
160 win2.overwrite(win, 1, 2, 2, 1, 3, 3)
161 stdscr.redrawln(1,2)
162
163 stdscr.scrollok(1)
164 stdscr.scroll()
165 stdscr.scroll(2)
166 stdscr.scroll(-3)
167
168 stdscr.move(12, 2)
169 stdscr.setscrreg(10,15)
170 win3 = stdscr.subwin(10,10)
171 win3 = stdscr.subwin(10,10, 5,5)
172 stdscr.syncok(1)
173 stdscr.timeout(5)
174 stdscr.touchline(5,5)
175 stdscr.touchline(5,5,0)
176 stdscr.vline('a', 3)
177 stdscr.vline('a', 3, curses.A_STANDOUT)
178 stdscr.chgat(5, 2, 3, curses.A_BLINK)
179 stdscr.chgat(3, curses.A_BOLD)
180 stdscr.chgat(5, 8, curses.A_UNDERLINE)
181 stdscr.chgat(curses.A_BLINK)
182 stdscr.refresh()
183
184 stdscr.vline(1,1, 'a', 3)
185 stdscr.vline(1,1, 'a', 3, curses.A_STANDOUT)
186
187 if hasattr(curses, 'resize'):
188 stdscr.resize()
189 if hasattr(curses, 'enclose'):
190 stdscr.enclose()
191
Benjamin Peterson40a77c32016-08-13 18:15:28 -0700192 self.assertRaises(ValueError, stdscr.getstr, -400)
193 self.assertRaises(ValueError, stdscr.getstr, 2, 3, -400)
Benjamin Peterson432ea4f2016-08-15 21:40:14 -0700194 self.assertRaises(ValueError, stdscr.instr, -2)
195 self.assertRaises(ValueError, stdscr.instr, 2, 3, -2)
Benjamin Peterson40a77c32016-08-13 18:15:28 -0700196
Serhiy Storchaka08349052017-06-28 09:27:35 +0300197 def test_embedded_null_chars(self):
198 # reject embedded null bytes and characters
199 stdscr = self.stdscr
200 for arg in ['a', b'a']:
201 with self.subTest(arg=arg):
202 self.assertRaises(ValueError, stdscr.addstr, 'a\0')
203 self.assertRaises(ValueError, stdscr.addnstr, 'a\0', 1)
204 self.assertRaises(ValueError, stdscr.insstr, 'a\0')
205 self.assertRaises(ValueError, stdscr.insnstr, 'a\0', 1)
Zachary Warebaf45c52014-10-17 13:59:18 -0500206
207 def test_module_funcs(self):
208 "Test module-level functions"
Zachary Warebaf45c52014-10-17 13:59:18 -0500209 for func in [curses.baudrate, curses.beep, curses.can_change_color,
210 curses.cbreak, curses.def_prog_mode, curses.doupdate,
211 curses.filter, curses.flash, curses.flushinp,
212 curses.has_colors, curses.has_ic, curses.has_il,
213 curses.isendwin, curses.killchar, curses.longname,
214 curses.nocbreak, curses.noecho, curses.nonl,
215 curses.noqiflush, curses.noraw,
216 curses.reset_prog_mode, curses.termattrs,
217 curses.termname, curses.erasechar, curses.getsyx]:
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300218 with self.subTest(func=func.__qualname__):
219 func()
Zachary Warebaf45c52014-10-17 13:59:18 -0500220
221 # Functions that actually need arguments
222 if curses.tigetstr("cnorm"):
223 curses.curs_set(1)
224 curses.delay_output(1)
225 curses.echo() ; curses.echo(1)
226
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300227 with tempfile.TemporaryFile() as f:
228 self.stdscr.putwin(f)
229 f.seek(0)
230 curses.getwin(f)
Zachary Warebaf45c52014-10-17 13:59:18 -0500231
232 curses.halfdelay(1)
233 curses.intrflush(1)
234 curses.meta(1)
235 curses.napms(100)
236 curses.newpad(50,50)
237 win = curses.newwin(5,5)
238 win = curses.newwin(5,5, 1,1)
239 curses.nl() ; curses.nl(1)
240 curses.putp(b'abc')
241 curses.qiflush()
242 curses.raw() ; curses.raw(1)
243 curses.setsyx(5,5)
244 curses.tigetflag('hc')
245 curses.tigetnum('co')
246 curses.tigetstr('cr')
247 curses.tparm(b'cr')
248 curses.typeahead(sys.__stdin__.fileno())
249 curses.unctrl('a')
250 curses.ungetch('a')
251 curses.use_env(1)
252
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300253 # Functions only available on a few platforms
254 def test_colors_funcs(self):
255 if not curses.has_colors():
Xavier de Gaye645bc802017-01-06 09:50:27 +0100256 self.skipTest('requires colors support')
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300257 curses.start_color()
258 curses.init_pair(2, 1,1)
259 curses.color_content(1)
260 curses.color_pair(2)
261 curses.pair_content(curses.COLOR_PAIRS - 1)
262 curses.pair_number(0)
Zachary Warebaf45c52014-10-17 13:59:18 -0500263
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300264 if hasattr(curses, 'use_default_colors'):
265 curses.use_default_colors()
Zachary Warebaf45c52014-10-17 13:59:18 -0500266
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300267 @requires_curses_func('keyname')
268 def test_keyname(self):
269 curses.keyname(13)
Zachary Warebaf45c52014-10-17 13:59:18 -0500270
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300271 @requires_curses_func('has_key')
272 def test_has_key(self):
273 curses.has_key(13)
Zachary Warebaf45c52014-10-17 13:59:18 -0500274
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300275 @requires_curses_func('getmouse')
276 def test_getmouse(self):
277 (availmask, oldmask) = curses.mousemask(curses.BUTTON1_PRESSED)
278 if availmask == 0:
Xavier de Gaye645bc802017-01-06 09:50:27 +0100279 self.skipTest('mouse stuff not available')
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300280 curses.mouseinterval(10)
281 # just verify these don't cause errors
282 curses.ungetmouse(0, 0, 0, 0, curses.BUTTON1_PRESSED)
283 m = curses.getmouse()
Zachary Warebaf45c52014-10-17 13:59:18 -0500284
285 def test_userptr_without_set(self):
286 w = curses.newwin(10, 10)
287 p = curses.panel.new_panel(w)
288 # try to access userptr() before calling set_userptr() -- segfaults
289 with self.assertRaises(curses.panel.error,
290 msg='userptr should fail since not set'):
291 p.userptr()
292
293 def test_userptr_memory_leak(self):
294 w = curses.newwin(10, 10)
295 p = curses.panel.new_panel(w)
296 obj = object()
297 nrefs = sys.getrefcount(obj)
298 for i in range(100):
299 p.set_userptr(obj)
300
301 p.set_userptr(None)
302 self.assertEqual(sys.getrefcount(obj), nrefs,
303 "set_userptr leaked references")
304
305 def test_userptr_segfault(self):
306 panel = curses.panel.new_panel(self.stdscr)
307 class A:
308 def __del__(self):
309 panel.set_userptr(None)
310 panel.set_userptr(A())
311 panel.set_userptr(None)
312
Serhiy Storchakae3f1b092016-05-08 20:46:22 +0300313 def test_new_curses_panel(self):
314 panel = curses.panel.new_panel(self.stdscr)
315 self.assertRaises(TypeError, type(panel))
316
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300317 @requires_curses_func('is_term_resized')
318 def test_is_term_resized(self):
319 curses.is_term_resized(*self.stdscr.getmaxyx())
320
321 @requires_curses_func('resize_term')
Zachary Warebaf45c52014-10-17 13:59:18 -0500322 def test_resize_term(self):
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300323 curses.resize_term(*self.stdscr.getmaxyx())
324
325 @requires_curses_func('resizeterm')
326 def test_resizeterm(self):
327 stdscr = self.stdscr
Zachary Warebaf45c52014-10-17 13:59:18 -0500328 lines, cols = curses.LINES, curses.COLS
329 new_lines = lines - 1
330 new_cols = cols + 1
331 curses.resizeterm(new_lines, new_cols)
332
333 self.assertEqual(curses.LINES, new_lines)
334 self.assertEqual(curses.COLS, new_cols)
335
336 def test_issue6243(self):
337 curses.ungetch(1025)
338 self.stdscr.getkey()
339
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300340 @requires_curses_func('unget_wch')
Zachary Warebaf45c52014-10-17 13:59:18 -0500341 def test_unget_wch(self):
342 stdscr = self.stdscr
343 encoding = stdscr.encoding
344 for ch in ('a', '\xe9', '\u20ac', '\U0010FFFF'):
345 try:
346 ch.encode(encoding)
347 except UnicodeEncodeError:
348 continue
349 try:
350 curses.unget_wch(ch)
351 except Exception as err:
352 self.fail("unget_wch(%a) failed with encoding %s: %s"
353 % (ch, stdscr.encoding, err))
354 read = stdscr.get_wch()
355 self.assertEqual(read, ch)
356
357 code = ord(ch)
358 curses.unget_wch(code)
359 read = stdscr.get_wch()
360 self.assertEqual(read, ch)
361
362 def test_issue10570(self):
363 b = curses.tparm(curses.tigetstr("cup"), 5, 3)
364 self.assertIs(type(b), bytes)
Zachary Warebaf45c52014-10-17 13:59:18 -0500365
366 def test_encoding(self):
367 stdscr = self.stdscr
368 import codecs
369 encoding = stdscr.encoding
370 codecs.lookup(encoding)
Zachary Warebaf45c52014-10-17 13:59:18 -0500371 with self.assertRaises(TypeError):
372 stdscr.encoding = 10
Zachary Warebaf45c52014-10-17 13:59:18 -0500373 stdscr.encoding = encoding
374 with self.assertRaises(TypeError):
375 del stdscr.encoding
376
377 def test_issue21088(self):
378 stdscr = self.stdscr
379 #
380 # http://bugs.python.org/issue21088
381 #
382 # the bug:
383 # when converting curses.window.addch to Argument Clinic
384 # the first two parameters were switched.
385
386 # if someday we can represent the signature of addch
387 # we will need to rewrite this test.
388 try:
389 signature = inspect.signature(stdscr.addch)
390 self.assertFalse(signature)
391 except ValueError:
392 # not generating a signature is fine.
393 pass
394
395 # So. No signature for addch.
396 # But Argument Clinic gave us a human-readable equivalent
397 # as the first line of the docstring. So we parse that,
398 # and ensure that the parameters appear in the correct order.
399 # Since this is parsing output from Argument Clinic, we can
400 # be reasonably certain the generated parsing code will be
401 # correct too.
402 human_readable_signature = stdscr.addch.__doc__.split("\n")[0]
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300403 self.assertIn("[y, x,]", human_readable_signature)
404
Serhiy Storchakabdf9e0e2016-12-28 10:16:06 +0200405 def test_issue13051(self):
406 stdscr = self.stdscr
407 box = curses.textpad.Textbox(stdscr, insert_mode=True)
408 lines, cols = stdscr.getmaxyx()
409 stdscr.resize(lines-2, cols-2)
410 # this may cause infinite recursion, leading to a RuntimeError
411 box._insert_printable_char('a')
412
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300413
414class MiscTests(unittest.TestCase):
Zachary Warebaf45c52014-10-17 13:59:18 -0500415
Berker Peksag53926f12016-08-19 17:59:01 +0300416 @requires_curses_func('update_lines_cols')
Steve Dowerd2bc3892015-04-15 18:06:05 -0400417 def test_update_lines_cols(self):
418 # this doesn't actually test that LINES and COLS are updated,
419 # because we can't automate changing them. See Issue #4254 for
420 # a manual test script. We can only test that the function
421 # can be called.
422 curses.update_lines_cols()
423
Alexandre Vassalotti5ff02352009-07-22 21:27:53 +0000424
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300425class TestAscii(unittest.TestCase):
426
Serhiy Storchaka514f9732016-06-18 22:08:11 +0300427 def test_controlnames(self):
428 for name in curses.ascii.controlnames:
429 self.assertTrue(hasattr(curses.ascii, name), name)
430
431 def test_ctypes(self):
432 def check(func, expected):
433 with self.subTest(ch=c, func=func):
434 self.assertEqual(func(i), expected)
435 self.assertEqual(func(c), expected)
436
437 for i in range(256):
438 c = chr(i)
439 b = bytes([i])
440 check(curses.ascii.isalnum, b.isalnum())
441 check(curses.ascii.isalpha, b.isalpha())
442 check(curses.ascii.isdigit, b.isdigit())
443 check(curses.ascii.islower, b.islower())
444 check(curses.ascii.isspace, b.isspace())
445 check(curses.ascii.isupper, b.isupper())
446
447 check(curses.ascii.isascii, i < 128)
448 check(curses.ascii.ismeta, i >= 128)
449 check(curses.ascii.isctrl, i < 32)
450 check(curses.ascii.iscntrl, i < 32 or i == 127)
451 check(curses.ascii.isblank, c in ' \t')
452 check(curses.ascii.isgraph, 32 < i <= 126)
453 check(curses.ascii.isprint, 32 <= i <= 126)
454 check(curses.ascii.ispunct, c in string.punctuation)
455 check(curses.ascii.isxdigit, c in string.hexdigits)
456
Serhiy Storchaka283de2b2016-12-28 10:04:27 +0200457 for i in (-2, -1, 256, sys.maxunicode, sys.maxunicode+1):
458 self.assertFalse(curses.ascii.isalnum(i))
459 self.assertFalse(curses.ascii.isalpha(i))
460 self.assertFalse(curses.ascii.isdigit(i))
461 self.assertFalse(curses.ascii.islower(i))
462 self.assertFalse(curses.ascii.isspace(i))
463 self.assertFalse(curses.ascii.isupper(i))
464
465 self.assertFalse(curses.ascii.isascii(i))
466 self.assertFalse(curses.ascii.isctrl(i))
467 self.assertFalse(curses.ascii.iscntrl(i))
468 self.assertFalse(curses.ascii.isblank(i))
469 self.assertFalse(curses.ascii.isgraph(i))
470 self.assertFalse(curses.ascii.isprint(i))
471 self.assertFalse(curses.ascii.ispunct(i))
472 self.assertFalse(curses.ascii.isxdigit(i))
473
474 self.assertFalse(curses.ascii.ismeta(-1))
475
Serhiy Storchaka514f9732016-06-18 22:08:11 +0300476 def test_ascii(self):
477 ascii = curses.ascii.ascii
478 self.assertEqual(ascii('\xc1'), 'A')
479 self.assertEqual(ascii('A'), 'A')
480 self.assertEqual(ascii(ord('\xc1')), ord('A'))
481
482 def test_ctrl(self):
483 ctrl = curses.ascii.ctrl
484 self.assertEqual(ctrl('J'), '\n')
485 self.assertEqual(ctrl('\n'), '\n')
486 self.assertEqual(ctrl('@'), '\0')
487 self.assertEqual(ctrl(ord('J')), ord('\n'))
488
489 def test_alt(self):
490 alt = curses.ascii.alt
491 self.assertEqual(alt('\n'), '\x8a')
492 self.assertEqual(alt('A'), '\xc1')
493 self.assertEqual(alt(ord('A')), 0xc1)
494
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300495 def test_unctrl(self):
496 unctrl = curses.ascii.unctrl
497 self.assertEqual(unctrl('a'), 'a')
498 self.assertEqual(unctrl('A'), 'A')
499 self.assertEqual(unctrl(';'), ';')
500 self.assertEqual(unctrl(' '), ' ')
501 self.assertEqual(unctrl('\x7f'), '^?')
502 self.assertEqual(unctrl('\n'), '^J')
503 self.assertEqual(unctrl('\0'), '^@')
Serhiy Storchaka514f9732016-06-18 22:08:11 +0300504 self.assertEqual(unctrl(ord('A')), 'A')
505 self.assertEqual(unctrl(ord('\n')), '^J')
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300506 # Meta-bit characters
507 self.assertEqual(unctrl('\x8a'), '!^J')
508 self.assertEqual(unctrl('\xc1'), '!A')
Serhiy Storchaka514f9732016-06-18 22:08:11 +0300509 self.assertEqual(unctrl(ord('\x8a')), '!^J')
510 self.assertEqual(unctrl(ord('\xc1')), '!A')
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300511
512
Alexandre Vassalotti5ff02352009-07-22 21:27:53 +0000513if __name__ == '__main__':
Zachary Warebaf45c52014-10-17 13:59:18 -0500514 unittest.main()