use crate::error::Result;
use crate::gpu::executor::{CpuExecutor, ExecutorCall, GpuExecutorTrait, MockExecutor};
#[test]
fn test_mock_executor_has_call_found() {
let mut mock = MockExecutor::new("test");
let _ = mock.matmul(&[1.0; 4], &[1.0; 4], 2, 2, 2);
let expected_call = ExecutorCall::Matmul {
a_len: 4,
b_len: 4,
m: 2,
k: 2,
n: 2,
};
assert!(mock.has_call(&expected_call));
}
#[test]
fn test_mock_executor_has_call_not_found() {
let mut mock = MockExecutor::new("test");
let _ = mock.matmul(&[1.0; 4], &[1.0; 4], 2, 2, 2);
let different_call = ExecutorCall::Matmul {
a_len: 9,
b_len: 9,
m: 3,
k: 3,
n: 3,
};
assert!(!mock.has_call(&different_call));
}
#[test]
fn test_mock_executor_has_call_synchronize() {
let mock = MockExecutor::new("test");
let _ = mock.synchronize();
assert!(!mock.has_call(&ExecutorCall::Synchronize));
}
#[test]
fn test_mock_executor_has_call_empty() {
let mock = MockExecutor::new("test");
let call = ExecutorCall::Matmul {
a_len: 4,
b_len: 4,
m: 2,
k: 2,
n: 2,
};
assert!(!mock.has_call(&call));
}
#[test]
fn test_mock_executor_matmul_transpose_b_basic() {
let mut mock = MockExecutor::new("test");
let a = vec![1.0; 6]; let b = vec![1.0; 12];
let result = mock.matmul_transpose_b(&a, &b, 2, 3, 4).unwrap();
assert_eq!(result.len(), 8);
assert_eq!(result, vec![0.0; 8]);
assert_eq!(mock.call_count(), 1);
}
#[test]
fn test_mock_executor_matmul_transpose_b_records_call() {
let mut mock = MockExecutor::new("test");
let a = vec![1.0; 6];
let b = vec![1.0; 12];
let _ = mock.matmul_transpose_b(&a, &b, 2, 3, 4);
let last = mock.last_call().unwrap();
assert!(matches!(
last,
ExecutorCall::MatmulTransposeB {
a_len: 6,
b_len: 12,
m: 2,
k: 3,
n: 4,
}
));
}
#[test]
fn test_mock_executor_matmul_transpose_b_with_custom_result() {
let custom_result = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0];
let mut mock = MockExecutor::new("test").with_matmul_result(custom_result.clone());
let a = vec![1.0; 6];
let b = vec![1.0; 12];
let result = mock.matmul_transpose_b(&a, &b, 2, 3, 4).unwrap();
assert_eq!(result, custom_result);
}
#[test]
fn test_mock_executor_matmul_transpose_b_failure() {
let mut mock = MockExecutor::new("test").with_matmul_failure();
let a = vec![1.0; 6];
let b = vec![1.0; 12];
let result = mock.matmul_transpose_b(&a, &b, 2, 3, 4);
assert!(result.is_err());
let err_msg = format!("{:?}", result.unwrap_err());
assert!(err_msg.contains("configured to fail"));
}
#[test]
fn test_mock_executor_matmul_transpose_b_call_counter() {
let mut mock = MockExecutor::new("test");
let _ = mock.matmul(&[1.0; 4], &[1.0; 4], 2, 2, 2);
let _ = mock.matmul_transpose_b(&[1.0; 4], &[1.0; 4], 2, 2, 2);
let _ = mock.matmul(&[1.0; 4], &[1.0; 4], 2, 2, 2);
assert_eq!(mock.call_count(), 3);
assert_eq!(mock.matmul_count(), 2); }
#[test]
fn test_cpu_executor_matmul_transpose_b_2x2() {
let mut cpu = CpuExecutor::new();
let a = vec![1.0, 2.0, 3.0, 4.0];
let b = vec![5.0, 6.0, 7.0, 8.0];
let c = cpu.matmul_transpose_b(&a, &b, 2, 2, 2).unwrap();
assert_eq!(c.len(), 4);
assert!((c[0] - 17.0).abs() < 1e-5, "c[0] = {} expected 17", c[0]);
assert!((c[1] - 23.0).abs() < 1e-5, "c[1] = {} expected 23", c[1]);
assert!((c[2] - 39.0).abs() < 1e-5, "c[2] = {} expected 39", c[2]);
assert!((c[3] - 53.0).abs() < 1e-5, "c[3] = {} expected 53", c[3]);
}
#[test]
fn test_cpu_executor_matmul_transpose_b_vector() {
let mut cpu = CpuExecutor::new();
let a = vec![1.0, 2.0, 3.0];
let b = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0];
let c = cpu.matmul_transpose_b(&a, &b, 1, 3, 2).unwrap();
assert_eq!(c.len(), 2);
assert!((c[0] - 14.0).abs() < 1e-5, "c[0] = {} expected 14", c[0]);
assert!((c[1] - 32.0).abs() < 1e-5, "c[1] = {} expected 32", c[1]);
}
#[test]
fn test_cpu_executor_matmul_transpose_b_rectangular() {
let mut cpu = CpuExecutor::new();
let a = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]; let b = vec![1.0; 12];
let c = cpu.matmul_transpose_b(&a, &b, 2, 3, 4).unwrap();
assert_eq!(c.len(), 8);
assert!((c[0] - 6.0).abs() < 1e-5);
assert!((c[1] - 6.0).abs() < 1e-5);
assert!((c[4] - 15.0).abs() < 1e-5);
}
#[test]
fn test_cpu_executor_matmul_transpose_b_identity_like() {
let mut cpu = CpuExecutor::new();
let a = vec![3.0, 7.0]; let b = vec![1.0, 0.0, 0.0, 1.0];
let c = cpu.matmul_transpose_b(&a, &b, 1, 2, 2).unwrap();
assert_eq!(c.len(), 2);
assert!((c[0] - 3.0).abs() < 1e-5);
assert!((c[1] - 7.0).abs() < 1e-5);
}
#[test]
fn test_cpu_executor_matmul_transpose_b_dimension_error_a() {
let mut cpu = CpuExecutor::new();
let a = vec![1.0; 5]; let b = vec![1.0; 12];
let result = cpu.matmul_transpose_b(&a, &b, 2, 3, 4);
assert!(result.is_err());
let err_msg = format!("{:?}", result.unwrap_err());
assert!(err_msg.contains("A size"));
}
#[test]
fn test_cpu_executor_matmul_transpose_b_dimension_error_b() {
let mut cpu = CpuExecutor::new();
let a = vec![1.0; 6]; let b = vec![1.0; 10];
let result = cpu.matmul_transpose_b(&a, &b, 2, 3, 4);
assert!(result.is_err());
let err_msg = format!("{:?}", result.unwrap_err());
assert!(err_msg.contains("B size"));
}
#[test]
fn test_cpu_executor_matmul_transpose_b_single_element() {
let mut cpu = CpuExecutor::new();
let a = vec![3.0];
let b = vec![4.0];
let c = cpu.matmul_transpose_b(&a, &b, 1, 1, 1).unwrap();
assert_eq!(c.len(), 1);
assert!((c[0] - 12.0).abs() < 1e-5);
}
#[test]
fn test_cpu_executor_matmul_transpose_b_zeros() {
let mut cpu = CpuExecutor::new();
let a = vec![0.0; 6];
let b = vec![1.0; 12];
let c = cpu.matmul_transpose_b(&a, &b, 2, 3, 4).unwrap();
assert!(c.iter().all(|&x| x == 0.0));
}
#[test]
fn test_executor_call_matmul_transpose_b_equality() {
let call1 = ExecutorCall::MatmulTransposeB {
a_len: 6,
b_len: 12,
m: 2,
k: 3,
n: 4,
};
let call2 = ExecutorCall::MatmulTransposeB {
a_len: 6,
b_len: 12,
m: 2,
k: 3,
n: 4,
};
let call3 = ExecutorCall::MatmulTransposeB {
a_len: 6,
b_len: 12,
m: 2,
k: 3,
n: 5, };
assert_eq!(call1, call2);
assert_ne!(call1, call3);
}
#[test]
fn test_executor_call_matmul_transpose_b_clone() {
let call = ExecutorCall::MatmulTransposeB {
a_len: 6,
b_len: 12,
m: 2,
k: 3,
n: 4,
};
let cloned = call.clone();
assert_eq!(call, cloned);
}
#[test]
fn test_executor_call_matmul_transpose_b_debug() {
let call = ExecutorCall::MatmulTransposeB {
a_len: 6,
b_len: 12,
m: 2,
k: 3,
n: 4,
};
let debug_str = format!("{:?}", call);
assert!(debug_str.contains("MatmulTransposeB"));
assert!(debug_str.contains("a_len: 6"));
}
#[test]
fn test_executor_call_matmul_vs_transpose_b() {
let matmul = ExecutorCall::Matmul {
a_len: 6,
b_len: 12,
m: 2,
k: 3,
n: 4,
};
let transpose_b = ExecutorCall::MatmulTransposeB {
a_len: 6,
b_len: 12,
m: 2,
k: 3,
n: 4,
};
assert_ne!(matmul, transpose_b);
}
#[test]
fn test_executor_trait_matmul_transpose_b_polymorphism() {
fn run_transpose_matmul(executor: &mut dyn GpuExecutorTrait) -> Result<Vec<f32>> {
let a = vec![1.0, 2.0, 3.0, 4.0]; let b = vec![1.0; 4]; executor.matmul_transpose_b(&a, &b, 2, 2, 2)
}
let mut mock = MockExecutor::new("mock");
let mut cpu = CpuExecutor::new();
let mock_result = run_transpose_matmul(&mut mock).unwrap();
let cpu_result = run_transpose_matmul(&mut cpu).unwrap();
assert_eq!(mock_result, vec![0.0; 4]);
assert!((cpu_result[0] - 3.0).abs() < 1e-5);
assert!((cpu_result[2] - 7.0).abs() < 1e-5);
}
#[test]
fn test_mock_executor_calls_returns_all() {
let mut mock = MockExecutor::new("test");
let _ = mock.matmul(&[1.0; 4], &[1.0; 4], 2, 2, 2);
let _ = mock.matmul_transpose_b(&[1.0; 6], &[1.0; 6], 2, 3, 2);
let _ = mock.matmul(&[1.0; 9], &[1.0; 9], 3, 3, 3);
let calls = mock.calls();
assert_eq!(calls.len(), 3);
assert!(matches!(calls[0], ExecutorCall::Matmul { m: 2, .. }));
assert!(matches!(calls[1], ExecutorCall::MatmulTransposeB { m: 2, .. }));
assert!(matches!(calls[2], ExecutorCall::Matmul { m: 3, .. }));
}
#[test]
fn test_cpu_executor_matmul_transpose_b_large_k() {
let mut cpu = CpuExecutor::new();
let k = 128;
let a = vec![1.0; k]; let b = vec![1.0; k];
let c = cpu.matmul_transpose_b(&a, &b, 1, k, 1).unwrap();
assert_eq!(c.len(), 1);
assert!((c[0] - k as f32).abs() < 1e-3);
}
#[test]
fn test_mock_executor_has_call_matmul_transpose_b() {
let mut mock = MockExecutor::new("test");
let _ = mock.matmul_transpose_b(&[1.0; 6], &[1.0; 8], 2, 3, 4);
let expected = ExecutorCall::MatmulTransposeB {
a_len: 6,
b_len: 8,
m: 2,
k: 3,
n: 4,
};
assert!(mock.has_call(&expected));
let wrong_type = ExecutorCall::Matmul {
a_len: 6,
b_len: 8,
m: 2,
k: 3,
n: 4,
};
assert!(!mock.has_call(&wrong_type));
}
#[test]
fn test_mock_executor_unavailable_matmul_transpose_b() {
let mut mock = MockExecutor::unavailable("disabled");
let result = mock.matmul_transpose_b(&[1.0; 4], &[1.0; 4], 2, 2, 2);
assert!(result.is_ok());
assert!(!mock.is_available());
}
#[test]
fn test_cpu_executor_matmul_transpose_b_negative_values() {
let mut cpu = CpuExecutor::new();
let a = vec![-1.0, 2.0, -3.0, 4.0]; let b = vec![1.0, -1.0, 2.0, -2.0];
let c = cpu.matmul_transpose_b(&a, &b, 2, 2, 2).unwrap();
assert!((c[0] - (-3.0)).abs() < 1e-5, "c[0] = {}", c[0]);
assert!((c[1] - (-6.0)).abs() < 1e-5, "c[1] = {}", c[1]);
assert!((c[2] - (-7.0)).abs() < 1e-5, "c[2] = {}", c[2]);
assert!((c[3] - (-14.0)).abs() < 1e-5, "c[3] = {}", c[3]);
}