
    [iI                       d Z ddlmZ ddlZddlmc mZ ddl	Z
ddlZddlZddlZddlmZ ddlmZ ddlZ ed      Zedz  Zedz  Z ee      ej.                  vr"ej.                  j1                  d ee             dd	Z ed
      Z ed      Zej8                  j:                  ZddZdddZ d dZ!d dZ"d dZ#d dZ$d dZ%d dZ&d!dZ'd!dZ(d dZ)d dZ*d dZ+d!dZ,d!dZ-d!dZ.y)"u%  IDS Phase 2 — magazine-ppt-ko 회귀 테스트 (G2 게이트).

self-contained: conftest 없이도 수집/실행 가능.
- 외부 API mock 차단 (정적 검사)
- 한글 100% string-match
- PPTX 생성 + 한글 추출 검증

python-pptx 미설치 시 PPTX 관련 케이스는 자동 skip.
    )annotationsN)Path)Anyz*/home/jay/workspace/skills/magazine-ppt-koscripts	templatesc                ,   t         j                  j                  | t        |  dz        }||j                  t        d|        t         j                  j                  |      }|t        j                  | <   |j                  j                  |       |S )uG   scripts/ 디렉토리의 모듈을 importlib으로 안전하게 로드.z.pyzcannot load )
	importlibutilspec_from_file_locationSCRIPTS_DIRloaderImportErrormodule_from_specsysmodulesexec_module)namespecmodules      A/home/jay/workspace/tests/design-team/test_ids_phase2_ppt_deck.py_import_moduler      s|    >>11$cl8RSD|t{{*L/00^^,,T2FCKKKKF#M    
build_deckverify_koreanc                 D    t         j                  j                  d      d uS )Npptx)r	   r
   	find_spec r   r   _has_python_pptxr   4   s    >>##F+477r   c                4   d| dddddddd	d
d
d| ddddddd| ddddddddddddd d!d"| d#d$d%d&d'd(d)d*d+d,d-d.d/d0d1d2| d3d4d5d6d7d8d9d:d;d<d=d>| d?d@dAdBdCdD| dEdFdGdHdIdJdKdLdM| dNdOdPdQdRdSdTdUdV	dW| dXdYdZd[d\d]d^d_d`da
db| dcdddedfdAdgdhdi
}||    S )ju-   layout별 샘플 변수 dict (한글 가득).u   임원 보고u   분기 실적u   매출 320억 달성uQ   전년 동기 대비 24% 성장하며 사상 최대 실적을 기록했습니다.u   신규 고객 12만명 확보u   구독 갱신율 92%u   운영 비용 8% 절감u   전략기획실u   2026년 5월01)
titleeyebrowkpi_headlineledebullet_1bullet_2bullet_3authordatepage_numberu
   피치 덱u   보험 혁신u   보험을 다시 쓰다u^   데이터 기반 맞춤 보험으로 한국인 1만 가구의 보험료를 절감했습니다.u   다음 라운드 목표u   100억 원 시리즈 A)r"   badgeheadlinesubcopy	cta_label	cta_valueu   4월 회고u   월간 회고u
   잘한 점u"   스프린트 일정 준수율 100%u!   팀 간 커뮤니케이션 개선u   버그 발생률 30% 감소u	   문제점u'   테스트 자동화 커버리지 부족u"   온콜 부담 특정 인원 집중u"   고객 응대 응답 시간 지연u   시도할 점u   TDD 도입 파일럿u   온콜 로테이션 균등화u   고객 응대 SLA 30분 목표)r"   r#   
keep_labelkeep_1keep_2keep_3problem_label	problem_1	problem_2	problem_3	try_labeltry_1try_2try_3u   주간 운영 현황u   2026년 5월 1주차u   신규 가입1240u!   전주 대비 12 퍼센트 증가u   활성 사용자48300u    전주 대비 5 퍼센트 증가u   매출u
   8.2억 원u!   전주 대비 18 퍼센트 증가u	   이탈률z2.1u"   전주 대비 0.4 포인트 감소uY   신규 캠페인 효과로 가입자가 늘었고 이탈률은 안정화 추세입니다.)r"   period
kpi1_label
kpi1_value
kpi1_delta
kpi2_label
kpi2_value
kpi2_delta
kpi3_label
kpi3_value
kpi3_delta
kpi4_label
kpi4_value
kpi4_deltacommentu   하반기 로드맵u   프로젝트 일정u:   단계별 마일스톤과 책임자를 정리했습니다.u   7월u0   베타 기능 출시 및 초기 사용자 모집u   8월u0   결제 시스템 통합 및 가격 정책 확정u   9월u,   정식 런칭 및 마케팅 캠페인 가동u   10월u0   리텐션 분석 및 다음 분기 계획 수립)r"   r#   r%   when_1what_1when_2what_2when_3what_3when_4what_4u   보험 혁신 보고서u   2026년 상반기 사업 전략u   사내 발표u   전략기획실 김지훈u   2026년 5월 3일)r"   subtitler#   	presenterr*   u   오늘 다룰 내용u   목차u2   다섯 가지 핵심 주제로 구성했습니다.u   현황과 시장 분석u   핵심 전략 방향u   주요 실행 과제u   성과 측정 지표u   질의응답 및 토론)r"   r#   r%   item_1item_2item_3item_4item_5u   신규 시장 진입 전략u   전략 방향uR   30대 직장인을 핵심 타겟으로 모바일 전용 상품을 출시합니다.u2   월 만원대 마이크로 보험 라인업 출시u2   카카오 친구톡 기반 고객 응대 자동화u1   직장인 커뮤니티와 제휴 마케팅 진행u   타겟 고객u   320만u$   30대 직장인 잠재 고객 규모)	r"   r#   r%   r&   r'   r(   visual_labelvisual_valuevisual_captionu   정리하며u   요약u   데이터 기반 의사결정uF   주간 단위 KPI 검토를 정례화하여 빠르게 대응합니다.u   고객 경험 우선uK   응대 시간을 30분 이내로 단축하고 만족도를 측정합니다.u   팀 단위 실행u9   월간 회고를 통해 조직 학습을 누적합니다.u   다음 액션u?   다음 주까지 실행 계획서를 정리해 공유합니다.)
r"   r#   point1_titlepoint1_descpoint2_titlepoint2_descpoint3_titlepoint3_descaction_labelaction_copyu   질의응답 세션u   질문해 주세요uh   오늘 발표에 대한 의견과 추가 논의가 필요한 부분을 자유롭게 말씀해 주세요.u	   마무리u	   연락처zjihoon@example.com)r"   r-   r.   r#   contact_labelcontact_namecontact_email
	executivepitchretrostatusplanintroagendacontentsummaryqar   )layoutsuffixbases      r   _sample_varsrx   8   s    %VH-&2g7.1'"
 "&*$1w21
 #6(+&&:93(B==(+45
" ,F84,) =,!<"&=%>r
$ +6(3,PHHDH
 /vh79&4'
 ,F84H/,,,/	
 36(;&hLLK+$D

 $F8,;c2h/V+\
 +6(3- B"(71
Wt'Dj <r   c           	     X   g d}|D cg c]  }t        |       }}t        j                  ||d| dz        }|j                  }t	        |      }d}||k(  }|s
t        j                  d|fd||f      dt        j                         v st        j                  t              rt        j                  t              nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      d	z  }	d
d|	iz  }
t        t        j                  |
            dx}x}x}}|j                  D ]  }|j                  } |       }|st        j                  d|       dz   dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }t        t        j                  |            dx}}|j                  } |       }|j                   }d}||kD  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      t        j                  |      dz  }t        j                  d|       dz   d|iz  }t        t        j                  |            dx}x}x}x}} |j"                  }|j                  } |       }|sddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      dz  }t        t        j                  |            dx}x}}yc c}w )uE   1. linear 스타일 PPT 10장 — 매거진 5 + 덱 5 = 10장 빌드.rj   linearlayout_namesvariables_listbrand
output_dir
   ==zP%(py5)s
{%(py5)s = %(py0)s(%(py3)s
{%(py3)s = %(py1)s.html_paths
})
} == %(py8)slenresultpy0py1py3py5py8assert %(py10)spy10Nzslide html not generated: C
>assert %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.exists
}()
}pr   py2py4d   >z_%(py6)s
{%(py6)s = %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.stat
}()
}.st_size
} > %(py9)sr   r   r   py6py9zslide html too small: 
>assert %(py11)spy11zdassert %(py6)s
{%(py6)s = %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.manifest_path
}.exists
}()
}r   r   r   r   )rx   r   build
html_pathsr   
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_safereprAssertionError_format_explanationexists_format_assertmsgstatst_sizemanifest_path)tmp_pathr|   r   r}   r   @py_assert2@py_assert4@py_assert7@py_assert6@py_format9@py_format11r   @py_assert1@py_assert3@py_format5@py_assert5@py_assert8@py_format10@py_format12@py_format7s                       r   *test_scenario_1_linear_style_ppt_10_slidesr      s   L 6BBTl4(BNB !%h&	  F   '3 !'R'!R''''!R''''''3'''3''''''v'''v''' '''!'''R''''''' Dxx;xz;z;;7s;;;;;;;q;;;q;;;x;;;z;;;;;;vvCvxCxC#C#%CCC#CCCCCCqCCCqCCCvCCCxCCCCCC#CCC)?s'CCCCCCCCD (&&(&((((((((6(((6((((((&(((((((((( Cs   P'c                   g d}|D cg c]  }t        |       }}t        j                  ||d| dz        }|j                  }t	        |      }d}||k(  }|s
t        j                  d|fd||f      dt        j                         v st        j                  t              rt        j                  t              nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      d	z  }	d
d|	iz  }
t        t        j                  |
            dx}x}x}}yc c}w )u7   2. supabase 스타일 덱 7장 — 덱 5 + 매거진 2.)rp   rq   rr   rs   rt   rk   rn   supabaser{      r   r   r   r   r   r   r   Nrx   r   r   r   r   r   r   r   r   r   r   r   r   r   r|   r   r}   r   r   r   r   r   r   r   s              r   ,test_scenario_2_supabase_style_deck_7_slidesr      s    L 6BBTl4(BNB!%j(	  F   &3 !&Q&!Q&&&&!Q&&&&&&3&&&3&&&&&&v&&&v&&& &&&!&&&Q&&&&&&& C   E-c                   g d}|D cg c]  }t        |       }}t        j                  ||d| dz        }|j                  }t	        |      }d}||k(  }|s
t        j                  d|fd||f      dt        j                         v st        j                  t              rt        j                  t              nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      d	z  }	d
d|	iz  }
t        t        j                  |
            dx}x}x}}yc c}w )uR   3. apple 미니멀 덱 3종 — 디자인 토큰 fallback 또는 design-md 사용.)rp   rr   rt   appler{      r   r   r   r   r   r   r   Nr   r   s              r   +test_scenario_3_apple_minimal_deck_3_slidesr      s    -L5ABTl4(BNB!%g%	  F   &3 !&Q&!Q&&&&!Q&&&&&&3&&&3&&&&&&v&&&v&&& &&&!&&&Q&&&&&&& Cr   c           	        g d}|D cg c]  }t        |       }}t        j                  ||d| dz        }t        j	                  |j
                  |j                        }|d   }d}||u }|st        j                  d|fd||f      t        j                  |      t        j                  |      d	z  }	t        j                  d
|       dz   d|	iz  }
t        t        j                  |
            dx}x}}|d   D ]q  }|d   }|sft        j                  d|d    d|j                  d             dz   dt        j                  |      iz  }t        t        j                  |            d}s yc c}w )uO   4. 한글 100% — manifest의 모든 한글이 HTML에 string-match로 존재.)rk   rl   rm   rp   rt   r   koreanr{   passTisz%(py1)s is %(py4)sr   r   zkorean string-match failed: 
>assert %(py6)sr   Nresultszslide filez
 missing: missingz
>assert %(py1)sr   )rx   r   r   r   verify_htmlr   r   r   r   r   r   r   r   get)r   r|   r   r}   r   report@py_assert0r   r   r   r   slide@py_format2s                r   (test_scenario_4_korean_100_percent_matchr      s.   AL5ABTl4(BNB!%h&	  F &&v';';V=N=NOF&>JTJ>T!JJJ>TJJJ>JJJTJJJ%A&#JJJJJJJJ	" WV}V}VVuV}oZ		)@T?UVVVV}VVVVVVW Cs   E5c                ,   t               st        j                  d       t        d      }g d}|D cg c]  }t	        |       }}t
        j                  ||d| dz        }| dz  dz  }|j                  |j                  |j                  |      }|j                  } |       }	|	sdd	t        j                         v st        j                  |      rt        j                  |      nd	t        j                  |      t        j                  |	      d
z  }
t!        t        j"                  |
            dx}}	|j$                  } |       }	|	j&                  }d}||kD  }|st        j(                  d|fd||f      d	t        j                         v st        j                  |      rt        j                  |      nd	t        j                  |      t        j                  |	      t        j                  |      t        j                  |      dz  }dd|iz  }t!        t        j"                  |            dx}x}	x}x}}ddl}|j-                  t/        |            }|j0                  }t3        |      }d}||k(  }|s
t        j(                  d|fd||f      dt        j                         v st        j                  t2              rt        j                  t2              nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t!        t        j"                  |            dx}x}x}}yc c}w )uY   5. PPTX export — html_to_pptx 호출 후 .pptx 파일 존재 + 슬라이드 수 일치.python-pptx not installedhtml_to_pptx)rk   rp   rt   r   r   r{   	deck.pptxAassert %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.exists
}()
}	pptx_pathr   Ni   r   r   r   zassert %(py11)sr   r   r   r   )zL%(py5)s
{%(py5)s = %(py0)s(%(py3)s
{%(py3)s = %(py1)s.slides
})
} == %(py8)sr   presentationr   r   r   )r   pytestskipr   rx   r   r   compile_pptxr   r   r   r   r   r   r   r   r   r   r   r   r   r   Presentationstrslidesr   )r   r   r|   r   r}   r   pptx_outr   r   r   r   r   r   r   r   r   _pptxr   r   r   r   r   r   s                          r   test_scenario_5_pptx_exportr   
  sV   /0!.1L/L5ABTl4(BNB!%f$	  F & ;.H))6//I 99>>*>*##*d*#d****#d******9***9***>******#***d*******%%c)n5L""(3"#(q(#q((((#q((((((3(((3((((((|(((|((("(((#(((q(((((((% Cs   Nc                   t               st        j                  d       t        d      }ddg}|D cg c]  }t	        |       }}t
        j                  ||d| dz        }| dz  dz  }|j                  |j                  |j                  |       t        j                  |j                  |      }|d	   }d
}	||	u }
|
st        j                  d|
fd||	f      t        j                  |      t        j                  |	      dz  }t        j                  d|       dz   d|iz  }t!        t        j"                  |            dx}x}
}	|d   }d}	||	k(  }
|
slt        j                  d|
fd||	f      t        j                  |      t        j                  |	      dz  }dd|iz  }t!        t        j"                  |            dx}x}
}	yc c}w )uN   6. PPTX 텍스트 검증 — python-pptx로 다시 읽어 한글 string-match.r   r   rl   rq   Npptx2r{   r   r   Tr   r   r   zpptx korean missing: r   r   slide_count   r   )z%(py1)s == %(py4)szassert %(py6)s)r   r   r   r   rx   r   r   r   r   r   r   verify_pptx_textr   r   r   r   r   r   )r   r   r|   r   r}   r   r   r   r   r   r   r   r   s                r   &test_scenario_6_pptx_korean_extractionr   )  sg   /0!.1LX&L5ABTl4(BNB!%g%	  F '!K/Hf//1E1ExP++F,@,@(KF&>CTC>T!CCC>TCCC>CCCTCCC%:6(#CCCCCCCC- %A% A%%%% A%%% %%%A%%%%%%% Cs   Gc                    d} t        t        j                  d            }|s{t        j                  d      dz   ddt        j                         v st        j                  |      rt        j                  |      ndiz  }t        t        j                  |            g }|D ]  }|j                  d      }| D ]}  }d	t        j                  |       d
dt        j                  |       dg}|D ]D  }t        j                  ||t        j                        s)|j!                  t#        |      |f       F   | }	|	s~t        j                  d|       dz   ddt        j                         v st        j                  |      rt        j                  |      ndiz  }
t        t        j                  |
            d}	y)uO   7. 외부 API mock 차단 — openai/anthropic/google.generativeai import 0건.)openai	anthropiczgoogle.generativeaigenai*.pyzscripts/*.py not foundz
>assert %(py0)sr   py_filesutf-8encoding^\s*import\s+z	(\s|$|\.)^\s*from\s+z(\.|\s+import\s+)zforbidden imports found: 
>assert not %(py0)s	offendersN)listr   rglobr   r   r   r   r   r   r   r   	read_textreescapesearch	MULTILINEappendr   )forbidden_modulesr   @py_format1r   pathtextmodpatternspatr   r   s              r   +test_scenario_7_no_external_api_sdk_importsr  C  sG   OK%%f-.H---------8---8-----')I 
7~~w~/$ 	7C !3 0	:ryy~..?@H   799S$5$$c$i%567	7
7 =A=AA5i[AAAAAAAyAAAyAAAAAAr   c                    d} t        t        j                  d            }g }|D ]<  }|j                  d      }| D ]#  }||v s|j	                  t        |      |f       % > | }|s~t        j                  d|       dz   ddt        j                         v st        j                  |      rt        j                  |      ndiz  }t        t        j                  |            d	}y	)
uV   8. 직접 URL 차단 — api.openai.com / api.anthropic.com / generativelanguage 0건.)zapi.openai.comzapi.anthropic.comz!generativelanguage.googleapis.comr   r   r   zforbidden URLs found: r   r   r   N)r   r   r   r   r  r   r   r   r   r   r   r   r   r   )forbidden_urlsr   r   r  r  urlr   r   s           r   $test_scenario_8_no_external_api_urlsr  \  s    N
 K%%f-.H')I 3~~w~/! 	3Cd{  #d)S!12	33
 =>=>>29+>>>>>>>y>>>y>>>>>>r   c                   t         j                         }|D cg c]  }t        |       }}t         j                  ||d| dz        }t        j                  |j                        }|d   }d}||u }|st        j                  d|fd||f      t        j                  |      t        j                  |      dz  }	t        j                  d	|       d
z   d|	iz  }
t        t        j                  |
            dx}x}}yc c}w )u`   9. 폰트 fallback 차단 — 모든 슬라이드 HTML body의 font-family가 Pretendard 시작.r   fontr{   r   Tr   r   r   zfont stack check failed: r   r   N)r   list_layoutsrx   r   r   verify_font_stack_in_htmlr   r   r   r   r   r   r   )r   r|   r   r}   r   r   r   r   r   r   r   s              r   +test_scenario_9_font_stack_pretendard_firstr  p  s    **,L5ABTl4(BNB!%f$	  F 44V5F5FGF&>GTG>T!GGG>TGGG>GGGTGGG%>vh#GGGGGGGG Cs   Dc                   dg}t        d      g}t        j                  ||d| dz        }d}|j                  }||v }|st	        j
                  d|fd||f      t	        j                  |      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      d	z  }d
d|iz  }t        t	        j                  |            dx}x}}|j                  d   j                  d      }	d}||	v }|st	        j
                  d|fd||	f      t	        j                  |      dt        j                         v st	        j                  |	      rt	        j                  |	      nddz  }
dd|
iz  }t        t	        j                  |            dx}}d}||	v }|st	        j
                  d|fd||	f      t	        j                  |      dt        j                         v st	        j                  |	      rt	        j                  |	      nddz  }
dd|
iz  }t        t	        j                  |            dx}}d}||	v }|st	        j
                  d|fd||	f      t	        j                  |      dt        j                         v st	        j                  |	      rt	        j                  |	      nddz  }
dd|
iz  }t        t	        j                  |            dx}}y)uI   10. design-md inject — 디자인 토큰이 HTML/CSS에 반영되는지.rk   r   tokensr{   primaryin)z.%(py1)s in %(py5)s
{%(py5)s = %(py3)s.tokens
}r   r   r   r   zassert %(py7)spy7Nr   r   r   z--color-primary:z%(py1)s in %(py3)shtmlr   r   assert %(py5)sr   
PretendardzNoto Sans KR)rx   r   r   r  r   r   r   r   r   r   r   r   r   r   )r   r|   r}   r   r   r   r   @py_format6@py_format8r  @py_format4s              r   !test_scenario_10_design_md_injectr$    s   =L";/0N!%h&	  F %%9%%%%9%%%9%%%%%%%%%%%%%%%%%%%Q))7);D%%%%%%%%%%%%%%%%%%%%%%%%<4<4<44!>T!!!!>T!!!>!!!!!!T!!!T!!!!!!!r   c                   dg}t        d      g}t        j                  ||d| dz        }|j                  d   }|j                  } |       }|s`dt        j                  |      t        j                  |      t        j                  |      dz  }t        t        j                  |            dx}x}}|j                  d   j                  d	
      }d}||v }|st        j                  d|fd||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }	dd|	iz  }t        t        j                  |            dx}}y)uV   11. fallback 토큰 — 잘못된 brand 입력 시 fallback_tokens()로 정상 빌드.rp   z$this-brand-definitely-does-not-existfallbackr{   r   zAassert %(py5)s
{%(py5)s = %(py3)s
{%(py3)s = %(py1)s.exists
}()
}r  Nr   r   r   r  r  r  r  r  r   )rx   r   r   r   r   r   r   r   r   r   r   r   r   r   )
r   r|   r}   r   r   r   r   r!  r  r#  s
             r   .test_scenario_11_fallback_tokens_invalid_brandr'    s   9L"7+,N!%4j(	  F Q(&&(&((((((((&((((((((((Q))7);D<4<4<44r   c            	     B   t         dz  } | j                  } |       }|sddt        j                         v st	        j
                  |       rt	        j                  |       ndt	        j                  |      t	        j                  |      dz  }t        t	        j                  |            dx}}| j                  dd      5 }t        j                  |      }ddd       j                  d	i       }h d
}|j                  } |       }	t        |	      }
|
|k(  }|s~t	        j                  d|fd|
|f      dt        j                         v st	        j
                  t              rt	        j                  t              ndd	t        j                         v st	        j
                  |      rt	        j                  |      nd	t	        j                  |      t	        j                  |	      t	        j                  |
      dt        j                         v st	        j
                  |      rt	        j                  |      nddz  }t	        j                   dt        |j                               |z         dz   d|iz  }t        t	        j                  |            dx}x}	x}
}|j#                         D ]O  \  }}t         |d   z  }|j                  } |       }|st	        j                   d| d|       dz   dt        j                         v st	        j
                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |      dz  }t        t	        j                  |            dx}}|j                  dd      5 }t        j                  |      }ddd       d}|v }|st	        j                  d|fd||f      t	        j                  |      dt        j                         v st	        j
                  |      rt	        j                  |      nddz  }t	        j                   d|       dz   d|iz  }t        t	        j                  |            dx}}d}||v }|st	        j                  d|fd||f      t	        j                  |      dt        j                         v st	        j
                  |      rt	        j                  |      nddz  }t	        j                   d |       dz   d|iz  }t        t	        j                  |            dx}}|d   D ]  }|d   }||v }|st	        j                  d|fd!||f      d"t        j                         v st	        j
                  |      rt	        j                  |      nd"t	        j                  |      d#z  }t	        j                   d$| d%|       dz   d|iz  }t        t	        j                  |            dx}} R y# 1 sw Y   0xY w# 1 sw Y   exY w)&uH   12. registry.json 무결성 — 10종 모두 존재 + vars 스키마 OK.zregistry.jsonr   registry_pathr   Nrr   r   layouts>
   rt   ro   rp   rl   rm   rq   rn   rr   rs   rk   r   )za%(py7)s
{%(py7)s = %(py0)s(%(py5)s
{%(py5)s = %(py3)s
{%(py3)s = %(py1)s.keys
}()
})
} == %(py9)ssetexpected)r   r   r   r   r  r   zmissing/extra layouts: r   r   schemazschema missing for z: r   schema_pathvarsr  r  r  zvars missing in schema z
>assert %(py5)sr   korean_slotszkorean_slots missing in )z%(py0)s in %(py3)sslot)r   r   zslot z not in vars for )TEMPLATES_DIRr   r   r   r   r   r   r   r   openjsonloadr   keysr,  r   r   items)r)  r   r   r   fregistryr+  r-  r   r   r   r   r   r   r   metar/  r.  r   r#  r!  r2  s                         r   #test_scenario_12_registry_integrityr<    s   !O3M!!!!!!!!!=!!!=!!!!!!!!!!!!!			C'		2  a99Q< ll9b)GH ||f|~f3~f(*fff(ffffff3fff3ffffffwfffwfff|fff~fffffffff(fff(ffff.Ec',,.FY\dFdEe,ffffffff mmo 	Q
d#d8n4!!P!#P#PP':4&;-%PPPPPPP{PPP{PPP!PPP#PPPPPPcG4 	"YYq\F	"AvAAAvAAAvAAAAAAAAAAAAA#:4&!AAAAAAAJ~'JJJ~JJJ~JJJJJJJJJJJJJ+CD6)JJJJJJJ>* 	QD!&>P4>)PPP4>PPPPPP4PPP4PPP>PPPU4&8I$+PPPPPPP	Q	Q   	" 	"s   XXXX	c                    t         dz  } | j                  } |       }|sddt        j                         v st	        j
                  |       rt	        j                  |       ndt	        j                  |      t	        j                  |      dz  }t        t	        j                  |            dx}}| j                  d      }|j                  }d} ||      }|sd	d
t        j                         v st	        j
                  |      rt	        j                  |      nd
t	        j                  |      t	        j                  |      t	        j                  |      dz  }t        t	        j                  |            dx}x}}d}||v }|st	        j                  d|fd||f      t	        j                  |      d
t        j                         v st	        j
                  |      rt	        j                  |      nd
dz  }	dd|	iz  }
t        t	        j                  |
            dx}}d}||v }|st	        j                  d|fd||f      t	        j                  |      d
t        j                         v st	        j
                  |      rt	        j                  |      nd
dz  }	dd|	iz  }
t        t	        j                  |
            dx}}y)u6   SKILL.md에 name/description frontmatter가 있는지.zSKILL.mdr   skill_mdr   Nr   r   z---zLassert %(py6)s
{%(py6)s = %(py2)s
{%(py2)s = %(py0)s.startswith
}(%(py4)s)
}r  r   zname: magazine-ppt-kor  r  r  r  r   zdescription:)
SKILL_ROOTr   r   r   r   r   r   r   r   r   
startswithr   )r>  r   r   r   r  r   r   r   r   r#  r!  s              r   !test_skill_md_frontmatter_presentrA    s   J&H???88?w/D??!5!?5!!!!!!!!4!!!4!!!?!!!5!!!!!!!!!!"*"d****"d***"******d***d*******!>T!!!!>T!!!>!!!!!!T!!!T!!!!!!!r   c                    d} t        t        j                  d            }g }|D ]  }|j                  d      }| D ]  }t	        j
                  dt	        j                  |       |t        j                        r|j                  t        |      |f       t	        j
                  dt	        j                  |       d|t        j                        s|j                  t        |      |f         | }|s~t        j                  d|       d	z   d
dt        j                         v st        j                  |      rt        j                  |      ndiz  }t!        t        j"                  |            d}y)uA   urlopen / requests / httpx import 0건 (IDS §0.5 보강 검사).)zurllib.requestrequestshttpxaiohttpr   r   r   r   r   z	\s+importzhttp client imports found: r   r   r   N)r   r   r   r   r   r  r   r  r  r   r   r   r   r   r   r   r   r   )	forbiddenr   r   r  r  r  r   r   s           r   test_no_http_client_importsrG    s   BIK%%f-.H')I 3~~w~/ 	3CyyM"))C.)9:D",,O  #d)S!12yyK		#'7yA4V  #d)S!12		33 =C=CC7	{CCCCCCCyCCCyCCCCCCr   )r   r   returnr   )rH  bool) )ru   r   rv   r   rH  zdict[str, str])r   r   rH  None)rH  rK  )/__doc__
__future__r   builtinsr   _pytest.assertion.rewrite	assertionrewriter   importlib.utilr	   r5  r   r   pathlibr   typingr   r   r?  r   r3  r   r  insertr   r   r   markdesign_team
pytestmarkr   rx   r   r   r   r   r   r   r  r  r  r$  r'  r<  rA  rG  r   r   r   <module>rY     s    #      	 
    >?
9$[({388#HHOOAs;'( L)
/ [[$$
8wz)4'*'"W*)>&4B2?(H"". (Q:"Dr   