From d99a3c2feed5831d391016018844aa5230c06e14 Mon Sep 17 00:00:00 2001
From: Xyfer <39858937+cxyfer@users.noreply.github.com>
Date: Mon, 26 Jan 2026 11:18:14 +0800
Subject: [PATCH] fix(windows): stabilize test environment (#644)
* fix(windows): embed common-controls manifest
* fix(windows): prefer HOME for config paths
* test(windows): fix export_sql invalid path
* fix(windows): remove unused env import in config.rs
---
src-tauri/build.rs | 17 ++++++++++++++++-
src-tauri/common-controls.manifest | 13 +++++++++++++
src-tauri/src/codex_config.rs | 7 +++++++
src-tauri/src/config.rs | 12 ++++++++----
src-tauri/src/gemini_config.rs | 7 +++++++
src-tauri/src/settings.rs | 11 +++++++++++
src-tauri/tests/import_export_sync.rs | 14 ++++++++++----
7 files changed, 72 insertions(+), 9 deletions(-)
create mode 100644 src-tauri/common-controls.manifest
diff --git a/src-tauri/build.rs b/src-tauri/build.rs
index d860e1e6a..12b5797b3 100644
--- a/src-tauri/build.rs
+++ b/src-tauri/build.rs
@@ -1,3 +1,18 @@
fn main() {
- tauri_build::build()
+ tauri_build::build();
+
+ #[cfg(target_os = "windows")]
+ {
+ let manifest_path = std::path::PathBuf::from(
+ std::env::var("CARGO_MANIFEST_DIR").expect("missing CARGO_MANIFEST_DIR"),
+ )
+ .join("common-controls.manifest");
+ let manifest_arg = format!("/MANIFESTINPUT:{}", manifest_path.display());
+
+ println!("cargo:rustc-link-arg=/MANIFEST:EMBED");
+ println!("cargo:rustc-link-arg={}", manifest_arg);
+ // Avoid duplicate manifest resources in binary builds.
+ println!("cargo:rustc-link-arg-bins=/MANIFEST:NO");
+ println!("cargo:rerun-if-changed={}", manifest_path.display());
+ }
}
diff --git a/src-tauri/common-controls.manifest b/src-tauri/common-controls.manifest
new file mode 100644
index 000000000..8324d4bdd
--- /dev/null
+++ b/src-tauri/common-controls.manifest
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
diff --git a/src-tauri/src/codex_config.rs b/src-tauri/src/codex_config.rs
index 040e5f0c3..e57d79027 100644
--- a/src-tauri/src/codex_config.rs
+++ b/src-tauri/src/codex_config.rs
@@ -11,6 +11,13 @@ use std::path::Path;
/// 获取用户主目录,带回退和日志
fn get_home_dir() -> PathBuf {
+ #[cfg(windows)]
+ if let Ok(home) = std::env::var("HOME") {
+ let trimmed = home.trim();
+ if !trimmed.is_empty() {
+ return PathBuf::from(trimmed);
+ }
+ }
dirs::home_dir().unwrap_or_else(|| {
log::warn!("无法获取用户主目录,回退到当前目录");
PathBuf::from(".")
diff --git a/src-tauri/src/config.rs b/src-tauri/src/config.rs
index 6eae3a2cd..cabc0e878 100644
--- a/src-tauri/src/config.rs
+++ b/src-tauri/src/config.rs
@@ -7,6 +7,13 @@ use crate::error::AppError;
/// 获取用户主目录,带回退和日志
fn get_home_dir() -> PathBuf {
+ #[cfg(windows)]
+ if let Ok(home) = std::env::var("HOME") {
+ let trimmed = home.trim();
+ if !trimmed.is_empty() {
+ return PathBuf::from(trimmed);
+ }
+ }
dirs::home_dir().unwrap_or_else(|| {
log::warn!("无法获取用户主目录,回退到当前目录");
PathBuf::from(".")
@@ -71,10 +78,7 @@ pub fn get_app_config_dir() -> PathBuf {
if let Some(custom) = crate::app_store::get_app_config_dir_override() {
return custom;
}
-
- dirs::home_dir()
- .expect("无法获取用户主目录")
- .join(".cc-switch")
+ get_home_dir().join(".cc-switch")
}
/// 获取应用配置文件路径
diff --git a/src-tauri/src/gemini_config.rs b/src-tauri/src/gemini_config.rs
index 6ea476662..c652d61d4 100644
--- a/src-tauri/src/gemini_config.rs
+++ b/src-tauri/src/gemini_config.rs
@@ -7,6 +7,13 @@ use std::path::PathBuf;
/// 获取用户主目录,带回退和日志
fn get_home_dir() -> PathBuf {
+ #[cfg(windows)]
+ if let Ok(home) = std::env::var("HOME") {
+ let trimmed = home.trim();
+ if !trimmed.is_empty() {
+ return PathBuf::from(trimmed);
+ }
+ }
dirs::home_dir().unwrap_or_else(|| {
log::warn!("无法获取用户主目录,回退到当前目录");
PathBuf::from(".")
diff --git a/src-tauri/src/settings.rs b/src-tauri/src/settings.rs
index 301151a27..2d3580739 100644
--- a/src-tauri/src/settings.rs
+++ b/src-tauri/src/settings.rs
@@ -154,6 +154,17 @@ impl Default for AppSettings {
impl AppSettings {
fn settings_path() -> Option {
// settings.json 保留用于旧版本迁移和无数据库场景
+ #[cfg(windows)]
+ if let Ok(home) = std::env::var("HOME") {
+ let trimmed = home.trim();
+ if !trimmed.is_empty() {
+ return Some(
+ PathBuf::from(trimmed)
+ .join(".cc-switch")
+ .join("settings.json"),
+ );
+ }
+ }
dirs::home_dir().map(|h| h.join(".cc-switch").join("settings.json"))
}
diff --git a/src-tauri/tests/import_export_sync.rs b/src-tauri/tests/import_export_sync.rs
index 50fd70f3e..24a1667fb 100644
--- a/src-tauri/tests/import_export_sync.rs
+++ b/src-tauri/tests/import_export_sync.rs
@@ -971,12 +971,18 @@ fn export_sql_returns_error_for_invalid_path() {
let state = create_test_state().expect("create test state");
- // Try to export to an invalid path (parent directory doesn't exist)
- let invalid_path = PathBuf::from("/nonexistent/directory/export.sql");
+ // Try to export to an invalid path (nonexistent parent or invalid name on Windows)
+ let invalid_parent = if cfg!(windows) {
+ std::env::temp_dir().join("cc-switch-test-invalid<>dir")
+ } else {
+ PathBuf::from("/nonexistent/directory")
+ };
+ let invalid_path = invalid_parent.join("export.sql");
let err = state
.db
.export_sql(&invalid_path)
.expect_err("export to invalid path should fail");
+ let invalid_prefix = invalid_parent.to_string_lossy();
// The error can be either IoContext or Io depending on where it fails
match err {
@@ -988,8 +994,8 @@ fn export_sql_returns_error_for_invalid_path() {
}
AppError::Io { path, .. } => {
assert!(
- path.starts_with("/nonexistent"),
- "expected error for /nonexistent path, got: {path:?}"
+ path.starts_with(invalid_prefix.as_ref()),
+ "expected error for {invalid_parent:?}, got: {path:?}"
);
}
other => panic!("expected IoContext or Io error, got {other:?}"),