52 lines
1.7 KiB
Python
52 lines
1.7 KiB
Python
"""Tests for Password hashing and verification."""
|
|||
|
|
|
||
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
from volumen.password import hash_password, verify_password
|
||
|
|
|
||
|
|
|
||
|
|
class TestHash:
|
||
|
|
def test_hash_produces_string(self) -> None:
|
||
|
|
result = hash_password("secret")
|
||
|
|
assert isinstance(result, str)
|
||
|
|
|
||
|
|
def test_hash_format(self) -> None:
|
||
|
|
result = hash_password("pw")
|
||
|
|
assert result.startswith("scrypt$16384$8$1$")
|
||
|
|
|
||
|
|
def test_hash_is_deterministic_in_format(self) -> None:
|
||
|
|
result = hash_password("pw")
|
||
|
|
parts = result.split("$")
|
||
|
|
assert len(parts) == 6
|
||
|
|
assert parts[0] == "scrypt"
|
||
|
|
assert parts[1] == "16384"
|
||
|
|
assert parts[2] == "8"
|
||
|
|
assert parts[3] == "1"
|
||
|
|
|
||
|
|
|
||
|
|
class TestVerify:
|
||
|
|
def test_verify_correct_password(self) -> None:
|
||
|
|
encoded = hash_password("s3cret")
|
||
|
|
assert verify_password("s3cret", encoded) is True
|
||
|
|
|
||
|
|
def test_verify_wrong_password(self) -> None:
|
||
|
|
encoded = hash_password("s3cret")
|
||
|
|
assert verify_password("nope", encoded) is False
|
||
|
|
|
||
|
|
def test_verify_empty_string(self) -> None:
|
||
|
|
encoded = hash_password("")
|
||
|
|
assert verify_password("", encoded) is True
|
||
|
|
|
||
|
|
def test_verify_malformed_input(self) -> None:
|
||
|
|
assert verify_password("x", "not-a-hash") is False
|
||
|
|
assert verify_password("x", "") is False
|
||
|
|
|
||
|
|
def test_verify_tampered_hash(self) -> None:
|
||
|
|
encoded = hash_password("s3cret")
|
||
|
|
tampered = encoded[:-1] + ("X" if encoded[-1] != "X" else "Y")
|
||
|
|
assert verify_password("s3cret", tampered) is False
|
||
|
|
|
||
|
|
def test_verify_empty_password_against_hash(self) -> None:
|
||
|
|
encoded = hash_password("secret")
|
||
|
|
assert verify_password("", encoded) is False
|