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

@@ -0,0 +1,166 @@
use super::*;
#[test]
fn text_fields_normalize_writes_without_changing_queries_or_raw_content() {
let directory = Directory::new();
let source = directory.0.join("module/demo/account");
std::fs::create_dir_all(&source).unwrap();
std::fs::write(
source.join("model.dever"),
r#"type Account {
name: Text(1, 8) lower unique
note: Text? upper
body: Text raw
label: Text default " 默认 "
}
"#,
)
.unwrap();
std::fs::write(source.join("app.dever"), r#"create(name: Text, note: Text?, body: Text) (row: model.Account) {
row = model.create({name = name, note = note, body = body})
}
update(id: model.id, name: Text) (row: model.Account) {
row = model.update(id, {name = name})
}
replace(expected: Text, next: Text) (changed: Int) {
changed = model.update({where = name == expected}, {name = next})
}
lookup(name: Text) (row: model.Account?) {
row = model.first({where = name == name})
}
many() (total: Int) {
total = model.createMany([{name = " B ", note = " ß ", body = " b "}, {name = " C ", note = null, body = " c "}])
}
merge(name: Text, body: Text) (row: model.Account) {
row = model.upsert({name = name}, {note = null, body = body}, {body = body})
}
guard(value: Bool) (ok: Bool) {
dever.api.require(value, dever.api.Error.Forbidden)
ok = contains(["a", "b"], "a") and not contains([], "c")
}
decode(value: Json) (items: List<Text>) {
items = dever.json.decode(value)
}
type Entry {
label: Text
values: List<Int>
}
type Envelope {
entries: List<Entry>
optional: Text?
}
decodeRecord(value: Json) (row: Envelope) {
row = dever.json.decode(value)
}
"#).unwrap();
std::fs::write(source.join("api.dever"), "cmd create = app.create\ncmd update = app.update\ncmd replace = app.replace\ncmd lookup = app.lookup\ncmd many = app.many\ncmd merge = app.merge\ncmd guard = app.guard\ncmd decode = app.decode\ncmd decode_record = app.decodeRecord\n").unwrap();
let project = Project::load(&directory.0).unwrap();
let program = project.check().unwrap();
let binary = build::build(
&program,
&project.sources,
"main",
&directory.0.join("text"),
)
.unwrap();
std::fs::create_dir(directory.0.join("config")).unwrap();
std::fs::write(
directory.0.join("config/setting.json"),
r#"{"database":{"default":{"type":"sqlite","path":"text.db"}}}"#,
)
.unwrap();
let run = |name: &str, input: serde_json::Value| {
let output = execute(&binary, &format!("demo.account.{name}"), &input.to_string());
assert!(
output.status.success(),
"{name}: {}",
String::from_utf8_lossy(&output.stderr)
);
serde_json::from_slice::<serde_json::Value>(&output.stdout).unwrap()["data"].clone()
};
let row = run(
"create",
serde_json::json!({"name":"\u{2003}Ä\t", "note":" ß ", "body":" \n code\n "}),
);
assert_eq!(row["name"], "ä");
assert_eq!(row["note"], "SS");
assert_eq!(row["body"], " \n code\n ");
assert_eq!(row["label"], "默认");
assert!(run("lookup", serde_json::json!({"name":" ä "})).is_null());
assert_eq!(run("lookup", serde_json::json!({"name":"ä"})), row);
assert_eq!(
run(
"replace",
serde_json::json!({"expected":" ä ","next":" D "})
),
0
);
assert_eq!(
run("replace", serde_json::json!({"expected":"ä","next":" D "})),
1
);
assert_eq!(
run("update", serde_json::json!({"id":row["id"],"name":" E "}))["name"],
"e"
);
assert_eq!(run("many", serde_json::json!({})), 2);
let merged = run("merge", serde_json::json!({"name":" B ","body":" exact "}));
assert_eq!(merged["name"], "b");
assert_eq!(merged["body"], " exact ");
assert!(run("lookup", serde_json::json!({"name":"c"}))["note"].is_null());
for name in [" ", "ABCDEFGHI", " E "] {
assert!(
!execute(
&binary,
"demo.account.create",
&serde_json::json!({"name":name,"note":null,"body":""}).to_string()
)
.status
.success()
);
}
assert_eq!(run("guard", serde_json::json!({"value":true})), true);
assert_eq!(
run("decode", serde_json::json!({"value":["雪", " x "]})),
serde_json::json!(["雪", " x "])
);
assert!(
!execute(&binary, "demo.account.decode", r#"{"value":[1]}"#)
.status
.success()
);
assert!(
!execute(&binary, "demo.account.guard", r#"{"value":false}"#)
.status
.success()
);
let record = serde_json::json!({"entries":[{"label":" x ","values":[1,2]}],"optional":null});
assert_eq!(
run("decode_record", serde_json::json!({"value":record})),
record
);
for record in [
r#"{"entries":[],"extra":1}"#,
r#"{"entries":[{"label":"x","values":[true]}]}"#,
r#"{"optional":null}"#,
] {
let input = format!("{{\"value\":{record}}}");
assert!(
!execute(&binary, "demo.account.decode_record", &input)
.status
.success(),
"{record}"
);
}
}
#[test]
fn owned_trim_preserves_allocation_and_unicode_boundaries() {
for input in ["", "abc", " ", "\u{2003}雪\t", " a\n b ", "\0 x \0"] {
let value = String::from(input);
let allocation = value.as_ptr();
let trimmed = dever_runtime::value::text::trim_owned(value);
assert_eq!(trimmed, input.trim());
assert_eq!(trimmed.as_ptr(), allocation);
}
}