blob: 8411cdb0f25346853297116a6b5380406c633ea1 [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
13import sys
14import tempfile
15import unittest
16
17from test.support import requires, import_module, verbose
Andrew M. Kuchling2158df02001-10-22 15:26:09 +000018
19# Optionally test curses module. This currently requires that the
20# 'curses' resource be given on the regrtest command line using the -u
21# option. If not available, nothing after this line will be executed.
Larry Hastings9147a962014-05-04 04:41:18 -070022import inspect
Neal Norwitz9f39f682006-01-06 04:18:21 +000023requires('curses')
24
R. David Murraya21e4ca2009-03-31 23:16:50 +000025# If either of these don't exist, skip the tests.
26curses = import_module('curses')
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +030027import_module('curses.panel')
28import_module('curses.ascii')
R. David Murraya21e4ca2009-03-31 23:16:50 +000029
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +030030def requires_curses_func(name):
31 return unittest.skipUnless(hasattr(curses, name),
32 'requires curses.%s' % name)
Mark Dickinson945e2422010-02-21 13:42:03 +000033
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +030034term = os.environ.get('TERM')
35
36# If newterm was supported we could use it instead of initscr and not exit
37@unittest.skipIf(not term or term == 'unknown',
Zachary Warebaf45c52014-10-17 13:59:18 -050038 "$TERM=%r, calling initscr() may cause exit" % term)
39@unittest.skipIf(sys.platform == "cygwin",
40 "cygwin's curses mostly just hangs")
41class TestCurses(unittest.TestCase):
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +030042
Zachary Warebaf45c52014-10-17 13:59:18 -050043 @classmethod
44 def setUpClass(cls):
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +030045 if not sys.__stdout__.isatty():
Serhiy Storchaka53a00352016-05-22 18:16:20 +030046 # Temporary skip tests on non-tty
Serhiy Storchaka0a91e432016-05-22 18:23:36 +030047 raise unittest.SkipTest('sys.__stdout__ is not a tty')
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +030048 cls.tmp = tempfile.TemporaryFile()
49 fd = cls.tmp.fileno()
50 else:
51 cls.tmp = None
52 fd = sys.__stdout__.fileno()
53 # testing setupterm() inside initscr/endwin
54 # causes terminal breakage
55 curses.setupterm(fd=fd)
56
57 @classmethod
58 def tearDownClass(cls):
59 if cls.tmp:
60 cls.tmp.close()
61 del cls.tmp
Andrew M. Kuchling2158df02001-10-22 15:26:09 +000062
Zachary Warebaf45c52014-10-17 13:59:18 -050063 def setUp(self):
64 if verbose:
65 # just to make the test output a little more readable
66 print()
67 self.stdscr = curses.initscr()
68 curses.savetty()
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000069
Zachary Warebaf45c52014-10-17 13:59:18 -050070 def tearDown(self):
Andrew M. Kuchling2158df02001-10-22 15:26:09 +000071 curses.resetty()
Andrew M. Kuchling2158df02001-10-22 15:26:09 +000072 curses.endwin()
Zachary Warebaf45c52014-10-17 13:59:18 -050073
74 def test_window_funcs(self):
75 "Test the methods of windows"
76 stdscr = self.stdscr
77 win = curses.newwin(10,10)
78 win = curses.newwin(5,5, 5,5)
79 win2 = curses.newwin(15,15, 5,5)
80
81 for meth in [stdscr.addch, stdscr.addstr]:
82 for args in [('a'), ('a', curses.A_BOLD),
83 (4,4, 'a'), (5,5, 'a', curses.A_BOLD)]:
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +030084 with self.subTest(meth=meth.__qualname__, args=args):
85 meth(*args)
Zachary Warebaf45c52014-10-17 13:59:18 -050086
87 for meth in [stdscr.box, stdscr.clear, stdscr.clrtobot,
88 stdscr.clrtoeol, stdscr.cursyncup, stdscr.delch,
89 stdscr.deleteln, stdscr.erase, stdscr.getbegyx,
90 stdscr.getbkgd, stdscr.getkey, stdscr.getmaxyx,
91 stdscr.getparyx, stdscr.getyx, stdscr.inch,
92 stdscr.insertln, stdscr.instr, stdscr.is_wintouched,
93 win.noutrefresh, stdscr.redrawwin, stdscr.refresh,
94 stdscr.standout, stdscr.standend, stdscr.syncdown,
95 stdscr.syncup, stdscr.touchwin, stdscr.untouchwin]:
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +030096 with self.subTest(meth=meth.__qualname__):
97 meth()
Zachary Warebaf45c52014-10-17 13:59:18 -050098
99 stdscr.addnstr('1234', 3)
100 stdscr.addnstr('1234', 3, curses.A_BOLD)
101 stdscr.addnstr(4,4, '1234', 3)
102 stdscr.addnstr(5,5, '1234', 3, curses.A_BOLD)
103
104 stdscr.attron(curses.A_BOLD)
105 stdscr.attroff(curses.A_BOLD)
106 stdscr.attrset(curses.A_BOLD)
107 stdscr.bkgd(' ')
108 stdscr.bkgd(' ', curses.A_REVERSE)
109 stdscr.bkgdset(' ')
110 stdscr.bkgdset(' ', curses.A_REVERSE)
111
112 win.border(65, 66, 67, 68,
113 69, 70, 71, 72)
114 win.border('|', '!', '-', '_',
115 '+', '\\', '#', '/')
116 with self.assertRaises(TypeError,
117 msg="Expected win.border() to raise TypeError"):
118 win.border(65, 66, 67, 68,
119 69, [], 71, 72)
120
121 stdscr.clearok(1)
122
123 win4 = stdscr.derwin(2,2)
124 win4 = stdscr.derwin(1,1, 5,5)
125 win4.mvderwin(9,9)
126
127 stdscr.echochar('a')
128 stdscr.echochar('a', curses.A_BOLD)
129 stdscr.hline('-', 5)
130 stdscr.hline('-', 5, curses.A_BOLD)
131 stdscr.hline(1,1,'-', 5)
132 stdscr.hline(1,1,'-', 5, curses.A_BOLD)
133
134 stdscr.idcok(1)
135 stdscr.idlok(1)
136 stdscr.immedok(1)
137 stdscr.insch('c')
138 stdscr.insdelln(1)
139 stdscr.insnstr('abc', 3)
140 stdscr.insnstr('abc', 3, curses.A_BOLD)
141 stdscr.insnstr(5, 5, 'abc', 3)
142 stdscr.insnstr(5, 5, 'abc', 3, curses.A_BOLD)
143
144 stdscr.insstr('def')
145 stdscr.insstr('def', curses.A_BOLD)
146 stdscr.insstr(5, 5, 'def')
147 stdscr.insstr(5, 5, 'def', curses.A_BOLD)
148 stdscr.is_linetouched(0)
149 stdscr.keypad(1)
150 stdscr.leaveok(1)
151 stdscr.move(3,3)
152 win.mvwin(2,2)
153 stdscr.nodelay(1)
154 stdscr.notimeout(1)
155 win2.overlay(win)
156 win2.overwrite(win)
157 win2.overlay(win, 1, 2, 2, 1, 3, 3)
158 win2.overwrite(win, 1, 2, 2, 1, 3, 3)
159 stdscr.redrawln(1,2)
160
161 stdscr.scrollok(1)
162 stdscr.scroll()
163 stdscr.scroll(2)
164 stdscr.scroll(-3)
165
166 stdscr.move(12, 2)
167 stdscr.setscrreg(10,15)
168 win3 = stdscr.subwin(10,10)
169 win3 = stdscr.subwin(10,10, 5,5)
170 stdscr.syncok(1)
171 stdscr.timeout(5)
172 stdscr.touchline(5,5)
173 stdscr.touchline(5,5,0)
174 stdscr.vline('a', 3)
175 stdscr.vline('a', 3, curses.A_STANDOUT)
176 stdscr.chgat(5, 2, 3, curses.A_BLINK)
177 stdscr.chgat(3, curses.A_BOLD)
178 stdscr.chgat(5, 8, curses.A_UNDERLINE)
179 stdscr.chgat(curses.A_BLINK)
180 stdscr.refresh()
181
182 stdscr.vline(1,1, 'a', 3)
183 stdscr.vline(1,1, 'a', 3, curses.A_STANDOUT)
184
185 if hasattr(curses, 'resize'):
186 stdscr.resize()
187 if hasattr(curses, 'enclose'):
188 stdscr.enclose()
189
190
191 def test_module_funcs(self):
192 "Test module-level functions"
Zachary Warebaf45c52014-10-17 13:59:18 -0500193 for func in [curses.baudrate, curses.beep, curses.can_change_color,
194 curses.cbreak, curses.def_prog_mode, curses.doupdate,
195 curses.filter, curses.flash, curses.flushinp,
196 curses.has_colors, curses.has_ic, curses.has_il,
197 curses.isendwin, curses.killchar, curses.longname,
198 curses.nocbreak, curses.noecho, curses.nonl,
199 curses.noqiflush, curses.noraw,
200 curses.reset_prog_mode, curses.termattrs,
201 curses.termname, curses.erasechar, curses.getsyx]:
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300202 with self.subTest(func=func.__qualname__):
203 func()
Zachary Warebaf45c52014-10-17 13:59:18 -0500204
205 # Functions that actually need arguments
206 if curses.tigetstr("cnorm"):
207 curses.curs_set(1)
208 curses.delay_output(1)
209 curses.echo() ; curses.echo(1)
210
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300211 with tempfile.TemporaryFile() as f:
212 self.stdscr.putwin(f)
213 f.seek(0)
214 curses.getwin(f)
Zachary Warebaf45c52014-10-17 13:59:18 -0500215
216 curses.halfdelay(1)
217 curses.intrflush(1)
218 curses.meta(1)
219 curses.napms(100)
220 curses.newpad(50,50)
221 win = curses.newwin(5,5)
222 win = curses.newwin(5,5, 1,1)
223 curses.nl() ; curses.nl(1)
224 curses.putp(b'abc')
225 curses.qiflush()
226 curses.raw() ; curses.raw(1)
227 curses.setsyx(5,5)
228 curses.tigetflag('hc')
229 curses.tigetnum('co')
230 curses.tigetstr('cr')
231 curses.tparm(b'cr')
232 curses.typeahead(sys.__stdin__.fileno())
233 curses.unctrl('a')
234 curses.ungetch('a')
235 curses.use_env(1)
236
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300237 # Functions only available on a few platforms
238 def test_colors_funcs(self):
239 if not curses.has_colors():
240 self.skip('requires colors support')
241 curses.start_color()
242 curses.init_pair(2, 1,1)
243 curses.color_content(1)
244 curses.color_pair(2)
245 curses.pair_content(curses.COLOR_PAIRS - 1)
246 curses.pair_number(0)
Zachary Warebaf45c52014-10-17 13:59:18 -0500247
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300248 if hasattr(curses, 'use_default_colors'):
249 curses.use_default_colors()
Zachary Warebaf45c52014-10-17 13:59:18 -0500250
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300251 @requires_curses_func('keyname')
252 def test_keyname(self):
253 curses.keyname(13)
Zachary Warebaf45c52014-10-17 13:59:18 -0500254
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300255 @requires_curses_func('has_key')
256 def test_has_key(self):
257 curses.has_key(13)
Zachary Warebaf45c52014-10-17 13:59:18 -0500258
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300259 @requires_curses_func('getmouse')
260 def test_getmouse(self):
261 (availmask, oldmask) = curses.mousemask(curses.BUTTON1_PRESSED)
262 if availmask == 0:
263 self.skip('mouse stuff not available')
264 curses.mouseinterval(10)
265 # just verify these don't cause errors
266 curses.ungetmouse(0, 0, 0, 0, curses.BUTTON1_PRESSED)
267 m = curses.getmouse()
Zachary Warebaf45c52014-10-17 13:59:18 -0500268
269 def test_userptr_without_set(self):
270 w = curses.newwin(10, 10)
271 p = curses.panel.new_panel(w)
272 # try to access userptr() before calling set_userptr() -- segfaults
273 with self.assertRaises(curses.panel.error,
274 msg='userptr should fail since not set'):
275 p.userptr()
276
277 def test_userptr_memory_leak(self):
278 w = curses.newwin(10, 10)
279 p = curses.panel.new_panel(w)
280 obj = object()
281 nrefs = sys.getrefcount(obj)
282 for i in range(100):
283 p.set_userptr(obj)
284
285 p.set_userptr(None)
286 self.assertEqual(sys.getrefcount(obj), nrefs,
287 "set_userptr leaked references")
288
289 def test_userptr_segfault(self):
290 panel = curses.panel.new_panel(self.stdscr)
291 class A:
292 def __del__(self):
293 panel.set_userptr(None)
294 panel.set_userptr(A())
295 panel.set_userptr(None)
296
Serhiy Storchakae3f1b092016-05-08 20:46:22 +0300297 def test_new_curses_panel(self):
298 panel = curses.panel.new_panel(self.stdscr)
299 self.assertRaises(TypeError, type(panel))
300
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300301 @requires_curses_func('is_term_resized')
302 def test_is_term_resized(self):
303 curses.is_term_resized(*self.stdscr.getmaxyx())
304
305 @requires_curses_func('resize_term')
Zachary Warebaf45c52014-10-17 13:59:18 -0500306 def test_resize_term(self):
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300307 curses.resize_term(*self.stdscr.getmaxyx())
308
309 @requires_curses_func('resizeterm')
310 def test_resizeterm(self):
311 stdscr = self.stdscr
Zachary Warebaf45c52014-10-17 13:59:18 -0500312 lines, cols = curses.LINES, curses.COLS
313 new_lines = lines - 1
314 new_cols = cols + 1
315 curses.resizeterm(new_lines, new_cols)
316
317 self.assertEqual(curses.LINES, new_lines)
318 self.assertEqual(curses.COLS, new_cols)
319
320 def test_issue6243(self):
321 curses.ungetch(1025)
322 self.stdscr.getkey()
323
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300324 @requires_curses_func('unget_wch')
Zachary Warebaf45c52014-10-17 13:59:18 -0500325 def test_unget_wch(self):
326 stdscr = self.stdscr
327 encoding = stdscr.encoding
328 for ch in ('a', '\xe9', '\u20ac', '\U0010FFFF'):
329 try:
330 ch.encode(encoding)
331 except UnicodeEncodeError:
332 continue
333 try:
334 curses.unget_wch(ch)
335 except Exception as err:
336 self.fail("unget_wch(%a) failed with encoding %s: %s"
337 % (ch, stdscr.encoding, err))
338 read = stdscr.get_wch()
339 self.assertEqual(read, ch)
340
341 code = ord(ch)
342 curses.unget_wch(code)
343 read = stdscr.get_wch()
344 self.assertEqual(read, ch)
345
346 def test_issue10570(self):
347 b = curses.tparm(curses.tigetstr("cup"), 5, 3)
348 self.assertIs(type(b), bytes)
Zachary Warebaf45c52014-10-17 13:59:18 -0500349
350 def test_encoding(self):
351 stdscr = self.stdscr
352 import codecs
353 encoding = stdscr.encoding
354 codecs.lookup(encoding)
Zachary Warebaf45c52014-10-17 13:59:18 -0500355 with self.assertRaises(TypeError):
356 stdscr.encoding = 10
Zachary Warebaf45c52014-10-17 13:59:18 -0500357 stdscr.encoding = encoding
358 with self.assertRaises(TypeError):
359 del stdscr.encoding
360
361 def test_issue21088(self):
362 stdscr = self.stdscr
363 #
364 # http://bugs.python.org/issue21088
365 #
366 # the bug:
367 # when converting curses.window.addch to Argument Clinic
368 # the first two parameters were switched.
369
370 # if someday we can represent the signature of addch
371 # we will need to rewrite this test.
372 try:
373 signature = inspect.signature(stdscr.addch)
374 self.assertFalse(signature)
375 except ValueError:
376 # not generating a signature is fine.
377 pass
378
379 # So. No signature for addch.
380 # But Argument Clinic gave us a human-readable equivalent
381 # as the first line of the docstring. So we parse that,
382 # and ensure that the parameters appear in the correct order.
383 # Since this is parsing output from Argument Clinic, we can
384 # be reasonably certain the generated parsing code will be
385 # correct too.
386 human_readable_signature = stdscr.addch.__doc__.split("\n")[0]
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300387 self.assertIn("[y, x,]", human_readable_signature)
388
389
390class MiscTests(unittest.TestCase):
Zachary Warebaf45c52014-10-17 13:59:18 -0500391
Steve Dowerd2bc3892015-04-15 18:06:05 -0400392 def test_update_lines_cols(self):
393 # this doesn't actually test that LINES and COLS are updated,
394 # because we can't automate changing them. See Issue #4254 for
395 # a manual test script. We can only test that the function
396 # can be called.
397 curses.update_lines_cols()
398
Alexandre Vassalotti5ff02352009-07-22 21:27:53 +0000399
Serhiy Storchaka0eb39e72016-05-21 21:36:11 +0300400class TestAscii(unittest.TestCase):
401
402 def test_unctrl(self):
403 unctrl = curses.ascii.unctrl
404 self.assertEqual(unctrl('a'), 'a')
405 self.assertEqual(unctrl('A'), 'A')
406 self.assertEqual(unctrl(';'), ';')
407 self.assertEqual(unctrl(' '), ' ')
408 self.assertEqual(unctrl('\x7f'), '^?')
409 self.assertEqual(unctrl('\n'), '^J')
410 self.assertEqual(unctrl('\0'), '^@')
411 # Meta-bit characters
412 self.assertEqual(unctrl('\x8a'), '!^J')
413 self.assertEqual(unctrl('\xc1'), '!A')
414
415
Alexandre Vassalotti5ff02352009-07-22 21:27:53 +0000416if __name__ == '__main__':
Zachary Warebaf45c52014-10-17 13:59:18 -0500417 unittest.main()