"""Shared crop primitive (#114) — pure Pillow, no DB, so it runs in the fast unit lane (no integration marker).""" from PIL import Image from backend.app.services.ml.crops import crop_region def _quadrant_img(): """400x400 red with a blue bottom-right quadrant, so a crop's content is checkable by pixel.""" img = Image.new("RGB", (400, 400), (255, 0, 0)) img.paste(Image.new("RGB", (200, 200), (0, 0, 255)), (200, 200)) return img def test_crop_returns_region_pixels(): crop = crop_region(_quadrant_img(), (0.5, 0.5, 0.5, 0.5)) assert crop is not None assert crop.size == (200, 200) assert crop.getpixel((100, 100)) == (0, 0, 255) # the blue quadrant def test_crop_below_floor_is_rejected(): # 0.05 * 400 = 20px on a side — below max(64, 0.10*400=40) → None. assert crop_region(_quadrant_img(), (0.0, 0.0, 0.05, 0.05)) is None def test_crop_clamped_to_image_bounds(): # Box runs off the right/bottom edge; clamps to the remaining 0.2*400=80px. crop = crop_region(_quadrant_img(), (0.8, 0.8, 0.5, 0.5)) assert crop is not None assert crop.size == (80, 80) def test_pad_expands_the_crop(): base = crop_region(_quadrant_img(), (0.4, 0.4, 0.2, 0.2)) padded = crop_region(_quadrant_img(), (0.4, 0.4, 0.2, 0.2), pad=0.5) assert base.size == (80, 80) assert padded.size[0] > base.size[0] and padded.size[1] > base.size[1] def test_out_size_resizes_square(): crop = crop_region(_quadrant_img(), (0.25, 0.25, 0.5, 0.5), out_size=224) assert crop.size == (224, 224)