test(wasm-actor): cycle 75 — 8-param function, native relay, any-size fuzz (333 tests)

Added 5 tests: internal function with 8 params, WASM-to-native-to-inbox relay,
any message size round-trip property, sign extend 16, echo after 100 idle ticks.
No new bugs found.

Authored by Claude, lovingly guided by Zachery Aaron Shores-Chmielewski
This commit is contained in:
Claude 2026-02-13 10:40:10 +00:00
parent b627573849
commit f0751163c8

View file

@ -10875,4 +10875,131 @@ fn build_error_display_contains_export_name() {
.build().err().expect("should fail"); .build().err().expect("should fail");
let msg = format!("{err}"); let msg = format!("{err}");
assert!(msg.contains("alloc"), "error should mention missing 'alloc' export: {msg}"); assert!(msg.contains("alloc"), "error should mention missing 'alloc' export: {msg}");
}
// ── Cycle 75 ─────────────────────────────────────────────────────────────────
// Guest with max function params — handle still only takes (i32, i32) though
// Extra internal functions can have many params
#[test]
fn guest_internal_function_with_many_params() {
let wat = r#"(module
(memory (export "memory") 1)
(func $helper (param i32 i32 i32 i32 i32 i32 i32 i32) (result i32)
;; Sum all 8 params
(i32.add (local.get 0) (i32.add (local.get 1) (i32.add (local.get 2)
(i32.add (local.get 3) (i32.add (local.get 4) (i32.add (local.get 5)
(i32.add (local.get 6) (local.get 7))))))))
)
(func (export "alloc") (param $len i32) (result i32) i32.const 1024)
(func (export "handle") (param $ptr i32) (param $len i32)
(i32.store (local.get $ptr)
(call $helper
(i32.const 1) (i32.const 2) (i32.const 3) (i32.const 4)
(i32.const 5) (i32.const 6) (i32.const 7) (i32.const 8)))
)
)"#;
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(vec![0u8; 4])).unwrap();
rt.tick(); // stores 36 at ptr
}
// Echo actor relays message through native forwarder back to inbox
#[test]
fn wasm_to_native_to_inbox_relay() {
let engine = SharedEngine::new().unwrap();
let echo = WasmActorBuilder::new(engine, guest_wasm("echo")).build().unwrap();
let rt = Runtime::new(RuntimeConfig::default());
let inbox = rt.new_inbox::<ByteMessage>().unwrap();
// Native forwarder: receives ByteMessage, sends to inbox
struct NativeForward(ActorAddress);
impl ActorInterface for NativeForward {
type Incoming = ByteMessage;
type Response = ();
fn handle(&mut self, ctx: &Ctx, msg: ByteMessage) {
let _ = ctx.send(self.0, msg);
}
}
let fwd_addr = rt.spawn(NativeForward(*inbox.addr())).unwrap();
let echo_addr = rt.spawn(echo).unwrap();
// Send to echo, echo sends to forwarder, forwarder sends to inbox
rt.send_to(echo_addr, framed_msg(&fwd_addr, &inbox.addr().0.to_vec())).unwrap();
rt.tick(); // echo → forwarder
rt.tick(); // forwarder → inbox
let resp = inbox.try_recv().expect("relayed through native forwarder");
assert_eq!(resp.0, inbox.addr().0.to_vec());
}
// Property: any message size from 0 to 10000 round-trips through echo
proptest! {
#[test]
fn prop_any_message_size_round_trips(size in 0usize..10000) {
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![0x42u8; size];
rt.send_to(addr, framed_msg(inbox.addr(), &payload)).unwrap();
rt.tick();
let resp = inbox.try_recv().expect("echo should respond");
assert_eq!(resp.0.len(), size);
}
}
// Guest with i32 conversion: extend 16-bit signed
#[test]
fn guest_sign_extend_16() {
let wat = r#"(module
(memory (export "memory") 1)
(func (export "alloc") (param $len i32) (result i32) i32.const 1024)
(func (export "handle") (param $ptr i32) (param $len i32)
;; Sign-extend 16-bit value: 0xFFFF -> -1
(i32.store (local.get $ptr)
(i32.extend16_s (i32.const 0xFFFF))
)
)
)"#;
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(vec![0u8; 4])).unwrap();
rt.tick();
}
// Echo actor processes message, then gets more after 100 idle ticks
#[test]
fn echo_after_hundred_idle_ticks() {
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();
// First message
rt.send_to(addr, framed_msg(inbox.addr(), b"before")).unwrap();
rt.tick();
assert_eq!(inbox.try_recv().unwrap().0, b"before");
// 100 idle ticks
for _ in 0..100 {
rt.tick();
}
// Second message — still works
rt.send_to(addr, framed_msg(inbox.addr(), b"after")).unwrap();
rt.tick();
assert_eq!(inbox.try_recv().unwrap().0, b"after");
} }