
    Ii"                       d Z ddlmZ ddlZddlZddlmZ ddlZ ed      Z	d Z
 ej                  d      d	        Z ej                  d      d
        Z ej                  d      d        Z ej                  d      d        Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Z d Z!y)u   task-2401 — IDS Phase 1 satori 한글 폰트 임베드 회귀 테스트.

silent corruption (한글 □□□, 빈 검은 화면) 영구 차단.
    )annotationsN)Pathz/home/jay/workspacec                   t         j                  j                  | |      }||j                  
J d|        t         j                  j	                  |      }|t
        j                  | <   |j                  j                  |       |S )Nzfailed to spec )	importlibutilspec_from_file_locationloadermodule_from_specsysmodulesexec_module)namepathspecmods       J/home/jay/workspace/tests/design-team/test_ids_phase1_korean_font_embed.py_loadr      sr    >>11$=D 7Q?4&9QQ7
..
)
)$
/CCKKKKC J    module)scopec                 (    t        dt        dz        S )N
_sc_satori!skills/satori-cardnews/_satori.pyr   	WORKSPACE r   r   
satori_modr      s    y+NNOOr   c                 (    t        dt        dz        S )N
_sc_verify/skills/satori-cardnews/scripts/verify_korean.pyr   r   r   r   
verify_modr!      s    y+\\]]r   c                 (    t        dt        dz        S )N
_sc_renderz,skills/satori-cardnews/scripts/render_one.pyr   r   r   r   
render_modr$      s    y+YYZZr   c                 (    t        dt        dz        S )Nz$skills.hybrid_image.patterns._satoriz'skills/hybrid-image/patterns/_satori.pyr   r   r   r   hi_satori_modr&       s    7En9noor   c                    | j                   D cg c]  }|j                         s| }}t        |      dk\  sJ d| j                           yc c}w )u;   Pretendard 폰트 파일이 명시 경로에 실제 존재.   zno Pretendard font at N)PRETENDARD_PATHSexistslenr   pfounds      r   #test_01_pretendard_font_paths_existr/   &   sM    "33B1qxxzQBEBu:?R4Z5P5P4QRR? Cs
   AAc                    | j                   D cg c]  }|j                         s| }}t        |      dk\  sJ yc c}w )u1   NotoSansCJK fallback 폰트 명시 경로 존재.r(   N)NOTO_CJK_PATHSr*   r+   r,   s      r   !test_02_noto_cjk_font_paths_existr2   +   s9    "11@1QXXZQ@E@u:?? As   <<c                    | j                         }t        |t              rt        |      dk\  sJ t	        d |D              sJ t        d |D              sJ y)u:   find_korean_fonts → satori-호환 dict 리스트 반환.r(   c              3  0   K   | ]  }d |v xr d|v   yw)r   r   Nr   .0fs     r   	<genexpr>z9test_03_find_korean_fonts_returns_list.<locals>.<genexpr>4   s      :qv{*v{*:s   c              3  ,   K   | ]  }|d    dk(    yw)r   
PretendardNr   r5   s     r   r8   z9test_03_find_korean_fonts_returns_list.<locals>.<genexpr>5   s     8QqyL(8s   N)find_korean_fonts
isinstancelistr+   allany)r   fontss     r   &test_03_find_korean_fonts_returns_listrA   0   sR    ((*EeT"s5zQ66:E::::8%8888r   c                h    | j                   }d|vrd|vrd|j                         vsJ d|v rd|v sJ y)uA   KOREAN_FONT_STACK에 Arial/Helvetica/sans-serif 절대 미포함.Arial	Helveticaz
sans-serifr:   zNoto Sans KRN)KOREAN_FONT_STACKlower)r   ss     r   5test_04_korean_font_stack_constant_no_system_fallbackrH   7   sG    $$A!1 4QWWY9VVV11!444!4r   c                x    | j                          | j                          |j                  j                  dv sJ y)u(   install_silent_fallback_guard 멱등성.)_blocked_fallback_blockedN)install_silent_fallback_guard_pillow_fallback__name__)r   r&   s     r   1test_05_silent_fallback_guard_installs_idempotentrO   =   s5    ,,.,,.))226WWWWr   c                    | j                          t        j                  t        d      5  |j	                  d|dz  dd       ddd       y# 1 sw Y   yxY w)uF   guard 후 hybrid-image _pillow_fallback 호출 시 RuntimeError raise.silent fallback blockedmatchz<div>test</div>x.pngd   widthheightN)rL   pytestraisesRuntimeErrorrM   r   r&   tmp_paths      r   $test_06_guard_blocks_pillow_fallbackr^   D   sU    ,,.	|+D	E e&&'8(W:LTW`c&de e es   AAc                    | j                          t        j                  t        d      5  |j	                  |dz  dd       ddd       y# 1 sw Y   yxY w)u9   guard 후 _write_blank_png 호출 시 RuntimeError raise.rQ   rR   rT   rU   N)rL   rY   rZ   r[   _write_blank_pngr\   s      r   $test_07_guard_blocks_write_blank_pngra   J   sM    ,,.	|+D	E E&&x''93DE E Es   AAc                    d| j                   z   dz   }|dz  }| j                  ||dd      }|j                         sJ |j                         j                  dk\  s"J d|j                         j                          y	)
u0   safe_render_html_to_png 정상 동작 + ≥10KB.zq<div style="display:flex;width:600px;height:400px;background:linear-gradient(135deg,#1a365d,#0a1628);font-family:u}   ;flex-direction:column;justify-content:center;align-items:center;color:#ffffff;font-size:48px;">한글 렌더 테스트</div>z	smoke.pngiX  i  rV   '  zPNG too small: N)rE   safe_render_html_to_pngr*   statst_size)r   r]   htmloutresults        r   test_08_safe_render_smokerj   P   s    ~  @J  @\  @\  \  ]\  \D
[
 C//cS/QF==??;;=  F*Uofkkm>S>S=T,UU*r   c                    |j                  dd        t        j                  t        t        f      5  | j                  d|dz  dd       ddd       y# 1 sw Y   yxY w)uC   node binary 부재 시 FileNotFoundError raise (silent fallback 0).zshutil.whichc                     | |d fd   S )N   r   )aks     r   <lambda>z>test_09_safe_render_raises_when_node_missing.<locals>.<lambda>Z   s    AtQ r   z<div>x</div>rT   rU   rV   N)setattrrY   rZ   FileNotFoundErrorr[   rd   )r   r]   monkeypatchs      r   ,test_09_safe_render_raises_when_node_missingrt   X   s\    (GH	)<8	9 f**>8g;MUXad*ef f fs   AAc                    d| j                   z   dz   }|dz  }| j                  ||dd       |j                  |g d|      }|d   d	u s
J d
|        |d   d   dk  sJ y)u<   실 렌더 PNG → verify_png pass=True + tofu_score 낮음.zs<div style="display:flex;width:1080px;height:1080px;background:linear-gradient(135deg,#0a0a1a,#0d1b3e);font-family:u   ;flex-direction:column;justify-content:center;align-items:center;color:#ffffff;font-size:64px;">보험 가이드 한글 테스트</div>zreal.png8  rV   )   보험	   가이드u   한글expected_koreanhtml_sourcepassTzverify failed: metrics
tofu_scoreg      ?N)rE   rd   
verify_png)r   r!   r]   rg   rh   ri   s         r   'test_10_verify_png_pass_for_real_renderr   ^   s     A  BL  B^  B^  ^  _h  hD
Z
C&&tST&J""38Ygk"lF&>T!=_VH#==!)\*S000r   c                    ddl m} |dz  }|j                  ddd      j                  |       | j	                  |dg      }|d	   d
u sJ |d   d   d
u sJ y)u;   1×1 blank PNG → file_size_ok=False (silent pass 차단).r   Imagez	blank.pngRGB)r(   r(   )r   r   r   xrz   r|   Fchecksfile_size_okNPILr   newsaver   )r!   r]   r   blankri   s        r   ,test_11_verify_png_detects_blank_placeholderr   g   sk    {"E	IIeVY',,U3""53%"@F&>U"""(N+u444r   c                    ddl m} |dz  }|j                  ddd      j                  |       | j	                  |dg      }|d	   d
   du s
J d|        y)u3   단색 1080×1080 PNG → color_diversity_ok=False.r   r   z	solid.pngr   rv   rv   )   r      r   r   r   color_diversity_okFzshould detect solid color: Nr   )r!   r]   r   solidri   s        r   &test_12_verify_png_detects_solid_colorr   p   si    {"E	IIe\<055e<""53%"@F(01U:b>YZ`Ya<bb:r   c                    ddl m} |dz  }|j                  ddd      j                  |       | j	                  |dg      }|d	   d
v sJ |d	   dk7  sJ y)uG   tesseract 미설치 시에도 mode='PIXEL-ONLY' 명시 (silent skip 0).r   r   zm.pngr   r   )2   r   rU   r   r   mode)z	PIXEL+OCR
PIXEL-ONLYSKIPNr   r!   r]   r   imgri   s        r   )test_13_verify_png_mode_explicitly_markedr   y   sf    
W
C	IIe\=166s;""3">F&>8888&>V###r   c                    ddl m} |dz  }|j                  ddd      j                  |       | j	                  |ddgd	
      }|d   d   du sJ y)u;   expected_korean 미포함 html → html_string_match=False.r   r   rT   r   r   )
   r      rw   rx   u   <div>영문만</div>ry   r   html_string_matchFNr   r   s        r   "test_14_html_string_match_requiredr      s`    
W
C	IIe\<055c:""3;8O]s"tF(/0E999r   c                    |dz  }| j                  ddddd|      }|j                         r|j                         j                  dk\  sJ |d	   d
u sJ y)u+   render_one.render_and_verify 통합 동작.zint.pngsupabaseh4_gradient_cardr   u   보험 가입 가이드u'   한 번에 비교하고 절약하세요)brandpatternsizetitlebodyoutput_pathrc   r|   TN)render_and_verifyr*   re   rf   )r$   r]   rh   ri   s       r   %test_15_render_and_verify_integrationr      sh    
Y
C))"4<'.W * F
 ::<CHHJ..&888&>T!!!r   c                     t         dz  j                         } g d}|D cg c]%  }|j                         | j                         v s$|' }}|r
J d|        yc c}w )u:   _satori.py 소스에 외부 API URL 미포함 (IDS §0.5).r   )z
openai.comzanthropic.comgeminicohere	replicatehuggingfacez!forbidden API ref in _satori.py: N)r   	read_textrF   )src	forbiddenur.   s       r   (test_16_no_external_api_in_satori_moduler      s]    ::
E
E
GC_I!>1QWWY#))+%=Q>E>A9%AA9u ?s   %AAc                 f    t         dz  j                         } d| vrd| vsJ d       d| v sJ d       y)u_   verify_korean.py: pytesseract import 실패 시 mode를 명시 표기, 'SKIP' 절대 미사용.r    z'SKIP'z"SKIP"zsilent SKIP mode forbiddenr   z*PIXEL-ONLY mode must be explicitly emittedN)r   r   )r   s    r   %test_17b_verify_korean_no_silent_skipr      sE    HH
S
S
UC383#6T8TT63L LLr   c                 v    ddl } t        dz  j                         }| j                  d|      }|r
J d|        y)u2   _satori.py에 silent except pass 패턴 미존재.r   Nr   zexcept[^:]*:\s*passzsilent except pass found: )rer   r   findall)r   r   matchess      r   $test_17_no_silent_fallback_in_satorir      sA    ::
E
E
GCjj/5G>4WI>>;wr   )"__doc__
__future__r   importlib.utilr   r   pathlibr   rY   r   r   fixturer   r!   r$   r&   r/   r2   rA   rH   rO   r^   ra   rj   rt   r   r   r   r   r   r   r   r   r   r   r   r   <module>r      s   #   &'	 hP  P h^  ^ h[  [ hp  p
S

95XeEVf15c$:	"BM?r   