
    /ii0                       d Z ddlmZ ddlZddlmZ ddlZddlZddl	m
Z
mZ  ed      Zej                  j                  d ee             ddlmZmZ ddlmZ d	Zd
Zg dZdddddddddddddddgZddddddZd-dZd.dZd.dZd.d Zd.d!Zd.d"Zej@                  jB                  d/d#       Z"ej@                  jF                  ej@                  jI                  d$ e%d%      D  cg c]  }  e%d%      D ]  }| |f  c}}       d0d&              Z&ej@                  jF                  d1d'       Z'ej@                  jF                  d1d(       Z(ej@                  jF                  d1d)       Z)ej@                  jF                  d1d*       Z*ej@                  jF                  d1d+       Z+ej@                  jF                  d1d,       Z,yc c}} w )2u  test_real_render_25.py — task-2428 Phase 2-4 회귀 테스트.

실 렌더링 25장 (h{1..5} × v{1..5}) + 적대 케이스 5건 검증:
  - 25장 batch: visual_diversity / brand_color / hybrid_pattern threshold 통과 보장
  - 적대 케이스 5건 (TV-static, 단조, 99% 회색, 한글 미달, 폰트 미달): FAIL 검출 보장

결정성 전략:
  - BASE_SEED=42 + 패턴별 1000 offset + 변형별 100 offset (재현 가능)
  - 환경 BLOCKED (tesseract 미설치): font_size/ocr_confidence 검증 BLOCKED 처리
  - smoke (단일) vs full (25장) 분리 — pytest -m smoke / -m full
  - 타임아웃: 패턴당 60초 (Satori 호출 timeout 120초의 1/2)

작성: 디자인팀 카구야 (단위 테스트 담당)
    )annotationsN)Path)Image	ImageDrawz*/home/jay/workspace/skills/satori-cardnews)
EvalResultevaluate_image)_render_with_seed*   )i8  iF  )h1_photo_cardh2_illustration_cardh3_gpt_style_cardh4_gradient_cardh5_user_photo_cardu   보험료 과다 청구u   올해 평균 23% 인상.)titlebodyu   실손보험 비교의 정석u!   월 4만원대 보장 격차 87%.u   갱신형 vs 비갱신형u"   10년 후 보험료 차이 2.4배.u   운전자보험 1만원 룰u&   과실 50% 합의금 평균 380만원.u   암보험 진단금 100% 약속u$   유사암 약관 회피 6개 상품.z#0f1729z#d4a853InsuRoz#fafaf8z#d4d8e0)primary	secondarynametitle_color
body_colorc                j    | j                   D cg c]  }d|vrd|vr| }}t        |      dkD  S c c}w )uN   visual/brand/hybrid 중 1개 이상 FAIL인지 확인 (환경 BLOCKED 무시).z[font_size]z[ocr_confidence]r   )fail_reasonslen)resultr
real_failss      >/home/jay/workspace/tests/skills/satori/test_real_render_25.py_is_visual_fail_onlyr   >   sM     &&!&8&A 	
J  z?Q	s   0c                    t         j                  j                  d      }|j                  dd|| dft         j                        }t        j                  |d      S )	uF   TV-static unstructured noise — 로키 [중대] 회귀 차단 대상.i  )seedr         )sizedtypeRGBmode)nprandomdefault_rngintegersuint8r   	fromarray)whrngarrs       r   _make_tv_staticr3   K   sJ    
))

S

)C
,,q#Q1IRXX,
>C??3U++    c                    t        j                  || dft         j                        }t        |      D ]"  }t	        d||z  dz  z         }|||ddddf<   $ t        j                  |d      S )u:   단조 그라데이션 — task-2401 회귀 차단 대상.r#   r%         Nr&   r'   )r)   zerosr-   rangeintr   r.   )r/   r0   r2   yvs        r   _make_monotone_gradientr>   R   sh    
((Aq!9BHH
-C1X a!er\!"Aq!G ??3U++r4   c                    t        j                  || dfdt         j                        }t        d|dz        }d|d|d| df<   d|d|d| df<   d|d|d| d	f<   t	        j
                  |d
      S )uE   99% 회색 + 1% 청록 — 로키 MEDIUM 면적 비율 우회 차단.r#      r6      d   r   N      r&   r'   )r)   fullr-   maxr   r.   )r/   r0   r2   band_hs       r   _make_99_gray_1_brandrH   [   s    
''1a)S
1CAHFC!QC!QC!Q??3U++r4   c                    t        j                  d| |fd      }t        j                  |      }|j	                  ddd       |S )u   OCR 한글 비율 < 50% (영문 위주) — 로키 LOW 우회 차단.

    실제 OCR 검증을 위한 이미지 — 환경에 tesseract 없으면 BLOCKED 처리됨.
    r&   r7   r7      color(   rO   u   SAVE 50% NOW JOIN HOM 한글   rQ   rQ   fillr   newr   Drawtextr/   r0   imgdraws       r   _make_korean_lt_50r[   f   s@    
 ))EAq6
6C>>#DIIh6_IMJr4   c                    t        j                  d| |fd      }t        j                  |      }|j	                  ddd       |S )u   폰트 < 40px — dq-rules.json absolute_min 위반.

    환경에 tesseract 없으면 BLOCKED — task-2421 정책에 따라 명시 알림.
    r&   rJ   rL   rN   u   tiny korean 한글 12pxrP   rR   rT   rX   s       r   _make_font_lt_40r]   r   s@    
 ))EAq6
6C>>#DIIh1IHJr4   c           	     F   | dz  }t         dz   dz   }t        t        d   t        dt        ||i        |j                         sJ |j                         j                  dkD  sJ t        |t        dt              }|j                  d   }|j                  d   }|j                  d	   }|d
   dk\  sJ d|d
           |d   dk\  sJ d|d           |d   dk  sJ d|d           |d   sJ d|j                  d              |d   sJ d|j                  d              y)u   smoke: h4 단일 렌더 — 통합 동작 빠른 확인 (< 5초).

    재현 시드: BASE_SEED + 3000 (h4 패턴 base offset).
    이 시드는 evidence-25-stratified-v4 h4_v1.png와 동일한 결과 산출.
    zsmoke_h4.pngi    r   r   content	design_mdhybrid_patterntarget_sizeoutput_pathr!   hintsvisual_diversitybrand_color_matchrc   std_mean      8@zsmoke h4 std_mean too low: unique_colorsz smoke h4 unique_colors too low: spatial_diff      9@z smoke h4 spatial_diff too high: passedzbrand_color_match FAIL: reasonzhybrid_pattern FAIL: N)	BASE_SEEDr	   CONTENTS	DESIGN_MDSIZEexistsstatst_sizer   detailsget)tmp_pathoutr!   r   visualbrandhybrids          r   test_smoke_h4_single_renderr~      sv    ^
#C td"D) ::<<88:$$$ C,>EF^^./FNN./E^^,-F*% 
%fZ&8%9:% /"d* 
*6/+B*CD* .!T) 
*6.+A*BC) ?L6uyy7J6KLL?(K4VZZ5I4JKKr4   zpi,vi   c                   t         |   }t        |   }t        |dz  z   |dz  z   dz   }| |j                  d      d    d|dz    dz  }t	        |t
        |t        ||i        |j                         sJ t        |t
        |t              }|j                  d	   }|j                  d
   }	|dk(  r7|d   dk\  r|d   dk\  r|d   dk  siJ d|dz    d|d    d|d    d|d           |d   sEJ | d|dz    d|j                  d       d|j                  d       d|j                  d       	       |	d   s!J | d|dz    d|	j                  d              y)u   25장 stratified: 각 (pattern, variant) 쌍이 visual+brand+hybrid 통과.

    환경 BLOCKED (OCR/font_size)는 별도 검증. 본 테스트는 visual_diversity,
    brand_color_match, hybrid_pattern threshold만 검증한다.
    r_   rB   _r   _vrA   .pngr`   rg   rh   r   ri   rj   rk   rl   rm   zh4 vz: std=z unique=z spat=rn   z vz visual_diversity FAIL: ro   z; std=z brand_color FAIL: N)PATTERNSrq   rp   splitr	   rr   rs   rt   r   rw   rx   )
ry   pivipatternra   r!   rz   r   r{   r|   s
             r   !test_25_stratified_visual_qualityr      s    rlGrlG rDy 28+d2D
c*1-.ba=
=C ::<<CGT:F ^^./FNN./E$$j!T)f_.E.MRXYgRhlpRp 	
2a4&vj12(6/;R:S T>*+-	
p
 h 	
ir"Q$7

88L7M N::j)*(6::o3N2OQ	
 ? )2bdV.uyy/B.CD?r4   c                     t        t         } t        d      }| j                  |       t	        |t
        dt              }t        |      s-J d|j                  d   d    d|j                  d   d           y)	uY   적대 케이스 1: TV-static spatial_diff > 25 → FAIL 검출 보장 (로키 [중대]).z/tmp/adv_tv_static.pngr   u8   TV-static 차단 실패 (silent pass 회귀!): std_mean=rg   ri   z, spatial_diff=rl   N)r3   rs   r   saver   rr   r   rw   )rY   tmpr   s      r   "test_adversarial_tv_static_blockedr      s     4
 C
'
(CHHSMCOTBF' NN#56zBC D'9:>JK	M'r4   c                     t        t         } t        d      }| j                  |       t	        |t
        dt              }|j                  d   }|d   rJ d|d    d|d           |d   d	k  sJ d
|d    d       y)uU   적대 케이스 2: 단조 그라데이션 std_mean < 25 → FAIL 검출 (task-2401).z/tmp/adv_monotone.pngr   rg   rn   u&   단조 회귀 차단 실패: std_mean=ri   z, unique_colors=rk   rm   u&   단조 std_mean 임계 검증 실패: z >= 25N)r>   rs   r   r   r   rr   rw   )rY   r   r   r{   s       r   *test_adversarial_monotone_gradient_blockedr      s     "4
(C
&
'CHHSMC,>EF^^./Fh 
0
1C0D E01	3 *$ 
0
1C0DFK$r4   c                     t        t         } t        d      }| j                  |       i t        ddi}t        ||dt              }|j                  d   }|d   rJ d|j                  d              y	)
uc   적대 케이스 3: 99% 회색 + 1% 청록 → matching_area_ratio < 0.10 → FAIL (로키 MEDIUM).z/tmp/adv_99gray.pngr   z#00c5c5r   rh   rn   u4   1% 면적 우회 차단 실패: matching_area_ratio=matching_area_ratioN)rH   rs   r   r   rr   r   rw   rx   )rY   r   mdr   r|   s        r   (test_adversarial_99_gray_1_brand_blockedr      s      
&C
$
%CHHSM	,I	,y)	,BC%7>FNN./EX 
>uyyI^?_>`ar4   c                     t        t         } t        d      }| j                  |       t	        |t
        dt              }|j                  d   }|j                  dd      r|j                  dd      s
J d|        y	y	)
u   적대 케이스 4: OCR 한글 < 50% → FAIL or BLOCKED (로키 LOW).

    환경에 tesseract 있으면 한글 비율 < 0.5 → FAIL.
    환경에 tesseract 없으면 BLOCKED (silent pass 차단).
    z/tmp/adv_korean_lt50.pngr   ocr_confidencern   TblockedFu(   한글 비율 우회 차단 실패: ocr=N)r[   rs   r   r   r   rr   rw   rx   )rY   r   r   ocrs       r   %test_adversarial_korean_lt_50_blockedr     s{     d
#C
)
*CHHSMCOTBF
..)
*C$'CGGIu,E 
23%8E,E'r4   c                     t        t         } t        d      }| j                  |       t	        |t
        dt              }|j                  d   }|j                  dd      r|j                  dd      s
J d|        y	y	)
uS   적대 케이스 5: 폰트 < 40px → FAIL or BLOCKED (dq-rules.json absolute_min).z/tmp/adv_font_lt40.pngr   	font_sizern   Tr   Fu"   폰트 미달 차단 실패: font=N)r]   rs   r   r   r   rr   rw   rx   )rY   r   r   fonts       r   #test_adversarial_font_lt_40_blockedr     sz     D
!C
'
(CHHSMCOTBF>>+&D4(TXXi-G 
,TF3G-G(r4   c                    t        d      } | j                         st        j                  d       t        D ]q  }|j                  d      d   }t        dd      D ]L  }| | d| dz  }| | d| d	z  }|j                         s
J d
|        |j                         rDJ d|         s | dz  }|dz  j                         sJ |dz  j                         sJ | dz  j                         sJ y)uY   evidence-25-stratified-v4 디렉토리 무결성 — 27장 PNG + meta JSON 존재 확인.zF/home/jay/workspace/memory/reports/task-2424-evidence-25-stratified-v4uH   evidence 디렉토리 미생성 — render_25.py 실행 후 재테스트r   r   rA      r   r   z
.meta.jsonu   PNG 누락: u   meta 누락: extraszsupabase_h4.pngzfinancial_h4.pngz
SUMMARY.mdN)r   rt   pytestskipr   r   r:   )basepshortr=   pngmetar   s          r   %test_evidence_25_dir_artifact_presentr   '  s    XYD;;=^_ 9Qq! 	9AE7"QCt,,CUG2aS
33D::<5<u!55<;;=8M$"88=		99 H_F&&..000''//111<'')))r4   )r   r   returnbool)r/   r;   r0   r;   r   zImage.Image)ry   r   r   None)ry   r   r   r;   r   r;   r   r   )r   r   )-__doc__
__future__r   syspathlibr   numpyr)   r   PILr   r   _SATORI_ROOTpathinsertstrscripts.quality_evaluatorr   r   scripts.retry_loopr	   rp   rs   r   rq   rr   r   r3   r>   rH   r[   r]   marksmoker~   rE   parametrizer:   r   r   r   r   r   r   r   )r   r=   s   00r   <module>r      s   # 
      @A 3|$ % 1
 	 (1LM-7Z[)3WX+5]^/9_` 	,,,		  'L 'LT 58"NaU1X"NAq6"N6"NO) P )X 
 
    
 
  " 	 	 * *u #Os   ,G