]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_expand/src/tests.rs
New upstream version 1.69.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;
136023e0 5use rustc_span::create_default_session_if_not_set_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;
9ffffee4 11use rustc_errors::{Handler, MultiSpan, PResult, TerminalUrl};
dfeec247
XL
12
13use std::io;
14use std::io::prelude::*;
15use std::iter::Peekable;
16use std::path::{Path, PathBuf};
17use std::str;
18use std::sync::{Arc, Mutex};
19
20/// Map string to parser (via tts).
21fn string_to_parser(ps: &ParseSess, source_str: String) -> Parser<'_> {
22 new_parser_from_source_str(ps, PathBuf::from("bogofile").into(), source_str)
23}
24
923072b8 25pub(crate) fn with_error_checking_parse<'a, T, F>(s: String, ps: &'a ParseSess, f: F) -> T
dfeec247
XL
26where
27 F: FnOnce(&mut Parser<'a>) -> PResult<'a, T>,
28{
29 let mut p = string_to_parser(&ps, s);
30 let x = f(&mut p).unwrap();
31 p.sess.span_diagnostic.abort_if_errors();
32 x
33}
34
35/// Maps a string to tts, using a made-up filename.
923072b8 36pub(crate) fn string_to_stream(source_str: String) -> TokenStream {
9ffffee4
FG
37 let ps = ParseSess::new(
38 vec![crate::DEFAULT_LOCALE_RESOURCE, rustc_parse::DEFAULT_LOCALE_RESOURCE],
39 FilePathMapping::empty(),
40 );
dfeec247
XL
41 source_file_to_stream(
42 &ps,
43 ps.source_map().new_source_file(PathBuf::from("bogofile").into(), source_str),
44 None,
45 )
dfeec247
XL
46}
47
48/// Parses a string, returns a crate.
923072b8 49pub(crate) fn string_to_crate(source_str: String) -> ast::Crate {
9ffffee4
FG
50 let ps = ParseSess::new(
51 vec![crate::DEFAULT_LOCALE_RESOURCE, rustc_parse::DEFAULT_LOCALE_RESOURCE],
52 FilePathMapping::empty(),
53 );
dfeec247
XL
54 with_error_checking_parse(source_str, &ps, |p| p.parse_crate_mod())
55}
56
57/// Does the given string match the pattern? whitespace in the first string
58/// may be deleted or replaced with other whitespace to match the pattern.
59/// This function is relatively Unicode-ignorant; fortunately, the careful design
60/// of UTF-8 mitigates this ignorance. It doesn't do NKF-normalization(?).
923072b8 61pub(crate) fn matches_codepattern(a: &str, b: &str) -> bool {
dfeec247
XL
62 let mut a_iter = a.chars().peekable();
63 let mut b_iter = b.chars().peekable();
64
65 loop {
66 let (a, b) = match (a_iter.peek(), b_iter.peek()) {
67 (None, None) => return true,
68 (None, _) => return false,
69 (Some(&a), None) => {
70 if rustc_lexer::is_whitespace(a) {
71 break; // Trailing whitespace check is out of loop for borrowck.
72 } else {
73 return false;
74 }
75 }
76 (Some(&a), Some(&b)) => (a, b),
77 };
78
79 if rustc_lexer::is_whitespace(a) && rustc_lexer::is_whitespace(b) {
80 // Skip whitespace for `a` and `b`.
81 scan_for_non_ws_or_end(&mut a_iter);
82 scan_for_non_ws_or_end(&mut b_iter);
83 } else if rustc_lexer::is_whitespace(a) {
84 // Skip whitespace for `a`.
85 scan_for_non_ws_or_end(&mut a_iter);
86 } else if a == b {
87 a_iter.next();
88 b_iter.next();
89 } else {
90 return false;
91 }
92 }
93
94 // Check if a has *only* trailing whitespace.
95 a_iter.all(rustc_lexer::is_whitespace)
96}
97
98/// Advances the given peekable `Iterator` until it reaches a non-whitespace character.
99fn scan_for_non_ws_or_end<I: Iterator<Item = char>>(iter: &mut Peekable<I>) {
5869c6ff 100 while iter.peek().copied().map(rustc_lexer::is_whitespace) == Some(true) {
dfeec247
XL
101 iter.next();
102 }
103}
104
105/// Identifies a position in the text by the n'th occurrence of a string.
106struct Position {
107 string: &'static str,
108 count: usize,
109}
110
111struct SpanLabel {
112 start: Position,
113 end: Position,
114 label: &'static str,
115}
116
923072b8 117pub(crate) struct Shared<T: Write> {
dfeec247
XL
118 pub data: Arc<Mutex<T>>,
119}
120
121impl<T: Write> Write for Shared<T> {
122 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
123 self.data.lock().unwrap().write(buf)
124 }
125
126 fn flush(&mut self) -> io::Result<()> {
127 self.data.lock().unwrap().flush()
128 }
129}
130
131fn test_harness(file_text: &str, span_labels: Vec<SpanLabel>, expected_output: &str) {
136023e0 132 create_default_session_if_not_set_then(|_| {
dfeec247
XL
133 let output = Arc::new(Mutex::new(Vec::new()));
134
9ffffee4
FG
135 let fallback_bundle = rustc_errors::fallback_fluent_bundle(
136 vec![crate::DEFAULT_LOCALE_RESOURCE, rustc_parse::DEFAULT_LOCALE_RESOURCE],
137 false,
138 );
dfeec247
XL
139 let source_map = Lrc::new(SourceMap::new(FilePathMapping::empty()));
140 source_map.new_source_file(Path::new("test.rs").to_owned().into(), file_text.to_owned());
141
142 let primary_span = make_span(&file_text, &span_labels[0].start, &span_labels[0].end);
143 let mut msp = MultiSpan::from_span(primary_span);
144 for span_label in span_labels {
145 let span = make_span(&file_text, &span_label.start, &span_label.end);
064997fb 146 msp.push_span_label(span, span_label.label);
dfeec247
XL
147 println!("span: {:?} label: {:?}", span, span_label.label);
148 println!("text: {:?}", source_map.span_to_snippet(span));
149 }
150
151 let emitter = EmitterWriter::new(
152 Box::new(Shared { data: output.clone() }),
153 Some(source_map.clone()),
04454e1e
FG
154 None,
155 fallback_bundle,
dfeec247
XL
156 false,
157 false,
158 false,
159 None,
160 false,
487cf647 161 false,
9ffffee4 162 TerminalUrl::No,
dfeec247
XL
163 );
164 let handler = Handler::with_emitter(true, None, Box::new(emitter));
9c376795 165 #[allow(rustc::untranslatable_diagnostic)]
dfeec247
XL
166 handler.span_err(msp, "foo");
167
168 assert!(
169 expected_output.chars().next() == Some('\n'),
170 "expected output should begin with newline"
171 );
172 let expected_output = &expected_output[1..];
173
174 let bytes = output.lock().unwrap();
175 let actual_output = str::from_utf8(&bytes).unwrap();
176 println!("expected output:\n------\n{}------", expected_output);
177 println!("actual output:\n------\n{}------", actual_output);
178
179 assert!(expected_output == actual_output)
180 })
181}
182
183fn make_span(file_text: &str, start: &Position, end: &Position) -> Span {
184 let start = make_pos(file_text, start);
185 let end = make_pos(file_text, end) + end.string.len(); // just after matching thing ends
186 assert!(start <= end);
187 Span::with_root_ctxt(BytePos(start as u32), BytePos(end as u32))
188}
189
190fn make_pos(file_text: &str, pos: &Position) -> usize {
191 let mut remainder = file_text;
192 let mut offset = 0;
193 for _ in 0..pos.count {
194 if let Some(n) = remainder.find(&pos.string) {
195 offset += n;
196 remainder = &remainder[n + 1..];
197 } else {
198 panic!("failed to find {} instances of {:?} in {:?}", pos.count, pos.string, file_text);
199 }
200 }
201 offset
202}
203
204#[test]
205fn ends_on_col0() {
206 test_harness(
207 r#"
208fn foo() {
209}
210"#,
211 vec![SpanLabel {
212 start: Position { string: "{", count: 1 },
213 end: Position { string: "}", count: 1 },
214 label: "test",
215 }],
216 r#"
217error: foo
218 --> test.rs:2:10
219 |
2202 | fn foo() {
221 | __________^
2223 | | }
223 | |_^ test
224
225"#,
226 );
227}
228
229#[test]
230fn ends_on_col2() {
231 test_harness(
232 r#"
233fn foo() {
234
235
236 }
237"#,
238 vec![SpanLabel {
239 start: Position { string: "{", count: 1 },
240 end: Position { string: "}", count: 1 },
241 label: "test",
242 }],
243 r#"
244error: foo
245 --> test.rs:2:10
246 |
2472 | fn foo() {
248 | __________^
2493 | |
2504 | |
2515 | | }
252 | |___^ test
253
254"#,
255 );
256}
257#[test]
258fn non_nested() {
259 test_harness(
260 r#"
261fn foo() {
262 X0 Y0
263 X1 Y1
264 X2 Y2
265}
266"#,
267 vec![
268 SpanLabel {
269 start: Position { string: "X0", count: 1 },
270 end: Position { string: "X2", count: 1 },
271 label: "`X` is a good letter",
272 },
273 SpanLabel {
274 start: Position { string: "Y0", count: 1 },
275 end: Position { string: "Y2", count: 1 },
276 label: "`Y` is a good letter too",
277 },
278 ],
279 r#"
280error: foo
281 --> test.rs:3:3
282 |
2833 | X0 Y0
487cf647
FG
284 | ___^__-
285 | |___|
dfeec247
XL
286 | ||
2874 | || X1 Y1
2885 | || X2 Y2
289 | ||____^__- `Y` is a good letter too
487cf647 290 | |_____|
dfeec247
XL
291 | `X` is a good letter
292
293"#,
294 );
295}
296
297#[test]
298fn nested() {
299 test_harness(
300 r#"
301fn foo() {
302 X0 Y0
303 Y1 X1
304}
305"#,
306 vec![
307 SpanLabel {
308 start: Position { string: "X0", count: 1 },
309 end: Position { string: "X1", count: 1 },
310 label: "`X` is a good letter",
311 },
312 SpanLabel {
313 start: Position { string: "Y0", count: 1 },
314 end: Position { string: "Y1", count: 1 },
315 label: "`Y` is a good letter too",
316 },
317 ],
318 r#"
319error: foo
320 --> test.rs:3:3
321 |
3223 | X0 Y0
487cf647
FG
323 | ___^__-
324 | |___|
dfeec247
XL
325 | ||
3264 | || Y1 X1
327 | ||____-__^ `X` is a good letter
487cf647 328 | |____|
dfeec247
XL
329 | `Y` is a good letter too
330
331"#,
332 );
333}
334
335#[test]
336fn different_overlap() {
337 test_harness(
338 r#"
339fn foo() {
340 X0 Y0 Z0
341 X1 Y1 Z1
342 X2 Y2 Z2
343 X3 Y3 Z3
344}
345"#,
346 vec![
347 SpanLabel {
348 start: Position { string: "Y0", count: 1 },
349 end: Position { string: "X2", count: 1 },
350 label: "`X` is a good letter",
351 },
352 SpanLabel {
353 start: Position { string: "Z1", count: 1 },
354 end: Position { string: "X3", count: 1 },
355 label: "`Y` is a good letter too",
356 },
357 ],
358 r#"
359error: foo
360 --> test.rs:3:6
361 |
3623 | X0 Y0 Z0
487cf647
FG
363 | _______^
3644 | | X1 Y1 Z1
365 | | _________-
dfeec247
XL
3665 | || X2 Y2 Z2
367 | ||____^ `X` is a good letter
487cf647
FG
3686 | | X3 Y3 Z3
369 | |____- `Y` is a good letter too
dfeec247
XL
370
371"#,
372 );
373}
374
375#[test]
376fn triple_overlap() {
377 test_harness(
378 r#"
379fn foo() {
380 X0 Y0 Z0
381 X1 Y1 Z1
382 X2 Y2 Z2
383}
384"#,
385 vec![
386 SpanLabel {
387 start: Position { string: "X0", count: 1 },
388 end: Position { string: "X2", count: 1 },
389 label: "`X` is a good letter",
390 },
391 SpanLabel {
392 start: Position { string: "Y0", count: 1 },
393 end: Position { string: "Y2", count: 1 },
394 label: "`Y` is a good letter too",
395 },
396 SpanLabel {
397 start: Position { string: "Z0", count: 1 },
398 end: Position { string: "Z2", count: 1 },
399 label: "`Z` label",
400 },
401 ],
402 r#"
403error: foo
404 --> test.rs:3:3
405 |
4063 | X0 Y0 Z0
487cf647
FG
407 | ___^__-__-
408 | |___|__|
409 | ||___|
dfeec247
XL
410 | |||
4114 | ||| X1 Y1 Z1
4125 | ||| X2 Y2 Z2
413 | |||____^__-__- `Z` label
487cf647
FG
414 | ||_____|__|
415 | |______| `Y` is a good letter too
dfeec247
XL
416 | `X` is a good letter
417
418"#,
419 );
420}
421
422#[test]
423fn triple_exact_overlap() {
424 test_harness(
425 r#"
426fn foo() {
427 X0 Y0 Z0
428 X1 Y1 Z1
429 X2 Y2 Z2
430}
431"#,
432 vec![
433 SpanLabel {
434 start: Position { string: "X0", count: 1 },
435 end: Position { string: "X2", count: 1 },
436 label: "`X` is a good letter",
437 },
438 SpanLabel {
439 start: Position { string: "X0", count: 1 },
440 end: Position { string: "X2", count: 1 },
441 label: "`Y` is a good letter too",
442 },
443 SpanLabel {
444 start: Position { string: "X0", count: 1 },
445 end: Position { string: "X2", count: 1 },
446 label: "`Z` label",
447 },
448 ],
449 r#"
450error: foo
451 --> test.rs:3:3
452 |
4533 | / X0 Y0 Z0
4544 | | X1 Y1 Z1
4555 | | X2 Y2 Z2
456 | | ^
457 | | |
458 | | `X` is a good letter
459 | |____`Y` is a good letter too
460 | `Z` label
461
462"#,
463 );
464}
465
466#[test]
467fn minimum_depth() {
468 test_harness(
469 r#"
470fn foo() {
471 X0 Y0 Z0
472 X1 Y1 Z1
473 X2 Y2 Z2
474 X3 Y3 Z3
475}
476"#,
477 vec![
478 SpanLabel {
479 start: Position { string: "Y0", count: 1 },
480 end: Position { string: "X1", count: 1 },
481 label: "`X` is a good letter",
482 },
483 SpanLabel {
484 start: Position { string: "Y1", count: 1 },
485 end: Position { string: "Z2", count: 1 },
486 label: "`Y` is a good letter too",
487 },
488 SpanLabel {
489 start: Position { string: "X2", count: 1 },
490 end: Position { string: "Y3", count: 1 },
491 label: "`Z`",
492 },
493 ],
494 r#"
495error: foo
496 --> test.rs:3:6
497 |
4983 | X0 Y0 Z0
487cf647
FG
499 | _______^
5004 | | X1 Y1 Z1
501 | | ____^_-
dfeec247 502 | ||____|
487cf647
FG
503 | | `X` is a good letter
5045 | | X2 Y2 Z2
505 | |___-______- `Y` is a good letter too
506 | ___|
507 | |
5086 | | X3 Y3 Z3
509 | |_______- `Z`
dfeec247
XL
510
511"#,
512 );
513}
514
515#[test]
516fn non_overlaping() {
517 test_harness(
518 r#"
519fn foo() {
520 X0 Y0 Z0
521 X1 Y1 Z1
522 X2 Y2 Z2
523 X3 Y3 Z3
524}
525"#,
526 vec![
527 SpanLabel {
528 start: Position { string: "X0", count: 1 },
529 end: Position { string: "X1", count: 1 },
530 label: "`X` is a good letter",
531 },
532 SpanLabel {
533 start: Position { string: "Y2", count: 1 },
534 end: Position { string: "Z3", count: 1 },
535 label: "`Y` is a good letter too",
536 },
537 ],
538 r#"
539error: foo
540 --> test.rs:3:3
541 |
5423 | / X0 Y0 Z0
5434 | | X1 Y1 Z1
544 | |____^ `X` is a good letter
5455 | X2 Y2 Z2
546 | ______-
5476 | | X3 Y3 Z3
548 | |__________- `Y` is a good letter too
549
550"#,
551 );
552}
553
554#[test]
555fn overlaping_start_and_end() {
556 test_harness(
557 r#"
558fn foo() {
559 X0 Y0 Z0
560 X1 Y1 Z1
561 X2 Y2 Z2
562 X3 Y3 Z3
563}
564"#,
565 vec![
566 SpanLabel {
567 start: Position { string: "Y0", count: 1 },
568 end: Position { string: "X1", count: 1 },
569 label: "`X` is a good letter",
570 },
571 SpanLabel {
572 start: Position { string: "Z1", count: 1 },
573 end: Position { string: "Z3", count: 1 },
574 label: "`Y` is a good letter too",
575 },
576 ],
577 r#"
578error: foo
579 --> test.rs:3:6
580 |
5813 | X0 Y0 Z0
487cf647
FG
582 | _______^
5834 | | X1 Y1 Z1
584 | | ____^____-
dfeec247 585 | ||____|
487cf647
FG
586 | | `X` is a good letter
5875 | | X2 Y2 Z2
5886 | | X3 Y3 Z3
589 | |__________- `Y` is a good letter too
dfeec247
XL
590
591"#,
592 );
593}
594
595#[test]
596fn multiple_labels_primary_without_message() {
597 test_harness(
598 r#"
599fn foo() {
600 a { b { c } d }
601}
602"#,
603 vec![
604 SpanLabel {
605 start: Position { string: "b", count: 1 },
606 end: Position { string: "}", count: 1 },
607 label: "",
608 },
609 SpanLabel {
610 start: Position { string: "a", count: 1 },
611 end: Position { string: "d", count: 1 },
612 label: "`a` is a good letter",
613 },
614 SpanLabel {
615 start: Position { string: "c", count: 1 },
616 end: Position { string: "c", count: 1 },
617 label: "",
618 },
619 ],
620 r#"
621error: foo
622 --> test.rs:3:7
623 |
6243 | a { b { c } d }
625 | ----^^^^-^^-- `a` is a good letter
626
627"#,
628 );
629}
630
631#[test]
632fn multiple_labels_secondary_without_message() {
633 test_harness(
634 r#"
635fn foo() {
636 a { b { c } d }
637}
638"#,
639 vec![
640 SpanLabel {
641 start: Position { string: "a", count: 1 },
642 end: Position { string: "d", count: 1 },
643 label: "`a` is a good letter",
644 },
645 SpanLabel {
646 start: Position { string: "b", count: 1 },
647 end: Position { string: "}", count: 1 },
648 label: "",
649 },
650 ],
651 r#"
652error: foo
653 --> test.rs:3:3
654 |
6553 | a { b { c } d }
656 | ^^^^-------^^ `a` is a good letter
657
658"#,
659 );
660}
661
662#[test]
663fn multiple_labels_primary_without_message_2() {
664 test_harness(
665 r#"
666fn foo() {
667 a { b { c } d }
668}
669"#,
670 vec![
671 SpanLabel {
672 start: Position { string: "b", count: 1 },
673 end: Position { string: "}", count: 1 },
674 label: "`b` is a good letter",
675 },
676 SpanLabel {
677 start: Position { string: "a", count: 1 },
678 end: Position { string: "d", count: 1 },
679 label: "",
680 },
681 SpanLabel {
682 start: Position { string: "c", count: 1 },
683 end: Position { string: "c", count: 1 },
684 label: "",
685 },
686 ],
687 r#"
688error: foo
689 --> test.rs:3:7
690 |
6913 | a { b { c } d }
692 | ----^^^^-^^--
693 | |
694 | `b` is a good letter
695
696"#,
697 );
698}
699
700#[test]
701fn multiple_labels_secondary_without_message_2() {
702 test_harness(
703 r#"
704fn foo() {
705 a { b { c } d }
706}
707"#,
708 vec![
709 SpanLabel {
710 start: Position { string: "a", count: 1 },
711 end: Position { string: "d", count: 1 },
712 label: "",
713 },
714 SpanLabel {
715 start: Position { string: "b", count: 1 },
716 end: Position { string: "}", count: 1 },
717 label: "`b` is a good letter",
718 },
719 ],
720 r#"
721error: foo
722 --> test.rs:3:3
723 |
7243 | a { b { c } d }
725 | ^^^^-------^^
726 | |
727 | `b` is a good letter
728
729"#,
730 );
731}
732
733#[test]
734fn multiple_labels_secondary_without_message_3() {
735 test_harness(
736 r#"
737fn foo() {
738 a bc d
739}
740"#,
741 vec![
742 SpanLabel {
743 start: Position { string: "a", count: 1 },
744 end: Position { string: "b", count: 1 },
745 label: "`a` is a good letter",
746 },
747 SpanLabel {
748 start: Position { string: "c", count: 1 },
749 end: Position { string: "d", count: 1 },
750 label: "",
751 },
752 ],
753 r#"
754error: foo
755 --> test.rs:3:3
756 |
7573 | a bc d
758 | ^^^^----
759 | |
760 | `a` is a good letter
761
762"#,
763 );
764}
765
766#[test]
767fn multiple_labels_without_message() {
768 test_harness(
769 r#"
770fn foo() {
771 a { b { c } d }
772}
773"#,
774 vec![
775 SpanLabel {
776 start: Position { string: "a", count: 1 },
777 end: Position { string: "d", count: 1 },
778 label: "",
779 },
780 SpanLabel {
781 start: Position { string: "b", count: 1 },
782 end: Position { string: "}", count: 1 },
783 label: "",
784 },
785 ],
786 r#"
787error: foo
788 --> test.rs:3:3
789 |
7903 | a { b { c } d }
791 | ^^^^-------^^
792
793"#,
794 );
795}
796
797#[test]
798fn multiple_labels_without_message_2() {
799 test_harness(
800 r#"
801fn foo() {
802 a { b { c } d }
803}
804"#,
805 vec![
806 SpanLabel {
807 start: Position { string: "b", count: 1 },
808 end: Position { string: "}", count: 1 },
809 label: "",
810 },
811 SpanLabel {
812 start: Position { string: "a", count: 1 },
813 end: Position { string: "d", count: 1 },
814 label: "",
815 },
816 SpanLabel {
817 start: Position { string: "c", count: 1 },
818 end: Position { string: "c", count: 1 },
819 label: "",
820 },
821 ],
822 r#"
823error: foo
824 --> test.rs:3:7
825 |
8263 | a { b { c } d }
827 | ----^^^^-^^--
828
829"#,
830 );
831}
832
833#[test]
834fn multiple_labels_with_message() {
835 test_harness(
836 r#"
837fn foo() {
838 a { b { c } d }
839}
840"#,
841 vec![
842 SpanLabel {
843 start: Position { string: "a", count: 1 },
844 end: Position { string: "d", count: 1 },
845 label: "`a` is a good letter",
846 },
847 SpanLabel {
848 start: Position { string: "b", count: 1 },
849 end: Position { string: "}", count: 1 },
850 label: "`b` is a good letter",
851 },
852 ],
853 r#"
854error: foo
855 --> test.rs:3:3
856 |
8573 | a { b { c } d }
858 | ^^^^-------^^
859 | | |
860 | | `b` is a good letter
861 | `a` is a good letter
862
863"#,
864 );
865}
866
867#[test]
868fn single_label_with_message() {
869 test_harness(
870 r#"
871fn foo() {
872 a { b { c } d }
873}
874"#,
875 vec![SpanLabel {
876 start: Position { string: "a", count: 1 },
877 end: Position { string: "d", count: 1 },
878 label: "`a` is a good letter",
879 }],
880 r#"
881error: foo
882 --> test.rs:3:3
883 |
8843 | a { b { c } d }
885 | ^^^^^^^^^^^^^ `a` is a good letter
886
887"#,
888 );
889}
890
891#[test]
892fn single_label_without_message() {
893 test_harness(
894 r#"
895fn foo() {
896 a { b { c } d }
897}
898"#,
899 vec![SpanLabel {
900 start: Position { string: "a", count: 1 },
901 end: Position { string: "d", count: 1 },
902 label: "",
903 }],
904 r#"
905error: foo
906 --> test.rs:3:3
907 |
9083 | a { b { c } d }
909 | ^^^^^^^^^^^^^
910
911"#,
912 );
913}
914
915#[test]
916fn long_snippet() {
917 test_harness(
918 r#"
919fn foo() {
920 X0 Y0 Z0
921 X1 Y1 Z1
9221
9232
9243
9254
9265
9276
9287
9298
9309
93110
932 X2 Y2 Z2
933 X3 Y3 Z3
934}
935"#,
936 vec![
937 SpanLabel {
938 start: Position { string: "Y0", count: 1 },
939 end: Position { string: "X1", count: 1 },
940 label: "`X` is a good letter",
941 },
942 SpanLabel {
943 start: Position { string: "Z1", count: 1 },
944 end: Position { string: "Z3", count: 1 },
945 label: "`Y` is a good letter too",
946 },
947 ],
948 r#"
949error: foo
950 --> test.rs:3:6
951 |
9523 | X0 Y0 Z0
487cf647
FG
953 | _______^
9544 | | X1 Y1 Z1
955 | | ____^____-
dfeec247 956 | ||____|
487cf647
FG
957 | | `X` is a good letter
9585 | | 1
9596 | | 2
9607 | | 3
961... |
96215 | | X2 Y2 Z2
96316 | | X3 Y3 Z3
964 | |__________- `Y` is a good letter too
dfeec247
XL
965
966"#,
967 );
968}
969
970#[test]
971fn long_snippet_multiple_spans() {
972 test_harness(
973 r#"
974fn foo() {
975 X0 Y0 Z0
9761
9772
9783
979 X1 Y1 Z1
9804
9815
9826
983 X2 Y2 Z2
9847
9858
9869
98710
988 X3 Y3 Z3
989}
990"#,
991 vec![
992 SpanLabel {
993 start: Position { string: "Y0", count: 1 },
994 end: Position { string: "Y3", count: 1 },
995 label: "`Y` is a good letter",
996 },
997 SpanLabel {
998 start: Position { string: "Z1", count: 1 },
999 end: Position { string: "Z2", count: 1 },
1000 label: "`Z` is a good letter too",
1001 },
1002 ],
1003 r#"
1004error: foo
1005 --> test.rs:3:6
1006 |
10073 | X0 Y0 Z0
487cf647
FG
1008 | _______^
10094 | | 1
10105 | | 2
10116 | | 3
10127 | | X1 Y1 Z1
1013 | | _________-
dfeec247
XL
10148 | || 4
10159 | || 5
101610 | || 6
101711 | || X2 Y2 Z2
1018 | ||__________- `Z` is a good letter too
487cf647
FG
1019... |
102015 | | 10
102116 | | X3 Y3 Z3
1022 | |________^ `Y` is a good letter
dfeec247
XL
1023
1024"#,
1025 );
1026}