874b6f20c2
Основа — Horizon (MIT). История апстрима не переносится: этот репозиторий ведёт свою.
92 lines
4.5 KiB
Python
92 lines
4.5 KiB
Python
#!/usr/bin/env python3
|
|
"""Shared runner for the audio differential harnesses.
|
|
|
|
Each harness writes an input file, runs a Java oracle against the pinned
|
|
client (the real SoundManager / SoundEngine / MusicManager / ambient handlers;
|
|
OpenAL runs on OpenAL Soft's "No Output" device so channel parameters can be
|
|
read back from real AL sources) and a Rust example replaying the same inputs
|
|
through Horizon's audio code, then requires byte-identical output.
|
|
"""
|
|
import json
|
|
import os
|
|
from pathlib import Path
|
|
import platform
|
|
import subprocess
|
|
|
|
try:
|
|
from . import lab, test_rust_parity as base, test_model_baking_parity as baking
|
|
except ImportError:
|
|
import lab, test_rust_parity as base, test_model_baking_parity as baking
|
|
|
|
RESOURCES = lab.RESOURCES
|
|
COMMON_SOURCES = [
|
|
lab.ROOT / 'tools/audio_harness.py',
|
|
lab.ROOT / 'tools/test_rust_parity.py',
|
|
lab.ROOT / 'tools/lab.py',
|
|
lab.ROOT / 'Cargo.toml',
|
|
lab.ROOT / 'Cargo.lock',
|
|
lab.ROOT / 'crates/horizon-client/Cargo.toml',
|
|
lab.ROOT / 'crates/horizon-client/src/sound_events.rs',
|
|
lab.ROOT / 'crates/horizon-client/src/sound_engine.rs',
|
|
]
|
|
|
|
|
|
def require_sounds():
|
|
if not (RESOURCES / 'assets/minecraft/sounds.json').is_file():
|
|
raise SystemExit('Sound assets missing: run cargo run -p horizon-prepare -- sounds first')
|
|
|
|
|
|
def run_harness(name, oracle, example, inputs_text, extra_sources=(), java_args=(), rust_args=(), scope='', timeout=1800):
|
|
"""Run oracle and the client probe `example` on inputs; returns the number of matched lines."""
|
|
require_sounds()
|
|
lock, jars, _ = base.verify_artifacts()
|
|
libraries = baking.client_libraries()
|
|
build = lab.LOCAL / f'rust-{name}'
|
|
build.mkdir(parents=True, exist_ok=True)
|
|
report = build / 'report.json'
|
|
report.unlink(missing_ok=True)
|
|
oracle_path = lab.ROOT / f'mods/horizon/src/test/java/dev/horizonlab/parity/{oracle}.java'
|
|
example_path = lab.ROOT / f'crates/horizon-client/examples/probe/{example}.rs'
|
|
sources = [*COMMON_SOURCES, oracle_path, example_path, *[Path(s) for s in extra_sources]]
|
|
tested = base.source_hashes(sources)
|
|
inputs = build / 'inputs.txt'
|
|
inputs.write_text(inputs_text)
|
|
input_hash = lab.digest(inputs, 'sha256')
|
|
|
|
def run(command, log, env=None):
|
|
with (build / (log + ".log")).open("w") as out:
|
|
try:
|
|
subprocess.run(list(map(str, command)), cwd=lab.ROOT, check=True, timeout=timeout, stdout=out, stderr=subprocess.STDOUT, env=env)
|
|
except subprocess.CalledProcessError:
|
|
raise SystemExit(f"{log} failed: see {build / (log + '.log')}") from None
|
|
|
|
classes = build / 'classes'
|
|
classes.mkdir(exist_ok=True)
|
|
dependencies = os.pathsep.join(map(str, [jars['client'], *libraries]))
|
|
run(['javac', '--release', lock['minecraft']['java_major'], '-proc:none', '-sourcepath', lab.ROOT / 'mods/horizon/src/test/java',
|
|
'-cp', dependencies, '-d', classes, oracle_path], 'compile-java')
|
|
run(['cargo', 'build', '--locked', '-p', 'horizon-client', '--example', 'client_probe'], 'compile-rust')
|
|
metadata = json.loads(subprocess.check_output(['cargo', 'metadata', '--locked', '--no-deps', '--format-version', '1'], cwd=lab.ROOT))
|
|
binary = Path(metadata['target_directory']) / 'debug/examples' / ('client_probe.exe' if os.name == 'nt' else 'client_probe')
|
|
run([binary, example, *rust_args, inputs, build / 'rust.txt'], 'rust')
|
|
env = dict(os.environ, ALSOFT_DRIVERS='null')
|
|
run(['java', '-Xmx1G', '-cp', str(classes) + os.pathsep + dependencies, f'dev.horizonlab.parity.{oracle}', *java_args, inputs, build / 'client.txt'],
|
|
'client', env=env)
|
|
matched = base.compare(build / 'client.txt', build / 'rust.txt')
|
|
base.ensure_sources_unchanged(sources, tested)
|
|
if input_hash != lab.digest(inputs, 'sha256'):
|
|
raise AssertionError('Input fixtures changed')
|
|
lab.write_json(report, dict(
|
|
schema=1, minecraft=lock['minecraft']['version'], manifest_sha1=lock['minecraft']['manifest_sha1'], platform=platform.platform(),
|
|
rustc=subprocess.check_output(['rustc', '--version'], text=True).strip(),
|
|
java=subprocess.check_output(['java', '--version'], text=True).splitlines()[0],
|
|
sources_sha256=tested, input_sha256=input_hash, client_jar_sha256=lab.digest(jars['client'], 'sha256'),
|
|
sounds_json_sha256=lab.digest(RESOURCES / 'assets/minecraft/sounds.json', 'sha256'),
|
|
matched_output_lines=matched, output_sha256=lab.digest(build / 'rust.txt', 'sha256'), scope=scope))
|
|
return matched, report
|
|
|
|
|
|
def bits(value):
|
|
import struct
|
|
return struct.pack('>f', value).hex()
|