1 // Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 use codemap::{CodeMap, FilePathMapping};
13 use errors::emitter::EmitterWriter;
15 use std::io::prelude::*;
16 use rustc_data_structures::sync::Lrc;
18 use std::sync::{Arc, Mutex};
20 use syntax_pos::{BytePos, NO_EXPANSION, Span, MultiSpan};
23 /// Identify a position in the text by the Nth occurrence of a string.
35 struct Shared<T: Write> {
39 impl<T: Write> Write for Shared<T> {
40 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
41 self.data.lock().unwrap().write(buf)
44 fn flush(&mut self) -> io::Result<()> {
45 self.data.lock().unwrap().flush()
49 fn test_harness(file_text: &str, span_labels: Vec<SpanLabel>, expected_output: &str) {
51 let output = Arc::new(Mutex::new(Vec::new()));
53 let code_map = Lrc::new(CodeMap::new(FilePathMapping::empty()));
54 code_map.new_filemap(Path::new("test.rs").to_owned().into(), file_text.to_owned());
56 let primary_span = make_span(&file_text, &span_labels[0].start, &span_labels[0].end);
57 let mut msp = MultiSpan::from_span(primary_span);
58 for span_label in span_labels {
59 let span = make_span(&file_text, &span_label.start, &span_label.end);
60 msp.push_span_label(span, span_label.label.to_string());
61 println!("span: {:?} label: {:?}", span, span_label.label);
62 println!("text: {:?}", code_map.span_to_snippet(span));
65 let emitter = EmitterWriter::new(Box::new(Shared { data: output.clone() }),
66 Some(code_map.clone()),
69 let handler = Handler::with_emitter(true, false, Box::new(emitter));
70 handler.span_err(msp, "foo");
72 assert!(expected_output.chars().next() == Some('\n'),
73 "expected output should begin with newline");
74 let expected_output = &expected_output[1..];
76 let bytes = output.lock().unwrap();
77 let actual_output = str::from_utf8(&bytes).unwrap();
78 println!("expected output:\n------\n{}------", expected_output);
79 println!("actual output:\n------\n{}------", actual_output);
81 assert!(expected_output == actual_output)
85 fn make_span(file_text: &str, start: &Position, end: &Position) -> Span {
86 let start = make_pos(file_text, start);
87 let end = make_pos(file_text, end) + end.string.len(); // just after matching thing ends
88 assert!(start <= end);
89 Span::new(BytePos(start as u32), BytePos(end as u32), NO_EXPANSION)
92 fn make_pos(file_text: &str, pos: &Position) -> usize {
93 let mut remainder = file_text;
95 for _ in 0..pos.count {
96 if let Some(n) = remainder.find(&pos.string) {
98 remainder = &remainder[n + 1..];
100 panic!("failed to find {} instances of {:?} in {:?}",
193 label: "`X` is a good letter",
204 label: "`Y` is a good letter too",
217 | ||____^__- `Y` is a good letter too
219 | `X` is a good letter
242 label: "`X` is a good letter",
253 label: "`Y` is a good letter too",
265 | ||____-__^ `X` is a good letter
267 | `Y` is a good letter too
273 fn different_overlap() {
292 label: "`X` is a good letter",
303 label: "`Y` is a good letter too",
315 | ||____^ `X` is a good letter
317 | |_____- `Y` is a good letter too
323 fn triple_overlap() {
341 label: "`X` is a good letter",
352 label: "`Y` is a good letter too",
377 | |||____^__-__- `Z` label
379 | |____| `Y` is a good letter too
380 | `X` is a good letter
405 label: "`X` is a good letter",
416 label: "`Y` is a good letter too",
439 | | `X` is a good letter
441 | |____-______- `Y` is a good letter too
451 fn non_overlaping() {
470 label: "`X` is a good letter",
481 label: "`Y` is a good letter too",
490 | |____^ `X` is a good letter
494 | |__________- `Y` is a good letter too
500 fn overlaping_start_and_end() {
519 label: "`X` is a good letter",
530 label: "`Y` is a good letter too",
542 | | `X` is a good letter
545 | |___________- `Y` is a good letter too
551 fn multiple_labels_primary_without_message() {
578 label: "`a` is a good letter",
597 | ----^^^^-^^-- `a` is a good letter
603 fn multiple_labels_secondary_without_message() {
619 label: "`a` is a good letter",
638 | ^^^^-------^^ `a` is a good letter
644 fn multiple_labels_primary_without_message_2() {
660 label: "`b` is a good letter",
692 | `b` is a good letter
698 fn multiple_labels_secondary_without_message_2() {
725 label: "`b` is a good letter",
735 | `b` is a good letter
741 fn multiple_labels_secondary_without_message_3() {
757 label: "`a` is a good letter",
778 | `a` is a good letter
784 fn multiple_labels_without_message() {
825 fn multiple_labels_without_message_2() {
877 fn multiple_labels_with_message() {
893 label: "`a` is a good letter",
904 label: "`b` is a good letter",
914 | | `b` is a good letter
915 | `a` is a good letter
921 fn single_label_with_message() {
937 label: "`a` is a good letter",
945 | ^^^^^^^^^^^^^ `a` is a good letter
951 fn single_label_without_message() {
1010 label: "`X` is a good letter",
1021 label: "`Y` is a good letter too",
1033 | | `X` is a good letter
1040 | |___________- `Y` is a good letter too
1046 fn long_snippet_multiple_spans() {
1075 label: "`Y` is a good letter",
1086 label: "`Z` is a good letter too",
1104 | ||__________- `Z` is a good letter too
1108 | |_______^ `Y` is a good letter