Files
remove-ai-watermarks/tests/test_audioseal_oracle.py
T
Victor Kuznetsov 464fd142ea Add audio and video watermark benchmark oracles, cohorts, and research studies
Extend the development-only benchmark family from images to audio and
video, and close four research directions from the watermark-landscape
map with local, revision-pinned evidence.

Benchmark schema: media_type audio and video rows, audioseal and
videoseal adapters with media-checked adapter binding, sample-domain
audio fidelity (SNR with unbounded_identical), frame-domain video
fidelity (mean PSNR, changed-frame fraction), and per-frame temporal
evidence in videoseal detection records. The report accepts all three
media types and carries SNR columns.

Audio: shared pinned AudioSeal oracle, synthetic and system-voice
speech cohorts with matched negatives, codec, noise, removed, and
forged arms, and the provenance experiment proving visual-only video
cleaning leaves the audio bitstream and watermark verdict invariant.

Video: TorchScript-only VideoSeal oracle (the pip package is unusable
on macOS arm64 and its loader resolves paths relative to cwd), video
cohort with crf/scale/fps attacks and four-state arms, temporal
evaluation measuring the crf decay curve, the frame-aggregation matrix
(computed locally after finding the TorchScript build ignores the
aggregation argument), and real provider clips as carriers.

Forgery: double-embedding study showing the last writer wins completely
under both oracles, scoped remover-trace probe, and the forged/
removed cohort arms encoding each scheme's correct expected verdict
(presence rule for audioseal, message rule for videoseal).

C2PA resolution: measured the five vendors' resolver contracts and the
C2PA 2.2 18.10.5 privacy gradient; product decision recorded that this
tool never resolves over the network. A registry guard pins the
published resolution-API set.

Gate: ruff and pyright src/ clean, 2114 passed / 3 skipped; maintain.sh
stops only on the known unfixed lightning 2.6.5 CVEs, pre-existing.
2026-09-07 18:23:18 -07:00

42 lines
1.4 KiB
Python

"""Tests for the shared AudioSeal oracle's pure helpers."""
from __future__ import annotations
import sys
from pathlib import Path
import pytest
SCRIPTS = Path(__file__).resolve().parents[1] / "scripts"
if str(SCRIPTS) not in sys.path:
sys.path.insert(0, str(SCRIPTS))
from audioseal_oracle import SAMPLE_RATE, window_bounds # noqa: E402
class TestWindowBounds:
def test_exact_multiple_covers_every_sample_once(self) -> None:
bounds = window_bounds(32_000, 1.0, SAMPLE_RATE)
assert bounds == [(0, 16_000), (16_000, 32_000)]
def test_trailing_remainder_keeps_its_own_window(self) -> None:
bounds = window_bounds(32_500, 1.0, SAMPLE_RATE)
assert bounds[-1] == (32_000, 32_500)
assert len(bounds) == 3
def test_short_signal_is_one_partial_window(self) -> None:
assert window_bounds(100, 1.0, SAMPLE_RATE) == [(0, 100)]
def test_empty_signal_has_no_windows(self) -> None:
assert window_bounds(0, 1.0, SAMPLE_RATE) == []
@pytest.mark.parametrize(
("total", "window_s", "rate"),
[(-1, 1.0, 16_000), (100, 0.0, 16_000), (100, -1.0, 16_000), (100, 1.0, 0), (100, 0.00001, 16_000)],
)
def test_rejects_degenerate_arguments(self, total: int, window_s: float, rate: int) -> None:
with pytest.raises(ValueError, match=r"total_samples|window_s|sample_rate"):
window_bounds(total, window_s, rate)