use crate::encoding::encode_world;
use anyhow::{Context, Result, bail};
use wasm_encoder::{ComponentBuilder, ComponentExportKind, ComponentTypeRef};
use wasmparser::{ComponentTypeRef as ImportTypeRef, Parser, Payload, Validator, WasmFeatures};
use wit_parser::decoding::{DecodedWasm, decode};
use wit_parser::{Resolve, WorldId};
pub fn targets(
resolve: &Resolve,
world: WorldId,
component_to_test: &[u8],
semver_compatible: bool,
) -> Result<()> {
let mut root_component = ComponentBuilder::default();
let component_to_test_idx = if semver_compatible {
check_imports_are_wit(component_to_test)?;
let (mut test_resolve, test_world) = match decode(component_to_test)
.context("failed to decode the WIT world of the component to test")?
{
DecodedWasm::Component(resolve, world) => (resolve, world),
DecodedWasm::WitPackage(..) => bail!("expected a component, found a WIT package"),
};
test_resolve.merge_world_imports_based_on_semver(test_world)?;
let component_ty = encode_world(&test_resolve, test_world, true)?;
let component_ty_idx = root_component.type_component(None, &component_ty);
root_component.import(
"component-to-test",
ComponentTypeRef::Component(component_ty_idx),
)
} else {
root_component.component_raw(None, component_to_test)
};
let test_component_idx = {
let component_ty = if semver_compatible {
let mut resolve = resolve.clone();
resolve.merge_world_imports_based_on_semver(world)?;
encode_world(&resolve, world, true)?
} else {
encode_world(resolve, world, false)?
};
let mut component = ComponentBuilder::default();
let component_ty_idx = component.type_component(None, &component_ty);
component.import(
&resolve.worlds[world].name,
ComponentTypeRef::Component(component_ty_idx),
);
root_component.component(None, component)
};
let args: Vec<(String, ComponentExportKind, u32)> = vec![(
resolve.worlds[world].name.clone(),
ComponentExportKind::Component,
component_to_test_idx,
)];
root_component.instantiate(None, test_component_idx, args);
let bytes = root_component.finish();
Validator::new_with_features(WasmFeatures::all())
.validate_all(&bytes)
.context("failed to validate encoded bytes")?;
Ok(())
}
fn check_imports_are_wit(component: &[u8]) -> Result<()> {
let mut depth = 0;
for payload in Parser::new(0).parse_all(component) {
match payload? {
Payload::ModuleSection { .. } | Payload::ComponentSection { .. } => depth += 1,
Payload::End(_) => depth -= 1,
Payload::ComponentImportSection(imports) if depth == 0 => {
for import in imports {
let import = import?;
match import.ty {
ImportTypeRef::Instance(_)
| ImportTypeRef::Func(_)
| ImportTypeRef::Type(_) => {}
_ => bail!(
"import `{}` of the component to test cannot be represented in WIT",
import.name.name
),
}
}
}
_ => {}
}
}
Ok(())
}