use turkos_os_syscall_abi::syscall_abi::{AbiResult, DecodeError, Errno, Success}; use turkos_os_user_runtime_client::{Client, Error, Transport}; #[derive(Default)] struct Probe { calls: Vec<(u64, u64, [u64; 6])>, replies: Vec, } impl Probe { fn with_replies(replies: &[u64]) -> Self { Self {calls: Vec::new(), replies: replies.to_vec()} } } impl Transport for Probe { fn call(&mut self, version: u64, number: u64, arguments: [u64; 6]) -> u64 { self.calls.push((version, number, arguments)); self.replies.remove(0) } } fn ok(value: u64) -> u64 { AbiResult::Ok(Success::new(value).unwrap()).encode() } fn err(errno: Errno) -> u64 { AbiResult::Err(errno).encode() } #[test] fn typed_calls_preserve_numbers_arguments_and_owner() { let mut client = Client::new(Probe::with_replies(&[ok(1), ok(0x80004000), ok(0)])); assert_eq!(client.version(), Ok(1)); let allocation = client.alloc(64, 16).unwrap(); assert_eq!((allocation.address(), allocation.bytes(), allocation.alignment()), (0x80004000, 64, 16)); assert!(client.free(allocation).is_ok()); let probe = client.into_transport(); assert_eq!(probe.calls, vec![ (1, 0, [0; 6]), (2, 4, [64, 16, 0, 0, 0, 0]), (2, 5, [0x80004000, 0, 0, 0, 0, 0]), ]); } #[test] fn invalid_request_and_enomem_never_create_allocation() { let mut client = Client::new(Probe::with_replies(&[err(Errno::NoMem)])); assert!(matches!(client.alloc(0, 8), Err(Error::Kernel(Errno::Invalid)))); assert!(matches!(client.alloc(64, 3), Err(Error::Kernel(Errno::Invalid)))); assert!(matches!(client.alloc(4097, 8), Err(Error::Kernel(Errno::Invalid)))); assert!(matches!(client.alloc(64, 8), Err(Error::Kernel(Errno::NoMem)))); assert_eq!(client.into_transport().calls.len(), 1); } #[test] fn failed_free_returns_the_same_owner_for_retry() { let mut client = Client::new(Probe::with_replies(&[ ok(0x80004000), err(Errno::Io), ok(0), ])); let allocation = client.alloc(8, 8).unwrap(); let (error, allocation) = client.free(allocation).err().unwrap(); assert_eq!(error, Error::Kernel(Errno::Io)); assert_eq!(allocation.address(), 0x80004000); assert!(client.free(allocation).is_ok()); assert_eq!(client.into_transport().calls.len(), 3); } #[test] fn malformed_or_unaligned_success_never_becomes_a_buffer() { let mut client = Client::new(Probe::with_replies(&[ u64::MAX - 9000, ok(0), ok(0x80004001), ])); assert!(matches!(client.alloc(8, 8), Err(Error::Wire(DecodeError::NegativeSuccess)))); assert!(matches!(client.alloc(8, 8), Err(Error::InvalidReturn))); assert!(matches!(client.alloc(8, 8), Err(Error::InvalidReturn))); assert_eq!(client.into_transport().calls.len(), 3); } #[test] fn exit_uses_canonical_signed_code_and_reports_unexpected_return() { let mut client = Client::new(Probe::with_replies(&[ok(0)])); assert_eq!(client.exit(-7), Error::UnexpectedExitReturn); assert_eq!(client.into_transport().calls, vec![(2, 3, [(-7i64) as u64, 0, 0, 0, 0, 0])]); }