
    i                     f   U d 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mZmZ ddlmZ ddlmZ ddlmZmZ ddlZ ee      j,                  j,                  Zedz  Zej2                  j5                  de      Zg ZdZeeuZeZerej@                  Z!dZ"e!e"uZ#e#ZesB ejH                  d	efd
eef      d ejJ                         v s ejL                  e      r ejN                  e      nd ejN                  e      dz  Z(dde(iz  Z)ejU                  e)       er ejH                  d	e#fde!e"f      d ejJ                         v s ejL                  e      r ejN                  e      nd ejN                  e!       ejN                  e"      dz  Z+dde+iz  Z,ejU                  e,        ejZ                  ed      i z  Z.dde.iz  Z/ e0 ejb                  e/            dxZxZxZxZxZ!xZ#Z"ej2                  je                  e      Z3e3e
jh                  d<   ej@                  jk                  e3       edz  Z6ej2                  j5                  de6      Z7g ZdZe7euZeZere7j@                  Z!dZ"e!e"uZ#e#ZesB ejH                  d	efd
e7ef      d ejJ                         v s ejL                  e7      r ejN                  e7      nd ejN                  e      dz  Z(dde(iz  Z)ejU                  e)       er ejH                  d	e#fde!e"f      d ejJ                         v s ejL                  e7      r ejN                  e7      nd ejN                  e!       ejN                  e"      dz  Z+dde+iz  Z,ejU                  e,        ejZ                  ed      i z  Z.dde.iz  Z/ e0 ejb                  e/            dxZxZxZxZxZ!xZ#Z"ej2                  je                  e7      Z8e8e
jh                  d<   e7j@                  jk                  e8       dede9e:ef   fdZ;dede9e:e<e:   f   defdZ= G d d      Z> G d  d!      Z? G d" d#      Z@ G d$ d%      ZA G d& d'      ZB G d( d)      ZC G d* d+      ZD G d, d-      ZE G d. d/      ZF G d0 d1      ZG G d2 d3      ZH G d4 d5      ZI G d6 d7      ZJ G d8 d9      ZK G d: d;      ZL G d< d=      ZMed>z  ZNd?e:defd@ZOdAdBdCdDgdEdDgdFdGZPe9e:ef   eQdH<   dIdJdCdDgdEdDgdFdGZRe9e:ef   eQdK<   dLdDdEgdDdCgdFdMdNZSe9e:ef   eQdO<   dPdEdDgdCdDgdFdQdNZTe9e:ef   eQdR<   dSg dTZUe9e:ef   eQdU<   dVdWdXgdTZVe9e:ef   eQdY<   dZeRd[d\idLeSd]d^d_gd`ZWe9e:ef   eQda<    G db dc      ZX G dd de      ZY G df dg      ZZ G dh di      Z[ G dj dk      Z\ G dl dm      Z] G dn do      Z^y)pu  Tests for output-review.py and output_review_helpers.py — TDD RED phase.

헬퍼 모듈(output_review_helpers)과 메인 스크립트(output-review)에 대한 테스트.
아직 구현이 없으므로 ImportError 또는 AttributeError로 실패하는 것이 정상(RED 단계).
    N)datetimetimezone)Path)Any)	MagicMockpatchzoutput_review_helpers.pyoutput_review_helpersis not)z%(py2)s is not %(py5)s_helpers_spec)py2py5z%(py7)spy7)z5%(py11)s
{%(py11)s = %(py9)s.loader
} is not %(py14)s)py9py11py14z%(py16)spy16zassert %(py19)spy19zoutput-review.pyoutput_review
_main_spectmp_pathreturnc                     | dz  dz  dz  }|j                  d       | dz  dz  dz  }|j                  d       | dz  dz  dz  }|j                          | dz  d	z  }|j                  d       ||||d
S )u(   테스트용 디렉토리 구조 생성.memoryskill-learning	championsT)parentszchampions-archivelearnings.jsonlskillsshared)champions_dirarchive_dirlearnings_pathskills_shared)mkdirtouch)r   r!   r"   r#   r$   s        7/home/jay/workspace/scripts/tests/test_output_review.py_make_tmp_dirsr(   .   s    x'*::[HM%X%(88;NNKd#(+;;>OONx'(2M%&"(&	     r$   datac                 \    | dz  }|j                  t        j                  |      d       |S )u   eval-axes.json 파일 생성.zeval-axes.jsonutf-8encoding)
write_textjsondumps)r$   r*   paths      r'   _make_eval_axes_jsonr3   @   s+    ++DOODJJt$wO7Kr)   c                   <    e Zd ZddZddZddZddZddZddZy)	TestBuildChampionDataNc                     t         j                  dddddg      }g d}|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)uB   champion 데이터에 필수 필드가 모두 존재해야 한다.satori-cardnewsbusinesszsample output text
   훅 강도   시각 밸런스
skill_name
skill_typechampion_outputeval_axes_used)r<   r=   r>   r?   
created_at	last_usedstatusconsecutive_defensesconsecutive_lossesreinit_count_this_monthmonth_reset_dateinit_methodbenchmark_sourcein)z%(py0)s in %(py2)sfieldr*   py0r   u   필드 'u   ' 누락z
>assert %(py4)spy4N)orhbuild_champion_data
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_saferepr_format_assertmsgAssertionError_format_explanation)selfr*   required_fieldsrK   @py_assert1@py_format3@py_format5s          r'   (test_build_champion_data_required_fieldsz>TestBuildChampionData.test_build_champion_data_required_fieldsM   s    &&(!0(*<=	 ' 

 % 	=ED=<<<5D<<<<<<5<<<5<<<<<<D<<<D<<<<HUG8"<<<<<<<	=r)   c                    t         j                  ddddg      }|d   }t        |t              }|sddt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      d	t	        j
                         v st        j                  t              rt        j                  t              nd	t        j                  |      d
z  }t        t        j                  |            dx}}|d   }t        |t              }|sddt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      d	t	        j
                         v st        j                  t              rt        j                  t              nd	t        j                  |      d
z  }t        t        j                  |            dx}}|d   }t        |t              }|sddt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      d	t	        j
                         v st        j                  t              rt        j                  t              nd	t        j                  |      d
z  }t        t        j                  |            dx}}|d   }t        |t              }|sddt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      dt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      d
z  }t        t        j                  |            dx}}|d   }t        |t              }|sddt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      d	t	        j
                         v st        j                  t              rt        j                  t              nd	t        j                  |      d
z  }t        t        j                  |            dx}}|d   }t        |t              }|sddt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      d	t	        j
                         v st        j                  t              rt        j                  t              nd	t        j                  |      d
z  }t        t        j                  |            dx}}|d   }t        |t              }|sddt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      d	t	        j
                         v st        j                  t              rt        j                  t              nd	t        j                  |      d
z  }t        t        j                  |            dx}}|d   }t        |t              }|sddt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      dt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      d
z  }t        t        j                  |            dx}}|d   }t        |t              }|sddt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      dt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      d
z  }t        t        j                  |            dx}}|d   }t        |t              }|sddt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      dt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      d
z  }t        t        j                  |            dx}}|d   }t        |t              }|sddt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      d	t	        j
                         v st        j                  t              rt        j                  t              nd	t        j                  |      d
z  }t        t        j                  |            dx}}|d   }t        |t              }|sddt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      d	t	        j
                         v st        j                  t              rt        j                  t              nd	t        j                  |      d
z  }t        t        j                  |            dx}}|d   }t        |t              }|sddt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      d	t	        j
                         v st        j                  t              rt        j                  t              nd	t        j                  |      d
z  }t        t        j                  |            dx}}y)u9   각 필드의 타입이 스키마와 일치해야 한다.r7   r8   outputr9   r;   r<   5assert %(py5)s
{%(py5)s = %(py0)s(%(py2)s, %(py3)s)
}
isinstancestrrM   r   py3r   Nr=   r>   r?   listr@   rA   rB   rC   intrD   rE   rF   rG   rH   )rO   rP   rc   rd   rS   rT   rQ   rU   rV   rX   rY   rg   rh   )rZ   r*   r\   @py_assert4@py_format6s        r'   $test_build_champion_data_field_typesz:TestBuildChampionData.test_build_champion_data_field_typesg   s   &&(!$(>	 ' 
 |,2z,c22222222z222z222,222222c222c2222222222|,2z,c22222222z222z222,222222c222c2222222222017z1377777777z777z7771777777377737777777777/07z0$77777777z777z7770777777$777$7777777777|,2z,c22222222z222z222,222222c222c2222222222{+1z+S11111111z111z111+111111S111S1111111111x..z.#........z...z..........#...#..........56<z6<<<<<<<<z<<<z<<<6<<<<<<<<<<<<<<<<<<<34:z4c::::::::z:::z:::4::::::c:::c::::::::::89?z93????????z???z???9??????3???3??????????128z2C88888888z888z8882888888C888C8888888888}-3z-s33333333z333z333-333333s333s3333333333128z2C88888888z888z8882888888C888C8888888888r)   c                 6   t         j                  dddg       }|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}}|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}}|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}}|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}}|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}}|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)u8   초기값이 스키마 기본값과 일치해야 한다.
test-skillcreativera   r;   rB   active==z%(py1)s == %(py4)spy1rN   assert %(py6)spy6NrC   r   rD   rE   rG   full_benchmarkrH   online_expertrO   rP   rQ   rR   rV   rX   rY   rZ   r*   @py_assert0@py_assert3@py_assert2r^   @py_format7s          r'   'test_build_champion_data_default_valuesz=TestBuildChampionData.test_build_champion_data_default_values}   s   &&#!$	 ' 
 H~))~))))~)))~))))))))))*+0q0+q0000+q000+000q0000000().Q.)Q....)Q...)...Q.......-.3!3.!3333.!333.333!3333333M"6&66"&66666"&6666"666&66666666&':?:'?::::'?:::':::?:::::::r)   c                 <   t         j                  ddddgdd      }|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}}|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)uI   init_method 및 benchmark_source 커스텀 값이 적용되어야 한다.rm   
analyticalra   accuracymanualinternal_team)r<   r=   r>   r?   rG   rH   rG   rp   rr   rs   ru   rv   NrH   ry   rz   s          r'   +test_build_champion_data_custom_init_methodzATestBuildChampionData.test_build_champion_data_custom_init_method   s    &&##$&< , ' 
 M".h."h...."h..."...h.......&':?:'?::::'?:::':::?:::::::r)   c                 6   t         j                  dddg       }|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)u/   skill_name이 정확히 보존되어야 한다.zmy-special-skillr8   ra   r;   r<   rp   rr   rs   ru   rv   Nry   rz   s          r'   -test_build_champion_data_skill_name_preservedzCTestBuildChampionData.test_build_champion_data_skill_name_preserved   s{    &&)!$	 ' 
 L!7%77!%77777!%7777!777%77777777r)   c                    g d}t         j                  ddd|      }|d   }||k(  }|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)u=   eval_axes_used 리스트가 그대로 저장되어야 한다.r9   r:      정보 밀도rm   r8   ra   r;   r?   rp   )z%(py1)s == %(py3)saxesrt   rf   assert %(py5)sr   N)
rO   rP   rQ   rR   rV   rS   rT   rU   rX   rY   )rZ   r   r*   r{   r}   @py_format4rj   s          r'   ,test_build_champion_data_eval_axes_preservedzBTestBuildChampionData.test_build_champion_data_eval_axes_preserved   s    B&&#!$	 ' 
 $%-%----%---%----------------r)   r   N)	__name__
__module____qualname__r_   rk   r   r   r   r    r)   r'   r5   r5   L   s     =49,;;8	.r)   r5   c                       e Zd Zdedej
                  ddfdZdedej
                  ddfdZdedej
                  ddfdZy)TestSaveAndLoadChampionr   monkeypatchr   Nc                 6   t        |       |j                  dt        |             t        j	                  ddddg      }t        j                  d|       t        j                  d      }d}||u}|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}}|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}}
|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}}
|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)uF   저장 후 로드하면 동일한 데이터가 반환되어야 한다.WORKSPACE_ROOTr7   r8   ztest outputr9   r;   Nr
   z%(py0)s is not %(py3)sloadedrM   rf   r   r   r<   rp   rr   rs   ru   rv   r>   r?   )r(   setenvrd   rO   rP   save_championload_championrQ   rR   rS   rT   rU   rV   rX   rY   )rZ   r   r   champion_datar   r}   r\   r   rj   r{   r|   r^   r~   s                r'   %test_save_and_load_champion_roundtripz=TestSaveAndLoadChampion.test_save_and_load_champion_roundtrip   s   x +S];//(!)(>	 0 
 	+];""#45!!vT!!!!vT!!!!!!v!!!v!!!T!!!!!!!l#B}\'BB#'BBBBB#'BBBB#BBB'BBBBBBBB'(LM:K,LL(,LLLLL(,LLLL(LLL,LLLLLLLL&'J=9I+JJ'+JJJJJ'+JJJJ'JJJ+JJJJJJJJr)   c                    t        |       |j                  dt        |             t        j	                  dddg       }t        j                  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}|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}||k(  }|st        j"                  d|fd||f      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@   save_champion은 저장된 파일 경로를 반환해야 한다.r   rm   r8   ra   r;   5assert %(py4)s
{%(py4)s = %(py0)s(%(py1)s, %(py2)s)
}rc   result_pathr   rM   rt   r   rN   NAassert %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.exists
}()
}rM   r   rN   ztest-skill.jsonrp   )z,%(py2)s
{%(py2)s = %(py0)s.name
} == %(py5)srM   r   r   assert %(py7)sr   )r(   r   rd   rO   rP   r   rc   r   rS   rT   rQ   rU   rV   rX   rY   existsnamerR   )rZ   r   r   r*   r   r|   r^   r\   ri   rj   @py_format8s              r'   test_save_champion_returns_pathz7TestSaveAndLoadChampion.test_save_champion_returns_path   s   x +S];&&#!$	 ' 
 ''d;+t,,,,,,,,z,,,z,,,,,,+,,,+,,,,,,t,,,t,,,,,,,,,,!!#!########{###{###!##########4#44#44444#4444444{444{444444#44444444r)   c                    t        |       |j                  dt        |             t        j	                  ddddg      }t        j                  d|      }|j                  d      }t        j                  |      }|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)u3   저장된 파일이 유효한 JSON이어야 한다.r   z	json-testr8   ra   axis1r;   r,   r-   r<   rp   rr   rs   ru   rv   N)r(   r   rd   rO   rP   r   	read_textr0   loadsrQ   rR   rV   rX   rY   )rZ   r   r   r*   
saved_pathrawparsedr{   r|   r}   r^   r~   s               r'   %test_save_champion_creates_valid_jsonz=TestSaveAndLoadChampion.test_save_champion_creates_valid_json   s    x +S];&&"!$#9	 ' 
 &&{D9
""G"4Cl#2{2#{2222#{222#222{2222222r)   )	r   r   r   r   pytestMonkeyPatchr   r   r   r   r)   r'   r   r      sk    Kd KQWQcQc Khl K&5 56K]K] 5bf 5"3d 3QWQcQc 3hl 3r)   r   c                   \    e Zd Zdedej
                  ddfdZdedej
                  ddfdZy)TestLoadChampionNotExistsr   r   r   Nc                    t        |       |j                  dt        |             t        j	                  d      }d}||u }|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)
uB   존재하지 않는 스킬 로드 시 None을 반환해야 한다.r   nonexistent-skillNisz%(py0)s is %(py3)sresultr   r   r   r(   r   rd   rO   r   rQ   rR   rS   rT   rU   rV   rX   rY   rZ   r   r   r   r}   r\   r   rj   s           r'   ,test_load_champion_returns_none_when_missingzFTestLoadChampionNotExists.test_load_champion_returns_none_when_missing   s    x +S];""#67v~vvvr)   c                    t        |       |j                  dt        |             t        j	                  d      }d}||u }|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)
uN   존재하지 않는 스킬 로드 시 예외가 발생하지 않아야 한다.r   zmissing-skill-xyzNr   r   r   r   r   r   r   r   s           r'   !test_load_champion_does_not_raisez;TestLoadChampionNotExists.test_load_champion_does_not_raise   s    x +S]; ""#67v~vvvr)   )r   r   r   r   r   r   r   r   r   r)   r'   r   r      sE    T X^XjXj os $ VM_M_ dh r)   r   c                       e Zd Zdedej
                  ddfdZdedej
                  ddfdZdedej
                  ddfdZy)TestArchiveChampionr   r   r   Nc           	      	   t        |      }|j                  dt        |             t        j	                  ddddg      }t        j                  d|       t        j                  d      }d}||u}|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}}|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}}
g }|d   }|j                   }||v }|}|s!|d   }t        |      }t        |      }||v }|}|s't        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  }|j#                  |       |sFt        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d
t        j                         v st        j                  |      rt        j                  |      nd
t        j                  |      dz  }dd|iz  }|j#                  |       t        j$                  |d      i z  }dd|iz  }t        t        j                  |            dx}x}x}x}x}x}x}x}}|j&                  }d}||k(  }
|
st        j                  d|
fd ||f      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[   기존 챔피언을 아카이브하면 타임스탬프 파일명으로 이동해야 한다.r   zarchive-testr8   z
old outputr   r;   Nr
   r   archived_pathr   r   r   r   r   r"   rI   )z/%(py3)s in %(py7)s
{%(py7)s = %(py5)s.parents
})rf   r   r   z%(py9)sr   )zV%(py15)s
{%(py15)s = %(py11)s(%(py13)s)
} in %(py20)s
{%(py20)s = %(py17)s(%(py18)s)
}rd   )r   py13py15py17py18py20z%(py22)spy22   zassert %(py25)spy25z.jsonrp   )z.%(py2)s
{%(py2)s = %(py0)s.suffix
} == %(py5)sr   r   r   )r(   r   rd   rO   rP   r   archive_championrQ   rR   rS   rT   rU   rV   rX   rY   r   r   append_format_boolopsuffix)rZ   r   r   dirsr   r   r}   r\   r   rj   r|   r^   @py_assert6ri   r{   @py_assert12@py_assert14@py_assert19@py_assert16r   @py_format10@py_format21@py_format23@py_format24@py_format26s                            r'    test_archive_champion_moves_filez4TestArchiveChampion.test_archive_champion_moves_file  s   h'+S]; //%!(#9	 0 
 	.-8,,^<$((}D((((}D((((((}(((}(((D(((((((##%#%%%%%%%%}%%%}%%%#%%%%%%%%%%mtM"mm&;&;m"&;;m4CVmsCV?Wm[^_l[mm?W[m?mmmmm"&;mmm"mmmmmmmmmmmmmm&;mmmmmmm?W[mmmmmmmsmmmsmmmCVmmm?Wmmmmmm[^mmm[^mmmmmm_lmmm_lmmm[mmmmmmmmmmmmmmmm##.w.#w....#w......}...}...#...w.......r)   c                    t        |       |j                  dt        |             t        j	                  dddg       }t        j                  d|       t        j                  d      }d}||u}|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}}|j                  }	d |	D        }t!        |      }
|
st        j"                  d|	       dz   dt        j                         v st        j                  t               rt        j                  t               ndt        j                  |      t        j                  |
      dz  }t        t        j                  |            dx}}
y)uD   아카이브 파일명에 타임스탬프가 포함되어야 한다.r   zts-testr8   ra   r;   Nr
   r   r   r   r   r   c              3   <   K   | ]  }|j                           y wN)isdigit).0chs     r'   	<genexpr>zSTestArchiveChampion.test_archive_champion_filename_has_timestamp.<locals>.<genexpr>0  s     /B2::</s   u   타임스탬프 없음: z.
>assert %(py4)s
{%(py4)s = %(py0)s(%(py2)s)
}anyr   )r(   r   rd   rO   rP   r   r   rQ   rR   rS   rT   rU   rV   rX   rY   stemr   rW   )rZ   r   r   r*   r   r}   r\   r   rj   r   r|   r^   s               r'   ,test_archive_champion_filename_has_timestampz@TestArchiveChampion.test_archive_champion_filename_has_timestamp  s8   x +S];&& !$	 ' 
 	)T*,,Y7$((}D((((}D((((((}(((}(((D(((((((!!/$/Rs//R/RR3KD61RRRRRRRsRRRsRRR/RRR/RRRRRRr)   c                    t        |      }|j                  dt        |             t        j	                  dddg       }t        j                  d|       |d   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}}t        j                  d       |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}x}}	y)uP   아카이브 후 원본 champions/{skill}.json이 존재하지 않아야 한다.r   zremove-testr8   ra   r;   r!   zremove-test.jsonr   originalr   NzEassert not %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.exists
}()
})r(   r   rd   rO   rP   r   r   rS   rT   rQ   rU   rV   rX   rY   r   )rZ   r   r   r   r*   r   r\   r|   r^   @py_assert5rj   s              r'   &test_archive_champion_original_removedz:TestArchiveChampion.test_archive_champion_original_removed2  s/   h'+S];&&$!$	 ' 
 	-.(+==         x   x             ]+??$?$$$$$$$$$$$8$$$8$$$?$$$$$$$$$$r)   )	r   r   r   r   r   r   r   r   r   r   r)   r'   r   r     sk    / /FL^L^ /cg /.ST SX^XjXj Sos S&%t %RXRdRd %im %r)   r   c                   \    e Zd Zdedej
                  ddfdZdedej
                  ddfdZy)TestArchiveChampionNoExistingr   r   r   Nc                    t        |       |j                  dt        |             t        j	                  d      }d}||u }|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)
uC   아카이브할 챔피언이 없으면 None을 반환해야 한다.r   zdoes-not-existNr   r   r   r   r   r   r(   r   rd   rO   r   rQ   rR   rS   rT   rU   rV   rX   rY   r   s           r'   .test_archive_nonexistent_champion_returns_nonezLTestArchiveChampionNoExisting.test_archive_nonexistent_champion_returns_noneK  s    x +S];%%&67v~vvvr)   c                    t        |       |j                  dt        |             t        j	                  d      }d}||u }|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)
uO   아카이브할 챔피언이 없어도 예외가 발생하지 않아야 한다.r   zghost-skillNr   r   r   r   r   r   r   r   s           r'   'test_archive_nonexistent_does_not_raisezETestArchiveChampionNoExisting.test_archive_nonexistent_does_not_raiseS  s    x +S]; %%m4v~vvvr)   )r   r   r   r   r   r   r   r   r   r)   r'   r   r   J  sF    t Z`ZlZl qu  SYSeSe jn r)   r   c                       e Zd Zdedej
                  ddfdZdedej
                  ddfdZdedej
                  ddfdZdedej
                  ddfdZ	y)	TestAppendLearningr   r   r   Nc                 |   t        |       |j                  dt        |             |dz  dz  dz  }t        |j	                  d      j                               }ddd	t        j                  t        j                        j                         d
}t        j                  |       t        |j	                  d      j                               }d}||z   }||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"                  |      rt        j$                  |      ndt        j$                  |      dz  }
dd|
iz  }t'        t        j(                  |            dx}	x}}y)uL   append_learning 호출 시 learnings.jsonl 줄 수가 1 증가해야 한다.r   r   r   r   r,   r-   rm   Au   더 나은 훅)r<   winnerreason	timestampr   rp   )z%(py0)s == (%(py2)s + %(py4)s)	new_linesinitial_linesr   r   r   N)r(   r   rd   lenr   
splitlinesr   nowr   utc	isoformatrO   append_learningrQ   rR   rS   rT   rU   rV   rX   rY   )rZ   r   r   r#   r   entryr   r|   r   r\   rj   r   s               r'   )test_append_learning_increases_line_countz<TestAppendLearning.test_append_learning_increases_line_countc  s6   x +S];!H,/??BSSN44g4FQQST '&!hll3==?	
 	E"00'0BMMOP	,--MA--y-----y-------y---y------M---M---A-------r)   c                 (   t        |       |j                  dt        |             dddd}t        j	                  |       |dz  dz  dz  }|j                  d	
      j                         j                         d   }t        j                  |      }|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)u0   append된 줄이 유효한 JSON이어야 한다.r   z
json-skilldefenseg333333?)r<   eventscorer   r   r   r,   r-   r<   rp   rr   rs   ru   rv   N)r(   r   rd   rO   r  r   stripr   r0   r   rQ   rR   rV   rX   rY   )rZ   r   r   r  r#   	last_liner   r{   r|   r}   r^   r~   s               r'   $test_append_learning_valid_json_linez7TestAppendLearning.test_append_learning_valid_json_linev  s    x +S];+i$OE"!H,/??BSS",,g,>DDFQQSTVW	I&l#3|3#|3333#|333#333|3333333r)   c                 b   t        |       |j                  dt        |             t        d      D ]  }t        j                  |d| d        |dz  dz  dz  }|j                  d	      j                         D cg c]  }|j                         s| }}t        |      }d}||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                  |      t        j                  |      dz  }
dd|
iz  }t!        t        j"                  |            dx}x}	}yc c}w )u;   여러 번 append 시 각각 줄로 저장되어야 한다.r      zskill-)indexr<   r   r   r   r,   r-   rp   z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)sr   linesrM   rt   rf   rv   assert %(py8)spy8N)r(   r   rd   rangerO   r  r   r   r  r   rQ   rR   rS   rT   rU   rV   rX   rY   )rZ   r   r   ir#   lr  r}   r   ri   r~   @py_format9s               r'   %test_append_learning_multiple_entriesz8TestAppendLearning.test_append_learning_multiple_entries  s,   x +S];q 	JA!VA3< HI	J "H,/??BSS*44g4FQQSaqWXW^W^W`aa5zQzQzQss55zQ bs   ?F,F,c                    t        |       |j                  dt        |             |dz  dz  dz  }|j                  t	        j
                  ddi      dz   d	       t        j                  d
di       |j                  d	      j                         D cg c]  }|j                         s| }}t        |      }d}||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"                  |      t        j"                  |      dz  }	dd|	iz  }
t%        t        j&                  |
            dx}x}}t	        j(                  |d         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 )uP   append_learning은 기존 내용을 덮어쓰지 않아야 한다 (append-only).r   r   r   r   existingr  
r,   r-   new   rp   r  r   r  r  r  r  Nr   rr   rs   ru   rv   )r(   r   rd   r/   r0   r1   rO   r  r   r   r  r   rQ   rR   rS   rT   rU   rV   rX   rY   r   )rZ   r   r   r#   r  r  r}   r   ri   r~   r  r{   r|   r^   s                 r'   'test_append_learning_does_not_overwritez:TestAppendLearning.test_append_learning_does_not_overwrite  s   x +S];!H,/??BSS!!$**j'-B"Cd"JU\!]UG,-*44g4FQQSaqWXW^W^W`aa5zQzQzQss55zQzz%(#J/:7:/7::::/7:::/:::7::::::: bs   I,I)
r   r   r   r   r   r   r  r  r  r!  r   r)   r'   r   r   b  s    .$ .U[UgUg .lp .&4T 4PVPbPb 4gk 4
d 
QWQcQc 
hl 
; ;SYSeSe ;jn ;r)   r   c                   \    e Zd Zdedej
                  ddfdZdedej
                  ddfdZy)TestLoadEvalAxesr   r   r   Nc                 4   t        |      }|j                  dt        |             t        |d   g ddgd       t        j                  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}g d}||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)uR   eval-axes.json에서 해당 스킬의 평가 축 리스트를 반환해야 한다.r   r$   r   r   )r7   zother-skillr7   r   rc   r   rg   r   Nrp   z%(py0)s == %(py3)sr   r   r   )r(   r   rd   r3   rO   load_eval_axesrc   rg   rS   rT   rQ   rU   rV   rX   rY   rR   )rZ   r   r   r   r   r|   r^   r}   r\   r   rj   s              r'    test_load_eval_axes_returns_listz1TestLoadEvalAxes.test_load_eval_axes_returns_list  s5   h'+S];!#V *|	
 !!"34$%%%%%%%%z%%%z%%%%%%$%%%$%%%%%%%%%%%%%%%%%%%JJtJJJJJtJJJJJJJtJJJtJJJJJJJJJJJr)   c                 l   t        |      }|j                  dt        |             t        |d   ddgdgd       t        j                  d      }t        j                  d      }d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}}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)u6   다른 스킬의 축과 혼동되지 않아야 한다.r   r$   zaxis-a1zaxis-a2zaxis-b1)skill-askill-br)  r*  rp   r%  axes_ar   r   r   Naxes_br(   r   rd   r3   rO   r&  rQ   rR   rS   rT   rU   rV   rX   rY   )
rZ   r   r   r   r+  r,  r}   r\   r   rj   s
             r'   !test_load_eval_axes_correct_skillz2TestLoadEvalAxes.test_load_eval_axes_correct_skill  s!   h'+S];!%y1%;	
 ##I.##I.#Y//v/////v///////v///v///////////#$v$$$$v$$$$$$v$$$v$$$$$$$$$$r)   )r   r   r   r   r   r   r'  r.  r   r)   r'   r#  r#    sH    K KFL^L^ Kcg K"%$ %VM_M_ %dh %r)   r#  c                   \    e Zd Zdedej
                  ddfdZdedej
                  ddfdZy)TestLoadEvalAxesMissingSkillr   r   r   Nc                    t        |      }|j                  dt        |             t        |d   ddgi       t        j                  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)uH   eval-axes.json에 없는 스킬은 빈 리스트를 반환해야 한다.r   r$   zexisting-skillr   r   rp   r%  r   r   r   r   Nr-  )	rZ   r   r   r   r   r}   r\   r   rj   s	            r'   %test_missing_skill_returns_empty_listzBTestLoadEvalAxesMissingSkill.test_missing_skill_returns_empty_list  s    h'+S];!y)	

 ##$78v|vvvr)   c                    t        |       |j                  dt        |             t        j	                  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	)
uO   eval-axes.json 파일 자체가 없어도 빈 리스트를 반환해야 한다.r   z	any-skillrp   r%  r   r   r   r   N)r(   r   rd   rO   r&  rQ   rR   rS   rT   rU   rV   rX   rY   r   s           r'   .test_missing_eval_axes_file_returns_empty_listzKTestLoadEvalAxesMissingSkill.test_missing_eval_axes_file_returns_empty_list  s    x +S]; ##K0v|vvvr)   )r   r   r   r   r   r   r2  r4  r   r)   r'   r0  r0    sF    d QWQcQc hl t Z`ZlZl qu r)   r0  c                   $    e Zd ZddZddZddZy)TestRecordDefenseNc                 :   dddd}t         j                  |      }|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)u@   방어 기록 시 consecutive_defenses가 1 증가해야 한다.r   r   ro   rC   rD   rB   rC   r  rp   rr   rs   ru   rv   NrO   record_defenserQ   rR   rV   rX   rY   rZ   championupdatedr{   r|   r}   r^   r~   s           r'   3test_record_defense_increments_consecutive_defenseszETestRecordDefense.test_record_defense_increments_consecutive_defenses  sy     %&"#$

 $$X.-.3!3.!3333.!333.333!3333333r)   c                 :   dddd}t         j                  |      }|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)uG   방어 기록 시 consecutive_losses가 0으로 리셋되어야 한다.r   r   ro   r8  rD   rp   rr   rs   ru   rv   Nr9  r;  s           r'   -test_record_defense_resets_consecutive_lossesz?TestRecordDefense.test_record_defense_resets_consecutive_losses  sy     %&"#$

 $$X.+,11,1111,111,1111111111r)   c                 :   dddd}t         j                  |      }|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}}|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)u   record_defense는 원본 dict를 변경하거나 변경된 복사본을 반환해도 무방하지만
        반환값이 올바른 상태여야 한다.r   ro   r8  rC   r   rp   rr   rs   ru   rv   NrD   r9  r;  s           r'   ,test_record_defense_does_not_modify_originalz>TestRecordDefense.test_record_defense_does_not_modify_original   s     %&"#$

 $$X.-.3!3.!3333.!333.333!3333333+,11,1111,111,1111111111r)   r   )r   r   r   r>  r@  rB  r   r)   r'   r6  r6    s    42
2r)   r6  c                   $    e Zd ZddZddZddZy)TestRecordLossNc                 :   dddd}t         j                  |      }|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)u>   패배 기록 시 consecutive_losses가 1 증가해야 한다.r  r   ro   r8  rD   r   rp   rr   rs   ru   rv   NrO   record_lossrQ   rR   rV   rX   rY   r;  s           r'   .test_record_loss_increments_consecutive_lossesz=TestRecordLoss.test_record_loss_increments_consecutive_losses  sw     %&"#$

 //(++,11,1111,111,1111111111r)   c                 :   dddd}t         j                  |      }|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)uI   패배 기록 시 consecutive_defenses가 0으로 리셋되어야 한다.   r   ro   r8  rC   rp   rr   rs   ru   rv   NrF  r;  s           r'   ,test_record_loss_resets_consecutive_defensesz;TestRecordLoss.test_record_loss_resets_consecutive_defenses  sw     %&"#$

 //(+-.3!3.!3333.!333.333!3333333r)   c                 :   dddd}t         j                  |      }|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}}|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)uF   0에서 패배 기록 시 consecutive_losses가 1이 되어야 한다.r   ro   r8  rD   r   rp   rr   rs   ru   rv   NrC   rF  r;  s           r'   test_record_loss_from_zeroz)TestRecordLoss.test_record_loss_from_zero'  s     %&"#$

 //(++,11,1111,111,1111111111-.3!3.!3333.!333.333!3333333r)   r   )r   r   r   rH  rK  rM  r   r)   r'   rD  rD    s    24	4r)   rD  c                   $    e Zd ZddZddZddZy)TestStatusStableNc                    dddt        j                  t        j                        j	                         dd}t
        j                  |      }|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)u:   5연속 방어 시 status가 'stable'이 되어야 한다.rJ  r   ro   rC   rD   rE   rA   rB   rB   stablerp   rr   rs   ru   rv   Nr   r  r   r  r  rO   update_champion_statusrQ   rR   rV   rX   rY   r;  s           r'   -test_five_consecutive_defenses_becomes_stablez>TestStatusStable.test_five_consecutive_defenses_becomes_stable9       %&"#'(!hll3==?$
 ,,X6x ,H, H,,,, H,,, ,,,H,,,,,,,r)   c                    dddt        j                  t        j                        j	                         dd}t
        j                  |      }|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)u3   5 초과 연속 방어도 'stable'이어야 한다.
   r   ro   rQ  rB   rR  rp   rr   rs   ru   rv   NrS  r;  s           r'   &test_more_than_five_defenses_is_stablez7TestStatusStable.test_more_than_five_defenses_is_stableE  s     %'"#'(!hll3==?$
 ,,X6x ,H, H,,,, H,,, ,,,H,,,,,,,r)   c                    dddt        j                  t        j                        j	                         dd}t
        j                  |      }|d   }d}||k7  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      d	z  }d
d|iz  }t        t        j                  |            dx}x}}y)u2   4연속 방어는 'stable'이 아니어야 한다.   r   ro   rQ  rB   rR  !=z%(py1)s != %(py4)srs   ru   rv   NrS  r;  s           r'   )test_four_consecutive_defenses_not_stablez:TestStatusStable.test_four_consecutive_defenses_not_stableQ  rV  r)   r   )r   r   r   rU  rY  r_  r   r)   r'   rO  rO  8  s    
-
-
-r)   rO  c                   $    e Zd ZddZddZddZy)TestStatusUnstableNc                    dddt        j                  t        j                        j	                         dd}t
        j                  |      }|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)u<   3연속 패배 시 status가 'unstable'이 되어야 한다.r   r  ro   rQ  rB   unstablerp   rr   rs   ru   rv   NrS  r;  s           r'   .test_three_consecutive_losses_becomes_unstablezATestStatusUnstable.test_three_consecutive_losses_becomes_unstabled       %&"#'(!hll3==?$
 ,,X6x .J. J.... J... ...J.......r)   c                    dddt        j                  t        j                        j	                         dd}t
        j                  |      }|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)u5   3 초과 연속 패배도 'unstable'이어야 한다.r   rJ  ro   rQ  rB   rc  rp   rr   rs   ru   rv   NrS  r;  s           r'   'test_more_than_three_losses_is_unstablez:TestStatusUnstable.test_more_than_three_losses_is_unstablep  re  r)   c                    dddt        j                  t        j                        j	                         dd}t
        j                  |      }|d   }d}||k7  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      d	z  }d
d|iz  }t        t        j                  |            dx}x}}y)u4   2연속 패배는 'unstable'이 아니어야 한다.r   r   ro   rQ  rB   rc  r\  r^  rs   ru   rv   NrS  r;  s           r'   (test_two_consecutive_losses_not_unstablez;TestStatusUnstable.test_two_consecutive_losses_not_unstable|  re  r)   r   )r   r   r   rd  rg  ri  r   r)   r'   ra  ra  c  s    
/
/
/r)   ra  c                   $    e Zd ZddZddZddZy)TestStatusManualInterventionNc                    dddt        j                  t        j                        j	                         dd}t
        j                  |      }|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)uT   reinit_count_this_month >= 2 시 'manual_intervention_required'가 되어야 한다.r   r   ro   rQ  rB   manual_intervention_requiredrp   rr   rs   ru   rv   NrS  r;  s           r'   1test_reinit_count_two_becomes_manual_interventionzNTestStatusManualIntervention.test_reinit_count_two_becomes_manual_intervention       %&"#'(!hll3==?$
 ,,X6x B$BB $BBBBB $BBBB BBB$BBBBBBBBr)   c                    dddt        j                  t        j                        j	                         dd}t
        j                  |      }|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)uL   reinit_count_this_month >= 3도 'manual_intervention_required'여야 한다.r   r  ro   rQ  rB   rm  rp   rr   rs   ru   rv   NrS  r;  s           r'   3test_reinit_count_three_becomes_manual_interventionzPTestStatusManualIntervention.test_reinit_count_three_becomes_manual_intervention  ro  r)   c                    dddt        j                  t        j                        j	                         dd}t
        j                  |      }|d   }d}||k7  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      d	z  }d
d|iz  }t        t        j                  |            dx}x}}y)uV   reinit_count_this_month == 1은 'manual_intervention_required'가 아니어야 한다.r   r   ro   rQ  rB   rm  r\  r^  rs   ru   rv   NrS  r;  s           r'   -test_reinit_count_one_not_manual_interventionzJTestStatusManualIntervention.test_reinit_count_one_not_manual_intervention  ro  r)   r   )r   r   r   rn  rq  rs  r   r)   r'   rk  rk    s    
C
C
Cr)   rk  c                   $    e Zd ZddZddZddZy)TestGracefulDegradationNc                    t         j                  ddg d      }d}||u}|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)uS   eval_axes가 빈 리스트일 때도 compare_outputs가 정상 동작해야 한다.u   첫 번째 아웃풋입니다.u   두 번째 아웃풋입니다.rm   output_aoutput_b	eval_axesr<   Nr
   r   r   r   r   r   
rO   compare_outputsrQ   rR   rS   rT   rU   rV   rX   rY   rZ   r   r}   r\   r   rj   s         r'   .test_compare_outputs_empty_axes_does_not_raisezFTestGracefulDegradation.test_compare_outputs_empty_axes_does_not_raise  s~    $$55#	 % 
 "!vT!!!!vT!!!!!!v!!!v!!!T!!!!!!!r)   c                 v   t         j                  ddg 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>   eval_axes 빈 리스트 시에도 dict를 반환해야 한다.output Aoutput Brm   rw  r   rc   r   dictr   NrO   r|  rc   r  rS   rT   rQ   rU   rV   rX   rY   )rZ   r   r|   r^   s       r'   ,test_compare_outputs_empty_axes_returns_dictzDTestGracefulDegradation.test_compare_outputs_empty_axes_returns_dict  s    $$#	 % 
 &$''''''''z'''z''''''&'''&''''''$'''$''''''''''r)   c                    t         j                  dddgd      }d}||u}|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@   빈 문자열 아웃풋에도 예외 없이 동작해야 한다. r   rm   rw  Nr
   r   r   r   r   r   r{  r}  s         r'   )test_compare_outputs_empty_string_outputszATestGracefulDegradation.test_compare_outputs_empty_string_outputs  s    $$i#	 % 
 "!vT!!!!vT!!!!!!v!!!v!!!T!!!!!!!r)   r   )r   r   r   r~  r  r  r   r)   r'   ru  ru    s    "("r)   ru  c                   D    e Zd Zd	dZd	dZd	dZd	dZd	dZd	dZd	dZ	y)
TestCompareOutputsStructureNc                    t         j                  ddddg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)u2   비교 결과에 'winner' 키가 있어야 한다.output A contentoutput B contentr9   r:   r7   rw  r   rI   z%(py1)s in %(py3)sr   r   r   r   N
rO   r|  rQ   rR   rV   rS   rT   rU   rX   rY   rZ   r   r{   r}   r   rj   s         r'   #test_compare_outputs_has_winner_keyz?TestCompareOutputsStructure.test_compare_outputs_has_winner_key  s    $$''#%78(	 % 
 !x6!!!!x6!!!x!!!!!!6!!!6!!!!!!!r)   c                    t         j                  dddg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)u2   비교 결과에 'reason' 키가 있어야 한다.r  r  r   rm   rw  r   rI   r  r   r   r   r   Nr  r  s         r'   #test_compare_outputs_has_reason_keyz?TestCompareOutputsStructure.test_compare_outputs_has_reason_key      $$i#	 % 
 !x6!!!!x6!!!x!!!!!!6!!!6!!!!!!!r)   c                    t         j                  dddg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)u2   비교 결과에 'scores' 키가 있어야 한다.r  r  r   rm   rw  scoresrI   r  r   r   r   r   Nr  r  s         r'   #test_compare_outputs_has_scores_keyz?TestCompareOutputsStructure.test_compare_outputs_has_scores_key  r  r)   c                 6   t         j                  dddgd      }|d   }d}||v }|slt        j                  d|fd	||f      t        j                  |      t        j                  |      d
z  }dd|iz  }t        t        j                  |            dx}x}}y)*   winner 값은 'A' 또는 'B'여야 한다.r  r  r   rm   rw  r   r   BrI   z%(py1)s in %(py4)srs   ru   rv   N)rO   r|  rQ   rR   rV   rX   rY   )rZ   r   r{   r|   r}   r^   r~   s          r'   %test_compare_outputs_winner_is_a_or_bzATestCompareOutputsStructure.test_compare_outputs_winner_is_a_or_b  sy    $$i#	 % 
 h-:-:----:------:-------r)   c                 ,   t         j                  ddddgd      }|d   }t        |t              }|sdd	t	        j
                         v st        j                  t              rt        j                  t              nd	t        j                  |      d
t	        j
                         v st        j                  t              rt        j                  t              nd
t        j                  |      dz  }t        t        j                  |            dx}}y)u   scores는 dict여야 한다.r  r  r9   r:   r7   rw  r  rb   rc   r  re   Nr  rZ   r   r\   ri   rj   s        r'   #test_compare_outputs_scores_is_dictz?TestCompareOutputsStructure.test_compare_outputs_scores_is_dict  s    $$''#%78(	 % 
 !*1z*D11111111z111z111*111111D111D1111111111r)   c                    t         j                  dddg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}|j                         D ]  \  }}t        t        t        f}t        ||      }|st        j                  d| d      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t        j                  |      t        j                  |      dz  }	t        t        j                  |	            dx}} y)uZ   scores 내 값이 유효한 형식이어야 한다 (list 또는 numeric, 또는 빈 dict).r  r  r   rm   rw  r  r   rc   r  r   Nzscores[u!   ]는 list 또는 숫자여야 함z7
>assert %(py5)s
{%(py5)s = %(py0)s(%(py1)s, %(py3)s)
}val)rM   rt   rf   r   )rO   r|  rc   r  rS   rT   rQ   rU   rV   rX   rY   itemsrg   rh   floatrW   )
rZ   r   r  r|   r^   keyr  r}   ri   rj   s
             r'   ,test_compare_outputs_scores_values_are_validzHTestCompareOutputsStructure.test_compare_outputs_scores_values_are_valid  sk   $$i#	 % 
 !&$''''''''z'''z''''''&'''&''''''$'''$'''''''''' 	iHC$(#u#5h:c#56h6hh'#Fg8hhhhhhh:hhh:hhhhhhchhhchhh#5hhh6hhhhhh	ir)   c                 *   t         j                  dddgd      }|d   }t        |t              }|sddt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      d	t	        j
                         v st        j                  t              rt        j                  t              nd	t        j                  |      d
z  }t        t        j                  |            dx}}y)u(   reason 값이 문자열이어야 한다.r  r  r   rm   rw  r   rb   rc   rd   re   N)rO   r|  rc   rd   rS   rT   rQ   rU   rV   rX   rY   r  s        r'   %test_compare_outputs_reason_is_stringzATestCompareOutputsStructure.test_compare_outputs_reason_is_string  s    $$i#	 % 
 !*0z*C00000000z000z000*000000C000C0000000000r)   r   )
r   r   r   r  r  r  r  r  r  r  r   r)   r'   r  r    s&    """.2i1r)   r  c                   X    e Zd Zdedej
                  ddfdZdej
                  ddfdZy)TestGetWorkspaceRootr   r   r   Nc                 @   |j                  d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}||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                  |      rt        j                  |      nd
dz  }dd|iz  }t        t        j                  |            d}y)u[   WORKSPACE_ROOT 환경변수가 설정되어 있으면 해당 경로를 반환해야 한다.r   r   rc   rootr   r   Nrp   z%(py0)s == %(py2)sr   rL   assert %(py4)srN   )r   rd   rO   get_workspace_rootrc   r   rS   rT   rQ   rU   rV   rX   rY   rR   )rZ   r   r   r  r|   r^   r\   r]   s           r'    test_get_workspace_root_from_envz5TestGetWorkspaceRoot.test_get_workspace_root_from_env/  s   +S];%%'$%%%%%%%%z%%%z%%%%%%$%%%$%%%%%%%%%%%%%%%%%%%xtxttxxr)   c                    |j                  dd       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	}y	)
u)   반환값이 Path 타입이어야 한다.r   F)raisingr   rc   r  r   r   N)delenvrO   r  rc   r   rS   rT   rQ   rU   rV   rX   rY   )rZ   r   r  r|   r^   s        r'   )test_get_workspace_root_returns_path_typez>TestGetWorkspaceRoot.test_get_workspace_root_returns_path_type6  s    +U;%%'$%%%%%%%%z%%%z%%%%%%$%%%$%%%%%%%%%%%%%%%%%%%r)   )r   r   r   r   r   r   r  r  r   r)   r'   r  r  .  s=       FL^L^  cg  &VEWEW &\` &r)   r  zoutput_review_ai.pycontent_textc                 L    t               }| |_        t               }|g|_        |S )z%Create a mock Anthropic API response.)r   textcontent)r  mock_contentmock_responses      r'   _mock_anthropic_responser  D  s(    ;L$LKM)NMr)   1u:   아웃풋 1이 훅 강도와 정보 밀도에서 우수함r[  r  rJ  )r9   r   r   r   r  MOCK_COMPARISON_RESULTr   u7   Output A가 훅 강도와 정보 밀도에서 우수함MOCK_COMPARISON_RESULT_ABTuK   v2가 훅 강도와 정보 밀도에서 v1보다 높은 점수를 기록함)improved
comparisonr   MOCK_DELTA_RESULT_IMPROVEDFu:   v2가 v1보다 낮은 점수를 기록하여 개선 실패MOCK_DELTA_RESULT_NOT_IMPROVEDpass)verdictsuggestionsMOCK_CROSS_MODEL_PASSimprove   훅을 더 강하게   정보를 더 구체적으로MOCK_CROSS_MODEL_IMPROVEu$   개선된 최종 챔피언 아웃풋expert_textu   전문가 아웃풋 예시ab_comparisonbenchmark_resultimprovement_applieddelta_resultu   훅 강도 개선이 효과적u/   정보 밀도 상향이 품질 향상에 기여r>   init_process	learningsMOCK_INIT_ENHANCEMENT_RESULTc                   8    e Zd ZdZddZddZddZddZddZy)	TestCompareOutputsAIuJ   compare_outputs_ai 함수의 구조 및 동작을 mock으로 검증한다.Nc                    t        j                  ddt               i      5  ddl}t        |j
                  _        |j                  ddddg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}}ddd       y# 1 sw Y   yxY w)uZ   compare_outputs_ai가 winner, reason, scores 키를 포함한 dict를 반환해야 한다.sys.modulesoutput_review_air   N   첫 번째 아웃풋   두 번째 아웃풋r9   r   r7   rw  r   rI   r  r   r   r   r   r   r  )r   r  r   r  r  compare_outputs_aireturn_valuerQ   rR   rV   rS   rT   rU   rX   rY   )rZ   orair   r{   r}   r   rj   s          r'   1test_compare_outputs_ai_returns_correct_structurezFTestCompareOutputsAI.test_compare_outputs_ai_returns_correct_structure  sq   ZZ(:IK'HI 	&+3LD##0,,//'9,	 - F %8v%%%%8v%%%8%%%%%%v%%%v%%%%%%%%8v%%%%8v%%%8%%%%%%v%%%v%%%%%%%%8v%%%%8v%%%8%%%%%%v%%%v%%%%%%%	& 	& 	&s   H I

Ic                    t        j                  ddt               i      5  ddl}t        |j
                  _        |j                  dddgd	      }|d
   }d}||v }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}ddd       y# 1 sw Y   yxY w)r  r  r  r   Nr  r  r9   rm   rw  r   r  rI   r  rs   ru   rv   )r   r  r   r  r  r  r  rQ   rR   rV   rX   rY   )rZ   r  r   r{   r|   r}   r^   r~   s           r'   (test_compare_outputs_ai_winner_is_a_or_bz=TestCompareOutputsAI.test_compare_outputs_ai_winner_is_a_or_b  s    ZZ(:IK'HI 	2+3LD##0,,##'.'	 - F (#1z1#z1111#z111#111z1111111	2 	2 	2s   B/CC"c           	      L   t        j                  ddt               i      5  ddl}t        |j
                  _        |j                  ddddg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}|j                         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        |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}	||	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                  |      t        j                  |	      dz  }dd|iz  }t        t        j                  |            dx}x}
}	d |D        }t)        |      }|sddt        j                         v st        j                  t(              rt        j                  t(              ndt        j                  |      t        j                  |      dz  }t        t        j                  |            dx}} 	 ddd       y# 1 sw Y   yxY w)uI   scores는 평가 축별 [a_score, b_score] 리스트 구조여야 한다.r  r  r   Nr  r  r9   r   rm   rw  r  r   rc   r  r   	axis_namerd   
score_pairrg   r   rp   r  r   r  r  r  c              3   H   K   | ]  }t        |t        t        f        y wr   )rc   rh   r  )r   ss     r'   r   zYTestCompareOutputsAI.test_compare_outputs_ai_scores_structure_per_axis.<locals>.<genexpr>  s     K1:a#u6Ks    "z,assert %(py4)s
{%(py4)s = %(py0)s(%(py2)s)
}allr   )r   r  r   r  r  r  r  rc   rS   rT   rQ   rU   rV   rX   rY   r  rd   rg   r   rR   r  )rZ   r  r   r  r|   r^   r  r  r}   r   ri   r~   r  r\   s                 r'   1test_compare_outputs_ai_scores_structure_per_axiszFTestCompareOutputsAI.test_compare_outputs_ai_scores_structure_per_axis  s   ZZ(:IK'HI 	L+3LD##0,,##'9'	 - F H%Ffd++++++++:+++:++++++f+++f++++++d+++d++++++++++)/ L%	:!)S11111111z111z111111)111)111111S111S1111111111!*d33333333z333z333333*333*333333d333d3333333333:+!+!++++!++++++s+++s++++++:+++:++++++!+++++++K
KKsKKKKKKKKKsKKKsKKKKKKKKKKKKKK	L	L 	L 	Ls   U/VV#c                 T   ddi d}t        j                  ddt               i      5  ddl}||j                  _        |j	                  dd	g d
      }d}||u}|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}}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   }t        |t              }	|	sddt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |	      dz  }t        t        j                  |            dx}}	ddd       y# 1 sw Y   yxY w)uD   eval_axes가 빈 리스트여도 graceful하게 동작해야 한다.r   u+   eval_axes 없이 전반적 품질로 판단r  r  r  r   Nr  r  rm   rw  r
   r   r   r   r   r   r   rI   r  r   r  rb   rc   r  re   )r   r  r   r  r  r  rQ   rR   rS   rT   rU   rV   rX   rY   rc   )
rZ   empty_axes_resultr  r   r}   r\   r   rj   r{   ri   s
             r'   0test_compare_outputs_ai_empty_eval_axes_gracefulzETestCompareOutputsAI.test_compare_outputs_ai_empty_eval_axes_graceful  s    C-

 ZZ(:IK'HI 	6+3DD##0,,##'	 - F "&%6%%%%6%%%%%%6%%%6%%%%%%%%%%%8v%%%%8v%%%8%%%%%%v%%%v%%%%%%%$X.5:.55555555:555:555.5555555555555555555	6 	6 	6s   I.JJ'c                 :   t               }t        d      |j                  _        t	        j
                  dd|i      5  ddl}t        j                  t        d      5  |j                  dd	d
gd       ddd       ddd       y# 1 sw Y   xY w# 1 sw Y   yxY w)uH   ANTHROPIC_API_KEY가 없을 때 EnvironmentError가 발생해야 한다.z1ANTHROPIC_API_KEY environment variable is not setr  r  r   NANTHROPIC_API_KEY)matchr  r  r9   rm   rw  )	r   EnvironmentErrorr  side_effectr   r  r  r   raises)rZ   mock_moduler  s      r'   ;test_compare_outputs_ai_no_api_key_raises_environment_errorzPTestCompareOutputsAI.test_compare_outputs_ai_no_api_key_raises_environment_error  s    k5E?6
&&2 ZZ(:K'HI 		+/7JK ''''+n+	 ( 		 		 		 		s#    BB4BB	
BBr   )	r   r   r   __doc__r  r  r  r  r  r   r)   r'   r  r    s    T&$2 L,6.r)   r  c                        e Zd ZdZddZddZy) TestComparisonOrderRandomizationuA   A/B 순서 랜덤화 및 winner 매핑 정확성을 검증한다.Nc                    dddddgid}dddddgid}t               }||g|j                  _        t        j                  d	d
|i      5  ddl}|j                  dddgd      }|j                  dddgd      }|d   |d   h}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                  |	      dz  }t        j                  d      dz   d|iz  }t        t        j                  |            dx}x}
}	ddd       y# 1 sw Y   yxY w)ui   여러 번 호출 시 A/B 순서가 섞이는지 확인한다 (mock으로 순서 변화 시뮬레이션).r   u   A가 더 나음r9   rJ  r  r  r  u   B가 더 나음r  r  r   Nzoutput Xzoutput Yrm   rw  r   r   rp   r  r   winnersr  u+   랜덤화로 인해 winner가 달라야 함z
>assert %(py8)sr  )r   r  r  r   r  r  r   rQ   rR   rS   rT   rU   rV   rW   rX   rY   )rZ   result_a_winsresult_b_winsr  r  result1result2r  r}   r   ri   r~   r  s                r'   'test_randomization_produces_mixed_orderzHTestComparisonOrderRandomization.test_randomization_produces_mixed_order  sz    '#aV,)
 '#aV,)
  k6C]5S&&2ZZ(:K'HI 	T+--##'.'	 . G --##'.'	 . G x('(*;<Gw<S1S<1$SSS<1SSSSSS3SSS3SSSSSSwSSSwSSS<SSS1SSS&SSSSSSSS%	T 	T 	Ts   
E"F55F>c                 n   dddddgid}t               }||j                  _        t        j                  dd|i      5  d	d
l}|j                  dddgd      }|d   }d}||v }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|i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}}d
d
d
       y
# 1 sw Y   y
xY w)uS   순서가 바뀌어도 winner가 올바르게 원래 A/B로 매핑되어야 한다.r  u   position 1이 더 나음r9   rJ  r  r  r  r  r   Nzoutput A textzoutput B textrm   rw  r   )r   r  r  2rI   r  rs   ru   rv   r   r  r   r   r   r   r  )r   r  r  r   r  r  rQ   rR   rV   rX   rY   rS   rT   rU   )rZ   position_resultr  r  r   r{   r|   r}   r^   r~   r   rj   s               r'   9test_winner_correctly_mapped_to_original_ab_after_shufflezZTestComparisonOrderRandomization.test_winner_correctly_mapped_to_original_ab_after_shuffle  s    0#aV,+
  k6E&&3ZZ(:K'HI 	&+,,(('.'	 - F (#;';;#';;;;;#';;;;#;;;';;;;;;;;%8v%%%%8v%%%8%%%%%%v%%%v%%%%%%%%8v%%%%8v%%%8%%%%%%v%%%v%%%%%%%	& 	& 	&s   G$H++H4r   )r   r   r   r  r  r  r   r)   r'   r  r    s    K$TL!&r)   r  c                   8    e Zd ZdZddZddZddZddZddZy)	TestInitEnhancementuA   run_init_enhancement 전체 플로우를 mock으로 검증한다.Nc                    t               }t        |j                  _        t	        j
                  dd|i      5  ddl}|j                  ddddg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  }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}}ddd       y# 1 sw Y   yxY w)uc   online_expert 모드: A/B 비교 → expert 벤치마크 → 개선 → delta 검증 → 챔피언.r  r  r   Nr  r  r9   r   r7   rx   rx  ry  rz  r<   benchmark_methodr  r  rI   r  	init_procr   r   r   r  r  )r   r  run_init_enhancementr  r   r  r  rQ   rR   rV   rS   rT   rU   rX   rY   )	rZ   r  r  r   r  r{   r}   r   rj   s	            r'   !test_online_expert_mode_full_flowz5TestInitEnhancement.test_online_expert_mode_full_flowF  s   k8T((5ZZ(:K'HI 	6+..//'9,!0 / F ~.I"/?i////?i///?//////i///i///////%2%2222%222%2222222222222222(5(I5555(I555(555555I555I5555555	6 	6 	6s   HIIc                    dt         t        dt        ddgd}t               }||j                  _        t        j                  dd|i      5  dd	l}|j	                  d
dddg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  }dd|iz  }	t        t        j                   |	            d	x}}|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	d	d	       y	# 1 sw Y   y	xY w)u`   cross_model 모드: A/B 비교 → cross-model verify → 개선 → delta 검증 → 챔피언.u*   cross-model 검증 후 개선된 챔피언Tr  u&   cross-model 검증으로 개선 확인r  r  r  r   Nr  r  r9   r   r7   cross_modelr  r  r  rI   r  r  r   r   r   r  	benchmark)r  r  r  r   r  r  r   r  r  rQ   rR   rV   rS   rT   rU   rX   rY   )rZ   cross_model_resultr  r  r   r  r{   r}   r   rj   r  s              r'   test_cross_model_mode_full_flowz3TestInitEnhancement.test_cross_model_mode_full_flow\  sb     L!:$<'+ :	 CC	.
  k8J((5ZZ(:K'HI 	*+..//'9,!. / F ~.I%2%2222%222%2222222222222222!"45I)9	))))9	)))9))))))	)))	)))))))	* 	* 	*s   E1GGc                    t               }t        |j                  _        t	        j
                  dd|i      5  ddl}|j                  dddg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  }dd|iz  }t        t        j                  |            dx}}|d   }t        |t               }	|	sddt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      dt        j                         v st        j                  t               rt        j                  t               ndt        j                  |	      dz  }t        t        j                  |            dx}}	ddd       y# 1 sw Y   yxY w)u9   반환 구조에 champion_output 키가 있어야 한다.r  r  r   Nr  r  r9   rm   rx   r  r>   rI   r  r   r   r   r   rb   rc   rd   re   )r   r  r  r  r   r  r  rQ   rR   rV   rS   rT   rU   rX   rY   rc   rd   
rZ   r  r  r   r{   r}   r   rj   r\   ri   s
             r'   1test_run_init_enhancement_returns_champion_outputzETestInitEnhancement.test_run_init_enhancement_returns_champion_output}  sH   k8T((5ZZ(:K'HI 	>+..##'.'!0 / F %.$....$...$................$%67=:7========:===:===7===================	> 	> 	>   F:G;;Hc                    t               }t        |j                  _        t	        j
                  dd|i      5  ddl}|j                  dddg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  }dd|iz  }t        t        j                  |            dx}}|d   }t        |t
              }	|	sddt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      dt        j                         v st        j                  t
              rt        j                  t
              ndt        j                  |	      dz  }t        t        j                  |            dx}}	ddd       y# 1 sw Y   yxY w)u6   반환 구조에 init_process 키가 있어야 한다.r  r  r   Nr  r  r9   rm   rx   r  r  rI   r  r   r   r   r   rb   rc   r  re   )r   r  r  r  r   r  r  rQ   rR   rV   rS   rT   rU   rX   rY   rc   r  s
             r'   .test_run_init_enhancement_returns_init_processzBTestInitEnhancement.test_run_init_enhancement_returns_init_process  sD   k8T((5ZZ(:K'HI 	<+..##'.'!0 / F "+>V++++>V+++>++++++V+++V+++++++$^4;:4d;;;;;;;;:;;;:;;;4;;;;;;d;;;d;;;;;;;;;;	< 	< 	<r  c                    t               }t        |j                  _        t	        j
                  dd|i      5  ddl}|j                  dddg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  }dd|iz  }t        t        j                  |            dx}}|d   }t        |t               }	|	sddt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      dt        j                         v st        j                  t               rt        j                  t               ndt        j                  |	      dz  }t        t        j                  |            dx}}	ddd       y# 1 sw Y   yxY w)u3   반환 구조에 learnings 키가 있어야 한다.r  r  r   Nr  r  r9   rm   rx   r  r  rI   r  r   r   r   r   rb   rc   rg   re   )r   r  r  r  r   r  r  rQ   rR   rV   rS   rT   rU   rX   rY   rc   rg   r  s
             r'   +test_run_init_enhancement_returns_learningsz?TestInitEnhancement.test_run_init_enhancement_returns_learnings  sD   k8T((5ZZ(:K'HI 	9+..##'.'!0 / F (;&((((;&(((;((((((&(((&((((((($[18:1488888888:888:8881888888488848888888888	9 	9 	9r  r   )	r   r   r   r  r	  r  r  r  r  r   r)   r'   r  r  C  s    K6,*B>&<&9r)   r  c                   8    e Zd ZdZddZddZddZddZddZy)	TestDeltaVerifyuE   delta_verify 함수의 improved True/False 케이스를 검증한다.Nc                    t               }t        |j                  _        t	        j
                  dd|i      5  ddl}|j                  ddddgd	
      }|d   }d}||u }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}ddd       y# 1 sw Y   yxY w)uB   v2가 v1보다 나은 경우 improved=True를 반환해야 한다.r  r  r   N   원본 아웃풋u   개선된 아웃풋r9   r   rm   v1v2rz  r<   r  Tr   z%(py1)s is %(py4)srs   ru   rv   )r   r  delta_verifyr  r   r  r  rQ   rR   rV   rX   rY   	rZ   r  r  r   r{   r|   r}   r^   r~   s	            r'   1test_delta_verify_v2_better_returns_improved_truezATestDeltaVerify.test_delta_verify_v2_better_returns_improved_true  s    k0J  -ZZ(:K'HI 
	.+&&%('9'	 ' F *%--%----%---%----------
	. 
	. 
	.   BCC%c                    t               }t        |j                  _        t	        j
                  dd|i      5  ddl}|j                  ddddgd	
      }|d   }d}||u }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}ddd       y# 1 sw Y   yxY w)uU   v2가 v1보다 못한 경우 improved=False를 반환하고 fallback이 필요하다.r  r  r   Nu   더 나은 원본 아웃풋u   품질이 저하된 아웃풋r9   r   rm   r  r  Fr   r  rs   ru   rv   )r   r  r  r  r   r  r  rQ   rR   rV   rX   rY   r   s	            r'   1test_delta_verify_v2_worse_returns_improved_falsezATestDeltaVerify.test_delta_verify_v2_worse_returns_improved_false  s    k0N  -ZZ(:K'HI 
	/+&&02'9'	 ' F *%..%....%...%..........
	/ 
	/ 
	/r"  c                    t               }t        |j                  _        t	        j
                  dd|i      5  ddl}|j                  dddg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dd       y# 1 sw Y   yxY w)u2   반환 구조에 improved 키가 있어야 한다.r  r  r   Nr  r  r   rm   r  r  rI   r  r   r   r   r   )r   r  r  r  r   r  r  rQ   rR   rV   rS   rT   rU   rX   rY   rZ   r  r  r   r{   r}   r   rj   s           r'   &test_delta_verify_returns_improved_keyz6TestDeltaVerify.test_delta_verify_returns_improved_key  s    k0J  -ZZ(:K'HI 
	(+&&")'	 ' F ':'''':''':''''''''''''''''
	( 
	( 
	(s   C DD
c                    t               }t        |j                  _        t	        j
                  dd|i      5  ddl}|j                  dddg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
   }t        |t
              }	|	sddt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      dt        j                         v st        j                  t
              rt        j                  t
              ndt        j                  |	      dz  }t        t        j                  |            dx}}	ddd       y# 1 sw Y   yxY w)u4   반환 구조에 comparison 키가 있어야 한다.r  r  r   Nr  r  r   rm   r  r  rI   r  r   r   r   r   rb   rc   r  re   )r   r  r  r  r   r  r  rQ   rR   rV   rS   rT   rU   rX   rY   rc   r  s
             r'   (test_delta_verify_returns_comparison_keyz8TestDeltaVerify.test_delta_verify_returns_comparison_key  sA   k0J  -ZZ(:K'HI 	:+&&")'	 ' F  )<6))))<6)))<))))))6)))6)))))))$\29:2D99999999:999:9992999999D999D9999999999	: 	: 	:   F9G::Hc                    t               }t        |j                  _        t	        j
                  dd|i      5  ddl}|j                  dddg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
   }t        |t               }	|	sddt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      dt        j                         v st        j                  t               rt        j                  t               ndt        j                  |	      dz  }t        t        j                  |            dx}}	ddd       y# 1 sw Y   yxY w)u0   반환 구조에 reason 키가 있어야 한다.r  r  r   Nr  r  r   rm   r  r   rI   r  r   r   r   r   rb   rc   rd   re   )r   r  r  r  r   r  r  rQ   rR   rV   rS   rT   rU   rX   rY   rc   rd   r  s
             r'   $test_delta_verify_returns_reason_keyz4TestDeltaVerify.test_delta_verify_returns_reason_key  sA   k0J  -ZZ(:K'HI 	5+&&")'	 ' F %8v%%%%8v%%%8%%%%%%v%%%v%%%%%%%$X.4:.44444444:444:444.4444444444444444444	5 	5 	5r*  r   )	r   r   r   r  r!  r$  r'  r)  r,  r   r)   r'   r  r    s    O."/"(":$5r)   r  c                   (    e Zd ZdZddZddZddZy)TestGracefulDegradation_Phase2u:   Phase 2 graceful degradation 시나리오를 검증한다.Nc                    dt         dddddgd}t               }d|j                  _        ||j                  _        t        j                  dd|i      5  d	dl}|j                  d
d      }d}||u }|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}}|j	                  dddgd
d      }	|	d   d   }
d}|
|u }|slt        j                  d|fd|
|f      t        j                  |
      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}
x}}|	d   d   }
d}|
|u }|slt        j                  d|fd|
|f      t        j                  |
      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}
x}}ddd       y# 1 sw Y   yxY w)uV   WebSearch 결과가 None일 때 A/B 선택본 그대로 챔피언이 되어야 한다.   A/B 비교 winner 아웃풋NFr  u<   expert 검색 실패로 A/B winner를 챔피언으로 지정r  r  r  r   rm   
some topicr<   topicr   r   expertr   r   r   r  r  r9   rx   r  r  r  r  rs   ru   rv   r  r  r   search_expert_outputr  r  r   r  r  rQ   rR   rS   rT   rU   rV   rX   rY   )rZ   no_benchmark_resultr  r  r4  r}   r\   r   rj   r   r{   r|   r^   r~   s                 r'   5test_websearch_none_result_uses_ab_winner_as_championzTTestGracefulDegradation_Phase2.test_websearch_none_result_uses_ab_winner_as_champion  s     =!:$(', $	 YY	/
  k8<((58K((5ZZ(:K'HI 	J+ ..,l.[F!!6T>!!!6T!!!!!!6!!!6!!!T!!!!!!! ..##'.'!0 / F .)*<=EE=EEEE=EEE=EEEEEEEEEE.)*?@IEI@EIIII@EIII@IIIEIIIIIII!	J 	J 	Js   GH66H?c           	          dt         dg ddddddgd	}t               }t        d
      |j                  _        ||j
                  _        t        j                  dd|i      5  ddl	}t        j                  t              5  |j                  dd       ddd       |j                  dddgdd      }|d   d   }d}||u}|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}}|j(                  }d}
 ||
      }d}||k(  }|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d       y# 1 sw Y   xY w# 1 sw Y   yxY w)$uN   cross_model_verify가 예외 발생 시 self-review로 대체되어야 한다.u   self-review fallback 챔피언r  self_review)r  r  fallbackFNr  u8   cross_model_verify 오류로 self-review fallback 적용r  zCross model verification failedr  r  r   zsome outputrm   ra   r<   r  r  r9   r  r  r  r  r
   r   r  r   r   r   r;  rp   )zI%(py6)s
{%(py6)s = %(py2)s
{%(py2)s = %(py0)s.get
}(%(py4)s)
} == %(py9)s)rM   r   rN   rv   r   zassert %(py11)sr   )r  r   RuntimeErrorcross_model_verifyr  r  r  r   r  r  r   r  rQ   rR   rS   rT   rU   rV   rX   rY   get)rZ   fallback_resultr  r  r   r  r}   r\   r   rj   r|   r   @py_assert8@py_assert7r   @py_format12s                   r'   ;test_cross_model_verify_exception_falls_back_to_self_reviewzZTestGracefulDegradation_Phase2.test_cross_model_verify_exception_falls_back_to_self_reviewC  s     @!:06rWd$e', $	 UU	+
  k5ABc5d&&28G((5ZZ(:K'HI 	>+ |, W''}'VW ..##'.'!. / F ~./ABI$((9D((((9D((((((9(((9(((D(((((((=====,==,====,======9===9==========,==========#	> 	>W W		> 	>s%   "I4 I'G
I4'I1	,I44I=c                    dt         ddiddddgd}t               }d|j                  _        ||j                  _        t        j                  d	d
|i      5  ddl}|j                  dd      }d}||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}}|j	                  dddgdd      }	|	d   d   }
d}|
|u }|slt        j                  d|fd|
|f      t        j                  |
      t        j                  |      dz  }dd |iz  }t        t        j                  |            dx}
x}}ddd       y# 1 sw Y   yxY w)!uc   expert 검색 결과가 빈 문자열일 때 A/B 선택본 그대로 챔피언이 되어야 한다.r0  r  r  FNr  uB   expert 결과가 비어있어 A/B winner를 챔피언으로 지정r  r  r  r   rm   r1  r2  rp   r%  r4  r   r   r   r  r  r9   rx   r  r  r  r   r  rs   ru   rv   r5  )rZ   no_improvement_resultr  r  r4  r}   r\   r   rj   r   r{   r|   r^   r~   s                 r'   3test_expert_empty_string_uses_ab_winner_as_championzRTestGracefulDegradation_Phase2.test_expert_empty_string_uses_ab_winner_as_championi  sp     =!:%2B$7', $	 __	1
  k8:((58M((5ZZ(:K'HI 	J+..,l.[F6R<6R66R..##'.'!0 / F .)*?@IEI@EIIII@EIII@IIIEIIIIIII	J 	J 	Js   EF77G r   )r   r   r   r  r8  rD  rG  r   r)   r'   r.  r.    s    D"JH$>LJr)   r.  c                   8    e Zd ZdZddZddZddZddZddZy)	TestCrossModelVerifyu;   cross_model_verify 스텁의 반환 구조를 검증한다.Nc                    t               }t        |j                  _        t	        j
                  dd|i      5  ddl}|j                  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  }dd|iz  }t        t        j                  |            dx}}ddd       y# 1 sw Y   yxY w)u1   반환 구조에 verdict 키가 있어야 한다.r  r  r   N   테스트 아웃풋 텍스트rm   r<  r  rI   r  r   r   r   r   )r   r  r>  r  r   r  r  rQ   rR   rV   rS   rT   rU   rX   rY   r&  s           r'   +test_cross_model_verify_returns_verdict_keyz@TestCrossModelVerify.test_cross_model_verify_returns_verdict_key  s    k6K&&3ZZ(:K'HI 	'+,,6' - F
 &9&&&&9&&&9&&&&&&&&&&&&&&&&	' 	' 	's   B=C>>Dc                    t               }t        |j                  _        t	        j
                  dd|i      5  ddl}|j                  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  }dd|iz  }t        t        j                  |            dx}}|d   }t        |t               }	|	sddt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      dt        j                         v st        j                  t               rt        j                  t               ndt        j                  |	      dz  }t        t        j                  |            dx}}	ddd       y# 1 sw Y   yxY w)u5   반환 구조에 suggestions 키가 있어야 한다.r  r  r   NrK  rm   r<  r  rI   r  r   r   r   r   rb   rc   rg   re   )r   r  r>  r  r   r  r  rQ   rR   rV   rS   rT   rU   rX   rY   rc   rg   r  s
             r'   /test_cross_model_verify_returns_suggestions_keyzDTestCrossModelVerify.test_cross_model_verify_returns_suggestions_key  s9   k6K&&3ZZ(:K'HI 		;+,,6' - F
 !*=F****=F***=******F***F*******$]3::3T::::::::::::::::3::::::T:::T::::::::::		; 		; 		;s   F6G77H c                    t               }t        |j                  _        t	        j
                  dd|i      5  ddl}|j                  dd      }|d   }d	}||v }|slt        j                  d
|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}ddd       y# 1 sw Y   yxY w)u4   verdict 값은 'pass' 또는 'improve'여야 한다.r  r  r   NrK  rm   r<  r  )r  r  rI   r  rs   ru   rv   r   r  r>  r  r   r  r  rQ   rR   rV   rX   rY   r   s	            r'   2test_cross_model_verify_verdict_is_pass_or_improvezGTestCrossModelVerify.test_cross_model_verify_verdict_is_pass_or_improve  s    k6K&&3ZZ(:K'HI 	<+,,6' - F
 )$;(;;$(;;;;;$(;;;;$;;;(;;;;;;;;	< 	< 	<s   BCC!c                    t               }t        |j                  _        t	        j
                  dd|i      5  ddl}|j                  dd      }|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}}ddd       y# 1 sw Y   yxY w)u6   현재 스텁은 항상 'pass'를 반환해야 한다.r  r  r   Nu   어떤 아웃풋이든rm   r<  r  r  rp   rr   rs   ru   rv   rP  r   s	            r'   )test_cross_model_verify_stub_returns_passz>TestCrossModelVerify.test_cross_model_verify_stub_returns_pass  s    k6K&&3ZZ(:K'HI 	/+,,/' - F
 )$..$....$...$..........	/ 	/ 	/   BCC"c                    t               }t        |j                  _        t	        j
                  dd|i      5  ddl}|j                  dd      }|d   }g }||k(  }|slt        j                  d	|fd
||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}ddd       y# 1 sw Y   yxY w)u?   'pass' 결과는 빈 suggestions 리스트를 가져야 한다.r  r  r   Nu   테스트 아웃풋rm   r<  r  rp   rr   rs   ru   rv   rP  r   s	            r'   2test_cross_model_verify_pass_has_empty_suggestionszGTestCrossModelVerify.test_cross_model_verify_pass_has_empty_suggestions  s    k6K&&3ZZ(:K'HI 	/+,,,' - F
 -(.B.(B....(B...(...B.......	/ 	/ 	/rT  r   )	r   r   r   r  rL  rN  rQ  rS  rV  r   r)   r'   rI  rI    s    E'; <//r)   rI  c                   0    e Zd ZdZddZddZddZddZy)TestGenerateImprovedOutputu:   generate_improved_output 함수의 동작을 검증한다.Nc                 j   d}t               }||j                  _        t        j                  dd|i      5  ddl}|j                  |g ddg      }||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                  |      rt        j                  |      nddz  }dd|iz  }t        t        j                  |            d}ddd       y# 1 sw Y   yxY w)uE   suggestions가 비어있을 때 원본 출력을 반환해야 한다.u   원본 아웃풋 텍스트r  r  r   Nrm   r9   r   r  r<   rz  rp   r  r   original_textrL   r  rN   )r   generate_improved_outputr  r   r  r  rQ   rR   rS   rT   rU   rV   rX   rY   )rZ   r[  r  r  r   r\   r]   r^   s           r'   'test_empty_suggestions_returns_originalzBTestGenerateImprovedOutput.test_empty_suggestions_returns_original  s    4k<I,,9ZZ(:K'HI 
	++22&''.	 3 F ]****6]******6***6******]***]*******
	+ 
	+ 
	+s   C*D))D2c                    d}t               }||j                  _        t        j                  dd|i      5  ddl}|j                  dddgd	d
dg      }|j                  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                  |      rt        j                  |      nddz  }dd|iz  }t        t        j                  |            d}ddd       y# 1 sw Y   yxY w)uP   suggestions가 있을 때 AI 개선 호출이 정상 동작해야 한다 (mock).u#   AI가 개선한 아웃풋 텍스트r  r  r   Nr  r  r  r7   r9   r   rZ  rp   r  r   improved_textrL   r  rN   )r   r\  r  r   r  r  assert_called_oncerQ   rR   rS   rT   rU   rV   rX   rY   )rZ   r_  r  r  r   r\   r]   r^   s           r'   7test_generate_improved_output_with_suggestions_calls_aizRTestGenerateImprovedOutput.test_generate_improved_output_with_suggestions_calls_ai  s    =k<I,,9ZZ(:K'HI 	++22+35TU,'9	 3 F ))<<>]****6]******6***6******]***]*******	+ 	+ 	+s   DEEc                 
   t               }d|j                  _        t        j                  dd|i      5  ddl}|j                  ddgdd	g
      }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dd       y# 1 sw Y   yxY w)uD   generate_improved_output은 항상 문자열을 반환해야 한다.u   개선된 문자열r  r  r   Nu   원본u   개선 제안rm   r   rZ  r   rc   r   rd   r   )r   r\  r  r   r  r  rc   rd   rS   rT   rQ   rU   rV   rX   rY   )rZ   r  r  r   r|   r^   s         r'   ,test_generate_improved_output_returns_stringzGTestGenerateImprovedOutput.test_generate_improved_output_returns_string  s    k<Q,,9ZZ(:K'HI 
	++22!,-'")	 3 F fc********:***:******f***f******c***c**********
	+ 
	+ 
	+s   D<E99Fc                    d}t        |      }t               }|j                  d   j                  |j                  _        t        j                  dd|i      5  ddl}|j	                  dddgd	d
dg      }||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                  |      rt        j                  |      nddz  }dd|iz  }t        t        j                   |            d}ddd       y# 1 sw Y   yxY w)uT   Anthropic 클라이언트 mock을 통해 AI 개선 호출이 이루어져야 한다.u*   Anthropic AI가 개선한 최종 아웃풋r   r  r  Nr  u   구체적인 수치 추가u   감성적 표현 강화r7   r9   r   rZ  rp   r  r   improved_contentrL   r  rN   )r  r   r  r  r\  r  r   r  r  rQ   rR   rS   rT   rU   rV   rX   rY   )	rZ   re  r  r  r  r   r\   r]   r^   s	            r'   1test_generate_improved_output_uses_anthropic_mockzLTestGenerateImprovedOutput.test_generate_improved_output_uses_anthropic_mock   s    G01ABk<I<Q<QRS<T<Y<Y,,9ZZ(:K'HI 
	.+22+9;TU,'9	 3 F -----6-------6---6------------------
	. 
	. 
	.s   C-EEr   )r   r   r   r  r]  ra  rc  rf  r   r)   r'   rX  rX    s    D+&+*+".r)   rX  )_r  builtinsrS   _pytest.assertion.rewrite	assertionrewriterQ   importlib.util	importlibr0   sysr   r   pathlibr   typingr   unittest.mockr   r   r   __file__parent_SCRIPTS_DIR_HELPERS_PATHutilspec_from_file_locationr   r\   ri   r|   r{   loader@py_assert10@py_assert13r   rR   rT   rU   rV   rj   r   r   @py_format15@py_format17r   @py_format18@py_format20rX   rY   module_from_specrO   modulesexec_module
_MAIN_PATHr   ormr  rd   r(   rg   r3   r5   r   r   r   r   r   r#  r0  r6  rD  rO  ra  rk  ru  r  r  _AI_MODULE_PATHr  r  __annotations__r  r  r  r  r  r  r  r  r  r  r.  rI  rX  r   r)   r'   <module>r     sG       
 '   *  H~$$++ 99667NP]^ ED E}D  E]%9%9 E E%9%E E E E}D E E E E E} E E E} E E ED E E E E E E E%9 E E E E E] E E E] E E E%9 E E E E E E E E E E E E E E Enn%%m4'*# $        % ..
^^33OZP
 ? ?z ?*"3"3 ?4 ?"34"? ? ? ?z ? ? ? ? ?z ? ? ?z ? ? ? ? ? ? ? ? ? ?"34 ? ? ? ? ?* ? ? ?* ? ? ?"3 ? ?4 ? ? ? ? ? ? ? ? ? ? ? ? ?nn%%j1"O  
    c "T d39o $ Dd3i4H T `. `.P33 33v 0;% ;%F 09; 9;B#% #%V :2 2N4 4L#- #-V#/ #/V#C #CV" "JH1 H1`& && !663 9  J!fQ* S#X  G!fQ- 4S>  "#Q1a&A[. DcN  "#Q1a&AJ2 S#X  ) tCH~  *,KL, $sCx.  >2*,HI#2	 34ef	0 d38n 	"a aRJ& J&dq9 q9rX5 X5@kJ kJfM/ M/jO. O.r)   