
    (<iUI              !       ,   d Z ddlZddlZddlZddlmZ ej                  j                  d e ee	      j                  j                  j                  j                               ddlmZmZ 	 	 	 	 	 	 	 	 d/dededededz  d	ed
edededefdZ	 	 	 	 	 	 	 	 	 d0dedededededededededz  defdZ G d dej(                        Z G d dej(                        Z G d dej(                        Z G d d ej(                        Z G d! d"ej(                        Z G d# d$ej(                        Z	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d1dedededededededed%ed&ed'ed(ed)ed*ededz  def d+Z G d, d-ej(                        Zed.k(  r ej<                          yy)2u0   test_reporter.py - TDD 테스트 (RED → GREEN)    N)Path)estimate_costgenerate_reportskill
started_atended_atroundsfinal_scoretotal_roundskeptrevertedreturnc           	           | ||||ng ||||dS )Nr   r   r   r	   r
   r   r   r    r   s           Y/home/jay/workspace/.worktrees/task-2057-dev2/scripts/autoresearch/tests/test_reporter.py_make_log_datar      s-      ".&B"$	 	    	round_nummutation_typemutation_descriptionscore_beforescore_afterdecisioninput_tokensoutput_tokensitems_detailc	           
      ,    | ||||||nddddg|||d	S )NclarityPASSok)idresultreason)	roundr   r   r   r   r   r   r   r   r   	r   r   r   r   r   r   r   r   r   s	            r   _make_roundr'   $   s<     & 4$"(4L)W]im;n:o$& r   c                   P    e Zd ZdZddZddZddZddZddZddZ	dd	Z
dd
Zy)TestEstimateCostu   estimate_cost() 테스트Nc                 H    t        ddd      }| j                  |dd       y)	u   Sonnet: input 1M 토큰 = $3@B r   sonnetr   r   modelg      @   placesNr   assertAlmostEqualselfcosts     r   test_sonnet_input_ratez'TestEstimateCost.test_sonnet_input_rateA   s%    )1HUtS3r   c                 H    t        ddd      }| j                  |dd       y)	u   Sonnet: output 1M 토큰 = $15r   r+   r,   r-   g      .@r/   r0   Nr2   r4   s     r   test_sonnet_output_ratez(TestEstimateCost.test_sonnet_output_rateF   s%    !9HUtT!4r   c                 L    t        ddd      }d}| j                  ||d       y)	u+   Sonnet: input 50,000 + output 25,000 토큰P  a  r,   r-   g?r/   r0   Nr2   )r5   r6   expecteds      r   test_sonnet_combinedz%TestEstimateCost.test_sonnet_combinedK   s*    &hWKtXa8r   c                 H    t        ddd      }| j                  |dd       y)	u   Haiku: input 1M 토큰 = $0.80r+   r   haikur-   皙?r/   r0   Nr2   r4   s     r   test_haiku_input_ratez&TestEstimateCost.test_haiku_input_rateQ   s%    )1GTtT!4r   c                 H    t        ddd      }| j                  |dd       y)	u   Haiku: output 1M 토큰 = $4r   r+   r@   r-   g      @r/   r0   Nr2   r4   s     r   test_haiku_output_ratez'TestEstimateCost.test_haiku_output_rateV   s%    !9GTtS3r   c                 H    t        ddd      }| j                  |dd       y)u"   Haiku: input 1M + output 1M 토큰r+   r@   r-   g333333@r/   r0   Nr2   r4   s     r   test_haiku_combinedz$TestEstimateCost.test_haiku_combined[   s&    )9T[\tT!4r   c                 b    t        dd      }t        ddd      }| j                  ||d       y)	u(   model 미지정 시 sonnet 단가 사용順 r;   r   r   r,   r-   r/   r0   Nr2   )r5   cost_defaultcost_sonnets      r   test_default_model_is_sonnetz-TestEstimateCost.test_default_model_is_sonnet`   s2    $'P#V^_|[Cr   c                 F    t        dd      }| j                  |dd       y)u   토큰 0이면 비용 0r   rI           r/   r0   Nr2   r4   s     r   test_zero_tokensz!TestEstimateCost.test_zero_tokensf   s#    !1=tS3r   r   N)__name__
__module____qualname____doc__r7   r9   r>   rB   rD   rF   rL   rO   r   r   r   r)   r)   >   s.    #4
5
95
4
5
D4r   r)   c                   @    e Zd ZdZd	dZd	dZd	dZd	dZd	dZd	dZ	y)
TestGenerateReportBasicu)   generate_report() 기본 동작 테스트Nc                 6    t        j                         | _        y Ntempfilemkdtemptmpdirr5   s    r   setUpzTestGenerateReportBasic.setUpo       &&(r   c                     t        g       }t        t        | j                        dz        }t	        ||      }| j                  |t               | j                  t        |      dkD         y)u6   빈 rounds → 기본 보고서 생성 (오류 없음)r	   	report.mdr   N)r   strr   r\   r   assertIsInstance
assertTruelenr5   log_dataoutput_pathr#   s       r   "test_empty_rounds_generates_reportz:TestGenerateReportBasic.test_empty_rounds_generates_reportr   sT    !,$t{{+k9: ;7fc*Fa(r   c                     t        g       }t        t        | j                        dz        }t	        ||      }| j                  t        |      j                                y)u(   저장된 파일의 절대 경로 반환ra   rb   N)r   rc   r   r\   r   re   is_absoluterg   s       r   test_returns_absolute_pathz2TestGenerateReportBasic.test_returns_absolute_pathz   sI    !,$t{{+k9: ;7V0023r   c                    t        g       }t        t        | j                        dz        }t	        ||      }| j                  t        |      j                                | j                  t        |      j                                y)u,   보고서 파일이 output_path에 저장됨ra   rb   N)r   rc   r   r\   r   re   existsis_filerg   s       r   'test_report_file_created_at_output_pathz?TestGenerateReportBasic.test_report_file_created_at_output_path   sb    !,$t{{+k9: ;7V++-.V,,./r   c                     t        | j                        dz  dz  }t        |dz        }t        g       }t	        ||      }| j                  t        |      j                                y)u.   부모 디렉토리가 없으면 자동 생성subdirnestedrb   ra   N)r   r\   rc   r   r   re   ro   )r5   nonexistent_dirri   rh   r#   s        r   !test_auto_create_parent_directoryz9TestGenerateReportBasic.test_auto_create_parent_directory   sX    t{{+h6A/K78!, ;7V++-.r   c                     t        dg       }t        t        | j                        dz        }t	        ||       t        |      j                  d      }| j                  d|       y)u   보고서에 스킬명 포함zmy-skill)r   r	   rb   utf-8encodingNr   rc   r   r\   r   	read_textassertInr5   rh   ri   contents       r   test_report_contains_skill_namez7TestGenerateReportBasic.test_report_contains_skill_name   sV    !
2>$t{{+k9:+.{#--w-?j'*r   rP   )
rQ   rR   rS   rT   r^   rj   rm   rq   rv   r   r   r   r   rV   rV   l   s#    3))40/+r   rV   c                   @    e Zd ZdZd	dZd	dZd	dZd	dZd	dZd	dZ	y)
TestGenerateReportSectionsu)   generate_report() 섹션 구분 테스트Nc                     t        j                         | _        t        dddddd      | _        t        dd	d
ddd      | _        t        | j                  | j
                  gddd      | _        y )N      규칙 추가   새 규칙 추가333333?rA   r   )r   r   r   r   r   r         표현 수정   지시문 변경ffffff?r   )r	   r
   r   r   )rZ   r[   r\   r'   
kept_roundreverted_roundr   rh   r]   s    r   r^   z TestGenerateReportSections.setUp   sz    &&(%)!4
 *)!3
 'OOT%8%89	
r   c                     t        t        | j                        dz        }t        | j                  |       t        |      j                  d      }| j                  d|       | j                  d|       y)u8   kept 라운드가 '유지된 변경' 섹션에 표시됨rb   rx   ry   r   r   Nrc   r   r\   r   rh   r|   r}   r5   ri   r   s      r   'test_kept_rounds_appear_in_kept_sectionzBTestGenerateReportSections.test_kept_rounds_appear_in_kept_section   s]    $t{{+k9:{3{#--w-?)73ow/r   c                     t        t        | j                        dz        }t        | j                  |       t        |      j                  d      }| j                  d|       | j                  d|       y)u<   reverted 라운드가 '롤백된 변경' 섹션에 표시됨rb   rx   ry   r   r   Nr   r   s      r   /test_reverted_rounds_appear_in_reverted_sectionzJTestGenerateReportSections.test_reverted_rounds_appear_in_reverted_section   s]    $t{{+k9:{3{#--w-?('2ow/r   c                     t        t        | j                        dz        }t        | j                  |       t        |      j                  d      }| j                  d|       | j                  d|       y)u+   kept/reverted 섹션이 분리되어 있음rb   rx   ry   u   유지u   롤백Nr   r   s      r   +test_kept_and_reverted_in_separate_sectionszFTestGenerateReportSections.test_kept_and_reverted_in_separate_sections   s\    $t{{+k9:{3{#--w-?h(h(r   c                     t        | j                  gdd      }t        t        | j                        dz        }t        ||       t        |      j                  d      }| j                  |t               y)u)   kept 라운드가 없어도 섹션 표시r   r   r	   r   r   rb   rx   ry   N)r   r   rc   r   r\   r   r|   rd   r~   s       r   test_empty_kept_section_handledz:TestGenerateReportSections.test_empty_kept_section_handled   sj    !''(

 $t{{+k9:+.{#--w-?gs+r   c                     t        | j                  gdd      }t        t        | j                        dz        }t        ||       t        |      j                  d      }| j                  |t               y)u-   reverted 라운드가 없어도 섹션 표시r   r   r   rb   rx   ry   N)r   r   rc   r   r\   r   r|   rd   r~   s       r   #test_empty_reverted_section_handledz>TestGenerateReportSections.test_empty_reverted_section_handled   sh    !OO$

 $t{{+k9:+.{#--w-?gs+r   rP   )
rQ   rR   rS   rT   r^   r   r   r   r   r   r   r   r   r   r      s#    3
200)
,
,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)	TestGenerateReportScoreChangeu!   점수 변화율 계산 테스트Nc                 6    t        j                         | _        y rX   rY   r]   s    r   r^   z#TestGenerateReportScoreChange.setUp   r_   r   c                    t        t        ddd      gd      }d|d   d   d<   t        t        | j                        d	z        }t        ||       t        |      j                  d
      }| j                  d|v xs
 d|v xs d|v        y)u9   초기점수 0.60 → 최종점수 0.92, 변화율 +53.3%r   gq=
ףp?r   r   r   r   r	   r
   r	   r   r   rb   rx   ry   z+53.3z53.33z53.3%N)r   r'   rc   r   r\   r   r|   re   r~   s       r   test_score_change_positivez8TestGenerateReportScoreChange.test_score_change_positive   s    !SdVTU

 141n-$t{{+k9:+.{#--w-?7*Vg.@VGwDVWr   c                 
   t        t        ddd      gd      }d|d   d   d<   t        t        | j                        d	z        }t        ||       t        |      j                  d
      }| j                  |t               y)u?   초기 점수가 0이면 변화율 표시 (ZeroDivision 없음)rN         ?r   r   r   r	   r   r   rb   rx   ry   N)r   r'   rc   r   r\   r   r|   rd   r~   s       r   test_score_change_zero_initialz<TestGenerateReportScoreChange.test_score_change_zero_initial   s~    !ScFST
 141n-$t{{+k9:+.{#--w-?gs+r   c                    t        dddd      t        dddd      g}t        |d      }t        t        | j                        d	z        }t        ||       t        |      j                  d
      }| j                  d|       y)u5   초기 점수는 첫 번째 라운드의 score_beforer   r   r   r   )r   r   r   r   r   g?r   rb   rx   ry   z0.50Nr'   r   rc   r   r\   r   r|   r}   r5   r	   rh   ri   r   s        r   #test_initial_score_from_first_roundzATestGenerateReportScoreChange.test_initial_score_from_first_round
  s     !#3QWX!#3QWX
 "SA$t{{+k9:+.{#--w-?fg&r   c                     t        t        ddd      gd      }t        t        | j                        dz        }t        ||       t        |      j                  d      }| j                  d	|       y
)u'   최종 점수가 보고서에 표시됨r   rA   r   r   r   rb   rx   ry   z0.80N)r   r'   rc   r   r\   r   r|   r}   r~   s       r   test_final_score_in_reportz8TestGenerateReportScoreChange.test_final_score_in_report  sh    !ScFST
 $t{{+k9:+.{#--w-?fg&r   rP   )	rQ   rR   rS   rT   r^   r   r   r   r   r   r   r   r   r      s    +)X,'	'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)	TestGenerateReportCostSectionu   비용 섹션 테스트Nc                 6    t        j                         | _        y rX   rY   r]   s    r   r^   z#TestGenerateReportCostSection.setUp&  r_   r   c                     t        ddd      g}t        |      }t        t        | j                        dz        }t        ||       t        |      j                  d      }| j                  d	|       y
)u'   비용 섹션이 보고서에 포함됨r;   r<   r   r   r   r   ra   rb   rx   ry   u   비용Nr   r   s        r   test_cost_section_existsz6TestGenerateReportCostSection.test_cost_section_exists)  sk     V6FS
 "0$t{{+k9:+.{#--w-?h(r   c                    t        ddd      t        ddd      g}t        |      }t        t        | j                        d	z        }t        ||       t        |      j                  d
      }| j                  d|v xs d|v        y)u5   입력/출력 토큰 합계가 보고서에 표시됨r;   r<   r   r   '    r   ra   rb   rx   ry   z60,00060000N)r'   r   rc   r   r\   r   r|   re   r   s        r   test_total_tokens_in_reportz9TestGenerateReportCostSection.test_total_tokens_in_report4  s     V6FSV5:V
 "0$t{{+k9:+.{#--w-?G+Aw'/ABr   c                     t        ddd      g}t        |      }t        t        | j                        dz        }t        ||       t        |      j                  d      }| j                  d	|       y
)u*   예상 비용($)이 보고서에 표시됨r;   r<   r   r   ra   rb   rx   ry   $Nr   r   s        r   test_cost_estimation_in_reportz<TestGenerateReportCostSection.test_cost_estimation_in_reportA  sk     V6FS
 "0$t{{+k9:+.{#--w-?c7#r   c                     t        ddd      g}t        |      }t        t        | j                        dz        }t        ||       t        |      j                  d      }| j                  d|       y	)
u   토큰 0이어도 오류 없음r   r   r   ra   rb   rx   ry   r   Nr   r   s        r   test_zero_tokens_no_errorz7TestGenerateReportCostSection.test_zero_tokens_no_errorL  se    1AOP!0$t{{+k9:+.{#--w-?c7#r   rP   )	rQ   rR   rS   rT   r^   r   r   r   r   r   r   r   r   r   #  s    !)	)C	$$r   r   c                   0    e Zd ZdZddZddZddZddZy)TestGenerateReportMetadatauH   보고서 메타데이터(시작/종료 시간, 총 라운드) 테스트Nc                 6    t        j                         | _        y rX   rY   r]   s    r   r^   z TestGenerateReportMetadata.setUpY  r_   r   c                     t        dg       }t        t        | j                        dz        }t	        ||       t        |      j                  d      }| j                  d|       y)u'   시작 시간이 보고서에 포함됨2026-03-26T00:00:00+00:00)r   r	   rb   rx   ry   z
2026-03-26Nr{   r~   s       r   test_started_at_in_reportz4TestGenerateReportMetadata.test_started_at_in_report\  s\    !2
 $t{{+k9:+.{#--w-?lG,r   c                     t        dg       }t        t        | j                        dz        }t	        ||       t        |      j                  d      }| j                  d|       y)u+   총 라운드 수가 보고서에 포함됨2   )r   r	   rb   rx   ry   50Nr{   r~   s       r   test_total_rounds_in_reportz6TestGenerateReportMetadata.test_total_rounds_in_reporth  sV    !r"=$t{{+k9:+.{#--w-?dG$r   c                     t        g       }t        t        | j                        dz        }t	        ||       t        |      j                  d      }| j                  d|       y)u2   보고서가 마크다운 형식 (# 헤더 포함)ra   rb   rx   ry   #Nr{   r~   s       r   test_report_is_markdownz2TestGenerateReportMetadata.test_report_is_markdownp  sT    !,$t{{+k9:+.{#--w-?c7#r   rP   )rQ   rR   rS   rT   r^   r   r   r   r   r   r   r   r   V  s    R)
-%$r   r   mutation_input_tokensmutation_output_tokensexecution_input_tokensexecution_output_tokensjudge_input_tokensjudge_output_tokensc                 j    t        | ||||||||	      }||d<   |	|d<   |
|d<   ||d<   ||d<   ||d<   |S )Nr&   r   r   r   r   r   r   )r'   )r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   ds                   r   _make_round_with_breakdownr   y  sr    " 	#1!!#!
	A "7A"8A"8A#:A 0A2AHr   c                   0    e Zd ZdZddZddZddZddZy)TestGenerateReportCostBreakdownu   비용 세분화 테스트Nc                 6    t        j                         | _        y rX   rY   r]   s    r   r^   z%TestGenerateReportCostBreakdown.setUp  r_   r   c                    t        dddddd      g}t        |      }t        t        | j                        dz        }t        ||       t        |      j                  d	      }| j                  d
|       | j                  d|       y)u@   새 토큰 필드가 있으면 Sonnet+Haiku 분리 비용 표시r   r   i N  i  r   r   r   r   r   r   ra   rb   rx   ry   zSonnet:zHaiku:Nr   r   rc   r   r\   r   r|   r}   r   s        r   #test_cost_breakdown_with_new_fieldszCTestGenerateReportCostBreakdown.test_cost_breakdown_with_new_fields  s     '&+'+',(-#'$(	
 "0$t{{+k9:+.{#--w-?i)h(r   c                     t        ddd      g}t        |      }t        t        | j                        dz        }t        ||       t        |      j                  d      }| j                  d	|       y
)u0   새 필드 없으면 기존 Sonnet 기준 표시r;   r<   r   r   ra   rb   rx   ry   u   Sonnet 기준Nr   r   s        r   test_cost_backward_compatz9TestGenerateReportCostBreakdown.test_cost_backward_compat  sf    5PVWX!0$t{{+k9:+.{#--w-?ow/r   c                     t        dddddd      g}t        |      }t        t        | j                        dz        }t        ||       t        |      j                  d      }| j                  d|       y	)
u   비용 계산 정확도 검증rH   r;   r   ra   rb   rx   ry   z2.38Nr   r   s        r   test_cost_calculation_accuracyz>TestGenerateReportCostBreakdown.test_cost_calculation_accuracy  s{     '&,','-(-#)$)	
 "0$t{{+k9:+.{#--w-?
 	fg&r   rP   )rQ   rR   rS   rT   r^   r   r   r   r   r   r   r   r     s    $))&0'r   r   __main__)zad-creativer   z2026-03-26T01:30:00+00:00NrA         r   )	r   r   r   r   rA   r   d   r   N)r   r   r   r   rA   r   r   r   r   r   r   r   r   r   N)rT   sysrZ   unittestpathlibr   pathinsertrc   __file__parentscripts.autoresearch.reporterr   r   listfloatintdictr   r'   TestCaser)   rV   r   r   r   r   r   r   rQ   mainr   r   r   <module>r      s   6 
    3tH~,,33::AAB C H 1/  4K	
     
. ( 3 $  	
     + 
4+4x(( +4\++h// ++\L,!2!2 L,^7'H$5$5 7't0$H$5$5 0$f $!2!2  $H ( 3!""#"##$  $""" " 	"
 " " " " "  "  " !" " " +"  
!"J6'h&7&7 6'r zHMMO r   