1 #[macro_export] 2 macro_rules! glam_test { 3 ($name:ident, $block:block) => { 4 #[cfg_attr(not(target_arch = "wasm32"), test)] 5 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] 6 fn $name() { 7 $block 8 } 9 }; 10 } 11 12 #[macro_export] 13 macro_rules! should_panic { 14 ($block:block) => {{ 15 #[cfg(all(feature = "std", panic = "unwind"))] 16 assert!(std::panic::catch_unwind(|| $block).is_err()); 17 }}; 18 } 19 20 #[macro_export] 21 macro_rules! should_glam_assert { 22 ($block:block) => {{ 23 #[cfg(any(feature = "glam-assert", feature = "debug-glam-assert"))] 24 should_panic!($block); 25 }}; 26 } 27 28 #[macro_export] 29 macro_rules! assert_approx_eq { 30 ($a:expr, $b:expr) => {{ 31 #[allow(unused_imports)] 32 use $crate::support::FloatCompare; 33 let eps = f32::EPSILON; 34 let (a, b) = (&$a, &$b); 35 assert!( 36 a.approx_eq(b, eps), 37 "assertion failed: `(left !== right)` \ 38 (left: `{:?}`, right: `{:?}`, expect diff: `{:?}`, real diff: `{:?}`)", 39 *a, 40 *b, 41 eps, 42 a.abs_diff(b) 43 ); 44 }}; 45 ($a:expr, $b:expr, $eps:expr) => {{ 46 use $crate::support::FloatCompare; 47 let (a, b) = (&$a, &$b); 48 let eps = $eps; 49 assert!( 50 a.approx_eq(b, $eps), 51 "assertion failed: `(left !== right)` \ 52 (left: `{:?}`, right: `{:?}`, expect diff: `{:?}`, real diff: `{:?}`)", 53 *a, 54 *b, 55 eps, 56 a.abs_diff(b) 57 ); 58 }}; 59 ($a:expr, $b:expr, $eps:expr, $ctx:expr) => {{ 60 use $crate::support::FloatCompare; 61 let (a, b) = (&$a, &$b); 62 let eps = $eps; 63 assert!( 64 a.approx_eq(b, $eps), 65 "assertion failed: `(left !== right)` \ 66 (left: `{:?}`, right: `{:?}`, expect diff: `{:?}`, real diff: `{:?}`), \ 67 additional context: {}", 68 *a, 69 *b, 70 eps, 71 a.abs_diff(b), 72 $ctx 73 ); 74 }}; 75 } 76 77 /// Test vector normalization for float vector 78 #[macro_export] 79 macro_rules! impl_vec_float_normalize_tests { 80 ($t:ident, $vec:ident) => { 81 /// Works for vec2, vec3, vec4 82 fn from_x_y(x: $t, y: $t) -> $vec { 83 let mut v = $vec::ZERO; 84 v.x = x; 85 v.y = y; 86 v 87 } 88 89 glam_test!(test_normalize, { 90 assert_eq!(from_x_y(-42.0, 0.0).normalize(), from_x_y(-1.0, 0.0)); 91 assert_eq!( 92 from_x_y($t::MAX.sqrt(), 0.0).normalize(), 93 from_x_y(1.0, 0.0) 94 ); 95 // 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 96 97 // We expect not to be able to normalize small numbers: 98 should_glam_assert!({ from_x_y(0.0, 0.0).normalize() }); 99 should_glam_assert!({ from_x_y($t::MIN_POSITIVE, 0.0).normalize() }); 100 101 // We expect not to be able to normalize non-finite vectors: 102 should_glam_assert!({ from_x_y($t::INFINITY, 0.0).normalize() }); 103 should_glam_assert!({ from_x_y($t::NAN, 0.0).normalize() }); 104 }); 105 106 #[cfg(not(any(feature = "debug-glam-assert", feature = "glam-assert")))] 107 glam_test!(test_normalize_no_glam_assert, { 108 // We expect not to be able to normalize small numbers: 109 assert!(!from_x_y(0.0, 0.0).normalize().is_finite()); 110 assert!(!from_x_y($t::MIN_POSITIVE, 0.0).normalize().is_finite()); 111 112 // We expect not to be able to normalize non-finite vectors: 113 assert!(!from_x_y($t::INFINITY, 0.0).normalize().is_finite()); 114 assert!(!from_x_y($t::NAN, 0.0).normalize().is_finite()); 115 }); 116 117 glam_test!(test_try_normalize, { 118 assert_eq!( 119 from_x_y(-42.0, 0.0).try_normalize(), 120 Some(from_x_y(-1.0, 0.0)) 121 ); 122 assert_eq!( 123 from_x_y($t::MAX.sqrt(), 0.0).try_normalize(), 124 Some(from_x_y(1.0, 0.0)) 125 ); 126 127 // We expect `try_normalize` to return None when inputs are very small: 128 assert_eq!(from_x_y(0.0, 0.0).try_normalize(), None); 129 assert_eq!(from_x_y($t::MIN_POSITIVE, 0.0).try_normalize(), None); 130 131 // We expect `try_normalize` to return None when inputs are non-finite: 132 assert_eq!(from_x_y($t::INFINITY, 0.0).try_normalize(), None); 133 assert_eq!(from_x_y($t::NAN, 0.0).try_normalize(), None); 134 135 // We expect `try_normalize` to return None when inputs are very large: 136 assert_eq!(from_x_y($t::MAX, 0.0).try_normalize(), None); 137 assert_eq!(from_x_y($t::MAX, $t::MAX).try_normalize(), None); 138 }); 139 140 glam_test!(test_normalize_or, { 141 assert_eq!( 142 from_x_y(-42.0, 0.0).normalize_or($vec::Y), 143 from_x_y(-1.0, 0.0) 144 ); 145 assert_eq!( 146 from_x_y($t::MAX.sqrt(), 0.0).normalize_or($vec::Y), 147 from_x_y(1.0, 0.0) 148 ); 149 150 // We expect `normalize_or` to return the fallback value when inputs are very small: 151 assert_eq!(from_x_y(0.0, 0.0).normalize_or($vec::Y), $vec::Y); 152 assert_eq!( 153 from_x_y($t::MIN_POSITIVE, 0.0).normalize_or($vec::Y), 154 $vec::Y 155 ); 156 157 // We expect `normalize` to return zero when inputs are non-finite: 158 assert_eq!(from_x_y($t::INFINITY, 0.0).normalize_or($vec::Y), $vec::Y); 159 assert_eq!(from_x_y($t::NAN, 0.0).normalize_or($vec::Y), $vec::Y); 160 161 // We expect `normalize` to return zero when inputs are very large: 162 assert_eq!(from_x_y($t::MAX, 0.0).normalize_or($vec::Y), $vec::Y); 163 assert_eq!(from_x_y($t::MAX, $t::MAX).normalize_or($vec::Y), $vec::Y); 164 }); 165 166 glam_test!(test_normalize_or_zero, { 167 assert_eq!( 168 from_x_y(-42.0, 0.0).normalize_or_zero(), 169 from_x_y(-1.0, 0.0) 170 ); 171 assert_eq!( 172 from_x_y($t::MAX.sqrt(), 0.0).normalize_or_zero(), 173 from_x_y(1.0, 0.0) 174 ); 175 176 // We expect `normalize_or_zero` to return zero when inputs are very small: 177 assert_eq!(from_x_y(0.0, 0.0).normalize_or_zero(), $vec::ZERO); 178 assert_eq!( 179 from_x_y($t::MIN_POSITIVE, 0.0).normalize_or_zero(), 180 $vec::ZERO 181 ); 182 183 // We expect `normalize_or_zero` to return zero when inputs are non-finite: 184 assert_eq!(from_x_y($t::INFINITY, 0.0).normalize_or_zero(), $vec::ZERO); 185 assert_eq!(from_x_y($t::NAN, 0.0).normalize_or_zero(), $vec::ZERO); 186 187 // We expect `normalize_or_zero` to return zero when inputs are very large: 188 assert_eq!(from_x_y($t::MAX, 0.0).normalize_or_zero(), $vec::ZERO); 189 assert_eq!(from_x_y($t::MAX, $t::MAX).normalize_or_zero(), $vec::ZERO); 190 }); 191 }; 192 } 193 194 /// Useful test vectors 195 #[macro_export] 196 macro_rules! vec3_float_test_vectors { 197 ($vec3:ident) => { 198 [ 199 $vec3::X, 200 $vec3::Y, 201 $vec3::Z, 202 -$vec3::X, 203 -$vec3::Y, 204 -$vec3::Z, 205 $vec3::new(1.0, 1e-3, 0.0), 206 $vec3::new(1.0, 1e-4, 0.0), 207 $vec3::new(1.0, 1e-5, 0.0), 208 $vec3::new(1.0, 1e-6, 0.0), 209 $vec3::new(1.0, 1e-7, 0.0), 210 $vec3::new(1.0, 1e-14, 0.0), 211 $vec3::new(1.0, 1e-15, 0.0), 212 $vec3::new(1.0, 1e-16, 0.0), 213 $vec3::new(0.1, 0.2, 0.3), 214 $vec3::new(0.2, 0.3, 0.4), 215 $vec3::new(4.0, -5.0, 6.0), 216 $vec3::new(-2.0, 0.5, -1.0), 217 // Pathological cases from <https://graphics.pixar.com/library/OrthonormalB/paper.pdf>: 218 $vec3::new(0.00038527316, 0.00038460016, -0.99999988079), 219 $vec3::new(-0.00019813581, -0.00008946839, -0.99999988079), 220 ] 221 }; 222 } 223 224 #[macro_export] 225 macro_rules! vec2_float_test_vectors { 226 ($vec2:ident) => { 227 [ 228 $vec2::X, 229 $vec2::Y, 230 -$vec2::X, 231 -$vec2::Y, 232 $vec2::new(1.0, 1e-3), 233 $vec2::new(1.0, 1e-4), 234 $vec2::new(1.0, 1e-5), 235 $vec2::new(1.0, 1e-6), 236 $vec2::new(1.0, 1e-7), 237 $vec2::new(1.0, 1e-14), 238 $vec2::new(1.0, 1e-15), 239 $vec2::new(1.0, 1e-16), 240 $vec2::new(0.1, 0.2), 241 $vec2::new(0.2, 0.3), 242 $vec2::new(4.0, -5.0), 243 $vec2::new(-2.0, 0.5), 244 // Pathological cases from <https://graphics.pixar.com/library/OrthonormalB/paper.pdf>: 245 $vec2::new(0.00038527316, 0.00038460016), 246 $vec2::new(-0.00019813581, -0.00008946839), 247 ] 248 }; 249 } 250 251 #[macro_export] 252 macro_rules! test_matrix_minor { 253 ($n:expr, $minor:expr, $input:expr, $i:expr, $j:expr) => { 254 let mut yy = 0; 255 for y in 0..$n { 256 if y != $j { 257 let mut xx = 0; 258 for x in 0..$n { 259 if x != $i { 260 assert_eq!($minor.col(xx)[yy], $input.col(x)[y]); 261 xx += 1; 262 } 263 } 264 yy += 1; 265 } 266 } 267 }; 268 } 269