mod decode;
mod readers;
pub use decode::decode_waveform_chunks;
#[cfg(test)]
#[cfg_attr(coverage, coverage(off))]
mod tests {
use super::decode_waveform_chunks;
use crate::data::{AnalogSamples, DigitalSamples, IqSamples, Waveform};
use crate::decoder::readers::{
read_f32_chunks, read_f64_chunks, read_i8_chunks, read_i16_chunks, read_i32_chunks,
};
use crate::errors::DecodeError;
use crate::tekscope::WaveformHeader;
fn base_header() -> WaveformHeader {
WaveformHeader {
sourcename: "ch1".to_string(),
verticalunits: "V".to_string(),
horizontal_units: "s".to_string(),
hasdata: true,
..Default::default()
}
}
fn base_iq_header() -> WaveformHeader {
WaveformHeader {
sourcename: "iq1".to_string(),
verticalunits: "V".to_string(),
horizontal_units: "s".to_string(),
hasdata: true,
wfmtype: 6,
sourcewidth: 2,
noofsamples: 2,
iq_fft_length: 1024.0,
iq_rbw: 1e6,
iq_span: 1e9,
..Default::default()
}
}
fn decode_from_bytes(header: &WaveformHeader, data: &[u8]) -> Result<Waveform, DecodeError> {
let chunks = vec![data.to_vec()];
decode_waveform_chunks(header, &chunks)
}
#[test]
fn decode_analog_i8_preserves_signedness() {
let header = WaveformHeader {
wfmtype: 1,
sourcewidth: 1,
noofsamples: 3,
..base_header()
};
let data = [0xFF, 0x01, 0x80];
let waveform = decode_from_bytes(&header, &data).expect("decode failed");
match waveform {
Waveform::Analog(waveform) => match waveform.y_axis_values {
AnalogSamples::I8(values) => {
assert_eq!(values[..3], [-1, 1, -128]);
}
_ => panic!("unexpected analog sample type"),
},
_ => panic!("unexpected waveform type"),
}
}
#[test]
fn decode_digital_i8_preserves_signedness() {
let header = WaveformHeader {
wfmtype: 4,
sourcewidth: 1,
noofsamples: 2,
..base_header()
};
let data = [0xFF, 0x7F];
let waveform = decode_from_bytes(&header, &data).expect("decode failed");
match waveform {
Waveform::Digital(waveform) => match waveform.y_axis_bytes {
DigitalSamples::I8(values) => {
assert_eq!(values[..2], [-1, 127]);
}
DigitalSamples::I16(_) => panic!("unexpected digital sample type"),
},
_ => panic!("unexpected waveform type"),
}
}
#[test]
fn decode_digital_i16_preserves_signedness() {
let header = WaveformHeader {
wfmtype: 4,
sourcewidth: 2,
noofsamples: 2,
..base_header()
};
let data = [0xFF, 0xFF, 0x01, 0x00];
let waveform = decode_from_bytes(&header, &data).expect("decode failed");
match waveform {
Waveform::Digital(waveform) => match waveform.y_axis_bytes {
DigitalSamples::I16(values) => {
assert_eq!(values[..2], [-1, 1]);
}
_ => panic!("unexpected digital sample type"),
},
_ => panic!("unexpected waveform type"),
}
}
#[test]
fn decode_iq_i16_preserves_dtype() {
let header = WaveformHeader { ..base_iq_header() };
let data = [0x01, 0x00, 0xFF, 0x7F];
let waveform = decode_from_bytes(&header, &data).expect("decode failed");
match waveform {
Waveform::Iq(waveform) => match waveform.interleaved_iq {
IqSamples::I16(values) => {
assert_eq!(values[..2], [1, 32767]);
}
_ => panic!("unexpected iq sample type"),
},
_ => panic!("unexpected waveform type"),
}
}
#[test]
fn decode_rejects_invalid_header() {
let header = WaveformHeader {
wfmtype: 1,
sourcewidth: 4,
noofsamples: 0,
hasdata: true,
..base_header()
};
let data = [0x00, 0x00, 0x00, 0x00];
let err = decode_from_bytes(&header, &data).expect_err("expected decode error");
assert!(matches!(err, DecodeError::InvalidHeader));
}
#[test]
fn decode_rejects_unspecified_wfmtype() {
let header = WaveformHeader {
wfmtype: 0,
sourcewidth: 1,
noofsamples: 1,
..base_header()
};
let err = decode_from_bytes(&header, &[0x00]).expect_err("expected decode error");
assert!(matches!(err, DecodeError::InvalidHeader));
}
#[test]
fn decode_rejects_unknown_wfmtype_value() {
let header = WaveformHeader {
wfmtype: 99,
sourcewidth: 1,
noofsamples: 1,
..base_header()
};
let err = decode_from_bytes(&header, &[0x00]).expect_err("expected decode error");
assert!(matches!(err, DecodeError::InvalidHeader));
}
#[test]
fn decode_rejects_invalid_header_sourcewidth() {
let header = WaveformHeader {
wfmtype: 1,
sourcewidth: 3,
noofsamples: 4,
hasdata: true,
..base_header()
};
let data = [0x00, 0x00, 0x00, 0x00];
let err = decode_from_bytes(&header, &data).expect_err("expected decode error");
assert!(matches!(err, DecodeError::UnsupportedSourceWidth { .. }));
}
#[test]
fn decode_rejects_mismatched_wfmtype_sourcewidth() {
let header = WaveformHeader {
wfmtype: 4,
sourcewidth: 4,
noofsamples: 2,
hasdata: true,
..base_header()
};
let err = decode_from_bytes(&header, &[0x00, 0x00, 0x00, 0x00])
.expect_err("expected decode error");
assert!(matches!(err, DecodeError::UnsupportedSourceWidth { .. }));
}
#[test]
fn decode_rejects_invalid_header_no_data() {
let header = WaveformHeader {
wfmtype: 1,
sourcewidth: 1,
noofsamples: 4,
hasdata: false,
..base_header()
};
let data = [0x00, 0x00, 0x00, 0x00];
let err = decode_from_bytes(&header, &data).expect_err("expected decode error");
assert!(matches!(err, DecodeError::InvalidHeader));
}
#[test]
fn decode_iq_sample_rate_blackharris() {
let header = WaveformHeader {
iq_window_type: "Blackharris".to_string(),
..base_iq_header()
};
let data = [0x00, 0x00, 0x00, 0x00];
let waveform = decode_from_bytes(&header, &data).expect("decode failed");
match waveform {
Waveform::Iq(waveform) => {
let expected = (1024.0 * 1e6) / 1.9;
assert!((waveform.meta_info.iq_sample_rate - expected).abs() < f64::EPSILON);
}
_ => panic!("unexpected waveform type"),
}
}
#[test]
fn decode_iq_sample_rate_flattop2() {
let header = WaveformHeader {
iq_window_type: "Flattop2".to_string(),
..base_iq_header()
};
let data = [0x00, 0x00, 0x00, 0x00];
let waveform = decode_from_bytes(&header, &data).expect("decode failed");
match waveform {
Waveform::Iq(waveform) => {
let expected = (1024.0 * 1e6) / 3.77;
assert!((waveform.meta_info.iq_sample_rate - expected).abs() < f64::EPSILON);
}
_ => panic!("unexpected waveform type"),
}
}
#[test]
fn decode_iq_sample_rate_hanning() {
let header = WaveformHeader {
iq_window_type: "Hanning".to_string(),
..base_iq_header()
};
let waveform =
decode_from_bytes(&header, &[0x00, 0x00, 0x00, 0x00]).expect("decode failed");
match waveform {
Waveform::Iq(waveform) => {
let expected = (1024.0 * 1e6) / 1.44;
assert!((waveform.meta_info.iq_sample_rate - expected).abs() < f64::EPSILON);
}
_ => panic!("unexpected waveform type"),
}
}
#[test]
fn decode_iq_sample_rate_hamming() {
let header = WaveformHeader {
iq_window_type: "Hamming".to_string(),
..base_iq_header()
};
let waveform =
decode_from_bytes(&header, &[0x00, 0x00, 0x00, 0x00]).expect("decode failed");
match waveform {
Waveform::Iq(waveform) => {
let expected = (1024.0 * 1e6) / 1.3;
assert!((waveform.meta_info.iq_sample_rate - expected).abs() < f64::EPSILON);
}
_ => panic!("unexpected waveform type"),
}
}
#[test]
fn decode_iq_sample_rate_rectangle() {
let header = WaveformHeader {
iq_window_type: "Rectangle".to_string(),
..base_iq_header()
};
let waveform =
decode_from_bytes(&header, &[0x00, 0x00, 0x00, 0x00]).expect("decode failed");
match waveform {
Waveform::Iq(waveform) => {
let expected = (1024.0 * 1e6) / 0.89;
assert!((waveform.meta_info.iq_sample_rate - expected).abs() < f64::EPSILON);
}
_ => panic!("unexpected waveform type"),
}
}
#[test]
fn decode_iq_sample_rate_kaiserbessel() {
let header = WaveformHeader {
iq_window_type: "Kaiserbessel".to_string(),
..base_iq_header()
};
let waveform =
decode_from_bytes(&header, &[0x00, 0x00, 0x00, 0x00]).expect("decode failed");
match waveform {
Waveform::Iq(waveform) => {
let expected = (1024.0 * 1e6) / 2.23;
assert!((waveform.meta_info.iq_sample_rate - expected).abs() < f64::EPSILON);
}
_ => panic!("unexpected waveform type"),
}
}
#[test]
fn decode_iq_sample_rate_unknown_uses_span() {
let header = WaveformHeader {
iq_window_type: "UnknownWindow".to_string(),
iq_span: 42.0,
..base_iq_header()
};
let waveform =
decode_from_bytes(&header, &[0x00, 0x00, 0x00, 0x00]).expect("decode failed");
match waveform {
Waveform::Iq(waveform) => {
assert!((waveform.meta_info.iq_sample_rate - 42.0).abs() < f64::EPSILON);
}
_ => panic!("unexpected waveform type"),
}
}
#[test]
fn decode_analog_f32_length_matches_header() {
let header = WaveformHeader {
wfmtype: 1,
sourcewidth: 4,
noofsamples: 4,
..base_header()
};
let data = [0u8; 16];
let waveform = decode_from_bytes(&header, &data).expect("decode failed");
match waveform {
Waveform::Analog(waveform) => match waveform.y_axis_values {
AnalogSamples::F32(values) => assert_eq!(values.len(), 4),
_ => panic!("unexpected analog sample type"),
},
_ => panic!("unexpected waveform type"),
}
}
#[test]
fn decode_analog_preserves_dtypes() {
let header_i8 = WaveformHeader {
wfmtype: 1,
sourcewidth: 1,
noofsamples: 1,
..base_header()
};
let waveform = decode_from_bytes(&header_i8, &[0x00]).expect("decode failed");
match waveform {
Waveform::Analog(waveform) => match waveform.y_axis_values {
AnalogSamples::I8(_) => {}
_ => panic!("unexpected analog sample type"),
},
_ => panic!("unexpected waveform type"),
}
let header_i16 = WaveformHeader {
wfmtype: 1,
sourcewidth: 2,
noofsamples: 1,
..base_header()
};
let waveform = decode_from_bytes(&header_i16, &[0x00, 0x00]).expect("decode failed");
match waveform {
Waveform::Analog(waveform) => match waveform.y_axis_values {
AnalogSamples::I16(_) => {}
_ => panic!("unexpected analog sample type"),
},
_ => panic!("unexpected waveform type"),
}
let header_f64 = WaveformHeader {
wfmtype: 1,
sourcewidth: 8,
noofsamples: 1,
..base_header()
};
let waveform = decode_from_bytes(&header_f64, &[0; 8]).expect("decode failed");
match waveform {
Waveform::Analog(waveform) => match waveform.y_axis_values {
AnalogSamples::F64(_) => {}
_ => panic!("unexpected analog sample type"),
},
_ => panic!("unexpected waveform type"),
}
}
#[test]
fn decode_iq_preserves_dtypes() {
let header_i8 = WaveformHeader {
sourcewidth: 1,
noofsamples: 1,
..base_iq_header()
};
let waveform = decode_from_bytes(&header_i8, &[0x00]).expect("decode failed");
match waveform {
Waveform::Iq(waveform) => match waveform.interleaved_iq {
IqSamples::I8(_) => {}
_ => panic!("unexpected iq sample type"),
},
_ => panic!("unexpected waveform type"),
}
let header_i32 = WaveformHeader {
sourcewidth: 4,
noofsamples: 1,
..base_iq_header()
};
let waveform =
decode_from_bytes(&header_i32, &[0x00, 0x00, 0x00, 0x00]).expect("decode failed");
match waveform {
Waveform::Iq(waveform) => match waveform.interleaved_iq {
IqSamples::I32(_) => {}
_ => panic!("unexpected iq sample type"),
},
_ => panic!("unexpected waveform type"),
}
}
#[test]
fn decode_digital_length_matches_header() {
let header = WaveformHeader {
wfmtype: 4,
sourcewidth: 1,
noofsamples: 4,
..base_header()
};
let data = [1u8, 2, 3, 4];
let waveform = decode_from_bytes(&header, &data).expect("decode failed");
match waveform {
Waveform::Digital(waveform) => match waveform.y_axis_bytes {
DigitalSamples::I8(values) => assert_eq!(values.len(), 4),
DigitalSamples::I16(values) => assert_eq!(values.len(), 4),
},
_ => panic!("unexpected waveform type"),
}
}
fn naive_read_i8(data: &[u8], sample_count: usize) -> Vec<i8> {
let mut output = vec![0i8; sample_count];
let count = sample_count.min(data.len());
for idx in 0..count {
output[idx] = data[idx] as i8;
}
output
}
fn naive_read_i16(data: &[u8], sample_count: usize) -> Vec<i16> {
let mut output = vec![0i16; sample_count];
let count = sample_count.min(data.len() / 2);
for idx in 0..count {
let start = idx * 2;
output[idx] = i16::from_le_bytes([data[start], data[start + 1]]);
}
output
}
fn naive_read_i32(data: &[u8], sample_count: usize) -> Vec<i32> {
let mut output = vec![0i32; sample_count];
let count = sample_count.min(data.len() / 4);
for idx in 0..count {
let start = idx * 4;
output[idx] = i32::from_le_bytes([
data[start],
data[start + 1],
data[start + 2],
data[start + 3],
]);
}
output
}
fn naive_read_f32(data: &[u8], sample_count: usize) -> Vec<f32> {
let mut output = vec![0.0f32; sample_count];
let count = sample_count.min(data.len() / 4);
for idx in 0..count {
let start = idx * 4;
output[idx] = f32::from_le_bytes([
data[start],
data[start + 1],
data[start + 2],
data[start + 3],
]);
}
output
}
fn naive_read_f64(data: &[u8], sample_count: usize) -> Vec<f64> {
let mut output = vec![0.0f64; sample_count];
let count = sample_count.min(data.len() / 8);
for idx in 0..count {
let start = idx * 8;
output[idx] = f64::from_le_bytes([
data[start],
data[start + 1],
data[start + 2],
data[start + 3],
data[start + 4],
data[start + 5],
data[start + 6],
data[start + 7],
]);
}
output
}
#[test]
fn read_i8_chunks_matches_contiguous() {
let data = [0x01u8, 0xFF, 0x7F, 0x80];
let chunks = vec![data[..1].to_vec(), data[1..3].to_vec(), data[3..].to_vec()];
let sample_count = 6;
assert_eq!(
read_i8_chunks(&chunks, sample_count),
naive_read_i8(&data, sample_count)
);
}
#[test]
fn read_i16_chunks_matches_contiguous() {
let values = [1i16, -2i16, 32000i16, -123i16];
let mut data = Vec::new();
for value in values {
data.extend_from_slice(&value.to_le_bytes());
}
let chunks = vec![data[..1].to_vec(), data[1..5].to_vec(), data[5..].to_vec()];
let sample_count = 6;
assert_eq!(
read_i16_chunks(&chunks, sample_count),
naive_read_i16(&data, sample_count)
);
}
#[test]
fn read_i32_chunks_matches_contiguous() {
let values = [1i32, -2i32, 32000i32];
let mut data = Vec::new();
for value in values {
data.extend_from_slice(&value.to_le_bytes());
}
let chunks = vec![data[..3].to_vec(), data[3..7].to_vec(), data[7..].to_vec()];
let sample_count = 5;
assert_eq!(
read_i32_chunks(&chunks, sample_count),
naive_read_i32(&data, sample_count)
);
}
#[test]
fn read_f32_chunks_matches_contiguous() {
let values = [1.5f32, -2.0f32, 3.25f32];
let mut data = Vec::new();
for value in values {
data.extend_from_slice(&value.to_le_bytes());
}
let chunks = vec![data[..2].to_vec(), data[2..6].to_vec(), data[6..].to_vec()];
let sample_count = 5;
assert_eq!(
read_f32_chunks(&chunks, sample_count),
naive_read_f32(&data, sample_count)
);
}
#[test]
fn read_f64_chunks_matches_contiguous() {
let values = [1.5f64, -2.0f64, 3.25f64];
let mut data = Vec::new();
for value in values {
data.extend_from_slice(&value.to_le_bytes());
}
let chunks = vec![
data[..3].to_vec(),
data[3..11].to_vec(),
data[11..].to_vec(),
];
let sample_count = 5;
assert_eq!(
read_f64_chunks(&chunks, sample_count),
naive_read_f64(&data, sample_count)
);
}
#[test]
fn read_i8_chunks_empty_returns_zeroed() {
let chunks: Vec<Vec<u8>> = Vec::new();
let output = read_i8_chunks(&chunks, 4);
assert_eq!(output, vec![0, 0, 0, 0]);
}
#[test]
fn read_i8_chunks_zero_sample_count_returns_empty() {
let chunks = vec![vec![1u8, 2, 3]];
let output = read_i8_chunks(&chunks, 0);
assert!(output.is_empty());
}
#[test]
fn read_i16_chunks_empty_returns_zeroed() {
let chunks: Vec<Vec<u8>> = Vec::new();
let output = read_i16_chunks(&chunks, 3);
assert_eq!(output, vec![0, 0, 0]);
}
#[test]
fn read_i16_chunks_zero_sample_count_returns_empty() {
let chunks = vec![vec![0x01u8, 0x02]];
let output = read_i16_chunks(&chunks, 0);
assert!(output.is_empty());
}
#[test]
fn read_i32_chunks_empty_returns_zeroed() {
let chunks: Vec<Vec<u8>> = Vec::new();
let output = read_i32_chunks(&chunks, 2);
assert_eq!(output, vec![0, 0]);
}
#[test]
fn read_i32_chunks_zero_sample_count_returns_empty() {
let chunks = vec![vec![0x01u8, 0x02, 0x03, 0x04]];
let output = read_i32_chunks(&chunks, 0);
assert!(output.is_empty());
}
#[test]
fn read_f32_chunks_empty_returns_zeroed() {
let chunks: Vec<Vec<u8>> = Vec::new();
let output = read_f32_chunks(&chunks, 2);
assert_eq!(output, vec![0.0, 0.0]);
}
#[test]
fn read_f32_chunks_zero_sample_count_returns_empty() {
let chunks = vec![vec![0x00u8, 0x00, 0x80, 0x3F]];
let output = read_f32_chunks(&chunks, 0);
assert!(output.is_empty());
}
#[test]
fn read_f64_chunks_empty_returns_zeroed() {
let chunks: Vec<Vec<u8>> = Vec::new();
let output = read_f64_chunks(&chunks, 2);
assert_eq!(output, vec![0.0, 0.0]);
}
#[test]
fn read_f64_chunks_zero_sample_count_returns_empty() {
let chunks = vec![vec![0x00u8, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x3F]];
let output = read_f64_chunks(&chunks, 0);
assert!(output.is_empty());
}
#[test]
fn read_i8_chunks_short_data_zero_filled_tail() {
let chunks = vec![vec![1u8, 2, 3]];
let output = read_i8_chunks(&chunks, 5);
assert_eq!(output, vec![1, 2, 3, 0, 0]);
}
#[test]
fn read_i16_chunks_short_data_zero_filled_tail() {
let data = vec![0x01u8, 0x00, 0xFF, 0xFF];
let chunks = vec![data];
let output = read_i16_chunks(&chunks, 3);
assert_eq!(output, vec![1, -1, 0]);
}
#[test]
fn read_i32_chunks_short_data_zero_filled_tail() {
let data = vec![0x01u8, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF];
let chunks = vec![data];
let output = read_i32_chunks(&chunks, 3);
assert_eq!(output, vec![1, -1, 0]);
}
#[test]
fn read_f32_chunks_short_data_zero_filled_tail() {
let mut data = Vec::new();
data.extend_from_slice(&1.0f32.to_le_bytes());
let chunks = vec![data];
let output = read_f32_chunks(&chunks, 2);
assert_eq!(output, vec![1.0, 0.0]);
}
#[test]
fn read_f64_chunks_short_data_zero_filled_tail() {
let mut data = Vec::new();
data.extend_from_slice(&1.0f64.to_le_bytes());
let chunks = vec![data];
let output = read_f64_chunks(&chunks, 2);
assert_eq!(output, vec![1.0, 0.0]);
}
#[test]
fn read_i16_chunks_handles_split_sample_across_chunks() {
let chunks = vec![vec![0x34u8], vec![0x12, 0x78], vec![0x56]];
let output = read_i16_chunks(&chunks, 2);
assert_eq!(output, vec![0x1234, 0x5678]);
}
#[test]
fn read_i16_chunks_drops_trailing_partial_sample() {
let chunks = vec![vec![0x34u8]];
let output = read_i16_chunks(&chunks, 1);
assert_eq!(output, vec![0]);
}
#[test]
fn read_i16_chunks_completes_sample_in_later_chunk() {
let chunks = vec![vec![0x34u8], vec![0x12]];
let output = read_i16_chunks(&chunks, 1);
assert_eq!(output, vec![0x1234]);
}
#[test]
fn read_i16_chunks_ignores_extra_bytes_after_fill() {
let chunks = vec![vec![0x34u8, 0x12, 0x78, 0x56, 0xAA]];
let output = read_i16_chunks(&chunks, 2);
assert_eq!(output, vec![0x1234, 0x5678]);
}
#[test]
fn read_i32_chunks_handles_split_sample_across_chunks() {
let chunks = vec![
vec![0xEFu8, 0xBE],
vec![0xAD, 0xDE, 0x01],
vec![0x00, 0x00, 0x00],
];
let output = read_i32_chunks(&chunks, 2);
assert_eq!(output, vec![0xDEADBEEF_u32 as i32, 1]);
}
#[test]
fn read_i32_chunks_drops_trailing_partial_sample() {
let chunks = vec![vec![0xEFu8, 0xBE, 0xAD]];
let output = read_i32_chunks(&chunks, 1);
assert_eq!(output, vec![0]);
}
#[test]
fn read_i32_chunks_completes_sample_in_later_chunk() {
let chunks = vec![vec![0xEFu8, 0xBE], vec![0xAD, 0xDE]];
let output = read_i32_chunks(&chunks, 1);
assert_eq!(output, vec![0xDEADBEEF_u32 as i32]);
}
#[test]
fn read_i32_chunks_ignores_extra_bytes_after_fill() {
let chunks = vec![vec![0xEFu8, 0xBE, 0xAD, 0xDE, 0x01, 0x00, 0x00, 0x00, 0xAA]];
let output = read_i32_chunks(&chunks, 2);
assert_eq!(output, vec![0xDEADBEEF_u32 as i32, 1]);
}
#[test]
fn read_f32_chunks_handles_split_sample_across_chunks() {
let bytes = 2.5f32.to_le_bytes();
let chunks = vec![vec![bytes[0], bytes[1]], vec![bytes[2], bytes[3]]];
let output = read_f32_chunks(&chunks, 1);
assert_eq!(output, vec![2.5]);
}
#[test]
fn read_f32_chunks_drops_trailing_partial_sample() {
let chunks = vec![vec![0x00u8, 0x00, 0x20]];
let output = read_f32_chunks(&chunks, 1);
assert_eq!(output, vec![0.0]);
}
#[test]
fn read_f32_chunks_completes_sample_in_later_chunk() {
let bytes = 2.5f32.to_le_bytes();
let chunks = vec![vec![bytes[0], bytes[1]], vec![bytes[2], bytes[3]]];
let output = read_f32_chunks(&chunks, 1);
assert_eq!(output, vec![2.5]);
}
#[test]
fn read_f32_chunks_ignores_extra_bytes_after_fill() {
let mut data = Vec::new();
for value in [1.0f32, 2.0f32] {
data.extend_from_slice(&value.to_le_bytes());
}
data.push(0xAA);
let chunks = vec![data];
let output = read_f32_chunks(&chunks, 2);
assert_eq!(output, vec![1.0, 2.0]);
}
#[test]
fn read_f64_chunks_handles_split_sample_across_chunks() {
let bytes = 2.5f64.to_le_bytes();
let chunks = vec![
vec![bytes[0], bytes[1], bytes[2]],
vec![bytes[3], bytes[4], bytes[5], bytes[6], bytes[7]],
];
let output = read_f64_chunks(&chunks, 1);
assert_eq!(output, vec![2.5]);
}
#[test]
fn read_f64_chunks_drops_trailing_partial_sample() {
let chunks = vec![vec![0x00u8, 0x00, 0x00, 0x00, 0x00]];
let output = read_f64_chunks(&chunks, 1);
assert_eq!(output, vec![0.0]);
}
#[test]
fn read_f64_chunks_completes_sample_in_later_chunk() {
let bytes = 2.5f64.to_le_bytes();
let chunks = vec![
vec![bytes[0], bytes[1], bytes[2], bytes[3]],
vec![bytes[4], bytes[5], bytes[6], bytes[7]],
];
let output = read_f64_chunks(&chunks, 1);
assert_eq!(output, vec![2.5]);
}
#[test]
fn read_f64_chunks_ignores_extra_bytes_after_fill() {
let mut data = Vec::new();
for value in [1.0f64, 2.0f64] {
data.extend_from_slice(&value.to_le_bytes());
}
data.push(0xAA);
let chunks = vec![data];
let output = read_f64_chunks(&chunks, 2);
assert_eq!(output, vec![1.0, 2.0]);
}
#[test]
fn read_i8_chunks_truncates_to_sample_count() {
let chunks = vec![vec![1u8, 2, 3, 4, 5]];
let output = read_i8_chunks(&chunks, 3);
assert_eq!(output, vec![1, 2, 3]);
}
#[test]
fn read_i16_chunks_truncates_to_sample_count() {
let mut data = Vec::new();
for value in [1i16, 2i16, 3i16] {
data.extend_from_slice(&value.to_le_bytes());
}
let chunks = vec![data];
let output = read_i16_chunks(&chunks, 2);
assert_eq!(output, vec![1, 2]);
}
#[test]
fn read_i32_chunks_truncates_to_sample_count() {
let mut data = Vec::new();
for value in [1i32, 2i32, 3i32] {
data.extend_from_slice(&value.to_le_bytes());
}
let chunks = vec![data];
let output = read_i32_chunks(&chunks, 2);
assert_eq!(output, vec![1, 2]);
}
#[test]
fn read_f32_chunks_truncates_to_sample_count() {
let mut data = Vec::new();
for value in [1.0f32, 2.0f32, 3.0f32] {
data.extend_from_slice(&value.to_le_bytes());
}
let chunks = vec![data];
let output = read_f32_chunks(&chunks, 2);
assert_eq!(output, vec![1.0, 2.0]);
}
#[test]
fn read_f64_chunks_truncates_to_sample_count() {
let mut data = Vec::new();
for value in [1.0f64, 2.0f64, 3.0f64] {
data.extend_from_slice(&value.to_le_bytes());
}
let chunks = vec![data];
let output = read_f64_chunks(&chunks, 2);
assert_eq!(output, vec![1.0, 2.0]);
}
}