69c7fd925e
The crafting module now matches shapeless recipes with a full bipartite assignment, shrinks shaped patterns like ShapedRecipePattern, keeps result components (suspicious stew effects), and implements the transmute, dye, imbue (tipped arrow), book cloning, firework rocket/star/fade, decorated pot, repair item, map extending, banner duplicate and shield decoration recipes with vanilla's matching and assembly. Crafting remainders now follow Item.craftRemainder only and are placed on the grid by recipe, so cloned books and duplicated banners stay. Stacks gain dyed colour, firework explosion, pot decorations, bundle contents, stew effects and map post-processing components, and their NBT now matches the codecs (defaults omitted, templates without count 1). A banner whose first layer was a rhombus was mistaken for the raid banner; that is fixed. tools/test_recipe_parity.py drives vanilla's RecipeManager (new VanillaRecipeOracle) and the Rust recipe_fixture over 50k generated crafting, cooking, stonecutting and smithing cases and compares matches, results and remainders as canonical NBT; all match. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
72 lines
2.9 KiB
Python
72 lines
2.9 KiB
Python
"""Shared plumbing for the interaction/inventory differential harnesses
|
|
(test_recipe_parity, test_menu_click_parity, test_block_interaction_parity):
|
|
compile and run a vanilla Java oracle headlessly, run the matching Rust
|
|
example, and report differing lines grouped by a key."""
|
|
import json
|
|
import os
|
|
from pathlib import Path
|
|
import subprocess
|
|
try:
|
|
from . import lab, test_rust_parity as base
|
|
except ImportError:
|
|
import lab
|
|
import test_rust_parity as base
|
|
|
|
RESOURCES = lab.LOCAL / 'horizon-client' / '26.3'
|
|
PARITY = lab.ROOT / 'mods/horizon/src/test/java/dev/horizonlab/parity'
|
|
|
|
|
|
def work_dir(name):
|
|
path = lab.LOCAL / name
|
|
path.mkdir(parents=True, exist_ok=True)
|
|
return path
|
|
|
|
|
|
class Vanilla:
|
|
"""Compiles oracles against the pinned server jar and runs them."""
|
|
|
|
def __init__(self, work):
|
|
self.lock, self.jars, self.libraries = base.verify_artifacts()
|
|
self.work = work
|
|
self.classes = work / 'classes'
|
|
self.classes.mkdir(exist_ok=True)
|
|
self.deps = os.pathsep.join(map(str, [self.jars['server'], *self.libraries]))
|
|
|
|
def compile(self, *oracles):
|
|
sources = [PARITY / (name + '.java') for name in oracles]
|
|
subprocess.run(['javac', '--release', str(self.lock['minecraft']['java_major']), '-proc:none',
|
|
'-sourcepath', str(lab.ROOT / 'mods/horizon/src/test/java'), '-nowarn',
|
|
'-cp', self.deps, '-d', str(self.classes), *map(str, sources)], check=True)
|
|
|
|
def run(self, oracle, *args, heap='2G'):
|
|
subprocess.run(['java', f'-Xmx{heap}', '-cp', str(self.classes) + os.pathsep + self.deps,
|
|
'dev.horizonlab.parity.' + oracle, *map(str, args)], check=True)
|
|
|
|
|
|
def cargo_example(package, example, *args, profile=None):
|
|
command = ['cargo', 'run', '-q', '-j3']
|
|
if profile:
|
|
command += ['--profile', profile]
|
|
command += ['-p', package, '--example', example, '--', *map(str, args)]
|
|
subprocess.run(command, check=True, cwd=lab.ROOT)
|
|
|
|
|
|
def compare(cases, native_path, rust_path, key, describe=None, limit=3):
|
|
"""Print differing cases grouped by key(case, native_line); returns the count."""
|
|
native = Path(native_path).read_text().split('\n')
|
|
rust = Path(rust_path).read_text().split('\n')
|
|
if len(native) != len(rust):
|
|
print(f'line counts differ: native {len(native)} rust {len(rust)}')
|
|
groups = {}
|
|
for case, a, b in zip(cases, native, rust):
|
|
if a != b:
|
|
groups.setdefault(key(case, a), []).append((case, a, b))
|
|
describe = describe or (lambda case: case if isinstance(case, str) else json.dumps(case))
|
|
total = sum(len(v) for v in groups.values())
|
|
for name, entries in sorted(groups.items(), key=lambda e: -len(e[1])):
|
|
print(f'{name}: {len(entries)} differing')
|
|
for case, a, b in entries[:limit]:
|
|
print(f' case {describe(case)}\n native {a}\n rust {b}')
|
|
print(f'{len(cases) - total}/{len(cases)} cases match')
|
|
return total
|