#[cfg(test)]
mod tests {
use crate::qubit::QubitId;
use scirs2_core::Complex64;
#[cfg(feature = "metal")]
use crate::gpu::metal_backend_scirs2_ready::{MetalQuantumState, *};
#[test]
fn test_metal_availability_detection() {
#[cfg(feature = "metal")]
{
let available = is_metal_available();
#[cfg(target_os = "macos")]
{
assert!(
available,
"Metal should be available on macOS with metal feature"
);
}
#[cfg(not(target_os = "macos"))]
{
assert!(!available, "Metal should not be available on non-macOS");
}
}
#[cfg(not(feature = "metal"))]
{
}
}
#[test]
fn test_metal_device_info() {
#[cfg(feature = "metal")]
{
let info = get_metal_device_info();
#[cfg(target_os = "macos")]
{
assert!(
info.is_some(),
"Should return device info on macOS with metal feature"
);
let info_str = info.expect("Device info should be Some on macOS");
assert!(info_str.contains("Metal Device"));
assert!(info_str.contains("Max threads per threadgroup"));
assert!(info_str.contains("Max buffer length"));
}
#[cfg(not(target_os = "macos"))]
{
assert!(info.is_none(), "Should return None on non-macOS");
}
}
#[cfg(not(feature = "metal"))]
{}
}
#[cfg(all(target_os = "macos", feature = "metal"))]
#[test]
fn test_metal_quantum_state_creation() {
for num_qubits in [1, 5, 10, 15] {
let result = MetalQuantumState::new(num_qubits);
assert!(result.is_ok(), "Should create {}-qubit state", num_qubits);
let state = result.expect("MetalQuantumState creation should succeed");
assert_eq!(state.num_qubits, num_qubits);
}
}
#[cfg(all(target_os = "macos", feature = "metal"))]
#[test]
fn test_single_qubit_gate_application() {
let mut state =
MetalQuantumState::new(5).expect("MetalQuantumState creation should succeed");
let pauli_x = [
Complex64::new(0.0, 0.0),
Complex64::new(1.0, 0.0),
Complex64::new(1.0, 0.0),
Complex64::new(0.0, 0.0),
];
let result = state.apply_single_qubit_gate(&pauli_x, QubitId(0));
assert!(result.is_ok(), "Should apply Pauli-X gate");
let sqrt2_inv = 1.0 / std::f64::consts::SQRT_2;
let hadamard = [
Complex64::new(sqrt2_inv, 0.0),
Complex64::new(sqrt2_inv, 0.0),
Complex64::new(sqrt2_inv, 0.0),
Complex64::new(-sqrt2_inv, 0.0),
];
let result = state.apply_single_qubit_gate(&hadamard, QubitId(1));
assert!(result.is_ok(), "Should apply Hadamard gate");
let result = state.apply_single_qubit_gate(&pauli_x, QubitId(5));
assert!(result.is_err(), "Should fail for out-of-range qubit");
}
#[cfg(all(target_os = "macos", feature = "metal"))]
#[test]
fn test_kernel_compilation() {
let state = MetalQuantumState::new(3).expect("MetalQuantumState creation should succeed");
let result = state.get_or_compile_kernel("apply_single_qubit_gate");
assert!(result.is_ok(), "Should compile single qubit gate kernel");
let kernel = result.expect("Kernel compilation should succeed");
assert_eq!(kernel.function_name, "apply_single_qubit_gate");
let result = state.get_or_compile_kernel("compute_probabilities");
assert!(result.is_ok(), "Should compile probabilities kernel");
let result = state.get_or_compile_kernel("invalid_kernel");
assert!(result.is_err(), "Should fail for invalid kernel name");
}
#[cfg(feature = "metal")]
#[test]
fn test_metal_shader_syntax() {
let shader_code = crate::gpu::metal_backend_scirs2_ready::METAL_QUANTUM_SHADERS;
assert!(shader_code.contains("#include <metal_stdlib>"));
assert!(shader_code.contains("using namespace metal"));
assert!(shader_code.contains("struct Complex"));
assert!(shader_code.contains("float real"));
assert!(shader_code.contains("float imag"));
assert!(shader_code.contains("kernel void apply_single_qubit_gate"));
assert!(shader_code.contains("kernel void compute_probabilities"));
assert!(shader_code.contains("[[buffer(0)]]"));
assert!(shader_code.contains("[[thread_position_in_grid]]"));
}
#[cfg(not(all(target_os = "macos", feature = "metal")))]
#[test]
#[ignore = "Skipping test that requires Metal GPU"]
fn test_metal_not_available() {
#[cfg(feature = "metal")]
{
use crate::gpu::metal_backend_scirs2_ready::MetalQuantumState;
let result = MetalQuantumState::new(5);
assert!(result.is_err(), "Should fail when Metal is not available");
match result {
Err(e) => {
let error_msg = format!("{}", e);
assert!(error_msg.contains("Metal support not compiled"));
}
Ok(_) => panic!("Expected error when Metal is not available"),
}
}
#[cfg(not(feature = "metal"))]
{
}
}
#[test]
fn test_placeholder_types() {
#[cfg(feature = "metal")]
{
use super::super::metal_backend_scirs2_ready::scirs2_metal_placeholder::*;
let device = MetalDeviceHandle {
name: "Test Device".to_string(),
};
assert_eq!(device.name, "Test Device");
let buffer: MetalBuffer<f32> = MetalBuffer {
buffer: MetalBufferHandle,
length: 1024,
_phantom: std::marker::PhantomData,
};
assert_eq!(buffer.length, 1024);
let kernel = MetalKernel {
pipeline: MetalComputePipeline,
function_name: "test_kernel".to_string(),
};
assert_eq!(kernel.function_name, "test_kernel");
}
}
#[test]
fn test_scirs2_compatibility() {
use crate::gpu::scirs2_adapter::is_gpu_available;
let _gpu_available = is_gpu_available();
#[cfg(feature = "metal")]
{
let metal_available = is_metal_available();
#[cfg(feature = "gpu")]
{
let any_gpu = _gpu_available || metal_available;
let _ = any_gpu;
}
}
}
}