1use crate::encoding::encode_world;
2use anyhow::{Context, Result, bail};
3use wasm_encoder::{ComponentBuilder, ComponentExportKind, ComponentTypeRef};
4use wasmparser::{ComponentTypeRef as ImportTypeRef, Parser, Payload, Validator, WasmFeatures};
5use wit_parser::decoding::{DecodedWasm, decode};
6use wit_parser::{Resolve, WorldId};
7
8pub fn targets(
17 resolve: &Resolve,
18 world: WorldId,
19 component_to_test: &[u8],
20 semver_compatible: bool,
21) -> Result<()> {
22 let mut root_component = ComponentBuilder::default();
23
24 let component_to_test_idx = if semver_compatible {
29 check_imports_are_wit(component_to_test)?;
30 let (mut test_resolve, test_world) = match decode(component_to_test)
31 .context("failed to decode the WIT world of the component to test")?
32 {
33 DecodedWasm::Component(resolve, world) => (resolve, world),
34 DecodedWasm::WitPackage(..) => bail!("expected a component, found a WIT package"),
35 };
36 test_resolve.merge_world_imports_based_on_semver(test_world)?;
37 let component_ty = encode_world(&test_resolve, test_world, true)?;
38 let component_ty_idx = root_component.type_component(None, &component_ty);
39 root_component.import(
40 "component-to-test",
41 ComponentTypeRef::Component(component_ty_idx),
42 )
43 } else {
44 root_component.component_raw(None, component_to_test)
45 };
46
47 let test_component_idx = {
50 let component_ty = if semver_compatible {
51 let mut resolve = resolve.clone();
52 resolve.merge_world_imports_based_on_semver(world)?;
53 encode_world(&resolve, world, true)?
54 } else {
55 encode_world(resolve, world, false)?
56 };
57 let mut component = ComponentBuilder::default();
58 let component_ty_idx = component.type_component(None, &component_ty);
59 component.import(
60 &resolve.worlds[world].name,
61 ComponentTypeRef::Component(component_ty_idx),
62 );
63 root_component.component(None, component)
64 };
65
66 let args: Vec<(String, ComponentExportKind, u32)> = vec![(
68 resolve.worlds[world].name.clone(),
69 ComponentExportKind::Component,
70 component_to_test_idx,
71 )];
72 root_component.instantiate(None, test_component_idx, args);
73
74 let bytes = root_component.finish();
75
76 Validator::new_with_features(WasmFeatures::all())
77 .validate_all(&bytes)
78 .context("failed to validate encoded bytes")?;
79
80 Ok(())
81}
82
83fn check_imports_are_wit(component: &[u8]) -> Result<()> {
86 let mut depth = 0;
87 for payload in Parser::new(0).parse_all(component) {
88 match payload? {
89 Payload::ModuleSection { .. } | Payload::ComponentSection { .. } => depth += 1,
90 Payload::End(_) => depth -= 1,
91 Payload::ComponentImportSection(imports) if depth == 0 => {
92 for import in imports {
93 let import = import?;
94 match import.ty {
95 ImportTypeRef::Instance(_)
96 | ImportTypeRef::Func(_)
97 | ImportTypeRef::Type(_) => {}
98 _ => bail!(
99 "import `{}` of the component to test cannot be represented in WIT",
100 import.name.name
101 ),
102 }
103 }
104 }
105 _ => {}
106 }
107 }
108 Ok(())
109}