#![allow(clippy::unnecessary_operation)] use std::collections::VecDeque; use std::fmt; use std::fs::{Metadata, Permissions}; use std::io; use std::io::prelude::*; use std::io::SeekFrom; use std::path::PathBuf; use std::sync::{Arc, Mutex}; pub struct File { shared: Arc>, } pub struct Handle { shared: Arc>, } struct Shared { calls: VecDeque, } #[derive(Debug)] enum Call { Read(io::Result>), Write(io::Result>), Seek(SeekFrom, io::Result), SyncAll(io::Result<()>), SyncData(io::Result<()>), SetLen(u64, io::Result<()>), } impl Handle { pub fn read(&self, data: &[u8]) -> &Self { let mut s = self.shared.lock().unwrap(); s.calls.push_back(Call::Read(Ok(data.to_owned()))); self } pub fn read_err(&self) -> &Self { let mut s = self.shared.lock().unwrap(); s.calls .push_back(Call::Read(Err(io::ErrorKind::Other.into()))); self } pub fn write(&self, data: &[u8]) -> &Self { let mut s = self.shared.lock().unwrap(); s.calls.push_back(Call::Write(Ok(data.to_owned()))); self } pub fn write_err(&self) -> &Self { let mut s = self.shared.lock().unwrap(); s.calls .push_back(Call::Write(Err(io::ErrorKind::Other.into()))); self } pub fn seek_start_ok(&self, offset: u64) -> &Self { let mut s = self.shared.lock().unwrap(); s.calls .push_back(Call::Seek(SeekFrom::Start(offset), Ok(offset))); self } pub fn seek_current_ok(&self, offset: i64, ret: u64) -> &Self { let mut s = self.shared.lock().unwrap(); s.calls .push_back(Call::Seek(SeekFrom::Current(offset), Ok(ret))); self } pub fn sync_all(&self) -> &Self { let mut s = self.shared.lock().unwrap(); s.calls.push_back(Call::SyncAll(Ok(()))); self } pub fn sync_all_err(&self) -> &Self { let mut s = self.shared.lock().unwrap(); s.calls .push_back(Call::SyncAll(Err(io::ErrorKind::Other.into()))); self } pub fn sync_data(&self) -> &Self { let mut s = self.shared.lock().unwrap(); s.calls.push_back(Call::SyncData(Ok(()))); self } pub fn sync_data_err(&self) -> &Self { let mut s = self.shared.lock().unwrap(); s.calls .push_back(Call::SyncData(Err(io::ErrorKind::Other.into()))); self } pub fn set_len(&self, size: u64) -> &Self { let mut s = self.shared.lock().unwrap(); s.calls.push_back(Call::SetLen(size, Ok(()))); self } pub fn set_len_err(&self, size: u64) -> &Self { let mut s = self.shared.lock().unwrap(); s.calls .push_back(Call::SetLen(size, Err(io::ErrorKind::Other.into()))); self } pub fn remaining(&self) -> usize { let s = self.shared.lock().unwrap(); s.calls.len() } } impl Drop for Handle { fn drop(&mut self) { if !std::thread::panicking() { let s = self.shared.lock().unwrap(); assert_eq!(0, s.calls.len()); } } } impl File { pub fn open(_: PathBuf) -> io::Result { unimplemented!(); } pub fn create(_: PathBuf) -> io::Result { unimplemented!(); } pub fn mock() -> (Handle, File) { let shared = Arc::new(Mutex::new(Shared { calls: VecDeque::new(), })); let handle = Handle { shared: shared.clone(), }; let file = File { shared }; (handle, file) } pub fn sync_all(&self) -> io::Result<()> { use self::Call::*; let mut s = self.shared.lock().unwrap(); match s.calls.pop_front() { Some(SyncAll(ret)) => ret, Some(op) => panic!("expected next call to be {:?}; was sync_all", op), None => panic!("did not expect call"), } } pub fn sync_data(&self) -> io::Result<()> { use self::Call::*; let mut s = self.shared.lock().unwrap(); match s.calls.pop_front() { Some(SyncData(ret)) => ret, Some(op) => panic!("expected next call to be {:?}; was sync_all", op), None => panic!("did not expect call"), } } pub fn set_len(&self, size: u64) -> io::Result<()> { use self::Call::*; let mut s = self.shared.lock().unwrap(); match s.calls.pop_front() { Some(SetLen(arg, ret)) => { assert_eq!(arg, size); ret } Some(op) => panic!("expected next call to be {:?}; was sync_all", op), None => panic!("did not expect call"), } } pub fn metadata(&self) -> io::Result { unimplemented!(); } pub fn set_permissions(&self, _perm: Permissions) -> io::Result<()> { unimplemented!(); } pub fn try_clone(&self) -> io::Result { unimplemented!(); } } impl Read for &'_ File { fn read(&mut self, dst: &mut [u8]) -> io::Result { use self::Call::*; let mut s = self.shared.lock().unwrap(); match s.calls.pop_front() { Some(Read(Ok(data))) => { assert!(dst.len() >= data.len()); assert!(dst.len() <= 16 * 1024, "actual = {}", dst.len()); // max buffer &mut dst[..data.len()].copy_from_slice(&data); Ok(data.len()) } Some(Read(Err(e))) => Err(e), Some(op) => panic!("expected next call to be {:?}; was a read", op), None => panic!("did not expect call"), } } } impl Write for &'_ File { fn write(&mut self, src: &[u8]) -> io::Result { use self::Call::*; let mut s = self.shared.lock().unwrap(); match s.calls.pop_front() { Some(Write(Ok(data))) => { assert_eq!(src, &data[..]); Ok(src.len()) } Some(Write(Err(e))) => Err(e), Some(op) => panic!("expected next call to be {:?}; was write", op), None => panic!("did not expect call"), } } fn flush(&mut self) -> io::Result<()> { Ok(()) } } impl Seek for &'_ File { fn seek(&mut self, pos: SeekFrom) -> io::Result { use self::Call::*; let mut s = self.shared.lock().unwrap(); match s.calls.pop_front() { Some(Seek(expect, res)) => { assert_eq!(expect, pos); res } Some(op) => panic!("expected call {:?}; was `seek`", op), None => panic!("did not expect call; was `seek`"), } } } impl fmt::Debug for File { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct("mock::File").finish() } } #[cfg(unix)] impl std::os::unix::io::AsRawFd for File { fn as_raw_fd(&self) -> std::os::unix::io::RawFd { unimplemented!(); } } #[cfg(unix)] impl std::os::unix::io::FromRawFd for File { unsafe fn from_raw_fd(_: std::os::unix::io::RawFd) -> Self { unimplemented!(); } } #[cfg(windows)] impl std::os::windows::io::AsRawHandle for File { fn as_raw_handle(&self) -> std::os::windows::io::RawHandle { unimplemented!(); } } #[cfg(windows)] impl std::os::windows::io::FromRawHandle for File { unsafe fn from_raw_handle(_: std::os::windows::io::RawHandle) -> Self { unimplemented!(); } }