Move unit tests inside conditionally compiled mod tests { } blocks
Idiomatic rust organizes unit tests into `mod tests { }` blocks
using conditional compilation `[cfg(test)]` to decide whether to
compile the code in that block.
This commit moves "bare" test functions into such blocks, and puts
the block at the bottom of respective file.
This commit is contained in:
39
src/body.rs
39
src/body.rs
@@ -150,8 +150,27 @@ fn copy_chunked<R: Read, W: Write>(reader: &mut R, writer: &mut W) -> io::Result
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_copy_chunked() {
|
||||
/// Helper to send a body, either as chunked or not.
|
||||
pub(crate) fn send_body(
|
||||
mut body: SizedReader,
|
||||
do_chunk: bool,
|
||||
stream: &mut Stream,
|
||||
) -> io::Result<()> {
|
||||
if do_chunk {
|
||||
copy_chunked(&mut body.reader, stream)?;
|
||||
} else {
|
||||
copy(&mut body.reader, stream)?;
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_copy_chunked() {
|
||||
let mut source = Vec::<u8>::new();
|
||||
source.resize(CHUNK_MAX_PAYLOAD_SIZE, 33);
|
||||
source.extend_from_slice(b"hello world");
|
||||
@@ -168,19 +187,5 @@ fn test_copy_chunked() {
|
||||
dest_expected.extend_from_slice(b"0\r\n\r\n");
|
||||
|
||||
assert_eq!(dest, dest_expected);
|
||||
}
|
||||
|
||||
/// Helper to send a body, either as chunked or not.
|
||||
pub(crate) fn send_body(
|
||||
mut body: SizedReader,
|
||||
do_chunk: bool,
|
||||
stream: &mut Stream,
|
||||
) -> io::Result<()> {
|
||||
if do_chunk {
|
||||
copy_chunked(&mut body.reader, stream)?;
|
||||
} else {
|
||||
copy(&mut body.reader, stream)?;
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
33
src/error.rs
33
src/error.rs
@@ -342,17 +342,21 @@ impl fmt::Display for ErrorKind {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn status_code_error() {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn status_code_error() {
|
||||
let mut response = Response::new(404, "NotFound", "").unwrap();
|
||||
response.set_url("http://example.org/".parse().unwrap());
|
||||
let err = Error::Status(response.status(), response);
|
||||
|
||||
assert_eq!(err.to_string(), "http://example.org/: status code 404");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn status_code_error_redirect() {
|
||||
#[test]
|
||||
fn status_code_error_redirect() {
|
||||
use crate::{get, test};
|
||||
|
||||
test::set_handler("/redirect_a", |unit| {
|
||||
@@ -380,10 +384,10 @@ fn status_code_error_redirect() {
|
||||
err.to_string(),
|
||||
"http://example.com/status/500: status code 500 (redirected from test://example.org/redirect_a)"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn io_error() {
|
||||
#[test]
|
||||
fn io_error() {
|
||||
let ioe = io::Error::new(io::ErrorKind::TimedOut, "too slow");
|
||||
let mut err = Error::new(ErrorKind::Io, Some("oops".to_string())).src(ioe);
|
||||
|
||||
@@ -392,10 +396,10 @@ fn io_error() {
|
||||
err.to_string(),
|
||||
"http://example.com/: Network Error: oops: too slow"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn connection_closed() {
|
||||
#[test]
|
||||
fn connection_closed() {
|
||||
let ioe = io::Error::new(io::ErrorKind::ConnectionReset, "connection reset");
|
||||
let err = ErrorKind::Io.new().src(ioe);
|
||||
assert!(err.connection_closed());
|
||||
@@ -403,12 +407,13 @@ fn connection_closed() {
|
||||
let ioe = io::Error::new(io::ErrorKind::ConnectionAborted, "connection aborted");
|
||||
let err = ErrorKind::Io.new().src(ioe);
|
||||
assert!(err.connection_closed());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn error_is_send_and_sync() {
|
||||
#[test]
|
||||
fn error_is_send_and_sync() {
|
||||
fn takes_send(_: impl Send) {}
|
||||
fn takes_sync(_: impl Sync) {}
|
||||
takes_send(crate::error::ErrorKind::InvalidUrl.new());
|
||||
takes_sync(crate::error::ErrorKind::InvalidUrl.new());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,8 +145,12 @@ impl FromStr for Header {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_valid_name() {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_valid_name() {
|
||||
assert!(valid_name("example"));
|
||||
assert!(valid_name("Content-Type"));
|
||||
assert!(valid_name("h-123456789"));
|
||||
@@ -155,10 +159,10 @@ fn test_valid_name() {
|
||||
assert!(!valid_name(" some-header"));
|
||||
assert!(!valid_name("\"invalid\""));
|
||||
assert!(!valid_name("Gödel"));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_valid_value() {
|
||||
#[test]
|
||||
fn test_valid_value() {
|
||||
assert!(valid_value("example"));
|
||||
assert!(valid_value("foo bar"));
|
||||
assert!(valid_value(" foobar "));
|
||||
@@ -168,10 +172,10 @@ fn test_valid_value() {
|
||||
assert!(valid_value(" "));
|
||||
assert!(!valid_value(" \nfoo"));
|
||||
assert!(!valid_value("foo\x7F"));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_invalid_name() {
|
||||
#[test]
|
||||
fn test_parse_invalid_name() {
|
||||
let cases = vec![
|
||||
"Content-Type :",
|
||||
" Content-Type: foo",
|
||||
@@ -191,26 +195,27 @@ fn test_parse_invalid_name() {
|
||||
result
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_value() {
|
||||
#[test]
|
||||
fn empty_value() {
|
||||
let h = "foo:".parse::<Header>().unwrap();
|
||||
assert_eq!(h.value(), "");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn value_with_whitespace() {
|
||||
#[test]
|
||||
fn value_with_whitespace() {
|
||||
let h = "foo: bar ".parse::<Header>().unwrap();
|
||||
assert_eq!(h.value(), "bar");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn name_and_value() {
|
||||
#[test]
|
||||
fn name_and_value() {
|
||||
let header: Header = "X-Forwarded-For: 127.0.0.1".parse().unwrap();
|
||||
assert_eq!("X-Forwarded-For", header.name());
|
||||
assert_eq!("127.0.0.1", header.value());
|
||||
assert!(header.is_name("X-Forwarded-For"));
|
||||
assert!(header.is_name("x-forwarded-for"));
|
||||
assert!(header.is_name("X-FORWARDED-FOR"));
|
||||
}
|
||||
}
|
||||
|
||||
169
src/pool.rs
169
src/pool.rs
@@ -219,88 +219,6 @@ impl PoolKey {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn poolkey_new() {
|
||||
// Test that PoolKey::new() does not panic on unrecognized schemes.
|
||||
PoolKey::new(&Url::parse("zzz:///example.com").unwrap(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pool_connections_limit() {
|
||||
// Test inserting connections with different keys into the pool,
|
||||
// filling and draining it. The pool should evict earlier connections
|
||||
// when the connection limit is reached.
|
||||
let pool = ConnectionPool::new_with_limits(10, 1);
|
||||
let hostnames = (0..pool.max_idle_connections * 2).map(|i| format!("{}.example", i));
|
||||
let poolkeys = hostnames.map(|hostname| PoolKey {
|
||||
scheme: "https".to_string(),
|
||||
hostname,
|
||||
port: Some(999),
|
||||
proxy: None,
|
||||
});
|
||||
for key in poolkeys.clone() {
|
||||
pool.add(key, Stream::from_vec(vec![]))
|
||||
}
|
||||
assert_eq!(pool.len(), pool.max_idle_connections);
|
||||
|
||||
for key in poolkeys.skip(pool.max_idle_connections) {
|
||||
let result = pool.remove(&key);
|
||||
assert!(result.is_some(), "expected key was not in pool");
|
||||
}
|
||||
assert_eq!(pool.len(), 0)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pool_per_host_connections_limit() {
|
||||
// Test inserting connections with the same key into the pool,
|
||||
// filling and draining it. The pool should evict earlier connections
|
||||
// when the per-host connection limit is reached.
|
||||
let pool = ConnectionPool::new_with_limits(10, 2);
|
||||
let poolkey = PoolKey {
|
||||
scheme: "https".to_string(),
|
||||
hostname: "example.com".to_string(),
|
||||
port: Some(999),
|
||||
proxy: None,
|
||||
};
|
||||
|
||||
for _ in 0..pool.max_idle_connections_per_host * 2 {
|
||||
pool.add(poolkey.clone(), Stream::from_vec(vec![]))
|
||||
}
|
||||
assert_eq!(pool.len(), pool.max_idle_connections_per_host);
|
||||
|
||||
for _ in 0..pool.max_idle_connections_per_host {
|
||||
let result = pool.remove(&poolkey);
|
||||
assert!(result.is_some(), "expected key was not in pool");
|
||||
}
|
||||
assert_eq!(pool.len(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pool_checks_proxy() {
|
||||
// Test inserting different poolkeys with same address but different proxies.
|
||||
// Each insertion should result in an additional entry in the pool.
|
||||
let pool = ConnectionPool::new_with_limits(10, 1);
|
||||
let url = Url::parse("zzz:///example.com").unwrap();
|
||||
|
||||
pool.add(PoolKey::new(&url, None), Stream::from_vec(vec![]));
|
||||
assert_eq!(pool.len(), 1);
|
||||
|
||||
pool.add(
|
||||
PoolKey::new(&url, Some(Proxy::new("localhost:9999").unwrap())),
|
||||
Stream::from_vec(vec![]),
|
||||
);
|
||||
assert_eq!(pool.len(), 2);
|
||||
|
||||
pool.add(
|
||||
PoolKey::new(
|
||||
&url,
|
||||
Some(Proxy::new("user:password@localhost:9999").unwrap()),
|
||||
),
|
||||
Stream::from_vec(vec![]),
|
||||
);
|
||||
assert_eq!(pool.len(), 3);
|
||||
}
|
||||
|
||||
/// Read wrapper that returns the stream to the pool once the
|
||||
/// read is exhausted (reached a 0).
|
||||
///
|
||||
@@ -360,3 +278,90 @@ impl<R: Read + Sized + Into<Stream>> Read for PoolReturnRead<R> {
|
||||
Ok(amount)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn poolkey_new() {
|
||||
// Test that PoolKey::new() does not panic on unrecognized schemes.
|
||||
PoolKey::new(&Url::parse("zzz:///example.com").unwrap(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pool_connections_limit() {
|
||||
// Test inserting connections with different keys into the pool,
|
||||
// filling and draining it. The pool should evict earlier connections
|
||||
// when the connection limit is reached.
|
||||
let pool = ConnectionPool::new_with_limits(10, 1);
|
||||
let hostnames = (0..pool.max_idle_connections * 2).map(|i| format!("{}.example", i));
|
||||
let poolkeys = hostnames.map(|hostname| PoolKey {
|
||||
scheme: "https".to_string(),
|
||||
hostname,
|
||||
port: Some(999),
|
||||
proxy: None,
|
||||
});
|
||||
for key in poolkeys.clone() {
|
||||
pool.add(key, Stream::from_vec(vec![]))
|
||||
}
|
||||
assert_eq!(pool.len(), pool.max_idle_connections);
|
||||
|
||||
for key in poolkeys.skip(pool.max_idle_connections) {
|
||||
let result = pool.remove(&key);
|
||||
assert!(result.is_some(), "expected key was not in pool");
|
||||
}
|
||||
assert_eq!(pool.len(), 0)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pool_per_host_connections_limit() {
|
||||
// Test inserting connections with the same key into the pool,
|
||||
// filling and draining it. The pool should evict earlier connections
|
||||
// when the per-host connection limit is reached.
|
||||
let pool = ConnectionPool::new_with_limits(10, 2);
|
||||
let poolkey = PoolKey {
|
||||
scheme: "https".to_string(),
|
||||
hostname: "example.com".to_string(),
|
||||
port: Some(999),
|
||||
proxy: None,
|
||||
};
|
||||
|
||||
for _ in 0..pool.max_idle_connections_per_host * 2 {
|
||||
pool.add(poolkey.clone(), Stream::from_vec(vec![]))
|
||||
}
|
||||
assert_eq!(pool.len(), pool.max_idle_connections_per_host);
|
||||
|
||||
for _ in 0..pool.max_idle_connections_per_host {
|
||||
let result = pool.remove(&poolkey);
|
||||
assert!(result.is_some(), "expected key was not in pool");
|
||||
}
|
||||
assert_eq!(pool.len(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pool_checks_proxy() {
|
||||
// Test inserting different poolkeys with same address but different proxies.
|
||||
// Each insertion should result in an additional entry in the pool.
|
||||
let pool = ConnectionPool::new_with_limits(10, 1);
|
||||
let url = Url::parse("zzz:///example.com").unwrap();
|
||||
|
||||
pool.add(PoolKey::new(&url, None), Stream::from_vec(vec![]));
|
||||
assert_eq!(pool.len(), 1);
|
||||
|
||||
pool.add(
|
||||
PoolKey::new(&url, Some(Proxy::new("localhost:9999").unwrap())),
|
||||
Stream::from_vec(vec![]),
|
||||
);
|
||||
assert_eq!(pool.len(), 2);
|
||||
|
||||
pool.add(
|
||||
PoolKey::new(
|
||||
&url,
|
||||
Some(Proxy::new("user:password@localhost:9999").unwrap()),
|
||||
),
|
||||
Stream::from_vec(vec![]),
|
||||
);
|
||||
assert_eq!(pool.len(), 3);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,8 +171,7 @@ Proxy-Connection: Keep-Alive\r\n\
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::Proto;
|
||||
use super::Proxy;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn parse_proxy_fakeproto() {
|
||||
|
||||
@@ -397,8 +397,12 @@ impl Request {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn request_implements_send_and_sync() {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn request_implements_send_and_sync() {
|
||||
let _request: Box<dyn Send> = Box::new(Request::new(
|
||||
Agent::new(),
|
||||
"GET".to_string(),
|
||||
@@ -409,13 +413,14 @@ fn request_implements_send_and_sync() {
|
||||
"GET".to_string(),
|
||||
"https://example.com/".to_string(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn send_byte_slice() {
|
||||
#[test]
|
||||
fn send_byte_slice() {
|
||||
let bytes = vec![1, 2, 3];
|
||||
crate::agent()
|
||||
.post("http://example.com")
|
||||
.send(&bytes[1..2])
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -632,15 +632,6 @@ impl<R: Read> Read for LimitedRead<R> {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn short_read() {
|
||||
use std::io::Cursor;
|
||||
let mut lr = LimitedRead::new(Cursor::new(vec![b'a'; 3]), 10);
|
||||
let mut buf = vec![0; 1000];
|
||||
let result = lr.read_to_end(&mut buf);
|
||||
assert!(result.err().unwrap().kind() == io::ErrorKind::UnexpectedEof);
|
||||
}
|
||||
|
||||
impl<R: Read> From<LimitedRead<R>> for Stream
|
||||
where
|
||||
Stream: From<R>,
|
||||
@@ -667,10 +658,30 @@ pub(crate) fn charset_from_content_type(header: Option<&str>) -> &str {
|
||||
.unwrap_or(DEFAULT_CHARACTER_SET)
|
||||
}
|
||||
|
||||
// ErrorReader returns an error for every read.
|
||||
// The error is as close to a clone of the underlying
|
||||
// io::Error as we can get.
|
||||
struct ErrorReader(io::Error);
|
||||
|
||||
impl Read for ErrorReader {
|
||||
fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> {
|
||||
Err(io::Error::new(self.0.kind(), self.0.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn short_read() {
|
||||
use std::io::Cursor;
|
||||
let mut lr = LimitedRead::new(Cursor::new(vec![b'a'; 3]), 10);
|
||||
let mut buf = vec![0; 1000];
|
||||
let result = lr.read_to_end(&mut buf);
|
||||
assert!(result.err().unwrap().kind() == io::ErrorKind::UnexpectedEof);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn content_type_without_charset() {
|
||||
let s = "HTTP/1.1 200 OK\r\n\
|
||||
@@ -823,14 +834,3 @@ mod tests {
|
||||
assert_eq!(hist, ["http://1.example.com/", "http://2.example.com/"])
|
||||
}
|
||||
}
|
||||
|
||||
// ErrorReader returns an error for every read.
|
||||
// The error is as close to a clone of the underlying
|
||||
// io::Error as we can get.
|
||||
struct ErrorReader(io::Error);
|
||||
|
||||
impl Read for ErrorReader {
|
||||
fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> {
|
||||
Err(io::Error::new(self.0.kind(), self.0.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user