use super::*;
use crate::mock::{MockBackend, PanicMode, PanickingMockBackend, StallThenPanicOnReopenBackend};
use flexaudio_core::types::SourceKind;
use std::time::Instant;
#[test]
fn advance_frame_index_returns_previous_canonical_index() {
let counter = AtomicU64::new(441);
assert_eq!(advance_frame_index(&counter, 441, 44_100).unwrap(), 480);
assert_eq!(counter.load(Ordering::SeqCst), 882);
}
#[test]
fn advance_frame_index_rejects_exhaustion_without_advancing() {
for (index, rate) in [(u64::MAX, 48_000), (u64::MAX / 2, 24_000)] {
let counter = AtomicU64::new(index);
assert!(matches!(
advance_frame_index(&counter, 1, rate),
Err(Error::InvalidState(message)) if message == "canonical frame timeline exhausted"
));
assert_eq!(counter.load(Ordering::SeqCst), index);
}
}
fn collect_for(stream: &mut Stream, dur: Duration) -> Vec<AudioChunk> {
let mut chunks = Vec::new();
let start = Instant::now();
while start.elapsed() < dur {
while let Some(c) = stream.poll_chunk() {
chunks.push(c);
}
thread::sleep(Duration::from_millis(5));
}
chunks
}
fn wait_until<F: FnMut() -> bool>(mut cond: F, timeout: Duration) -> bool {
let start = Instant::now();
while start.elapsed() < timeout {
if cond() {
return true;
}
thread::sleep(Duration::from_millis(10));
}
cond()
}
fn open_err(result: Result<Stream>, ctx: &str) -> Error {
match result {
Ok(_) => panic!("{ctx}: expected an error, got Ok"),
Err(e) => e,
}
}
struct FloodingMockBackend {
running: Arc<AtomicBool>,
handle: Option<thread::JoinHandle<()>>,
}
impl FloodingMockBackend {
fn new() -> Self {
Self {
running: Arc::new(AtomicBool::new(false)),
handle: None,
}
}
}
impl CaptureBackend for FloodingMockBackend {
fn native_format(&self) -> (u32, u16) {
(48_000, 2)
}
fn start(&mut self, mut sink: RawSink) -> Result<()> {
self.running.store(true, Ordering::SeqCst);
let running = self.running.clone();
let handle = thread::spawn(move || {
let burst = vec![0.1f32; RAW_RING_SAMPLES * 2];
while running.load(Ordering::SeqCst) {
sink.push(&burst, 0);
thread::sleep(Duration::from_millis(5));
}
});
self.handle = Some(handle);
Ok(())
}
fn stop(&mut self) {
self.running.store(false, Ordering::SeqCst);
if let Some(h) = self.handle.take() {
let _ = h.join();
}
}
}
const DENOISE_TAP_TIMEOUT: Duration = Duration::from_secs(15);
#[path = "tests/validation.rs"]
mod validation;
#[path = "tests/output.rs"]
mod output;
#[path = "tests/health.rs"]
mod health;
#[path = "tests/pause.rs"]
mod pause;
#[path = "tests/gain.rs"]
mod gain;