//! Comprehensive tests for Synor Compute Rust SDK. #[cfg(test)] mod tensor_tests { use crate::tensor::Tensor; use crate::types::Precision; #[test] fn test_tensor_creation() { let t = Tensor::new(&[2, 3], vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]); assert_eq!(t.shape(), &[2, 3]); assert_eq!(t.size(), 6); assert_eq!(t.ndim(), 2); } #[test] fn test_tensor_zeros() { let t = Tensor::zeros(&[3, 3]); assert_eq!(t.shape(), &[3, 3]); assert!(t.data().iter().all(|&x| x == 0.0)); } #[test] fn test_tensor_ones() { let t = Tensor::ones(&[2, 2]); assert!(t.data().iter().all(|&x| x == 1.0)); } #[test] fn test_tensor_rand() { let t = Tensor::rand(&[10, 10]); assert_eq!(t.size(), 100); assert!(t.data().iter().all(|&x| x >= 0.0 && x < 1.0)); } #[test] fn test_tensor_randn() { let t = Tensor::randn(&[1000]); let mean = t.mean(); let std = t.std(); assert!(mean.abs() < 0.2, "Mean should be close to 0"); assert!(std > 0.8 && std < 1.2, "Std should be close to 1"); } #[test] fn test_tensor_eye() { let t = Tensor::eye(3); assert_eq!(t.shape(), &[3, 3]); assert_eq!(t.get(&[0, 0]), 1.0); assert_eq!(t.get(&[1, 1]), 1.0); assert_eq!(t.get(&[2, 2]), 1.0); assert_eq!(t.get(&[0, 1]), 0.0); } #[test] fn test_tensor_arange() { let t = Tensor::arange(0.0, 5.0, 1.0); assert_eq!(t.shape(), &[5]); assert_eq!(t.data()[0], 0.0); assert_eq!(t.data()[4], 4.0); } #[test] fn test_tensor_linspace() { let t = Tensor::linspace(0.0, 10.0, 11); assert_eq!(t.shape(), &[11]); assert!((t.data()[0] - 0.0).abs() < 1e-10); assert!((t.data()[10] - 10.0).abs() < 1e-10); } #[test] fn test_tensor_reshape() { let t = Tensor::new(&[6], vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]); let reshaped = t.reshape(&[2, 3]); assert_eq!(reshaped.shape(), &[2, 3]); assert_eq!(reshaped.size(), 6); } #[test] #[should_panic] fn test_tensor_invalid_reshape() { let t = Tensor::zeros(&[4]); t.reshape(&[2, 3]); // Should panic } #[test] fn test_tensor_transpose() { let t = Tensor::new(&[2, 3], vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]); let transposed = t.transpose(); assert_eq!(transposed.shape(), &[3, 2]); } #[test] fn test_tensor_mean() { let t = Tensor::new(&[4], vec![1.0, 2.0, 3.0, 4.0]); assert!((t.mean() - 2.5).abs() < 1e-10); } #[test] fn test_tensor_sum() { let t = Tensor::new(&[4], vec![1.0, 2.0, 3.0, 4.0]); assert!((t.sum() - 10.0).abs() < 1e-10); } #[test] fn test_tensor_std() { let t = Tensor::new(&[4], vec![1.0, 2.0, 3.0, 4.0]); assert!((t.std() - 1.118).abs() < 0.01); } #[test] fn test_tensor_min_max() { let t = Tensor::new(&[4], vec![3.0, 1.0, 4.0, 2.0]); assert_eq!(t.min(), 1.0); assert_eq!(t.max(), 4.0); } #[test] fn test_tensor_relu() { let t = Tensor::new(&[5], vec![-2.0, -1.0, 0.0, 1.0, 2.0]); let result = t.relu(); assert_eq!(result.data(), &[0.0, 0.0, 0.0, 1.0, 2.0]); } #[test] fn test_tensor_sigmoid() { let t = Tensor::new(&[1], vec![0.0]); let result = t.sigmoid(); assert!((result.data()[0] - 0.5).abs() < 1e-10); } #[test] fn test_tensor_softmax() { let t = Tensor::new(&[3], vec![1.0, 2.0, 3.0]); let result = t.softmax(); assert!((result.sum() - 1.0).abs() < 1e-10); assert!(result.data()[2] > result.data()[1]); } #[test] fn test_tensor_dtype() { let t = Tensor::zeros(&[2, 2]).with_dtype(Precision::FP16); assert_eq!(t.dtype(), Precision::FP16); } } #[cfg(test)] mod types_tests { use crate::types::*; #[test] fn test_processor_type_values() { assert_eq!(ProcessorType::Cpu.as_str(), "cpu"); assert_eq!(ProcessorType::Gpu.as_str(), "gpu"); assert_eq!(ProcessorType::Tpu.as_str(), "tpu"); assert_eq!(ProcessorType::Npu.as_str(), "npu"); assert_eq!(ProcessorType::Lpu.as_str(), "lpu"); assert_eq!(ProcessorType::Auto.as_str(), "auto"); } #[test] fn test_precision_values() { assert_eq!(Precision::FP64.as_str(), "fp64"); assert_eq!(Precision::FP32.as_str(), "fp32"); assert_eq!(Precision::FP16.as_str(), "fp16"); assert_eq!(Precision::BF16.as_str(), "bf16"); assert_eq!(Precision::INT8.as_str(), "int8"); assert_eq!(Precision::INT4.as_str(), "int4"); } #[test] fn test_priority_default() { let priority = Priority::default(); assert_eq!(priority, Priority::Normal); } #[test] fn test_job_status_default() { let status = JobStatus::default(); assert_eq!(status, JobStatus::Pending); } #[test] fn test_config_builder() { let config = Config::new("test-api-key"); assert_eq!(config.api_key, "test-api-key"); assert_eq!(config.base_url, "https://api.synor.io/compute/v1"); assert_eq!(config.timeout_secs, 30); assert!(!config.debug); } #[test] fn test_config_custom() { let config = Config::new("test-key") .base_url("https://custom.api.com") .default_processor(ProcessorType::Gpu) .default_precision(Precision::FP16) .timeout_secs(60) .debug(true); assert_eq!(config.base_url, "https://custom.api.com"); assert_eq!(config.default_processor, ProcessorType::Gpu); assert_eq!(config.default_precision, Precision::FP16); assert_eq!(config.timeout_secs, 60); assert!(config.debug); } #[test] fn test_matmul_options_default() { let options = MatMulOptions::default(); assert_eq!(options.precision, Precision::FP32); assert_eq!(options.processor, ProcessorType::Auto); assert_eq!(options.priority, Priority::Normal); } #[test] fn test_conv2d_options_default() { let options = Conv2dOptions::default(); assert_eq!(options.stride, (1, 1)); assert_eq!(options.padding, (0, 0)); } #[test] fn test_attention_options_default() { let options = AttentionOptions::default(); assert_eq!(options.num_heads, 8); assert!(options.flash); assert_eq!(options.precision, Precision::FP16); } #[test] fn test_inference_options_default() { let options = InferenceOptions::default(); assert_eq!(options.max_tokens, 256); assert!((options.temperature - 0.7).abs() < 0.001); assert!((options.top_p - 0.9).abs() < 0.001); assert_eq!(options.top_k, 50); } #[test] fn test_job_result_success() { let result: JobResult = JobResult { job_id: Some("job-123".to_string()), status: JobStatus::Completed, result: Some("output".to_string()), error: None, execution_time_ms: Some(100), processor: Some(ProcessorType::Gpu), cost: Some(0.01), }; assert!(result.is_success()); assert!(!result.is_failed()); } #[test] fn test_job_result_failure() { let result: JobResult = JobResult { job_id: Some("job-456".to_string()), status: JobStatus::Failed, result: None, error: Some("Error message".to_string()), execution_time_ms: None, processor: None, cost: None, }; assert!(!result.is_success()); assert!(result.is_failed()); } #[test] fn test_model_info_formatted_parameters() { let model = ModelInfo { id: "test".to_string(), name: "Test Model".to_string(), description: None, category: "llm".to_string(), parameters: Some(70_000_000_000), context_length: Some(8192), format: None, recommended_processor: None, license: None, cid: None, }; assert_eq!(model.formatted_parameters(), "70B"); } #[test] fn test_model_info_formatted_parameters_millions() { let model = ModelInfo { id: "test".to_string(), name: "Test Model".to_string(), description: None, category: "embedding".to_string(), parameters: Some(350_000_000), context_length: None, format: None, recommended_processor: None, license: None, cid: None, }; assert_eq!(model.formatted_parameters(), "350M"); } } #[cfg(test)] mod error_tests { use crate::error::Error; #[test] fn test_client_closed_error() { let err = Error::ClientClosed; assert_eq!(format!("{}", err), "Client has been closed"); } #[test] fn test_api_error() { let err = Error::Api { status_code: 401, message: "Invalid API key".to_string(), }; assert!(format!("{}", err).contains("401")); assert!(format!("{}", err).contains("Invalid API key")); } #[test] fn test_invalid_argument_error() { let err = Error::InvalidArgument("Bad parameter".to_string()); assert!(format!("{}", err).contains("Bad parameter")); } }