Skip to content

Commit 8e6c085

Browse files
committed
paasio: Prevent non-unwinding panic in tests
Related forum post: https://forum.exercism.org/t/test-runner-fail-on-paas/19426
1 parent 7967fa3 commit 8e6c085

File tree

1 file changed

+30
-2
lines changed

1 file changed

+30
-2
lines changed

exercises/practice/paasio/tests/paasio.rs

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,21 @@ mod write_string {
136136
fn sink_buffered_windowed() {
137137
let data = INPUT;
138138
let size = data.len();
139-
let mut writer = BufWriter::new(WriteStats::new(io::sink()));
139+
140+
// We store the inner writer in a separate variable so its
141+
// destructor is called correctly. We then wrap a mutable
142+
// reference to it in a buffered writer. The destructor of the
143+
// buffered writer is suppressed, because it tries to flush the
144+
// inner writer. (It doesn't do anything else, so it's fine to
145+
// skip it.) This would cause a non-unwinding panic if the inner
146+
// writer hasn't implemented `write` yet. The standard library
147+
// implementation of `BufWriter` does try to keep track of a
148+
// panic by the inner writer, but it's not perfect. We access
149+
// the inner writer later with `.get_ref()`. If there is a panic
150+
// in that situation, the buffered writer cannot observe and
151+
// track it.
152+
let mut inner_writer = WriteStats::new(io::sink());
153+
let mut writer = std::mem::ManuallyDrop::new(BufWriter::new(&mut inner_writer));
140154

141155
for chunk in data.chunks(CHUNK_SIZE) {
142156
let written = writer.write(chunk);
@@ -286,7 +300,21 @@ mod write_byte_literal {
286300
fn sink_buffered_windowed() {
287301
let data = INPUT;
288302
let size = data.len();
289-
let mut writer = BufWriter::new(WriteStats::new(io::sink()));
303+
304+
// We store the inner writer in a separate variable so its
305+
// destructor is called correctly. We then wrap a mutable
306+
// reference to it in a buffered writer. The destructor of the
307+
// buffered writer is suppressed, because it tries to flush the
308+
// inner writer. (It doesn't do anything else, so it's fine to
309+
// skip it.) This would cause a non-unwinding panic if the inner
310+
// writer hasn't implemented `write` yet. The standard library
311+
// implementation of `BufWriter` does try to keep track of a
312+
// panic by the inner writer, but it's not perfect. We access
313+
// the inner writer later with `.get_ref()`. If there is a panic
314+
// in that situation, the buffered writer cannot observe and
315+
// track it.
316+
let mut inner_writer = WriteStats::new(io::sink());
317+
let mut writer = std::mem::ManuallyDrop::new(BufWriter::new(&mut inner_writer));
290318

291319
for chunk in data.chunks(CHUNK_SIZE) {
292320
let written = writer.write(chunk);

0 commit comments

Comments
 (0)