blob: 6811ff936633e70022a8247f1a5729c796ff242b [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
Hai Shia7f5d932020-08-04 00:41:24 +080018from test.support import requires, verbose, SaveSignals
19from test.support.import_helper import import_module
Andrew M. Kuchling2158df02001-10-22 15:26:09 +000020
21# Optionally test curses module. This currently requires that the
22# 'curses' resource be given on the regrtest command line using the -u
23# option. If not available, nothing after this line will be executed.
Larry Hastings9147a962014-05-04 04:41:18 -070024import inspect
Neal Norwitz9f39f682006-01-06 04:18:21 +000025requires('curses')
26
R. David Murraya21e4ca2009-03-31 23:16:50 +000027# If either of these don't exist, skip the tests.
28curses = import_module('curses')
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +030029import_module('curses.ascii')
Serhiy Storchakabdf9e0e2016-12-28 10:16:06 +020030import_module('curses.textpad')
Serhiy Storchakabaac01e2017-10-31 13:56:44 +020031try:
32 import curses.panel
33except ImportError:
34 pass
R. David Murraya21e4ca2009-03-31 23:16:50 +000035
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +030036def requires_curses_func(name):
37 return unittest.skipUnless(hasattr(curses, name),
38 'requires curses.%s' % name)
Mark Dickinson945e2422010-02-21 13:42:03 +000039
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +030040term = os.environ.get('TERM')
41
42# If newterm was supported we could use it instead of initscr and not exit
43@unittest.skipIf(not term or term == 'unknown',
Zachary Warebaf45c52014-10-17 13:59:18 -050044 "$TERM=%r, calling initscr() may cause exit" % term)
45@unittest.skipIf(sys.platform == "cygwin",
46 "cygwin's curses mostly just hangs")
47class TestCurses(unittest.TestCase):
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +030048
Zachary Warebaf45c52014-10-17 13:59:18 -050049 @classmethod
50 def setUpClass(cls):
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +030051 # testing setupterm() inside initscr/endwin
52 # causes terminal breakage
Serhiy Storchaka607501a2021-01-02 19:35:15 +020053 stdout_fd = sys.__stdout__.fileno()
54 curses.setupterm(fd=stdout_fd)
Andrew M. Kuchling2158df02001-10-22 15:26:09 +000055
Zachary Warebaf45c52014-10-17 13:59:18 -050056 def setUp(self):
Serhiy Storchaka607501a2021-01-02 19:35:15 +020057 self.isatty = True
58 self.output = sys.__stdout__
59 stdout_fd = sys.__stdout__.fileno()
60 if not sys.__stdout__.isatty():
61 # initstr() unconditionally uses C stdout.
62 # If it is redirected to file or pipe, try to attach it
63 # to terminal.
64 # First, save a copy of the file descriptor of stdout, so it
65 # can be restored after finishing the test.
66 dup_fd = os.dup(stdout_fd)
67 self.addCleanup(os.close, dup_fd)
68 self.addCleanup(os.dup2, dup_fd, stdout_fd)
69
70 if sys.__stderr__.isatty():
71 # If stderr is connected to terminal, use it.
72 tmp = sys.__stderr__
73 self.output = sys.__stderr__
74 else:
75 try:
76 # Try to open the terminal device.
77 tmp = open('/xdev/tty', 'wb', buffering=0)
78 except OSError:
79 # As a fallback, use regular file to write control codes.
80 # Some functions (like savetty) will not work, but at
81 # least the garbage control sequences will not be mixed
82 # with the testing report.
83 tmp = tempfile.TemporaryFile(mode='wb', buffering=0)
84 self.isatty = False
85 self.addCleanup(tmp.close)
86 self.output = None
87 os.dup2(tmp.fileno(), stdout_fd)
88
Victor Stinner19f68302017-10-31 03:14:01 -070089 self.save_signals = SaveSignals()
90 self.save_signals.save()
Serhiy Storchaka607501a2021-01-02 19:35:15 +020091 self.addCleanup(self.save_signals.restore)
92 if verbose and self.output is not None:
Zachary Warebaf45c52014-10-17 13:59:18 -050093 # just to make the test output a little more readable
Serhiy Storchaka607501a2021-01-02 19:35:15 +020094 sys.stderr.flush()
95 sys.stdout.flush()
96 print(file=self.output, flush=True)
Zachary Warebaf45c52014-10-17 13:59:18 -050097 self.stdscr = curses.initscr()
Serhiy Storchaka607501a2021-01-02 19:35:15 +020098 if self.isatty:
99 curses.savetty()
100 self.addCleanup(curses.endwin)
101 self.addCleanup(curses.resetty)
Zachary Warebaf45c52014-10-17 13:59:18 -0500102
103 def test_window_funcs(self):
104 "Test the methods of windows"
105 stdscr = self.stdscr
106 win = curses.newwin(10,10)
107 win = curses.newwin(5,5, 5,5)
108 win2 = curses.newwin(15,15, 5,5)
109
110 for meth in [stdscr.addch, stdscr.addstr]:
Serhiy Storchakaf7eae0a2017-06-28 08:30:06 +0300111 for args in [('a',), ('a', curses.A_BOLD),
Zachary Warebaf45c52014-10-17 13:59:18 -0500112 (4,4, 'a'), (5,5, 'a', curses.A_BOLD)]:
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300113 with self.subTest(meth=meth.__qualname__, args=args):
114 meth(*args)
Zachary Warebaf45c52014-10-17 13:59:18 -0500115
Serhiy Storchaka4f469c02017-11-01 20:48:49 +0200116 for meth in [stdscr.clear, stdscr.clrtobot,
Zachary Warebaf45c52014-10-17 13:59:18 -0500117 stdscr.clrtoeol, stdscr.cursyncup, stdscr.delch,
118 stdscr.deleteln, stdscr.erase, stdscr.getbegyx,
Serhiy Storchaka607501a2021-01-02 19:35:15 +0200119 stdscr.getbkgd, stdscr.getmaxyx,
Zachary Warebaf45c52014-10-17 13:59:18 -0500120 stdscr.getparyx, stdscr.getyx, stdscr.inch,
121 stdscr.insertln, stdscr.instr, stdscr.is_wintouched,
122 win.noutrefresh, stdscr.redrawwin, stdscr.refresh,
123 stdscr.standout, stdscr.standend, stdscr.syncdown,
124 stdscr.syncup, stdscr.touchwin, stdscr.untouchwin]:
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300125 with self.subTest(meth=meth.__qualname__):
126 meth()
Zachary Warebaf45c52014-10-17 13:59:18 -0500127
128 stdscr.addnstr('1234', 3)
129 stdscr.addnstr('1234', 3, curses.A_BOLD)
130 stdscr.addnstr(4,4, '1234', 3)
131 stdscr.addnstr(5,5, '1234', 3, curses.A_BOLD)
132
133 stdscr.attron(curses.A_BOLD)
134 stdscr.attroff(curses.A_BOLD)
135 stdscr.attrset(curses.A_BOLD)
136 stdscr.bkgd(' ')
137 stdscr.bkgd(' ', curses.A_REVERSE)
138 stdscr.bkgdset(' ')
139 stdscr.bkgdset(' ', curses.A_REVERSE)
140
141 win.border(65, 66, 67, 68,
142 69, 70, 71, 72)
143 win.border('|', '!', '-', '_',
144 '+', '\\', '#', '/')
145 with self.assertRaises(TypeError,
146 msg="Expected win.border() to raise TypeError"):
147 win.border(65, 66, 67, 68,
148 69, [], 71, 72)
149
Serhiy Storchaka4f469c02017-11-01 20:48:49 +0200150 win.box(65, 67)
151 win.box('!', '_')
152 win.box(b':', b'~')
153 self.assertRaises(TypeError, win.box, 65, 66, 67)
154 self.assertRaises(TypeError, win.box, 65)
155 win.box()
156
Zachary Warebaf45c52014-10-17 13:59:18 -0500157 stdscr.clearok(1)
158
159 win4 = stdscr.derwin(2,2)
160 win4 = stdscr.derwin(1,1, 5,5)
161 win4.mvderwin(9,9)
162
163 stdscr.echochar('a')
164 stdscr.echochar('a', curses.A_BOLD)
165 stdscr.hline('-', 5)
166 stdscr.hline('-', 5, curses.A_BOLD)
167 stdscr.hline(1,1,'-', 5)
168 stdscr.hline(1,1,'-', 5, curses.A_BOLD)
169
170 stdscr.idcok(1)
171 stdscr.idlok(1)
Serhiy Storchakabaac01e2017-10-31 13:56:44 +0200172 if hasattr(stdscr, 'immedok'):
173 stdscr.immedok(1)
Serhiy Storchaka894ebd02017-11-01 14:34:20 +0200174 stdscr.immedok(0)
Zachary Warebaf45c52014-10-17 13:59:18 -0500175 stdscr.insch('c')
176 stdscr.insdelln(1)
177 stdscr.insnstr('abc', 3)
178 stdscr.insnstr('abc', 3, curses.A_BOLD)
179 stdscr.insnstr(5, 5, 'abc', 3)
180 stdscr.insnstr(5, 5, 'abc', 3, curses.A_BOLD)
181
182 stdscr.insstr('def')
183 stdscr.insstr('def', curses.A_BOLD)
184 stdscr.insstr(5, 5, 'def')
185 stdscr.insstr(5, 5, 'def', curses.A_BOLD)
186 stdscr.is_linetouched(0)
187 stdscr.keypad(1)
188 stdscr.leaveok(1)
189 stdscr.move(3,3)
190 win.mvwin(2,2)
191 stdscr.nodelay(1)
192 stdscr.notimeout(1)
193 win2.overlay(win)
194 win2.overwrite(win)
195 win2.overlay(win, 1, 2, 2, 1, 3, 3)
196 win2.overwrite(win, 1, 2, 2, 1, 3, 3)
197 stdscr.redrawln(1,2)
198
199 stdscr.scrollok(1)
200 stdscr.scroll()
201 stdscr.scroll(2)
202 stdscr.scroll(-3)
203
204 stdscr.move(12, 2)
205 stdscr.setscrreg(10,15)
206 win3 = stdscr.subwin(10,10)
207 win3 = stdscr.subwin(10,10, 5,5)
Serhiy Storchaka894ebd02017-11-01 14:34:20 +0200208 if hasattr(stdscr, 'syncok') and not sys.platform.startswith("sunos"):
Serhiy Storchakabaac01e2017-10-31 13:56:44 +0200209 stdscr.syncok(1)
Zachary Warebaf45c52014-10-17 13:59:18 -0500210 stdscr.timeout(5)
211 stdscr.touchline(5,5)
212 stdscr.touchline(5,5,0)
213 stdscr.vline('a', 3)
214 stdscr.vline('a', 3, curses.A_STANDOUT)
Serhiy Storchaka894ebd02017-11-01 14:34:20 +0200215 if hasattr(stdscr, 'chgat'):
216 stdscr.chgat(5, 2, 3, curses.A_BLINK)
217 stdscr.chgat(3, curses.A_BOLD)
218 stdscr.chgat(5, 8, curses.A_UNDERLINE)
219 stdscr.chgat(curses.A_BLINK)
Zachary Warebaf45c52014-10-17 13:59:18 -0500220 stdscr.refresh()
221
222 stdscr.vline(1,1, 'a', 3)
223 stdscr.vline(1,1, 'a', 3, curses.A_STANDOUT)
224
Serhiy Storchaka894ebd02017-11-01 14:34:20 +0200225 if hasattr(stdscr, 'resize'):
226 stdscr.resize(25, 80)
227 if hasattr(stdscr, 'enclose'):
228 stdscr.enclose(10, 10)
Zachary Warebaf45c52014-10-17 13:59:18 -0500229
Serhiy Storchaka607501a2021-01-02 19:35:15 +0200230 with tempfile.TemporaryFile() as f:
231 self.stdscr.putwin(f)
232 f.seek(0)
233 curses.getwin(f)
234
Benjamin Peterson40a77c32016-08-13 18:15:28 -0700235 self.assertRaises(ValueError, stdscr.getstr, -400)
236 self.assertRaises(ValueError, stdscr.getstr, 2, 3, -400)
Benjamin Peterson432ea4f2016-08-15 21:40:14 -0700237 self.assertRaises(ValueError, stdscr.instr, -2)
238 self.assertRaises(ValueError, stdscr.instr, 2, 3, -2)
Benjamin Peterson40a77c32016-08-13 18:15:28 -0700239
Serhiy Storchakaf7eae0a2017-06-28 08:30:06 +0300240 def test_embedded_null_chars(self):
241 # reject embedded null bytes and characters
242 stdscr = self.stdscr
243 for arg in ['a', b'a']:
244 with self.subTest(arg=arg):
245 self.assertRaises(ValueError, stdscr.addstr, 'a\0')
246 self.assertRaises(ValueError, stdscr.addnstr, 'a\0', 1)
247 self.assertRaises(ValueError, stdscr.insstr, 'a\0')
248 self.assertRaises(ValueError, stdscr.insnstr, 'a\0', 1)
Zachary Warebaf45c52014-10-17 13:59:18 -0500249
250 def test_module_funcs(self):
251 "Test module-level functions"
Zachary Warebaf45c52014-10-17 13:59:18 -0500252 for func in [curses.baudrate, curses.beep, curses.can_change_color,
Serhiy Storchaka607501a2021-01-02 19:35:15 +0200253 curses.doupdate, curses.flash, curses.flushinp,
Zachary Warebaf45c52014-10-17 13:59:18 -0500254 curses.has_colors, curses.has_ic, curses.has_il,
255 curses.isendwin, curses.killchar, curses.longname,
Serhiy Storchaka607501a2021-01-02 19:35:15 +0200256 curses.noecho, curses.nonl, curses.noqiflush,
257 curses.termattrs, curses.termname, curses.erasechar,
Hans Petter Janssonda4e09f2020-08-03 22:51:33 -0500258 curses.has_extended_color_support]:
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300259 with self.subTest(func=func.__qualname__):
260 func()
Serhiy Storchaka607501a2021-01-02 19:35:15 +0200261 if self.isatty:
262 for func in [curses.cbreak, curses.def_prog_mode,
263 curses.nocbreak, curses.noraw,
264 curses.reset_prog_mode]:
265 with self.subTest(func=func.__qualname__):
266 func()
Serhiy Storchakabaac01e2017-10-31 13:56:44 +0200267 if hasattr(curses, 'filter'):
268 curses.filter()
269 if hasattr(curses, 'getsyx'):
270 curses.getsyx()
Zachary Warebaf45c52014-10-17 13:59:18 -0500271
272 # Functions that actually need arguments
273 if curses.tigetstr("cnorm"):
274 curses.curs_set(1)
275 curses.delay_output(1)
276 curses.echo() ; curses.echo(1)
277
Zachary Warebaf45c52014-10-17 13:59:18 -0500278 curses.halfdelay(1)
Serhiy Storchaka607501a2021-01-02 19:35:15 +0200279 if self.isatty:
280 curses.intrflush(1)
Zachary Warebaf45c52014-10-17 13:59:18 -0500281 curses.meta(1)
282 curses.napms(100)
283 curses.newpad(50,50)
284 win = curses.newwin(5,5)
285 win = curses.newwin(5,5, 1,1)
286 curses.nl() ; curses.nl(1)
287 curses.putp(b'abc')
288 curses.qiflush()
Serhiy Storchaka607501a2021-01-02 19:35:15 +0200289 if self.isatty:
290 curses.raw() ; curses.raw(1)
Anthony Sottileb32cb972019-10-31 02:13:48 -0700291 curses.set_escdelay(25)
292 self.assertEqual(curses.get_escdelay(), 25)
293 curses.set_tabsize(4)
294 self.assertEqual(curses.get_tabsize(), 4)
Serhiy Storchakabaac01e2017-10-31 13:56:44 +0200295 if hasattr(curses, 'setsyx'):
296 curses.setsyx(5,5)
Zachary Warebaf45c52014-10-17 13:59:18 -0500297 curses.tigetflag('hc')
298 curses.tigetnum('co')
299 curses.tigetstr('cr')
300 curses.tparm(b'cr')
Serhiy Storchakabaac01e2017-10-31 13:56:44 +0200301 if hasattr(curses, 'typeahead'):
302 curses.typeahead(sys.__stdin__.fileno())
Zachary Warebaf45c52014-10-17 13:59:18 -0500303 curses.unctrl('a')
304 curses.ungetch('a')
Serhiy Storchakabaac01e2017-10-31 13:56:44 +0200305 if hasattr(curses, 'use_env'):
306 curses.use_env(1)
Zachary Warebaf45c52014-10-17 13:59:18 -0500307
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300308 # Functions only available on a few platforms
309 def test_colors_funcs(self):
310 if not curses.has_colors():
Xavier de Gaye645bc802017-01-06 09:50:27 +0100311 self.skipTest('requires colors support')
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300312 curses.start_color()
313 curses.init_pair(2, 1,1)
314 curses.color_content(1)
315 curses.color_pair(2)
316 curses.pair_content(curses.COLOR_PAIRS - 1)
317 curses.pair_number(0)
Zachary Warebaf45c52014-10-17 13:59:18 -0500318
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300319 if hasattr(curses, 'use_default_colors'):
320 curses.use_default_colors()
Zachary Warebaf45c52014-10-17 13:59:18 -0500321
Hans Petter Janssonda4e09f2020-08-03 22:51:33 -0500322 self.assertRaises(ValueError, curses.color_content, -1)
323 self.assertRaises(ValueError, curses.color_content, curses.COLORS + 1)
324 self.assertRaises(ValueError, curses.color_content, -2**31 - 1)
325 self.assertRaises(ValueError, curses.color_content, 2**31)
326 self.assertRaises(ValueError, curses.color_content, -2**63 - 1)
327 self.assertRaises(ValueError, curses.color_content, 2**63 - 1)
328 self.assertRaises(ValueError, curses.pair_content, -1)
329 self.assertRaises(ValueError, curses.pair_content, curses.COLOR_PAIRS)
330 self.assertRaises(ValueError, curses.pair_content, -2**31 - 1)
331 self.assertRaises(ValueError, curses.pair_content, 2**31)
332 self.assertRaises(ValueError, curses.pair_content, -2**63 - 1)
333 self.assertRaises(ValueError, curses.pair_content, 2**63 - 1)
334
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300335 @requires_curses_func('keyname')
336 def test_keyname(self):
337 curses.keyname(13)
Zachary Warebaf45c52014-10-17 13:59:18 -0500338
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300339 @requires_curses_func('has_key')
340 def test_has_key(self):
341 curses.has_key(13)
Zachary Warebaf45c52014-10-17 13:59:18 -0500342
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300343 @requires_curses_func('getmouse')
344 def test_getmouse(self):
345 (availmask, oldmask) = curses.mousemask(curses.BUTTON1_PRESSED)
346 if availmask == 0:
Xavier de Gaye645bc802017-01-06 09:50:27 +0100347 self.skipTest('mouse stuff not available')
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300348 curses.mouseinterval(10)
349 # just verify these don't cause errors
350 curses.ungetmouse(0, 0, 0, 0, curses.BUTTON1_PRESSED)
351 m = curses.getmouse()
Zachary Warebaf45c52014-10-17 13:59:18 -0500352
Serhiy Storchakabaac01e2017-10-31 13:56:44 +0200353 @requires_curses_func('panel')
Zachary Warebaf45c52014-10-17 13:59:18 -0500354 def test_userptr_without_set(self):
355 w = curses.newwin(10, 10)
356 p = curses.panel.new_panel(w)
357 # try to access userptr() before calling set_userptr() -- segfaults
358 with self.assertRaises(curses.panel.error,
359 msg='userptr should fail since not set'):
360 p.userptr()
361
Serhiy Storchakabaac01e2017-10-31 13:56:44 +0200362 @requires_curses_func('panel')
Zachary Warebaf45c52014-10-17 13:59:18 -0500363 def test_userptr_memory_leak(self):
364 w = curses.newwin(10, 10)
365 p = curses.panel.new_panel(w)
366 obj = object()
367 nrefs = sys.getrefcount(obj)
368 for i in range(100):
369 p.set_userptr(obj)
370
371 p.set_userptr(None)
372 self.assertEqual(sys.getrefcount(obj), nrefs,
373 "set_userptr leaked references")
374
Serhiy Storchakabaac01e2017-10-31 13:56:44 +0200375 @requires_curses_func('panel')
Zachary Warebaf45c52014-10-17 13:59:18 -0500376 def test_userptr_segfault(self):
Serhiy Storchakaa7723d82017-11-03 20:29:33 +0200377 w = curses.newwin(10, 10)
378 panel = curses.panel.new_panel(w)
Zachary Warebaf45c52014-10-17 13:59:18 -0500379 class A:
380 def __del__(self):
381 panel.set_userptr(None)
382 panel.set_userptr(A())
383 panel.set_userptr(None)
384
Serhiy Storchakabaac01e2017-10-31 13:56:44 +0200385 @requires_curses_func('panel')
Serhiy Storchakae3f1b092016-05-08 20:46:22 +0300386 def test_new_curses_panel(self):
Serhiy Storchakaa7723d82017-11-03 20:29:33 +0200387 w = curses.newwin(10, 10)
388 panel = curses.panel.new_panel(w)
Serhiy Storchakae3f1b092016-05-08 20:46:22 +0300389 self.assertRaises(TypeError, type(panel))
390
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300391 @requires_curses_func('is_term_resized')
392 def test_is_term_resized(self):
393 curses.is_term_resized(*self.stdscr.getmaxyx())
394
395 @requires_curses_func('resize_term')
Zachary Warebaf45c52014-10-17 13:59:18 -0500396 def test_resize_term(self):
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300397 curses.resize_term(*self.stdscr.getmaxyx())
398
399 @requires_curses_func('resizeterm')
400 def test_resizeterm(self):
Zachary Warebaf45c52014-10-17 13:59:18 -0500401 lines, cols = curses.LINES, curses.COLS
402 new_lines = lines - 1
403 new_cols = cols + 1
404 curses.resizeterm(new_lines, new_cols)
405
406 self.assertEqual(curses.LINES, new_lines)
407 self.assertEqual(curses.COLS, new_cols)
408
409 def test_issue6243(self):
410 curses.ungetch(1025)
411 self.stdscr.getkey()
412
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300413 @requires_curses_func('unget_wch')
Serhiy Storchakab232df92018-10-30 13:22:42 +0200414 @unittest.skipIf(getattr(curses, 'ncurses_version', (99,)) < (5, 8),
415 "unget_wch is broken in ncurses 5.7 and earlier")
Zachary Warebaf45c52014-10-17 13:59:18 -0500416 def test_unget_wch(self):
417 stdscr = self.stdscr
418 encoding = stdscr.encoding
419 for ch in ('a', '\xe9', '\u20ac', '\U0010FFFF'):
420 try:
421 ch.encode(encoding)
422 except UnicodeEncodeError:
423 continue
424 try:
425 curses.unget_wch(ch)
426 except Exception as err:
427 self.fail("unget_wch(%a) failed with encoding %s: %s"
428 % (ch, stdscr.encoding, err))
429 read = stdscr.get_wch()
430 self.assertEqual(read, ch)
431
432 code = ord(ch)
433 curses.unget_wch(code)
434 read = stdscr.get_wch()
435 self.assertEqual(read, ch)
436
437 def test_issue10570(self):
438 b = curses.tparm(curses.tigetstr("cup"), 5, 3)
439 self.assertIs(type(b), bytes)
Zachary Warebaf45c52014-10-17 13:59:18 -0500440
441 def test_encoding(self):
442 stdscr = self.stdscr
443 import codecs
444 encoding = stdscr.encoding
445 codecs.lookup(encoding)
Zachary Warebaf45c52014-10-17 13:59:18 -0500446 with self.assertRaises(TypeError):
447 stdscr.encoding = 10
Zachary Warebaf45c52014-10-17 13:59:18 -0500448 stdscr.encoding = encoding
449 with self.assertRaises(TypeError):
450 del stdscr.encoding
451
452 def test_issue21088(self):
453 stdscr = self.stdscr
454 #
455 # http://bugs.python.org/issue21088
456 #
457 # the bug:
458 # when converting curses.window.addch to Argument Clinic
459 # the first two parameters were switched.
460
461 # if someday we can represent the signature of addch
462 # we will need to rewrite this test.
463 try:
464 signature = inspect.signature(stdscr.addch)
465 self.assertFalse(signature)
466 except ValueError:
467 # not generating a signature is fine.
468 pass
469
470 # So. No signature for addch.
471 # But Argument Clinic gave us a human-readable equivalent
472 # as the first line of the docstring. So we parse that,
473 # and ensure that the parameters appear in the correct order.
474 # Since this is parsing output from Argument Clinic, we can
475 # be reasonably certain the generated parsing code will be
476 # correct too.
477 human_readable_signature = stdscr.addch.__doc__.split("\n")[0]
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300478 self.assertIn("[y, x,]", human_readable_signature)
479
Serhiy Storchakabdf9e0e2016-12-28 10:16:06 +0200480 def test_issue13051(self):
481 stdscr = self.stdscr
Serhiy Storchaka894ebd02017-11-01 14:34:20 +0200482 if not hasattr(stdscr, 'resize'):
483 raise unittest.SkipTest('requires curses.window.resize')
Serhiy Storchakabdf9e0e2016-12-28 10:16:06 +0200484 box = curses.textpad.Textbox(stdscr, insert_mode=True)
485 lines, cols = stdscr.getmaxyx()
486 stdscr.resize(lines-2, cols-2)
487 # this may cause infinite recursion, leading to a RuntimeError
488 box._insert_printable_char('a')
489
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300490
491class MiscTests(unittest.TestCase):
Zachary Warebaf45c52014-10-17 13:59:18 -0500492
Berker Peksag53926f12016-08-19 17:59:01 +0300493 @requires_curses_func('update_lines_cols')
Steve Dowerd2bc3892015-04-15 18:06:05 -0400494 def test_update_lines_cols(self):
495 # this doesn't actually test that LINES and COLS are updated,
496 # because we can't automate changing them. See Issue #4254 for
497 # a manual test script. We can only test that the function
498 # can be called.
499 curses.update_lines_cols()
500
Serhiy Storchakab232df92018-10-30 13:22:42 +0200501 @requires_curses_func('ncurses_version')
502 def test_ncurses_version(self):
503 v = curses.ncurses_version
504 self.assertIsInstance(v[:], tuple)
505 self.assertEqual(len(v), 3)
506 self.assertIsInstance(v[0], int)
507 self.assertIsInstance(v[1], int)
508 self.assertIsInstance(v[2], int)
509 self.assertIsInstance(v.major, int)
510 self.assertIsInstance(v.minor, int)
511 self.assertIsInstance(v.patch, int)
512 self.assertEqual(v[0], v.major)
513 self.assertEqual(v[1], v.minor)
514 self.assertEqual(v[2], v.patch)
515 self.assertGreaterEqual(v.major, 0)
516 self.assertGreaterEqual(v.minor, 0)
517 self.assertGreaterEqual(v.patch, 0)
Alexandre Vassalotti5ff02352009-07-22 21:27:53 +0000518
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300519class TestAscii(unittest.TestCase):
520
Serhiy Storchaka514f9732016-06-18 22:08:11 +0300521 def test_controlnames(self):
522 for name in curses.ascii.controlnames:
523 self.assertTrue(hasattr(curses.ascii, name), name)
524
525 def test_ctypes(self):
526 def check(func, expected):
527 with self.subTest(ch=c, func=func):
528 self.assertEqual(func(i), expected)
529 self.assertEqual(func(c), expected)
530
531 for i in range(256):
532 c = chr(i)
533 b = bytes([i])
534 check(curses.ascii.isalnum, b.isalnum())
535 check(curses.ascii.isalpha, b.isalpha())
536 check(curses.ascii.isdigit, b.isdigit())
537 check(curses.ascii.islower, b.islower())
538 check(curses.ascii.isspace, b.isspace())
539 check(curses.ascii.isupper, b.isupper())
540
541 check(curses.ascii.isascii, i < 128)
542 check(curses.ascii.ismeta, i >= 128)
543 check(curses.ascii.isctrl, i < 32)
544 check(curses.ascii.iscntrl, i < 32 or i == 127)
545 check(curses.ascii.isblank, c in ' \t')
546 check(curses.ascii.isgraph, 32 < i <= 126)
547 check(curses.ascii.isprint, 32 <= i <= 126)
548 check(curses.ascii.ispunct, c in string.punctuation)
549 check(curses.ascii.isxdigit, c in string.hexdigits)
550
Serhiy Storchaka283de2b2016-12-28 10:04:27 +0200551 for i in (-2, -1, 256, sys.maxunicode, sys.maxunicode+1):
552 self.assertFalse(curses.ascii.isalnum(i))
553 self.assertFalse(curses.ascii.isalpha(i))
554 self.assertFalse(curses.ascii.isdigit(i))
555 self.assertFalse(curses.ascii.islower(i))
556 self.assertFalse(curses.ascii.isspace(i))
557 self.assertFalse(curses.ascii.isupper(i))
558
559 self.assertFalse(curses.ascii.isascii(i))
560 self.assertFalse(curses.ascii.isctrl(i))
561 self.assertFalse(curses.ascii.iscntrl(i))
562 self.assertFalse(curses.ascii.isblank(i))
563 self.assertFalse(curses.ascii.isgraph(i))
564 self.assertFalse(curses.ascii.isprint(i))
565 self.assertFalse(curses.ascii.ispunct(i))
566 self.assertFalse(curses.ascii.isxdigit(i))
567
568 self.assertFalse(curses.ascii.ismeta(-1))
569
Serhiy Storchaka514f9732016-06-18 22:08:11 +0300570 def test_ascii(self):
571 ascii = curses.ascii.ascii
572 self.assertEqual(ascii('\xc1'), 'A')
573 self.assertEqual(ascii('A'), 'A')
574 self.assertEqual(ascii(ord('\xc1')), ord('A'))
575
576 def test_ctrl(self):
577 ctrl = curses.ascii.ctrl
578 self.assertEqual(ctrl('J'), '\n')
579 self.assertEqual(ctrl('\n'), '\n')
580 self.assertEqual(ctrl('@'), '\0')
581 self.assertEqual(ctrl(ord('J')), ord('\n'))
582
583 def test_alt(self):
584 alt = curses.ascii.alt
585 self.assertEqual(alt('\n'), '\x8a')
586 self.assertEqual(alt('A'), '\xc1')
587 self.assertEqual(alt(ord('A')), 0xc1)
588
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300589 def test_unctrl(self):
590 unctrl = curses.ascii.unctrl
591 self.assertEqual(unctrl('a'), 'a')
592 self.assertEqual(unctrl('A'), 'A')
593 self.assertEqual(unctrl(';'), ';')
594 self.assertEqual(unctrl(' '), ' ')
595 self.assertEqual(unctrl('\x7f'), '^?')
596 self.assertEqual(unctrl('\n'), '^J')
597 self.assertEqual(unctrl('\0'), '^@')
Serhiy Storchaka514f9732016-06-18 22:08:11 +0300598 self.assertEqual(unctrl(ord('A')), 'A')
599 self.assertEqual(unctrl(ord('\n')), '^J')
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300600 # Meta-bit characters
601 self.assertEqual(unctrl('\x8a'), '!^J')
602 self.assertEqual(unctrl('\xc1'), '!A')
Serhiy Storchaka514f9732016-06-18 22:08:11 +0300603 self.assertEqual(unctrl(ord('\x8a')), '!^J')
604 self.assertEqual(unctrl(ord('\xc1')), '!A')
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300605
606
Alexandre Vassalotti5ff02352009-07-22 21:27:53 +0000607if __name__ == '__main__':
Zachary Warebaf45c52014-10-17 13:59:18 -0500608 unittest.main()