mirror of
https://github.com/python/cpython.git
synced 2025-08-09 19:38:42 +00:00
[3.12] gh-71339: Add additional assertion methods in test.support (GH-128707) (GH-128815) (GH-129059)
Add a mix-in class ExtraAssertions containing the following methods: * assertHasAttr() and assertNotHasAttr() * assertIsSubclass() and assertNotIsSubclass() * assertStartsWith() and assertNotStartsWith() * assertEndsWith() and assertNotEndsWith() (cherry picked from commitc6a566e47b
) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> (cherry picked from commit06cad77a5b
)
This commit is contained in:
parent
7f68e7bf2a
commit
032058cb62
6 changed files with 68 additions and 49 deletions
|
@ -1,6 +1,63 @@
|
|||
from math import copysign, isnan
|
||||
|
||||
|
||||
class ExtraAssertions:
|
||||
|
||||
def assertIsSubclass(self, cls, superclass, msg=None):
|
||||
if issubclass(cls, superclass):
|
||||
return
|
||||
standardMsg = f'{cls!r} is not a subclass of {superclass!r}'
|
||||
self.fail(self._formatMessage(msg, standardMsg))
|
||||
|
||||
def assertNotIsSubclass(self, cls, superclass, msg=None):
|
||||
if not issubclass(cls, superclass):
|
||||
return
|
||||
standardMsg = f'{cls!r} is a subclass of {superclass!r}'
|
||||
self.fail(self._formatMessage(msg, standardMsg))
|
||||
|
||||
def assertHasAttr(self, obj, name, msg=None):
|
||||
if not hasattr(obj, name):
|
||||
if isinstance(obj, types.ModuleType):
|
||||
standardMsg = f'module {obj.__name__!r} has no attribute {name!r}'
|
||||
elif isinstance(obj, type):
|
||||
standardMsg = f'type object {obj.__name__!r} has no attribute {name!r}'
|
||||
else:
|
||||
standardMsg = f'{type(obj).__name__!r} object has no attribute {name!r}'
|
||||
self.fail(self._formatMessage(msg, standardMsg))
|
||||
|
||||
def assertNotHasAttr(self, obj, name, msg=None):
|
||||
if hasattr(obj, name):
|
||||
if isinstance(obj, types.ModuleType):
|
||||
standardMsg = f'module {obj.__name__!r} has unexpected attribute {name!r}'
|
||||
elif isinstance(obj, type):
|
||||
standardMsg = f'type object {obj.__name__!r} has unexpected attribute {name!r}'
|
||||
else:
|
||||
standardMsg = f'{type(obj).__name__!r} object has unexpected attribute {name!r}'
|
||||
self.fail(self._formatMessage(msg, standardMsg))
|
||||
|
||||
def assertStartsWith(self, s, prefix, msg=None):
|
||||
if s.startswith(prefix):
|
||||
return
|
||||
standardMsg = f"{s!r} doesn't start with {prefix!r}"
|
||||
self.fail(self._formatMessage(msg, standardMsg))
|
||||
|
||||
def assertNotStartsWith(self, s, prefix, msg=None):
|
||||
if not s.startswith(prefix):
|
||||
return
|
||||
self.fail(self._formatMessage(msg, f"{s!r} starts with {prefix!r}"))
|
||||
|
||||
def assertEndsWith(self, s, suffix, msg=None):
|
||||
if s.endswith(suffix):
|
||||
return
|
||||
standardMsg = f"{s!r} doesn't end with {suffix!r}"
|
||||
self.fail(self._formatMessage(msg, standardMsg))
|
||||
|
||||
def assertNotEndsWith(self, s, suffix, msg=None):
|
||||
if not s.endswith(suffix):
|
||||
return
|
||||
self.fail(self._formatMessage(msg, f"{s!r} ends with {suffix!r}"))
|
||||
|
||||
|
||||
class ExceptionIsLikeMixin:
|
||||
def assertExceptionIsLike(self, exc, template):
|
||||
"""
|
||||
|
|
|
@ -15,6 +15,7 @@ import weakref
|
|||
from copy import deepcopy
|
||||
from contextlib import redirect_stdout
|
||||
from test import support
|
||||
from test.support.testcase import ExtraAssertions
|
||||
|
||||
try:
|
||||
import _testcapi
|
||||
|
@ -403,15 +404,7 @@ class OperatorsTest(unittest.TestCase):
|
|||
self.assertEqual(range(sys.maxsize).__len__(), sys.maxsize)
|
||||
|
||||
|
||||
class ClassPropertiesAndMethods(unittest.TestCase):
|
||||
|
||||
def assertHasAttr(self, obj, name):
|
||||
self.assertTrue(hasattr(obj, name),
|
||||
'%r has no attribute %r' % (obj, name))
|
||||
|
||||
def assertNotHasAttr(self, obj, name):
|
||||
self.assertFalse(hasattr(obj, name),
|
||||
'%r has unexpected attribute %r' % (obj, name))
|
||||
class ClassPropertiesAndMethods(unittest.TestCase, ExtraAssertions):
|
||||
|
||||
def test_python_dicts(self):
|
||||
# Testing Python subclass of dict...
|
||||
|
|
|
@ -7,6 +7,7 @@ import sys
|
|||
import sysconfig
|
||||
import unittest
|
||||
from test import support
|
||||
from test.support.testcase import ExtraAssertions
|
||||
|
||||
|
||||
GDB_PROGRAM = shutil.which('gdb') or 'gdb'
|
||||
|
@ -152,7 +153,7 @@ def setup_module():
|
|||
print()
|
||||
|
||||
|
||||
class DebuggerTests(unittest.TestCase):
|
||||
class DebuggerTests(unittest.TestCase, ExtraAssertions):
|
||||
|
||||
"""Test that the debugger can debug Python."""
|
||||
|
||||
|
@ -280,11 +281,6 @@ class DebuggerTests(unittest.TestCase):
|
|||
|
||||
return out
|
||||
|
||||
def assertEndsWith(self, actual, exp_end):
|
||||
'''Ensure that the given "actual" string ends with "exp_end"'''
|
||||
self.assertTrue(actual.endswith(exp_end),
|
||||
msg='%r did not end with %r' % (actual, exp_end))
|
||||
|
||||
def assertMultilineMatches(self, actual, pattern):
|
||||
m = re.match(pattern, actual, re.DOTALL)
|
||||
if not m:
|
||||
|
|
|
@ -10,6 +10,7 @@ import pyclbr
|
|||
from unittest import TestCase, main as unittest_main
|
||||
from test.test_importlib import util as test_importlib_util
|
||||
import warnings
|
||||
from test.support.testcase import ExtraAssertions
|
||||
|
||||
|
||||
StaticMethodType = type(staticmethod(lambda: None))
|
||||
|
@ -22,7 +23,7 @@ ClassMethodType = type(classmethod(lambda c: None))
|
|||
# is imperfect (as designed), testModule is called with a set of
|
||||
# members to ignore.
|
||||
|
||||
class PyclbrTest(TestCase):
|
||||
class PyclbrTest(TestCase, ExtraAssertions):
|
||||
|
||||
def assertListEq(self, l1, l2, ignore):
|
||||
''' succeed iff {l1} - {ignore} == {l2} - {ignore} '''
|
||||
|
@ -31,14 +32,6 @@ class PyclbrTest(TestCase):
|
|||
print("l1=%r\nl2=%r\nignore=%r" % (l1, l2, ignore), file=sys.stderr)
|
||||
self.fail("%r missing" % missing.pop())
|
||||
|
||||
def assertHasattr(self, obj, attr, ignore):
|
||||
''' succeed iff hasattr(obj,attr) or attr in ignore. '''
|
||||
if attr in ignore: return
|
||||
if not hasattr(obj, attr): print("???", attr)
|
||||
self.assertTrue(hasattr(obj, attr),
|
||||
'expected hasattr(%r, %r)' % (obj, attr))
|
||||
|
||||
|
||||
def assertHaskey(self, obj, key, ignore):
|
||||
''' succeed iff key in obj or key in ignore. '''
|
||||
if key in ignore: return
|
||||
|
@ -86,7 +79,7 @@ class PyclbrTest(TestCase):
|
|||
for name, value in dict.items():
|
||||
if name in ignore:
|
||||
continue
|
||||
self.assertHasattr(module, name, ignore)
|
||||
self.assertHasAttr(module, name, ignore)
|
||||
py_item = getattr(module, name)
|
||||
if isinstance(value, pyclbr.Function):
|
||||
self.assertIsInstance(py_item, (FunctionType, BuiltinFunctionType))
|
||||
|
|
|
@ -47,6 +47,7 @@ import weakref
|
|||
import types
|
||||
|
||||
from test.support import captured_stderr, cpython_only
|
||||
from test.support.testcase import ExtraAssertions
|
||||
from test.typinganndata import ann_module695, mod_generics_cache, _typed_dict_helper
|
||||
|
||||
|
||||
|
@ -55,21 +56,7 @@ NOT_A_BASE_TYPE = "type 'typing.%s' is not an acceptable base type"
|
|||
CANNOT_SUBCLASS_INSTANCE = 'Cannot subclass an instance of %s'
|
||||
|
||||
|
||||
class BaseTestCase(TestCase):
|
||||
|
||||
def assertIsSubclass(self, cls, class_or_tuple, msg=None):
|
||||
if not issubclass(cls, class_or_tuple):
|
||||
message = '%r is not a subclass of %r' % (cls, class_or_tuple)
|
||||
if msg is not None:
|
||||
message += ' : %s' % msg
|
||||
raise self.failureException(message)
|
||||
|
||||
def assertNotIsSubclass(self, cls, class_or_tuple, msg=None):
|
||||
if issubclass(cls, class_or_tuple):
|
||||
message = '%r is a subclass of %r' % (cls, class_or_tuple)
|
||||
if msg is not None:
|
||||
message += ' : %s' % msg
|
||||
raise self.failureException(message)
|
||||
class BaseTestCase(TestCase, ExtraAssertions):
|
||||
|
||||
def clear_caches(self):
|
||||
for f in typing._cleanups:
|
||||
|
@ -1051,10 +1038,6 @@ class UnpackTests(BaseTestCase):
|
|||
|
||||
class TypeVarTupleTests(BaseTestCase):
|
||||
|
||||
def assertEndsWith(self, string, tail):
|
||||
if not string.endswith(tail):
|
||||
self.fail(f"String {string!r} does not end with {tail!r}")
|
||||
|
||||
def test_name(self):
|
||||
Ts = TypeVarTuple('Ts')
|
||||
self.assertEqual(Ts.__name__, 'Ts')
|
||||
|
|
|
@ -25,6 +25,7 @@ from test.support import (captured_stdout, captured_stderr,
|
|||
requires_resource, copy_python_src_ignore)
|
||||
from test.support.os_helper import (can_symlink, EnvironmentVarGuard, rmtree,
|
||||
TESTFN, FakePath)
|
||||
from test.support.testcase import ExtraAssertions
|
||||
import unittest
|
||||
import venv
|
||||
from unittest.mock import patch, Mock
|
||||
|
@ -58,7 +59,7 @@ def check_output(cmd, encoding=None):
|
|||
p.returncode, cmd, out, err)
|
||||
return out, err
|
||||
|
||||
class BaseTest(unittest.TestCase):
|
||||
class BaseTest(unittest.TestCase, ExtraAssertions):
|
||||
"""Base class for venv tests."""
|
||||
maxDiff = 80 * 50
|
||||
|
||||
|
@ -98,10 +99,6 @@ class BaseTest(unittest.TestCase):
|
|||
result = f.read()
|
||||
return result
|
||||
|
||||
def assertEndsWith(self, string, tail):
|
||||
if not string.endswith(tail):
|
||||
self.fail(f"String {string!r} does not end with {tail!r}")
|
||||
|
||||
class BasicTest(BaseTest):
|
||||
"""Test venv module functionality."""
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue