import numpy as np from edge.models import BBox from edge.snapshot import RingBuffer, FaceBlurrer, Snapshotter def _frame(val=128): return np.full((64, 64, 3), val, dtype=np.uint8) def test_ringbuffer_keeps_recent(): rb = RingBuffer(maxlen=3) for i in range(5): rb.push(float(i), _frame(i)) assert len(rb.frames) == 3 assert rb.frames[-1][0] == 4.0 def test_timeline_picks_frames_nearest_to_offsets(): rb = RingBuffer(maxlen=90) for i in range(6): # t = 0..5, 1초 간격 rb.push(float(i), _frame(i * 10), [BBox(i, 0, i + 1, 1)]) frames, boxes = rb.timeline(now=5.0, offsets_s=(2.5, 1.0, 0.0)) assert len(frames) == 3 # 과거→현재 순: 목표 2.5/4.0/5.0초에 가장 가까운 t=2(또는 3), 4, 5 assert frames[-1][0, 0, 0] == 50 # 마지막은 현재 프레임 assert boxes[-1][0].x1 == 5 # 각 프레임의 '자기 시점' 블러 박스 assert frames[0][0, 0, 0] < frames[1][0, 0, 0] < frames[2][0, 0, 0] def test_timeline_short_buffer_returns_fewer_without_duplicates(): rb = RingBuffer(maxlen=90) rb.push(0.0, _frame(10), []) frames, boxes = rb.timeline(now=0.0, offsets_s=(2.5, 1.0, 0.0)) assert len(frames) == 1 # 기동 직후: 있는 프레임 하나만, 중복 없음 assert len(boxes) == 1 def test_face_blur_actually_destroys_the_region(): # PIPA 대응의 유일한 실행 가능한 증거. 이전 버전은 out is not None / shape만 봤기 때문에 # blur()가 `return frame`(무동작)으로 퇴화해도 통과했다 — 즉 "스냅샷은 익명화되어 전송된다"는 # 제품의 약속을 뒷받침하지 못했다. 픽셀이 실제로 뭉개졌는지 단언한다. fb = FaceBlurrer() f = _frame(0) f[0:10, 0:10] = 255 f[0:10:2, 0:10] = 0 # 줄무늬 = 얼굴을 식별하게 하는 고주파 디테일 before = f[0:10, 0:10].copy() out = fb.blur(f.copy(), [BBox(0, 0, 10, 10)]) assert out.shape == f.shape face = out[0:10, 0:10] assert not np.array_equal(face, before), "얼굴 영역이 원본 그대로 남았다" # 단순히 '달라졌다'가 아니라 디테일이 파괴됐는지를 본다: 분산이 한 자릿수 %로 떨어져야 # 원본 패턴을 복원할 수 없다. 블러가 약해지면(sigma 축소 등) 이 단언이 먼저 깨진다. assert face.var() < before.var() * 0.1 # 얼굴 밖은 건드리지 않는다 — 증거 가치가 남아야 한다(자세·위치·주변 상황). assert np.array_equal(out[32:64, 32:64], f[32:64, 32:64]) def test_face_blur_without_boxes_leaves_frame_untouched(): # 박스가 비면 무동작이어야 한다. 이 경로가 조용히 전체를 뭉개면 증거가 사라진다. fb = FaceBlurrer() f = _frame(90) assert np.array_equal(fb.blur(f.copy(), []), f) def test_snapshotter_returns_jpeg_bytes(): snap = Snapshotter(FaceBlurrer()) imgs = snap.capture([_frame(100), _frame(120)], [[], []]) assert 1 <= len(imgs) <= 3 assert imgs[0][:2] == b"\xff\xd8" # JPEG magic