use super::checked; #[test] fn unconstrained_parameters_do_not_expand_clause_products() { let inputs = (0..40) .map(|position| format!("flag{position}: Bool")) .collect::>() .join(", "); let body = (0..40) .map(|position| format!("flag{position}")) .collect::>() .join(" or "); let ordinary = format!("choose({inputs}) (answer: Bool) {{ answer = {body} }}\n"); assert!(checked(&ordinary).is_ok()); let clause = |pattern: &str| { format!("choose(test: {pattern}, {inputs}) (answer: Bool) {{ answer = {body} }}\n") }; assert!(checked(&(clause("true") + &clause("false"))).is_ok()); assert_eq!(checked(&clause("true")).unwrap_err().code, "C009"); assert_eq!( checked(&(clause("Bool") + &clause("false"))) .unwrap_err() .code, "C009" ); assert!(checked("type State { One\n Two }\nvalue(input: State, optional: Bool?) (answer: Bool) { answer = optional == null }").is_ok()); } #[test] fn choice_coverage_and_payload_contracts() { let prefix = "type State { Idle\n Working(value: Int) }\n"; let valid = "read(value: State.Idle) (answer: Int) { answer = 0 }\nread(value: State.Working(number)) (answer: Int) { answer = number }"; assert!(checked(&(prefix.to_owned() + valid)).is_ok()); for (body, code) in [ ( "read(value: State.Idle) (answer: Int) { answer = 0 }", "C009", ), ( "read(value: State) (answer: Int) { answer = 0 }\nread(value: State.Idle) (answer: Int) { answer = 1 }", "C009", ), ( "read(value: State.Working) (answer: Int) { answer = 0 }", "C005", ), ( "read(value: State.Working(first, second)) (answer: Int) { answer = first }", "C005", ), ( "read(value: State.Working(value)) (answer: Int) { answer = 0 }", "C009", ), ( "main() (answer: State) { answer = State.Working() }", "C005", ), ( "main() (answer: State) { answer = State.Working(true) }", "C005", ), ( "read(value: State) (answer: Int) { answer = value.value }", "C005", ), ] { let error = checked(&(prefix.to_owned() + body)).unwrap_err(); assert_eq!(error.code, code, "{body}: {error:?}"); } let wildcard = "read(value: State.Working(_)) (answer: Int) { answer = 1 }\nread(value: other) (answer: Int) { answer = 0 }"; assert!(checked(&(prefix.to_owned() + wildcard)).is_ok()); assert_eq!( checked("type Cycle { Next(value: Cycle) }") .unwrap_err() .code, "C007" ); assert_eq!( checked("type State { Item(value: Row) }\ntype Row { state: State }") .unwrap_err() .code, "C007" ); } #[test] fn nullable_domains_and_complements_are_order_independent() { for clauses in [ "read(value: Text) (answer: Int) { answer = length(value) }\nread(value: null) (answer: Int) { answer = -1 }", "read(value: null) (answer: Int) { answer = -1 }\nread(value: Text) (answer: Int) { answer = length(value) }", "read(value: other) (answer: Int) { answer = length(value) }\nread(value: null) (answer: Int) { answer = -1 }\nread(value: \"x\") (answer: Int) { answer = 1 }", ] { assert!(checked(clauses).is_ok(), "{clauses}"); } for clauses in [ "read(value: Text?) (answer: Int) { answer = 0 }\nread(value: null) (answer: Int) { answer = 1 }", "read(value: \"x\") (answer: Int) { answer = 0 }\nread(value: null) (answer: Int) { answer = 1 }", ] { assert_eq!(checked(clauses).unwrap_err().code, "C009"); } assert!(checked("equal(value: Int?) (answer: Bool) { answer = value == null or null == value or value == 1 or 1 == value }").is_ok()); assert!(checked("number() (answer: Decimal?) { answer = 1 }").is_ok()); assert!(checked("number() (answer: Float?) { answer = 1.5 + 2.5 }").is_ok()); assert!(checked("values() (answer: List?) { answer = [] }").is_ok()); } #[test] fn payload_bindings_do_not_shadow_inputs_or_outputs() { for binding in ["value", "answer"] { let text = format!( "type State {{ Item(number: Int) }}\nread(value: State.Item({binding})) (answer: Int) {{ answer = 1 }}" ); assert_eq!(checked(&text).unwrap_err().code, "C002"); } }