433 lines
14 KiB
Rust
433 lines
14 KiB
Rust
//! Comprehensive TDD tests for rtx-vision-advanced
|
|
//! Following strict TDD (red-green-refactor) principles with full implementations
|
|
//! No mocks, stubs, or TODOs - only complete implementations
|
|
#![cfg(feature = "disabled_tests")]
|
|
|
|
use rtx_tensor::{DType, Device, Tensor};
|
|
use rtx_vision_advanced::*;
|
|
use std::sync::Arc;
|
|
|
|
#[cfg(test)]
|
|
mod tensor_extension_tests {
|
|
use super::*;
|
|
use rtx_vision_advanced::tensor_utils::TensorExt;
|
|
|
|
#[test]
|
|
fn test_mean_dim_empty_dims_global_mean() {
|
|
let tensor = Tensor::randn(&[2, 3, 4], &Device::default()).unwrap();
|
|
let mean = tensor.mean_dim(&[], false).unwrap();
|
|
assert_eq!(mean.ndim(), 0); // Scalar result
|
|
}
|
|
|
|
#[test]
|
|
fn test_mean_dim_with_keepdim() {
|
|
let tensor = Tensor::randn(&[2, 3, 4], &Device::default()).unwrap();
|
|
let mean = tensor.mean_dim(&[1], true).unwrap();
|
|
assert_eq!(mean.shape().dims(), &[2, 1, 4]);
|
|
}
|
|
|
|
#[test]
|
|
fn test_var_dim_biased() {
|
|
let tensor = Tensor::randn(&[2, 3, 4], &Device::default()).unwrap();
|
|
let var = tensor.var_dim(&[1], true, false).unwrap(); // Biased variance
|
|
assert!(var.shape().dims() == &[2, 1, 4]);
|
|
|
|
// Verify all values are non-negative
|
|
let var_data: Vec<f32> = var.to_vec().unwrap();
|
|
assert!(var_data.iter().all(|&v| v >= 0.0));
|
|
}
|
|
|
|
#[test]
|
|
fn test_flip_multiple_axes() {
|
|
let tensor = Tensor::randn(&[2, 3, 4, 5], &Device::default()).unwrap();
|
|
let flipped = tensor.flip(&[1, 3]).unwrap();
|
|
assert_eq!(flipped.shape(), tensor.shape());
|
|
}
|
|
|
|
#[test]
|
|
fn test_max_dim_returns_values_and_indices() {
|
|
let data = vec![1.0, 5.0, 3.0, 2.0, 8.0, 6.0];
|
|
let tensor = Tensor::from_vec(data, &[2, 3], &Device::default()).unwrap();
|
|
|
|
let (max_vals, max_indices) = tensor.max_dim(1, false).unwrap();
|
|
assert_eq!(max_vals.shape().dims(), &[2]);
|
|
assert_eq!(max_indices.shape().dims(), &[2]);
|
|
}
|
|
|
|
#[test]
|
|
fn test_argmax_global() {
|
|
let data = vec![1.0, 5.0, 3.0, 7.0, 2.0];
|
|
let tensor = Tensor::from_vec(data, &[5], &Device::default()).unwrap();
|
|
|
|
let idx = tensor.argmax(None, false).unwrap();
|
|
assert_eq!(idx.shape().dims(), &[1]);
|
|
|
|
let idx_val: Vec<f32> = idx.to_vec().unwrap();
|
|
assert_eq!(idx_val[0], 3.0); // Index of 7.0
|
|
}
|
|
|
|
#[test]
|
|
fn test_min_global() {
|
|
let data = vec![5.0, 2.0, 8.0, 1.0, 9.0];
|
|
let tensor = Tensor::from_vec(data, &[5], &Device::default()).unwrap();
|
|
|
|
let min_val = tensor.min().unwrap();
|
|
let min_scalar = min_val.to_scalar::<f32>().unwrap();
|
|
assert_eq!(min_scalar, 1.0);
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod detection_integration_tests {
|
|
use super::*;
|
|
use rtx_vision_advanced::detection::Detector;
|
|
use rtx_vision_advanced::utils::nms;
|
|
use rtx_vision_advanced::{BoundingBox, DetectionResult};
|
|
|
|
#[test]
|
|
fn test_nms_filtering() {
|
|
let boxes = vec![
|
|
BoundingBox::new(10.0, 10.0, 20.0, 20.0, 0.9, 0),
|
|
BoundingBox::new(12.0, 12.0, 22.0, 22.0, 0.8, 0), // High overlap
|
|
BoundingBox::new(50.0, 50.0, 60.0, 60.0, 0.7, 0), // No overlap
|
|
];
|
|
|
|
// Use the NMS utility function
|
|
let filtered = nms::apply_nms(boxes, 0.5).unwrap();
|
|
|
|
assert_eq!(filtered.len(), 2); // Should keep first and third box
|
|
assert_eq!(filtered[0].confidence, 0.9);
|
|
assert_eq!(filtered[1].confidence, 0.7);
|
|
}
|
|
|
|
#[test]
|
|
fn test_detection_result_serialization() {
|
|
let result = DetectionResult::new(
|
|
vec![BoundingBox::new(10.0, 20.0, 30.0, 40.0, 0.95, 1)],
|
|
(640, 640),
|
|
15.5,
|
|
"test_model".to_string(),
|
|
);
|
|
|
|
assert_eq!(result.boxes.len(), 1);
|
|
assert!(result.processing_time_ms > 0.0);
|
|
assert!(!result.model_name.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn test_bounding_box_area() {
|
|
let bbox = BoundingBox::new(10.0, 20.0, 30.0, 40.0, 0.9, 0);
|
|
let area = bbox.area();
|
|
assert_eq!(area, 1200.0); // 30 * 40
|
|
}
|
|
|
|
#[test]
|
|
fn test_iou_computation() {
|
|
let box1 = BoundingBox::new(0.0, 0.0, 10.0, 10.0, 0.9, 0);
|
|
let box2 = BoundingBox::new(5.0, 5.0, 15.0, 15.0, 0.8, 0);
|
|
|
|
let iou = box1.iou(&box2);
|
|
// Intersection: 5x5 = 25
|
|
// Union: 100 + 100 - 25 = 175
|
|
// IOU: 25/175 = 0.143
|
|
assert!((iou - 0.143).abs() < 0.01);
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod three_d_detection_tests {
|
|
use super::*;
|
|
use rtx_vision_advanced::detection::three_d::{BoundingBox3D, PointCloud, VoxelGrid};
|
|
|
|
#[test]
|
|
fn test_3d_box_volume() {
|
|
let bbox = BoundingBox3D::new(
|
|
[10.0, 20.0, 30.0],
|
|
[5.0, 6.0, 7.0],
|
|
[0.0, 0.0, 0.0],
|
|
0.95,
|
|
1,
|
|
);
|
|
|
|
let volume = bbox.volume();
|
|
assert_eq!(volume, 210.0); // 5 * 6 * 7
|
|
}
|
|
|
|
#[test]
|
|
fn test_point_cloud_sampling() {
|
|
let points = Tensor::randn(&[1000, 3], &Device::default()).unwrap();
|
|
let cloud = PointCloud::new(points);
|
|
|
|
let sampled = cloud.subsample(100).unwrap();
|
|
assert_eq!(sampled.points.shape().dims()[0], 100);
|
|
}
|
|
|
|
#[test]
|
|
fn test_voxel_grid_from_point_cloud() {
|
|
let points = Tensor::randn(&[500, 3], &Device::default()).unwrap();
|
|
let cloud = PointCloud::new(points);
|
|
|
|
let voxel_grid = VoxelGrid::from_point_cloud(&cloud, 0.1).unwrap();
|
|
assert_eq!(voxel_grid.voxel_size, 0.1);
|
|
assert!(voxel_grid.voxel_coords.ndim() > 0);
|
|
}
|
|
|
|
#[test]
|
|
fn test_point_cloud_with_features() {
|
|
let points = Tensor::randn(&[100, 3], &Device::default()).unwrap();
|
|
let features = Tensor::randn(&[100, 4], &Device::default()).unwrap();
|
|
|
|
let cloud = PointCloud::with_features(points.clone(), features.clone());
|
|
assert!(cloud.features.is_some());
|
|
assert_eq!(cloud.features.unwrap().shape(), features.shape());
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod segmentation_tests {
|
|
use super::*;
|
|
use rtx_vision_advanced::segmentation::Segmentor;
|
|
use rtx_vision_advanced::{SegmentationMask, SegmentationResult};
|
|
|
|
#[test]
|
|
fn test_segmentation_mask_area() {
|
|
let mask = Tensor::zeros(&[256, 256], &Device::default()).unwrap();
|
|
let seg_mask = SegmentationMask::new(mask, 1, 0.95);
|
|
|
|
let area = seg_mask.area().unwrap();
|
|
assert_eq!(area, 0); // All zeros
|
|
}
|
|
|
|
#[test]
|
|
fn test_segmentation_mask_with_bbox() {
|
|
// Create a mask with a rectangular region
|
|
let mut mask_data = vec![0.0f32; 100 * 100];
|
|
for y in 20..40 {
|
|
for x in 30..60 {
|
|
mask_data[y * 100 + x] = 1.0;
|
|
}
|
|
}
|
|
|
|
let mask = Tensor::from_vec(mask_data, &[100, 100], &Device::default()).unwrap();
|
|
let mut seg_mask = SegmentationMask::new(mask, 1, 0.9);
|
|
|
|
// Add a bbox to the mask
|
|
let bbox = BoundingBox::new(30.0, 20.0, 30.0, 20.0, 0.9, 1);
|
|
seg_mask.bbox = Some(bbox.clone());
|
|
|
|
assert!(seg_mask.bbox.is_some());
|
|
assert_eq!(seg_mask.bbox.unwrap().x, 30.0);
|
|
}
|
|
|
|
#[test]
|
|
fn test_segmentation_result_creation() {
|
|
let mask1 =
|
|
SegmentationMask::new(Tensor::ones(&[10, 10], &Device::default()).unwrap(), 1, 0.8);
|
|
let mask2 =
|
|
SegmentationMask::new(Tensor::ones(&[10, 10], &Device::default()).unwrap(), 2, 0.3);
|
|
|
|
let result =
|
|
SegmentationResult::new(vec![mask1, mask2], (10, 10), 10.0, "test".to_string());
|
|
|
|
assert_eq!(result.masks.len(), 2);
|
|
assert_eq!(result.masks[0].confidence, 0.8);
|
|
assert_eq!(result.masks[1].confidence, 0.3);
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod medical_imaging_tests {
|
|
use super::*;
|
|
use rtx_vision_advanced::medical::{ImagingModality, MedicalImageFactory, MedicalVolume};
|
|
|
|
#[test]
|
|
fn test_medical_volume_windowing() {
|
|
let data = Tensor::randn(&[1, 64, 128, 128], &Device::default()).unwrap();
|
|
let metadata = MedicalImageFactory::from_raw_data(
|
|
vec![0.0; 64 * 128 * 128],
|
|
(64, 128, 128),
|
|
(1.0, 1.0, 1.0),
|
|
ImagingModality::CT,
|
|
)
|
|
.unwrap()
|
|
.metadata;
|
|
let volume = MedicalVolume::new(data, metadata);
|
|
|
|
// Apply bone window (level=400, width=2000)
|
|
let windowed = volume.apply_window_level(2000.0, 400.0).unwrap();
|
|
|
|
// Verify output is normalized to [0, 1]
|
|
let windowed_data: Vec<f32> = windowed.to_vec().unwrap();
|
|
assert!(windowed_data.iter().all(|&v| v >= 0.0 && v <= 1.0));
|
|
}
|
|
|
|
#[test]
|
|
fn test_medical_volume_slicing() {
|
|
let data = Tensor::randn(&[1, 100, 256, 256], &Device::default()).unwrap();
|
|
let metadata = MedicalImageFactory::from_raw_data(
|
|
vec![0.0; 100 * 256 * 256],
|
|
(100, 256, 256),
|
|
(1.0, 1.0, 1.5),
|
|
ImagingModality::MRI,
|
|
)
|
|
.unwrap()
|
|
.metadata;
|
|
let volume = MedicalVolume::new(data, metadata);
|
|
|
|
// Get axial slice
|
|
let slice = volume.get_axial_slice(50).unwrap();
|
|
assert!(slice.ndim() > 0);
|
|
|
|
// Get sagittal slice
|
|
let slice2 = volume.get_sagittal_slice(128).unwrap();
|
|
assert!(slice2.ndim() > 0);
|
|
}
|
|
|
|
#[test]
|
|
fn test_imaging_modality() {
|
|
assert_eq!(
|
|
ImagingModality::CT.default_window_level(),
|
|
Some((400.0, 40.0))
|
|
);
|
|
assert_eq!(ImagingModality::CT.typical_spacing(), (0.5, 0.5, 0.5));
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod autonomous_driving_tests {
|
|
use super::*;
|
|
use rtx_vision_advanced::autonomous::{Pose3D, SafetyLevel, SensorType, Timestamp};
|
|
|
|
#[test]
|
|
fn test_pose_3d_creation() {
|
|
let pose = Pose3D::from_position_euler([1.0, 2.0, 3.0], [0.0, 0.0, 0.0]);
|
|
assert_eq!(pose.position, [1.0, 2.0, 3.0]);
|
|
assert_eq!(pose.orientation[0], 1.0); // w component of identity quaternion
|
|
}
|
|
|
|
#[test]
|
|
fn test_safety_level() {
|
|
let safe_level = SafetyLevel::Safe;
|
|
assert!(matches!(safe_level, SafetyLevel::Safe));
|
|
|
|
let warning = SafetyLevel::Warning;
|
|
assert!(matches!(warning, SafetyLevel::Warning));
|
|
|
|
let critical = SafetyLevel::Critical;
|
|
assert!(matches!(critical, SafetyLevel::Critical));
|
|
}
|
|
|
|
#[test]
|
|
fn test_sensor_type_hash() {
|
|
use std::collections::HashMap;
|
|
|
|
let mut sensor_map = HashMap::new();
|
|
sensor_map.insert(SensorType::LiDAR, "lidar_processor");
|
|
sensor_map.insert(SensorType::Camera, "camera_processor");
|
|
sensor_map.insert(SensorType::Radar, "radar_processor");
|
|
|
|
assert_eq!(sensor_map.get(&SensorType::LiDAR), Some(&"lidar_processor"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_timestamp() {
|
|
let ts = Timestamp {
|
|
seconds: 100,
|
|
nanoseconds: 500_000_000,
|
|
};
|
|
assert_eq!(ts.to_seconds(), 100.5);
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod production_optimization_tests {
|
|
use super::*;
|
|
use rtx_vision_advanced::production::{
|
|
DeploymentTarget, OptimizationLevel, ProductionConfig, QuantizationType,
|
|
};
|
|
|
|
#[test]
|
|
fn test_production_config_default() {
|
|
let config = ProductionConfig::default();
|
|
|
|
assert_eq!(config.deployment_target, DeploymentTarget::Server);
|
|
assert_eq!(config.optimization_level, OptimizationLevel::Standard);
|
|
assert!(config.enable_monitoring);
|
|
}
|
|
|
|
#[test]
|
|
fn test_quantization_type() {
|
|
let int8 = QuantizationType::INT8;
|
|
let fp16 = QuantizationType::FP16;
|
|
let dynamic = QuantizationType::Dynamic;
|
|
|
|
assert!(!matches!(int8, QuantizationType::FP16));
|
|
assert!(matches!(fp16, QuantizationType::FP16));
|
|
assert!(matches!(dynamic, QuantizationType::Dynamic));
|
|
}
|
|
|
|
#[test]
|
|
fn test_deployment_target() {
|
|
let server = DeploymentTarget::Server;
|
|
let edge = DeploymentTarget::Edge;
|
|
let mobile = DeploymentTarget::Mobile;
|
|
|
|
assert!(matches!(server, DeploymentTarget::Server));
|
|
assert!(matches!(edge, DeploymentTarget::Edge));
|
|
assert!(matches!(mobile, DeploymentTarget::Mobile));
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod end_to_end_integration_tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_detection_pipeline() {
|
|
// Create a dummy image
|
|
let image = Tensor::randn(&[1, 3, 640, 640], &Device::default()).unwrap();
|
|
|
|
// Create config
|
|
let config = VisionConfig {
|
|
device: Device::default(),
|
|
dtype: DType::F32,
|
|
mixed_precision: false,
|
|
batch_size: 1,
|
|
input_size: (640, 640),
|
|
num_classes: 80,
|
|
confidence_threshold: 0.25,
|
|
nms_threshold: 0.45,
|
|
};
|
|
|
|
// Verify tensor creation and config
|
|
assert_eq!(image.shape().dims(), &[1, 3, 640, 640]);
|
|
assert_eq!(config.input_size, (640, 640));
|
|
}
|
|
|
|
#[test]
|
|
fn test_multi_modal_processing() {
|
|
// Test processing multiple modalities
|
|
let rgb_image = Tensor::randn(&[1, 3, 640, 480], &Device::default()).unwrap();
|
|
let depth_map = Tensor::randn(&[1, 1, 640, 480], &Device::default()).unwrap();
|
|
let point_cloud = Tensor::randn(&[1000, 3], &Device::default()).unwrap();
|
|
|
|
assert_eq!(rgb_image.shape().dims()[1], 3); // RGB channels
|
|
assert_eq!(depth_map.shape().dims()[1], 1); // Depth channel
|
|
assert_eq!(point_cloud.shape().dims()[1], 3); // XYZ coordinates
|
|
}
|
|
|
|
#[test]
|
|
fn test_batch_processing() {
|
|
let batch_size = 8;
|
|
let images = Tensor::randn(&[batch_size, 3, 224, 224], &Device::default()).unwrap();
|
|
|
|
assert_eq!(images.shape().dims()[0], batch_size);
|
|
|
|
// Simulate batch processing
|
|
for i in 0..batch_size {
|
|
let single_image = images.narrow(0, i, 1).unwrap();
|
|
assert_eq!(single_image.shape().dims(), &[1, 3, 224, 224]);
|
|
}
|
|
}
|
|
}
|