//! The module that implements the `wasmtime wast` command. use clap::Parser; use std::path::PathBuf; use wasmtime::{Engine, Result, error::Context as _}; use wasmtime_cli_flags::CommonOptions; use wasmtime_wast::{SpectestConfig, WastContext}; /// Runs a WebAssembly test script file #[derive(Parser)] pub struct WastCommand { #[command(flatten)] common: CommonOptions, /// The path of the WebAssembly test script to run #[arg(required = true, value_name = "SCRIPT_FILE")] scripts: Vec, /// Whether or not to generate DWARF debugging information in text-to-binary /// transformations to show line numbers in backtraces. #[arg(long, require_equals = true, value_name = "true|false")] generate_dwarf: Option>, /// Saves precompiled versions of modules to this path instead of running /// tests. #[arg(long)] precompile_save: Option, /// Load precompiled modules from the specified directory instead of /// compiling natively. #[arg(long)] precompile_load: Option, /// Whether or not to run wasm in async mode. /// /// This is enabled by default but disabling it may be useful when testing /// Wasmtime itself. #[arg(long = "async", require_equals = true, value_name = "true|false")] async_: Option>, } impl WastCommand { /// Executes the command. pub fn execute(mut self) -> Result<()> { self.common.init_logging()?; let async_ = optional_flag_with_default(self.async_, true); let mut config = self.common.config(None)?; config.shared_memory(true); let engine = Engine::new(&config)?; let mut wast_context = WastContext::new( &engine, if async_ { wasmtime_wast::Async::Yes } else { wasmtime_wast::Async::No }, move |store| { if let Some(fuel) = self.common.wasm.fuel { store.set_fuel(fuel).unwrap(); } if let Some(true) = self.common.wasm.epoch_interruption { store.epoch_deadline_trap(); store.set_epoch_deadline(1); } }, ); wast_context.generate_dwarf(optional_flag_with_default(self.generate_dwarf, true)); wast_context .register_spectest(&SpectestConfig { use_shared_memory: true, suppress_prints: false, }) .expect("error instantiating \"spectest\""); if let Some(path) = &self.precompile_save { wast_context.precompile_save(path); } if let Some(path) = &self.precompile_load { wast_context.precompile_load(path); } for script in self.scripts.iter() { wast_context .run_file(script) .with_context(|| format!("failed to run script file '{}'", script.display()))?; } Ok(()) } } fn optional_flag_with_default(flag: Option>, default: bool) -> bool { match flag { None => default, Some(None) => true, Some(Some(val)) => val, } }