use wolfram_expr::{expr, Expr};
use wstp::{sys, Link, LinkStr, Protocol, Token, TokenType};
fn check_loopback_roundtrip(expr: Expr) {
let mut link = Link::new_loopback().expect("failed to create Loopback link");
link.put_expr(&expr).expect("failed to write expr");
let read = link.get_expr().expect("failed to read expr");
assert_eq!(expr, read);
}
#[test]
fn test_loopback_link() {
check_loopback_roundtrip(Expr::from(5i64));
check_loopback_roundtrip(expr!(System::List[1]));
check_loopback_roundtrip(expr!(Global::MyHead[1i16]));
}
#[test]
fn test_loopback_get_put_atoms() {
let mut link = Link::new_loopback().expect("failed to create Loopback link");
{
link.put_expr(&Expr::string("Hello!")).unwrap();
let link_str: LinkStr = link.get_string_ref().unwrap();
assert_eq!(link_str.as_str(), "Hello!")
}
{
link.put_expr(&expr!(System::Plot)).unwrap();
let link_str: LinkStr = link.get_symbol_ref().unwrap();
assert_eq!(link_str.as_str(), "System`Plot")
}
}
#[test]
fn test_is_loopback() {
let link = Link::new_loopback().unwrap();
assert!(link.is_loopback());
let link = Link::listen(Protocol::IntraProcess, "name-test").unwrap();
assert!(!link.is_loopback());
}
#[test]
fn test_loopback_idempotence_of_get_arg_count() {
let mut link = Link::new_loopback().unwrap();
link.put_function("List", 1).unwrap();
link.put_i64(10).unwrap();
assert_eq!(link.raw_get_next(), Ok(sys::WSTKFUNC.into()));
for _ in 0..5 {
assert_eq!(link.get_arg_count(), Ok(1));
}
assert_eq!(
link.get_string_ref().map(|s| s.as_str().to_owned()),
Ok(String::from("List"))
);
}
#[test]
fn test_get_arg_count_must_be_called_at_least_once() {
let mut link = Link::new_loopback().unwrap();
link.put_function("List", 1).unwrap();
link.put_i64(10).unwrap();
assert_eq!(link.raw_get_next(), Ok(sys::WSTKFUNC.into()));
assert_eq!(
link.get_string_ref().unwrap_err().code(),
Some(sys::WSEGSEQ)
);
}
#[test]
fn test_loopback_basic_put_and_get_list() {
let mut link = Link::new_loopback().unwrap();
link.put_function("List", 1).unwrap();
link.put_i64(10).unwrap();
assert_eq!(link.raw_get_next(), Ok(sys::WSTKFUNC.into()));
assert_eq!(link.get_arg_count(), Ok(1));
assert_eq!(
link.get_string_ref().map(|s| s.as_str().to_owned()),
Ok(String::from("List"))
);
assert_eq!(link.get_i64(), Ok(10));
}
#[test]
fn test_loopback_get_next() {
let mut link = Link::new_loopback().unwrap();
link.put_function("List", 1).unwrap();
link.put_i64(10).unwrap();
assert!(link.is_ready());
assert_eq!(link.raw_get_next(), Ok(sys::WSTKFUNC.into()));
assert_eq!(link.raw_get_next(), Ok(sys::WSTKSYM.into()));
assert_eq!(link.raw_get_next(), Ok(sys::WSTKINT.into()));
assert_eq!(link.raw_get_next().unwrap_err().code(), Some(sys::WSEABORT));
assert!(!link.is_ready());
}
#[test]
fn test_loopback_new_packet() {
let mut link = Link::new_loopback().unwrap();
link.put_function("List", 1).unwrap();
link.put_i64(10).unwrap();
assert!(link.is_ready());
assert_eq!(link.raw_get_next(), Ok(sys::WSTKFUNC.into()));
assert_eq!(link.new_packet(), Ok(()));
assert_eq!(link.raw_get_next().unwrap_err().code(), Some(sys::WSEABORT));
assert!(!link.is_ready());
}
#[test]
fn test_loopback_test_head() {
let mut link = Link::new_loopback().unwrap();
link.put_function("List", 1).unwrap();
link.put_i64(10).unwrap();
assert_eq!(link.test_head("List"), Ok(1));
}
#[test]
fn test_loopback_test_head_error() {
let mut link = Link::new_loopback().unwrap();
link.put_function("List", 1).unwrap();
link.put_i64(10).unwrap();
assert_eq!(
link.test_head("Plot").unwrap_err().code().unwrap(),
sys::WSEGSEQ
);
}
#[test]
fn test_loopback_transfer_simple() {
let mut link = Link::new_loopback().unwrap();
link.put_str("hello").unwrap();
let mut new = Link::new_loopback().unwrap();
link.transfer_to_end_of_loopback_link(&mut new).unwrap();
assert_eq!(new.get_string_ref().unwrap().as_str(), "hello");
}
#[test]
fn test_loopback_transfer_list() {
let mut link = Link::new_loopback().unwrap();
link.put_function("System`List", 3).unwrap();
link.put_i64(5).unwrap();
link.put_str("second").unwrap();
link.put_symbol("Global`foo").unwrap();
let mut new = Link::new_loopback().unwrap();
link.transfer_to_end_of_loopback_link(&mut new).unwrap();
assert_eq!(
new.get_expr().unwrap().to_string(),
"{5, \"second\", Global`foo}"
);
}
#[test]
#[rustfmt::skip]
fn test_loopback_get_tokens() {
let mut link = Link::new_loopback().unwrap();
link.put_function("System`List", 3).unwrap();
link.put_i64(5).unwrap();
link.put_str("second").unwrap();
link.put_symbol("Global`foo").unwrap();
assert!(matches!(link.get_token().unwrap(), Token::Function { length: 3 }));
assert!(matches!(link.get_token().unwrap(), Token::Symbol(s) if s.as_str() == "System`List"));
assert!(matches!(link.get_token().unwrap(), Token::Integer(5)));
assert!(matches!(link.get_token().unwrap(), Token::String(s) if s.as_str() == "second"));
assert!(matches!(link.get_token().unwrap(), Token::Symbol(s) if s.as_str() == "Global`foo"));
}
#[test]
#[rustfmt::skip]
fn test_loopback_get_token_type_is_idempotent() {
let mut link = Link::new_loopback().unwrap();
link.put_function("System`List", 3).unwrap();
link.put_i64(5).unwrap();
link.put_str("second").unwrap();
link.put_symbol("Global`foo").unwrap();
assert_eq!(link.get_type().unwrap(), TokenType::Function);
assert_eq!(link.get_type().unwrap(), TokenType::Function);
assert_eq!(link.get_type().unwrap(), TokenType::Function);
assert!(matches!(link.get_token().unwrap(), Token::Function { length: 3 }));
assert_eq!(link.get_type().unwrap(), TokenType::Symbol);
assert_eq!(link.get_type().unwrap(), TokenType::Symbol);
assert_eq!(link.get_type().unwrap(), TokenType::Symbol);
assert!(matches!(link.get_token().unwrap(), Token::Symbol(s) if s.as_str() == "System`List"));
assert_eq!(link.get_type().unwrap(), TokenType::Integer);
assert_eq!(link.get_type().unwrap(), TokenType::Integer);
assert_eq!(link.get_type().unwrap(), TokenType::Integer);
assert!(matches!(link.get_token().unwrap(), Token::Integer(5)));
}