test: Cycle 42 — internal calls, raw WAT, build-discard, float ops, empty bytes
- module_with_internal_function_calls: helper functions (double, add_ten) composed in handle - build_from_raw_wat_bytes: WAT-compiled silent actor works - build_and_discard_100_actors: WasmActor drops cleanly 100 times - handle_uses_floating_point: f64 arithmetic with i32.trunc_f64_s - empty_wasm_bytes_error: empty Vec<u8> produces build error All 180 tests pass. No new bugs found. Authored by Claude, lovingly guided by Zachery Aaron Shores-Chmielewski
This commit is contained in:
parent
8e8ea693a6
commit
c8bf78231b
1 changed files with 135 additions and 0 deletions
|
|
@ -6400,3 +6400,138 @@ fn fan_in_from_multiple_native_senders() {
|
|||
assert_eq!(msg.0, vec![i as u8], "inbox {i} should get correct payload");
|
||||
}
|
||||
}
|
||||
|
||||
// ── Module with multiple functions calling each other ────────────────────────
|
||||
|
||||
#[test]
|
||||
fn module_with_internal_function_calls() {
|
||||
// Guest has helper functions called from handle.
|
||||
let wat = r#"
|
||||
(module
|
||||
(import "swactor" "send" (func $send (param i32 i32 i32)))
|
||||
(memory (export "memory") 1)
|
||||
(func $double (param $x i32) (result i32)
|
||||
(i32.mul (local.get $x) (i32.const 2))
|
||||
)
|
||||
(func $add_ten (param $x i32) (result i32)
|
||||
(i32.add (local.get $x) (i32.const 10))
|
||||
)
|
||||
(func (export "alloc") (param i32) (result i32) i32.const 4096)
|
||||
(func (export "handle") (param $ptr i32) (param $len i32)
|
||||
;; Read first payload byte, double it, add 10
|
||||
(i32.store8 (i32.const 200)
|
||||
(call $add_ten
|
||||
(call $double
|
||||
(i32.load8_u (i32.add (local.get $ptr) (i32.const 32)))
|
||||
)
|
||||
)
|
||||
)
|
||||
(call $send (local.get $ptr) (i32.const 200) (i32.const 1))
|
||||
)
|
||||
)
|
||||
"#;
|
||||
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();
|
||||
|
||||
// input=5: double(5)=10, add_ten(10)=20
|
||||
rt.send_to(addr, framed_msg(inbox.addr(), &[5])).unwrap();
|
||||
// input=100: double(100)=200, add_ten(200)=210
|
||||
rt.send_to(addr, framed_msg(inbox.addr(), &[100])).unwrap();
|
||||
rt.tick();
|
||||
|
||||
let msg1 = inbox.try_recv().unwrap();
|
||||
let msg2 = inbox.try_recv().unwrap();
|
||||
assert_eq!(msg1.0[0], 20);
|
||||
assert_eq!(msg2.0[0], 210);
|
||||
}
|
||||
|
||||
// ── Build from pre-compiled WAT bytes (no guest dir needed) ─────────────────
|
||||
|
||||
#[test]
|
||||
fn build_from_raw_wat_bytes() {
|
||||
let wat = r#"
|
||||
(module
|
||||
(memory (export "memory") 1)
|
||||
(func (export "alloc") (param i32) (result i32) i32.const 0)
|
||||
(func (export "handle") (param i32 i32))
|
||||
)
|
||||
"#;
|
||||
// Convert WAT → WASM at runtime
|
||||
let wasm = wat::parse_str(wat).unwrap();
|
||||
let engine = SharedEngine::new().unwrap();
|
||||
let actor = WasmActorBuilder::new(engine, wasm).build().unwrap();
|
||||
|
||||
// Verify it works (silent actor — no sends)
|
||||
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"silent")).unwrap();
|
||||
rt.tick();
|
||||
assert!(inbox.try_recv().is_none(), "silent actor should not send anything");
|
||||
}
|
||||
|
||||
// ── Rapidly build and discard actors without spawning ────────────────────────
|
||||
|
||||
#[test]
|
||||
fn build_and_discard_100_actors() {
|
||||
// Build 100 actors but don't spawn them. Tests that WasmActor drops cleanly.
|
||||
let engine = SharedEngine::new().unwrap();
|
||||
for _ in 0..100 {
|
||||
let actor = WasmActorBuilder::new(engine.clone(), guest_wasm("echo"))
|
||||
.build()
|
||||
.unwrap();
|
||||
drop(actor);
|
||||
}
|
||||
// No panic = success
|
||||
}
|
||||
|
||||
// ── Guest with f32/f64 floating point ops ───────────────────────────────────
|
||||
|
||||
#[test]
|
||||
fn handle_uses_floating_point() {
|
||||
// Guest performs f64 arithmetic and stores result as i32.
|
||||
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)
|
||||
;; Compute floor(3.14 * 10) = floor(31.4) = 31
|
||||
(i32.store8 (i32.const 200)
|
||||
(i32.trunc_f64_s
|
||||
(f64.mul (f64.const 3.14) (f64.const 10.0))
|
||||
)
|
||||
)
|
||||
(call $send (local.get $ptr) (i32.const 200) (i32.const 1))
|
||||
)
|
||||
)
|
||||
"#;
|
||||
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"float")).unwrap();
|
||||
rt.tick();
|
||||
|
||||
let msg = inbox.try_recv().unwrap();
|
||||
assert_eq!(msg.0[0], 31, "floor(3.14 * 10) = 31");
|
||||
}
|
||||
|
||||
// ── Empty WASM bytes produces error ─────────────────────────────────────────
|
||||
|
||||
#[test]
|
||||
fn empty_wasm_bytes_error() {
|
||||
let engine = SharedEngine::new().unwrap();
|
||||
let result = WasmActorBuilder::new(engine, Vec::<u8>::new()).build();
|
||||
assert!(result.is_err(), "empty bytes should fail");
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue