double-exposure / tests /test_app.py
Eddie Faillace
double-exposure app deploy snapshot 2026-07-21 (WP-24 calibration pass)
7dff04f
Raw
History Blame Contribute Delete
6.3 kB
"""WP-0: Tests for the Gradio application — build_app constructs successfully."""
from __future__ import annotations
import gradio as gr
class TestBuildApp:
def test_build_app_returns_blocks(self):
from app.main import build_app
demo = build_app()
assert isinstance(demo, gr.Blocks)
def test_build_app_has_expected_components(self):
from app.main import build_app
demo = build_app()
# Blocks should be a non-empty layout tree
assert demo is not None
def test_build_app_idempotent(self):
from app.main import build_app
demo1 = build_app()
demo2 = build_app()
assert isinstance(demo1, gr.Blocks)
assert isinstance(demo2, gr.Blocks)
class TestProcessNegativeWP13:
"""WP-13 D5: process_negative runs green with affine/flat_guard wiring."""
def test_process_negative_on_fixture(self):
import numpy as np
from PIL import Image
from app.main import process_negative
data = np.load("synth/fixtures/case_000.npz")
scan = data["scan"].astype(np.float32)
upload = Image.fromarray((scan * 255.0).clip(0, 255).astype(np.uint8))
out = process_negative(
upload,
film_stock="Generic",
physics_weight=1.0,
perceptual_weight=0.5,
num_candidates=3,
include_deep_prior=False,
full_res_export=False,
scan_type="Positive",
scan_calibration="auto-exposed",
auto_trim=False,
)
# 11-tuple return
assert len(out) == 11
positive_pil, recombined_pil, img_a, img_b, status, best_state, ranked, gallery, conf, fa, fb = out
assert img_a is not None and img_b is not None
assert ranked is not None and len(ranked) >= 1
assert "Error" not in (status or "")
# Affine ranking path should produce finite hybrid scores
assert np.isfinite(ranked[0].score.total_loss)
# Best must not be a flat solid pair when structured candidates exist
from app.scoring import _is_flat_pair
obs = np.asarray(positive_pil.convert("RGB"), dtype=np.float32) / 255.0
# Use preprocessed observed from best_state if available
if best_state and best_state.get("observed_rgb") is not None:
obs = best_state["observed_rgb"]
a = ranked[0].separation.image_a
b = ranked[0].separation.image_b
# With guard on, if anything non-flat exists best should not be flat
assert not _is_flat_pair(a, b, obs) or len(ranked) == 1
class TestAsymmetricWP14:
"""WP-14 D3: checkbox OFF byte-identical; ON offline asym_sub + note."""
def _upload(self):
import numpy as np
from PIL import Image
data = np.load("synth/fixtures/case_000.npz")
scan = data["scan"].astype(np.float32)
return Image.fromarray((scan * 255.0).clip(0, 255).astype(np.uint8))
def test_checkbox_off_byte_identical_population(self):
"""Default path (asym OFF) matches explicit asymmetric_recovery=False."""
import os
from app.main import process_negative
upload = self._upload()
kwargs = dict(
film_stock="Generic",
physics_weight=1.0,
perceptual_weight=0.5,
num_candidates=3,
include_deep_prior=False,
full_res_export=False,
scan_type="Positive",
scan_calibration="auto-exposed",
auto_trim=False,
)
# Ensure no accidental key influence
old = os.environ.pop("REPLICATE_API_TOKEN", None)
try:
out_default = process_negative(upload, **kwargs)
out_off = process_negative(upload, **kwargs, asymmetric_recovery=False)
finally:
if old is not None:
os.environ["REPLICATE_API_TOKEN"] = old
ranked_d = out_default[6]
ranked_o = out_off[6]
assert ranked_d is not None and ranked_o is not None
ids_d = [r.candidate_id for r in ranked_d]
ids_o = [r.candidate_id for r in ranked_o]
assert ids_d == ids_o
# No asym candidates when off
assert "asym_sub" not in ids_d
assert "asym_fill" not in ids_d
# Scores byte-identical
for a, b in zip(ranked_d, ranked_o):
assert a.candidate_id == b.candidate_id
assert abs(a.score.total_loss - b.score.total_loss) < 1e-12
def test_checkbox_on_offline_asym_sub_no_network(self):
"""ON without keys → asym_sub present; offline note; no network attempted."""
import os
from unittest.mock import patch
from app.main import process_negative, ASYM_CONSENT
upload = self._upload()
old_r = os.environ.pop("REPLICATE_API_TOKEN", None)
old_a = os.environ.pop("ANTHROPIC_API_KEY", None)
try:
with patch("app.asymmetric._replicate_inpaint") as mock_inpaint:
mock_inpaint.side_effect = AssertionError("network must not be called")
out = process_negative(
upload,
film_stock="Generic",
physics_weight=1.0,
perceptual_weight=0.5,
num_candidates=3,
include_deep_prior=False,
full_res_export=False,
scan_type="Positive",
scan_calibration="auto-exposed",
auto_trim=False,
asymmetric_recovery=True,
asymmetric_anchor="Auto",
)
mock_inpaint.assert_not_called()
finally:
if old_r is not None:
os.environ["REPLICATE_API_TOKEN"] = old_r
if old_a is not None:
os.environ["ANTHROPIC_API_KEY"] = old_a
status = out[4] or ""
ranked = out[6]
assert ranked is not None
ids = [r.candidate_id for r in ranked]
assert "asym_sub" in ids, f"asym_sub missing from {ids}"
assert "asym_fill" not in ids
assert "offline" in status.lower() or "no REPLICATE" in status or ASYM_CONSENT[:40] in status
assert "Asymmetric recovery" in status