128 lines
4.1 KiB
Rust
128 lines
4.1 KiB
Rust
use super::{ADAPTER, APP, PORT, packages};
|
|
|
|
#[test]
|
|
fn roles_cannot_call_around_the_port_boundary() {
|
|
for call in [
|
|
"app.read(value)",
|
|
"domain.read(value)",
|
|
"port.read(value)",
|
|
"foreign.library.read(value)",
|
|
"shop.account.adapter.other.helper(value)",
|
|
] {
|
|
let adapter = format!("port.read(value: Int) (answer: Int) {{ answer = {call} }}");
|
|
let error = packages(&[
|
|
("shop.account.app", APP),
|
|
(
|
|
"shop.account.domain",
|
|
"read(value: Int) (answer: Int) { answer = value }",
|
|
),
|
|
("shop.account.port", PORT),
|
|
("shop.account.adapter.local", &adapter),
|
|
(
|
|
"foreign.library",
|
|
"public read(value: Int) (answer: Int) { answer = value }",
|
|
),
|
|
])
|
|
.unwrap_err();
|
|
assert!(
|
|
matches!(error.code, "C004" | "C005" | "C006"),
|
|
"{call}: {error:?}"
|
|
);
|
|
}
|
|
for caller in ["shop.account.domain", "shop.other.app", "foreign"] {
|
|
let error = packages(&[
|
|
("shop.account.app", APP),
|
|
("shop.account.port", PORT),
|
|
("shop.account.adapter", ADAPTER),
|
|
(
|
|
caller,
|
|
"entry(value: Int) (answer: Int) { answer = shop.account.port.read(value) }",
|
|
),
|
|
])
|
|
.unwrap_err();
|
|
assert_eq!(error.code, "C006", "{caller}: {error:?}");
|
|
}
|
|
for call in [
|
|
"adapter.helper(value)",
|
|
"adapter.port.read(value)",
|
|
"shop.account.adapter.port.read(value)",
|
|
] {
|
|
assert!(
|
|
packages(&[
|
|
("shop.account.app", &APP.replace("port.read(value)", call)),
|
|
("shop.account.port", PORT),
|
|
("shop.account.adapter", ADAPTER)
|
|
])
|
|
.is_err(),
|
|
"{call}"
|
|
);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn only_app_types_in_the_complete_contract_graph_are_visible() {
|
|
let app = "type Problem { error Missing(message: Text) }\ntype Person { name: Text }\ntype Unrelated { number: Int }\nread(value: Person) (answer: Text) { answer = port.read(port.Row { person = value }) }";
|
|
let port = "type Row { person: app.Person }\nread(value: Row) (answer: Text) fails app.Problem";
|
|
let adapter = "port.read(value: port.Row) (answer: Text) { answer = label(value.person) }\nlabel(value: app.Person) (answer: Text) { answer = value.name }";
|
|
assert!(
|
|
packages(&[
|
|
("shop.account.adapter", adapter),
|
|
("shop.account.port", port),
|
|
("shop.account.app", app)
|
|
])
|
|
.is_ok()
|
|
);
|
|
for bad in [
|
|
format!("{adapter}\nunused(value: app.Unrelated) () {{}}"),
|
|
adapter.replace(
|
|
"answer = label(value.person)",
|
|
"hidden = app.Unrelated { number = 1 }\nanswer = label(value.person)",
|
|
),
|
|
format!("{adapter}\ntype Hidden {{ value: List<app.Unrelated> }}"),
|
|
] {
|
|
assert_eq!(
|
|
packages(&[
|
|
("shop.account.adapter", &bad),
|
|
("shop.account.port", port),
|
|
("shop.account.app", app)
|
|
])
|
|
.unwrap_err()
|
|
.code,
|
|
"C006"
|
|
);
|
|
}
|
|
let bad = format!("{port}\ntype Unused {{ value: app.Unrelated }}");
|
|
assert_eq!(
|
|
packages(&[
|
|
("shop.account.app", app),
|
|
("shop.account.port", &bad),
|
|
("shop.account.adapter", adapter)
|
|
])
|
|
.unwrap_err()
|
|
.code,
|
|
"C006"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn adapter_cannot_read_another_ports_private_dto() {
|
|
let error = packages(&[
|
|
("shop.account.app", APP),
|
|
("shop.account.port", PORT),
|
|
(
|
|
"shop.account.port.other",
|
|
"type Hidden { value: Int }\nwrite(value: Int) () fails app.Problem",
|
|
),
|
|
(
|
|
"shop.account.adapter.first",
|
|
&format!("{ADAPTER}\nunused(value: port.other.Hidden) () {{}}"),
|
|
),
|
|
(
|
|
"shop.account.adapter.second",
|
|
"port.other.write(value: Int) () {}",
|
|
),
|
|
])
|
|
.unwrap_err();
|
|
assert_eq!(error.code, "C006");
|
|
}
|