1
1
#![ cfg( not( windows) ) ] // TODO: should fix these tests on Windows
2
2
3
- #[ macro_use]
4
3
extern crate duct;
5
4
extern crate env_logger;
6
5
#[ macro_use]
7
6
extern crate log;
8
- #[ macro_use]
9
- extern crate pretty_assertions;
10
7
extern crate rustfix;
11
8
extern crate serde_json;
12
9
extern crate tempdir;
10
+ #[ macro_use]
11
+ extern crate failure;
12
+ extern crate difference;
13
13
14
+ use std:: ffi:: OsString ;
14
15
use std:: { env, fs} ;
15
- use std:: error:: Error ;
16
16
use std:: path:: { Path , PathBuf } ;
17
17
use std:: collections:: HashSet ;
18
18
use std:: process:: Output ;
19
+
20
+ use failure:: { Error , ResultExt } ;
19
21
use tempdir:: TempDir ;
20
22
21
23
use rustfix:: apply_suggestions;
22
24
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 > {
24
41
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)
37
59
. env ( "CLIPPY_DISABLE_DOCS_LINKS" , "true" )
38
60
. stdout_capture ( )
39
61
. stderr_capture ( )
@@ -43,24 +65,19 @@ fn compile(file: &Path) -> Result<Output, Box<Error>> {
43
65
Ok ( res)
44
66
}
45
67
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 ) ?;
48
70
let stderr = String :: from_utf8 ( res. stderr ) ?;
49
71
50
- use std:: io:: { Error , ErrorKind } ;
51
72
match res. status . code ( ) {
52
73
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) ) ,
57
75
}
58
76
}
59
77
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 ) ?;
62
80
63
- use std:: io:: { Error , ErrorKind } ;
64
81
match res. status . code ( ) {
65
82
Some ( 0 ) => Ok ( ( ) ) ,
66
83
_ => {
@@ -69,18 +86,15 @@ fn compiles_without_errors(file: &Path) -> Result<(), Box<Error>> {
69
86
file,
70
87
String :: from_utf8( res. stderr) ?
71
88
) ;
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
+ ) )
79
93
}
80
94
}
81
95
}
82
96
83
- fn read_file ( path : & Path ) -> Result < String , Box < Error > > {
97
+ fn read_file ( path : & Path ) -> Result < String , Error > {
84
98
use std:: io:: Read ;
85
99
86
100
let mut buffer = String :: new ( ) ;
@@ -89,53 +103,90 @@ fn read_file(path: &Path) -> Result<String, Box<Error>> {
89
103
Ok ( buffer)
90
104
}
91
105
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 > {
93
136
let file: & Path = file. as_ref ( ) ;
94
137
let json_file = file. with_extension ( "json" ) ;
95
138
let fixed_file = file. with_extension ( "fixed.rs" ) ;
96
139
97
140
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( ) ) ) ?;
100
145
let suggestions = rustfix:: get_suggestions_from_json ( & errors, & HashSet :: new ( ) )
101
- . expect ( "could not load suggestions" ) ;
146
+ . context ( "could not load suggestions" ) ? ;
102
147
103
- if std:: env:: var ( "RUSTFIX_TEST_RECORD_JSON" ) . is_ok ( ) {
148
+ if std:: env:: var ( settings :: RECORD_JSON ) . is_ok ( ) {
104
149
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( ) ) ) ?;
106
152
recorded_json. write_all ( errors. as_bytes ( ) ) ?;
107
153
}
108
154
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
+ }
116
167
117
- let fixed = apply_suggestions ( & code, & suggestions) ?;
168
+ let fixed = apply_suggestions ( & code, & suggestions)
169
+ . context ( format ! ( "could not apply suggestions to {}" , file. display( ) ) ) ?;
118
170
119
- if std:: env:: var ( "RUSTFIX_TEST_RECORD_FIXED_RUST" ) . is_ok ( ) {
171
+ if std:: env:: var ( settings :: RECORD_FIXED_RUST ) . is_ok ( ) {
120
172
use std:: io:: Write ;
121
173
let mut recorded_rust = fs:: File :: create ( & file. with_extension ( "recorded.rs" ) ) ?;
122
174
recorded_rust. write_all ( fixed. as_bytes ( ) ) ?;
123
175
}
124
176
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( ) )
131
182
) ;
132
183
133
- compiles_without_errors ( & fixed_file) ?;
184
+ compiles_without_errors ( & fixed_file, mode ) ?;
134
185
135
186
Ok ( ( ) )
136
187
}
137
188
138
- fn get_fixture_files ( p : & str ) -> Result < Vec < PathBuf > , Box < Error > > {
189
+ fn get_fixture_files ( p : & str ) -> Result < Vec < PathBuf > , Error > {
139
190
Ok ( fs:: read_dir ( & p) ?
140
191
. into_iter ( )
141
192
. map ( |e| e. unwrap ( ) . path ( ) )
@@ -148,16 +199,40 @@ fn get_fixture_files(p: &str) -> Result<Vec<PathBuf>, Box<Error>> {
148
199
}
149
200
150
201
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 ! ( "\t caused by: {}" , cause) ;
213
+ }
214
+ failures += 1 ;
215
+ }
155
216
info ! ( "passed: {:?}" , file) ;
156
217
}
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
+ }
157
226
}
158
227
159
228
#[ test]
160
229
fn everything ( ) {
161
230
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 ) ;
163
238
}
0 commit comments