167 lines
5.5 KiB
Rust
167 lines
5.5 KiB
Rust
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);
|
|
}
|
|
}
|