Coverage Report

Created: 2026-10-31 07:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wasm-tools/crates/wit-component/src/targets.rs
Line
Count
Source
1
use crate::encoding::encode_world;
2
use anyhow::{Context, Result, bail};
3
use wasm_encoder::{ComponentBuilder, ComponentExportKind, ComponentTypeRef};
4
use wasmparser::{ComponentTypeRef as ImportTypeRef, Parser, Payload, Validator, WasmFeatures};
5
use wit_parser::decoding::{DecodedWasm, decode};
6
use wit_parser::{Resolve, WorldId};
7
8
/// This function checks whether `component_to_test` correctly conforms to the world specified.
9
/// It does so by instantiating a generated component that imports a component instance with
10
/// the component type as described by the "target" world.
11
///
12
/// When `semver_compatible` is set, interfaces are matched by their canonical
13
/// names, so semver-compatible versions (e.g. `wasi:cli@0.2.3` and
14
/// `wasi:cli@0.2.0`) are matched with each other and then type-checked
15
/// structurally.
16
0
pub fn targets(
17
0
    resolve: &Resolve,
18
0
    world: WorldId,
19
0
    component_to_test: &[u8],
20
0
    semver_compatible: bool,
21
0
) -> Result<()> {
22
0
    let mut root_component = ComponentBuilder::default();
23
24
    // (1) Embed the component to test. With `semver_compatible`, the names in
25
    // the component itself may not be canonical, so we decode its world,
26
    // merge semver-compatible imports, and import a component whose type is
27
    // that world encoded with canonical names.
28
0
    let component_to_test_idx = if semver_compatible {
29
0
        check_imports_are_wit(component_to_test)?;
30
0
        let (mut test_resolve, test_world) = match decode(component_to_test)
31
0
            .context("failed to decode the WIT world of the component to test")?
32
        {
33
0
            DecodedWasm::Component(resolve, world) => (resolve, world),
34
0
            DecodedWasm::WitPackage(..) => bail!("expected a component, found a WIT package"),
35
        };
36
0
        test_resolve.merge_world_imports_based_on_semver(test_world)?;
37
0
        let component_ty = encode_world(&test_resolve, test_world, true)?;
38
0
        let component_ty_idx = root_component.type_component(None, &component_ty);
39
0
        root_component.import(
40
            "component-to-test",
41
0
            ComponentTypeRef::Component(component_ty_idx),
42
        )
43
    } else {
44
0
        root_component.component_raw(None, component_to_test)
45
    };
46
47
    // (2) Encode the world to a component type and embed a new component which
48
    // imports the encoded component type.
49
0
    let test_component_idx = {
50
0
        let component_ty = if semver_compatible {
51
0
            let mut resolve = resolve.clone();
52
0
            resolve.merge_world_imports_based_on_semver(world)?;
53
0
            encode_world(&resolve, world, true)?
54
        } else {
55
0
            encode_world(resolve, world, false)?
56
        };
57
0
        let mut component = ComponentBuilder::default();
58
0
        let component_ty_idx = component.type_component(None, &component_ty);
59
0
        component.import(
60
0
            &resolve.worlds[world].name,
61
0
            ComponentTypeRef::Component(component_ty_idx),
62
        );
63
0
        root_component.component(None, component)
64
    };
65
66
    // (3) Instantiate the component from (2) with the component to test from (1).
67
0
    let args: Vec<(String, ComponentExportKind, u32)> = vec![(
68
0
        resolve.worlds[world].name.clone(),
69
0
        ComponentExportKind::Component,
70
0
        component_to_test_idx,
71
0
    )];
72
0
    root_component.instantiate(None, test_component_idx, args);
73
74
0
    let bytes = root_component.finish();
75
76
0
    Validator::new_with_features(WasmFeatures::all())
77
0
        .validate_all(&bytes)
78
0
        .context("failed to validate encoded bytes")?;
79
80
0
    Ok(())
81
0
}
82
83
/// Decoding a component to WIT skips imports that aren't representable in WIT.
84
/// For example, importing a component, a core module, or a value.
85
0
fn check_imports_are_wit(component: &[u8]) -> Result<()> {
86
0
    let mut depth = 0;
87
0
    for payload in Parser::new(0).parse_all(component) {
88
0
        match payload? {
89
0
            Payload::ModuleSection { .. } | Payload::ComponentSection { .. } => depth += 1,
90
0
            Payload::End(_) => depth -= 1,
91
0
            Payload::ComponentImportSection(imports) if depth == 0 => {
92
0
                for import in imports {
93
0
                    let import = import?;
94
0
                    match import.ty {
95
                        ImportTypeRef::Instance(_)
96
                        | ImportTypeRef::Func(_)
97
0
                        | ImportTypeRef::Type(_) => {}
98
0
                        _ => bail!(
99
                            "import `{}` of the component to test cannot be represented in WIT",
100
                            import.name.name
101
                        ),
102
                    }
103
                }
104
            }
105
0
            _ => {}
106
        }
107
    }
108
0
    Ok(())
109
0
}