bin-runner #36
1 changed files with 126 additions and 0 deletions
|
|
@ -11988,4 +11988,130 @@ fn heterogeneous_wat_actors_on_same_runtime() {
|
|||
// One is "hello", other is [0x42]
|
||||
assert!(msgs.iter().any(|m| m == b"hello"));
|
||||
assert!(msgs.iter().any(|m| m == &[0x42]));
|
||||
}
|
||||
|
||||
// ── Cycle 84 ─────────────────────────────────────────────────────────────────
|
||||
|
||||
// Guest inverts bit pattern: i32.xor with 0xFFFFFFFF on 4-byte chunks
|
||||
#[test]
|
||||
fn guest_inverts_i32_pattern() {
|
||||
let wat = r#"(module
|
||||
(import "swactor" "send" (func $send (param i32 i32 i32)))
|
||||
(memory (export "memory") 1)
|
||||
(func (export "alloc") (param $len i32) (result i32) i32.const 1024)
|
||||
(func (export "handle") (param $ptr i32) (param $len i32)
|
||||
(local $i i32)
|
||||
;; Need at least 36 bytes (32 addr + 4 payload)
|
||||
(if (i32.lt_u (local.get $len) (i32.const 36)) (then return))
|
||||
;; XOR 4 bytes at ptr+32 with 0xFFFFFFFF
|
||||
(i32.store (i32.add (local.get $ptr) (i32.const 32))
|
||||
(i32.xor
|
||||
(i32.load (i32.add (local.get $ptr) (i32.const 32)))
|
||||
(i32.const -1)))
|
||||
(call $send
|
||||
(local.get $ptr)
|
||||
(i32.add (local.get $ptr) (i32.const 32))
|
||||
(i32.const 4))
|
||||
)
|
||||
)"#;
|
||||
let engine = SharedEngine::new().unwrap();
|
||||
let actor = WasmActorBuilder::new(engine, wat::parse_str(wat).unwrap())
|
||||
.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(), &[0x12, 0x34, 0x56, 0x78])).unwrap();
|
||||
rt.tick();
|
||||
|
||||
let resp = inbox.try_recv().expect("inverted pattern");
|
||||
assert_eq!(resp.0, vec![0xED, 0xCB, 0xA9, 0x87]);
|
||||
}
|
||||
|
||||
// Native actor that spawns WASM and sends to it
|
||||
struct NativeWasmSpawner2 {
|
||||
engine: SharedEngine,
|
||||
inbox_addr: ActorAddress,
|
||||
}
|
||||
impl ActorInterface for NativeWasmSpawner2 {
|
||||
type Incoming = ByteMessage;
|
||||
type Response = ();
|
||||
fn handle(&mut self, ctx: &Ctx, _msg: ByteMessage) {
|
||||
let actor = WasmActorBuilder::new(self.engine.clone(), guest_wasm("echo"))
|
||||
.build().unwrap();
|
||||
let wasm_addr = ctx.spawn(actor).unwrap();
|
||||
let _ = ctx.send(wasm_addr, framed_msg(&self.inbox_addr, b"spawned-inline"));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn native_spawns_wasm_and_sends_in_handler() {
|
||||
let engine = SharedEngine::new().unwrap();
|
||||
let rt = Runtime::new(RuntimeConfig::default());
|
||||
let inbox = rt.new_inbox::<ByteMessage>().unwrap();
|
||||
|
||||
let spawner = NativeWasmSpawner2 {
|
||||
engine,
|
||||
inbox_addr: *inbox.addr(),
|
||||
};
|
||||
let s_addr = rt.spawn(spawner).unwrap();
|
||||
rt.send_to(s_addr, ByteMessage(vec![])).unwrap();
|
||||
rt.tick(); // spawner spawns WASM + sends to it
|
||||
rt.tick(); // WASM echo processes message
|
||||
rt.tick(); // ensure delivery
|
||||
|
||||
let resp = inbox.try_recv().expect("spawned WASM should echo");
|
||||
assert_eq!(resp.0, b"spawned-inline");
|
||||
}
|
||||
|
||||
// Guest with nested loop computing factorial(5) = 120
|
||||
#[test]
|
||||
fn guest_factorial_loop() {
|
||||
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)
|
||||
(local $result i32)
|
||||
(local $n i32)
|
||||
(local.set $result (i32.const 1))
|
||||
(local.set $n (i32.const 5))
|
||||
(block $exit
|
||||
(loop $loop
|
||||
(br_if $exit (i32.le_u (local.get $n) (i32.const 1)))
|
||||
(local.set $result (i32.mul (local.get $result) (local.get $n)))
|
||||
(local.set $n (i32.sub (local.get $n) (i32.const 1)))
|
||||
(br $loop)
|
||||
)
|
||||
)
|
||||
(i32.store (local.get $ptr) (local.get $result))
|
||||
)
|
||||
)"#;
|
||||
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();
|
||||
}
|
||||
|
||||
// Verify echo determinism: same input always produces same output
|
||||
#[test]
|
||||
fn echo_determinism_ten_runs() {
|
||||
let engine = SharedEngine::new().unwrap();
|
||||
let payload = b"deterministic-test-payload";
|
||||
|
||||
let mut outputs = Vec::new();
|
||||
for _ in 0..10 {
|
||||
let actor = WasmActorBuilder::new(engine.clone(), guest_wasm("echo")).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(), payload)).unwrap();
|
||||
rt.tick();
|
||||
outputs.push(inbox.try_recv().unwrap().0);
|
||||
}
|
||||
|
||||
assert!(outputs.iter().all(|o| o == &outputs[0]),
|
||||
"all 10 runs should produce identical output");
|
||||
}
|
||||
Loading…
Reference in a new issue