diff --git a/.github/workflows/tox.yml b/.github/workflows/tox.yml index 74f3ea8..4c3d66e 100644 --- a/.github/workflows/tox.yml +++ b/.github/workflows/tox.yml @@ -23,6 +23,8 @@ jobs: fail-fast: false steps: - uses: actions/checkout@v4 + with: + submodules: recursive - uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} @@ -50,6 +52,8 @@ jobs: fail-fast: false steps: - uses: actions/checkout@v4 + with: + submodules: recursive - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v5 with: diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..fea4701 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "spec/multihash"] + path = spec/multihash + url = https://github.com/multiformats/multihash.git diff --git a/MANIFEST.in b/MANIFEST.in index 965b2dd..75e41c8 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -9,3 +9,4 @@ recursive-exclude * __pycache__ recursive-exclude * *.py[co] recursive-include docs *.rst conf.py Makefile make.bat *.jpg *.png *.gif +graft spec diff --git a/newsfragments/53.misc.rst b/newsfragments/53.misc.rst new file mode 100644 index 0000000..3269635 --- /dev/null +++ b/newsfragments/53.misc.rst @@ -0,0 +1 @@ +Add official multihash spec vector tests validating :func:`~multihash.sum` against ``spec/multihash`` test cases. diff --git a/spec/multihash b/spec/multihash new file mode 160000 index 0000000..b43ec10 --- /dev/null +++ b/spec/multihash @@ -0,0 +1 @@ +Subproject commit b43ec1026a610fa87878e53b3daecf3a14b3ef6f diff --git a/tests/test_spec_vectors.py b/tests/test_spec_vectors.py new file mode 100644 index 0000000..90f3da6 --- /dev/null +++ b/tests/test_spec_vectors.py @@ -0,0 +1,49 @@ +"""Official multihash spec vector tests.""" + +import csv +from binascii import hexlify +from pathlib import Path + +import pytest + +from multihash import FuncReg, HashComputationError, sum + +SPEC_VECTORS = Path(__file__).resolve().parents[1] / "spec" / "multihash" / "tests" / "values" / "test_cases.csv" + +# Spec CSV uses "sha3" as an alias for sha3-512 (same as go-multihash). +_ALGORITHM_ALIASES = { + "sha3": "sha3-512", +} + + +def _load_cases(): + if not SPEC_VECTORS.is_file(): + pytest.skip(f"spec vectors not found at {SPEC_VECTORS} (init git submodules?)") + with SPEC_VECTORS.open(newline="") as f: + reader = csv.reader(f) + next(reader) # header + return list(reader) + + +@pytest.mark.parametrize("algorithm,bits_str,input_hex,expected_hex", _load_cases()) +def test_spec_vectors(algorithm, bits_str, input_hex, expected_hex): + """Validate sum() against official multihash test vectors. + + The CSV ``input`` column is hashed as UTF-8/ASCII of the hex string itself + (not as decoded binary), matching go-multihash ``TestSpecVectors``. + """ + algorithm = _ALGORITHM_ALIASES.get(algorithm, algorithm) + length_bytes = int(bits_str) // 8 + data = input_hex.encode() + + try: + FuncReg.get(algorithm) + except KeyError: + pytest.skip(f"hash {algorithm} not registered") + + try: + actual = sum(data, algorithm, length=length_bytes) + except (HashComputationError, KeyError, ValueError) as exc: + pytest.skip(f"hash {algorithm} unavailable: {exc}") + + assert hexlify(actual.encode()).decode() == expected_hex