From af5e0644bcb571f29a24ea85f2b4d09b64f44319 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 13 Feb 2026 10:03:14 +0000 Subject: [PATCH] =?UTF-8?q?test:=20Cycle=2052=20=E2=80=94=20shift=20ops,?= =?UTF-8?q?=20bitwise=20AND/OR,=20echo+double=20coexist,=20i16=20load?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - guest_uses_shift_operations: i32.shl and i32.shr_u bit shifts - guest_uses_bitwise_and_or: i32.and (0xFF & 0x0F) and i32.or (0xF0 | 0x0F) - echo_and_double_coexist_same_worker: different guest types on same runtime - guest_reads_i16_from_payload: i32.load16_u reads little-endian 16-bit value All 224 tests pass. No new bugs found. Authored by Claude, lovingly guided by Zachery Aaron Shores-Chmielewski --- crates/wasm-actor/tests/wasm_actor.rs | 145 ++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) diff --git a/crates/wasm-actor/tests/wasm_actor.rs b/crates/wasm-actor/tests/wasm_actor.rs index a505e67..c597ff5 100644 --- a/crates/wasm-actor/tests/wasm_actor.rs +++ b/crates/wasm-actor/tests/wasm_actor.rs @@ -7768,4 +7768,149 @@ fn byte_message_various_constructors() { assert!(msg2.0.is_empty()); let msg3 = ByteMessage(vec![0; 1024]); assert_eq!(msg3.0.len(), 1024); +} + +// ── Guest with i32.shl/shr_u shift operations ───────────────────────────── + +#[test] +fn guest_uses_shift_operations() { + 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) + ;; Read first payload byte, shift left by 1, store result + (i32.store8 (i32.const 200) + (i32.shl + (i32.load8_u (i32.add (local.get $ptr) (i32.const 32))) + (i32.const 1) + ) + ) + ;; Read second payload byte, shift right by 2 + (i32.store8 (i32.const 201) + (i32.shr_u + (i32.load8_u (i32.add (local.get $ptr) (i32.const 33))) + (i32.const 2) + ) + ) + (call $send (local.get $ptr) (i32.const 200) (i32.const 2)) + ) + ) + "#; + 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(), &[5, 100])).unwrap(); + rt.tick(); + + let msg = inbox.try_recv().unwrap(); + assert_eq!(msg.0[0], 10, "5 << 1 = 10"); + assert_eq!(msg.0[1], 25, "100 >> 2 = 25"); +} + +// ── Guest with i32.and/or for masking ────────────────────────────────────── + +#[test] +fn guest_uses_bitwise_and_or() { + 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) + ;; AND: 0xFF & 0x0F = 0x0F + (i32.store8 (i32.const 200) (i32.and (i32.const 0xFF) (i32.const 0x0F))) + ;; OR: 0xF0 | 0x0F = 0xFF + (i32.store8 (i32.const 201) (i32.or (i32.const 0xF0) (i32.const 0x0F))) + (call $send (local.get $ptr) (i32.const 200) (i32.const 2)) + ) + ) + "#; + 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"mask")).unwrap(); + rt.tick(); + + let msg = inbox.try_recv().unwrap(); + assert_eq!(msg.0[0], 0x0F, "0xFF & 0x0F = 0x0F"); + assert_eq!(msg.0[1], 0xFF, "0xF0 | 0x0F = 0xFF"); +} + +// ── Two WASM actors with different guest modules on same worker ───────────── + +#[test] +fn echo_and_double_coexist_same_worker() { + let engine = SharedEngine::new().unwrap(); + let echo = WasmActorBuilder::new(engine.clone(), guest_wasm("echo")).build().unwrap(); + let double = WasmActorBuilder::new(engine, guest_wasm("double")).build().unwrap(); + + let rt = Runtime::new(RuntimeConfig::default()); + let inbox = rt.new_inbox::().unwrap(); + let e_addr = rt.spawn(echo).unwrap(); + let d_addr = rt.spawn(double).unwrap(); + + rt.send_to(e_addr, framed_msg(inbox.addr(), b"E")).unwrap(); + rt.send_to(d_addr, framed_msg(inbox.addr(), b"D")).unwrap(); + rt.tick(); + + let mut msgs: Vec> = Vec::new(); + while let Some(msg) = inbox.try_recv() { + msgs.push(msg.0); + } + msgs.sort(); + // Echo: "E" (1x), Double: "D" (2x) + assert_eq!(msgs, vec![b"D".to_vec(), b"D".to_vec(), b"E".to_vec()]); +} + +// ── Guest reads i16 from payload (i32.load16_u) ──────────────────────────── + +#[test] +fn guest_reads_i16_from_payload() { + 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) + ;; Read 2-byte LE value from first payload bytes + (local $val i32) + (local.set $val + (i32.load16_u (i32.add (local.get $ptr) (i32.const 32))) + ) + ;; Store low byte of the i16 value + (i32.store8 (i32.const 200) (local.get $val)) + ;; Store high byte + (i32.store8 (i32.const 201) (i32.shr_u (local.get $val) (i32.const 8))) + (call $send (local.get $ptr) (i32.const 200) (i32.const 2)) + ) + ) + "#; + 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 0x0102 as little-endian: [0x02, 0x01] + rt.send_to(addr, framed_msg(inbox.addr(), &[0x02, 0x01])).unwrap(); + rt.tick(); + + let msg = inbox.try_recv().unwrap(); + // i32.load16_u reads LE: 0x0102 + assert_eq!(msg.0[0], 0x02, "low byte of 0x0102"); + assert_eq!(msg.0[1], 0x01, "high byte of 0x0102"); } \ No newline at end of file