feat(v1): harden typed runtime boundaries
Elect one canonical EffectBatch codec, remove the parallel postcard API, and strengthen fail-closed host, form, sync, WASM, macro, generated-contract, and test-harness proofs with mutation-driven coverage. req: wire/008 req: wire/009 req: wire/010 req: push/008 req: client_local/015 req: client_local/016 req: client_local/017 req: client_local/018 req: client_local/019 req: sync/024 req: sync/025 req: sync/026 req: sync/027 req: sync/028 req: sync/029 req: test/020 req: test/021
This commit is contained in:
+93
-1
@@ -468,6 +468,28 @@ mod tests {
|
||||
native_shell_host_profile("ios-android-webview-test")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn capability_names_and_standard_profile_identity_are_stable() {
|
||||
let names = [
|
||||
(Capability::Haptics, "haptics"),
|
||||
(Capability::Microphone, "microphone"),
|
||||
(Capability::Camera, "camera"),
|
||||
(Capability::Share, "share"),
|
||||
(Capability::SecureStorage, "secure_storage"),
|
||||
(Capability::Notifications, "notifications"),
|
||||
(Capability::Clipboard, "clipboard"),
|
||||
(Capability::FilePicker, "file_picker"),
|
||||
(Capability::Geolocation, "geolocation"),
|
||||
(Capability::custom("vendor.camera"), "vendor.camera"),
|
||||
];
|
||||
|
||||
for (capability, expected) in names {
|
||||
assert_eq!(capability.as_str(), expected);
|
||||
}
|
||||
assert_eq!(web_host().name, "browser-pwa");
|
||||
// req: host/001 req: host/004
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn browser_host_js_is_a_thin_host_adapter_not_a_dom_runtime() {
|
||||
// req: host/001 req: host/002 req: host/005
|
||||
@@ -509,6 +531,37 @@ mod tests {
|
||||
assert_eq!(manifest.check(&web_host()), Ok(()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn manifest_and_host_support_require_the_exact_capability_shape() {
|
||||
let wrong_shape_host = HostProfile::new(
|
||||
"wrong-shape",
|
||||
[CapabilityUse::new(Capability::Share, CapabilityShape::Fire)],
|
||||
);
|
||||
let wrong_capability_host = HostProfile::new(
|
||||
"wrong-capability",
|
||||
[CapabilityUse::new(
|
||||
Capability::Haptics,
|
||||
CapabilityShape::Request,
|
||||
)],
|
||||
);
|
||||
let manifest = CapabilityManifest::new([CapabilityUse::new(
|
||||
Capability::Share,
|
||||
CapabilityShape::Request,
|
||||
)]);
|
||||
|
||||
assert!(!wrong_shape_host.supports(&Capability::Share, CapabilityShape::Request));
|
||||
assert!(!wrong_capability_host.supports(&Capability::Share, CapabilityShape::Request));
|
||||
assert_eq!(
|
||||
manifest.check(&wrong_shape_host),
|
||||
Err(HostCheckError::UnsupportedCapability {
|
||||
capability: Capability::Share,
|
||||
shape: CapabilityShape::Request,
|
||||
host: "wrong-shape".into(),
|
||||
})
|
||||
);
|
||||
// req: host/001 req: host/004
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn host_calls_must_be_declared_and_supported() {
|
||||
// req: host/001 req: host/004
|
||||
@@ -516,12 +569,38 @@ mod tests {
|
||||
Capability::Share,
|
||||
CapabilityShape::Request,
|
||||
)]);
|
||||
let payload = SharePayload::text("log");
|
||||
assert_eq!(
|
||||
payload,
|
||||
SharePayload {
|
||||
title: None,
|
||||
text: Some("log".into()),
|
||||
url: None,
|
||||
}
|
||||
);
|
||||
let call = HostCall::Share {
|
||||
id: HostCallId::new("share-1"),
|
||||
payload: SharePayload::text("log"),
|
||||
payload,
|
||||
};
|
||||
assert_eq!(manifest.validate_call(&web_host(), &call), Ok(()));
|
||||
|
||||
let unsupported_host = HostProfile::new("offline-shell", []);
|
||||
let unsupported = manifest
|
||||
.validate_call(&unsupported_host, &call)
|
||||
.expect_err("declared calls still require host support");
|
||||
assert_eq!(
|
||||
unsupported,
|
||||
HostCheckError::UnsupportedCapability {
|
||||
capability: Capability::Share,
|
||||
shape: CapabilityShape::Request,
|
||||
host: "offline-shell".into(),
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
unsupported.to_string(),
|
||||
"host `offline-shell` does not support capability `share` with shape Request"
|
||||
);
|
||||
|
||||
let haptic = HostCall::Haptic {
|
||||
id: HostCallId::new("tap"),
|
||||
pattern: HapticPattern::Success,
|
||||
@@ -584,6 +663,19 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn host_failure_builders_preserve_call_context() {
|
||||
let failure = HostFailure::new(HostFailureKind::Timeout, "host timed out")
|
||||
.with_id(HostCallId::new("share-1"))
|
||||
.with_capability(Capability::Share);
|
||||
|
||||
assert_eq!(failure.id, Some(HostCallId::new("share-1")));
|
||||
assert_eq!(failure.capability, Some(Capability::Share));
|
||||
assert_eq!(failure.kind, HostFailureKind::Timeout);
|
||||
assert_eq!(failure.message, "host timed out");
|
||||
// req: host/002 req: host/005
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn web_pwa_host_result_routes_through_app_code_before_hemx_effect() {
|
||||
// req: host/001 req: host/002 req: host/005
|
||||
|
||||
Reference in New Issue
Block a user