
    xi"b                        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mZ ddlmZ ddlZ ee      j$                  j$                  Ze
j(                  j+                  d ee             edz  Zej0                  j3                  de      ZdZeeuZes ej:                  defdeef      d	 ej<                         v s ej>                  e      r ej@                  e      nd	 ej@                  e      d
z  Z!dde!iz  Z" e# ejH                  e"            dxZZej0                  jK                  e      Z&ejN                  ZdZ(ee(uZ)e)s ej:                  de)fdee(f      d	 ej<                         v s ej>                  e      r ej@                  e      nd	 ej@                  e       ej@                  e(      dz  Z"dde"iz  Z* e# ejH                  e*            dxZxZ)Z(ejN                  jW                  e&       dedefdZ,dede-defdZ.dedefdZ/dedededefdZ0 G d d      Z1 G d d      Z2 G d d       Z3 G d! d"      Z4 G d# d$      Z5 G d% d&      Z6 G d' d(      Z7y))u:  
test_pattern_detector.py

scripts/pattern-detector.py 단위 테스트 (TDD)

테스트 항목:
1. 각 패턴 타입 감지 (보고서 내용 모킹)
   - test_missing 감지
   - pyright_error 감지
   - scope_exceeded 감지
   - qc_fail 감지
   - regression 감지
2. 팀 추출 로직 테스트
   - 보고서 내용에서 팀 추출
   - task-timers.json 역참조
   - 팀 추출 실패 시 "unknown"
3. risk_score 계산 테스트
4. 빈 보고서 디렉토리 graceful 처리
5. --days 필터링 테스트
6. team-patterns.json 없는 경우 (신규 생성)
    N)datetime	timedeltatimezone)Pathzpattern-detector.pypattern_detectoris notz%(py0)s is not %(py3)sspecpy0py3assert %(py5)spy5)z2%(py2)s
{%(py2)s = %(py0)s.loader
} is not %(py5)s)r   py2r   zassert %(py7)spy7tmp_pathreturnc                 <    | dz  dz  }|j                  dd       |S )NmemoryreportsTparentsexist_okmkdir)r   reports_dirs     :/home/jay/workspace/scripts/tests/test_pattern_detector.pymake_reports_dirr   0   *    X%	1KdT2    tasksc                     | dz  }|j                  dd       |dz  }|j                  t        j                  d|i      d       | S )Nr   Tr   ztask-timers.jsonr"   utf-8encoding)r   
write_textjsondumps)r   r"   
memory_dirfs       r   make_task_timersr,   6   sM    H$JTD1''ALLWe,-L@Or!   c                 <    | dz  dz  }|j                  dd       |S )Nr   whisperTr   r   )r   whisper_dirs     r   make_whisper_dirr0   >   r    r!   r   filenamecontentc                 6    | |z  }|j                  |d       |S )Nr$   r%   )r'   )r   r1   r2   r+   s       r   write_reportr4   D   s!    hALL7L+Hr!   c                   @    e Zd ZdZd Zd Zd Zd Zd Zd Z	d Z
d	 Zy
)TestPatternDetectionu"   각 패턴 타입 감지 테스트c                    g d}|D ]  }t         j                  |      }d}||v }|st        j                  d|fd||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }t        j                  d|      dz   d	|iz  }t        t        j                  |            d
x}} y
)u!   테스트 미작성 패턴 감지)u*   작업 완료. 테스트 없이 배포함.u$   이번 작업은 test 없이 진행.u$   테스트 미작성 상태로 제출u&   일정 문제로 테스트 SKIP 처리u$   시간 부족으로 테스트 생략test_missinginz%(py1)s in %(py3)spatternspy1r   ztest_missing not detected in: 
>assert %(py5)sr   Nr   detect_patterns
@pytest_ar_call_reprcompare	_saferepr@py_builtinslocals_should_repr_global_name_format_assertmsgAssertionError_format_explanationselfcontentsr2   r<   @py_assert0@py_assert2@py_format4@py_format6s           r   !test_detect_test_missing_keywordsz6TestPatternDetection.test_detect_test_missing_keywordsR   s    
   	\G'77@H![>X-[[[>X[[[>[[[[[[X[[[X[[[[1OPW{/[[[[[[[	\r!   c                    g d}|D ]  }t         j                  |      }d}||v }|st        j                  d|fd||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }t        j                  d|      dz   d	|iz  }t        t        j                  |            d
x}} y
)u#   pyright 에러 반복 패턴 감지)u   pyright 에러 5건 발생z!pyright error: Cannot find moduleu(   타입 에러 발생으로 빌드 실패pyright_errorr9   r;   r<   r=   zpyright_error not detected in: r?   r   Nr@   rK   s           r   "test_detect_pyright_error_keywordsz7TestPatternDetection.test_detect_pyright_error_keywords_   s    

   	^G'77@H"]?h.]]]?h]]]?]]]]]]h]]]h]]]]2QRYQ\0]]]]]]]	^r!   c                    g d}|D ]  }t         j                  |      }d}||v }|st        j                  d|fd||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }t        j                  d|      dz   d	|iz  }t        t        j                  |            d
x}} y
)u   scope 초과 패턴 감지)u$   scope 초과로 추가 작업 필요u0   범위 초과 발생, 다음 태스크로 이월u%   예상치 못한 추가 작업 발생u   작업이 예상보다 커짐scope_exceededr9   r;   r<   r=   z scope_exceeded not detected in: r?   r   Nr@   rK   s           r   #test_detect_scope_exceeded_keywordsz8TestPatternDetection.test_detect_scope_exceeded_keywordsj   s    
   	`G'77@H#_#x/___#x___#______x___x____3ST[S^1_______	`r!   c                    g d}|D ]  }t         j                  |      }d}||v }|st        j                  d|fd||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }t        j                  d|      dz   d	|iz  }t        t        j                  |            d
x}} y
)u   QC FAIL 패턴 감지)u   QC FAIL — 재작업 필요zqc_verify: FAILu   검증 결과: FAILqc_failr9   r;   r<   r=   zqc_fail not detected in: r?   r   Nr@   rK   s           r   test_detect_qc_fail_keywordsz1TestPatternDetection.test_detect_qc_fail_keywordsv   s    

   	RG'77@HQ9(QQQ9QQQ9QQQQQQQQQQQQQ,Eg[*QQQQQQQ	Rr!   c                    g d}|D ]  }t         j                  |      }d}||v }|st        j                  d|fd||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }t        j                  d|      dz   d	|iz  }t        t        j                  |            d
x}} y
)u   회귀 발생 패턴 감지)u   배포 후 회귀 발생 확인u'   regression 발생, 기존 기능 깨짐u   기존 테스트 실패 발생
regressionr9   r;   r<   r=   zregression not detected in: r?   r   Nr@   rK   s           r   test_detect_regression_keywordsz4TestPatternDetection.test_detect_regression_keywords   s    

   	XG'77@HW<8+WWW<8WWW<WWWWWW8WWW8WWWW/KG;-WWWWWWW	Xr!   c                    d}t         j                  |      }t        |      }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  t              rt        j                  t              nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }t        j                  d|       d	z   d
|iz  }t        t        j                  |            dx}x}}y)u'   정상 보고서에서 패턴 미감지u   
# task-100.1 완료 보고서

## 테스트 결과
모든 테스트 통과: 45/45 PASSED
pyright: 에러 없음
QC 통과
회귀 없음
r   ==)z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)slenr<   )r   r>   r   py6zFalse positives detected: z
>assert %(py8)spy8N)r   rA   rb   rB   rC   rE   rF   rG   rD   rH   rI   rJ   )rL   r2   r<   rO   @py_assert5@py_assert4@py_format7@py_format9s           r   test_no_false_positivesz,TestPatternDetection.test_no_false_positives   s     $33G<8}JJ}!JJJ}JJJJJJsJJJsJJJJJJ8JJJ8JJJ}JJJJJJ%?z#JJJJJJJJr!   c                    d}t         j                  |      }d}||v }|st        j                  d|fd||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }dd|iz  }t        t        j                  |            d	x}}d
}||v }|st        j                  d|fd||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }dd|iz  }t        t        j                  |            d	x}}d}||v }|st        j                  d|fd||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }dd|iz  }t        t        j                  |            d	x}}y	)u   복수 패턴 동시 감지u?   테스트 없이 배포. 또한 pyright 에러 발생. QC FAIL.r8   r9   r;   r<   r=   r   r   NrT   rZ   
r   rA   rB   rC   rD   rE   rF   rG   rI   rJ   rL   r2   r<   rN   rO   rP   rQ   s          r   test_detect_multiple_patternsz2TestPatternDetection.test_detect_multiple_patterns   s"   S#33G<)~))))~)))~))))))))))))))))*(****(*********(***(*******$yH$$$$yH$$$y$$$$$$H$$$H$$$$$$$r!   c                 |   d}t         j                  |      }d}||v }|st        j                  d|fd||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }dd|iz  }t        t        j                  |            d	x}}y	)
u0   qc_fail: qc_verify.*FAIL 정규식 패턴 감지u(   qc_verify: status=FAIL, 재시도 필요rZ   r9   r;   r<   r=   r   r   Nrk   rl   s          r   $test_detect_case_insensitive_qc_failz9TestPatternDetection.test_detect_case_insensitive_qc_fail   sp    <#33G<$yH$$$$yH$$$y$$$$$$H$$$H$$$$$$$r!   N)__name__
__module____qualname____doc__rR   rU   rX   r[   r^   ri   rm   ro    r!   r   r6   r6   O   s3    ,\	^
`	R	XK%%r!   r6   c                   :    e Zd ZdZd Zd Zd Zd Zd Zd Z	d Z
y	)
TestTeamExtractionu+   보고서에서 팀 추출 로직 테스트c                    d}t         j                  |di       }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
)u/   보고서 내용에서 팀 추출 (팀: 패턴)    **팀:** dev1-team
작업 완료task-100.1.md	dev1-teamr`   z%(py0)s == %(py3)steamr   r   r   N
r   extract_team_from_contentrB   rC   rE   rF   rG   rD   rI   rJ   rL   r2   r|   rO   @py_assert1rP   rQ   s          r   %test_extract_team_from_report_contentz8TestTeamExtraction.test_extract_team_from_report_content   u    599'?TVW""t{""""t{""""""t"""t"""{"""""""r!   c                    d}t         j                  |di       }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
)u-   보고서 내용에서 team_id: 패턴 추출u    team_id: dev2-team
작업 내용ry   	dev2-teamr`   r{   r|   r   r   r   Nr}   r   s          r   $test_extract_team_from_team_id_fieldz7TestTeamExtraction.test_extract_team_from_team_id_field   r   r!   c                    ddddi}d}t         j                  |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}}y)u(   task-timers.json에서 team_id 역참조task-200	dev3-teamtask_idteam_idu   일반 보고서 내용task-200.1.mdr`   r{   r|   r   r   r   Nr}   rL   r"   r2   r|   rO   r   rP   rQ   s           r   "test_extract_team_from_task_timersz5TestTeamExtraction.test_extract_team_from_task_timers   s     %&
 ,99'?TYZ""t{""""t{""""""t"""t"""{"""""""r!   c                    d}t         j                  |di       }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
)u$   팀 추출 실패 시 unknown 반환u   팀 정보 없는 보고서ztask-999.1.mdunknownr`   r{   r|   r   r   r   Nr}   r   s          r   "test_extract_team_unknown_fallbackz5TestTeamExtraction.test_extract_team_unknown_fallback   su    /99'?TVW  ty    ty      t   t   y       r!   c                    ddddi}d}t         j                  |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}}y)u:   보고서 내용의 팀 정보가 task-timers보다 우선ztask-300r   r   rx   ztask-300.1.mdrz   r`   r{   r|   r   r   r   Nr}   r   s           r   .test_extract_team_priority_content_over_timerszATestTeamExtraction.test_extract_team_priority_content_over_timers   s     %&
 699'?TYZ""t{""""t{""""""t"""t"""{"""""""r!   c                 >   t         j                  }d} ||      }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d	x}x}x}x}}t         j                  }d
} ||      }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d	x}x}x}x}}t         j                  }d} ||      }d	}||u }|st        j                  d|fd||f      dt	        j
                         v st        j                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d	x}x}x}x}}y	)u   파일명에서 task-id 추출ry   ztask-100r`   )zc%(py6)s
{%(py6)s = %(py2)s
{%(py2)s = %(py0)s.extract_task_id_from_filename
}(%(py4)s)
} == %(py9)sr   )r   r   py4rc   py9assert %(py11)spy11Nztask-200.2.mdr   zrandom-report.md)is)zc%(py6)s
{%(py6)s = %(py2)s
{%(py2)s = %(py0)s.extract_task_id_from_filename
}(%(py4)s)
} is %(py9)s)
r   extract_task_id_from_filenamerB   rC   rE   rF   rG   rD   rI   rJ   )rL   r   @py_assert3re   @py_assert8@py_assert7@py_format10@py_format12s           r   "test_extract_task_id_from_filenamez5TestTeamExtraction.test_extract_task_id_from_filename   s   ==\o\=oN\R\\NR\\\\\NR\\\\\\\\\\\\\=\\\o\\\N\\\R\\\\\\\\==\o\=oN\R\\NR\\\\\NR\\\\\\\\\\\\\=\\\o\\\N\\\R\\\\\\\\==Y>PY=>PQYUYYQUYYYYYQUYYYYYYYYYYYYY=YYY>PYYYQYYYUYYYYYYYYYr!   c           	      .   g d}|D ]  \  }}t         j                  |di       }||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  }t        j                  d|d	|d
|      dz   d|iz  }t        t        j                  |            d} y)u"   다양한 팀 표기 형식 추출))u   **팀:** dev2-teamr   )u   팀: dev3-teamr   )zteam: dev1-teamrz   zx.mdr`   )z%(py0)s == %(py2)sr|   expected)r   r   z	Expected z from z, got z
>assert %(py4)sr   N)r   r~   rB   rC   rE   rF   rG   rD   rH   rI   rJ   )rL   contents_teamsr2   r   r|   r   @py_format3@py_format5s           r   !test_extract_team_various_formatsz4TestTeamExtraction.test_extract_team_various_formats   s    

 "0 	]GX#==gvrRD8#\\\48\\\\\\4\\\4\\\\\\8\\\8\\\\yF7+VTXS[%\\\\\\\	]r!   N)rp   rq   rr   rs   r   r   r   r   r   r   r   rt   r!   r   rv   rv      s*    5##
#!
#Z	]r!   rv   c                   4    e Zd ZdZd Zd Zd Zd Zd Zd Z	y)	TestRiskScoreCalculationu   risk_score 계산 테스트c                    ddi}t         j                  |d      }d}||z
  }t        |      }d}||k  }|s
t        j                  d|fd||f      dt        j                         v st        j                  t              rt        j                  t              ndd	t        j                         v st        j                  |      rt        j                  |      nd	t        j                  |      t        j                  |      t        j                  |      d
z  }dd|iz  }	t        t        j                  |	            dx}x}x}x}}y)u,   QC FAIL 1건, 보고서 10건 시 risk_scorerZ      
   gQ?&.><z;%(py6)s
{%(py6)s = %(py0)s((%(py1)s - %(py3)s))
} < %(py9)sabsscorer   r>   r   rc   r   r   r   Nr   calculate_risk_scorer   rB   rC   rE   rF   rG   rD   rI   rJ   
rL   pattern_countsr   rO   rf   re   r   r   r   r   s
             r   test_risk_score_single_qc_failz7TestRiskScoreCalculation.test_risk_score_single_qc_fail   s     $Q 55nbI'54<'s< '4' 4'''' 4''''''s'''s''''''5'''5'''4''' '''4''''''''r!   c                    dddd}t         j                  |d      }d}||z
  }t        |      }d}||k  }|s
t        j                  d|fd	||f      d
t        j                         v st        j                  t              rt        j                  t              nd
dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }	t        t        j                  |	            dx}x}x}x}}y)u   복수 패턴 risk_score 계산      r   )rZ   r8   rT   r   g{Gz?r   r   r   r   r   r   r   r   Nr   r   s
             r   !test_risk_score_multiple_patternsz:TestRiskScoreCalculation.test_risk_score_multiple_patterns   s     &'AN 55nbI'54<'s< '4' 4'''' 4''''''s'''s''''''5'''5'''4''' '''4''''''''r!   c                 |   t         j                  i 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}}y	)
u    패턴 없을 때 risk_score = 0r           r`   r{   r   r   r   r   N
r   r   rB   rC   rE   rF   rG   rD   rI   rJ   rL   r   rO   r   rP   rQ   s         r   %test_risk_score_zero_when_no_patternsz>TestRiskScoreCalculation.test_risk_score_zero_when_no_patterns  sl     55b"=u|uuur!   c                    t         j                  ddi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}}y)u8   보고서 없을 때 risk_score = 0 (0 나누기 방지)rZ      r   r   r`   r{   r   r   r   r   Nr   r   s         r   $test_risk_score_zero_when_no_reportsz=TestRiskScoreCalculation.test_risk_score_zero_when_no_reports
  sp     55y!naHu|uuur!   c                 $   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}}|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)u%   모든 패턴 타입 가중치 검증rZ   g333333?r`   z%(py1)s == %(py4)sr>   r   assert %(py6)src   Nr8   g      ?rT   g?rW   g333333?r]   g?)r   PATTERN_WEIGHTSrB   rC   rD   rI   rJ   )rL   weightsrN   r   rO   r   rg   s          r   #test_risk_score_all_pattern_weightsz<TestRiskScoreCalculation.test_risk_score_all_pattern_weights  s   "22y!(S(!S((((!S(((!(((S(((((((~&.$.&$....&$...&...$.......'.3.'3....'3...'...3.......'(0D0(D0000(D000(000D0000000|$++$++++$+++$++++++++++r!   c                    dddddd}t         j                  |d      }d}||z
  }t        |      }d}||k  }|s
t        j                  d|fd||f      dt        j                         v st        j                  t              rt        j                  t              ndd	t        j                         v st        j                  |      rt        j                  |      nd	t        j                  |      t        j                  |      t        j                  |      d
z  }dd|iz  }	t        t        j                  |	            dx}x}x}x}}y)u8   극단적 케이스에서 risk_score가 합리적 범위r   )rZ   r8   rT   rW   r]   r   g      $@r   r   r   r   r   r   r   r   Nr   r   s
             r   %test_risk_score_clamped_or_reasonablez>TestRiskScoreCalculation.test_risk_score_clamped_or_reasonable  s      
 !55naH'54<'s< '4' 4'''' 4''''''s'''s''''''5'''5'''4''' '''4''''''''r!   N)
rp   rq   rr   rs   r   r   r   r   r   r   rt   r!   r   r   r      s#    %((

,(r!   r   c                   (    e Zd ZdZd Zd Zd Zd Zy)TestEmptyReportsDirectoryu,   빈 디렉토리 및 에러 처리 테스트c                    t        |      }t        |i        t        |       t        j	                  t        |      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}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }d	d
|iz  }t        t        j                  |            dx}x}}|d   }i }||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!   빈 보고서 디렉토리 처리   	workspacedayssummarytotal_reports_analyzedr   r`   r   r   r   rc   Ntotal_patterns_foundteams)r   r,   r0   r   analyze_reportsstrrB   rC   rD   rI   rJ   	rL   r   r   resultrN   r   rO   r   rg   s	            r   +test_empty_reports_dir_returns_empty_resultzETestEmptyReportsDirectory.test_empty_reports_dir_returns_empty_result/  s=   &x02&"!11(m 2 

 i !9:?a?:a????:a???:???a???????i !78=A=8A====8A===8===A=======g$"$"$$$$"$$$$$$"$$$$$$$r!   c                 x   t        |i        t        |       t        j                  t	        |      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}}y)u4   보고서 디렉토리가 없을 때 graceful 처리r   r   r   r   r   r`   r   r   r   rc   N)
r,   r0   r   r   r   rB   rC   rD   rI   rJ   )rL   r   r   rN   r   rO   r   rg   s           r   %test_nonexistent_reports_dir_gracefulz?TestEmptyReportsDirectory.test_nonexistent_reports_dir_graceful>  s    2&"!11(m 2 

 i !9:?a?:a????:a???:???a???????r!   c                    t        |      }t        |i        t        |       t        |dd       t        |dd       t        j                  t        |      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}}y)uJ   읽기 실패 보고서는 건너뜀 (디렉토리를 파일처럼 생성)ry   u'   정상 보고서. 테스트 SKIP 처리task-101.1.md r   r   r   r   r   >=z%(py1)s >= %(py4)sr   r   rc   Nr   r,   r0   r4   r   r   r   rB   rC   rD   rI   rJ   r   s	            r   test_unreadable_report_skippedz8TestEmptyReportsDirectory.test_unreadable_report_skippedJ  s    &x02&" 	[/3\][/26!11(m 2 
 i !9:?a?:a????:a???:???a???????r!   c                    t        |      }t        |       t        |dd       t        j	                  t        |      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}}y)u*   task-timers.json 없어도 graceful 처리ry   u#   **팀:** dev1-team
정상 보고서r   r   r   r   r   r   r   r   r   rc   N)r   r0   r4   r   r   r   rB   rC   rD   rI   rJ   r   s	            r   %test_nonexistent_task_timers_gracefulz?TestEmptyReportsDirectory.test_nonexistent_task_timers_graceful\  s    &x0"[/3YZ!11(m 2 

 i !9:?a?:a????:a???:???a???????r!   N)rp   rq   rr   rs   r   r   r   r   rt   r!   r   r   r   ,  s    6%
@@$@r!   r   c                   "    e Zd ZdZd Zd Zd Zy)TestDaysFilteringu   최근 N일 필터링 테스트c                 2   ddl }ddl}t        |      }t        |i        t	        |       t        |dd      }t        |dd      }|j                         dz
  }|j                  t        |      ||f       t        j                  t        |      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}}
y)u   30일 이전 파일 제외r   Ntask-new.mdu!   **팀:** dev1-team
테스트 SKIPtask-old.md   **팀:** dev1-team
QC FAILi O r   r   r   r   r   r`   r   r   r   rc   ostimer   r,   r0   r4   utimer   r   r   rB   rC   rD   rI   rJ   )rL   r   r   r   r   
new_report
old_reportold_timer   rN   r   rO   r   rg   s                 r   %test_days_filter_excludes_old_reportsz7TestDaysFiltering.test_days_filter_excludes_old_reportsr  s    &x02&" "0

 ")


 99;.1
Z8X"67!11(m 2 
 i !9:?a?:a????:a???:???a???????r!   c                 2   ddl }ddl}t        |      }t        |i        t	        |       t        |dd       t        |dd      }|j                         dz
  }|j                  t        |      ||f       t        j                  t        |      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}
}	y)u(   days=60이면 60일 이내 파일 포함r   Nr      **팀:** dev1-team
정상r   iS; <   r   r   r   r   r`   r   r   r   rc   r   )rL   r   r   r   r   r   r   r   rN   r   rO   r   rg   s                r   (test_days_filter_includes_recent_reportsz:TestDaysFiltering.test_days_filter_includes_recent_reports  s    &x02&" 	[-1MN "(


 99;.1
Z8X"67!11(m 2 

 i !9:?a?:a????:a???:???a???????r!   c                 2   ddl }ddl}t        |      }t        |i        t	        |       t        |dd       t        |dd      }|j                         dz
  }|j                  t        |      ||f       t        j                  t        |      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}
}	y)u!   days=0이면 모든 파일 포함r   Nz	task-1.mdr   z	task-2.mdu   **팀:** dev2-team
정상i3r   r   r   r   r`   r   r   r   rc   r   )rL   r   r   r   r   very_oldr   r   rN   r   rO   r   rg   s                r   test_days_filter_zero_means_allz1TestDaysFiltering.test_days_filter_zero_means_all  s    &x02&"[+/KL[:VW99;/2
X8 45!11(m 2 

 i !9:?a?:a????:a???:???a???????r!   N)rp   rq   rr   rs   r   r   r   rt   r!   r   r   r   o  s    )@B@8@r!   r   c                   .    e Zd ZdZd Zd Zd Zd Zd Zy)TestOutputFileu#   team-patterns.json 저장 테스트c                 ^   t        |      }t        |i        t        |      }t        |dd       t        j                  t        |      d      }|dz  }t        j                  |t        |             |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"                  |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}}d}
|
|	v }|st        j&                  d|fd|
|	f      t        j                  |
      dt        j                         v st        j                  |	      rt        j                  |	      nddz  }dd|iz  }t        t        j                  |            d	x}
}d}
|
|	v }|st        j&                  d|fd|
|	f      t        j                  |
      dt        j                         v st        j                  |	      rt        j                  |	      nddz  }dd|iz  }t        t        j                  |            d	x}
}d}
|
|	v }|st        j&                  d|fd|
|	f      t        j                  |
      dt        j                         v st        j                  |	      rt        j                  |	      nddz  }dd|iz  }t        t        j                  |            d	x}
}y	)u-   team-patterns.json이 없으면 신규 생성ry   u(   **팀:** dev1-team
테스트 SKIP 처리r   r   team-patterns.jsonAassert %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.exists
}()
}output_pathr   r   r   Nr$   r%   versionr   r`   r   r   r   rc   last_updatedr9   r;   datar=   r   r   r   r   )r   r,   r0   r4   r   r   r   save_resultsexistsrE   rF   rB   rG   rD   rI   rJ   r(   loads	read_textrC   )rL   r   r   r/   r   r  r   r   r   r  rN   rO   rg   rP   rQ   s                  r   #test_creates_new_team_patterns_jsonz2TestOutputFile.test_creates_new_team_patterns_json  sF   &x02&&x07	
 "11(m 2 

 "$88%%fc+.>?!!#!########{###{###!##########zz+///ABI#!#!####!######!#######%~%%%%~%%%~%%%%%%%%%%%%%%%%w$w$w$$ yD    yD   y      D   D       r!   c                 z   t        |      }t        |i        t        |       t        |dd       t        j                  t        |      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}||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   }||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   }||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   }||v }|slt        j                  d|fd||f      t        j                  |      t        j                  |      d	z  }d
d|iz  }t        t        j                  |            dx}x}}y)u   출력 JSON 구조 검증ry   u/   **팀:** dev1-team
QC FAIL — 재작업 필요r   r   r  r   r`   r   r   r   rc   Nr  r9   r;   r   r=   r   r   r   r   r   z%(py1)s in %(py4)sr   highest_risk_team)r   r,   r0   r4   r   r   r   rB   rC   rD   rI   rJ   rE   rF   rG   )rL   r   r   r   rN   r   rO   r   rg   rP   rQ   s              r   )test_output_structure_has_required_fieldsz8TestOutputFile.test_output_structure_has_required_fields  s   &x02&">	
 "11(m 2 

 i %A% A%%%% A%%% %%%A%%%%%%%'~''''~'''~'''''''''''''''' w&    w&   w      &   &       "yF""""yF"""y""""""F"""F"""""""'<6)+<<'+<<<<<'+<<<<'<<<+<<<<<<<<%:	)::%):::::%)::::%:::)::::::::"7fY&77"&77777"&7777"777&77777777r!   c                 (   t        |      }t        |i        t        |       t        |dd       t        j                  t        |      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}||	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   }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)u   팀 항목 구조 검증ry   r   r   r   rz   r   r9   r  r   r   rc   Nr<   r;   	team_datar=   r   r   
risk_score5assert %(py5)s
{%(py5)s = %(py0)s(%(py2)s, %(py3)s)
}
isinstancelistr   r   r   r   float)r   r,   r0   r4   r   r   r   rB   rC   rD   rI   rJ   rE   rF   rG   r  r  r  )rL   r   r   r   rN   r   rO   r   rg   r  rP   rQ   r   rf   s                 r   test_team_entry_structurez(TestOutputFile.test_team_entry_structure  s`   &x02&")	
 "11(m 2 

 -fWo-{o----{o---{---o-------7OK0	&zY&&&&zY&&&z&&&&&&Y&&&Y&&&&&&&(|y((((|y(((|((((((y(((y(((((((#J/6z/66666666z666z666/6666666666666666666#L19z1599999999z999z9991999999599959999999999r!   c                 f   t        |      }t        |i        t        |       t        |dd       t        j                  t        |      d      }|d   d   }|d   }t        |      }d}||kD  }|st        j                  d	|fd
||f      dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |      t        j                  |      dz  }	dd|	iz  }
t        t        j                  |
            dx}x}x}}|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   }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   패턴 항목 구조 검증ry   r   r   r   r   rz   r<   r   )>)z/%(py4)s
{%(py4)s = %(py0)s(%(py2)s)
} > %(py7)srb   )r   r   r   r   zassert %(py9)sr   Ntyper9   r;   pattern_entryr=   r   r   countrecent_reportsr  r  r  r  )r   r,   r0   r4   r   r   r   rb   rB   rC   rE   rF   rG   rD   rI   rJ   r  r  )rL   r   r   r   r  r   r   @py_assert6re   @py_format8r   r  rN   rO   rP   rQ   rf   s                    r   test_pattern_entry_structurez+TestOutputFile.test_pattern_entry_structure  s   &x02&")	
 "11(m 2 

 7OK0	Z(-s()-A-)A----)A------s---s---(---)---A-------!*-a0&v&&&&v&&&v&&&&&&&&&&&&&&&&'w-''''w-'''w''''''-'''-'''''''0=0000=000000000=000=0000000'(89@z94@@@@@@@@z@@@z@@@9@@@@@@4@@@4@@@@@@@@@@r!   c                    t        |      }t        |i        |dz  dz  dz  }t        j                  t	        |      d      }t        j                  |t	        |             |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}}y	)
u/   whisper 디렉토리가 없으면 자동 생성r   r.   r  r   r   r  r  r  N)r   r,   r   r   r   r  r	  rE   rF   rB   rG   rD   rI   rJ   )rL   r   r   r  r   r   r   r   s           r   #test_whisper_dir_created_if_missingz2TestOutputFile.test_whisper_dir_created_if_missing2  s    &x02& )I58LL!11(m 2 
 	%%fc+.>?!!#!########{###{###!##########r!   N)	rp   rq   rr   rs   r  r  r  r"  r$  rt   r!   r   r   r     s    -!682:0A2$r!   r   c                   .    e Zd ZdZd Zd Zd Zd Zd Zy)TestIntegrationu    analyze_reports 통합 테스트c           	      	   t        |      }t        |ddddi       t        |       t        |dd       t        |dd       t        |dd	       t        j                  t        |      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   }||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   D 	ci c]  }	|	d   |	d    }
}	|
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                  |      t        j                  |      t        j                  |      t        j                  |      t        j                  |      d"z  }d#d$|iz  }t        t        j                  |            dx}x}x}x}x}}|
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                  |      t        j                  |      t        j                  |      t        j                  |      t        j                  |      d"z  }d#d$|iz  }t        t        j                  |            dx}x}x}x}x}}|
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                  |      t        j                  |      t        j                  |      t        j                  |      t        j                  |      d"z  }d#d$|iz  }t        t        j                  |            dx}x}x}x}x}}yc c}	w )'u#   복수 팀, 복수 보고서 분석r   r   r   ry   u>   **팀:** dev1-team
QC FAIL — 재작업 필요
테스트 SKIPr   u-   **팀:** dev1-team
pyright 에러 3건 발생r       **팀:** dev2-team
정상 완료r   r   r   r   r   r`   r   r   r   rc   Nrz   r   r9   r  r<   r  r  rZ   r   r   r   )zS%(py8)s
{%(py8)s = %(py2)s
{%(py2)s = %(py0)s.get
}(%(py4)s, %(py6)s)
} >= %(py11)sdev1_patterns)r   r   r   rc   rd   r   zassert %(py13)spy13r8   rT   )r   r,   r0   r4   r   r   r   rB   rC   rD   rI   rJ   getrE   rF   rG   )rL   r   r   r   rN   r   rO   r   rg   pr)  r   re   r   @py_assert10@py_assert9r   @py_format14s                     r   !test_full_analysis_multiple_teamsz1TestIntegration.test_full_analysis_multiple_teamsJ  sq   &x0
{K	
 	"N	

 	<	

 	/	
 "11(m 2 

 i !9:?a?:a????:a???:???a???????-fWo-{o----{o---{---o------- 9?w8TU_8`a16AgJ.aa  33A3 A.3!3.!3333.!333333}333}333 333333A333.333!33333333  888 38q83q88883q888888}888}888 8888888883888q88888888  99!9 !499499994999999}999}999 999999!999499999999999 bs   >Sc                    t        |      }t        |i        t        |       t        |dd       t        |dd       t        j                  t        |      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}}y)u1   highest_risk_team이 가장 높은 risk_score 팀ry   u8   **팀:** dev1-team
QC FAIL
테스트 SKIP
pyright 에러r   r(  r   r   r   r  rz   r`   r   r   r   rc   Nr   r   s	            r   !test_highest_risk_team_in_summaryz1TestIntegration.test_highest_risk_team_in_summarys  s    &x02&"I	

 	/	
 "11(m 2 

 i !45DD5DDDD5DDD5DDDDDDDDDDr!   c                    t        |      }t        |i        t        |       t        |dd       t        j                  t        |      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}}y)u%   total_patterns_found 합산 정확성ry   u)   **팀:** dev1-team
QC FAIL
테스트 SKIPr   r   r   r   r   r   r   r   r   rc   Nr   r   s	            r   test_total_patterns_countz)TestIntegration.test_total_patterns_count  s    &x02&" 	9	
 "11(m 2 

 i !78=A=8A====8A===8===A=======r!   c                 &   t        |      }t        |i        t        |       t        |dd       t        j                  t        |      d      }|d   d   d   }t        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}}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	)u5   recent_reports에 파일명이 포함되는지 확인ry   r   r   r   r   rz   r<   c              3   2   K   | ]  }|d    dk(  s|  yw)r  rZ   Nrt   ).0r,  s     r   	<genexpr>zFTestIntegration.test_recent_reports_list_in_pattern.<locals>.<genexpr>  s     NqyI7M1Ns   Nr   r
   
qc_patternr   r   r   r  r9   r  r   r   rc   )r   r,   r0   r4   r   r   r   nextrB   rC   rE   rF   rG   rD   rI   rJ   )rL   r   r   r   r)  r9  rO   r   rP   rQ   rN   r   r   rg   s                 r   #test_recent_reports_list_in_patternz3TestIntegration.test_recent_reports_list_in_pattern  s$   &x02&")	
 "11(m 2 

 w4Z@NmNPTU
!%%z%%%%z%%%%%%z%%%z%%%%%%%%%%>*-=">>">>>>>">>>>>>>">>>>>>>>r!   c                    t        |      }t        |ddddi       t        |       t        |dd       t        j                  t        |      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)u(   task-timers.json 역참조로 팀 식별ztask-500r   r   ztask-500.1.mdu   작업 완료. 테스트 SKIP.r   r   r   r9   r  r   r   rc   Nr   r   s	            r   test_task_timers_team_lookupz,TestIntegration.test_task_timers_team_lookup  s    &x0
{K	
 	" 	,	
 "11(m 2 

 -fWo-{o----{o---{---o-------r!   N)	rp   rq   rr   rs   r0  r2  r4  r;  r=  rt   r!   r   r&  r&  G  s     *':RE0>(?,.r!   r&  )8rs   builtinsrE   _pytest.assertion.rewrite	assertionrewriterB   importlib.util	importlibr(   sysr   r   r   pathlibr   pytest__file__parent_SCRIPTS_DIRpathinsertr   _MODULE_PATHutilspec_from_file_locationr   rO   r   rC   rF   rG   rD   rP   rQ   rI   rJ   module_from_specr   loaderrf   r   r!  exec_moduler   dictr,   r0   r4   r6   rv   r   r   r   r   r&  rt   r!   r   <module>rS     s  ,     
 2 2   H~$$++ 3|$ % 33~~--.@,O t4   t4     t   t   4      >>2248 {{ $ {$   {$     t   t   {  $         ( )t  t D T t  d c C D W% W%~<] <]H2( 2(t;@ ;@FS@ S@vu$ u$zE. E.r!   