77//! compares the result with the corresponding `.fixed.rs` file. If they don't
88//! match, then the test fails.
99//!
10- //! There are several debugging environment variables for this test that you can set:
10+ //! The files ending in `.nightly.rs` will run only on the nightly toolchain
1111//!
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.
12+ //! To override snapshots, run `SNAPSHOTS=overwrite cargo test`.
13+ //! See [`snapbox::assert::Action`] for different actions.
2214
2315#![ allow( clippy:: disallowed_methods, clippy:: print_stdout, clippy:: print_stderr) ]
2416
2517use anyhow:: { anyhow, Context , Error } ;
2618use rustfix:: apply_suggestions;
19+ use serde_json:: Value ;
20+ use snapbox:: data:: DataFormat ;
21+ use snapbox:: { Assert , Data } ;
2722use std:: collections:: HashSet ;
2823use std:: env;
2924use std:: ffi:: OsString ;
3025use std:: fs;
3126use std:: path:: Path ;
3227use std:: process:: { Command , Output } ;
3328use tempfile:: tempdir;
34- use tracing:: info;
3529
3630mod fixmode {
3731 pub const EVERYTHING : & str = "yolo" ;
3832}
3933
40- mod settings {
41- // can be set as env var to debug
42- pub const CHECK_JSON : & str = "RUSTFIX_TEST_CHECK_JSON" ;
43- pub const RECORD_JSON : & str = "RUSTFIX_TEST_RECORD_JSON" ;
44- pub const RECORD_FIXED_RUST : & str = "RUSTFIX_TEST_RECORD_FIXED_RUST" ;
45- pub const BLESS : & str = "RUSTFIX_TEST_BLESS" ;
46- }
47-
4834static mut VERSION : ( u32 , bool ) = ( 0 , false ) ;
4935
5036// Temporarily copy from `cargo_test_macro::version`.
@@ -108,53 +94,19 @@ fn compiles_without_errors(file: &Path) -> Result<(), Error> {
10894
10995 match res. status . code ( ) {
11096 Some ( 0 ) => Ok ( ( ) ) ,
111- _ => {
112- info ! (
113- "file {:?} failed to compile:\n {}" ,
114- file,
115- String :: from_utf8( res. stderr) ?
116- ) ;
117- Err ( anyhow ! (
118- "failed with status {:?} (`env RUST_LOG=parse_and_replace=info` for more info)" ,
119- res. status. code( ) ,
120- ) )
121- }
122- }
123- }
124-
125- fn diff ( expected : & str , actual : & str ) -> String {
126- use similar:: { ChangeTag , TextDiff } ;
127- use std:: fmt:: Write ;
128-
129- let mut res = String :: new ( ) ;
130- let diff = TextDiff :: from_lines ( expected. trim ( ) , actual. trim ( ) ) ;
131-
132- let mut different = false ;
133- for op in diff. ops ( ) {
134- for change in diff. iter_changes ( op) {
135- let prefix = match change. tag ( ) {
136- ChangeTag :: Equal => continue ,
137- ChangeTag :: Insert => "+" ,
138- ChangeTag :: Delete => "-" ,
139- } ;
140- if !different {
141- writeln ! ( & mut res, "differences found (+ == actual, - == expected):" ) . unwrap ( ) ;
142- different = true ;
143- }
144- write ! ( & mut res, "{} {}" , prefix, change. value( ) ) . unwrap ( ) ;
145- }
146- }
147- if different {
148- write ! ( & mut res, "" ) . unwrap ( ) ;
97+ _ => Err ( anyhow ! (
98+ "file {:?} failed compile with status {:?}:\n {}" ,
99+ file,
100+ res. status. code( ) ,
101+ String :: from_utf8( res. stderr) ?
102+ ) ) ,
149103 }
150-
151- res
152104}
153105
154106fn test_rustfix_with_file < P : AsRef < Path > > ( file : P , mode : & str ) {
155107 let file: & Path = file. as_ref ( ) ;
156108 let json_file = file. with_extension ( "json" ) ;
157- let fixed_file = file. with_extension ( "fixed.rs" ) ;
109+ let expected_fixed_file = file. with_extension ( "fixed.rs" ) ;
158110
159111 let filter_suggestions = if mode == fixmode:: EVERYTHING {
160112 rustfix:: Filter :: Everything
@@ -163,60 +115,51 @@ fn test_rustfix_with_file<P: AsRef<Path>>(file: P, mode: &str) {
163115 } ;
164116
165117 let code = fs:: read_to_string ( file) . unwrap ( ) ;
166- let errors = compile_and_get_json_errors ( file)
167- . with_context ( || format ! ( "could not compile {}" , file. display( ) ) ) . unwrap ( ) ;
168- let suggestions =
169- rustfix:: get_suggestions_from_json ( & errors, & HashSet :: new ( ) , filter_suggestions)
170- . context ( "could not load suggestions" ) . unwrap ( ) ;
171118
172- if std :: env :: var ( settings :: RECORD_JSON ) . is_ok ( ) {
173- fs :: write ( file . with_extension ( "recorded.json" ) , & errors ) . unwrap ( ) ;
174- }
119+ let json = compile_and_get_json_errors ( file )
120+ . with_context ( || format ! ( "could not compile {}" , file . display ( ) ) )
121+ . unwrap ( ) ;
175122
176- if std:: env:: var ( settings:: CHECK_JSON ) . is_ok ( ) {
177- let expected_json = fs:: read_to_string ( & json_file)
178- . with_context ( || format ! ( "could not load json fixtures for {}" , file. display( ) ) ) . unwrap ( ) ;
179- let expected_suggestions =
180- rustfix:: get_suggestions_from_json ( & expected_json, & HashSet :: new ( ) , filter_suggestions)
181- . context ( "could not load expected suggestions" ) . unwrap ( ) ;
182-
183- assert ! (
184- expected_suggestions == suggestions,
185- "got unexpected suggestions from clippy:\n {}" ,
186- diff(
187- & format!( "{:?}" , expected_suggestions) ,
188- & format!( "{:?}" , suggestions)
189- )
190- ) ;
191- }
123+ let suggestions =
124+ rustfix:: get_suggestions_from_json ( & json, & HashSet :: new ( ) , filter_suggestions)
125+ . context ( "could not load suggestions" )
126+ . unwrap ( ) ;
192127
193128 let fixed = apply_suggestions ( & code, & suggestions)
194- . with_context ( || format ! ( "could not apply suggestions to {}" , file. display( ) ) ) . unwrap ( )
129+ . with_context ( || format ! ( "could not apply suggestions to {}" , file. display( ) ) )
130+ . unwrap ( )
195131 . replace ( '\r' , "" ) ;
196132
197- if std:: env:: var ( settings:: RECORD_FIXED_RUST ) . is_ok ( ) {
198- fs:: write ( file. with_extension ( "recorded.rs" ) , & fixed) . unwrap ( ) ;
199- }
200-
201- if let Some ( bless_name) = std:: env:: var_os ( settings:: BLESS ) {
202- if bless_name == file. file_name ( ) . unwrap ( ) {
203- std:: fs:: write ( & json_file, & errors) . unwrap ( ) ;
204- std:: fs:: write ( & fixed_file, & fixed) . unwrap ( ) ;
205- }
206- }
207-
208- let expected_fixed = fs:: read_to_string ( & fixed_file)
209- . with_context ( || format ! ( "could read fixed file for {}" , file. display( ) ) ) . unwrap ( )
210- . replace ( '\r' , "" ) ;
211- assert ! (
212- fixed. trim( ) == expected_fixed. trim( ) ,
213- "file {} doesn't look fixed:\n {}" ,
214- file. display( ) ,
215- diff( fixed. trim( ) , expected_fixed. trim( ) )
133+ let assert = Assert :: new ( ) . action_env ( snapbox:: assert:: DEFAULT_ACTION_ENV ) ;
134+ let ( actual_fix, expected_fix) = assert. normalize (
135+ Data :: text ( & fixed) ,
136+ Data :: read_from ( expected_fixed_file. as_path ( ) , Some ( DataFormat :: Text ) ) ,
216137 ) ;
217138
218- compiles_without_errors ( & fixed_file) . unwrap ( ) ;
139+ if actual_fix != expected_fix {
140+ let fixed_assert = assert. try_eq ( Some ( & "Current Fix" ) , actual_fix, expected_fix) ;
141+ assert ! ( fixed_assert. is_ok( ) , "{}" , fixed_assert. err( ) . unwrap( ) ) ;
142+
143+ let expected_json = Data :: read_from ( json_file. as_path ( ) , Some ( DataFormat :: Text ) ) ;
144+
145+ let pretty_json = json
146+ . split ( "\n " )
147+ . filter ( |j| !j. is_empty ( ) )
148+ . map ( |j| {
149+ serde_json:: to_string_pretty ( & serde_json:: from_str :: < Value > ( j) . unwrap ( ) ) . unwrap ( )
150+ } )
151+ . collect :: < Vec < String > > ( )
152+ . join ( "\n " ) ;
153+
154+ let json_assert = assert. try_eq (
155+ Some ( & "Compiler Error" ) ,
156+ Data :: text ( pretty_json) ,
157+ expected_json,
158+ ) ;
159+ assert ! ( json_assert. is_ok( ) , "{}" , json_assert. err( ) . unwrap( ) ) ;
160+ }
219161
162+ compiles_without_errors ( & expected_fixed_file) . unwrap ( ) ;
220163}
221164
222165macro_rules! run_test {
0 commit comments