
    i                         d Z ddlZddlZddlm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                               ddlmZmZmZmZmZmZmZ  G d d      Z G d	 d
      Z G d d      Z G d d      Zy)uN   gemini_nb2_generate.py의 순수 함수 및 상수에 대한 단위 테스트.    N)Path)Any)	MagicMockpatch)GEMINI_API_BASEGEMINI_SCOPEMODEL_ID
OUTPUT_DIRRESULTS_JSON	SCENARIOS	log_errorc                   4    e Zd ZddZddZddZddZddZy)TestConstantsNc                     t         dk(  sJ y)uB   모델 ID가 Nano Banana 2 (gemini-3.1-flash-image-preview)이다.zgemini-3.1-flash-image-previewN)r	   selfs    \/home/jay/workspace/.worktrees/task-2116-dev1/tools/ai-image-gen/test_gemini_nb2_generate.pytest_model_id_is_nano_banana2z+TestConstants.test_model_id_is_nano_banana2   s    ;;;;    c                 F    t        j                  d      sJ dt         v sJ y)u0   Gemini API 기본 URL이 올바른 형식이다.zhttps://z!generativelanguage.googleapis.comN)r   
startswithr   s    r   !test_gemini_api_base_is_valid_urlz/TestConstants.test_gemini_api_base_is_valid_url!   s$    ))*5552oEEEr   c                     dt         v sJ y)u2   Gemini API 스코프가 generative-language이다.zgenerative-languageN)r   r   s    r   (test_gemini_scope_is_generative_languagez6TestConstants.test_gemini_scope_is_generative_language&   s    $444r   c                 *    dt        t              v sJ y)u2   출력 디렉토리가 v2-gemini-nb2 폴더이다.zv2-gemini-nb2N)strr
   r   s    r    test_output_dir_is_v2_gemini_nb2z.TestConstants.test_output_dir_is_v2_gemini_nb2*   s    #j/111r   c                 6    t         j                  t        k(  sJ y)u,   results.json이 OUTPUT_DIR 하위에 있다.N)r   parentr
   r   s    r   "test_results_json_is_in_output_dirz0TestConstants.test_results_json_is_in_output_dir.   s    ""j000r   returnN)__name__
__module____qualname__r   r   r   r   r     r   r   r   r      s    <F
521r   r   c                   <    e Zd ZddZddZddZddZddZddZy)	TestScenariosNc                 ,    t        t              dk(  sJ y)u7   SCENARIOS dict에 3개의 시나리오가 존재한다.   N)lenr   r   s    r   test_has_three_scenariosz&TestScenarios.test_has_three_scenarios9   s    9~"""r   c                 L    t        t        j                               h dk(  sJ y)u#   SCENARIOS의 키는 A, B, C 이다.>   ABCN)setr   keysr   s    r   test_scenario_keys_are_a_b_cz*TestScenarios.test_scenario_keys_are_a_b_c=   s    9>>#$777r   c                     t        j                         D ]9  \  }}t        |t              sJ d| d       t	        |      dkD  r0J d| d        y)u@   모든 시나리오 값은 비어 있지 않은 문자열이다.u   시나리오 u   의 값이 str이 아닙니다.r   u   의 값이 비어 있습니다.N)r   items
isinstancer   r+   )r   keyvalues      r   %test_all_values_are_non_empty_stringsz3TestScenarios.test_all_values_are_non_empty_stringsA   s\    #//+ 	XJCeS)_]3%?^+__)u:>W]3%7V#WW>	Xr   c                 R    dt         d   j                         v sdt         d   v sJ yy)u@   시나리오 A에 리크루팅 관련 키워드가 포함된다.
recruitingr.   u	   커리어Nr   lowerr   s    r   ,test_scenario_a_contains_recruiting_keywordsz:TestScenarios.test_scenario_a_contains_recruiting_keywordsG   s/    y~3355	RU9VVV9V5r   c                 R    dt         d   j                         v sdt         d   v sJ yy)u=   시나리오 B에 브랜딩 관련 키워드가 포함된다.brandingr/   u   보험Nr<   r   s    r   *test_scenario_b_contains_branding_keywordsz8TestScenarios.test_scenario_b_contains_branding_keywordsK   s.    Ys^1133x9S>7QQQ7Q3r   c                 R    dt         d   j                         v sdt         d   v sJ yy)u@   시나리오 C에 동기부여 관련 키워드가 포함된다.motivationalr0   u   기회Nr<   r   s    r   .test_scenario_c_contains_motivational_keywordsz<TestScenarios.test_scenario_c_contains_motivational_keywordsO   s/    3!5!5!778yQT~;UUU;U7r   r!   )	r#   r$   r%   r,   r3   r9   r>   rA   rD   r&   r   r   r(   r(   8   s$    #8XWRVr   r(   c                   \    e Zd ZdededdfdZdededdfdZdededdfdZdededdfdZy)	TestLogErrortmp_pathmonkeypatchr"   Nc                     ddl }|dz  }|j                  |d|       |j                  d       |j                         sJ y)u:   log_error 호출 시 에러 로그 파일이 생성된다.r   N
errors.log
ERRORS_LOGu   테스트 에러 메시지)gemini_nb2_generatesetattrr   exists)r   rG   rH   mod
errors_logs        r   test_log_error_creates_filez(TestLogError.test_log_error_creates_fileZ   s@    ),
Cz:23  """r   c                     ddl }|dz  }|j                  |d|       |j                  d       |j                  d      }d|v sJ y)u@   log_error 호출 시 메시지가 로그 파일에 기록된다.r   NrJ   rK   u   에러 내용: 테스트utf-8encodingrL   rM   r   	read_textr   rG   rH   rO   rP   contents         r   test_log_error_writes_messagez*TestLogError.test_log_error_writes_messagee   sO    ),
Cz:01&&&8)W444r   c                     ddl }|dz  }|j                  |d|       |j                  d       |j                  d       |j                  d      }d|v sJ d|v sJ y)	u:   log_error를 두 번 호출하면 두 줄이 기록된다.r   NrJ   rK   u   첫 번째 에러u   두 번째 에러rS   rT   rV   rX   s         r   test_log_error_appendsz#TestLogError.test_log_error_appendsq   sj    ),
Cz:)*)*&&&8"g---"g---r   c                     ddl }|dz  }|j                  |d|       |j                  d       |j                  d      }d|v sd	|v sJ yy)
u4   log_error 로그에 타임스탬프가 포함된다.r   NrJ   rK   u   타임스탬프 확인rS   rT   z[2026-z[202rV   rX   s         r   !test_log_error_includes_timestampz.TestLogError.test_log_error_includes_timestamp   s\    ),
Cz:./&&&87"f&777&7"r   )	r#   r$   r%   r   r   rQ   rZ   r\   r^   r&   r   r   rF   rF   Y   sl    	#D 	#s 	#t 	#
5d 
5 
5QU 
5.t .# .$ .8$ 8S 8UY 8r   rF   c                       e Zd ZddZddZy)TestGetGcloudAccessTokenNc                 t   ddl }t               }d|_        t        j                  |dddd      5  t        dt        d            5  t        d	|
      5 }|j                         }ddd       ddd       ddd       dk(  sJ j                          y# 1 sw Y   1xY w# 1 sw Y   5xY w# 1 sw Y   9xY w)uS   gcloud_auth.get_access_token()이 gcloud CLI fallback으로 토큰을 반환한다.r   Nzfake-token-12345
_token_cachetokenexpirygoogle.auth.default
   ADC 없음side_effectsubprocess.runreturn_valuezfake-token-12345)gcloud_authr   stdoutr   object	Exceptionget_access_tokenassert_called_once)r   rm   mock_resultmock_runrd   s        r   test_returns_token_on_successz6TestGetGcloudAccessToken.test_returns_token_on_success   s    k1\\+~QU7VW 	;,)L:QR ;++F ;('88:E;;	;
 ****##%	; ;; ;	; 	;s;   B.B"B&B".B.BB""B+	'B..B7c           	         ddl }t               }d|_        t        j                  |dddd      5  t        dt        d            5  t        d	|
      5  t        j                  t        d      5  |j                          ddd       ddd       ddd       ddd       y# 1 sw Y   "xY w# 1 sw Y   &xY w# 1 sw Y   *xY w# 1 sw Y   yxY w)uP   gcloud CLI fallback에서 빈 토큰 반환 시 RuntimeError를 발생시킨다.r   Nz   
rb   rc   rf   rg   rh   rj   rk   u
   빈 토큰)match)
rm   r   rn   r   ro   rp   pytestraisesRuntimeErrorrq   )r   rm   rs   s      r   test_raises_on_empty_tokenz3TestGetGcloudAccessToken.test_raises_on_empty_token   s    k$\\+~QU7VW 	7,)L:QR 7++F 7|<H 7#446777	7 	77 77 77 7	7 	7sS   CB;B/1B#	B/
B;C#B,(B//B84B;;C	 CCr!   )r#   r$   r%   ru   r{   r&   r   r   r`   r`      s    &7r   r`   )__doc__jsonsyspathlibr   typingr   unittest.mockr   r   rx   pathinsertr   __file__r   rL   r   r   r	   r
   r   r   r   r   r(   rF   r`   r&   r   r   <module>r      sv    T  
   *  3tH~,,- .  1 18V VB18 18r7 7r   