//! Wasm host lifecycle: validate, instantiate, declare, invoke, fuel //! (`SMH-SPEC-WASM0001`). use smith_harness::wasm::{PluginEngine, PluginInstance}; /// Build the echo artifact, returning its path. fn echo_artifact() -> std::path::PathBuf { let status = std::process::Command::new("cargo") .args([ "build", "-p", "smith-plugin-echo", "--target", "wasm32-wasip2", ]) .status() .unwrap(); assert!(status.success(), "echo plugin build failed"); let manifest = std::env::var("CARGO_MANIFEST_DIR").unwrap(); std::path::Path::new(&manifest).join("../target/wasm32-wasip2/debug/smith_plugin_echo.wasm") } #[test] fn echo_plugin_loads_declares_and_invokes() { let artifact = echo_artifact(); let engine = PluginEngine::new().unwrap(); let mut instance = PluginInstance::load(&engine, &artifact).unwrap(); let tools = instance.declare_tools().unwrap(); assert_eq!(tools.len(), 1); assert_eq!(tools[0].name, "echo"); let echoed = instance.invoke("echo", "{\"text\":\"hi\"}").unwrap(); assert_eq!(echoed, "{\"text\":\"hi\"}"); let rejected = match instance.invoke("nope", "{}") { Err(error) => error, Ok(value) => panic!("expected plugin error, got {value}"), }; assert!(rejected.to_string().contains("unknown tool: nope")); } #[test] fn invalid_artifact_fails_validation() { let junk = std::env::temp_dir().join(format!("smith_junk_{}.wasm", std::process::id())); std::fs::write(&junk, b"not a component").unwrap(); let engine = PluginEngine::new().unwrap(); let Err(error) = PluginInstance::load(&engine, &junk) else { panic!("expected validation failure") }; assert!(error.to_string().contains("validation failed")); let _ = std::fs::remove_file(&junk); }