test(wasm-actor): cycle 59 — local.tee, 16KB payload, dual runtime, i64 wrap (255 tests)

Added 5 tests: local.tee instruction, 16KB payload round-trip, two independent
runtimes with WASM actors, i64-to-i32 wrap instruction, random WAT variations
property test. No new bugs found.

Authored by Claude, lovingly guided by Zachery Aaron Shores-Chmielewski
This commit is contained in:
Claude 2026-02-13 10:13:06 +00:00
parent 384a6a56cb
commit b13a846b1f

View file

@ -8678,4 +8678,139 @@ fn builder_accepts_slice_reference() {
let addr = rt.spawn(actor).unwrap(); let addr = rt.spawn(actor).unwrap();
rt.send_to(addr, ByteMessage(vec![])).unwrap(); rt.send_to(addr, ByteMessage(vec![])).unwrap();
rt.tick(); rt.tick();
}
// ── Cycle 59 ─────────────────────────────────────────────────────────────────
// Guest that uses local.tee instruction (sets local and leaves value on stack)
#[test]
fn guest_uses_local_tee() {
let wat = r#"(module
(memory (export "memory") 1)
(global $heap (mut i32) (i32.const 65536))
(func (export "alloc") (param $len i32) (result i32)
global.get $heap
global.get $heap
local.get $len
i32.add
global.set $heap)
(func (export "handle") (param $ptr i32) (param $len i32)
;; Use local.tee: ptr2 = alloc_start, also keep on stack
(local $ptr2 i32)
global.get $heap
local.tee $ptr2
drop ;; just exercising the instruction
)
)"#;
let engine = SharedEngine::new().unwrap();
let actor = WasmActorBuilder::new(engine, wat::parse_str(wat).unwrap())
.build().unwrap();
let rt = Runtime::new(RuntimeConfig::default());
let addr = rt.spawn(actor).unwrap();
rt.send_to(addr, ByteMessage(b"tee".to_vec())).unwrap();
rt.tick(); // no trap
}
// Guest that writes a 16KB response — tests larger-than-page payloads round-trip
#[test]
fn sixteen_kb_payload_round_trip() {
let engine = SharedEngine::new().unwrap();
let actor = WasmActorBuilder::new(engine, guest_wasm("echo")).build().unwrap();
let rt = Runtime::new(RuntimeConfig::default());
let inbox = rt.new_inbox::<ByteMessage>().unwrap();
let addr = rt.spawn(actor).unwrap();
let payload: Vec<u8> = (0..16384u32).map(|i| (i % 251) as u8).collect();
rt.send_to(addr, framed_msg(inbox.addr(), &payload)).unwrap();
rt.tick();
let resp = inbox.try_recv().expect("should receive 16KB echo");
assert_eq!(resp.0, payload);
}
// Two runtimes with WASM actors operating independently at the same time
#[test]
fn two_independent_runtimes_with_wasm_actors() {
let engine = SharedEngine::new().unwrap();
let actor1 = WasmActorBuilder::new(engine.clone(), guest_wasm("echo")).build().unwrap();
let actor2 = WasmActorBuilder::new(engine, guest_wasm("double")).build().unwrap();
let rt1 = Runtime::new(RuntimeConfig::default());
let rt2 = Runtime::new(RuntimeConfig::default());
let inbox1 = rt1.new_inbox::<ByteMessage>().unwrap();
let inbox2 = rt2.new_inbox::<ByteMessage>().unwrap();
let addr1 = rt1.spawn(actor1).unwrap();
let addr2 = rt2.spawn(actor2).unwrap();
rt1.send_to(addr1, framed_msg(inbox1.addr(), b"A")).unwrap();
rt2.send_to(addr2, framed_msg(inbox2.addr(), b"B")).unwrap();
rt1.tick();
rt2.tick();
let msgs1: Vec<_> = std::iter::from_fn(|| inbox1.try_recv().map(|m| m.0)).collect();
let msgs2: Vec<_> = std::iter::from_fn(|| inbox2.try_recv().map(|m| m.0)).collect();
assert_eq!(msgs1.len(), 1, "echo from rt1");
assert_eq!(msgs2.len(), 2, "double from rt2");
assert_eq!(msgs1[0], b"A");
assert!(msgs2.iter().all(|m| m == b"B"));
}
// Guest that uses i32.wrap_i64 instruction
#[test]
fn guest_uses_i64_to_i32_wrap() {
let wat = r#"(module
(memory (export "memory") 1)
(global $heap (mut i32) (i32.const 65536))
(func (export "alloc") (param $len i32) (result i32)
global.get $heap
global.get $heap
local.get $len
i32.add
global.set $heap)
(func (export "handle") (param $ptr i32) (param $len i32)
;; Wrap i64 to i32: 0x1_0000_00FF -> 0xFF
i64.const 4294967551 ;; 0x1_000000FF
i32.wrap_i64
;; result is 255, store at ptr
local.get $ptr
i32.store8 offset=0
)
)"#;
let engine = SharedEngine::new().unwrap();
let actor = WasmActorBuilder::new(engine, wat::parse_str(wat).unwrap())
.build().unwrap();
let rt = Runtime::new(RuntimeConfig::default());
let addr = rt.spawn(actor).unwrap();
rt.send_to(addr, ByteMessage(b"W".to_vec())).unwrap();
rt.tick(); // no trap, wrapping is well-defined
}
// Property test: building from random subsets of valid WAT always succeeds or fails cleanly
proptest! {
#[test]
fn prop_random_valid_wat_variations_never_panic(
alloc_offset in 1024u32..60000,
pages in 1u32..5,
handle_body in proptest::bool::ANY,
) {
let store_body = if handle_body {
"local.get $ptr\nlocal.get $ptr\ni32.load8_u\ni32.store8"
} else {
""
};
let wat = format!(r#"(module
(memory (export "memory") {pages})
(func (export "alloc") (param $len i32) (result i32)
i32.const {alloc_offset})
(func (export "handle") (param $ptr i32) (param $len i32)
{store_body})
)"#);
let engine = SharedEngine::new().unwrap();
let result = WasmActorBuilder::new(engine, wat::parse_str(&wat).unwrap()).build();
assert!(result.is_ok(), "valid WAT should build");
}
} }