Coverage Report

Created: 2026-10-12 08:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wasm-tools/crates/wit-smith/src/lib.rs
Line
Count
Source
1
//! A small crate to generate arbitrary WIT documents.
2
//!
3
//! This crate is modeled after the `wasm-smith` crate but is used to generate
4
//! WIT documents instead of WebAssembly modules. This crate is intended to
5
//! generate "interesting" WIT package structures in addition to interesting
6
//! type structures.
7
8
use arbitrary::{Result, Unstructured};
9
use wit_parser::{Resolve, ResolveErrorKind};
10
11
mod config;
12
pub use self::config::Config;
13
mod generate;
14
15
/// Generates an arbitrary WIT document encoded as a WebAssembly binary.
16
///
17
/// The `config` guides the generation of the document and the `u` bytes are
18
/// used as input to construct the document.
19
3.90k
pub fn smith(config: &Config, u: &mut Unstructured<'_>) -> Result<Vec<u8>> {
20
3.90k
    let pkgs = generate::Generator::new(config.clone()).generate(u)?;
21
3.90k
    let mut resolve = Resolve::default();
22
3.90k
    resolve.all_features = true;
23
3.90k
    let mut last = None;
24
6.90k
    for pkg in pkgs {
25
6.90k
        log::trace!("appending package {:?}", pkg.name);
26
6.90k
        let group = pkg.sources.parse().unwrap();
27
6.90k
        let id = match resolve.push_group(group) {
28
6.89k
            Ok(id) => id,
29
18
            Err(e) => match e.kind() {
30
                ResolveErrorKind::InvalidTransitiveDependency { .. } => {
31
18
                    return Err(arbitrary::Error::IncorrectFormat);
32
                }
33
                ResolveErrorKind::ItemShadowing { .. }
34
                | ResolveErrorKind::StabilityMismatch { .. } => {
35
0
                    log::error!("{e}");
36
0
                    return Err(arbitrary::Error::IncorrectFormat);
37
                }
38
                _ => {
39
0
                    panic!("bad wit parse: {e:?}")
40
                }
41
            },
42
        };
43
6.89k
        last = Some(id);
44
    }
45
3.88k
    let pkg = last.unwrap();
46
47
3.88k
    let wasm = wit_component::encode(&resolve, pkg, config.canonical_names)
48
3.88k
        .expect("failed to encode WIT document");
49
50
3.88k
    if let Err(e) = wasmparser::Validator::new_with_features(wasmparser::WasmFeatures::all())
51
3.88k
        .validate_all(&wasm)
52
    {
53
        // Handle disallowing `stream<char>` here vs not generating it to start
54
        // with as it's a bit easier to handle.
55
39
        if e.to_string()
56
39
            .contains("`stream<char>` is not valid at this time")
57
        {
58
23
            return Err(arbitrary::Error::IncorrectFormat);
59
16
        }
60
61
        // Easier to handle this limit here rather than in generation right now.
62
16
        if e.to_string()
63
16
            .contains("value type's maximum in-memory size exceeds maximum byte size")
64
        {
65
16
            return Err(arbitrary::Error::IncorrectFormat);
66
0
        }
67
3.84k
    }
68
3.84k
    Ok(wasm)
69
3.90k
}