Skip to content

Commit df30b78

Browse files
authored
Get test_crypto.py to typecheck! (#1400)
1 parent 67d973a commit df30b78

File tree

2 files changed

+90
-67
lines changed

2 files changed

+90
-67
lines changed

tests/test_crypto.py

+89-66
Original file line numberDiff line numberDiff line change
@@ -1605,22 +1605,16 @@ def test_set_attribute_failure(self) -> None:
16051605
setattr(name, "O", b"x" * 512)
16061606

16071607

1608-
class _PKeyInteractionTestsMixin:
1608+
class TestX509Req:
16091609
"""
1610-
Tests which involve another thing and a PKey.
1610+
Tests for `OpenSSL.crypto.X509Req`.
16111611
"""
16121612

1613-
def signable(self):
1614-
"""
1615-
Return something with `set_pubkey` and `sign` methods.
1616-
"""
1617-
raise NotImplementedError()
1618-
16191613
def test_sign_with_ungenerated(self) -> None:
16201614
"""
16211615
`X509Req.sign` raises `ValueError` when passed a `PKey` with no parts.
16221616
"""
1623-
request = self.signable()
1617+
request = X509Req()
16241618
key = PKey()
16251619
with pytest.raises(ValueError):
16261620
request.sign(key, GOOD_DIGEST)
@@ -1630,7 +1624,7 @@ def test_sign_with_public_key(self) -> None:
16301624
`X509Req.sign` raises `ValueError` when passed a `PKey` with no private
16311625
part as the signing key.
16321626
"""
1633-
request = self.signable()
1627+
request = X509Req()
16341628
key = PKey()
16351629
key.generate_key(TYPE_RSA, 2048)
16361630
request.set_pubkey(key)
@@ -1643,7 +1637,7 @@ def test_sign_with_unknown_digest(self) -> None:
16431637
`X509Req.sign` raises `ValueError` when passed a digest name which is
16441638
not known.
16451639
"""
1646-
request = self.signable()
1640+
request = X509Req()
16471641
key = PKey()
16481642
key.generate_key(TYPE_RSA, 2048)
16491643
with pytest.raises(ValueError):
@@ -1655,7 +1649,7 @@ def test_sign(self) -> None:
16551649
valid digest function. `X509Req.verify` can be used to check
16561650
the signature.
16571651
"""
1658-
request = self.signable()
1652+
request = X509Req()
16591653
key = PKey()
16601654
key.generate_key(TYPE_RSA, 2048)
16611655
request.set_pubkey(key)
@@ -1670,18 +1664,6 @@ def test_sign(self) -> None:
16701664
with pytest.raises(Error):
16711665
request.verify(key)
16721666

1673-
1674-
class TestX509Req(_PKeyInteractionTestsMixin):
1675-
"""
1676-
Tests for `OpenSSL.crypto.X509Req`.
1677-
"""
1678-
1679-
def signable(self):
1680-
"""
1681-
Create and return a new `X509Req`.
1682-
"""
1683-
return X509Req()
1684-
16851667
def test_construction(self) -> None:
16861668
"""
16871669
`X509Req` takes no arguments and returns an `X509Req` instance.
@@ -1848,23 +1830,57 @@ def test_convert_to_cryptography_key(self) -> None:
18481830
assert isinstance(crypto_req, x509.CertificateSigningRequest)
18491831

18501832

1851-
class TestX509(_PKeyInteractionTestsMixin):
1833+
class TestX509:
18521834
"""
18531835
Tests for `OpenSSL.crypto.X509`.
18541836
"""
18551837

18561838
pemData = root_cert_pem + root_key_pem
18571839

1858-
def signable(self):
1840+
def test_sign_with_ungenerated(self) -> None:
1841+
"""
1842+
`X509.sign` raises `ValueError` when passed a `PKey` with no parts.
1843+
"""
1844+
cert = X509()
1845+
key = PKey()
1846+
with pytest.raises(ValueError):
1847+
cert.sign(key, GOOD_DIGEST)
1848+
1849+
def test_sign_with_public_key(self) -> None:
18591850
"""
1860-
Create and return a new `X509`.
1851+
`X509.sign` raises `ValueError` when passed a `PKey` with no private
1852+
part as the signing key.
18611853
"""
1862-
certificate = X509()
1863-
# Fill in placeholder validity values. signable only expects to call
1864-
# set_pubkey and sign.
1865-
certificate.gmtime_adj_notBefore(-24 * 60 * 60)
1866-
certificate.gmtime_adj_notAfter(24 * 60 * 60)
1867-
return certificate
1854+
cert = X509()
1855+
key = PKey()
1856+
key.generate_key(TYPE_RSA, 2048)
1857+
cert.set_pubkey(key)
1858+
pub = cert.get_pubkey()
1859+
with pytest.raises(ValueError):
1860+
cert.sign(pub, GOOD_DIGEST)
1861+
1862+
def test_sign_with_unknown_digest(self) -> None:
1863+
"""
1864+
`X509.sign` raises `ValueError` when passed a digest name which is
1865+
not known.
1866+
"""
1867+
cert = X509()
1868+
key = PKey()
1869+
key.generate_key(TYPE_RSA, 2048)
1870+
with pytest.raises(ValueError):
1871+
cert.sign(key, BAD_DIGEST)
1872+
1873+
def test_sign(self) -> None:
1874+
"""
1875+
`X509.sign` succeeds when passed a private key object and a
1876+
valid digest function. `X509Req.verify` can be used to check
1877+
the signature.
1878+
"""
1879+
cert = X509()
1880+
key = PKey()
1881+
key.generate_key(TYPE_RSA, 2048)
1882+
cert.set_pubkey(key)
1883+
cert.sign(key, GOOD_DIGEST)
18681884

18691885
def test_construction(self) -> None:
18701886
"""
@@ -1912,63 +1928,64 @@ def test_serial_number(self) -> None:
19121928
certificate.set_serial_number(2**128 + 1)
19131929
assert certificate.get_serial_number() == 2**128 + 1
19141930

1915-
def _setBoundTest(self, which):
1931+
def _setBoundTest(
1932+
self,
1933+
get: typing.Callable[[X509], bytes | None],
1934+
set: typing.Callable[[X509, bytes], None],
1935+
) -> None:
19161936
"""
19171937
`X509.set_notBefore` takes a string in the format of an
19181938
ASN1 GENERALIZEDTIME and sets the beginning of the certificate's
19191939
validity period to it.
19201940
"""
19211941
certificate = X509()
1922-
set = getattr(certificate, "set_not" + which)
1923-
get = getattr(certificate, "get_not" + which)
19241942

19251943
# Starts with no value.
1926-
assert get() is None
1944+
assert get(certificate) is None
19271945

19281946
# GMT (Or is it UTC?) -exarkun
19291947
when = b"20040203040506Z"
1930-
set(when)
1931-
assert get() == when
1948+
set(certificate, when)
1949+
assert get(certificate) == when
19321950

19331951
# A plus two hours and thirty minutes offset
19341952
when = b"20040203040506+0530"
1935-
set(when)
1936-
assert get() == when
1953+
set(certificate, when)
1954+
assert get(certificate) == when
19371955

19381956
# A minus one hour fifteen minutes offset
19391957
when = b"20040203040506-0115"
1940-
set(when)
1941-
assert get() == when
1958+
set(certificate, when)
1959+
assert (
1960+
get(
1961+
certificate,
1962+
)
1963+
== when
1964+
)
19421965

19431966
# An invalid string results in a ValueError
19441967
with pytest.raises(ValueError):
1945-
set(b"foo bar")
1946-
1947-
# The wrong number of arguments results in a TypeError.
1948-
with pytest.raises(TypeError):
1949-
set()
1950-
with pytest.raises(TypeError):
1951-
set(b"20040203040506Z", b"20040203040506Z")
1952-
with pytest.raises(TypeError):
1953-
get(b"foo bar")
1954-
1955-
# XXX ASN1_TIME (not GENERALIZEDTIME)
1968+
set(certificate, b"foo bar")
19561969

19571970
def test_set_notBefore(self) -> None:
19581971
"""
19591972
`X509.set_notBefore` takes a string in the format of an
19601973
ASN1 GENERALIZEDTIME and sets the beginning of the certificate's
19611974
validity period to it.
19621975
"""
1963-
self._setBoundTest("Before")
1976+
self._setBoundTest(
1977+
lambda c: c.get_notBefore(), lambda c, v: c.set_notBefore(v)
1978+
)
19641979

19651980
def test_set_notAfter(self) -> None:
19661981
"""
19671982
`X509.set_notAfter` takes a string in the format of an ASN1
19681983
GENERALIZEDTIME and sets the end of the certificate's validity period
19691984
to it.
19701985
"""
1971-
self._setBoundTest("After")
1986+
self._setBoundTest(
1987+
lambda c: c.get_notAfter(), lambda c, v: c.set_notAfter(v)
1988+
)
19721989

19731990
def test_get_notBefore(self) -> None:
19741991
"""
@@ -2463,7 +2480,7 @@ def test_load_locations_parameters(
24632480
capath: str | bytes | None,
24642481
call_cafile: object,
24652482
call_capath: object,
2466-
monkeypatch,
2483+
monkeypatch: pytest.MonkeyPatch,
24672484
) -> None:
24682485
class LibMock:
24692486
def load_locations(
@@ -3244,7 +3261,7 @@ def test_untrusted_chain_wrong_args(
32443261
X509StoreContext(store, self.intermediate_server_cert, chain=chain)
32453262

32463263
def test_failure_building_untrusted_chain_raises(
3247-
self, monkeypatch
3264+
self, monkeypatch: pytest.MonkeyPatch
32483265
) -> None:
32493266
"""
32503267
Creating ``X509StoreContext`` raises ``OpenSSL.crypto.Error`` when
@@ -3625,30 +3642,36 @@ def test_delegatedEq(self) -> None:
36253642
The result of comparison using C{==} is delegated to the right-hand
36263643
operand if it is of an unrelated type.
36273644
"""
3645+
called = False
36283646

36293647
class Delegate:
3630-
def __eq__(self, other):
3631-
# Do something crazy and obvious.
3632-
return [self]
3648+
def __eq__(self, other: object) -> bool:
3649+
nonlocal called
3650+
called = True
3651+
return False
36333652

36343653
a = self.anInstance()
36353654
b = Delegate()
3636-
assert (a == b) == [b] # type: ignore[comparison-overlap]
3655+
assert not (a == b)
3656+
assert called
36373657

36383658
def test_delegateNe(self) -> None:
36393659
"""
36403660
The result of comparison using C{!=} is delegated to the right-hand
36413661
operand if it is of an unrelated type.
36423662
"""
3663+
called = False
36433664

36443665
class Delegate:
3645-
def __ne__(self, other):
3646-
# Do something crazy and obvious.
3647-
return [self]
3666+
def __ne__(self, other: object) -> bool:
3667+
nonlocal called
3668+
called = True
3669+
return False
36483670

36493671
a = self.anInstance()
36503672
b = Delegate()
3651-
assert (a != b) == [b] # type: ignore[comparison-overlap]
3673+
assert not (a != b) # type: ignore[comparison-overlap]
3674+
assert called
36523675

36533676

36543677
class TestEllipticCurveHash:

tox.ini

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ extras =
4747
deps =
4848
mypy
4949
commands =
50-
mypy src/ tests/conftest.py
50+
mypy src/ tests/conftest.py tests/test_crypto.py
5151

5252
[testenv:check-manifest]
5353
deps =

0 commit comments

Comments
 (0)