use kopitiam_gpu::ops::{vector_add_cpu, VectorAdd, VectorAddInput};
use kopitiam_gpu::{Executor, GpuContext};
fn sample() -> (Vec<f32>, Vec<f32>, Vec<f32>) {
let a: Vec<f32> = (0..300).map(|i| i as f32).collect();
let b: Vec<f32> = (0..300).map(|i| (i as f32) * 0.5).collect();
let expected: Vec<f32> = a.iter().zip(&b).map(|(x, y)| x + y).collect();
(a, b, expected)
}
#[test]
fn cascade_is_always_correct() {
let (a, b, expected) = sample();
let exec = Executor::new();
if exec.has_gpu() {
eprintln!(
"cascade_is_always_correct: GPU present ({})",
exec.gpu_context().unwrap().describe_backend()
);
} else {
eprintln!("cascade_is_always_correct: no GPU, running on CPU path");
}
let got = exec.run(&VectorAdd, &VectorAddInput { a: &a, b: &b });
assert_eq!(got, expected);
}
#[test]
fn cpu_fallback_is_correct() {
let (a, b, expected) = sample();
assert_eq!(vector_add_cpu(&a, &b), expected);
let exec = Executor::cpu_only();
assert!(!exec.has_gpu());
let got = exec.run(&VectorAdd, &VectorAddInput { a: &a, b: &b });
assert_eq!(got, expected);
}
#[test]
fn gpu_matches_cpu_when_present() {
let (a, b, expected) = sample();
let ctx = match GpuContext::new() {
Ok(ctx) => ctx,
Err(e) => {
eprintln!("gpu_matches_cpu_when_present: no GPU ({e}); skipping GPU==CPU check");
return; }
};
let gpu = kopitiam_gpu::ops::vector_add_gpu(&ctx, &a, &b)
.expect("GPU present but the vector_add kernel failed");
assert_eq!(gpu, expected, "GPU result diverged from the known-good sum");
assert_eq!(gpu, vector_add_cpu(&a, &b), "GPU and CPU results disagree");
}
#[test]
fn gpu_rejects_mismatched_lengths() {
let ctx = match GpuContext::new() {
Ok(ctx) => ctx,
Err(_) => return, };
let a = [1.0f32, 2.0, 3.0];
let b = [1.0f32, 2.0];
let err = kopitiam_gpu::ops::vector_add_gpu(&ctx, &a, &b);
assert!(err.is_err(), "unequal lengths should be rejected by the GPU path");
}