about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/lib.rs3
-rw-r--r--src/libsyntax/test_snippet.rs446
2 files changed, 449 insertions, 0 deletions
diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs
index 34280812421..0545cccabf7 100644
--- a/src/libsyntax/lib.rs
+++ b/src/libsyntax/lib.rs
@@ -144,4 +144,7 @@ pub mod ext {
     }
 }
 
+#[cfg(test)]
+mod test_snippet;
+
 // __build_diagnostic_array! { libsyntax, DIAGNOSTICS }
diff --git a/src/libsyntax/test_snippet.rs b/src/libsyntax/test_snippet.rs
new file mode 100644
index 00000000000..4ce51076adc
--- /dev/null
+++ b/src/libsyntax/test_snippet.rs
@@ -0,0 +1,446 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use codemap::CodeMap;
+use errors::Handler;
+use errors::emitter::EmitterWriter;
+use std::io;
+use std::io::prelude::*;
+use std::rc::Rc;
+use std::str;
+use std::sync::{Arc, Mutex};
+use syntax_pos::{BytePos, NO_EXPANSION, Span, MultiSpan};
+
+/// Identify a position in the text by the Nth occurrence of a string.
+struct Position {
+    string: &'static str,
+    count: usize,
+}
+
+struct SpanLabel {
+    start: Position,
+    end: Position,
+    label: &'static str,
+}
+
+struct Shared<T: Write> {
+    data: Arc<Mutex<T>>,
+}
+
+impl<T: Write> Write for Shared<T> {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        self.data.lock().unwrap().write(buf)
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        self.data.lock().unwrap().flush()
+    }
+}
+
+fn test_harness(file_text: &str, span_labels: Vec<SpanLabel>, expected_output: &str) {
+    let output = Arc::new(Mutex::new(Vec::new()));
+
+    let code_map = Rc::new(CodeMap::new());
+    code_map.new_filemap_and_lines("test.rs", None, &file_text);
+
+    let primary_span = make_span(&file_text, &span_labels[0].start, &span_labels[0].end);
+    let mut msp = MultiSpan::from_span(primary_span);
+    for span_label in span_labels {
+        let span = make_span(&file_text, &span_label.start, &span_label.end);
+        msp.push_span_label(span, span_label.label.to_string());
+        println!("span: {:?} label: {:?}", span, span_label.label);
+        println!("text: {:?}", code_map.span_to_snippet(span));
+    }
+
+    let emitter = EmitterWriter::new(Box::new(Shared { data: output.clone() }),
+                                     Some(code_map.clone()));
+    let handler = Handler::with_emitter(true, false, Box::new(emitter));
+    handler.span_err(msp, "foo");
+
+    assert!(expected_output.chars().next() == Some('\n'),
+            "expected output should begin with newline");
+    let expected_output = &expected_output[1..];
+
+    let bytes = output.lock().unwrap();
+    let actual_output = str::from_utf8(&bytes).unwrap();
+    println!("expected output:\n------\n{}------", expected_output);
+    println!("actual output:\n------\n{}------", actual_output);
+
+    assert!(expected_output == actual_output)
+}
+
+fn make_span(file_text: &str, start: &Position, end: &Position) -> Span {
+    let start = make_pos(file_text, start);
+    let end = make_pos(file_text, end) + end.string.len(); // just after matching thing ends
+    assert!(start <= end);
+    Span {
+        lo: BytePos(start as u32),
+        hi: BytePos(end as u32),
+        expn_id: NO_EXPANSION,
+    }
+}
+
+fn make_pos(file_text: &str, pos: &Position) -> usize {
+    let mut remainder = file_text;
+    let mut offset = 0;
+    for _ in 0..pos.count {
+        if let Some(n) = remainder.find(&pos.string) {
+            offset += n;
+            remainder = &remainder[n + 1..];
+        } else {
+            panic!("failed to find {} instances of {:?} in {:?}",
+                   pos.count,
+                   pos.string,
+                   file_text);
+        }
+    }
+    offset
+}
+
+#[test]
+fn ends_on_col0() {
+    test_harness(r#"
+fn foo() {
+}
+"#,
+    vec![
+        SpanLabel {
+           start: Position {
+               string: "{",
+               count: 1,
+           },
+           end: Position {
+               string: "}",
+               count: 1,
+           },
+           label: "test",
+       },
+    ],
+    r#"
+error: foo
+ --> test.rs:2:10
+  |
+2 |   fn foo() {
+  |  __________^ starting here...
+3 | | }
+  | |_^ ...ending here: test
+
+"#);
+}
+
+#[test]
+fn ends_on_col2() {
+    test_harness(r#"
+fn foo() {
+
+
+  }
+"#,
+     vec![
+        SpanLabel {
+            start: Position {
+                string: "{",
+                count: 1,
+            },
+            end: Position {
+                string: "}",
+                count: 1,
+            },
+            label: "test",
+        },
+     ],
+     r#"
+error: foo
+ --> test.rs:2:10
+  |
+2 |   fn foo() {
+  |  __________^ starting here...
+3 | |
+4 | |
+5 | |   }
+  | |___^ ...ending here: test
+
+"#);
+}
+#[test]
+fn non_nested() {
+    test_harness(r#"
+fn foo() {
+  X0 Y0
+  X1 Y1
+  X2 Y2
+}
+"#,
+    vec![
+        SpanLabel {
+            start: Position {
+                string: "X0",
+                count: 1,
+            },
+            end: Position {
+                string: "X2",
+                count: 1,
+            },
+            label: "`X` is a good letter",
+        },
+        SpanLabel {
+            start: Position {
+                string: "Y0",
+                count: 1,
+            },
+            end: Position {
+                string: "Y2",
+                count: 1,
+            },
+            label: "`Y` is a good letter too",
+        },
+    ],
+    r#"
+error: foo
+ --> test.rs:3:3
+  |
+3 |      X0 Y0
+  |  ____^__- starting here...
+  | | ___|
+  | ||   starting here...
+4 | ||   X1 Y1
+5 | ||   X2 Y2
+  | ||____^__- ...ending here: `Y` is a good letter too
+  |  |____|
+  |       ...ending here: `X` is a good letter
+
+"#);
+}
+
+#[test]
+fn nested() {
+    test_harness(r#"
+fn foo() {
+  X0 Y0
+  Y1 X1
+}
+"#,
+    vec![
+        SpanLabel {
+            start: Position {
+                string: "X0",
+                count: 1,
+            },
+            end: Position {
+                string: "X1",
+                count: 1,
+            },
+            label: "`X` is a good letter",
+        },
+        SpanLabel {
+            start: Position {
+                string: "Y0",
+                count: 1,
+            },
+            end: Position {
+                string: "Y1",
+                count: 1,
+            },
+            label: "`Y` is a good letter too",
+        },
+    ],
+r#"
+error: foo
+ --> test.rs:3:3
+  |
+3 |      X0 Y0
+  |  ____^__- starting here...
+  | | ___|
+  | ||   starting here...
+4 | ||   Y1 X1
+  | ||____-__^ ...ending here: `X` is a good letter
+  | |_____|
+  |       ...ending here: `Y` is a good letter too
+
+"#);
+}
+
+#[test]
+fn different_overlap() {
+    test_harness(r#"
+fn foo() {
+  X0 Y0 Z0
+  X1 Y1 Z1
+  X2 Y2 Z2
+  X3 Y3 Z3
+}
+"#,
+    vec![
+        SpanLabel {
+            start: Position {
+                string: "Y0",
+                count: 1,
+            },
+            end: Position {
+                string: "X2",
+                count: 1,
+            },
+            label: "`X` is a good letter",
+        },
+        SpanLabel {
+            start: Position {
+                string: "Z1",
+                count: 1,
+            },
+            end: Position {
+                string: "X3",
+                count: 1,
+            },
+            label: "`Y` is a good letter too",
+        },
+    ],
+    r#"
+error: foo
+ --> test.rs:3:6
+  |
+3 |      X0 Y0 Z0
+  |   ______^ starting here...
+4 |  |   X1 Y1 Z1
+  |  |_________- starting here...
+5 | ||   X2 Y2 Z2
+  | ||____^ ...ending here: `X` is a good letter
+6 | |    X3 Y3 Z3
+  | |_____- ...ending here: `Y` is a good letter too
+
+"#);
+}
+
+#[test]
+fn triple_overlap() {
+    test_harness(r#"
+fn foo() {
+  X0 Y0 Z0
+  X1 Y1 Z1
+  X2 Y2 Z2
+}
+"#,
+    vec![
+        SpanLabel {
+            start: Position {
+                string: "X0",
+                count: 1,
+            },
+            end: Position {
+                string: "X2",
+                count: 1,
+            },
+            label: "`X` is a good letter",
+        },
+        SpanLabel {
+            start: Position {
+                string: "Y0",
+                count: 1,
+            },
+            end: Position {
+                string: "Y2",
+                count: 1,
+            },
+            label: "`Y` is a good letter too",
+        },
+        SpanLabel {
+            start: Position {
+                string: "Z0",
+                count: 1,
+            },
+            end: Position {
+                string: "Z2",
+                count: 1,
+            },
+            label: "`Z` label",
+        },
+    ],
+    r#"
+error: foo
+ --> test.rs:3:3
+  |
+3 |       X0 Y0 Z0
+  |  _____^__-__- starting here...
+  | | ____|__|
+  | || ___|  starting here...
+  | |||   starting here...
+4 | |||   X1 Y1 Z1
+5 | |||   X2 Y2 Z2
+  | |||____^__-__- ...ending here: `Z` label
+  |  ||____|__|
+  |   |____|  ...ending here: `Y` is a good letter too
+  |        ...ending here: `X` is a good letter
+
+"#);
+}
+
+#[test]
+fn minimum_depth() {
+    test_harness(r#"
+fn foo() {
+  X0 Y0 Z0
+  X1 Y1 Z1
+  X2 Y2 Z2
+  X3 Y3 Z3
+}
+"#,
+    vec![
+        SpanLabel {
+            start: Position {
+                string: "Y0",
+                count: 1,
+            },
+            end: Position {
+                string: "X1",
+                count: 1,
+            },
+            label: "`X` is a good letter",
+        },
+        SpanLabel {
+            start: Position {
+                string: "Y1",
+                count: 1,
+            },
+            end: Position {
+                string: "Z2",
+                count: 1,
+            },
+            label: "`Y` is a good letter too",
+        },
+        SpanLabel {
+            start: Position {
+                string: "X2",
+                count: 1,
+            },
+            end: Position {
+                string: "Y3",
+                count: 1,
+            },
+            label: "`Z`",
+        },
+    ],
+    r#"
+error: foo
+ --> test.rs:3:6
+  |
+3 |      X0 Y0 Z0
+  |   ______^ starting here...
+4 |  |   X1 Y1 Z1
+  |  |____^_- starting here...
+  | ||____|
+  | |     ...ending here: `X` is a good letter
+5 | |    X2 Y2 Z2
+  | |____-______- ...ending here: `Y` is a good letter too
+  |  ____|
+  | |    starting here...
+6 | |    X3 Y3 Z3
+  | |________- ...ending here: `Z`
+
+"#);
+}