]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/test_snippet.rs
Auto merge of #61212 - alexcrichton:skip-rustc, r=pietroalbini
[rust.git] / src / libsyntax / test_snippet.rs
1 use crate::source_map::{SourceMap, FilePathMapping};
2 use crate::with_default_globals;
3
4 use errors::Handler;
5 use errors::emitter::EmitterWriter;
6
7 use std::io;
8 use std::io::prelude::*;
9 use rustc_data_structures::sync::Lrc;
10 use std::str;
11 use std::sync::{Arc, Mutex};
12 use std::path::Path;
13 use syntax_pos::{BytePos, NO_EXPANSION, Span, MultiSpan};
14
15 /// Identify a position in the text by the Nth occurrence of a string.
16 struct Position {
17     string: &'static str,
18     count: usize,
19 }
20
21 struct SpanLabel {
22     start: Position,
23     end: Position,
24     label: &'static str,
25 }
26
27 struct Shared<T: Write> {
28     data: Arc<Mutex<T>>,
29 }
30
31 impl<T: Write> Write for Shared<T> {
32     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
33         self.data.lock().unwrap().write(buf)
34     }
35
36     fn flush(&mut self) -> io::Result<()> {
37         self.data.lock().unwrap().flush()
38     }
39 }
40
41 fn test_harness(file_text: &str, span_labels: Vec<SpanLabel>, expected_output: &str) {
42     with_default_globals(|| {
43         let output = Arc::new(Mutex::new(Vec::new()));
44
45         let source_map = Lrc::new(SourceMap::new(FilePathMapping::empty()));
46         source_map.new_source_file(Path::new("test.rs").to_owned().into(), file_text.to_owned());
47
48         let primary_span = make_span(&file_text, &span_labels[0].start, &span_labels[0].end);
49         let mut msp = MultiSpan::from_span(primary_span);
50         for span_label in span_labels {
51             let span = make_span(&file_text, &span_label.start, &span_label.end);
52             msp.push_span_label(span, span_label.label.to_string());
53             println!("span: {:?} label: {:?}", span, span_label.label);
54             println!("text: {:?}", source_map.span_to_snippet(span));
55         }
56
57         let emitter = EmitterWriter::new(Box::new(Shared { data: output.clone() }),
58                                         Some(source_map.clone()),
59                                         false,
60                                         false,
61                                         false);
62         let handler = Handler::with_emitter(true, None, Box::new(emitter));
63         handler.span_err(msp, "foo");
64
65         assert!(expected_output.chars().next() == Some('\n'),
66                 "expected output should begin with newline");
67         let expected_output = &expected_output[1..];
68
69         let bytes = output.lock().unwrap();
70         let actual_output = str::from_utf8(&bytes).unwrap();
71         println!("expected output:\n------\n{}------", expected_output);
72         println!("actual output:\n------\n{}------", actual_output);
73
74         assert!(expected_output == actual_output)
75     })
76 }
77
78 fn make_span(file_text: &str, start: &Position, end: &Position) -> Span {
79     let start = make_pos(file_text, start);
80     let end = make_pos(file_text, end) + end.string.len(); // just after matching thing ends
81     assert!(start <= end);
82     Span::new(BytePos(start as u32), BytePos(end as u32), NO_EXPANSION)
83 }
84
85 fn make_pos(file_text: &str, pos: &Position) -> usize {
86     let mut remainder = file_text;
87     let mut offset = 0;
88     for _ in 0..pos.count {
89         if let Some(n) = remainder.find(&pos.string) {
90             offset += n;
91             remainder = &remainder[n + 1..];
92         } else {
93             panic!("failed to find {} instances of {:?} in {:?}",
94                    pos.count,
95                    pos.string,
96                    file_text);
97         }
98     }
99     offset
100 }
101
102 #[test]
103 fn ends_on_col0() {
104     test_harness(r#"
105 fn foo() {
106 }
107 "#,
108     vec![
109         SpanLabel {
110            start: Position {
111                string: "{",
112                count: 1,
113            },
114            end: Position {
115                string: "}",
116                count: 1,
117            },
118            label: "test",
119        },
120     ],
121     r#"
122 error: foo
123  --> test.rs:2:10
124   |
125 2 |   fn foo() {
126   |  __________^
127 3 | | }
128   | |_^ test
129
130 "#);
131 }
132
133 #[test]
134 fn ends_on_col2() {
135     test_harness(r#"
136 fn foo() {
137
138
139   }
140 "#,
141      vec![
142         SpanLabel {
143             start: Position {
144                 string: "{",
145                 count: 1,
146             },
147             end: Position {
148                 string: "}",
149                 count: 1,
150             },
151             label: "test",
152         },
153      ],
154      r#"
155 error: foo
156  --> test.rs:2:10
157   |
158 2 |   fn foo() {
159   |  __________^
160 3 | |
161 4 | |
162 5 | |   }
163   | |___^ test
164
165 "#);
166 }
167 #[test]
168 fn non_nested() {
169     test_harness(r#"
170 fn foo() {
171   X0 Y0
172   X1 Y1
173   X2 Y2
174 }
175 "#,
176     vec![
177         SpanLabel {
178             start: Position {
179                 string: "X0",
180                 count: 1,
181             },
182             end: Position {
183                 string: "X2",
184                 count: 1,
185             },
186             label: "`X` is a good letter",
187         },
188         SpanLabel {
189             start: Position {
190                 string: "Y0",
191                 count: 1,
192             },
193             end: Position {
194                 string: "Y2",
195                 count: 1,
196             },
197             label: "`Y` is a good letter too",
198         },
199     ],
200     r#"
201 error: foo
202  --> test.rs:3:3
203   |
204 3 |      X0 Y0
205   |  ____^__-
206   | | ___|
207   | ||
208 4 | ||   X1 Y1
209 5 | ||   X2 Y2
210   | ||____^__- `Y` is a good letter too
211   |  |____|
212   |       `X` is a good letter
213
214 "#);
215 }
216
217 #[test]
218 fn nested() {
219     test_harness(r#"
220 fn foo() {
221   X0 Y0
222   Y1 X1
223 }
224 "#,
225     vec![
226         SpanLabel {
227             start: Position {
228                 string: "X0",
229                 count: 1,
230             },
231             end: Position {
232                 string: "X1",
233                 count: 1,
234             },
235             label: "`X` is a good letter",
236         },
237         SpanLabel {
238             start: Position {
239                 string: "Y0",
240                 count: 1,
241             },
242             end: Position {
243                 string: "Y1",
244                 count: 1,
245             },
246             label: "`Y` is a good letter too",
247         },
248     ],
249 r#"
250 error: foo
251  --> test.rs:3:3
252   |
253 3 |      X0 Y0
254   |  ____^__-
255   | | ___|
256   | ||
257 4 | ||   Y1 X1
258   | ||____-__^ `X` is a good letter
259   | |_____|
260   |       `Y` is a good letter too
261
262 "#);
263 }
264
265 #[test]
266 fn different_overlap() {
267     test_harness(r#"
268 fn foo() {
269   X0 Y0 Z0
270   X1 Y1 Z1
271   X2 Y2 Z2
272   X3 Y3 Z3
273 }
274 "#,
275     vec![
276         SpanLabel {
277             start: Position {
278                 string: "Y0",
279                 count: 1,
280             },
281             end: Position {
282                 string: "X2",
283                 count: 1,
284             },
285             label: "`X` is a good letter",
286         },
287         SpanLabel {
288             start: Position {
289                 string: "Z1",
290                 count: 1,
291             },
292             end: Position {
293                 string: "X3",
294                 count: 1,
295             },
296             label: "`Y` is a good letter too",
297         },
298     ],
299     r#"
300 error: foo
301  --> test.rs:3:6
302   |
303 3 |      X0 Y0 Z0
304   |   ______^
305 4 |  |   X1 Y1 Z1
306   |  |_________-
307 5 | ||   X2 Y2 Z2
308   | ||____^ `X` is a good letter
309 6 | |    X3 Y3 Z3
310   | |_____- `Y` is a good letter too
311
312 "#);
313 }
314
315 #[test]
316 fn triple_overlap() {
317     test_harness(r#"
318 fn foo() {
319   X0 Y0 Z0
320   X1 Y1 Z1
321   X2 Y2 Z2
322 }
323 "#,
324     vec![
325         SpanLabel {
326             start: Position {
327                 string: "X0",
328                 count: 1,
329             },
330             end: Position {
331                 string: "X2",
332                 count: 1,
333             },
334             label: "`X` is a good letter",
335         },
336         SpanLabel {
337             start: Position {
338                 string: "Y0",
339                 count: 1,
340             },
341             end: Position {
342                 string: "Y2",
343                 count: 1,
344             },
345             label: "`Y` is a good letter too",
346         },
347         SpanLabel {
348             start: Position {
349                 string: "Z0",
350                 count: 1,
351             },
352             end: Position {
353                 string: "Z2",
354                 count: 1,
355             },
356             label: "`Z` label",
357         },
358     ],
359     r#"
360 error: foo
361  --> test.rs:3:3
362   |
363 3 |       X0 Y0 Z0
364   |  _____^__-__-
365   | | ____|__|
366   | || ___|
367   | |||
368 4 | |||   X1 Y1 Z1
369 5 | |||   X2 Y2 Z2
370   | |||____^__-__- `Z` label
371   |  ||____|__|
372   |   |____|  `Y` is a good letter too
373   |        `X` is a good letter
374
375 "#);
376 }
377
378 #[test]
379 fn triple_exact_overlap() {
380     test_harness(r#"
381 fn foo() {
382   X0 Y0 Z0
383   X1 Y1 Z1
384   X2 Y2 Z2
385 }
386 "#,
387     vec![
388         SpanLabel {
389             start: Position {
390                 string: "X0",
391                 count: 1,
392             },
393             end: Position {
394                 string: "X2",
395                 count: 1,
396             },
397             label: "`X` is a good letter",
398         },
399         SpanLabel {
400             start: Position {
401                 string: "X0",
402                 count: 1,
403             },
404             end: Position {
405                 string: "X2",
406                 count: 1,
407             },
408             label: "`Y` is a good letter too",
409         },
410         SpanLabel {
411             start: Position {
412                 string: "X0",
413                 count: 1,
414             },
415             end: Position {
416                 string: "X2",
417                 count: 1,
418             },
419             label: "`Z` label",
420         },
421     ],
422     r#"
423 error: foo
424  --> test.rs:3:3
425   |
426 3 | /   X0 Y0 Z0
427 4 | |   X1 Y1 Z1
428 5 | |   X2 Y2 Z2
429   | |    ^
430   | |    |
431   | |    `X` is a good letter
432   | |____`Y` is a good letter too
433   |      `Z` label
434
435 "#);
436 }
437
438 #[test]
439 fn minimum_depth() {
440     test_harness(r#"
441 fn foo() {
442   X0 Y0 Z0
443   X1 Y1 Z1
444   X2 Y2 Z2
445   X3 Y3 Z3
446 }
447 "#,
448     vec![
449         SpanLabel {
450             start: Position {
451                 string: "Y0",
452                 count: 1,
453             },
454             end: Position {
455                 string: "X1",
456                 count: 1,
457             },
458             label: "`X` is a good letter",
459         },
460         SpanLabel {
461             start: Position {
462                 string: "Y1",
463                 count: 1,
464             },
465             end: Position {
466                 string: "Z2",
467                 count: 1,
468             },
469             label: "`Y` is a good letter too",
470         },
471         SpanLabel {
472             start: Position {
473                 string: "X2",
474                 count: 1,
475             },
476             end: Position {
477                 string: "Y3",
478                 count: 1,
479             },
480             label: "`Z`",
481         },
482     ],
483     r#"
484 error: foo
485  --> test.rs:3:6
486   |
487 3 |      X0 Y0 Z0
488   |   ______^
489 4 |  |   X1 Y1 Z1
490   |  |____^_-
491   | ||____|
492   | |     `X` is a good letter
493 5 | |    X2 Y2 Z2
494   | |____-______- `Y` is a good letter too
495   |  ____|
496   | |
497 6 | |    X3 Y3 Z3
498   | |________- `Z`
499
500 "#);
501 }
502
503 #[test]
504 fn non_overlaping() {
505     test_harness(r#"
506 fn foo() {
507   X0 Y0 Z0
508   X1 Y1 Z1
509   X2 Y2 Z2
510   X3 Y3 Z3
511 }
512 "#,
513     vec![
514         SpanLabel {
515             start: Position {
516                 string: "X0",
517                 count: 1,
518             },
519             end: Position {
520                 string: "X1",
521                 count: 1,
522             },
523             label: "`X` is a good letter",
524         },
525         SpanLabel {
526             start: Position {
527                 string: "Y2",
528                 count: 1,
529             },
530             end: Position {
531                 string: "Z3",
532                 count: 1,
533             },
534             label: "`Y` is a good letter too",
535         },
536     ],
537     r#"
538 error: foo
539  --> test.rs:3:3
540   |
541 3 | /   X0 Y0 Z0
542 4 | |   X1 Y1 Z1
543   | |____^ `X` is a good letter
544 5 |     X2 Y2 Z2
545   |  ______-
546 6 | |   X3 Y3 Z3
547   | |__________- `Y` is a good letter too
548
549 "#);
550 }
551
552 #[test]
553 fn overlaping_start_and_end() {
554     test_harness(r#"
555 fn foo() {
556   X0 Y0 Z0
557   X1 Y1 Z1
558   X2 Y2 Z2
559   X3 Y3 Z3
560 }
561 "#,
562     vec![
563         SpanLabel {
564             start: Position {
565                 string: "Y0",
566                 count: 1,
567             },
568             end: Position {
569                 string: "X1",
570                 count: 1,
571             },
572             label: "`X` is a good letter",
573         },
574         SpanLabel {
575             start: Position {
576                 string: "Z1",
577                 count: 1,
578             },
579             end: Position {
580                 string: "Z3",
581                 count: 1,
582             },
583             label: "`Y` is a good letter too",
584         },
585     ],
586     r#"
587 error: foo
588  --> test.rs:3:6
589   |
590 3 |      X0 Y0 Z0
591   |   ______^
592 4 |  |   X1 Y1 Z1
593   |  |____^____-
594   | ||____|
595   | |     `X` is a good letter
596 5 | |    X2 Y2 Z2
597 6 | |    X3 Y3 Z3
598   | |___________- `Y` is a good letter too
599
600 "#);
601 }
602
603 #[test]
604 fn multiple_labels_primary_without_message() {
605     test_harness(r#"
606 fn foo() {
607   a { b { c } d }
608 }
609 "#,
610     vec![
611         SpanLabel {
612             start: Position {
613                 string: "b",
614                 count: 1,
615             },
616             end: Position {
617                 string: "}",
618                 count: 1,
619             },
620             label: "",
621         },
622         SpanLabel {
623             start: Position {
624                 string: "a",
625                 count: 1,
626             },
627             end: Position {
628                 string: "d",
629                 count: 1,
630             },
631             label: "`a` is a good letter",
632         },
633         SpanLabel {
634             start: Position {
635                 string: "c",
636                 count: 1,
637             },
638             end: Position {
639                 string: "c",
640                 count: 1,
641             },
642             label: "",
643         },
644     ],
645     r#"
646 error: foo
647  --> test.rs:3:7
648   |
649 3 |   a { b { c } d }
650   |   ----^^^^-^^-- `a` is a good letter
651
652 "#);
653 }
654
655 #[test]
656 fn multiple_labels_secondary_without_message() {
657     test_harness(r#"
658 fn foo() {
659   a { b { c } d }
660 }
661 "#,
662     vec![
663         SpanLabel {
664             start: Position {
665                 string: "a",
666                 count: 1,
667             },
668             end: Position {
669                 string: "d",
670                 count: 1,
671             },
672             label: "`a` is a good letter",
673         },
674         SpanLabel {
675             start: Position {
676                 string: "b",
677                 count: 1,
678             },
679             end: Position {
680                 string: "}",
681                 count: 1,
682             },
683             label: "",
684         },
685     ],
686     r#"
687 error: foo
688  --> test.rs:3:3
689   |
690 3 |   a { b { c } d }
691   |   ^^^^-------^^ `a` is a good letter
692
693 "#);
694 }
695
696 #[test]
697 fn multiple_labels_primary_without_message_2() {
698     test_harness(r#"
699 fn foo() {
700   a { b { c } d }
701 }
702 "#,
703     vec![
704         SpanLabel {
705             start: Position {
706                 string: "b",
707                 count: 1,
708             },
709             end: Position {
710                 string: "}",
711                 count: 1,
712             },
713             label: "`b` is a good letter",
714         },
715         SpanLabel {
716             start: Position {
717                 string: "a",
718                 count: 1,
719             },
720             end: Position {
721                 string: "d",
722                 count: 1,
723             },
724             label: "",
725         },
726         SpanLabel {
727             start: Position {
728                 string: "c",
729                 count: 1,
730             },
731             end: Position {
732                 string: "c",
733                 count: 1,
734             },
735             label: "",
736         },
737     ],
738     r#"
739 error: foo
740  --> test.rs:3:7
741   |
742 3 |   a { b { c } d }
743   |   ----^^^^-^^--
744   |       |
745   |       `b` is a good letter
746
747 "#);
748 }
749
750 #[test]
751 fn multiple_labels_secondary_without_message_2() {
752     test_harness(r#"
753 fn foo() {
754   a { b { c } d }
755 }
756 "#,
757     vec![
758         SpanLabel {
759             start: Position {
760                 string: "a",
761                 count: 1,
762             },
763             end: Position {
764                 string: "d",
765                 count: 1,
766             },
767             label: "",
768         },
769         SpanLabel {
770             start: Position {
771                 string: "b",
772                 count: 1,
773             },
774             end: Position {
775                 string: "}",
776                 count: 1,
777             },
778             label: "`b` is a good letter",
779         },
780     ],
781     r#"
782 error: foo
783  --> test.rs:3:3
784   |
785 3 |   a { b { c } d }
786   |   ^^^^-------^^
787   |       |
788   |       `b` is a good letter
789
790 "#);
791 }
792
793 #[test]
794 fn multiple_labels_secondary_without_message_3() {
795     test_harness(r#"
796 fn foo() {
797   a  bc  d
798 }
799 "#,
800     vec![
801         SpanLabel {
802             start: Position {
803                 string: "a",
804                 count: 1,
805             },
806             end: Position {
807                 string: "b",
808                 count: 1,
809             },
810             label: "`a` is a good letter",
811         },
812         SpanLabel {
813             start: Position {
814                 string: "c",
815                 count: 1,
816             },
817             end: Position {
818                 string: "d",
819                 count: 1,
820             },
821             label: "",
822         },
823     ],
824     r#"
825 error: foo
826  --> test.rs:3:3
827   |
828 3 |   a  bc  d
829   |   ^^^^----
830   |   |
831   |   `a` is a good letter
832
833 "#);
834 }
835
836 #[test]
837 fn multiple_labels_without_message() {
838     test_harness(r#"
839 fn foo() {
840   a { b { c } d }
841 }
842 "#,
843     vec![
844         SpanLabel {
845             start: Position {
846                 string: "a",
847                 count: 1,
848             },
849             end: Position {
850                 string: "d",
851                 count: 1,
852             },
853             label: "",
854         },
855         SpanLabel {
856             start: Position {
857                 string: "b",
858                 count: 1,
859             },
860             end: Position {
861                 string: "}",
862                 count: 1,
863             },
864             label: "",
865         },
866     ],
867     r#"
868 error: foo
869  --> test.rs:3:3
870   |
871 3 |   a { b { c } d }
872   |   ^^^^-------^^
873
874 "#);
875 }
876
877 #[test]
878 fn multiple_labels_without_message_2() {
879     test_harness(r#"
880 fn foo() {
881   a { b { c } d }
882 }
883 "#,
884     vec![
885         SpanLabel {
886             start: Position {
887                 string: "b",
888                 count: 1,
889             },
890             end: Position {
891                 string: "}",
892                 count: 1,
893             },
894             label: "",
895         },
896         SpanLabel {
897             start: Position {
898                 string: "a",
899                 count: 1,
900             },
901             end: Position {
902                 string: "d",
903                 count: 1,
904             },
905             label: "",
906         },
907         SpanLabel {
908             start: Position {
909                 string: "c",
910                 count: 1,
911             },
912             end: Position {
913                 string: "c",
914                 count: 1,
915             },
916             label: "",
917         },
918     ],
919     r#"
920 error: foo
921  --> test.rs:3:7
922   |
923 3 |   a { b { c } d }
924   |   ----^^^^-^^--
925
926 "#);
927 }
928
929 #[test]
930 fn multiple_labels_with_message() {
931     test_harness(r#"
932 fn foo() {
933   a { b { c } d }
934 }
935 "#,
936     vec![
937         SpanLabel {
938             start: Position {
939                 string: "a",
940                 count: 1,
941             },
942             end: Position {
943                 string: "d",
944                 count: 1,
945             },
946             label: "`a` is a good letter",
947         },
948         SpanLabel {
949             start: Position {
950                 string: "b",
951                 count: 1,
952             },
953             end: Position {
954                 string: "}",
955                 count: 1,
956             },
957             label: "`b` is a good letter",
958         },
959     ],
960     r#"
961 error: foo
962  --> test.rs:3:3
963   |
964 3 |   a { b { c } d }
965   |   ^^^^-------^^
966   |   |   |
967   |   |   `b` is a good letter
968   |   `a` is a good letter
969
970 "#);
971 }
972
973 #[test]
974 fn single_label_with_message() {
975     test_harness(r#"
976 fn foo() {
977   a { b { c } d }
978 }
979 "#,
980     vec![
981         SpanLabel {
982             start: Position {
983                 string: "a",
984                 count: 1,
985             },
986             end: Position {
987                 string: "d",
988                 count: 1,
989             },
990             label: "`a` is a good letter",
991         },
992     ],
993     r#"
994 error: foo
995  --> test.rs:3:3
996   |
997 3 |   a { b { c } d }
998   |   ^^^^^^^^^^^^^ `a` is a good letter
999
1000 "#);
1001 }
1002
1003 #[test]
1004 fn single_label_without_message() {
1005     test_harness(r#"
1006 fn foo() {
1007   a { b { c } d }
1008 }
1009 "#,
1010     vec![
1011         SpanLabel {
1012             start: Position {
1013                 string: "a",
1014                 count: 1,
1015             },
1016             end: Position {
1017                 string: "d",
1018                 count: 1,
1019             },
1020             label: "",
1021         },
1022     ],
1023     r#"
1024 error: foo
1025  --> test.rs:3:3
1026   |
1027 3 |   a { b { c } d }
1028   |   ^^^^^^^^^^^^^
1029
1030 "#);
1031 }
1032
1033 #[test]
1034 fn long_snippet() {
1035     test_harness(r#"
1036 fn foo() {
1037   X0 Y0 Z0
1038   X1 Y1 Z1
1039 1
1040 2
1041 3
1042 4
1043 5
1044 6
1045 7
1046 8
1047 9
1048 10
1049   X2 Y2 Z2
1050   X3 Y3 Z3
1051 }
1052 "#,
1053     vec![
1054         SpanLabel {
1055             start: Position {
1056                 string: "Y0",
1057                 count: 1,
1058             },
1059             end: Position {
1060                 string: "X1",
1061                 count: 1,
1062             },
1063             label: "`X` is a good letter",
1064         },
1065         SpanLabel {
1066             start: Position {
1067                 string: "Z1",
1068                 count: 1,
1069             },
1070             end: Position {
1071                 string: "Z3",
1072                 count: 1,
1073             },
1074             label: "`Y` is a good letter too",
1075         },
1076     ],
1077     r#"
1078 error: foo
1079   --> test.rs:3:6
1080    |
1081 3  |      X0 Y0 Z0
1082    |   ______^
1083 4  |  |   X1 Y1 Z1
1084    |  |____^____-
1085    | ||____|
1086    | |     `X` is a good letter
1087 5  | |  1
1088 6  | |  2
1089 7  | |  3
1090 ...  |
1091 15 | |    X2 Y2 Z2
1092 16 | |    X3 Y3 Z3
1093    | |___________- `Y` is a good letter too
1094
1095 "#);
1096 }
1097
1098 #[test]
1099 fn long_snippet_multiple_spans() {
1100     test_harness(r#"
1101 fn foo() {
1102   X0 Y0 Z0
1103 1
1104 2
1105 3
1106   X1 Y1 Z1
1107 4
1108 5
1109 6
1110   X2 Y2 Z2
1111 7
1112 8
1113 9
1114 10
1115   X3 Y3 Z3
1116 }
1117 "#,
1118     vec![
1119         SpanLabel {
1120             start: Position {
1121                 string: "Y0",
1122                 count: 1,
1123             },
1124             end: Position {
1125                 string: "Y3",
1126                 count: 1,
1127             },
1128             label: "`Y` is a good letter",
1129         },
1130         SpanLabel {
1131             start: Position {
1132                 string: "Z1",
1133                 count: 1,
1134             },
1135             end: Position {
1136                 string: "Z2",
1137                 count: 1,
1138             },
1139             label: "`Z` is a good letter too",
1140         },
1141     ],
1142     r#"
1143 error: foo
1144   --> test.rs:3:6
1145    |
1146 3  |      X0 Y0 Z0
1147    |   ______^
1148 4  |  | 1
1149 5  |  | 2
1150 6  |  | 3
1151 7  |  |   X1 Y1 Z1
1152    |  |_________-
1153 8  | || 4
1154 9  | || 5
1155 10 | || 6
1156 11 | ||   X2 Y2 Z2
1157    | ||__________- `Z` is a good letter too
1158 ...   |
1159 15 |  | 10
1160 16 |  |   X3 Y3 Z3
1161    |  |_______^ `Y` is a good letter
1162
1163 "#);
1164 }