feat: unify source and skills for Dever 0.1.2 installation

This commit is contained in:
Antigravity committed 2026-10-05 02:49:17 +00:00
1 parent a2e0436ed4
commit 19f122b4b4
47 files changed
+1951 -63

No files matched your search

+187
View File
@@ -116,6 +116,193 @@ fn missing_pack_fails_without_host_tools_and_check_and_empty_test_need_no_pack()
assert!(!toolchain.path().join("cache").exists());
}
#[test]
fn application_check_rejects_redundancy_before_preparing_build_resources() {
let toolchain = TemporaryDirectory::new();
let compiler = compiler(toolchain.path(), "dever");
let project_dir = TemporaryDirectory::new();
let root = project_dir.path();
write(root, "config/setting.json", "{}");
write(
root,
"module/sample/profile/domain.dever",
"normalize(value: Text) (result: Text) pure { result = text.trim(value) }\nalias(value: Text) (result: Text) pure { result = normalize(value) }\norphan() (result: Text) pure { result = \"unused\" }",
);
write(
root,
"module/sample/profile/app.dever",
"greet(value: Text) (result: Text) { result = domain.alias(value) }\nunused() (result: Text) { result = \"unused\" }",
);
write(
root,
"module/sample/profile/api.dever",
"cmd greet = app.greet",
);
let checked = cli(&compiler, root, "check", &[]);
failure(&checked, "C016");
let diagnostic = String::from_utf8_lossy(&checked.stderr);
for expected in [
"sample/profile/app.dever:2:1: error[C016]",
"function 'sample.profile.unused' is unreachable",
"sample/profile/domain.dever:2:1: error[C016]",
"only forwards unchanged inputs",
"sample/profile/domain.dever:3:1: error[C016]",
"function 'sample.profile.domain.orphan' is unreachable",
] {
assert!(diagnostic.contains(expected), "{expected}: {diagnostic}");
}
// The same source fails before native packs, output publication or execution.
let executable = root.join("must-not-build");
for (action, args) in [
("run", Vec::new()),
("build", vec!["--output", executable.to_str().unwrap()]),
] {
let rejected = cli(&compiler, root, action, &args);
assert!(!rejected.status.success());
assert_eq!(rejected.stderr, checked.stderr);
}
assert!(!executable.exists());
assert!(!root.join("data").exists());
assert!(!toolchain.path().join("cache").exists());
}
#[test]
fn application_check_rejects_plain_model_get_wrapper_without_opening_database() {
let toolchain = TemporaryDirectory::new();
let compiler = compiler(toolchain.path(), "dever");
let project_dir = TemporaryDirectory::new();
let root = project_dir.path();
write(root, "config/setting.json", "{}");
write(
root,
"module/sample/profile/model.dever",
"type Profile { name: Text }",
);
write(
root,
"module/sample/profile/app.dever",
"lookup(id: model.id) (profile: model.Profile) { profile = model.get(id) }",
);
write(
root,
"module/sample/profile/api.dever",
"cmd lookup = app.lookup",
);
let rejected = cli(&compiler, root, "check", &[]);
failure(&rejected, "C016");
let diagnostic = String::from_utf8_lossy(&rejected.stderr);
for expected in [
"sample/profile/app.dever:1:1: error[C016]",
"only forwards a Model CRUD operation; declare rest for plain CRUD",
] {
assert!(diagnostic.contains(expected), "{expected}: {diagnostic}");
}
assert!(!root.join("data").exists());
assert!(!toolchain.path().join("cache").exists());
}
#[test]
fn application_check_accepts_both_templates_and_preserves_markdown_locations() {
let toolchain = TemporaryDirectory::new();
let compiler = compiler(toolchain.path(), "dever");
let workspace = TemporaryDirectory::new();
for markdown in [false, true] {
let root = workspace
.path()
.join(if markdown { "markdown" } else { "plain" });
dever_cli::project::create(&root, markdown).unwrap();
success(&cli(&compiler, &root, "check", &[]));
// Removing the production declaration must not make the test a production root.
let suffix = if markdown { "dever.md" } else { "dever" };
fs::remove_file(root.join(format!("module/hello/greeting/api.{suffix}"))).unwrap();
let rejected = cli(&compiler, &root, "check", &[]);
failure(&rejected, "C016");
failure(
&rejected,
"unreachable from API, CMD, or Job production entries",
);
let app = root.join(format!("module/hello/greeting/app.{suffix}"));
let source = fs::read_to_string(&app).unwrap();
let line = source
.lines()
.position(|line| line.starts_with("greet("))
.unwrap()
+ 1;
failure(&rejected, &format!("hello/greeting/app.{suffix}:{line}:1"));
assert!(!root.join("data").exists());
}
assert!(!toolchain.path().join("cache").exists());
}
#[test]
fn application_check_needs_no_database_worker_or_runtime_pack() {
let toolchain = TemporaryDirectory::new();
let compiler = compiler(toolchain.path(), "dever");
let project_dir = TemporaryDirectory::new();
let root = project_dir.path();
write(root, "config/setting.json", "{}");
write(
root,
"module/sample/profile/model.dever",
"type Profile { name: Text }",
);
// A model-only project has no App/Domain code to reject, even without entries.
success(&cli(&compiler, root, "check", &[]));
write(
root,
"module/notification/mail/app.dever",
"read() (value: Int) { value = port.read() }",
);
write(
root,
"module/notification/mail/port.dever",
"read() (value: Int) fails dever.time.SleepResult",
);
write(
root,
"module/notification/mail/adapter.dever",
"external exec \"worker/must-not-start\" {}",
);
write(
root,
"module/notification/mail/api.dever",
"cmd read = app.read",
);
success(&cli(&compiler, root, "check", &[]));
assert!(!root.join("data").exists());
assert!(!root.join("dever.lock").exists());
assert!(!toolchain.path().join("cache").exists());
}
#[test]
fn application_check_does_not_apply_production_reachability_to_tests() {
let toolchain = TemporaryDirectory::new();
let compiler = compiler(toolchain.path(), "dever");
let project_dir = TemporaryDirectory::new();
let root = project_dir.path();
write(
root,
"module/sample/profile/app.dever",
"greet() (value: Text) { value = \"hello\" }",
);
write(root, "config/setting.json", "{}");
failure(&cli(&compiler, root, "check", &[]), "C016");
let empty = cli(&compiler, root, "test", &[]);
success(&empty);
assert!(String::from_utf8_lossy(&empty.stdout).contains("0 passed; 0 failed"));
write(
root,
"test/sample/profile/greeting.dever",
"greeting() () { assert_eq(app.greet(), \"hello\") }",
);
// The real case reaches the test compiler's missing-pack boundary, not C016.
let tests = cli(&compiler, root, "test", &[]);
failure(&tests, "runtime pack");
assert!(!String::from_utf8_lossy(&tests.stderr).contains("C016"));
assert!(!String::from_utf8_lossy(&tests.stdout).contains("C016"));
assert!(!toolchain.path().join("cache").exists());
}
#[test]
fn cross_build_requires_the_selected_pack_even_when_host_pack_exists() {
let root = TemporaryDirectory::new();