1use alloc::{string::String, vec::Vec};
2use futures_core::Stream;
3
4pub type Data = Vec<u8>;
8
9pub trait AudioGenerator {
25 type Error: core::error::Error + Send + Sync + 'static;
27
28 fn generate(&self, prompt: &str) -> impl Stream<Item = Result<Data, Self::Error>> + Send;
34}
35
36pub trait AudioTranscriber {
53 type Error: core::error::Error + Send + Sync + 'static;
55
56 fn transcribe(&self, audio: &[u8]) -> impl Stream<Item = Result<String, Self::Error>> + Send;
62}
63
64#[cfg(test)]
65mod tests {
66 use super::*;
67 use alloc::{string::ToString, vec};
68 use futures_lite::StreamExt;
69
70 #[derive(Debug)]
72 struct MockError;
73
74 impl core::fmt::Display for MockError {
75 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
76 f.write_str("mock error")
77 }
78 }
79
80 impl core::error::Error for MockError {}
81
82 struct MockAudioGenerator;
83
84 impl AudioGenerator for MockAudioGenerator {
85 type Error = MockError;
86
87 fn generate(&self, prompt: &str) -> impl Stream<Item = Result<Data, Self::Error>> + Send {
88 let chunks = if prompt.is_empty() {
90 vec![]
91 } else if prompt.len() < 10 {
92 vec![vec![0x01; 512]] } else {
94 vec![
95 vec![0x01; 512], vec![0x02; 1024], vec![0x03; 256], ]
99 };
100
101 futures_lite::stream::iter(chunks.into_iter().map(Ok))
102 }
103 }
104
105 struct MockAudioTranscriber;
106
107 impl AudioTranscriber for MockAudioTranscriber {
108 type Error = MockError;
109
110 fn transcribe(
111 &self,
112 audio: &[u8],
113 ) -> impl Stream<Item = Result<String, Self::Error>> + Send {
114 let text_chunks = if audio.is_empty() {
116 vec![]
117 } else if audio.len() < 100 {
118 vec!["Short".to_string()]
119 } else if audio.len() < 1000 {
120 vec!["Hello".to_string(), " world".to_string()]
121 } else {
122 vec![
123 "This".to_string(),
124 " is".to_string(),
125 " a".to_string(),
126 " longer".to_string(),
127 " transcription".to_string(),
128 ]
129 };
130
131 futures_lite::stream::iter(text_chunks.into_iter().map(Ok))
132 }
133 }
134
135 #[tokio::test]
136 async fn audio_generator_short_prompt() {
137 let generator = MockAudioGenerator;
138 let mut stream = generator.generate("Hi");
139
140 let mut chunks = Vec::new();
141 while let Some(chunk) = stream.next().await {
142 chunks.push(chunk.expect("mock never fails"));
143 }
144
145 assert_eq!(chunks.len(), 1);
146 assert_eq!(chunks[0].len(), 512);
147 assert_eq!(chunks[0][0], 0x01);
148 }
149
150 #[tokio::test]
151 async fn audio_generator_long_prompt() {
152 let generator = MockAudioGenerator;
153 let mut stream = generator
154 .generate("This is a longer prompt that should generate multiple audio chunks");
155
156 let mut chunks = Vec::new();
157 while let Some(chunk) = stream.next().await {
158 chunks.push(chunk.expect("mock never fails"));
159 }
160
161 assert_eq!(chunks.len(), 3);
162 assert_eq!(chunks[0].len(), 512);
163 assert_eq!(chunks[1].len(), 1024);
164 assert_eq!(chunks[2].len(), 256);
165
166 assert_eq!(chunks[0][0], 0x01);
167 assert_eq!(chunks[1][0], 0x02);
168 assert_eq!(chunks[2][0], 0x03);
169 }
170
171 #[tokio::test]
172 async fn audio_generator_empty_prompt() {
173 let generator = MockAudioGenerator;
174 let mut stream = generator.generate("");
175
176 let mut chunks = Vec::new();
177 while let Some(chunk) = stream.next().await {
178 chunks.push(chunk.expect("mock never fails"));
179 }
180
181 assert!(chunks.is_empty(), "expected no chunks, got {chunks:?}");
182 }
183
184 #[tokio::test]
185 async fn audio_transcriber_short_audio() {
186 let transcriber = MockAudioTranscriber;
187 let audio_data = vec![0x01; 50]; let mut stream = transcriber.transcribe(&audio_data);
189
190 let mut text_chunks = Vec::new();
191 while let Some(chunk) = stream.next().await {
192 text_chunks.push(chunk.expect("mock never fails"));
193 }
194
195 assert_eq!(text_chunks.len(), 1);
196 assert_eq!(text_chunks[0], "Short");
197 }
198
199 #[tokio::test]
200 async fn audio_transcriber_medium_audio() {
201 let transcriber = MockAudioTranscriber;
202 let audio_data = vec![0x01; 500]; let mut stream = transcriber.transcribe(&audio_data);
204
205 let mut text_chunks = Vec::new();
206 while let Some(chunk) = stream.next().await {
207 text_chunks.push(chunk.expect("mock never fails"));
208 }
209
210 assert_eq!(text_chunks.len(), 2);
211 assert_eq!(text_chunks[0], "Hello");
212 assert_eq!(text_chunks[1], " world");
213 }
214
215 #[tokio::test]
216 async fn audio_transcriber_long_audio() {
217 let transcriber = MockAudioTranscriber;
218 let audio_data = vec![0x01; 2000]; let mut stream = transcriber.transcribe(&audio_data);
220
221 let mut text_chunks = Vec::new();
222 while let Some(chunk) = stream.next().await {
223 text_chunks.push(chunk.expect("mock never fails"));
224 }
225
226 assert_eq!(text_chunks.len(), 5);
227 let full_text: String = text_chunks.join("");
228 assert_eq!(full_text, "This is a longer transcription");
229 }
230
231 #[tokio::test]
232 async fn audio_transcriber_empty_audio() {
233 let transcriber = MockAudioTranscriber;
234 let audio_data = vec![]; let mut stream = transcriber.transcribe(&audio_data);
236
237 let mut text_chunks = Vec::new();
238 while let Some(chunk) = stream.next().await {
239 text_chunks.push(chunk.expect("mock never fails"));
240 }
241
242 assert!(
243 text_chunks.is_empty(),
244 "expected no text chunks, got {text_chunks:?}"
245 );
246 }
247
248 #[test]
249 fn data_type_alias() {
250 let data: Data = vec![1, 2, 3, 4, 5];
251 assert_eq!(data.len(), 5);
252 assert_eq!(data[0], 1);
253 assert_eq!(data[4], 5);
254 }
255
256 #[test]
257 fn data_operations() {
258 let mut data: Data = vec![0xFF; 1024];
259 assert_eq!(data.len(), 1024);
260
261 data.push(0x00);
263 assert_eq!(data.len(), 1025);
264 assert_eq!(data[1024], 0x00);
265
266 data.extend_from_slice(&[0x01, 0x02, 0x03]);
268 assert_eq!(data.len(), 1028);
269 assert_eq!(data[1025], 0x01);
270 assert_eq!(data[1026], 0x02);
271 assert_eq!(data[1027], 0x03);
272
273 data.clear();
275 assert!(
276 data.is_empty(),
277 "expected no audio data, got {} bytes",
278 data.len()
279 );
280 }
281
282 #[test]
283 fn data_creation() {
284 let empty_data: Data = Vec::new();
285 assert!(
286 empty_data.is_empty(),
287 "expected no audio data, got {} bytes",
288 empty_data.len()
289 );
290
291 let filled_data: Data = vec![42; 100];
292 assert_eq!(filled_data.len(), 100);
293 assert!(filled_data.iter().all(|&x| x == 42));
294 }
295
296 #[tokio::test]
297 async fn audio_workflow() {
298 let generator = MockAudioGenerator;
299 let transcriber = MockAudioTranscriber;
300
301 let prompt = "Hello world";
303 let mut audio_stream = generator.generate(prompt);
304
305 let mut all_audio_data = Vec::new();
306 while let Some(chunk) = audio_stream.next().await {
307 all_audio_data.extend_from_slice(&chunk.expect("mock never fails"));
308 }
309
310 let mut transcription_stream = transcriber.transcribe(&all_audio_data);
312
313 let mut transcription_chunks = Vec::new();
314 while let Some(chunk) = transcription_stream.next().await {
315 transcription_chunks.push(chunk.expect("mock never fails"));
316 }
317
318 assert!(!all_audio_data.is_empty(), "expected audio data, got none");
320 assert!(
321 !transcription_chunks.is_empty(),
322 "expected transcription chunks, got none"
323 );
324
325 let full_transcription: String = transcription_chunks.join("");
326 assert_eq!(full_transcription, "This is a longer transcription");
327 }
328}