From ad76ab2a4b8fe52d1ae93186cd6dd5f79e7b4b73 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Tue, 5 Jan 2021 09:13:15 +0200 Subject: [PATCH] [3.9] bpo-42681: Fix test_curses failures related to color pairs (GH-24089) On ncurses 6.1 pair numbers are limited by SHORT_MAX-1, even with extended color support. Improve error reporting and tests for color functions.. (cherry picked from commit 59f9b4e4509be67494f3d45489fa55523175ff69) Co-authored-by: Serhiy Storchaka --- Lib/test/test_curses.py | 33 ++++++++++++++++++++++++++------- Modules/_cursesmodule.c | 26 ++++++++++++++++++-------- 2 files changed, 44 insertions(+), 15 deletions(-) diff --git a/Lib/test/test_curses.py b/Lib/test/test_curses.py index e310d191f97..de9f301737d 100644 --- a/Lib/test/test_curses.py +++ b/Lib/test/test_curses.py @@ -323,11 +323,20 @@ class TestCurses(unittest.TestCase): def bad_pairs(self): return (-2**31 - 1, 2**31, -2**63 - 1, 2**63, 2**64) + def test_start_color(self): + if not curses.has_colors(): + self.skipTest('requires colors support') + curses.start_color() + if verbose: + print(f'COLORS = {curses.COLORS}', file=sys.stderr) + print(f'COLOR_PAIRS = {curses.COLOR_PAIRS}', file=sys.stderr) + @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(min(curses.COLORS - 1, SHORT_MAX)) + maxcolor = min(curses.COLORS - 1, SHORT_MAX) + curses.color_content(maxcolor) for color in self.bad_colors(): self.assertRaises(OverflowError, curses.color_content, color) @@ -368,13 +377,18 @@ class TestCurses(unittest.TestCase): self.assertRaises(curses.error, curses.init_color, 0, 0, comp, 0) self.assertRaises(curses.error, curses.init_color, 0, 0, 0, comp) + def get_pair_limit(self): + return min(curses.COLOR_PAIRS, SHORT_MAX) + @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(min(curses.COLOR_PAIRS - 1, SHORT_MAX)) + maxpair = self.get_pair_limit() - 1 + if maxpair > 0: + curses.pair_content(maxpair) for pair in self.bad_pairs(): self.assertRaises(OverflowError, curses.pair_content, pair) @@ -389,11 +403,14 @@ class TestCurses(unittest.TestCase): curses.init_pair(1, 0, 0) self.assertEqual(curses.pair_content(1), (0, 0)) maxcolor = min(curses.COLORS - 1, SHORT_MAX) - curses.init_pair(1, maxcolor, maxcolor) - self.assertEqual(curses.pair_content(1), (maxcolor, maxcolor)) - maxpair = min(curses.COLOR_PAIRS - 1, SHORT_MAX) - curses.init_pair(maxpair, 2, 3) - self.assertEqual(curses.pair_content(maxpair), (2, 3)) + curses.init_pair(1, maxcolor, 0) + self.assertEqual(curses.pair_content(1), (maxcolor, 0)) + curses.init_pair(1, 0, maxcolor) + self.assertEqual(curses.pair_content(1), (0, maxcolor)) + maxpair = self.get_pair_limit() - 1 + if maxpair > 1: + curses.init_pair(maxpair, 0, 0) + self.assertEqual(curses.pair_content(maxpair), (0, 0)) for pair in self.bad_pairs(): self.assertRaises(OverflowError, curses.init_pair, pair, 0, 0) @@ -591,6 +608,8 @@ class MiscTests(unittest.TestCase): @requires_curses_func('ncurses_version') def test_ncurses_version(self): v = curses.ncurses_version + if verbose: + print(f'ncurses_version = {curses.ncurses_version}', flush=True) self.assertIsInstance(v[:], tuple) self.assertEqual(len(v), 3) self.assertIsInstance(v[0], int) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 0914e20466f..d129248e363 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -2592,13 +2592,18 @@ _curses_color_content_impl(PyObject *module, short color_number) PyCursesInitialised; PyCursesInitialisedColor; - if (color_content(color_number, &r, &g, &b) != ERR) - return Py_BuildValue("(iii)", r, g, b); - else { - PyErr_SetString(PyCursesError, - "Argument 1 was out of range. Check value of COLORS."); + if (color_content(color_number, &r, &g, &b) == ERR) { + if (color_number >= COLORS) { + PyErr_SetString(PyCursesError, + "Argument 1 was out of range. Check value of COLORS."); + } + else { + PyErr_SetString(PyCursesError, "color_content() returned ERR"); + } return NULL; } + + return Py_BuildValue("(iii)", r, g, b); } /*[clinic input] @@ -3701,9 +3706,14 @@ _curses_pair_content_impl(PyObject *module, short pair_number) PyCursesInitialised; PyCursesInitialisedColor; - if (pair_content(pair_number, &f, &b)==ERR) { - PyErr_SetString(PyCursesError, - "Argument 1 was out of range. (0..COLOR_PAIRS-1)"); + if (pair_content(pair_number, &f, &b) == ERR) { + if (pair_number >= COLOR_PAIRS) { + PyErr_SetString(PyCursesError, + "Argument 1 was out of range. (0..COLOR_PAIRS-1)"); + } + else { + PyErr_SetString(PyCursesError, "pair_content() returned ERR"); + } return NULL; }