summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorMartin Haug <mhaug@live.de>2022-06-01 16:57:38 +0200
committerGitHub <noreply@github.com>2022-06-01 16:57:38 +0200
commita937462491a63f5cff3551b5bb8bc45fb350f0b6 (patch)
tree7916fca31328fef3e21d3bd62eca132369da81b0 /tests
parent665ed12825918bd02a6d6dbcb67860a83dd41600 (diff)
parentaf10b08cc1bd5ef78c5c048a0cbc83b123f1ffd4 (diff)
Merge pull request #73 from typst/span-numbers
Diffstat (limited to 'tests')
-rw-r--r--tests/typeset.rs104
1 files changed, 71 insertions, 33 deletions
diff --git a/tests/typeset.rs b/tests/typeset.rs
index 0d603125..614449a1 100644
--- a/tests/typeset.rs
+++ b/tests/typeset.rs
@@ -9,7 +9,6 @@ use tiny_skia as sk;
use unscanny::Scanner;
use walkdir::WalkDir;
-use typst::diag::Error;
use typst::eval::{Smart, Value};
use typst::frame::{Element, Frame};
use typst::geom::{Length, RgbaColor, Sides};
@@ -18,7 +17,7 @@ use typst::library::text::{TextNode, TextSize};
use typst::loading::FsLoader;
use typst::model::StyleMap;
use typst::source::SourceFile;
-use typst::syntax::Span;
+use typst::syntax::SyntaxNode;
use typst::{bail, Config, Context};
const TYP_DIR: &str = "./typ";
@@ -299,9 +298,10 @@ fn test_part(
let (local_compare_ref, mut ref_errors) = parse_metadata(&source);
let compare_ref = local_compare_ref.unwrap_or(compare_ref);
+ ok &= test_spans(source.root());
ok &= test_reparse(ctx.sources.get(id).src(), i, rng);
- let (mut frames, mut errors) = match typst::typeset(ctx, id) {
+ let (mut frames, errors) = match typst::typeset(ctx, id) {
Ok(frames) => (frames, vec![]),
Err(errors) => (vec![], *errors),
};
@@ -311,15 +311,19 @@ fn test_part(
frames.clear();
}
- // TODO: Also handle errors from other files.
- errors.retain(|error| error.span.source == id);
- for error in &mut errors {
- error.trace.clear();
- }
+ // Map errors to range and message format, discard traces and errors from
+ // other files.
+ let mut errors: Vec<_> = errors
+ .into_iter()
+ .filter(|error| error.span.source() == id)
+ .map(|error| {
+ let range = error.pos.apply(ctx.sources.range(error.span));
+ (range, error.message)
+ })
+ .collect();
- // The comparison never fails since all spans are from the same source file.
- ref_errors.sort_by(|a, b| a.span.partial_cmp(&b.span).unwrap());
- errors.sort_by(|a, b| a.span.partial_cmp(&b.span).unwrap());
+ errors.sort_by_key(|error| error.0.start);
+ ref_errors.sort_by_key(|error| error.0.start);
if errors != ref_errors {
println!(" Subtest {i} does not match expected errors. ❌");
@@ -327,7 +331,7 @@ fn test_part(
let source = ctx.sources.get(id);
for error in errors.iter() {
- if error.span.source == id && !ref_errors.contains(error) {
+ if !ref_errors.contains(error) {
print!(" Not annotated | ");
print_error(&source, line, error);
}
@@ -344,7 +348,7 @@ fn test_part(
(ok, compare_ref, frames)
}
-fn parse_metadata(source: &SourceFile) -> (Option<bool>, Vec<Error>) {
+fn parse_metadata(source: &SourceFile) -> (Option<bool>, Vec<(Range<usize>, String)>) {
let mut compare_ref = None;
let mut errors = vec![];
@@ -382,23 +386,24 @@ fn parse_metadata(source: &SourceFile) -> (Option<bool>, Vec<Error>) {
let mut s = Scanner::new(rest);
let start = pos(&mut s);
let end = if s.eat_if('-') { pos(&mut s) } else { start };
- let span = Span::new(source.id(), start, end);
+ let range = start .. end;
- errors.push(Error::new(span, s.after().trim()));
+ errors.push((range, s.after().trim().to_string()));
}
(compare_ref, errors)
}
-fn print_error(source: &SourceFile, line: usize, error: &Error) {
- let start_line = 1 + line + source.byte_to_line(error.span.start).unwrap();
- let start_col = 1 + source.byte_to_column(error.span.start).unwrap();
- let end_line = 1 + line + source.byte_to_line(error.span.end).unwrap();
- let end_col = 1 + source.byte_to_column(error.span.end).unwrap();
- println!(
- "Error: {start_line}:{start_col}-{end_line}:{end_col}: {}",
- error.message,
- );
+fn print_error(
+ source: &SourceFile,
+ line: usize,
+ (range, message): &(Range<usize>, String),
+) {
+ let start_line = 1 + line + source.byte_to_line(range.start).unwrap();
+ let start_col = 1 + source.byte_to_column(range.start).unwrap();
+ let end_line = 1 + line + source.byte_to_line(range.end).unwrap();
+ let end_col = 1 + source.byte_to_column(range.end).unwrap();
+ println!("Error: {start_line}:{start_col}-{end_line}:{end_col}: {message}");
}
/// Pseudorandomly edit the source file and test whether a reparse produces the
@@ -452,21 +457,26 @@ fn test_reparse(src: &str, i: usize, rng: &mut LinearShift) -> bool {
incr_source.edit(replace.clone(), with);
let edited_src = incr_source.src();
- let ref_source = SourceFile::detached(edited_src);
let incr_root = incr_source.root();
+ let ref_source = SourceFile::detached(edited_src);
let ref_root = ref_source.root();
- let same = incr_root == ref_root;
- if !same {
+ let mut ok = incr_root == ref_root;
+ if !ok {
println!(
" Subtest {i} reparse differs from clean parse when inserting '{with}' at {}-{} ❌\n",
replace.start, replace.end,
);
println!(" Expected reference tree:\n{ref_root:#?}\n");
println!(" Found incremental tree:\n{incr_root:#?}");
- println!("Full source ({}):\n\"{edited_src:?}\"", edited_src.len());
+ println!(
+ " Full source ({}):\n\"{edited_src:?}\"",
+ edited_src.len()
+ );
}
- same
+ ok &= test_spans(ref_root);
+ ok &= test_spans(incr_root);
+ ok
};
let mut pick = |range: Range<usize>| {
@@ -487,15 +497,43 @@ fn test_reparse(src: &str, i: usize, rng: &mut LinearShift) -> bool {
ok &= apply(start .. end, supplement);
}
- let red = SourceFile::detached(src).red();
- let leafs = red.as_ref().leafs();
- let leaf_start = leafs[pick(0 .. leafs.len())].span().start;
+ let source = SourceFile::detached(src);
+ let leafs = source.root().leafs();
+ let start = source.range(leafs[pick(0 .. leafs.len())].span()).start;
let supplement = supplements[pick(0 .. supplements.len())];
- ok &= apply(leaf_start .. leaf_start, supplement);
+ ok &= apply(start .. start, supplement);
ok
}
+/// Ensure that all spans are properly ordered (and therefore unique).
+#[track_caller]
+fn test_spans(root: &SyntaxNode) -> bool {
+ test_spans_impl(root, 0 .. u64::MAX)
+}
+
+#[track_caller]
+fn test_spans_impl(node: &SyntaxNode, within: Range<u64>) -> bool {
+ if !within.contains(&node.span().number()) {
+ eprintln!(" Node: {node:#?}");
+ eprintln!(
+ " Wrong span order: {} not in {within:?} ❌",
+ node.span().number(),
+ );
+ }
+
+ let start = node.span().number() + 1;
+ let mut children = node.children().peekable();
+ while let Some(child) = children.next() {
+ let end = children.peek().map_or(within.end, |next| next.span().number());
+ if !test_spans_impl(child, start .. end) {
+ return false;
+ }
+ }
+
+ true
+}
+
/// Draw all frames into one image with padding in between.
fn render(ctx: &mut Context, frames: &[Arc<Frame>]) -> sk::Pixmap {
let pixel_per_pt = 2.0;