test: Cycle 51 — XOR transform, address reconstruction, double+watch, constructors

- guest_xor_transform_key: loop-based XOR cipher with 0xAA key
- actor_address_reconstructible_from_bytes: ActorAddress round-trips through raw bytes
- double_guest_watch_fires_once_on_stop: double works + watch notifies exactly once
- byte_message_various_constructors: ByteMessage from string, empty, 1024 zeros

All 220 tests pass. No new bugs found.

Authored by Claude, lovingly guided by Zachery Aaron Shores-Chmielewski
This commit is contained in:
Claude 2026-02-13 10:02:15 +00:00
parent f235266300
commit 372c0bbf9e

View file

@ -7644,3 +7644,128 @@ proptest! {
while let Some(_) = inbox.try_recv() {} while let Some(_) = inbox.try_recv() {}
} }
} }
// ── Guest with i32.xor for byte transformation ─────────────────────────────
#[test]
fn guest_xor_transform_key() {
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)
(local $i i32)
(local $payload_start i32)
(local $payload_len i32)
(local.set $payload_start (i32.add (local.get $ptr) (i32.const 32)))
(local.set $payload_len (i32.sub (local.get $len) (i32.const 32)))
(local.set $i (i32.const 0))
(block $break
(loop $loop
(br_if $break (i32.ge_u (local.get $i) (local.get $payload_len)))
(i32.store8
(i32.add (i32.const 200) (local.get $i))
(i32.xor
(i32.load8_u (i32.add (local.get $payload_start) (local.get $i)))
(i32.const 0xAA)
)
)
(local.set $i (i32.add (local.get $i) (i32.const 1)))
(br $loop)
)
)
(call $send (local.get $ptr) (i32.const 200) (local.get $payload_len))
)
)
"#;
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(), &[0x00, 0xFF, 0x55, 0xAA])).unwrap();
rt.tick();
let msg = inbox.try_recv().unwrap();
assert_eq!(msg.0, vec![0xAA, 0x55, 0xFF, 0x00], "XOR with 0xAA");
}
// ── ActorAddress reconstruction from raw bytes ──────────────────────────────
#[test]
fn actor_address_reconstructible_from_bytes() {
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 reconstructed = ActorAddress(addr.0);
assert_eq!(addr, reconstructed);
rt.send_to(reconstructed, framed_msg(inbox.addr(), b"reconstructed")).unwrap();
rt.tick();
let msg = inbox.try_recv().unwrap();
assert_eq!(msg.0, b"reconstructed");
}
// ── Double guest + watch fires once on stop ─────────────────────────────────
#[test]
fn double_guest_watch_fires_once_on_stop() {
let engine = SharedEngine::new().unwrap();
let actor = WasmActorBuilder::new(engine, guest_wasm("double")).build().unwrap();
let exit_count = std::sync::Arc::new(std::sync::atomic::AtomicUsize::new(0));
let ec = exit_count.clone();
struct WatchCounter3 {
target: Option<ActorAddress>,
count: std::sync::Arc<std::sync::atomic::AtomicUsize>,
}
impl ActorInterface for WatchCounter3 {
type Incoming = ByteMessage;
type Response = ();
fn handle(&mut self, ctx: &Ctx, _msg: ByteMessage) {
if let Some(t) = self.target.take() { ctx.watch(t); }
}
fn on_actor_exit(&mut self, _ctx: &Ctx, _exited: swactor::actor::ActorExited) {
self.count.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
}
}
let rt = Runtime::new(RuntimeConfig::default());
let inbox = rt.new_inbox::<ByteMessage>().unwrap();
let double_addr = rt.spawn(actor).unwrap();
let w_addr = rt.spawn(WatchCounter3 { target: Some(double_addr), count: ec }).unwrap();
rt.send_to(w_addr, ByteMessage(vec![])).unwrap();
rt.tick();
rt.send_to(double_addr, framed_msg(inbox.addr(), b"D")).unwrap();
rt.tick();
assert_eq!(inbox.try_recv().unwrap().0, b"D");
assert_eq!(inbox.try_recv().unwrap().0, b"D");
rt.stop_actor(double_addr);
rt.tick();
rt.tick();
assert_eq!(exit_count.load(std::sync::atomic::Ordering::SeqCst), 1);
}
// ── ByteMessage constructors ────────────────────────────────────────────────
#[test]
fn byte_message_various_constructors() {
let msg1 = ByteMessage("hello".as_bytes().to_vec());
assert_eq!(msg1.0, b"hello");
let msg2 = ByteMessage(Vec::new());
assert!(msg2.0.is_empty());
let msg3 = ByteMessage(vec![0; 1024]);
assert_eq!(msg3.0.len(), 1024);
}