blob: cabc10da8365c3f19811f1e07b5d75d50221777c [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,
Hans Petter Janssonda4e09f2020-08-03 22:51:33 -0500235 curses.termname, curses.erasechar,
236 curses.has_extended_color_support]:
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300237 with self.subTest(func=func.__qualname__):
238 func()
Serhiy Storchakabaac01e2017-10-31 13:56:44 +0200239 if hasattr(curses, 'filter'):
240 curses.filter()
241 if hasattr(curses, 'getsyx'):
242 curses.getsyx()
Zachary Warebaf45c52014-10-17 13:59:18 -0500243
244 # Functions that actually need arguments
245 if curses.tigetstr("cnorm"):
246 curses.curs_set(1)
247 curses.delay_output(1)
248 curses.echo() ; curses.echo(1)
249
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300250 with tempfile.TemporaryFile() as f:
251 self.stdscr.putwin(f)
252 f.seek(0)
253 curses.getwin(f)
Zachary Warebaf45c52014-10-17 13:59:18 -0500254
255 curses.halfdelay(1)
256 curses.intrflush(1)
257 curses.meta(1)
258 curses.napms(100)
259 curses.newpad(50,50)
260 win = curses.newwin(5,5)
261 win = curses.newwin(5,5, 1,1)
262 curses.nl() ; curses.nl(1)
263 curses.putp(b'abc')
264 curses.qiflush()
265 curses.raw() ; curses.raw(1)
Anthony Sottileb32cb972019-10-31 02:13:48 -0700266 curses.set_escdelay(25)
267 self.assertEqual(curses.get_escdelay(), 25)
268 curses.set_tabsize(4)
269 self.assertEqual(curses.get_tabsize(), 4)
Serhiy Storchakabaac01e2017-10-31 13:56:44 +0200270 if hasattr(curses, 'setsyx'):
271 curses.setsyx(5,5)
Zachary Warebaf45c52014-10-17 13:59:18 -0500272 curses.tigetflag('hc')
273 curses.tigetnum('co')
274 curses.tigetstr('cr')
275 curses.tparm(b'cr')
Serhiy Storchakabaac01e2017-10-31 13:56:44 +0200276 if hasattr(curses, 'typeahead'):
277 curses.typeahead(sys.__stdin__.fileno())
Zachary Warebaf45c52014-10-17 13:59:18 -0500278 curses.unctrl('a')
279 curses.ungetch('a')
Serhiy Storchakabaac01e2017-10-31 13:56:44 +0200280 if hasattr(curses, 'use_env'):
281 curses.use_env(1)
Zachary Warebaf45c52014-10-17 13:59:18 -0500282
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300283 # Functions only available on a few platforms
284 def test_colors_funcs(self):
285 if not curses.has_colors():
Xavier de Gaye645bc802017-01-06 09:50:27 +0100286 self.skipTest('requires colors support')
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300287 curses.start_color()
288 curses.init_pair(2, 1,1)
289 curses.color_content(1)
290 curses.color_pair(2)
291 curses.pair_content(curses.COLOR_PAIRS - 1)
292 curses.pair_number(0)
Zachary Warebaf45c52014-10-17 13:59:18 -0500293
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300294 if hasattr(curses, 'use_default_colors'):
295 curses.use_default_colors()
Zachary Warebaf45c52014-10-17 13:59:18 -0500296
Hans Petter Janssonda4e09f2020-08-03 22:51:33 -0500297 self.assertRaises(ValueError, curses.color_content, -1)
298 self.assertRaises(ValueError, curses.color_content, curses.COLORS + 1)
299 self.assertRaises(ValueError, curses.color_content, -2**31 - 1)
300 self.assertRaises(ValueError, curses.color_content, 2**31)
301 self.assertRaises(ValueError, curses.color_content, -2**63 - 1)
302 self.assertRaises(ValueError, curses.color_content, 2**63 - 1)
303 self.assertRaises(ValueError, curses.pair_content, -1)
304 self.assertRaises(ValueError, curses.pair_content, curses.COLOR_PAIRS)
305 self.assertRaises(ValueError, curses.pair_content, -2**31 - 1)
306 self.assertRaises(ValueError, curses.pair_content, 2**31)
307 self.assertRaises(ValueError, curses.pair_content, -2**63 - 1)
308 self.assertRaises(ValueError, curses.pair_content, 2**63 - 1)
309
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300310 @requires_curses_func('keyname')
311 def test_keyname(self):
312 curses.keyname(13)
Zachary Warebaf45c52014-10-17 13:59:18 -0500313
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300314 @requires_curses_func('has_key')
315 def test_has_key(self):
316 curses.has_key(13)
Zachary Warebaf45c52014-10-17 13:59:18 -0500317
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300318 @requires_curses_func('getmouse')
319 def test_getmouse(self):
320 (availmask, oldmask) = curses.mousemask(curses.BUTTON1_PRESSED)
321 if availmask == 0:
Xavier de Gaye645bc802017-01-06 09:50:27 +0100322 self.skipTest('mouse stuff not available')
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300323 curses.mouseinterval(10)
324 # just verify these don't cause errors
325 curses.ungetmouse(0, 0, 0, 0, curses.BUTTON1_PRESSED)
326 m = curses.getmouse()
Zachary Warebaf45c52014-10-17 13:59:18 -0500327
Serhiy Storchakabaac01e2017-10-31 13:56:44 +0200328 @requires_curses_func('panel')
Zachary Warebaf45c52014-10-17 13:59:18 -0500329 def test_userptr_without_set(self):
330 w = curses.newwin(10, 10)
331 p = curses.panel.new_panel(w)
332 # try to access userptr() before calling set_userptr() -- segfaults
333 with self.assertRaises(curses.panel.error,
334 msg='userptr should fail since not set'):
335 p.userptr()
336
Serhiy Storchakabaac01e2017-10-31 13:56:44 +0200337 @requires_curses_func('panel')
Zachary Warebaf45c52014-10-17 13:59:18 -0500338 def test_userptr_memory_leak(self):
339 w = curses.newwin(10, 10)
340 p = curses.panel.new_panel(w)
341 obj = object()
342 nrefs = sys.getrefcount(obj)
343 for i in range(100):
344 p.set_userptr(obj)
345
346 p.set_userptr(None)
347 self.assertEqual(sys.getrefcount(obj), nrefs,
348 "set_userptr leaked references")
349
Serhiy Storchakabaac01e2017-10-31 13:56:44 +0200350 @requires_curses_func('panel')
Zachary Warebaf45c52014-10-17 13:59:18 -0500351 def test_userptr_segfault(self):
Serhiy Storchakaa7723d82017-11-03 20:29:33 +0200352 w = curses.newwin(10, 10)
353 panel = curses.panel.new_panel(w)
Zachary Warebaf45c52014-10-17 13:59:18 -0500354 class A:
355 def __del__(self):
356 panel.set_userptr(None)
357 panel.set_userptr(A())
358 panel.set_userptr(None)
359
Serhiy Storchakabaac01e2017-10-31 13:56:44 +0200360 @requires_curses_func('panel')
Serhiy Storchakae3f1b092016-05-08 20:46:22 +0300361 def test_new_curses_panel(self):
Serhiy Storchakaa7723d82017-11-03 20:29:33 +0200362 w = curses.newwin(10, 10)
363 panel = curses.panel.new_panel(w)
Serhiy Storchakae3f1b092016-05-08 20:46:22 +0300364 self.assertRaises(TypeError, type(panel))
365
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300366 @requires_curses_func('is_term_resized')
367 def test_is_term_resized(self):
368 curses.is_term_resized(*self.stdscr.getmaxyx())
369
370 @requires_curses_func('resize_term')
Zachary Warebaf45c52014-10-17 13:59:18 -0500371 def test_resize_term(self):
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300372 curses.resize_term(*self.stdscr.getmaxyx())
373
374 @requires_curses_func('resizeterm')
375 def test_resizeterm(self):
376 stdscr = self.stdscr
Zachary Warebaf45c52014-10-17 13:59:18 -0500377 lines, cols = curses.LINES, curses.COLS
378 new_lines = lines - 1
379 new_cols = cols + 1
380 curses.resizeterm(new_lines, new_cols)
381
382 self.assertEqual(curses.LINES, new_lines)
383 self.assertEqual(curses.COLS, new_cols)
384
385 def test_issue6243(self):
386 curses.ungetch(1025)
387 self.stdscr.getkey()
388
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300389 @requires_curses_func('unget_wch')
Serhiy Storchakab232df92018-10-30 13:22:42 +0200390 @unittest.skipIf(getattr(curses, 'ncurses_version', (99,)) < (5, 8),
391 "unget_wch is broken in ncurses 5.7 and earlier")
Zachary Warebaf45c52014-10-17 13:59:18 -0500392 def test_unget_wch(self):
393 stdscr = self.stdscr
394 encoding = stdscr.encoding
395 for ch in ('a', '\xe9', '\u20ac', '\U0010FFFF'):
396 try:
397 ch.encode(encoding)
398 except UnicodeEncodeError:
399 continue
400 try:
401 curses.unget_wch(ch)
402 except Exception as err:
403 self.fail("unget_wch(%a) failed with encoding %s: %s"
404 % (ch, stdscr.encoding, err))
405 read = stdscr.get_wch()
406 self.assertEqual(read, ch)
407
408 code = ord(ch)
409 curses.unget_wch(code)
410 read = stdscr.get_wch()
411 self.assertEqual(read, ch)
412
413 def test_issue10570(self):
414 b = curses.tparm(curses.tigetstr("cup"), 5, 3)
415 self.assertIs(type(b), bytes)
Zachary Warebaf45c52014-10-17 13:59:18 -0500416
417 def test_encoding(self):
418 stdscr = self.stdscr
419 import codecs
420 encoding = stdscr.encoding
421 codecs.lookup(encoding)
Zachary Warebaf45c52014-10-17 13:59:18 -0500422 with self.assertRaises(TypeError):
423 stdscr.encoding = 10
Zachary Warebaf45c52014-10-17 13:59:18 -0500424 stdscr.encoding = encoding
425 with self.assertRaises(TypeError):
426 del stdscr.encoding
427
428 def test_issue21088(self):
429 stdscr = self.stdscr
430 #
431 # http://bugs.python.org/issue21088
432 #
433 # the bug:
434 # when converting curses.window.addch to Argument Clinic
435 # the first two parameters were switched.
436
437 # if someday we can represent the signature of addch
438 # we will need to rewrite this test.
439 try:
440 signature = inspect.signature(stdscr.addch)
441 self.assertFalse(signature)
442 except ValueError:
443 # not generating a signature is fine.
444 pass
445
446 # So. No signature for addch.
447 # But Argument Clinic gave us a human-readable equivalent
448 # as the first line of the docstring. So we parse that,
449 # and ensure that the parameters appear in the correct order.
450 # Since this is parsing output from Argument Clinic, we can
451 # be reasonably certain the generated parsing code will be
452 # correct too.
453 human_readable_signature = stdscr.addch.__doc__.split("\n")[0]
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300454 self.assertIn("[y, x,]", human_readable_signature)
455
Serhiy Storchakabdf9e0e2016-12-28 10:16:06 +0200456 def test_issue13051(self):
457 stdscr = self.stdscr
Serhiy Storchaka894ebd02017-11-01 14:34:20 +0200458 if not hasattr(stdscr, 'resize'):
459 raise unittest.SkipTest('requires curses.window.resize')
Serhiy Storchakabdf9e0e2016-12-28 10:16:06 +0200460 box = curses.textpad.Textbox(stdscr, insert_mode=True)
461 lines, cols = stdscr.getmaxyx()
462 stdscr.resize(lines-2, cols-2)
463 # this may cause infinite recursion, leading to a RuntimeError
464 box._insert_printable_char('a')
465
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300466
467class MiscTests(unittest.TestCase):
Zachary Warebaf45c52014-10-17 13:59:18 -0500468
Berker Peksag53926f12016-08-19 17:59:01 +0300469 @requires_curses_func('update_lines_cols')
Steve Dowerd2bc3892015-04-15 18:06:05 -0400470 def test_update_lines_cols(self):
471 # this doesn't actually test that LINES and COLS are updated,
472 # because we can't automate changing them. See Issue #4254 for
473 # a manual test script. We can only test that the function
474 # can be called.
475 curses.update_lines_cols()
476
Serhiy Storchakab232df92018-10-30 13:22:42 +0200477 @requires_curses_func('ncurses_version')
478 def test_ncurses_version(self):
479 v = curses.ncurses_version
480 self.assertIsInstance(v[:], tuple)
481 self.assertEqual(len(v), 3)
482 self.assertIsInstance(v[0], int)
483 self.assertIsInstance(v[1], int)
484 self.assertIsInstance(v[2], int)
485 self.assertIsInstance(v.major, int)
486 self.assertIsInstance(v.minor, int)
487 self.assertIsInstance(v.patch, int)
488 self.assertEqual(v[0], v.major)
489 self.assertEqual(v[1], v.minor)
490 self.assertEqual(v[2], v.patch)
491 self.assertGreaterEqual(v.major, 0)
492 self.assertGreaterEqual(v.minor, 0)
493 self.assertGreaterEqual(v.patch, 0)
Alexandre Vassalotti5ff02352009-07-22 21:27:53 +0000494
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300495class TestAscii(unittest.TestCase):
496
Serhiy Storchaka514f9732016-06-18 22:08:11 +0300497 def test_controlnames(self):
498 for name in curses.ascii.controlnames:
499 self.assertTrue(hasattr(curses.ascii, name), name)
500
501 def test_ctypes(self):
502 def check(func, expected):
503 with self.subTest(ch=c, func=func):
504 self.assertEqual(func(i), expected)
505 self.assertEqual(func(c), expected)
506
507 for i in range(256):
508 c = chr(i)
509 b = bytes([i])
510 check(curses.ascii.isalnum, b.isalnum())
511 check(curses.ascii.isalpha, b.isalpha())
512 check(curses.ascii.isdigit, b.isdigit())
513 check(curses.ascii.islower, b.islower())
514 check(curses.ascii.isspace, b.isspace())
515 check(curses.ascii.isupper, b.isupper())
516
517 check(curses.ascii.isascii, i < 128)
518 check(curses.ascii.ismeta, i >= 128)
519 check(curses.ascii.isctrl, i < 32)
520 check(curses.ascii.iscntrl, i < 32 or i == 127)
521 check(curses.ascii.isblank, c in ' \t')
522 check(curses.ascii.isgraph, 32 < i <= 126)
523 check(curses.ascii.isprint, 32 <= i <= 126)
524 check(curses.ascii.ispunct, c in string.punctuation)
525 check(curses.ascii.isxdigit, c in string.hexdigits)
526
Serhiy Storchaka283de2b2016-12-28 10:04:27 +0200527 for i in (-2, -1, 256, sys.maxunicode, sys.maxunicode+1):
528 self.assertFalse(curses.ascii.isalnum(i))
529 self.assertFalse(curses.ascii.isalpha(i))
530 self.assertFalse(curses.ascii.isdigit(i))
531 self.assertFalse(curses.ascii.islower(i))
532 self.assertFalse(curses.ascii.isspace(i))
533 self.assertFalse(curses.ascii.isupper(i))
534
535 self.assertFalse(curses.ascii.isascii(i))
536 self.assertFalse(curses.ascii.isctrl(i))
537 self.assertFalse(curses.ascii.iscntrl(i))
538 self.assertFalse(curses.ascii.isblank(i))
539 self.assertFalse(curses.ascii.isgraph(i))
540 self.assertFalse(curses.ascii.isprint(i))
541 self.assertFalse(curses.ascii.ispunct(i))
542 self.assertFalse(curses.ascii.isxdigit(i))
543
544 self.assertFalse(curses.ascii.ismeta(-1))
545
Serhiy Storchaka514f9732016-06-18 22:08:11 +0300546 def test_ascii(self):
547 ascii = curses.ascii.ascii
548 self.assertEqual(ascii('\xc1'), 'A')
549 self.assertEqual(ascii('A'), 'A')
550 self.assertEqual(ascii(ord('\xc1')), ord('A'))
551
552 def test_ctrl(self):
553 ctrl = curses.ascii.ctrl
554 self.assertEqual(ctrl('J'), '\n')
555 self.assertEqual(ctrl('\n'), '\n')
556 self.assertEqual(ctrl('@'), '\0')
557 self.assertEqual(ctrl(ord('J')), ord('\n'))
558
559 def test_alt(self):
560 alt = curses.ascii.alt
561 self.assertEqual(alt('\n'), '\x8a')
562 self.assertEqual(alt('A'), '\xc1')
563 self.assertEqual(alt(ord('A')), 0xc1)
564
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300565 def test_unctrl(self):
566 unctrl = curses.ascii.unctrl
567 self.assertEqual(unctrl('a'), 'a')
568 self.assertEqual(unctrl('A'), 'A')
569 self.assertEqual(unctrl(';'), ';')
570 self.assertEqual(unctrl(' '), ' ')
571 self.assertEqual(unctrl('\x7f'), '^?')
572 self.assertEqual(unctrl('\n'), '^J')
573 self.assertEqual(unctrl('\0'), '^@')
Serhiy Storchaka514f9732016-06-18 22:08:11 +0300574 self.assertEqual(unctrl(ord('A')), 'A')
575 self.assertEqual(unctrl(ord('\n')), '^J')
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300576 # Meta-bit characters
577 self.assertEqual(unctrl('\x8a'), '!^J')
578 self.assertEqual(unctrl('\xc1'), '!A')
Serhiy Storchaka514f9732016-06-18 22:08:11 +0300579 self.assertEqual(unctrl(ord('\x8a')), '!^J')
580 self.assertEqual(unctrl(ord('\xc1')), '!A')
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300581
582
Alexandre Vassalotti5ff02352009-07-22 21:27:53 +0000583if __name__ == '__main__':
Zachary Warebaf45c52014-10-17 13:59:18 -0500584 unittest.main()