1# 2# Test script for the curses module 3# 4# This script doesn't actually display anything very coherent. but it 5# does call (nearly) every method and function. 6# 7# Functions not tested: {def,reset}_{shell,prog}_mode, getch(), getstr(), 8# init_color() 9# Only called, not tested: getmouse(), ungetmouse() 10# 11 12import os 13import string 14import sys 15import tempfile 16import unittest 17 18from test.test_support import requires, import_module, verbose, run_unittest 19 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. 23requires('curses') 24 25# If either of these don't exist, skip the tests. 26curses = import_module('curses') 27import_module('curses.panel') 28import_module('curses.ascii') 29 30def requires_curses_func(name): 31 return unittest.skipUnless(hasattr(curses, name), 32 'requires curses.%s' % name) 33 34term = 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', 38 "$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): 42 43 @classmethod 44 def setUpClass(cls): 45 if not sys.__stdout__.isatty(): 46 # Temporary skip tests on non-tty 47 raise unittest.SkipTest('sys.__stdout__ is not a tty') 48 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 62 63 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() 69 70 def tearDown(self): 71 curses.resetty() 72 curses.endwin() 73 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)]: 84 meth(*args) 85 86 for meth in [stdscr.box, stdscr.clear, stdscr.clrtobot, 87 stdscr.clrtoeol, stdscr.cursyncup, stdscr.delch, 88 stdscr.deleteln, stdscr.erase, stdscr.getbegyx, 89 stdscr.getbkgd, stdscr.getkey, stdscr.getmaxyx, 90 stdscr.getparyx, stdscr.getyx, stdscr.inch, 91 stdscr.insertln, stdscr.instr, stdscr.is_wintouched, 92 win.noutrefresh, stdscr.redrawwin, stdscr.refresh, 93 stdscr.standout, stdscr.standend, stdscr.syncdown, 94 stdscr.syncup, stdscr.touchwin, stdscr.untouchwin]: 95 meth() 96 97 stdscr.addnstr('1234', 3) 98 stdscr.addnstr('1234', 3, curses.A_BOLD) 99 stdscr.addnstr(4,4, '1234', 3) 100 stdscr.addnstr(5,5, '1234', 3, curses.A_BOLD) 101 102 stdscr.attron(curses.A_BOLD) 103 stdscr.attroff(curses.A_BOLD) 104 stdscr.attrset(curses.A_BOLD) 105 stdscr.bkgd(' ') 106 stdscr.bkgd(' ', curses.A_REVERSE) 107 stdscr.bkgdset(' ') 108 stdscr.bkgdset(' ', curses.A_REVERSE) 109 110 win.border(65, 66, 67, 68, 111 69, 70, 71, 72) 112 win.border('|', '!', '-', '_', 113 '+', '\\', '#', '/') 114 with self.assertRaises(TypeError, 115 msg="Expected win.border() to raise TypeError"): 116 win.border(65, 66, 67, 68, 117 69, [], 71, 72) 118 119 stdscr.clearok(1) 120 121 win4 = stdscr.derwin(2,2) 122 win4 = stdscr.derwin(1,1, 5,5) 123 win4.mvderwin(9,9) 124 125 stdscr.echochar('a') 126 stdscr.echochar('a', curses.A_BOLD) 127 stdscr.hline('-', 5) 128 stdscr.hline('-', 5, curses.A_BOLD) 129 stdscr.hline(1,1,'-', 5) 130 stdscr.hline(1,1,'-', 5, curses.A_BOLD) 131 132 stdscr.idcok(1) 133 stdscr.idlok(1) 134 stdscr.immedok(1) 135 stdscr.insch('c') 136 stdscr.insdelln(1) 137 stdscr.insnstr('abc', 3) 138 stdscr.insnstr('abc', 3, curses.A_BOLD) 139 stdscr.insnstr(5, 5, 'abc', 3) 140 stdscr.insnstr(5, 5, 'abc', 3, curses.A_BOLD) 141 142 stdscr.insstr('def') 143 stdscr.insstr('def', curses.A_BOLD) 144 stdscr.insstr(5, 5, 'def') 145 stdscr.insstr(5, 5, 'def', curses.A_BOLD) 146 stdscr.is_linetouched(0) 147 stdscr.keypad(1) 148 stdscr.leaveok(1) 149 stdscr.move(3,3) 150 win.mvwin(2,2) 151 stdscr.nodelay(1) 152 stdscr.notimeout(1) 153 win2.overlay(win) 154 win2.overwrite(win) 155 win2.overlay(win, 1, 2, 2, 1, 3, 3) 156 win2.overwrite(win, 1, 2, 2, 1, 3, 3) 157 stdscr.redrawln(1,2) 158 159 stdscr.scrollok(1) 160 stdscr.scroll() 161 stdscr.scroll(2) 162 stdscr.scroll(-3) 163 164 stdscr.move(12, 2) 165 stdscr.setscrreg(10,15) 166 win3 = stdscr.subwin(10,10) 167 win3 = stdscr.subwin(10,10, 5,5) 168 stdscr.syncok(1) 169 stdscr.timeout(5) 170 stdscr.touchline(5,5) 171 stdscr.touchline(5,5,0) 172 stdscr.vline('a', 3) 173 stdscr.vline('a', 3, curses.A_STANDOUT) 174 stdscr.chgat(5, 2, 3, curses.A_BLINK) 175 stdscr.chgat(3, curses.A_BOLD) 176 stdscr.chgat(5, 8, curses.A_UNDERLINE) 177 stdscr.chgat(curses.A_BLINK) 178 stdscr.refresh() 179 180 stdscr.vline(1,1, 'a', 3) 181 stdscr.vline(1,1, 'a', 3, curses.A_STANDOUT) 182 183 if hasattr(curses, 'resize'): 184 stdscr.resize() 185 if hasattr(curses, 'enclose'): 186 stdscr.enclose() 187 188 self.assertRaises(ValueError, stdscr.getstr, -400) 189 self.assertRaises(ValueError, stdscr.getstr, 2, 3, -400) 190 self.assertRaises(ValueError, stdscr.instr, -2) 191 self.assertRaises(ValueError, stdscr.instr, 2, 3, -2) 192 193 194 def test_module_funcs(self): 195 "Test module-level functions" 196 for func in [curses.baudrate, curses.beep, curses.can_change_color, 197 curses.cbreak, curses.def_prog_mode, curses.doupdate, 198 curses.filter, curses.flash, curses.flushinp, 199 curses.has_colors, curses.has_ic, curses.has_il, 200 curses.isendwin, curses.killchar, curses.longname, 201 curses.nocbreak, curses.noecho, curses.nonl, 202 curses.noqiflush, curses.noraw, 203 curses.reset_prog_mode, curses.termattrs, 204 curses.termname, curses.erasechar, curses.getsyx]: 205 func() 206 207 # Functions that actually need arguments 208 if curses.tigetstr("cnorm"): 209 curses.curs_set(1) 210 curses.delay_output(1) 211 curses.echo() ; curses.echo(1) 212 213 with tempfile.TemporaryFile() as f: 214 self.stdscr.putwin(f) 215 f.seek(0) 216 curses.getwin(f) 217 218 curses.halfdelay(1) 219 curses.intrflush(1) 220 curses.meta(1) 221 curses.napms(100) 222 curses.newpad(50,50) 223 win = curses.newwin(5,5) 224 win = curses.newwin(5,5, 1,1) 225 curses.nl() ; curses.nl(1) 226 curses.putp(b'abc') 227 curses.qiflush() 228 curses.raw() ; curses.raw(1) 229 curses.setsyx(5,5) 230 curses.tigetflag('hc') 231 curses.tigetnum('co') 232 curses.tigetstr('cr') 233 curses.tparm(b'cr') 234 curses.typeahead(sys.__stdin__.fileno()) 235 curses.unctrl('a') 236 curses.ungetch('a') 237 curses.use_env(1) 238 239 # Functions only available on a few platforms 240 def test_colors_funcs(self): 241 if not curses.has_colors(): 242 self.skip('requires colors support') 243 curses.start_color() 244 curses.init_pair(2, 1,1) 245 curses.color_content(1) 246 curses.color_pair(2) 247 curses.pair_content(curses.COLOR_PAIRS - 1) 248 curses.pair_number(0) 249 250 if hasattr(curses, 'use_default_colors'): 251 curses.use_default_colors() 252 253 @requires_curses_func('keyname') 254 def test_keyname(self): 255 curses.keyname(13) 256 257 @requires_curses_func('has_key') 258 def test_has_key(self): 259 curses.has_key(13) 260 261 @requires_curses_func('getmouse') 262 def test_getmouse(self): 263 (availmask, oldmask) = curses.mousemask(curses.BUTTON1_PRESSED) 264 if availmask == 0: 265 self.skip('mouse stuff not available') 266 curses.mouseinterval(10) 267 # just verify these don't cause errors 268 curses.ungetmouse(0, 0, 0, 0, curses.BUTTON1_PRESSED) 269 m = curses.getmouse() 270 271 def test_userptr_without_set(self): 272 w = curses.newwin(10, 10) 273 p = curses.panel.new_panel(w) 274 # try to access userptr() before calling set_userptr() -- segfaults 275 with self.assertRaises(curses.panel.error, 276 msg='userptr should fail since not set'): 277 p.userptr() 278 279 def test_userptr_memory_leak(self): 280 w = curses.newwin(10, 10) 281 p = curses.panel.new_panel(w) 282 obj = object() 283 nrefs = sys.getrefcount(obj) 284 for i in range(100): 285 p.set_userptr(obj) 286 287 p.set_userptr(None) 288 self.assertEqual(sys.getrefcount(obj), nrefs, 289 "set_userptr leaked references") 290 291 def test_userptr_segfault(self): 292 panel = curses.panel.new_panel(self.stdscr) 293 class A: 294 def __del__(self): 295 panel.set_userptr(None) 296 panel.set_userptr(A()) 297 panel.set_userptr(None) 298 299 def test_new_curses_panel(self): 300 panel = curses.panel.new_panel(self.stdscr) 301 self.assertRaises(TypeError, type(panel)) 302 303 @requires_curses_func('is_term_resized') 304 def test_is_term_resized(self): 305 curses.is_term_resized(*self.stdscr.getmaxyx()) 306 307 @requires_curses_func('resize_term') 308 def test_resize_term(self): 309 curses.resize_term(*self.stdscr.getmaxyx()) 310 311 @requires_curses_func('resizeterm') 312 def test_resizeterm(self): 313 stdscr = self.stdscr 314 lines, cols = curses.LINES, curses.COLS 315 new_lines = lines - 1 316 new_cols = cols + 1 317 curses.resizeterm(new_lines, new_cols) 318 319 self.assertEqual(curses.LINES, new_lines) 320 self.assertEqual(curses.COLS, new_cols) 321 322 def test_issue6243(self): 323 curses.ungetch(1025) 324 self.stdscr.getkey() 325 326 def test_issue10570(self): 327 b = curses.tparm(curses.tigetstr("cup"), 5, 3) 328 self.assertIs(type(b), bytes) 329 330 331class TestAscii(unittest.TestCase): 332 333 def test_controlnames(self): 334 for name in curses.ascii.controlnames: 335 self.assertTrue(hasattr(curses.ascii, name), name) 336 337 def test_ctypes(self): 338 def check(func, expected): 339 self.assertEqual(func(i), expected) 340 self.assertEqual(func(c), expected) 341 342 for i in range(256): 343 c = b = chr(i) 344 check(curses.ascii.isalnum, b.isalnum()) 345 check(curses.ascii.isalpha, b.isalpha()) 346 check(curses.ascii.isdigit, b.isdigit()) 347 check(curses.ascii.islower, b.islower()) 348 check(curses.ascii.isspace, b.isspace()) 349 check(curses.ascii.isupper, b.isupper()) 350 351 check(curses.ascii.isascii, i < 128) 352 check(curses.ascii.ismeta, i >= 128) 353 check(curses.ascii.isctrl, i < 32) 354 check(curses.ascii.iscntrl, i < 32 or i == 127) 355 check(curses.ascii.isblank, c in ' \t') 356 check(curses.ascii.isgraph, 32 < i <= 126) 357 check(curses.ascii.isprint, 32 <= i <= 126) 358 check(curses.ascii.ispunct, c in string.punctuation) 359 check(curses.ascii.isxdigit, c in string.hexdigits) 360 361 def test_ascii(self): 362 ascii = curses.ascii.ascii 363 self.assertEqual(ascii('\xc1'), 'A') 364 self.assertEqual(ascii('A'), 'A') 365 self.assertEqual(ascii(ord('\xc1')), ord('A')) 366 367 def test_ctrl(self): 368 ctrl = curses.ascii.ctrl 369 self.assertEqual(ctrl('J'), '\n') 370 self.assertEqual(ctrl('\n'), '\n') 371 self.assertEqual(ctrl('@'), '\0') 372 self.assertEqual(ctrl(ord('J')), ord('\n')) 373 374 def test_alt(self): 375 alt = curses.ascii.alt 376 self.assertEqual(alt('\n'), '\x8a') 377 self.assertEqual(alt('A'), '\xc1') 378 self.assertEqual(alt(ord('A')), 0xc1) 379 380 def test_unctrl(self): 381 unctrl = curses.ascii.unctrl 382 self.assertEqual(unctrl('a'), 'a') 383 self.assertEqual(unctrl('A'), 'A') 384 self.assertEqual(unctrl(';'), ';') 385 self.assertEqual(unctrl(' '), ' ') 386 self.assertEqual(unctrl('\x7f'), '^?') 387 self.assertEqual(unctrl('\n'), '^J') 388 self.assertEqual(unctrl('\0'), '^@') 389 self.assertEqual(unctrl(ord('A')), 'A') 390 self.assertEqual(unctrl(ord('\n')), '^J') 391 # Meta-bit characters 392 self.assertEqual(unctrl('\x8a'), '!^J') 393 self.assertEqual(unctrl('\xc1'), '!A') 394 self.assertEqual(unctrl(ord('\x8a')), '!^J') 395 self.assertEqual(unctrl(ord('\xc1')), '!A') 396 397 398def test_main(): 399 run_unittest(TestCurses, TestAscii) 400 401 402if __name__ == "__main__": 403 unittest.main() 404