mod common;
use std::io::{self, Cursor, Read, Seek, SeekFrom};
use common::{fixture_bytes, open, vector};
use wav_codec::{Error, Sample, SampleFormat, WavReader, WavSpec, WavSpecEx, WavWriter};
fn spec(channels: u16, bits: u16, format: SampleFormat) -> WavSpec {
WavSpec {
channels,
sample_rate: 8000,
bits_per_sample: bits,
sample_format: format,
}
}
fn write_all<S: Sample>(spec_ex: WavSpecEx, samples: &[S]) -> Vec<u8> {
let mut out = Cursor::new(Vec::new());
let mut w = WavWriter::new_with_spec_ex(&mut out, spec_ex).unwrap();
w.write_samples(samples).unwrap();
w.finalize().unwrap();
out.into_inner()
}
fn ex(spec: WavSpec, bytes_per_sample: u16) -> WavSpecEx {
WavSpecEx {
spec,
bytes_per_sample,
}
}
fn chunk_ids(bytes: &[u8]) -> Vec<(String, u32)> {
let mut out = Vec::new();
let mut pos = 12;
while pos + 8 <= bytes.len() {
let id = String::from_utf8_lossy(&bytes[pos..pos + 4]).into_owned();
let size = u32::from_le_bytes([
bytes[pos + 4],
bytes[pos + 5],
bytes[pos + 6],
bytes[pos + 7],
]);
out.push((id, size));
pos += 8 + size as usize + (size & 1) as usize;
}
out
}
#[test]
fn eight_bit_maps_to_i8_and_back() {
let bytes = fixture_bytes(&vector("V01"));
let got: Vec<i8> = open(&bytes)
.unwrap()
.samples()
.map(Result::unwrap)
.collect();
assert_eq!(got, [-128, -127, -1, 0, 127]);
let wide: Vec<i16> = open(&bytes)
.unwrap()
.samples()
.map(Result::unwrap)
.collect();
assert_eq!(wide, [-128, -127, -1, 0, 127]);
let written = write_all(ex(spec(1, 8, SampleFormat::Int), 1), &wide);
assert_eq!(&written[44..49], &bytes[44..49]);
}
#[test]
fn writer_picks_the_canonical_header_per_spec() {
let pcm16 = write_all(ex(spec(2, 16, SampleFormat::Int), 2), &[1i16, 2]);
assert_eq!(chunk_ids(&pcm16), [("fmt ".into(), 16), ("data".into(), 4)]);
let pcm24 = write_all(ex(spec(1, 24, SampleFormat::Int), 3), &[1i32]);
assert_eq!(chunk_ids(&pcm24), [("fmt ".into(), 16), ("data".into(), 3)]);
let f32_mono = write_all(ex(spec(1, 32, SampleFormat::Float), 4), &[0.5f32]);
assert_eq!(
chunk_ids(&f32_mono),
[("fmt ".into(), 18), ("fact".into(), 4), ("data".into(), 4)]
);
let fact = u32::from_le_bytes([f32_mono[46], f32_mono[47], f32_mono[48], f32_mono[49]]);
assert_eq!(fact, 1, "fact carries the frame count");
let six = write_all(ex(spec(6, 16, SampleFormat::Int), 2), &[0i16; 12]);
assert_eq!(chunk_ids(&six), [("fmt ".into(), 40), ("data".into(), 24)]);
let reader = open(&six).unwrap();
assert_eq!(reader.spec(), spec(6, 16, SampleFormat::Int));
assert_eq!(reader.duration(), 2);
let f64_six = write_all(ex(spec(6, 64, SampleFormat::Float), 8), &[0.25f64; 6]);
assert_eq!(
chunk_ids(&f64_six),
[("fmt ".into(), 40), ("fact".into(), 4), ("data".into(), 48)]
);
let reader = open(&f64_six).unwrap();
assert_eq!(reader.spec(), spec(6, 64, SampleFormat::Float));
}
#[test]
fn writer_emits_extensible_for_wide_containers() {
let spec_ex = ex(spec(2, 24, SampleFormat::Int), 4);
let samples = [1i32, 2, 3, 4, -1, 8_388_607];
let bytes = write_all(spec_ex, &samples);
assert_eq!(
chunk_ids(&bytes),
[("fmt ".into(), 40), ("data".into(), 24)]
);
let mut reader = open(&bytes).unwrap();
assert_eq!(reader.spec_ex(), spec_ex);
let got: Vec<i32> = reader.samples().map(Result::unwrap).collect();
assert_eq!(got, samples);
reader.seek(2).unwrap();
let tail: Vec<i32> = reader.samples().map(Result::unwrap).collect();
assert_eq!(tail, [-1, 8_388_607]);
}
#[test]
fn new_derives_the_narrowest_container() {
for (bits, format, want) in [
(8, SampleFormat::Int, 1),
(12, SampleFormat::Int, 2),
(16, SampleFormat::Int, 2),
(20, SampleFormat::Int, 3),
(24, SampleFormat::Int, 3),
(32, SampleFormat::Int, 4),
(32, SampleFormat::Float, 4),
(64, SampleFormat::Float, 8),
] {
let w = WavWriter::new(Cursor::new(Vec::new()), spec(1, bits, format)).unwrap();
assert_eq!(w.spec_ex().bytes_per_sample, want, "{} bits", bits);
assert_eq!(w.spec(), spec(1, bits, format));
}
}
#[test]
fn writer_rejects_specs_the_reader_could_not_decode() {
let reject = |s: WavSpecEx| WavWriter::new_with_spec_ex(Cursor::new(Vec::new()), s).err();
assert!(matches!(
reject(ex(spec(0, 16, SampleFormat::Int), 2)),
Some(Error::Format(_))
));
assert!(matches!(
reject(ex(spec(1, 0, SampleFormat::Int), 2)),
Some(Error::Format(_))
));
assert!(matches!(
reject(ex(spec(1, 16, SampleFormat::Int), 0)),
Some(Error::Format(_))
));
assert!(matches!(
reject(ex(spec(1, 24, SampleFormat::Int), 2)),
Some(Error::Format(_))
));
assert!(matches!(
reject(ex(spec(1, 4, SampleFormat::Int), 1)),
Some(Error::Format(_))
));
assert!(matches!(
reject(ex(spec(1, 40, SampleFormat::Int), 5)),
Some(Error::TooWide)
));
assert!(matches!(
WavWriter::new(Cursor::new(Vec::new()), spec(1, 40, SampleFormat::Int)),
Err(Error::TooWide)
));
assert!(matches!(
reject(ex(spec(1, 16, SampleFormat::Float), 2)),
Some(Error::Unsupported(_))
));
let zero_rate = WavSpec {
sample_rate: 0,
..spec(1, 16, SampleFormat::Int)
};
assert!(matches!(reject(ex(zero_rate, 2)), Some(Error::Format(_))));
let huge_rate = WavSpec {
sample_rate: u32::MAX,
..spec(2, 16, SampleFormat::Int)
};
assert!(matches!(
reject(ex(huge_rate, 2)),
Some(Error::Unsupported(_))
));
}
#[test]
fn constructors_agree_on_the_error_variant() {
let f24 = spec(1, 24, SampleFormat::Float);
assert!(matches!(
WavWriter::new(Cursor::new(Vec::new()), f24),
Err(Error::Unsupported(_))
));
assert!(matches!(
WavWriter::new_with_spec_ex(Cursor::new(Vec::new()), ex(f24, 3)),
Err(Error::Unsupported(_))
));
assert!(matches!(
WavWriter::new(Cursor::new(Vec::new()), spec(1, 48, SampleFormat::Int)),
Err(Error::TooWide)
));
}
#[test]
fn too_wide_on_read() {
let v02 = fixture_bytes(&vector("V02"));
let mut reader = open(&v02).unwrap();
let mut narrow = reader.samples::<i8>();
assert!(matches!(narrow.next(), Some(Err(Error::TooWide))));
assert!(narrow.next().is_none(), "one TooWide, then fused");
drop(narrow);
assert!(matches!(
reader.samples::<f32>().next(),
Some(Err(Error::TooWide))
));
assert!(matches!(
reader.read_samples(&mut [0f64; 2]),
Err(Error::TooWide)
));
let ok: Vec<i16> = reader.samples().map(Result::unwrap).collect();
assert_eq!(ok.len(), 8, "a failed type check consumes nothing");
let v05 = fixture_bytes(&vector("V05"));
let mut reader = open(&v05).unwrap();
assert!(matches!(
reader.samples::<i32>().next(),
Some(Err(Error::TooWide))
));
let widened: Vec<f64> = reader.samples::<f64>().map(Result::unwrap).collect();
assert_eq!(widened, [0.0, 1.0, -1.0, 0.5, -0.25]);
let v03 = fixture_bytes(&vector("V03"));
assert!(matches!(
open(&v03).unwrap().samples::<i16>().next(),
Some(Err(Error::TooWide))
));
}
#[test]
fn too_wide_on_write() {
let mut w = WavWriter::new(Cursor::new(Vec::new()), spec(1, 8, SampleFormat::Int)).unwrap();
w.write_sample(127i16).unwrap();
w.write_sample(-128i32).unwrap();
assert!(matches!(w.write_sample(128i16), Err(Error::TooWide)));
assert!(matches!(w.write_sample(-129i32), Err(Error::TooWide)));
assert!(matches!(w.write_sample(0.5f32), Err(Error::TooWide)));
assert_eq!(w.len(), 2, "rejected samples are not counted");
let mut w = WavWriter::new(Cursor::new(Vec::new()), spec(1, 24, SampleFormat::Int)).unwrap();
w.write_sample(8_388_607i32).unwrap();
w.write_sample(-8_388_608i32).unwrap();
assert!(matches!(w.write_sample(8_388_608i32), Err(Error::TooWide)));
assert!(matches!(
w.write_samples(&[1i32, 8_388_608, 2]),
Err(Error::TooWide)
));
assert_eq!(w.len(), 3, "a slice write stops at the offending value");
let mut w = WavWriter::new(Cursor::new(Vec::new()), spec(1, 32, SampleFormat::Float)).unwrap();
w.write_sample(0.5f32).unwrap();
assert!(matches!(w.write_sample(0.5f64), Err(Error::TooWide)));
assert!(matches!(w.write_sample(1i16), Err(Error::TooWide)));
let mut w = WavWriter::new(Cursor::new(Vec::new()), spec(1, 64, SampleFormat::Float)).unwrap();
w.write_sample(0.5f32).unwrap();
w.write_sample(0.25f64).unwrap();
assert_eq!(w.len(), 2);
}
#[test]
fn narrow_integers_widen_on_write() {
let bytes = write_all(ex(spec(1, 32, SampleFormat::Int), 4), &[-1i8, 1]);
let got: Vec<i32> = open(&bytes)
.unwrap()
.samples()
.map(Result::unwrap)
.collect();
assert_eq!(got, [-1, 1]);
let bytes = write_all(ex(spec(1, 24, SampleFormat::Int), 3), &[-2i16, 2]);
let got: Vec<i32> = open(&bytes)
.unwrap()
.samples()
.map(Result::unwrap)
.collect();
assert_eq!(got, [-2, 2]);
}
#[test]
fn finalize_mid_frame_returns_unfinished_frame() {
let mut out = Cursor::new(Vec::new());
let w = {
let mut w = WavWriter::new(&mut out, spec(2, 16, SampleFormat::Int)).unwrap();
w.write_sample(7i16).unwrap();
w.write_sample(8i16).unwrap();
w.write_sample(9i16).unwrap();
assert_eq!(w.len(), 3);
assert_eq!(w.duration(), 1);
w
};
assert!(matches!(w.finalize(), Err(Error::UnfinishedFrame)));
let bytes = out.into_inner();
let data_size = u32::from_le_bytes([bytes[40], bytes[41], bytes[42], bytes[43]]);
assert_eq!(data_size, 4, "header keeps whole frames only");
let got: Vec<i16> = open(&bytes)
.unwrap()
.samples()
.map(Result::unwrap)
.collect();
assert_eq!(got, [7, 8]);
}
#[test]
fn incomplete_frame_finalize_errors() {
let spec = spec(2, 16, SampleFormat::Int);
let mut out = Cursor::new(Vec::new());
let mut w = WavWriter::new(&mut out, spec).unwrap();
w.write_sample(1i16).unwrap();
assert!(matches!(w.finalize(), Err(Error::UnfinishedFrame)));
let bytes = out.into_inner();
let data_size = u32::from_le_bytes([bytes[40], bytes[41], bytes[42], bytes[43]]);
assert_eq!(data_size, 0);
assert!(open(&bytes).unwrap().is_empty());
let mut dropped = Cursor::new(Vec::new());
{
let mut w = WavWriter::new(&mut dropped, spec).unwrap();
w.write_sample(1i16).unwrap();
}
assert!(open(&dropped.into_inner()).unwrap().is_empty());
}
#[test]
fn hostile_writer_spec_no_overflow() {
let spec = WavSpec {
channels: 1,
sample_rate: 8000,
bits_per_sample: u16::MAX,
sample_format: SampleFormat::Int,
};
let caught = std::panic::catch_unwind(|| WavWriter::new(Cursor::new(Vec::new()), spec));
let result = match caught {
Ok(r) => r,
Err(_) => panic!("WavWriter::new panics on bits_per_sample = u16::MAX"),
};
match result {
Err(Error::TooWide) => {}
Err(e) => panic!("expected TooWide, got {}", e),
Ok(_) => panic!("expected TooWide, got Ok"),
}
assert!(
matches!(
WavWriter::new_with_spec_ex(Cursor::new(Vec::new()), ex(spec, 2)),
Err(Error::TooWide)
),
"new_with_spec_ex must match new on bits_per_sample > 32"
);
}
#[test]
fn drop_finalizes_like_finalize() {
let samples = [1i16, -1, 3];
let explicit = write_all(ex(spec(1, 16, SampleFormat::Int), 2), &samples);
let mut out = Cursor::new(Vec::new());
{
let mut w = WavWriter::new(&mut out, spec(1, 16, SampleFormat::Int)).unwrap();
w.write_samples(&samples).unwrap();
}
assert_eq!(out.into_inner(), explicit);
let mut out = Cursor::new(Vec::new());
{
let w = WavWriter::new(&mut out, spec(1, 16, SampleFormat::Int)).unwrap();
assert!(w.is_empty());
}
let bytes = out.into_inner();
assert_eq!(bytes.len(), 44);
let reader = open(&bytes).unwrap();
assert!(reader.is_empty());
assert_eq!(reader.len(), 0);
}
#[test]
fn flush_pushes_samples_without_patching_sizes() {
let mut out = Cursor::new(Vec::new());
let mut w = WavWriter::new(&mut out, spec(1, 16, SampleFormat::Int)).unwrap();
w.write_sample(5i16).unwrap();
w.flush().unwrap();
assert_eq!(w.len(), 1);
let snapshot = w.spec();
assert_eq!(snapshot.bits_per_sample, 16);
w.finalize().unwrap();
let bytes = out.into_inner();
assert_eq!(bytes.len(), 46);
let data_size = u32::from_le_bytes([bytes[40], bytes[41], bytes[42], bytes[43]]);
assert_eq!(data_size, 2);
}
#[test]
fn writer_at_a_nonzero_stream_offset() {
let mut out = Cursor::new(b"prefix--".to_vec());
out.seek(SeekFrom::End(0)).unwrap();
{
let mut w = WavWriter::new(&mut out, spec(1, 8, SampleFormat::Int)).unwrap();
w.write_samples(&[1i8, 2, 3]).unwrap();
w.finalize().unwrap();
}
let bytes = out.into_inner();
assert_eq!(&bytes[..8], b"prefix--");
let wav = &bytes[8..];
assert_eq!(wav.len(), 48, "3 samples plus a pad byte");
let riff_size = u32::from_le_bytes([wav[4], wav[5], wav[6], wav[7]]);
assert_eq!(riff_size, 40);
let got: Vec<i8> = open(wav).unwrap().samples().map(Result::unwrap).collect();
assert_eq!(got, [1, 2, 3]);
}
#[test]
fn writer_spans_many_blocks() {
let n = 100_000usize;
let samples: Vec<i32> = (0..n as i32)
.map(|i| i.wrapping_mul(2_654_435_761u32 as i32))
.collect();
let bytes = write_all(ex(spec(1, 32, SampleFormat::Int), 4), &samples);
assert_eq!(bytes.len(), 44 + n * 4);
let mut reader = open(&bytes).unwrap();
let got: Vec<i32> = reader.samples().map(Result::unwrap).collect();
assert_eq!(got, samples);
let mut out = Cursor::new(Vec::new());
{
let mut w = WavWriter::new(&mut out, spec(1, 32, SampleFormat::Int)).unwrap();
for &s in &samples {
w.write_sample(s).unwrap();
}
w.finalize().unwrap();
}
assert_eq!(out.into_inner(), bytes);
}
#[test]
fn read_samples_reports_the_end_with_a_short_count() {
let bytes = fixture_bytes(&vector("V02"));
let mut reader = open(&bytes).unwrap();
let mut buf = [0i16; 5];
assert_eq!(reader.read_samples(&mut buf).unwrap(), 5);
assert_eq!(buf, [0, 1, -1, 32767, -32768]);
assert_eq!(reader.read_samples(&mut buf).unwrap(), 3);
assert_eq!(&buf[..3], &[12345, -12345, 256]);
assert_eq!(reader.read_samples(&mut buf).unwrap(), 0);
assert_eq!(reader.read_samples(&mut [0i16; 0]).unwrap(), 0);
}
#[test]
fn iterator_then_bulk_share_one_position() {
let bytes = fixture_bytes(&vector("V02"));
let mut reader = open(&bytes).unwrap();
assert_eq!(reader.samples::<i16>().nth(2).map(Result::unwrap), Some(-1));
let mut buf = [0i16; 2];
assert_eq!(reader.read_samples(&mut buf).unwrap(), 2);
assert_eq!(buf, [32767, -32768]);
let rest: Vec<i16> = reader.samples().map(Result::unwrap).collect();
assert_eq!(rest, [12345, -12345, 256]);
}
#[test]
fn into_samples_returns_the_reader() {
let bytes = fixture_bytes(&vector("V02"));
let mut iter = open(&bytes).unwrap().into_samples::<i16>();
assert_eq!(iter.next().map(Result::unwrap), Some(0));
let (lo, hi) = iter.size_hint();
assert_eq!((lo, hi), (0, Some(7)));
let mut reader = iter.into_inner();
let rest: Vec<i16> = reader.samples().map(Result::unwrap).collect();
assert_eq!(rest.len(), 7);
let inner = reader.into_inner();
assert_eq!(inner.position() as usize, bytes.len());
}
struct Dribble<'a> {
data: &'a [u8],
pos: usize,
calls: usize,
}
impl<'a> Read for Dribble<'a> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.calls += 1;
if self.calls % 3 == 0 {
return Err(io::Error::new(io::ErrorKind::Interrupted, "again"));
}
if self.pos == self.data.len() || buf.is_empty() {
return Ok(0);
}
buf[0] = self.data[self.pos];
self.pos += 1;
Ok(1)
}
}
#[test]
fn short_and_interrupted_reads_decode_the_same_samples() {
for id in ["V02", "V03", "V06", "V09", "V10", "V11", "V12"] {
let v = vector(id);
let bytes = fixture_bytes(&v);
let direct = open(&bytes).unwrap();
let mut dribbled = WavReader::new(Dribble {
data: &bytes,
pos: 0,
calls: 0,
})
.unwrap();
assert_eq!(dribbled.spec_ex(), direct.spec_ex(), "{}", id);
match direct.spec().sample_format {
SampleFormat::Int => {
let want: Vec<i32> = open(&bytes)
.unwrap()
.samples()
.map(Result::unwrap)
.collect();
let got: Vec<i32> = dribbled.samples().map(Result::unwrap).collect();
assert_eq!(got, want, "{}", id);
}
SampleFormat::Float => {
let want: Vec<f64> = open(&bytes)
.unwrap()
.samples()
.map(Result::unwrap)
.collect();
let got: Vec<f64> = dribbled.samples().map(Result::unwrap).collect();
assert_eq!(got, want, "{}", id);
}
}
}
let x02 = fixture_bytes(&vector("X02"));
let mut dribbled = WavReader::new(Dribble {
data: &x02,
pos: 0,
calls: 0,
})
.unwrap();
let items: Vec<wav_codec::Result<i16>> = dribbled.samples().collect();
assert_eq!(items.len(), 3);
assert!(matches!(items[2], Err(Error::Format(_))));
}
#[test]
fn riff_size_is_not_trusted_on_read() {
let mut bytes = fixture_bytes(&vector("V02"));
bytes[4..8].copy_from_slice(&0xFFFF_FFFFu32.to_le_bytes());
let got: Vec<i16> = open(&bytes)
.unwrap()
.samples()
.map(Result::unwrap)
.collect();
assert_eq!(got.len(), 8);
bytes[4..8].copy_from_slice(&0u32.to_le_bytes());
let got: Vec<i16> = open(&bytes)
.unwrap()
.samples()
.map(Result::unwrap)
.collect();
assert_eq!(got.len(), 8);
}
#[test]
fn open_and_create_on_disk() {
let dir = std::env::temp_dir();
let path = dir.join(format!("wav-codec-api-{}.wav", std::process::id()));
{
let mut w = WavWriter::create(&path, spec(2, 16, SampleFormat::Int)).unwrap();
w.write_samples(&[1i16, 2, 3, 4]).unwrap();
w.finalize().unwrap();
}
let mut reader = WavReader::open(&path).unwrap();
assert_eq!(reader.duration(), 2);
reader.seek(1).unwrap();
let tail: Vec<i16> = reader.samples().map(Result::unwrap).collect();
assert_eq!(tail, [3, 4]);
let _ = std::fs::remove_file(&path);
assert!(matches!(WavReader::open(&path), Err(Error::Io(_))));
}
#[test]
fn error_display_and_source() {
let io_err = Error::from(io::Error::new(io::ErrorKind::Other, "disk"));
assert!(io_err.to_string().contains("disk"));
assert!(std::error::Error::source(&io_err).is_some());
for e in [
Error::Format("x"),
Error::Unsupported("y"),
Error::TooWide,
Error::UnfinishedFrame,
Error::TooLarge,
] {
assert!(!e.to_string().is_empty());
assert!(std::error::Error::source(&e).is_none());
let _ = format!("{:?}", e);
}
}
#[test]
fn scope_limits_are_clean_errors() {
let rf64 = b"RF64\xFF\xFF\xFF\xFFWAVEds64";
assert!(matches!(open(rf64), Err(Error::Unsupported(_))));
let rifx = b"RIFX\x00\x00\x00\x10WAVEfmt ";
assert!(matches!(open(rifx), Err(Error::Unsupported(_))));
let mut not_wave = fixture_bytes(&vector("V02"));
not_wave[8..12].copy_from_slice(b"AVI ");
assert!(matches!(open(¬_wave), Err(Error::Format(_))));
let mut mulaw = fixture_bytes(&vector("V01"));
mulaw[20..22].copy_from_slice(&7u16.to_le_bytes());
assert!(matches!(open(&mulaw), Err(Error::Unsupported(_))));
let headers_only = &fixture_bytes(&vector("V02"))[..36];
assert!(matches!(open(headers_only), Err(Error::Format(_))));
}
#[test]
fn odd_chunk_nonzero_pad_rejected() {
let mut bytes = fixture_bytes(&vector("V10"));
let junk = bytes
.windows(4)
.position(|w| w == b"JUNK")
.expect("V10 carries a JUNK chunk");
let size = u32::from_le_bytes(bytes[junk + 4..junk + 8].try_into().unwrap());
assert_eq!(size, 3);
let pad_at = junk + 8 + size as usize;
assert_eq!(bytes[pad_at], 0, "canonical V10 pad is zero");
bytes[pad_at] = 0x7f;
match open(&bytes) {
Err(Error::Format(_)) => {}
other => panic!(
"nonzero pad after an odd chunk must be Format, got {:?}",
other.map(|_| ())
),
}
}
#[test]
fn extensible_common_bits_validated() {
let mut bytes = fixture_bytes(&vector("V09"));
let fmt = bytes
.windows(4)
.position(|w| w == b"fmt ")
.expect("V09 carries a fmt chunk");
let bits_at = fmt + 8 + 14;
let common = u16::from_le_bytes(bytes[bits_at..bits_at + 2].try_into().unwrap());
assert_eq!(common, 32, "V09 stores container width in the common field");
bytes[bits_at..bits_at + 2].copy_from_slice(&u16::MAX.to_le_bytes());
match open(&bytes) {
Err(Error::Format(_)) => {}
other => panic!(
"EXTENSIBLE common bits_per_sample over the container must be Format, got {:?}",
other.map(|_| ())
),
}
}
#[test]
fn reader_and_writer_impl_debug() {
let bytes = fixture_bytes(&vector("V02"));
let mut reader = open(&bytes).unwrap();
let text = format!("{:?}", reader);
assert!(text.contains("WavReader"));
assert!(
!text.contains("buf"),
"Debug must not dump the 64 KiB block buffer"
);
let samples = format!("{:?}", reader.samples::<i16>());
assert!(samples.contains("Samples"));
let owned = format!("{:?}", open(&bytes).unwrap().into_samples::<i16>());
assert!(owned.contains("IntoSamples"));
let w = WavWriter::new(Cursor::new(Vec::new()), spec(1, 16, SampleFormat::Int)).unwrap();
let text = format!("{:?}", w);
assert!(text.contains("WavWriter"));
assert!(
!text.contains("block"),
"Debug must not dump the encode block"
);
}