mirror of
https://github.com/horizon-rust/horizon.git
synced 2026-11-08 08:07:53 -10:00
Keep superclass air refill for NoAI Nautilus
Skip only the Nautilus custom air handler under NoAI, preserving the existing Breath/drown path and normal custom behavior. Cover actual Game and full Mob ticks against fresh Java. Co-Authored-By: Codex <[email protected]>
This commit is contained in:
1 parent
87c51ab9c9
commit
3443abbde5
4 files changed
+380
-2
No files matched your search
@@ -1197,9 +1197,11 @@ fn base_tick(m: &mut Mob, w: &MobWorld, events: &mut Vec<MobEvent>) {
|
||||
m.damage(1.0, Damage::of(DamageKind::InWall));
|
||||
}
|
||||
// Air supply and drowning (WaterAnimal.handleAirSupply for aquatic mobs).
|
||||
// Nautilus.baseTick: NoAI skips only the custom handler; the
|
||||
// superclass Breath/drown path must still process its air.
|
||||
if m.species() == Species::Axolotl {
|
||||
axolotl_air_supply(m, w);
|
||||
} else if m.kind.flags.needs_water {
|
||||
} else if m.kind.flags.needs_water && !(m.no_ai && m.species() == Species::Nautilus) {
|
||||
if !m.fluids.in_water {
|
||||
m.air -= 1;
|
||||
if m.air == -20 {
|
||||
@@ -5053,3 +5055,77 @@ mod flight_effect_fall_tests {
|
||||
assert!(ran, "prepared resources must run the integration fixture");
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod nautilus_noai_air_tests {
|
||||
use super::*;
|
||||
use std::sync::Arc;
|
||||
|
||||
fn check(water: bool, no_ai: bool, initial: i32, expected: [i32; 2]) {
|
||||
let build = |world: &mut crate::world::World,
|
||||
registry: &horizon_world::registry::BlockRegistry| {
|
||||
world
|
||||
.chunks
|
||||
.insert((0, 0), Arc::new(crate::chunk::Chunk::empty(0, 0)));
|
||||
if water {
|
||||
let state = registry.default_state("minecraft:water").unwrap();
|
||||
for x in 0..=4 {
|
||||
for z in 0..=4 {
|
||||
for y in 0..=8 {
|
||||
world.set(x, y, z, state).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
let ran = crate::mobs::world::with_built_test_world(&[], build, |w, types| {
|
||||
let kind = Arc::new(types.types["minecraft:nautilus"].clone());
|
||||
assert!(kind.flags.needs_water && kind.flags.breathes_water);
|
||||
let mut mob = Mob::new(1, kind, Vec3::new(2.5, 3.0, 2.5), 0.0);
|
||||
mob.no_ai = no_ai;
|
||||
mob.no_gravity = true;
|
||||
mob.persistent = true;
|
||||
mob.attrs.speed = 0.0;
|
||||
mob.health = 10.0;
|
||||
mob.air = initial;
|
||||
let mut random = LegacyRandom::new(0);
|
||||
let mut events = Vec::new();
|
||||
for (index, expected) in expected.into_iter().enumerate() {
|
||||
assert!(tick(&mut mob, w, &mut random, &mut events));
|
||||
assert_eq!(mob.age, (index + 1) as u32);
|
||||
assert_eq!(mob.fluids.eye_in_water, water);
|
||||
assert_eq!(mob.health, 10.0);
|
||||
assert_eq!(mob.no_ai, no_ai);
|
||||
assert_eq!(
|
||||
mob.air,
|
||||
expected,
|
||||
"water={water}, NoAI={no_ai}, initial={initial}, tick={}",
|
||||
index + 1
|
||||
);
|
||||
}
|
||||
});
|
||||
if !ran {
|
||||
eprintln!("Prepared mob data unavailable; Nautilus full-tick coverage did not run");
|
||||
}
|
||||
}
|
||||
|
||||
/// `Nautilus.baseTick`: NoAI skips only handleAirSupply; super.baseTick
|
||||
/// still refills a breathing mob by four, capped at300.
|
||||
#[test]
|
||||
fn noai_nautilus_keeps_superclass_refill_in_both_media() {
|
||||
for water in [false, true] {
|
||||
check(water, true, 300, [300, 300]);
|
||||
check(water, true, 100, [104, 108]);
|
||||
}
|
||||
}
|
||||
|
||||
/// With AI, handleAirSupply still uses the pre-super air on land and
|
||||
/// writes300 in water. The NoAI exception must not alter that policy.
|
||||
#[test]
|
||||
fn normal_nautilus_keeps_its_custom_handler() {
|
||||
check(false, false, 300, [299, 298]);
|
||||
check(false, false, 100, [99, 98]);
|
||||
check(true, false, 300, [300, 300]);
|
||||
check(true, false, 100, [300, 300]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
# NoAI Nautilus superclass air
|
||||
|
||||
Pinned 26.3 `Nautilus.baseTick` records the old air, calls the superclass, and
|
||||
invokes its custom `handleAirSupply` only with AI enabled on the server. The
|
||||
custom handler uses that pre-super air on land, and writes 300 in water. With
|
||||
NoAI the inherited breathing still refills by four, capped at 300; air must not
|
||||
be frozen or forced to the maximum. Bytecode and the port ledger were inspected
|
||||
independently.
|
||||
|
||||
The fix excludes only `Species::Nautilus` under NoAI from the existing
|
||||
`needs_water` branch. It reaches the unchanged generic Breath/drown body,
|
||||
including the current native hooks. Other species and the normal custom-handler
|
||||
body stay unchanged. The existing normal-handler drown/dry_out damage-kind gap
|
||||
is retained in the ledger; this is not a whole Nautilus handler port.
|
||||
|
||||
## Frozen actual Game/Java proof
|
||||
|
||||
`tools/test_noai_nautilus_air_parity.py` uses the existing command harness,
|
||||
actual Game and fresh pinned Java. Both binaries are built on frozen source
|
||||
`87c51ab9c9368700223726f03f3d5689f145bb10` with identical declared scripts and
|
||||
fresh reference bytes. No pending H072/H224 production is imported.
|
||||
|
||||
Eight actual UUID-bound, Health 10, persistent Nautilus cover NoAI 0/1 × land/water
|
||||
× loaded Short 300/100. NoGravity and a real zero movement-speed attribute keep
|
||||
actors stationary without disabling normal AI. The actual owner, typed actors,
|
||||
Health/NoAI/Pos, loaded floor and medium, fresh result/success sentinels and
|
||||
exact two world ticks are guarded. The prepared official type data gives eye
|
||||
height 0.2751 and height 0.95: both body and eye at Y=201 lie inside the queried
|
||||
201 cell, with an additional 202 source-cell control. The full unit verifies
|
||||
actual eye-fluid state from its real world.
|
||||
|
||||
Fresh Java independently validates the following Air values at cumulative 0/1/2:
|
||||
|
||||
| AI | Medium | Initial 300 | Initial 100 |
|
||||
|---|---|---|---|
|
||||
| disabled | land | 300/300/300 | 100/104/108 |
|
||||
| disabled | water | 300/300/300 | 100/104/108 |
|
||||
| enabled | land | 300/299/298 | 100/99/98 |
|
||||
| enabled | water | 300/300/300 | 100/300/300 |
|
||||
|
||||
The predeclared 278-record canonical contract retains complete raw air feedback,
|
||||
styles, callback/store values, Short-typed predicates, all actor/mode/media/load
|
||||
and relative-clock controls. All 24 complete actor bodies and two absolute startup
|
||||
clock replies remain executable trace diagnostics in the 304-record full program.
|
||||
These categories were declared before the first captures. No tolerance, record
|
||||
mutation or comparison mask is used.
|
||||
|
||||
Program SHA256:
|
||||
|
||||
- canonical: `778193efd641e930748fe2a9411f41f9066fd6e1df1ed60a8a9af651f418fc42`
|
||||
- full: `3d19326d3734898a3ce75742021f49c2f947b9f8ac70724ed80bb706e0303573`
|
||||
|
||||
All scripts, references, raw replies and bodies, worlds, bytecode, binary hashes,
|
||||
source checkpoints and manifests are retained locally in `.local/h071`. Unknown
|
||||
phase times stay null. No game files or coordinator payloads are committed.
|
||||
|
||||
## Reachable full-tick regression
|
||||
|
||||
`cargo test -p horizon-client-lib --lib nautilus_noai_air_tests` calls the real
|
||||
full `mobs::ai::tick` in the existing prepared-resource world factory, with real
|
||||
water or air. It guards the actual Nautilus flags, tick age, eye immersion,
|
||||
Health and NoAI, and checks the independently measured air values. Old production
|
||||
has one passing normal-handler test and one failing NoAI test (land 300→299,
|
||||
expected 300). This is not a copied timer model or a direct reset-helper call.
|
||||
Prepared data is required; its absence is reported, not counted as runtime
|
||||
coverage. The own old failure establishes that this local fixture actually ran.
|
||||
|
||||
The normal custom-handler body, caps and damage cadence are unchanged. No
|
||||
Zombie Nautilus, other aquatic species, damage-policy, effect, lifetime, packet,
|
||||
rendering or general AI closure is claimed.
|
||||
|
||||
```sh
|
||||
python3 tools/test_noai_nautilus_air_parity.py --binary target/fast/horizon-client --work-dir .local/noai-nautilus-air
|
||||
python3 tools/test_noai_nautilus_air_parity.py --binary target/fast/horizon-client --work-dir .local/noai-nautilus-air-full --full-diagnostic
|
||||
```
|
||||
|
||||
## Paired results and full residual table
|
||||
|
||||
| View | Unchanged | Fixed |
|
||||
|---|---|---|
|
||||
| Canonical | 260/278 | 278/278 |
|
||||
| Full diagnostic | 260/304 | 278/304 |
|
||||
| Actual full-tick tests | 1/2 | 2/2 |
|
||||
|
||||
No 304/304 claim. Every fixed full-program residual is listed below. CD denotes
|
||||
`Brain.memories."minecraft:attack_target_cooldown".value` (Int), not air.
|
||||
|
||||
| Label | Expected Java | Actual Game |
|
||||
|---|---|---|
|
||||
| clock-start | `[[true, 301]]` | `[[true, 0]]` |
|
||||
| air_full-0-body | `CD absent` | `CD 0` |
|
||||
| air_low-0-body | `CD absent` | `CD 0` |
|
||||
| water_full-0-body | `CD absent` | `CD 0` |
|
||||
| water_low-0-body | `CD absent` | `CD 0` |
|
||||
| normal_air_full-0-body | `CD absent` | `CD 0` |
|
||||
| normal_air_low-0-body | `CD absent` | `CD 0` |
|
||||
| normal_water_full-0-body | `CD absent` | `CD 0` |
|
||||
| normal_water_low-0-body | `CD absent` | `CD 0` |
|
||||
| air_full-1-body | `CD absent` | `CD 0` |
|
||||
| air_low-1-body | `CD absent` | `CD 0` |
|
||||
| water_full-1-body | `CD absent` | `CD 0` |
|
||||
| water_low-1-body | `CD absent` | `CD 0` |
|
||||
| normal_air_full-1-body | `CD absent` | `CD 0` |
|
||||
| normal_air_low-1-body | `CD absent` | `CD 0` |
|
||||
| normal_water_full-1-body | `CD 2816; Rotation: [0.0f, 0.0f]` | `CD 2466; Rotation: [350.0f, 0.0f]` |
|
||||
| normal_water_low-1-body | `CD 2754; Rotation: [0.0f, 0.0f]` | `CD 3114; Rotation: [350.0f, 0.0f]` |
|
||||
| air_full-2-body | `CD absent` | `CD 0` |
|
||||
| air_low-2-body | `CD absent` | `CD 0` |
|
||||
| water_full-2-body | `CD absent` | `CD 0` |
|
||||
| water_low-2-body | `CD absent` | `CD 0` |
|
||||
| normal_air_full-2-body | `CD absent` | `CD 0` |
|
||||
| normal_air_low-2-body | `CD absent` | `CD 0` |
|
||||
| normal_water_full-2-body | `CD 2815; Rotation: [0.0f, 0.0f]` | `CD 2465; Rotation: [340.0f, 0.12813261f]` |
|
||||
| normal_water_low-2-body | `CD 2753; Rotation: [0.0f, 0.0f]` | `CD 3113; Rotation: [340.0f, 0.12813261f]` |
|
||||
| clock-end | `[[true, 303]]` | `[[true, 2]]` |
|
||||
|
||||
All body callbacks remain `[true,1]`. Complete raw strings/styles and Brain
|
||||
values are retained without modification. These pre-existing Brain projection
|
||||
and normal-water pose/cooldown observations are outside H071, without a claim
|
||||
about their full cause or random equality. Both relative clock deltas are
|
||||
exactly two; raw absolute values remain intact. No Brain, pose or clock repair
|
||||
is included.
|
||||
|
||||
## Required checks and scope limits
|
||||
|
||||
`tools/pr_ready.py --quick --base 87c51ab9c9368700223726f03f3d5689f145bb10`
|
||||
ran once on the final Rust/harness patch:1980 Rust passes,65 ignored and one
|
||||
pre-existing `entities::drop_motion_tests::drops_match_vanillas_motion_bit_for_bit`
|
||||
failure. At yaw37.5/pitch-21.25, Z bits are4597448471913462162 versus expected
|
||||
4597448471913462163. Our own untouched a171 executable already reproduces that
|
||||
exact failure. The drop-motion function/test and jmath source are unchanged;
|
||||
the later entities.rs delta is unrelated ArmorStand first-tick state. The prior
|
||||
log/provenance is retained without claiming a new H071 baseline execution.
|
||||
|
||||
Python reports698 tests, four known installer/shell failures and one skip:
|
||||
the installer signature fixture lacks `horizon-macos-arm64.zip`, and three
|
||||
optional-archive cases encounter Bash3.2 empty-array unbound variables. No
|
||||
installer or drop-motion repair is included; the full self-check is not green.
|
||||
|
||||
Formatting, Clippy with warnings denied, doctests and public-tree checks pass;
|
||||
Cargo.lock is unchanged. The ledger check reports the existing callee advisories
|
||||
and a long-uncited test-fixture helper, with no new gaps. The normal Nautilus
|
||||
drown/dry_out gap remains explicitly open. Assigned Game parity ran separately
|
||||
from quick mode's broad-harness skip. Only evidence notes were added afterward;
|
||||
Rust and harness files are unchanged.
|
||||
|
||||
The later98af9399c source checkpoint has no air-source delta; an isolated
|
||||
armor-stand harness filter does not change this fixture's selected group.
|
||||
The actual Game pair remains frozen to87c51ab9c, without a latest-base replay
|
||||
claim. Resource plans retained a5GiB hard guard and combined-link headroom,
|
||||
jobs2/incremental0 and one heavy build. Only verified inactive OWN artifacts
|
||||
were archived, preserving original paths and per-file hashes. Unknown phase
|
||||
times stay null. H072 and H224 remain independent, with no pending production
|
||||
imported and no combined-runtime claim.
|
||||
@@ -26,7 +26,7 @@ Nautilus.getAmbientSound port crates/horizon-client/src/mobs/nautilus.rs::sounds
|
||||
Nautilus.getHurtSound port crates/horizon-client/src/mobs/nautilus.rs::sounds by age and by under water or on land
|
||||
Nautilus.getDeathSound port crates/horizon-client/src/mobs/nautilus.rs::sounds by age and by under water or on land
|
||||
Nautilus.playEatingSound port crates/horizon-client/src/mobs/nautilus.rs::eat_sound baby and adult eat sounds
|
||||
Nautilus.baseTick inline crates/horizon-client/src/mobs/ai.rs::base_tick gap: minor: dries out on land through the generic needs_water air supply, so the damage is the drown kind instead of dry_out and a no-AI nautilus dries out too
|
||||
Nautilus.baseTick inline crates/horizon-client/src/mobs/ai.rs::base_tick NoAI skips custom supply and uses superclass Breath/drown; gap: minor: the normal handler still uses generic needs_water air so damage is drown instead of dry_out
|
||||
NautilusAi.initCoreActivity inline crates/horizon-client/src/mobs/nautilus.rs::register panic 1.6 is a goal; the look and move sinks are the generic controls and the cooldown counters tick in ai_step
|
||||
NautilusAi.initIdleActivity inline crates/horizon-client/src/mobs/nautilus.rs::register gap: minor: breed 0.4, tempt 1.3, swim stroll 1.0 and the target pick (find_target), but SetWalkTargetFromLookTarget is not ported so it does not swim toward what it looks at
|
||||
NautilusAi.initFightActivity inline crates/horizon-client/src/mobs/nautilus.rs::register the Charge goal: speed 0.6, 12 block range, 80 tick cooldown, only without love or temptation
|
||||
|
||||
|
@@ -0,0 +1,148 @@
|
||||
#!/usr/bin/env python3
|
||||
"""NoAI Nautilus keeps superclass air, skipping only its custom handler.
|
||||
|
||||
Complete scalar/action records stay strict. Full bodies and absolute clocks are
|
||||
predeclared executable diagnostics; the actual two-tick delta remains strict.
|
||||
"""
|
||||
import hashlib
|
||||
import json
|
||||
from pathlib import Path
|
||||
import sys
|
||||
import test_command_exec_parity as driver
|
||||
|
||||
|
||||
def subjects():
|
||||
return [
|
||||
(1, 'air_full', False, True, 300, [2.5, 201.0, 2.5]),
|
||||
(2, 'air_low', False, True, 100, [6.5, 201.0, 2.5]),
|
||||
(3, 'water_full', True, True, 300, [10.5, 201.0, 10.5]),
|
||||
(4, 'water_low', True, True, 100, [13.5, 201.0, 10.5]),
|
||||
(5, 'normal_air_full', False, False, 300, [2.5, 201.0, 6.5]),
|
||||
(6, 'normal_air_low', False, False, 100, [6.5, 201.0, 6.5]),
|
||||
(7, 'normal_water_full', True, False, 300, [10.5, 201.0, 13.5]),
|
||||
(8, 'normal_water_low', True, False, 100, [13.5, 201.0, 13.5]),
|
||||
]
|
||||
|
||||
|
||||
def expected_air(water, no_ai, initial, elapsed):
|
||||
if elapsed == 0:
|
||||
return initial
|
||||
if no_ai:
|
||||
return min(300, initial + 4 * elapsed)
|
||||
return 300 if water else initial - elapsed
|
||||
|
||||
|
||||
def program(full=False):
|
||||
ops = []
|
||||
|
||||
def cmd(text, label, expected=None, admission=True, diagnostic=False):
|
||||
op = dict(op='cmd', cmd=text, label=label, admission=admission)
|
||||
if expected is not None:
|
||||
op['expect_result'] = expected
|
||||
if diagnostic and not full:
|
||||
op.update(record=False, trace=True)
|
||||
ops.append(op)
|
||||
|
||||
def tick(n, label):
|
||||
cmd(f'/tick step {n}', label + '-request')
|
||||
ops.append(dict(op='tick', n=n))
|
||||
|
||||
cmd('/tick freeze', 'freeze')
|
||||
for key in ['spawn_mobs', 'advance_time', 'mob_griefing']:
|
||||
cmd('/gamerule ' + key + ' false', key)
|
||||
cmd('/gamerule random_tick_speed 0', 'random-ticks')
|
||||
cmd('/forceload add 0 0 15 15', 'force', 1)
|
||||
ops.append(dict(op='settle', required_chunks=[[0, 0]]))
|
||||
cmd('/fill 0 199 0 15 199 15 stone', 'floor', 256)
|
||||
cmd('/fill 0 200 0 15 205 15 air', 'clear')
|
||||
cmd('/fill 8 200 8 15 204 15 glass', 'pool-shell', 320)
|
||||
cmd('/fill 9 200 9 14 204 14 water', 'pool-water', 180)
|
||||
cmd('/tp @s 1.5 200 1.5 0 0', 'owner-position', 1)
|
||||
cmd('/gamemode creative @s', 'owner-mode')
|
||||
cmd('/execute if entity @s[type=player,name=Player]', 'owner-type', 1)
|
||||
for key, value in [('UUID', 4), ('Health', 20), ('playerGameType', 1), ('Pos', 3)]:
|
||||
cmd('/data get entity @s ' + key, 'owner-' + key, value)
|
||||
cmd('/scoreboard objectives add h071 dummy', 'objective')
|
||||
cmd('/execute store result score start h071 run time query gametime', 'clock-start', diagnostic=True)
|
||||
for i, label, water, no_ai, initial, pos in subjects():
|
||||
xyz = ' '.join(map(str, pos))
|
||||
body = '{UUID:[I;71,0,0,%d],Tags:["h071_%s"],Health:10f,NoAI:%db,NoGravity:1b,PersistenceRequired:1b,Air:%ds,attributes:[{id:"minecraft:movement_speed",base:0.0d}]}' % (i, label, no_ai, initial)
|
||||
cmd(f'/summon nautilus {xyz} {body}', label + '-summon')
|
||||
cmd(f'/execute if loaded {int(pos[0])} 201 {int(pos[2])}', label + '-loaded', 1)
|
||||
cmd(f'/execute if block {int(pos[0])} 199 {int(pos[2])} stone', label + '-floor', 1)
|
||||
for y in [201, 202]:
|
||||
block = 'water[level=0]' if water else 'air'
|
||||
cmd(f'/execute if block {int(pos[0])} {y} {int(pos[2])} {block}', f'{label}-medium-{y}', 1)
|
||||
for elapsed in [0, 1, 2]:
|
||||
if elapsed:
|
||||
tick(1, f'tick{elapsed}')
|
||||
for i, label, water, no_ai, initial, pos in subjects():
|
||||
uid = f'00000047-0000-0000-0000-{i:012x}'
|
||||
phase = f'{label}-{elapsed}'
|
||||
body = '{UUID:[I;71,0,0,%d],Tags:["h071_%s"],Health:10f,NoGravity:1b,PersistenceRequired:1b}' % (i, label)
|
||||
cmd(f'/execute if entity @e[type=nautilus,nbt={body}]', phase + '-identity', 1)
|
||||
cmd(f'/execute {"if" if no_ai else "unless"} entity @e[type=nautilus,nbt={{UUID:[I;71,0,0,{i}],NoAI:1b}}]', phase + '-ai', 1)
|
||||
cmd(f'/data get entity {uid} Pos', phase + '-position')
|
||||
for field in ['result', 'success']:
|
||||
cmd(f'/scoreboard players set {field} h071 -99', phase + '-reset-' + field, -99)
|
||||
value = expected_air(water, no_ai, initial, elapsed)
|
||||
cmd(f'/execute store result score result h071 store success score success h071 run data get entity {uid} Air', phase + '-air-read', admission=False)
|
||||
cmd('/scoreboard players get result h071', phase + '-air-result', admission=False)
|
||||
cmd('/scoreboard players get success h071', phase + '-air-success', 1)
|
||||
cmd(f'/execute if entity @e[type=nautilus,nbt={{UUID:[I;71,0,0,{i}],Air:{value}s}}]', phase + '-air-typed', admission=False)
|
||||
cmd(f'/data get entity {uid}', phase + '-body', diagnostic=True)
|
||||
cmd('/execute store result score end h071 run time query gametime', 'clock-end', diagnostic=True)
|
||||
cmd('/scoreboard players operation end h071 -= start h071', 'clock-delta-operation', 2)
|
||||
cmd('/scoreboard players get end h071', 'clock-delta', 2)
|
||||
return ops
|
||||
|
||||
|
||||
def main():
|
||||
full = '--full-diagnostic' in sys.argv
|
||||
if full:
|
||||
sys.argv.remove('--full-diagnostic')
|
||||
reference = None
|
||||
if '--reference' in sys.argv:
|
||||
i = sys.argv.index('--reference')
|
||||
reference = Path(sys.argv[i + 1]).resolve().read_bytes()
|
||||
del sys.argv[i:i + 2]
|
||||
if '--binary' not in sys.argv:
|
||||
raise SystemExit('--binary is required (also for a reference-only run)')
|
||||
build = Path(sys.argv[sys.argv.index('--work-dir') + 1]).resolve()
|
||||
ops = program(full)
|
||||
driver.corpus_module.groups = lambda: [('NoAI nautilus air', ops)]
|
||||
sys.argv.append('--allow-gaps')
|
||||
driver.main()
|
||||
recorded = [o for o in ops if o['op'] == 'cmd' and o.get('record', True)]
|
||||
java_bytes = (build / 'vanilla.jsonl').read_bytes()
|
||||
java = [json.loads(s) for s in java_bytes.splitlines()]
|
||||
rows = {o['label']: r for o, r in zip(recorded, java)}
|
||||
assert len(recorded) == len(java)
|
||||
for elapsed in [0, 1, 2]:
|
||||
for i, label, water, no_ai, initial, pos in subjects():
|
||||
value = expected_air(water, no_ai, initial, elapsed)
|
||||
assert rows[f'{label}-{elapsed}-air-read']['results'] == [[True, value]]
|
||||
assert rows[f'{label}-{elapsed}-air-typed']['results'] == [[True, 1]]
|
||||
if '--reference-only' in sys.argv:
|
||||
return
|
||||
if reference and not full:
|
||||
assert reference == java_bytes, 'fresh reference changed'
|
||||
comparison = reference or java_bytes
|
||||
(build / 'comparison-reference.jsonl').write_bytes(comparison)
|
||||
java = [json.loads(s) for s in comparison.splitlines()]
|
||||
native = [json.loads(s) for s in (build / 'rust.jsonl').read_bytes().splitlines()]
|
||||
assert len(recorded) == len(java) == len(native)
|
||||
differences = [dict(label=o['label'], expected=a, actual=b) for o, a, b in zip(recorded, java, native) if a != b]
|
||||
report = dict(records=len(native), passed=len(native)-len(differences), differences=differences,
|
||||
reference_sha256=hashlib.sha256(comparison).hexdigest(), comparison='complete records; no masks or tolerances')
|
||||
(build / 'strict-report.json').write_text(json.dumps(report, indent=2)+'\n')
|
||||
for o, a, b in zip(recorded, java, native):
|
||||
if o['admission'] and not o['label'].endswith('-body') and o['label'] not in ['clock-start', 'clock-end']:
|
||||
assert a == b, ('admission', o, a, b)
|
||||
print(f'Strict raw records: {report["passed"]}/{report["records"]}')
|
||||
if differences:
|
||||
raise SystemExit(1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in new issue
Block a user