wasmtime_cli/commands/
wast.rs

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