edq.testing.asserts
More complex testing assertions. Often used as output checks in CLI tests.
1""" 2More complex testing assertions. 3Often used as output checks in CLI tests. 4""" 5 6import re 7import typing 8 9import edq.testing.unittest 10 11TRACEBACK_LINE_REGEX: str = r'^\s*File "[^"]+", line \d+,.*$\n.*$(\n\s*[\^~]+\s*$)?' 12TRACEBACK_LINE_REPLACEMENT: str = '<TRACEBACK_LINE>' 13 14TEXT_NORMALIZATIONS: typing.List[typing.Tuple[str, str]] = [ 15 (r'^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d+ \[\S+ *\] - .*\.py:\d+ -- ', '<LOG_PREFIX> -- '), 16 (r'\d+\.\d+ seconds', '<DURATION_SECONDS>'), 17 (r'\bv\d+\.\d+\.\d+\b', '<VERSION>'), 18 (r'^\s*File "[^"]+", line \d+,.*$\n.*$(\n\s*[\^~]+\s*$)?', '<TRACEBACK_LINE>'), 19 (rf'{TRACEBACK_LINE_REPLACEMENT}(\n{TRACEBACK_LINE_REPLACEMENT})*', '<TRACEBACK>'), 20] 21""" 22Normalization to make to the CLI output. 23Formatted as: [(regex, replacement), ...] 24""" 25 26@typing.runtime_checkable 27class StringComparisonAssertion(typing.Protocol): 28 """ 29 A function that can be used as a comparison assertion for a test. 30 """ 31 32 def __call__(self, 33 test: edq.testing.unittest.BaseTest, 34 expected: str, actual: str, 35 **kwargs: typing.Any) -> None: 36 """ 37 Perform an assertion between expected and actual data. 38 """ 39 40 41def content_equals_raw(test: edq.testing.unittest.BaseTest, expected: str, actual: str, **kwargs: typing.Any) -> None: 42 """ Check for equality using a simple string comparison. """ 43 44 test.assertEqual(expected, actual) 45 46def content_equals_normalize(test: edq.testing.unittest.BaseTest, expected: str, actual: str, **kwargs: typing.Any) -> None: 47 """ 48 Perform some standard text normalizations (see TEXT_NORMALIZATIONS) before using simple string comparison. 49 """ 50 51 for (regex, replacement) in TEXT_NORMALIZATIONS: 52 expected = re.sub(regex, replacement, expected, flags = re.MULTILINE) 53 actual = re.sub(regex, replacement, actual, flags = re.MULTILINE) 54 55 content_equals_raw(test, expected, actual) 56 57def has_content_100(test: edq.testing.unittest.BaseTest, expected: str, actual: str, **kwargs: typing.Any) -> None: 58 """ Check the that output has at least 100 characters. """ 59 60 return has_content(test, expected, actual, min_length = 100) 61 62def has_content(test: edq.testing.unittest.BaseTest, expected: str, actual: str, min_length: int = 100) -> None: 63 """ Ensure that the output has content of at least some length. """ 64 65 message = f"Output does not meet minimum length of {min_length}, it is only {len(actual)}." 66 test.assertTrue((len(actual) >= min_length), msg = message)
TRACEBACK_LINE_REGEX: str =
'^\\s*File "[^"]+", line \\d+,.*$\\n.*$(\\n\\s*[\\^~]+\\s*$)?'
TRACEBACK_LINE_REPLACEMENT: str =
'<TRACEBACK_LINE>'
TEXT_NORMALIZATIONS: List[Tuple[str, str]] =
[('^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2},\\d+ \\[\\S+ *\\] - .*\\.py:\\d+ -- ', '<LOG_PREFIX> -- '), ('\\d+\\.\\d+ seconds', '<DURATION_SECONDS>'), ('\\bv\\d+\\.\\d+\\.\\d+\\b', '<VERSION>'), ('^\\s*File "[^"]+", line \\d+,.*$\\n.*$(\\n\\s*[\\^~]+\\s*$)?', '<TRACEBACK_LINE>'), ('<TRACEBACK_LINE>(\\n<TRACEBACK_LINE>)*', '<TRACEBACK>')]
Normalization to make to the CLI output. Formatted as: [(regex, replacement), ...]
@typing.runtime_checkable
class
StringComparisonAssertion27@typing.runtime_checkable 28class StringComparisonAssertion(typing.Protocol): 29 """ 30 A function that can be used as a comparison assertion for a test. 31 """ 32 33 def __call__(self, 34 test: edq.testing.unittest.BaseTest, 35 expected: str, actual: str, 36 **kwargs: typing.Any) -> None: 37 """ 38 Perform an assertion between expected and actual data. 39 """
A function that can be used as a comparison assertion for a test.
StringComparisonAssertion(*args, **kwargs)
1953def _no_init_or_replace_init(self, *args, **kwargs): 1954 cls = type(self) 1955 1956 if cls._is_protocol: 1957 raise TypeError('Protocols cannot be instantiated') 1958 1959 # Already using a custom `__init__`. No need to calculate correct 1960 # `__init__` to call. This can lead to RecursionError. See bpo-45121. 1961 if cls.__init__ is not _no_init_or_replace_init: 1962 return 1963 1964 # Initially, `__init__` of a protocol subclass is set to `_no_init_or_replace_init`. 1965 # The first instantiation of the subclass will call `_no_init_or_replace_init` which 1966 # searches for a proper new `__init__` in the MRO. The new `__init__` 1967 # replaces the subclass' old `__init__` (ie `_no_init_or_replace_init`). Subsequent 1968 # instantiation of the protocol subclass will thus use the new 1969 # `__init__` and no longer call `_no_init_or_replace_init`. 1970 for base in cls.__mro__: 1971 init = base.__dict__.get('__init__', _no_init_or_replace_init) 1972 if init is not _no_init_or_replace_init: 1973 cls.__init__ = init 1974 break 1975 else: 1976 # should not happen 1977 cls.__init__ = object.__init__ 1978 1979 cls.__init__(self, *args, **kwargs)
def
content_equals_raw( test: edq.testing.unittest.BaseTest, expected: str, actual: str, **kwargs: Any) -> None:
42def content_equals_raw(test: edq.testing.unittest.BaseTest, expected: str, actual: str, **kwargs: typing.Any) -> None: 43 """ Check for equality using a simple string comparison. """ 44 45 test.assertEqual(expected, actual)
Check for equality using a simple string comparison.
def
content_equals_normalize( test: edq.testing.unittest.BaseTest, expected: str, actual: str, **kwargs: Any) -> None:
47def content_equals_normalize(test: edq.testing.unittest.BaseTest, expected: str, actual: str, **kwargs: typing.Any) -> None: 48 """ 49 Perform some standard text normalizations (see TEXT_NORMALIZATIONS) before using simple string comparison. 50 """ 51 52 for (regex, replacement) in TEXT_NORMALIZATIONS: 53 expected = re.sub(regex, replacement, expected, flags = re.MULTILINE) 54 actual = re.sub(regex, replacement, actual, flags = re.MULTILINE) 55 56 content_equals_raw(test, expected, actual)
Perform some standard text normalizations (see TEXT_NORMALIZATIONS) before using simple string comparison.
def
has_content_100( test: edq.testing.unittest.BaseTest, expected: str, actual: str, **kwargs: Any) -> None:
58def has_content_100(test: edq.testing.unittest.BaseTest, expected: str, actual: str, **kwargs: typing.Any) -> None: 59 """ Check the that output has at least 100 characters. """ 60 61 return has_content(test, expected, actual, min_length = 100)
Check the that output has at least 100 characters.
def
has_content( test: edq.testing.unittest.BaseTest, expected: str, actual: str, min_length: int = 100) -> None:
63def has_content(test: edq.testing.unittest.BaseTest, expected: str, actual: str, min_length: int = 100) -> None: 64 """ Ensure that the output has content of at least some length. """ 65 66 message = f"Output does not meet minimum length of {min_length}, it is only {len(actual)}." 67 test.assertTrue((len(actual) >= min_length), msg = message)
Ensure that the output has content of at least some length.