]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_expand/src/tests.rs
New upstream version 1.76.0+dfsg1
[rustc.git] / compiler / rustc_expand / src / tests.rs
CommitLineData
3dfed10e 1use rustc_ast as ast;
74b04a01 2use rustc_ast::tokenstream::TokenStream;
dfeec247 3use rustc_parse::{new_parser_from_source_str, parser::Parser, source_file_to_stream};
74b04a01 4use rustc_session::parse::ParseSess;
ed00b5ec 5use rustc_span::create_default_session_globals_then;
dfeec247 6use rustc_span::source_map::{FilePathMapping, SourceMap};
04454e1e 7use rustc_span::{BytePos, Span};
dfeec247
XL
8
9use rustc_data_structures::sync::Lrc;
10use rustc_errors::emitter::EmitterWriter;
4b012472 11use rustc_errors::{DiagCtxt, MultiSpan, PResult};
add651ee 12use termcolor::WriteColor;
dfeec247
XL
13
14use std::io;
15use std::io::prelude::*;
16use std::iter::Peekable;
17use std::path::{Path, PathBuf};
18use std::str;
19use std::sync::{Arc, Mutex};
20
21/// Map string to parser (via tts).
22fn string_to_parser(ps: &ParseSess, source_str: String) -> Parser<'_> {
23 new_parser_from_source_str(ps, PathBuf::from("bogofile").into(), source_str)
24}
25
4b012472 26fn create_test_handler() -> (DiagCtxt, Lrc<SourceMap>, Arc<Mutex<Vec<u8>>>) {
add651ee
FG
27 let output = Arc::new(Mutex::new(Vec::new()));
28 let source_map = Lrc::new(SourceMap::new(FilePathMapping::empty()));
29 let fallback_bundle = rustc_errors::fallback_fluent_bundle(
30 vec![crate::DEFAULT_LOCALE_RESOURCE, rustc_parse::DEFAULT_LOCALE_RESOURCE],
31 false,
32 );
33 let emitter = EmitterWriter::new(Box::new(Shared { data: output.clone() }), fallback_bundle)
34 .sm(Some(source_map.clone()))
35 .diagnostic_width(Some(140));
4b012472
FG
36 let dcx = DiagCtxt::with_emitter(Box::new(emitter));
37 (dcx, source_map, output)
add651ee
FG
38}
39
40/// Returns the result of parsing the given string via the given callback.
41///
42/// If there are any errors, this will panic.
923072b8 43pub(crate) fn with_error_checking_parse<'a, T, F>(s: String, ps: &'a ParseSess, f: F) -> T
dfeec247
XL
44where
45 F: FnOnce(&mut Parser<'a>) -> PResult<'a, T>,
46{
47 let mut p = string_to_parser(&ps, s);
48 let x = f(&mut p).unwrap();
4b012472 49 p.sess.dcx.abort_if_errors();
dfeec247
XL
50 x
51}
52
add651ee
FG
53/// Verifies that parsing the given string using the given callback will
54/// generate an error that contains the given text.
55pub(crate) fn with_expected_parse_error<T, F>(source_str: &str, expected_output: &str, f: F)
56where
57 F: for<'a> FnOnce(&mut Parser<'a>) -> PResult<'a, T>,
58{
59 let (handler, source_map, output) = create_test_handler();
4b012472 60 let ps = ParseSess::with_dcx(handler, source_map);
add651ee
FG
61 let mut p = string_to_parser(&ps, source_str.to_string());
62 let result = f(&mut p);
63 assert!(result.is_ok());
64
65 let bytes = output.lock().unwrap();
66 let actual_output = str::from_utf8(&bytes).unwrap();
67 println!("expected output:\n------\n{}------", expected_output);
68 println!("actual output:\n------\n{}------", actual_output);
69
70 assert!(actual_output.contains(expected_output))
71}
72
dfeec247 73/// Maps a string to tts, using a made-up filename.
923072b8 74pub(crate) fn string_to_stream(source_str: String) -> TokenStream {
9ffffee4
FG
75 let ps = ParseSess::new(
76 vec![crate::DEFAULT_LOCALE_RESOURCE, rustc_parse::DEFAULT_LOCALE_RESOURCE],
77 FilePathMapping::empty(),
78 );
dfeec247
XL
79 source_file_to_stream(
80 &ps,
81 ps.source_map().new_source_file(PathBuf::from("bogofile").into(), source_str),
82 None,
83 )
dfeec247
XL
84}
85
86/// Parses a string, returns a crate.
923072b8 87pub(crate) fn string_to_crate(source_str: String) -> ast::Crate {
9ffffee4
FG
88 let ps = ParseSess::new(
89 vec![crate::DEFAULT_LOCALE_RESOURCE, rustc_parse::DEFAULT_LOCALE_RESOURCE],
90 FilePathMapping::empty(),
91 );
dfeec247
XL
92 with_error_checking_parse(source_str, &ps, |p| p.parse_crate_mod())
93}
94
95/// Does the given string match the pattern? whitespace in the first string
96/// may be deleted or replaced with other whitespace to match the pattern.
97/// This function is relatively Unicode-ignorant; fortunately, the careful design
98/// of UTF-8 mitigates this ignorance. It doesn't do NKF-normalization(?).
923072b8 99pub(crate) fn matches_codepattern(a: &str, b: &str) -> bool {
dfeec247
XL
100 let mut a_iter = a.chars().peekable();
101 let mut b_iter = b.chars().peekable();
102
103 loop {
104 let (a, b) = match (a_iter.peek(), b_iter.peek()) {
105 (None, None) => return true,
106 (None, _) => return false,
107 (Some(&a), None) => {
108 if rustc_lexer::is_whitespace(a) {
109 break; // Trailing whitespace check is out of loop for borrowck.
110 } else {
111 return false;
112 }
113 }
114 (Some(&a), Some(&b)) => (a, b),
115 };
116
117 if rustc_lexer::is_whitespace(a) && rustc_lexer::is_whitespace(b) {
118 // Skip whitespace for `a` and `b`.
119 scan_for_non_ws_or_end(&mut a_iter);
120 scan_for_non_ws_or_end(&mut b_iter);
121 } else if rustc_lexer::is_whitespace(a) {
122 // Skip whitespace for `a`.
123 scan_for_non_ws_or_end(&mut a_iter);
124 } else if a == b {
125 a_iter.next();
126 b_iter.next();
127 } else {
128 return false;
129 }
130 }
131
132 // Check if a has *only* trailing whitespace.
133 a_iter.all(rustc_lexer::is_whitespace)
134}
135
136/// Advances the given peekable `Iterator` until it reaches a non-whitespace character.
137fn scan_for_non_ws_or_end<I: Iterator<Item = char>>(iter: &mut Peekable<I>) {
4b012472 138 while iter.peek().copied().is_some_and(rustc_lexer::is_whitespace) {
dfeec247
XL
139 iter.next();
140 }
141}
142
143/// Identifies a position in the text by the n'th occurrence of a string.
144struct Position {
145 string: &'static str,
146 count: usize,
147}
148
149struct SpanLabel {
150 start: Position,
151 end: Position,
152 label: &'static str,
153}
154
923072b8 155pub(crate) struct Shared<T: Write> {
dfeec247
XL
156 pub data: Arc<Mutex<T>>,
157}
158
add651ee
FG
159impl<T: Write> WriteColor for Shared<T> {
160 fn supports_color(&self) -> bool {
161 false
162 }
163
164 fn set_color(&mut self, _spec: &termcolor::ColorSpec) -> io::Result<()> {
165 Ok(())
166 }
167
168 fn reset(&mut self) -> io::Result<()> {
169 Ok(())
170 }
171}
172
dfeec247
XL
173impl<T: Write> Write for Shared<T> {
174 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
175 self.data.lock().unwrap().write(buf)
176 }
177
178 fn flush(&mut self) -> io::Result<()> {
179 self.data.lock().unwrap().flush()
180 }
181}
182
183fn test_harness(file_text: &str, span_labels: Vec<SpanLabel>, expected_output: &str) {
ed00b5ec 184 create_default_session_globals_then(|| {
add651ee 185 let (handler, source_map, output) = create_test_handler();
dfeec247
XL
186 source_map.new_source_file(Path::new("test.rs").to_owned().into(), file_text.to_owned());
187
188 let primary_span = make_span(&file_text, &span_labels[0].start, &span_labels[0].end);
189 let mut msp = MultiSpan::from_span(primary_span);
190 for span_label in span_labels {
191 let span = make_span(&file_text, &span_label.start, &span_label.end);
064997fb 192 msp.push_span_label(span, span_label.label);
dfeec247
XL
193 println!("span: {:?} label: {:?}", span, span_label.label);
194 println!("text: {:?}", source_map.span_to_snippet(span));
195 }
196
9c376795 197 #[allow(rustc::untranslatable_diagnostic)]
dfeec247
XL
198 handler.span_err(msp, "foo");
199
200 assert!(
201 expected_output.chars().next() == Some('\n'),
202 "expected output should begin with newline"
203 );
204 let expected_output = &expected_output[1..];
205
206 let bytes = output.lock().unwrap();
207 let actual_output = str::from_utf8(&bytes).unwrap();
208 println!("expected output:\n------\n{}------", expected_output);
209 println!("actual output:\n------\n{}------", actual_output);
210
211 assert!(expected_output == actual_output)
212 })
213}
214
215fn make_span(file_text: &str, start: &Position, end: &Position) -> Span {
216 let start = make_pos(file_text, start);
217 let end = make_pos(file_text, end) + end.string.len(); // just after matching thing ends
218 assert!(start <= end);
219 Span::with_root_ctxt(BytePos(start as u32), BytePos(end as u32))
220}
221
222fn make_pos(file_text: &str, pos: &Position) -> usize {
223 let mut remainder = file_text;
224 let mut offset = 0;
225 for _ in 0..pos.count {
226 if let Some(n) = remainder.find(&pos.string) {
227 offset += n;
228 remainder = &remainder[n + 1..];
229 } else {
230 panic!("failed to find {} instances of {:?} in {:?}", pos.count, pos.string, file_text);
231 }
232 }
233 offset
234}
235
236#[test]
237fn ends_on_col0() {
238 test_harness(
239 r#"
240fn foo() {
241}
242"#,
243 vec![SpanLabel {
244 start: Position { string: "{", count: 1 },
245 end: Position { string: "}", count: 1 },
246 label: "test",
247 }],
248 r#"
249error: foo
250 --> test.rs:2:10
251 |
2522 | fn foo() {
253 | __________^
2543 | | }
255 | |_^ test
256
257"#,
258 );
259}
260
261#[test]
262fn ends_on_col2() {
263 test_harness(
264 r#"
265fn foo() {
266
267
268 }
269"#,
270 vec![SpanLabel {
271 start: Position { string: "{", count: 1 },
272 end: Position { string: "}", count: 1 },
273 label: "test",
274 }],
275 r#"
276error: foo
277 --> test.rs:2:10
278 |
2792 | fn foo() {
280 | __________^
2813 | |
2824 | |
2835 | | }
284 | |___^ test
285
286"#,
287 );
288}
289#[test]
290fn non_nested() {
291 test_harness(
292 r#"
293fn foo() {
294 X0 Y0
295 X1 Y1
296 X2 Y2
297}
298"#,
299 vec![
300 SpanLabel {
301 start: Position { string: "X0", count: 1 },
302 end: Position { string: "X2", count: 1 },
303 label: "`X` is a good letter",
304 },
305 SpanLabel {
306 start: Position { string: "Y0", count: 1 },
307 end: Position { string: "Y2", count: 1 },
308 label: "`Y` is a good letter too",
309 },
310 ],
311 r#"
312error: foo
313 --> test.rs:3:3
314 |
3153 | X0 Y0
487cf647
FG
316 | ___^__-
317 | |___|
dfeec247
XL
318 | ||
3194 | || X1 Y1
3205 | || X2 Y2
321 | ||____^__- `Y` is a good letter too
487cf647 322 | |_____|
dfeec247
XL
323 | `X` is a good letter
324
325"#,
326 );
327}
328
329#[test]
330fn nested() {
331 test_harness(
332 r#"
333fn foo() {
334 X0 Y0
335 Y1 X1
336}
337"#,
338 vec![
339 SpanLabel {
340 start: Position { string: "X0", count: 1 },
341 end: Position { string: "X1", count: 1 },
342 label: "`X` is a good letter",
343 },
344 SpanLabel {
345 start: Position { string: "Y0", count: 1 },
346 end: Position { string: "Y1", count: 1 },
347 label: "`Y` is a good letter too",
348 },
349 ],
350 r#"
351error: foo
352 --> test.rs:3:3
353 |
3543 | X0 Y0
487cf647
FG
355 | ___^__-
356 | |___|
dfeec247
XL
357 | ||
3584 | || Y1 X1
359 | ||____-__^ `X` is a good letter
487cf647 360 | |____|
dfeec247
XL
361 | `Y` is a good letter too
362
363"#,
364 );
365}
366
367#[test]
368fn different_overlap() {
369 test_harness(
370 r#"
371fn foo() {
372 X0 Y0 Z0
373 X1 Y1 Z1
374 X2 Y2 Z2
375 X3 Y3 Z3
376}
377"#,
378 vec![
379 SpanLabel {
380 start: Position { string: "Y0", count: 1 },
381 end: Position { string: "X2", count: 1 },
382 label: "`X` is a good letter",
383 },
384 SpanLabel {
385 start: Position { string: "Z1", count: 1 },
386 end: Position { string: "X3", count: 1 },
387 label: "`Y` is a good letter too",
388 },
389 ],
390 r#"
391error: foo
392 --> test.rs:3:6
393 |
3943 | X0 Y0 Z0
487cf647
FG
395 | _______^
3964 | | X1 Y1 Z1
397 | | _________-
dfeec247
XL
3985 | || X2 Y2 Z2
399 | ||____^ `X` is a good letter
487cf647
FG
4006 | | X3 Y3 Z3
401 | |____- `Y` is a good letter too
dfeec247
XL
402
403"#,
404 );
405}
406
407#[test]
408fn triple_overlap() {
409 test_harness(
410 r#"
411fn foo() {
412 X0 Y0 Z0
413 X1 Y1 Z1
414 X2 Y2 Z2
415}
416"#,
417 vec![
418 SpanLabel {
419 start: Position { string: "X0", count: 1 },
420 end: Position { string: "X2", count: 1 },
421 label: "`X` is a good letter",
422 },
423 SpanLabel {
424 start: Position { string: "Y0", count: 1 },
425 end: Position { string: "Y2", count: 1 },
426 label: "`Y` is a good letter too",
427 },
428 SpanLabel {
429 start: Position { string: "Z0", count: 1 },
430 end: Position { string: "Z2", count: 1 },
431 label: "`Z` label",
432 },
433 ],
434 r#"
435error: foo
436 --> test.rs:3:3
437 |
4383 | X0 Y0 Z0
487cf647
FG
439 | ___^__-__-
440 | |___|__|
441 | ||___|
dfeec247
XL
442 | |||
4434 | ||| X1 Y1 Z1
4445 | ||| X2 Y2 Z2
445 | |||____^__-__- `Z` label
487cf647
FG
446 | ||_____|__|
447 | |______| `Y` is a good letter too
dfeec247
XL
448 | `X` is a good letter
449
450"#,
451 );
452}
453
454#[test]
455fn triple_exact_overlap() {
456 test_harness(
457 r#"
458fn foo() {
459 X0 Y0 Z0
460 X1 Y1 Z1
461 X2 Y2 Z2
462}
463"#,
464 vec![
465 SpanLabel {
466 start: Position { string: "X0", count: 1 },
467 end: Position { string: "X2", count: 1 },
468 label: "`X` is a good letter",
469 },
470 SpanLabel {
471 start: Position { string: "X0", count: 1 },
472 end: Position { string: "X2", count: 1 },
473 label: "`Y` is a good letter too",
474 },
475 SpanLabel {
476 start: Position { string: "X0", count: 1 },
477 end: Position { string: "X2", count: 1 },
478 label: "`Z` label",
479 },
480 ],
481 r#"
482error: foo
483 --> test.rs:3:3
484 |
4853 | / X0 Y0 Z0
4864 | | X1 Y1 Z1
4875 | | X2 Y2 Z2
488 | | ^
489 | | |
490 | | `X` is a good letter
491 | |____`Y` is a good letter too
492 | `Z` label
493
494"#,
495 );
496}
497
498#[test]
499fn minimum_depth() {
500 test_harness(
501 r#"
502fn foo() {
503 X0 Y0 Z0
504 X1 Y1 Z1
505 X2 Y2 Z2
506 X3 Y3 Z3
507}
508"#,
509 vec![
510 SpanLabel {
511 start: Position { string: "Y0", count: 1 },
512 end: Position { string: "X1", count: 1 },
513 label: "`X` is a good letter",
514 },
515 SpanLabel {
516 start: Position { string: "Y1", count: 1 },
517 end: Position { string: "Z2", count: 1 },
518 label: "`Y` is a good letter too",
519 },
520 SpanLabel {
521 start: Position { string: "X2", count: 1 },
522 end: Position { string: "Y3", count: 1 },
523 label: "`Z`",
524 },
525 ],
526 r#"
527error: foo
528 --> test.rs:3:6
529 |
5303 | X0 Y0 Z0
487cf647
FG
531 | _______^
5324 | | X1 Y1 Z1
533 | | ____^_-
dfeec247 534 | ||____|
487cf647
FG
535 | | `X` is a good letter
5365 | | X2 Y2 Z2
537 | |___-______- `Y` is a good letter too
538 | ___|
539 | |
5406 | | X3 Y3 Z3
541 | |_______- `Z`
dfeec247
XL
542
543"#,
544 );
545}
546
547#[test]
49aad941 548fn non_overlapping() {
dfeec247
XL
549 test_harness(
550 r#"
551fn foo() {
552 X0 Y0 Z0
553 X1 Y1 Z1
554 X2 Y2 Z2
555 X3 Y3 Z3
556}
557"#,
558 vec![
559 SpanLabel {
560 start: Position { string: "X0", count: 1 },
561 end: Position { string: "X1", count: 1 },
562 label: "`X` is a good letter",
563 },
564 SpanLabel {
565 start: Position { string: "Y2", count: 1 },
566 end: Position { string: "Z3", count: 1 },
567 label: "`Y` is a good letter too",
568 },
569 ],
570 r#"
571error: foo
572 --> test.rs:3:3
573 |
5743 | / X0 Y0 Z0
5754 | | X1 Y1 Z1
576 | |____^ `X` is a good letter
5775 | X2 Y2 Z2
578 | ______-
5796 | | X3 Y3 Z3
580 | |__________- `Y` is a good letter too
581
582"#,
583 );
584}
585
586#[test]
49aad941 587fn overlapping_start_and_end() {
dfeec247
XL
588 test_harness(
589 r#"
590fn foo() {
591 X0 Y0 Z0
592 X1 Y1 Z1
593 X2 Y2 Z2
594 X3 Y3 Z3
595}
596"#,
597 vec![
598 SpanLabel {
599 start: Position { string: "Y0", count: 1 },
600 end: Position { string: "X1", count: 1 },
601 label: "`X` is a good letter",
602 },
603 SpanLabel {
604 start: Position { string: "Z1", count: 1 },
605 end: Position { string: "Z3", count: 1 },
606 label: "`Y` is a good letter too",
607 },
608 ],
609 r#"
610error: foo
611 --> test.rs:3:6
612 |
6133 | X0 Y0 Z0
487cf647
FG
614 | _______^
6154 | | X1 Y1 Z1
616 | | ____^____-
dfeec247 617 | ||____|
487cf647
FG
618 | | `X` is a good letter
6195 | | X2 Y2 Z2
6206 | | X3 Y3 Z3
621 | |__________- `Y` is a good letter too
dfeec247
XL
622
623"#,
624 );
625}
626
627#[test]
628fn multiple_labels_primary_without_message() {
629 test_harness(
630 r#"
631fn foo() {
632 a { b { c } d }
633}
634"#,
635 vec![
636 SpanLabel {
637 start: Position { string: "b", count: 1 },
638 end: Position { string: "}", count: 1 },
639 label: "",
640 },
641 SpanLabel {
642 start: Position { string: "a", count: 1 },
643 end: Position { string: "d", count: 1 },
644 label: "`a` is a good letter",
645 },
646 SpanLabel {
647 start: Position { string: "c", count: 1 },
648 end: Position { string: "c", count: 1 },
649 label: "",
650 },
651 ],
652 r#"
653error: foo
654 --> test.rs:3:7
655 |
6563 | a { b { c } d }
657 | ----^^^^-^^-- `a` is a good letter
658
659"#,
660 );
661}
662
663#[test]
664fn multiple_labels_secondary_without_message() {
665 test_harness(
666 r#"
667fn foo() {
668 a { b { c } d }
669}
670"#,
671 vec![
672 SpanLabel {
673 start: Position { string: "a", count: 1 },
674 end: Position { string: "d", count: 1 },
675 label: "`a` is a good letter",
676 },
677 SpanLabel {
678 start: Position { string: "b", count: 1 },
679 end: Position { string: "}", count: 1 },
680 label: "",
681 },
682 ],
683 r#"
684error: foo
685 --> test.rs:3:3
686 |
6873 | a { b { c } d }
688 | ^^^^-------^^ `a` is a good letter
689
690"#,
691 );
692}
693
694#[test]
695fn multiple_labels_primary_without_message_2() {
696 test_harness(
697 r#"
698fn foo() {
699 a { b { c } d }
700}
701"#,
702 vec![
703 SpanLabel {
704 start: Position { string: "b", count: 1 },
705 end: Position { string: "}", count: 1 },
706 label: "`b` is a good letter",
707 },
708 SpanLabel {
709 start: Position { string: "a", count: 1 },
710 end: Position { string: "d", count: 1 },
711 label: "",
712 },
713 SpanLabel {
714 start: Position { string: "c", count: 1 },
715 end: Position { string: "c", count: 1 },
716 label: "",
717 },
718 ],
719 r#"
720error: foo
721 --> test.rs:3:7
722 |
7233 | a { b { c } d }
724 | ----^^^^-^^--
725 | |
726 | `b` is a good letter
727
728"#,
729 );
730}
731
732#[test]
733fn multiple_labels_secondary_without_message_2() {
734 test_harness(
735 r#"
736fn foo() {
737 a { b { c } d }
738}
739"#,
740 vec![
741 SpanLabel {
742 start: Position { string: "a", count: 1 },
743 end: Position { string: "d", count: 1 },
744 label: "",
745 },
746 SpanLabel {
747 start: Position { string: "b", count: 1 },
748 end: Position { string: "}", count: 1 },
749 label: "`b` is a good letter",
750 },
751 ],
752 r#"
753error: foo
754 --> test.rs:3:3
755 |
7563 | a { b { c } d }
757 | ^^^^-------^^
758 | |
759 | `b` is a good letter
760
761"#,
762 );
763}
764
765#[test]
766fn multiple_labels_secondary_without_message_3() {
767 test_harness(
768 r#"
769fn foo() {
770 a bc d
771}
772"#,
773 vec![
774 SpanLabel {
775 start: Position { string: "a", count: 1 },
776 end: Position { string: "b", count: 1 },
777 label: "`a` is a good letter",
778 },
779 SpanLabel {
780 start: Position { string: "c", count: 1 },
781 end: Position { string: "d", count: 1 },
782 label: "",
783 },
784 ],
785 r#"
786error: foo
787 --> test.rs:3:3
788 |
7893 | a bc d
790 | ^^^^----
791 | |
792 | `a` is a good letter
793
794"#,
795 );
796}
797
798#[test]
799fn multiple_labels_without_message() {
800 test_harness(
801 r#"
802fn foo() {
803 a { b { c } d }
804}
805"#,
806 vec![
807 SpanLabel {
808 start: Position { string: "a", count: 1 },
809 end: Position { string: "d", count: 1 },
810 label: "",
811 },
812 SpanLabel {
813 start: Position { string: "b", count: 1 },
814 end: Position { string: "}", count: 1 },
815 label: "",
816 },
817 ],
818 r#"
819error: foo
820 --> test.rs:3:3
821 |
8223 | a { b { c } d }
823 | ^^^^-------^^
824
825"#,
826 );
827}
828
829#[test]
830fn multiple_labels_without_message_2() {
831 test_harness(
832 r#"
833fn foo() {
834 a { b { c } d }
835}
836"#,
837 vec![
838 SpanLabel {
839 start: Position { string: "b", count: 1 },
840 end: Position { string: "}", count: 1 },
841 label: "",
842 },
843 SpanLabel {
844 start: Position { string: "a", count: 1 },
845 end: Position { string: "d", count: 1 },
846 label: "",
847 },
848 SpanLabel {
849 start: Position { string: "c", count: 1 },
850 end: Position { string: "c", count: 1 },
851 label: "",
852 },
853 ],
854 r#"
855error: foo
856 --> test.rs:3:7
857 |
8583 | a { b { c } d }
859 | ----^^^^-^^--
860
861"#,
862 );
863}
864
865#[test]
866fn multiple_labels_with_message() {
867 test_harness(
868 r#"
869fn foo() {
870 a { b { c } d }
871}
872"#,
873 vec![
874 SpanLabel {
875 start: Position { string: "a", count: 1 },
876 end: Position { string: "d", count: 1 },
877 label: "`a` is a good letter",
878 },
879 SpanLabel {
880 start: Position { string: "b", count: 1 },
881 end: Position { string: "}", count: 1 },
882 label: "`b` is a good letter",
883 },
884 ],
885 r#"
886error: foo
887 --> test.rs:3:3
888 |
8893 | a { b { c } d }
890 | ^^^^-------^^
891 | | |
892 | | `b` is a good letter
893 | `a` is a good letter
894
895"#,
896 );
897}
898
899#[test]
900fn single_label_with_message() {
901 test_harness(
902 r#"
903fn foo() {
904 a { b { c } d }
905}
906"#,
907 vec![SpanLabel {
908 start: Position { string: "a", count: 1 },
909 end: Position { string: "d", count: 1 },
910 label: "`a` is a good letter",
911 }],
912 r#"
913error: foo
914 --> test.rs:3:3
915 |
9163 | a { b { c } d }
917 | ^^^^^^^^^^^^^ `a` is a good letter
918
919"#,
920 );
921}
922
923#[test]
924fn single_label_without_message() {
925 test_harness(
926 r#"
927fn foo() {
928 a { b { c } d }
929}
930"#,
931 vec![SpanLabel {
932 start: Position { string: "a", count: 1 },
933 end: Position { string: "d", count: 1 },
934 label: "",
935 }],
936 r#"
937error: foo
938 --> test.rs:3:3
939 |
9403 | a { b { c } d }
941 | ^^^^^^^^^^^^^
942
943"#,
944 );
945}
946
947#[test]
948fn long_snippet() {
949 test_harness(
950 r#"
951fn foo() {
952 X0 Y0 Z0
953 X1 Y1 Z1
9541
9552
9563
9574
9585
9596
9607
9618
9629
96310
964 X2 Y2 Z2
965 X3 Y3 Z3
966}
967"#,
968 vec![
969 SpanLabel {
970 start: Position { string: "Y0", count: 1 },
971 end: Position { string: "X1", count: 1 },
972 label: "`X` is a good letter",
973 },
974 SpanLabel {
975 start: Position { string: "Z1", count: 1 },
976 end: Position { string: "Z3", count: 1 },
977 label: "`Y` is a good letter too",
978 },
979 ],
980 r#"
981error: foo
982 --> test.rs:3:6
983 |
9843 | X0 Y0 Z0
487cf647
FG
985 | _______^
9864 | | X1 Y1 Z1
987 | | ____^____-
dfeec247 988 | ||____|
487cf647
FG
989 | | `X` is a good letter
9905 | | 1
9916 | | 2
9927 | | 3
993... |
99415 | | X2 Y2 Z2
99516 | | X3 Y3 Z3
996 | |__________- `Y` is a good letter too
dfeec247
XL
997
998"#,
999 );
1000}
1001
1002#[test]
1003fn long_snippet_multiple_spans() {
1004 test_harness(
1005 r#"
1006fn foo() {
1007 X0 Y0 Z0
10081
10092
10103
1011 X1 Y1 Z1
10124
10135
10146
1015 X2 Y2 Z2
10167
10178
10189
101910
1020 X3 Y3 Z3
1021}
1022"#,
1023 vec![
1024 SpanLabel {
1025 start: Position { string: "Y0", count: 1 },
1026 end: Position { string: "Y3", count: 1 },
1027 label: "`Y` is a good letter",
1028 },
1029 SpanLabel {
1030 start: Position { string: "Z1", count: 1 },
1031 end: Position { string: "Z2", count: 1 },
1032 label: "`Z` is a good letter too",
1033 },
1034 ],
1035 r#"
1036error: foo
1037 --> test.rs:3:6
1038 |
10393 | X0 Y0 Z0
487cf647
FG
1040 | _______^
10414 | | 1
10425 | | 2
10436 | | 3
10447 | | X1 Y1 Z1
1045 | | _________-
dfeec247
XL
10468 | || 4
10479 | || 5
104810 | || 6
104911 | || X2 Y2 Z2
1050 | ||__________- `Z` is a good letter too
487cf647
FG
1051... |
105215 | | 10
105316 | | X3 Y3 Z3
1054 | |________^ `Y` is a good letter
dfeec247
XL
1055
1056"#,
1057 );
1058}