Files
skate-3-rust-engine/tools/test_setup_assets.py
T
Hails 11ff8cd9c2 Setup: extract and decode the disc's game audio (new audio group)
- audio_formats.py: EA SNR (EA-XMA) stream scanner with block-chain
  validation, SPLC bank streams and patch tree (records, layers,
  containers; verified on all 20 banks), .grain files (speed-sweep
  recordings), loopable speed bands, gain-free 5->2 downmix.
- audio_export.py: decodes only what the engine plays (22 ambience
  beds, 14 grains x 6 speed bands, wheel spins, 23 sample banks) to
  PCM16 WAV in assets/private/audio with audio_manifest.json (v3,
  incl. SPLC patch trees). Decoder: pinned vgmstream r2117
  (SHA-256 checked) via the existing dependency() helper.
- Registered as optional asset group `audio` (versions, receipts,
  asset_exports, install); a failure records audio-availability.json
  and the game runs silent. Other groups' fingerprints unchanged.
- .gitignore: retail audio extensions and *.wav (Skyline mod WAVs
  excepted). Tests updated for the new group.
2026-10-01 17:37:30 -06:00

63 lines
3.6 KiB
Python

"""Independent HUD installation checks without retail data."""
import json
import sys
from pathlib import Path
import tempfile
import unittest
from unittest.mock import patch
sys.path.insert(0,str(Path(__file__).resolve().parent))
import prepare_runtime_huds as huds
def scoring(game, output, *args):
(output/'runtime').mkdir(parents=True)
(output/'runtime/trickdisplay.json').write_text(json.dumps(dict(
version=1, format='skate3-scoring-hud', shapes={}, fonts={})))
def marker(game, output):
output.mkdir(parents=True)
(output/'hud.json').write_text(json.dumps(dict(version=1, canvas=[1280,720], meshes=[{}], textures=[])))
class HudWorkspace(unittest.TestCase):
def test_long_install_uses_short_temporary_workspace_and_keeps_outputs(self):
with tempfile.TemporaryDirectory() as temp:
root=Path(temp); assets=root/'assets'; seen=[]
long_work=root/('nested-install-'*12)/'conversion/hud'
def prepare(game, output, *args):
seen.append(output)
self.assertNotIn(long_work,output.parents)
self.assertLess(len(str(output/'source-cache/assets/data/fe/source/images/buttons/xbox360/buttons/0000_button_DPad_Down_hud.Texture.texture.bin')),260)
scoring(game,output,*args)
with patch.object(huds,'prepare_scoring',side_effect=prepare),patch.object(huds,'prepare_marker',side_effect=marker):
self.assertEqual(len(huds.prepare(root/'game',assets,long_work)),2)
self.assertTrue((assets/'private/hud/runtime/trickdisplay.json').is_file())
self.assertTrue(all(not p.exists() for p in seen))
def test_one_missing_hud_still_installs_other_and_receipts_allow_reuse(self):
from tools.asset_pipeline.group_receipts import record, damaged
with tempfile.TemporaryDirectory() as temp:
root=Path(temp); assets=root/'assets'
with patch.object(huds,'prepare_scoring',side_effect=KeyError('missing font')),patch.object(huds,'prepare_marker',side_effect=marker):
self.assertEqual(len(huds.prepare(root/'game',assets,root/'work')),1)
self.assertEqual(json.loads((assets/'private/hud-availability.json').read_text())['status'],'unavailable')
receipt=record(root,'hud')
self.assertTrue(receipt)
self.assertEqual(damaged(root,{'outputs':{'hud':receipt}},exclude=('core','character','environment','maps','audio')),set())
def test_failure_keeps_verified_existing_huds(self):
with tempfile.TemporaryDirectory() as temp:
root=Path(temp);assets=root/'assets'
scoring(None,assets/'private/hud');marker(None,assets/'private/session-marker')
before=(assets/'private/hud/runtime/trickdisplay.json').read_bytes()
with patch.object(huds,'prepare_scoring',side_effect=RuntimeError('decode failed')),patch.object(huds,'prepare_marker',side_effect=FileNotFoundError('missing bank')):
self.assertEqual(huds.prepare(root/'game',assets,root/'work'),{})
self.assertEqual((assets/'private/hud/runtime/trickdisplay.json').read_bytes(),before)
for name in ('hud','session-marker'):
self.assertEqual(json.loads((assets/'private'/(name+'-availability.json')).read_text())['status'],'retained')
def test_disk_errors_still_abort(self):
with tempfile.TemporaryDirectory() as temp,patch.object(huds,'prepare_scoring',side_effect=PermissionError('read denied')):
with self.assertRaises(PermissionError):huds.prepare(Path(temp),Path(temp)/'assets',Path(temp)/'work')