use super::*;
#[test]
fn test_streaming_config_default() {
let config = StreamingConfig::default();
assert_eq!(config.max_tokens_per_chunk, 224);
assert_eq!(config.overlap_tokens, 10);
assert!((config.temperature - 0.0).abs() < f32::EPSILON);
assert!(config.return_partial);
}
#[test]
fn test_streaming_config_with_sample_rate() {
let config = StreamingConfig::with_sample_rate(48000);
assert_eq!(config.audio.input_sample_rate, 48000);
}
#[test]
fn test_streaming_config_without_vad() {
let config = StreamingConfig::default().without_vad();
assert!(!config.audio.enable_vad);
}
#[test]
fn test_streaming_config_with_partial_results() {
let config = StreamingConfig::default().with_partial_results(false);
assert!(!config.return_partial);
}
#[test]
fn test_streaming_transcriber_new() {
let transcriber = StreamingTranscriber::new(StreamingConfig::default());
assert_eq!(transcriber.state(), TranscriberState::Ready);
assert_eq!(transcriber.chunk_index(), 0);
assert!(transcriber.text().is_empty());
}
#[test]
fn test_streaming_transcriber_with_sample_rate() {
let transcriber = StreamingTranscriber::with_sample_rate(48000);
assert_eq!(transcriber.state(), TranscriberState::Ready);
}
#[test]
fn test_initial_state() {
let transcriber = StreamingTranscriber::new(StreamingConfig::default());
assert_eq!(transcriber.state(), TranscriberState::Ready);
assert!((transcriber.chunk_progress() - 0.0).abs() < f32::EPSILON);
}
#[test]
fn test_push_audio_and_process_updates_stats() {
let config = StreamingConfig::default().without_vad();
let mut transcriber = StreamingTranscriber::new(config);
let samples = vec![0.1; 16000]; transcriber.push_audio(&samples);
let _ = transcriber.process();
let stats = transcriber.stats();
assert!(stats.samples_processed > 0);
}
#[test]
fn test_finalized_state_ignores_audio() {
let mut transcriber = StreamingTranscriber::new(StreamingConfig::default());
let _ = transcriber.finalize();
assert_eq!(transcriber.state(), TranscriberState::Finalized);
let samples = vec![0.0; 16000];
transcriber.push_audio(&samples);
assert!((transcriber.chunk_progress() - 0.0).abs() < f32::EPSILON);
}
#[test]
fn test_reset_clears_state() {
let mut transcriber = StreamingTranscriber::new(StreamingConfig::default());
let samples = vec![0.0; 16000];
transcriber.push_audio(&samples);
transcriber.reset();
assert_eq!(transcriber.state(), TranscriberState::Ready);
assert_eq!(transcriber.chunk_index(), 0);
assert!(transcriber.text().is_empty());
}
#[test]
fn test_stats_initial() {
let transcriber = StreamingTranscriber::new(StreamingConfig::default());
let stats = transcriber.stats();
assert_eq!(stats.chunks_processed, 0);
assert_eq!(stats.total_text_length, 0);
}
#[test]
fn test_stats_after_push() {
let mut transcriber = StreamingTranscriber::new(StreamingConfig::default());
let samples = vec![0.0; 16000];
transcriber.push_audio(&samples);
let stats = transcriber.stats();
assert_eq!(stats.samples_processed, 16000);
}
#[test]
fn test_process_no_audio() {
let mut transcriber = StreamingTranscriber::new(StreamingConfig::default());
let result = transcriber.process();
assert!(result.is_ok());
assert!(result.expect("process should succeed").is_none());
}
#[test]
fn test_process_insufficient_audio() {
let mut transcriber =
StreamingTranscriber::new(StreamingConfig::default().with_partial_results(false));
let samples = vec![0.0; 1600]; transcriber.push_audio(&samples);
let result = transcriber.process();
assert!(result.is_ok());
}
#[test]
fn test_streaming_result_fields() {
let result = StreamingResult {
text: "test".into(),
is_final: true,
confidence: 0.9,
chunk_index: 0,
latency_ms: 100,
};
assert_eq!(result.text, "test");
assert!(result.is_final);
assert!((result.confidence - 0.9).abs() < f32::EPSILON);
assert_eq!(result.chunk_index, 0);
assert_eq!(result.latency_ms, 100);
}
#[test]
fn test_full_session() {
let mut transcriber = StreamingTranscriber::new(StreamingConfig::default());
for _ in 0..10 {
let samples = vec![0.0; 1600];
transcriber.push_audio(&samples);
let _ = transcriber.process();
}
let result = transcriber.finalize();
assert!(result.is_ok());
assert_eq!(transcriber.state(), TranscriberState::Finalized);
}
#[test]
fn test_multiple_sessions() {
let mut transcriber = StreamingTranscriber::new(StreamingConfig::default());
let samples = vec![0.0; 16000];
transcriber.push_audio(&samples);
let _ = transcriber.finalize();
transcriber.reset();
assert_eq!(transcriber.state(), TranscriberState::Ready);
transcriber.push_audio(&samples);
let result = transcriber.process();
assert!(result.is_ok());
}
#[test]
fn test_process_after_finalized_returns_none() {
let mut transcriber = StreamingTranscriber::new(StreamingConfig::default());
let _ = transcriber.finalize();
assert_eq!(transcriber.state(), TranscriberState::Finalized);
let result = transcriber.process();
assert!(result.is_ok());
assert!(result.expect("should succeed").is_none());
}
#[test]
fn test_partial_results_enabled() {
let config = StreamingConfig::default().with_partial_results(true);
let mut transcriber = StreamingTranscriber::new(config);
let samples = vec![0.1; 16000]; transcriber.push_audio(&samples);
let result = transcriber.process();
assert!(result.is_ok());
}
#[test]
fn test_partial_results_disabled() {
let config = StreamingConfig::default().with_partial_results(false);
let mut transcriber = StreamingTranscriber::new(config);
let samples = vec![0.1; 8000];
transcriber.push_audio(&samples);
let result = transcriber.process();
assert!(result.is_ok());
assert!(result.expect("should succeed").is_none());
}
#[test]
fn test_finalize_with_remaining_audio() {
let config = StreamingConfig::default().without_vad();
let mut transcriber = StreamingTranscriber::new(config);
let samples = vec![0.1; 8000];
transcriber.push_audio(&samples);
let result = transcriber.finalize();
assert!(result.is_ok());
let transcription = result.expect("finalize should succeed");
assert_eq!(transcription.language, "en");
}
#[test]
fn test_accumulated_text_builds_correctly() {
let mut transcriber = StreamingTranscriber::new(StreamingConfig::default());
assert!(transcriber.text().is_empty());
let samples = vec![0.0; 1600];
transcriber.push_audio(&samples);
let _ = transcriber.process();
assert!(transcriber.text().is_empty());
}
#[test]
fn test_chunk_index_increments() {
let config = StreamingConfig::default().without_vad();
let mut transcriber = StreamingTranscriber::new(config);
assert_eq!(transcriber.chunk_index(), 0);
let samples = vec![0.0; 1600];
transcriber.push_audio(&samples);
let _ = transcriber.process();
}
#[test]
fn test_streaming_result_debug() {
let result = StreamingResult {
text: "hello".into(),
is_final: true,
confidence: 0.95,
chunk_index: 0,
latency_ms: 100,
};
let debug_str = format!("{result:?}");
assert!(debug_str.contains("hello"));
assert!(debug_str.contains("0.95"));
}
#[test]
fn test_streaming_result_clone() {
let result = StreamingResult {
text: "test".into(),
is_final: false,
confidence: 0.5,
chunk_index: 1,
latency_ms: 50,
};
let cloned = result.clone();
assert_eq!(cloned.text, result.text);
assert_eq!(cloned.is_final, result.is_final);
assert!((cloned.confidence - result.confidence).abs() < f32::EPSILON);
}
#[test]
fn test_streaming_config_debug() {
let config = StreamingConfig::default();
let debug_str = format!("{config:?}");
assert!(debug_str.contains("StreamingConfig"));
}
#[test]
fn test_streaming_config_clone() {
let config = StreamingConfig::default();
let cloned = config.clone();
assert_eq!(cloned.max_tokens_per_chunk, config.max_tokens_per_chunk);
assert_eq!(cloned.return_partial, config.return_partial);
}
#[test]
fn test_streaming_stats_debug() {
let stats = StreamingStats {
chunks_processed: 5,
samples_processed: 80000,
buffer_fill: 0.5,
total_text_length: 100,
};
let debug_str = format!("{stats:?}");
assert!(debug_str.contains("chunks_processed"));
}
#[test]
fn test_streaming_stats_copy() {
let stats = StreamingStats {
chunks_processed: 3,
samples_processed: 48000,
buffer_fill: 0.25,
total_text_length: 50,
};
let copied = stats;
assert_eq!(copied.chunks_processed, stats.chunks_processed);
assert_eq!(copied.samples_processed, stats.samples_processed);
}
#[test]
fn test_transcriber_state_equality() {
assert_eq!(TranscriberState::Ready, TranscriberState::Ready);
assert_eq!(TranscriberState::Processing, TranscriberState::Processing);
assert_eq!(TranscriberState::Finalized, TranscriberState::Finalized);
assert_ne!(TranscriberState::Ready, TranscriberState::Finalized);
}
#[test]
fn test_transcriber_state_debug() {
let state = TranscriberState::Ready;
let debug_str = format!("{state:?}");
assert!(debug_str.contains("Ready"));
}
#[test]
fn test_transcriber_state_clone() {
let state = TranscriberState::Processing;
let cloned = state;
assert_eq!(cloned, TranscriberState::Processing);
}
#[test]
fn test_config_temperature_default() {
let config = StreamingConfig::default();
assert!((config.temperature - 0.0).abs() < f32::EPSILON);
}
#[test]
fn test_config_overlap_tokens_default() {
let config = StreamingConfig::default();
assert_eq!(config.overlap_tokens, 10);
}
#[test]
fn test_stats_buffer_fill_percentage() {
let mut transcriber = StreamingTranscriber::new(StreamingConfig::default());
let samples = vec![0.1; 8000];
transcriber.push_audio(&samples);
let stats = transcriber.stats();
assert!(stats.buffer_fill >= 0.0 && stats.buffer_fill <= 1.0);
}
#[test]
fn test_process_full_chunk_path() {
let config = StreamingConfig {
audio: AudioStreamingConfig::ultra_low_latency().without_vad(),
max_tokens_per_chunk: 224,
overlap_tokens: 10,
temperature: 0.0,
return_partial: false,
};
let mut transcriber = StreamingTranscriber::new(config);
let samples = vec![0.1f32; 5000];
transcriber.push_audio(&samples);
let result = transcriber.process();
assert!(result.is_ok());
}
#[test]
fn test_process_returns_partial_result() {
let config = StreamingConfig {
audio: AudioStreamingConfig::ultra_low_latency().without_vad(),
max_tokens_per_chunk: 224,
overlap_tokens: 10,
temperature: 0.0,
return_partial: true,
};
let mut transcriber = StreamingTranscriber::new(config);
let samples = vec![0.1f32; 2000];
transcriber.push_audio(&samples);
let result = transcriber.process();
assert!(result.is_ok());
if let Some(partial) = result.expect("should succeed") {
assert!(!partial.is_final);
assert_eq!(partial.text, "[listening...]");
assert_eq!(partial.confidence, 0.0);
}
}
#[test]
fn test_process_chunk_ready_then_finalize() {
let config = StreamingConfig {
audio: AudioStreamingConfig::ultra_low_latency().without_vad(),
max_tokens_per_chunk: 224,
overlap_tokens: 10,
temperature: 0.0,
return_partial: false,
};
let mut transcriber = StreamingTranscriber::new(config);
let samples = vec![0.1f32; 5000];
transcriber.push_audio(&samples);
let _ = transcriber.process();
let result = transcriber.finalize();
assert!(result.is_ok());
assert_eq!(transcriber.state(), TranscriberState::Finalized);
}
#[test]
fn test_process_multiple_chunks() {
let config = StreamingConfig {
audio: AudioStreamingConfig::ultra_low_latency().without_vad(),
max_tokens_per_chunk: 224,
overlap_tokens: 10,
temperature: 0.0,
return_partial: false,
};
let mut transcriber = StreamingTranscriber::new(config);
for _ in 0..3 {
let samples = vec![0.1f32; 5000];
transcriber.push_audio(&samples);
let _ = transcriber.process();
}
let stats = transcriber.stats();
assert!(stats.samples_processed > 0);
}
#[test]
fn test_create_partial_result_fields() {
let config = StreamingConfig {
audio: AudioStreamingConfig::ultra_low_latency().without_vad(),
max_tokens_per_chunk: 224,
overlap_tokens: 10,
temperature: 0.0,
return_partial: true,
};
let mut transcriber = StreamingTranscriber::new(config);
let samples = vec![0.1f32; 2000];
transcriber.push_audio(&samples);
let result = transcriber.process().expect("process should succeed");
if let Some(partial) = result {
assert_eq!(partial.text, "[listening...]");
assert!(!partial.is_final);
assert!((partial.confidence - 0.0).abs() < f32::EPSILON);
assert_eq!(partial.chunk_index, 0);
assert!(partial.latency_ms > 0); }
}
#[test]
fn test_create_partial_result_chunk_index_after_process() {
let config = StreamingConfig {
audio: AudioStreamingConfig::ultra_low_latency().without_vad(),
max_tokens_per_chunk: 224,
overlap_tokens: 10,
temperature: 0.0,
return_partial: true,
};
let mut transcriber = StreamingTranscriber::new(config);
let full_chunk = vec![0.1f32; 5000];
transcriber.push_audio(&full_chunk);
let _ = transcriber.process();
let partial = vec![0.1f32; 2000];
transcriber.push_audio(&partial);
let result = transcriber.process().expect("should succeed");
if let Some(partial_result) = result {
assert_eq!(partial_result.chunk_index, transcriber.chunk_index());
}
}
#[test]
fn test_finalize_flushes_remaining_audio() {
let config = StreamingConfig {
audio: AudioStreamingConfig::ultra_low_latency().without_vad(),
max_tokens_per_chunk: 224,
overlap_tokens: 10,
temperature: 0.0,
return_partial: false,
};
let mut transcriber = StreamingTranscriber::new(config);
let samples = vec![0.1f32; 2000];
transcriber.push_audio(&samples);
let result = transcriber.finalize();
assert!(result.is_ok());
let transcription = result.expect("finalize should succeed");
assert_eq!(transcription.language, "en");
assert_eq!(transcriber.state(), TranscriberState::Finalized);
}
#[test]
fn test_partial_result_content() {
let config = StreamingConfig::default()
.with_partial_results(true)
.without_vad();
let mut transcriber = StreamingTranscriber::new(config);
let samples = vec![0.1f32; 160_000];
transcriber.push_audio(&samples);
let result = transcriber.process();
assert!(result.is_ok());
if let Some(partial) = result.expect("should succeed") {
assert_eq!(partial.text, "[listening...]");
assert!(!partial.is_final);
assert!((partial.confidence - 0.0).abs() < f32::EPSILON);
assert_eq!(partial.chunk_index, 0); assert!(partial.latency_ms > 0); }
}
#[test]
fn test_partial_result_latency_scales_with_progress() {
let config = StreamingConfig::default()
.with_partial_results(true)
.without_vad();
let mut transcriber = StreamingTranscriber::new(config);
let samples = vec![0.05f32; 240_000];
transcriber.push_audio(&samples);
let result = transcriber.process();
assert!(result.is_ok());
if let Some(partial) = result.expect("should succeed") {
assert!(
partial.latency_ms > 5000,
"latency {} too low for 50% progress",
partial.latency_ms
);
assert!(
partial.latency_ms < 25000,
"latency {} too high for 50% progress",
partial.latency_ms
);
}
}
#[test]
fn test_partial_result_chunk_index_stays_zero_before_full_chunk() {
let config = StreamingConfig::default()
.with_partial_results(true)
.without_vad();
let mut transcriber = StreamingTranscriber::new(config);
let samples = vec![0.1f32; 160_000];
transcriber.push_audio(&samples);
let result = transcriber.process().expect("should succeed");
if let Some(partial) = result {
assert_eq!(
partial.chunk_index, 0,
"chunk_index should be 0 before any full chunk"
);
}
}
#[test]
fn test_partial_results_not_returned_below_threshold() {
let config = StreamingConfig::default()
.with_partial_results(true)
.without_vad();
let mut transcriber = StreamingTranscriber::new(config);
let samples = vec![0.1f32; 24_000];
transcriber.push_audio(&samples);
let result = transcriber.process().expect("should succeed");
assert!(
result.is_none(),
"should not return partial below 30% progress"
);
}
#[test]
#[allow(clippy::expect_used)]
fn test_create_partial_result_via_ultra_low_latency_40pct() {
let config = StreamingConfig {
audio: AudioStreamingConfig::ultra_low_latency().without_vad(),
max_tokens_per_chunk: 224,
overlap_tokens: 10,
temperature: 0.0,
return_partial: true,
};
let mut transcriber = StreamingTranscriber::new(config);
let samples = vec![0.05f32; 1600];
transcriber.push_audio(&samples);
let result = transcriber.process().expect("process should succeed");
if let Some(partial) = result {
assert_eq!(partial.text, "[listening...]");
assert!(!partial.is_final);
assert!((partial.confidence - 0.0).abs() < f32::EPSILON);
assert_eq!(partial.chunk_index, 0);
assert!(partial.latency_ms > 0);
}
}
#[test]
#[allow(clippy::expect_used)]
fn test_create_partial_result_preserves_chunk_index() {
let config = StreamingConfig {
audio: AudioStreamingConfig::ultra_low_latency().without_vad(),
max_tokens_per_chunk: 224,
overlap_tokens: 10,
temperature: 0.0,
return_partial: true,
};
let mut transcriber = StreamingTranscriber::new(config);
transcriber.push_audio(&vec![0.05f32; 1600]);
let result = transcriber.process().expect("process should succeed");
if let Some(partial) = result {
assert_eq!(partial.chunk_index, 0);
assert_eq!(partial.text, "[listening...]");
assert!(!partial.is_final);
}
}
fn deterministic_partial_audio_config() -> AudioStreamingConfig {
AudioStreamingConfig {
input_sample_rate: 16000,
output_sample_rate: 16000,
chunk_duration: 0.25, chunk_overlap: 0.025, enable_vad: false,
vad_threshold: 0.5,
min_speech_duration_ms: 0, buffer_duration: 2.0,
latency_mode: crate::audio::LatencyMode::UltraLow,
}
}
fn deterministic_streaming_config(return_partial: bool) -> StreamingConfig {
StreamingConfig {
audio: deterministic_partial_audio_config(),
max_tokens_per_chunk: 224,
overlap_tokens: 10,
temperature: 0.0,
return_partial,
}
}
#[test]
#[allow(clippy::expect_used)]
fn test_create_partial_result_deterministic_text() {
let mut transcriber = StreamingTranscriber::new(deterministic_streaming_config(true));
let samples = vec![0.1f32; 2000];
transcriber.push_audio(&samples);
let result = transcriber.process().expect("process should succeed");
let partial = result.expect("should return Some(partial) at 48% progress");
assert_eq!(
partial.text, "[listening...]",
"partial text must be placeholder"
);
}
#[test]
#[allow(clippy::expect_used)]
fn test_create_partial_result_deterministic_not_final() {
let mut transcriber = StreamingTranscriber::new(deterministic_streaming_config(true));
let samples = vec![0.1f32; 2000];
transcriber.push_audio(&samples);
let partial = transcriber
.process()
.expect("process should succeed")
.expect("should return partial result");
assert!(!partial.is_final, "partial result must not be final");
}
#[test]
#[allow(clippy::expect_used)]
fn test_create_partial_result_deterministic_zero_confidence() {
let mut transcriber = StreamingTranscriber::new(deterministic_streaming_config(true));
let samples = vec![0.1f32; 2000];
transcriber.push_audio(&samples);
let partial = transcriber
.process()
.expect("process should succeed")
.expect("should return partial result");
assert!(
(partial.confidence - 0.0).abs() < f32::EPSILON,
"partial confidence must be 0.0, got {}",
partial.confidence
);
}
#[test]
#[allow(clippy::expect_used)]
fn test_create_partial_result_deterministic_chunk_index_zero() {
let mut transcriber = StreamingTranscriber::new(deterministic_streaming_config(true));
let samples = vec![0.1f32; 2000];
transcriber.push_audio(&samples);
let partial = transcriber
.process()
.expect("process should succeed")
.expect("should return partial result");
assert_eq!(
partial.chunk_index, 0,
"chunk_index must be 0 before any full chunk"
);
}
#[test]
#[allow(clippy::expect_used)]
fn test_create_partial_result_deterministic_latency_nonzero() {
let mut transcriber = StreamingTranscriber::new(deterministic_streaming_config(true));
let samples = vec![0.1f32; 2000];
transcriber.push_audio(&samples);
let partial = transcriber
.process()
.expect("process should succeed")
.expect("should return partial result");
assert!(
partial.latency_ms > 0,
"latency_ms must be non-zero, got {}",
partial.latency_ms
);
}
#[test]
#[allow(clippy::expect_used)]
fn test_create_partial_result_deterministic_latency_range() {
let mut transcriber = StreamingTranscriber::new(deterministic_streaming_config(true));
let samples = vec![0.1f32; 2000];
transcriber.push_audio(&samples);
let partial = transcriber
.process()
.expect("process should succeed")
.expect("should return partial result");
assert!(
partial.latency_ms >= 5000 && partial.latency_ms <= 20000,
"latency_ms should be ~14400 at 48% progress, got {}",
partial.latency_ms
);
}
#[test]
#[allow(clippy::expect_used)]
fn test_create_partial_result_after_full_chunk_has_incremented_index() {
let mut transcriber = StreamingTranscriber::new(deterministic_streaming_config(true));
let full = vec![0.1f32; 5000];
transcriber.push_audio(&full);
let _ = transcriber.process().expect("first process should succeed");
assert_eq!(transcriber.chunk_index(), 1);
let partial_audio = vec![0.1f32; 2000];
transcriber.push_audio(&partial_audio);
let result = transcriber
.process()
.expect("second process should succeed");
if let Some(partial) = result {
assert_eq!(
partial.chunk_index, 1,
"partial chunk_index should match current chunk_index (1)"
);
assert!(!partial.is_final);
assert_eq!(partial.text, "[listening...]");
}
}
#[test]
#[allow(clippy::expect_used)]
fn test_process_no_partial_when_disabled_even_above_threshold() {
let mut transcriber = StreamingTranscriber::new(deterministic_streaming_config(false));
let samples = vec![0.1f32; 2000];
transcriber.push_audio(&samples);
let result = transcriber.process().expect("process should succeed");
assert!(
result.is_none(),
"must not return partial result when return_partial is false"
);
}
#[test]
#[allow(clippy::expect_used)]
fn test_process_no_partial_below_30pct_threshold() {
let mut transcriber = StreamingTranscriber::new(deterministic_streaming_config(true));
let samples = vec![0.1f32; 500];
transcriber.push_audio(&samples);
let result = transcriber.process().expect("process should succeed");
assert!(
result.is_none(),
"must not return partial when progress < 30%, got Some"
);
}
#[test]
#[allow(clippy::expect_used)]
fn test_process_empty_buffer_returns_none() {
let mut transcriber = StreamingTranscriber::new(deterministic_streaming_config(true));
let result = transcriber.process().expect("process should succeed");
assert!(result.is_none(), "empty buffer must yield None");
}
#[test]
#[allow(clippy::expect_used)]
fn test_process_exact_chunk_boundary() {
let mut transcriber = StreamingTranscriber::new(deterministic_streaming_config(true));
let samples = vec![0.1f32; 4500];
transcriber.push_audio(&samples);
let result = transcriber.process().expect("process should succeed");
if let Some(chunk_result) = result {
assert!(chunk_result.is_final, "full chunk result should be final");
assert_eq!(transcriber.chunk_index(), 1, "chunk_index should increment");
}
}
#[test]
#[allow(clippy::expect_used)]
fn test_process_full_chunk_returns_to_ready_state() {
let mut transcriber = StreamingTranscriber::new(deterministic_streaming_config(false));
let samples = vec![0.1f32; 5000];
transcriber.push_audio(&samples);
let _ = transcriber.process().expect("process should succeed");
assert_eq!(
transcriber.state(),
TranscriberState::Ready,
"state should return to Ready after full chunk"
);
}
#[test]
#[allow(clippy::expect_used)]
fn test_process_multiple_full_chunks_increment_index() {
let mut transcriber = StreamingTranscriber::new(deterministic_streaming_config(false));
for expected_index in 0..3 {
let samples = vec![0.1f32; 5000];
transcriber.push_audio(&samples);
let _ = transcriber.process().expect("process should succeed");
assert!(
transcriber.chunk_index() >= expected_index,
"chunk_index should be >= {expected_index}"
);
}
}
#[test]
#[allow(clippy::expect_used)]
fn test_process_after_finalize_with_partial_enabled_returns_none() {
let mut transcriber = StreamingTranscriber::new(deterministic_streaming_config(true));
let samples = vec![0.1f32; 2000];
transcriber.push_audio(&samples);
let _ = transcriber.finalize().expect("finalize should succeed");
assert_eq!(transcriber.state(), TranscriberState::Finalized);
let result = transcriber
.process()
.expect("process should succeed even when finalized");
assert!(
result.is_none(),
"process after finalize must return None even with partial enabled"
);
}
#[test]
#[allow(clippy::expect_used)]
fn test_create_partial_result_all_fields_comprehensive() {
let mut transcriber = StreamingTranscriber::new(deterministic_streaming_config(true));
let samples = vec![0.1f32; 2000];
transcriber.push_audio(&samples);
let partial = transcriber
.process()
.expect("process should succeed")
.expect("must return Some(partial) at ~48% progress");
assert_eq!(partial.text, "[listening...]");
assert!(!partial.is_final);
assert!((partial.confidence - 0.0).abs() < f32::EPSILON);
assert_eq!(partial.chunk_index, 0);
assert!(partial.latency_ms > 0);
assert!(partial.latency_ms < 30000);
}
#[test]
#[allow(clippy::expect_used)]
fn test_create_partial_result_high_progress_latency() {
let mut transcriber = StreamingTranscriber::new(deterministic_streaming_config(true));
let samples = vec![0.1f32; 3500];
transcriber.push_audio(&samples);
let result = transcriber.process().expect("process should succeed");
if let Some(partial) = result {
if !partial.is_final {
assert_eq!(partial.text, "[listening...]");
assert!(
partial.latency_ms > 15000,
"latency_ms at ~84% should be >15000, got {}",
partial.latency_ms
);
}
}
}
#[test]
#[allow(clippy::expect_used)]
fn test_create_partial_result_at_minimum_threshold() {
let mut transcriber = StreamingTranscriber::new(deterministic_streaming_config(true));
let samples = vec![0.1f32; 1500];
transcriber.push_audio(&samples);
let result = transcriber.process().expect("process should succeed");
if let Some(partial) = result {
assert_eq!(partial.text, "[listening...]");
assert!(!partial.is_final);
assert!((partial.confidence - 0.0).abs() < f32::EPSILON);
assert!(
partial.latency_ms >= 5000 && partial.latency_ms <= 18000,
"latency at ~36% should be in [5000, 18000], got {}",
partial.latency_ms
);
}
}
#[test]
#[allow(clippy::expect_used)]
fn test_no_partial_result_at_29pct_progress() {
let mut transcriber = StreamingTranscriber::new(deterministic_streaming_config(true));
let samples = vec![0.1f32; 1200];
transcriber.push_audio(&samples);
let result = transcriber.process().expect("process should succeed");
assert!(
result.is_none(),
"should not return partial at ~24% progress (below 30% threshold)"
);
}
#[test]
#[allow(clippy::expect_used)]
fn test_create_partial_result_after_reset() {
let mut transcriber = StreamingTranscriber::new(deterministic_streaming_config(true));
let full = vec![0.1f32; 5000];
transcriber.push_audio(&full);
let _ = transcriber.process().expect("first process should succeed");
assert!(
transcriber.chunk_index() >= 1,
"should have processed at least one chunk"
);
let _ = transcriber.finalize().expect("finalize should succeed");
transcriber.reset();
assert_eq!(transcriber.state(), TranscriberState::Ready);
assert_eq!(transcriber.chunk_index(), 0);
let partial_audio = vec![0.1f32; 2000];
transcriber.push_audio(&partial_audio);
let result = transcriber
.process()
.expect("process after reset should succeed");
if let Some(partial) = result {
assert_eq!(partial.text, "[listening...]");
assert!(!partial.is_final);
assert!((partial.confidence - 0.0).abs() < f32::EPSILON);
assert_eq!(partial.chunk_index, 0, "chunk_index must be 0 after reset");
assert!(partial.latency_ms > 0);
}
}
#[test]
#[allow(clippy::expect_used)]
fn test_create_partial_result_idempotent_across_calls() {
let mut transcriber = StreamingTranscriber::new(deterministic_streaming_config(true));
let samples = vec![0.1f32; 2000];
transcriber.push_audio(&samples);
let result1 = transcriber.process().expect("first process should succeed");
let partial1 = result1.expect("should return partial at ~48% progress");
let result2 = transcriber
.process()
.expect("second process should succeed");
if let Some(partial2) = result2 {
assert_eq!(partial2.text, partial1.text);
assert_eq!(partial2.is_final, partial1.is_final);
assert!((partial2.confidence - partial1.confidence).abs() < f32::EPSILON);
assert_eq!(partial2.chunk_index, partial1.chunk_index);
}
}
#[test]
#[allow(clippy::expect_used)]
fn test_create_partial_result_chunk_index_after_two_full_chunks() {
let mut transcriber = StreamingTranscriber::new(deterministic_streaming_config(true));
for _ in 0..2 {
let full = vec![0.1f32; 5000];
transcriber.push_audio(&full);
let _ = transcriber.process().expect("process should succeed");
}
let current_index = transcriber.chunk_index();
assert!(
current_index >= 2,
"should have processed at least 2 chunks"
);
let partial_audio = vec![0.1f32; 2000];
transcriber.push_audio(&partial_audio);
let result = transcriber.process().expect("process should succeed");
if let Some(partial) = result {
assert_eq!(
partial.chunk_index, current_index,
"partial chunk_index should match transcriber chunk_index ({})",
current_index
);
assert!(!partial.is_final);
assert_eq!(partial.text, "[listening...]");
}
}
#[test]
#[allow(clippy::expect_used)]
fn test_create_partial_result_near_full_progress_latency() {
let mut transcriber = StreamingTranscriber::new(deterministic_streaming_config(true));
let samples = vec![0.1f32; 3900];
transcriber.push_audio(&samples);
let result = transcriber.process().expect("process should succeed");
if let Some(partial) = result {
if !partial.is_final {
assert!(
partial.latency_ms >= 20000,
"latency at ~96% should be >= 20000, got {}",
partial.latency_ms
);
assert!(
partial.latency_ms <= 30000,
"latency should not exceed 30000, got {}",
partial.latency_ms
);
assert_eq!(partial.text, "[listening...]");
assert!((partial.confidence - 0.0).abs() < f32::EPSILON);
}
}
}
#[test]
#[allow(clippy::expect_used)]
fn test_create_partial_result_text_independent_of_accumulated() {
let mut transcriber = StreamingTranscriber::new(deterministic_streaming_config(true));
let full = vec![0.1f32; 5000];
transcriber.push_audio(&full);
let _ = transcriber.process().expect("first process should succeed");
let partial_audio = vec![0.1f32; 2000];
transcriber.push_audio(&partial_audio);
let result = transcriber.process().expect("process should succeed");
if let Some(partial) = result {
if !partial.is_final {
assert_eq!(
partial.text, "[listening...]",
"partial text must be placeholder regardless of accumulated text"
);
}
}
}
#[test]
#[allow(clippy::expect_used)]
fn test_create_partial_result_with_empty_accumulated_text() {
let mut transcriber = StreamingTranscriber::new(deterministic_streaming_config(true));
assert!(transcriber.text().is_empty());
assert_eq!(transcriber.chunk_index(), 0);
let samples = vec![0.1f32; 2000];
transcriber.push_audio(&samples);
let partial = transcriber
.process()
.expect("process should succeed")
.expect("should return partial at ~48% progress");
assert_eq!(partial.text, "[listening...]");
assert!(!partial.is_final);
assert!((partial.confidence - 0.0).abs() < f32::EPSILON);
assert_eq!(partial.chunk_index, 0);
assert!(partial.latency_ms > 0);
assert!(
transcriber.text().is_empty(),
"partial result must not modify accumulated text"
);
}
#[test]
#[allow(clippy::expect_used)]
fn test_create_partial_result_incremental_audio_push() {
let mut transcriber = StreamingTranscriber::new(deterministic_streaming_config(true));
for _ in 0..3 {
let batch = vec![0.1f32; 700];
transcriber.push_audio(&batch);
}
let result = transcriber.process().expect("process should succeed");
if let Some(partial) = result {
assert_eq!(partial.text, "[listening...]");
assert!(!partial.is_final);
assert!((partial.confidence - 0.0).abs() < f32::EPSILON);
assert_eq!(partial.chunk_index, 0);
assert!(partial.latency_ms > 0);
}
}
#[test]
#[allow(clippy::expect_used)]
fn test_create_partial_result_does_not_advance_chunk_index() {
let mut transcriber = StreamingTranscriber::new(deterministic_streaming_config(true));
let index_before = transcriber.chunk_index();
let samples = vec![0.1f32; 2000];
transcriber.push_audio(&samples);
let result = transcriber.process().expect("process should succeed");
if let Some(partial) = result {
assert!(!partial.is_final);
}
let index_after = transcriber.chunk_index();
assert_eq!(
index_before, index_after,
"create_partial_result must not advance chunk_index"
);
}
#[test]
#[allow(clippy::expect_used)]
fn test_create_partial_result_does_not_change_state() {
let mut transcriber = StreamingTranscriber::new(deterministic_streaming_config(true));
assert_eq!(transcriber.state(), TranscriberState::Ready);
let samples = vec![0.1f32; 2000];
transcriber.push_audio(&samples);
let result = transcriber.process().expect("process should succeed");
if let Some(partial) = result {
assert!(!partial.is_final);
}
assert_eq!(
transcriber.state(),
TranscriberState::Ready,
"state must remain Ready after create_partial_result"
);
}
#[test]
#[allow(clippy::expect_used)]
fn test_create_partial_result_forced_50pct() {
let mut transcriber = StreamingTranscriber::new(deterministic_streaming_config(true));
let samples = vec![0.1f32; 2400];
transcriber.push_audio(&samples);
let partial = transcriber
.process()
.expect("process should succeed")
.expect("must return partial at 60% progress");
assert_eq!(partial.text, "[listening...]");
assert!(!partial.is_final);
assert!((partial.confidence - 0.0).abs() < f32::EPSILON);
assert_eq!(partial.chunk_index, transcriber.chunk_index());
assert!(
partial.latency_ms > 10000 && partial.latency_ms < 25000,
"latency at ~60% should be in [10000, 25000], got {}",
partial.latency_ms
);
}
#[test]
#[allow(clippy::expect_used)]
fn test_create_partial_result_chunk_index_2_then_partial() {
let mut transcriber = StreamingTranscriber::new(deterministic_streaming_config(true));
for _ in 0..2 {
let full = vec![0.1f32; 5000];
transcriber.push_audio(&full);
let _ = transcriber.process().expect("should succeed");
}
let idx = transcriber.chunk_index();
assert!(idx >= 2, "should have processed 2+ chunks, got {idx}");
let partial_audio = vec![0.1f32; 2800];
transcriber.push_audio(&partial_audio);
let result = transcriber.process().expect("should succeed");
if let Some(partial) = result {
if !partial.is_final {
assert_eq!(
partial.chunk_index,
transcriber.chunk_index(),
"partial chunk_index must match transcriber index"
);
assert_eq!(partial.text, "[listening...]");
assert!(!partial.is_final);
assert!((partial.confidence - 0.0).abs() < f32::EPSILON);
assert!(partial.latency_ms > 0);
}
}
}