use std::ops::Sub;
use bevy::prelude::{Quat, Vec2, Vec3, Vec4};
#[cfg(feature = "gpu_tests")]
use bevy::render::renderer::{RenderDevice, RenderQueue, WgpuWrapper};
pub(crate) trait AbsDiffEq {
fn abs_diff(a: &Self, b: &Self) -> f32;
fn abs_diff_eq(a: &Self, b: &Self, tol: f32) -> bool;
}
impl AbsDiffEq for f32 {
fn abs_diff(a: &f32, b: &f32) -> f32 {
(a - b).abs()
}
fn abs_diff_eq(a: &f32, b: &f32, tol: f32) -> bool {
(a - b).abs() < tol
}
}
impl AbsDiffEq for f64 {
fn abs_diff(a: &f64, b: &f64) -> f32 {
(a - b).abs() as f32
}
fn abs_diff_eq(a: &f64, b: &f64, tol: f32) -> bool {
(a - b).abs() < tol as f64
}
}
impl AbsDiffEq for Vec2 {
fn abs_diff(a: &Vec2, b: &Vec2) -> f32 {
a.sub(*b).abs().max_element()
}
fn abs_diff_eq(a: &Vec2, b: &Vec2, tol: f32) -> bool {
a.abs_diff_eq(*b, tol)
}
}
impl AbsDiffEq for Vec3 {
fn abs_diff(a: &Vec3, b: &Vec3) -> f32 {
a.sub(*b).abs().max_element()
}
fn abs_diff_eq(a: &Vec3, b: &Vec3, tol: f32) -> bool {
a.abs_diff_eq(*b, tol)
}
}
impl AbsDiffEq for Vec4 {
fn abs_diff(a: &Vec4, b: &Vec4) -> f32 {
a.sub(*b).abs().max_element()
}
fn abs_diff_eq(a: &Vec4, b: &Vec4, tol: f32) -> bool {
a.abs_diff_eq(*b, tol)
}
}
impl AbsDiffEq for Quat {
fn abs_diff(a: &Quat, b: &Quat) -> f32 {
Vec4::from(*a).sub(Vec4::from(*b)).abs().max_element()
}
fn abs_diff_eq(a: &Quat, b: &Quat, tol: f32) -> bool {
a.abs_diff_eq(*b, tol)
}
}
macro_rules! assert_approx_eq {
($left:expr, $right:expr $(,)?) => {
match (&$left, &$right) {
(left_val, right_val) => {
assert!(
crate::test_utils::AbsDiffEq::abs_diff_eq(left_val, right_val, 1e-5),
"assertion failed: expected={} actual={} delta={} tol=1e-5(default)",
left_val,
right_val,
crate::test_utils::AbsDiffEq::abs_diff(left_val, right_val),
);
}
}
};
($left:expr, $right:expr, $tol:expr $(,)?) => {
match (&$left, &$right, &$tol) {
(left_val, right_val, tol_val) => {
assert!(
crate::test_utils::AbsDiffEq::abs_diff_eq(left_val, right_val, *tol_val),
"assertion failed: expected={} actual={} delta={} tol={}",
left_val,
right_val,
crate::test_utils::AbsDiffEq::abs_diff(left_val, right_val),
tol_val
);
}
}
};
}
pub(crate) use assert_approx_eq;
#[cfg(feature = "gpu_tests")]
#[allow(dead_code)]
pub(crate) struct MockRenderer {
instance: wgpu::Instance,
adapter: wgpu::Adapter,
device: RenderDevice,
queue: RenderQueue,
}
#[cfg(feature = "gpu_tests")]
impl MockRenderer {
pub fn new() -> Self {
#[cfg(debug_assertions)]
let flags = wgpu::InstanceFlags::DEBUG | wgpu::InstanceFlags::VALIDATION;
#[cfg(not(debug_assertions))]
let flags = wgpu::InstanceFlags::empty();
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
backends: wgpu::Backends::PRIMARY,
flags,
backend_options: wgpu::BackendOptions::default(),
memory_budget_thresholds: wgpu::MemoryBudgetThresholds::default(),
display: None,
});
let adapter =
futures::executor::block_on(instance.request_adapter(&wgpu::RequestAdapterOptions {
power_preference: wgpu::PowerPreference::default(),
force_fallback_adapter: false,
compatible_surface: None,
}))
.expect("Failed to find an appropriate adapter");
let (device, queue) =
futures::executor::block_on(adapter.request_device(&wgpu::DeviceDescriptor {
required_features: wgpu::Features::MAPPABLE_PRIMARY_BUFFERS,
required_limits: wgpu::Limits::downlevel_defaults(),
..Default::default()
}))
.expect("Failed to create device");
let device = RenderDevice::from(device);
let queue = RenderQueue(std::sync::Arc::new(WgpuWrapper::new(queue)));
Self {
instance,
adapter,
device,
queue,
}
}
pub fn device(&self) -> RenderDevice {
self.device.clone()
}
pub fn queue(&self) -> RenderQueue {
self.queue.clone()
}
}