Hoshe critical fixes:
- _action_enum_to_wire uses InputMapper.Action constants instead of
fragile integer literals; OPEN_MENU explicitly handled as client-only
- Remove int() coercion on tick/entity_id — use direct assignment since
GDScript int is signed 64-bit (safe for realistic tick values)
- Check encode result before buffering in send_input() — reject empty
bytes instead of corrupting the outbound stream
- Test snapshot now uses Protocol format {tick, entities} instead of
legacy schema; GameState updated to derive player position from
entity data; main.gd and world_renderer.gd updated accordingly
Hoshe warnings:
- 5 negative tests added (truncated bytes, wrong type, missing fields,
empty bytes, encode validation) — 20/20 tests pass
- receive_bytes signal is emitted at consume time in poll_snapshot by
design (documented in code)
Tyre suggestions:
- Remove duplicated root-level fixtures — single source of truth in
client/tests/fixtures/msgpack/
- gen_fixtures.rs writes directly to client/ directory
- Add `make fixtures` target for regeneration
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
65 lines
2.3 KiB
Rust
65 lines
2.3 KiB
Rust
//! Generate MessagePack fixture files for cross-language testing (D-030 Layer 1).
|
|
//! Run with: cargo test --test gen_fixtures -- --ignored
|
|
|
|
use settled_reach_server::bridge::types::*;
|
|
use std::fs;
|
|
use std::path::Path;
|
|
|
|
fn write_fixture(name: &str, bytes: &[u8]) {
|
|
// Write directly into the Godot project's test fixtures (single source of truth)
|
|
let dir = Path::new("../client/tests/fixtures/msgpack");
|
|
fs::create_dir_all(dir).expect("create fixture dir");
|
|
let path = dir.join(format!("{}.msgpack", name));
|
|
fs::write(&path, bytes).expect("write fixture");
|
|
eprintln!("Wrote {} ({} bytes)", path.display(), bytes.len());
|
|
}
|
|
|
|
#[test]
|
|
#[ignore] // Run manually: cargo test --test gen_fixtures -- --ignored
|
|
fn generate_msgpack_fixtures() {
|
|
// Snapshot with one NPC entity
|
|
let snapshot = ObserverSnapshot {
|
|
tick: 42,
|
|
entities: vec![VisibleEntity {
|
|
entity_id: 1,
|
|
x: 10.0,
|
|
y: 20.0,
|
|
z: 0,
|
|
kind: EntityKind::Npc,
|
|
}],
|
|
};
|
|
write_fixture("snapshot_one_npc", &rmp_serde::to_vec_named(&snapshot).unwrap());
|
|
|
|
// Empty snapshot
|
|
let empty = ObserverSnapshot {
|
|
tick: 0,
|
|
entities: vec![],
|
|
};
|
|
write_fixture("snapshot_empty", &rmp_serde::to_vec_named(&empty).unwrap());
|
|
|
|
// PlayerInput: MoveNorth
|
|
let input_north = PlayerInput {
|
|
tick: 100,
|
|
action: PlayerAction::MoveNorth,
|
|
};
|
|
write_fixture("input_move_north", &rmp_serde::to_vec_named(&input_north).unwrap());
|
|
|
|
// PlayerInput: UsePerceptionMode
|
|
let input_perception = PlayerInput {
|
|
tick: 200,
|
|
action: PlayerAction::UsePerceptionMode("thermal".to_string()),
|
|
};
|
|
write_fixture("input_perception_mode", &rmp_serde::to_vec_named(&input_perception).unwrap());
|
|
|
|
// Snapshot with multiple entities and all EntityKind variants
|
|
let snapshot_multi = ObserverSnapshot {
|
|
tick: 999,
|
|
entities: vec![
|
|
VisibleEntity { entity_id: 1, x: 5.0, y: 10.0, z: 0, kind: EntityKind::Npc },
|
|
VisibleEntity { entity_id: 2, x: 15.5, y: 3.0, z: 1, kind: EntityKind::Object },
|
|
VisibleEntity { entity_id: 3, x: 0.0, y: 0.0, z: -1, kind: EntityKind::Terrain },
|
|
],
|
|
};
|
|
write_fixture("snapshot_multi_entity", &rmp_serde::to_vec_named(&snapshot_multi).unwrap());
|
|
}
|