test: Cycle 52 — shift ops, bitwise AND/OR, echo+double coexist, i16 load
- 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
This commit is contained in:
parent
372c0bbf9e
commit
af5e0644bc
1 changed files with 145 additions and 0 deletions
|
|
@ -7769,3 +7769,148 @@ fn byte_message_various_constructors() {
|
||||||
let msg3 = ByteMessage(vec![0; 1024]);
|
let msg3 = ByteMessage(vec![0; 1024]);
|
||||||
assert_eq!(msg3.0.len(), 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::<ByteMessage>().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::<ByteMessage>().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::<ByteMessage>().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<u8>> = 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::<ByteMessage>().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");
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue