Integration tests (350 passing): - test_evidence_summary.py: HTML/PDF generation, XSS safety, anchor rendering - test_tor.py: Tor module unit tests (mocked, no Tor needed) - test_c2pa_importer.py: Import result dataclass, trust evaluation, graceful degradation - test_file_attestation.py: All file types (PNG, PDF, CSV, empty, large), determinism - test_paths.py: Registry correctness, env var override, all paths under BASE_DIR - test_killswitch_coverage.py: Tor keys, trusted keys, carrier history destruction Playwright e2e infrastructure: - tests/e2e/ with conftest (live server, auth fixtures), helpers (test file generators) - test_auth.py: Setup flow, login/logout, protected routes - test_attest.py: Image/PDF/CSV attestation, verify, attestation log - test_dropbox.py: Token creation, source upload, branding check - test_keys.py: Identity display, trust store - test_fieldkit.py: Status dashboard, killswitch page - test_navigation.py: All nav links, responsive layout Run: pytest (unit/integration) or pytest -m e2e tests/e2e/ (browser) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
208 lines
7.5 KiB
Python
208 lines
7.5 KiB
Python
"""Integration tests for c2pa_bridge/importer.py — data-mapping logic.
|
|
|
|
All tests run without c2pa-python installed. Tests that exercise the full
|
|
import pipeline are skipped automatically when c2pa-python is absent.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import fields
|
|
from typing import Any
|
|
|
|
import pytest
|
|
|
|
from fieldwitness.c2pa_bridge.importer import C2PAImportResult, import_c2pa
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# test_c2pa_import_result_dataclass
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TestC2PAImportResultDataclass:
|
|
def test_required_fields_exist(self):
|
|
expected = {"success", "manifests", "attestation_record",
|
|
"fieldwitness_assertions", "trust_status"}
|
|
actual = {f.name for f in fields(C2PAImportResult)}
|
|
assert expected.issubset(actual)
|
|
|
|
def test_error_field_exists(self):
|
|
field_names = {f.name for f in fields(C2PAImportResult)}
|
|
assert "error" in field_names
|
|
|
|
def test_construct_success_result(self):
|
|
result = C2PAImportResult(
|
|
success=True,
|
|
manifests=[],
|
|
attestation_record=None,
|
|
fieldwitness_assertions={},
|
|
trust_status="unknown",
|
|
error=None,
|
|
)
|
|
assert result.success is True
|
|
assert result.error is None
|
|
|
|
def test_construct_failure_result(self):
|
|
result = C2PAImportResult(
|
|
success=False,
|
|
manifests=[],
|
|
attestation_record=None,
|
|
fieldwitness_assertions={},
|
|
trust_status="invalid",
|
|
error="c2pa-python is not installed",
|
|
)
|
|
assert result.success is False
|
|
assert result.error is not None
|
|
|
|
def test_manifests_is_list(self):
|
|
result = C2PAImportResult(
|
|
success=False,
|
|
manifests=[{"key": "value"}],
|
|
attestation_record=None,
|
|
fieldwitness_assertions={},
|
|
trust_status="unknown",
|
|
)
|
|
assert isinstance(result.manifests, list)
|
|
|
|
def test_fieldwitness_assertions_is_dict(self):
|
|
result = C2PAImportResult(
|
|
success=True,
|
|
manifests=[],
|
|
attestation_record=None,
|
|
fieldwitness_assertions={"org.fieldwitness.perceptual-hashes": {}},
|
|
trust_status="self-signed",
|
|
)
|
|
assert isinstance(result.fieldwitness_assertions, dict)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# test_import_without_c2pa_returns_error
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TestImportWithoutC2pa:
|
|
def test_returns_failure_result(self):
|
|
"""import_c2pa must never raise — it returns a failure C2PAImportResult."""
|
|
# Pass dummy bytes; without c2pa-python this should fail gracefully.
|
|
result = import_c2pa(b"dummy image data", "jpeg")
|
|
|
|
# Either c2pa is installed (success possible) or we get a clean failure.
|
|
if not result.success:
|
|
assert result.error is not None
|
|
assert len(result.error) > 0
|
|
|
|
def test_no_exception_raised_for_any_input(self):
|
|
"""import_c2pa must not propagate exceptions regardless of input."""
|
|
# Various bad inputs — all must be caught internally.
|
|
for image_data, fmt in [
|
|
(b"", "jpeg"),
|
|
(b"\x00" * 100, "png"),
|
|
(b"not an image", "webp"),
|
|
]:
|
|
result = import_c2pa(image_data, fmt)
|
|
assert isinstance(result, C2PAImportResult)
|
|
|
|
def test_failure_result_has_trust_status(self):
|
|
"""Even a failure result must carry a trust_status string."""
|
|
result = import_c2pa(b"garbage", "jpeg")
|
|
assert isinstance(result.trust_status, str)
|
|
assert len(result.trust_status) > 0
|
|
|
|
def test_failure_result_has_empty_manifests(self):
|
|
"""On failure without c2pa, manifests must be an empty list."""
|
|
try:
|
|
import c2pa # noqa: F401
|
|
pytest.skip("c2pa-python is installed — this test covers the absent case")
|
|
except ImportError:
|
|
pass
|
|
|
|
result = import_c2pa(b"garbage", "jpeg")
|
|
assert result.manifests == []
|
|
|
|
def test_error_message_mentions_install(self):
|
|
"""When c2pa is absent, the error message must include install guidance."""
|
|
try:
|
|
import c2pa # noqa: F401
|
|
pytest.skip("c2pa-python is installed — this test covers the absent case")
|
|
except ImportError:
|
|
pass
|
|
|
|
result = import_c2pa(b"dummy", "jpeg")
|
|
assert not result.success
|
|
assert "pip install" in (result.error or "")
|
|
|
|
def test_unsupported_format_returns_failure(self):
|
|
"""An unsupported image format must return success=False with an error."""
|
|
try:
|
|
import c2pa # noqa: F401
|
|
except ImportError:
|
|
pytest.skip("c2pa-python not installed; format validation not reached")
|
|
|
|
result = import_c2pa(b"dummy", "bmp")
|
|
assert not result.success
|
|
assert result.error is not None
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# test_trust_status_values
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TestTrustStatusValues:
|
|
"""Verify the four trust statuses are valid, non-empty strings."""
|
|
|
|
VALID_STATUSES = {"trusted", "self-signed", "unknown", "invalid"}
|
|
|
|
def test_trusted_is_valid_string(self):
|
|
assert "trusted" in self.VALID_STATUSES
|
|
|
|
def test_self_signed_is_valid_string(self):
|
|
assert "self-signed" in self.VALID_STATUSES
|
|
|
|
def test_unknown_is_valid_string(self):
|
|
assert "unknown" in self.VALID_STATUSES
|
|
|
|
def test_invalid_is_valid_string(self):
|
|
assert "invalid" in self.VALID_STATUSES
|
|
|
|
def test_all_statuses_are_non_empty(self):
|
|
for status in self.VALID_STATUSES:
|
|
assert len(status) > 0
|
|
|
|
def test_result_trust_status_is_one_of_valid(self):
|
|
"""Every C2PAImportResult.trust_status value must be in the valid set."""
|
|
# Absent c2pa returns "unknown"; with c2pa and corrupt data returns "invalid".
|
|
result = import_c2pa(b"not a real image", "jpeg")
|
|
assert result.trust_status in self.VALID_STATUSES
|
|
|
|
def test_evaluate_trust_invalid_flag(self):
|
|
"""Internal _evaluate_trust must return 'invalid' when _fw_invalid is set."""
|
|
from fieldwitness.c2pa_bridge.importer import _evaluate_trust
|
|
|
|
manifest: dict[str, Any] = {"_fw_invalid": True}
|
|
assert _evaluate_trust(manifest, trusted_certs=None) == "invalid"
|
|
|
|
def test_evaluate_trust_unknown_for_no_cert(self):
|
|
"""No cert chain and no invalid flag -> 'unknown'."""
|
|
from fieldwitness.c2pa_bridge.importer import _evaluate_trust
|
|
|
|
manifest: dict[str, Any] = {"signature_info": {}}
|
|
assert _evaluate_trust(manifest, trusted_certs=None) == "unknown"
|
|
|
|
def test_evaluate_trust_self_signed_fw(self):
|
|
"""Self-signed cert + 'FieldWitness' in claim_generator -> 'self-signed'."""
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
from fieldwitness.c2pa_bridge.importer import _evaluate_trust
|
|
|
|
dummy_pem = "DUMMY_PEM"
|
|
|
|
with patch("fieldwitness.c2pa_bridge.importer._cert_is_self_signed", return_value=True):
|
|
manifest: dict[str, Any] = {
|
|
"claim_generator": "FieldWitness/0.3.0",
|
|
"signature_info": {"cert_chain": [dummy_pem]},
|
|
}
|
|
result = _evaluate_trust(manifest, trusted_certs=None)
|
|
|
|
assert result == "self-signed"
|