Skip to content
Merged
Changes from 1 commit
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
d80b1b1
add helper for _hashlib detection
picnixz Feb 13, 2025
73b7756
remove unused function `ignore_warning`
picnixz Feb 13, 2025
fe7a300
cleanup whitespaces
picnixz Feb 13, 2025
72f956f
clean imports and test guards
picnixz Feb 13, 2025
3e827a7
Add mixins for interacting with HMAC
picnixz Feb 13, 2025
7f4fcc8
add mixin for RFC test cases
picnixz Feb 13, 2025
e47dd8b
use RFC mixin classes
picnixz Feb 13, 2025
acda122
refactor `CompareDigestTestCase`
picnixz Feb 13, 2025
d2eb48a
refactor `CopyTestCase`
picnixz Feb 13, 2025
105f6ce
refactor `UpdateTestCase`
picnixz Feb 13, 2025
412f5c2
refactor `SanityTestCase`
picnixz Feb 13, 2025
c682945
refactor `ConstructorTestCase`
picnixz Feb 13, 2025
7e62a58
Merge branch 'main' into test/hmac/refactor-99108
picnixz Feb 15, 2025
c04233d
update comments
picnixz Feb 15, 2025
fb7e577
extend coverage
picnixz Feb 15, 2025
168d018
Merge branch 'main' into test/hmac/refactor-99108
picnixz Feb 24, 2025
4177afa
add regression test for HMAC `repr()`
picnixz Feb 25, 2025
644f577
change a bit the digestmod tests
picnixz Feb 25, 2025
e71f03d
Merge branch 'main' into test/hmac/refactor-99108
picnixz Mar 2, 2025
dbe3ce4
remove mixin that is not yet needed
picnixz Mar 3, 2025
ca0822a
add comments
picnixz Mar 3, 2025
a0b3569
semantics: 'digest' -> 'hexdigest'
picnixz Mar 3, 2025
321a7a9
use `__init_subclass__` instead of `setUpClass`
picnixz Mar 3, 2025
ca7851c
document and reorganize method order in `DigestModTestCaseMixin`
picnixz Mar 3, 2025
a347ee5
use separate factories for creating bad digestmod cases
picnixz Mar 3, 2025
85364b4
minor tweak on `CompareDigestMixin`
picnixz Mar 3, 2025
740fe81
do not allow 'hashfunc' or 'hashname' to be None for RFC tests
picnixz Mar 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
refactor CompareDigestTestCase
  • Loading branch information
picnixz committed Feb 13, 2025
commit acda1223551de56863a644b4af5d27dd85bbe9c8
161 changes: 84 additions & 77 deletions Lib/test/test_hmac.py
Original file line number Diff line number Diff line change
Expand Up @@ -695,126 +695,133 @@ def test_equality_new(self):
"Hexdigest of copy doesn't match original hexdigest.")


class CompareDigestTestCase(unittest.TestCase):
class CompareDigestMixin:

def test_hmac_compare_digest(self):
self._test_compare_digest(hmac.compare_digest)
if openssl_compare_digest is not None:
self.assertIs(hmac.compare_digest, openssl_compare_digest)
else:
self.assertIs(hmac.compare_digest, operator_compare_digest)

def test_operator_compare_digest(self):
self._test_compare_digest(operator_compare_digest)

@hashlib_helper.requires_hashlib()
def test_openssl_compare_digest(self):
self._test_compare_digest(openssl_compare_digest)

def _test_compare_digest(self, compare_digest):
# Testing input type exception handling
a, b = 100, 200
self.assertRaises(TypeError, compare_digest, a, b)
a, b = 100, b"foobar"
self.assertRaises(TypeError, compare_digest, a, b)
a, b = b"foobar", 200
self.assertRaises(TypeError, compare_digest, a, b)
a, b = "foobar", b"foobar"
self.assertRaises(TypeError, compare_digest, a, b)
a, b = b"foobar", "foobar"
self.assertRaises(TypeError, compare_digest, a, b)
def compare_digest(self, a, b):
raise NotImplementedError

def assert_digest_equal(self, a, b):
with self.subTest(a=a, b=b):
self.assertTrue(self.compare_digest(a, b))
with self.subTest(a=b, b=a):
self.assertTrue(self.compare_digest(b, a))

def assert_digest_not_equal(self, a, b):
with self.subTest(a=a, b=b):
self.assertFalse(self.compare_digest(a, b))
with self.subTest(a=b, b=a):
self.assertFalse(self.compare_digest(b, a))

def test_exceptions(self):
for a, b in [
# Testing input type exception handling
(100, 200), (100, b"foobar"), ("foobar", b"foobar"),
# non-ASCII strings
("fooä", "fooä")
]:
self.assertRaises(TypeError, self.compare_digest, a, b)
self.assertRaises(TypeError, self.compare_digest, b, a)

def test_bytes(self):
# Testing bytes of different lengths
a, b = b"foobar", b"foo"
self.assertFalse(compare_digest(a, b))
self.assert_digest_not_equal(a, b)
a, b = b"\xde\xad\xbe\xef", b"\xde\xad"
self.assertFalse(compare_digest(a, b))
self.assert_digest_not_equal(a, b)

# Testing bytes of same lengths, different values
a, b = b"foobar", b"foobaz"
self.assertFalse(compare_digest(a, b))
self.assert_digest_not_equal(a, b)
a, b = b"\xde\xad\xbe\xef", b"\xab\xad\x1d\xea"
self.assertFalse(compare_digest(a, b))
self.assert_digest_not_equal(a, b)

# Testing bytes of same lengths, same values
a, b = b"foobar", b"foobar"
self.assertTrue(compare_digest(a, b))
self.assert_digest_equal(a, b)
a, b = b"\xde\xad\xbe\xef", b"\xde\xad\xbe\xef"
self.assertTrue(compare_digest(a, b))
self.assert_digest_equal(a, b)

def test_bytearray(self):
# Testing bytearrays of same lengths, same values
a, b = bytearray(b"foobar"), bytearray(b"foobar")
self.assertTrue(compare_digest(a, b))
self.assert_digest_equal(a, b)

# Testing bytearrays of different lengths
a, b = bytearray(b"foobar"), bytearray(b"foo")
self.assertFalse(compare_digest(a, b))
self.assert_digest_not_equal(a, b)

# Testing bytearrays of same lengths, different values
a, b = bytearray(b"foobar"), bytearray(b"foobaz")
self.assertFalse(compare_digest(a, b))
self.assert_digest_not_equal(a, b)

def test_mixed_types(self):
# Testing byte and bytearray of same lengths, same values
a, b = bytearray(b"foobar"), b"foobar"
self.assertTrue(compare_digest(a, b))
self.assertTrue(compare_digest(b, a))
self.assert_digest_equal(a, b)

# Testing byte bytearray of different lengths
a, b = bytearray(b"foobar"), b"foo"
self.assertFalse(compare_digest(a, b))
self.assertFalse(compare_digest(b, a))
self.assert_digest_not_equal(a, b)

# Testing byte and bytearray of same lengths, different values
a, b = bytearray(b"foobar"), b"foobaz"
self.assertFalse(compare_digest(a, b))
self.assertFalse(compare_digest(b, a))
self.assert_digest_not_equal(a, b)

def test_string(self):
# Testing str of same lengths
a, b = "foobar", "foobar"
self.assertTrue(compare_digest(a, b))
self.assert_digest_equal(a, b)

# Testing str of different lengths
a, b = "foo", "foobar"
self.assertFalse(compare_digest(a, b))
self.assert_digest_not_equal(a, b)

# Testing bytes of same lengths, different values
# Testing str of same lengths, different values
a, b = "foobar", "foobaz"
self.assertFalse(compare_digest(a, b))

# Testing error cases
a, b = "foobar", b"foobar"
self.assertRaises(TypeError, compare_digest, a, b)
a, b = b"foobar", "foobar"
self.assertRaises(TypeError, compare_digest, a, b)
a, b = b"foobar", 1
self.assertRaises(TypeError, compare_digest, a, b)
a, b = 100, 200
self.assertRaises(TypeError, compare_digest, a, b)
a, b = "fooä", "fooä"
self.assertRaises(TypeError, compare_digest, a, b)

# subclasses are supported by ignore __eq__
class mystr(str):
self.assert_digest_not_equal(a, b)

def test_string_subclass(self):
class S(str):
def __eq__(self, other):
return False
raise ValueError("should not be called")

a, b = mystr("foobar"), mystr("foobar")
self.assertTrue(compare_digest(a, b))
a, b = mystr("foobar"), "foobar"
self.assertTrue(compare_digest(a, b))
a, b = mystr("foobar"), mystr("foobaz")
self.assertFalse(compare_digest(a, b))
a, b = S("foobar"), S("foobar")
self.assert_digest_equal(a, b)
a, b = S("foobar"), "foobar"
self.assert_digest_equal(a, b)
a, b = S("foobar"), S("foobaz")
self.assert_digest_not_equal(a, b)

class mybytes(bytes):
def test_bytes_subclass(self):
class B(bytes):
def __eq__(self, other):
return False

a, b = mybytes(b"foobar"), mybytes(b"foobar")
self.assertTrue(compare_digest(a, b))
a, b = mybytes(b"foobar"), b"foobar"
self.assertTrue(compare_digest(a, b))
a, b = mybytes(b"foobar"), mybytes(b"foobaz")
self.assertFalse(compare_digest(a, b))
raise ValueError("should not be called")

a, b = B(b"foobar"), B(b"foobar")
self.assert_digest_equal(a, b)
a, b = B(b"foobar"), b"foobar"
self.assert_digest_equal(a, b)
a, b = B(b"foobar"), B(b"foobaz")
self.assert_digest_not_equal(a, b)


class HMACCompareDigestTestCase(CompareDigestMixin, unittest.TestCase):
compare_digest = hmac.compare_digest

def test_compare_digest_func(self):
if openssl_compare_digest is not None:
self.assertIs(hmac.compare_digest, openssl_compare_digest)
else:
self.assertIs(hmac.compare_digest, operator_compare_digest)


@hashlib_helper.requires_hashlib()
class OpenSSLCompareDigestTestCase(CompareDigestMixin, unittest.TestCase):
compare_digest = openssl_compare_digest


class OperatorCompareDigestTestCase(CompareDigestMixin, unittest.TestCase):
compare_digest = operator_compare_digest


if __name__ == "__main__":
Expand Down