§
    Æ½j%"  ã                   ó~  — d Z ddlZddlmc mZ ddlZddlZddl	Z	ddl
Z
ddlmZ  ee¦  «                             ¦   «         j        j        j        Zedz  Z ee¦  «        ej        vr$ej                             d ee¦  «        ¦  «          ee¦  «        ej        vr$ej                             d ee¦  «        ¦  «         ddlmZmZ ddlmZ edz  dz  Zed	z  d
z  dz  Zed	z  d
z  dz  Zed	z  d
z  dz  Zed	z  d
z  dz  Zedz  dz  dz  dz  Z G d„ de	j         ¦  «        Z!e"dk    r e	j#        ¦   «          dS dS )uõ  
Unit and Integration Test Suite for FreeExile Milestone 4 Dodge Roll & i-Frame Evasion:
- Client-side Huyá»…n áº¢nh Bá»™ (0.25s i-frame window, cooldown gating, phantom trails)
- Client-side monster attack damage negation & floating combat text ('NÃ‰ Ä�Ã’N! (i-frame)')
- Server-side CombatEngine 250ms evasion window boundary verification
- Multi-platform synchronization (Server Python, Client WebApp JS, Client iOS TypeScript)
- Strict code hygiene & line count compliance (<= 500 lines hard cap)
é    N)ÚPathÚserver)ÚCombatEngineÚCombatActor)ÚFiveElementsÚclientÚwebappÚjsÚenginezcombat_skills.jszmonster_system.jszcanvas_renderer.jszentity_renderer.jsÚsrcÚcombatzCombatController.tsc                   ó„   — e Zd Ze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d„ Zd„ Zd„ Zd„ ZdS )ÚTestDodgeRollAndIFrameEvasionc                 ó  — t                                d¬¦  «        | _        t                               d¬¦  «        | _        t
                               d¬¦  «        | _        t                               d¬¦  «        | _        d S )Núutf-8©Úencoding)	ÚCOMBAT_SKILLS_JSÚ	read_textÚcombat_skills_codeÚMONSTER_SYSTEM_JSÚmonster_system_codeÚCANVAS_RENDERER_JSÚcanvas_renderer_codeÚENTITY_RENDERER_JSÚentity_renderer_code)Úclss    úAC:\Projects\FreeExile\tests\unit\test_dodge_and_evasion_iframe.pyÚ
setUpClassz(TestDodgeRollAndIFrameEvasion.setUpClass#   sl   € å!1×!;Ò!;ÀWÐ!;Ñ!MÔ!MˆÔÝ"3×"=Ò"=ÀwÐ"=Ñ"OÔ"OˆÔÝ#5×#?Ò#?ÈÐ#?Ñ#QÔ#QˆÔ Ý#5×#?Ò#?ÈÐ#?Ñ#QÔ#QˆÔ Ð Ð ó    c                 ór   — |                       d| j        ¦  «         |                       d| j        ¦  «         dS )zFVerifies combat_skills.js sets isIFrame = true and iFrameTimer = 0.25.zplayer.isIFrame = true;zplayer.iFrameTimer = 0.25;N©ÚassertInr   ©Úselfs    r   Ú$test_client_dodge_sets_iframe_windowzBTestDodgeRollAndIFrameEvasion.test_client_dodge_sets_iframe_window+   s8   € à�ŠÐ/°Ô1HÑIÔIÐIØ�ŠÐ2°DÔ4KÑLÔLÐLÐLÐLr    c                 ór   — |                       d| j        ¦  «         |                       d| j        ¦  «         dS )zBVerifies dodge charges pool and dodge animation state are present.ÚdodgeChargeszplayer.animState = 'dodge';Nr"   r$   s    r   Ú#test_client_dodge_charges_and_statezATestDodgeRollAndIFrameEvasion.test_client_dodge_charges_and_state0   s7   € à�Š�n dÔ&=Ñ>Ô>Ð>Ø�ŠÐ3°TÔ5LÑMÔMÐMÐMÐMr    c                 ór   — |                       d| j        ¦  «         |                       d| j        ¦  «         dS )zNVerifies doDodge contains guards against double-casting or cooldown violation.ÚdoDodgeÚtriggerCooldownNr"   r$   s    r   Ú!test_client_dodge_cooldown_gatingz?TestDodgeRollAndIFrameEvasion.test_client_dodge_cooldown_gating5   s7   € à�Š�i Ô!8Ñ9Ô9Ð9Ø�ŠÐ'¨Ô)@ÑAÔAÐAÐAÐAr    c                 ór   — |                       d| j        ¦  «         |                       d| j        ¦  «         dS )zTVerifies ghost trails are generated in canvas_renderer and drawn in entity_renderer.zplayer.ghostTrails.pushzplayer.ghostTrailsN)r#   r   r   r$   s    r   Ú#test_client_ghost_trail_integrationzATestDodgeRollAndIFrameEvasion.test_client_ghost_trail_integration:   s8   € à�ŠÐ/°Ô1JÑKÔKÐKØ�ŠÐ*¨DÔ,EÑFÔFÐFÐFÐFr    c                 ór   — |                       d| j        ¦  «         |                       d| j        ¦  «         dS )zEVerifies monster attack checks player i-frame before applying damage.ÚexecuteMonsterAttackOnPlayerzplayer.isIFrameN©r#   r   r$   s    r   Ú test_monster_system_iframe_checkz>TestDodgeRollAndIFrameEvasion.test_monster_system_iframe_check@   s8   € à�ŠÐ4°dÔ6NÑOÔOÐOØ�ŠÐ'¨Ô)AÑBÔBÐBÐBÐBr    c                 ór   — |                       d| j        ¦  «         |                       d| j        ¦  «         dS )uG   Verifies floating combat text 'NÃ‰ Ä�Ã’N! (i-frame)' in cyan (#38bdf8).u   NÃ‰ Ä�Ã’N! (i-frame)z#38bdf8Nr2   r$   s    r   Ú)test_monster_system_evasion_floating_textzGTestDodgeRollAndIFrameEvasion.test_monster_system_evasion_floating_textE   s7   € à�ŠÐ,¨dÔ.FÑGÔGÐGØ�Š�i Ô!9Ñ:Ô:Ð:Ð:Ð:r    c                 ó<   — |                       d| j        ¦  «         dS )z?Verifies dodge whoosh sound effect plays on successful evasion.ÚplayDodgeWhooshNr2   r$   s    r   Útest_monster_system_evasion_sfxz=TestDodgeRollAndIFrameEvasion.test_monster_system_evasion_sfxJ   s    € à�ŠÐ'¨Ô)AÑBÔBÐBÐBÐBr    c                 ót   — t          ddt          j        ¬¦  «        }|                      |j        d¦  «         dS )zFVerifies server CombatActor default evasion_iframe_duration_ms is 250.é   ÚTestHero)Úactor_idÚnameÚelementéú   N)r   r   ÚKIMÚassertEqualÚevasion_iframe_duration_ms)r%   Úactors     r   Ú*test_server_actor_iframe_duration_constantzHTestDodgeRollAndIFrameEvasion.test_server_actor_iframe_duration_constantO   s8   € å Q¨ZÅÔAQÐRÑRÔRˆØ×Ò˜Ô9¸3Ñ?Ô?Ð?Ð?Ð?r    c                 ó   — t          ¦   «         }t          ddt          j        d¬¦  «        }t          ddt          j        dd¬¦  «        }|                     |¦  «         |                     |¦  «         d	}|                     |j        |¦  «         |                     |j        |j        dt          j        |¦  «        }|  	                    |j
        ¦  «         |                      |j        d
¦  «         |                      |j        d¦  «         dS )z@Attack landing at exactly t+0ms is completely evaded (0 damage).r:   ÚMobç      Y@©Úbase_attacké   ÚHeroç     @@©Ú
current_hpÚmax_hpé@B ç        N©r   r   r   ÚHOAr@   Úregister_actorÚtrigger_phantom_evasionr<   Úcalculate_damageÚ
assertTrueÚ	is_evadedrA   Úfinal_damagerN   ©r%   r   ÚatkÚdefnÚnow_msÚress         r   Ú#test_server_iframe_boundary_zero_mszATestDodgeRollAndIFrameEvasion.test_server_iframe_boundary_zero_msT   só   € å‘”ˆÝ˜!˜U¥LÔ$4À%ÐHÑHÔHˆÝ˜1˜f¥lÔ&6À5ÐQVÐWÑWÔWˆØ×Ò˜cÑ"Ô"Ð"Ø×Ò˜dÑ#Ô#Ð#àˆØ×&Ò& t¤}°fÑ=Ô=Ð=Ø×%Ò% c¤l°D´MÀ5Í,ÔJZÐ\bÑcÔcˆØ�Š˜œÑ&Ô&Ð&Ø×Ò˜Ô)¨3Ñ/Ô/Ð/Ø×Ò˜œ¨%Ñ0Ô0Ð0Ð0Ð0r    c                 ó&  — t          ¦   «         }t          ddt          j        d¬¦  «        }t          ddt          j        dd¬¦  «        }|                     |¦  «         |                     |¦  «         d	}|                     |j        |¦  «         |                     |j        |j        dt          j        |d
z   ¦  «        }|  	                    |j
        ¦  «         |                      |j        d¦  «         |                      |j        d¦  «         dS )z?Attack landing at t+249ms (inside window) is completely evaded.r:   rF   rG   rH   rJ   rK   rL   rM   rP   éù   rQ   NrR   rZ   s         r   Ú!test_server_iframe_boundary_249msz?TestDodgeRollAndIFrameEvasion.test_server_iframe_boundary_249msc   óù   € å‘”ˆÝ˜!˜U¥LÔ$4À%ÐHÑHÔHˆÝ˜1˜f¥lÔ&6À5ÐQVÐWÑWÔWˆØ×Ò˜cÑ"Ô"Ð"Ø×Ò˜dÑ#Ô#Ð#àˆØ×&Ò& t¤}°fÑ=Ô=Ð=Ø×%Ò% c¤l°D´MÀ5Í,ÔJZÐ\bÐehÑ\hÑiÔiˆØ�Š˜œÑ&Ô&Ð&Ø×Ò˜Ô)¨3Ñ/Ô/Ð/Ø×Ò˜œ¨%Ñ0Ô0Ð0Ð0Ð0r    c                 ó&  — t          ¦   «         }t          ddt          j        d¬¦  «        }t          ddt          j        dd¬¦  «        }|                     |¦  «         |                     |¦  «         d	}|                     |j        |¦  «         |                     |j        |j        dt          j        |d
z   ¦  «        }|  	                    |j
        ¦  «         |                      |j        d¦  «         |                      |j        d¦  «         dS )zAAttack landing at exactly t+250ms (inclusive boundary) is evaded.r:   rF   rG   rH   rJ   rK   rL   rM   rP   r?   rQ   NrR   rZ   s         r   Ú!test_server_iframe_boundary_250msz?TestDodgeRollAndIFrameEvasion.test_server_iframe_boundary_250msr   rc   r    c                 ó&  — t          ¦   «         }t          ddt          j        d¬¦  «        }t          ddt          j        dd¬¦  «        }|                     |¦  «         |                     |¦  «         d	}|                     |j        |¦  «         |                     |j        |j        dt          j        |d
z   ¦  «        }|  	                    |j
        ¦  «         |                      |j        d¦  «         |                      |j        d¦  «         dS )zAAttack landing at t+251ms (outside window) applies normal damage.r:   rF   rG   rH   rJ   rK   rL   rM   rP   éû   rQ   N)r   r   r   rS   r@   rT   rU   r<   rV   ÚassertFalserX   ÚassertGreaterrY   Ú
assertLessrN   rZ   s         r   Ú test_server_iframe_expired_251msz>TestDodgeRollAndIFrameEvasion.test_server_iframe_expired_251ms�   sù   € å‘”ˆÝ˜!˜U¥LÔ$4À%ÐHÑHÔHˆÝ˜1˜f¥lÔ&6À5ÐQVÐWÑWÔWˆØ×Ò˜cÑ"Ô"Ð"Ø×Ò˜dÑ#Ô#Ð#àˆØ×&Ò& t¤}°fÑ=Ô=Ð=Ø×%Ò% c¤l°D´MÀ5Í,ÔJZÐ\bÐehÑ\hÑiÔiˆØ×Ò˜œÑ'Ô'Ð'Ø×Ò˜3Ô+¨SÑ1Ô1Ð1Ø�Š˜œ¨Ñ/Ô/Ð/Ð/Ð/r    c                 óð  — t          ¦   «         }t          ddt          j        d¬¦  «        }t          ddt          j        dd¬¦  «        }|                     |¦  «         |                     |¦  «         d	}|                     |j        |¦  «         |                     |j        |j        dt          j        |d
z
  ¦  «        }|  	                    |j
        ¦  «         |                      |j        d¦  «         dS )zFAttack landing before evasion timestamp (e.g. t - 50ms) is not evaded.r:   rF   rG   rH   rJ   rK   rL   rM   rP   é2   rQ   N)r   r   r   rS   r@   rT   rU   r<   rV   rh   rX   ri   rY   rZ   s         r   Ú.test_server_iframe_negative_timestamp_rejectedzLTestDodgeRollAndIFrameEvasion.test_server_iframe_negative_timestamp_rejected�   sã   € å‘”ˆÝ˜!˜U¥LÔ$4À%ÐHÑHÔHˆÝ˜1˜f¥lÔ&6À5ÐQVÐWÑWÔWˆØ×Ò˜cÑ"Ô"Ð"Ø×Ò˜dÑ#Ô#Ð#àˆØ×&Ò& t¤}°fÑ=Ô=Ð=Ø×%Ò% c¤l°D´MÀ5Í,ÔJZÐ\bÐegÑ\gÑhÔhˆØ×Ò˜œÑ'Ô'Ð'Ø×Ò˜3Ô+¨SÑ1Ô1Ð1Ð1Ð1r    c                 óž   — t                                ¦   «         r3t                                d¬¦  «        }|                      d|¦  «         dS dS )z?Verifies iOS CombatController.ts uses identical 250ms duration.r   r   z%evasionIframeDurationMs: number = 250N)ÚIOS_COMBAT_TSÚexistsr   r#   )r%   Úts_codes     r   Ú0test_ios_metal_combat_controller_duration_parityzNTestDodgeRollAndIFrameEvasion.test_ios_metal_combat_controller_duration_parityŸ   sT   € å×ÒÑ!Ô!ð 	LÝ#×-Ò-°wÐ-Ñ?Ô?ˆGØ�MŠMÐAÀ7ÑKÔKÐKÐKÐKð	Lð 	Lr    c                 óˆ   — t          | j                             ¦   «         ¦  «        }|                      |dd|› d�¦  «         dS )z4combat_skills.js must not exceed 500 lines hard cap.éô  zcombat_skills.js has ú lines (Hard Cap 500)N)Úlenr   Ú
splitlinesÚassertLessEqual©r%   Úliness     r   Útest_combat_skills_line_capz9TestDodgeRollAndIFrameEvasion.test_combat_skills_line_cap¦   sH   € å�DÔ+×6Ò6Ñ8Ô8Ñ9Ô9ˆØ×Ò˜U CÐ)]ÀÐ)]Ð)]Ð)]Ñ^Ô^Ð^Ð^Ð^r    c                 óˆ   — t          | j                             ¦   «         ¦  «        }|                      |dd|› d�¦  «         dS )z5monster_system.js must not exceed 500 lines hard cap.ru   zmonster_system.js has rv   N)rw   r   rx   ry   rz   s     r   Útest_monster_system_line_capz:TestDodgeRollAndIFrameEvasion.test_monster_system_line_cap«   sH   € å�DÔ,×7Ò7Ñ9Ô9Ñ:Ô:ˆØ×Ò˜U CÐ)^À%Ð)^Ð)^Ð)^Ñ_Ô_Ð_Ð_Ð_r    N)Ú__name__Ú
__module__Ú__qualname__Úclassmethodr   r&   r)   r-   r/   r3   r5   r8   rD   r_   rb   re   rk   rn   rs   r|   r~   © r    r   r   r   "   s@  € € € € € ØðRð Rñ „[ðRðMð Mð Mð
Nð Nð Nð
Bð Bð Bð
Gð Gð GðCð Cð Cð
;ð ;ð ;ð
Cð Cð Cð
@ð @ð @ð
1ð 1ð 1ð1ð 1ð 1ð1ð 1ð 1ð0ð 0ð 0ð2ð 2ð 2ðLð Lð Lð_ð _ð _ð
`ð `ð `ð `ð `r    r   Ú__main__)$Ú__doc__ÚbuiltinsÚ@py_builtinsÚ_pytest.assertion.rewriteÚ	assertionÚrewriteÚ
@pytest_arÚosÚsysÚunittestÚtimeÚpathlibr   Ú__file__ÚresolveÚparentÚPROJECT_ROOTÚ
SERVER_DIRÚstrÚpathÚinsertÚworld.combat_enginer   r   Úworld.martial_matrixr   Ú
WEBAPP_DIRr   r   r   r   rp   ÚTestCaser   r   Úmainrƒ   r    r   ú<module>rž      s  ððð ð € € € € € € € € € € € € €	€	€	€	Ø 
€
€
€
Ø €€€Ø €€€Ø Ð Ð Ð Ð Ð àˆt�H‰~Œ~×%Ò%Ñ'Ô'Ô.Ô5Ô<€Ø˜HÑ$€
Ø€3€z�?„?˜#œ(Ð"Ð"Ø„H‡O‚O�A�s�s˜:‘”Ñ'Ô'Ð'Ø€3€|ÑÔ˜CœHÐ$Ð$Ø„H‡O‚O�A�s�s˜<Ñ(Ô(Ñ)Ô)Ð)à 9Ð 9Ð 9Ð 9Ð 9Ð 9Ð 9Ð 9Ø -Ð -Ð -Ð -Ð -Ð -à˜HÑ$ xÑ/€
Ø Ñ$ xÑ/Ð2DÑDÐ Ø Ñ%¨Ñ0Ð3FÑFÐ Ø $Ñ&¨Ñ1Ð4HÑHÐ Ø $Ñ&¨Ñ1Ð4HÑHÐ Ø˜xÑ'¨%Ñ/°(Ñ:Ð=RÑR€ðL`ð L`ð L`ð L`ð L` HÔ$5ñ L`ô L`ð L`ð^ ˆzÒÐØ€H„M�O„O€O€O€Oð Ðr    