diff --git a/crates/wasm-actor/tests/wasm_actor.rs b/crates/wasm-actor/tests/wasm_actor.rs index d20957e..60671e8 100644 --- a/crates/wasm-actor/tests/wasm_actor.rs +++ b/crates/wasm-actor/tests/wasm_actor.rs @@ -4109,3 +4109,107 @@ fn wasm_actor_watching_another_wasm_actor_doesnt_crash() { assert!(rt.send_to(addr_a, ByteMessage(vec![1])).is_err()); assert!(rt.send_to(addr_b, ByteMessage(vec![1])).is_err()); } + +// ── Guest reads len parameter correctly ───────────────────────────────────── + +#[test] +fn guest_receives_correct_len_parameter() { + // Guest stores the len parameter as a 4-byte LE integer at offset 200 + // and sends it back. Verifies the host passes the correct length. + let wat = r#" + (module + (import "swactor" "send" (func $send (param i32 i32 i32))) + (memory (export "memory") 1) + (func (export "alloc") (param i32) (result i32) i32.const 4096) + (func (export "handle") (param $ptr i32) (param $len i32) + ;; Store len at offset 200 as i32 + (i32.store (i32.const 200) (local.get $len)) + ;; Send 4 bytes from offset 200 + local.get $ptr + i32.const 200 + i32.const 4 + call $send + ) + ) + "#; + let wasm = wat::parse_str(wat).unwrap(); + let engine = SharedEngine::new().unwrap(); + let actor = WasmActorBuilder::new(engine, wasm).build().unwrap(); + + let rt = Runtime::new(RuntimeConfig::default()); + let inbox = rt.new_inbox::().unwrap(); + let addr = rt.spawn(actor).unwrap(); + + // Send a message with 32-byte addr + 10 bytes payload = 42 bytes total + let payload = vec![0u8; 10]; + rt.send_to(addr, framed_msg(inbox.addr(), &payload)).unwrap(); + rt.tick(); + + let received = inbox.try_recv().expect("should receive len value"); + let len = i32::from_le_bytes(received.0.try_into().unwrap()); + assert_eq!(len, 42, "guest should receive total message len (32 addr + 10 payload)"); +} + +// ── Guest reads ptr parameter correctly ───────────────────────────────────── + +#[test] +fn guest_receives_correct_ptr_parameter() { + // Guest stores ptr at offset 200 and sends it back. The ptr should be + // the address returned by alloc (4096 in this case). + let wat = r#" + (module + (import "swactor" "send" (func $send (param i32 i32 i32))) + (memory (export "memory") 1) + (func (export "alloc") (param i32) (result i32) i32.const 4096) + (func (export "handle") (param $ptr i32) (param $len i32) + (i32.store (i32.const 200) (local.get $ptr)) + local.get $ptr + i32.const 200 + i32.const 4 + call $send + ) + ) + "#; + let wasm = wat::parse_str(wat).unwrap(); + let engine = SharedEngine::new().unwrap(); + let actor = WasmActorBuilder::new(engine, wasm).build().unwrap(); + + let rt = Runtime::new(RuntimeConfig::default()); + let inbox = rt.new_inbox::().unwrap(); + let addr = rt.spawn(actor).unwrap(); + + rt.send_to(addr, framed_msg(inbox.addr(), b"ptr-check")).unwrap(); + rt.tick(); + + let received = inbox.try_recv().expect("should receive ptr value"); + let ptr = i32::from_le_bytes(received.0.try_into().unwrap()); + assert_eq!(ptr, 4096, "guest should receive ptr = alloc return value"); +} + +// ── Double guest with empty payload: sends two zero-length messages ───────── + +#[test] +fn double_guest_with_minimal_payload() { + // Double guest with exactly 32 bytes (addr only, no payload). + // Since double checks `len < 32`, a 32-byte message passes the check. + // payload_len = 32 - 32 = 0, so it sends two zero-length messages. + let engine = SharedEngine::new().unwrap(); + let actor = WasmActorBuilder::new(engine, guest_wasm("double")) + .build() + .unwrap(); + + let rt = Runtime::new(RuntimeConfig::default()); + let inbox = rt.new_inbox::().unwrap(); + let addr = rt.spawn(actor).unwrap(); + + // Send exactly 32 bytes (just the address, no payload) + let msg = ByteMessage(inbox.addr().0.to_vec()); + rt.send_to(addr, msg).unwrap(); + rt.tick(); + + let first = inbox.try_recv().expect("double should send first empty message"); + let second = inbox.try_recv().expect("double should send second empty message"); + assert!(first.0.is_empty(), "payload should be empty"); + assert!(second.0.is_empty(), "payload should be empty"); + assert!(inbox.try_recv().is_none(), "exactly two messages"); +}