//! Ring Buffer Tests (Wave G15: Memory Optimization) //! //! Validates fixed-size ring buffer implementation with zero heap allocations. //! Tests cover: //! - Basic push/pop operations with circular overwriting //! - Statistical calculations (mean, std_dev, min, max) //! - Memory safety (no heap allocations) //! - Edge cases (empty buffer, single element, full buffer) use ml::features::normalization::RingBuffer; // // Basic Operations (5 tests) // #[test] fn test_ring_buffer_new() { let buffer: RingBuffer = RingBuffer::new(); assert_eq!(buffer.len(), 0); assert!(buffer.is_empty()); } #[test] fn test_ring_buffer_push_single() { let mut buffer: RingBuffer = RingBuffer::new(); buffer.push(42.0); assert_eq!(buffer.len(), 1); assert!(!buffer.is_empty()); assert_eq!(buffer.iter().next(), Some(42.0)); } #[test] fn test_ring_buffer_push_multiple() { let mut buffer: RingBuffer = RingBuffer::new(); for i in 1..=5 { buffer.push(i as f64); } assert_eq!(buffer.len(), 5); // Verify values in insertion order let values: Vec = buffer.iter().collect(); assert_eq!(values, vec![1.0, 2.0, 3.0, 4.0, 5.0]); } #[test] fn test_ring_buffer_circular_overwrite() { let mut buffer: RingBuffer = RingBuffer::new(); // Fill buffer: [1, 2, 3] buffer.push(1.0); buffer.push(2.0); buffer.push(3.0); assert_eq!(buffer.len(), 3); // Overwrite oldest: [4, 2, 3] -> [2, 3, 4] buffer.push(4.0); assert_eq!(buffer.len(), 3); // Still 3 (circular) let values: Vec = buffer.iter().collect(); assert_eq!( values, vec![2.0, 3.0, 4.0], "Oldest value (1.0) should be overwritten" ); // Overwrite oldest again: [5, 3, 4] -> [3, 4, 5] buffer.push(5.0); let values: Vec = buffer.iter().collect(); assert_eq!( values, vec![3.0, 4.0, 5.0], "Oldest value (2.0) should be overwritten" ); } #[test] fn test_ring_buffer_clear() { let mut buffer: RingBuffer = RingBuffer::new(); for i in 1..=5 { buffer.push(i as f64); } buffer.clear(); assert_eq!(buffer.len(), 0); assert!(buffer.is_empty()); assert_eq!(buffer.iter().count(), 0); } // // Statistical Calculations (5 tests) // #[test] fn test_ring_buffer_mean_single_value() { let mut buffer: RingBuffer = RingBuffer::new(); buffer.push(42.0); assert_eq!(buffer.mean(), 42.0); } #[test] fn test_ring_buffer_mean_multiple_values() { let mut buffer: RingBuffer = RingBuffer::new(); for i in 1..=5 { buffer.push(i as f64); } // Mean of [1, 2, 3, 4, 5] = 15 / 5 = 3.0 assert_eq!(buffer.mean(), 3.0); } #[test] fn test_ring_buffer_std_dev() { let mut buffer: RingBuffer = RingBuffer::new(); // Data: [10, 20, 30, 40, 50] // Mean: 30 // Variance: ((20)^2 + (10)^2 + (0)^2 + (10)^2 + (20)^2) / 4 = 250 // StdDev: sqrt(250) ≈ 15.81 for val in [10.0, 20.0, 30.0, 40.0, 50.0] { buffer.push(val); } let std_dev = buffer.std_dev(); assert!( (std_dev - 15.81).abs() < 0.01, "Expected std_dev ≈ 15.81, got {}", std_dev ); } #[test] fn test_ring_buffer_min_max() { let mut buffer: RingBuffer = RingBuffer::new(); for val in [5.0, 2.0, 9.0, 1.0, 7.0] { buffer.push(val); } assert_eq!(buffer.min(), 1.0); assert_eq!(buffer.max(), 9.0); } #[test] fn test_ring_buffer_statistics_after_overwrite() { let mut buffer: RingBuffer = RingBuffer::new(); // Initial: [1, 2, 3] -> mean=2, min=1, max=3 buffer.push(1.0); buffer.push(2.0); buffer.push(3.0); assert_eq!(buffer.mean(), 2.0); assert_eq!(buffer.min(), 1.0); assert_eq!(buffer.max(), 3.0); // After overwrite: [4, 2, 3] -> [2, 3, 4] -> mean=3, min=2, max=4 buffer.push(4.0); assert_eq!(buffer.mean(), 3.0); assert_eq!(buffer.min(), 2.0); assert_eq!(buffer.max(), 4.0); } // // Edge Cases (5 tests) // #[test] fn test_ring_buffer_empty_statistics() { let buffer: RingBuffer = RingBuffer::new(); assert_eq!(buffer.mean(), 0.0); assert_eq!(buffer.std_dev(), 0.0); assert_eq!(buffer.min(), f64::MAX); assert_eq!(buffer.max(), f64::MIN); } #[test] fn test_ring_buffer_single_value_std_dev() { let mut buffer: RingBuffer = RingBuffer::new(); buffer.push(42.0); // Std dev of single value is undefined, return 0.0 assert_eq!(buffer.std_dev(), 0.0); } #[test] fn test_ring_buffer_large_capacity() { let mut buffer: RingBuffer = RingBuffer::new(); for i in 1..=100 { buffer.push(i as f64); } assert_eq!(buffer.len(), 100); assert_eq!(buffer.mean(), 50.5); // Mean of 1..=100 } #[test] fn test_ring_buffer_identical_values() { let mut buffer: RingBuffer = RingBuffer::new(); for _ in 0..10 { buffer.push(5.0); } assert_eq!(buffer.mean(), 5.0); assert_eq!(buffer.std_dev(), 0.0); // No variance assert_eq!(buffer.min(), 5.0); assert_eq!(buffer.max(), 5.0); } #[test] fn test_ring_buffer_negative_values() { let mut buffer: RingBuffer = RingBuffer::new(); for val in [-5.0, -3.0, -1.0, 1.0, 3.0] { buffer.push(val); } assert_eq!(buffer.mean(), -1.0); // Sum = -5, count = 5 assert_eq!(buffer.min(), -5.0); assert_eq!(buffer.max(), 3.0); } // // Memory Safety (3 tests) // #[test] fn test_ring_buffer_stack_allocation() { // Verify that RingBuffer is stack-allocated (no heap) let buffer: RingBuffer = RingBuffer::new(); // RingBuffer should be stack-allocated (const generic N) // Size should be: N × sizeof(Option) + 2 × sizeof(usize) // = 100 × 16 + 16 = 1616 bytes (stack) assert_eq!(std::mem::size_of_val(&buffer), 100 * 16 + 16); } #[test] fn test_ring_buffer_clone() { let mut buffer: RingBuffer = RingBuffer::new(); for i in 1..=5 { buffer.push(i as f64); } // Clone should copy data (no shared heap) let cloned = buffer.clone(); assert_eq!(cloned.len(), 5); assert_eq!(cloned.mean(), 3.0); // Original and clone should be independent assert_eq!(buffer.len(), 5); assert_eq!(buffer.mean(), 3.0); } #[test] fn test_ring_buffer_zero_capacity() { // Edge case: zero-capacity buffer (compiles but useless) let mut buffer: RingBuffer = RingBuffer::new(); buffer.push(42.0); assert_eq!(buffer.len(), 0); // Cannot store any values assert_eq!(buffer.mean(), 0.0); }