1 //! The module that implements the `wasmtime wast` command. 2 3 use clap::Parser; 4 use std::path::PathBuf; 5 use wasmtime::{Engine, Result, error::Context as _}; 6 use wasmtime_cli_flags::CommonOptions; 7 use wasmtime_wast::{SpectestConfig, WastContext}; 8 9 /// Runs a WebAssembly test script file 10 #[derive(Parser)] 11 pub struct WastCommand { 12 #[command(flatten)] 13 common: CommonOptions, 14 15 /// The path of the WebAssembly test script to run 16 #[arg(required = true, value_name = "SCRIPT_FILE")] 17 scripts: Vec<PathBuf>, 18 19 /// Whether or not to generate DWARF debugging information in text-to-binary 20 /// transformations to show line numbers in backtraces. 21 #[arg(long, require_equals = true, value_name = "true|false")] 22 generate_dwarf: Option<Option<bool>>, 23 24 /// Saves precompiled versions of modules to this path instead of running 25 /// tests. 26 #[arg(long)] 27 precompile_save: Option<PathBuf>, 28 29 /// Load precompiled modules from the specified directory instead of 30 /// compiling natively. 31 #[arg(long)] 32 precompile_load: Option<PathBuf>, 33 34 /// Whether or not to run wasm in async mode. 35 /// 36 /// This is enabled by default but disabling it may be useful when testing 37 /// Wasmtime itself. 38 #[arg(long = "async", require_equals = true, value_name = "true|false")] 39 async_: Option<Option<bool>>, 40 } 41 42 impl WastCommand { 43 /// Executes the command. 44 pub fn execute(mut self) -> Result<()> { 45 self.common.init_logging()?; 46 47 let async_ = optional_flag_with_default(self.async_, true); 48 let mut config = self.common.config(None)?; 49 config.shared_memory(true); 50 let engine = Engine::new(&config)?; 51 let mut wast_context = WastContext::new( 52 &engine, 53 if async_ { 54 wasmtime_wast::Async::Yes 55 } else { 56 wasmtime_wast::Async::No 57 }, 58 move |store| { 59 if let Some(fuel) = self.common.wasm.fuel { 60 store.set_fuel(fuel).unwrap(); 61 } 62 if let Some(true) = self.common.wasm.epoch_interruption { 63 store.epoch_deadline_trap(); 64 store.set_epoch_deadline(1); 65 } 66 }, 67 ); 68 69 wast_context.generate_dwarf(optional_flag_with_default(self.generate_dwarf, true)); 70 wast_context 71 .register_spectest(&SpectestConfig { 72 use_shared_memory: true, 73 suppress_prints: false, 74 }) 75 .expect("error instantiating \"spectest\""); 76 77 if let Some(path) = &self.precompile_save { 78 wast_context.precompile_save(path); 79 } 80 if let Some(path) = &self.precompile_load { 81 wast_context.precompile_load(path); 82 } 83 84 for script in self.scripts.iter() { 85 wast_context 86 .run_file(script) 87 .with_context(|| format!("failed to run script file '{}'", script.display()))?; 88 } 89 90 Ok(()) 91 } 92 } 93 94 fn optional_flag_with_default(flag: Option<Option<bool>>, default: bool) -> bool { 95 match flag { 96 None => default, 97 Some(None) => true, 98 Some(Some(val)) => val, 99 } 100 } 101