Skip to content

Commit 4d27d7b

Browse files
committed
update how algorithms are discovered for RFC test cases
1 parent 6ccdfcb commit 4d27d7b

File tree

1 file changed

+42
-32
lines changed

1 file changed

+42
-32
lines changed

Lib/test/test_hmac.py

Lines changed: 42 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -329,28 +329,50 @@ def hmac_digest_by_name(self, key, msg=None, hashname=None):
329329
return self.hmac_digest(key, msg, digestmod=openssl_func)
330330

331331

332-
class RFCTestCasesMixin(TestVectorsMixin):
333-
"""Test HMAC implementations against test vectors from the RFC.
334-
335-
Subclasses must override the 'md5' and other 'sha*' attributes
336-
to test the implementations. Their value can be a string, a callable,
337-
or a PEP-257 module.
338-
"""
332+
class HashFunctionsTrait:
333+
"""Trait class for 'hashfunc' in hmac_new() and hmac_digest()."""
339334

340335
ALGORITHMS = [
341336
'md5', 'sha1',
342337
'sha224', 'sha256', 'sha384', 'sha512',
343338
]
344339

345-
# Those will be automatically set to non-None on subclasses
346-
# as they are set by __init_subclass()__.
347-
md5 = sha1 = sha224 = sha256 = sha384 = sha512 = None
340+
# By default, a missing algorithm skips the test that uses it.
341+
md5 = sha1 = sha224 = sha256 = sha384 = sha512 = property(
342+
lambda self: self.skipTest("missing hash function")
343+
)
344+
345+
346+
class WithOpenSSLHashFunctions(HashFunctionsTrait):
347+
"""Test a HMAC implementation with an OpenSSL-based callable 'hashfunc'."""
348+
349+
@classmethod
350+
def setUpClass(cls):
351+
super().setUpClass()
352+
353+
for name in cls.ALGORITHMS:
354+
@property
355+
@hashlib_helper.requires_hashlib()
356+
@hashlib_helper.requires_hashdigest(name, openssl=True)
357+
def func(self, *, __name=name): # __name needed to bind 'name'
358+
return getattr(_hashlib, f'openssl_{__name}')
359+
setattr(cls, name, func)
360+
361+
362+
class WithNamedHashFunctions(HashFunctionsTrait):
363+
"""Test a HMAC implementation with a named 'hashfunc'."""
364+
365+
@classmethod
366+
def setUpClass(cls):
367+
super().setUpClass()
348368

349-
def __init_subclass__(cls, *args, **kwargs):
350-
super().__init_subclass__(*args, **kwargs)
351369
for name in cls.ALGORITHMS:
352370
setattr(cls, name, name)
353371

372+
373+
class RFCTestCasesMixin(HashFunctionsTrait):
374+
"""Test HMAC implementations against test vectors from the RFC."""
375+
354376
def test_md5(self):
355377
def md5test(key, msg, hexdigest):
356378
self.assert_hmac(key, msg, hexdigest, self.md5, "md5", 16, 64)
@@ -550,31 +572,17 @@ def hmactest(key, data, hexdigests):
550572
})
551573

552574

553-
class RFCWithOpenSSLHashFunctionTestCasesMixin(RFCTestCasesMixin):
554-
555-
def __init_subclass__(cls, *args, **kwargs):
556-
super().__init_subclass__(*args, **kwargs)
557-
558-
for name in cls.ALGORITHMS:
559-
@property
560-
@hashlib_helper.requires_hashlib()
561-
@hashlib_helper.requires_hashdigest(name, openssl=True)
562-
def func(self, *, __name=name): # __name needed to bind 'name'
563-
return getattr(_hashlib, f'openssl_{__name}')
564-
setattr(cls, name, func)
565-
566-
567-
class PyRFCTestCase(PyTestVectorsMixin, ThroughObjectMixin,
568-
RFCWithOpenSSLHashFunctionTestCasesMixin,
575+
class PyRFCTestCase(ThroughObjectMixin, PyTestVectorsMixin,
576+
WithOpenSSLHashFunctions, RFCTestCasesMixin,
569577
unittest.TestCase):
570578
"""Python implementation of HMAC using hmac.HMAC().
571579
572580
The underlying hash functions are OpenSSL-based.
573581
"""
574582

575583

576-
class PyDotNewRFCTestCase(PyTestVectorsMixin, ThroughModuleAPIMixin,
577-
RFCWithOpenSSLHashFunctionTestCasesMixin,
584+
class PyDotNewRFCTestCase(ThroughModuleAPIMixin, PyTestVectorsMixin,
585+
WithOpenSSLHashFunctions, RFCTestCasesMixin,
578586
unittest.TestCase):
579587
"""Python implementation of HMAC using hmac.new().
580588
@@ -583,11 +591,13 @@ class PyDotNewRFCTestCase(PyTestVectorsMixin, ThroughModuleAPIMixin,
583591

584592

585593
class OpenSSLRFCTestCase(OpenSSLTestVectorsMixin,
586-
RFCWithOpenSSLHashFunctionTestCasesMixin,
594+
WithOpenSSLHashFunctions, RFCTestCasesMixin,
587595
unittest.TestCase):
588596
"""OpenSSL implementation of HMAC.
589597
590-
The underlying hash functions are also OpenSSL-based."""
598+
The underlying hash functions are also OpenSSL-based.
599+
"""
600+
591601

592602

593603
# TODO(picnixz): once we have a HACL* HMAC, we should also test the Python

0 commit comments

Comments
 (0)