fieldwitness/tests/test_attest_hashing.py
Aaron D. Lee 490f9d4a1d Rebrand SooSeF to FieldWitness
Complete project rebrand for better positioning in the press freedom
and digital security space. FieldWitness communicates both field
deployment and evidence testimony — appropriate for the target audience
of journalists, NGOs, and human rights organizations.

Rename mapping:
- soosef → fieldwitness (package, CLI, all imports)
- soosef.stegasoo → fieldwitness.stego
- soosef.verisoo → fieldwitness.attest
- ~/.soosef/ → ~/.fwmetadata/ (innocuous data dir name)
- SOOSEF_DATA_DIR → FIELDWITNESS_DATA_DIR
- SoosefConfig → FieldWitnessConfig
- SoosefError → FieldWitnessError

Also includes:
- License switch from MIT to GPL-3.0
- C2PA bridge module (Phase 0-2 MVP): cert.py, export.py, vendor_assertions.py
- README repositioned to lead with provenance/federation, stego backgrounded
- Threat model skeleton at docs/security/threat-model.md
- Planning docs: docs/planning/c2pa-integration.md, docs/planning/gtm-feasibility.md

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 15:05:13 -04:00

86 lines
2.6 KiB
Python

"""Basic tests for image hashing."""
from io import BytesIO
import pytest
from PIL import Image
from fieldwitness.attest.hashing import hash_image, perceptual_distance, is_same_image
def create_test_image(width: int = 100, height: int = 100, color: tuple = (255, 0, 0)) -> bytes:
"""Create a simple test image."""
img = Image.new("RGB", (width, height), color)
buffer = BytesIO()
img.save(buffer, format="PNG")
return buffer.getvalue()
class TestHashImage:
"""Tests for hash_image function."""
def test_hash_returns_all_components(self):
"""Hash should return sha256, phash, and dhash."""
image_data = create_test_image()
hashes = hash_image(image_data)
assert hashes.sha256
assert hashes.phash
assert hashes.dhash
assert len(hashes.sha256) == 64 # SHA-256 hex
def test_identical_images_same_hash(self):
"""Identical bytes should produce identical hashes."""
image_data = create_test_image()
hash1 = hash_image(image_data)
hash2 = hash_image(image_data)
assert hash1.sha256 == hash2.sha256
assert hash1.phash == hash2.phash
assert hash1.dhash == hash2.dhash
def test_different_images_different_hash(self):
"""Different images should produce different SHA-256."""
red = create_test_image(color=(255, 0, 0))
blue = create_test_image(color=(0, 0, 255))
hash_red = hash_image(red)
hash_blue = hash_image(blue)
assert hash_red.sha256 != hash_blue.sha256
class TestPerceptualDistance:
"""Tests for perceptual distance calculation."""
def test_identical_hashes_zero_distance(self):
"""Identical hashes should have zero distance."""
h = "0123456789abcdef"
assert perceptual_distance(h, h) == 0
def test_different_hashes_nonzero_distance(self):
"""Different hashes should have positive distance."""
h1 = "0000000000000000"
h2 = "0000000000000001"
assert perceptual_distance(h1, h2) == 1
def test_completely_different_max_distance(self):
"""Completely different hashes should have max distance."""
h1 = "0000000000000000"
h2 = "ffffffffffffffff"
assert perceptual_distance(h1, h2) == 64 # 16 hex chars = 64 bits
class TestIsSameImage:
"""Tests for image comparison."""
def test_exact_match(self):
"""Identical bytes should be exact match."""
image_data = create_test_image()
hash1 = hash_image(image_data)
hash2 = hash_image(image_data)
is_same, reason = is_same_image(hash1, hash2)
assert is_same
assert reason == "exact"