22//! https://github.com/rust-analyzer/rust-analyzer/pull/5101
33use std:: {
44 collections:: HashMap ,
5- env, fmt, fs,
5+ env, fmt, fs, mem ,
66 ops:: Range ,
77 panic,
88 path:: { Path , PathBuf } ,
@@ -14,7 +14,7 @@ use once_cell::sync::Lazy;
1414use stdx:: { lines_with_ends, trim_indent} ;
1515
1616const HELP : & str = "
17- You can update all `expect![[]]` tests by:
17+ You can update all `expect![[]]` tests by running :
1818
1919 env UPDATE_EXPECT=1 cargo test
2020
@@ -25,24 +25,48 @@ fn update_expect() -> bool {
2525 env:: var ( "UPDATE_EXPECT" ) . is_ok ( )
2626}
2727
28- /// expect![["" ]]
28+ /// expect![[r#"inline snapshot"# ]]
2929#[ macro_export]
3030macro_rules! expect {
31- [ [ $lit: literal] ] => { $crate:: Expect {
32- file: file!( ) ,
33- line: line!( ) ,
34- column: column!( ) ,
35- data: $lit,
31+ [ [ $data: literal] ] => { $crate:: Expect {
32+ position: $crate:: Position {
33+ file: file!( ) ,
34+ line: line!( ) ,
35+ column: column!( ) ,
36+ } ,
37+ data: $data,
3638 } } ;
3739 [ [ ] ] => { $crate:: expect![ [ "" ] ] } ;
3840}
3941
42+ /// expect_file!["/crates/foo/test_data/bar.html"]
43+ #[ macro_export]
44+ macro_rules! expect_file {
45+ [ $path: literal] => { $crate:: ExpectFile { path: $path } } ;
46+ }
47+
4048#[ derive( Debug ) ]
4149pub struct Expect {
50+ pub position : Position ,
51+ pub data : & ' static str ,
52+ }
53+
54+ #[ derive( Debug ) ]
55+ pub struct ExpectFile {
56+ pub path : & ' static str ,
57+ }
58+
59+ #[ derive( Debug ) ]
60+ pub struct Position {
4261 pub file : & ' static str ,
4362 pub line : u32 ,
4463 pub column : u32 ,
45- pub data : & ' static str ,
64+ }
65+
66+ impl fmt:: Display for Position {
67+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
68+ write ! ( f, "{}:{}:{}" , self . file, self . line, self . column)
69+ }
4670}
4771
4872impl Expect {
@@ -51,7 +75,7 @@ impl Expect {
5175 if & trimmed == actual {
5276 return ;
5377 }
54- Runtime :: fail ( self , & trimmed, actual) ;
78+ Runtime :: fail_expect ( self , & trimmed, actual) ;
5579 }
5680 pub fn assert_debug_eq ( & self , actual : & impl fmt:: Debug ) {
5781 let actual = format ! ( "{:#?}\n " , actual) ;
@@ -69,7 +93,7 @@ impl Expect {
6993 let mut target_line = None ;
7094 let mut line_start = 0 ;
7195 for ( i, line) in lines_with_ends ( file) . enumerate ( ) {
72- if i == self . line as usize - 1 {
96+ if i == self . position . line as usize - 1 {
7397 let pat = "expect![[" ;
7498 let offset = line. find ( pat) . unwrap ( ) ;
7599 let literal_start = line_start + offset + pat. len ( ) ;
@@ -87,6 +111,25 @@ impl Expect {
87111 }
88112}
89113
114+ impl ExpectFile {
115+ pub fn assert_eq ( & self , actual : & str ) {
116+ let expected = self . read ( ) ;
117+ if actual == expected {
118+ return ;
119+ }
120+ Runtime :: fail_file ( self , & expected, actual) ;
121+ }
122+ fn read ( & self ) -> String {
123+ fs:: read_to_string ( self . abs_path ( ) ) . unwrap_or_default ( ) . replace ( "\r \n " , "\n " )
124+ }
125+ fn write ( & self , contents : & str ) {
126+ fs:: write ( self . abs_path ( ) , contents) . unwrap ( )
127+ }
128+ fn abs_path ( & self ) -> PathBuf {
129+ workspace_root ( ) . join ( self . path )
130+ }
131+ }
132+
90133#[ derive( Default ) ]
91134struct Runtime {
92135 help_printed : bool ,
@@ -95,27 +138,39 @@ struct Runtime {
95138static RT : Lazy < Mutex < Runtime > > = Lazy :: new ( Default :: default) ;
96139
97140impl Runtime {
98- fn fail ( expect : & Expect , expected : & str , actual : & str ) {
141+ fn fail_expect ( expect : & Expect , expected : & str , actual : & str ) {
99142 let mut rt = RT . lock ( ) . unwrap_or_else ( |poisoned| poisoned. into_inner ( ) ) ;
100- let mut updated = "" ;
101143 if update_expect ( ) {
102- updated = " (updated)" ;
144+ println ! ( " \x1b [1m \x1b [92mupdating \x1b [0m: {}" , expect . position ) ;
103145 rt. per_file
104- . entry ( expect. file )
146+ . entry ( expect. position . file )
105147 . or_insert_with ( || FileRuntime :: new ( expect) )
106148 . update ( expect, actual) ;
149+ return ;
107150 }
108- let print_help = !rt. help_printed && !update_expect ( ) ;
109- rt. help_printed = true ;
151+ rt. panic ( expect. position . to_string ( ) , expected, actual) ;
152+ }
153+
154+ fn fail_file ( expect : & ExpectFile , expected : & str , actual : & str ) {
155+ let mut rt = RT . lock ( ) . unwrap_or_else ( |poisoned| poisoned. into_inner ( ) ) ;
156+ if update_expect ( ) {
157+ println ! ( "\x1b [1m\x1b [92mupdating\x1b [0m: {}" , expect. path) ;
158+ expect. write ( actual) ;
159+ return ;
160+ }
161+ rt. panic ( expect. path . to_string ( ) , expected, actual) ;
162+ }
110163
164+ fn panic ( & mut self , position : String , expected : & str , actual : & str ) {
165+ let print_help = !mem:: replace ( & mut self . help_printed , true ) ;
111166 let help = if print_help { HELP } else { "" } ;
112167
113168 let diff = Changeset :: new ( actual, expected, "\n " ) ;
114169
115170 println ! (
116171 "\n
117- \x1b [1m\x1b [91merror\x1b [97m: expect test failed\x1b [0m{}
118- \x1b [1m\x1b [34m-->\x1b [0m {}:{}:{}
172+ \x1b [1m\x1b [91merror\x1b [97m: expect test failed\x1b [0m
173+ \x1b [1m\x1b [34m-->\x1b [0m {}
119174{}
120175\x1b [1mExpect\x1b [0m:
121176----
@@ -132,7 +187,7 @@ impl Runtime {
132187{}
133188----
134189" ,
135- updated , expect . file , expect . line , expect . column , help, expected, actual, diff
190+ position , help, expected, actual, diff
136191 ) ;
137192 // Use resume_unwind instead of panic!() to prevent a backtrace, which is unnecessary noise.
138193 panic:: resume_unwind ( Box :: new ( ( ) ) ) ;
@@ -147,7 +202,7 @@ struct FileRuntime {
147202
148203impl FileRuntime {
149204 fn new ( expect : & Expect ) -> FileRuntime {
150- let path = workspace_root ( ) . join ( expect. file ) ;
205+ let path = workspace_root ( ) . join ( expect. position . file ) ;
151206 let original_text = fs:: read_to_string ( & path) . unwrap ( ) ;
152207 let patchwork = Patchwork :: new ( original_text. clone ( ) ) ;
153208 FileRuntime { path, original_text, patchwork }
0 commit comments