
    ?# j;                     8   d 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  ZdZ	deddfd	Z
d$ded
ededefdZdedefdZ	 	 	 	 d%dededee   dz  dee   dz  dededz  deeef   fdZ	 	 d&dededededz  dee   dz  deeeef   fdZej'                          Zej*                  j-                  e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y)'u<  
test_pre_push_guard.py — pre_push_guard.py 회귀 테스트 (Guard MVP Phase 1, task-2434)

시나리오 (7개):
    1. test_clean_tree_scope_match_qc_match          — clean + scope 일치 + qc 일치 → rc=0
    2. test_modified_outside_scope_fail_b1            — task scope 외 파일 modified → rc=1 (B-1)
    3. test_behind_origin_fail_b2                     — HEAD behind base ref → rc=1 (B-2)
    4. test_forbidden_path_match_fail_b3              — head_diff에 forbidden_paths 매치 → rc=1 (B-3)
    5. test_qc_warn_report_overall_pass_fail_b4       — qc=WARN + 보고서=OVERALL PASS → rc=1 (B-4)
    6. test_normal_push_pass                          — 정상 push 케이스 → rc=0
    7. test_system_ignore_excluded_b1                 — memory/logs/*.log modified → system-ignore로 PASS
    N)Pathz/home/jay/workspace/scriptszpre_push_guard.pyztask-2434-testpathreturnc                 Z     dt         dd f fd} |d        |ddd        |ddd	       y )
Nargsr   c                  f    t        j                  ddt              gt        |       z   dd       y )Ngit-CTcheckcapture_output)
subprocessrunstrlist)r   r   s    R/home/jay/workspace/.worktrees/task-2537-dev4/tests/scripts/test_pre_push_guard.py_gz_init_git.<locals>._g#   s+    D#d)$tDz1t	
    initconfig
user.emailtest@test.com	user.nameTest)r   )r   r   s   ` r   	_init_gitr   "   s7    
# 
$ 

 vJx/xv&r   file_relcontentc           	         | |z  }|j                   j                  dd       |j                  |       t        j                  ddt        |       d|gdd       t        j                  ddt        |       ddd	| gdd       t        j                  ddt        |       d
dgddd      }|j                  j                         S )NTparentsexist_okr	   r
   addr   commitz-mzadd z	rev-parseHEADr   r   text)parentmkdir
write_textr   r   r   stdoutstrip)r   r   r   targetrs        r   _make_commitr.   -   s    H_F
MMt4
gNNE4TE8<d4NNE4THdd8*<MNd4	c$if54d	A 88>>r   c                     t        j                  ddt        |       dddgddd      }|j                  j	                         S )Nr	   r
   zrev-listz--max-parents=0r$   Tr%   )r   r   r   r*   r+   )r   r-   s     r   _get_first_shar0   <   s?    	c$i->G4d	A 88>>r   tmptask_idallowed_pathsforbidden_pathsqc_verdict_jsonreport_contentc                    | dz  }dD ]  }||z  j                  dd        ||xs ddg|xs g dd}|d	z  d
z  | dz  j                  t        j                  |      d       |d	z  dz  | dz  j                  d| dd       ||i d}	|d	z  dz  | dz  j                  t        j                  |	      d       ||d	z  dz  | dz  j                  |d       | dz  }
|
j                          t	        |
       ||
fS )u  
    tmp/workspace 구조 생성:
      memory/capabilities/<task_id>.json
      memory/tasks/<task_id>.md
      memory/events/<task_id>.qc-result
      memory/reports/<task_id>.md  (선택)
    또한 tmp/repo 에 최소 git repo 생성.
    반환: (workspace, repo)
    	workspace)zmemory/capabilitieszmemory/taskszmemory/eventszmemory/reportszmemory/logsTr   
scripts/**tests/**)pathsr4   )r2   allowed_resourcesmemorycapabilitiesz.jsonzutf-8)encodingtasksz.mdz# 
)r2   	qc_resultchecks_summaryeventsz
.qc-resultreportsrepo)r(   r)   jsondumpsr   )r1   r2   r3   r4   r5   r6   wsdcaprB   rF   s              r   _setup_workspacerL   D   sh    
{	B@ 4	atd34 "@|Z&@.4"
C (]^#	&77CC

3' D 
 (]W'#.::
WIR7 ; 
 $/UWXI(]X7): 66BB

9 C 
 !	h	"y_	4@@W 	A 	

 <DJJLdOt8Or   rI   rF   base_sha
extra_argsc           
         t         j                  t        t              d|dt        |       dt        |      g}|r|d|gz  }|r||z  }t	        j
                  |ddt        |             }|j                  |j                  |j                  fS )u:   pre_push_guard.py 실행 → (returncode, stdout, stderr).z	--task-idz--workspacez--cwdz
--base-shaT)r   r&   cwd)	sys
executabler   	_GUARD_PYr   r   
returncoder*   stderr)rI   rF   r2   rM   rN   cmdr-   s          r   
_run_guardrW   }   s    
 	IWs2wTC h''zs4dBHA<<188++r   z8pre_push_guard.py not yet implemented (Thor in progress))reasontmp_pathc                     d}t        | t        ddgd|      \  }}t        |d       t        |      }t        |d       t	        ||t        |      \  }}}|d	k(  sJ d
| d| d|        y)u<   clean working tree + scope 일치 + qc=PASS → rc=0 (PASS).z7---
qc_verdict: PASS
---
# Report

## QC Verdict

PASS
r9   r:   PASSr3   r5   r6   scripts/hello.pytests/test_hello.pyrM   r    expected PASS (rc=0) but got rc=
stdout=
stderr=NrL   TASK_IDr.   r0   rW   rY   reportrI   rF   rM   rcr*   rU   s           r   $test_clean_tree_scope_match_qc_matchrh      s    	"   '#Z0	HB )*d#H,- $BgIB7 
*2$ixyQ7r   c                    t        | t        ddgd      \  }}t        |d       t        |      }t        |d       |dz  dz  }|j                  j                  d	d	
       |j                  d       t        j                  ddt        |      ddgd	d	       t        ||t        |      \  }}}|dk(  sJ d| d| d|        ||z   }d|v s0d|j                         v sd|j                         v s
J d|        yyy)uE   task scope 외 파일이 working tree에 modified → B-1 FAIL, rc=1.r9   r:   r[   r3   r5   r]   r^   	extensionzfoo.jsTr   z	modified
r	   r
   r"   zextension/foo.jsr   r_      z%expected FAIL (rc=1, B-1) but got rc=ra   rb   zB-1workingdirtyz2Expected B-1 / dirty / working mention in output:
N)rL   rd   r.   r0   r'   r(   r)   r   r   r   rW   lower)	rY   rI   rF   rM   out_of_scoperg   r*   rU   combineds	            r   #test_modified_outside_scope_fail_b1rr      s1     '#Z0HB )*d#H,- +%0LdT:L)NN	c$i(:;4 $BgIB7 
/t9VHIfXV7 HH	X^^-= =HNNL\A\ 
=hZH\A\ =r   c                    t        | t        dgd      \  }}| dz  }t        j                  ddddt	        |      gd	d	
       t        |d       t        |      }t        j                  ddt	        |      dddt	        |      gd	d	
       t        j                  ddt	        |      ddddgd	d	
       | dz  }t        j                  ddt	        |      t	        |      gd	d	
       t        j                  ddt	        |      dddgd	d	
       t        j                  ddt	        |      dddgd	d	
       t        |d       t        j                  ddt	        |      dddgd	d	
       t        ||t        |      \  }}}|dk(  sJ d| d| d|        ||z   }	d|	v s0d |	j                         v sd!|	j                         v s
J d"|	        y#y#y#)$u   base_sha 이후 HEAD가 뒤처진 상황 → B-2 FAIL, rc=1.

    실제 'behind origin' 상태를 흉내 내기 위해:
    origin 역할의 bare repo를 만들고 origin에 추가 커밋을 push한 후
    로컬을 fetch 없이 HEAD 고정.
    r9   r[   rj   z
origin.gitr	   r   z--barez--initial-branch=mainTr   scripts/a.pyr
   remoter"   originpushz-uz	HEAD:maincloner   r   r   r   r   zscripts/origin_extra.pyr_   rl   z%expected FAIL (rc=1, B-2) but got rc=ra   rb   zB-2behindaheadz1Expected B-2 / behind / ahead mention in output:
N)	rL   rd   r   r   r   r.   r0   rW   ro   )
rY   rI   rF   rv   rM   rx   rg   r*   rU   rq   s
             r   test_behind_origin_fail_b2r{      s     '#nHB $FNN	"93v;G4
 ~&d#HNN	c$i5(CKH4 NN	c$ixE4 wENN	Vc%j14 NN	c%j(L/J4 NN	c%j(K@4 12NN	c%j&(K@4 $BgIB7 
/t9VHIfXV7 HHHNN,< <8>>K[@[ 
<XJG[@[ <r   c                 N   t        | t        ddgddgd      \  }}t        |d       t        |      }t        |dd	       t	        ||t        |
      \  }}}|dk(  sJ d| d| d|        ||z   }d|v s0d|j                         v sd|j                         v s
J d|        yyy)uL   head_diff에 forbidden_paths 패턴 매칭 파일 포함 → B-3 FAIL, rc=1.r9   r:   zscripts/finish-task.shzscripts/auto_merge.pyr[   )r3   r4   r5   zscripts/safe.pyz#!/bin/bash
echo hi
)r   r_   rl   z%expected FAIL (rc=1, B-3) but got rc=ra   rb   zB-3	forbiddenscopez4Expected B-3 / forbidden / scope mention in output:
NrL   rd   r.   r0   rW   ro   )rY   rI   rF   rM   rg   r*   rU   rq   s           r   !test_forbidden_path_match_fail_b3r   )  s      '#Z013JK	HB ()d#H/9QR#BgIB7 
/t9VHIfXV7 HHx~~/? ?7hnnN^C^ 
?zJ^C^ ?r   c                 H   d}t        | t        dgd|      \  }}t        |d       t        |      }t        |d       t	        ||t        |      \  }}}|dk(  sJ d	| d
| d|        ||z   }d|v s0d|j                         v sd|j                         v s
J d|        yyy)u   qc-result=WARN + 보고서 본문에 'OVERALL PASS' → B-4 FAIL, rc=1.

    task-2431 사고 재발 방지 회귀 가드.
    z<---
title: Report
---
# Report

## QC Verdict

OVERALL PASS
r9   WARNr\   rt   scripts/b.pyr_   rl   z%expected FAIL (rc=1, B-4) but got rc=ra   rb   zB-4qcwarnz,Expected B-4 / qc / warn mention in output:
Nr   )	rY   rf   rI   rF   rM   rg   r*   rU   rq   s	            r   (test_qc_warn_report_overall_pass_fail_b4r   F  s    	*   '#n	HB ~&d#H~&#BgIB7 
/t9VHIfXV7 HH(8 8FhnnFV<V 
7zBV<V 8r   c                     d}t        | t        ddgg d|      \  }}t        |d       t        |      }t        |d       t	        ||t        |      \  }}}|d	k(  sJ d
| d| d|        y)uO   정상 push 가능 케이스: clean tree + scope 내 커밋 + qc=PASS → rc=0.----
qc_verdict: PASS
---
## QC Verdict

PASS
r9   r:   r[   )r3   r4   r5   r6   zscripts/util.pyztests/test_util.pyr_   r   r`   ra   rb   Nrc   re   s           r   test_normal_push_passr   m  s    	"   '#Z0HB ()d#H+, $BgIB7 
*2$ixyQ7r   c                 4   d}t        | t        dgd|      \  }}t        |d       t        |      }t        |d       |dz  dz  }|j	                  d	d	
       |dz  j                  d       t        ||t        |      \  }}}|dk(  sJ d| d| d|        y)u   memory/logs/*.log 만 dirty → SYSTEM_IGNORE_PATTERN 적용으로 B-1 무시, rc=0.

    memory/logs/ 는 SYSTEM_IGNORE_PATTERN에 포함되므로 working tree dirty로
    처리하지 않아야 한다.
    r   r9   r[   r\   rt   r   r=   logsTr   zfoo.logzlog content
r_   r   z3expected PASS (rc=0, system-ignore log) but got rc=ra   rb   N)rL   rd   r.   r0   r(   r)   rW   )	rY   rf   rI   rF   rM   log_dirrg   r*   rU   s	            r   test_system_ignore_excluded_b1r     s    	"   '#n	HB ~&d#H~& Xo&GMM$M.y$$_5 $BgIB7 
=bT B6(	,7r   )zdata
)NNr[   N)NN)__doc__rG   r   rQ   pathlibr   pytest_SCRIPTS_DIRrS   rd   r   r   r.   r0   r   tuplerL   intrW   exists_GUARD_MISSINGmarkskipif_skip_if_missingrh   rr   r{   r   r   r   r    r   r   <module>r      sf     
  
 1211	'D 'T 't s S   #  8<9=,226	6$ 6 6$(I$46&*3i$&66 '*6 &)4Z	6 <At;L	6t '+.2,4 ,t ,c ,t,9t+,7<S#s]7K,. %%'';;%%E &   4 D  B $ 4  H < <$ < <F    8 t   L D T  > "T "d " "r   