Skip to content

Commit

Permalink
Annotations for tests, part 2 (#728)
Browse files Browse the repository at this point in the history
* Annotations for test_encoding

* Annotations for test_exc

* Annotations for test_generichash

Only fix here was to add an assertion to some bare equality tests.
The other changes are just clarifications.

* Annotations for test_hash

* Annotations for test_hashlib_scrypt

* Annotations for test_kx

* Annotations for test_public

* Annotations for test_pwhash

* Don't use TypedDict

This doesn't exist in the stdbib until Python 3.8, and I don't think
it's worth the faff to pull in `typing_extensions` just to annotate test
source code.
  • Loading branch information
DMRobertson committed Dec 23, 2021
1 parent 3f34a25 commit e980348
Show file tree
Hide file tree
Showing 9 changed files with 184 additions and 78 deletions.
16 changes: 16 additions & 0 deletions pyproject.toml
Expand Up @@ -45,6 +45,14 @@ files = [
"tests/test_aead.py",
"tests/test_bindings.py",
"tests/test_box.py",
"tests/test_encoding.py",
"tests/test_exc.py",
"tests/test_generichash.py",
"tests/test_hash.py",
"tests/test_hashlib_scrypt.py",
"tests/test_kx.py",
"tests/test_public.py",
"tests/test_pwhash.py",
"tests/test_signing.py",
"tests/utils.py",
]
Expand Down Expand Up @@ -78,6 +86,14 @@ module = [
"tests.test_aead",
"tests.test_bindings",
"tests.test_box",
"tests.test_encoding",
"tests.test_exc",
"tests.test_generichash",
"tests.test_hash",
"tests.test_hashlib_scrypt",
"tests.test_kx",
"tests.test_public",
"tests.test_pwhash",
"tests.test_signing",
]
# Some library helpers types' involve `Any`, in particular `pytest.mark.parameterize`
Expand Down
2 changes: 1 addition & 1 deletion tests/test_encoding.py
Expand Up @@ -74,7 +74,7 @@


@pytest.mark.parametrize(("encoder", "ciphertext"), VECTORS)
def test_encoders(encoder, ciphertext):
def test_encoders(encoder: nacl.encoding.Encoder, ciphertext: bytes):
box = nacl.secret.SecretBox(KEY)

test_ciphertext = box.encrypt(TEXT, NONCE, encoder=encoder)
Expand Down
21 changes: 18 additions & 3 deletions tests/test_exc.py
Expand Up @@ -22,20 +22,35 @@ class CustomError(exc.CryptoError):
pass


# Type safety: mypy can spot comparisons that will always evaluate to False, and the
# bad argument type. Suppress these: we want to test these are detected at runtime.


def test_exceptions_ensure_with_true_condition():
exc.ensure(1 == 1, "one equals one")


def test_exceptions_ensure_with_false_condition():
with pytest.raises(exc.AssertionError):
exc.ensure(1 == 0, "one is not zero", raising=exc.AssertionError)
exc.ensure(
1 == 0, # type: ignore[comparison-overlap]
"one is not zero",
raising=exc.AssertionError,
)


def test_exceptions_ensure_with_unwanted_kwarg():
with pytest.raises(exc.TypeError):
exc.ensure(1 == 1, unexpected="unexpected")
exc.ensure(
1 == 1,
unexpected="unexpected", # type: ignore[arg-type]
)


def test_exceptions_ensure_custom_exception():
with pytest.raises(CustomError):
exc.ensure(1 == 0, "Raising a CustomError", raising=CustomError)
exc.ensure(
1 == 0, # type: ignore[comparison-overlap]
"Raising a CustomError",
raising=CustomError,
)
83 changes: 58 additions & 25 deletions tests/test_generichash.py
Expand Up @@ -12,11 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.


import binascii
import copy
import json
import os
from typing import AnyStr, Dict, List, Tuple, Union

import pytest

Expand All @@ -36,23 +36,29 @@
]


def generichash_vectors():
def generichash_vectors() -> List[Tuple[bytes, bytes, bytes, bytes]]:
# Format: <message> <tab> <key> <tab> <output length> <tab> <output>
DATA = "crypto-test-vectors-blake2-nosalt-nopersonalization.txt"
return read_crypto_test_vectors(DATA, delimiter=b"\t")
# Type safety: read_crypto_test_vectors returns an arbitrary length tuple, but we
# know this file's test entries contain exactly four fields.
return read_crypto_test_vectors(DATA, delimiter=b"\t") # type: ignore[return-value]


def blake2_salt_pers_vectors():
def blake2_salt_pers_vectors() -> List[
Tuple[bytes, bytes, bytes, bytes, bytes, bytes]
]:
# Format: <message> <tab> <key> <tab> <salt> <tab>
# <personalization> <tab> <output length> <tab> <output>
DATA = "crypto-test-vectors-blake2-salt-personalization.txt"
return read_crypto_test_vectors(DATA, delimiter=b"\t")
# Type safety: read_crypto_test_vectors returns an arbitrary length tuple, but we
# know this file's test entries contain exactly six fields.
return read_crypto_test_vectors(DATA, delimiter=b"\t") # type: ignore[return-value]


def blake2_reference_vectors():
def blake2_reference_vectors() -> List[Tuple[str, str, int, str]]:
DATA = "blake2-kat.json"
path = os.path.join(os.path.dirname(__file__), "data", DATA)
jvectors = json.load(open(path))
jvectors: List[Dict[str, str]] = json.load(open(path))
vectors = [
(x["in"], x["key"], len(x["out"]) // 2, x["out"])
for x in jvectors
Expand All @@ -64,21 +70,28 @@ def blake2_reference_vectors():
@pytest.mark.parametrize(
["message", "key", "outlen", "output"], generichash_vectors()
)
def test_generichash(message, key, outlen, output):
def test_generichash(
message: AnyStr, key: AnyStr, outlen: Union[AnyStr, int], output: AnyStr
):
msg = binascii.unhexlify(message)
output = binascii.hexlify(binascii.unhexlify(output))
output_bytes = binascii.hexlify(binascii.unhexlify(output))
k = binascii.unhexlify(key)
outlen = int(outlen)
out = nacl.hash.generichash(msg, digest_size=outlen, key=k)
assert out == output
outlen_parsed = int(outlen)
out = nacl.hash.generichash(msg, digest_size=outlen_parsed, key=k)
assert out == output_bytes


@pytest.mark.parametrize(
["message", "key", "salt", "person", "outlen", "output"],
OVERLONG_PARAMS_VECTORS,
)
def test_overlong_blake2b_oneshot_params(
message, key, salt, person, outlen, output
message: bytes,
key: bytes,
salt: bytes,
person: bytes,
outlen: int,
output: bytes,
):
with pytest.raises(exc.ValueError):
nacl.hash.blake2b(
Expand All @@ -89,23 +102,32 @@ def test_overlong_blake2b_oneshot_params(
@pytest.mark.parametrize(
["message", "key", "outlen", "output"], blake2_reference_vectors()
)
def test_generichash_blake2_ref(message, key, outlen, output):
def test_generichash_blake2_ref(
message: str, key: str, outlen: int, output: str
):
test_generichash(message, key, outlen, output)


@pytest.mark.parametrize(
["message", "key", "salt", "person", "outlen", "output"],
blake2_salt_pers_vectors(),
)
def test_hash_blake2b(message, key, salt, person, outlen, output):
def test_hash_blake2b(
message: bytes,
key: bytes,
salt: bytes,
person: bytes,
outlen: bytes,
output: bytes,
):
msg = binascii.unhexlify(message)
output = binascii.hexlify(binascii.unhexlify(output))
k = binascii.unhexlify(key)
slt = binascii.unhexlify(salt)
pers = binascii.unhexlify(person)
outlen = int(outlen)
outlen_parsed = int(outlen)
out = nacl.hash.blake2b(
msg, digest_size=outlen, key=k, salt=slt, person=pers
msg, digest_size=outlen_parsed, key=k, salt=slt, person=pers
)
assert out == output

Expand Down Expand Up @@ -134,7 +156,9 @@ def test_expected_bindings_level_pickle_and_copy_failures():
@pytest.mark.parametrize(
["message", "key", "outlen", "output"], blake2_reference_vectors()
)
def test_hashlib_blake2_ref_vectors(message, key, outlen, output):
def test_hashlib_blake2_ref_vectors(
message: str, key: str, outlen: int, output: str
):
msg = binascii.unhexlify(message)
k = binascii.unhexlify(key)
outlen = int(outlen)
Expand All @@ -147,7 +171,9 @@ def test_hashlib_blake2_ref_vectors(message, key, outlen, output):
@pytest.mark.parametrize(
["message", "key", "outlen", "output"], blake2_reference_vectors()
)
def test_hashlib_blake2_iuf_ref_vectors(message, key, outlen, output):
def test_hashlib_blake2_iuf_ref_vectors(
message: str, key: str, outlen: int, output: str
):
msg = binascii.unhexlify(message)
k = binascii.unhexlify(key)
outlen = int(outlen)
Expand All @@ -165,7 +191,9 @@ def test_hashlib_blake2_iuf_ref_vectors(message, key, outlen, output):
@pytest.mark.parametrize(
["message", "key", "outlen", "output"], blake2_reference_vectors()
)
def test_hashlib_blake2_iuf_cp_ref_vectors(message, key, outlen, output):
def test_hashlib_blake2_iuf_cp_ref_vectors(
message: str, key: str, outlen: int, output: str
):
msg = binascii.unhexlify(message)
msglen = len(msg)
if msglen < 2:
Expand All @@ -190,7 +218,12 @@ def test_hashlib_blake2_iuf_cp_ref_vectors(message, key, outlen, output):
OVERLONG_PARAMS_VECTORS,
)
def test_overlong_blake2b_iuf_params(
message, key, salt, person, outlen, output
message: bytes,
key: bytes,
salt: bytes,
person: bytes,
outlen: int,
output: bytes,
):
with pytest.raises(exc.ValueError):
nacl.hashlib.blake2b(
Expand All @@ -201,12 +234,12 @@ def test_overlong_blake2b_iuf_params(
def test_blake2_descriptors_presence():
h = nacl.hashlib.blake2b()
assert h.name == "blake2b"
h.block_size == 128
h.digest_size == 32 # this is the default digest_size
assert h.block_size == 128
assert h.digest_size == 32 # this is the default digest_size


def test_blake2_digest_size_descriptor_coherence():
h = nacl.hashlib.blake2b(digest_size=64)
assert h.name == "blake2b"
h.block_size == 128
h.digest_size == 64
assert h.block_size == 128
assert h.digest_size == 64
10 changes: 4 additions & 6 deletions tests/test_hash.py
Expand Up @@ -11,8 +11,6 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


import pytest

import nacl.encoding
Expand All @@ -32,7 +30,7 @@
),
],
)
def test_sha256_hex(inp, expected):
def test_sha256_hex(inp: bytes, expected: bytes):
assert nacl.hash.sha256(inp) == expected


Expand All @@ -55,7 +53,7 @@ def test_sha256_hex(inp, expected):
),
],
)
def test_sha256_binary(inp, expected):
def test_sha256_binary(inp: bytes, expected: bytes):
assert nacl.hash.sha256(inp, encoder=nacl.encoding.RawEncoder) == expected


Expand All @@ -78,7 +76,7 @@ def test_sha256_binary(inp, expected):
),
],
)
def test_sha512_hex(inp, expected):
def test_sha512_hex(inp: bytes, expected: bytes):
assert nacl.hash.sha512(inp) == expected


Expand All @@ -104,5 +102,5 @@ def test_sha512_hex(inp, expected):
),
],
)
def test_sha512_binary(inp, expected):
def test_sha512_binary(inp: bytes, expected: bytes):
assert nacl.hash.sha512(inp, encoder=nacl.encoding.RawEncoder) == expected
10 changes: 9 additions & 1 deletion tests/test_hashlib_scrypt.py
Expand Up @@ -119,7 +119,15 @@
@pytest.mark.parametrize(
("password", "salt", "n", "r", "p", "dklen", "expected"), RFC_7914_VECTORS
)
def test_hashlib_scrypt_api(password, salt, n, r, p, dklen, expected):
def test_hashlib_scrypt_api(
password: bytes,
salt: bytes,
n: int,
r: int,
p: int,
dklen: int,
expected: bytes,
):
_exp = unhexlify(expected.replace(b" ", b""))
dgst = nacl.hashlib.scrypt(
password, salt=salt, n=n, r=r, p=p, dklen=dklen, maxmem=2 * (1024 ** 3)
Expand Down
9 changes: 5 additions & 4 deletions tests/test_kx.py
Expand Up @@ -34,7 +34,7 @@ def test_crypto_kx_keypair():
binary(min_size=32, max_size=32),
)
@settings(max_examples=100)
def test_crypto_kx_seed_keypair(seed1, seed2):
def test_crypto_kx_seed_keypair(seed1: bytes, seed2: bytes):
seeded = b.crypto_kx_seed_keypair(seed1)
seeded_other = b.crypto_kx_seed_keypair(seed2)
if seed1 != seed2:
Expand All @@ -47,7 +47,7 @@ def test_crypto_kx_seed_keypair(seed1, seed2):
binary(min_size=33, max_size=128),
)
@settings(max_examples=20, suppress_health_check=[HealthCheck.too_slow])
def test_crypto_kx_seed_keypair_seed_too_large(seed):
def test_crypto_kx_seed_keypair_seed_too_large(seed: bytes):
with pytest.raises(exc.TypeError):
b.crypto_kx_seed_keypair(seed)

Expand All @@ -56,7 +56,7 @@ def test_crypto_kx_seed_keypair_seed_too_large(seed):
binary(min_size=0, max_size=31),
)
@settings(max_examples=20)
def test_crypto_kx_seed_keypair_seed_too_small(seed):
def test_crypto_kx_seed_keypair_seed_too_small(seed: bytes):
with pytest.raises(exc.TypeError):
b.crypto_kx_seed_keypair(seed)

Expand All @@ -66,7 +66,7 @@ def test_crypto_kx_seed_keypair_seed_too_small(seed):
binary(min_size=32, max_size=32),
)
@settings(max_examples=100)
def test_crypto_kx_session_keys(seed1, seed2):
def test_crypto_kx_session_keys(seed1: bytes, seed2: bytes):
s_keys = b.crypto_kx_seed_keypair(seed1)
c_keys = b.crypto_kx_seed_keypair(seed2)

Expand All @@ -85,6 +85,7 @@ def test_crypto_kx_session_wrong_key_lengths():
s_keys = b.crypto_kx_keypair()
c_keys = b.crypto_kx_keypair()

# TODO: should invalid argument lengths (but correct types) raise ValueError?
with pytest.raises(exc.TypeError):
b.crypto_kx_server_session_keys(s_keys[0][:-1], s_keys[1], c_keys[0])

Expand Down

0 comments on commit e980348

Please sign in to comment.