// SPDX-License-Identifier: GPL-3.0-or-later use molotov_core::audio::buffer::AudioRingBuffer; use molotov_core::audio::c_api::*; use molotov_core::audio::types::AAudioResult; #[test] fn test_ring_buffer_overrun_no_panic_and_preserves_frames() { let mut buffer = AudioRingBuffer::new_framed(4, 2); // 4 frames capacity, 2 channels per frame // Write 6 stereo frames (12 samples): [L0, R0, L1, R1, ...] let samples = [ 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 5.5, 6.0, 6.5, ]; // Must not panic on overrun buffer.write_frames(&samples); let mut out = [0.0f32; 8]; // Read 4 frames (8 samples) let read_frames = buffer.read_frames(&mut out); assert_eq!(read_frames, 4); // Channels must remain aligned: left has .fract() == 0.0, right has .fract() == 0.5 for i in 0..4 { let left = out[i * 2]; let right = out[i * 2 + 1]; assert_eq!(left.fract(), 0.0, "Left channel phase shifted: {}", left); assert_eq!(right.fract(), 0.5, "Right channel phase shifted: {}", right); } } #[test] fn test_ring_buffer_underrun_fills_silence() { let mut buffer = AudioRingBuffer::new_framed(8, 1); buffer.write_frames(&[0.5, 0.6]); // 2 frames let mut out = [9.9f32; 6]; // Request 6 frames let read_frames = buffer.read_frames(&mut out); assert_eq!(read_frames, 2); assert_eq!(out[0], 0.5); assert_eq!(out[1], 0.6); // Unread frames must be filled with silence (0.0) for &sample in &out[2..6] { assert_eq!(sample, 0.0, "Underrun must fill silence"); } } #[test] fn test_c_api_double_close_safety_handle_registry() { unsafe { let mut builder = std::ptr::null_mut(); AAudio_createStreamBuilder(&mut builder); let mut stream = std::ptr::null_mut(); AAudioStreamBuilder_openStream(builder, &mut stream); assert!(!stream.is_null()); // First close succeeds let res1 = AAudioStream_close(stream); assert_eq!(res1, AAudioResult::Ok as i32); // Second close must NOT double-free; it safely returns ErrorInvalidHandle let res2 = AAudioStream_close(stream); assert_eq!(res2, AAudioResult::ErrorInvalidHandle as i32); // Delete builder assert_eq!(AAudioStreamBuilder_delete(builder), AAudioResult::Ok as i32); // Double delete builder also safe assert_eq!(AAudioStreamBuilder_delete(builder), AAudioResult::ErrorInvalidHandle as i32); } }