Files
horizon-airdef/tests/test_lab.py
T
Ludovic Marie cb19660fbe Build Horizon Rust parity foundations and differential validation
Add version-bound core, world data, geometry, generation and feature implementations with native client/server comparison tools and scoped evidence reports. Apply Horizon project branding.

Workspace tests, Clippy and 147 Python tests passed. Full 51-family survival and expanded provider comparisons are still running; complete gameplay parity and a playable Rust client remain unfinished. Private game artifacts and the isolated simple-block placement work are excluded.
2026-10-06 11:24:51 +02:00

132 lines
6.9 KiB
Python

import hashlib
import io
import json
from pathlib import Path
import struct
import subprocess
import tempfile
import unittest
from unittest import mock
import zipfile
from tools import check_public_tree, lab
def minimal_class(source="Example.java"):
# A valid class-file structure with no fields/methods and one SourceFile attribute.
def utf8(value):
data = value.encode()
return b"\x01" + struct.pack(">H", len(data)) + data
return (b"\xca\xfe\xba\xbe" + struct.pack(">HHH", 0, 69, 5)
+ utf8("SourceFile") + utf8(source) + utf8("Example") + b"\x07\x00\x03"
+ struct.pack(">HHHHHHHHIH", 1, 4, 0, 0, 0, 0, 1, 1, 2, 2))
class ArtifactTests(unittest.TestCase):
def test_download_rejects_corruption_without_overwriting_existing_file(self):
with tempfile.TemporaryDirectory() as temp:
destination = Path(temp) / "game.jar"
destination.write_bytes(b"existing")
with mock.patch("urllib.request.urlopen", return_value=io.BytesIO(b"corrupt")):
with self.assertRaisesRegex(ValueError, "Checksum mismatch"):
lab.download("https://example.invalid/game.jar", destination, "0" * 40)
self.assertEqual(destination.read_bytes(), b"existing")
self.assertEqual([p.name for p in Path(temp).iterdir()], ["game.jar"])
def test_cached_download_is_verified(self):
with tempfile.TemporaryDirectory() as temp:
destination = Path(temp) / "game.jar"
destination.write_bytes(b"verified")
with mock.patch("urllib.request.urlopen") as request:
lab.download("https://example.invalid", destination, hashlib.sha1(b"verified").hexdigest())
request.assert_not_called()
def test_sourcefile_metadata_covers_inner_classes(self):
with tempfile.TemporaryDirectory() as temp:
path = Path(temp) / "game.jar"
with zipfile.ZipFile(path, "w") as archive:
archive.writestr("demo/Example.class", minimal_class())
archive.writestr("demo/Example$Inner.class", minimal_class())
result = lab.inventory(path)
self.assertEqual(result["class_count"], 2)
self.assertEqual(result["expected_source_files"], ["demo/Example.java"])
def test_invalid_class_is_rejected(self):
for data in [b"oops", b"\xca\xfe\xba\xbe"]:
with self.assertRaises(ValueError):
lab.ClassReader(data).metadata()
def test_server_bundler_extracts_actual_game_and_checks_checksum(self):
with tempfile.TemporaryDirectory() as temp:
directory = Path(temp)
path = directory / "server.jar"
game = b"inner game jar"
library = b"dependency"
with zipfile.ZipFile(path, "w") as archive:
archive.writestr("META-INF/versions.list", f"{hashlib.sha256(game).hexdigest()}\t26.3\t26.3/game.jar\n")
archive.writestr("META-INF/versions/26.3/game.jar", game)
archive.writestr("META-INF/libraries.list", f"{hashlib.sha256(library).hexdigest()}\tdemo:lib:1\tdemo/lib.jar\n")
archive.writestr("META-INF/libraries/demo/lib.jar", library)
extracted, libraries = lab.unpack_server(path, directory, "26.3")
self.assertEqual(extracted.read_bytes(), game)
self.assertEqual(libraries[0].read_bytes(), library)
with self.assertRaises(ValueError):
lab.unpack_server(path, directory, "wrong-version")
def test_server_bundler_rejects_path_traversal(self):
for relative in ["../../escape.jar", "/escape.jar", "..\\escape.jar"]:
with zipfile.ZipFile(io.BytesIO(), "w") as archive:
archive.writestr("entries", f"{'0' * 64}\tdemo\t{relative}")
with self.assertRaisesRegex(ValueError, "Unsafe bundled path"):
list(lab.bundle_entries(archive, "entries"))
def test_coverage_reports_missing_files_and_failed_method_markers(self):
with tempfile.TemporaryDirectory() as temp:
directory = Path(temp)
lab.write_json(directory / "reports" / "client-inventory.json", {
"class_count": 3, "expected_source_files": ["demo/Example.java", "demo/Missing.java"]
})
sources = directory / "sources" / "client" / "demo"
sources.mkdir(parents=True)
(sources / "Example.java").write_text("// $VF: Couldn't be decompiled\n")
report = lab.coverage(directory, "client")
self.assertEqual(report["missing_source_files"], ["demo/Missing.java"])
self.assertEqual(report["files_with_decompiler_error_markers"], ["demo/Example.java"])
class PublicationTests(unittest.TestCase):
def test_private_paths_rejected(self):
for path in [".local/minecraft/source.java", "decompiled/Foo.txt", "game.JAR", "capture.jfr", "source/Foo.java"]:
self.assertTrue(check_public_tree.prohibited(path), path)
for path in ["tools/lab.py", "crates/voxel-kernels/src/lib.rs", "Cargo.lock", "docs/analysis.md",
"mods/horizon/src/main/java/dev/horizonlab/HorizonLab.java",
"mods/horizon-lab/src/main/java/dev/horizonlab/HorizonLab.java"]:
self.assertFalse(check_public_tree.prohibited(path), path)
self.assertTrue(check_public_tree.prohibited("mods/horizon/src/main/java/net/minecraft/Client.java"))
for path in ["tools/JfrSummary.java", "tests/java/JfrFixture.java"]:
self.assertFalse(check_public_tree.prohibited(path), path)
for path in ["tools/Minecraft.java", "tests/java/Client.java", ".local/tools/JfrSummary.java"]:
self.assertTrue(check_public_tree.prohibited(path), path)
def test_force_added_ignored_file_is_detected_in_index_and_history(self):
with tempfile.TemporaryDirectory() as temp:
directory = Path(temp)
real_check_output = subprocess.check_output
def git(*args):
return real_check_output(["git", *args], cwd=directory, stderr=subprocess.DEVNULL)
git("init", "-b", "main")
(directory / ".gitignore").write_text("/.local/\n")
(directory / ".local").mkdir()
(directory / ".local" / "artifact.txt").write_text("private fixture")
git("add", ".gitignore")
git("add", "-f", ".local/artifact.txt")
with mock.patch("tools.check_public_tree.subprocess.check_output",
side_effect=lambda command: git(*command[1:])):
self.assertIn(".local/artifact.txt", check_public_tree.paths_in_repository())
git("-c", "user.name=Test", "-c", "user.email=test@example.invalid", "commit", "-m", "fixture")
self.assertIn(".local/artifact.txt", check_public_tree.paths_in_repository(history=True))
if __name__ == "__main__":
unittest.main()