§
    yÂj/,  ã            
       óÐ  — d Z ddlZddlZddlZddlZddlZej                             dej                             ej         	                    ej         
                    e¦  «        d¦  «        ¦  «        ¦  «         ddlmZmZmZmZ ddlmZ ddlmZ ddlmZmZ ddlmZ dd	lmZmZ dd
lmZ  G d„ d¦  «        Z G d„ dej         ¦  «        Z!e"dk    r ej#        ¦   «          dS dS )aU  
Unit tests for FreeExile Character Stat Aggregator, Formula Persistence, and Server Engine Integration.
Verifies Path of Exile modifier mathematics, tag filtering, conditional modifiers,
AST generation, SQLite persistence, and ServerEngineLoop registration.
Strictly decoupled, non-trivial test cases with genuine mathematical validations.
é    Nz../../server)ÚModifierTypeÚStatModifierÚEvaluationContextÚAggregatedCharacterStats)ÚFormulaPersistenceService)ÚCharacterStatAggregator)ÚServerEngineLoopÚFiveElements)ÚMeridianStatBonus)ÚAffixÚ	AffixType)ÚItemTypec                   ó@   — e Zd Zddej        fdedededededefd	„Zd
S )ÚMockItemFÚ	MAIN_HANDÚnameÚitem_idÚaffixesÚis_2hÚslotÚ	item_typec                 óh   — || _         || _        || _        || _        || _        ||rdnddœ| _        d S )NÚ
TWO_HANDEDÚ
ONE_HANDED)Úis_two_handedÚgrip)r   r   r   r   r   Úmetadata)Úselfr   r   r   r   r   r   s          úBC:\Projects\FreeExile\tests\unit\test_character_stat_aggregator.pyÚ__init__zMockItem.__init__   sB   € ØˆŒ	ØˆŒØˆŒØ"ˆŒØˆŒ	Ø*/ÈÐ9`¸¸ÐT`ÐaÐaˆŒˆˆó    N)	Ú__name__Ú
__module__Ú__qualname__r   ÚWEAPONÚstrÚlistÚboolr    © r!   r   r   r      s~   € € € € € ØMRÐ`kð  DLô  DSð bð b˜Sð b¨3ð b¸ð bÀdð bÐZ]ð bð  yAð bð bð bð bð bð br!   r   c                   óv   — e Zd Zdd„Zdd„Zdd„Zdd„Zdd„Zdd„Zdd	„Z	dd
„Z
dd„Zdd„Zdd„Zdd„Zdd„ZdS )ÚTestCharacterStatAggregatorÚreturnNc                 ó,   — t          ¦   «         | _        d S )N)r   Ú
aggregator)r   s    r   ÚsetUpz!TestCharacterStatAggregator.setUp)   s   € Ý1Ñ3Ô3ˆŒˆˆr!   c                 ó<  — t          dt          j        dd¬¦  «        g}t          t	          dh¦  «        ¬¦  «        }| j                             ||¬¦  «        }| j                             |t          ¦   «         ¬¦  «        }|                      |j        d¦  «         d	S )
zJVerifies base 50.0 attack + 30.0 flat yields exactly 80.0 without scaling.Úattack_damageç      >@Úgem©ÚsourceÚphysical©Úactive_tags©Úcustom_modifiersÚcontextg      T@N)	r   r   ÚFLATr   Ú	frozensetr.   Úcalculate_statsÚassertEqualr1   )r   ÚmodsÚctxÚstatsÚstats_cleans        r   Útest_flat_modifiers_onlyz4TestCharacterStatAggregator.test_flat_modifiers_only,   s’   € å˜_­lÔ.?ÀÈeÐTÑTÔTÐUˆÝ­I°z°lÑ,CÔ,CÐDÑDÔDˆØ”×/Ò/ÀÈsÐ/ÑSÔSˆØ”o×5Ò5ÀtÕUfÑUhÔUhÐ5ÑiÔiˆØ×Ò˜Ô2°DÑ9Ô9Ð9Ð9Ð9r!   c                 ó   — t          dt          j        dd¬¦  «        t          dt          j        dd¬¦  «        g}| j                             |t          ¦   «         ¬¦  «        }|                      |j        d¦  «         d	S )
z?Verifies additive (1.0 + (Inc - Red)/100.0) percentage scaling.r1   ç      D@Úringr4   ç      $@Úcurser9   ç     @P@N)	r   r   Ú	INCREASEDÚREDUCEDr.   r>   r   r?   r1   ©r   r@   rB   s      r   Ú$test_increased_and_reduced_modifiersz@TestCharacterStatAggregator.test_increased_and_reduced_modifiers4   s{   € õ ˜­,Ô*@À$ÈvÐVÑVÔVÝ˜­,Ô*>ÀÈWÐUÑUÔUð
ˆð ”×/Ò/ÀÕO`ÑObÔObÐ/ÑcÔcˆØ×Ò˜Ô,¨dÑ3Ô3Ð3Ð3Ð3r!   c                 ó   — t          dt          j        dd¬¦  «        t          dt          j        dd¬¦  «        g}| j                             |t          ¦   «         ¬¦  «        }|                      |j        d¦  «         d	S )
zQVerifies multiplicative compound scaling: base * (1 + More/100) * (1 - Less/100).r1   ç      4@Úsupport_gemr4   rH   Údebuffr9   g      K@N)	r   r   ÚMOREÚLESSr.   r>   r   r?   r1   rM   s      r   Útest_more_and_less_multipliersz:TestCharacterStatAggregator.test_more_and_less_multipliers=   s{   € õ ˜­,Ô*;¸TÈ-ÐXÑXÔXÝ˜­,Ô*;¸TÈ(ÐSÑSÔSð
ˆð ”×/Ò/ÀÕO`ÑObÔObÐ/ÑcÔcˆØ×Ò˜Ô,¨dÑ3Ô3Ð3Ð3Ð3r!   c                 ó^  — t          dt          j        dd¬¦  «        t          dt          j        dd¬¦  «        t          dt          j        dd¬¦  «        g}t          t          h d£¦  «        ¬	¦  «        }| j                             ||¬
¦  «        }|  	                    |j
        d¦  «         dS )zPVerifies (Base + Flat) * (1 + Inc/100) * More = (50 + 30) * 1.60 * 1.50 = 192.0.r1   r2   Úswordr4   ç      I@ÚbeltÚtwo_hand_grip>   ÚmeleeÚattackr6   r7   r9   g      h@N)r   r   r<   rK   rS   r   r=   r.   r>   r?   r1   )r   r@   rA   rB   s       r   Ú!test_full_poe_formula_combinationz=TestCharacterStatAggregator.test_full_poe_formula_combinationF   sª   € õ ˜­,Ô*;¸TÈ'ÐRÑRÔRÝ˜­,Ô*@À$ÈvÐVÑVÔVÝ˜­,Ô*;¸TÈ/ÐZÑZÔZð
ˆõ
  ­IÐ6UÐ6UÐ6UÑ,VÔ,VÐWÑWÔWˆØ”×/Ò/ÀÈsÐ/ÑSÔSˆØ×Ò˜Ô,¨eÑ4Ô4Ð4Ð4Ð4r!   c           	      ó
  — t          dt          j        dt          dh¦  «        d¬¦  «        t          dt          j        dt          dh¦  «        d¬¦  «        g}t	          t          dh¦  «        ¬	¦  «        }| j                             ||¬
¦  «        }|                      |j        d¦  «         t	          t          dh¦  «        ¬	¦  «        }| j                             ||¬
¦  «        }|                      |j        d¦  «         dS )zNVerifies modifiers are only evaluated when context tags satisfy required tags.r1   rF   ÚfireÚfire_gem)Útagsr5   rP   ÚcoldÚcold_gemr7   r9   g     €V@g     €Q@N)	r   r   r<   r=   r   r.   r>   r?   r1   )r   r@   Úctx_fireÚ
stats_fireÚctx_coldÚ
stats_colds         r   Útest_tag_based_filteringz4TestCharacterStatAggregator.test_tag_based_filteringQ   sû   € õ ˜­,Ô*;¸TÍ	ÐSYÐRZÑH[ÔH[ÐdnÐoÑoÔoÝ˜­,Ô*;¸TÍ	ÐSYÐRZÑH[ÔH[ÐdnÐoÑoÔoð
ˆõ %µ¸F¸8Ñ1DÔ1DÐEÑEÔEˆØ”_×4Ò4ÀdÐT\Ð4Ñ]Ô]ˆ
Ø×Ò˜Ô1°4Ñ8Ô8Ð8å$µ¸F¸8Ñ1DÔ1DÐEÑEÔEˆØ”_×4Ò4ÀdÐT\Ð4Ñ]Ô]ˆ
Ø×Ò˜Ô1°4Ñ8Ô8Ð8Ð8Ð8r!   c                 ó`  — t          dt          j        ddd¬¦  «        g}t          d¬¦  «        }| j                             ||¬¦  «        }|                      |j        d	¦  «         t          d
¬¦  «        }| j                             ||¬¦  «        }|                      |j        d¦  «         dS )zSVerifies conditional modifier triggers when on_low_health and is skipped otherwise.r1   r2   Úon_low_healthÚlow_hp_node)Ú	conditionr5   gš™™™™™É?)Úcurrent_hp_ratior9   rJ   g      ð?rX   N)r   r   rS   r   r.   r>   r?   r1   )r   r@   Úctx_lowÚ	stats_lowÚctx_fullÚ
stats_fulls         r   Ú(test_conditional_modifiers_on_low_healthzDTestCharacterStatAggregator.test_conditional_modifiers_on_low_health_   sµ   € õ ˜­,Ô*;¸TÈ_ÐerÐsÑsÔsð
ˆõ $°TÐ:Ñ:Ô:ˆØ”O×3Ò3ÀTÐSZÐ3Ñ[Ô[ˆ	Ø×Ò˜Ô0°$Ñ7Ô7Ð7å$°cÐ:Ñ:Ô:ˆØ”_×4Ò4ÀdÐT\Ð4Ñ]Ô]ˆ
Ø×Ò˜Ô1°4Ñ8Ô8Ð8Ð8Ð8r!   c                 ó  — t          dt          j        dddd¬¦  «        }t          dt          j        dddd¬¦  «        }t          dd	||g¦  «        }t	          d
dddd¬¦  «        }| j                             |g|t          ¦   «         ¬¦  «        }|                      |j	        d¦  «         |                      |j
        d¦  «         |                      |j        dd¬¦  «         |                      |j        d         d¦  «         dS )zIVerifies aggregator ingests equipment items and Meridian bonuses cleanly.u   Tháº§n Thá»ƒÚmax_hpéP   )r   Ú
affix_typeÚstat_keyÚmin_valÚmax_valÚcurrent_valu   ToÃ¡i Cá»‘tÚphys_dmgé#   u   Thanh Long Kiáº¿mÚwpn_sword_1é–   rP   gš™™™™™¹?g{®Gáz¤?ç      .@)ÚhpÚdpsÚdps_multÚ	crit_rateÚresist)Ú	inventoryÚmeridian_bonusr;   g      ”@g     à\@gìQ¸…ëÁ?é   )ÚplacesÚhoaN)r   r   ÚPREFIXr   r   r.   r>   r   r?   rt   r1   ÚassertAlmostEqualÚcrit_chanceÚresistances)r   Úaffix_hpÚ
affix_physÚitemÚmeridianrB   s         r   Ú-test_mock_player_items_and_passives_ingestionzITestCharacterStatAggregator.test_mock_player_items_and_passives_ingestionl   s(  € å˜n½Ô9IÐT\ÐfhÐrtð  CEð  Fñ  Fô  FˆÝ ½)Ô:JÐU_ÐikÐuwð  FHð  Iñ  Iô  Iˆ
ÝÐ+¨]¸XÀzÐ<RÑSÔSˆå$¨°ÀÐPTÐ]aÐbÑbÔbˆØ”×/Ò/¸4¸&ÐQYÕctÑcvÔcvÐ/ÑwÔwˆà×Ò˜œ vÑ.Ô.Ð.Ø×Ò˜Ô,¨eÑ4Ô4Ð4Ø×Ò˜uÔ0°$¸qÐÑAÔAÐAØ×Ò˜Ô*¨5Ô1°4Ñ8Ô8Ð8Ð8Ð8r!   c                 óÆ  — t          ddg dd¬¦  «        }| j                             |g¬¦  «        }|                      |j        d¦  «         t          dd	g d
d¬¦  «        }t          ddg d
d¬¦  «        }| j                             ||g¬¦  «        }|                      |j        d         d¦  «         |                      |j                             dd¦  «        d¦  «         dS )z\Verifies 2H weapon grants +50% More damage and Dual-Wield grants +10% More APS & +15% block.u   Cá»± Ä�áº¡i Cá»• Ä�ao 2HÚwpn_2h_bladeTr   )r   r   )r…   ç     ÀR@u   Ä�oáº£n Kiáº¿m 1Úwpn_1h_1Fu   Ä�oáº£n Kiáº¿m 2Úwpn_1h_2ÚOFF_HANDÚattack_speedgffffffò?Úblock_chanceç        r   N)r   r.   r>   r?   r1   ÚassertGreaterÚ	all_statsÚget)r   Úitem_2hÚstats_2hÚ	item_dw_1Ú	item_dw_2Ústats_dws         r   Ú/test_weapon_mechanics_two_handed_and_dual_wieldzKTestCharacterStatAggregator.test_weapon_mechanics_two_handed_and_dual_wieldz   sî   € åÐ5°~ÀrÐQUÐ\gÐhÑhÔhˆØ”?×2Ò2¸g¸YÐ2ÑGÔGˆØ×Ò˜Ô/°Ñ6Ô6Ð6åÐ/°¸RÀuÐS^Ð_Ñ_Ô_ˆ	ÝÐ/°¸RÀuÐS]Ð^Ñ^Ô^ˆ	Ø”?×2Ò2¸iÈÐ=SÐ2ÑTÔTˆØ×Ò˜8Ô-¨nÔ=¸tÑDÔDÐDØ×Ò˜Ô+×/Ò/°ÀÑDÔDÀdÑKÔKÐKÐKÐKr!   c                 ó|  — t          dt          j        dd¬¦  «        t          dt          j        dd¬¦  «        t          dt          j        dd¬¦  «        g}t          d	¦  «        }t          |¬
¦  «        }|                     |d¬¦  «         |                     dd¬¦  «        }|  	                    t          |¦  «        d¦  «         |d         d         }|                      d|¦  «         |d         }|  	                    |d         d         d¦  «         |  	                    |d         d         d¦  «         |  	                    |d         d         d¦  «         |  	                    |d         d         d¦  «         t          j        |¦  «        }|                      t          j        |¦  «        t           ¦  «         dS )zGVerifies AST contains expected node types and serializes to valid JSON.r1   rP   Úflat_srcr4   r   Úinc_srcrH   Úmore_srcz:memory:)Úpersistence_serviceÚplayer_ast_test)r:   Ú	player_idé   )Úlimitr   Úformula_astÚbaseÚast_typeÚConstantÚflatÚSumÚscaleÚScaleFactorÚmoreÚProductN)r   r   r<   rK   rS   r   r   r>   Úget_player_calculationsr?   ÚlenÚassertInÚjsonÚdumpsÚassertIsInstanceÚloadsÚdict)r   r@   Úcalc_serviceÚaggÚhistoryÚast_dataÚatk_astÚ
serializeds           r   Ú)test_ast_hierarchy_and_json_serializationzETestCharacterStatAggregator.test_ast_hierarchy_and_json_serialization†   s�  € õ ˜­,Ô*;¸TÈ*ÐUÑUÔUÝ˜­,Ô*@À$ÈyÐYÑYÔYÝ˜­,Ô*;¸TÈ*ÐUÑUÔUð
ˆõ
 1°Ñ<Ô<ˆÝ%¸,ÐGÑGÔGˆØ×Ò¨TÐ=NÐÑOÔOÐOà×6Ò6Ð7HÐPQÐ6ÑRÔRˆØ×Ò�˜W™œ qÑ)Ô)Ð)Ø˜1”:˜mÔ,ˆØ�Š�o xÑ0Ô0Ð0Ø˜?Ô+ˆà×Ò˜ œ¨Ô4°jÑAÔAÐAØ×Ò˜ œ¨Ô4°eÑ<Ô<Ð<Ø×Ò˜ Ô)¨*Ô5°}ÑEÔEÐEØ×Ò˜ œ¨Ô4°iÑ@Ô@Ð@å”Z Ñ)Ô)ˆ
Ø×Ò�dœj¨Ñ4Ô4µdÑ;Ô;Ð;Ð;Ð;r!   c           	      óÚ  — t          j        ¦   «         5 }t          j                             |d¦  «        }t          |¬¦  «        }|                     dddddiiddd	œd
g¬¦  «        }|                      |d¦  «         |                     d¦  «        }|  	                    |¦  «         |  
                    |d         d¦  «         |  
                    |d         d         d¦  «         |                     d¦  «        }|  
                    t          |¦  «        d¦  «         |  
                    |d         d         d¦  «         |                     ¦   «          ddd¦  «         dS # 1 swxY w Y   dS )zRVerifies disk-backed SQLite database persistence, retrieval, and schema integrity.ztest_formulas.db)Údb_pathÚuser_123Úcalc_123r€   Úvalueg     À’@r•   )rt   r1   r[   )r«   Úcalculation_idr®   Úfinal_statsÚcontext_tagsr   r«   rÍ   rt   r¬   rÌ   N)ÚtempfileÚTemporaryDirectoryÚosÚpathÚjoinr   Úsave_calculationrœ   Úget_calculationÚassertIsNotNoner?   r¸   r¹   Úclose)r   Útmp_dirrÈ   ÚserviceÚrow_idÚrecÚplayer_historys          r   Ú#test_sqlite_persistence_and_queriesz?TestCharacterStatAggregator.test_sqlite_persistence_and_queriesŸ   s®  € åÔ(Ñ*Ô*ð 	¨gÝ”g—l’l 7Ð,>Ñ?Ô?ˆGÝ/¸Ð@Ñ@Ô@ˆGØ×-Ò-Ø$Ø)Ø! G¨VÐ#4Ð5Ø'-ÀÐEÐEØ%˜Yð .ñ ô ˆFð ×Ò˜v qÑ)Ô)Ð)à×)Ò)¨*Ñ5Ô5ˆCØ× Ò  Ñ%Ô%Ð%Ø×Ò˜S Ô-¨zÑ:Ô:Ð:Ø×Ò˜S Ô/°Ô9¸6ÑBÔBÐBà$×<Ò<¸ZÑHÔHˆNØ×Ò�S Ñ0Ô0°!Ñ4Ô4Ð4Ø×Ò˜^¨AÔ.Ð/?Ô@À*ÑMÔMÐMØ�MŠM‰OŒOˆOð)	ð 	ð 	ñ 	ô 	ð 	ð 	ð 	ð 	ð 	ð 	ð 	øøøð 	ð 	ð 	ð 	ð 	ð 	s   ”D?E Å E$Å'E$c           
      ób  — t          ¦   «         }t          d|¬¦  «        }t          ddddddd	d
œ¬¦  «        }|                     ddd|¬¦  «        }|                      |j        d¦  «         |                      |j        d¦  «         |                      |j        d¦  «         |                      |j        d¦  «         |  	                    |j
        ¦  «         |                      |j        t          j                 d¦  «         |j        j        d         }|                      |j        d¦  «         dS )zMVerifies ServerEngineLoop registers CombatActor with calculated stats > 50.0.ç      P@)Ú	cell_sizeÚstat_aggregatorg     €a@g     p—@g      Ð?gÍÌÌÌÌÌ @g      (@g     €F@r2   )r‰   Úthuy)r1   rt   rŒ   Úcrit_multiplierÚ
move_speedr�   r¬   rH   )Ú	entity_idÚ	initial_xÚ	initial_yÚaggregated_statsN)r   r	   r   Úregister_playerr?   Úbase_attackrt   rŒ   rã   Ú
assertTrueÚ	is_playerr�   r
   ÚHOAÚmovement_authorityÚplayersrä   )r   rÁ   ÚengineÚcustom_statsÚactorÚplayer_chars         r   Ú:test_server_engine_loop_registration_with_aggregated_statszVTestCharacterStatAggregator.test_server_engine_loop_registration_with_aggregated_stats·   s;  € å%Ñ'Ô'ˆÝ!¨DÀ#ÐFÑFÔFˆå/ØØØØ ØØ $¨dÐ3Ð3ð
ñ 
ô 
ˆð ×&Ò&Ø 4°4È,ð 'ñ 
ô 
ˆð 	×Ò˜Ô*¨EÑ2Ô2Ð2Ø×Ò˜œ vÑ.Ô.Ð.Ø×Ò˜Ô*¨DÑ1Ô1Ð1Ø×Ò˜Ô.°Ñ5Ô5Ð5Ø�Š˜œÑ(Ô(Ð(Ø×Ò˜Ô*­<Ô+;Ô<¸dÑCÔCÐCàÔ/Ô7¸Ô:ˆØ×Ò˜Ô/°Ñ6Ô6Ð6Ð6Ð6r!   c                 ó„  — t          d¬¦  «        }|                     ddd¬¦  «        }|                      |j        d¦  «         |                      |j        d¦  «         |                      |j        d¦  «         |                      |j        d	¦  «         |                      |j        j        d         j	        d
¦  «         dS )zRVerifies legacy register_player without stats maintains 50.0 attack and 1000.0 HP.rß   )rà   éc   r›   )rå   ræ   rç   rX   g     @�@gš™™™™™©?g      ø?g      @N)
r	   ré   r?   rê   rt   rŒ   rã   rî   rï   rä   )r   rð   rò   s      r   Ú.test_server_engine_loop_backward_compatibilityzJTestCharacterStatAggregator.test_server_engine_loop_backward_compatibilityÑ   s¹   € å!¨DÐ1Ñ1Ô1ˆØ×&Ò&°¸sÈcÐ&ÑRÔRˆØ×Ò˜Ô*¨DÑ1Ô1Ð1Ø×Ò˜œ vÑ.Ô.Ð.Ø×Ò˜Ô*¨DÑ1Ô1Ð1Ø×Ò˜Ô.°Ñ5Ô5Ð5Ø×Ò˜Ô2Ô:¸2Ô>ÔIÈ3ÑOÔOÐOÐOÐOr!   )r,   N)r"   r#   r$   r/   rD   rN   rU   r]   rh   rr   r’   r¤   rÆ   rÝ   rô   r÷   r)   r!   r   r+   r+   (   s"  € € € € € ð4ð 4ð 4ð 4ð:ð :ð :ð :ð4ð 4ð 4ð 4ð4ð 4ð 4ð 4ð	5ð 	5ð 	5ð 	5ð9ð 9ð 9ð 9ð9ð 9ð 9ð 9ð9ð 9ð 9ð 9ð
Lð 
Lð 
Lð 
Lð<ð <ð <ð <ð2ð ð ð ð07ð 7ð 7ð 7ð4Pð Pð Pð Pð Pð Pr!   r+   Ú__main__)$Ú__doc__rÑ   Úsysr»   rÏ   ÚunittestrÒ   ÚinsertÚabspathrÓ   ÚdirnameÚ__file__Úserver.stats.stat_typesr   r   r   r   Ú server.stats.formula_persistencer   Úserver.stats.stat_aggregatorr   Úserver.world.server_engine_loopr	   r
   Úserver.world.meridian_typesr   Ú#server.world.primal_stones_craftingr   r   Ú server.inventory.inventory_typesr   r   ÚTestCaser+   r"   Úmainr)   r!   r   ú<module>r	     sË  ððð ð 
€	€	€	Ø 
€
€
€
Ø €€€Ø €€€Ø €€€à „‡‚��2”7—?’? 2¤7§<¢<°´·²ÀÑ0IÔ0IÈ>Ñ#ZÔ#ZÑ[Ô[Ñ \Ô \Ð \ðð ð ð ð ð ð ð ð ð ð ð ð GÐ FÐ FÐ FÐ FÐ FØ @Ð @Ð @Ð @Ð @Ð @Ø JÐ JÐ JÐ JÐ JÐ JÐ JÐ JØ 9Ð 9Ð 9Ð 9Ð 9Ð 9Ø @Ð @Ð @Ð @Ð @Ð @Ð @Ð @Ø 5Ð 5Ð 5Ð 5Ð 5Ð 5ðbð bð bð bð bñ bô bð bðqPð qPð qPð qPð qP (Ô"3ñ qPô qPð qPðh ˆzÒÐØ€H„M�O„O€O€O€Oð Ðr!   