Skip to content

Commit c3ca2dd

Browse files
committed
fix(assert): Change set_stdin to clarify intent
While the documentation for `set_stdin` and `with_stdin` is clear, we can't expect everyone to read the documentation closely. This attempts to make the API harder to misuse so users can be more successful. BREAKING CHANGE: `Assert::set_cmd` and `Assert::set_stdin` have been replaced with `Assert::append_context`. Fixes assert-rs#29
1 parent b6e0f7e commit c3ca2dd

File tree

4 files changed

+63
-44
lines changed

4 files changed

+63
-44
lines changed

src/assert.rs

+20-25
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use std::str;
77
use predicates;
88
use predicates::str::PredicateStrExt;
99

10-
use cmd::dump_buffer;
10+
use errors::dump_buffer;
1111
use errors::output_fmt;
1212

1313
/// Assert the state of an `Output`.
@@ -51,7 +51,7 @@ impl OutputAssertExt for process::Output {
5151
impl<'c> OutputAssertExt for &'c mut process::Command {
5252
fn assert(self) -> Assert {
5353
let output = self.output().unwrap();
54-
Assert::new(output).set_cmd(format!("{:?}", self))
54+
Assert::new(output).append_context("command", format!("{:?}", self))
5555
}
5656
}
5757

@@ -71,32 +71,26 @@ impl<'c> OutputAssertExt for &'c mut process::Command {
7171
/// .assert()
7272
/// .success();
7373
/// ```
74-
#[derive(Debug)]
7574
pub struct Assert {
7675
output: process::Output,
77-
cmd: Option<String>,
78-
stdin: Option<Vec<u8>>,
76+
context: Vec<(&'static str, Box<fmt::Display>)>,
7977
}
8078

8179
impl Assert {
8280
/// Create an `Assert` for a given `Output`.
8381
pub fn new(output: process::Output) -> Self {
8482
Self {
8583
output,
86-
cmd: None,
87-
stdin: None,
84+
context: vec![],
8885
}
8986
}
9087

91-
/// Add the command line for additional context.
92-
pub fn set_cmd(mut self, cmd: String) -> Self {
93-
self.cmd = Some(cmd);
94-
self
95-
}
96-
97-
/// Add the `stdn` for additional context.
98-
pub fn set_stdin(mut self, stdin: Vec<u8>) -> Self {
99-
self.stdin = Some(stdin);
88+
/// Clarify failures with additional context.
89+
pub fn append_context<D>(mut self, name: &'static str, context: D) -> Self
90+
where
91+
D: fmt::Display + 'static,
92+
{
93+
self.context.push((name, Box::new(context)));
10094
self
10195
}
10296

@@ -298,20 +292,21 @@ impl Assert {
298292

299293
impl fmt::Display for Assert {
300294
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
301-
if let Some(ref cmd) = self.cmd {
302-
writeln!(f, "command=`{}`", cmd)?;
303-
}
304-
if let Some(ref stdin) = self.stdin {
305-
if let Ok(stdin) = str::from_utf8(stdin) {
306-
writeln!(f, "stdin=```{}```", stdin)?;
307-
} else {
308-
writeln!(f, "stdin=```{:?}```", stdin)?;
309-
}
295+
for (name, context) in &self.context {
296+
writeln!(f, "{}=`{}`", name, context)?;
310297
}
311298
output_fmt(&self.output, f)
312299
}
313300
}
314301

302+
impl fmt::Debug for Assert {
303+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
304+
f.debug_struct("Assert")
305+
.field("output", &self.output)
306+
.finish()
307+
}
308+
}
309+
315310
/// Used by `Assert::code` to convert `Self` into the needed `Predicate<i32>`.
316311
///
317312
/// # Examples

src/cmd.rs

+1-9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::process;
2-
use std::str;
32

3+
use errors::dump_buffer;
44
use errors::OutputError;
55
use errors::OutputResult;
66

@@ -116,11 +116,3 @@ impl<'c> OutputOkExt for &'c mut process::Command {
116116
}
117117
}
118118
}
119-
120-
pub(crate) fn dump_buffer(buffer: &[u8]) -> String {
121-
if let Ok(buffer) = str::from_utf8(buffer) {
122-
buffer.to_string()
123-
} else {
124-
format!("{:?}", buffer)
125-
}
126-
}

src/errors.rs

+38-7
Original file line numberDiff line numberDiff line change
@@ -162,16 +162,47 @@ pub(crate) fn output_fmt(output: &process::Output, f: &mut fmt::Formatter) -> fm
162162
} else {
163163
writeln!(f, "code=<interrupted>")?;
164164
}
165-
if let Ok(stdout) = str::from_utf8(&output.stdout) {
166-
writeln!(f, "stdout=```{}```", stdout)?;
165+
166+
write!(f, "stdout=```")?;
167+
write_buffer(&output.stdout, f)?;
168+
writeln!(f, "```")?;
169+
170+
write!(f, "stderr=```")?;
171+
write_buffer(&output.stderr, f)?;
172+
writeln!(f, "```")?;
173+
174+
Ok(())
175+
}
176+
177+
pub(crate) fn dump_buffer(buffer: &[u8]) -> String {
178+
if let Ok(buffer) = str::from_utf8(buffer) {
179+
buffer.to_string()
167180
} else {
168-
writeln!(f, "stdout=```{:?}```", output.stdout)?;
181+
format!("{:?}", buffer)
169182
}
170-
if let Ok(stderr) = str::from_utf8(&output.stderr) {
171-
writeln!(f, "stderr=```{}```", stderr)?;
183+
}
184+
185+
pub(crate) fn write_buffer(buffer: &[u8], f: &mut fmt::Formatter) -> fmt::Result {
186+
if let Ok(buffer) = str::from_utf8(buffer) {
187+
write!(f, "{}", buffer)
172188
} else {
173-
writeln!(f, "stderr=```{:?}```", output.stderr)?;
189+
write!(f, "{:?}", buffer)
190+
}
191+
}
192+
193+
#[derive(Debug)]
194+
pub(crate) struct DebugBuffer {
195+
buffer: Vec<u8>,
196+
}
197+
198+
impl DebugBuffer {
199+
pub(crate) fn new(buffer: Vec<u8>) -> Self {
200+
DebugBuffer { buffer }
174201
}
202+
}
175203

176-
Ok(())
204+
impl fmt::Display for DebugBuffer {
205+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
206+
write_buffer(&self.buffer, f)
207+
}
177208
}

src/stdin.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ use std::process;
77

88
use assert::Assert;
99
use assert::OutputAssertExt;
10-
use cmd::dump_buffer;
1110
use cmd::OutputOkExt;
11+
use errors::dump_buffer;
12+
use errors::DebugBuffer;
1213
use errors::OutputError;
1314
use errors::OutputResult;
1415

@@ -189,7 +190,7 @@ impl<'c> OutputAssertExt for &'c mut StdInCommand<'c> {
189190
fn assert(self) -> Assert {
190191
let output = self.output().unwrap();
191192
Assert::new(output)
192-
.set_cmd(format!("{:?}", self.cmd))
193-
.set_stdin(self.stdin.clone())
193+
.append_context("command", format!("{:?}", self.cmd))
194+
.append_context("stdin", DebugBuffer::new(self.stdin.clone()))
194195
}
195196
}

0 commit comments

Comments
 (0)