Skip to content

Commit bf2739b

Browse files
committed
Run rustfmt on the test actual output and expectations
1 parent 187920d commit bf2739b

File tree

3 files changed

+109
-9
lines changed

3 files changed

+109
-9
lines changed

tests/rustfmt.toml

Whitespace-only changes.

tests/test-one.sh

+4
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ eval ./target/debug/bindgen \
5656
-o "\"$BINDINGS\"" \
5757
$FLAGS
5858

59+
rustup run nightly rustfmt "$BINDINGS" || true
60+
5961
dot -Tpng ir.dot -o ir.png
6062

6163
echo
@@ -78,6 +80,8 @@ EXPECTED=${TEST/headers/expectations\/tests}
7880
EXPECTED=${EXPECTED/.hpp/.rs}
7981
EXPECTED=${EXPECTED/.h/.rs}
8082

83+
rustup run nightly rustfmt "$EXPECTED" || true
84+
8185
# Don't exit early if there is a diff.
8286
diff -U8 "$EXPECTED" "$BINDINGS" || true
8387

tests/tests.rs

+105-9
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,110 @@ extern crate shlex;
55

66
use bindgen::{Builder, builder, clang_version};
77
use std::fs;
8-
use std::io::{BufRead, BufReader, Error, ErrorKind, Read, Write};
8+
use std::io::{self, BufRead, BufReader, Error, ErrorKind, Read, Write};
99
use std::path::PathBuf;
10+
use std::process;
11+
use std::sync::{Once, ONCE_INIT};
1012

1113
#[path = "../src/options.rs"]
1214
mod options;
1315
use options::builder_from_flags;
1416

17+
// Run `rustfmt` on the given source string and return a tuple of the formatted
18+
// bindings, and rustfmt's stderr.
19+
fn rustfmt(source: String) -> (String, String) {
20+
static INSTALL_RUSTFMT: Once = ONCE_INIT;
21+
22+
INSTALL_RUSTFMT.call_once(|| {
23+
let have_working_rustfmt = process::Command::new("rustup")
24+
.args(&["run", "nightly", "rustfmt", "--version"])
25+
.stdout(process::Stdio::null())
26+
.stderr(process::Stdio::null())
27+
.status()
28+
.expect("should run `rustup run nightly rustfmt --version` OK")
29+
.success();
30+
31+
if have_working_rustfmt {
32+
return;
33+
}
34+
35+
// Because `rustfmt` needs to match its exact nightly version, we update
36+
// both at the same time.
37+
38+
let status = process::Command::new("rustup")
39+
.args(&["update", "nightly"])
40+
.status()
41+
.expect("should run `rustup update nightly` OK");
42+
assert!(status.success(), "should run `rustup update nightly` OK");
43+
44+
let status = process::Command::new("rustup")
45+
.args(&["run", "nightly", "cargo", "install", "-f", "rustfmt-nightly"])
46+
.status()
47+
.expect("should run `rustup run nightly cargo install rustfmt-nightly` OK");
48+
assert!(status.success(), "should install rustfmt OK");
49+
});
50+
51+
let mut child = process::Command::new("rustup")
52+
.args(&[
53+
"run",
54+
"nightly",
55+
"rustfmt",
56+
"--config-path",
57+
concat!(env!("CARGO_MANIFEST_DIR"), "/tests/rustfmt.toml")
58+
])
59+
.stdin(process::Stdio::piped())
60+
.stdout(process::Stdio::piped())
61+
.stderr(process::Stdio::piped())
62+
.spawn()
63+
.expect("should spawn `rustup run nightly rustfmt`");
64+
65+
let mut stdin = child.stdin.take().unwrap();
66+
let mut stdout = child.stdout.take().unwrap();
67+
let mut stderr = child.stderr.take().unwrap();
68+
69+
// Write to stdin in a new thread, so that we can read from stdout on this
70+
// thread. This keeps the child from blocking on writing to its stdout which
71+
// might block us from writing to its stdin.
72+
let stdin_handle = ::std::thread::spawn(move || {
73+
stdin.write_all(source.as_bytes())
74+
});
75+
76+
// Read stderr on a new thread for similar reasons.
77+
let stderr_handle = ::std::thread::spawn(move || {
78+
let mut output = vec![];
79+
io::copy(&mut stderr, &mut output)
80+
.map(|_| String::from_utf8_lossy(&output).to_string())
81+
});
82+
83+
let mut output = vec![];
84+
io::copy(&mut stdout, &mut output)
85+
.expect("Should copy stdout into vec OK");
86+
87+
// Ignore actual rustfmt status because it is often non-zero for trivial
88+
// things.
89+
let _ = child.wait().expect("should wait on rustfmt child OK");
90+
91+
stdin_handle.join()
92+
.expect("writer thread should not have panicked")
93+
.expect("should have written to child rustfmt's stdin OK");
94+
95+
let bindings = String::from_utf8(output)
96+
.expect("rustfmt should only emit valid utf-8");
97+
98+
let stderr = stderr_handle.join()
99+
.expect("stderr reader thread should not have panicked")
100+
.expect("should have read child rustfmt's stderr OK");
101+
102+
(bindings, stderr)
103+
}
104+
15105
fn compare_generated_header(
16106
header: &PathBuf,
17107
builder: Builder,
18108
) -> Result<(), Error> {
19109
let file_name = try!(header.file_name().ok_or(Error::new(
20110
ErrorKind::Other,
21-
"spawn_bindgen expects a file",
111+
"compare_generated_header expects a file",
22112
)));
23113

24114
let mut expected = PathBuf::from(header);
@@ -69,9 +159,12 @@ fn compare_generated_header(
69159
}
70160

71161
// We skip the generate() error here so we get a full diff below
72-
let output = match builder.generate() {
73-
Ok(bindings) => bindings.to_string(),
74-
Err(_) => "".to_string(),
162+
let (bindings, rustfmt_stderr) = match builder.generate() {
163+
Ok(bindings) => {
164+
let bindings = bindings.to_string();
165+
rustfmt(bindings)
166+
}
167+
Err(()) => ("<error generating bindings>".to_string(), "".to_string()),
75168
};
76169

77170
let mut buffer = String::new();
@@ -80,9 +173,10 @@ fn compare_generated_header(
80173
try!(BufReader::new(expected_file).read_to_string(&mut buffer));
81174
}
82175
}
176+
let (buffer, _) = rustfmt(buffer);
83177

84-
if output == buffer {
85-
if !output.is_empty() {
178+
if bindings == buffer {
179+
if !bindings.is_empty() {
86180
return Ok(());
87181
}
88182
return Err(Error::new(
@@ -91,11 +185,13 @@ fn compare_generated_header(
91185
));
92186
}
93187

188+
println!("{}", rustfmt_stderr);
189+
94190
println!("diff expected generated");
95191
println!("--- expected: {:?}", expected);
96192
println!("+++ generated from: {:?}", header);
97193

98-
for diff in diff::lines(&buffer, &output) {
194+
for diff in diff::lines(&buffer, &bindings) {
99195
match diff {
100196
diff::Result::Left(l) => println!("-{}", l),
101197
diff::Result::Both(l, _) => println!(" {}", l),
@@ -106,7 +202,7 @@ fn compare_generated_header(
106202
// Override the diff.
107203
{
108204
let mut expected_file = try!(fs::File::create(&expected));
109-
try!(expected_file.write_all(output.as_bytes()));
205+
try!(expected_file.write_all(bindings.as_bytes()));
110206
}
111207

112208
Err(Error::new(ErrorKind::Other, "Header and binding differ!"))

0 commit comments

Comments
 (0)