mirror of
https://github.com/tokio-rs/tokio.git
synced 2026-08-25 00:00:18 +02:00
266 lines
6.8 KiB
Rust
266 lines
6.8 KiB
Rust
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<Mutex<Shared>>,
|
||
|
|
}
|
||
|
|
|
||
|
|
pub struct Handle {
|
||
|
|
shared: Arc<Mutex<Shared>>,
|
||
|
|
}
|
||
|
|
|
||
|
|
struct Shared {
|
||
|
|
calls: VecDeque<Call>,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug)]
|
||
|
|
enum Call {
|
||
|
|
Read(io::Result<Vec<u8>>),
|
||
|
|
Write(io::Result<Vec<u8>>),
|
||
|
|
Seek(SeekFrom, io::Result<u64>),
|
||
|
|
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<File> {
|
||
|
|
unimplemented!();
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn create(_: PathBuf) -> io::Result<File> {
|
||
|
|
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<Metadata> {
|
||
|
|
unimplemented!();
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn set_permissions(&self, _perm: Permissions) -> io::Result<()> {
|
||
|
|
unimplemented!();
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn try_clone(&self) -> io::Result<Self> {
|
||
|
|
unimplemented!();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
impl Read for &'_ File {
|
||
|
|
fn read(&mut self, dst: &mut [u8]) -> io::Result<usize> {
|
||
|
|
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<usize> {
|
||
|
|
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<u64> {
|
||
|
|
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()
|
||
|
|
}
|
||
|
|
}
|