110 lines
4.1 KiB
Rust
110 lines
4.1 KiB
Rust
use super::{checked, package::packages};
|
|
|
|
#[test]
|
|
fn api_snapshot_uses_declared_contracts_not_private_bodies_or_inferred_constants() {
|
|
let snapshot = |body: &str| {
|
|
checked(&format!("public value(input: Int) (answer: Int) {{ answer = helper(input) }}\nhelper(input: Int) (answer: Int) {{ {body} }}")).unwrap().api_snapshot()
|
|
};
|
|
let first = snapshot("answer = 1");
|
|
assert_eq!(
|
|
first,
|
|
"dever-api 5\nfunction main.value(Int) (answer: Int []) pure=false recover=None effects=[] errors=[] recoveries={}\n"
|
|
);
|
|
assert_eq!(first, snapshot("answer = input + 2"));
|
|
let constrained =
|
|
checked("public value(input: Int) (answer: Int >= 0) { answer = 1 }").unwrap();
|
|
assert!(
|
|
constrained
|
|
.api_snapshot()
|
|
.contains("answer: Int [0..9223372036854775807]")
|
|
);
|
|
let difference = constrained.check_api(&first).unwrap_err();
|
|
assert!(
|
|
difference.contains("- function main.value")
|
|
&& difference.contains("+ function main.value")
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn api_snapshot_tracks_public_shape_construction_failure_and_transitive_recovery() {
|
|
let snapshot = |key: &str| {
|
|
checked(&format!(
|
|
"public type Session {{ private key: {key}\nlabel: Text }}"
|
|
))
|
|
.unwrap()
|
|
.api_snapshot()
|
|
};
|
|
let private = snapshot("Int");
|
|
assert_eq!(private, snapshot("Text"));
|
|
assert_eq!(
|
|
private,
|
|
"dever-api 5\ntype main.Session record construct=private {label: Text []}\n"
|
|
);
|
|
let exposed = checked("public type Session { key: Int\nlabel: Text }").unwrap();
|
|
assert!(
|
|
exposed
|
|
.check_api(&private)
|
|
.unwrap_err()
|
|
.contains("construct=public")
|
|
);
|
|
let failing = checked("public type Problem { error Bad(message: Text) }\npublic value() () { fail(Problem.Bad(\"bad\")) }").unwrap();
|
|
let baseline = failing.api_snapshot();
|
|
assert!(baseline.contains("errors=[main.Problem.Bad]"));
|
|
assert!(baseline.contains("type main.Problem error Bad(message: Text [])"));
|
|
let snapshot = |reason: &str| {
|
|
checked(&format!(
|
|
"public value() () {{ helper() }}\nhelper() () recover(\"{reason}\") {{}}"
|
|
))
|
|
.unwrap()
|
|
.api_snapshot()
|
|
};
|
|
assert_ne!(snapshot("use zero"), snapshot("use one"));
|
|
assert!(snapshot("use zero").contains("recoveries={\"use zero\"}"));
|
|
}
|
|
|
|
#[test]
|
|
fn api_snapshot_is_stable_across_app_topics_and_binds_command_inputs() {
|
|
let snapshot = |topic: &str, input: &str| {
|
|
packages(&[
|
|
(
|
|
topic,
|
|
&format!("value({input}: Int) (answer: Int) {{ answer = {input} }}"),
|
|
),
|
|
("shop.account.api", "cmd value = app.value"),
|
|
])
|
|
.unwrap()
|
|
.api_snapshot()
|
|
};
|
|
assert_eq!(
|
|
snapshot("shop.account.app", "input"),
|
|
snapshot("shop.account.app.read", "input")
|
|
);
|
|
assert_ne!(
|
|
snapshot("shop.account.app", "input"),
|
|
snapshot("shop.account.app", "renamed")
|
|
);
|
|
assert!(
|
|
snapshot("shop.account.app", "input")
|
|
.contains("cmd shop.account.value = shop.account.value(input: Int [])")
|
|
);
|
|
let program = checked("public apply(action: handler(input: Int) (answer: Int), input: Int) (answer: Int) { answer = action(input) }").unwrap();
|
|
assert!(
|
|
program
|
|
.api_snapshot()
|
|
.contains("function main.apply(handler(Int [])(answer: Int []), Int)")
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn public_handler_snapshot_keeps_constraints_and_ignores_specializations() {
|
|
let source = "public apply(action: handler(input: Int >= 0) (answer: Int >= 0)) (answer: Int >= 0) { answer = action(1) }";
|
|
let original = checked(source).unwrap().api_snapshot();
|
|
assert!(
|
|
original.contains(
|
|
"handler(Int [0..9223372036854775807])(answer: Int [0..9223372036854775807])"
|
|
)
|
|
);
|
|
let called = checked(&format!("{source}\nnonnegative(input: Int) (answer: Int >= 0) {{ answer = 0 }}\nmain() (answer: Int) {{ answer = apply(nonnegative) }}")).unwrap();
|
|
assert_eq!(original, called.api_snapshot());
|
|
}
|