
     hi;                        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 ddlZ ed      Z ed      Zedz  Zedz  ZdZej%                          Zej%                          Zej*                  j-                  ed	
      Zej*                  j-                  ed
      Z	 d$dededededz  def
dZdedededefdZ	 d$dededededz  dedz  defdZededdfd       Zededdfd       Zededdfd       Z ededdfd       Z!ededdfd       Z"ededdfd       Z#ededdfd       Z$ed%d        Z%ed%d!       Z&ededdfd"       Z'ededdfd#       Z(y)&u7  
test_qc_report_guard.py — qc_report_guard.py 회귀 테스트 (Guard MVP Phase 1, task-2434)

시나리오 (9개):
    1. test_pass_pass_ok                             — JSON=PASS + frontmatter PASS → ok=True
    2. test_warn_overall_pass_fail                    — JSON=WARN + 본문 OVERALL PASS → ok=False (task-2431)
    3. test_warn_pass_with_warn_ok                   — JSON=WARN + frontmatter PASS_WITH_WARN + 항목 명시 → ok=True
    4. test_warn_pass_with_warn_missing_items_fail    — JSON=WARN + PASS_WITH_WARN 그러나 항목 누락 → ok=False
    5. test_fail_overall_fail_ok                     — JSON=FAIL + 본문 OVERALL FAIL + 사유 → ok=True
    6. test_quoted_overall_pass_ignored              — 인용 블록 가짜 verdict 무시, 실제 PASS_WITH_WARN → ok=True
    7. test_no_verdict_marker_fail                   — frontmatter도 ## QC Verdict도 없음 → ok=False
    8. test_pass_pass_with_warn_mismatch_fail        — JSON=PASS + 보고서 PASS_WITH_WARN → ok=False (MISMATCH)
    9. test_missing_warns_no_uncaught_exception_when_json_pass — JSON=PASS 시 UnboundLocalError 없음

    (통합) test_guard_sh_help                    — guard.sh --help → exit 0
    (통합) test_guard_sh_phase2_3_not_implemented — guard.sh enqueue → exit 2 + "not implemented"
    N)Pathz/home/jay/workspace/scriptsz/home/jay/workspacezqc_report_guard.pyzguard.shztask-2434-qc-testz9qc_report_guard.py not yet implemented (Thor in progress))reasonz/guard.sh not yet implemented (Thor in progress)pathtask_idverdictchecks_summaryreturnc                     | dz  | dz  }|j                   j                  dd       |||xs i d}|j                  t        j                  |      d       |S )u5   memory/events/<task_id>.qc-result JSON 파일 생성.eventsz
.qc-resultTparentsexist_ok)r   	qc_resultr   utf-8encoding)parentmkdir
write_textjsondumps)r   r   r   r   fpayloads         9/home/jay/workspace/tests/scripts/test_qc_report_guard.py_write_qc_resultr   8   sb     	xWIZ00AHHNN4$N/(.BG
 LLG$wL7H    contentc                 |    | dz  | dz  }|j                   j                  dd       |j                  |d       |S )u*   memory/reports/<task_id>.md 파일 생성.reportsz.mdTr   r   r   )r   r   r   )r   r   r   r   s       r   _write_reportr    F   s@    ygYc?*AHHNN4$N/LL7L+Hr   tmp
qc_verdictreport_contentc                    | dz  }|j                  dd       t        ||||      }d}|t        |||      }t        t              t
        j                  vr-t
        j                  j                  dt        t                     ddl}|j                  d      }	|	j                  |t        |      t        |      |rt        |      nd      }
|
S )u   
    qc_report_guard.py 의 check() 함수를 subprocess CLI로 호출하여
    결과 dict를 반환.  --json-output 플래그로 stdout에 JSON 출력 기대.
    CLI가 없으면 직접 임포트하여 check() 호출.
    	workspaceTr   Nr   qc_report_guard)r   r%   qc_result_pathreport_path)r   r   r    str_SCRIPTS_DIRsysr   insert	importlibimport_modulecheck)r!   r   r"   r#   r   wsqc_pathr(   r-   modresults              r   
_run_checkr4   N   s     
{	BHHTDH)"2w
NKGK!#B@ <(3|,-

!
!"3
4CYYb'7|(3C$	  F Mr   tmp_pathc                    d}t        | t        d|      }|d   }d}||u }|st        j                  d|fd||f      t        j                  |      t        j                  |      dz  }t        j
                  d	|d    d
|j                  d             dz   d|iz  }t        t        j                  |            dx}x}}|d   }g }||k(  }|st        j                  d|fd||f      t        j                  |      t        j                  |      dz  }t        j
                  d|d          dz   d|iz  }t        t        j                  |            dx}x}}y)u5   JSON=PASS + frontmatter qc_verdict: PASS → ok=True.z7---
qc_verdict: PASS
---
# Report

## QC Verdict

PASS
PASSr"   r#   okTisz%(py1)s is %(py4)spy1py4zexpected ok=True but got ok=, violations=
violations
>assert %(py6)spy6N==z%(py1)s == %(py4)szexpected no violations but got 	r4   TASK_ID
@pytest_ar_call_reprcompare	_saferepr_format_assertmsggetAssertionError_format_explanationr5   reportr3   @py_assert0@py_assert3@py_assert2@py_format5@py_format7s           r   test_pass_pass_okrW   s   sY   	"  'f'-/F $< 4 <4  <4             'vd|nM&**\BZA[\     , 2 2%  2         $&    *&*>)?@     r   c                 p   d}t        | t        d|      }|d   }d}||u }|st        j                  d|fd||f      t        j                  |      t        j                  |      dz  }t        j
                  d	|d          d
z   d|iz  }t        t        j                  |            dx}x}}|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  }t        j
                  d|d          dz   d|iz  }t        t        j                  |            dx}x}x}
}	y)u   JSON=WARN + 보고서 본문 '## QC Verdict\n\nOVERALL PASS' → ok=False.

    WARN qc-result인데 보고서가 OVERALL PASS로 선언하는 불일치를 반드시 잡아야 한다.
    zA---
title: Some Report
---
# Report

## QC Verdict

OVERALL PASS
WARNr8   r9   Fr:   r<   r=   z=expected ok=False (WARN vs OVERALL PASS mismatch) but got ok=rB   rC   NrA   r   >)z/%(py4)s
{%(py4)s = %(py0)s(%(py2)s)
} > %(py7)slen)py0py2r?   py7z&expected at least 1 violation but got z
>assert %(py9)spy9)r4   rH   rI   rJ   rK   rL   rN   rO   r\   @py_builtinslocals_should_repr_global_name)r5   rQ   r3   rR   rS   rT   rU   rV   @py_assert1@py_assert6@py_assert5@py_format8@py_format10s                r   test_warn_overall_pass_failri      s   	*  'f'-/F $< 5 <5   <5        !    Ht~V     l# 3#$ q $q(  $q              $    %    ()    11E0FG     r   c           
      2   d}t        | t        d|ddi      }|d   }d}||u }|st        j                  d|fd||f      t        j                  |      t        j                  |      d	z  }t        j
                  d
|d    d|j                  d       d|j                  d             dz   d|iz  }t        t        j                  |            dx}x}}|j                  }d}g }	 |||	      }
g }|
|k(  }|st        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  }t        j
                  d|j                  d             dz   d|iz  }t        t        j                  |            dx}x}x}	x}
x}}y)uR   JSON=WARN + frontmatter PASS_WITH_WARN + 본문에 WARN 항목 명시 → ok=True.u   ---
qc_verdict: PASS_WITH_WARN
---
# Report

## QC Verdict

PASS_WITH_WARN

### WARN Items
- WARN: 테스트 커버리지 60% (목표 80% 미달)
rY   u   테스트 커버리지r"   r#   r   r9   Tr:   r<   r=   z?expected ok=True (WARN + PASS_WITH_WARN with items) but got ok=r@   rA   z, missing_warns=missing_warnsrB   rC   NrD   )zS%(py8)s
{%(py8)s = %(py2)s
{%(py2)s = %(py0)s.get
}(%(py4)s, %(py6)s)
} == %(py11)sr3   )r]   r^   r?   rC   py8py11z"expected no missing_warns but got z
>assert %(py13)spy13)r4   rH   rI   rJ   rK   rL   rM   rN   rO   ra   rb   rc   )r5   rQ   r3   rR   rS   rT   rU   rV   rd   rf   @py_assert7@py_assert10@py_assert9@py_format12@py_format14s                  r   test_warn_pass_with_warn_okru      s   	C  'f'-(@&'IKF $< 4 <4  	<4   	    	     Tl^=L1I0J KO45	7   	 
 :: o r :or* b *b0   *b                  &    (*    +    /1    -VZZ-H,IJ     r   c                 F   d}t        | t        d|ddi      }|d   }d}||u }|st        j                  d|fd||f      t        j                  |      t        j                  |      d	z  }t        j
                  d
|d          dz   d|iz  }t        t        j                  |            dx}x}}g }|j                  }	d}
g } |	|
|      }t        |      }d}||kD  }|}|s-|j                  }d}g } |||      }t        |      }d}||kD  }|}|st        j                  d|fd||f      dt        j                         v st        j                  t              rt        j                  t              nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |	      t        j                  |
      t        j                  |      t        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }|j                  |       |s9t        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                        t        j                        t        j                  |      t        j                  |      dz  }dd|iz  }|j                  |       t        j                  |d      i z  }t        j
                  d|j                  d       d|j                  d             dz   d |iz  }t        t        j                  |            dx}x}x}	x}
x}x}x}x}x}x}x}x}x}x}x}}y)!u[   JSON=WARN + frontmatter PASS_WITH_WARN 그러나 본문에 WARN 항목 없음 → ok=False.ux   ---
qc_verdict: PASS_WITH_WARN
---
# Report

## QC Verdict

PASS_WITH_WARN

모든 항목이 기준을 충족합니다.
rY      문서 업데이트rk   r9   Fr:   r<   r=   z@expected ok=False (PASS_WITH_WARN but no WARN items) but got ok=rB   rC   Nrl   r   rA   rZ   )zt%(py13)s
{%(py13)s = %(py2)s(%(py11)s
{%(py11)s = %(py5)s
{%(py5)s = %(py3)s.get
}(%(py7)s, %(py9)s)
})
} > %(py16)sr\   r3   )r^   py3py5r_   r`   rn   ro   py16z%(py18)spy18)zz%(py31)s
{%(py31)s = %(py20)s(%(py29)s
{%(py29)s = %(py23)s
{%(py23)s = %(py21)s.get
}(%(py25)s, %(py27)s)
})
} > %(py34)s)py20py21py23py25py27py29py31py34z%(py36)spy36   z;expected missing_warns or violations but got missing_warns=r@   z
>assert %(py39)spy39)r4   rH   rI   rJ   rK   rL   rN   rO   rM   r\   ra   rb   rc   append_format_boolop)r5   rQ   r3   rR   rS   rT   rU   rV   rd   @py_assert4re   @py_assert8rq   @py_assert12@py_assert15@py_assert14@py_assert22@py_assert24@py_assert26@py_assert28@py_assert30@py_assert33@py_assert32@py_format17@py_format19@py_format35@py_format37@py_format38@py_format40s                                r   +test_warn_pass_with_warn_missing_items_failr      s   	8  'f'-(=v'FHF $< 5 <5   <5        !   Tl^	%    vzz / 2 z/2. 3./ ! /!3 6:: l TV :lTV;W s;W7X [\ 7X[\7\   /!                            *    ,.    /    0    34     7X[\      8;    8;      <B    <B    <F    GS    UW    <X    8Y    \]       O45]6::lC[B\	^        r   c                    d}t        | t        d|      }|d   }d}||u }|st        j                  d|fd||f      t        j                  |      t        j                  |      dz  }t        j
                  d	|d    d
|j                  d             dz   d|iz  }t        t        j                  |            dx}x}}y)u   JSON=FAIL + 본문 '## QC Verdict\n\nOVERALL FAIL' + 사유 명시 → ok=True.

    FAIL verdict를 정직하게 보고서에도 기재하면 ok=True 여야 한다.
    ue   ---
qc_verdict: FAIL
---
# Report

## QC Verdict

OVERALL FAIL

사유: 핵심 테스트 3건 실패
FAILr8   r9   Tr:   r<   r=   z5expected ok=True (FAIL honestly reported) but got ok=r@   rA   rB   rC   NrG   rP   s           r   test_fail_overall_fail_okr      s    	1  'f'-/F $< 4 <4  <4            Tl^=L1I0J	L     r   c           
         d}t        | t        d|ddi      }|d   }d}||u }|st        j                  d|fd||f      t        j                  |      t        j                  |      d	z  }t        j
                  d
|d    d|j                  d       d|j                  d             dz   d|iz  }t        t        j                  |            dx}x}}y)u   인용 블록(> ...) 안의 가짜 OVERALL PASS 무시 — 실제 verdict PASS_WITH_WARN → ok=True.

    보고서에 '> 이전 표현: OVERALL PASS' 인용이 있어도
    실제 ## QC Verdict 섹션이 PASS_WITH_WARN이면 ok=True여야 한다.
    u   ---
qc_verdict: PASS_WITH_WARN
---
# Report

> 이전 표현: OVERALL PASS

## QC Verdict

PASS_WITH_WARN

### WARN Items
- WARN: 문서 업데이트 지연
rY   rw   rk   r9   Tr:   r<   r=   zDexpected ok=True (quoted OVERALL PASS should be ignored) but got ok=r@   rA   z, report_verdict=report_verdictrB   rC   NrG   rP   s           r    test_quoted_overall_pass_ignoredr     s    	/  'f'-(=v'FHF $< 4 <4  	<4   	    	     Tl^=L1I0J K **%567	9   	  r   c                    d}t        | t        d|      }|d   }d}||u }|st        j                  d|fd||f      t        j                  |      t        j                  |      dz  }t        j
                  d	|d          d
z   d|iz  }t        t        j                  |            dx}x}}g }|j                  }d}	 ||	      }
d}|
|u }|}|s|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  }|j                  |       |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  }|j                  |       t        j                  |d      i z  }t        j
                  d|j                  d             dz   d|iz  }t        t        j                  |            dx}x}x}x}	x}
x}x}x}x}x}x}}y)uW   frontmatter도 ## QC Verdict 섹션도 없으면 ok=False (보고서 정직성 강제).uF   # 그냥 보고서

작업 내용만 있고 QC Verdict 선언 없음.
r7   r8   r9   Fr:   r<   r=   z1expected ok=False (no verdict marker) but got ok=rB   rC   Nr    )zJ%(py8)s
{%(py8)s = %(py4)s
{%(py4)s = %(py2)s.get
}(%(py6)s)
} is %(py11)sr3   )r^   r?   rC   rm   rn   z%(py13)sro   rD   )zP%(py21)s
{%(py21)s = %(py17)s
{%(py17)s = %(py15)s.get
}(%(py19)s)
} == %(py24)s)py15py17py19r}   py24z%(py26)spy26r   z1expected report_verdict to be None/empty but got z
>assert %(py29)sr   )r4   rH   rI   rJ   rK   rL   rN   rO   rM   ra   rb   rc   r   r   )r5   rQ   r3   rR   rS   rT   rU   rV   rd   rf   rp   rq   rr   @py_assert16@py_assert18@py_assert20@py_assert23r   rs   rt   @py_format25@py_format27@py_format28@py_format30s                           r   test_no_verdict_marker_failr   #  s   	>  'f'-/F $< 5 <5   <5        !    <F4L>J    6:: & :&' 4 '4/ 6:: >N :>N3O SU 3OSU3U   '4                  '    (    ,0     3OSU      4:    4:    4>    ?O    4P    TV        <FJJGW<X;YZ       r   c                  B   t        j                  dt        t              dgddt        t                    } | 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  }t        j                  d
| j
                   d| j                   d| j                         dz   d|iz  }t        t        j                   |            dx}x}}| j                  | j                  z   fd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)u8   ./scripts/guard.sh --help → exit 0 + 사용법 출력.bashz--helpTcapture_outputtextcwdr   rD   z2%(py2)s
{%(py2)s = %(py0)s.returncode
} == %(py5)sr3   r]   r^   ry   z&expected exit 0 for --help but got rc=
stdout=
stderr=
>assert %(py7)sr_   Nc              3   B   K   | ]  }|j                         v   y wN)lower).0kwcombineds     r   	<genexpr>z%test_guard_sh_help.<locals>.<genexpr>F  s     ^"rX^^%%^s   )usageguardscopehelpu   사용z&Expected usage info in --help output:
z.
>assert %(py4)s
{%(py4)s = %(py0)s(%(py2)s)
}anyr]   r^   r?   )
subprocessrunr)   	_GUARD_SH
_WORKSPACE
returncoderI   rJ   ra   rb   rc   rK   rL   stdoutstderrrN   rO   r   )r3   rd   r   rS   @py_format6rg   rU   r   s          @r   test_guard_sh_helpr   9  s    ^^	Y*$
OF
   !                    !"    11B1B0C D--	&--	:     }}v}},H^0]^ 3^^ ^   2(<             _    _     r   c                     dD ]n  } t        j                  dt        t              | dgddt        t                    }|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  }t        j                  d|  d|j
                   d|j                   d|j                         dz   d|iz  }t        t        j                   |            dx}x}}d}|j                  }|j"                  } |       }	||	v }
|
st        j                  d|
fd||	f      t        j                  |      d	t        j                         v st        j                  |      rt        j                  |      nd	t        j                  |      t        j                  |      t        j                  |	      dz  }t        j                  d|  d|j                         dz   d|iz  }t        t        j                   |            dx}x}
x}x}}	q y)uA   guard.sh enqueue task-x → exit 2 + stderr에 'not implemented'.)enqueuezpre-taskz
merge-nextr   ztask-xTr      rD   r   r3   r   z	guard.sh z: expected exit 2 but got rc=r   r   r   r_   Nznot implemented)in)z`%(py1)s in %(py9)s
{%(py9)s = %(py7)s
{%(py7)s = %(py5)s
{%(py5)s = %(py3)s.stderr
}.lower
}()
})r>   rx   ry   r_   r`   z0: expected 'not implemented' in stderr but got:
z
>assert %(py11)srn   )r   r   r)   r   r   r   rI   rJ   ra   rb   rc   rK   rL   r   r   rN   rO   r   )cmdr3   rd   r   rS   r   rg   rR   re   r   rT   rh   rs   s                r   &test_guard_sh_phase2_3_not_implementedr   K  sL    5 
S^S(3dJ

    	
A 	
 A% 	
 	
 A 	
 	
 
6	
 	
   	
 	
 
	  	
 	
 
	 ! 	
 	
 
	 %& 	
 	
  u9&:K:K9L Mmm_Ifmm_>	
 	
 	
 	
 	
 ! 	
FMM 	
M$7$7 	
$7$9 	
 $99 	
 	
 $9 	
 	
 		 ! 	
 	
	6	
 	
  %+ 	
 	
 		 %+ 	
 	
 		 %2 	
 	
 		 %8 	
 	
 		 %: 	
 	
  uMfmm_]	
 	
 	
 	
 	
 	

r   c                 R   | dz  }|j                  dd       | dz  }|j                  dd       ddlm}  |d	t        |       t        |      t        |      
      }|d   }d}||u }|st	        j
                  d|fd||f      t	        j                  |      t	        j                  |      dz  }t	        j                  d|       dz   d|iz  }	t        t	        j                  |	            dx}x}}d |d   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}
}y)uK   JSON=PASS인데 보고서가 PASS_WITH_WARN이면 정직성 위반 — FAILqc.jsonz+{"qc_result": "PASS", "checks_summary": {}}r   r   	report.mduN   ---
qc_verdict: PASS_WITH_WARN
---
# 보고서

## QC Verdict

PASS with WARN
r   r/   test-xr%   r(   r'   r9   Fr:   r<   r=   u(   PASS+PASS_WITH_WARN 은 mismatch여야: rB   rC   Nc              3   $   K   | ]  }d |v  
 yw)MISMATCHN )r   vs     r   r   z9test_pass_pass_with_warn_mismatch_fail.<locals>.<genexpr>o  s     =1zQ=s   rA   z,assert %(py4)s
{%(py4)s = %(py0)s(%(py2)s)
}r   r   )r   r&   r/   r)   rI   rJ   rK   rL   rN   rO   r   ra   rb   rc   )r5   r1   r(   r/   r3   rR   rS   rT   rU   rV   rd   s              r   &test_pass_pass_with_warn_mismatch_failr   a  s0    "GDwW[(K`   &8s8}";/GNF$<U5U<5 UUU<5UUU<UUU5UUU$LVH"UUUUUUUU=|(<==3=========3===3==============r   c                    | dz  }|j                  dd       | dz  }|j                  dd       ddlm}  |d	t        |       t        |      t        |      
      }|d   }d}||u }|st	        j
                  d|fd||f      t	        j                  |      t	        j                  |      dz  }t	        j                  d|       dz   d|iz  }	t        t	        j                  |	            dx}x}}|d   }g }||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\   JSON=PASS일 때 missing_warns 분기 들어가지 않아도 UnboundLocalError 없이 동작r   z8{"qc_result": "PASS", "checks_summary": {"foo": "PASS"}}r   r   r   uB   ---
qc_verdict: PASS
---
# 보고서

## QC Verdict

OVERALL PASS
r   r   r   r   r9   Tr:   r<   r=   u   PASS+PASS는 OK여야: rB   rC   Nrl   rD   rF   zassert %(py6)s)
r   r&   r/   r)   rI   rJ   rK   rL   rN   rO   )
r5   r1   r(   r/   r3   rR   rS   rT   rU   rV   s
             r   7test_missing_warns_no_uncaught_exception_when_json_passr   r  s    "GQ\cd[(KT   &8s8}";/GNF$<C4C<4CCC<4CCC<CCC4CCC#:6(!CCCCCCCC/"(b("b(((("b((("(((b(((((((r   r   )r	   N))__doc__builtinsra   _pytest.assertion.rewrite	assertionrewriterI   r   r   r+   pathlibr   pytestr*   r   _GUARD_QC_PYr   rH   exists_QC_MISSING_SH_MISSINGmarkskipif_skip_qc_skip_shr)   dictr   r    r4   rW   ri   ru   r   r   r   r   r   r   r   r   r   r   r   <module>r      s  $    
  
 12)*
22j(	"
  &&((##%%;;F   ;;<   484 #  %)D[<@ s S T  .2D 3 "Tz  $d{ 7;J 
   
0 
$ 4  
6 
$ 4  
< 
$ 4  
< 
   
6 
t   
@ 
$ 4  
* 
 
" 

 

* 
>T >d > 
>  
)d )t ) 
)r   