
    P1ifL                     J   d Z ddlZddlmZmZmZ ddlmZ ddlm	Z	 ddl
m
Z
 ddlmZmZmZmZmZmZmZmZ  G d d	      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 G d de      Z G d de      Zy)z
Test cases for LiuYao AI analysis functionality.

This module tests various scenarios including normal cases, edge cases, and outliers.
    N)Mockpatch	MagicMock)TestCase)timezone)datetime)LiuYaoConstantsDataFormatterResponseValidatorget_hexagram_nameget_trigram_nameidentify_changing_linesanalyze_liuyaoprepare_liuyao_promptc                       e Zd ZdZd Zd Zy)
MockLiuYaozMock LiuYao object for testing.c                    |j                  dd      | _        |j                  dd      | _        |j                  dt        j                               | _        |j                  dd      | _        |j                  dd	      | _        |j                  d
d      | _        |j                  dd      | _	        |j                  dd      | _
        |j                  dd      | _        |j                  dd      | _        |j                  di       | _        |j                  dd       | _        |j                  dd      | _        |j                  dd       | _        y )Nid   questionu   测试问题qdatey1111y20y3y41y5y6reading dataai_analysisanalysis_statuspendinganalysis_timestamp)getr   r   r   nowr   r   r   r   r   r   r    r!   r#   r$   r%   r'   selfkwargss     ?/home/cursorai/projects/iching/ai/tests/test_liuyao_analysis.py__init__zMockLiuYao.__init__   s	   **T1%

:~>ZZ8
**T5)**T3'**T5)**T3'**T5)**T5)zz)R0JJvr*	!::mT:%zz*;YG"(**-A4"H    c                      y)zMock save method.N r*   s     r-   savezMockLiuYao.save+   s    r/   N)__name__
__module____qualname____doc__r.   r2   r1   r/   r-   r   r      s    )I r/   r   c                   (    e Zd ZdZd Zd Zd Zd Zy)TestLiuYaoConstantsz,Test LiuYao constants and utility functions.c                     | j                  t        t        j                        d       t	        dd      D ]"  }| j                  |t        j                         $ y)z'Test that all 64 hexagrams are defined.@   r   A   N)assertEquallenr	   HEXAGRAM_NAMESrangeassertInr+   is     r-   test_hexagram_names_coveragez0TestLiuYaoConstants.test_hexagram_names_coverage3   sA    _;;<bAq"AMM!_;;< r/   c                     | j                  t        t        j                        d       g d}|D ]"  }| j	                  |t        j                         $ y)z%Test that all 8 trigrams are defined.   )r   000001010100110101011N)r<   r=   r	   TRIGRAM_NAMESr@   )r+   expected_trigramstrigrams      r-   test_trigram_names_coveragez/TestLiuYaoConstants.test_trigram_names_coverage9   sA    _::;Q?T(GMM'?#@#@A )r/   c                     | j                  t        t        j                        d       t	        dd      D ]"  }| j                  |t        j                         $ y)z*Test line positions are correctly defined.   r      N)r<   r=   r	   LINE_POSITIONSr?   r@   rA   s     r-   test_line_positionsz'TestLiuYaoConstants.test_line_positions@   sA    _;;<a@q!AMM!_;;< r/   c                     | j                  t        t        j                        d       t	        d      D ]"  }| j                  |t        j                         $ y)z*Test six gods names are correctly defined.rR   N)r<   r=   r	   SIX_GOD_NAMESr?   r@   rA   s     r-   test_six_gods_namesz'TestLiuYaoConstants.test_six_gods_namesF   s?    _::;Q?qAMM!_::; r/   N)r3   r4   r5   r6   rC   rP   rU   rX   r1   r/   r-   r8   r8   0   s    6=B=<r/   r8   c                   "    e Zd ZdZd Zd Zd Zy)TestUtilityFunctionszTest utility functions.c                    | j                  t        d      d       | j                  t        d      d       | j                  t        d      d       | j                  t        d      d       | j                  t        d	      d
       y)zTest hexagram name retrieval.r   u   乾 (qián) - The Creativer:   u%   未济 (wèi jì) - Before Completionr   zUnknown hexagram 0r;   zUnknown hexagram 65zUnknown hexagram -1N)r<   r   r+   s    r-   test_get_hexagram_namez+TestUtilityFunctions.test_get_hexagram_nameP   sy     	*1-/KL*2.0WX 	*1-/CD*2.0EF*2.0EFr/   c                     | j                  t        d      d       | j                  t        d      d       | j                  t        d      d       | j                  t        d      d       y	)
zTest trigram name retrieval.r   u   乾 (qián) - HeavenrF   u   坤 (kūn) - Earth222zUnknown trigram 222r"   zUnknown trigram N)r<   r   r]   s    r-   test_get_trigram_namez*TestUtilityFunctions.test_get_trigram_name[   sb     	)%02HI)%02FG 	)%02GH)"-/ABr/   c                 D   t        dddddd      }t        |      }| j                  t        |      h d       t        dddddd      }t        |      }| j                  |g        t        dddddd      }t        |      }| j                  t        |      h d       y)z&Test identification of changing lines.rF   r   r   r   r   r   r   r   r    >   r            rR   >   r   rd      re   rf   rR   N)r   r   r<   set)r+   liuyaochanging_liness      r-   test_identify_changing_linesz1TestUtilityFunctions.test_identify_changing_linese   s     u35UuU08^,o> ssssssK08, u5UuQVW08^,.@Ar/   N)r3   r4   r5   r6   r^   ra   rk   r1   r/   r-   rZ   rZ   M   s    !	GCBr/   rZ   c                   4    e Zd ZdZd Zd Zd Zd Zd Zd Z	y)	TestDataFormatterzTest DataFormatter class.c                 T    t        j                  dd      }| j                  |d       y)zTest formatting string data.ztest stringtestNr
   format_datar<   r+   results     r-   test_format_data_stringz)TestDataFormatter.test_format_data_stringz   s$    **=&A/r/   c                 t    ddd}t        j                  |d      }ddg}|D ]  }| j                  ||        y)z Test formatting dictionary data.value1value2)key1key2ro   u   key1：value1u   key2：value2Nr
   rq   r@   r+   r#   rs   expected_lineslines        r-   test_format_data_dictz'TestDataFormatter.test_format_data_dict   s@     (3**48)?;"DMM$' #r/   c                 r    g d}t        j                  |d      }g d}|D ]  }| j                  ||        y)zTest formatting list data.)item1item2item3ro   Nrz   r{   s        r-   test_format_data_listz'TestDataFormatter.test_format_data_list   s6    ***484"DMM$' #r/   c                     t        j                  dd      }| j                  |d       t        j                  dd      }| j                  |d       y)zTest formatting empty data.Nro   u   无test数据 (No test data)r"   rp   rr   s     r-   test_format_data_emptyz(TestDataFormatter.test_format_data_empty   sH    **48!?@**2v6!?@r/   c                 T   t        d      D ]L  }t        j                  |      }| j                  d|       | j                  t        j
                  |   |       N t        j                  d      }| j                  |d       t        j                  d      }| j                  d|       y)zTest Six Gods formatting.rR   u   六神:Nu"   无六神数据 (No Six Gods data)
   u   未知 (Unknown): 10)r?   r
   format_six_godsr@   r	   rW   r<   )r+   rB   rs   s      r-   test_format_six_godsz&TestDataFormatter.test_format_six_gods   s     qA"2215FMM)V,MM/77:FC  ..t4!EF..r2,f5r/   c                 l   ddgddgd}t        j                  |      }| j                  d|       | j                  d|       | j                  d|       | j                  d	|       t        j                  i       }| j                  |d
       t        j                  d      }| j                  |d
       y)zTest wangshui line formatting.emptyzcs12-3producezcs12-7)daymonthu   日:u   月:u   空u   生r"   N)r
   format_wangshui_liner@   r<   )r+   rel_datars   s      r-   test_format_wangshui_linez+TestDataFormatter.test_format_wangshui_line   s     X&*
 33H=ff%ff%eV$eV$ 33B7$33D9$r/   N)
r3   r4   r5   r6   rt   r~   r   r   r   r   r1   r/   r-   rm   rm   w   s$    #0
((A6%r/   rm   c                   .    e Zd ZdZd Zd Zd Zd Zd Zy)TestResponseValidatorzTest ResponseValidator class.c                     d}t        j                  |      }| j                  |       | j                  |d   d       | j                  |d   d       y)z/Test JSON extraction from markdown code blocks.z
        Here is the analysis:
        ```json
        {
            "think": "This is my thinking",
            "analysis": "This is the analysis"
        }
        ```
        thinkzThis is my thinkinganalysiszThis is the analysisNr   extract_json_from_textassertIsNotNoner<   r+   textrs   s      r-   $test_extract_json_from_text_markdownz:TestResponseValidator.test_extract_json_from_text_markdown   sT     #99$?V$*?@
+-CDr/   c                     d}t        j                  |      }| j                  |       | j                  |d   d       | j                  |d   d       y)zTest direct JSON extraction.z;{"think": "Direct thinking", "analysis": "Direct analysis"}r   zDirect thinkingr   zDirect analysisNr   r   s      r-   "test_extract_json_from_text_directz8TestResponseValidator.test_extract_json_from_text_direct   sP    L"99$?V$*;<
+->?r/   c                 T    d}t        j                  |      }| j                  |       y)zTest handling of invalid JSON.zThis is not JSON at allN)r   r   assertIsNoner   s      r-   #test_extract_json_from_text_invalidz9TestResponseValidator.test_extract_json_from_text_invalid   s%    ("99$?&!r/   c                     d}t        j                  |      }| j                  |d   d       | j                  |d   d       y)z)Test manual field extraction using regex.zJResponse with "think": "Manual thinking" and "analysis": "Manual analysis"r   zManual thinkingr   zManual analysisN)r   extract_fields_manuallyr<   r   s      r-   test_extract_fields_manuallyz2TestResponseValidator.test_extract_fields_manually   sB    ["::4@*;<
+->?r/   c                    d}t        j                  |      }| j                  |d   d       | j                  |d   d       d}t        j                  |      }| j                  |d   |       | j                  |d   d       y)	z"Test complete response validation.z?{"think": "Complete thinking", "analysis": "Complete analysis"}r   zComplete thinkingliuyao_analysiszComplete analysisz$This is just plain text without JSONr"   N)r   validate_liuyao_responser<   )r+   responsers   s      r-   &test_validate_liuyao_response_completez<TestResponseValidator.test_validate_liuyao_response_complete   s     U";;HE*=> 124GH :";;HE 12H="-r/   N)	r3   r4   r5   r6   r   r   r   r   r   r1   r/   r-   r   r      s!    'E @"@.r/   r   c                       e Zd ZdZ ed       ed       ed      d                      Z ed      d        Z ed       ed      d               Zy)	TestAnalyzeLiuYaoz&Test the main analyze_liuyao function.z.ai.utils.liuyao_analysis.prepare_liuyao_promptz*ai.utils.liuyao_analysis.LLMServiceFactoryzai.utils.config.get_ai_configc                    d|_         t               }d|j                  _         d|_        ||j                  _         ddd|_         t               }t        |      }| j                  |       | j                  |d   d       | j                  |d   d	       | j                  |d
   d       | j                  |d   d       | j                  |j                  d       y)zTest successful analysis.Test promptz7{"think": "Test thinking", "analysis": "Test analysis"}z
test-modelztest-provider)providermodelr   zTest thinkingr   zTest analysisr   languagezzh-hans	completedN)
return_valuer   get_completionr   get_servicer   r   r   r<   r%   )r+   mock_get_ai_configmock_factorymock_prepare_promptmock_serviceri   rs   s          r-   test_analyze_liuyao_successz-TestAnalyzeLiuYao.test_analyze_liuyao_success   s     ,9( {3l##0)0<  -7FQ]*^'   ' 	V$/: 12OD,7
+Y7//=r/   c                     d|_         t               }t        |      }| j                  |       | j	                  |j
                  d       y)z4Test analysis failure when prompt preparation fails.Nerror)r   r   r   r   r<   r%   )r+   r   ri   rs   s       r-   test_analyze_liuyao_no_promptz/TestAnalyzeLiuYao.test_analyze_liuyao_no_prompt  sB     ,0('&!//9r/   c                     d|_         t               }d|j                  _         ||j                  _         t	               }t        |      }| j                  |       | j                  |j                  d       y)z$Test handling of empty LLM response.r   r"   r   N)	r   r   r   r   r   r   r   r<   r%   )r+   r   r   r   ri   rs   s         r-   "test_analyze_liuyao_empty_responsez4TestAnalyzeLiuYao.test_analyze_liuyao_empty_response  se     ,9( {35##00<  -'&!//9r/   N)r3   r4   r5   r6   r   r   r   r   r1   r/   r-   r   r      s{    0
;<
78
*+> , 9 =>0 ;<: =: ;<
78: 9 =:r/   r   c                   (    e Zd ZdZd Zd Zd Zd Zy)TestEdgeCasesz#Test edge cases and error handling.c                 x    t        d      }| j                  d|       t        d      }| j                  d|       y)z*Test handling of extreme hexagram numbers.i?B zUnknown hexagramiN)r   r@   rr   s     r-   test_extreme_hexagram_numbersz+TestEdgeCases.test_extreme_hexagram_numbers.  s8     #6*(&1 #4((&1r/   c                 T    g d}|D ]  }t        |      }| j                  d|       ! y)z)Test handling of malformed trigram codes.)1234abc12r"   zUnknown trigramN)r   r@   )r+   
test_casescasers   s       r-   test_malformed_trigram_codesz*TestEdgeCases.test_malformed_trigram_codes8  s*    .
D%d+FMM+V4 r/   c                      G d d      } |       }	 t        |      }| j                  |t               y# t        $ r Y yw xY w)z,Test LiuYao objects with missing attributes.c                       e Zd Zd Zy)KTestEdgeCases.test_liuyao_with_missing_attributes.<locals>.IncompleteLiuYaoc                      d| _         d| _        y )Nr   r   )r   r   r]   s    r-   r.   zTTestEdgeCases.test_liuyao_with_missing_attributes.<locals>.IncompleteLiuYao.__init__B  s    r/   N)r3   r4   r5   r.   r1   r/   r-   IncompleteLiuYaor   A  s    r/   r   N)r   assertIsInstancelistAttributeError)r+   r   ri   rs   s       r-   #test_liuyao_with_missing_attributesz1TestEdgeCases.test_liuyao_with_missing_attributes?  sG    	 	 "#	,V4F!!&$/ 		s   !5 	A Ac                     ddgddddddd	d
gd}t        j                  |d      }| j                  |t               | j	                  d|       y)z/Test DataFormatter with complex nested objects.r   r   N)level2level2br   rd   )abrg   re   )cd)level1list_of_dictscomplexr   )r
   rq   r   strr@   )r+   complex_datars   s      r-   (test_data_formatter_with_complex_objectsz6TestEdgeCases.test_data_formatter_with_complex_objectsQ  sd     #G,
 a a 	
 **<Cfc*h'r/   N)r3   r4   r5   r6   r   r   r   r   r1   r/   r-   r   r   +  s    -25$(r/   r   c                   (    e Zd ZdZd Zd Zd Zd Zy)TestOutlierCaseszTest outlier and unusual cases.c                 t    g d}|D ]/  }t        |      }t        |      }| j                  |t               1 y)z0Test handling of Unicode and special characters.)u   测试中文问题？u   Test with émojis 🔮✨u   Mixed 中英文 questionzSpecial chars: @#$%^&*()r"   )r   Nr   r   r   r   )r+   unicode_questionsr   ri   rs   s        r-   test_unicode_question_textz+TestOutlierCases.test_unicode_question_textf  s:    
 *H2F,V4F!!&$/	 *r/   c           
          g d}|dd D ]>  }|dd D ]4  }t        ||dddd      }t        |      }| j                  |t               6 @ y)z*Test all possible line value combinations.)r   r   r   rF   invalidNrg   r   rc   r   )r+   line_valuesr   r   ri   rs   s         r-   #test_all_possible_line_combinationsz4TestOutlierCases.test_all_possible_line_combinationsv  sV    9bq/B!"1o#rbUuSXY08%%fd3 & "r/   c                     g dddgd}t        j                  |      }t        j                  |      }| j	                  |       y)z(Test handling of array-format responses.)zFirst thoughtzSecond thoughtzThird thoughtzFirst paragraphzSecond paragraph)r   r   N)jsondumpsr   r   r   )r+   array_responsejson_responsers   s       r-   test_response_with_array_formatz0TestOutlierCases.test_response_with_array_format  sF     J*,>?
 

>2";;MJV$r/   c                     ddz  }d| d}t        j                  |      }| j                  |       | j                  t	        |d         t	        |             y)z%Test handling of very long responses.zVery long analysis i  z({"think": "Long thinking", "analysis": "z"}r   N)r   r   r   r<   r=   )r+   	long_textlong_responsers   s       r-   test_extremely_long_responsesz.TestOutlierCases.test_extremely_long_responses  sW    )D0	CI;cR";;MJV$V$567YHr/   N)r3   r4   r5   r6   r   r   r   r   r1   r/   r-   r   r   c  s    )0 4
%Ir/   r   c                   ,    e Zd ZdZ ed      d        Zy)TestIntegrationScenariosz<Test integration scenarios that combine multiple components.z,ai.utils.liuyao_analysis.get_active_templatec                 0   d|_         ddddddddid	ddd
ddd
ddd
ddd
dddddi d}t        dddd|      }t        d      5 }d|i|_         t        |      }| j	                  |       | j                  d|       ddd       y# 1 sw Y   yxY w)z1Test prompt preparation with complex LiuYao data.zUQuestion: {{question}}
Hexagram: {{hexagram_info}}
Changing lines: {{changing_lines}}r   rg   rR   )palaceshiyin)guar   r   r   )oguacgua)gerd   re   rf   )r   r   )yearr   r   hourr   )lybzgod6relu   复杂问题测试r   r   r   )r   r   r   r   r#   z+iching.utils.liuyao.recalculate_liuyao_datar#   N)r   r   r   r   r   r@   )r+   mock_get_active_templater   ri   mock_recalcrs   s         r-   %test_prepare_prompt_with_complex_dataz>TestIntegrationScenarios.test_prepare_prompt_with_complex_data  s     1J - )*1Q?
 1  a( q)Q'a( q) %
* )su
 @A[(.'=K$*62F  (MM.7 BAAs   8BBN)r3   r4   r5   r6   r   r  r1   r/   r-   r   r     s    F
9:&8 ;&8r/   r   c                       e Zd ZdZd Zy)TestResponseValidationSamples7Test response validation with various sample responses.c                    g d}|D ]  }| j                  t        |      dkD  r|dd dz   n|      5  t        j                  |      }| j	                  |t
               | j                  d|       | j                  d|       | j                  t        |d         dkD  xs! t        |d         dkD  xs t        |      dk(         ddd        y# 1 sw Y   xY w)	r
  )z;{"think": "Normal thinking", "analysis": "Normal analysis"}z```json
            {
                "think": "Markdown thinking",
                "analysis": "Markdown analysis"
            }
            ```z4{"think": "Broken JSON", "analysis": "Missing quote}z;This is just plain text analysis without any JSON structurezTSome text before {"think": "Mixed thinking", "analysis": "Mixed analysis"} and afterzC{"think": ["Think 1", "Think 2"], "analysis": ["Para 1", "Para 2"]}r"   aa  {"think": "Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking Very long thinking ", "analysis": "Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis Very long analysis "}2   Nz...)r   r   r   r   )subTestr=   r   r   r   dictr@   
assertTrue)r+   sample_responsesresponse_textrs   s       r-    test_response_validation_samplesz>TestResponseValidationSamples.test_response_validation_samples  s    
> .MSEWZ\E\}Sb'9E'Abop*CCMR %%fd3/8gv. 012Q6 ,w(1,,&!+ qp .pps   BCC	N)r3   r4   r5   r6   r  r1   r/   r-   r	  r	    s
    A/r/   r	  )r6   r   unittest.mockr   r   r   django.testr   django.utilsr   r   ai.utils.liuyao_analysisr	   r
   r   r   r   r   r   r   r   r8   rZ   rm   r   r   r   r   r   r	  r1   r/   r-   <module>r     s   
  0 0   ! 	 	 	 0<( <:'B8 'BTA% A%H4.H 4.n6: 6:r5(H 5(p0Ix 0If*8x *8Z2H 2r/   