openpencil/crates/op-cli/src/cli_conversion_tests.rs

153 lines
4.4 KiB
Rust

use super::*;
use std::path::PathBuf;
fn temp_json(name: &str, contents: &str) -> String {
let path = std::env::temp_dir().join(format!(
"op-cli-conversion-{name}-{}.json",
std::process::id()
));
std::fs::write(&path, contents).expect("write temp json");
path.to_string_lossy().into_owned()
}
fn temp_out_dir(name: &str) -> PathBuf {
let path =
std::env::temp_dir().join(format!("op-cli-skill-export-{name}-{}", std::process::id()));
std::fs::remove_dir_all(&path).ok();
path
}
#[test]
fn design_upsert_vars_maps_to_tool_call() {
let vars = temp_json(
"vars",
r##"{"color/primary":{"type":"color","value":"#3366ff"}}"##,
);
let parsed = parse_args(&[
"design:upsert-vars".into(),
"--key".into(),
"tokens:theme.css".into(),
"--file".into(),
vars.clone(),
"--source".into(),
"src/theme.css".into(),
"--hash".into(),
"h1".into(),
])
.expect("parse design:upsert-vars");
std::fs::remove_file(vars).ok();
match parsed.command {
Command::ToolCall { tool, args } => {
assert_eq!(tool, "upsert_variables");
assert!(args.contains(&("key".into(), "tokens:theme.css".into())));
assert!(args
.iter()
.any(|(key, value)| key == "variables" && value.contains("color/primary")));
assert!(args.contains(&("sourcePath".into(), "src/theme.css".into())));
assert!(args.contains(&("sourceHash".into(), "h1".into())));
}
other => panic!("expected ToolCall, got {other:?}"),
}
}
#[test]
fn design_upsert_component_requires_name() {
let node = temp_json("component", r#"{"type":"frame","id":"button"}"#);
let parsed = parse_args(&[
"design:upsert-component".into(),
"--key".into(),
"src/Button.tsx#Button".into(),
"--file".into(),
node.clone(),
]);
std::fs::remove_file(node).ok();
assert!(parsed.is_err());
}
#[test]
fn design_upsert_screen_maps_payload_file() {
let node = temp_json("screen", r#"{"type":"frame","id":"home"}"#);
let parsed = parse_args(&[
"design:upsert-screen".into(),
"--key".into(),
"route:/".into(),
"--file".into(),
node.clone(),
])
.expect("parse design:upsert-screen");
std::fs::remove_file(node).ok();
assert_eq!(
parsed.command,
Command::ToolCall {
tool: "upsert_screen".into(),
args: vec![
("key".into(), "route:/".into()),
("node_json".into(), r#"{"type":"frame","id":"home"}"#.into()),
],
}
);
}
#[test]
fn design_status_and_lint_map_to_read_tools() {
let status = parse_args(&["design:status".into(), "--kind".into(), "component".into()])
.expect("parse design:status");
assert_eq!(
status.command,
Command::ToolCall {
tool: "conversion_status".into(),
args: vec![("kind".into(), "component".into())],
}
);
let lint = parse_args(&["design:lint".into(), "--node".into(), "n1".into()])
.expect("parse design:lint");
assert_eq!(
lint.command,
Command::ToolCall {
tool: "lint_document".into(),
args: vec![("nodeId".into(), "n1".into())],
}
);
}
#[test]
fn skill_export_maps_to_cli_command() {
let parsed = parse_args(&[
"skill:export".into(),
"code-to-design".into(),
"--out".into(),
".tmp-skills".into(),
])
.expect("parse skill:export");
assert_eq!(
parsed.command,
Command::SkillExport {
name: "code-to-design".into(),
out_dir: Some(".tmp-skills".into()),
}
);
}
#[test]
fn skill_export_writes_claude_skill_md() {
let out_dir = temp_out_dir("code-to-design");
let output = crate::skill_export_cli::run_export(
"code-to-design",
Some(out_dir.to_string_lossy().as_ref()),
)
.expect("export code-to-design skill");
let skill_path = out_dir.join("code-to-design").join("SKILL.md");
let contents = std::fs::read_to_string(&skill_path).expect("read exported skill");
std::fs::remove_dir_all(&out_dir).ok();
assert!(output.contains("SKILL.md"));
assert!(contents.starts_with("---\nname: code-to-design\n"));
assert!(contents.contains("Five-step"));
assert!(contents.contains("upsert_variables"));
}