
    iJF                    0   d Z ddlmZ ddlZddlmc mZ ddl	m
Z
 ddlZddlmZmZmZmZmZmZmZmZmZmZmZmZmZmZ dZ ej8                  d      d	        Z G d
 d      Z G d d      Z G d d      Z  G d d      Z! G d d      Z" G d d      Z#y)u  skill_loader.py Progressive Disclosure 기능 단위 테스트.

테스트 대상:
- SkillLevel enum (CORE, STANDARD, EXTENDED)
- classify_skill(name)
- match_skills_by_prompt(prompt, skills_dir)
- get_skills_by_level(skills_dir, level)
- check_security_whitelist(skills_dir)
- set_progressive_disclosure / is_progressive_disclosure_enabled
- list_skills, view_skill, load_skill (회귀 테스트)
    )annotationsN)Path)KEYWORD_TRIGGERSSECURITY_WHITELISTSkillDetail
SkillLevelSkillSummarycheck_security_whitelistclassify_skillget_skills_by_level!is_progressive_disclosure_enabledlist_skills
load_skillmatch_skills_by_promptset_progressive_disclosure
view_skillz/home/jay/workspace/skillsT)autousec               #  *   K   d t        d       yw)u[   각 테스트가 끝난 뒤 Progressive Disclosure flag를 True(기본값)로 복원한다.NT)r        ./home/jay/workspace/tests/test_skill_loader.pyrestore_progressive_disclosurer   ,   s      
t$s   c                  4    e Zd ZdZd Zd Zd Zd Zd Zd Z	y)	TestClassifySkilluK   classify_skill 함수의 CORE / STANDARD / EXTENDED 분류를 검증한다.c                h   t         D ](  }t        |      }t        j                  }||k(  }|st	        j
                  d|fd||f      dt        j                         v st	        j                  |      rt	        j                  |      nddt        j                         v st	        j                  t              rt	        j                  t              ndt	        j                  |      dz  }t	        j                  d| d| d      d	z   d
|iz  }t        t	        j                  |            dx}}+ y)uI   SECURITY_WHITELIST에 포함된 스킬은 CORE로 분류되어야 한다.==)z,%(py0)s == %(py4)s
{%(py4)s = %(py2)s.CORE
}resultr   py0py2py4'u   ' 은 CORE여야 하지만     로 분류됨
>assert %(py6)spy6N)r   r   r   CORE
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_saferepr_format_assertmsgAssertionError_format_explanationself
skill_namer   @py_assert3@py_assert1@py_format5@py_format7s          r   'test_security_whitelist_skills_are_corez9TestClassifySkill.test_security_whitelist_skills_are_core;   s    , 	pJ#J/F'__o6_,ooo6_oooooo6ooo6ooooooZoooZooo_ooo*=XY_X``n.oooooooo	pr   c                h   t         D ](  }t        |      }t        j                  }||k(  }|st	        j
                  d|fd||f      dt        j                         v st	        j                  |      rt	        j                  |      nddt        j                         v st	        j                  t              rt	        j                  t              ndt	        j                  |      dz  }t	        j                  d| d| d      d	z   d
|iz  }t        t	        j                  |            dx}}+ y)uK   KEYWORD_TRIGGERS에 포함된 스킬은 STANDARD로 분류되어야 한다.r   )z0%(py0)s == %(py4)s
{%(py4)s = %(py2)s.STANDARD
}r   r   r   r#   u   ' 은 STANDARD여야 하지만 r$   r%   r&   N)r   r   r   STANDARDr(   r)   r*   r+   r,   r-   r.   r/   r0   r1   s          r   (test_keyword_trigger_skills_are_standardz:TestClassifySkill.test_keyword_trigger_skills_are_standardA   s    * 	xJ#J/F'00w600www60wwwwww6www6wwwwwwZwwwZwww0wwwAj\A`ag`hhv2wwwwwwww	xr   c                h   g d}|D ](  }t        |      }t        j                  }||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      nddt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      dz  }t        j                  d| d| d	      d
z   d|iz  }t        t        j                  |            dx}}+ y)u7   미등록 스킬은 EXTENDED로 분류되어야 한다.)totally-unknown-skillzmy-custom-skillznot-a-real-skill-xyzr   )z0%(py0)s == %(py4)s
{%(py4)s = %(py2)s.EXTENDED
}r   r   r   r#   u   ' 은 EXTENDED여야 하지만 r$   r%   r&   N)r   r   EXTENDEDr(   r)   r*   r+   r,   r-   r.   r/   r0   )r2   unregistered_namesnamer   r4   r5   r6   r7   s           r   #test_unregistered_skill_is_extendedz5TestClassifySkill.test_unregistered_skill_is_extendedG   s    

 ' 	rD#D)F'00q600qqq60qqqqqq6qqq6qqqqqqZqqqZqqq0qqqAdV;Z[aZbbp2qqqqqqqq	rr   c                   d}t        |      }t        j                  }||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  t               rt        j                  t               ndt        j                  |      t        j                  |      dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      dz  }dd|iz  }t        t        j                  |            d	x}x}x}}y	)
uF   blog-writer는 KEYWORD_TRIGGERS에 있으므로 STANDARD여야 한다.blog-writerr   zN%(py4)s
{%(py4)s = %(py0)s(%(py2)s)
} == %(py8)s
{%(py8)s = %(py6)s.STANDARD
}r   r   r    r!   r"   r&   py8assert %(py10)spy10Nr   r   r:   r(   r)   r*   r+   r,   r-   r/   r0   r2   r5   r4   @py_assert7@py_assert5@py_format9@py_format11s          r   test_blog_writer_is_standardz.TestClassifySkill.test_blog_writer_is_standardR   s    +C~m,C
0C0CC,0CCCCC,0CCCCCCC~CCC~CCCmCCC,CCCCCC
CCC
CCC0CCCCCCCCr   c                   d}t        |      }t        j                  }||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  t               rt        j                  t               ndt        j                  |      t        j                  |      dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      dz  }dd|iz  }t        t        j                  |            d	x}x}x}}y	)
uI   nuclear-approval은 SECURITY_WHITELIST에 있으므로 CORE여야 한다.nuclear-approvalr   zJ%(py4)s
{%(py4)s = %(py0)s(%(py2)s)
} == %(py8)s
{%(py8)s = %(py6)s.CORE
}r   r   rE   rG   rH   N)r   r   r'   r(   r)   r*   r+   r,   r-   r/   r0   rJ   s          r   test_nuclear_approval_is_corez/TestClassifySkill.test_nuclear_approval_is_coreV   s    0D~01DZ__D1_DDDD1_DDDDDD~DDD~DDD0DDD1DDDDDDZDDDZDDD_DDDDDDDr   c                   d}t        |      }t        j                  }||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  t               rt        j                  t               ndt        j                  |      t        j                  |      dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      dz  }dd|iz  }t        t        j                  |            d	x}x}x}}y	)
u@   retro는 KEYWORD_TRIGGERS에 있으므로 STANDARD여야 한다.retror   rD   r   r   rE   rG   rH   NrI   rJ   s          r   test_retro_is_standardz(TestClassifySkill.test_retro_is_standardZ   s    %=~g&=**=*==&*=====&*=======~===~===g===&======*===*===*========r   N)
__name__
__module____qualname____doc__r8   r;   rA   rO   rS   rV   r   r   r   r   r   8   s(    Upx	rDE>r   r   c                  .    e Zd ZdZd Zd Zd Zd Zd Zy)TestFeatureFlagu;   Progressive Disclosure feature flag 동작을 검증한다.c                   t        d       t               }d}||u }|st        j                  d|fd||f      dt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}y)	u6   기본 상태에서 feature flag가 True여야 한다.Tisz)%(py2)s
{%(py2)s = %(py0)s()
} is %(py5)sr   r    r!   py5assert %(py7)spy7N
r   r   r(   r)   r*   r+   r,   r-   r/   r0   r2   r5   @py_assert4r4   @py_format6@py_format8s         r   test_flag_default_is_enabledz,TestFeatureFlag.test_flag_default_is_enabledg   s{    "4(02:d:2d::::2d::::::0:::0:::2:::d:::::::r   c                
   t        d       d}t        |      }t        j                  }||k(  }|st	        j
                  d|fd||f      dt        j                         v st	        j                  t              rt	        j                  t              ndt	        j                  |      t	        j                  |      dt        j                         v st	        j                  t              rt	        j                  t              ndt	        j                  |      dz  }dd	|iz  }t        t	        j                  |            d
x}x}x}}d}t        |      }t        j                  }||k(  }|st	        j
                  d|fd||f      dt        j                         v st	        j                  t              rt	        j                  t              ndt	        j                  |      t	        j                  |      dt        j                         v st	        j                  t              rt	        j                  t              ndt	        j                  |      dz  }dd	|iz  }t        t	        j                  |            d
x}x}x}}d}t        |      }t        j                  }||k(  }|st	        j
                  d|fd||f      dt        j                         v st	        j                  t              rt	        j                  t              ndt	        j                  |      t	        j                  |      dt        j                         v st	        j                  t              rt	        j                  t              ndt	        j                  |      dz  }dd	|iz  }t        t	        j                  |            d
x}x}x}}d}t        |      }t        j                  }||k(  }|st	        j
                  d|fd||f      dt        j                         v st	        j                  t              rt	        j                  t              ndt	        j                  |      t	        j                  |      dt        j                         v st	        j                  t              rt	        j                  t              ndt	        j                  |      dz  }dd	|iz  }t        t	        j                  |            d
x}x}x}}y
)uB   flag가 OFF이면 모든 스킬이 CORE로 분류되어야 한다.FrC   r   rR   r   r   rE   rG   rH   NrU   r=   rQ   )r   r   r   r'   r(   r)   r*   r+   r,   r-   r/   r0   rJ   s          r   $test_flag_off_all_skills_become_corez4TestFeatureFlag.test_flag_off_all_skills_become_corel   s   "5)+?~m,?
?,????,??????~???~???m???,??????
???
??????????%9~g&9*//9&/9999&/999999~999~999g999&999999*999*999/99999995I~56I*//I6/IIII6/IIIIII~III~III5III6IIIIII*III*III/IIIIIII0D~01DZ__D1_DDDD1_DDDDDD~DDD~DDD0DDD1DDDDDDZDDDZDDD_DDDDDDDr   c                   t        d       d}t        |      }t        j                  }||k(  }|st	        j
                  d|fd||f      dt        j                         v st	        j                  t              rt	        j                  t              ndt	        j                  |      t	        j                  |      dt        j                         v st	        j                  t              rt	        j                  t              ndt	        j                  |      dz  }dd	|iz  }t        t	        j                  |            d
x}x}x}}d}t        |      }t        j                  }||k(  }|st	        j
                  d|fd||f      dt        j                         v st	        j                  t              rt	        j                  t              ndt	        j                  |      t	        j                  |      dt        j                         v st	        j                  t              rt	        j                  t              ndt	        j                  |      dz  }dd	|iz  }t        t	        j                  |            d
x}x}x}}d}t        |      }t        j                  }||k(  }|st	        j
                  d|fd||f      dt        j                         v st	        j                  t              rt	        j                  t              ndt	        j                  |      t	        j                  |      dt        j                         v st	        j                  t              rt	        j                  t              ndt	        j                  |      dz  }dd	|iz  }t        t	        j                  |            d
x}x}x}}y
)uG   flag가 ON이면 정상적인 3단계 분류가 이루어져야 한다.TrQ   r   rR   r   r   rE   rG   rH   NrC   rD   zunknown-xyz)zN%(py4)s
{%(py4)s = %(py0)s(%(py2)s)
} == %(py8)s
{%(py8)s = %(py6)s.EXTENDED
})r   r   r   r'   r(   r)   r*   r+   r,   r-   r/   r0   r:   r>   rJ   s          r   "test_flag_on_normal_classificationz2TestFeatureFlag.test_flag_on_normal_classificationu   s   "4(0D~01DZ__D1_DDDD1_DDDDDD~DDD~DDD0DDD1DDDDDDZDDDZDDD_DDDDDDD+C~m,C
0C0CC,0CCCCC,0CCCCCCC~CCC~CCCmCCC,CCCCCC
CCC
CCC0CCCCCCCC+C~m,C
0C0CC,0CCCCC,0CCCCCCC~CCC~CCCmCCC,CCCCCC
CCC
CCC0CCCCCCCCr   c                ,   t        d       d}t        |      }t        j                  }||k(  }|st	        j
                  d|fd||f      dt        j                         v st	        j                  t              rt	        j                  t              ndt	        j                  |      t	        j                  |      dt        j                         v st	        j                  t              rt	        j                  t              ndt	        j                  |      dz  }dd	|iz  }t        t	        j                  |            d
x}x}x}}t        d       d}t        |      }t        j                  }||k(  }|st	        j
                  d|fd||f      dt        j                         v st	        j                  t              rt	        j                  t              ndt	        j                  |      t	        j                  |      dt        j                         v st	        j                  t              rt	        j                  t              ndt	        j                  |      dz  }dd	|iz  }t        t	        j                  |            d
x}x}x}}y
)uR   flag를 OFF→ON으로 토글하면 분류가 원래대로 복원되어야 한다.FrC   r   rR   r   r   rE   rG   rH   NTrD   )r   r   r   r'   r(   r)   r*   r+   r,   r-   r/   r0   r:   rJ   s          r   (test_flag_toggle_restores_classificationz8TestFeatureFlag.test_flag_toggle_restores_classification}   s_   "5)+?~m,?
?,????,??????~???~???m???,??????
???
??????????"4(+C~m,C
0C0CC,0CCCCC,0CCCCCCC~CCC~CCCmCCC,CCCCCC
CCC
CCC0CCCCCCCCr   c                   t        d       t               }d}||u }|st        j                  d|fd||f      dt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}y)	uf   autouse fixture가 flag를 True로 복원하는지 검증하기 위해 OFF로 설정 후 확인한다.Fr^   r`   r   ra   rc   rd   Nre   rf   s         r    test_flag_is_restored_after_testz0TestFeatureFlag.test_flag_is_restored_after_test   s{    "5)02;e;2e;;;;2e;;;;;;0;;;0;;;2;;;e;;;;;;;r   N)	rW   rX   rY   rZ   rj   rl   rn   rp   rr   r   r   r   r\   r\   d   s!    E;
EDD<r   r\   c                  @    e Zd ZdZd Zd Zd Zd Zd Zd Z	d Z
d	 Zy
)TestMatchSkillsByPromptu[   match_skills_by_prompt가 프롬프트 키워드를 정확히 매칭하는지 검증한다.c                   t        dt              }|D cg c]  }|j                   }}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}}y
c c}w )uV   '블로그' 키워드가 포함된 프롬프트는 blog-writer를 매칭해야 한다.u   블로그 글 써줘rC   inz%(py1)s in %(py3)smatched_namespy1py3uV   '블로그 글 써줘' 프롬프트에서 blog-writer가 매칭되지 않음. 결과: 
>assert %(py5)srb   Nr   
SKILLS_DIRr@   r(   r)   r-   r*   r+   r,   r.   r/   r0   r2   resultssry   @py_assert0@py_assert2@py_format4rh   s           r   'test_korean_keyword_matches_blog_writerz?TestMatchSkillsByPrompt.test_korean_keyword_matches_blog_writer   s    ()?L)01A11	t]*	tbsbs	t]	t 	tjsjs 	t 	tmsms	t 	t[s[s +	t 	tjsjs +	t 	tbsbscdqcrs	t 	t 	t`s`s	t 	t 2   C)c                   t        dt              }|D cg c]  }|j                   }}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}}y
c c}w )uO   'pdf' 키워드가 포함된 영어 프롬프트는 pdf를 매칭해야 한다.zhelp with PDFpdfrv   rx   ry   rz   uG   'help with PDF' 프롬프트에서 pdf가 매칭되지 않음. 결과: r}   rb   Nr~   r   s           r    test_english_keyword_matches_pdfz8TestMatchSkillsByPrompt.test_english_keyword_matches_pdf   s    (*E)01A11  	Au%  	A  	A  	Au  	A  	A  	Au  	A  	A  	A  	A  	A  	A  	A  	A  	A  	A  	A  	A  	A)pq~p  (A  	A  	A  	A  	A  	A  	A 2r   c                   t        dt              }|D cg c]  }|j                   }}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}}y
c c}w )ua   대소문자를 무시하고 'SEO'가 포함된 프롬프트는 seo-audit을 매칭해야 한다.u   SEO audit 해줘	seo-auditrv   rx   ry   rz   uP   'SEO audit 해줘' 프롬프트에서 seo-audit이 매칭되지 않음. 결과: r}   rb   Nr~   r   s           r   test_case_insensitive_seo_auditz7TestMatchSkillsByPrompt.test_case_insensitive_seo_audit   s    ();ZH)01A11	n=(	n\m\m	n=	n 	ndmdm 	n 	ngmgm	n 	nUmUm )	n 	ndmdm )	n 	n\m\m]^k]lm	n 	n 	nZmZm	n 	n 2r   c                   t        dt              }g }||k(  }|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z   d|iz  }t        t        j                  |            d	x}}y	)
uI   매칭되는 키워드가 없으면 빈 리스트를 반환해야 한다.u+   아무 키워드도 없는 일반 텍스트r   z%(py0)s == %(py3)sr   r    r|   u3   매칭 없을 때 빈 리스트여야 함. 결과: r}   rb   N)r   r   r(   r)   r*   r+   r,   r-   r.   r/   r0   )r2   r   r   r5   r   rh   s         r   "test_no_keyword_returns_empty_listz:TestMatchSkillsByPrompt.test_no_keyword_returns_empty_list   sz    ()VXbc]w"}]]]w"]]]]]]w]]]w]]]"]]] ST[S\]]]]]]]r   c                X   t        dt              }|D cg c]  }|j                   }}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}}y
c c}w )ua   '블로그 SEO 전략' 프롬프트는 blog-writer와 seo-audit을 동시에 매칭해야 한다.u   블로그 SEO 전략rC   rv   rx   ry   rz   uI   '블로그 SEO 전략'에서 blog-writer가 매칭되지 않음. 결과: r}   rb   Nr   uG   '블로그 SEO 전략'에서 seo-audit이 매칭되지 않음. 결과: r~   r   s           r   )test_multiple_skills_match_simultaneouslyzATestMatchSkillsByPrompt.test_multiple_skills_match_simultaneously   s   ()?L)01A11	g]*	gUfUf	g]	g 	g]f]f 	g 	g`f`f	g 	gNfNf +	g 	g]f]f +	g 	gUfUfVWdVef	g 	g 	gSfSf	g 	g   	G{m+  	G  	G  	G{m  	G  	G  	G{  	G  	G  	G  	G  	G  	Gm  	G  	G  	Gm  	G  	G  	G  	G/v  xE  wF  .G  	G  	G  	G  	G  	G  	G	 2s   F'c                   t        dt              }t        |t              }|sd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dt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      dz  }t        t        j                  |            d}|D ]E  }t        |t              }|s-t        j                  dt        |             d	z   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
dt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      dz  }t        t        j                  |            d}H y)u1   반환 타입이 list[SkillSummary]여야 한다.u
   pdf 변환5assert %(py4)s
{%(py4)s = %(py0)s(%(py1)s, %(py2)s)
}
isinstancer   listr    r{   r!   r"   Nu)   결과 항목이 SkillSummary가 아님: 7
>assert %(py4)s
{%(py4)s = %(py0)s(%(py1)s, %(py2)s)
}itemr	   )r   r   r   r   r*   r+   r(   r,   r-   r/   r0   r	   r.   type)r2   r   r4   r6   r   s        r   )test_result_type_is_list_of_skill_summaryzATestMatchSkillsByPrompt.test_result_type_is_list_of_skill_summary   sJ   (zB'4((((((((z(((z(((((('((('((((((4(((4(((((((((( 	lDdL1k1kk5^_cdh_i^j3kkkkkkk:kkk:kkkkkkdkkkdkkkkkkLkkkLkkk1kkkkkk	lr   c                   t        dt              }|D cg c]  }|j                   }}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}}y
c c}w )uM   '회고' 키워드가 포함된 프롬프트는 retro를 매칭해야 한다.u   이번 주 회고 작성해줘rU   rv   rx   ry   rz   uM   '이번 주 회고 작성해줘'에서 retro가 매칭되지 않음. 결과: r}   rb   Nr~   r   s           r   test_retro_keyword_matchz0TestMatchSkillsByPrompt.test_retro_keyword_match   s    ()I:V)01A11  	Iw-'  	I  	I  	Iw-  	I  	I  	Iw  	I  	I  	I  	I  	I  	I-  	I  	I  	I-  	I  	I  	I  	I+x  zG  yH  *I  	I  	I  	I  	I  	I  	I 2r   c                   t        dt              }|D cg c]  }|j                   }}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	c c}w )
u?   소문자 'pdf' 키워드도 pdf 스킬을 매칭해야 한다.u   pdf 파일 만들어줘r   rv   rx   ry   rz   assert %(py5)srb   N)r   r   r@   r(   r)   r-   r*   r+   r,   r/   r0   r   s           r   test_lowercase_pdf_keywordz2TestMatchSkillsByPrompt.test_lowercase_pdf_keyword   s    ()BJO)01A11%u%%%%u%%%u%%%%%%%%%%%%%%%% 2s   CN)rW   rX   rY   rZ   r   r   r   r   r   r   r   r   r   r   r   rt   rt      s4    etAn^
GlI&r   rt   c                  (    e Zd ZdZd Zd Zd Zd Zy)TestCheckSecurityWhitelistuh   check_security_whitelist가 보안 관련 미등록 스킬을 올바르게 감지하는지 검증한다.c                   t        t              }t        |t              }|s-t	        j
                  dt        |             dz   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dt        j                         v st	        j                  t              rt	        j                  t              ndt	        j                  |      dz  }t        t	        j                  |            d}y)u(   반환 타입이 list[str]여야 한다.u)   반환 타입이 list여야 함. 실제: r   r   r   r   r   N)r
   r   r   r   r(   r.   r   r*   r+   r,   r-   r/   r0   r2   r   r4   r6   s       r   test_returns_list_typez1TestCheckSecurityWhitelist.test_returns_list_type   s    )*5&$'c'cc+TUYZ`UaTb)ccccccczccczcccccc&ccc&cccccc$ccc$ccc'ccccccr   c                   t        t              }|D ]E  }t        |t              }|s-t	        j
                  dt        |             dz   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dt        j                         v st	        j                  t              rt	        j                  t              ndt	        j                  |      dz  }t        t	        j                  |            d}H y)u?   반환된 목록의 모든 항목이 문자열이어야 한다.u+   목록 항목이 str이어야 함. 실제: r   r   r   strr   N)r
   r   r   r   r(   r.   r   r*   r+   r,   r-   r/   r0   r2   r   r   r4   r6   s        r   test_all_items_are_stringsz5TestCheckSecurityWhitelist.test_all_items_are_strings   s    )*5 	eDdC(d(dd,WX\]aXbWc*ddddddd:ddd:dddddddddddddddddCdddCddd(dddddd	er   c                   t        t              }t        D ]  }||v}|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      nddt        j                         v st        j                  |      rt        j                  |      nddz  }t        j                  d| d      dz   d	|iz  }t        t        j                  |            d
} y
)uY   SECURITY_WHITELIST에 등록된 스킬은 경고 목록에 포함되지 않아야 한다.not in)z%(py0)s not in %(py2)sr3   r   r    r!   u   화이트리스트 스킬 'u   '이 경고 목록에 포함됨
>assert %(py4)sr"   N)r
   r   r   r(   r)   r*   r+   r,   r-   r.   r/   r0   )r2   r   r3   r5   @py_format3r6   s         r   'test_whitelisted_skills_not_in_warningszBTestCheckSecurityWhitelist.test_whitelisted_skills_not_in_warnings   s    )*5, 	wJV+vvv:Vvvvvvv:vvv:vvvvvvVvvvVvvvv/J:,Vu-vvvvvvv	wr   c                f   t        d      }g }||k(  }|st        j                  d|fd||f      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}}y)	uI   존재하지 않는 디렉토리는 빈 리스트를 반환해야 한다.z/nonexistent/path/to/skillsr   r   r   r   r   rb   N)	r
   r(   r)   r*   r+   r,   r-   r/   r0   r2   r   r   r5   r   rh   s         r   'test_nonexistent_dir_returns_empty_listzBTestCheckSecurityWhitelist.test_nonexistent_dir_returns_empty_list   se    )*GHv|vvvr   N)rW   rX   rY   rZ   r   r   r   r   r   r   r   r   r      s    rd
ewr   r   c                  4    e Zd ZdZd Zd Zd Zd Zd Zd Z	y)	TestGetSkillsByLeveluU   get_skills_by_level이 레벨별 스킬을 올바르게 반환하는지 검증한다.c                $   t        t        t        j                        }|D cg c]  }|j                   }}t
        D cg c](  }t        t              |z  dz  j                         s'|* }}t        |      }d}||kD  }|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                  |      dz  }	t        j                  d      d	z   d
|	iz  }
t!        t        j"                  |
            dx}x}}|D ]  }||v }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      nddt        j                         v st        j                  |      rt        j                  |      nddz  }t        j                  d| d|       dz   d|iz  }t!        t        j"                  |            d} yc c}w c c}w )u~   CORE 레벨 조회 시 SECURITY_WHITELIST에 있는 스킬(skills 디렉토리에 존재하는 것)이 포함되어야 한다.SKILL.mdr   >z/%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} > %(py6)slenexisting_whitelistr    r{   r|   r&   uK   테스트 전제: SECURITY_WHITELIST 스킬이 1개 이상 존재해야 함
>assert %(py8)srF   Nrv   z%(py0)s in %(py2)sr3   
core_namesr   u   CORE 레벨에 'u.   '이 포함되어야 함. CORE 스킬 목록: r   r"   )r   r   r   r'   r@   r   r   existsr   r(   r)   r*   r+   r,   r-   r.   r/   r0   )r2   core_skillsr   r   r@   r   r   rL   rg   r7   rM   r3   r5   r   r6   s                  r   2test_core_level_includes_security_whitelist_skillszGTestGetSkillsByLevel.test_core_level_includes_security_whitelist_skills   s   )*jooF&12aff2
2 0Butd:FVY]F]`jFjErErEtduu%&yy&*yyy&yyyyyysyyysyyyyyy%yyy%yyy&yyyyyy,yyyyyyyy, 	GJ+  G  G  G:  G  G  G  G  G  G:  G  G  G:  G  G  G  G  G  G  G  G  G  G  G  G  G/?
|Ky  {E  zF  .G  G  G  G  G  G  G	G 3 vs   J (J)Jc                   t        t        t        j                        }t	        |t
              }|sd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dt        j                         v st        j                  t
              rt        j                  t
              ndt        j                  |      dz  }t        t        j                  |            d}|D ]#  }t	        |t              }|sd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dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      dz  }t        t        j                  |            d}& y)	u=   CORE 레벨 조회 결과가 list[SkillSummary]여야 한다.r   r   r   r   r   Nr   r	   )r   r   r   r'   r   r   r*   r+   r(   r,   r-   r/   r0   r	   )r2   r   r4   r6   r   s        r   -test_core_level_returns_list_of_skill_summaryzBTestGetSkillsByLevel.test_core_level_returns_list_of_skill_summary   s1   $ZA&$''''''''z'''z''''''&'''&''''''$'''$'''''''''' 	2DdL11111111:111:111111d111d111111L111L1111111111	2r   c                    t        t        t        j                        }|D cg c]  }|j                   }}t
        D cg c](  }t        t              |z  dz  j                         s'|* }}t        |      }d}||kD  }|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                  |      dz  }	t        j                  d      d	z   d
|	iz  }
t!        t        j"                  |
            dx}x}}|D ]  }||v }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      nddt        j                         v st        j                  |      rt        j                  |      nddz  }t        j                  d| d      dz   d|iz  }t!        t        j"                  |            d} yc c}w c c}w )uq   STANDARD 레벨에는 KEYWORD_TRIGGERS 스킬 중 skills 디렉토리에 있는 것들이 포함되어야 한다.r   r   r   r   r   existing_standardr   uI   테스트 전제: KEYWORD_TRIGGERS 스킬이 1개 이상 존재해야 함r   rF   Nrv   r   r3   standard_namesr   u   STANDARD 레벨에 'u   '이 포함되어야 함.r   r"   )r   r   r   r:   r@   r   r   r   r   r(   r)   r*   r+   r,   r-   r.   r/   r0   )r2   standard_skillsr   r   r@   r   r   rL   rg   r7   rM   r3   r5   r   r6   s                  r   3test_standard_level_includes_keyword_trigger_skillszHTestGetSkillsByLevel.test_standard_level_includes_keyword_trigger_skills  s   -j*:M:MN*9:Q!&&::.>rd4
CSVZCZ]gCgBoBoBqTrr$%vv%)vvv%vvvvvvsvvvsvvvvvv$vvv$vvv%vvvvvv+vvvvvvvv+ 	nJ/mmm:mmmmmm:mmm:mmmmmmmmmmmmm3G
|Sl1mmmmmmm	n ;rs   J (J)Jc                   t        t        t        j                        }|D ]M  }|j                  }|t
        v}|s
t        j                  d|fd|t
        f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dt        j                         v st        j                  t
              rt        j                  t
              nddz  }t        j                  d|j                   d      dz   d	|iz  }t        t        j                  |            d
x}}|j                  }|t        v}|s
t        j                  d|fd|t        f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dt        j                         v st        j                  t              rt        j                  t              nddz  }t        j                  d|j                   d      dz   d	|iz  }t        t        j                  |            d
x}}P y
)ue   EXTENDED 레벨에는 SECURITY_WHITELIST나 KEYWORD_TRIGGERS에 포함된 스킬이 없어야 한다.r   )z0%(py2)s
{%(py2)s = %(py0)s.name
} not in %(py4)sskillr   r   u.   EXTENDED 레벨에 SECURITY_WHITELIST 스킬 'u   '이 포함됨r%   r&   Nr   u,   EXTENDED 레벨에 KEYWORD_TRIGGERS 스킬 ')r   r   r   r>   r@   r   r(   r)   r*   r+   r,   r-   r.   r/   r0   r   )r2   extended_skillsr   r5   r4   r6   r7   s          r   3test_extended_level_excludes_whitelist_and_triggerszHTestGetSkillsByLevel.test_extended_level_excludes_whitelist_and_triggers  sH   -j*:M:MN$ 	AE

["44[ [IZIZ["4[ [TZTZ[ [BZBZ [ [QZQZ [ [QZQZ [ [TZTZ[ [BZBZ #5[ [QZQZ #5[ [IZIZ?

|>Z[ [ [GZGZ[ [ ::  A:%55  A  A  A:%5  A  A  A  A  A  A5  A  A  A5  A  A  A:  A  A  A  A  A  A%5  A  A  A%5  A  A  A  A9efkfpfpeqq  8A  A  A  A  A  A  A  A		Ar   c           	        t        d       t        t              }t        t        t        j
                        }t        |      }t        |      }||k(  }|st        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                  |      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                  |      dz  }t        j                  dt        |       d	t        |       d
      dz   d|iz  }t        t        j                  |            dx}x}}y)uT   flag가 OFF이면 get_skills_by_level(CORE)이 모든 스킬을 반환해야 한다.Fr   )zN%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py8)s
{%(py8)s = %(py5)s(%(py6)s)
}r   r   
all_skills)r    r{   r|   rb   r&   rF   u   flag OFF 시 CORE 스킬 수(u   )가 전체 스킬 수(u   )와 같아야 함z
>assert %(py10)srH   N)r   r   r   r   r   r'   r   r(   r)   r*   r+   r,   r-   r.   r/   r0   )r2   r   r   r   rK   rg   rM   rN   s           r    test_flag_off_all_skills_in_corez5TestGetSkillsByLevel.test_flag_off_all_skills_in_core  s   "5) ,
)*jooF; 	x3$
 	x $
 
 	x 	xfwfw	x $
 	x 	xqwqw	x 	x_w_w  	x 	xnwnw  	x 	xqwqw	x 	x_w_w  	x 	xnwnw  	x 	xnwnw   	x 	xqwqw	x 	x_w_w $' 	x 	xnwnw $' 	x 	xqwqw	x 	x_w_w 	x 	xnwnw 	x 	xnwnw$
 	x 	xfwfw*3{+;*<<STWXbTcSddvw	x 	x 	xdwdw	x 	x 	xr   c           	     N   t        d       t        j                  }t        t        |      }g }||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                  t              rt        j                  t              nddt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |      t        j                  |      dz  }dd	|iz  }t        t        j                  |            d
x}x}x}}t        j                  }t        t        |      }g }||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                  t              rt        j                  t              nddt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |      t        j                  |      dz  }dd	|iz  }t        t        j                  |            d
x}x}x}}y
)uV   flag가 OFF이면 STANDARD와 EXTENDED 레벨은 빈 리스트를 반환해야 한다.Fr   )zW%(py6)s
{%(py6)s = %(py0)s(%(py1)s, %(py4)s
{%(py4)s = %(py2)s.STANDARD
})
} == %(py9)sr   r   r   )r    r{   r!   r"   r&   py9zassert %(py11)spy11N)zW%(py6)s
{%(py6)s = %(py0)s(%(py1)s, %(py4)s
{%(py4)s = %(py2)s.EXTENDED
})
} == %(py9)s)r   r   r:   r   r   r(   r)   r*   r+   r,   r-   r/   r0   r>   )r2   r4   rL   @py_assert8rK   @py_format10@py_format12s          r   )test_flag_off_standard_and_extended_emptyz>TestGetSkillsByLevel.test_flag_off_standard_and_extended_empty#  s   "5)/9/B/BI":/BCIrICrIIIICrIIIIII"III"IIIIII:III:IIIIIIzIIIzIII/BIIICIIIrIIIIIII/9/B/BI":/BCIrICrIIIICrIIIIII"III"IIIIII:III:IIIIIIzIIIzIII/BIIICIIIrIIIIIIIr   N)
rW   rX   rY   rZ   r   r   r   r   r   r   r   r   r   r   r      s(    _
G2	nAxJr   r   c                  X    e 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)TestLegacyFunctionsuE   list_skills, view_skill, load_skill의 기존 동작을 검증한다.c                   t        t              }t        |t              }|s-t	        j
                  dt        |             dz   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dt        j                         v st	        j                  t              rt	        j                  t              ndt	        j                  |      dz  }t        t	        j                  |            d}y)u8   list_skills 호출 시 결과가 리스트여야 한다.u.   list_skills 결과가 list여야 함. 실제: r   r   r   r   r   N)r   r   r   r   r(   r.   r   r*   r+   r,   r-   r/   r0   r   s       r   test_list_skills_returns_listz1TestLegacyFunctions.test_list_skills_returns_list2  s    Z(&$'h'hh+YZ^_eZfYg)hhhhhhhzhhhzhhhhhh&hhh&hhhhhh$hhh$hhh'hhhhhhr   c                p   t        t              }t        |      }d}||kD  }|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                  |      dz  }t        j                  d      dz   d	|iz  }t        t        j                  |            d
x}x}}y
)uV   실제 skills 디렉토리에서 list_skills 결과가 비어 있지 않아야 한다.r   r   r   r   r   r   u:   skills 디렉토리에 스킬이 1개 이상 있어야 함r   rF   N)r   r   r   r(   r)   r*   r+   r,   r-   r.   r/   r0   r2   r   r   rL   rg   r7   rM   s          r   test_list_skills_not_emptyz.TestLegacyFunctions.test_list_skills_not_empty7  s    Z(6{\Q\{Q\\\{Q\\\\\\s\\\s\\\\\\6\\\6\\\{\\\Q\\\ \\\\\\\\r   c                   t        t              }|D ]E  }t        |t              }|s-t	        j
                  dt        |             dz   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dt        j                         v st	        j                  t              rt	        j                  t              ndt	        j                  |      dz  }t        t	        j                  |            d}H y)uK   list_skills 결과의 각 항목이 SkillSummary 인스턴스여야 한다.u*   항목이 SkillSummary여야 함. 실제: r   r   r   r	   r   N)r   r   r   r	   r(   r.   r   r*   r+   r,   r-   r/   r0   r   s        r   1test_list_skills_contains_skill_summary_instanceszETestLegacyFunctions.test_list_skills_contains_skill_summary_instances<  s    Z( 	mDdL1l1ll5_`dei`j_k3lllllll:lll:lllllldllldllllllLlllLlll1llllll	mr   c                   t        t        d      }t        |t              }|s-t	        j
                  dt        |             dz   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dt        j                         v st	        j                  t              rt	        j                  t              ndt	        j                  |      dz  }t        t	        j                  |            d}y)	uO   view_skill('retro') 호출 시 SkillDetail 인스턴스를 반환해야 한다.rU   u@   view_skill('retro') 결과가 SkillDetail이어야 함. 실제: r   r   r   r   r   N)r   r   r   r   r(   r.   r   r*   r+   r,   r-   r/   r0   r   s       r   *test_view_skill_retro_returns_skill_detailz>TestLegacyFunctions.test_view_skill_retro_returns_skill_detailB  s-   J0&+.  	B.  	B  	B2rswx~s  sA  1B  	B  	B  	B  	B  	B  	Bz  	B  	B  	Bz  	B  	B  	B  	B  	B  	B&  	B  	B  	B&  	B  	B  	B  	B  	B  	B+  	B  	B  	B+  	B  	B  	B.  	B  	B  	B  	B  	B  	Br   c                H	   t        t        d      }d}t        ||      }|sd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                  |      dz  }t        t        j                  |            dx}}d}t        ||      }|sd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                  |      dz  }t        t        j                  |            dx}}d	}t        ||      }|sd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                  |      dz  }t        t        j                  |            dx}}d
}t        ||      }|sd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                  |      dz  }t        t        j                  |            dx}}d}t        ||      }|sd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                  |      dz  }t        t        j                  |            dx}}y)u_   view_skill('retro') 결과에 name, description, triggers, requires 필드가 있어야 한다.rU   r@   z5assert %(py5)s
{%(py5)s = %(py0)s(%(py1)s, %(py3)s)
}hasattrdetail)r    r{   r|   rb   Ndescriptiontriggersrequires	full_path)
r   r   r   r*   r+   r(   r,   r-   r/   r0   )r2   r   r   rg   rh   s        r   *test_view_skill_detail_has_required_fieldsz>TestLegacyFunctions.test_view_skill_detail_has_required_fieldsG  sk   J0%&wvv&&&&&&&&w&&&w&&&&&&v&&&v&&&v&&&&&&&&&&,-wv}--------w---w------v---v---}----------)*wvz********w***w******v***v***z**********)*wvz********w***w******v***v***z***********+wv{++++++++w+++w++++++v+++v+++{++++++++++r   c                   t        t        d      }t        |t              }|s-t	        j
                  dt        |             dz   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dt        j                         v st	        j                  t              rt	        j                  t              ndt	        j                  |      dz  }t        t	        j                  |            d}y)	u>   load_skill('pdf') 호출 시 문자열을 반환해야 한다.r   u6   load_skill('pdf') 결과가 str이어야 함. 실제: r   r   r   r   r   N)r   r   r   r   r(   r.   r   r*   r+   r,   r-   r/   r0   r   s       r   "test_load_skill_pdf_returns_stringz6TestLegacyFunctions.test_load_skill_pdf_returns_stringP  s    J.&#&o&oo*`aeflam`n(ooooooozooozoooooo&ooo&oooooo#ooo#ooo&oooooor   c                r   t        t        d      }t        |      }d}||kD  }|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                  |      dz  }t        j                  d      d	z   d
|iz  }t        t        j                  |            dx}x}}y)uH   load_skill('pdf')의 반환 문자열이 비어 있지 않아야 한다.r   r   r   r   r   r   r   u)   load_skill('pdf') 결과가 비어 있음r   rF   N)r   r   r   r(   r)   r*   r+   r,   r-   r.   r/   r0   r   s          r   test_load_skill_pdf_not_emptyz1TestLegacyFunctions.test_load_skill_pdf_not_emptyU  s    J.6{KQK{QKKK{QKKKKKKsKKKsKKKKKK6KKK6KKK{KKKQKKK KKKKKKKKr   c                    t        j                  t              5  t        t        d       ddd       y# 1 sw Y   yxY w)ug   존재하지 않는 스킬 이름으로 view_skill 호출 시 FileNotFoundError가 발생해야 한다.nonexistent-skill-xyz-123N)pytestraisesFileNotFoundErrorr   r   r2   s    r   1test_view_skill_nonexistent_raises_file_not_foundzETestLegacyFunctions.test_view_skill_nonexistent_raises_file_not_foundZ  3    ]],- 	@z#>?	@ 	@ 	@   4=c                    t        j                  t              5  t        t        d       ddd       y# 1 sw Y   yxY w)ug   존재하지 않는 스킬 이름으로 load_skill 호출 시 FileNotFoundError가 발생해야 한다.r   N)r   r   r   r   r   r   s    r   1test_load_skill_nonexistent_raises_file_not_foundzETestLegacyFunctions.test_load_skill_nonexistent_raises_file_not_found_  r   r   c                f   t        d      }g }||k(  }|st        j                  d|fd||f      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}}y)	u`   존재하지 않는 디렉토리로 list_skills 호출 시 빈 리스트를 반환해야 한다.z/nonexistent/path/xyzr   r   r   r   r   rb   N)	r   r(   r)   r*   r+   r,   r-   r/   r0   r   s         r   .test_list_skills_nonexistent_dir_returns_emptyzBTestLegacyFunctions.test_list_skills_nonexistent_dir_returns_emptyd  se    45v|vvvr   c                d   t        t        d      }t        |t              }|sd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dt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      dz  }t        t        j                  |            d}y)uU   view_skill('blog-writer') 호출 시 SkillDetail 인스턴스를 반환해야 한다.rC   r   r   r   r   r   N)r   r   r   r   r*   r+   r(   r,   r-   r/   r0   r   s       r   0test_view_skill_blog_writer_returns_skill_detailzDTestLegacyFunctions.test_view_skill_blog_writer_returns_skill_detaili  s    J6&+........z...z......&...&......+...+..........r   c                   t        t        d      }t        |t              }|sd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dt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      dz  }t        t        j                  |            d}t        |      }d}||kD  }|st        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                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}y)u@   load_skill('retro') 호출 시 문자열을 반환해야 한다.rU   r   r   r   r   r   Nr   r   r   r   r   zassert %(py8)srF   )r   r   r   r   r*   r+   r(   r,   r-   r/   r0   r   r)   )	r2   r   r4   r6   r   rL   rg   r7   rM   s	            r   $test_load_skill_retro_returns_stringz8TestLegacyFunctions.test_load_skill_retro_returns_stringn  s!   J0&#&&&&&&&&z&&&z&&&&&&&&&&&&&&&&&#&&&#&&&&&&&&&&6{Q{Q{Qss66{Qr   N)rW   rX   rY   rZ   r   r   r   r   r   r   r   r   r   r   r   r  r   r   r   r   r   /  sI    Oi
]
mB
,p
L
@
@

/
r   r   )$rZ   
__future__r   builtinsr*   _pytest.assertion.rewrite	assertionrewriter(   pathlibr   r   utils.skill_loaderr   r   r   r   r	   r
   r   r   r   r   r   r   r   r   r   fixturer   r   r\   rt   r   r   r   r   r   r   <module>r
     s   
 #        " *
 % %$> $>X$< $<Z8& 8&@ >7J 7J~C Cr   