aboutsummaryrefslogtreecommitdiff
path: root/Lib/test
diff options
context:
space:
mode:
authorSerhiy Storchaka <storchaka@gmail.com>2021-01-03 22:51:11 +0200
committerGitHub <noreply@github.com>2021-01-03 22:51:11 +0200
commit1470edd6131c29b8a09ce012cdfee3afa269d553 (patch)
treebd719cd5b488dc5c17716374826bd774e11884d0 /Lib/test
parentbpo-41798: pyexpat: Allocate the expat_CAPI on the heap memory (GH-24061) (diff)
downloadcpython-1470edd6131c29b8a09ce012cdfee3afa269d553.tar.gz
cpython-1470edd6131c29b8a09ce012cdfee3afa269d553.tar.bz2
cpython-1470edd6131c29b8a09ce012cdfee3afa269d553.zip
bpo-42681: Fix range checks for color and pair numbers in curses (GH-23874)
Diffstat (limited to 'Lib/test')
-rw-r--r--Lib/test/test_curses.py133
1 files changed, 107 insertions, 26 deletions
diff --git a/Lib/test/test_curses.py b/Lib/test/test_curses.py
index 6811ff93663..31fb882b724 100644
--- a/Lib/test/test_curses.py
+++ b/Lib/test/test_curses.py
@@ -4,8 +4,7 @@
# This script doesn't actually display anything very coherent. but it
# does call (nearly) every method and function.
#
-# Functions not tested: {def,reset}_{shell,prog}_mode, getch(), getstr(),
-# init_color()
+# Functions not tested: {def,reset}_{shell,prog}_mode, getch(), getstr()
# Only called, not tested: getmouse(), ungetmouse()
#
@@ -13,6 +12,7 @@ import os
import string
import sys
import tempfile
+import functools
import unittest
from test.support import requires, verbose, SaveSignals
@@ -37,6 +37,15 @@ def requires_curses_func(name):
return unittest.skipUnless(hasattr(curses, name),
'requires curses.%s' % name)
+def requires_colors(test):
+ @functools.wraps(test)
+ def wrapped(self, *args, **kwargs):
+ if not curses.has_colors():
+ self.skipTest('requires colors support')
+ curses.start_color()
+ test(self, *args, **kwargs)
+ return wrapped
+
term = os.environ.get('TERM')
# If newterm was supported we could use it instead of initscr and not exit
@@ -48,6 +57,8 @@ class TestCurses(unittest.TestCase):
@classmethod
def setUpClass(cls):
+ if verbose:
+ print(f'TERM={term}', file=sys.stderr, flush=True)
# testing setupterm() inside initscr/endwin
# causes terminal breakage
stdout_fd = sys.__stdout__.fileno()
@@ -306,31 +317,101 @@ class TestCurses(unittest.TestCase):
curses.use_env(1)
# Functions only available on a few platforms
- def test_colors_funcs(self):
- if not curses.has_colors():
- self.skipTest('requires colors support')
- curses.start_color()
- curses.init_pair(2, 1,1)
- curses.color_content(1)
- curses.color_pair(2)
+
+ def bad_colors(self):
+ return (-1, curses.COLORS, -2**31 - 1, 2**31, -2**63 - 1, 2**63, 2**64)
+
+ def bad_colors2(self):
+ return (curses.COLORS, 2**31, 2**63, 2**64)
+
+ def bad_pairs(self):
+ return (-1, -2**31 - 1, 2**31, -2**63 - 1, 2**63, 2**64)
+
+ @requires_colors
+ def test_color_content(self):
+ self.assertEqual(curses.color_content(curses.COLOR_BLACK), (0, 0, 0))
+ curses.color_content(0)
+ curses.color_content(curses.COLORS - 1)
+
+ for color in self.bad_colors():
+ self.assertRaises(ValueError, curses.color_content, color)
+
+ @requires_colors
+ def test_init_color(self):
+ if not curses.can_change_color:
+ self.skipTest('cannot change color')
+
+ old = curses.color_content(0)
+ try:
+ curses.init_color(0, *old)
+ except curses.error:
+ self.skipTest('cannot change color (init_color() failed)')
+ self.addCleanup(curses.init_color, 0, *old)
+ curses.init_color(0, 0, 0, 0)
+ self.assertEqual(curses.color_content(0), (0, 0, 0))
+ curses.init_color(0, 1000, 1000, 1000)
+ self.assertEqual(curses.color_content(0), (1000, 1000, 1000))
+
+ old = curses.color_content(curses.COLORS - 1)
+ curses.init_color(curses.COLORS - 1, *old)
+ self.addCleanup(curses.init_color, curses.COLORS - 1, *old)
+ curses.init_color(curses.COLORS - 1, 0, 500, 1000)
+ self.assertEqual(curses.color_content(curses.COLORS - 1), (0, 500, 1000))
+
+ for color in self.bad_colors():
+ self.assertRaises(ValueError, curses.init_color, color, 0, 0, 0)
+ for comp in (-1, 1001):
+ self.assertRaises(ValueError, curses.init_color, 0, comp, 0, 0)
+ self.assertRaises(ValueError, curses.init_color, 0, 0, comp, 0)
+ self.assertRaises(ValueError, curses.init_color, 0, 0, 0, comp)
+
+ @requires_colors
+ def test_pair_content(self):
+ if not hasattr(curses, 'use_default_colors'):
+ self.assertEqual(curses.pair_content(0),
+ (curses.COLOR_WHITE, curses.COLOR_BLACK))
+ curses.pair_content(0)
curses.pair_content(curses.COLOR_PAIRS - 1)
- curses.pair_number(0)
-
- if hasattr(curses, 'use_default_colors'):
- curses.use_default_colors()
-
- self.assertRaises(ValueError, curses.color_content, -1)
- self.assertRaises(ValueError, curses.color_content, curses.COLORS + 1)
- self.assertRaises(ValueError, curses.color_content, -2**31 - 1)
- self.assertRaises(ValueError, curses.color_content, 2**31)
- self.assertRaises(ValueError, curses.color_content, -2**63 - 1)
- self.assertRaises(ValueError, curses.color_content, 2**63 - 1)
- self.assertRaises(ValueError, curses.pair_content, -1)
- self.assertRaises(ValueError, curses.pair_content, curses.COLOR_PAIRS)
- self.assertRaises(ValueError, curses.pair_content, -2**31 - 1)
- self.assertRaises(ValueError, curses.pair_content, 2**31)
- self.assertRaises(ValueError, curses.pair_content, -2**63 - 1)
- self.assertRaises(ValueError, curses.pair_content, 2**63 - 1)
+
+ for pair in self.bad_pairs():
+ self.assertRaises(ValueError, curses.pair_content, pair)
+
+ @requires_colors
+ def test_init_pair(self):
+ old = curses.pair_content(1)
+ curses.init_pair(1, *old)
+ self.addCleanup(curses.init_pair, 1, *old)
+
+ curses.init_pair(1, 0, 0)
+ self.assertEqual(curses.pair_content(1), (0, 0))
+ curses.init_pair(1, curses.COLORS - 1, curses.COLORS - 1)
+ self.assertEqual(curses.pair_content(1),
+ (curses.COLORS - 1, curses.COLORS - 1))
+ curses.init_pair(curses.COLOR_PAIRS - 1, 2, 3)
+ self.assertEqual(curses.pair_content(curses.COLOR_PAIRS - 1), (2, 3))
+
+ for pair in self.bad_pairs():
+ self.assertRaises(ValueError, curses.init_pair, pair, 0, 0)
+ for color in self.bad_colors2():
+ self.assertRaises(ValueError, curses.init_pair, 1, color, 0)
+ self.assertRaises(ValueError, curses.init_pair, 1, 0, color)
+
+ @requires_colors
+ def test_color_attrs(self):
+ for pair in 0, 1, 255:
+ attr = curses.color_pair(pair)
+ self.assertEqual(curses.pair_number(attr), pair, attr)
+ self.assertEqual(curses.pair_number(attr | curses.A_BOLD), pair)
+ self.assertEqual(curses.color_pair(0), 0)
+ self.assertEqual(curses.pair_number(0), 0)
+
+ @requires_curses_func('use_default_colors')
+ @requires_colors
+ def test_use_default_colors(self):
+ self.assertIn(curses.pair_content(0),
+ ((curses.COLOR_WHITE, curses.COLOR_BLACK), (-1, -1)))
+ curses.use_default_colors()
+ self.assertEqual(curses.pair_content(0), (-1, -1))
@requires_curses_func('keyname')
def test_keyname(self):