Skip to content
This repository was archived by the owner on Nov 24, 2023. It is now read-only.

Commit 74df290

Browse files
committed
Rustfix edition testing setup
Also refactors the test setup to finally run as many tests as possible and give useful errors.
1 parent c74cb4b commit 74df290

File tree

2 files changed

+139
-64
lines changed

2 files changed

+139
-64
lines changed

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ failure = "0.1.1"
2626
duct = "0.8.2"
2727
env_logger = "0.5.0-rc.1"
2828
log = "0.4.1"
29-
pretty_assertions = "0.4.1"
3029
tempdir = "0.3.5"
3130
proptest = "0.7.0"
31+
difference = "2.0.0"
3232

3333
[workspace]
3434
members = [

tests/parse_and_replace.rs

+138-63
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,61 @@
11
#![cfg(not(windows))] // TODO: should fix these tests on Windows
22

3-
#[macro_use]
43
extern crate duct;
54
extern crate env_logger;
65
#[macro_use]
76
extern crate log;
8-
#[macro_use]
9-
extern crate pretty_assertions;
107
extern crate rustfix;
118
extern crate serde_json;
129
extern crate tempdir;
10+
#[macro_use]
11+
extern crate failure;
12+
extern crate difference;
1313

14+
use std::ffi::OsString;
1415
use std::{env, fs};
15-
use std::error::Error;
1616
use std::path::{Path, PathBuf};
1717
use std::collections::HashSet;
1818
use std::process::Output;
19+
20+
use failure::{Error, ResultExt};
1921
use tempdir::TempDir;
2022

2123
use rustfix::apply_suggestions;
2224

23-
fn compile(file: &Path) -> Result<Output, Box<Error>> {
25+
mod fixmode {
26+
pub const EVERYTHING: &str = "yolo";
27+
pub const EDITION: &str = "edition";
28+
}
29+
30+
mod settings {
31+
// can be set as env var to debug
32+
pub const CHECK_JSON: &str = "RUSTFIX_TEST_CHECK_JSON";
33+
pub const RECORD_JSON: &str = "RUSTFIX_TEST_RECORD_JSON";
34+
pub const RECORD_FIXED_RUST: &str = "RUSTFIX_TEST_RECORD_FIXED_RUST";
35+
36+
// set automatically
37+
pub const MODE: &str = "RUSTFIX_MODE";
38+
}
39+
40+
fn compile(file: &Path, mode: &str) -> Result<Output, Error> {
2441
let tmp = TempDir::new("rustfix-tests")?;
25-
let better_call_clippy = cmd!(
26-
"rustc",
27-
file,
28-
"--error-format=pretty-json",
29-
"-Zunstable-options",
30-
"--emit=metadata",
31-
"--crate-name=rustfix_test",
32-
"-Zsuggestion-applicability",
33-
"--out-dir",
34-
tmp.path()
35-
);
36-
let res = better_call_clippy
42+
43+
let mut args: Vec<OsString> = vec![
44+
file.into(),
45+
"--error-format=pretty-json".into(),
46+
"-Zunstable-options".into(),
47+
"--emit=metadata".into(),
48+
"--crate-name=rustfix_test".into(),
49+
"-Zsuggestion-applicability".into(),
50+
"--out-dir".into(),
51+
tmp.path().into(),
52+
];
53+
54+
if mode == fixmode::EDITION {
55+
args.push("--edition=2018".into());
56+
}
57+
58+
let res = duct::cmd("rustc", &args)
3759
.env("CLIPPY_DISABLE_DOCS_LINKS", "true")
3860
.stdout_capture()
3961
.stderr_capture()
@@ -43,24 +65,19 @@ fn compile(file: &Path) -> Result<Output, Box<Error>> {
4365
Ok(res)
4466
}
4567

46-
fn compile_and_get_json_errors(file: &Path) -> Result<String, Box<Error>> {
47-
let res = compile(file)?;
68+
fn compile_and_get_json_errors(file: &Path, mode: &str) -> Result<String, Error> {
69+
let res = compile(file, mode)?;
4870
let stderr = String::from_utf8(res.stderr)?;
4971

50-
use std::io::{Error, ErrorKind};
5172
match res.status.code() {
5273
Some(0) | Some(1) | Some(101) => Ok(stderr),
53-
_ => Err(Box::new(Error::new(
54-
ErrorKind::Other,
55-
format!("failed with status {:?}: {}", res.status.code(), stderr),
56-
))),
74+
_ => Err(format_err!("failed with status {:?}: {}", res.status.code(), stderr)),
5775
}
5876
}
5977

60-
fn compiles_without_errors(file: &Path) -> Result<(), Box<Error>> {
61-
let res = compile(file)?;
78+
fn compiles_without_errors(file: &Path, mode: &str) -> Result<(), Error> {
79+
let res = compile(file, mode)?;
6280

63-
use std::io::{Error, ErrorKind};
6481
match res.status.code() {
6582
Some(0) => Ok(()),
6683
_ => {
@@ -69,18 +86,15 @@ fn compiles_without_errors(file: &Path) -> Result<(), Box<Error>> {
6986
file,
7087
String::from_utf8(res.stderr)?
7188
);
72-
Err(Box::new(Error::new(
73-
ErrorKind::Other,
74-
format!(
75-
"failed with status {:?} (`env RUST_LOG=everything=info` for more info)",
76-
res.status.code(),
77-
),
78-
)))
89+
Err(format_err!(
90+
"failed with status {:?} (`env RUST_LOG=parse_and_replace=info` for more info)",
91+
res.status.code(),
92+
))
7993
}
8094
}
8195
}
8296

83-
fn read_file(path: &Path) -> Result<String, Box<Error>> {
97+
fn read_file(path: &Path) -> Result<String, Error> {
8498
use std::io::Read;
8599

86100
let mut buffer = String::new();
@@ -89,53 +103,90 @@ fn read_file(path: &Path) -> Result<String, Box<Error>> {
89103
Ok(buffer)
90104
}
91105

92-
fn test_rustfix_with_file<P: AsRef<Path>>(file: P) -> Result<(), Box<Error>> {
106+
fn diff(expected: &str, actual: &str) -> String {
107+
use std::fmt::Write;
108+
use difference::{Changeset, Difference};
109+
110+
let mut res = String::new();
111+
let changeset = Changeset::new(expected.trim(), actual.trim(), "\n");
112+
113+
let mut different = false;
114+
for diff in changeset.diffs {
115+
let (prefix, diff) = match diff {
116+
Difference::Same(_) => continue,
117+
Difference::Add(add) => ("+", add),
118+
Difference::Rem(rem) => ("-", rem),
119+
};
120+
if !different {
121+
write!(&mut res, "differences found (+ == actual, - == expected):\n");
122+
different = true;
123+
}
124+
for diff in diff.lines() {
125+
writeln!(&mut res, "{} {}", prefix, diff);
126+
}
127+
}
128+
if different {
129+
write!(&mut res, "");
130+
}
131+
132+
res
133+
}
134+
135+
fn test_rustfix_with_file<P: AsRef<Path>>(file: P, mode: &str) -> Result<(), Error> {
93136
let file: &Path = file.as_ref();
94137
let json_file = file.with_extension("json");
95138
let fixed_file = file.with_extension("fixed.rs");
96139

97140
debug!("next up: {:?}", file);
98-
let code = read_file(file)?;
99-
let errors = compile_and_get_json_errors(file)?;
141+
let code = read_file(file)
142+
.context(format!("could not read {}", file.display()))?;
143+
let errors = compile_and_get_json_errors(file, mode)
144+
.context(format!("could compile {}", file.display()))?;
100145
let suggestions = rustfix::get_suggestions_from_json(&errors, &HashSet::new())
101-
.expect("could not load suggestions");
146+
.context("could not load suggestions")?;
102147

103-
if std::env::var("RUSTFIX_TEST_RECORD_JSON").is_ok() {
148+
if std::env::var(settings::RECORD_JSON).is_ok() {
104149
use std::io::Write;
105-
let mut recorded_json = fs::File::create(&file.with_extension("recorded.json"))?;
150+
let mut recorded_json = fs::File::create(&file.with_extension("recorded.json"))
151+
.context(format!("could not create recorded.json for {}", file.display()))?;
106152
recorded_json.write_all(errors.as_bytes())?;
107153
}
108154

109-
let expected_json = read_file(&json_file)?;
110-
let expected_suggestions = rustfix::get_suggestions_from_json(&expected_json, &HashSet::new())
111-
.expect("could not load expected suggesitons");
112-
assert_eq!(
113-
expected_suggestions, suggestions,
114-
"got unexpected suggestions from clippy",
115-
);
155+
if std::env::var(settings::CHECK_JSON).is_ok() {
156+
let expected_json = read_file(&json_file)
157+
.context(format!("could not load json fixtures for {}", file.display()))?;;
158+
let expected_suggestions = rustfix::get_suggestions_from_json(&expected_json, &HashSet::new())
159+
.context("could not load expected suggesitons")?;
160+
161+
ensure!(
162+
expected_suggestions == suggestions,
163+
"got unexpected suggestions from clippy:\n{}",
164+
diff(&format!("{:?}", expected_suggestions), &format!("{:?}", suggestions))
165+
);
166+
}
116167

117-
let fixed = apply_suggestions(&code, &suggestions)?;
168+
let fixed = apply_suggestions(&code, &suggestions)
169+
.context(format!("could not apply suggestions to {}", file.display()))?;
118170

119-
if std::env::var("RUSTFIX_TEST_RECORD_FIXED_RUST").is_ok() {
171+
if std::env::var(settings::RECORD_FIXED_RUST).is_ok() {
120172
use std::io::Write;
121173
let mut recorded_rust = fs::File::create(&file.with_extension("recorded.rs"))?;
122174
recorded_rust.write_all(fixed.as_bytes())?;
123175
}
124176

125-
let expected_fixed = read_file(&fixed_file)?;
126-
assert_eq!(
127-
fixed.trim(),
128-
expected_fixed.trim(),
129-
"file {} doesn't look fixed",
130-
file.display()
177+
let expected_fixed = read_file(&fixed_file)
178+
.context(format!("could read fixed file for {}", file.display()))?;
179+
ensure!(
180+
fixed.trim() == expected_fixed.trim(),
181+
"file {} doesn't look fixed:\n{}", file.display(), diff(fixed.trim(), expected_fixed.trim())
131182
);
132183

133-
compiles_without_errors(&fixed_file)?;
184+
compiles_without_errors(&fixed_file, mode)?;
134185

135186
Ok(())
136187
}
137188

138-
fn get_fixture_files(p: &str) -> Result<Vec<PathBuf>, Box<Error>> {
189+
fn get_fixture_files(p: &str) -> Result<Vec<PathBuf>, Error> {
139190
Ok(fs::read_dir(&p)?
140191
.into_iter()
141192
.map(|e| e.unwrap().path())
@@ -148,16 +199,40 @@ fn get_fixture_files(p: &str) -> Result<Vec<PathBuf>, Box<Error>> {
148199
}
149200

150201
fn assert_fixtures(dir: &str, mode: &str) {
151-
for file in &get_fixture_files(&dir).unwrap() {
152-
env::set_var("RUSTFIX_MODE", mode);
153-
test_rustfix_with_file(file).unwrap();
154-
env::remove_var("RUSTFIX_MODE")
202+
let files = get_fixture_files(&dir)
203+
.context(format!("couldn't load dir `{}`", dir))
204+
.unwrap();
205+
let mut failures = 0;
206+
207+
for file in &files {
208+
if let Err(err) = test_rustfix_with_file(file, mode) {
209+
println!("failed: {}", file.display());
210+
warn!("{}", err);
211+
for cause in err.causes().skip(1) {
212+
info!("\tcaused by: {}", cause);
213+
}
214+
failures += 1;
215+
}
155216
info!("passed: {:?}", file);
156217
}
218+
219+
if failures > 0 {
220+
panic!(
221+
"{} out of {} fixture asserts failed\n\
222+
(run with `env RUST_LOG=parse_and_replace=info` to get more details)",
223+
failures, files.len(),
224+
);
225+
}
157226
}
158227

159228
#[test]
160229
fn everything() {
161230
let _ = env_logger::try_init();
162-
assert_fixtures("./tests/everything", "yolo");
231+
assert_fixtures("./tests/everything", fixmode::EVERYTHING);
232+
}
233+
234+
#[test]
235+
fn edition() {
236+
let _ = env_logger::try_init();
237+
assert_fixtures("./tests/edition", fixmode::EDITION);
163238
}

0 commit comments

Comments
 (0)