
    eiF                     R   d Z ddlZddlmc mZ ddlZddlZddl	m	Z	m
Z
mZ ddlmZ ddlZej                  j!                  d e ee      j&                  j&                               ddl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)u  Tests for learnings-archiver.py - TDD approach (RED phase first).

테스트 케이스:
1. add_learning → 파일에 올바른 형식으로 추가되는지
2. get_learnings → 해당 스킬만 반환, 다른 스킬 learning 미포함
3. archive_expired → 만료 항목 이동 + 원본에서 제거 + archive에 존재
4. jay-feedback → expires_at null → TTL 아카이브에서 제외
5. 잘못된 source → 에러 발생
6. 빈 파일에서 get_learnings → 빈 리스트 반환
    N)datetime	timedeltatimezone)Pathc                   P    e Zd ZdZdeddfdZdeddfdZdeddfdZdeddfdZy)	TestAddLearninguO   테스트 1: add_learning → 파일에 올바른 형식으로 추가되는지.tmp_pathreturnNc                 b   |dz  }|dz  }t        j                  dd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      j                         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}
}	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  }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"   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }d d!|iz  }t        t        j                  |            d
x}x}}|d#   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }d d!|iz  }t        t        j                  |            d
x}x}}d$}||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}}t#        j$                  |d$         }t#        j$                  |d%         }||z
  }d&}|j&                  }	||	k  }d'}|	|k  }|r|st        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  }t        t        j                  |            d
x}x}x}x}	}y
).uO   add_learning 호출 시 learnings.jsonl에 올바른 형식으로 추가된다.learnings.jsonllearnings-archive.jsonlsatori-cardnewschampion-battleu`   CTA를 마지막 슬라이드가 아닌 3번째에 배치하면 시선 흐름이 자연스럽다
skill_namesourcelearninglearnings_patharchive_pathzAassert %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.exists
}()
}learnings_file)py0py2py4Nutf-8encoding   ==z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)slenlinesr   py1py3py6assert %(py8)spy8r   idinz%(py1)s in %(py3)sentryr$   r%   assert %(py5)spy5r   z%(py1)s == %(py4)sr$   r   assert %(py6)sr&   r   r   
created_at
expires_at;   =   )<=r8   )z,%(py1)s <= %(py6)s
{%(py6)s = %(py4)s.days
}z,%(py6)s
{%(py6)s = %(py4)s.days
} <= %(py8)sdelta)r$   r   r&   r(   assert %(py10)spy10)laadd_learningexists@py_builtinslocals
@pytest_ar_should_repr_global_name	_safereprAssertionError_format_explanation	read_textstrip
splitlinesr!   _call_reprcomparejsonloadsr   fromisoformatdays)selfr	   r   archive_file@py_assert1@py_assert3@py_format5r"   @py_assert2@py_assert5@py_assert4@py_format7@py_format9r-   @py_assert0@py_format4@py_format6createdexpiresr9   @py_assert7@py_format11s                         </home/jay/workspace/scripts/tests/test_learnings_archiver.py+test_add_learning_creates_valid_jsonl_entryz;TestAddLearning.test_add_learning_creates_valid_jsonl_entry   se   !$55";;
($w)%	
 $$&$&&&&&&&&~&&&~&&&$&&&&&&&&&&(('(:@@BMMO5zQzQzQss55zQ

58$tu}tutuu\"7&77"&77777"&7777"777&77777777X3"33"33333"3333333"33333333Z   	G  %G  	G   %G  G  	G  	G  	G   %G  	G  	G  	G   	G  	G  	G  %G  	G  	G  	G  	G  	G  	G  	G$|u$$$$|u$$$|$$$$$$u$$$u$$$$$$$$|u$$$$|u$$$|$$$$$$u$$$u$$$$$$$((|)<=((|)<='!%UZZ%rZ%%2%Z2%%%%%rZ2%%%r%%%%%%U%%%U%%%Z%%%2%%%%%%%%    c                    |dz  }|dz  }t        j                  ddd||       t        j                  ddd	||       |j                  d
      j                         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}}y)uD   add_learning을 여러 번 호출하면 append-only로 추가된다.r   r   skill-aself-reviewu   첫 번째 학습r   skill-bcross-modelu   두 번째 학습r   r      r   r    r!   r"   r#   r'   r(   Nr<   r=   rF   rG   rH   r!   rA   rI   r?   r@   rB   rC   rD   rE   )
rN   r	   r   rO   r"   rS   rT   rU   rV   rW   s
             r_   *test_add_learning_appends_multiple_entriesz:TestAddLearning.test_add_learning_appends_multiple_entries:   s   !$55";;
  ()%	
 	  ()%	
 (('(:@@BMMO5zQzQzQss55zQra   c                    |dz  }|dz  }t        j                  ddd||       |j                  d      j                         j	                         }t        j                  |d	         }|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)u@   source가 jay-feedback이면 expires_at이 null이어야 한다.r   r   r   jay-feedbacku   jay의 중요 피드백r   r   r   r   r5   Nisz%(py1)s is %(py4)sr2   r3   r&   )r<   r=   rF   rG   rH   rJ   rK   rA   rI   rC   rD   rE   )rN   r	   r   rO   r"   r-   rX   rQ   rS   rR   rV   s              r_   2test_add_learning_jay_feedback_has_null_expires_atzBTestAddLearning.test_add_learning_jay_feedback_has_null_expires_atQ   s    !$55";;
(!.)%	
 (('(:@@BMMO

58$\"*d*"d****"d***"***d*******ra   c                 H   |dz  }|dz  }t        j                  ddd||       |j                  d      j                         j	                         }t        j                  |d	         }|d
   }|j                  d      }t        |      dk(  xr |j                  d      dk(  }g }	|}
|s|}
|
sdddt        j                         v st        j                  |      rt        j                  |      ndiz  }|	j                  |       |sXdddt        j                         v st        j                  |      rt        j                  |      ndiz  }|	j                  |       t        j                   |	d      i z  }dd|iz  }t#        t        j$                  |            dx}
}	y)u3   id는 learn-NNN 또는 UUID 형식이어야 한다.r   r   
test-skillgithub-learn   테스트 학습r   r   r   r   r)   learn-$   -   z%(py2)sr   is_learn_formatz%(py4)sr   is_uuid_formatr   zassert %(py7)spy7N)r<   r=   rF   rG   rH   rJ   rK   
startswithr!   countr?   r@   rA   rB   rC   append_format_booloprD   rE   )rN   r	   r   rO   r"   r-   entry_idrx   ry   rP   rX   @py_format3rR   rZ   @py_format8s                  r_   test_add_learning_id_formatz+TestAddLearning.test_add_learning_id_formatb   s   !$55";;
#!')%	
 (('(:@@BMMO

58$;"--h7X",I1D1I00.000000000000000000.000.000000000000ra   )	__name__
__module____qualname____doc__r   r`   ri   ro   r    ra   r_   r   r      sR    Y&D &T &<4 D .+4 +TX +"1D 1T 1ra   r   c                   @    e Zd ZdZdeddfdZdeddfdZdeddfdZy)TestGetLearningsuY   테스트 2: get_learnings → 해당 스킬만 반환, 다른 스킬 learning 미포함.r	   r
   Nc           	         |dz  }t        j                         }|t        d      z   j                         }|t        d      z
  j                         }dddd|j                         |d	d
ddd|j                         |d	dddd|j                         |d	g}|j	                  dj                  d |D              d       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)$uC   get_learnings는 지정한 스킬의 활성 항목만 반환한다.r      rM   r   	learn-001rc   rd   u   skill-a의 학습r)   r   r   r   r4   r5   	learn-002re   u!   skill-b의 학습 (다른 스킬)z	learn-003rf   u   skill-a의 만료된 학습
c              3   F   K   | ]  }t        j                  |        y wNrJ   dumps.0es     r_   	<genexpr>zPTestGetLearnings.test_get_learnings_returns_only_target_skill.<locals>.<genexpr>        +KaDJJqM+K   !r   r   r   r   r    r!   resultr#   r'   r(   Nr   r)   r1   r2   r3   r&   r   r   nowr   	isoformat
write_textjoinr<   get_learningsr!   rA   rI   r?   r@   rB   rC   rD   rE   )rN   r	   r   r   futurepastentriesr   rS   rT   rU   rV   rW   rX   rQ   rR   s                   r_   ,test_get_learnings_returns_only_target_skillz=TestGetLearnings.test_get_learnings_returns_only_target_skill{   s   !$55lln	r**557iQ''224 "''/!mmo$ "''?!mmo$ "''9!mmo"#
4 	!!$))+K7+K"KV]!^!!)NK 6{a{a{ass66{aay-+-+----+------+-------ay&3)3&)3333&)333&333)3333333ra   c                 @   |dz  }t        j                         }|t        d      z   j                         }dddd|j                         |dg}|j	                  d	j                  d
 |D              d       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}	}y)uL   get_learnings는 다른 스킬의 learning을 절대 포함하지 않는다.r   r   r   r   re   rd   u   다른 스킬의 학습r   r   c              3   F   K   | ]  }t        j                  |        y wr   r   r   s     r_   r   zLTestGetLearnings.test_get_learnings_excludes_other_skills.<locals>.<genexpr>   r   r   r   r   rc   r   r   r   r    r!   r   r#   r'   r(   Nr   )rN   r	   r   r   r   r   r   rS   rT   rU   rV   rW   s               r_   (test_get_learnings_excludes_other_skillsz9TestGetLearnings.test_get_learnings_excludes_other_skills   s   !$55lln	r**557 "''5!mmo$	
 	!!$))+K7+K"KV]!^!!)NK6{a{a{ass66{ara   c                 
   |dz  }t        j                         }dddd|j                         ddg}|j                  dj	                  d	 |D              d
       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}||u }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }	t        t        j                  |	            dx}x}}y)uA   expires_at이 null인 항목은 항상 활성으로 반환한다.r   r   rc   rk   u   영구 유지 학습Nr   r   c              3   F   K   | ]  }t        j                  |        y wr   r   r   s     r_   r   zOTestGetLearnings.test_get_learnings_includes_null_expires_at.<locals>.<genexpr>   r   r   r   r   r   r   r   r    r!   r   r#   r'   r(   r   r5   rl   rn   r2   r3   r&   )r   r   r   r   r   r<   r   r!   rA   rI   r?   r@   rB   rC   rD   rE   )rN   r	   r   r   r   r   rS   rT   rU   rV   rW   rX   rQ   rR   s                 r_   +test_get_learnings_includes_null_expires_atz<TestGetLearnings.test_get_learnings_includes_null_expires_at   sW   !$55lln "'(2!mmo"	
 	!!$))+K7+K"KV]!^!!)NK6{a{a{ass66{aay&.$.&$....&$...&...$.......ra   )r   r   r   r   r   r   r   r   r   ra   r_   r   r   x   s?    c(4T (4d (4T   $  ,/D /T /ra   r   c                   @    e Zd ZdZdeddfdZdeddfdZdeddfdZy)TestArchiveExpiredu`   테스트 3: archive_expired → 만료 항목 이동 + 원본에서 제거 + archive에 존재.r	   r
   Nc                 l
   |dz  }|dz  }t        j                         }|t        d      z   j                         }|t        d      z
  j                         }dddd	|j                         |d
dddd|j                         |d
g}|j	                  dj                  d |D              d       t        j                  ||      }d}	||	k(  }
|
st        j                  d|
fd||	f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |	      dz  }dd|iz  }t        t        j                  |            dx}
}	|j!                         j#                         j%                         D cg c]  }t'        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!   }d}||k(  }	|	slt        j                  d|	fd"||f      t        j                  |      t        j                  |      d#z  }d$d%|iz  }t        t        j                  |            dx}x}	}|j!                         j#                         j%                         D cg c]  }t'        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!   }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c c}w c c}w )'uY   archive_expired는 만료된 항목을 archive로 이동하고 원본에서 제거한다.r   r   r   r   r   r   rc   rd   u   활성 학습r   r   rf   u   만료된 학습r   c              3   F   K   | ]  }t        j                  |        y wr   r   r   s     r_   r   zPTestArchiveExpired.test_archive_expired_moves_expired_entries.<locals>.<genexpr>   r   r   r   r   r   r   r   z%(py0)s == %(py3)sr|   r   r%   r/   r0   Nr    r!   	remainingr#   r'   r(   r   r)   r1   r2   r3   r&   archived)r   r   r   r   r   r   r<   archive_expiredrA   rI   r?   r@   rB   rC   rD   rE   rF   rG   rH   rJ   rK   r!   )rN   r	   r   rO   r   r   r   r   r|   rS   rP   rY   rZ   liner   rT   rU   rV   rW   rX   rQ   rR   r   s                          r_   *test_archive_expired_moves_expired_entriesz=TestArchiveExpired.test_archive_expired_moves_expired_entries   sj   !$55";;lln	r**557iQ''224 "''+!mmo$ "''.!mmo"
$ 	!!$))+K7+K"KV]!^"".|\uzuuu 3A2J2J2L2R2R2T2_2_2ab$TZZ%b	b9~""~""""~""""""s"""s""""""9"""9"""~""""""""""|D!0[0![0000![000!000[0000000 2>1G1G1I1O1O1Q1\1\1^_DJJt$__8}!!}!!!!}!!!!!!s!!!s!!!!!!8!!!8!!!}!!!!!!!!!!{4 /K/ K//// K/// ///K/////// c
 `s   T,:T1c           	      b   |dz  }|dz  }t        j                         }|t        d      z
  j                         }dddd|j                         |t        d	      z
  j                         d
}|j	                  t        j                  |      dz   d       dddd|j                         |d
}|j	                  t        j                  |      dz   d       t        j                  ||       |j                         j                         j                         D cg c]  }t        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 cg c]  }|d   	 }}d}||v }
|
st        j                  d|
fd||f      t        j&                  |      dt!        j"                         v st        j$                  |      rt        j&                  |      ndd z  }d!d"|iz  }t)        t        j*                  |            dx}}
d}||v }
|
st        j                  d|
fd||f      t        j&                  |      dt!        j"                         v st        j$                  |      rt        j&                  |      ndd z  }d!d"|iz  }t)        t        j*                  |            dx}}
yc c}w c c}w )#uK   archive_expired는 기존 archive에 append한다 (덮어쓰지 않는다).r   r   r   r   z	learn-oldre   rd   u   기존 아카이브 항목
   r   r   r   r   z	learn-newrc   rf   u   새 만료 항목r   rg   r   r    r!   r   r#   r'   r(   Nr)   r*   r,   idsr.   r/   r0   )r   r   r   r   r   rJ   r   r<   r   rF   rG   rH   rK   r!   rA   rI   r?   r@   rB   rC   rD   rE   )rN   r	   r   rO   r   r   existing_archivednew_expiredr   r   rS   rT   rU   rV   rW   ar   rX   rY   rZ   s                       r_   0test_archive_expired_appends_to_existing_archivezCTestArchiveExpired.test_archive_expired_appends_to_existing_archive   s}   !$55";;llniQ''224 ##4--/!33>>@
 	

+< = DwW ##+--/
 	!!$**["9D"@7!S
.|T1=1G1G1I1O1O1Q1\1\1^_DJJt$__8}!!}!!!!}!!!!!!s!!!s!!!!!!8!!!8!!!}!!!!!!!!!! ()1qw))!{c!!!!{c!!!{!!!!!!c!!!c!!!!!!!!{c!!!!{c!!!{!!!!!!c!!!c!!!!!!!	 `)s   N'N,c           
         |dz  }|dz  }t        j                         }|t        d      z
  j                         }t	        d      D cg c]   }d|ddd	d
| |j                         |d" }}|j                  dj                  d |D              d       t        j                  ||      }d}	||	k(  }
|
st        j                  d|
fd||	f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |	      dz  }dd|iz  }t        t        j                   |            dx}
}	yc c}w )u>   archive_expired는 아카이브된 항목 수를 반환한다.r   r   r   r      rt   03drc   rd   u   만료 학습 r   r   c              3   F   K   | ]  }t        j                  |        y wr   r   r   s     r_   r   zHTestArchiveExpired.test_archive_expired_returns_count.<locals>.<genexpr>6  r   r   r   r   r   r   r   r|   r   r/   r0   N)r   r   r   r   ranger   r   r<   r   rA   rI   r?   r@   rB   rC   rD   rE   )rN   r	   r   rO   r   r   ir   r|   rS   rP   rY   rZ   s                r_   "test_archive_expired_returns_countz5TestArchiveExpired.test_archive_expired_returns_count$  s   !$55";;llniQ''224 1X

  qg&'',QC0!mmo"

 

 	!!$))+K7+K"KV]!^"".|\uzuuu

s   	%E)r   r   r   r   r   r   r   r   r   ra   r_   r   r      sA    j(04 (0D (0T#" #"RV #"J4 D ra   r   c                   0    e Zd ZdZdeddfdZdeddfdZy)TestJayFeedbackTTLExclusionuP   테스트 4: jay-feedback → expires_at null → TTL 아카이브에서 제외.r	   r
   Nc                    |dz  }|dz  }t        j                         }|t        d      z
  j                         }dddd|j                         d	d
dddd|j                         |d
g}|j	                  dj                  d |D              d       t        j                  ||      }d}||k(  }	|	st        j                  d|	fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }
dd|
iz  }t        t        j                  |            d	x}	}|j!                         j#                         j%                         D cg c]  }t'        j(                  |       }}|D cg c]  }|d   	 }}d}||v }|st        j                  d|fd||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }
dd|
iz  }t        t        j                  |            d	x}}d}||v}|st        j                  d|fd||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }
dd|
iz  }t        t        j                  |            d	x}}y	c c}w c c}w ) uS   source가 jay-feedback이고 expires_at이 null이면 아카이브하지 않는다.r   r   r   r   r   rc   rk   u   jay의 영구 피드백Nr   r   rd   u   만료된 일반 학습r   c              3   F   K   | ]  }t        j                  |        y wr   r   r   s     r_   r   zbTestJayFeedbackTTLExclusion.test_jay_feedback_with_null_expires_at_not_archived.<locals>.<genexpr>Y  r   r   r   r   r   r   r   r|   r   r/   r0   r)   r*   r,   remaining_idsr.   )not in)z%(py1)s not in %(py3)s)r   r   r   r   r   r   r<   r   rA   rI   r?   r@   rB   rC   rD   rE   rF   rG   rH   rJ   rK   )rN   r	   r   rO   r   r   r   r|   rS   rP   rY   rZ   r   r   rr   rX   s                    r_   3test_jay_feedback_with_null_expires_at_not_archivedzOTestJayFeedbackTTLExclusion.test_jay_feedback_with_null_expires_at_not_archived@  s   !$55";;llniQ''224 "'(5!mmo" "''5!mmo"
$ 	!!$))+K7+K"KV]!^"".|\ uzuuu2@2J2J2L2R2R2T2_2_2ab$TZZ%b	b*34Q444+{m++++{m+++{++++++m+++m+++++++/{-////{-///{//////-///-/////// c4s   >K9 K>c                 v   |dz  }|dz  }t        j                         }|t        d      z
  j                         }dddd|j                         |d	g}|j	                  d
j                  d |D              d       t        j                  ||      }d}||k(  }	|	st        j                  d|	fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }
dd|
iz  }t        t        j                  |            dx}	}y)uu   source가 jay-feedback이면 expires_at이 명시적으로 설정되어 만료되어도 아카이브하지 않는다.r   r   r   r   r   rc   rk   u   만료된 jay 피드백r   r   c              3   F   K   | ]  }t        j                  |        y wr   r   r   s     r_   r   z_TestJayFeedbackTTLExclusion.test_jay_feedback_with_expired_date_NOT_archived.<locals>.<genexpr>v  r   r   r   r   r   r   r   r   r|   r   r/   r0   N)r   r   r   r   r   r   r<   r   rA   rI   r?   r@   rB   rC   rD   rE   )rN   r	   r   rO   r   r   r   r|   rS   rP   rY   rZ   s               r_   0test_jay_feedback_with_expired_date_NOT_archivedzLTestJayFeedbackTTLExclusion.test_jay_feedback_with_expired_date_NOT_archivede  s    !$55";;llniQ''224 "'(5!mmo"	
 	!!$))+K7+K"KV]!^"".|\ uzuuura   )r   r   r   r   r   r   r   r   ra   r_   r   r   =  s.    Z#0D #0UY #0J RV ra   r   c                   0    e Zd ZdZdeddfdZdeddfdZy)TestInvalidSourceu0   테스트 5: 잘못된 source → 에러 발생.r	   r
   Nc                     |dz  }|dz  }t        j                  t        d      5  t        j                  ddd||       d	d	d	       y	# 1 sw Y   y	xY w)
uQ   유효하지 않은 source로 add_learning 호출 시 ValueError가 발생한다.r   r   zInvalid source)matchrq   zinvalid-sourcers   r   N)pytestraises
ValueErrorr<   r=   )rN   r	   r   rO   s       r_   -test_add_learning_invalid_source_raises_errorz?TestInvalidSource.test_add_learning_invalid_source_raises_error  sW    !$55";;]]:-=> 	OO''+-)	 	 	s   A

Ac           	         |dz  }|dz  }g d}|D ]  }t        j                  d|| d||       ! |j                  d      j                         j	                         }t        |      }t        |      }||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                  |      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                  |      dz  }
dd|
iz  }t        t        j                  |            dx}x}	}y)u=   유효한 source 목록은 모두 에러 없이 추가된다.r   r   )rd   rf   rk   zonline-expertrr   r   rq   u    학습r   r   r   r   )zN%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py8)s
{%(py8)s = %(py5)s(%(py6)s)
}r!   r"   valid_sources)r   r$   r%   r0   r&   r(   r:   r;   Nrh   )rN   r	   r   rO   r   r   r"   rS   r]   rU   rW   r^   s               r_   ,test_add_learning_valid_sources_do_not_raisez>TestInvalidSource.test_add_learning_valid_sources_do_not_raise  sK   !$55";;
 $ 	FOO'"87+-)	 (('(:@@BMMO5z/S//z/////z///////s///s//////5///5///z//////S///S////////////////////ra   )r   r   r   r   r   r   r   r   ra   r_   r   r   ~  s+    :d t 0T 0d 0ra   r   c                   @    e Zd ZdZdeddfdZdeddfdZdeddfdZy)TestEmptyFileGetLearningsuE   테스트 6: 빈 파일에서 get_learnings → 빈 리스트 반환.r	   r
   Nc                    |dz  }|j                  dd       t        j                  d|      }g }||k(  }|st        j                  d|fd||f      d	t        j                         v st        j                  |      rt        j                  |      nd	t        j                  |      d
z  }dd|iz  }t        t        j                  |            dx}}y)uR   learnings.jsonl이 비어있으면 get_learnings는 빈 리스트를 반환한다.r    r   r   rc   r   r   r   r   r   r/   r0   N)r   r<   r   rA   rI   r?   r@   rB   rC   rD   rE   rN   r	   r   r   rS   rP   rY   rZ   s           r_   5test_get_learnings_from_empty_file_returns_empty_listzOTestEmptyFileGetLearnings.test_get_learnings_from_empty_file_returns_empty_list  s    !$55!!"w!7!!)NKv|vvvra   c                    |dz  }t        j                  d|      }g }||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd	|iz  }t        t        j                  |            d
x}}y
)uY   learnings.jsonl이 존재하지 않으면 get_learnings는 빈 리스트를 반환한다.r   rc   r   r   r   r   r   r/   r0   N)
r<   r   rA   rI   r?   r@   rB   rC   rD   rE   r   s           r_   ;test_get_learnings_from_nonexistent_file_returns_empty_listzUTestEmptyFileGetLearnings.test_get_learnings_from_nonexistent_file_returns_empty_list  sw    !$55!!)NKv|vvvra   c                    |dz  }|dz  }|j                  dd       t        j                  ||      }d}||k(  }|st        j                  d|fd	||f      d
t        j                         v st        j                  |      rt        j                  |      nd
t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}y)uH   learnings.jsonl이 비어있으면 archive_expired는 0을 반환한다.r   r   r   r   r   r   r   r   r   r|   r   r/   r0   N)r   r<   r   rA   rI   r?   r@   rB   rC   rD   rE   )	rN   r	   r   rO   r|   rS   rP   rY   rZ   s	            r_   1test_archive_expired_from_empty_file_returns_zerozKTestEmptyFileGetLearnings.test_archive_expired_from_empty_file_returns_zero  s    !$55";;!!"w!7"".|\uzuuura   )r   r   r   r   r   r   r   r   r   ra   r_   r   r     sB    Od W[ TX ]a $ SW ra   r   )r   builtinsr?   _pytest.assertion.rewrite	assertionrewriterA   rJ   sysr   r   r   pathlibr   r   pathinsertstr__file__parentlearnings_archiverr<   r   r   r   r   r   r   r   ra   r_   <module>r      s   	   
 2 2   3tH~,,334 5 \1 \1~W/ W/th hV> >B)0 )0X ra   