use oxicuda_backend::{BackendError, BackendTranspose, ComputeBackend};
use oxicuda_webgpu::WebGpuBackend;
fn try_init() -> Option<WebGpuBackend> {
let mut b = WebGpuBackend::new();
b.init().ok().map(|()| b)
}
#[test]
fn non_multiple_of_4_alloc_rounds_up_and_roundtrips() {
let Some(backend) = try_init() else { return };
const LEN: usize = 13;
let ptr = backend
.alloc(LEN)
.expect("a non-multiple-of-4 alloc size must still succeed (rounds up internally)");
let data: Vec<u8> = (0u8..LEN as u8)
.map(|i| i.wrapping_mul(17).wrapping_add(1))
.collect();
backend
.copy_htod(ptr, &data)
.expect("copy_htod of exactly LEN bytes");
let mut back = vec![0u8; LEN];
backend
.copy_dtoh(&mut back, ptr)
.expect("copy_dtoh of exactly LEN bytes");
assert_eq!(
back, data,
"the requested (unaligned) byte range must round-trip exactly"
);
backend.free(ptr).expect("free");
}
#[test]
fn oversized_alloc_returns_out_of_memory() {
let Some(backend) = try_init() else { return };
const HUGE: usize = 1usize << 40;
let result = backend.alloc(HUGE);
assert_eq!(
result,
Err(BackendError::OutOfMemory),
"a 1 TiB allocation must be rejected as OutOfMemory"
);
let ptr = backend
.alloc(64)
.expect("small alloc after OOM must still work");
backend.free(ptr).expect("free after OOM must still work");
}
#[test]
fn batch_count_over_65535_is_rejected() {
let Some(backend) = try_init() else { return };
let (m, n, k, batch_count) = (1usize, 1usize, 1usize, 70_000usize);
let a_ptr = backend.alloc(batch_count * 4).expect("alloc a");
let b_ptr = backend.alloc(batch_count * 4).expect("alloc b");
let c_ptr = backend.alloc(batch_count * 4).expect("alloc c");
let result = backend.batched_gemm(
BackendTranspose::NoTrans,
BackendTranspose::NoTrans,
m,
n,
k,
1.0,
a_ptr,
k,
m * k,
b_ptr,
n,
k * n,
0.0,
c_ptr,
n,
m * n,
batch_count,
);
assert!(
matches!(result, Err(BackendError::InvalidArgument(_))),
"batch_count=70_000 must be rejected with InvalidArgument (exceeds the \
65_535 per-dimension workgroup cap), got {result:?}"
);
}