use std::fmt; use std::io::{self, Read, Write, Cursor}; use std::net::SocketAddr; use net::{NetworkStream, NetworkConnector}; pub struct MockStream { pub read: Cursor>, pub write: Vec, } impl Clone for MockStream { fn clone(&self) -> MockStream { MockStream { read: Cursor::new(self.read.get_ref().clone()), write: self.write.clone() } } } impl fmt::Debug for MockStream { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "MockStream {{ read: {:?}, write: {:?} }}", self.read.get_ref(), self.write) } } impl PartialEq for MockStream { fn eq(&self, other: &MockStream) -> bool { self.read.get_ref() == other.read.get_ref() && self.write == other.write } } impl MockStream { pub fn new() -> MockStream { MockStream { read: Cursor::new(vec![]), write: vec![], } } pub fn with_input(input: &[u8]) -> MockStream { MockStream { read: Cursor::new(input.to_vec()), write: vec![] } } } impl Read for MockStream { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.read.read(buf) } } impl Write for MockStream { fn write(&mut self, msg: &[u8]) -> io::Result { Write::write(&mut self.write, msg) } fn flush(&mut self) -> io::Result<()> { Ok(()) } } impl NetworkStream for MockStream { fn peer_addr(&mut self) -> io::Result { Ok("127.0.0.1:1337".parse().unwrap()) } } pub struct MockConnector; impl NetworkConnector for MockConnector { type Stream = MockStream; fn connect(&mut self, _host: &str, _port: u16, _scheme: &str) -> io::Result { Ok(MockStream::new()) } } /// new connectors must be created if you wish to intercept requests. macro_rules! mock_connector ( ($name:ident { $($url:expr => $res:expr)* }) => ( struct $name; impl ::net::NetworkConnector for $name { type Stream = ::mock::MockStream; fn connect(&mut self, host: &str, port: u16, scheme: &str) -> ::std::io::Result<::mock::MockStream> { use std::collections::HashMap; use std::io::Cursor; debug!("MockStream::connect({:?}, {:?}, {:?})", host, port, scheme); let mut map = HashMap::new(); $(map.insert($url, $res);)* let key = format!("{}://{}", scheme, host); // ignore port for now match map.get(&*key) { Some(res) => Ok(::mock::MockStream { write: vec![], read: Cursor::new(res.to_string().into_bytes()), }), None => panic!("{:?} doesn't know url {}", stringify!($name), key) } } } ) );