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

+149
View File
@@ -0,0 +1,149 @@
use dever::compiler::format;
use dever::syntax::source::Source;
use std::path::PathBuf;
#[test]
fn format_keeps_literals_comments_groups_and_field_order() {
let text = "# leading\nmain( ) (answer: Int) {\n answer=(1+2)*3 # same line\n}\n";
let source = Source::new(0, "case.dever", text.into());
let output = format::format(&source).unwrap();
assert_eq!(
output,
"# leading\nmain() (answer: Int) {\n answer = (1 + 2) * 3 # same line\n}\n"
);
assert_eq!(
format::format(&Source::new(0, "case.dever", output.clone())).unwrap(),
output
);
let literals = Source::new(
0,
"case.dever",
"main() (answer: Text) { answer=\"# \\u{41} \\\"\" }\n".into(),
);
assert!(
format::format(&literals)
.unwrap()
.contains("\"# \\u{41} \\\"\"")
);
let fields = Source::new(
0,
"case.dever",
"main() (answer: Item) { answer=Item { second=2, first=1 } }\n".into(),
);
assert!(
format::format(&fields)
.unwrap()
.contains("second = 2, first = 1")
);
}
#[test]
fn format_preserves_crlf() {
let text = "main( ) (answer: Int) {\r\n answer=1\r\n}\r\n";
let output = format::format(&Source::new(0, "case.dever", text.into())).unwrap();
assert_eq!(
output,
text.replace("main( )", "main()")
.replace(" answer=1", " answer = 1")
);
}
#[test]
fn format_preserves_local_type_annotations() {
let source = Source::new(
0,
"case.dever",
"main() () { value:List<Int?>=[null,1] }".into(),
);
let formatted = format::format(&source).unwrap();
assert!(
formatted.contains("value: List<Int?> = [null, 1]"),
"{formatted}"
);
assert_eq!(
format::format(&Source::new(0, "case.dever", formatted.clone())).unwrap(),
formatted
);
}
#[test]
fn format_preserves_text_policy_and_camel_functions() {
let input = "type Category { name: Text(1,80)\ncode: Text lower unique\nbody: Text raw\nnote: Text? upper }\nreadName(input_value: Text) (output_value: Text) { output_value = input_value }";
let output = format::format(&Source::new(0, "model.dever", input.into())).unwrap();
for preserved in [
"code: Text lower unique",
"body: Text raw",
"note: Text? upper",
"readName(input_value: Text)",
] {
assert!(output.contains(preserved), "{output}");
}
assert_eq!(
format::format(&Source::new(0, "model.dever", output.clone())).unwrap(),
output
);
}
struct Directory(PathBuf);
impl Directory {
fn new() -> Self {
let path = std::env::temp_dir().join(format!(
"dever-format-{}-{}",
std::process::id(),
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_nanos()
));
std::fs::create_dir(&path).unwrap();
Self(path)
}
}
impl Drop for Directory {
fn drop(&mut self) {
let _ = std::fs::remove_dir_all(&self.0);
}
}
#[test]
fn project_prepares_module_and_tests_before_any_rewrite() {
let directory = Directory::new();
std::fs::create_dir(directory.0.join("module")).unwrap();
std::fs::create_dir(directory.0.join("test")).unwrap();
let module = directory.0.join("module/main.dever");
let test = directory.0.join("test/main.dever");
let input = "main( ) () {}\n";
std::fs::write(&module, input).unwrap();
std::fs::write(&test, "main( {").unwrap();
assert!(format::project(&directory.0, false).is_err());
assert_eq!(std::fs::read_to_string(&module).unwrap(), input);
std::fs::write(&test, input).unwrap();
let report = format::project(&directory.0, true).unwrap();
assert_eq!(report.checked, 2);
assert_eq!(report.changed.len(), 2);
assert_eq!(std::fs::read_to_string(&module).unwrap(), input);
format::project(&directory.0, false).unwrap();
assert!(
format::project(&directory.0, true)
.unwrap()
.changed
.is_empty()
);
}
#[test]
#[cfg(unix)]
fn project_rejects_links_without_touching_their_target() {
let directory = Directory::new();
let target = directory.0.join("actual.dever");
std::fs::write(&target, "main( ) () {}\n").unwrap();
std::os::unix::fs::symlink(&target, directory.0.join("link.dever")).unwrap();
assert!(
format::project(&directory.0, false)
.unwrap_err()
.contains("links")
);
assert_eq!(std::fs::read_to_string(target).unwrap(), "main( ) () {}\n");
}