§
    G¿j  ã                  ó,  — d Z ddlmZ ddlZddlZddlZddlZddlmZ ddl	Z	 ee
¦  «                             ¦   «         j        j        j        Zedz  dz  Zedz  Zedz  d	z  Zedz  d
z  Zedz  dz  Zedz  dz  Zedz  dz  dz  Z G d„ d¦  «        ZdS )aZ  
Unit Test Suite for FreeExile PC Desktop Web Client Layout & DOM Architecture.
Verifies:
- 100vw x 100vh Fullscreen layout with zero scrollbars/overflow
- Absolute elimination of mobile simulation artifacts (.iphone-frame, #simulator-bar)
- Hidden dummy joystick DOM elements to prevent canvas_renderer null-dereference
- Base href tag linking shared webapp assets without duplication
- Grimdark Action HUD (Dual Fluid Orbs, Central Action Bar, Minimap, Chat Dock)
- Dedicated dev server configuration (tools/serve_web_pc.py on port 8089)
- Zero regression on mobile webapp (client/webapp/index.html)
é    )ÚannotationsN)ÚPathÚclientÚweb_pcz
index.htmlÚcsszpc_main.cssz
pc_hud.csszpc_modals.cssÚtoolszserve_web_pc.pyÚwebappc                  ób   — e Zd 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S )ÚTestPcWebClientLayoutUnitzIVerifies PC web client layout contracts, DOM elements, and server config.ÚreturnÚNonec                óˆ  — t           t          t          fD ]…}|                     ¦   «         sJ |j        › d�¦   «         ‚|                     d¬¦  «                             ¦   «         }t          |¦  «        dk    s"J |j        › dt          |¦  «        › d�¦   «         ‚Œ†t                                d¬¦  «        }d|v sJ ‚d|v sJ ‚d	S )
zIVerifies CSS files exist, enforce overflow:hidden, and respect line caps.z must existúutf-8©Úencodingi^  z (z lines) exceeds soft capzoverflow: hiddenz	margin: 0N)ÚCSS_MAINÚCSS_HUDÚ
CSS_MODALSÚexistsÚnameÚ	read_textÚ
splitlinesÚlen)ÚselfÚcss_fileÚlinesÚmain_contents       ú=C:\Projects\FreeExile\tests\unit\test_pc_web_client_layout.pyÚ0test_css_files_exist_and_enforce_zero_scrollbarszJTestPcWebClientLayoutUnit.test_css_files_exist_and_enforce_zero_scrollbars"   sÞ   € å!¥7­JÐ7ð 	_ð 	_ˆHØ—?’?Ñ$Ô$ÐCÐC¨¬Ð&CÐ&CÐ&CÑCÔCÐ$Ø×&Ò&°Ð&Ñ8Ô8×CÒCÑEÔEˆEÝ�u‘:”: Ò$Ð$Ð$¨¬Ð&^Ð&^½#¸e¹*¼*Ð&^Ð&^Ð&^Ñ$Ô$Ð$Ð$å×)Ò)°7Ð)Ñ;Ô;ˆØ! \Ð1Ð1Ð1Ð1Ø˜lÐ*Ð*Ð*Ð*Ð*Ð*ó    c                óÖ   — t                                ¦   «         s
J d¦   «         ‚t                                d¬¦  «        }d|v s
J d¦   «         ‚d|v s
J d¦   «         ‚d|v s
J d	¦   «         ‚d
S )zKVerifies tools/serve_web_pc.py exists, uses port 8089, and routes properly.zserve_web_pc.py must existr   r   Ú8089z)serve_web_pc.py must default to port 8089Ú
WEBAPP_DIRz)serve_web_pc.py must reference WEBAPP_DIRÚPC_DIRz%serve_web_pc.py must reference PC_DIRN)ÚSERVE_PC_PYr   r   ©r   Úcontents     r   Útest_serve_web_pc_configurationz9TestPcWebClientLayoutUnit.test_serve_web_pc_configuration-   s�   € å×!Ò!Ñ#Ô#ÐAÐAÐ%AÑAÔAÐ#Ý×'Ò'°Ð'Ñ9Ô9ˆØ˜Ð Ð Ð Ð"MÑ Ô Ð Ø˜wÐ&Ð&Ð&Ð(SÑ&Ô&Ð&Ø˜7Ð"Ð"Ð"Ð$KÑ"Ô"Ð"Ð"Ð"r    c                óº   — t                                ¦   «         st          j        d¦  «         t                                d¬¦  «        }d|v sJ ‚d|v sJ ‚d|v sJ ‚dS )zKVerifies index.html has base href ../webapp/ and full-screen #app-viewport.ú(index.html is being written by worker_m1r   r   z<base href="../webapp/">zid="app-viewport"zid="game-canvas"N©Ú
INDEX_HTMLr   ÚpytestÚskipr   r&   s     r   Ú-test_html_base_href_and_viewport_architecturezGTestPcWebClientLayoutUnit.test_html_base_href_and_viewport_architecture5   sw   € å× Ò Ñ"Ô"ð 	DÝŒKÐBÑCÔCÐCÝ×&Ò&°Ð&Ñ8Ô8ˆØ)¨WÐ4Ð4Ð4Ð4Ø" gÐ-Ð-Ð-Ð-Ø! WÐ,Ð,Ð,Ð,Ð,Ð,r    c                óê   — t                                ¦   «         st          j        d¦  «         t                                d¬¦  «        }d|vs
J d¦   «         ‚d|vs
J d¦   «         ‚d|vs
J d	¦   «         ‚d
S )z=Verifies zero mobile chassis elements exist in PC index.html.r*   r   r   úiphone-framez%No .iphone-frame allowed in PC clientúid="simulator-bar"z&No #simulator-bar allowed in PC clientzid="mode-iphone"zNo mobile mode buttons allowedNr+   r&   s     r   Ú!test_mobile_artifacts_eliminationz;TestPcWebClientLayoutUnit.test_mobile_artifacts_elimination>   s’   € å× Ò Ñ"Ô"ð 	DÝŒKÐBÑCÔCÐCÝ×&Ò&°Ð&Ñ8Ô8ˆØ WÐ,Ð,Ð,Ð.UÑ,Ô,Ð,Ø#¨7Ð2Ð2Ð2Ð4\Ñ2Ô2Ð2Ø!¨Ð0Ð0Ð0Ð2RÑ0Ô0Ð0Ð0Ð0r    c                óÒ   — t                                ¦   «         st          j        d¦  «         t                                d¬¦  «        }d|v sJ ‚d|v sJ ‚d|v s
d|v sd|v sJ ‚d	S d	S d	S )
zFVerifies hidden dummy joystick DOM exists to prevent null dereference.r*   r   r   úid="joystick-zone"zid="joystick-stick"zdisplay:nonezdisplay: noneÚhiddenNr+   r&   s     r   Ú"test_dummy_joystick_guard_presencez<TestPcWebClientLayoutUnit.test_dummy_joystick_guard_presenceG   s˜   € å× Ò Ñ"Ô"ð 	DÝŒKÐBÑCÔCÐCÝ×&Ò&°Ð&Ñ8Ô8ˆØ# wÐ.Ð.Ð.Ð.Ø$¨Ð/Ð/Ð/Ð/à 'Ð)Ð)¨_ÀÐ-GÐ-GÈ8ÐW^ÐK^ÐK^ÐK^Ð^Ð)Ð)Ð-GÐ-GÐK^ÐK^r    c                ó6  — t                                ¦   «         st          j        d¦  «         t                                d¬¦  «        }d|v sJ ‚d|v sJ ‚t          dd¦  «        D ]}d|› d	�|v sJ ‚Œd
D ]}d|› d	�|v sJ ‚Œd|v sJ ‚d|v sJ ‚d|v sJ ‚d|v sJ ‚dS )z@Verifies dual fluid orbs, central action bar slots, and exp bar.r*   r   r   zid="life-orb-canvas"zid="mana-orb-canvas"é   é   zid="skill-flask-ú")ÚqÚwÚeÚrz
id="skill-zid="skill-lmb"zid="skill-rmb"zid="skill-dodge"zid="player-exp-bar"N)r,   r   r-   r.   r   Úrange)r   r'   ÚiÚks       r   Ú"test_grimdark_action_hud_structurez<TestPcWebClientLayoutUnit.test_grimdark_action_hud_structureQ   s  € å× Ò Ñ"Ô"ð 	DÝŒKÐBÑCÔCÐCÝ×&Ò&°Ð&Ñ8Ô8ˆà%¨Ð0Ð0Ð0Ð0Ø%¨Ð0Ð0Ð0Ð0å�q˜!‘”ð 	6ð 	6ˆAØ* aÐ*Ð*Ð*¨gÐ5Ð5Ð5Ð5Ð5à%ð 	0ð 	0ˆAØ$ Ð$Ð$Ð$¨Ð/Ð/Ð/Ð/Ð/à 7Ð*Ð*Ð*Ð*Ø 7Ð*Ð*Ð*Ð*à! WÐ,Ð,Ð,Ð,Ø$¨Ð/Ð/Ð/Ð/Ð/Ð/r    c                óÒ   — t                                ¦   «         st          j        d¦  «         t                                d¬¦  «        }d|v sJ ‚d|v sJ ‚d|v sJ ‚d|v sJ ‚d|v sJ ‚d	S )
z>Verifies top-right minimap and telemetry header in index.html.r*   r   r   zid="minimap-canvas"zid="minimap-zone-label"zid="minimap-coords"zid="hud-fps"zid="hud-ping"Nr+   r&   s     r   Útest_minimap_and_telemetry_hudz8TestPcWebClientLayoutUnit.test_minimap_and_telemetry_hudf   s™   € å× Ò Ñ"Ô"ð 	DÝŒKÐBÑCÔCÐCÝ×&Ò&°Ð&Ñ8Ô8ˆØ$¨Ð/Ð/Ð/Ð/Ø(¨GÐ3Ð3Ð3Ð3Ø$¨Ð/Ð/Ð/Ð/Ø Ð(Ð(Ð(Ð(Ø 'Ð)Ð)Ð)Ð)Ð)Ð)r    c                óÒ   — t                                ¦   «         st          j        d¦  «         t                                d¬¦  «        }d|v sJ ‚d|v sJ ‚d|v sJ ‚d|v sJ ‚d|v sJ ‚d	S )
z>Verifies collapsible chat dock with ticker and expanded panel.r*   r   r   zid="chat-dock"zid="chat-minimized-bar"zid="chat-expanded-panel"zid="chat-input"zid="chat-send-btn"Nr+   r&   s     r   Ú$test_collapsible_chat_dock_structurez>TestPcWebClientLayoutUnit.test_collapsible_chat_dock_structureq   s™   € å× Ò Ñ"Ô"ð 	DÝŒKÐBÑCÔCÐCÝ×&Ò&°Ð&Ñ8Ô8ˆØ 7Ð*Ð*Ð*Ð*Ø(¨GÐ3Ð3Ð3Ð3Ø)¨WÐ4Ð4Ð4Ð4Ø  GÐ+Ð+Ð+Ð+Ø# wÐ.Ð.Ð.Ð.Ð.Ð.r    c                óÆ   — t                                ¦   «         st          j        d¦  «         t                                d¬¦  «        }d|v sJ ‚d|v sJ ‚d|v sJ ‚d|v sJ ‚dS )	z=Verifies #game-tooltip and #overlay-pause are present in DOM.r*   r   r   zid="game-tooltip"zid="tooltip-title"zid="tooltip-desc"zid="overlay-pause"Nr+   r&   s     r   Ú'test_floating_tooltip_and_pause_overlayzATestPcWebClientLayoutUnit.test_floating_tooltip_and_pause_overlay|   sˆ   € å× Ò Ñ"Ô"ð 	DÝŒKÐBÑCÔCÐCÝ×&Ò&°Ð&Ñ8Ô8ˆØ" gÐ-Ð-Ð-Ð-Ø# wÐ.Ð.Ð.Ð.Ø" gÐ-Ð-Ð-Ð-Ø# wÐ.Ð.Ð.Ð.Ð.Ð.r    c                óÆ   — t                                ¦   «         sJ ‚t                                d¬¦  «        }d|v s
J d¦   «         ‚d|v s
J d¦   «         ‚d|v s
J d¦   «         ‚d	S )
zLVerifies mobile webapp at client/webapp/index.html is completely unmodified.r   r   r1   z'Mobile webapp must retain .iphone-framer2   z'Mobile webapp must retain simulator barr5   z(Mobile webapp must retain touch joystickN)ÚMOBILE_INDEX_HTMLr   r   )r   Úmobile_contents     r   Ú"test_zero_mobile_webapp_regressionz<TestPcWebClientLayoutUnit.test_zero_mobile_webapp_regression†   s„   € å ×'Ò'Ñ)Ô)Ð)Ð)Ð)Ý*×4Ò4¸gÐ4ÑFÔFˆØ Ð/Ð/Ð/Ð1ZÑ/Ô/Ð/Ø# ~Ð5Ð5Ð5Ð7`Ñ5Ô5Ð5Ø# ~Ð5Ð5Ð5Ð7aÑ5Ô5Ð5Ð5Ð5r    N)r   r   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   r(   r/   r3   r7   rC   rE   rG   rI   rM   © r    r   r   r      sô   € € € € € ØSÐSð	+ð 	+ð 	+ð 	+ðLð Lð Lð Lð-ð -ð -ð -ðSð Sð Sð Sð`ð `ð `ð `ð0ð 0ð 0ð 0ð*	*ð 	*ð 	*ð 	*ð	/ð 	/ð 	/ð 	/ð/ð /ð /ð /ðbð bð bð bð bð br    r   )rQ   Ú
__future__r   ÚinspectÚosÚreÚsysÚpathlibr   r-   Ú__file__ÚresolveÚparentÚPROJECT_ROOTÚ
WEB_PC_DIRr,   r   r   r   r%   rK   r   rR   r    r   ú<module>r^      s5  ðð
ð 
ð #Ð "Ð "Ð "Ð "Ð "Ø €€€Ø 	€	€	€	Ø 	€	€	€	Ø 
€
€
€
Ø Ð Ð Ð Ð Ð Ø €€€àˆt�H‰~Œ~×%Ò%Ñ'Ô'Ô.Ô5Ô<€Ø˜HÑ$ xÑ/€
Ø˜,Ñ&€
Ø˜Ñ Ñ-€Ø
�uÑ
˜|Ñ
+€Ø˜%Ñ /Ñ1€
Ø˜WÑ$Ð'8Ñ8€Ø  8Ñ+¨hÑ6¸ÑEÐ ðmbð mbð mbð mbð mbñ mbô mbð mbð mbð mbr    