f7a720204a
- 移除 GovAI, nomifun-tauri, 算力盒子 的 submodule 引用 - 添加所有子项目的完整源代码 - 保留原始 .git 为 .git.bak 备份
117 lines
3.8 KiB
Rust
117 lines
3.8 KiB
Rust
use std::time::{SystemTime, UNIX_EPOCH};
|
|
|
|
use nomifun_cron::skill_file::{
|
|
ParsedSkillContent, build_skill_content, content_hash, cron_skill_dir, cron_skill_file_path, parse_skill_content,
|
|
read_skill_content, validate_skill_content, write_raw_skill_file, write_skill_file,
|
|
};
|
|
|
|
fn unique_temp_dir(label: &str) -> std::path::PathBuf {
|
|
let nanos = SystemTime::now()
|
|
.duration_since(UNIX_EPOCH)
|
|
.unwrap_or_default()
|
|
.as_nanos();
|
|
std::env::temp_dir().join(format!("nomifun-cron-{label}-{}-{nanos}", std::process::id()))
|
|
}
|
|
|
|
#[test]
|
|
fn build_skill_content_matches_frontend_shape() {
|
|
let content = build_skill_content(
|
|
"Daily Report",
|
|
"Line 1\nLine 2\r\nLine 3",
|
|
"Run report",
|
|
Some("Every day at 9am"),
|
|
);
|
|
|
|
assert!(content.contains("name: Daily Report"));
|
|
assert!(content.contains("description: Line 1 Line 2 Line 3"));
|
|
assert!(content.contains("This is a scheduled task: **Daily Report**"));
|
|
assert!(content.contains("Schedule: Every day at 9am"));
|
|
assert!(content.contains("## Instructions"));
|
|
assert!(content.ends_with("Run report"));
|
|
}
|
|
|
|
#[test]
|
|
fn parse_skill_content_roundtrips_built_files() {
|
|
let built = build_skill_content("My Job", "My Description", "First\n\nSecond", None);
|
|
let parsed = parse_skill_content(&built).unwrap();
|
|
assert_eq!(
|
|
parsed,
|
|
ParsedSkillContent {
|
|
name: "My Job".into(),
|
|
description: "My Description".into(),
|
|
body: "First\n\nSecond".into(),
|
|
}
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn parse_skill_content_skips_blank_lines_after_frontmatter() {
|
|
let parsed = parse_skill_content("---\nname: Test\ndescription: Desc\n---\n\n\nPrompt").unwrap();
|
|
assert_eq!(parsed.body, "Prompt");
|
|
}
|
|
|
|
#[test]
|
|
fn parse_skill_content_handles_empty_body() {
|
|
let parsed = parse_skill_content("---\nname: Test\ndescription: Desc\n---\n\n").unwrap();
|
|
assert_eq!(parsed.body, "");
|
|
}
|
|
|
|
#[test]
|
|
fn validate_skill_content_rejects_placeholders() {
|
|
let err =
|
|
validate_skill_content("---\nname: skill-name\ndescription: Real description\n---\n\nReal body").unwrap_err();
|
|
assert!(err.to_string().contains("template placeholder"));
|
|
}
|
|
|
|
#[test]
|
|
fn content_hash_normalizes_line_endings_and_edges() {
|
|
let a = content_hash("---\nname: Test\ndescription: Desc\n---\n\nBody\n");
|
|
let b = content_hash("---\r\nname: Test\r\ndescription: Desc\r\n---\r\n\r\nBody");
|
|
let c = content_hash(" ---\nname: Test\ndescription: Desc\n---\n\nBody ");
|
|
assert_eq!(a, b);
|
|
assert_eq!(a, c);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn write_read_and_resolve_skill_file_paths() {
|
|
let base = unique_temp_dir("write-read");
|
|
std::fs::create_dir_all(&base).unwrap();
|
|
|
|
let file_path = write_skill_file(
|
|
&base,
|
|
"job-123",
|
|
"Daily Report",
|
|
"Generate daily report",
|
|
"Run report",
|
|
Some("Every day at 9am"),
|
|
)
|
|
.await
|
|
.unwrap();
|
|
|
|
assert_eq!(
|
|
cron_skill_dir(&base, "job-123").unwrap(),
|
|
base.join("cron").join("skills").join("cron-job-123")
|
|
);
|
|
assert_eq!(file_path, cron_skill_file_path(&base, "job-123").unwrap());
|
|
|
|
let raw = read_skill_content(&base, "job-123").await.unwrap().unwrap();
|
|
let parsed = parse_skill_content(&raw).unwrap();
|
|
assert_eq!(parsed.name, "Daily Report");
|
|
assert_eq!(parsed.description, "Generate daily report");
|
|
assert_eq!(parsed.body, "Run report");
|
|
|
|
std::fs::remove_dir_all(&base).unwrap();
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn write_raw_skill_file_validates_before_writing() {
|
|
let base = unique_temp_dir("write-raw");
|
|
std::fs::create_dir_all(&base).unwrap();
|
|
|
|
let err = write_raw_skill_file(&base, "job-456", "not valid").await.unwrap_err();
|
|
assert!(err.to_string().contains("skill file must start with YAML frontmatter"));
|
|
assert!(read_skill_content(&base, "job-456").await.unwrap().is_none());
|
|
|
|
std::fs::remove_dir_all(&base).unwrap();
|
|
}
|