use sift::{GpuSiftConfig, GpuSiftContext};
#[tokio::test]
async fn test_gpu_sift_basic() {
let width = 32u32;
let height = 32u32;
let mut image = vec![0u8; (width * height) as usize];
for y in 0..height {
for x in 0..width {
let idx = (y * width + x) as usize;
let checker = ((x / 4) + (y / 4)) % 2;
image[idx] = if checker == 0 { 50 } else { 200 };
}
}
let config = GpuSiftConfig {
octaves: 2,
scales: 3,
base_sigma: 1.6,
contrast_threshold: 0.01,
edge_threshold: 10.0,
};
let ctx = GpuSiftContext::new(config)
.await
.expect("Failed to create GPU context");
let result = ctx.detect(&image, width, height).await;
match result {
Ok((keypoints, descriptors)) => {
println!("✓ GPU SIFT completed successfully");
println!(" Keypoints: {}", keypoints.len());
println!(" Descriptors: {}", descriptors.len());
assert_eq!(
keypoints.len(),
descriptors.len(),
"Keypoint and descriptor count mismatch"
);
for kp in keypoints.iter().take(5) {
assert!(
kp.x >= 0.0 && kp.x <= width as f32,
"Keypoint x out of bounds"
);
assert!(
kp.y >= 0.0 && kp.y <= height as f32,
"Keypoint y out of bounds"
);
assert!(kp.size > 0.0, "Keypoint size should be positive");
assert!(
kp.angle >= -std::f32::consts::PI && kp.angle <= std::f32::consts::PI,
"Keypoint angle out of range"
);
}
if !descriptors.is_empty() {
let desc = &descriptors[0];
let sum: u32 = desc.iter().map(|&v| v as u32).sum();
assert!(sum > 0, "First descriptor is all zeros");
}
}
Err(e) => {
println!("⚠ GPU SIFT failed (this is expected in CI): {}", e);
println!(" Test passed (GPU not required)");
}
}
}
#[tokio::test]
async fn test_gpu_sift_gradient() {
let width = 64u32;
let height = 64u32;
let mut image = vec![0u8; (width * height) as usize];
for y in 0..height {
for x in 0..width {
let idx = (y * width + x) as usize;
image[idx] = ((x + y) * 255 / (width + height)) as u8;
}
}
let config = GpuSiftConfig::default();
match GpuSiftContext::new(config).await {
Ok(ctx) => match ctx.detect(&image, width, height).await {
Ok((keypoints, descriptors)) => {
println!("✓ Gradient test: {} keypoints", keypoints.len());
assert_eq!(keypoints.len(), descriptors.len());
}
Err(e) => {
println!("⚠ GPU detection failed: {}", e);
}
},
Err(e) => {
println!("⚠ GPU context creation failed: {}", e);
}
}
}
#[tokio::test]
async fn test_gpu_sift_different_sizes() {
let sizes = vec![(16, 16), (32, 32), (64, 48), (128, 96)];
let config = GpuSiftConfig {
octaves: 3,
scales: 4,
base_sigma: 1.6,
contrast_threshold: 0.02,
edge_threshold: 10.0,
};
match GpuSiftContext::new(config).await {
Ok(ctx) => {
for (width, height) in sizes {
let image = vec![128u8; (width * height) as usize];
match ctx.detect(&image, width, height).await {
Ok((keypoints, descriptors)) => {
println!("✓ {}×{}: {} keypoints", width, height, keypoints.len());
assert_eq!(keypoints.len(), descriptors.len());
}
Err(e) => {
println!("⚠ {}×{} failed: {}", width, height, e);
}
}
}
}
Err(e) => {
println!("⚠ GPU context creation failed: {}", e);
}
}
}
#[test]
fn test_gpu_sift_config_defaults() {
let config = GpuSiftConfig::default();
assert_eq!(config.octaves, 4);
assert_eq!(config.scales, 5);
assert_eq!(config.base_sigma, 1.6);
assert_eq!(config.contrast_threshold, 0.03);
assert_eq!(config.edge_threshold, 10.0);
}
#[test]
fn test_gpu_sift_config_custom() {
let config = GpuSiftConfig {
octaves: 3,
scales: 4,
base_sigma: 2.0,
contrast_threshold: 0.01,
edge_threshold: 15.0,
};
assert_eq!(config.octaves, 3);
assert_eq!(config.scales, 4);
assert_eq!(config.base_sigma, 2.0);
assert_eq!(config.contrast_threshold, 0.01);
assert_eq!(config.edge_threshold, 15.0);
}