blob: 2c6d14c3f79ddac2b06d8e76238e230095e2cc4f [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 if not sys.__stdout__.isatty():
Serhiy Storchaka53a00352016-05-22 18:16:20 +030052 # Temporary skip tests on non-tty
Serhiy Storchaka0a91e432016-05-22 18:23:36 +030053 raise unittest.SkipTest('sys.__stdout__ is not a tty')
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +030054 cls.tmp = tempfile.TemporaryFile()
55 fd = cls.tmp.fileno()
56 else:
57 cls.tmp = None
58 fd = sys.__stdout__.fileno()
59 # testing setupterm() inside initscr/endwin
60 # causes terminal breakage
61 curses.setupterm(fd=fd)
62
63 @classmethod
64 def tearDownClass(cls):
65 if cls.tmp:
66 cls.tmp.close()
67 del cls.tmp
Andrew M. Kuchling2158df02001-10-22 15:26:09 +000068
Zachary Warebaf45c52014-10-17 13:59:18 -050069 def setUp(self):
Victor Stinner19f68302017-10-31 03:14:01 -070070 self.save_signals = SaveSignals()
71 self.save_signals.save()
Zachary Warebaf45c52014-10-17 13:59:18 -050072 if verbose:
73 # just to make the test output a little more readable
74 print()
75 self.stdscr = curses.initscr()
76 curses.savetty()
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000077
Zachary Warebaf45c52014-10-17 13:59:18 -050078 def tearDown(self):
Andrew M. Kuchling2158df02001-10-22 15:26:09 +000079 curses.resetty()
Andrew M. Kuchling2158df02001-10-22 15:26:09 +000080 curses.endwin()
Victor Stinner19f68302017-10-31 03:14:01 -070081 self.save_signals.restore()
Zachary Warebaf45c52014-10-17 13:59:18 -050082
83 def test_window_funcs(self):
84 "Test the methods of windows"
85 stdscr = self.stdscr
86 win = curses.newwin(10,10)
87 win = curses.newwin(5,5, 5,5)
88 win2 = curses.newwin(15,15, 5,5)
89
90 for meth in [stdscr.addch, stdscr.addstr]:
Serhiy Storchakaf7eae0a2017-06-28 08:30:06 +030091 for args in [('a',), ('a', curses.A_BOLD),
Zachary Warebaf45c52014-10-17 13:59:18 -050092 (4,4, 'a'), (5,5, 'a', curses.A_BOLD)]:
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +030093 with self.subTest(meth=meth.__qualname__, args=args):
94 meth(*args)
Zachary Warebaf45c52014-10-17 13:59:18 -050095
Serhiy Storchaka4f469c02017-11-01 20:48:49 +020096 for meth in [stdscr.clear, stdscr.clrtobot,
Zachary Warebaf45c52014-10-17 13:59:18 -050097 stdscr.clrtoeol, stdscr.cursyncup, stdscr.delch,
98 stdscr.deleteln, stdscr.erase, stdscr.getbegyx,
99 stdscr.getbkgd, stdscr.getkey, stdscr.getmaxyx,
100 stdscr.getparyx, stdscr.getyx, stdscr.inch,
101 stdscr.insertln, stdscr.instr, stdscr.is_wintouched,
102 win.noutrefresh, stdscr.redrawwin, stdscr.refresh,
103 stdscr.standout, stdscr.standend, stdscr.syncdown,
104 stdscr.syncup, stdscr.touchwin, stdscr.untouchwin]:
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300105 with self.subTest(meth=meth.__qualname__):
106 meth()
Zachary Warebaf45c52014-10-17 13:59:18 -0500107
108 stdscr.addnstr('1234', 3)
109 stdscr.addnstr('1234', 3, curses.A_BOLD)
110 stdscr.addnstr(4,4, '1234', 3)
111 stdscr.addnstr(5,5, '1234', 3, curses.A_BOLD)
112
113 stdscr.attron(curses.A_BOLD)
114 stdscr.attroff(curses.A_BOLD)
115 stdscr.attrset(curses.A_BOLD)
116 stdscr.bkgd(' ')
117 stdscr.bkgd(' ', curses.A_REVERSE)
118 stdscr.bkgdset(' ')
119 stdscr.bkgdset(' ', curses.A_REVERSE)
120
121 win.border(65, 66, 67, 68,
122 69, 70, 71, 72)
123 win.border('|', '!', '-', '_',
124 '+', '\\', '#', '/')
125 with self.assertRaises(TypeError,
126 msg="Expected win.border() to raise TypeError"):
127 win.border(65, 66, 67, 68,
128 69, [], 71, 72)
129
Serhiy Storchaka4f469c02017-11-01 20:48:49 +0200130 win.box(65, 67)
131 win.box('!', '_')
132 win.box(b':', b'~')
133 self.assertRaises(TypeError, win.box, 65, 66, 67)
134 self.assertRaises(TypeError, win.box, 65)
135 win.box()
136
Zachary Warebaf45c52014-10-17 13:59:18 -0500137 stdscr.clearok(1)
138
139 win4 = stdscr.derwin(2,2)
140 win4 = stdscr.derwin(1,1, 5,5)
141 win4.mvderwin(9,9)
142
143 stdscr.echochar('a')
144 stdscr.echochar('a', curses.A_BOLD)
145 stdscr.hline('-', 5)
146 stdscr.hline('-', 5, curses.A_BOLD)
147 stdscr.hline(1,1,'-', 5)
148 stdscr.hline(1,1,'-', 5, curses.A_BOLD)
149
150 stdscr.idcok(1)
151 stdscr.idlok(1)
Serhiy Storchakabaac01e2017-10-31 13:56:44 +0200152 if hasattr(stdscr, 'immedok'):
153 stdscr.immedok(1)
Serhiy Storchaka894ebd02017-11-01 14:34:20 +0200154 stdscr.immedok(0)
Zachary Warebaf45c52014-10-17 13:59:18 -0500155 stdscr.insch('c')
156 stdscr.insdelln(1)
157 stdscr.insnstr('abc', 3)
158 stdscr.insnstr('abc', 3, curses.A_BOLD)
159 stdscr.insnstr(5, 5, 'abc', 3)
160 stdscr.insnstr(5, 5, 'abc', 3, curses.A_BOLD)
161
162 stdscr.insstr('def')
163 stdscr.insstr('def', curses.A_BOLD)
164 stdscr.insstr(5, 5, 'def')
165 stdscr.insstr(5, 5, 'def', curses.A_BOLD)
166 stdscr.is_linetouched(0)
167 stdscr.keypad(1)
168 stdscr.leaveok(1)
169 stdscr.move(3,3)
170 win.mvwin(2,2)
171 stdscr.nodelay(1)
172 stdscr.notimeout(1)
173 win2.overlay(win)
174 win2.overwrite(win)
175 win2.overlay(win, 1, 2, 2, 1, 3, 3)
176 win2.overwrite(win, 1, 2, 2, 1, 3, 3)
177 stdscr.redrawln(1,2)
178
179 stdscr.scrollok(1)
180 stdscr.scroll()
181 stdscr.scroll(2)
182 stdscr.scroll(-3)
183
184 stdscr.move(12, 2)
185 stdscr.setscrreg(10,15)
186 win3 = stdscr.subwin(10,10)
187 win3 = stdscr.subwin(10,10, 5,5)
Serhiy Storchaka894ebd02017-11-01 14:34:20 +0200188 if hasattr(stdscr, 'syncok') and not sys.platform.startswith("sunos"):
Serhiy Storchakabaac01e2017-10-31 13:56:44 +0200189 stdscr.syncok(1)
Zachary Warebaf45c52014-10-17 13:59:18 -0500190 stdscr.timeout(5)
191 stdscr.touchline(5,5)
192 stdscr.touchline(5,5,0)
193 stdscr.vline('a', 3)
194 stdscr.vline('a', 3, curses.A_STANDOUT)
Serhiy Storchaka894ebd02017-11-01 14:34:20 +0200195 if hasattr(stdscr, 'chgat'):
196 stdscr.chgat(5, 2, 3, curses.A_BLINK)
197 stdscr.chgat(3, curses.A_BOLD)
198 stdscr.chgat(5, 8, curses.A_UNDERLINE)
199 stdscr.chgat(curses.A_BLINK)
Zachary Warebaf45c52014-10-17 13:59:18 -0500200 stdscr.refresh()
201
202 stdscr.vline(1,1, 'a', 3)
203 stdscr.vline(1,1, 'a', 3, curses.A_STANDOUT)
204
Serhiy Storchaka894ebd02017-11-01 14:34:20 +0200205 if hasattr(stdscr, 'resize'):
206 stdscr.resize(25, 80)
207 if hasattr(stdscr, 'enclose'):
208 stdscr.enclose(10, 10)
Zachary Warebaf45c52014-10-17 13:59:18 -0500209
Benjamin Peterson40a77c32016-08-13 18:15:28 -0700210 self.assertRaises(ValueError, stdscr.getstr, -400)
211 self.assertRaises(ValueError, stdscr.getstr, 2, 3, -400)
Benjamin Peterson432ea4f2016-08-15 21:40:14 -0700212 self.assertRaises(ValueError, stdscr.instr, -2)
213 self.assertRaises(ValueError, stdscr.instr, 2, 3, -2)
Benjamin Peterson40a77c32016-08-13 18:15:28 -0700214
Serhiy Storchakaf7eae0a2017-06-28 08:30:06 +0300215 def test_embedded_null_chars(self):
216 # reject embedded null bytes and characters
217 stdscr = self.stdscr
218 for arg in ['a', b'a']:
219 with self.subTest(arg=arg):
220 self.assertRaises(ValueError, stdscr.addstr, 'a\0')
221 self.assertRaises(ValueError, stdscr.addnstr, 'a\0', 1)
222 self.assertRaises(ValueError, stdscr.insstr, 'a\0')
223 self.assertRaises(ValueError, stdscr.insnstr, 'a\0', 1)
Zachary Warebaf45c52014-10-17 13:59:18 -0500224
225 def test_module_funcs(self):
226 "Test module-level functions"
Zachary Warebaf45c52014-10-17 13:59:18 -0500227 for func in [curses.baudrate, curses.beep, curses.can_change_color,
228 curses.cbreak, curses.def_prog_mode, curses.doupdate,
Serhiy Storchakabaac01e2017-10-31 13:56:44 +0200229 curses.flash, curses.flushinp,
Zachary Warebaf45c52014-10-17 13:59:18 -0500230 curses.has_colors, curses.has_ic, curses.has_il,
231 curses.isendwin, curses.killchar, curses.longname,
232 curses.nocbreak, curses.noecho, curses.nonl,
233 curses.noqiflush, curses.noraw,
234 curses.reset_prog_mode, curses.termattrs,
Serhiy Storchakabaac01e2017-10-31 13:56:44 +0200235 curses.termname, curses.erasechar]:
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300236 with self.subTest(func=func.__qualname__):
237 func()
Serhiy Storchakabaac01e2017-10-31 13:56:44 +0200238 if hasattr(curses, 'filter'):
239 curses.filter()
240 if hasattr(curses, 'getsyx'):
241 curses.getsyx()
Zachary Warebaf45c52014-10-17 13:59:18 -0500242
243 # Functions that actually need arguments
244 if curses.tigetstr("cnorm"):
245 curses.curs_set(1)
246 curses.delay_output(1)
247 curses.echo() ; curses.echo(1)
248
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300249 with tempfile.TemporaryFile() as f:
250 self.stdscr.putwin(f)
251 f.seek(0)
252 curses.getwin(f)
Zachary Warebaf45c52014-10-17 13:59:18 -0500253
254 curses.halfdelay(1)
255 curses.intrflush(1)
256 curses.meta(1)
257 curses.napms(100)
258 curses.newpad(50,50)
259 win = curses.newwin(5,5)
260 win = curses.newwin(5,5, 1,1)
261 curses.nl() ; curses.nl(1)
262 curses.putp(b'abc')
263 curses.qiflush()
264 curses.raw() ; curses.raw(1)
Anthony Sottileb32cb972019-10-31 02:13:48 -0700265 curses.set_escdelay(25)
266 self.assertEqual(curses.get_escdelay(), 25)
267 curses.set_tabsize(4)
268 self.assertEqual(curses.get_tabsize(), 4)
Serhiy Storchakabaac01e2017-10-31 13:56:44 +0200269 if hasattr(curses, 'setsyx'):
270 curses.setsyx(5,5)
Zachary Warebaf45c52014-10-17 13:59:18 -0500271 curses.tigetflag('hc')
272 curses.tigetnum('co')
273 curses.tigetstr('cr')
274 curses.tparm(b'cr')
Serhiy Storchakabaac01e2017-10-31 13:56:44 +0200275 if hasattr(curses, 'typeahead'):
276 curses.typeahead(sys.__stdin__.fileno())
Zachary Warebaf45c52014-10-17 13:59:18 -0500277 curses.unctrl('a')
278 curses.ungetch('a')
Serhiy Storchakabaac01e2017-10-31 13:56:44 +0200279 if hasattr(curses, 'use_env'):
280 curses.use_env(1)
Zachary Warebaf45c52014-10-17 13:59:18 -0500281
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300282 # Functions only available on a few platforms
283 def test_colors_funcs(self):
284 if not curses.has_colors():
Xavier de Gaye645bc802017-01-06 09:50:27 +0100285 self.skipTest('requires colors support')
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300286 curses.start_color()
287 curses.init_pair(2, 1,1)
288 curses.color_content(1)
289 curses.color_pair(2)
290 curses.pair_content(curses.COLOR_PAIRS - 1)
291 curses.pair_number(0)
Zachary Warebaf45c52014-10-17 13:59:18 -0500292
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300293 if hasattr(curses, 'use_default_colors'):
294 curses.use_default_colors()
Zachary Warebaf45c52014-10-17 13:59:18 -0500295
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300296 @requires_curses_func('keyname')
297 def test_keyname(self):
298 curses.keyname(13)
Zachary Warebaf45c52014-10-17 13:59:18 -0500299
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300300 @requires_curses_func('has_key')
301 def test_has_key(self):
302 curses.has_key(13)
Zachary Warebaf45c52014-10-17 13:59:18 -0500303
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300304 @requires_curses_func('getmouse')
305 def test_getmouse(self):
306 (availmask, oldmask) = curses.mousemask(curses.BUTTON1_PRESSED)
307 if availmask == 0:
Xavier de Gaye645bc802017-01-06 09:50:27 +0100308 self.skipTest('mouse stuff not available')
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300309 curses.mouseinterval(10)
310 # just verify these don't cause errors
311 curses.ungetmouse(0, 0, 0, 0, curses.BUTTON1_PRESSED)
312 m = curses.getmouse()
Zachary Warebaf45c52014-10-17 13:59:18 -0500313
Serhiy Storchakabaac01e2017-10-31 13:56:44 +0200314 @requires_curses_func('panel')
Zachary Warebaf45c52014-10-17 13:59:18 -0500315 def test_userptr_without_set(self):
316 w = curses.newwin(10, 10)
317 p = curses.panel.new_panel(w)
318 # try to access userptr() before calling set_userptr() -- segfaults
319 with self.assertRaises(curses.panel.error,
320 msg='userptr should fail since not set'):
321 p.userptr()
322
Serhiy Storchakabaac01e2017-10-31 13:56:44 +0200323 @requires_curses_func('panel')
Zachary Warebaf45c52014-10-17 13:59:18 -0500324 def test_userptr_memory_leak(self):
325 w = curses.newwin(10, 10)
326 p = curses.panel.new_panel(w)
327 obj = object()
328 nrefs = sys.getrefcount(obj)
329 for i in range(100):
330 p.set_userptr(obj)
331
332 p.set_userptr(None)
333 self.assertEqual(sys.getrefcount(obj), nrefs,
334 "set_userptr leaked references")
335
Serhiy Storchakabaac01e2017-10-31 13:56:44 +0200336 @requires_curses_func('panel')
Zachary Warebaf45c52014-10-17 13:59:18 -0500337 def test_userptr_segfault(self):
Serhiy Storchakaa7723d82017-11-03 20:29:33 +0200338 w = curses.newwin(10, 10)
339 panel = curses.panel.new_panel(w)
Zachary Warebaf45c52014-10-17 13:59:18 -0500340 class A:
341 def __del__(self):
342 panel.set_userptr(None)
343 panel.set_userptr(A())
344 panel.set_userptr(None)
345
Serhiy Storchakabaac01e2017-10-31 13:56:44 +0200346 @requires_curses_func('panel')
Serhiy Storchakae3f1b092016-05-08 20:46:22 +0300347 def test_new_curses_panel(self):
Serhiy Storchakaa7723d82017-11-03 20:29:33 +0200348 w = curses.newwin(10, 10)
349 panel = curses.panel.new_panel(w)
Serhiy Storchakae3f1b092016-05-08 20:46:22 +0300350 self.assertRaises(TypeError, type(panel))
351
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300352 @requires_curses_func('is_term_resized')
353 def test_is_term_resized(self):
354 curses.is_term_resized(*self.stdscr.getmaxyx())
355
356 @requires_curses_func('resize_term')
Zachary Warebaf45c52014-10-17 13:59:18 -0500357 def test_resize_term(self):
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300358 curses.resize_term(*self.stdscr.getmaxyx())
359
360 @requires_curses_func('resizeterm')
361 def test_resizeterm(self):
362 stdscr = self.stdscr
Zachary Warebaf45c52014-10-17 13:59:18 -0500363 lines, cols = curses.LINES, curses.COLS
364 new_lines = lines - 1
365 new_cols = cols + 1
366 curses.resizeterm(new_lines, new_cols)
367
368 self.assertEqual(curses.LINES, new_lines)
369 self.assertEqual(curses.COLS, new_cols)
370
371 def test_issue6243(self):
372 curses.ungetch(1025)
373 self.stdscr.getkey()
374
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300375 @requires_curses_func('unget_wch')
Serhiy Storchakab232df92018-10-30 13:22:42 +0200376 @unittest.skipIf(getattr(curses, 'ncurses_version', (99,)) < (5, 8),
377 "unget_wch is broken in ncurses 5.7 and earlier")
Zachary Warebaf45c52014-10-17 13:59:18 -0500378 def test_unget_wch(self):
379 stdscr = self.stdscr
380 encoding = stdscr.encoding
381 for ch in ('a', '\xe9', '\u20ac', '\U0010FFFF'):
382 try:
383 ch.encode(encoding)
384 except UnicodeEncodeError:
385 continue
386 try:
387 curses.unget_wch(ch)
388 except Exception as err:
389 self.fail("unget_wch(%a) failed with encoding %s: %s"
390 % (ch, stdscr.encoding, err))
391 read = stdscr.get_wch()
392 self.assertEqual(read, ch)
393
394 code = ord(ch)
395 curses.unget_wch(code)
396 read = stdscr.get_wch()
397 self.assertEqual(read, ch)
398
399 def test_issue10570(self):
400 b = curses.tparm(curses.tigetstr("cup"), 5, 3)
401 self.assertIs(type(b), bytes)
Zachary Warebaf45c52014-10-17 13:59:18 -0500402
403 def test_encoding(self):
404 stdscr = self.stdscr
405 import codecs
406 encoding = stdscr.encoding
407 codecs.lookup(encoding)
Zachary Warebaf45c52014-10-17 13:59:18 -0500408 with self.assertRaises(TypeError):
409 stdscr.encoding = 10
Zachary Warebaf45c52014-10-17 13:59:18 -0500410 stdscr.encoding = encoding
411 with self.assertRaises(TypeError):
412 del stdscr.encoding
413
414 def test_issue21088(self):
415 stdscr = self.stdscr
416 #
417 # http://bugs.python.org/issue21088
418 #
419 # the bug:
420 # when converting curses.window.addch to Argument Clinic
421 # the first two parameters were switched.
422
423 # if someday we can represent the signature of addch
424 # we will need to rewrite this test.
425 try:
426 signature = inspect.signature(stdscr.addch)
427 self.assertFalse(signature)
428 except ValueError:
429 # not generating a signature is fine.
430 pass
431
432 # So. No signature for addch.
433 # But Argument Clinic gave us a human-readable equivalent
434 # as the first line of the docstring. So we parse that,
435 # and ensure that the parameters appear in the correct order.
436 # Since this is parsing output from Argument Clinic, we can
437 # be reasonably certain the generated parsing code will be
438 # correct too.
439 human_readable_signature = stdscr.addch.__doc__.split("\n")[0]
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300440 self.assertIn("[y, x,]", human_readable_signature)
441
Serhiy Storchakabdf9e0e2016-12-28 10:16:06 +0200442 def test_issue13051(self):
443 stdscr = self.stdscr
Serhiy Storchaka894ebd02017-11-01 14:34:20 +0200444 if not hasattr(stdscr, 'resize'):
445 raise unittest.SkipTest('requires curses.window.resize')
Serhiy Storchakabdf9e0e2016-12-28 10:16:06 +0200446 box = curses.textpad.Textbox(stdscr, insert_mode=True)
447 lines, cols = stdscr.getmaxyx()
448 stdscr.resize(lines-2, cols-2)
449 # this may cause infinite recursion, leading to a RuntimeError
450 box._insert_printable_char('a')
451
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300452
453class MiscTests(unittest.TestCase):
Zachary Warebaf45c52014-10-17 13:59:18 -0500454
Berker Peksag53926f12016-08-19 17:59:01 +0300455 @requires_curses_func('update_lines_cols')
Steve Dowerd2bc3892015-04-15 18:06:05 -0400456 def test_update_lines_cols(self):
457 # this doesn't actually test that LINES and COLS are updated,
458 # because we can't automate changing them. See Issue #4254 for
459 # a manual test script. We can only test that the function
460 # can be called.
461 curses.update_lines_cols()
462
Serhiy Storchakab232df92018-10-30 13:22:42 +0200463 @requires_curses_func('ncurses_version')
464 def test_ncurses_version(self):
465 v = curses.ncurses_version
466 self.assertIsInstance(v[:], tuple)
467 self.assertEqual(len(v), 3)
468 self.assertIsInstance(v[0], int)
469 self.assertIsInstance(v[1], int)
470 self.assertIsInstance(v[2], int)
471 self.assertIsInstance(v.major, int)
472 self.assertIsInstance(v.minor, int)
473 self.assertIsInstance(v.patch, int)
474 self.assertEqual(v[0], v.major)
475 self.assertEqual(v[1], v.minor)
476 self.assertEqual(v[2], v.patch)
477 self.assertGreaterEqual(v.major, 0)
478 self.assertGreaterEqual(v.minor, 0)
479 self.assertGreaterEqual(v.patch, 0)
Alexandre Vassalotti5ff02352009-07-22 21:27:53 +0000480
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300481class TestAscii(unittest.TestCase):
482
Serhiy Storchaka514f9732016-06-18 22:08:11 +0300483 def test_controlnames(self):
484 for name in curses.ascii.controlnames:
485 self.assertTrue(hasattr(curses.ascii, name), name)
486
487 def test_ctypes(self):
488 def check(func, expected):
489 with self.subTest(ch=c, func=func):
490 self.assertEqual(func(i), expected)
491 self.assertEqual(func(c), expected)
492
493 for i in range(256):
494 c = chr(i)
495 b = bytes([i])
496 check(curses.ascii.isalnum, b.isalnum())
497 check(curses.ascii.isalpha, b.isalpha())
498 check(curses.ascii.isdigit, b.isdigit())
499 check(curses.ascii.islower, b.islower())
500 check(curses.ascii.isspace, b.isspace())
501 check(curses.ascii.isupper, b.isupper())
502
503 check(curses.ascii.isascii, i < 128)
504 check(curses.ascii.ismeta, i >= 128)
505 check(curses.ascii.isctrl, i < 32)
506 check(curses.ascii.iscntrl, i < 32 or i == 127)
507 check(curses.ascii.isblank, c in ' \t')
508 check(curses.ascii.isgraph, 32 < i <= 126)
509 check(curses.ascii.isprint, 32 <= i <= 126)
510 check(curses.ascii.ispunct, c in string.punctuation)
511 check(curses.ascii.isxdigit, c in string.hexdigits)
512
Serhiy Storchaka283de2b2016-12-28 10:04:27 +0200513 for i in (-2, -1, 256, sys.maxunicode, sys.maxunicode+1):
514 self.assertFalse(curses.ascii.isalnum(i))
515 self.assertFalse(curses.ascii.isalpha(i))
516 self.assertFalse(curses.ascii.isdigit(i))
517 self.assertFalse(curses.ascii.islower(i))
518 self.assertFalse(curses.ascii.isspace(i))
519 self.assertFalse(curses.ascii.isupper(i))
520
521 self.assertFalse(curses.ascii.isascii(i))
522 self.assertFalse(curses.ascii.isctrl(i))
523 self.assertFalse(curses.ascii.iscntrl(i))
524 self.assertFalse(curses.ascii.isblank(i))
525 self.assertFalse(curses.ascii.isgraph(i))
526 self.assertFalse(curses.ascii.isprint(i))
527 self.assertFalse(curses.ascii.ispunct(i))
528 self.assertFalse(curses.ascii.isxdigit(i))
529
530 self.assertFalse(curses.ascii.ismeta(-1))
531
Serhiy Storchaka514f9732016-06-18 22:08:11 +0300532 def test_ascii(self):
533 ascii = curses.ascii.ascii
534 self.assertEqual(ascii('\xc1'), 'A')
535 self.assertEqual(ascii('A'), 'A')
536 self.assertEqual(ascii(ord('\xc1')), ord('A'))
537
538 def test_ctrl(self):
539 ctrl = curses.ascii.ctrl
540 self.assertEqual(ctrl('J'), '\n')
541 self.assertEqual(ctrl('\n'), '\n')
542 self.assertEqual(ctrl('@'), '\0')
543 self.assertEqual(ctrl(ord('J')), ord('\n'))
544
545 def test_alt(self):
546 alt = curses.ascii.alt
547 self.assertEqual(alt('\n'), '\x8a')
548 self.assertEqual(alt('A'), '\xc1')
549 self.assertEqual(alt(ord('A')), 0xc1)
550
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300551 def test_unctrl(self):
552 unctrl = curses.ascii.unctrl
553 self.assertEqual(unctrl('a'), 'a')
554 self.assertEqual(unctrl('A'), 'A')
555 self.assertEqual(unctrl(';'), ';')
556 self.assertEqual(unctrl(' '), ' ')
557 self.assertEqual(unctrl('\x7f'), '^?')
558 self.assertEqual(unctrl('\n'), '^J')
559 self.assertEqual(unctrl('\0'), '^@')
Serhiy Storchaka514f9732016-06-18 22:08:11 +0300560 self.assertEqual(unctrl(ord('A')), 'A')
561 self.assertEqual(unctrl(ord('\n')), '^J')
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300562 # Meta-bit characters
563 self.assertEqual(unctrl('\x8a'), '!^J')
564 self.assertEqual(unctrl('\xc1'), '!A')
Serhiy Storchaka514f9732016-06-18 22:08:11 +0300565 self.assertEqual(unctrl(ord('\x8a')), '!^J')
566 self.assertEqual(unctrl(ord('\xc1')), '!A')
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300567
568
Alexandre Vassalotti5ff02352009-07-22 21:27:53 +0000569if __name__ == '__main__':
Zachary Warebaf45c52014-10-17 13:59:18 -0500570 unittest.main()