• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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