bin-runner #36
1 changed files with 127 additions and 0 deletions
|
|
@ -10875,4 +10875,131 @@ fn build_error_display_contains_export_name() {
|
|||
.build().err().expect("should fail");
|
||||
let msg = format!("{err}");
|
||||
assert!(msg.contains("alloc"), "error should mention missing 'alloc' export: {msg}");
|
||||
}
|
||||
|
||||
// ── Cycle 75 ─────────────────────────────────────────────────────────────────
|
||||
|
||||
// Guest with max function params — handle still only takes (i32, i32) though
|
||||
// Extra internal functions can have many params
|
||||
#[test]
|
||||
fn guest_internal_function_with_many_params() {
|
||||
let wat = r#"(module
|
||||
(memory (export "memory") 1)
|
||||
(func $helper (param i32 i32 i32 i32 i32 i32 i32 i32) (result i32)
|
||||
;; Sum all 8 params
|
||||
(i32.add (local.get 0) (i32.add (local.get 1) (i32.add (local.get 2)
|
||||
(i32.add (local.get 3) (i32.add (local.get 4) (i32.add (local.get 5)
|
||||
(i32.add (local.get 6) (local.get 7))))))))
|
||||
)
|
||||
(func (export "alloc") (param $len i32) (result i32) i32.const 1024)
|
||||
(func (export "handle") (param $ptr i32) (param $len i32)
|
||||
(i32.store (local.get $ptr)
|
||||
(call $helper
|
||||
(i32.const 1) (i32.const 2) (i32.const 3) (i32.const 4)
|
||||
(i32.const 5) (i32.const 6) (i32.const 7) (i32.const 8)))
|
||||
)
|
||||
)"#;
|
||||
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(); // stores 36 at ptr
|
||||
}
|
||||
|
||||
// Echo actor relays message through native forwarder back to inbox
|
||||
#[test]
|
||||
fn wasm_to_native_to_inbox_relay() {
|
||||
let engine = SharedEngine::new().unwrap();
|
||||
let echo = WasmActorBuilder::new(engine, guest_wasm("echo")).build().unwrap();
|
||||
let rt = Runtime::new(RuntimeConfig::default());
|
||||
let inbox = rt.new_inbox::<ByteMessage>().unwrap();
|
||||
|
||||
// Native forwarder: receives ByteMessage, sends to inbox
|
||||
struct NativeForward(ActorAddress);
|
||||
impl ActorInterface for NativeForward {
|
||||
type Incoming = ByteMessage;
|
||||
type Response = ();
|
||||
fn handle(&mut self, ctx: &Ctx, msg: ByteMessage) {
|
||||
let _ = ctx.send(self.0, msg);
|
||||
}
|
||||
}
|
||||
|
||||
let fwd_addr = rt.spawn(NativeForward(*inbox.addr())).unwrap();
|
||||
let echo_addr = rt.spawn(echo).unwrap();
|
||||
|
||||
// Send to echo, echo sends to forwarder, forwarder sends to inbox
|
||||
rt.send_to(echo_addr, framed_msg(&fwd_addr, &inbox.addr().0.to_vec())).unwrap();
|
||||
rt.tick(); // echo → forwarder
|
||||
rt.tick(); // forwarder → inbox
|
||||
|
||||
let resp = inbox.try_recv().expect("relayed through native forwarder");
|
||||
assert_eq!(resp.0, inbox.addr().0.to_vec());
|
||||
}
|
||||
|
||||
// Property: any message size from 0 to 10000 round-trips through echo
|
||||
proptest! {
|
||||
#[test]
|
||||
fn prop_any_message_size_round_trips(size in 0usize..10000) {
|
||||
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::<ByteMessage>().unwrap();
|
||||
let addr = rt.spawn(actor).unwrap();
|
||||
|
||||
let payload = vec![0x42u8; size];
|
||||
rt.send_to(addr, framed_msg(inbox.addr(), &payload)).unwrap();
|
||||
rt.tick();
|
||||
|
||||
let resp = inbox.try_recv().expect("echo should respond");
|
||||
assert_eq!(resp.0.len(), size);
|
||||
}
|
||||
}
|
||||
|
||||
// Guest with i32 conversion: extend 16-bit signed
|
||||
#[test]
|
||||
fn guest_sign_extend_16() {
|
||||
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)
|
||||
;; Sign-extend 16-bit value: 0xFFFF -> -1
|
||||
(i32.store (local.get $ptr)
|
||||
(i32.extend16_s (i32.const 0xFFFF))
|
||||
)
|
||||
)
|
||||
)"#;
|
||||
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();
|
||||
}
|
||||
|
||||
// Echo actor processes message, then gets more after 100 idle ticks
|
||||
#[test]
|
||||
fn echo_after_hundred_idle_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::<ByteMessage>().unwrap();
|
||||
let addr = rt.spawn(actor).unwrap();
|
||||
|
||||
// First message
|
||||
rt.send_to(addr, framed_msg(inbox.addr(), b"before")).unwrap();
|
||||
rt.tick();
|
||||
assert_eq!(inbox.try_recv().unwrap().0, b"before");
|
||||
|
||||
// 100 idle ticks
|
||||
for _ in 0..100 {
|
||||
rt.tick();
|
||||
}
|
||||
|
||||
// Second message — still works
|
||||
rt.send_to(addr, framed_msg(inbox.addr(), b"after")).unwrap();
|
||||
rt.tick();
|
||||
assert_eq!(inbox.try_recv().unwrap().0, b"after");
|
||||
}
|
||||
Loading…
Reference in a new issue