Files
fn_registry/python/functions/ml/tests/test_pixeloe_downscale.py
T

123 lines
4.7 KiB
Python

"""Tests de pixeloe_downscale — tolerantes al entorno.
El venv del registry NO trae `pixeloe`, asi que estas pruebas ejercitan el
"bridge" de interprete (subprocess al python de ComfyUI, que si la tiene). Si
tampoco hay ningun interprete con pixeloe disponible, la funcion debe degradar
limpiamente: ok=False con error no vacio y SIN lanzar excepcion.
Por eso cada test PASA en los dos escenarios:
- pixeloe disponible (inproc o via bridge): assert sobre el resultado real.
- pixeloe ausente en todos lados: assert sobre la degradacion no-throw.
Asi la suite es verde tanto en este PC (ComfyUI presente) como en uno sin ComfyUI,
y el contrato "no-throw" queda cubierto en ambos.
"""
import os
import sys
import numpy as np
from PIL import Image
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from ml.pixeloe_downscale import pixeloe_downscale # noqa: E402
def _shapes_png(path, w=256, h=256):
"""PNG 256x256 RGB con un gradiente + formas (contraste con silueta clara)."""
yy, xx = np.mgrid[0:h, 0:w]
arr = np.zeros((h, w, 3), dtype=np.uint8)
arr[..., 0] = (xx * 255 // max(1, w - 1)).astype(np.uint8) # gradiente rojo
arr[..., 1] = (yy * 255 // max(1, h - 1)).astype(np.uint8) # gradiente verde
# Bloque azul central: borde duro para que el modo "contrast" tenga silueta.
arr[h // 4:3 * h // 4, w // 4:3 * w // 4, 2] = 255
Image.fromarray(arr, "RGB").save(path)
return path
def test_golden_downscale_64_or_clean_degrade(tmp_path):
"""Golden: 256x256 -> grid 64x64 (no_upscale). Si pixeloe no esta -> ok=False limpio."""
src = _shapes_png(str(tmp_path / "raw.png"))
dst = str(tmp_path / "grid64.png")
res = pixeloe_downscale(src, dst, target_size=64, no_upscale=True)
assert isinstance(res, dict)
if res["ok"]:
assert os.path.isfile(dst)
assert res["size"] == [64, 64] # no_upscale=True -> grid real
assert res["error"] == ""
assert res["via"] in ("inproc", "bridge")
assert res["mode"] == "contrast"
assert res["target_size"] == 64
else:
# Degradacion limpia: sin pixeloe en ningun interprete.
assert res["error"] != ""
assert res["via"] in ("", "bridge", "inproc")
def test_edge_target_size_32(tmp_path):
"""Edge: grid de 32 (iconos). size==[32,32] cuando pixeloe esta presente."""
src = _shapes_png(str(tmp_path / "raw.png"))
dst = str(tmp_path / "grid32.png")
res = pixeloe_downscale(src, dst, target_size=32, no_upscale=True)
if res["ok"]:
assert res["size"] == [32, 32]
assert res["target_size"] == 32
assert os.path.isfile(dst)
else:
assert res["error"] != ""
def test_edge_mode_nearest_no_color_matching(tmp_path):
"""Edge: otro modo + color_matching off; debe seguir produciendo el grid o degradar."""
src = _shapes_png(str(tmp_path / "raw.png"))
dst = str(tmp_path / "near.png")
res = pixeloe_downscale(
src, dst, mode="nearest", target_size=64,
color_matching=False, no_upscale=True,
)
assert isinstance(res, dict)
if res["ok"]:
assert res["mode"] == "nearest"
assert res["size"] == [64, 64]
else:
assert res["error"] != ""
def test_error_missing_src_no_throw(tmp_path):
"""Error path: src inexistente -> ok=False, error explica, sin excepcion."""
res = pixeloe_downscale(
str(tmp_path / "nope.png"), str(tmp_path / "o.png"), target_size=64,
)
assert res["ok"] is False
assert "no existe" in res["error"]
assert res["size"] == [0, 0]
def test_error_no_interpreter_with_pixeloe(tmp_path):
"""Error path: forzar comfy_python invalido cuando el actual no tiene pixeloe.
Si el interprete que corre el test YA tiene pixeloe (inproc), el comfy_python
invalido se ignora y la llamada puede salir ok=True; el test sigue siendo
valido (no-throw). Si NO lo tiene, no hay ningun interprete con pixeloe y debe
devolver ok=False con error, nunca lanzar.
"""
src = _shapes_png(str(tmp_path / "raw.png"))
dst = str(tmp_path / "o.png")
res = pixeloe_downscale(
src, dst, target_size=64, comfy_python="/no/such/python-interpreter",
)
assert isinstance(res, dict)
try:
import pixeloe # noqa: F401
has_local = True
except Exception: # noqa: BLE001
has_local = False
if has_local:
# pixeloe en el interprete del test -> ruta inproc, comfy_python ignorado.
assert res["ok"] is True
else:
# comfy_python invalido + env vacio: si ~/ComfyUI/.venv existe, puede
# bridgear y salir ok; si no, ok=False con error. Ambos no-throw.
assert res["ok"] in (True, False)
if not res["ok"]:
assert res["error"] != ""