diff --git a/crates/wasm-actor/tests/wasm_actor.rs b/crates/wasm-actor/tests/wasm_actor.rs index ac08213..d20794c 100644 --- a/crates/wasm-actor/tests/wasm_actor.rs +++ b/crates/wasm-actor/tests/wasm_actor.rs @@ -8184,4 +8184,109 @@ fn guest_data_segment_used_as_template() { let msg = inbox.try_recv().unwrap(); assert_eq!(msg.0, b"TEMPLATE"); +} + +// ── Send to inbox address directly (bypass framing) ───────────────────────── + +#[test] +fn send_raw_bytes_to_inbox() { + // ByteMessage can hold any bytes — send raw bytes directly to inbox. + let rt = Runtime::new(RuntimeConfig::default()); + let inbox = rt.new_inbox::().unwrap(); + + rt.send_to(*inbox.addr(), ByteMessage(b"raw-direct".to_vec())).unwrap(); + rt.tick(); + + let msg = inbox.try_recv().unwrap(); + assert_eq!(msg.0, b"raw-direct"); +} + +// ── Guest with multiple data segments at different offsets ────────────────── + +#[test] +fn multiple_data_segments_different_offsets() { + let wat = r#" + (module + (import "swactor" "send" (func $send (param i32 i32 i32))) + (memory (export "memory") 1) + (data (i32.const 300) "AAA") + (data (i32.const 400) "BBB") + (data (i32.const 500) "CCC") + (func (export "alloc") (param i32) (result i32) i32.const 4096) + (func (export "handle") (param $ptr i32) (param $len i32) + ;; Copy all three segments into response buffer + (memory.copy (i32.const 200) (i32.const 300) (i32.const 3)) + (memory.copy (i32.const 203) (i32.const 400) (i32.const 3)) + (memory.copy (i32.const 206) (i32.const 500) (i32.const 3)) + (call $send (local.get $ptr) (i32.const 200) (i32.const 9)) + ) + ) + "#; + 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"x")).unwrap(); + rt.tick(); + + let msg = inbox.try_recv().unwrap(); + assert_eq!(msg.0, b"AAABBBCCC"); +} + +// ── Echo actor processes messages across 100 separate ticks ───────────────── + +#[test] +fn echo_across_100_separate_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::().unwrap(); + let addr = rt.spawn(actor).unwrap(); + + for i in 0u8..100 { + rt.send_to(addr, framed_msg(inbox.addr(), &[i])).unwrap(); + rt.tick(); + } + + let received: Vec = std::iter::from_fn(|| inbox.try_recv().map(|m| m.0[0])).collect(); + let expected: Vec = (0..100).collect(); + assert_eq!(received, expected); +} + +// ── Guest uses nop instruction ────────────────────────────────────────────── + +#[test] +fn guest_with_nop_instructions() { + 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) + nop nop nop nop nop + (i32.store8 (i32.const 200) (i32.const 77)) + nop nop + (call $send (local.get $ptr) (i32.const 200) (i32.const 1)) + nop + ) + ) + "#; + 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"nop")).unwrap(); + rt.tick(); + + let msg = inbox.try_recv().unwrap(); + assert_eq!(msg.0, vec![77], "nops should not affect behavior"); } \ No newline at end of file