补齐桌面壳网络与门禁自检

桌面网络 HostBridge 补成功与失败映射单测

桌面壳配置脚本纳入受控脚本与替身词扫描

原生壳文档改用唯一完整路径清单口径

项目记忆同步桌面壳验收边界
This commit is contained in:
2026-06-20 16:47:08 +08:00
parent 2f16a43000
commit 51139ea83f
6 changed files with 96 additions and 11 deletions
+19 -2
View File
@@ -181,6 +181,7 @@ const desktopShellNavigationSource = fs.readFileSync(
);
const productionSourceRoots = [
new URL('../package.json', import.meta.url),
new URL('../scripts/', import.meta.url),
new URL('../src-tauri/Cargo.toml', import.meta.url),
new URL('../src-tauri/Info.plist', import.meta.url),
new URL('../src-tauri/build.rs', import.meta.url),
@@ -301,6 +302,9 @@ const expectedDesktopShellRustFiles = [
'webview.rs',
'window_state.rs',
];
const expectedDesktopShellScripts = [
'check-config.mjs',
];
function extractCargoPackageString(source, key) {
const match = source.match(new RegExp(`^${key}\\s*=\\s*"([^"]+)"`, 'm'));
@@ -576,7 +580,7 @@ function collectProductionSourceFiles(entry) {
if (!productionFileExtensions.has(extension)) {
return [];
}
if (path.includes('.test.') || path.endsWith('/scripts/check-config.mjs')) {
if (path.includes('.test.')) {
return [];
}
@@ -1197,6 +1201,11 @@ function readDirectoryFileList(directory, label) {
}
function assertDesktopSourceLayout() {
assertSameList(
readDirectoryFileList(new URL('../scripts/', import.meta.url), 'desktop shell scripts'),
expectedDesktopShellScripts,
'desktop shell scripts',
);
assertSameList(
readDirectoryEntryList(rustSourceDir, 'desktop shell Rust root entries'),
expectedDesktopRustRootEntries,
@@ -2009,11 +2018,19 @@ if (
}
for (const snippet of [
'resolve_desktop_host_bridge_network_status',
'map_desktop_host_bridge_network_status_result',
'resolve_desktop_host_bridge_network_status_payload',
'resolve_desktop_host_bridge_network_status_payload_with',
'network_status_unavailable_response',
'spawn_blocking(resolve_desktop_network_status)',
'spawn_blocking(resolver)',
'resolve_desktop_host_bridge_network_status_payload_with(resolve_desktop_network_status)',
'"isConnected": true',
'"connectionType": "unknown"',
'"network status unavailable"',
'network_status_unavailable_response_is_stable',
'network_status_success_response_reports_contract_shape',
'network_status_failure_hides_native_error_detail',
'private native resolver detail',
]) {
if (!desktopHostBridgeNetworkSource.includes(snippet)) {
throw new Error(`desktop shell network module is missing ${snippet}`);
@@ -2,19 +2,35 @@ use crate::host_bridge::protocol::{failed, ok, HostBridgeRequest, HostBridgeResp
use crate::shell::webview::resolve_desktop_network_status;
use serde_json::Value;
async fn resolve_desktop_host_bridge_network_status_payload() -> Result<Value, String> {
tauri::async_runtime::spawn_blocking(resolve_desktop_network_status)
fn map_desktop_host_bridge_network_status_result(
status: Result<Value, String>,
request: &HostBridgeRequest,
) -> HostBridgeResponse {
match status {
Ok(status) => ok(request.id.clone(), status),
Err(_) => network_status_unavailable_response(request),
}
}
async fn resolve_desktop_host_bridge_network_status_payload_with(
resolver: fn() -> Value,
) -> Result<Value, String> {
tauri::async_runtime::spawn_blocking(resolver)
.await
.map_err(|error| error.to_string())
}
async fn resolve_desktop_host_bridge_network_status_payload() -> Result<Value, String> {
resolve_desktop_host_bridge_network_status_payload_with(resolve_desktop_network_status).await
}
pub(crate) async fn resolve_desktop_host_bridge_network_status(
request: &HostBridgeRequest,
) -> HostBridgeResponse {
match resolve_desktop_host_bridge_network_status_payload().await {
Ok(status) => ok(request.id.clone(), status),
Err(_) => network_status_unavailable_response(request),
}
map_desktop_host_bridge_network_status_result(
resolve_desktop_host_bridge_network_status_payload().await,
request,
)
}
fn network_status_unavailable_response(request: &HostBridgeRequest) -> HostBridgeResponse {
@@ -25,6 +41,7 @@ fn network_status_unavailable_response(request: &HostBridgeRequest) -> HostBridg
mod tests {
use super::*;
use crate::host_bridge::protocol::request;
use serde_json::json;
#[test]
fn network_status_unavailable_response_is_stable() {
@@ -35,4 +52,37 @@ mod tests {
assert_eq!(error.code, "host_error");
assert_eq!(error.message, "network status unavailable");
}
#[test]
fn network_status_success_response_reports_contract_shape() {
let payload = json!({
"isConnected": true,
"isInternetReachable": true,
"connectionType": "unknown",
"nativeType": "online",
});
let response = map_desktop_host_bridge_network_status_result(
Ok(payload.clone()),
&request("network.status"),
);
assert!(response.ok);
assert_eq!(response.id, "request-1");
assert_eq!(response.result, Some(payload));
assert!(response.error.is_none());
}
#[test]
fn network_status_failure_hides_native_error_detail() {
let response = map_desktop_host_bridge_network_status_result(
Err("private native resolver detail".to_string()),
&request("network.status"),
);
assert!(!response.ok);
let error = response.error.expect("network status error");
assert_eq!(error.code, "host_error");
assert_eq!(error.message, "network status unavailable");
assert!(!error.message.contains("private native resolver detail"));
}
}