diff --git a/src/runtime2/tests/mod.rs b/src/runtime2/tests/mod.rs index c662f7760439d3068db4b43f1e79da64d2ed32bf..f2438d5a42ba702860ddfa35b7b77e2b86ff1bf2 100644 --- a/src/runtime2/tests/mod.rs +++ b/src/runtime2/tests/mod.rs @@ -1,4 +1,129 @@ +use std::sync::Arc; + +use super::runtime::*; +use crate::ProtocolDescription; +use crate::protocol::eval::*; + #[test] -fn testing_runtime2() { - println!("YESH!"); +fn test_single_message() { + // Simple test were we have a `putter` component, which will simply send a + // single message (a boolean), and a `getter` component, which will receive + // that message. + // We will write this behaviour in the various ways that the language + // currently allows. We will cheat a bit by peeking into the runtime to make + // sure that the getter actually received the message. + // TODO: Expose ports to a "native application" + + fn check_store_bool(value: &Value, expected: bool) { + if let Value::Bool(value) = value { + assert_eq!(*value, expected); + } else { + assert!(false); + } + } + fn run_putter_getter(code: &[u8]) { + // Compile code + let pd = ProtocolDescription::parse(code) + .expect("code successfully compiles"); + let pd = Arc::new(pd); + + // Construct runtime and the appropriate ports and connectors + let mut rt = Runtime::new(pd); + let (put_port, get_port) = rt.add_channel(); + + let mut put_args = ValueGroup::new_stack(vec![ + put_port, + ]); + rt.add_component("", "putter", put_args) + .expect("'putter' component created"); + + let mut get_args = ValueGroup::new_stack(vec![ + get_port, + ]); + rt.add_component("", "getter", get_args) + .expect("'getter' component created"); + + // Run until completion + rt.run(); + + // Check for success (the 'received' and 'did_receive" flags) + let getter_component = rt.connectors.get(&1).unwrap(); + let branch = &getter_component.branches[0]; + assert_eq!(branch.branch_state, BranchState::Finished); + + // Note: with the stack structure of the store, the first entry is the + // "previous stack pos" and the second one is the input port passed to + // the procedure. Hence the third/fourth entries are the boolean + // variables on the stack. + check_store_bool(&branch.code_state.prompt.store.stack[2], true); + check_store_bool(&branch.code_state.prompt.store.stack[3], true); + } + + // Without `fires()`, just a single valid behaviour + run_putter_getter( + b"primitive putter(out put_here) { + synchronous { + put(put_here, true); + } + } + + primitive getter(in get_here) { + bool received = false; + bool did_receive = false; + + synchronous { + received = get(get_here); + if (received) { + print(\"value was 'true'\"); + } else { + print(\"value was 'false'\"); + } + did_receive = true; + } + }"); + + // With `fires()`, but eliminating on the putter side + run_putter_getter( + b"primitive putter(out put_here) { + synchronous { + if (!fires(put_here)) { + assert(false); + } else { + put(put_here, true); + } + } + } + + primitive getter(in get_here) { + bool received = false; bool did_receive = false; + synchronous { + if (fires(get_here)) { + received = get(get_here); + did_receive = true; + } + } + }"); + + // With `fires()`, but eliminating on the getter side + run_putter_getter( + b"primitive putter(out put_here) { + synchronous { + if (fires(put_here)) { + put(put_here, true); + } + } + } + + primitive getter(in get_here) { + bool received = false; bool did_receive = false; + synchronous { + if (fires(get_here)) { + received = get(get_here); + did_receive = true; + } else { + assert(false); + } + } + }" + ); } \ No newline at end of file