From 90c048d053176f4075001d548fcf131168b9ed98 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 13 Feb 2026 10:31:26 +0000 Subject: [PATCH] =?UTF-8?q?test(wasm-actor):=20cycle=2071=20=E2=80=94=20f3?= =?UTF-8?q?2=20ops,=20nested=20blocks,=20mixed=20guest=20response=20fuzz?= =?UTF-8?q?=20(314=20tests)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added 5 tests: same payload to echo+double verified, f32 store/load, 50 silent actors clean shutdown, 5-deep nested blocks, property test mixed guest response counts. No new bugs found. Authored by Claude, lovingly guided by Zachery Aaron Shores-Chmielewski --- crates/wasm-actor/tests/wasm_actor.rs | 141 ++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) diff --git a/crates/wasm-actor/tests/wasm_actor.rs b/crates/wasm-actor/tests/wasm_actor.rs index 7e4f0d9..0617b7f 100644 --- a/crates/wasm-actor/tests/wasm_actor.rs +++ b/crates/wasm-actor/tests/wasm_actor.rs @@ -10361,4 +10361,145 @@ fn guest_xor_payload_with_key() { let resp = inbox.try_recv().expect("XOR response"); assert_eq!(resp.0, vec![0xFF, 0x00, 0x55], "each byte XORed with 0xFF"); +} + +// ── Cycle 71 ───────────────────────────────────────────────────────────────── + +// Same payload sent to echo and double — both produce correct results +#[test] +fn same_payload_to_echo_and_double_verified() { + 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_e = rt.new_inbox::().unwrap(); + let inbox_d = rt.new_inbox::().unwrap(); + let e_addr = rt.spawn(echo).unwrap(); + let d_addr = rt.spawn(double).unwrap(); + + let payload = b"shared-payload"; + rt.send_to(e_addr, framed_msg(inbox_e.addr(), payload)).unwrap(); + rt.send_to(d_addr, framed_msg(inbox_d.addr(), payload)).unwrap(); + rt.tick(); + + let e_msgs: Vec<_> = std::iter::from_fn(|| inbox_e.try_recv().map(|m| m.0)).collect(); + let d_msgs: Vec<_> = std::iter::from_fn(|| inbox_d.try_recv().map(|m| m.0)).collect(); + assert_eq!(e_msgs.len(), 1); + assert_eq!(d_msgs.len(), 2); + assert_eq!(e_msgs[0], payload); + assert!(d_msgs.iter().all(|m| m == payload)); +} + +// Guest stores and reloads a f32 value +#[test] +fn guest_f32_store_and_load() { + 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) + ;; Store f32 at ptr, load it back, add 1.0, store again + (f32.store (local.get $ptr) (f32.const 3.14)) + (f32.store (local.get $ptr) + (f32.add (f32.load (local.get $ptr)) (f32.const 1.0)) + ) + ) + )"#; + 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(); +} + +// Spawn 50 silent actors, tick, stop all — clean shutdown +#[test] +fn fifty_silent_actors_clean_shutdown() { + let engine = SharedEngine::new().unwrap(); + let rt = Runtime::new(RuntimeConfig::default()); + let addrs: Vec<_> = (0..50) + .map(|_| { + let actor = WasmActorBuilder::new(engine.clone(), guest_wasm("silent")) + .build().unwrap(); + rt.spawn(actor).unwrap() + }) + .collect(); + + for addr in &addrs { + rt.send_to(*addr, ByteMessage(vec![0])).unwrap(); + } + rt.tick(); + + for addr in &addrs { + rt.stop_actor(*addr); + } + rt.tick(); + rt.tick(); +} + +// Guest with deeply nested blocks (5 levels) +#[test] +fn guest_deeply_nested_blocks() { + 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) + (block $b0 + (block $b1 + (block $b2 + (block $b3 + (block $b4 + ;; Store nesting depth at ptr + (i32.store (local.get $ptr) (i32.const 5)) + ) + ) + ) + ) + ) + ) + )"#; + 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(); +} + +// Property: mixed guest types always produce expected response counts +proptest! { + #[test] + fn prop_mixed_guest_response_counts( + echo_count in 0usize..5, + double_count in 0usize..5, + silent_count in 0usize..5, + ) { + let engine = SharedEngine::new().unwrap(); + let rt = Runtime::new(RuntimeConfig::default()); + let inbox = rt.new_inbox::().unwrap(); + + for _ in 0..echo_count { + let actor = WasmActorBuilder::new(engine.clone(), guest_wasm("echo")).build().unwrap(); + let addr = rt.spawn(actor).unwrap(); + rt.send_to(addr, framed_msg(inbox.addr(), b"x")).unwrap(); + } + for _ in 0..double_count { + let actor = WasmActorBuilder::new(engine.clone(), guest_wasm("double")).build().unwrap(); + let addr = rt.spawn(actor).unwrap(); + rt.send_to(addr, framed_msg(inbox.addr(), b"x")).unwrap(); + } + for _ in 0..silent_count { + let actor = WasmActorBuilder::new(engine.clone(), guest_wasm("silent")).build().unwrap(); + let addr = rt.spawn(actor).unwrap(); + rt.send_to(addr, ByteMessage(b"x".to_vec())).unwrap(); + } + rt.tick(); + + let msg_count = std::iter::from_fn(|| inbox.try_recv()).count(); + let expected = echo_count + double_count * 2; + assert_eq!(msg_count, expected, + "echo({echo_count})+double({double_count}*2)+silent({silent_count}*0)={expected}, got {msg_count}"); + } } \ No newline at end of file