Skip to content

Commit

Permalink
Unit tests for FloatIter
Browse files Browse the repository at this point in the history
  • Loading branch information
Jefffrey committed Mar 13, 2024
1 parent 8e254a6 commit 9f7bbc4
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 6 deletions.
115 changes: 114 additions & 1 deletion src/reader/decode/float.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,14 @@ use snafu::ResultExt;
use crate::error::{self, Result};

/// Sealead trait to generically represent f32 and f64.
pub trait Float: Default + Copy + private::Sealed + Send + Sync + 'static {
pub trait Float:
Default + Copy + private::Sealed + Send + Sync + 'static + std::fmt::Debug + PartialEq
{
type Bytes: AsRef<[u8]> + AsMut<[u8]> + Default;

fn from_le_bytes(bytes: Self::Bytes) -> Self;

fn to_le_bytes(&self) -> Self::Bytes;
}

mod private {
Expand All @@ -21,6 +26,11 @@ impl Float for f32 {
fn from_le_bytes(bytes: Self::Bytes) -> Self {
Self::from_le_bytes(bytes)
}

#[inline]
fn to_le_bytes(&self) -> Self::Bytes {
Self::to_le_bytes(*self)
}
}

impl Float for f64 {
Expand All @@ -30,6 +40,11 @@ impl Float for f64 {
fn from_le_bytes(bytes: Self::Bytes) -> Self {
Self::from_le_bytes(bytes)
}

#[inline]
fn to_le_bytes(&self) -> Self::Bytes {
Self::to_le_bytes(*self)
}
}

/// An iterator
Expand Down Expand Up @@ -94,3 +109,101 @@ impl<T: Float, R: std::io::Read> Iterator for FloatIter<T, R> {
(remaining, Some(remaining))
}
}

#[cfg(test)]
mod tests {
use std::f32::consts as f32c;
use std::f64::consts as f64c;
use std::io::Cursor;

use super::*;

fn float_to_bytes<F: Float>(input: &[F]) -> Vec<u8> {
input
.iter()
.flat_map(|f| f.to_le_bytes().as_ref().to_vec())
.collect()
}

fn assert_roundtrip<F: Float>(input: Vec<F>) {
let bytes = float_to_bytes(&input);
let bytes = Cursor::new(bytes);

let iter = FloatIter::<F, _>::new(bytes, input.len());
let actual = iter.collect::<Result<Vec<_>>>().unwrap();

assert_eq!(input, actual);
}

#[test]
fn test_float_iter_empty() {
assert_roundtrip::<f32>(vec![]);
}

#[test]
fn test_double_iter_empty() {
assert_roundtrip::<f64>(vec![]);
}

#[test]
fn test_float_iter_one() {
assert_roundtrip(vec![f32c::PI]);
}

#[test]
fn test_double_iter_one() {
assert_roundtrip(vec![f64c::PI]);
}

#[test]
fn test_float_iter_nan() {
let bytes = float_to_bytes(&[f32::NAN]);
let bytes = Cursor::new(bytes);

let iter = FloatIter::<f32, _>::new(bytes, 1);
let actual = iter.collect::<Result<Vec<_>>>().unwrap();
assert_eq!(actual.len(), 1);
assert!(actual[0].is_nan());
}

#[test]
fn test_double_iter_nan() {
let bytes = float_to_bytes(&[f64::NAN]);
let bytes = Cursor::new(bytes);

let iter = FloatIter::<f64, _>::new(bytes, 1);
let actual = iter.collect::<Result<Vec<_>>>().unwrap();
assert_eq!(actual.len(), 1);
assert!(actual[0].is_nan());
}

#[test]
fn test_float_iter_many() {
assert_roundtrip(vec![
f32::NEG_INFINITY,
f32::MIN,
-1.0,
-0.0,
0.0,
1.0,
f32c::SQRT_2,
f32::MAX,
f32::INFINITY,
]);
}

#[test]
fn test_double_iter_many() {
assert_roundtrip(vec![
f64::NEG_INFINITY,
f64::MIN,
-1.0,
-0.0,
0.0,
1.0,
f64c::SQRT_2,
f64::MAX,
f64::INFINITY,
]);
}
}
6 changes: 1 addition & 5 deletions src/reader/decode/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,7 @@ pub fn read_u8(reader: &mut impl Read) -> Result<u8> {
pub fn try_read_u8(reader: &mut impl Read) -> Result<Option<u8>> {
let mut byte = [0];
let length = reader.read(&mut byte).context(error::IoSnafu)?;
if length == 0 {
Ok(None)
} else {
Ok(Some(byte[0]))
}
Ok((length > 0).then_some(byte[0]))
}

/// Extracting run length from first two header bytes.
Expand Down

0 comments on commit 9f7bbc4

Please sign in to comment.