xref: /wasmtime-44.0.1/src/commands/wast.rs (revision bda02c19)
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