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

+243
View File
@@ -0,0 +1,243 @@
use super::{Directory, fixture};
use dever::compiler::{build, emit, project::Project};
use std::path::Path;
fn document() -> String {
"verify() (answer: Bool) { answer = true }
"
.into()
}
fn write(root: &Path, name: &str, contents: impl AsRef<[u8]>) {
let path = root.join(name);
std::fs::create_dir_all(path.parent().unwrap()).unwrap();
std::fs::write(path, contents).unwrap();
}
fn load_error(path: &Path, needle: &str) {
let error = Project::load(path).err().expect("invalid source accepted");
assert!(error.contains(needle), "{error}");
}
#[test]
fn entry_reachability_excludes_unused_task_code_but_keeps_checks() {
for (sample, entry, features) in [
("core.dever", "verify", vec![]),
("handler.dever", "verify", vec![]),
("task.dever", "verify", vec!["task"]),
("task.dever", "yes", vec![]),
] {
let project = Project::load(&fixture().with_file_name(sample)).unwrap();
let program = project.check().unwrap();
let root = program
.functions
.iter()
.position(|function| function.signature.source == 0 && function.signature.name == entry)
.unwrap();
let functions = program.reachable([root]);
assert!(functions.contains(&root));
assert!(functions.len() < program.functions.len());
assert_eq!(
build::runtime_features(&program, &functions),
features,
"{sample}/{entry}"
);
let source = emit::generate(&program, &project.sources, &functions);
if features.is_empty() {
assert!(
!source.contains("dever_runtime::task::"),
"{sample}/{entry}"
);
}
for index in 0..program.functions.len() {
if !functions.contains(&index) {
assert!(
!source.contains(&format!("fn function{index}(")),
"{sample}/{entry}: {index}"
);
assert!(
!source.contains(&format!("as function{index};")),
"{sample}/{entry}: {index}"
);
assert!(
!source.contains(&format!("enum Failure{index} {{")),
"{sample}/{entry}: {index}"
);
}
}
}
let mut project = Project::load(&fixture()).unwrap();
let source = &project.sources[0];
let text = format!(
"{}\nunused() (answer: Int) {{ answer = true }}\n",
source.text
);
project.sources[0] = dever::syntax::source::Source::new(source.id, source.path.clone(), text);
assert!(project.check().unwrap_err().contains("C005"));
}
#[test]
fn packages_execute_with_original_cross_file_failure_locations() {
let directory = Directory::new();
let path = fixture().with_file_name("package");
let project = Project::load(&path).unwrap();
let program = project.check().unwrap();
assert_eq!(
&program.packages[..3],
&["calc.batch", "calc.value", "main"]
);
let second = Project::load(&path).unwrap();
assert_eq!(
emit::generate(
&program,
&project.sources,
&(0..program.functions.len()).collect()
),
emit::generate(
&second.check().unwrap(),
&second.sources,
&(0..program.functions.len()).collect()
)
);
for (entry, expected) in [
("verify", None),
("calc.batch.verify", None),
(
"failureEntry",
Some(("Problem.Rejected", "Problem.Rejected(\"negative\")")),
),
(
"faultEntry",
Some(("integer arithmetic fault", "value + 1")),
),
] {
let binary =
build::build(&program, &project.sources, entry, &directory.0.join(entry)).unwrap();
let result = std::process::Command::new(binary).output().unwrap();
if let Some((message, needle)) = expected {
assert!(!result.status.success());
assert!(result.stdout.is_empty());
let stderr = String::from_utf8(result.stderr).unwrap();
let source = project
.sources
.iter()
.find(|source| source.path.ends_with("calc/value.dever"))
.unwrap();
let (line, column) = source.position(source.text.find(needle).unwrap());
assert!(stderr.contains(message), "{stderr}");
assert!(
stderr.contains(&format!("{}:{line}:{column}:", source.path.display())),
"{stderr}"
);
} else {
assert!(
result.status.success(),
"{}",
String::from_utf8_lossy(&result.stderr)
);
assert_eq!(result.stdout, b"true\n");
}
}
assert!(
build::build(
&program,
&project.sources,
"calc.missing",
&directory.0.join("missing")
)
.is_err()
);
assert!(!directory.0.join("missing").exists());
}
#[test]
fn private_records_preserve_cross_package_value_semantics() {
let directory = Directory::new();
let project = Project::load(&fixture().with_file_name("private")).unwrap();
let program = project.check().unwrap();
let binary = build::build(
&program,
&project.sources,
"verify",
&directory.0.join("private"),
)
.unwrap();
let result = std::process::Command::new(binary).output().unwrap();
assert!(
result.status.success(),
"{}",
String::from_utf8_lossy(&result.stderr)
);
assert_eq!(result.stdout, b"true\n");
}
#[test]
fn package_paths_are_authoritative_and_discovery_is_stable() {
let directory = Directory::new();
write(&directory.0, "zeta/value.dever", document());
write(&directory.0, "alpha.dever", document());
write(&directory.0, "README.md", "not code");
write(&directory.0, ".hidden/invalid.dever", "not code");
let project = Project::load(&directory.0).unwrap();
let program = project.check().unwrap();
assert_eq!(&program.packages[..2], &["alpha", "zeta.value"]);
assert_eq!(
program.packages,
Project::load(&directory.0)
.unwrap()
.check()
.unwrap()
.packages
);
write(
&directory.0,
"zeta/value.dever",
document().replace("answer = true", "answer = 1"),
);
let error = Project::load(&directory.0).unwrap().check().unwrap_err();
assert!(
error.contains("zeta/value.dever:") && error.contains("C005"),
"{error}"
);
}
#[test]
fn package_loader_rejects_collisions_names_and_invalid_sources() {
for (name, needle) in [
("Wrong.dever", "lower_snake_case"),
("user..bad.dever", "lower_snake_case"),
("dever/custom.dever", "reserved standard"),
("shop/account/app.dever", "application role"),
] {
let directory = Directory::new();
write(&directory.0, name, document());
load_error(&directory.0, needle);
}
let directory = Directory::new();
load_error(&directory.0, "no Dever sources");
write(&directory.0, "sample.dever", document());
write(&directory.0, "sample.dever.md", "verify() () {}");
load_error(&directory.0, "use .dever source");
let directory = Directory::new();
write(&directory.0, "bad.dever", [0xff]);
load_error(&directory.0, "bad.dever");
let directory = Directory::new();
write(&directory.0, "module/shop/account/app.dever", document());
let error = Project::load(&directory.0).unwrap().check().unwrap_err();
assert!(
error.contains("application has no supported API/CMD entry"),
"{error}"
);
}
#[test]
fn package_loader_does_not_follow_source_links() {
let directory = Directory::new();
write(&directory.0, "sources/value.dever", document());
let source = directory.0.join("sources");
std::os::unix::fs::symlink(source.join("value.dever"), source.join("alias.dever")).unwrap();
load_error(&source, "source links");
load_error(&source.join("alias.dever"), "source links");
std::os::unix::fs::symlink(&source, directory.0.join("linked")).unwrap();
load_error(&directory.0.join("linked/value.dever"), "source links");
}