diff --git a/jxl/src/lib.rs b/jxl/src/lib.rs index 494697a..26f110d 100644 --- a/jxl/src/lib.rs +++ b/jxl/src/lib.rs @@ -13,4 +13,4 @@ pub mod headers; pub mod icc; pub mod image; pub mod render; -mod util; +pub mod util; diff --git a/jxl/src/render/stages/upsample.rs b/jxl/src/render/stages/upsample.rs index 4840c28..98ef979 100644 --- a/jxl/src/render/stages/upsample.rs +++ b/jxl/src/render/stages/upsample.rs @@ -87,7 +87,10 @@ impl RenderPipelineStage for Upsample2x { #[cfg(test)] mod test { use super::*; - use crate::{error::Result, image::Image, render::test::make_and_run_simple_pipeline}; + use crate::{ + error::Result, image::Image, render::test::make_and_run_simple_pipeline, + util::test::assert_almost_eq, + }; use test_log::test; #[test] @@ -112,7 +115,7 @@ mod test { make_and_run_simple_pipeline(stage, &[input], image_size, 123)?.1; for x in 0..image_size.0 { for y in 0..image_size.1 { - assert!((output[0].as_rect().row(y)[x] - val).abs() <= 0.0000001); + assert_almost_eq!(output[0].as_rect().row(y)[x], val, 0.0000001); } } Ok(()) diff --git a/jxl/src/util.rs b/jxl/src/util.rs index 898848b..fd00579 100644 --- a/jxl/src/util.rs +++ b/jxl/src/util.rs @@ -3,6 +3,9 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +#[allow(unused)] +pub mod test; + mod bits; #[allow(unused)] mod concat_slice; diff --git a/jxl/src/util/concat_slice.rs b/jxl/src/util/concat_slice.rs index 9eb6e95..39f016d 100644 --- a/jxl/src/util/concat_slice.rs +++ b/jxl/src/util/concat_slice.rs @@ -18,6 +18,7 @@ impl<'first, 'second> ConcatSlice<'first, 'second> { } } + #[allow(clippy::len_without_is_empty)] pub fn len(&self) -> usize { self.slices.0.len() + self.slices.1.len() } diff --git a/jxl/src/util/test.rs b/jxl/src/util/test.rs new file mode 100644 index 0000000..0b753a8 --- /dev/null +++ b/jxl/src/util/test.rs @@ -0,0 +1,84 @@ +// Copyright (c) the JPEG XL Project Authors. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +macro_rules! assert_almost_eq { + ($left:expr, $right:expr, $max_error:expr $(,)?) => { + match (&$left, &$right, &$max_error) { + (left_val, right_val, max_error) => { + let diff = if *left_val > *right_val { + *left_val - *right_val + } else { + *right_val - *left_val + }; + match diff.partial_cmp(max_error) { + Some(std::cmp::Ordering::Greater) | None => panic!( + "assertion failed: `(left ≈ right)`\n left: `{:?}`,\n right: `{:?}`,\n max_error: `{:?}`", + left_val, right_val, max_error + ), + _ => {} + } + } + } + }; +} +pub(crate) use assert_almost_eq; + +#[cfg(test)] +mod tests { + use std::panic; + + #[test] + fn test_with_floats() { + assert_almost_eq!(1.0000001f64, 1.0000002, 0.000001); + assert_almost_eq!(1.0, 1.1, 0.2); + } + + #[test] + fn test_with_integers() { + assert_almost_eq!(100, 101, 2); + assert_almost_eq!(777u32, 770, 7); + assert_almost_eq!(500i64, 498, 3); + } + + #[test] + #[should_panic] + fn test_panic_float() { + assert_almost_eq!(1.0, 1.2, 0.1); + } + #[test] + #[should_panic] + fn test_panic_integer() { + assert_almost_eq!(100, 105, 2); + } + + #[test] + #[should_panic] + fn test_nan_comparison() { + assert_almost_eq!(f64::NAN, f64::NAN, 0.1); + } + + #[test] + #[should_panic] + fn test_nan_tolerance() { + assert_almost_eq!(1.0, 1.0, f64::NAN); + } + + #[test] + fn test_infinity_tolerance() { + assert_almost_eq!(1.0, 1.0, f64::INFINITY); + } + + #[test] + #[should_panic] + fn test_nan_comparison_with_infinity_tolerance() { + assert_almost_eq!(f32::NAN, f32::NAN, f32::INFINITY); + } + + #[test] + #[should_panic] + fn test_infinity_comparison_with_infinity_tolerance() { + assert_almost_eq!(f32::INFINITY, f32::INFINITY, f32::INFINITY); + } +}