Initial Dever 0.0.1
This commit is contained in:
commit
81233d098c
1479 files changed
+163782
No files matched your search
@@ -0,0 +1,194 @@
|
||||
use super::{APP, PORT, packages, signature};
|
||||
|
||||
#[test]
|
||||
fn external_worker_secrets_belong_only_in_settings() {
|
||||
let adapter = "setting { token: Secret }\nexternal exec \"worker\" {}";
|
||||
for kind in [
|
||||
"Text",
|
||||
"Secret",
|
||||
"Secret?",
|
||||
"List<Secret>",
|
||||
"app.Credentials",
|
||||
] {
|
||||
let app = format!(
|
||||
"type Problem {{ error Failed(message: Text) }}\ntype Credentials {{ tokens: List<Secret?> }}\nread(value: {kind}) (answer: Int) {{ answer = port.read(value) }}"
|
||||
);
|
||||
let port = format!("read(value: {kind}) (answer: Int) fails app.Problem");
|
||||
let result = packages(&[
|
||||
("shop.account.app", &app),
|
||||
("shop.account.port", &port),
|
||||
("shop.account.adapter", adapter),
|
||||
]);
|
||||
if kind == "Text" {
|
||||
assert!(result.is_ok(), "{result:?}");
|
||||
} else {
|
||||
let error = result.unwrap_err();
|
||||
assert!(
|
||||
error.message.contains("Secret belongs only in setting"),
|
||||
"{kind}: {error:?}"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn settings_are_private_readonly_typed_values() {
|
||||
let adapter = "setting { offset: Int\ntoken: Secret }\nport.read(value: Int) (answer: Int) { answer = helper(value) }\nhelper(value: Int) (answer: Int) pure { answer = value + setting.offset }";
|
||||
let program = packages(&[
|
||||
("shop.account.app", APP),
|
||||
("shop.account.port", PORT),
|
||||
("shop.account.adapter", adapter),
|
||||
])
|
||||
.unwrap();
|
||||
assert!(signature(&program, "read").effects.configuration);
|
||||
assert!(signature(&program, "helper").pure);
|
||||
assert_eq!(signature(&program, "read").failures.len(), 2);
|
||||
for body in [
|
||||
"setting.offset = value\nanswer = value",
|
||||
"setting = value\nanswer = value",
|
||||
"answer = setting.missing",
|
||||
"answer = setting.offset()",
|
||||
"answer = setting.token",
|
||||
] {
|
||||
let bad = format!(
|
||||
"setting {{ offset: Int\ntoken: Secret }}\nport.read(value: Int) (answer: Int) {{ {body} }}"
|
||||
);
|
||||
assert!(
|
||||
packages(&[
|
||||
("shop.account.app", APP),
|
||||
("shop.account.port", PORT),
|
||||
("shop.account.adapter", &bad)
|
||||
])
|
||||
.is_err(),
|
||||
"{body}"
|
||||
);
|
||||
}
|
||||
let empty =
|
||||
"setting {}\nport.read(value: Int) (answer: Int) { setting = value\nanswer = value }";
|
||||
assert!(
|
||||
packages(&[
|
||||
("shop.account.app", APP),
|
||||
("shop.account.port", PORT),
|
||||
("shop.account.adapter", empty)
|
||||
])
|
||||
.is_err()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn settings_reject_wrong_roles_invalid_wire_fields_and_shadowing() {
|
||||
for owner in [
|
||||
"main",
|
||||
"shop.account.app",
|
||||
"shop.account.port",
|
||||
"shop.account.domain",
|
||||
] {
|
||||
assert!(
|
||||
packages(&[(owner, "setting { offset: Int }")]).is_err(),
|
||||
"{owner}"
|
||||
);
|
||||
}
|
||||
for setting in [
|
||||
"setting { Ready }",
|
||||
"setting { private offset: Int }",
|
||||
"setting { offset: Int > 0 }",
|
||||
"setting { file: dever.system.File }",
|
||||
"setting { values: Map<Text, Secret> }",
|
||||
"setting { offset: Int }\nsetting { token: Secret }",
|
||||
"setting { missing: Unknown }",
|
||||
] {
|
||||
let adapter =
|
||||
format!("{setting}\nport.read(value: Int) (answer: Int) {{ answer = value }}");
|
||||
assert!(
|
||||
packages(&[
|
||||
("shop.account.app", APP),
|
||||
("shop.account.port", PORT),
|
||||
("shop.account.adapter", &adapter)
|
||||
])
|
||||
.is_err(),
|
||||
"{setting}"
|
||||
);
|
||||
}
|
||||
for helper in [
|
||||
"helper(setting: Int) () {}",
|
||||
"helper() (setting: Int) { setting = 1 }",
|
||||
] {
|
||||
let adapter = format!(
|
||||
"setting {{ offset: Int }}\nport.read(value: Int) (answer: Int) {{ answer = value }}\n{helper}"
|
||||
);
|
||||
assert!(
|
||||
packages(&[
|
||||
("shop.account.app", APP),
|
||||
("shop.account.port", PORT),
|
||||
("shop.account.adapter", &adapter)
|
||||
])
|
||||
.is_err()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unused_adapter_candidates_still_enforce_failures_and_complete_contracts() {
|
||||
let valid = "port.read(value: Int) (answer: Int) { answer = value }";
|
||||
let invalid = "type Private { error Failed }\nport.read(value: Int) (answer: Int) { fail(Private.Failed()) }";
|
||||
assert_eq!(
|
||||
packages(&[
|
||||
("shop.account.app", APP),
|
||||
("shop.account.port", PORT),
|
||||
("shop.account.adapter.local", valid),
|
||||
("shop.account.adapter.remote", invalid)
|
||||
])
|
||||
.unwrap_err()
|
||||
.code,
|
||||
"C012"
|
||||
);
|
||||
let extra_port = format!("{PORT}\nwrite(value: Int) () fails app.Problem");
|
||||
let complete = format!("{valid}\nport.write(value: Int) () {{}}");
|
||||
assert!(
|
||||
packages(&[
|
||||
("shop.account.app", APP),
|
||||
("shop.account.port", &extra_port),
|
||||
("shop.account.adapter.local", &complete),
|
||||
("shop.account.adapter.remote", valid)
|
||||
])
|
||||
.is_err()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn selection_keeps_all_candidate_effects_and_failure_identity() {
|
||||
let quiet = "setting { offset: Int }\nport.read(value: Int) (answer: Int) { answer = value + setting.offset }";
|
||||
let scheduled = "port.read(value: Int) (answer: Int) { answer = wait(run(helper(value))) }\nhelper(value: Int) (answer: Int) { answer = value }";
|
||||
let program = packages(&[
|
||||
("shop.account.app", APP),
|
||||
("shop.account.port", PORT),
|
||||
("shop.account.adapter.local", quiet),
|
||||
("shop.account.adapter.remote", scheduled),
|
||||
])
|
||||
.unwrap();
|
||||
let effects = signature(&program, "read").effects;
|
||||
assert!(effects.configuration && effects.suspend && effects.schedule);
|
||||
let pure = APP.replace("(answer: Int) {", "(answer: Int) pure {");
|
||||
assert_eq!(
|
||||
packages(&[
|
||||
("shop.account.app", &pure),
|
||||
("shop.account.port", PORT),
|
||||
("shop.account.adapter.local", quiet),
|
||||
("shop.account.adapter.remote", scheduled),
|
||||
])
|
||||
.unwrap_err()
|
||||
.code,
|
||||
"C013"
|
||||
);
|
||||
let error = "port.read(value: Int) (answer: Int) { fail(app.Problem.Missing(\"missing\")) }";
|
||||
let program = packages(&[
|
||||
("shop.account.app", APP),
|
||||
("shop.account.port", PORT),
|
||||
("shop.account.adapter.local", quiet),
|
||||
("shop.account.adapter.remote", error),
|
||||
])
|
||||
.unwrap();
|
||||
assert_eq!(signature(&program, "read").failures.len(), 2);
|
||||
assert!(signature(&program, "read").effects.configuration);
|
||||
assert!(!program.api_snapshot().contains("setting.offset"));
|
||||
}
|
||||
Reference in new issue
Block a user