
    jKjޡ                     F   d dl Z d dlZd dlmZmZ d dlmZ d dlmZmZ  G d d      Z	 G d de j                        Z G d	 d
e      Z G d de      Z G d de      Z G d de      Z G d de      Z G d de      Z G d de      Zedk(  r e j(                          yy)    N)	MagicMockpatch)parameterized)PromptResultPromptsc                       e Zd ZdZddZd Zy)MockResponsezMock HTTP response for testing.Nc                 .    || _         || _        || _        y )N)
_json_datastatus_codeok)self	json_datar   r   s       m/Users/ahmed/devFolder/Ultron/claude-voice/.venv/lib/python3.12/site-packages/posthog/test/ai/test_prompts.py__init__zMockResponse.__init__   s    #&    c                 H    | j                   t        d      | j                   S )NzNo JSON data)r   
ValueError)r   s    r   jsonzMockResponse.json   s!    ??"^,,r   )N   T)__name__
__module____qualname____doc__r   r    r   r   r	   r	   
   s    )
r   r	   c            	       4    e Zd ZdZdddddddddZ	 	 	 dd	Zy
)TestPromptszTests for the Prompts class.   test-promptz=Hello, {{name}}! You are a helpful assistant for {{company}}.zuser@example.comz2024-01-01T00:00:00ZF)idnamepromptversion
created_by
created_at
updated_atdeletedc                 D    t               }||_        ||_        ||_        |S )zCreate a mock PostHog client.)r   personal_api_keyapi_keyraw_host)r   r)   project_api_keyhostmocks        r   create_mock_posthogzTestPrompts.create_mock_posthog&   s&     { 0&r   N)phx_test_keyphc_test_keyhttps://us.posthog.com)r   r   r   r   mock_prompt_responser/   r   r   r   r   r      s7    & Q(,,	 (&%	r   r   c                      e Zd ZdZ ed      d        Z ed      d        Z ed       ed      d               Z ed      d        Z ed       ed      d               Z	 ed       ed       ed	      d
                      Z
 ed       ed	      d               Z ed      d        Z ej                  di dfdddidfg       ed      d               Z ed      d        Zd Zd Z ed      d        Z ed      d        Z ed       ed      d               Z ed       ed      d               Z ed      d        Z ed      d        Z ed      d        Z ed       ed      d               Zy) TestPromptsGetz#Tests for the Prompts.get() method.posthog.ai.prompts._get_sessionc                    |j                   j                  }t        | j                        |_         | j	                         }t        |      }|j                  d      }| j                  || j                  d          |j                          |j                  }| j                  |d   d   d       | j                  d|d   d          | j                  |d   d   d   d	       y
)z#Should successfully fetch a prompt.r   r   r"   r   zahttps://us.posthog.com/api/environments/@current/llm_prompts/name/test-prompt/?token=phc_test_keyAuthorizationr   headerszBearer phx_test_keyN)
return_valuegetr	   r3   r/   r   assertEqualassert_called_once	call_argsassertIn)r   mock_get_sessionmock_getposthogpromptsresultr?   s          r    test_successfully_fetch_a_promptz/TestPromptsGet.test_successfully_fetch_a_prompt7   s     $0044 ,t7P7P Q**,'"]+!:!:8!DE##%&&	aLOo	
 	oy|I'>?aL#O46K	
r   c                 f   |j                   j                  }i | j                  ddd}t        |      |_         | j	                         }t        |      }|j                  dd      }| j                  ||d          |j                          |j                  }| j                  |d   d   d	       y
)z4Should successfully fetch a specific prompt version.Prompt version 1r   r"   r#   r8   r   r#   r"   r   zkhttps://us.posthog.com/api/environments/@current/llm_prompts/name/test-prompt/?token=phc_test_key&version=1N)	r;   r<   r3   r	   r/   r   r=   r>   r?   )r   rA   rB   versioned_prompt_responserC   rD   rE   r?   s           r   1test_successfully_fetch_a_specific_prompt_versionz@TestPromptsGet.test_successfully_fetch_a_specific_prompt_versionN   s     $0044%
''%
(%
!
 !-7P Q**,'"]A6!:8!DE##%&&	aLOy	
r   posthog.ai.prompts.time.timec                    |j                   j                  }t        | j                        |_         d|_         | j	                         }t        |      }|j                  dd      }| j                  || j                  d          | j                  |j                  d       d|_         |j                  dd      }| j                  || j                  d          | j                  |j                  d       y	)
z5Should return cached prompt when fresh (no API call).r8        @@r   ,  cache_ttl_secondsr"   r   g     @Nr;   r<   r	   r3   r/   r   r=   
call_count)r   	mock_timerA   rB   rC   rD   result1result2s           r   $test_return_cached_prompt_when_freshz3TestPromptsGet.test_return_cached_prompt_when_freshf   s     $0044 ,t7P7P Q!'	**,'" ++ms+C$";";H"EF,,a0 "(	 ++ms+C$";";H"EF,,a0r   c                 L   |j                   j                  }i | j                  ddd}i | j                  ddd}t        |      t        |      g|_        | j                         }t        |      }| j                  |j                  d      |d          | j                  |j                  dd	      |d          | j                  |j                  d      |d          | j                  |j                  dd	      |d          | j                  |j                  d       y
)z>Should cache latest and historical prompt versions separately.Latest prompt   rI   rH   r   r8   r   r"   rJ   N	r;   r<   r3   r	   side_effectr/   r   r=   rT   )r   rA   rB   latest_prompt_responserK   rC   rD   s          r   2test_cache_latest_and_versioned_prompts_separatelyzATestPromptsGet.test_cache_latest_and_versioned_prompts_separately~   s3    $0044"
''"
%"

%
''%
(%
! #9:#<= 

 **,'"]35KH5UVKKqK1%h/	
 	]35KH5UVKKqK1%h/	
 	,,a0r   c                    |j                   j                  }i | j                  ddi}t        | j                        t        |      g|_        d|_         | j                         }t        |      }|j                  dd      }| j                  || j                  d          | j                  |j                  d       d	|_         |j                  dd      }| j                  ||d          | j                  |j                  d
       y)z#Should refetch when cache is stale.r"   z Updated prompt: Hello, {{name}}!r8   rO   r   <   rQ   r        @r[   Nr\   )	r   rU   rA   rB   updated_prompt_responserC   rD   rV   rW   s	            r    test_refetch_when_cache_is_stalez/TestPromptsGet.test_refetch_when_cache_is_stale   s
    $0044#
''#
8#
 4#<#<=#:; 
 "(	**,'" ++mr+B$";";H"EF,,a0 "(	 ++mr+B"9("CD,,a0r   zposthog.ai.prompts.logc                 &   |j                   j                  }t        | j                        t	        d      g|_        d|_         | j                         }t        |      }|j                  dd      }| j                  || j                  d          d|_         |j                  dd      }| j                  || j                  d          |j                  j                          |j                  j                  }	| j                  d	|	d
   d
          y)z5Should use stale cache on fetch failure with warning.r8   Network errorrO   r   ra   rQ   r"   rb   zusing stale cacher   N)r;   r<   r	   r3   	Exceptionr]   r/   r   r=   warningassert_calledr?   r@   )
r   mock_logrU   rA   rB   rC   rD   rV   rW   warning_calls
             r   2test_use_stale_cache_on_fetch_failure_with_warningzATestPromptsGet.test_use_stale_cache_on_fetch_failure_with_warning   s     $00444#<#<=o& 
 "(	**,'" ++mr+B$";";H"EF "(	 ++mr+B$";";H"EF 	&&(''11)<?1+=>r   c                 d   |j                   j                  }t        d      |_        | j	                         }t        |      }d}|j                  d|      }| j                  ||       |j                  j                          |j                  j                  }| j                  d|d   d          y)z?Should use fallback when no cache and fetch fails with warning.rf   Default system prompt.r   fallbackzusing fallbackr   N)r;   r<   rg   r]   r/   r   r=   rh   ri   r?   r@   )	r   rj   rA   rB   rC   rD   rp   rE   rk   s	            r   <test_use_fallback_when_no_cache_and_fetch_fails_with_warningzKTestPromptsGet.test_use_fallback_when_no_cache_and_fetch_fails_with_warning   s     $0044(9**,'"+]X>* 	&&(''11&Q(:;r   c                 F   |j                   j                  }t        d      |_        | j	                         }t        |      }| j                  t              5 }|j                  d       ddd       | j                  dt        j                               y# 1 sw Y   /xY w)z9Should throw when no cache, no fallback, and fetch fails.rf   r   N
r;   r<   rg   r]   r/   r   assertRaisesr@   str	exceptionr   rA   rB   rC   rD   contexts         r   4test_throw_when_no_cache_no_fallback_and_fetch_failszCTestPromptsGet.test_throw_when_no_cache_no_fallback_and_fetch_fails   s     $0044(9**,'"y)WKK& * 	os7+<+<'=> *)s   BB latestz%Prompt "nonexistent-prompt" not found	versionedr#      z/Prompt "nonexistent-prompt" version 3 not foundc                 L   |j                   j                  }t        dd      |_         | j                         }t	        |      }| j                  t              5 } |j                  di | ddd       | j                  |t        j                               y# 1 sw Y   /xY w)z=Should handle 404 responses for latest and versioned prompts.i  Fr   r   N)znonexistent-prompt
r;   r<   r	   r/   r   rt   rg   r@   ru   rv   )	r   	_scenario
get_kwargsexpected_messagerA   rB   rC   rD   rx   s	            r   test_handle_404_responsez'TestPromptsGet.test_handle_404_response  s     $0044 , G**,'"y)WGKK;
; * 	&G,=,=(>? *)s   BB#c                 J   |j                   j                  }t        dd      |_         | j                         }t	        |      }| j                  t              5 }|j                  d       ddd       | j                  dt        j                               y# 1 sw Y   /xY w)zShould handle 403 response.i  Fr~   zrestricted-promptNz,Access denied for prompt "restricted-prompt"r   rw   s         r   test_handle_403_responsez'TestPromptsGet.test_handle_403_response   s     $0044 , G**,'"y)WKK+, * 	:C@Q@Q<R	
 *)s   BB"c                     | j                  d      }t        |      }| j                  t              5 }|j	                  d       ddd       | j                  dt        j                               y# 1 sw Y   /xY w)z4Should throw when no personal_api_key is configured.N)r)   r   z-personal_api_key is required to fetch promptsr/   r   rt   rg   r<   r@   ru   rv   r   rC   rD   rx   s       r   .test_throw_when_no_personal_api_key_configuredz=TestPromptsGet.test_throw_when_no_personal_api_key_configured0  sg    **D*A'"y)WKK& * 	;SARAR=S	
 *)   A33A<c                     | j                  d      }t        |      }| j                  t              5 }|j	                  d       ddd       | j                  dt        j                               y# 1 sw Y   /xY w)z3Should throw when no project_api_key is configured.N)r,   r   z,project_api_key is required to fetch promptsr   r   s       r   -test_throw_when_no_project_api_key_configuredz<TestPromptsGet.test_throw_when_no_project_api_key_configured<  sg    **4*@'"y)WKK& * 	:C@Q@Q<R	
 *)r   c                 L   |j                   j                  }t        ddi      |_         | j                         }t	        |      }| j                  t              5 }|j                  d       ddd       | j                  dt        j                               y# 1 sw Y   /xY w)z6Should throw when API returns invalid response format.invalidresponser8   r   NInvalid response formatr   rw   s         r   3test_throw_when_api_returns_invalid_response_formatzBTestPromptsGet.test_throw_when_api_returns_invalid_response_formatH  s     $0044 ,	:7N O**,'"y)WKK& * 	/W5F5F1GH *)s   BB#c                 :   |j                   j                  }t        | j                        |_         | j	                  d      }t        |      }|j                  d       |j                  }| j                  |d   d   j                  d      d|d   d           y)	z,Should use custom host from PostHog options.r8   https://eu.posthog.com)r-   r   r   zahttps://eu.posthog.com/api/environments/@current/llm_prompts/name/test-prompt/?token=phc_test_keyzExpected URL to start with 'https://eu.posthog.com/api/environments/@current/llm_prompts/name/test-prompt/?token=phc_test_key', got N)	r;   r<   r	   r3   r/   r   r?   
assertTrue
startswithr   rA   rB   rC   rD   r?   s         r   )test_use_custom_host_from_posthog_optionsz8TestPromptsGet.test_use_custom_host_from_posthog_optionsV  s     $0044 ,t7P7P Q**0H*I'"M"&&	aLO&&s S  T]  ^_  T`  ab  Tc  Sd  e		
r   c                    |j                   j                  }t        | j                        |_         d|_         | j	                         }t        |      }|j                  d       | j                  |j                  d       d|_         |j                  d       | j                  |j                  d       d|_         |j                  d       | j                  |j                  d       y)	z<Should use default cache TTL (5 minutes) when not specified.r8   rO   r   r   g     `@g     @@r[   NrS   r   rU   rA   rB   rC   rD   s         r   $test_use_default_cache_ttl_5_minutesz3TestPromptsGet.test_use_default_cache_ttl_5_minutesi  s     $0044 ,t7P7P Q!'	**,'" 	M",,a0 "3	 	M",,a0 "3	 	M",,a0r   c                 p   |j                   j                  }t        | j                        |_         d|_         | j	                         }t        |d      }|j                  d       | j                  |j                  d       d|_         |j                  d       | j                  |j                  d       y	)
z5Should use custom default cache TTL from constructor.r8   rO   ra   )default_cache_ttl_secondsr   r   rb   r[   NrS   r   s         r   2test_use_custom_default_cache_ttl_from_constructorzATestPromptsGet.test_use_custom_default_cache_ttl_from_constructor  s     $0044 ,t7P7P Q!'	**,'R@ 	M",,a0 "(	 	M",,a0r   c                    |j                   j                  }t        | j                        |_         | j	                         }t        |      }|j                  d       |j                  }| j                  |d   d   d       y)z7Should URL-encode prompt names with special characters.r8   zprompt with spaces/and/slashesr   z|https://us.posthog.com/api/environments/@current/llm_prompts/name/prompt%20with%20spaces%2Fand%2Fslashes/?token=phc_test_keyN)r;   r<   r	   r3   r/   r   r?   r=   r   s         r   4test_url_encode_prompt_names_with_special_characterszCTestPromptsGet.test_url_encode_prompt_names_with_special_characters  sw     $0044 ,t7P7P Q**,'"45&&	aLO K	
r   c                 ^   |j                   j                  }t        | j                        |_         t	        dd      }|j                  d      }| j                  || j                  d          |j                  }| j                  |d   d   d       | j                  |d	   d
   d   d       y)z4Should work with direct options (no PostHog client).r8   phx_direct_keyphc_direct_keyr)   r,   r   r"   r   zchttps://us.posthog.com/api/environments/@current/llm_prompts/name/test-prompt/?token=phc_direct_keyr   r:   r9   zBearer phx_direct_keyN)r;   r<   r	   r3   r   r=   r?   )r   rA   rB   rD   rE   r?   s         r   /test_work_with_direct_options_no_posthog_clientz>TestPromptsGet.test_work_with_direct_options_no_posthog_client  s     $0044 ,t7P7P Q-?O
 ]+!:!:8!DE&&	aLOq	
 	aL#O46M	
r   c                     |j                   j                  }t        | j                        |_         t	        ddd      }|j                  d       |j
                  }| j                  |d   d   d       y	)
z+Should use custom host from direct options.r8   r   r   r   )r)   r,   r-   r   r   zchttps://eu.posthog.com/api/environments/@current/llm_prompts/name/test-prompt/?token=phc_direct_keyN)r;   r<   r	   r3   r   r?   r=   )r   rA   rB   rD   r?   s        r   (test_use_custom_host_from_direct_optionsz7TestPromptsGet.test_use_custom_host_from_direct_options  sp     $0044 ,t7P7P Q-,)
 	M"&&	aLOq	
r   c                 R   |j                   j                  }t        | j                        |_         d|_         t	        ddd      }|j                  d       | j                  |j                  d       d	|_         |j                  d       | j                  |j                  d
       y)z8Should use custom default cache TTL from direct options.r8   rO   r   r   ra   )r)   r,   r   r   r   rb   r[   N)r;   r<   r	   r3   r   r=   rT   )r   rU   rA   rB   rD   s        r   5test_use_custom_default_cache_ttl_from_direct_optionszDTestPromptsGet.test_use_custom_default_cache_ttl_from_direct_options  s     $0044 ,t7P7P Q!'	-,&(
 	M",,a0 "(	 	M",,a0r   N)r   r   r   r   r   rF   rL   rX   r_   rd   rl   rq   ry   r   expandr   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r5   r5   4   s   -
,-
 .
, ,-
 .
. ,-
)*1 + .1, ,- 1 . 1D ,-
)*1 + .1< ,-
)*
#$? % + .?< ,-
#$< % .<( ,-? .? ]rBCAA	
	 ,-@ .	@ ,-
 .




 ,-I .I ,-
 .
$ ,-
)*1 + .16 ,-
)*1 + .1, ,-
 .
  ,-
 .
* ,-
 .
& ,-
)*1 + .1r   r5   c                       e Zd ZdZ ed      d        Z ed      d        Z ed       ed      d               Z ed      d        Z ed      d        Z	 ed      d	        Z
 ed      d
        Zy)TestPromptsGetWithMetadataz0Tests for Prompts.get() with with_metadata=True.r6   c           	         |j                   j                  }t        | j                        |_         | j	                         }t        |      }|j                  dd      }| j                  |t        d| j                  d   dd             y	)
z@Should return a PromptResult with source='api' on a fresh fetch.r8   r   Twith_metadataapir"   r   sourcer"   r!   r#   Nr;   r<   r	   r3   r/   r   r=   r   r   rA   rB   rC   rD   rE   s         r   8test_return_prompt_result_with_source_api_on_fresh_fetchzSTestPromptsGetWithMetadata.test_return_prompt_result_with_source_api_on_fresh_fetch  s    
 $0044 ,t7P7P Q**,'"]$?00:"		
r   c                    |j                   j                  }t        | j                        |_         | j	                         }t        |      }|j                  dd       |j                  ddd      }| j                  |j                  d       | j                  |j                  | j                  d          | j                  |j                  d       | j                  |j                  d	       | j                  |j                  d	       y
)z2Should return source='cache' on a fresh cache hit.r8   r   Tr   rP   r   rR   cacher"   r   N)r;   r<   r	   r3   r/   r   r=   r   r"   r!   r#   rT   r   s         r   +test_return_source_cache_on_fresh_cache_hitzFTestPromptsGetWithMetadata.test_return_source_cache_on_fresh_cache_hit  s     $0044 ,t7P7P Q**,'" 	M6 ]$RUV0(A(A((KLm4+,,a0r   rM   c                    |j                   j                  }t        | j                        t	        d      g|_        d|_         | j                         }t        |      }|j                  ddd       d|_         |j                  ddd      }| j                  |j                  d	       | j                  |j                  | j                  d
          | j                  |j                  d       | j                  |j                  d       y)zEShould return source='stale_cache' on fetch failure with stale cache.r8   rf   rO   r   Tra   r   rb   stale_cacher"   r   N)r;   r<   r	   r3   rg   r]   r/   r   r=   r   r"   r!   r#   r   rU   rA   rB   rC   rD   rE   s          r   /test_return_source_stale_cache_on_fetch_failurezJTestPromptsGetWithMetadata.test_return_source_stale_cache_on_fetch_failure$  s     $00444#<#<=o& 
 "(	**,'" 	ML "(	 ]$RTU6(A(A((KLm4+r   c           	          |j                   j                  }t        d      |_        | j	                         }t        |      }|j                  ddd      }| j                  |t        dddd             y)	zBShould return source='code_fallback' with name=None, version=None.rf   r   Trn   )r   rp   code_fallbackNr   )r;   r<   rg   r]   r/   r   r=   r   r   s         r   3test_return_source_code_fallback_with_none_metadatazNTestPromptsGetWithMetadata.test_return_source_code_fallback_with_none_metadataB  s|     $0044(9**,'"8P  
 	&/		
r   c                 J   |j                   j                  }t        d      |_        | j	                         }t        |      }| j                  t              5 }|j                  dd       ddd       | j                  dt        j                               y# 1 sw Y   /xY w)z+Should throw when no cache and no fallback.rf   r   Tr   Nrs   rw   s         r   (test_throw_when_no_cache_and_no_fallbackzCTestPromptsGetWithMetadata.test_throw_when_no_cache_and_no_fallbackY  s     $0044(9**,'"y)WKKTK: * 	os7+<+<'=> *)s   BB"c           	         |j                   j                  }t        i | j                  ddd      |_         | j	                         }t        |      }|j                  ddd      }| j                  |t        dddd	             y
)z=Should return correct version metadata for versioned fetches.r|   zVersion 3 prompt)r#   r"   r8   r   T)r   r#   r   r   Nr   r   s         r   8test_return_correct_version_metadata_for_versioned_fetchzSTestPromptsGetWithMetadata.test_return_correct_version_metadata_for_versioned_fetchg  s    
 $0044 ,++,!
 **,'"]$J)"		
r   c           	         |j                   j                  }t        | j                        |_         | j	                         }t        |      }|j                  dd      }| j                  || j                  d          |j                  dd      }| j                  |t        d| j                  d   dd	             | j                  |j                  d       y
)zFShould share cache between with_metadata=True and with_metadata=False.r8   r   Fr   r"   Tr   r   r   N)	r;   r<   r	   r3   r/   r   r=   r   rT   )r   rA   rB   rC   rD   string_resultmetadata_results          r   (test_share_cache_with_non_metadata_callszCTestPromptsGetWithMetadata.test_share_cache_with_non_metadata_calls  s     $0044 ,t7P7P Q**,'"  MG(A(A((KL "++m4+H00:"		
 	,,a0r   N)r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r     s    :
,-
 .
, ,-1 .1( ,-
)*, + .,8 ,-
 .
, ,-? .? ,-
 .
8 ,-1 .1r   r   c                   Z    e Zd ZdZ ej
                  g d       ed      d               Zy) TestPromptsGetDeprecationWarningzCTests for the deprecation warning when with_metadata is not passed.))
not_passedNr   )explicit_falseFr   )explicit_trueTr   r6   c                 
   |j                   j                  }t        | j                        |_         | j	                         }t        |      }i }|||d<   t        j                  d      5 }	t        j                  d        |j                  di |  |j                  di | ddd       	D 
cg c]  }
t        |
j                  t              s|
! }}
| j                  t        |      |       y# 1 sw Y   OxY wc c}
w )z7Should emit the correct number of deprecation warnings.r8   Nr   T)recordalways)r   )r;   r<   r	   r3   r/   r   warningscatch_warningssimplefilter
issubclasscategoryDeprecationWarningr=   len)r   r   r   expected_warningsrA   rB   rC   rD   kwargscaughtwdeprecation_warningss               r   test_deprecation_warning_countz?TestPromptsGetDeprecationWarning.test_deprecation_warning_count  s     $0044 ,t7P7P Q**,'"$&3F?#$$D1V!!(+GKK00GKK00	 2  
!AJJ8J!KAv 	  
 	124EF 21 
s   ,:C42D D 4C=N)r   r   r   r   r   r   r   r   r   r   r   r   r     s;    M]	
 ,-G .Gr   r   c            
           e Zd ZdZ ej
                  ddddfddddfd	dd
ddfdddddfg       ed      d               Zy) TestPromptsApiResponseValidationz/Tests for strengthened API response validation.missing_namehellor   rI   missing_versiontest)r"   r!   name_not_string{   )r"   r!   r#   version_not_int1r6   c                 L   |j                   j                  }t        |      |_         | j                         }t	        |      }| j                  t              5 }|j                  dd       ddd       | j                  dt        j                               y# 1 sw Y   /xY w)zAShould reject API responses with missing or invalid name/version.r8   r   Tr   Nr   r   )r   r   r   rA   rB   rC   rD   rx   s           r   .test_reject_api_response_with_invalid_metadatazOTestPromptsApiResponseValidation.test_reject_api_response_with_invalid_metadata  s     $0044 ,y A**,'"y)WKKTK: * 	/W5F5F1GH *)s   BB#N)r   r   r   r   r   r   r   r   r   r   r   r   r     ss    9]A>?7F CD7CA NO7Fs ST		
 ,-I .Ir   r   c                   R    e 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)TestPromptsCompilez'Tests for the Prompts.compile() method.c                     | j                         }t        |      }|j                  dddi      }| j                  |d       y)z!Should replace a single variable.Hello, {{name}}!r!   WorldHello, World!Nr/   r   compiler=   r   rC   rD   rE   s       r   test_replace_a_single_variablez1TestPromptsCompile.test_replace_a_single_variable  s@    **,'"!3fg5FG1r   c                     | j                         }t        |      }|j                  ddddd      }| j                  |d       y)z"Should replace multiple variables.z?Hello, {{name}}! Welcome to {{company}}. Your tier is {{tier}}.Johnz	Acme Corppremium)r!   companytierz8Hello, John! Welcome to Acme Corp. Your tier is premium.Nr   r   s       r   test_replace_multiple_variablesz2TestPromptsCompile.test_replace_multiple_variables  sK    **,'"MYG

 	N	
r   c                     | j                         }t        |      }|j                  dddi      }| j                  |d       y)zShould handle numbers.zYou have {{count}} items.count*   zYou have 42 items.Nr   r   s       r   test_handle_numbersz&TestPromptsCompile.test_handle_numbers  s@    **,'"!<wmL!56r   c                     | j                         }t        |      }|j                  dddi      }| j                  |d       y)zShould handle booleans.zFeature enabled: {{enabled}}enabledTzFeature enabled: TrueNr   r   s       r   test_handle_booleansz'TestPromptsCompile.test_handle_booleans  sA    **,'"!?)TARS!89r   c                     | j                         }t        |      }|j                  dddi      }| j                  |d       y)z+Should leave unmatched variables unchanged.z+Hello, {{name}}! Your {{unknown}} is ready.r!   r   z(Hello, World! Your {{unknown}} is ready.Nr   r   s       r   (test_leave_unmatched_variables_unchangedz;TestPromptsCompile.test_leave_unmatched_variables_unchanged  sE    **,'"9FG;L
 	!KLr   c                     | j                         }t        |      }|j                  di       }| j                  |d       y)z(Should handle prompts with no variables.zYou are a helpful assistant.Nr   r   s       r   %test_handle_prompts_with_no_variablesz8TestPromptsCompile.test_handle_prompts_with_no_variables  s<    **,'"!?D!?@r   c                     | j                         }t        |      }|j                  di       }| j                  |d       y)z#Should handle empty variables dict.r   Nr   r   s       r    test_handle_empty_variables_dictz3TestPromptsCompile.test_handle_empty_variables_dict   s<    **,'"!3R8!34r   c                     | j                         }t        |      }|j                  dddi      }| j                  |d       y)z8Should handle multiple occurrences of the same variable.z#Hello, {{name}}! Goodbye, {{name}}!r!   r   zHello, World! Goodbye, World!Nr   r   s       r   1test_handle_multiple_occurrences_of_same_variablezDTestPromptsCompile.test_handle_multiple_occurrences_of_same_variable)  sE    **,'"1FG3D
 	!@Ar   c                 j    t        dd      }|j                  dddi      }| j                  |d       y)	z/Should work with direct options initialization.r0   r1   r   r   r!   r   r   Nr   r   r=   r   rD   rE   s      r   ,test_work_with_direct_options_initializationz?TestPromptsCompile.test_work_with_direct_options_initialization4  s9    +^
 !3fg5FG1r   c                 j    t        dd      }|j                  dddi      }| j                  |d       y)	z%Should handle variables with hyphens.r0   r1   r   zUser ID: {{user-id}}zuser-id12345zUser ID: 12345Nr	  r
  s      r   "test_handle_variables_with_hyphensz5TestPromptsCompile.test_handle_variables_with_hyphens>  s:    +^
 !7)W9MN!12r   c                 j    t        dd      }|j                  dddi      }| j                  |d       y)	z"Should handle variables with dots.r0   r1   r   zCompany: {{company.name}}zcompany.nameAcmezCompany: AcmeNr	  r
  s      r   test_handle_variables_with_dotsz2TestPromptsCompile.test_handle_variables_with_dotsH  s9    +^
 !<~v>VW1r   N)r   r   r   r   r   r   r   r   r  r  r  r  r  r  r  r   r   r   r   r     s?    12
7:	MA5	B232r   r   c                       e Zd ZdZ ed      d        Z ed       ed      d               Z ed      d        Z ed      d        Z ed      d        Z	 ed      d	        Z
 ed      d
        Zy)TestPromptsCaptureErrorsz$Tests for the capture_errors option.r6   c                 f   |j                   j                  }t        d      |_        | j	                         }t        |d      }|j                  ddd      }| j                  |d       |j                  j                          |j                  j                  d   d   }| j                  dt        |             |j                  j                  j                  d	   }| j                  |d
   d       | j                  |d   d       | j                  |d   d       | j                  |d   d       y)zHShould call capture_exception on fetch failure when capture_errors=True.rf   Tcapture_errorsr   fallback promptr|   )rp   r#   r   
propertiesz$lib_featurez
ai.promptsprompt_nameprompt_versionposthog_hostr2   N)r;   r<   rg   r]   r/   r   r=   capture_exceptionr>   r?   r@   ru   r   )r   rA   rB   rC   rD   rE   captured_excr  s           r   <test_capture_exception_called_on_fetch_failure_with_fallbackzUTestPromptsCaptureErrors.test_capture_exception_called_on_fetch_failure_with_fallbackV  s   
 $0044(9**,'$7]5FPQR!23!!44600::1=a@os<'89..88??M
N3\BM2MB$45q9N35MNr   rM   c                    |j                   j                  }t        | j                        t	        d      g|_        d|_         | j                         }t        |d      }|j                  dd       d	|_         |j                  dd      }| j                  || j                  d
          |j                  j                          y)z?Should call capture_exception when falling back to stale cache.r8   rf   rO   Tr  r   ra   rQ   rb   r"   N)r;   r<   r	   r3   rg   r]   r/   r   r=   r  r>   r   s          r   ?test_capture_exception_called_on_fetch_failure_with_stale_cachezXTestPromptsCaptureErrors.test_capture_exception_called_on_fetch_failure_with_stale_cachen  s     $00444#<#<=o& 
 "(	**,'$7 	MR8 "(	 ]bA!:!:8!DE!!446r   c                 4   |j                   j                  }t        d      |_        | j	                         }t        |d      }| j                  t              5  |j                  d       ddd       |j                  j                          y# 1 sw Y   $xY w)zWShould call capture_exception even when the error is re-raised (no fallback, no cache).rf   Tr  r   N)	r;   r<   rg   r]   r/   r   rt   r  r>   r   rA   rB   rC   rD   s        r   2test_capture_exception_called_when_error_is_raisedzKTestPromptsCaptureErrors.test_capture_exception_called_when_error_is_raised  sx     $0044(9**,'$7y)KK& * 	!!446 *)s   BBc                     |j                   j                  }t        d      |_        | j	                         }t        |      }|j                  dd       |j                  j                          y)zFShould NOT call capture_exception when capture_errors=False (default).rf   r   r  ro   N)r;   r<   rg   r]   r/   r   r  assert_not_calledr"  s        r   6test_no_capture_exception_when_capture_errors_is_falsezOTestPromptsCaptureErrors.test_no_capture_exception_when_capture_errors_is_false  s]     $0044(9**,'"M,=>!!335r   c                     |j                   j                  }t        d      |_        t	        ddd      }|j                  dd      }| j                  |d       y	)
zAShould not error when capture_errors=True but no client provided.rf   r0   r1   T)r)   r,   r  r   r  ro   N)r;   r<   rg   r]   r   r=   )r   rA   rB   rD   rE   s        r   (test_no_capture_exception_without_clientzATestPromptsCaptureErrors.test_no_capture_exception_without_client  s[     $0044(9+*
 ]5FG!23r   c                     |j                   j                  }t        | j                        |_         | j	                         }t        |d      }|j                  d       |j                  j                          y)z6Should NOT call capture_exception on successful fetch.r8   Tr  r   N)r;   r<   r	   r3   r/   r   r  r%  r"  s        r   -test_no_capture_exception_on_successful_fetchzFTestPromptsCaptureErrors.test_no_capture_exception_on_successful_fetch  s`     $0044 ,t7P7P Q**,'$7M"!!335r   c                    |j                   j                  }t        d      |_        | j	                         }t        d      |j
                  _        t        |d      }|j                  dd      }| j                  |d       y)	zJIf capture_exception itself throws, the fallback should still be returned.rf   zcapture failedTr  r   r  ro   N)r;   r<   rg   r]   r/   r  r   r=   r   s         r   7test_capture_exception_failure_does_not_affect_fallbackzPTestPromptsCaptureErrors.test_capture_exception_failure_does_not_affect_fallback  st     $0044(9**,09:J0K!!-'$7]5FG!23r   N)r   r   r   r   r   r  r   r#  r&  r(  r*  r,  r   r   r   r  r  S  s    .
,-O .O. ,-
)*7 + .72 ,-7 .7 ,-
6 .
6 ,-4 .4 ,-
6 .
6 ,-4 .4r   r  c                       e Zd ZdZd Zd Z ed      d        Z ed      d        Z ed      d        Z	 ed      d        Z
y	)
TestPromptsClearCachez+Tests for the Prompts.clear_cache() method.c                     i | j                   ddd}i | j                   ddd}t        |      t        |      g|_        |j                  d       |j                  dd       ||fS )	zEPopulate cache with latest and versioned entries for the same prompt.rZ   r[   rI   rH   r   r8   r   rJ   )r3   r	   r]   r<   )r   rD   rB   r^   rK   s        r   _populate_versioned_cachez/TestPromptsClearCache._populate_versioned_cache  s    "
''"
%"

%
''%
(%
! #9:#<= 

 	M"M1-%'@@@r   c                     | j                         }t        |      }| j                  t              5 }|j	                  d       ddd       | j                  dt        j                               y# 1 sw Y   /xY w)zDShould enforce that versioned cache clearing requires a prompt name.r   rJ   Nzrequires 'name')r/   r   rt   r   clear_cacher@   ru   rv   r   s       r   <test_clear_cache_with_version_and_no_name_raises_value_errorzRTestPromptsClearCache.test_clear_cache_with_version_and_no_name_raises_value_error  se    **,'"z*g* + 	'W->->)?@ +*s   A22A;r6   c                 T   |j                   j                  }i | j                  ddi}t        | j                        t        |      t        | j                        g|_        | j                         }t        |      }|j                  d       |j                  d       | j                  |j                  d       |j                  d       |j                  d       | j                  |j                  d       |j                  d       | j                  |j                  d       y)z*Should clear a specific prompt from cache.r!   other-promptr8   r   r[   r|   N
r;   r<   r3   r	   r]   r/   r   r=   rT   r2  r   rA   rB   other_prompt_responserC   rD   s         r   'test_clear_a_specific_prompt_from_cachez=TestPromptsClearCache.test_clear_a_specific_prompt_from_cache  s     $0044 U4#<#< Ufn U 4#<#<=#894#<#<= 
 **,'" 	M"N#,,a0 	M* 	M",,a0 	N#,,a0r   c                    |j                   j                  }| j                         }t        |      }| j	                  ||      \  }}| j                  |j                  d       t        |      g|_        |j                  dd       |j                  d       | j                  |j                  d       |j                  dd       | j                  |j                  d       y)z:Should clear only the requested prompt version from cache.r[   r8   r   r   rJ   r|   N
r;   r<   r/   r   r0  r=   rT   r	   r]   r2  )r   rA   rB   rC   rD   _rK   s          r   /test_clear_a_specific_prompt_version_from_cachezETestPromptsClearCache.test_clear_a_specific_prompt_version_from_cache  s     $0044**,'"'+'E'Egx'X$$,,a0 ,7P QRM15M",,a0M1-,,a0r   c                    |j                   j                  }| j                         }t        |      }| j	                  ||      \  }}| j                  |j                  d       t        |      t        |      g|_        |j                  d       |j                  d       |j                  dd       | j                  |j                  d       y)zIShould clear latest and versioned cache entries for the same prompt name.r[   r8   r   r   rJ      Nr;  )r   rA   rB   rC   rD   r^   rK   s          r   3test_clear_a_prompt_name_clears_all_cached_versionszITestPromptsClearCache.test_clear_a_prompt_name_clears_all_cached_versions&  s     $0044**,'" **7H= 	: 9 	,,a0 #9:#<= 
 	M*M"M1-,,a0r   c                 0   |j                   j                  }i | j                  ddi}t        | j                        t        |      t        | j                        t        |      g|_        | j                         }t        |      }|j                  d       |j                  d       | j                  |j                  d       |j                          |j                  d       |j                  d       | j                  |j                  d       y)z=Should clear all prompts from cache when no name is provided.r!   r5  r8   r   r[   r?  Nr6  r7  s         r   !test_clear_all_prompts_from_cachez7TestPromptsClearCache.test_clear_all_prompts_from_cache=  s     $0044 U4#<#< Ufn U 4#<#<=#894#<#<=#89	 
 **,'" 	M"N#,,a0 	 	M"N#,,a0r   N)r   r   r   r   r0  r3  r   r9  r=  r@  rB  r   r   r   r.  r.    sy    5A,A ,-1 .1< ,-1 .1& ,-1 .1, ,-1 .1r   r.  __main__)unittestr   unittest.mockr   r   r   posthog.ai.promptsr   r   r	   TestCaser   r5   r   r   r   r   r  r.  r   mainr   r   r   <module>rI     s      * ' 4 (## 8~1[ ~1Bg1 g1T"G{ "GJI{ I8p2 p2fz4{ z4zH1K H1V zHMMO r   