Files
Genarrative/apps/ai-game-creator-shell/src-tauri/tests/frontend_dist_build.rs
T
kdletters 578f8019fc
Project CI / Repository checks (push) Successful in 1m14s
Project CI / Frontend tests (push) Successful in 3m9s
Project CI / Backend tests (push) Successful in 3m58s
Project CI / Native shell tests (push) Successful in 14m6s
优化AGC项目入口并识别Godot工作区
项目页只保留打开项目和新建项目并统一原生目录选择
按根目录及一层子目录识别project.godot并记录相对Godot根
保持.agent位于用户选择的工作区根并补齐Windows构建门禁
补充响应式布局、测试、技术方案和共享项目记忆
2026-08-14 21:53:43 +08:00

142 lines
4.8 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#[path = "../build_support/frontend_dist_guard.rs"]
mod frontend_dist_guard;
use frontend_dist_guard::validate_frontend_dist;
use std::fs;
use std::path::{Path, PathBuf};
use std::sync::atomic::{AtomicU64, Ordering};
static TEST_DIRECTORY_SEQUENCE: AtomicU64 = AtomicU64::new(0);
struct TestDirectory {
path: PathBuf,
}
impl TestDirectory {
fn new(label: &str) -> Self {
let sequence = TEST_DIRECTORY_SEQUENCE.fetch_add(1, Ordering::Relaxed);
let path = std::env::temp_dir().join(format!(
"genarrative-frontend-dist-{label}-{}-{sequence}",
std::process::id()
));
fs::create_dir(&path).expect("create frontend dist test directory");
Self { path }
}
fn path(&self) -> &Path {
&self.path
}
}
impl Drop for TestDirectory {
fn drop(&mut self) {
let _ = fs::remove_dir_all(&self.path);
}
}
fn write_file(path: &Path, content: impl AsRef<[u8]>) {
if let Some(parent) = path.parent() {
fs::create_dir_all(parent).expect("create frontend dist fixture parent");
}
fs::write(path, content).expect("write frontend dist fixture");
}
#[test]
fn clean_frontend_dist_passes() {
let fixture = TestDirectory::new("clean");
let dist = fixture.path().join("dist");
write_file(&dist.join("index.html"), "<main>GameAgent</main>");
write_file(
&dist.join("assets/index.js"),
"const defaultProjectPath = '';",
);
validate_frontend_dist(&dist).expect("clean frontendDist should pass");
}
#[test]
fn nested_frontend_asset_with_test_default_path_fails_with_relative_path() {
let fixture = TestDirectory::new("marker");
let dist = fixture.path().join("dist");
write_file(&dist.join("index.html"), "<main>GameAgent</main>");
write_file(
&dist.join("assets/chunks/launcher.js"),
"const projectPath = '/tmp/genarrative-ai-game-draft';",
);
let error = validate_frontend_dist(&dist)
.expect_err("production frontendDist must reject the test default path");
let portable_error = error.replace('\\', "/");
assert!(error.contains("/tmp/genarrative-ai-game-draft"));
assert!(portable_error.contains("assets/chunks/launcher.js"));
assert!(!error.contains(&dist.display().to_string()));
}
#[test]
fn test_fixture_outside_frontend_dist_does_not_fail_the_guard() {
let fixture = TestDirectory::new("fixture-scope");
let dist = fixture.path().join("dist");
write_file(&dist.join("assets/index.js"), "const projectPath = '';");
write_file(
&fixture.path().join("tests/project-path.fixture.txt"),
"/tmp/genarrative-ai-game-draft",
);
validate_frontend_dist(&dist)
.expect("explicit test fixtures outside frontendDist must remain allowed");
}
#[test]
fn missing_frontend_dist_fails_without_leaking_an_absolute_path() {
let fixture = TestDirectory::new("missing");
let dist = fixture.path().join("dist");
let error = validate_frontend_dist(&dist)
.expect_err("production frontendDist must exist before it can be embedded");
assert!(error.contains("frontendDist"));
assert!(error.contains(":."));
assert!(!error.contains(&dist.display().to_string()));
}
#[cfg(unix)]
#[test]
fn frontend_dist_symlink_fails_with_relative_path() {
use std::os::unix::fs::symlink;
let fixture = TestDirectory::new("symlink");
let dist = fixture.path().join("dist");
let target = fixture.path().join("fixture.js");
write_file(&target, "const projectPath = '';");
fs::create_dir_all(dist.join("assets")).expect("create symlink fixture parent");
symlink(&target, dist.join("assets/linked.js")).expect("create frontend dist symlink");
let error =
validate_frontend_dist(&dist).expect_err("production frontendDist must reject symlinks");
let portable_error = error.replace('\\', "/");
assert!(error.contains("符号链接"));
assert!(portable_error.contains("assets/linked.js"));
assert!(!error.contains(&dist.display().to_string()));
}
#[cfg(windows)]
#[test]
fn frontend_dist_symlink_fails_when_windows_allows_creating_it() {
use std::os::windows::fs::symlink_file;
let fixture = TestDirectory::new("windows-symlink");
let dist = fixture.path().join("dist");
let target = fixture.path().join("fixture.js");
write_file(&target, "const projectPath = '';");
fs::create_dir_all(dist.join("assets")).expect("create symlink fixture parent");
if symlink_file(&target, dist.join("assets/linked.js")).is_err() {
return;
}
let error = validate_frontend_dist(&dist)
.expect_err("production frontendDist must reject Windows symlinks");
let portable_error = error.replace('\\', "/");
assert!(error.contains("符号链接"));
assert!(portable_error.contains("assets/linked.js"));
assert!(!error.contains(&dist.display().to_string()));
}