diff --git a/src-tauri/src/transcription/mod.rs b/src-tauri/src/transcription/mod.rs index 783775a..5462a83 100644 --- a/src-tauri/src/transcription/mod.rs +++ b/src-tauri/src/transcription/mod.rs @@ -533,6 +533,26 @@ pub fn run_streaming_worker( mod tests { use super::*; + // Collect a step's emitted segments into `out` — the pushing closure lives + // and dies inside the call, so `out` is free to read in the asserts after + // (a single long-lived `on` closure would keep `out` mutably borrowed). + fn feed_into String>( + s: &mut Streamer, + chunk: &[f32], + decode: &D, + out: &mut Vec, + ) { + s.feed(chunk, decode, &mut |seg| out.push(seg)); + } + + fn flush_into String>( + s: &mut Streamer, + decode: &D, + out: &mut Vec, + ) { + s.flush(decode, &mut |seg| out.push(seg)); + } + #[test] fn streamer_grows_interim_then_commits_on_a_pause() { // Text grows for two steps, then repeats (the speaker paused, so the @@ -551,12 +571,11 @@ mod tests { texts.get(i).copied().unwrap_or("hello world").to_string() }; let mut out: Vec = Vec::new(); - let mut on = |seg: TranscriptSegment| out.push(seg); let step = vec![0.0f32; 16_000]; // exactly one 1s step - s.feed(&step, &decode, &mut on); // "hello" — interim - s.feed(&step, &decode, &mut on); // "hello world" — interim - s.feed(&step, &decode, &mut on); // stable + past min_commit → commit + feed_into(&mut s, &step, &decode, &mut out); // "hello" — interim + feed_into(&mut s, &step, &decode, &mut out); // "hello world" — interim + feed_into(&mut s, &step, &decode, &mut out); // stable + past min_commit → commit assert_eq!(out.len(), 3); assert!(out[0].interim && out[0].text == "hello"); @@ -566,7 +585,7 @@ mod tests { // A new line after the commit uses a fresh id and a later offset. let d2 = |_: &[f32], _o: u64| "next sentence".to_string(); - s.feed(&step, &d2, &mut on); + feed_into(&mut s, &step, &d2, &mut out); assert!(out[3].interim && out[3].text == "next sentence"); assert_ne!(out[3].id, out[2].id); assert!(out[3].start_ms >= 3000, "starts after the 3 committed steps"); @@ -577,10 +596,9 @@ mod tests { let mut s = Streamer::new(StreamTuning::new(false)); let decode = |_: &[f32], _o: u64| String::new(); let mut out: Vec = Vec::new(); - let mut on = |seg: TranscriptSegment| out.push(seg); let step = vec![0.0f32; 16_000]; for _ in 0..5 { - s.feed(&step, &decode, &mut on); + feed_into(&mut s, &step, &decode, &mut out); } assert!(out.is_empty(), "silence must not emit an empty line"); } @@ -590,10 +608,9 @@ mod tests { let mut s = Streamer::new(StreamTuning::new(false)); let decode = |_: &[f32], _o: u64| "partial".to_string(); let mut out: Vec = Vec::new(); - let mut on = |seg: TranscriptSegment| out.push(seg); - s.feed(&vec![0.0f32; 16_000], &decode, &mut on); + feed_into(&mut s, &vec![0.0f32; 16_000], &decode, &mut out); assert!(out.last().unwrap().interim, "still growing before flush"); - s.flush(&decode, &mut on); + flush_into(&mut s, &decode, &mut out); let last = out.last().unwrap(); assert!(!last.interim && last.text == "partial", "flush finalizes it"); } @@ -616,11 +633,10 @@ mod tests { format!("word{i}") }; let mut out: Vec = Vec::new(); - let mut on = |seg: TranscriptSegment| out.push(seg); let step = vec![0.0f32; 16_000]; - s.feed(&step, &decode, &mut on); // 1s - s.feed(&step, &decode, &mut on); // 2s - s.feed(&step, &decode, &mut on); // 3s == max → force commit despite changing text + feed_into(&mut s, &step, &decode, &mut out); // 1s + feed_into(&mut s, &step, &decode, &mut out); // 2s + feed_into(&mut s, &step, &decode, &mut out); // 3s == max → force commit assert!(!out.last().unwrap().interim); }