#[macro_export] macro_rules! glam_test { ($name:ident, $block:block) => { #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn $name() { $block } }; } #[macro_export] macro_rules! should_panic { ($block:block) => {{ #[cfg(all(feature = "std", panic = "unwind"))] assert!(std::panic::catch_unwind(|| $block).is_err()); }}; } #[macro_export] macro_rules! should_glam_assert { ($block:block) => {{ #[cfg(any(feature = "glam-assert", feature = "debug-glam-assert"))] should_panic!($block); }}; } #[macro_export] macro_rules! assert_approx_eq { ($a:expr, $b:expr) => {{ #[allow(unused_imports)] use $crate::support::FloatCompare; let eps = f32::EPSILON; let (a, b) = (&$a, &$b); assert!( a.approx_eq(b, eps), "assertion failed: `(left !== right)` \ (left: `{:?}`, right: `{:?}`, expect diff: `{:?}`, real diff: `{:?}`)", *a, *b, eps, a.abs_diff(b) ); }}; ($a:expr, $b:expr, $eps:expr) => {{ use $crate::support::FloatCompare; let (a, b) = (&$a, &$b); let eps = $eps; assert!( a.approx_eq(b, $eps), "assertion failed: `(left !== right)` \ (left: `{:?}`, right: `{:?}`, expect diff: `{:?}`, real diff: `{:?}`)", *a, *b, eps, a.abs_diff(b) ); }}; ($a:expr, $b:expr, $eps:expr, $ctx:expr) => {{ use $crate::support::FloatCompare; let (a, b) = (&$a, &$b); let eps = $eps; assert!( a.approx_eq(b, $eps), "assertion failed: `(left !== right)` \ (left: `{:?}`, right: `{:?}`, expect diff: `{:?}`, real diff: `{:?}`), \ additional context: {}", *a, *b, eps, a.abs_diff(b), $ctx ); }}; } /// Test vector normalization for float vector #[macro_export] macro_rules! impl_vec_float_normalize_tests { ($t:ident, $vec:ident) => { /// Works for vec2, vec3, vec4 fn from_x_y(x: $t, y: $t) -> $vec { let mut v = $vec::ZERO; v.x = x; v.y = y; v } glam_test!(test_normalize, { assert_eq!(from_x_y(-42.0, 0.0).normalize(), from_x_y(-1.0, 0.0)); assert_eq!( from_x_y($t::MAX.sqrt(), 0.0).normalize(), from_x_y(1.0, 0.0) ); // assert_eq!(from_x_y($t::MAX, 0.0).normalize(), from_x_y(1.0, 0.0)); // normalize fails for huge vectors and returns zero // We expect not to be able to normalize small numbers: should_glam_assert!({ from_x_y(0.0, 0.0).normalize() }); should_glam_assert!({ from_x_y($t::MIN_POSITIVE, 0.0).normalize() }); // We expect not to be able to normalize non-finite vectors: should_glam_assert!({ from_x_y($t::INFINITY, 0.0).normalize() }); should_glam_assert!({ from_x_y($t::NAN, 0.0).normalize() }); }); #[cfg(not(any(feature = "debug-glam-assert", feature = "glam-assert")))] glam_test!(test_normalize_no_glam_assert, { // We expect not to be able to normalize small numbers: assert!(!from_x_y(0.0, 0.0).normalize().is_finite()); assert!(!from_x_y($t::MIN_POSITIVE, 0.0).normalize().is_finite()); // We expect not to be able to normalize non-finite vectors: assert!(!from_x_y($t::INFINITY, 0.0).normalize().is_finite()); assert!(!from_x_y($t::NAN, 0.0).normalize().is_finite()); }); glam_test!(test_try_normalize, { assert_eq!( from_x_y(-42.0, 0.0).try_normalize(), Some(from_x_y(-1.0, 0.0)) ); assert_eq!( from_x_y($t::MAX.sqrt(), 0.0).try_normalize(), Some(from_x_y(1.0, 0.0)) ); // We expect `try_normalize` to return None when inputs are very small: assert_eq!(from_x_y(0.0, 0.0).try_normalize(), None); assert_eq!(from_x_y($t::MIN_POSITIVE, 0.0).try_normalize(), None); // We expect `try_normalize` to return None when inputs are non-finite: assert_eq!(from_x_y($t::INFINITY, 0.0).try_normalize(), None); assert_eq!(from_x_y($t::NAN, 0.0).try_normalize(), None); // We expect `try_normalize` to return None when inputs are very large: assert_eq!(from_x_y($t::MAX, 0.0).try_normalize(), None); assert_eq!(from_x_y($t::MAX, $t::MAX).try_normalize(), None); }); glam_test!(test_normalize_or, { assert_eq!( from_x_y(-42.0, 0.0).normalize_or($vec::Y), from_x_y(-1.0, 0.0) ); assert_eq!( from_x_y($t::MAX.sqrt(), 0.0).normalize_or($vec::Y), from_x_y(1.0, 0.0) ); // We expect `normalize_or` to return the fallback value when inputs are very small: assert_eq!(from_x_y(0.0, 0.0).normalize_or($vec::Y), $vec::Y); assert_eq!( from_x_y($t::MIN_POSITIVE, 0.0).normalize_or($vec::Y), $vec::Y ); // We expect `normalize` to return zero when inputs are non-finite: assert_eq!(from_x_y($t::INFINITY, 0.0).normalize_or($vec::Y), $vec::Y); assert_eq!(from_x_y($t::NAN, 0.0).normalize_or($vec::Y), $vec::Y); // We expect `normalize` to return zero when inputs are very large: assert_eq!(from_x_y($t::MAX, 0.0).normalize_or($vec::Y), $vec::Y); assert_eq!(from_x_y($t::MAX, $t::MAX).normalize_or($vec::Y), $vec::Y); }); glam_test!(test_normalize_or_zero, { assert_eq!( from_x_y(-42.0, 0.0).normalize_or_zero(), from_x_y(-1.0, 0.0) ); assert_eq!( from_x_y($t::MAX.sqrt(), 0.0).normalize_or_zero(), from_x_y(1.0, 0.0) ); // We expect `normalize_or_zero` to return zero when inputs are very small: assert_eq!(from_x_y(0.0, 0.0).normalize_or_zero(), $vec::ZERO); assert_eq!( from_x_y($t::MIN_POSITIVE, 0.0).normalize_or_zero(), $vec::ZERO ); // We expect `normalize_or_zero` to return zero when inputs are non-finite: assert_eq!(from_x_y($t::INFINITY, 0.0).normalize_or_zero(), $vec::ZERO); assert_eq!(from_x_y($t::NAN, 0.0).normalize_or_zero(), $vec::ZERO); // We expect `normalize_or_zero` to return zero when inputs are very large: assert_eq!(from_x_y($t::MAX, 0.0).normalize_or_zero(), $vec::ZERO); assert_eq!(from_x_y($t::MAX, $t::MAX).normalize_or_zero(), $vec::ZERO); }); }; } /// Useful test vectors #[macro_export] macro_rules! vec3_float_test_vectors { ($vec3:ident) => { [ $vec3::X, $vec3::Y, $vec3::Z, -$vec3::X, -$vec3::Y, -$vec3::Z, $vec3::new(1.0, 1e-3, 0.0), $vec3::new(1.0, 1e-4, 0.0), $vec3::new(1.0, 1e-5, 0.0), $vec3::new(1.0, 1e-6, 0.0), $vec3::new(1.0, 1e-7, 0.0), $vec3::new(1.0, 1e-14, 0.0), $vec3::new(1.0, 1e-15, 0.0), $vec3::new(1.0, 1e-16, 0.0), $vec3::new(0.1, 0.2, 0.3), $vec3::new(0.2, 0.3, 0.4), $vec3::new(4.0, -5.0, 6.0), $vec3::new(-2.0, 0.5, -1.0), // Pathological cases from : $vec3::new(0.00038527316, 0.00038460016, -0.99999988079), $vec3::new(-0.00019813581, -0.00008946839, -0.99999988079), ] }; } #[macro_export] macro_rules! vec2_float_test_vectors { ($vec2:ident) => { [ $vec2::X, $vec2::Y, -$vec2::X, -$vec2::Y, $vec2::new(1.0, 1e-3), $vec2::new(1.0, 1e-4), $vec2::new(1.0, 1e-5), $vec2::new(1.0, 1e-6), $vec2::new(1.0, 1e-7), $vec2::new(1.0, 1e-14), $vec2::new(1.0, 1e-15), $vec2::new(1.0, 1e-16), $vec2::new(0.1, 0.2), $vec2::new(0.2, 0.3), $vec2::new(4.0, -5.0), $vec2::new(-2.0, 0.5), // Pathological cases from : $vec2::new(0.00038527316, 0.00038460016), $vec2::new(-0.00019813581, -0.00008946839), ] }; } #[macro_export] macro_rules! test_matrix_minor { ($n:expr, $minor:expr, $input:expr, $i:expr, $j:expr) => { let mut yy = 0; for y in 0..$n { if y != $j { let mut xx = 0; for x in 0..$n { if x != $i { assert_eq!($minor.col(xx)[yy], $input.col(x)[y]); xx += 1; } } yy += 1; } } }; }