]>
Commit | Line | Data |
---|---|---|
1b1a35ee | 1 | use crate::io::prelude::*; |
a2a8927a XL |
2 | use crate::io::{self, BufReader, BufWriter, ErrorKind, IoSlice, LineWriter, ReadBuf, SeekFrom}; |
3 | use crate::mem::MaybeUninit; | |
1b1a35ee XL |
4 | use crate::panic; |
5 | use crate::sync::atomic::{AtomicUsize, Ordering}; | |
6 | use crate::thread; | |
7 | ||
8 | /// A dummy reader intended at testing short-reads propagation. | |
9 | pub struct ShortReader { | |
10 | lengths: Vec<usize>, | |
11 | } | |
12 | ||
13 | // FIXME: rustfmt and tidy disagree about the correct formatting of this | |
14 | // function. This leads to issues for users with editors configured to | |
15 | // rustfmt-on-save. | |
16 | impl Read for ShortReader { | |
17 | fn read(&mut self, _: &mut [u8]) -> io::Result<usize> { | |
18 | if self.lengths.is_empty() { Ok(0) } else { Ok(self.lengths.remove(0)) } | |
19 | } | |
20 | } | |
21 | ||
22 | #[test] | |
23 | fn test_buffered_reader() { | |
24 | let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; | |
25 | let mut reader = BufReader::with_capacity(2, inner); | |
26 | ||
27 | let mut buf = [0, 0, 0]; | |
28 | let nread = reader.read(&mut buf); | |
29 | assert_eq!(nread.unwrap(), 3); | |
30 | assert_eq!(buf, [5, 6, 7]); | |
31 | assert_eq!(reader.buffer(), []); | |
32 | ||
33 | let mut buf = [0, 0]; | |
34 | let nread = reader.read(&mut buf); | |
35 | assert_eq!(nread.unwrap(), 2); | |
36 | assert_eq!(buf, [0, 1]); | |
37 | assert_eq!(reader.buffer(), []); | |
38 | ||
39 | let mut buf = [0]; | |
40 | let nread = reader.read(&mut buf); | |
41 | assert_eq!(nread.unwrap(), 1); | |
42 | assert_eq!(buf, [2]); | |
43 | assert_eq!(reader.buffer(), [3]); | |
44 | ||
45 | let mut buf = [0, 0, 0]; | |
46 | let nread = reader.read(&mut buf); | |
47 | assert_eq!(nread.unwrap(), 1); | |
48 | assert_eq!(buf, [3, 0, 0]); | |
49 | assert_eq!(reader.buffer(), []); | |
50 | ||
51 | let nread = reader.read(&mut buf); | |
52 | assert_eq!(nread.unwrap(), 1); | |
53 | assert_eq!(buf, [4, 0, 0]); | |
54 | assert_eq!(reader.buffer(), []); | |
55 | ||
56 | assert_eq!(reader.read(&mut buf).unwrap(), 0); | |
57 | } | |
58 | ||
a2a8927a XL |
59 | #[test] |
60 | fn test_buffered_reader_read_buf() { | |
61 | let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; | |
62 | let mut reader = BufReader::with_capacity(2, inner); | |
63 | ||
64 | let mut buf = [MaybeUninit::uninit(); 3]; | |
65 | let mut buf = ReadBuf::uninit(&mut buf); | |
66 | ||
67 | reader.read_buf(&mut buf).unwrap(); | |
68 | ||
69 | assert_eq!(buf.filled(), [5, 6, 7]); | |
70 | assert_eq!(reader.buffer(), []); | |
71 | ||
72 | let mut buf = [MaybeUninit::uninit(); 2]; | |
73 | let mut buf = ReadBuf::uninit(&mut buf); | |
74 | ||
75 | reader.read_buf(&mut buf).unwrap(); | |
76 | ||
77 | assert_eq!(buf.filled(), [0, 1]); | |
78 | assert_eq!(reader.buffer(), []); | |
79 | ||
80 | let mut buf = [MaybeUninit::uninit(); 1]; | |
81 | let mut buf = ReadBuf::uninit(&mut buf); | |
82 | ||
83 | reader.read_buf(&mut buf).unwrap(); | |
84 | ||
85 | assert_eq!(buf.filled(), [2]); | |
86 | assert_eq!(reader.buffer(), [3]); | |
87 | ||
88 | let mut buf = [MaybeUninit::uninit(); 3]; | |
89 | let mut buf = ReadBuf::uninit(&mut buf); | |
90 | ||
91 | reader.read_buf(&mut buf).unwrap(); | |
92 | ||
93 | assert_eq!(buf.filled(), [3]); | |
94 | assert_eq!(reader.buffer(), []); | |
95 | ||
96 | reader.read_buf(&mut buf).unwrap(); | |
97 | ||
98 | assert_eq!(buf.filled(), [3, 4]); | |
99 | assert_eq!(reader.buffer(), []); | |
100 | ||
101 | buf.clear(); | |
102 | ||
103 | reader.read_buf(&mut buf).unwrap(); | |
104 | ||
105 | assert_eq!(buf.filled_len(), 0); | |
106 | } | |
107 | ||
1b1a35ee XL |
108 | #[test] |
109 | fn test_buffered_reader_seek() { | |
110 | let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; | |
111 | let mut reader = BufReader::with_capacity(2, io::Cursor::new(inner)); | |
112 | ||
113 | assert_eq!(reader.seek(SeekFrom::Start(3)).ok(), Some(3)); | |
114 | assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..])); | |
115 | assert_eq!(reader.seek(SeekFrom::Current(0)).ok(), Some(3)); | |
116 | assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..])); | |
117 | assert_eq!(reader.seek(SeekFrom::Current(1)).ok(), Some(4)); | |
118 | assert_eq!(reader.fill_buf().ok(), Some(&[1, 2][..])); | |
119 | reader.consume(1); | |
120 | assert_eq!(reader.seek(SeekFrom::Current(-2)).ok(), Some(3)); | |
121 | } | |
122 | ||
123 | #[test] | |
124 | fn test_buffered_reader_seek_relative() { | |
125 | let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; | |
126 | let mut reader = BufReader::with_capacity(2, io::Cursor::new(inner)); | |
127 | ||
128 | assert!(reader.seek_relative(3).is_ok()); | |
129 | assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..])); | |
130 | assert!(reader.seek_relative(0).is_ok()); | |
131 | assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..])); | |
132 | assert!(reader.seek_relative(1).is_ok()); | |
133 | assert_eq!(reader.fill_buf().ok(), Some(&[1][..])); | |
134 | assert!(reader.seek_relative(-1).is_ok()); | |
135 | assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..])); | |
136 | assert!(reader.seek_relative(2).is_ok()); | |
137 | assert_eq!(reader.fill_buf().ok(), Some(&[2, 3][..])); | |
138 | } | |
139 | ||
140 | #[test] | |
141 | fn test_buffered_reader_stream_position() { | |
142 | let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; | |
143 | let mut reader = BufReader::with_capacity(2, io::Cursor::new(inner)); | |
144 | ||
145 | assert_eq!(reader.stream_position().ok(), Some(0)); | |
146 | assert_eq!(reader.seek(SeekFrom::Start(3)).ok(), Some(3)); | |
147 | assert_eq!(reader.stream_position().ok(), Some(3)); | |
148 | // relative seeking within the buffer and reading position should keep the buffer | |
149 | assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..])); | |
150 | assert!(reader.seek_relative(0).is_ok()); | |
151 | assert_eq!(reader.stream_position().ok(), Some(3)); | |
152 | assert_eq!(reader.buffer(), &[0, 1][..]); | |
153 | assert!(reader.seek_relative(1).is_ok()); | |
154 | assert_eq!(reader.stream_position().ok(), Some(4)); | |
155 | assert_eq!(reader.buffer(), &[1][..]); | |
156 | assert!(reader.seek_relative(-1).is_ok()); | |
157 | assert_eq!(reader.stream_position().ok(), Some(3)); | |
158 | assert_eq!(reader.buffer(), &[0, 1][..]); | |
159 | // relative seeking outside the buffer will discard it | |
160 | assert!(reader.seek_relative(2).is_ok()); | |
161 | assert_eq!(reader.stream_position().ok(), Some(5)); | |
162 | assert_eq!(reader.buffer(), &[][..]); | |
163 | } | |
164 | ||
165 | #[test] | |
166 | fn test_buffered_reader_stream_position_panic() { | |
167 | let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; | |
168 | let mut reader = BufReader::with_capacity(4, io::Cursor::new(inner)); | |
169 | ||
170 | // cause internal buffer to be filled but read only partially | |
171 | let mut buffer = [0, 0]; | |
172 | assert!(reader.read_exact(&mut buffer).is_ok()); | |
173 | // rewinding the internal reader will cause buffer to loose sync | |
174 | let inner = reader.get_mut(); | |
175 | assert!(inner.seek(SeekFrom::Start(0)).is_ok()); | |
176 | // overflow when subtracting the remaining buffer size from current position | |
177 | let result = panic::catch_unwind(panic::AssertUnwindSafe(|| reader.stream_position().ok())); | |
178 | assert!(result.is_err()); | |
179 | } | |
180 | ||
181 | #[test] | |
182 | fn test_buffered_reader_invalidated_after_read() { | |
183 | let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; | |
184 | let mut reader = BufReader::with_capacity(3, io::Cursor::new(inner)); | |
185 | ||
186 | assert_eq!(reader.fill_buf().ok(), Some(&[5, 6, 7][..])); | |
187 | reader.consume(3); | |
188 | ||
189 | let mut buffer = [0, 0, 0, 0, 0]; | |
190 | assert_eq!(reader.read(&mut buffer).ok(), Some(5)); | |
191 | assert_eq!(buffer, [0, 1, 2, 3, 4]); | |
192 | ||
193 | assert!(reader.seek_relative(-2).is_ok()); | |
194 | let mut buffer = [0, 0]; | |
195 | assert_eq!(reader.read(&mut buffer).ok(), Some(2)); | |
196 | assert_eq!(buffer, [3, 4]); | |
197 | } | |
198 | ||
199 | #[test] | |
200 | fn test_buffered_reader_invalidated_after_seek() { | |
201 | let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; | |
202 | let mut reader = BufReader::with_capacity(3, io::Cursor::new(inner)); | |
203 | ||
204 | assert_eq!(reader.fill_buf().ok(), Some(&[5, 6, 7][..])); | |
205 | reader.consume(3); | |
206 | ||
207 | assert!(reader.seek(SeekFrom::Current(5)).is_ok()); | |
208 | ||
209 | assert!(reader.seek_relative(-2).is_ok()); | |
210 | let mut buffer = [0, 0]; | |
211 | assert_eq!(reader.read(&mut buffer).ok(), Some(2)); | |
212 | assert_eq!(buffer, [3, 4]); | |
213 | } | |
214 | ||
215 | #[test] | |
216 | fn test_buffered_reader_seek_underflow() { | |
217 | // gimmick reader that yields its position modulo 256 for each byte | |
218 | struct PositionReader { | |
219 | pos: u64, | |
220 | } | |
221 | impl Read for PositionReader { | |
222 | fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { | |
223 | let len = buf.len(); | |
224 | for x in buf { | |
225 | *x = self.pos as u8; | |
226 | self.pos = self.pos.wrapping_add(1); | |
227 | } | |
228 | Ok(len) | |
229 | } | |
230 | } | |
231 | impl Seek for PositionReader { | |
232 | fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { | |
233 | match pos { | |
234 | SeekFrom::Start(n) => { | |
235 | self.pos = n; | |
236 | } | |
237 | SeekFrom::Current(n) => { | |
238 | self.pos = self.pos.wrapping_add(n as u64); | |
239 | } | |
240 | SeekFrom::End(n) => { | |
241 | self.pos = u64::MAX.wrapping_add(n as u64); | |
242 | } | |
243 | } | |
244 | Ok(self.pos) | |
245 | } | |
246 | } | |
247 | ||
248 | let mut reader = BufReader::with_capacity(5, PositionReader { pos: 0 }); | |
249 | assert_eq!(reader.fill_buf().ok(), Some(&[0, 1, 2, 3, 4][..])); | |
250 | assert_eq!(reader.seek(SeekFrom::End(-5)).ok(), Some(u64::MAX - 5)); | |
251 | assert_eq!(reader.fill_buf().ok().map(|s| s.len()), Some(5)); | |
252 | // the following seek will require two underlying seeks | |
253 | let expected = 9223372036854775802; | |
254 | assert_eq!(reader.seek(SeekFrom::Current(i64::MIN)).ok(), Some(expected)); | |
255 | assert_eq!(reader.fill_buf().ok().map(|s| s.len()), Some(5)); | |
256 | // seeking to 0 should empty the buffer. | |
257 | assert_eq!(reader.seek(SeekFrom::Current(0)).ok(), Some(expected)); | |
258 | assert_eq!(reader.get_ref().pos, expected); | |
259 | } | |
260 | ||
261 | #[test] | |
262 | fn test_buffered_reader_seek_underflow_discard_buffer_between_seeks() { | |
263 | // gimmick reader that returns Err after first seek | |
264 | struct ErrAfterFirstSeekReader { | |
265 | first_seek: bool, | |
266 | } | |
267 | impl Read for ErrAfterFirstSeekReader { | |
268 | fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { | |
269 | for x in &mut *buf { | |
270 | *x = 0; | |
271 | } | |
272 | Ok(buf.len()) | |
273 | } | |
274 | } | |
275 | impl Seek for ErrAfterFirstSeekReader { | |
276 | fn seek(&mut self, _: SeekFrom) -> io::Result<u64> { | |
277 | if self.first_seek { | |
278 | self.first_seek = false; | |
279 | Ok(0) | |
280 | } else { | |
281 | Err(io::Error::new(io::ErrorKind::Other, "oh no!")) | |
282 | } | |
283 | } | |
284 | } | |
285 | ||
286 | let mut reader = BufReader::with_capacity(5, ErrAfterFirstSeekReader { first_seek: true }); | |
287 | assert_eq!(reader.fill_buf().ok(), Some(&[0, 0, 0, 0, 0][..])); | |
288 | ||
289 | // The following seek will require two underlying seeks. The first will | |
290 | // succeed but the second will fail. This should still invalidate the | |
291 | // buffer. | |
292 | assert!(reader.seek(SeekFrom::Current(i64::MIN)).is_err()); | |
293 | assert_eq!(reader.buffer().len(), 0); | |
294 | } | |
295 | ||
c295e0f8 XL |
296 | #[test] |
297 | fn test_buffered_reader_read_to_end_consumes_buffer() { | |
298 | let data: &[u8] = &[0, 1, 2, 3, 4, 5, 6, 7]; | |
299 | let mut reader = BufReader::with_capacity(3, data); | |
300 | let mut buf = Vec::new(); | |
301 | assert_eq!(reader.fill_buf().ok(), Some(&[0, 1, 2][..])); | |
302 | assert_eq!(reader.read_to_end(&mut buf).ok(), Some(8)); | |
303 | assert_eq!(&buf, &[0, 1, 2, 3, 4, 5, 6, 7]); | |
304 | assert!(reader.buffer().is_empty()); | |
305 | } | |
306 | ||
307 | #[test] | |
308 | fn test_buffered_reader_read_to_string_consumes_buffer() { | |
309 | let data: &[u8] = "deadbeef".as_bytes(); | |
310 | let mut reader = BufReader::with_capacity(3, data); | |
311 | let mut buf = String::new(); | |
312 | assert_eq!(reader.fill_buf().ok(), Some("dea".as_bytes())); | |
313 | assert_eq!(reader.read_to_string(&mut buf).ok(), Some(8)); | |
314 | assert_eq!(&buf, "deadbeef"); | |
315 | assert!(reader.buffer().is_empty()); | |
316 | } | |
317 | ||
1b1a35ee XL |
318 | #[test] |
319 | fn test_buffered_writer() { | |
320 | let inner = Vec::new(); | |
321 | let mut writer = BufWriter::with_capacity(2, inner); | |
322 | ||
323 | writer.write(&[0, 1]).unwrap(); | |
324 | assert_eq!(writer.buffer(), []); | |
325 | assert_eq!(*writer.get_ref(), [0, 1]); | |
326 | ||
327 | writer.write(&[2]).unwrap(); | |
328 | assert_eq!(writer.buffer(), [2]); | |
329 | assert_eq!(*writer.get_ref(), [0, 1]); | |
330 | ||
331 | writer.write(&[3]).unwrap(); | |
332 | assert_eq!(writer.buffer(), [2, 3]); | |
333 | assert_eq!(*writer.get_ref(), [0, 1]); | |
334 | ||
335 | writer.flush().unwrap(); | |
336 | assert_eq!(writer.buffer(), []); | |
337 | assert_eq!(*writer.get_ref(), [0, 1, 2, 3]); | |
338 | ||
339 | writer.write(&[4]).unwrap(); | |
340 | writer.write(&[5]).unwrap(); | |
341 | assert_eq!(writer.buffer(), [4, 5]); | |
342 | assert_eq!(*writer.get_ref(), [0, 1, 2, 3]); | |
343 | ||
344 | writer.write(&[6]).unwrap(); | |
345 | assert_eq!(writer.buffer(), [6]); | |
346 | assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5]); | |
347 | ||
348 | writer.write(&[7, 8]).unwrap(); | |
349 | assert_eq!(writer.buffer(), []); | |
350 | assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8]); | |
351 | ||
352 | writer.write(&[9, 10, 11]).unwrap(); | |
353 | assert_eq!(writer.buffer(), []); | |
354 | assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]); | |
355 | ||
356 | writer.flush().unwrap(); | |
357 | assert_eq!(writer.buffer(), []); | |
358 | assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]); | |
359 | } | |
360 | ||
361 | #[test] | |
362 | fn test_buffered_writer_inner_flushes() { | |
363 | let mut w = BufWriter::with_capacity(3, Vec::new()); | |
364 | w.write(&[0, 1]).unwrap(); | |
365 | assert_eq!(*w.get_ref(), []); | |
366 | let w = w.into_inner().unwrap(); | |
367 | assert_eq!(w, [0, 1]); | |
368 | } | |
369 | ||
370 | #[test] | |
371 | fn test_buffered_writer_seek() { | |
372 | let mut w = BufWriter::with_capacity(3, io::Cursor::new(Vec::new())); | |
373 | w.write_all(&[0, 1, 2, 3, 4, 5]).unwrap(); | |
374 | w.write_all(&[6, 7]).unwrap(); | |
375 | assert_eq!(w.seek(SeekFrom::Current(0)).ok(), Some(8)); | |
376 | assert_eq!(&w.get_ref().get_ref()[..], &[0, 1, 2, 3, 4, 5, 6, 7][..]); | |
377 | assert_eq!(w.seek(SeekFrom::Start(2)).ok(), Some(2)); | |
378 | w.write_all(&[8, 9]).unwrap(); | |
379 | assert_eq!(&w.into_inner().unwrap().into_inner()[..], &[0, 1, 8, 9, 4, 5, 6, 7]); | |
380 | } | |
381 | ||
382 | #[test] | |
383 | fn test_read_until() { | |
384 | let inner: &[u8] = &[0, 1, 2, 1, 0]; | |
385 | let mut reader = BufReader::with_capacity(2, inner); | |
386 | let mut v = Vec::new(); | |
387 | reader.read_until(0, &mut v).unwrap(); | |
388 | assert_eq!(v, [0]); | |
389 | v.truncate(0); | |
390 | reader.read_until(2, &mut v).unwrap(); | |
391 | assert_eq!(v, [1, 2]); | |
392 | v.truncate(0); | |
393 | reader.read_until(1, &mut v).unwrap(); | |
394 | assert_eq!(v, [1]); | |
395 | v.truncate(0); | |
396 | reader.read_until(8, &mut v).unwrap(); | |
397 | assert_eq!(v, [0]); | |
398 | v.truncate(0); | |
399 | reader.read_until(9, &mut v).unwrap(); | |
400 | assert_eq!(v, []); | |
401 | } | |
402 | ||
403 | #[test] | |
404 | fn test_line_buffer() { | |
405 | let mut writer = LineWriter::new(Vec::new()); | |
406 | writer.write(&[0]).unwrap(); | |
407 | assert_eq!(*writer.get_ref(), []); | |
408 | writer.write(&[1]).unwrap(); | |
409 | assert_eq!(*writer.get_ref(), []); | |
410 | writer.flush().unwrap(); | |
411 | assert_eq!(*writer.get_ref(), [0, 1]); | |
412 | writer.write(&[0, b'\n', 1, b'\n', 2]).unwrap(); | |
413 | assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n']); | |
414 | writer.flush().unwrap(); | |
415 | assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n', 2]); | |
416 | writer.write(&[3, b'\n']).unwrap(); | |
417 | assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n', 2, 3, b'\n']); | |
418 | } | |
419 | ||
420 | #[test] | |
421 | fn test_read_line() { | |
422 | let in_buf: &[u8] = b"a\nb\nc"; | |
423 | let mut reader = BufReader::with_capacity(2, in_buf); | |
424 | let mut s = String::new(); | |
425 | reader.read_line(&mut s).unwrap(); | |
426 | assert_eq!(s, "a\n"); | |
427 | s.truncate(0); | |
428 | reader.read_line(&mut s).unwrap(); | |
429 | assert_eq!(s, "b\n"); | |
430 | s.truncate(0); | |
431 | reader.read_line(&mut s).unwrap(); | |
432 | assert_eq!(s, "c"); | |
433 | s.truncate(0); | |
434 | reader.read_line(&mut s).unwrap(); | |
435 | assert_eq!(s, ""); | |
436 | } | |
437 | ||
438 | #[test] | |
439 | fn test_lines() { | |
440 | let in_buf: &[u8] = b"a\nb\nc"; | |
441 | let reader = BufReader::with_capacity(2, in_buf); | |
442 | let mut it = reader.lines(); | |
443 | assert_eq!(it.next().unwrap().unwrap(), "a".to_string()); | |
444 | assert_eq!(it.next().unwrap().unwrap(), "b".to_string()); | |
445 | assert_eq!(it.next().unwrap().unwrap(), "c".to_string()); | |
446 | assert!(it.next().is_none()); | |
447 | } | |
448 | ||
449 | #[test] | |
450 | fn test_short_reads() { | |
451 | let inner = ShortReader { lengths: vec![0, 1, 2, 0, 1, 0] }; | |
452 | let mut reader = BufReader::new(inner); | |
453 | let mut buf = [0, 0]; | |
454 | assert_eq!(reader.read(&mut buf).unwrap(), 0); | |
455 | assert_eq!(reader.read(&mut buf).unwrap(), 1); | |
456 | assert_eq!(reader.read(&mut buf).unwrap(), 2); | |
457 | assert_eq!(reader.read(&mut buf).unwrap(), 0); | |
458 | assert_eq!(reader.read(&mut buf).unwrap(), 1); | |
459 | assert_eq!(reader.read(&mut buf).unwrap(), 0); | |
460 | assert_eq!(reader.read(&mut buf).unwrap(), 0); | |
461 | } | |
462 | ||
463 | #[test] | |
464 | #[should_panic] | |
465 | fn dont_panic_in_drop_on_panicked_flush() { | |
466 | struct FailFlushWriter; | |
467 | ||
468 | impl Write for FailFlushWriter { | |
469 | fn write(&mut self, buf: &[u8]) -> io::Result<usize> { | |
470 | Ok(buf.len()) | |
471 | } | |
472 | fn flush(&mut self) -> io::Result<()> { | |
473 | Err(io::Error::last_os_error()) | |
474 | } | |
475 | } | |
476 | ||
477 | let writer = FailFlushWriter; | |
478 | let _writer = BufWriter::new(writer); | |
479 | ||
480 | // If writer panics *again* due to the flush error then the process will | |
481 | // abort. | |
482 | panic!(); | |
483 | } | |
484 | ||
485 | #[test] | |
486 | #[cfg_attr(target_os = "emscripten", ignore)] | |
487 | fn panic_in_write_doesnt_flush_in_drop() { | |
488 | static WRITES: AtomicUsize = AtomicUsize::new(0); | |
489 | ||
490 | struct PanicWriter; | |
491 | ||
492 | impl Write for PanicWriter { | |
493 | fn write(&mut self, _: &[u8]) -> io::Result<usize> { | |
494 | WRITES.fetch_add(1, Ordering::SeqCst); | |
495 | panic!(); | |
496 | } | |
497 | fn flush(&mut self) -> io::Result<()> { | |
498 | Ok(()) | |
499 | } | |
500 | } | |
501 | ||
502 | thread::spawn(|| { | |
503 | let mut writer = BufWriter::new(PanicWriter); | |
504 | let _ = writer.write(b"hello world"); | |
505 | let _ = writer.flush(); | |
506 | }) | |
507 | .join() | |
508 | .unwrap_err(); | |
509 | ||
510 | assert_eq!(WRITES.load(Ordering::SeqCst), 1); | |
511 | } | |
512 | ||
513 | #[bench] | |
514 | fn bench_buffered_reader(b: &mut test::Bencher) { | |
515 | b.iter(|| BufReader::new(io::empty())); | |
516 | } | |
517 | ||
5869c6ff XL |
518 | #[bench] |
519 | fn bench_buffered_reader_small_reads(b: &mut test::Bencher) { | |
520 | let data = (0..u8::MAX).cycle().take(1024 * 4).collect::<Vec<_>>(); | |
521 | b.iter(|| { | |
522 | let mut reader = BufReader::new(&data[..]); | |
523 | let mut buf = [0u8; 4]; | |
524 | for _ in 0..1024 { | |
525 | reader.read_exact(&mut buf).unwrap(); | |
064997fb | 526 | core::hint::black_box(&buf); |
5869c6ff XL |
527 | } |
528 | }); | |
529 | } | |
530 | ||
1b1a35ee XL |
531 | #[bench] |
532 | fn bench_buffered_writer(b: &mut test::Bencher) { | |
533 | b.iter(|| BufWriter::new(io::sink())); | |
534 | } | |
535 | ||
536 | /// A simple `Write` target, designed to be wrapped by `LineWriter` / | |
537 | /// `BufWriter` / etc, that can have its `write` & `flush` behavior | |
538 | /// configured | |
539 | #[derive(Default, Clone)] | |
540 | struct ProgrammableSink { | |
541 | // Writes append to this slice | |
542 | pub buffer: Vec<u8>, | |
543 | ||
1b1a35ee XL |
544 | // If true, writes will always be an error |
545 | pub always_write_error: bool, | |
546 | ||
547 | // If true, flushes will always be an error | |
548 | pub always_flush_error: bool, | |
549 | ||
550 | // If set, only up to this number of bytes will be written in a single | |
551 | // call to `write` | |
552 | pub accept_prefix: Option<usize>, | |
553 | ||
554 | // If set, counts down with each write, and writes return an error | |
555 | // when it hits 0 | |
556 | pub max_writes: Option<usize>, | |
557 | ||
558 | // If set, attempting to write when max_writes == Some(0) will be an | |
559 | // error; otherwise, it will return Ok(0). | |
560 | pub error_after_max_writes: bool, | |
561 | } | |
562 | ||
563 | impl Write for ProgrammableSink { | |
564 | fn write(&mut self, data: &[u8]) -> io::Result<usize> { | |
565 | if self.always_write_error { | |
566 | return Err(io::Error::new(io::ErrorKind::Other, "test - always_write_error")); | |
567 | } | |
568 | ||
569 | match self.max_writes { | |
570 | Some(0) if self.error_after_max_writes => { | |
571 | return Err(io::Error::new(io::ErrorKind::Other, "test - max_writes")); | |
572 | } | |
573 | Some(0) => return Ok(0), | |
574 | Some(ref mut count) => *count -= 1, | |
575 | None => {} | |
576 | } | |
577 | ||
578 | let len = match self.accept_prefix { | |
579 | None => data.len(), | |
580 | Some(prefix) => data.len().min(prefix), | |
581 | }; | |
582 | ||
583 | let data = &data[..len]; | |
584 | self.buffer.extend_from_slice(data); | |
585 | ||
586 | Ok(len) | |
587 | } | |
588 | ||
589 | fn flush(&mut self) -> io::Result<()> { | |
590 | if self.always_flush_error { | |
591 | Err(io::Error::new(io::ErrorKind::Other, "test - always_flush_error")) | |
592 | } else { | |
1b1a35ee XL |
593 | Ok(()) |
594 | } | |
595 | } | |
596 | } | |
597 | ||
598 | /// Previously the `LineWriter` could successfully write some bytes but | |
599 | /// then fail to report that it has done so. Additionally, an erroneous | |
600 | /// flush after a successful write was permanently ignored. | |
601 | /// | |
602 | /// Test that a line writer correctly reports the number of written bytes, | |
603 | /// and that it attempts to flush buffered lines from previous writes | |
604 | /// before processing new data | |
605 | /// | |
606 | /// Regression test for #37807 | |
607 | #[test] | |
608 | fn erroneous_flush_retried() { | |
609 | let writer = ProgrammableSink { | |
610 | // Only write up to 4 bytes at a time | |
611 | accept_prefix: Some(4), | |
612 | ||
613 | // Accept the first two writes, then error the others | |
614 | max_writes: Some(2), | |
615 | error_after_max_writes: true, | |
616 | ||
617 | ..Default::default() | |
618 | }; | |
619 | ||
620 | // This should write the first 4 bytes. The rest will be buffered, out | |
621 | // to the last newline. | |
622 | let mut writer = LineWriter::new(writer); | |
623 | assert_eq!(writer.write(b"a\nb\nc\nd\ne").unwrap(), 8); | |
624 | ||
625 | // This write should attempt to flush "c\nd\n", then buffer "e". No | |
626 | // errors should happen here because no further writes should be | |
627 | // attempted against `writer`. | |
628 | assert_eq!(writer.write(b"e").unwrap(), 1); | |
629 | assert_eq!(&writer.get_ref().buffer, b"a\nb\nc\nd\n"); | |
630 | } | |
631 | ||
632 | #[test] | |
633 | fn line_vectored() { | |
634 | let mut a = LineWriter::new(Vec::new()); | |
635 | assert_eq!( | |
636 | a.write_vectored(&[ | |
637 | IoSlice::new(&[]), | |
638 | IoSlice::new(b"\n"), | |
639 | IoSlice::new(&[]), | |
640 | IoSlice::new(b"a"), | |
641 | ]) | |
642 | .unwrap(), | |
643 | 2, | |
644 | ); | |
645 | assert_eq!(a.get_ref(), b"\n"); | |
646 | ||
647 | assert_eq!( | |
648 | a.write_vectored(&[ | |
649 | IoSlice::new(&[]), | |
650 | IoSlice::new(b"b"), | |
651 | IoSlice::new(&[]), | |
652 | IoSlice::new(b"a"), | |
653 | IoSlice::new(&[]), | |
654 | IoSlice::new(b"c"), | |
655 | ]) | |
656 | .unwrap(), | |
657 | 3, | |
658 | ); | |
659 | assert_eq!(a.get_ref(), b"\n"); | |
660 | a.flush().unwrap(); | |
661 | assert_eq!(a.get_ref(), b"\nabac"); | |
662 | assert_eq!(a.write_vectored(&[]).unwrap(), 0); | |
663 | assert_eq!( | |
664 | a.write_vectored(&[ | |
665 | IoSlice::new(&[]), | |
666 | IoSlice::new(&[]), | |
667 | IoSlice::new(&[]), | |
668 | IoSlice::new(&[]), | |
669 | ]) | |
670 | .unwrap(), | |
671 | 0, | |
672 | ); | |
673 | assert_eq!(a.write_vectored(&[IoSlice::new(b"a\nb"),]).unwrap(), 3); | |
674 | assert_eq!(a.get_ref(), b"\nabaca\nb"); | |
675 | } | |
676 | ||
677 | #[test] | |
678 | fn line_vectored_partial_and_errors() { | |
679 | use crate::collections::VecDeque; | |
680 | ||
681 | enum Call { | |
682 | Write { inputs: Vec<&'static [u8]>, output: io::Result<usize> }, | |
683 | Flush { output: io::Result<()> }, | |
684 | } | |
685 | ||
686 | #[derive(Default)] | |
687 | struct Writer { | |
688 | calls: VecDeque<Call>, | |
689 | } | |
690 | ||
691 | impl Write for Writer { | |
692 | fn write(&mut self, buf: &[u8]) -> io::Result<usize> { | |
693 | self.write_vectored(&[IoSlice::new(buf)]) | |
694 | } | |
695 | ||
696 | fn write_vectored(&mut self, buf: &[IoSlice<'_>]) -> io::Result<usize> { | |
697 | match self.calls.pop_front().expect("unexpected call to write") { | |
698 | Call::Write { inputs, output } => { | |
699 | assert_eq!(inputs, buf.iter().map(|b| &**b).collect::<Vec<_>>()); | |
700 | output | |
701 | } | |
702 | Call::Flush { .. } => panic!("unexpected call to write; expected a flush"), | |
703 | } | |
704 | } | |
705 | ||
706 | fn is_write_vectored(&self) -> bool { | |
707 | true | |
708 | } | |
709 | ||
710 | fn flush(&mut self) -> io::Result<()> { | |
711 | match self.calls.pop_front().expect("Unexpected call to flush") { | |
712 | Call::Flush { output } => output, | |
713 | Call::Write { .. } => panic!("unexpected call to flush; expected a write"), | |
714 | } | |
715 | } | |
716 | } | |
717 | ||
718 | impl Drop for Writer { | |
719 | fn drop(&mut self) { | |
720 | if !thread::panicking() { | |
721 | assert_eq!(self.calls.len(), 0); | |
722 | } | |
723 | } | |
724 | } | |
725 | ||
726 | // partial writes keep going | |
727 | let mut a = LineWriter::new(Writer::default()); | |
728 | a.write_vectored(&[IoSlice::new(&[]), IoSlice::new(b"abc")]).unwrap(); | |
729 | ||
730 | a.get_mut().calls.push_back(Call::Write { inputs: vec![b"abc"], output: Ok(1) }); | |
731 | a.get_mut().calls.push_back(Call::Write { inputs: vec![b"bc"], output: Ok(2) }); | |
732 | a.get_mut().calls.push_back(Call::Write { inputs: vec![b"x", b"\n"], output: Ok(2) }); | |
733 | ||
734 | a.write_vectored(&[IoSlice::new(b"x"), IoSlice::new(b"\n")]).unwrap(); | |
735 | ||
736 | a.get_mut().calls.push_back(Call::Flush { output: Ok(()) }); | |
737 | a.flush().unwrap(); | |
738 | ||
739 | // erroneous writes stop and don't write more | |
740 | a.get_mut().calls.push_back(Call::Write { inputs: vec![b"x", b"\na"], output: Err(err()) }); | |
741 | a.get_mut().calls.push_back(Call::Flush { output: Ok(()) }); | |
742 | assert!(a.write_vectored(&[IoSlice::new(b"x"), IoSlice::new(b"\na")]).is_err()); | |
743 | a.flush().unwrap(); | |
744 | ||
745 | fn err() -> io::Error { | |
746 | io::Error::new(io::ErrorKind::Other, "x") | |
747 | } | |
748 | } | |
749 | ||
750 | /// Test that, in cases where vectored writing is not enabled, the | |
751 | /// LineWriter uses the normal `write` call, which more-correctly handles | |
752 | /// partial lines | |
753 | #[test] | |
754 | fn line_vectored_ignored() { | |
755 | let writer = ProgrammableSink::default(); | |
756 | let mut writer = LineWriter::new(writer); | |
757 | ||
758 | let content = [ | |
759 | IoSlice::new(&[]), | |
760 | IoSlice::new(b"Line 1\nLine"), | |
761 | IoSlice::new(b" 2\nLine 3\nL"), | |
762 | IoSlice::new(&[]), | |
763 | IoSlice::new(&[]), | |
764 | IoSlice::new(b"ine 4"), | |
765 | IoSlice::new(b"\nLine 5\n"), | |
766 | ]; | |
767 | ||
768 | let count = writer.write_vectored(&content).unwrap(); | |
769 | assert_eq!(count, 11); | |
770 | assert_eq!(&writer.get_ref().buffer, b"Line 1\n"); | |
771 | ||
772 | let count = writer.write_vectored(&content[2..]).unwrap(); | |
773 | assert_eq!(count, 11); | |
774 | assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2\nLine 3\n"); | |
775 | ||
776 | let count = writer.write_vectored(&content[5..]).unwrap(); | |
777 | assert_eq!(count, 5); | |
778 | assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2\nLine 3\n"); | |
779 | ||
780 | let count = writer.write_vectored(&content[6..]).unwrap(); | |
781 | assert_eq!(count, 8); | |
782 | assert_eq!( | |
783 | writer.get_ref().buffer.as_slice(), | |
784 | b"Line 1\nLine 2\nLine 3\nLine 4\nLine 5\n".as_ref() | |
785 | ); | |
786 | } | |
787 | ||
788 | /// Test that, given this input: | |
789 | /// | |
790 | /// Line 1\n | |
791 | /// Line 2\n | |
792 | /// Line 3\n | |
793 | /// Line 4 | |
794 | /// | |
795 | /// And given a result that only writes to midway through Line 2 | |
796 | /// | |
797 | /// That only up to the end of Line 3 is buffered | |
798 | /// | |
799 | /// This behavior is desirable because it prevents flushing partial lines | |
800 | #[test] | |
801 | fn partial_write_buffers_line() { | |
802 | let writer = ProgrammableSink { accept_prefix: Some(13), ..Default::default() }; | |
803 | let mut writer = LineWriter::new(writer); | |
804 | ||
805 | assert_eq!(writer.write(b"Line 1\nLine 2\nLine 3\nLine4").unwrap(), 21); | |
806 | assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2"); | |
807 | ||
808 | assert_eq!(writer.write(b"Line 4").unwrap(), 6); | |
809 | assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2\nLine 3\n"); | |
810 | } | |
811 | ||
812 | /// Test that, given this input: | |
813 | /// | |
814 | /// Line 1\n | |
815 | /// Line 2\n | |
816 | /// Line 3 | |
817 | /// | |
818 | /// And given that the full write of lines 1 and 2 was successful | |
819 | /// That data up to Line 3 is buffered | |
820 | #[test] | |
821 | fn partial_line_buffered_after_line_write() { | |
822 | let writer = ProgrammableSink::default(); | |
823 | let mut writer = LineWriter::new(writer); | |
824 | ||
825 | assert_eq!(writer.write(b"Line 1\nLine 2\nLine 3").unwrap(), 20); | |
826 | assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2\n"); | |
827 | ||
828 | assert!(writer.flush().is_ok()); | |
829 | assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2\nLine 3"); | |
830 | } | |
831 | ||
832 | /// Test that, given a partial line that exceeds the length of | |
833 | /// LineBuffer's buffer (that is, without a trailing newline), that that | |
834 | /// line is written to the inner writer | |
835 | #[test] | |
836 | fn long_line_flushed() { | |
837 | let writer = ProgrammableSink::default(); | |
838 | let mut writer = LineWriter::with_capacity(5, writer); | |
839 | ||
840 | assert_eq!(writer.write(b"0123456789").unwrap(), 10); | |
841 | assert_eq!(&writer.get_ref().buffer, b"0123456789"); | |
842 | } | |
843 | ||
844 | /// Test that, given a very long partial line *after* successfully | |
845 | /// flushing a complete line, that that line is buffered unconditionally, | |
846 | /// and no additional writes take place. This assures the property that | |
847 | /// `write` should make at-most-one attempt to write new data. | |
848 | #[test] | |
849 | fn line_long_tail_not_flushed() { | |
850 | let writer = ProgrammableSink::default(); | |
851 | let mut writer = LineWriter::with_capacity(5, writer); | |
852 | ||
853 | // Assert that Line 1\n is flushed, and 01234 is buffered | |
854 | assert_eq!(writer.write(b"Line 1\n0123456789").unwrap(), 12); | |
855 | assert_eq!(&writer.get_ref().buffer, b"Line 1\n"); | |
856 | ||
857 | // Because the buffer is full, this subsequent write will flush it | |
858 | assert_eq!(writer.write(b"5").unwrap(), 1); | |
859 | assert_eq!(&writer.get_ref().buffer, b"Line 1\n01234"); | |
860 | } | |
861 | ||
862 | /// Test that, if an attempt to pre-flush buffered data returns Ok(0), | |
863 | /// this is propagated as an error. | |
864 | #[test] | |
865 | fn line_buffer_write0_error() { | |
866 | let writer = ProgrammableSink { | |
867 | // Accept one write, then return Ok(0) on subsequent ones | |
868 | max_writes: Some(1), | |
869 | ||
870 | ..Default::default() | |
871 | }; | |
872 | let mut writer = LineWriter::new(writer); | |
873 | ||
874 | // This should write "Line 1\n" and buffer "Partial" | |
875 | assert_eq!(writer.write(b"Line 1\nPartial").unwrap(), 14); | |
876 | assert_eq!(&writer.get_ref().buffer, b"Line 1\n"); | |
877 | ||
878 | // This will attempt to flush "partial", which will return Ok(0), which | |
879 | // needs to be an error, because we've already informed the client | |
880 | // that we accepted the write. | |
881 | let err = writer.write(b" Line End\n").unwrap_err(); | |
882 | assert_eq!(err.kind(), ErrorKind::WriteZero); | |
883 | assert_eq!(&writer.get_ref().buffer, b"Line 1\n"); | |
884 | } | |
885 | ||
886 | /// Test that, if a write returns Ok(0) after a successful pre-flush, this | |
887 | /// is propagated as Ok(0) | |
888 | #[test] | |
889 | fn line_buffer_write0_normal() { | |
890 | let writer = ProgrammableSink { | |
891 | // Accept two writes, then return Ok(0) on subsequent ones | |
892 | max_writes: Some(2), | |
893 | ||
894 | ..Default::default() | |
895 | }; | |
896 | let mut writer = LineWriter::new(writer); | |
897 | ||
898 | // This should write "Line 1\n" and buffer "Partial" | |
899 | assert_eq!(writer.write(b"Line 1\nPartial").unwrap(), 14); | |
900 | assert_eq!(&writer.get_ref().buffer, b"Line 1\n"); | |
901 | ||
902 | // This will flush partial, which will succeed, but then return Ok(0) | |
903 | // when flushing " Line End\n" | |
904 | assert_eq!(writer.write(b" Line End\n").unwrap(), 0); | |
905 | assert_eq!(&writer.get_ref().buffer, b"Line 1\nPartial"); | |
906 | } | |
907 | ||
908 | /// LineWriter has a custom `write_all`; make sure it works correctly | |
909 | #[test] | |
910 | fn line_write_all() { | |
911 | let writer = ProgrammableSink { | |
912 | // Only write 5 bytes at a time | |
913 | accept_prefix: Some(5), | |
914 | ..Default::default() | |
915 | }; | |
916 | let mut writer = LineWriter::new(writer); | |
917 | ||
918 | writer.write_all(b"Line 1\nLine 2\nLine 3\nLine 4\nPartial").unwrap(); | |
919 | assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2\nLine 3\nLine 4\n"); | |
920 | writer.write_all(b" Line 5\n").unwrap(); | |
921 | assert_eq!( | |
922 | writer.get_ref().buffer.as_slice(), | |
923 | b"Line 1\nLine 2\nLine 3\nLine 4\nPartial Line 5\n".as_ref(), | |
924 | ); | |
925 | } | |
926 | ||
927 | #[test] | |
928 | fn line_write_all_error() { | |
929 | let writer = ProgrammableSink { | |
930 | // Only accept up to 3 writes of up to 5 bytes each | |
931 | accept_prefix: Some(5), | |
932 | max_writes: Some(3), | |
933 | ..Default::default() | |
934 | }; | |
935 | ||
936 | let mut writer = LineWriter::new(writer); | |
937 | let res = writer.write_all(b"Line 1\nLine 2\nLine 3\nLine 4\nPartial"); | |
938 | assert!(res.is_err()); | |
939 | // An error from write_all leaves everything in an indeterminate state, | |
940 | // so there's nothing else to test here | |
941 | } | |
942 | ||
943 | /// Under certain circumstances, the old implementation of LineWriter | |
944 | /// would try to buffer "to the last newline" but be forced to buffer | |
945 | /// less than that, leading to inappropriate partial line writes. | |
946 | /// Regression test for that issue. | |
947 | #[test] | |
948 | fn partial_multiline_buffering() { | |
949 | let writer = ProgrammableSink { | |
950 | // Write only up to 5 bytes at a time | |
951 | accept_prefix: Some(5), | |
952 | ..Default::default() | |
953 | }; | |
954 | ||
955 | let mut writer = LineWriter::with_capacity(10, writer); | |
956 | ||
957 | let content = b"AAAAABBBBB\nCCCCDDDDDD\nEEE"; | |
958 | ||
959 | // When content is written, LineWriter will try to write blocks A, B, | |
960 | // C, and D. Only block A will succeed. Under the old behavior, LineWriter | |
961 | // would then try to buffer B, C and D, but because its capacity is 10, | |
962 | // it will only be able to buffer B and C. We don't want to buffer | |
963 | // partial lines concurrent with whole lines, so the correct behavior | |
964 | // is to buffer only block B (out to the newline) | |
965 | assert_eq!(writer.write(content).unwrap(), 11); | |
966 | assert_eq!(writer.get_ref().buffer, *b"AAAAA"); | |
967 | ||
968 | writer.flush().unwrap(); | |
969 | assert_eq!(writer.get_ref().buffer, *b"AAAAABBBBB\n"); | |
970 | } | |
971 | ||
972 | /// Same as test_partial_multiline_buffering, but in the event NO full lines | |
973 | /// fit in the buffer, just buffer as much as possible | |
974 | #[test] | |
975 | fn partial_multiline_buffering_without_full_line() { | |
976 | let writer = ProgrammableSink { | |
977 | // Write only up to 5 bytes at a time | |
978 | accept_prefix: Some(5), | |
979 | ..Default::default() | |
980 | }; | |
981 | ||
982 | let mut writer = LineWriter::with_capacity(5, writer); | |
983 | ||
984 | let content = b"AAAAABBBBBBBBBB\nCCCCC\nDDDDD"; | |
985 | ||
986 | // When content is written, LineWriter will try to write blocks A, B, | |
987 | // and C. Only block A will succeed. Under the old behavior, LineWriter | |
988 | // would then try to buffer B and C, but because its capacity is 5, | |
989 | // it will only be able to buffer part of B. Because it's not possible | |
990 | // for it to buffer any complete lines, it should buffer as much of B as | |
991 | // possible | |
992 | assert_eq!(writer.write(content).unwrap(), 10); | |
993 | assert_eq!(writer.get_ref().buffer, *b"AAAAA"); | |
994 | ||
995 | writer.flush().unwrap(); | |
996 | assert_eq!(writer.get_ref().buffer, *b"AAAAABBBBB"); | |
997 | } | |
998 | ||
999 | #[derive(Debug, Clone, PartialEq, Eq)] | |
1000 | enum RecordedEvent { | |
1001 | Write(String), | |
1002 | Flush, | |
1003 | } | |
1004 | ||
1005 | #[derive(Debug, Clone, Default)] | |
1006 | struct WriteRecorder { | |
1007 | pub events: Vec<RecordedEvent>, | |
1008 | } | |
1009 | ||
1010 | impl Write for WriteRecorder { | |
1011 | fn write(&mut self, buf: &[u8]) -> io::Result<usize> { | |
1012 | use crate::str::from_utf8; | |
1013 | ||
1014 | self.events.push(RecordedEvent::Write(from_utf8(buf).unwrap().to_string())); | |
1015 | Ok(buf.len()) | |
1016 | } | |
1017 | ||
1018 | fn flush(&mut self) -> io::Result<()> { | |
1019 | self.events.push(RecordedEvent::Flush); | |
1020 | Ok(()) | |
1021 | } | |
1022 | } | |
1023 | ||
1024 | /// Test that a normal, formatted writeln only results in a single write | |
1025 | /// call to the underlying writer. A naive implementation of | |
1026 | /// LineWriter::write_all results in two writes: one of the buffered data, | |
1027 | /// and another of the final substring in the formatted set | |
1028 | #[test] | |
1029 | fn single_formatted_write() { | |
1030 | let writer = WriteRecorder::default(); | |
1031 | let mut writer = LineWriter::new(writer); | |
1032 | ||
1033 | // Under a naive implementation of LineWriter, this will result in two | |
1034 | // writes: "hello, world" and "!\n", because write() has to flush the | |
1035 | // buffer before attempting to write the last "!\n". write_all shouldn't | |
1036 | // have this limitation. | |
1037 | writeln!(&mut writer, "{}, {}!", "hello", "world").unwrap(); | |
1038 | assert_eq!(writer.get_ref().events, [RecordedEvent::Write("hello, world!\n".to_string())]); | |
1039 | } |