@@ -155,7 +155,7 @@ pub fn add_cursor(text: &str, offset: TextSize) -> String {
155
155
res
156
156
}
157
157
158
- #[ derive( Debug ) ]
158
+ #[ derive( Debug , Eq , PartialEq ) ]
159
159
pub struct FixtureEntry {
160
160
pub meta : String ,
161
161
pub text : String ,
@@ -170,19 +170,26 @@ pub struct FixtureEntry {
170
170
/// // - other meta
171
171
/// ```
172
172
pub fn parse_fixture ( fixture : & str ) -> Vec < FixtureEntry > {
173
- let margin = fixture
174
- . lines ( )
175
- . filter ( |it| it. trim_start ( ) . starts_with ( "//-" ) )
176
- . map ( |it| it. len ( ) - it. trim_start ( ) . len ( ) )
177
- . next ( )
178
- . expect ( "empty fixture" ) ;
173
+ let fixture = indent_first_line ( fixture) ;
174
+ let margin = fixture_margin ( & fixture) ;
179
175
180
176
let mut lines = fixture
181
177
. split ( '\n' ) // don't use `.lines` to not drop `\r\n`
182
- . filter_map ( |line| {
178
+ . enumerate ( )
179
+ . filter_map ( |( ix, line) | {
183
180
if line. len ( ) >= margin {
184
181
assert ! ( line[ ..margin] . trim( ) . is_empty( ) ) ;
185
- Some ( & line[ margin..] )
182
+ let line_content = & line[ margin..] ;
183
+ if !line_content. starts_with ( "//-" ) {
184
+ assert ! (
185
+ !line_content. contains( "//-" ) ,
186
+ r#"Metadata line {} has invalid indentation. All metadata lines need to have the same indentation.
187
+ The offending line: {:?}"# ,
188
+ ix,
189
+ line
190
+ ) ;
191
+ }
192
+ Some ( line_content)
186
193
} else {
187
194
assert ! ( line. trim( ) . is_empty( ) ) ;
188
195
None
@@ -202,6 +209,85 @@ pub fn parse_fixture(fixture: &str) -> Vec<FixtureEntry> {
202
209
res
203
210
}
204
211
212
+ /// Adjusts the indentation of the first line to the minimum indentation of the rest of the lines.
213
+ /// This allows fixtures to start off in a different indentation, e.g. to align the first line with
214
+ /// the other lines visually:
215
+ /// ```
216
+ /// let fixture = "//- /lib.rs
217
+ /// mod foo;
218
+ /// //- /foo.rs
219
+ /// fn bar() {}
220
+ /// ";
221
+ /// assert_eq!(fixture_margin(fixture),
222
+ /// " //- /lib.rs
223
+ /// mod foo;
224
+ /// //- /foo.rs
225
+ /// fn bar() {}
226
+ /// ")
227
+ /// ```
228
+ fn indent_first_line ( fixture : & str ) -> String {
229
+ if fixture. is_empty ( ) {
230
+ return String :: new ( ) ;
231
+ }
232
+ let mut lines = fixture. lines ( ) ;
233
+ let first_line = lines. next ( ) . unwrap ( ) ;
234
+ if first_line. contains ( "//-" ) {
235
+ let rest = lines. collect :: < Vec < _ > > ( ) . join ( "\n " ) ;
236
+ let fixed_margin = fixture_margin ( & rest) ;
237
+ let fixed_indent = fixed_margin - indent_len ( first_line) ;
238
+ format ! ( "\n {}{}\n {}" , " " . repeat( fixed_indent) , first_line, rest)
239
+ } else {
240
+ fixture. to_owned ( )
241
+ }
242
+ }
243
+
244
+ fn fixture_margin ( fixture : & str ) -> usize {
245
+ fixture
246
+ . lines ( )
247
+ . filter ( |it| it. trim_start ( ) . starts_with ( "//-" ) )
248
+ . map ( indent_len)
249
+ . next ( )
250
+ . expect ( "empty fixture" )
251
+ }
252
+
253
+ fn indent_len ( s : & str ) -> usize {
254
+ s. len ( ) - s. trim_start ( ) . len ( )
255
+ }
256
+
257
+ #[ test]
258
+ #[ should_panic]
259
+ fn parse_fixture_checks_further_indented_metadata ( ) {
260
+ parse_fixture (
261
+ r"
262
+ //- /lib.rs
263
+ mod bar;
264
+
265
+ fn foo() {}
266
+ //- /bar.rs
267
+ pub fn baz() {}
268
+ " ,
269
+ ) ;
270
+ }
271
+
272
+ #[ test]
273
+ fn parse_fixture_can_handle_unindented_first_line ( ) {
274
+ let fixture = "//- /lib.rs
275
+ mod foo;
276
+ //- /foo.rs
277
+ struct Bar;
278
+ " ;
279
+ assert_eq ! (
280
+ parse_fixture( fixture) ,
281
+ parse_fixture(
282
+ "//- /lib.rs
283
+ mod foo;
284
+ //- /foo.rs
285
+ struct Bar;
286
+ "
287
+ )
288
+ )
289
+ }
290
+
205
291
/// Same as `parse_fixture`, except it allow empty fixture
206
292
pub fn parse_single_fixture ( fixture : & str ) -> Option < FixtureEntry > {
207
293
if !fixture. lines ( ) . any ( |it| it. trim_start ( ) . starts_with ( "//-" ) ) {
0 commit comments