
    jy/              	          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
Z
ddlZddlmZ ddlZ ee      j!                         j"                  d   Zedz  dz  Zedz  dz  Zdded	edz  d
e
j.                  fdZd ded	eded
e
j.                  fdZ ej6                         d        Zd Zd Zd Zd Z d Z!d Z"d Z#d Z$d Z%d Z&d Z'd Z(d Z)d Z*d Z+d Z,y)!u  
regression: test_stash_origin_audit_compat.py
task: task-2570 TODO-4
작성자: 하누만(테스터)

검증 목표:
1. 기존/unknown stash가 'unknown'으로 fallback 분류되는지 검증
2. finish-task.sh가 stash_audit.py 미존재 환경에서도 동작하는지 검증
   (bash -n 통과 + `if [ -x` 조건문 존재)
3. 기존 _STASH_AUDIT_BEFORE / _STASH_AUDIT_AFTER 변수 + cleanup-audit.jsonl 경로 보존
   (task-2569 호환성)
    N)Path   scriptszstash_audit.pyzfinish-task.shargscwdreturnc                     t         j                  t        t              g| z   }t	        j
                  |dd|xs t        t                    S )u   stash_audit.py 호출 helper.T)capture_outputtextr   )sys
executablestrSTASH_AUDIT_PY
subprocessrunWORKTREE_ROOT)r   r   cmds      F/home/jay/workspace/tests/regression/test_stash_origin_audit_compat.py
_run_auditr       sA    >>3~.
/$
6C>>%3}%	     checkc                     t         j                  j                         }d|d<   d|d<   d|d<   d|d<   t        j                  dg| z   |dd||	      S )
u$   git 명령 helper (tmp repo 전용).testGIT_AUTHOR_NAMEtest@test.comGIT_AUTHOR_EMAILGIT_COMMITTER_NAMEGIT_COMMITTER_EMAILgitT)r   r
   r   r   env)osenvironcopyr   r   )r   r   r   r    s       r   _gitr$   +   sg    
**//
C#C-C &C!0C>>	$ r   c                 F   t        |       }t        g d|       t        g d|       t        g d|       t        g d|       g d}t        |      D ]G  \  }}d| d}| |z  }|j                  d	| d
d       t        d|g|       t        ddd|g|       I |S )uP   
    패턴 매칭이 안 되는 unknown stash만 있는 isolated git repo.
    initz-bmainr   configz
user.emailr   r+   z	user.namer   )commit--allow-empty-mzinit: initial commit)zsome random work in progresszbackup before experimentztemp save 2026-05-14unknown_z.txtzcontent 
utf-8encodingaddstashpushr/   )r   r$   	enumerate
write_text)tmp_pathrepounknown_messagesimsgfnamefpaths          r   repo_with_unknown_stashrA   <   s    
 x=D	T*	2=	(d3	BM
 ,- 531#T"5 8A3b)G<eU^&gvtS)t45 Kr   c                    t        dd| g      }|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	z   d
|iz  }t        t        j                  |            dx}x}}t        j                  |j                        }|j                  d|j                  dg             }t!        |      }	d}
|	|
kD  }|st        j                  d|fd|	|
f      dt	        j
                         v st        j                  t               rt        j                  t               nddt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |	      t        j                  |
      dz  }t        j                  d      dz   d|iz  }t        t        j                  |            dx}	x}}
|D cg c]  }|j                  d       }}|D cg c]
  }|dk7  s	| }}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|       dz   d|iz  }t        t        j                  |            dx}	x}}
yc c}w c c}w )ue   
    표준 패턴을 따르지 않는 stash는 'unknown'으로 fallback 분류되어야 한다.
    --json--workspacer   ==z2%(py2)s
{%(py2)s = %(py0)s.returncode
} == %(py5)sresultpy0py2py5u%   stash_audit.py 실행 실패
stderr: 
>assert %(py7)spy7Nentriesstashes)>)z/%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} > %(py6)slenrJ   py1py3py6u   entries가 비어있음
>assert %(py8)spy8sourceunknown)z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)snon_unknownu$   unknown 외의 분류가 존재함: u   
전체 sources: )r   
returncode
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_saferepr_format_assertmsgstderrAssertionError_format_explanationjsonloadsstdoutgetrR   )rA   rH   @py_assert1@py_assert4@py_assert3@py_format6@py_format8datarO   @py_assert2@py_assert5@py_format7@py_format9esourcessr[   s                    r   *test_unknown_stash_fallback_classificationrx   [   s    =2IJKF  !                    !"    1@     ::fmm$Dhhy$((9b"9:Gw<6!6<!666<!66666636663666666w666w666<666!66666666666(/01quuX0G0%8i18K8{ q q    q                             !    /{m <")	%      18s   &O
OOc                    t        dd| g      }|j                  }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd	|iz  }t        t        j                  |            d
x}x}}t        j                  |j                        }|j                  di       j                  di       }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}	}
|d   }	d}|	|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
)uF   summary.count_by_source에 'unknown' 카테고리가 있어야 한다.rC   rD   r   rE   rG   rH   rI   assert %(py7)srN   Nsummarycount_by_sourcerZ   inz%(py1)s in %(py3)srT   rU   u(   count_by_source에 'unknown'이 없음: 
>assert %(py5)srL      >=)z%(py1)s >= %(py4)s)rT   py4u   unknown count가 3 미만: z
>assert %(py6)srV   r   r\   r]   r^   r_   r`   ra   rb   re   rf   rg   rh   ri   rj   rc   )rA   rH   rk   rl   rm   rn   ro   rp   r|   @py_assert0rq   @py_format4@py_format5rs   s                 r   .test_unknown_stash_count_by_source_has_unknownr   p   s   =2IJKF!!!!!!!!!!!!6!!!6!!!!!!!!!!!!!::fmm$Dhhy"-112CRHO 9'  9          (    (    3?2CD     9%  %*  %    &    *+    &oi&@%AB     r   c                 >   t        |       }t        g d|       t        g d|       t        g d|       t        g d|       t        dd|g      }|j                  }d}||k(  }|st	        j
                  d	|fd
||f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |      dz  }dd|iz  }t        t	        j                  |            dx}x}}t        j                  |j                        }|j                  d|j                  dg             }	g }
|	|
k(  }|st	        j
                  d	|fd|	|
f      dt        j                         v st	        j                  |	      rt	        j                  |	      ndt	        j                  |
      dz  }t	        j                   d|	       dz   d|iz  }t        t	        j                  |            dx}}
y)uV   
    stash가 없는 repo에서 실행 시 entries가 빈 리스트여야 한다.
    r&   r)   r*   r,   )r-   r.   r/   r'   rC   rD   r   rE   rG   rH   rI   rz   rN   NrO   rP   )z%(py0)s == %(py3)s)rJ   rU   u;   stash가 없는 repo에서 entries가 비어있지 않음: r   rL   )r   r$   r   r\   r]   r^   r_   r`   ra   rb   re   rf   rg   rh   ri   rj   rc   )r:   r;   rH   rk   rl   rm   rn   ro   rp   rO   rq   r   s               r    test_empty_repo_unknown_fallbackr   ~   s    x=D	T*	2=	(d3	2==$78F!!!!!!!!!!!!6!!!6!!!!!!!!!!!!!::fmm$Dhhy$((9b"9:G 7b=  7b                  FgYO    r   c           	         t        dd| g      }|j                  }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd	|iz  }t        t        j                  |            d
x}x}}t        j                  |j                        }|j                  d|j                  dg             }|D ]>  }	|	j                  d      dk(  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  }t        j                  d|	j                  d             dz   d|iz  }t        t        j                  |            d
x}x}x}
x}}A y
)uL   unknown으로 분류된 stash의 caller_script는 'unknown'이어야 한다.rC   rD   r   rE   rG   rH   rI   rz   rN   NrO   rP   rY   rZ   caller_script)zI%(py6)s
{%(py6)s = %(py2)s
{%(py2)s = %(py0)s.get
}(%(py4)s)
} == %(py9)sentry)rJ   rK   r   rV   py9u8   unknown source의 caller_script가 'unknown'이 아님: z
>assert %(py11)spy11r   )rA   rH   rk   rl   rm   rn   ro   rp   rO   r   rr   @py_assert8@py_assert7@py_format10@py_format12s                  r   +test_unknown_stash_caller_script_is_unknownr      s   =2IJKF!!!!!!!!!!!!6!!!6!!!!!!!!!!!!!::fmm$Dhhy$((9b"9:G 99X)+99 _ 9_-  -:  -   v      I    I    I -   I .   I 2;    K99_-.0     r   c                  8   t        j                  ddt        t              gdd      } | 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t               dz   d|iz  }t        t        j                  |            dx}x}}y)uL   
    finish-task.sh가 bash -n (문법 검사) 를 통과해야 한다.
    bashz-nT)r
   r   r   rE   rG   rH   rI   u%   bash -n 문법 검사 실패
stderr: u	   
파일: rM   rN   N)r   r   r   FINISH_TASK_SHr\   r]   r^   r_   r`   ra   rb   rc   rd   re   rf   )rH   rk   rl   rm   rn   ro   s         r   %test_finish_task_sh_bash_syntax_checkr      s    ^^	s>*+F
   !  	   	  	    	    	    	 !"   ==/ "!"	$   	  r   c                  V   t         j                  d      } t        j                  d      }|j                  } ||       }|st        j                  d      dz   dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      dz  }t        t        j                  |            d	x}}y	)
u   
    finish-task.sh에 `if [ -x ... stash_audit.py ]` 패턴이 존재해야 한다.
    stash_audit.py가 없어도 graceful하게 동작함을 보장.
    r2   r3    if\s+\[\s+-x\s+.*stash_audit\.pyu   finish-task.sh에 `if [ -x ... stash_audit.py ]` 조건문이 없음
stash_audit.py 미존재 환경에서 스크립트가 실패할 수 있음J
>assert %(py5)s
{%(py5)s = %(py2)s
{%(py2)s = %(py0)s.search
}(%(py3)s)
}patterncontentrJ   rK   rU   rL   N)r   	read_textrecompilesearchr]   rc   r_   r`   ra   rb   re   rf   r   r   rk   rl   rn   s        r   2test_finish_task_sh_has_if_x_guard_for_stash_auditr      s    
 &&&8Gjj<=G>> >'" "  	U                   "    "    #     r   c                     t         j                  d      } t        j                  d      }|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
t        |       d      dz   d|iz  }t        t        j                  |            dx}x}}y)ui   
    `if [ -x ... stash_audit.py ]` 가드가 최소 2번 (BEFORE/AFTER 각각) 존재해야 한다.
    r2   r3   r   r   r   )z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} >= %(py6)srR   matchesrS   u)   `if [ -x ... stash_audit.py ]` 가드가 uX   번만 존재 (최소 2번 필요)
BEFORE/AFTER 블록 각각에 가드가 있어야 함rW   rX   N)r   r   r   r   findallrR   r]   r^   r_   r`   ra   rb   rc   re   rf   )r   r   r   rq   rr   rl   rs   rt   s           r   3test_finish_task_sh_stash_audit_guard_appears_twicer      s=    &&&8Gjj<=Goog&Gw< 1 <1   <1                                4CL> B@ 	A     r   c                     t        j                  g dt        t              dd      } | j                  j                         r1t        | j                  j                         j                               nd}t        ddt        t              g       t        j                  g dt        t              dd      }|j                  j                         r1t        |j                  j                         j                               nd}||k(  }|st        j                  d|fd||f      d	t        j                         v st        j                  |      rt        j                  |      nd	d
t        j                         v st        j                  |      rt        j                  |      nd
dz  }t        j                  d| d| d      dz   d|iz  }t!        t        j"                  |            d}y)u   
    stash_audit.py 호출이 실제 워크스페이스 stash에 side effect를 주지 않는지 검증.
    (pop/drop 금지 — 호출 전후 stash count 동일해야 함)
    )r   r6   listT)r   r
   r   r   rC   rD   rE   )z%(py0)s == %(py2)sbefore_countafter_count)rJ   rK   u2   stash_audit.py 실행 후 stash 수가 변경됨: u    → u-   
read-only 원칙 위반 (pop/drop 가능성)z
>assert %(py4)sr   N)r   r   r   r   ri   striprR   
splitlinesr   r]   r^   r_   r`   ra   rb   rc   re   rf   )before_resultr   after_resultr   rk   @py_format3r   s          r   >test_stash_audit_callable_without_workspace_stash_side_effectsr      s    NN 	M FSEYEYE_E_Ea3}++113>>@AghL -]);<= >> 	L DPCVCVC\C\C^#l))//1<<>?deK;&  <;                '    '    =\N%P[} ]7 	8    r   c                     t         j                  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  }t        j                  d      d	z   d
|iz  }t        t        j                  |            dx}}y)uf   
    task-2569 호환성: _STASH_AUDIT_BEFORE 변수가 finish-task.sh에 보존되어야 한다.
    r2   r3   _STASH_AUDIT_BEFOREr}   r   r   r   uS   finish-task.sh에 _STASH_AUDIT_BEFORE 변수가 없음 (task-2569 호환성 깨짐)r   rL   Nr   r   r]   r^   rb   r_   r`   ra   rc   re   rf   r   r   rq   r   rn   s        r   9test_finish_task_sh_stash_audit_before_variable_preservedr           &&&8G   G+   G    !      %,    %,    	^    r   c                     t         j                  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  }t        j                  d      d	z   d
|iz  }t        t        j                  |            dx}}y)ue   
    task-2569 호환성: _STASH_AUDIT_AFTER 변수가 finish-task.sh에 보존되어야 한다.
    r2   r3   _STASH_AUDIT_AFTERr}   r   r   r   uR   finish-task.sh에 _STASH_AUDIT_AFTER 변수가 없음 (task-2569 호환성 깨짐)r   rL   Nr   r   s        r   8test_finish_task_sh_stash_audit_after_variable_preservedr      s     &&&8G 7*  7           $+    $+    	]    r   c                     t         j                  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  }t        j                  d      d	z   d
|iz  }t        t        j                  |            dx}}y)uf   
    task-2569 호환성: cleanup-audit.jsonl 경로가 finish-task.sh에 보존되어야 한다.
    r2   r3   zcleanup-audit.jsonlr}   r   r   r   uS   finish-task.sh에 cleanup-audit.jsonl 경로가 없음 (task-2569 호환성 깨짐)r   rL   Nr   r   s        r   6test_finish_task_sh_cleanup_audit_jsonl_path_preservedr     r   r   c                     t         j                  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  }t        j                  d      d	z   d
|iz  }t        t        j                  |            dx}}y)uh   
    finish-task.sh의 BEFORE 블록이 'audit': 'finish-task-start' 포맷을 포함해야 한다.
    r2   r3   zfinish-task-startr}   r   r   r   u>   BEFORE 블록에 'finish-task-start' audit 레코드가 없음r   rL   Nr   r   s        r   *test_finish_task_sh_audit_start_log_formatr     s     &&&8G ')  '          #*    #*    	I    r   c                     t         j                  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  }t        j                  d      d	z   d
|iz  }t        t        j                  |            dx}}y)ue   
    finish-task.sh의 AFTER 블록이 'audit': 'finish-task-end' 포맷을 포함해야 한다.
    r2   r3   zfinish-task-endr}   r   r   r   u;   AFTER 블록에 'finish-task-end' audit 레코드가 없음r   rL   Nr   r   s        r   (test_finish_task_sh_audit_end_log_formatr     s     &&&8G '            !(    !(    	F    r   c                     t         j                  d      } t        j                  d      }|j                  } ||       }|st        j                  d      dz   dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      dz  }t        t        j                  |            d	x}}g }d
}|| v }|}|rd}| j                  } |       }	||	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  }|j                  |       |rt        j                  d
fd	f      t        j                  |      dt        j                         v st        j                  |       rt        j                  |       ndt        j                        t        j                  |	      dz  }dd|iz  }|j                  |       t        j                   |d      i z  }t        j                  d      dz   d|iz  }t        t        j                  |            d	x}x}x}x}x}x}
x}}	y	)ue   
    finish-task.sh에 stash 5개 초과 시 WARN 로직이 있어야 한다 (task-2569 호환).
    r2   r3   z-gt\s+5u@   finish-task.sh에 stash 5개 초과 WARN 조건(-gt 5)이 없음r   r   r   r   NWARNr6   r}   )z%(py3)s in %(py5)s)rU   rL   z%(py7)srN   )zJ%(py10)s in %(py16)s
{%(py16)s = %(py14)s
{%(py14)s = %(py12)s.lower
}()
})py10py12py14py16z%(py18)spy18r   u7   finish-task.sh에 stash 과다 WARN 메시지가 없음z
>assert %(py21)spy21)r   r   r   r   r   r]   rc   r_   r`   ra   rb   re   rf   lowerr^   append_format_boolop)r   r   rk   rl   rn   rq   r   @py_assert9@py_assert13@py_assert15@py_assert11ro   @py_format17@py_format19@py_format20@py_format22s                   r   7test_finish_task_sh_stash_before_greater_than_five_warnr   $  s    &&&8Gjj$G>> >'" "   	K                   "    "    #     6 6W  GMM MO O!;   6W                   O    ")      -4    -4    -:    -<        	B      r   c                  t   t         j                  d      } t        j                  dt        j                        }|j
                  } ||       }|st        j                  d      dz   dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      dz  }t        t        j                  |            d	x}}y	)
u[   
    _STASH_AUDIT_BEFORE가 `git stash list | wc -l` 형태로 할당되어야 한다.
    r2   r3   z9_STASH_AUDIT_BEFORE\s*=\s*\$\(.*git stash list.*wc -l.*\)uM   _STASH_AUDIT_BEFORE가 `git stash list | wc -l` 형태로 할당되지 않음r   r   r   r   Nr   r   r   r   DOTALLr   r]   rc   r_   r`   ra   rb   re   rf   r   s        r   1test_finish_task_sh_stash_count_assignment_beforer   3  s    &&&8GjjD
		G >> >'" "   	X                   "    "    #     r   c                  t   t         j                  d      } t        j                  dt        j                        }|j
                  } ||       }|st        j                  d      dz   dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      dz  }t        t        j                  |            d	x}}y	)
uZ   
    _STASH_AUDIT_AFTER가 `git stash list | wc -l` 형태로 할당되어야 한다.
    r2   r3   z8_STASH_AUDIT_AFTER\s*=\s*\$\(.*git stash list.*wc -l.*\)uL   _STASH_AUDIT_AFTER가 `git stash list | wc -l` 형태로 할당되지 않음r   r   r   r   Nr   r   s        r   0test_finish_task_sh_stash_count_assignment_afterr   B  s    &&&8GjjC
		G >> >'" "   	W                   "    "    #     r   )N)T)-__doc__builtinsr_   _pytest.assertion.rewrite	assertionrewriter]   rg   r!   r   r   r   pathlibr   pytest__file__resolveparentsr   r   r   r   r   CompletedProcessr   boolr$   fixturerA   rx   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r    r   r   <module>r      s     	 	  
  X&&(003*-==*-==T d
 j6Q6Q t # d j6Q6Q "  <*&$ 
Hr   