66//! rustfix and applies the recommended suggestions to the `.rs` file. It then
77//! compares the result with the corresponding `.fixed.rs` file. If they don't
88//! match, then the test fails.
9- //!
10- //! There are several debugging environment variables for this test that you can set:
11- //!
12- //! - `RUST_LOG=parse_and_replace=debug`: Print debug information.
13- //! - `RUSTFIX_TEST_BLESS=test-name.rs`: When given the name of a test, this
14- //! will overwrite the `.json` and `.fixed.rs` files with the expected
15- //! values. This can be used when adding a new test.
16- //! - `RUSTFIX_TEST_RECORD_JSON=1`: Records the JSON output to
17- //! `*.recorded.json` files. You can then move that to `.json` or whatever
18- //! you need.
19- //! - `RUSTFIX_TEST_RECORD_FIXED_RUST=1`: Records the fixed result to
20- //! `*.recorded.rs` files. You can then move that to `.rs` or whatever you
21- //! need.
229
2310#![ allow( clippy:: disallowed_methods, clippy:: print_stdout, clippy:: print_stderr) ]
2411
2512use anyhow:: { anyhow, Context , Error } ;
2613use cargo_test_macro:: cargo_test;
2714use rustfix:: apply_suggestions;
15+ use serde_json:: Value ;
16+ use snapbox:: data:: DataFormat ;
17+ use snapbox:: { Assert , Data } ;
2818use std:: collections:: HashSet ;
2919use std:: env;
3020use std:: ffi:: OsString ;
@@ -38,14 +28,6 @@ mod fixmode {
3828 pub const EVERYTHING : & str = "yolo" ;
3929}
4030
41- mod settings {
42- // can be set as env var to debug
43- pub const CHECK_JSON : & str = "RUSTFIX_TEST_CHECK_JSON" ;
44- pub const RECORD_JSON : & str = "RUSTFIX_TEST_RECORD_JSON" ;
45- pub const RECORD_FIXED_RUST : & str = "RUSTFIX_TEST_RECORD_FIXED_RUST" ;
46- pub const BLESS : & str = "RUSTFIX_TEST_BLESS" ;
47- }
48-
4931fn compile ( file : & Path ) -> Result < Output , Error > {
5032 let tmp = tempdir ( ) ?;
5133
@@ -95,47 +77,15 @@ fn compiles_without_errors(file: &Path) -> Result<(), Error> {
9577 file,
9678 String :: from_utf8( res. stderr) ?
9779 ) ;
98- Err ( anyhow ! (
99- "failed with status {:?} (`env RUST_LOG=parse_and_replace=info` for more info)" ,
100- res. status. code( ) ,
101- ) )
102- }
103- }
104- }
105-
106- fn diff ( expected : & str , actual : & str ) -> String {
107- use similar:: { ChangeTag , TextDiff } ;
108- use std:: fmt:: Write ;
109-
110- let mut res = String :: new ( ) ;
111- let diff = TextDiff :: from_lines ( expected. trim ( ) , actual. trim ( ) ) ;
112-
113- let mut different = false ;
114- for op in diff. ops ( ) {
115- for change in diff. iter_changes ( op) {
116- let prefix = match change. tag ( ) {
117- ChangeTag :: Equal => continue ,
118- ChangeTag :: Insert => "+" ,
119- ChangeTag :: Delete => "-" ,
120- } ;
121- if !different {
122- writeln ! ( & mut res, "differences found (+ == actual, - == expected):" ) . unwrap ( ) ;
123- different = true ;
124- }
125- write ! ( & mut res, "{} {}" , prefix, change. value( ) ) . unwrap ( ) ;
80+ Err ( anyhow ! ( "failed with status {:?}" , res. status. code( ) ) )
12681 }
12782 }
128- if different {
129- write ! ( & mut res, "" ) . unwrap ( ) ;
130- }
131-
132- res
13383}
13484
13585fn test_rustfix_with_file < P : AsRef < Path > > ( file : P , mode : & str ) {
13686 let file: & Path = file. as_ref ( ) ;
13787 let json_file = file. with_extension ( "json" ) ;
138- let fixed_file = file. with_extension ( "fixed.rs" ) ;
88+ let expected_fixed_file = file. with_extension ( "fixed.rs" ) ;
13989
14090 let filter_suggestions = if mode == fixmode:: EVERYTHING {
14191 rustfix:: Filter :: Everything
@@ -144,60 +94,51 @@ fn test_rustfix_with_file<P: AsRef<Path>>(file: P, mode: &str) {
14494 } ;
14595
14696 let code = fs:: read_to_string ( file) . unwrap ( ) ;
147- let errors = compile_and_get_json_errors ( file)
148- . with_context ( || format ! ( "could not compile {}" , file. display( ) ) ) . unwrap ( ) ;
149- let suggestions =
150- rustfix:: get_suggestions_from_json ( & errors, & HashSet :: new ( ) , filter_suggestions)
151- . context ( "could not load suggestions" ) . unwrap ( ) ;
15297
153- if std :: env :: var ( settings :: RECORD_JSON ) . is_ok ( ) {
154- fs :: write ( file . with_extension ( "recorded.json" ) , & errors ) . unwrap ( ) ;
155- }
98+ let json = compile_and_get_json_errors ( file )
99+ . with_context ( || format ! ( "could not compile {}" , file . display ( ) ) )
100+ . unwrap ( ) ;
156101
157- if std:: env:: var ( settings:: CHECK_JSON ) . is_ok ( ) {
158- let expected_json = fs:: read_to_string ( & json_file)
159- . with_context ( || format ! ( "could not load json fixtures for {}" , file. display( ) ) ) . unwrap ( ) ;
160- let expected_suggestions =
161- rustfix:: get_suggestions_from_json ( & expected_json, & HashSet :: new ( ) , filter_suggestions)
162- . context ( "could not load expected suggestions" ) . unwrap ( ) ;
163-
164- assert ! (
165- expected_suggestions == suggestions,
166- "got unexpected suggestions from clippy:\n {}" ,
167- diff(
168- & format!( "{:?}" , expected_suggestions) ,
169- & format!( "{:?}" , suggestions)
170- )
171- ) ;
172- }
102+ let suggestions =
103+ rustfix:: get_suggestions_from_json ( & json, & HashSet :: new ( ) , filter_suggestions)
104+ . context ( "could not load suggestions" )
105+ . unwrap ( ) ;
173106
174107 let fixed = apply_suggestions ( & code, & suggestions)
175- . with_context ( || format ! ( "could not apply suggestions to {}" , file. display( ) ) ) . unwrap ( )
108+ . with_context ( || format ! ( "could not apply suggestions to {}" , file. display( ) ) )
109+ . unwrap ( )
176110 . replace ( '\r' , "" ) ;
177111
178- if std:: env:: var ( settings:: RECORD_FIXED_RUST ) . is_ok ( ) {
179- fs:: write ( file. with_extension ( "recorded.rs" ) , & fixed) . unwrap ( ) ;
180- }
181-
182- if let Some ( bless_name) = std:: env:: var_os ( settings:: BLESS ) {
183- if bless_name == file. file_name ( ) . unwrap ( ) {
184- std:: fs:: write ( & json_file, & errors) . unwrap ( ) ;
185- std:: fs:: write ( & fixed_file, & fixed) . unwrap ( ) ;
186- }
187- }
188-
189- let expected_fixed = fs:: read_to_string ( & fixed_file)
190- . with_context ( || format ! ( "could read fixed file for {}" , file. display( ) ) ) . unwrap ( )
191- . replace ( '\r' , "" ) ;
192- assert ! (
193- fixed. trim( ) == expected_fixed. trim( ) ,
194- "file {} doesn't look fixed:\n {}" ,
195- file. display( ) ,
196- diff( fixed. trim( ) , expected_fixed. trim( ) )
112+ let assert = Assert :: new ( ) . action_env ( snapbox:: assert:: DEFAULT_ACTION_ENV ) ;
113+ let ( actual_fix, expected_fix) = assert. normalize (
114+ Data :: text ( & fixed) ,
115+ Data :: read_from ( expected_fixed_file. as_path ( ) , Some ( DataFormat :: Text ) ) ,
197116 ) ;
198117
199- compiles_without_errors ( & fixed_file) . unwrap ( ) ;
118+ if actual_fix != expected_fix {
119+ let fixed_assert = assert. try_eq ( Some ( & "Current Fix" ) , actual_fix, expected_fix) ;
120+ assert ! ( fixed_assert. is_ok( ) , "{}" , fixed_assert. err( ) . unwrap( ) ) ;
121+
122+ let expected_json = Data :: read_from ( json_file. as_path ( ) , Some ( DataFormat :: Text ) ) ;
123+
124+ let pretty_json = json
125+ . split ( "\n " )
126+ . filter ( |j| !j. is_empty ( ) )
127+ . map ( |j| {
128+ serde_json:: to_string_pretty ( & serde_json:: from_str :: < Value > ( j) . unwrap ( ) ) . unwrap ( )
129+ } )
130+ . collect :: < Vec < String > > ( )
131+ . join ( "\n " ) ;
132+
133+ let json_assert = assert. try_eq (
134+ Some ( & "Compiler Error" ) ,
135+ Data :: text ( pretty_json) ,
136+ expected_json,
137+ ) ;
138+ assert ! ( json_assert. is_ok( ) , "{}" , json_assert. err( ) . unwrap( ) ) ;
139+ }
200140
141+ compiles_without_errors ( & expected_fixed_file) . unwrap ( ) ;
201142}
202143
203144macro_rules! run_test {
0 commit comments