§
    ¨á¾jÙ'  ã                  ón  — d Z ddlmZ ddlZddlmZ ddlZddlZddlZddl	m
Z
mZmZ ddlmZ ddlZddlmZmZ ddlmZmZ dd	lmZmZmZmZmZmZmZ  ee¦  «                             ¦   «         j         j         j         Z! G d
„ d¦  «        Z" G d„ d¦  «        Z# G d„ d¦  «        Z$ G d„ d¦  «        Z%dS )z÷
Empirical Adversarial Stress Test Suite for FreeExile Graphics Optimization:
Adversarially tests LOD Generator, WebP Compressor, Viewport Frustum Culling (10k+ entities),
and validates the Draw Call Budget (< 30 calls for 50 on-screen entities).
é    )ÚannotationsN)ÚPath)ÚDictÚListÚTuple)ÚImage)Úevaluate_lod_generationÚgenerate_sprite_lods)Úcompress_to_webpÚbatch_compress_directory)ÚAABBÚEntityBoundsÚ	Frustum2DÚbenchmark_cullingÚcull_entitiesÚ
intersectsÚproject_isoc                  ó2   — e Zd ZdZdd„Zdd„Zdd„Zdd	„Zd
S )Ú!TestLODGeneratorAdversarialStresszWStress tests for LOD sprite downsampling across extreme dimensions, modes, and entropy.Útmp_pathr   ÚreturnÚNonec                óà  — g d¢}|D �]e\  }}|d|› d|› d�z  }t          j        d||fd¦  «                             |¦  «         t          ||d|› d|› �z  ¦  «        }|d                              ¦   «         r|d	                              ¦   «         sJ ‚t          j        |d	         ¦  «        5 }t          d
t          t          |dz  ¦  «        ¦  «        ¦  «        }t          d
t          t          |dz  ¦  «        ¦  «        ¦  «        }	|j	        ||	fk    sJ ‚	 ddd¦  «         n# 1 swxY w Y   |dk    r7t          ||d|› d|› �z  ¦  «        }
|
j        dk    sJ d|
j        › d�¦   «         ‚�ŒgdS )zFTests 1x1, 2048x2048, and 4096x2048 textures under Lanczos resampling.©)é   r   )é   r   )i   r   Údim_Úxú.pngÚRGBA)éx   éP   éÈ   éÿ   Úout_Úlod0Úlod2r   g      Ð?Nr   Úeval_çš™™™™™Ù?zLOD-2 ratio z > 0.40)r   ÚnewÚsaver
   ÚexistsÚopenÚmaxÚintÚroundÚsizer	   Úlod2_size_ratio)Úselfr   ÚsizesÚwÚhÚpÚpathsÚimg_l2Ú
expected_wÚ
expected_hÚress              úPC:\Projects\FreeExile\tests\unit\test_challenger_graphics_optimization_stress.pyÚtest_lod_extreme_dimensionsz=TestLODGeneratorAdversarialStress.test_lod_extreme_dimensions+   sÞ  € à'KÐ'KÐ'KˆØð 	`ñ 	`‰DˆAˆqØÐ- !Ð-Ð- aÐ-Ð-Ð-Ñ-ˆAÝŒI�f˜q !˜fÐ&9Ñ:Ô:×?Ò?ÀÑBÔBÐBÝ(¨¨H°~¸a°~°~À!°~°~Ñ,EÑFÔFˆEØ˜”=×'Ò'Ñ)Ô)ÐD¨e°F¬m×.BÒ.BÑ.DÔ.DÐDÐDÐDå”˜E &œMÑ*Ô*ð ?¨fÝ  ¥C­¨a°$©h©¬Ñ$8Ô$8Ñ9Ô9�
Ý  ¥C­¨a°$©h©¬Ñ$8Ô$8Ñ9Ô9�
Ø”{ z°:Ð&>Ò>Ð>Ð>Ð>Ð>ð?ð ?ð ?ñ ?ô ?ð ?ð ?ð ?ð ?ð ?ð ?øøøð ?ð ?ð ?ð ?ð
 �DŠyˆyÝ-¨a°¸OÀA¸O¸OÈ¸O¸OÑ1KÑLÔL�ØÔ*¨dÒ2Ð2Ð2Ð4_À3ÔCVÐ4_Ð4_Ð4_Ñ2Ô2Ð2ùð	`ð 	`s   Â-A*D$Ä$D(	Ä+D(	c                óÒ  ‡— |dz  }t          j        ddd¦  «                             |¦  «         t          ||dz  ¦  «        }|j        dk    sJ ‚t          j        d¦  «        Št          ˆfd„t          d	¦  «        D ¦   «         ¦  «        }|d
z  }t          j	        ddt          |¦  «        ¦  «                             |¦  «         t          ||dz  ¦  «        }|j        dk    sJ ‚dS )z?Tests random uniform noise and completely transparent textures.ztrans_512.pngr    )é   r@   )r   r   r   r   Ú	out_transr)   iç  c              3  óB   •K  — | ]}‰                      d ¦  «        V — ŒdS )é   N)Úgetrandbits)Ú.0Ú_Úrngs     €r=   ú	<genexpr>z[TestLODGeneratorAdversarialStress.test_lod_high_entropy_and_transparency.<locals>.<genexpr>G   s/   øè è € ÐQÐQ°q §¢°Ñ 2Ô 2ÐQÐQÐQÐQÐQÐQó    i   znoise_256.png)é   rJ   Ú	out_noiseN)r   r*   r+   r	   r2   ÚrandomÚRandomÚ	bytearrayÚrangeÚ	frombytesÚbytes)r3   r   Útrans_pÚ	res_transÚnoise_bytesÚnoise_pÚ	res_noiserG   s          @r=   Ú&test_lod_high_entropy_and_transparencyzHTestLODGeneratorAdversarialStress.test_lod_high_entropy_and_transparency=   sö   ø€ ð ˜_Ñ,ˆÝŒ	�&˜* lÑ3Ô3×8Ò8¸ÑAÔAÐAÝ+¨G°XÀÑ5KÑLÔLˆ	ØÔ(¨DÒ0Ð0Ð0Ð0õ Œm˜CÑ Ô ˆÝÐQÐQÐQÐQ½EÀ-Ñ<PÔ<PÐQÑQÔQÑQÔQˆØ˜_Ñ,ˆÝŒ˜ 
­E°+Ñ,>Ô,>Ñ?Ô?×DÒDÀWÑMÔMÐMÝ+¨G°XÀÑ5KÑLÔLˆ	ØÔ(¨DÒ0Ð0Ð0Ð0Ð0Ð0rI   c                óÖ   — dD ]e}|d|› d�z  }t          j        |d¦  «                             |¦  «         t          ||d|› �z  ¦  «        }|d                              ¦   «         sJ ‚ŒfdS )zDTests L, P, RGB, and RGBA modes without unhandled conversion errors.)ÚLÚPÚRGBr    Úmode_r   ©é€   r^   r%   r'   N)r   r*   r+   r
   r,   )r3   r   Úmoder7   r8   s        r=   Útest_lod_image_modesz6TestLODGeneratorAdversarialStress.test_lod_image_modesM   sŠ   € à-ð 	*ð 	*ˆDØÐ- 4Ð-Ð-Ð-Ñ-ˆAÝŒI�d˜JÑ'Ô'×,Ò,¨QÑ/Ô/Ð/Ý(¨¨H°}¸d°}°}Ñ,DÑEÔEˆEØ˜”=×'Ò'Ñ)Ô)Ð)Ð)Ð)Ð)ð		*ð 	*rI   c                óÈ   — |dz  }t          j        ddd¦  «                             |¦  «         t          ||dz  ¦  «        }|j        dk    sJ ‚|j        d         dk    sJ ‚d	S )
zTDocuments empirical boundary where PNG container overhead dominates sub-16px assets.zmicro_4x4.pngr    )é   rb   )r$   r   r   r$   Ú	out_micror)   r'   r!   N)r   r*   r+   r	   r2   Ú	lod_sizes)r3   r   r7   r<   s       r=   Ú)test_lod_micro_texture_container_boundaryzKTestLODGeneratorAdversarialStress.test_lod_micro_texture_container_boundaryU   su   € à�Ñ&ˆÝŒ	�&˜&Ð"2Ñ3Ô3×8Ò8¸Ñ;Ô;Ð;Ý% a¨°KÑ)?Ñ@Ô@ˆàÔ" TÒ)Ð)Ð)Ð)ØŒ}˜VÔ$¨Ò+Ð+Ð+Ð+Ð+Ð+rI   N©r   r   r   r   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__r>   rW   r`   re   © rI   r=   r   r   (   sn   € € € € € ØaÐað`ð `ð `ð `ð$1ð 1ð 1ð 1ð *ð *ð *ð *ð,ð ,ð ,ð ,ð ,ð ,rI   r   c                  ó*   — e Zd ZdZd
d„Zd
d„Zd
d„Zd	S )Ú&TestTextureCompressorAdversarialStresszSStress tests for WebP compression under noisy, empty, and out-of-bounds parameters.r   r   r   r   c                ó,  — dD ]�\  }}|d|› d|› d�z  }|d|› d|› d�z  }t          j        d||fd¦  «                             |¦  «         t          ||d¬	¦  «        }|                     ¦   «         sJ ‚|j        d
k    sJ ‚|dk    r|j        dk    sJ ‚Œ‘dS )z5Tests 1x1, 2048x2048, and 4096x2048 WebP conversions.r   Útex_r   r   ú.webpr    )éd   é–   r#   r$   r"   ©Úqualityr   r   ç      à?N)r   r*   r+   r   r,   Úcompressed_sizeÚcompression_ratio)r3   r   r5   r6   ÚsrcÚdstr<   s          r=   Ú test_compress_extreme_dimensionszGTestTextureCompressorAdversarialStress.test_compress_extreme_dimensionsb   sÛ   € à8ð 	5ð 	5‰DˆAˆqØÐ/ AÐ/Ð/¨Ð/Ð/Ð/Ñ/ˆCØÐ0 AÐ0Ð0¨Ð0Ð0Ð0Ñ0ˆCÝŒI�f˜q !˜fÐ&:Ñ;Ô;×@Ò@ÀÑEÔEÐEÝ" 3¨°RÐ8Ñ8Ô8ˆCØ—:’:‘<”<ÐÐ�<ØÔ&¨Ò*Ð*Ð*Ð*Ø�DŠyˆyØÔ,°Ò4Ð4Ð4Ð4øð	5ð 	5rI   c                óè   — |dz  }t          j        ddd¦  «                             |¦  «         dD ]@}|d|› d�z  }t          |||¬¦  «        }|                     ¦   «         sJ ‚|j        d	k    sJ ‚ŒAd
S )zHVerifies robustness against out-of-bound quality inputs (e.g. -50, 150).zclamp_test.pngr    r]   )r#   é2   r"   r$   )iÎÿÿÿr   r"   rr   Úclamp_rp   rs   r   N)r   r*   r+   r   r,   rv   )r3   r   rx   Úqry   r<   s         r=   Útest_compress_quality_clampingzETestTextureCompressorAdversarialStress.test_compress_quality_clampingn   s�   € àÐ)Ñ)ˆÝŒ	�&˜*Ð&8Ñ9Ô9×>Ò>¸sÑCÔCÐCØ"ð 	+ð 	+ˆAØÐ. aÐ.Ð.Ð.Ñ.ˆCÝ" 3¨°QÐ7Ñ7Ô7ˆCØ—:’:‘<”<ÐÐ�<ØÔ&¨Ò*Ð*Ð*Ð*Ð*ð		+ð 	+rI   c                óZ  — t           dz  dz  dz  dz  }d„ |                     d¦  «        D ¦   «         }t          |¦  «        dk    sJ dt          |¦  «        › d	�¦   «         ‚|D ]G}||j        › d
�z  }t	          ||d¬¦  «        }|j        dk    sJ |j        › d|j        d›d�¦   «         ‚ŒHdS )zIValidates <= 50% WebP budget on all production character textures > 10KB.ÚclientÚwebappÚassetsÚ
charactersc                óL   — g | ]!}|                      ¦   «         j        d k    ¯|‘Œ"S )i (  )ÚstatÚst_size)rE   r7   s     r=   ú
<listcomp>zbTestTextureCompressorAdversarialStress.test_compress_production_sprites_budget.<locals>.<listcomp>{   s-   € ÐNÐNÐN�a°Q·V²V±X´XÔ5EÈÒ5MÐ5M�Ð5MÐ5MÐ5MrI   z*.pngrb   zFound z character textures > 10KBrp   r"   rs   ru   z ratio z.2fz > 0.50N)Ú	REPO_ROOTÚglobÚlenÚstemr   rw   Úname)r3   r   Úchar_dirÚpngsr7   ry   r<   s          r=   Ú'test_compress_production_sprites_budgetzNTestTextureCompressorAdversarialStress.test_compress_production_sprites_budgetx   sã   € å˜xÑ'¨(Ñ2°XÑ=ÀÑLˆØNÐN˜8Ÿ=š=¨Ñ1Ô1ÐNÑNÔNˆÝ�4‰yŒy˜AŠ~ˆ~ˆ~ÐM­¨D©	¬	ÐMÐMÐM‰~Œ~ˆ~Øð 	gð 	gˆAØ ¤Ð-Ð-Ð-Ñ-ˆCÝ" 1 c°2Ð6Ñ6Ô6ˆCØÔ(¨DÒ0Ð0Ð0°Q´VÐ2fÐ2fÀCÔDYÐ2fÐ2fÐ2fÐ2fÑ0Ô0Ð0Ð0ð	gð 	grI   Nrf   )rg   rh   ri   rj   rz   r   r�   rk   rI   r=   rm   rm   _   s\   € € € € € Ø]Ð]ð
5ð 
5ð 
5ð 
5ð+ð +ð +ð +ðgð gð gð gð gð grI   rm   c                  ó:   — e Zd ZdZd
d„Zd
d„Zd
d„Zd
d„Zd
d„Zd	S )Ú$TestViewportCullingAdversarialStresszXStress tests for frustum culling at scale (10,000 entities) and geometric singularities.r   r   c                óò   — t          dd¬¦  «        }|d         dk    sJ ‚d|d         cxk    rdk    sn J ‚|d         d	k     sJ d
|d         › d�¦   «         ‚|d         dk     sJ d|d         › d�¦   «         ‚dS )zFMeasures 10,000 entity culling throughput, latency, and culling ratio.i'  ©g      ž@g     à�@)Únum_entitiesÚviewport_sizeÚtotal_entitiesg      N@Úculled_percentageg     @U@Ú
elapsed_msg      ^@zElapsed zms exceeded 120ms capÚper_entity_usg      .@zPer-entity latency zus too highN)r   )r3   r<   s     r=   Ú"test_cull_10000_entities_benchmarkzGTestViewportCullingAdversarialStress.test_cull_10000_entities_benchmark†   s»   € å¨UÐBRÐSÑSÔSˆØÐ#Ô$¨Ò-Ð-Ð-Ð-Ø�sÐ.Ô/Ð7Ð7Ò7Ð7°4Ò7Ð7Ð7Ð7Ð7Ð7Ø�<Ô  5Ò(Ð(Ð(Ð*]°S¸Ô5FÐ*]Ð*]Ð*]Ñ(Ô(Ð(Ø�?Ô# dÒ*Ð*Ð*Ð,cÀ#ÀoÔBVÐ,cÐ,cÐ,cÑ*Ô*Ð*Ð*Ð*rI   c                ó&  — t          ddd¦  «        }t          dd|gd¬¦  «        }|g k    sJ ‚t          ddddd¬¦  «        }t          d	d
d
dd¬¦  «        }t          dd||gd¬¦  «        }t          |¦  «        dk    r|d         j        dk    sJ ‚dS )zMTests zero-size, negative-size viewports, and negative padding without crash.Úcenterç        ©rž   rž   )g      ‰@g     À‚@g     @À)ÚpaddingÚ
origin_dot)Úscreen_widthÚscreen_heightÚaway_dotg      @r   r   N)r   r   r‹   Ú	entity_id)r3   ÚentÚculledÚ	on_originÚ
off_originÚres_zeros         r=   Útest_cull_degenerate_viewportszCTestViewportCullingAdversarialStress.test_cull_degenerate_viewportsŽ   s¶   € å˜8 S¨#Ñ.Ô.ˆå˜z¨>¸C¸5È&ÐQÑQÔQˆØ˜Š|ˆ|ˆ|ˆ|õ ! ¨s°CÀcÐY\Ð]Ñ]Ô]ˆ	Ý! *¨c°3ÀSÐX[Ð\Ñ\Ô\ˆ
Ý  ¨Z¸)ÀZÐ9PÐZ]Ð^Ñ^Ô^ˆÝ�8‰}Œ} Ò!Ð! h¨q¤kÔ&;¸|Ò&KÐ&KÐ&KÐKÐ&KÐ&KrI   c                ó¾   — dD ]Y}||f}t          d|dz   |dz   ¦  «        }t          ddd¦  «        }t          |d||g¦  «        }d„ |D ¦   «         }d|v sJ ‚d|vsJ ‚ŒZdS )	zHVerifies culling precision with extreme floating-point camera positions.)g    €„.Ag    €„.Ág   ¢”mBÚneargš™™™™™¹?Úfarrž   r”   c                ó   — h | ]	}|j         ’Œ
S rk   )r¥   )rE   Úes     r=   ú	<setcomp>z\TestViewportCullingAdversarialStress.test_cull_extreme_camera_coordinates.<locals>.<setcomp>¢   s   € Ð4Ð4Ð4 q�q”{Ð4Ð4Ð4rI   N)r   r   )r3   Ú	cam_coordÚcamÚnear_entÚfar_entÚvisibleÚvis_idss          r=   Ú$test_cull_extreme_camera_coordinateszITestViewportCullingAdversarialStress.test_cull_extreme_camera_coordinates›   sž   € à*ð 	(ð 	(ˆIØ˜iÐ(ˆCÝ# F¨I¸©O¸YÈ¹_ÑMÔMˆHÝ" 5¨#¨sÑ3Ô3ˆGÝ# CÐ)9¸HÀgÐ;NÑOÔOˆGØ4Ð4¨GÐ4Ñ4Ô4ˆGØ˜WÐ$Ð$Ð$Ð$Ø Ð'Ð'Ð'Ð'Ð'ð	(ð 	(rI   c                ó"  — t          dt          d¦  «        d¦  «        }t          dd|g¦  «        }|g k    sJ ‚t          dt          d¦  «        d¦  «        }t          dd|g¦  «        }t          |¦  «        dk    r|d	         j        dk    sJ ‚d
S )zCDocuments IEEE 754 float behavior for infinite and NaN coordinates.Úinf_mobÚinfrž   rŸ   r”   Únan_mobÚnanr   r   N)r   Úfloatr   r‹   r¥   )r3   Úent_infÚvis_infÚent_nanÚvis_nans        r=   Ú%test_cull_nan_inf_boundary_conditionszJTestViewportCullingAdversarialStress.test_cull_nan_inf_boundary_conditions¦   s“   € å˜y­%°©,¬,¸Ñ<Ô<ˆÝ 
Ð,<¸w¸iÑHÔHˆØ˜"Š}ˆ}ˆ}ˆ}å˜y­%°©,¬,¸Ñ<Ô<ˆÝ 
Ð,<¸w¸iÑHÔHˆå�7‰|Œ|˜qÒ Ð  W¨Q¤ZÔ%9¸YÒ%FÐ%FÐ%FÐFÐ%FÐ%FrI   c                ó€   — t          ddd¦  «        \  }}t          dddd¬¦  «        \  }}||k    sJ ‚||dz
  k    sJ ‚dS )zRVerifies vertical displacement in isometric projection with extreme Z coordinates.g      $@rž   g     @�@g      8@)Úz_scaleg     p×@N)r   )r3   Úiso_x0Úiso_y0Úiso_xzÚiso_yzs        r=   Ú"test_cull_extreme_elevation_offsetzGTestViewportCullingAdversarialStress.test_cull_extreme_elevation_offset±   s^   € å$ T¨4°Ñ5Ô5‰ˆ�Ý$ T¨4°ÀÐFÑFÔF‰ˆ�Ø˜ÒÐÐÐØ˜ 'Ñ)Ò)Ð)Ð)Ð)Ð)Ð)rI   N©r   r   )	rg   rh   ri   rj   r›   r«   r¸   rÃ   rÊ   rk   rI   r=   r’   r’   ƒ   sŠ   € € € € € ØbÐbðdð dð dð dðLð Lð Lð Lð	(ð 	(ð 	(ð 	(ð	Gð 	Gð 	Gð 	Gð*ð *ð *ð *ð *ð *rI   r’   c                  óh   — e Zd ZdZej                             dg d¢¦  «        dd	„¦   «         Zdd
„ZdS )ÚTestDrawCallBudgetValidationzSValidates the AC5 constraint: For 50 on-screen entities, instanced draw calls < 30.zentity_count,num_archetypes))r|   r   )r|   é   )r|   é   )rq   rÏ   Úentity_countr/   Únum_archetypesr   r   c                óf   — |}d}d}||z   |z   }|dk     sJ d|› d|› d|› d�¦   «         ‚|dk    sJ ‚d	S )
zKCalculates draw calls under GPU palette instancing and asserts < 30 budget.é   r   é   zDraw calls z exceeded budget of 30 for z entities across z archetypesrC   Nrk   )r3   rÐ   rÑ   Úmonster_batchesÚ
hero_callsÚshadow_callÚtotal_instanced_draw_callss          r=   Ú%test_draw_call_instanced_budget_holdszBTestDrawCallBudgetValidation.test_draw_call_instanced_budget_holds¼   sŽ   € ð )ˆØˆ
ØˆØ%4°zÑ%AÀKÑ%OÐ"à)¨BÒ.Ð.Ð.ðNÐ4ð Nð NØðNð NØ2@ðNð Nð Nñ /Ô.Ð.ð *¨QÒ.Ð.Ð.Ð.Ð.Ð.rI   c                ó4   — d}|dz  }|dk    s
J d¦   «         ‚dS )zQProves that a naive unbatched renderer (1 call per entity) fails the < 30 budget.r|   r   rÔ   z/Naive renderer must exceed the 30 draw call capNrk   )r3   Úentities_on_screenÚnaive_unbatched_draw_callss      r=   Ú0test_draw_call_unbatched_baseline_exceeds_budgetzMTestDrawCallBudgetValidation.test_draw_call_unbatched_baseline_exceeds_budgetÎ   s3   € àÐØ%7¸!Ñ%;Ð"Ø)¨RÒ/Ð/Ð/Ð1bÑ/Ô/Ð/Ð/Ð/rI   N)rÐ   r/   rÑ   r/   r   r   rË   )	rg   rh   ri   rj   ÚpytestÚmarkÚparametrizerÙ   rÝ   rk   rI   r=   rÍ   rÍ   ¹   sn   € € € € € Ø]Ð]à„[×ÒÐ:Ð<aÐ<aÐ<aÑbÔbð/ð /ð /ñ cÔbð/ð"cð cð cð cð cð crI   rÍ   )&rj   Ú
__future__r   ÚmathÚpathlibr   rL   ÚtempfileÚtimeÚtypingr   r   r   ÚPILr   rÞ   Ú"tools.asset_pipeline.lod_generatorr	   r
   Ú'tools.asset_pipeline.texture_compressorr   r   Ú+tools.asset_pipeline.viewport_culling_utilsr   r   r   r   r   r   r   Ú__file__ÚresolveÚparentr‰   r   rm   r’   rÍ   rk   rI   r=   ú<module>rî      s  ððð ð #Ð "Ð "Ð "Ð "Ð "à €€€Ø Ð Ð Ð Ð Ð Ø €€€Ø €€€Ø €€€Ø $Ð $Ð $Ð $Ð $Ð $Ð $Ð $Ð $Ð $à Ð Ð Ð Ð Ð Ø €€€ðð ð ð ð ð ð ð ðð ð ð ð ð ð ð ðð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ˆD�‰NŒN×"Ò"Ñ$Ô$Ô+Ô2Ô9€	ð4,ð 4,ð 4,ð 4,ð 4,ñ 4,ô 4,ð 4,ðn!gð !gð !gð !gð !gñ !gô !gð !gðH3*ð 3*ð 3*ð 3*ð 3*ñ 3*ô 3*ð 3*ðlcð cð cð cð cñ cô cð cð cð crI   