Files
Unlucky-Launcher/crates/core/tests/launch/prelude.rs
T
AskaEth bc41dfcf7d
CI / fmt (rustfmt --check) (push) Canceled after 0s
CI / clippy (ubuntu-latest) (push) Canceled after 0s
CI / clippy (windows-latest) (push) Canceled after 0s
CI / test (ubuntu-latest) (push) Canceled after 0s
CI / test (windows-latest) (push) Canceled after 0s
CI / build release (ubuntu-latest) (push) Canceled after 0s
CI / build release (windows-latest) (push) Canceled after 0s
Guards / core 零 UI 守门 (push) Canceled after 0s
Guards / 文件行数 ≤400 守门 (push) Canceled after 0s
Guards / 依赖许可与来源(cargo-deny) (push) Canceled after 0s
Unlucky Launcher v0.0.1-alpha
Rust 原生单文件 Minecraft 启动器:CLI 完整可用(install/launch/accounts/java/diagnose/agent),
MCP server 接入外部 Agent 工具,GUI 开发中。
2026-10-31 21:54:10 +08:00

150 lines
6.0 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.
//! 测试共用设施。
//!
//! **crate 名只在本文件出现**(tower 定案 `unlucky_core`;若 M11 改包名,只改这里)。
use std::path::PathBuf;
pub use unlucky_core::launch::args_table::{assemble, AssembledCommand, AssemblyWarning};
pub use unlucky_core::launch::argument::{ArgumentEntry, Rule};
pub use unlucky_core::launch::command_builder::{self, CommandBuilder};
pub use unlucky_core::launch::error::{AssemblyError, LaunchError, MissingComponent};
pub use unlucky_core::launch::exit_analysis::{self, ExitType};
pub use unlucky_core::launch::game_version::GameVersion;
pub use unlucky_core::launch::log_level::{self, Level};
pub use unlucky_core::launch::platform::{OsFamily, PlatformCtx};
pub use unlucky_core::launch::pump::{LineSink, LogLine, RingBuffer, RingBufferConfig, Stream};
pub use unlucky_core::launch::redact::{Redactor, TOKEN_PLACEHOLDER};
pub use unlucky_core::launch::request::*;
pub use unlucky_core::launch::session::{EndReason, SessionMeta, SessionSink, SessionWriter};
pub use unlucky_core::launch::session_index;
pub use unlucky_core::launch::window_detect::WindowDetector;
pub use unlucky_core::launch::adapter::{
build_request, AdapterOptions, AdapterWarning, LibraryInput, SnapshotInput,
};
pub use unlucky_core::launch::crash_scan::CrashSource;
pub use unlucky_core::launch::diagnosis_hook::{DiagnosisHook, DiagnosisRequest};
pub use unlucky_core::launch::launch_session::SessionHandle;
pub use unlucky_core::launch::launcher::{DryRun, Launcher, LauncherConfig};
pub use unlucky_core::launch::process::ProcessConfig;
pub use unlucky_core::launch::sink::{CompositeSink, CountingSink, FnSink};
/// 断言 argv 逐项相等,失败时打印全部实际值。
pub fn assert_argv(command: &AssembledCommand, expected: &[&str]) {
let actual = command.argv();
if actual.len() != expected.len() {
panic!(
"argv 长度 {} != 期望 {}\n实际:\n{:#?}",
actual.len(),
expected.len(),
actual
);
}
for (index, (actual, expected)) in actual.iter().zip(expected.iter()).enumerate() {
assert_eq!(actual, expected, "第 {index} 个参数不同");
}
}
/// 一个“1.12.2 + Forge”的基准请求(Windows/x86_64)。
pub fn legacy_forge_request() -> (LaunchRequest, PlatformCtx) {
let ctx = PlatformCtx::new(OsFamily::Windows, "x86_64");
let request = LaunchRequest {
instance: InstanceInfo {
id: "inst-1".to_string(),
name: "1.12.2-Forge".to_string(),
version: GameVersion::parse("1.12.2"),
version_type: "release".to_string(),
},
launcher: LauncherInfo {
name: "UnluckyLauncher".to_string(),
version: "0.1.0".to_string(),
},
java: JavaSelection::new("C:/java/bin/java.exe", 17, 64),
memory: MemoryOptions {
min_mb: Some(1024),
max_mb: Some(4096),
},
manifest: ManifestArgs {
main_class: Some("net.minecraft.launchwrapper.Launch".to_string()),
..ManifestArgs::default()
},
dirs: LaunchDirs {
game_dir: PathBuf::from("C:/mc"),
assets_root: PathBuf::from("C:/mc/assets"),
game_assets: PathBuf::from("C:/mc/assets/virtual/legacy"),
assets_index: "1.12".to_string(),
natives_dir: PathBuf::from("C:/mc/versions/1.12.2/natives-windows-x86_64"),
library_dir: PathBuf::from("C:/mc/libraries"),
primary_jar: PathBuf::from("C:/mc/versions/1.12.2/1.12.2.jar"),
},
classpath: vec![
PathBuf::from("C:/mc/libraries/a.jar"),
PathBuf::from("C:/mc/libraries/b.jar"),
],
auth: AuthPlaceholders {
player_name: "Steve".to_string(),
uuid: "0123456789abcdef0123456789abcdef".to_string(),
access_token: "SECRET-TOKEN-123456".to_string(),
user_type: "msa".to_string(),
user_properties: "{}".to_string(),
},
log4j: Log4jOptions {
enabled: true,
config_file: Some(PathBuf::from("C:/mc/log4j2.xml")),
debug: false,
},
// 大部分断言只关心“命令骨架”,优化参数会淹没差异;需要时单独打开。
optimization: OptimizationOptions {
enabled: false,
physical_memory_mb: None,
},
language: "zh-CN".to_string(),
features: FeatureSet {
has_custom_resolution: true,
..FeatureSet::default()
},
resolution: Some(Resolution {
width: 854,
height: 480,
}),
..LaunchRequest::default()
};
(request, ctx)
}
/// 一个唯一的临时目录(不自动清理,便于失败时排查;OS 会回收)。
pub fn temp_dir(name: &str) -> PathBuf {
let nanos = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.map(|value| value.as_nanos())
.unwrap_or_default();
let dir =
std::env::temp_dir().join(format!("ull-launch-{name}-{}-{nanos}", std::process::id()));
let _ = std::fs::remove_dir_all(&dir);
std::fs::create_dir_all(&dir).expect("创建临时目录");
dir
}
/// 一个唯一的临时会话根目录(测试结束不自动清理,便于失败时排查;OS 会回收)。
pub fn temp_sessions_root(name: &str) -> PathBuf {
let nanos = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.map(|value| value.as_nanos())
.unwrap_or_default();
let root = std::env::temp_dir().join(format!(
"ull-launch-test-{name}-{}-{nanos}",
std::process::id()
));
let _ = std::fs::remove_dir_all(&root);
root
}
/// 读回 jsonl 的每一行并解析成 JSON。
pub fn read_events(path: &std::path::Path) -> Vec<serde_json::Value> {
let text = std::fs::read_to_string(path).expect("读取会话文件");
text.lines()
.filter(|line| !line.trim().is_empty())
.map(|line| serde_json::from_str(line).expect("解析事件行"))
.collect()
}