
    if                        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mZmZ ddlZe	j                   j#                  d e ee      j(                  j(                               ddlZdZdZdZdZdd	ed
efdZded	ed
efdZ G d d      Z G d d      Z G d d      Z G d d      Z  G d d      Z! G d d      Z" G d d      Z#y)ua  Tests for passive-feedback.py - TDD RED phase (구현체 없음, 테스트만 작성).

1. test_snapshot_save: snapshot 저장 → 파일 존재 + 내용 + 메타데이터 확인
2. test_detect_diff_normal: diff 정상 추출 + passive-diffs.jsonl 기록 확인
3. test_detect_whitespace_only: 공백만 변경 시 None 반환
4. test_learning_extraction: learning → learnings.jsonl에 jay-feedback source 저장
5. test_history: get_history → passive-diffs.jsonl 정상 반환
6. test_ai_call_mocking: anthropic SDK 모킹 검증
7. test_snapshot_path_auto_creation: 디렉토리 없어도 자동 생성
    N)Path)	MagicMockpatchzsatori-cardnewsu+   상담 예약하기
지금 신청하세요
u,   지금 무료 상담
지금 신청하세요
u-   상담 예약하기  
지금 신청하세요
textreturnc                 L    t               }| |_        t               }|g|_        |S )N)r   r   content)r   r	   resps      :/home/jay/workspace/scripts/tests/test_passive_feedback.py_ai_mockr      s%    kGGL;D9DLK    pathc                 ,    | j                  |d       | S )Nutf-8encoding)
write_text)r   r   s     r   _writer   &   s    OOD7O+Kr   c                       e Zd ZdeddfdZy)TestSnapshotSavetmp_pathr   Nc                 z   t        |      t        j                  d<   t        |dz  t              }t        j                  t        t        |      d      }t        |d         }|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}}|j"                  }d	} ||
      }|t        k(  }	|	st        j$                  d|	fd|t        f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      dt        j                         v st        j                  t              rt        j                  t              nddz  }
dd|
iz  }t        t        j                   |            d x}x}x}}	|d   }|t        k(  }|st        j$                  d|fd|t        f      t        j                  |      dt        j                         v st        j                  t              rt        j                  t              nddz  }dd|iz  }t        t        j                   |            d 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   }|s8ddt        j                  |      iz  }t        t        j                   |            d }y )NWORKSPACE_ROOT
source.txttask-001)
skill_name	file_pathtask_idsnapshot_pathAassert %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.exists
}()
}snappy0py2py4r   r   ==)zX%(py6)s
{%(py6)s = %(py2)s
{%(py2)s = %(py0)s.read_text
}(encoding=%(py4)s)
} == %(py8)sORIGINALr#   r$   r%   py6py8assert %(py10)spy10r   z%(py1)s == %(py3)sSKILLpy1py3assert %(py5)spy5r   z%(py1)s == %(py4)sr1   r%   assert %(py6)sr*   	timestampzassert %(py1)sr1   )strosenvironr   r(   pfsave_snapshotr/   r   exists@py_builtinslocals
@pytest_ar_should_repr_global_name	_safereprAssertionError_format_explanation	read_text_call_reprcompare)selfr   srcresultr!   @py_assert1@py_assert3@py_format5@py_assert5@py_assert7@py_format9@py_format11@py_assert0@py_assert2@py_format4@py_format6@py_format7@py_format2s                     r   test_snapshot_savez#TestSnapshotSave.test_snapshot_save,   s(   '*8}

#$X,h7!!Uc#hPZ[F?+,{{{}}tt{}~~;w;~w/;/8;;;;/8;;;;;;t;;;t;;;~;;;w;;;/;;;;;;8;;;8;;;;;;;l#,#u,,,,#u,,,#,,,,,,u,,,u,,,,,,,i .J. J.... J... ...J.......k"""""""""""""r   )__name__
__module____qualname__r   rX    r   r   r   r   +   s    #4 #D #r   r   c                       e Zd ZdeddfdZy)TestDetectDiffNormalr   r   Nc                 &   t        |      t        j                  d<   t        |dz  t              }t        |dz  t
              }t        d      5 }t               }||j                  _	        t               |j                  j                  _	        t        j                  t        t        |      t        |      d      }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z  dz  t        z  dz  }|j0                  } |       }|sddt%        j&                         v st!        j(                  |      rt!        j*                  |      ndt!        j*                  |      t!        j*                  |      dz  }t-        t!        j.                  |            d x}}|j3                  d      j5                         j7                         D cg c]  }t9        j:                  |       }}t=        |      }d}||k(  }|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*                  |      dz  }dd|iz  }t-        t!        j.                  |            d x}x}}|d   }|d   }|t        k(  }|st!        j"                  d|fd|t        f      t!        j*                  |      d t%        j&                         v st!        j(                  t              rt!        j*                  t              nd d!z  }	dd|	iz  }
t-        t!        j.                  |
            d 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'}||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*                  |      d0z  }
t-        t!        j.                  |
            d x}}y # 1 sw Y   GxY wc c}w )1Nr   orig.txtmod.txtpassive_feedback.anthropictask-002r   )is not)z%(py0)s is not %(py3)srJ   r#   r2   r3   r4   memoryskill-feedbackpassive-diffs.jsonlr    	diff_filer"   r   r      r&   z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)slenrecordsr#   r1   r2   r*   assert %(py8)sr+   r   r   r.   r/   r0   r   r5   r6   r7   r*   r8   in)z%(py1)s in %(py3)srecdiff_summary
diff_linesz5assert %(py5)s
{%(py5)s = %(py0)s(%(py2)s, %(py3)s)
}
isinstancelist)r#   r$   r2   r4   )!r9   r:   r;   r   r(   MODIFIEDr   r   	Anthropicreturn_valuer   messagescreater<   detect_diffr/   rA   rG   r?   r@   rB   rC   rD   rE   r>   rF   strip
splitlinesjsonloadsrm   rv   rw   )rH   r   origmod	mock_anthclientrJ   rS   rK   rT   rU   rj   rL   rM   lrn   rN   @py_assert4rV   rP   rs   rR   s                         r   test_detect_diff_normalz,TestDetectDiffNormal.test_detect_diff_normal;   s*   '*8}

#$h+X6X	)84/0 	TI[F/5I,2:*FOO""/^^E3t9c#h
SF		T "!vT!!!!vT!!!!!!v!!!v!!!T!!!!!!!x'*::UBEZZ	!!!!!!!!!y!!!y!!!!!!!!!!!!!*3*=*=w*=*O*U*U*W*b*b*deQ4::a=ee7| q |q    |q      s   s      7   7   |   q       aj< ) E)))) E))) ))))))E)))E)))))))9~++~++++~+++~++++++++++!{c!!!!{c!!!{!!!!!!c!!!c!!!!!!!$~$$$$~$$$~$$$$$$$$$$$$$$$$l+2z+T22222222z222z222+222222T222T2222222222#	T 	T fs   A.\\\)rY   rZ   r[   r   r   r\   r   r   r^   r^   :   s    3 3 3r   r^   c                       e Zd ZdeddfdZy)TestDetectWhitespaceOnlyr   r   Nc                 ,   t        |      t        j                  d<   t        |dz  t              }t        |dz  t
              }t        j                  t        t        |      t        |            }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}}y )
Nr   r`   ra   is)z%(py0)s is %(py3)srJ   rf   r3   r4   )r9   r:   r;   r   r(   WHITESPACE_ONLYr<   r}   r/   rA   rG   r?   r@   rB   rC   rD   rE   )	rH   r   r   r   rJ   rS   rK   rT   rU   s	            r   test_detect_whitespace_onlyz4TestDetectWhitespaceOnly.test_detect_whitespace_onlyU   s    '*8}

#$h+X6X	)?;s4y#c(;v~vvvr   )rY   rZ   r[   r   r   r\   r   r   r   r   T   s    D T r   r   c                       e Zd ZdeddfdZy)TestLearningExtractionr   r   Nc                    t        |      t        j                  d<   t        |dz  t              }t        |dz  t
              }d}t        d      5 }t               }||j                  _	        t        |      |j                  j                  _	        t        j                  t        t        |      t        |      d       d d d        |dz  d	z  d
z  }|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}}	|j1                  d      j3                         j5                         D cg c]  }t7        j8                  |       }}|D cg c]  }|j;                  d      dk(  s| }}|s{t'        j<                  d      dz   ddt#        j$                         v st'        j(                  |      rt'        j*                  |      ndiz  }t-        t'        j.                  |            |d   }|d   }|t        k(  }|st'        j>                  d|fd|t        f      t'        j*                  |      dt#        j$                         v st'        j(                  t              rt'        j*                  t              nddz  }dd|iz  }t-        t'        j.                  |            d x}}|d   }d }	||	u }|slt'        j>                  d|fd ||	f      t'        j*                  |      t'        j*                  |	      d!z  }
d"d#|
iz  }t-        t'        j.                  |            d x}x}}	|d$   }||k(  }|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 # 1 sw Y   xY wc c}w c c}w )&Nr   r`   ra   uE   CTA는 '예약' 대신 '무료' 키워드 포함 시 전환율 향상rb   ztask-003rd   rg   zskill-learningzlearnings.jsonlr    learnings_filer"   r   r   sourcezjay-feedbacku1   jay-feedback source 레코드가 있어야 한다z
>assert %(py0)sr#   jay_recordsr   r   r&   r.   r/   r0   r3   r4   
expires_atr   z%(py1)s is %(py4)sr6   r7   r*   learninglearning_text) r9   r:   r;   r   r(   rx   r   r   ry   rz   r   r{   r|   r<   r}   r/   r>   r?   r@   rA   rB   rC   rD   rE   rF   r~   r   r   r   get_format_assertmsgrG   )rH   r   r   r   r   r   r   r   rK   rL   rM   r   rn   rr   @py_format1rs   rR   rS   rT   rU   rV   s                         r   test_learning_extractionz/TestLearningExtraction.test_learning_extraction`   s   '*8}

#$h+X6X	)84_/0 	KI[F/5I,2:=2IFOO""/NN5#d)SXzJ		K "H,/??BSS$$&$&&&&&&&&~&&&~&&&$&&&&&&&&&&*8*B*BG*B*T*Z*Z*\*g*g*ijQ4::a=jj")OQQUU8_-NqOOOOOOOOOOO{OOO{OOOOO!n< ) E)))) E))) ))))))E)))E)))))))< (D( D(((( D((( (((D(((((((:/-////-/////////-///-///////	K 	K kOs   A/Q(Q
Q $Q Q)rY   rZ   r[   r   r   r\   r   r   r   r   _   s    0 0$ 0r   r   c                   ,    e Zd ZdeddfdZdeddfdZy)TestHistoryr   r   Nc           
         t        |      t        j                  d<   |dz  dz  t        z  }|j	                  dd       dt        ddd	g d
dddt        dddg dddg}|dz  j                  dj                  d |D              d       t        j                  t              }t        |t              }|sd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dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      dz  }t!        t        j"                  |            d }t%        |      }d}||k(  }	|	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                  |      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)   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 )*Nr   rg   rh   T)parentsexist_okz2026-03-25T12:00:00r   z
memory/...u
   CTA 변경u   무료 효과적z	learn-001)r8   r   r   r   rt   ru   learning_extractedlearning_idz2026-03-25T13:00:00rc   u   헤드라인 수정u"   숫자 포함 시 클릭률 향상z	learn-002ri   
c              3   J   K   | ]  }t        j                  |d         yw)F)ensure_asciiN)r   dumps).0r   s     r   	<genexpr>z+TestHistory.test_history.<locals>.<genexpr>   s     FAdjj77Fs   !#r   r   z5assert %(py4)s
{%(py4)s = %(py0)s(%(py1)s, %(py2)s)
}rv   historyrw   )r#   r1   r$   r%      r&   rl   rm   ro   rp   r+   r   r   r5   r6   r7   r*   rk   )r9   r:   r;   r/   mkdirr   joinr<   get_historyrv   rw   r?   r@   rA   rB   rC   rD   rE   rm   rG   )rH   r   diff_dirrowsr   rL   rM   rS   rN   r   rV   rP   rR   s                r   test_historyzTestHistory.test_historyx   s   '*8}

#$h&)99EAtd3 3#%!- , &8*	 3#%!- 5 &J*	
, 
)	)55IIFFFQX 	6 	
 ..''4((((((((z(((z(((((('((('((((((4(((4((((((((((7| q |q    |q      s   s      7   7   |   q       qz)$2
2$
2222$
222$222
2222222qz)$2
2$
2222$
222$222
2222222r   c                    t        |      t        j                  d<   t        j                  } |t
              }g }||k(  }|st        j                  d|fd||f      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                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}x}}y )	Nr   r&   )zQ%(py5)s
{%(py5)s = %(py2)s
{%(py2)s = %(py0)s.get_history
}(%(py3)s)
} == %(py8)sr<   r/   )r#   r$   r2   r4   r+   r,   r-   )r9   r:   r;   r<   r   r/   rA   rG   r?   r@   rB   rC   rD   rE   )rH   r   rK   r   rO   @py_assert6rP   rQ   s           r   test_history_empty_when_no_filez+TestHistory.test_history_empty_when_no_file   s    '*8}

#$~~*~e$**$****$******r***r***~******e***e***$**********r   )rY   rZ   r[   r   r   r   r\   r   r   r   r   w   s)    #3T #3d #3J+ + +r   r   c                       e Zd ZdeddfdZy)TestAiCallMockingr   r   Nc           
         t        |      t        j                  d<   t        |dz  t              }t        |dz  t
              }t        d      5 }t               }||j                  _	        t               |j                  j                  _	        t        j                  t        t        |      t        |             |j                  j!                          |j                  j                  j!                          |j                  j                  j"                  }|j$                  r|j$                  n|d   }d}|j&                  }	d}
d} |	|
|      }||v }|st)        j*                  d	|fd
||f      t)        j,                  |      dt/        j0                         v st)        j2                  |      rt)        j,                  |      ndt)        j,                  |	      t)        j,                  |
      t)        j,                  |      t)        j,                  |      dz  }dd|iz  }t5        t)        j6                  |            d x}x}x}	x}
x}}d d d        y # 1 sw Y   y xY w)Nr   r`   ra   rb   rk   zclaude-sonnet-4-6model rq   )zT%(py1)s in %(py11)s
{%(py11)s = %(py5)s
{%(py5)s = %(py3)s.get
}(%(py7)s, %(py9)s)
}kwargs)r1   r2   r4   py7py9py11zassert %(py13)spy13)r9   r:   r;   r   r(   rx   r   r   ry   rz   r   r{   r|   r<   r}   r/   assert_called_once	call_argsr   r   rA   rG   rC   r?   r@   rB   rD   rE   )rH   r   r   r   r   r   call_kwargsr   rR   r   r   @py_assert8@py_assert10rS   @py_format12@py_format14s                   r   test_ai_call_mockingz&TestAiCallMocking.test_ai_call_mocking   s   '*8}

#$h+X6X	)84/0 
	BI[F/5I,2:*FOO""/NN5#d)SX6224OO""557 //00::K+6+=+=['';q>F&A&**AWAbA*Wb*AA&*AAAAA&*AAAA&AAAAAA&AAA&AAA*AAAWAAAbAAA*AAAAAAAAA
	B 
	B 
	Bs   G=II)rY   rZ   r[   r   r   r\   r   r   r   r      s    BT Bd Br   r   c                       e Zd ZdeddfdZy)TestSnapshotPathAutoCreationr   r   Nc                 B   t        |      t        j                  d<   |dz  dz  t        z  dz  }|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}x}}t        |dz  t              }t        j                  t        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}}|d   }t!        |      }|j                  } |       }
|
sddt        j                         v st        j                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      t        j                  |
      dz  }t        t        j                  |            d x}x}x}}
|d   }d }||u }|slt        j"                  d|fd||f      t        j                  |      t        j                  |      dz  }	dd|	iz  }t        t        j                  |            d x}x}}y )Nr   rg   rh   	snapshotszEassert not %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.exists
}()
}snap_dirr"   r   )r   r   r    r   z_assert %(py8)s
{%(py8)s = %(py6)s
{%(py6)s = %(py4)s
{%(py4)s = %(py0)s(%(py2)s)
}.exists
}()
}r   r)   r   r   r   r6   r7   r*   )r9   r:   r;   r/   r>   r?   r@   rA   rB   rC   rD   rE   r   r(   r<   r=   r   rG   )rH   r   r   rK   rL   rN   rU   rI   rJ   rM   rO   rP   rR   rS   rV   s                  r    test_snapshot_path_auto_creationz=TestSnapshotPathAutoCreation.test_snapshot_path_auto_creation   s   '*8}

#$h&)99EAKO??$?$$$$$$$$$$$8$$$8$$$?$$$$$$$$$$X,h7!!Uc#hG         x   x             ?+5t+,5,335355555555t555t555+555,55535555555555i (D( D(((( D((( (((D(((((((r   )rY   rZ   r[   r   r   r\   r   r   r   r      s    
) 
)$ 
)r   r   )u5   CTA는 '무료' 키워드 포함 시 전환율 향상)$__doc__builtinsr?   _pytest.assertion.rewrite	assertionrewriterA   r   r:   syspathlibr   unittest.mockr   r   pytestr   insertr9   __file__parentpassive_feedbackr<   r/   r(   rx   r   r   r   r   r^   r   r   r   r   r   r\   r   r   <module>r      s   	   	 
  *  3tH~,,334 5 :;C3 U^  S T 
# #3 34 0 00(+ (+VB B&) )r   