Home | History | Annotate | Download | only in test
      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 
     12 import os
     13 import string
     14 import sys
     15 import tempfile
     16 import unittest
     17 
     18 from 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.
     23 requires('curses')
     24 
     25 # If either of these don't exist, skip the tests.
     26 curses = import_module('curses')
     27 import_module('curses.panel')
     28 import_module('curses.ascii')
     29 
     30 def requires_curses_func(name):
     31     return unittest.skipUnless(hasattr(curses, name),
     32                                'requires curses.%s' % name)
     33 
     34 term = 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")
     41 class 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 
    331 class 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 
    398 def test_main():
    399     run_unittest(TestCurses, TestAscii)
    400 
    401 
    402 if __name__ == "__main__":
    403     unittest.main()
    404