§
    1¯½j  ã                   óØ  — d Z ddlZddlmc mZ ddlZddlm	Z	  e	e
¦  «                             ¦   «         j        j        j        Zedz  dz  Zedz  Zedz  dz  d	z  Zedz  dz  d
z  Zedz  dz  Zedz  dz  dz  Zedz  dz  dz  Z G d„ dej        ¦  «        Z G d„ dej        ¦  «        Z G d„ dej        ¦  «        Z G d„ dej        ¦  «        Zedk    r ej        ¦   «          dS dS )a  
Comprehensive Unit Test Suite for FreeExile Milestone 1:
- Dual Fluid HUD Orbs (Canvas 2D Sinusoidal Crest & Dynamic Vignette)
- Modern ARPG 7-Slot Action Bar & Radial Cooldown Sweeps
- Joystick PointerEvents & Dead-Zone Clamping Engine
- Backward Compatibility and File Hygiene Caps
é    N)ÚPathÚclientÚwebappz
index.htmlÚjsÚuizhud_orbs.jszskill_bar_controller.jsÚcsszhud_skills.cssÚenginezjoystick.jszcombat_skills.jsc                   ó<   — e Zd Zed„ ¦   «         Zd„ Zd„ Zd„ Zd„ ZdS )ÚTestHudDualOrbsc                 óÆ   — t                                d¬¦  «        | _        t                               d¬¦  «        | _        t
                               d¬¦  «        | _        d S ©Núutf-8©Úencoding)Ú
INDEX_HTMLÚ	read_textÚhtml_contentÚHUD_ORBS_JSÚorbs_jsÚHUD_SKILLS_CSSÚcss_content©Úclss    ú?C:\Projects\FreeExile\tests\unit\test_hud_orbs_and_skill_bar.pyÚ
setUpClasszTestHudDualOrbs.setUpClass   sO   € å%×/Ò/¸Ð/ÑAÔAˆÔÝ!×+Ò+°WÐ+Ñ=Ô=ˆŒÝ(×2Ò2¸GÐ2ÑDÔDˆŒˆˆó    c                 óÌ   — g d¢}|D ]&}|                       d|› d�| j        d|› d�¦  «         Œ'|                       d| j        ¦  «         |                       d| j        ¦  «         dS )	zBVerifies index.html contains all Dual Orbs DOM elements and links.)
zhud-orbs-containerzhud-life-orbzhud-mana-orbzlife-orb-canvaszmana-orb-canvasztxt-life-curztxt-life-maxztxt-mana-curztxt-mana-maxzhud-low-hp-vignetteúid="ú"zMissing id 'ú'zhref="css/hud_skills.css"zsrc="js/ui/hud_orbs.js"N©ÚassertInr   )ÚselfÚexpected_idsÚeids      r   Ú!test_dual_orbs_dom_elements_existz1TestHudDualOrbs.test_dual_orbs_dom_elements_exist   sŒ   € ð
ð 
ð 
ˆð  ð 	Sð 	SˆCØ�MŠM˜- ˜-˜-˜-¨Ô):Ð<QÈ3Ð<QÐ<QÐ<QÑRÔRÐRÐRØ�ŠÐ1°4Ô3DÑEÔEÐEØ�ŠÐ/°Ô1BÑCÔCÐCÐCÐCr   c                 óÞ   — |                       d| j        ¦  «         |                       d| j        ¦  «         |                       d| j        ¦  «         |                       d| j        ¦  «         dS )zIVerifies sinusoidal liquid wave crest sin(x * 0.05 + time * 3.0) formula.zclass HudOrbszsin(0 * 0.05 + time * 3.0)zsin(x * 0.05 + time * 3.0)Ú
LERP_SPEEDN)r"   r   ©r#   s    r   Ú%test_hud_orbs_sinusoidal_wave_formulaz5TestHudDualOrbs.test_hud_orbs_sinusoidal_wave_formula*   sb   € à�Š�o t¤|Ñ4Ô4Ð4Ø�ŠÐ2°D´LÑAÔAÐAØ�ŠÐ2°D´LÑAÔAÐAØ�Š�l D¤LÑ1Ô1Ð1Ð1Ð1r   c                 óÞ   — |                       d| j        ¦  «         |                       d| j        ¦  «         |                       d| j        ¦  «         |                       d| j        ¦  «         dS )z;Verifies <25% low HP threshold and heartbeat pulse trigger.zLOW_HP_THRESHOLD = 0.25zorb-low-pulsez@keyframes crimsonHeartbeatz#hud-low-hp-vignetteN©r"   r   r   r)   s    r   Ú&test_hud_orbs_low_hp_warning_and_pulsez6TestHudDualOrbs.test_hud_orbs_low_hp_warning_and_pulse1   se   € à�ŠÐ/°´Ñ>Ô>Ð>Ø�Š�o t¤|Ñ4Ô4Ð4Ø�ŠÐ3°TÔ5EÑFÔFÐFØ�ŠÐ,¨dÔ.>Ñ?Ô?Ð?Ð?Ð?r   c                 óÞ   — |                       d| j        ¦  «         |                       d| j        ¦  «         |                       d| j        ¦  «         |                       d| j        ¦  «         dS )z;Verifies 180x180 retina canvas rendering, sheen, and bezel.zCANVAS_SIZE = 180zORB_RADIUS = 78z
.orb-sheenz
.orb-bezelNr,   r)   s    r   Ú$test_hud_orbs_canvas_and_retina_specz4TestHudDualOrbs.test_hud_orbs_canvas_and_retina_spec8   sd   € à�ŠÐ)¨4¬<Ñ8Ô8Ð8Ø�ŠÐ'¨¬Ñ6Ô6Ð6Ø�Š�l DÔ$4Ñ5Ô5Ð5Ø�Š�l DÔ$4Ñ5Ô5Ð5Ð5Ð5r   N)	Ú__name__Ú
__module__Ú__qualname__Úclassmethodr   r&   r*   r-   r/   © r   r   r   r      sr   € € € € € ØðEð Eñ „[ðEð
Dð Dð Dð2ð 2ð 2ð@ð @ð @ð6ð 6ð 6ð 6ð 6r   r   c                   óB   — e Zd Zed„ ¦   «         Zd„ Zd„ Zd„ Zd„ Zd„ Z	dS )Ú!TestSkillBarAndCooldownControllerc                 óÆ   — t                                d¬¦  «        | _        t                               d¬¦  «        | _        t
                               d¬¦  «        | _        d S r   )r   r   r   ÚSKILL_BAR_JSÚbar_jsr   r   r   s    r   r   z,TestSkillBarAndCooldownController.setUpClassA   sO   € å%×/Ò/¸Ð/ÑAÔAˆÔÝ!×+Ò+°WÐ+Ñ=Ô=ˆŒ
Ý(×2Ò2¸GÐ2ÑDÔDˆŒˆˆr   c                 ó`   — g d¢}|D ]&}|                       d|› d�| j        d|› d�¦  «         Œ'dS )zLVerifies all 7 action slots exist in index.html with backward compatibility.)zskill-potionz
skill-firezskill-slot-wzskill-thunderzskill-frostzskill-primaryzskill-dodger   r   zMissing slot 'r    Nr!   )r#   ÚslotsÚslots      r   Útest_seven_action_slots_in_htmlzATestSkillBarAndCooldownController.test_seven_action_slots_in_htmlG   sb   € ð
ð 
ð 
ˆð ð 	Wð 	WˆDØ�MŠM˜. ˜.˜.˜.¨$Ô*;Ð=UÈdÐ=UÐ=UÐ=UÑVÔVÐVÐVð	Wð 	Wr   c                 óX   — g d¢}|D ]"}|                       || j        d|› d�¦  «         Œ#dS )z5Verifies SkillBarController public API methods exist.)zregisterSlot(ztriggerCooldown(zonReady(zactivateSlot(zisSlotOnCooldown(zgetRemainingCooldown(zMissing method 'z' in controllerN©r"   r9   )r#   ÚmethodsÚms      r   Ú&test_skill_bar_controller_api_contractzHTestSkillBarAndCooldownController.test_skill_bar_controller_api_contractP   sY   € ð
ð 
ð 
ˆð ð 	Qð 	QˆAØ�MŠM˜!˜Tœ[Ð*O¸QÐ*OÐ*OÐ*OÑPÔPÐPÐPð	Qð 	Qr   c                 óX   — g d¢}|D ]"}|                       || j        d|› d�¦  «         Œ#dS )zFVerifies all 10 canonical active skills are mapped in SKILL_ATLAS_MAP.)
Úcuu_tieu_loi_kiemÚthanh_phong_van_kiem_vuÚu_minh_huyet_doc_chamÚthien_ma_boc_doc_kinhÚbang_phach_han_quang_tranÚbang_tien_xuyen_tamÚliet_hoa_toan_phong_tramÚliet_diem_boc_khi_tramÚkim_cang_truy_dia_chanÚkim_cang_bat_hoai_thezSkill 'z' missing from SKILL_ATLAS_MAPNr?   )r#   Úcanonical_skillsÚss      r   Ú!test_canonical_atlas_map_metadatazCTestSkillBarAndCooldownController.test_canonical_atlas_map_metadataY   sZ   € ð
ð 
ð 
Ðð "ð 	Wð 	WˆAØ�MŠM˜!˜Tœ[Ð*U°AÐ*UÐ*UÐ*UÑVÔVÐVÐVð	Wð 	Wr   c                 óÞ   — |                       d| j        ¦  «         |                       d| j        ¦  «         |                       d| j        ¦  «         |                       d| j        ¦  «         dS )zDVerifies 360-deg clockwise conic-gradient sweep and numeric counter.z.cooldown-overlayzconic-gradientz--cooldown-sweepz.cooldown-counterN©r"   r   r)   s    r   Ú,test_conic_radial_cooldown_sweep_and_counterzNTestSkillBarAndCooldownController.test_conic_radial_cooldown_sweep_and_countere   sh   € à�ŠÐ)¨4Ô+;Ñ<Ô<Ð<Ø�ŠÐ&¨Ô(8Ñ9Ô9Ð9Ø�ŠÐ(¨$Ô*:Ñ;Ô;Ð;Ø�ŠÐ)¨4Ô+;Ñ<Ô<Ð<Ð<Ð<r   c                 ó  — |                       d| j        ¦  «         |                       d| j        ¦  «         |                       d| j        ¦  «         |                       d| j        ¦  «         |                       d| j        ¦  «         dS )z=Verifies 0.25s golden ready pulse and cooldown blocked shake.z@keyframes skill-ready-pulsez0.25szrgba(251, 191, 36z.is-cooldown-blockedz@keyframes skill-blocked-shakeNrR   r)   s    r   Ú.test_luminous_ready_flash_and_blocked_feedbackzPTestSkillBarAndCooldownController.test_luminous_ready_flash_and_blocked_feedbackl   s   € à�ŠÐ4°dÔ6FÑGÔGÐGØ�Š�g˜tÔ/Ñ0Ô0Ð0Ø�ŠÐ)¨4Ô+;Ñ<Ô<Ð<Ø�ŠÐ,¨dÔ.>Ñ?Ô?Ð?Ø�ŠÐ6¸Ô8HÑIÔIÐIÐIÐIr   N)
r0   r1   r2   r3   r   r=   rB   rP   rS   rU   r4   r   r   r6   r6   @   s‰   € € € € € ØðEð Eñ „[ðEð
Wð Wð WðQð Qð Qð
Wð 
Wð 
Wð=ð =ð =ðJð Jð Jð Jð Jr   r6   c                   ó6   — e Zd Zed„ ¦   «         Zd„ Zd„ Zd„ ZdS )ÚTestJoystickAndInputErgonomicsc                 ó†   — t                                d¬¦  «        | _        t                               d¬¦  «        | _        d S r   )ÚJOYSTICK_JSr   Újoy_jsÚCOMBAT_SKILLS_JSÚ	combat_jsr   s    r   r   z)TestJoystickAndInputErgonomics.setUpClassv   s6   € å ×*Ò*°GÐ*Ñ<Ô<ˆŒ
Ý(×2Ò2¸GÐ2ÑDÔDˆŒˆˆr   c                 óÞ   — |                       d| j        ¦  «         |                       d| j        ¦  «         |                       d| j        ¦  «         |                       d| j        ¦  «         dS )zOVerifies W3C Pointer Events with setPointerCapture and active pointer tracking.ÚpointerdownÚsetPointerCaptureÚactivePointerIdÚreleasePointerCaptureN©r"   rZ   r)   s    r   Útest_pointer_events_and_capturez>TestJoystickAndInputErgonomics.test_pointer_events_and_capture{   sc   € à�Š�m T¤[Ñ1Ô1Ð1Ø�ŠÐ)¨4¬;Ñ7Ô7Ð7Ø�ŠÐ'¨¬Ñ5Ô5Ð5Ø�ŠÐ-¨t¬{Ñ;Ô;Ð;Ð;Ð;r   c                 ór   — |                       d| j        ¦  «         |                       d| j        ¦  «         dS )z3Verifies dead-zone threshold > 0.15 is implemented.zDEAD_ZONE = 0.15ÚJOYSTICK_DEAD_ZONENrb   r)   s    r   Útest_dead_zone_clampingz6TestJoystickAndInputErgonomics.test_dead_zone_clamping‚   s6   € à�ŠÐ(¨$¬+Ñ6Ô6Ð6Ø�ŠÐ*¨D¬KÑ8Ô8Ð8Ð8Ð8r   c                 óÞ   — |                       d| j        ¦  «         |                       d| j        ¦  «         |                       d| j        ¦  «         |                       d| j        ¦  «         dS )zDVerifies joystickActive and handleJoystickPointerMove are preserved.ÚjoystickActiveÚhandleJoystickPointerMoveÚdoPrimaryAttackÚdodgeChargesN)r"   rZ   r\   r)   s    r   Ú#test_backward_compatibility_handleszBTestJoystickAndInputErgonomics.test_backward_compatibility_handles‡   sc   € à�ŠÐ&¨¬Ñ4Ô4Ð4Ø�ŠÐ1°4´;Ñ?Ô?Ð?Ø�ŠÐ'¨¬Ñ8Ô8Ð8Ø�Š�n d¤nÑ5Ô5Ð5Ð5Ð5r   N)r0   r1   r2   r3   r   rc   rf   rl   r4   r   r   rW   rW   u   s]   € € € € € ØðEð Eñ „[ðEð<ð <ð <ð9ð 9ð 9ð
6ð 6ð 6ð 6ð 6r   rW   c                   ó   — e Zd Zd„ ZdS )ÚTestCodeHygieneAndLineCapsc                 ó¾  — t           ddft          ddft          ddft          ddft          ddft
          ddfg}|D ]¡\  }}}|                      |                     ¦   «         d|j        › d�¦  «         | 	                    d¬	¦  «         
                    ¦   «         }|                      t          |¦  «        ||j        › d
|› dt          |¦  «        › d|› d�¦  «         Œ¢dS )zBAsserts all modified and created files comply with soft/hard caps.i^  zSoft Capiô  zHard Capi�  zFile z must existr   r   z	 exceeds z (z > z lines)N)r   r8   r   rY   r[   r   Ú
assertTrueÚexistsÚnamer   Ú
splitlinesÚassertLessEqualÚlen)r#   ÚcapsÚpathÚ	max_linesÚcap_nameÚliness         r   Útest_file_line_capsz.TestCodeHygieneAndLineCaps.test_file_line_caps�   s  € õ ˜#˜zÐ*Ý˜3 
Ð+Ý˜S *Ð-Ý˜#˜zÐ*Ý˜s JÐ/Ý˜˜jÐ)ð
ˆð *.ð 	ð 	Ñ%ˆD�)˜XØ�OŠO˜DŸKšK™MœMÐ+I°4´9Ð+IÐ+IÐ+IÑJÔJÐJØ—N’N¨G�NÑ4Ô4×?Ò?ÑAÔAˆEØ× Ò Ý�E‘
”
˜IØ”9ÐTÐT xÐTÐTµ3°u±:´:ÐTÐTÀ)ÐTÐTÐTñô ð ð ð	ð 	r   N)r0   r1   r2   r{   r4   r   r   rn   rn   �   s#   € € € € € ðð ð ð ð r   rn   Ú__main__)Ú__doc__ÚbuiltinsÚ@py_builtinsÚ_pytest.assertion.rewriteÚ	assertionÚrewriteÚ
@pytest_arÚunittestÚpathlibr   Ú__file__ÚresolveÚparentÚPROJECT_ROOTÚ
WEBAPP_DIRr   r   r8   r   rY   r[   ÚTestCaser   r6   rW   rn   r0   Úmainr4   r   r   ú<module>r�      sÈ  ððð ð € € € € € € € € € € € € €€€€Ø Ð Ð Ð Ð Ð àˆt�H‰~Œ~×%Ò%Ñ'Ô'Ô.Ô5Ô<€Ø˜HÑ$ xÑ/€
Ø˜,Ñ&€
Ø˜4Ñ $Ñ&¨Ñ6€Ø˜DÑ  4Ñ'Ð*CÑC€Ø˜eÑ#Ð&6Ñ6€Ø˜4Ñ (Ñ*¨]Ñ:€Ø Ñ$ xÑ/Ð2DÑDÐ ð'6ð '6ð '6ð '6ð '6�hÔ'ñ '6ô '6ð '6ðT2Jð 2Jð 2Jð 2Jð 2J¨Ô(9ñ 2Jô 2Jð 2Jðj6ð 6ð 6ð 6ð 6 XÔ%6ñ 6ô 6ð 6ð4ð ð ð ð  Ô!2ñ ô ð ð( ˆzÒÐØ€H„M�O„O€O€O€Oð Ðr   