mirror of
https://github.com/tokio-rs/bytes.git
synced 2026-08-07 00:00:13 +02:00
Expand Buf tests (#747)
This commit is contained in:
+379
-74
@@ -1,88 +1,410 @@
|
||||
#![warn(rust_2018_idioms)]
|
||||
|
||||
use bytes::Buf;
|
||||
use ::bytes::{Buf, Bytes, BytesMut};
|
||||
use core::{cmp, mem};
|
||||
use std::collections::VecDeque;
|
||||
#[cfg(feature = "std")]
|
||||
use std::io::IoSlice;
|
||||
|
||||
// A random 64-byte ascii string, with the first 8 bytes altered to
|
||||
// give valid representations of f32 and f64 (making them easier to compare)
|
||||
// and negative signed numbers when interpreting as big endian
|
||||
// (testing Sign Extension for `Buf::get_int' and `Buf::get_int_ne`).
|
||||
const INPUT: &[u8] = b"\xffFqrjrDqPhvTc45vvq33f6bJrUtyHESuTeklWKgYd64xgzxJwvAkpYYnpNJyZSRn";
|
||||
|
||||
macro_rules! e {
|
||||
($big_endian_val:expr, $little_endian_val:expr) => {
|
||||
if cfg!(target_endian = "big") {
|
||||
$big_endian_val
|
||||
} else {
|
||||
$little_endian_val
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! buf_tests {
|
||||
($make_input:ident) => {
|
||||
buf_tests!($make_input, true);
|
||||
};
|
||||
($make_input:ident, $checks_vectored_is_complete:expr) => {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_fresh_cursor_vec() {
|
||||
let mut buf = &b"hello"[..];
|
||||
|
||||
assert_eq!(buf.remaining(), 5);
|
||||
assert_eq!(buf.chunk(), b"hello");
|
||||
|
||||
buf.advance(2);
|
||||
|
||||
assert_eq!(buf.remaining(), 3);
|
||||
assert_eq!(buf.chunk(), b"llo");
|
||||
|
||||
buf.advance(3);
|
||||
|
||||
fn empty_state() {
|
||||
let buf = $make_input(&[]);
|
||||
assert_eq!(buf.remaining(), 0);
|
||||
assert_eq!(buf.chunk(), b"");
|
||||
assert!(!buf.has_remaining());
|
||||
assert!(buf.chunk().is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_u8() {
|
||||
let mut buf = &b"\x21zomg"[..];
|
||||
assert_eq!(0x21, buf.get_u8());
|
||||
fn fresh_state() {
|
||||
let buf = $make_input(INPUT);
|
||||
assert_eq!(buf.remaining(), 64);
|
||||
assert!(buf.has_remaining());
|
||||
|
||||
let chunk = buf.chunk();
|
||||
assert!(chunk.len() <= 64);
|
||||
assert!(INPUT.starts_with(chunk));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_u16() {
|
||||
let mut buf = &b"\x21\x54zomg"[..];
|
||||
assert_eq!(0x2154, buf.get_u16());
|
||||
let mut buf = &b"\x21\x54zomg"[..];
|
||||
assert_eq!(0x5421, buf.get_u16_le());
|
||||
fn advance() {
|
||||
let mut buf = $make_input(INPUT);
|
||||
buf.advance(8);
|
||||
assert_eq!(buf.remaining(), 64 - 8);
|
||||
assert!(buf.has_remaining());
|
||||
|
||||
let chunk = buf.chunk();
|
||||
assert!(chunk.len() <= 64 - 8);
|
||||
assert!(INPUT[8..].starts_with(chunk));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_int() {
|
||||
let mut buf = &b"\xd6zomg"[..];
|
||||
assert_eq!(-42, buf.get_int(1));
|
||||
let mut buf = &b"\xd6zomg"[..];
|
||||
assert_eq!(-42, buf.get_int_le(1));
|
||||
fn advance_to_end() {
|
||||
let mut buf = $make_input(INPUT);
|
||||
buf.advance(64);
|
||||
assert_eq!(buf.remaining(), 0);
|
||||
assert!(!buf.has_remaining());
|
||||
|
||||
let mut buf = &b"\xfe\x1d\xc0zomg"[..];
|
||||
assert_eq!(0xffffffffffc01dfeu64 as i64, buf.get_int_le(3));
|
||||
let mut buf = &b"\xfe\x1d\xc0zomg"[..];
|
||||
assert_eq!(0xfffffffffffe1dc0u64 as i64, buf.get_int(3));
|
||||
let chunk = buf.chunk();
|
||||
assert!(chunk.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_get_u16_buffer_underflow() {
|
||||
let mut buf = &b"\x21"[..];
|
||||
buf.get_u16();
|
||||
fn advance_past_end() {
|
||||
let mut buf = $make_input(INPUT);
|
||||
buf.advance(65);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "std")]
|
||||
fn chunks_vectored_empty() {
|
||||
let buf = $make_input(&[]);
|
||||
let mut bufs = [IoSlice::new(&[]); 16];
|
||||
|
||||
let n = buf.chunks_vectored(&mut bufs);
|
||||
assert_eq!(n, 0);
|
||||
assert!(bufs.iter().all(|buf| buf.is_empty()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "std")]
|
||||
fn chunks_vectored_is_complete() {
|
||||
let buf = $make_input(INPUT);
|
||||
let mut bufs = [IoSlice::new(&[]); 16];
|
||||
|
||||
let n = buf.chunks_vectored(&mut bufs);
|
||||
assert!(n > 0);
|
||||
assert!(n <= 16);
|
||||
|
||||
let bufs_concat = bufs[..n]
|
||||
.iter()
|
||||
.flat_map(|b| b.iter().copied())
|
||||
.collect::<Vec<u8>>();
|
||||
if $checks_vectored_is_complete {
|
||||
assert_eq!(bufs_concat, INPUT);
|
||||
} else {
|
||||
// If this panics then `buf` implements `chunks_vectored`.
|
||||
// Remove the `false` argument from `buf_tests!` for that type.
|
||||
assert!(bufs_concat.len() < INPUT.len());
|
||||
assert!(INPUT.starts_with(&bufs_concat));
|
||||
}
|
||||
|
||||
for i in n..16 {
|
||||
assert!(bufs[i].is_empty());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn copy_to_slice() {
|
||||
let mut buf = $make_input(INPUT);
|
||||
|
||||
let mut chunk = [0u8; 8];
|
||||
buf.copy_to_slice(&mut chunk);
|
||||
assert_eq!(buf.remaining(), 64 - 8);
|
||||
assert!(buf.has_remaining());
|
||||
assert_eq!(chunk, INPUT[..8]);
|
||||
|
||||
let chunk = buf.chunk();
|
||||
assert!(chunk.len() <= 64 - 8);
|
||||
assert!(INPUT[8..].starts_with(chunk));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn copy_to_slice_big() {
|
||||
let mut buf = $make_input(INPUT);
|
||||
|
||||
let mut chunk = [0u8; 56];
|
||||
buf.copy_to_slice(&mut chunk);
|
||||
assert_eq!(buf.remaining(), 64 - 56);
|
||||
assert!(buf.has_remaining());
|
||||
assert_eq!(chunk, INPUT[..56]);
|
||||
|
||||
let chunk = buf.chunk();
|
||||
assert!(chunk.len() <= 64 - 56);
|
||||
assert!(INPUT[56..].starts_with(chunk));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn copy_to_slice_to_end() {
|
||||
let mut buf = $make_input(INPUT);
|
||||
|
||||
let mut chunk = [0u8; 64];
|
||||
buf.copy_to_slice(&mut chunk);
|
||||
assert_eq!(buf.remaining(), 0);
|
||||
assert!(!buf.has_remaining());
|
||||
assert_eq!(chunk, INPUT);
|
||||
|
||||
assert!(buf.chunk().is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn copy_to_slice_overflow() {
|
||||
let mut buf = $make_input(INPUT);
|
||||
|
||||
let mut chunk = [0u8; 65];
|
||||
buf.copy_to_slice(&mut chunk);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn copy_to_bytes() {
|
||||
let mut buf = $make_input(INPUT);
|
||||
|
||||
let chunk = buf.copy_to_bytes(8);
|
||||
assert_eq!(buf.remaining(), 64 - 8);
|
||||
assert!(buf.has_remaining());
|
||||
assert_eq!(chunk, INPUT[..8]);
|
||||
|
||||
let chunk = buf.chunk();
|
||||
assert!(chunk.len() <= 64 - 8);
|
||||
assert!(INPUT[8..].starts_with(chunk));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn copy_to_bytes_big() {
|
||||
let mut buf = $make_input(INPUT);
|
||||
|
||||
let chunk = buf.copy_to_bytes(56);
|
||||
assert_eq!(buf.remaining(), 64 - 56);
|
||||
assert!(buf.has_remaining());
|
||||
assert_eq!(chunk, INPUT[..56]);
|
||||
|
||||
let chunk = buf.chunk();
|
||||
assert!(chunk.len() <= 64 - 56);
|
||||
assert!(INPUT[56..].starts_with(chunk));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn copy_to_bytes_to_end() {
|
||||
let mut buf = $make_input(INPUT);
|
||||
|
||||
let chunk = buf.copy_to_bytes(64);
|
||||
assert_eq!(buf.remaining(), 0);
|
||||
assert!(!buf.has_remaining());
|
||||
assert_eq!(chunk, INPUT);
|
||||
|
||||
assert!(buf.chunk().is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn copy_to_bytes_overflow() {
|
||||
let mut buf = $make_input(INPUT);
|
||||
|
||||
let _ = buf.copy_to_bytes(65);
|
||||
}
|
||||
|
||||
buf_tests!(number $make_input, get_u8, get_u8_overflow, u8, get_u8, 0xff);
|
||||
buf_tests!(number $make_input, get_i8, get_i8_overflow, i8, get_i8, 0xffu8 as i8);
|
||||
buf_tests!(number $make_input, get_u16_be, get_u16_be_overflow, u16, get_u16, 0xff46);
|
||||
buf_tests!(number $make_input, get_u16_le, get_u16_le_overflow, u16, get_u16_le, 0x46ff);
|
||||
buf_tests!(number $make_input, get_u16_ne, get_u16_ne_overflow, u16, get_u16_ne, e!(0xff46, 0x46ff));
|
||||
buf_tests!(number $make_input, get_i16_be, get_i16_be_overflow, i16, get_i16, 0xff46u16 as i16);
|
||||
buf_tests!(number $make_input, get_i16_le, get_i16_le_overflow, i16, get_i16_le, 0x46ff);
|
||||
buf_tests!(number $make_input, get_i16_ne, get_i16_ne_overflow, i16, get_i16_ne, e!(0xff46u16 as i16, 0x46ff));
|
||||
buf_tests!(number $make_input, get_u32_be, get_u32_be_overflow, u32, get_u32, 0xff467172);
|
||||
buf_tests!(number $make_input, get_u32_le, get_u32_le_overflow, u32, get_u32_le, 0x727146ff);
|
||||
buf_tests!(number $make_input, get_u32_ne, get_u32_ne_overflow, u32, get_u32_ne, e!(0xff467172, 0x727146ff));
|
||||
buf_tests!(number $make_input, get_i32_be, get_i32_be_overflow, i32, get_i32, 0xff467172u32 as i32);
|
||||
buf_tests!(number $make_input, get_i32_le, get_i32_le_overflow, i32, get_i32_le, 0x727146ff);
|
||||
buf_tests!(number $make_input, get_i32_ne, get_i32_ne_overflow, i32, get_i32_ne, e!(0xff467172u32 as i32, 0x727146ff));
|
||||
buf_tests!(number $make_input, get_u64_be, get_u64_be_overflow, u64, get_u64, 0xff4671726a724471);
|
||||
buf_tests!(number $make_input, get_u64_le, get_u64_le_overflow, u64, get_u64_le, 0x7144726a727146ff);
|
||||
buf_tests!(number $make_input, get_u64_ne, get_u64_ne_overflow, u64, get_u64_ne, e!(0xff4671726a724471, 0x7144726a727146ff));
|
||||
buf_tests!(number $make_input, get_i64_be, get_i64_be_overflow, i64, get_i64, 0xff4671726a724471u64 as i64);
|
||||
buf_tests!(number $make_input, get_i64_le, get_i64_le_overflow, i64, get_i64_le, 0x7144726a727146ff);
|
||||
buf_tests!(number $make_input, get_i64_ne, get_i64_ne_overflow, i64, get_i64_ne, e!(0xff4671726a724471u64 as i64, 0x7144726a727146ff));
|
||||
buf_tests!(number $make_input, get_u128_be, get_u128_be_overflow, u128, get_u128, 0xff4671726a7244715068765463343576);
|
||||
buf_tests!(number $make_input, get_u128_le, get_u128_le_overflow, u128, get_u128_le, 0x76353463547668507144726a727146ff);
|
||||
buf_tests!(number $make_input, get_u128_ne, get_u128_ne_overflow, u128, get_u128_ne, e!(0xff4671726a7244715068765463343576, 0x76353463547668507144726a727146ff));
|
||||
buf_tests!(number $make_input, get_i128_be, get_i128_be_overflow, i128, get_i128, 0xff4671726a7244715068765463343576u128 as i128);
|
||||
buf_tests!(number $make_input, get_i128_le, get_i128_le_overflow, i128, get_i128_le, 0x76353463547668507144726a727146ff);
|
||||
buf_tests!(number $make_input, get_i128_ne, get_i128_ne_overflow, i128, get_i128_ne, e!(0xff4671726a7244715068765463343576u128 as i128, 0x76353463547668507144726a727146ff));
|
||||
buf_tests!(number $make_input, get_f32_be, get_f32_be_overflow, f32, get_f32, f32::from_bits(0xff467172));
|
||||
buf_tests!(number $make_input, get_f32_le, get_f32_le_overflow, f32, get_f32_le, f32::from_bits(0x727146ff));
|
||||
buf_tests!(number $make_input, get_f32_ne, get_f32_ne_overflow, f32, get_f32_ne, f32::from_bits(e!(0xff467172, 0x727146ff)));
|
||||
buf_tests!(number $make_input, get_f64_be, get_f64_be_overflow, f64, get_f64, f64::from_bits(0xff4671726a724471));
|
||||
buf_tests!(number $make_input, get_f64_le, get_f64_le_overflow, f64, get_f64_le, f64::from_bits(0x7144726a727146ff));
|
||||
buf_tests!(number $make_input, get_f64_ne, get_f64_ne_overflow, f64, get_f64_ne, f64::from_bits(e!(0xff4671726a724471, 0x7144726a727146ff)));
|
||||
|
||||
buf_tests!(var_number $make_input, get_uint_be, get_uint_be_overflow, u64, get_uint, 3, 0xff4671);
|
||||
buf_tests!(var_number $make_input, get_uint_le, get_uint_le_overflow, u64, get_uint_le, 3, 0x7146ff);
|
||||
buf_tests!(var_number $make_input, get_uint_ne, get_uint_ne_overflow, u64, get_uint_ne, 3, e!(0xff4671, 0x7146ff));
|
||||
buf_tests!(var_number $make_input, get_int_be, get_int_be_overflow, i64, get_int, 3, 0xffffffffffff4671u64 as i64);
|
||||
buf_tests!(var_number $make_input, get_int_le, get_int_le_overflow, i64, get_int_le, 3, 0x7146ff);
|
||||
buf_tests!(var_number $make_input, get_int_ne, get_int_ne_overflow, i64, get_int_ne, 3, e!(0xffffffffffff4671u64 as i64, 0x7146ff));
|
||||
};
|
||||
(number $make_input:ident, $ok_name:ident, $panic_name:ident, $number:ty, $method:ident, $value:expr) => {
|
||||
#[test]
|
||||
fn $ok_name() {
|
||||
let mut buf = $make_input(INPUT);
|
||||
|
||||
let value = buf.$method();
|
||||
assert_eq!(buf.remaining(), 64 - mem::size_of::<$number>());
|
||||
assert!(buf.has_remaining());
|
||||
assert_eq!(value, $value);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn $panic_name() {
|
||||
let mut buf = $make_input(&[]);
|
||||
|
||||
let _ = buf.$method();
|
||||
}
|
||||
};
|
||||
(var_number $make_input:ident, $ok_name:ident, $panic_name:ident, $number:ty, $method:ident, $len:expr, $value:expr) => {
|
||||
#[test]
|
||||
fn $ok_name() {
|
||||
let mut buf = $make_input(INPUT);
|
||||
|
||||
let value = buf.$method($len);
|
||||
assert_eq!(buf.remaining(), 64 - $len);
|
||||
assert!(buf.has_remaining());
|
||||
assert_eq!(value, $value);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn $panic_name() {
|
||||
let mut buf = $make_input(&[]);
|
||||
|
||||
let _ = buf.$method($len);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
mod u8_slice {
|
||||
fn make_input(buf: &'static [u8]) -> &'static [u8] {
|
||||
buf
|
||||
}
|
||||
|
||||
buf_tests!(make_input);
|
||||
}
|
||||
|
||||
mod bytes {
|
||||
fn make_input(buf: &'static [u8]) -> impl Buf {
|
||||
Bytes::from_static(buf)
|
||||
}
|
||||
|
||||
buf_tests!(make_input);
|
||||
}
|
||||
|
||||
mod bytes_mut {
|
||||
fn make_input(buf: &'static [u8]) -> impl Buf {
|
||||
BytesMut::from(buf)
|
||||
}
|
||||
|
||||
buf_tests!(make_input);
|
||||
}
|
||||
|
||||
mod vec_deque {
|
||||
fn make_input(buf: &'static [u8]) -> impl Buf {
|
||||
let mut deque = VecDeque::new();
|
||||
|
||||
if !buf.is_empty() {
|
||||
// Construct |b|some bytes|a| `VecDeque`
|
||||
let mid = buf.len() / 2;
|
||||
let (a, b) = buf.split_at(mid);
|
||||
|
||||
deque.reserve_exact(buf.len() + 1);
|
||||
|
||||
let extra_space = deque.capacity() - b.len() - 1;
|
||||
deque.resize(extra_space, 0);
|
||||
|
||||
deque.extend(a);
|
||||
deque.drain(..extra_space);
|
||||
deque.extend(b);
|
||||
|
||||
let (a, b) = deque.as_slices();
|
||||
assert!(
|
||||
!a.is_empty(),
|
||||
"could not setup test - attempt to create discontiguous VecDeque failed"
|
||||
);
|
||||
assert!(
|
||||
!b.is_empty(),
|
||||
"could not setup test - attempt to create discontiguous VecDeque failed"
|
||||
);
|
||||
}
|
||||
|
||||
deque
|
||||
}
|
||||
|
||||
buf_tests!(make_input, /* `VecDeque` does not do `chucks_vectored */ false);
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[test]
|
||||
fn test_bufs_vec() {
|
||||
let buf = &b"hello world"[..];
|
||||
mod cursor {
|
||||
use std::io::Cursor;
|
||||
|
||||
let b1: &[u8] = &mut [];
|
||||
let b2: &[u8] = &mut [];
|
||||
|
||||
let mut dst = [IoSlice::new(b1), IoSlice::new(b2)];
|
||||
|
||||
assert_eq!(1, buf.chunks_vectored(&mut dst[..]));
|
||||
fn make_input(buf: &'static [u8]) -> impl Buf {
|
||||
Cursor::new(buf)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_vec_deque() {
|
||||
use std::collections::VecDeque;
|
||||
buf_tests!(make_input);
|
||||
}
|
||||
|
||||
let mut buffer: VecDeque<u8> = VecDeque::new();
|
||||
buffer.extend(b"hello world");
|
||||
assert_eq!(11, buffer.remaining());
|
||||
assert_eq!(b"hello world", buffer.chunk());
|
||||
buffer.advance(6);
|
||||
assert_eq!(b"world", buffer.chunk());
|
||||
buffer.extend(b" piece");
|
||||
let mut out = [0; 11];
|
||||
buffer.copy_to_slice(&mut out);
|
||||
assert_eq!(b"world piece", &out[..]);
|
||||
mod box_bytes {
|
||||
fn make_input(buf: &'static [u8]) -> impl Buf {
|
||||
Box::new(Bytes::from_static(buf))
|
||||
}
|
||||
|
||||
buf_tests!(make_input);
|
||||
}
|
||||
|
||||
mod chain_u8_slice {
|
||||
fn make_input(buf: &'static [u8]) -> impl Buf {
|
||||
let (a, b) = buf.split_at(buf.len() / 2);
|
||||
Buf::chain(a, b)
|
||||
}
|
||||
|
||||
buf_tests!(make_input);
|
||||
}
|
||||
|
||||
mod chain_small_big_u8_slice {
|
||||
fn make_input(buf: &'static [u8]) -> impl Buf {
|
||||
let mid = cmp::min(1, buf.len());
|
||||
let (a, b) = buf.split_at(mid);
|
||||
Buf::chain(a, b)
|
||||
}
|
||||
|
||||
buf_tests!(make_input);
|
||||
}
|
||||
|
||||
mod chain_limited_slices {
|
||||
fn make_input(buf: &'static [u8]) -> impl Buf {
|
||||
let buf3 = &buf[cmp::min(buf.len(), 3)..];
|
||||
let a = Buf::take(buf3, 0);
|
||||
let b = Buf::take(buf, 3);
|
||||
let c = Buf::take(buf3, usize::MAX);
|
||||
let d = buf;
|
||||
Buf::take(Buf::chain(Buf::chain(a, b), Buf::chain(c, d)), buf.len())
|
||||
}
|
||||
|
||||
buf_tests!(make_input, /* `Limit` does not forward `chucks_vectored */ false);
|
||||
}
|
||||
|
||||
#[allow(unused_allocation)] // This is intentional.
|
||||
@@ -115,20 +437,3 @@ fn test_deref_buf_forwards() {
|
||||
assert_eq!((Box::new(Special) as Box<dyn Buf>).get_u8(), b'x');
|
||||
assert_eq!(Box::new(Special).get_u8(), b'x');
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn copy_to_bytes_less() {
|
||||
let mut buf = &b"hello world"[..];
|
||||
|
||||
let bytes = buf.copy_to_bytes(5);
|
||||
assert_eq!(bytes, &b"hello"[..]);
|
||||
assert_eq!(buf, &b" world"[..])
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn copy_to_bytes_overflow() {
|
||||
let mut buf = &b"hello world"[..];
|
||||
|
||||
let _bytes = buf.copy_to_bytes(12);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user