Initial Dever 0.0.1

This commit is contained in:
Codex committed 2026-11-03 03:32:07 +00:00
commit 81233d098c
1479 files changed
+163782

No files matched your search

+182
View File
@@ -0,0 +1,182 @@
use super::{Directory, fixture};
use dever::compiler::{build, project::Project};
use std::{path::Path, process::Command};
fn execute(binary: &Path, name: &str, input: serde_json::Value) -> std::process::Output {
Command::new(binary)
.args([format!("demo.value.{name}"), input.to_string()])
.output()
.unwrap()
}
#[test]
fn native_adapter_selection_settings_and_tasks_share_one_binary() {
let directory = Directory::new();
let source = fixture().with_file_name("adapters");
let project = Project::load(&source).unwrap();
let program = project.check().unwrap();
let binary =
build::build(&program, &project.sources, "main", &directory.0.join("app")).unwrap();
let original = std::fs::read(&binary).unwrap();
let config = directory.0.join("config");
std::fs::create_dir(&config).unwrap();
let path = config.join("setting.json");
let local = serde_json::json!({"adapter":{"demo.value":{"use":"local","setting":{"offset":1,"prefix":"local:","token":"key"}}}});
let remote = serde_json::json!({"adapter":{"demo.value":{"use":"remote"}}});
for (setting, number, prefix, sign) in
[(&local, 42, "local:", 247), (&remote, 141, "remote:", 82)]
{
std::fs::write(&path, setting.to_string()).unwrap();
for name in [
"calculate",
"worker",
"nested",
"mapped",
"parallel",
"scheduled",
"cancelled",
] {
let result = execute(&binary, name, serde_json::json!({"value":41}));
assert!(
result.status.success(),
"{name}: {}",
String::from_utf8_lossy(&result.stderr)
);
let actual: serde_json::Value = serde_json::from_slice(&result.stdout).unwrap();
assert_eq!(
actual["data"],
if name == "mapped" { number * 2 } else { number }
);
}
for (name, value, expected) in [
("echo", "雪", serde_json::json!(format!("{prefix}雪"))),
(
"sign",
"The quick brown fox jumps over the lazy dog",
serde_json::json!(sign),
),
] {
let result = execute(&binary, name, serde_json::json!({"value":value}));
assert!(
result.status.success(),
"{name}: {}",
String::from_utf8_lossy(&result.stderr)
);
let actual: serde_json::Value = serde_json::from_slice(&result.stdout).unwrap();
assert_eq!(actual["data"], expected);
}
}
for name in ["parallel", "scheduled"] {
let result = execute(&binary, name, serde_json::json!({"value":-1}));
assert!(!result.status.success());
assert!(result.stdout.is_empty());
let error = String::from_utf8_lossy(&result.stderr);
assert!(
error.contains("Problem.Missing") && error.contains("remote.dever:"),
"{error}"
);
}
for setting in [
"{}",
"null",
"[]",
"{",
r#"{"adapter":{"demo.value":{"use":"absent"}}}"#,
r#"{"adapter":{"demo.value":{"use":"local"}}}"#,
r#"{"adapter":{"demo.value":{"use":"local","setting":{"offset":"fixture-only-secret","prefix":"x","token":"x"}}}}"#,
r#"{"adapter":{"demo.value":{"use":"local","setting":[1,"x","fixture-only-secret"]}}}"#,
r#"{"adapter":{"demo.value":{"use":"remote","setting":{"token":"fixture-only-secret"}}}}"#,
r#"{"adapter":{"demo.value":{"use":"local","setting":{"offset":1,"prefix":"x","token":"x","token":"fixture-only-secret"}}}}"#,
] {
std::fs::write(&path, setting).unwrap();
let result = execute(&binary, "calculate", serde_json::json!({"value":41}));
assert!(!result.status.success(), "{setting}");
assert!(result.stdout.is_empty());
let error = String::from_utf8_lossy(&result.stderr);
assert!(
error.contains("Adapter") && !error.contains("fixture-only-secret"),
"{error}"
);
}
// 同一产物迁移到新目录;配置路径属于部署,不进入编译缓存或二进制。
let relocated = directory.0.join("relocated");
std::fs::create_dir(&relocated).unwrap();
let copy = relocated.join("app");
std::fs::copy(&binary, &copy).unwrap();
std::fs::write(&path, local.to_string()).unwrap();
let result = Command::new(&copy)
.arg("--config")
.arg(&path)
.args(["demo.value.calculate", r#"{"value":41}"#])
.output()
.unwrap();
assert!(
result.status.success(),
"{}",
String::from_utf8_lossy(&result.stderr)
);
assert_eq!(
serde_json::from_slice::<serde_json::Value>(&result.stdout).unwrap()["data"],
42
);
assert_eq!(std::fs::read(&binary).unwrap(), original);
// run 使用项目配置;只复制此测试源码到自有临时目录。
let project_root = directory.0.join("project");
let module = project_root.join("module/demo/value");
std::fs::create_dir_all(module.join("adapter")).unwrap();
for relative in [
"app.dever",
"port.dever",
"api.dever",
"adapter/local.dever",
"adapter/remote.dever",
] {
std::fs::copy(
source.join("module/demo/value").join(relative),
module.join(relative),
)
.unwrap();
}
std::fs::create_dir(project_root.join("config")).unwrap();
std::fs::write(project_root.join("config/setting.json"), local.to_string()).unwrap();
let result = Command::new(env!("CARGO_BIN_EXE_dever"))
.arg("run")
.arg(&project_root)
.args(["--", "demo.value.calculate", r#"{"value":41}"#])
.output()
.unwrap();
assert!(
result.status.success(),
"{}",
String::from_utf8_lossy(&result.stderr)
);
assert_eq!(
serde_json::from_slice::<serde_json::Value>(&result.stdout).unwrap()["data"],
42
);
// 单实现省略 use,只保留字段输入;无需多实现选择分支。
let local_source = std::fs::read_to_string(module.join("adapter/local.dever")).unwrap();
std::fs::write(
module.join("adapter.dever"),
local_source.replace("demo.value.adapter.local", "demo.value.adapter"),
)
.unwrap();
std::fs::remove_dir_all(module.join("adapter")).unwrap();
std::fs::write(project_root.join("config/setting.json"), serde_json::json!({"adapter":{"demo.value":{"setting":{"offset":2,"prefix":"one:","token":"key"}}}}).to_string()).unwrap();
let result = Command::new(env!("CARGO_BIN_EXE_dever"))
.arg("run")
.arg(&project_root)
.args(["--", "demo.value.worker", r#"{"value":41}"#])
.output()
.unwrap();
assert!(
result.status.success(),
"{}",
String::from_utf8_lossy(&result.stderr)
);
assert_eq!(
serde_json::from_slice::<serde_json::Value>(&result.stdout).unwrap()["data"],
43
);
}