use super::linked; #[test] fn selection_checks_named_outputs_static_fallback_and_affine_ownership() { let prefix = "work() (value: Int) { value = 1 }\nfallback() (value: Int) { value = 2 }\n"; for body in [ "value = timeout(run(work()), 1, fallback)", "first = run(work())\n second = run(work())\n value = race(first, second)", ] { assert!(linked(&format!("{prefix}main() (value: Int) {{ {body} }}")).is_ok()); } for (extra, body, code) in [ ( "wrong() (answer: Int) { answer = 0 }", "value = timeout(run(work()), 1, wrong)", "C005", ), ( "wrong(input: Int) (value: Int) { value = input }", "value = timeout(run(work()), 1, wrong)", "C005", ), ( "wrong() (answer: Int) { answer = 0 }", "value = race(run(work()), run(wrong()))", "C005", ), ("", "value = race(run(work()))", "C005"), ("", "value = race(run(work()), 1)", "C005"), ( "", "pending = run(work())\n value = race(pending, pending)", "C013", ), ( "", "pending = run(work())\n value = timeout(pending, 1, fallback)\n again = wait(pending)", "C013", ), ("", "value = timeout(run(work()), 1.0e0, fallback)", "C005"), ] { let source = format!("{prefix}{extra}\nmain() (value: Int) {{ {body} }}"); assert_eq!(linked(&source).unwrap_err().code, code, "{source}"); } } #[test] fn timeout_retains_task_ownership_while_duration_is_awaited() { let source = "work() (value: Int) { value = 1 }\nfallback() (value: Int) { value = 2 }\nduration() (value: Int) { dever.task.sleep(0)\n value = 1 }\nmain() (value: Int) { value = timeout(run(work()), duration(), fallback) }"; assert!(linked(source).is_ok()); assert_eq!(linked("work() () {}\nfallback() () { dever.io.println(\"blocked\") }\nmain() () { timeout(run(work()), 1, fallback) }").unwrap_err().code, "C013"); } #[test] fn cancellation_does_not_discharge_input_error_obligations() { let prefix = "type Result { Done\n error Failed(message: Text) }\nhandle(value: Result) () recover(\"handles input\") {}\nempty() () {}\n"; for body in [ "timeout(run(handle(Result.Failed(\"first\"))), 1, empty)", "race(run(handle(Result.Failed(\"first\"))), run(handle(Result.Failed(\"second\"))))", "problem = Result.Failed(\"shared\")\n race(run(handle(problem)), run(empty()))", ] { assert_eq!( linked(&format!("{prefix}main() () {{ {body} }}")) .unwrap_err() .code, "C012" ); } assert!(linked(&format!("{prefix}main() () {{ problem = Result.Failed(\"shared\")\n race(run(handle(problem)), run(handle(problem))) }}")).is_ok()); } #[test] fn selected_error_values_must_be_returned_or_handled() { let prefix = "type Result { Done(value: Int)\n error Failed(message: Text) }\nwork() (value: Result) { value = Result.Failed(\"reason\") }\nfallback() (value: Result) { value = Result.Done(0) }\n"; for operation in [ "timeout(run(work()), 1, fallback)", "race(run(work()), run(work()))", ] { assert_eq!( linked(&format!("{prefix}main() () {{ lost = {operation} }}")) .unwrap_err() .code, "C012" ); assert!( linked(&format!( "{prefix}main() (value: Result) {{ value = {operation} }}" )) .is_ok() ); } } #[test] fn selected_ranges_include_fallback_and_each_possible_winner() { let prefix = "one() (value: Int) { value = 1 }\ntwo() (value: Int) { value = 2 }\n"; for operation in [ "timeout(run(one()), 1, two)", "race(run(one()), run(two()))", ] { assert_eq!( linked(&format!( "{prefix}main() (value: Int <= 1) {{ value = {operation} }}" )) .unwrap_err() .code, "C011" ); assert!( linked(&format!( "{prefix}main() (value: Int <= 2) {{ value = {operation} }}" )) .is_ok() ); } }