diff options
| author | Martin Haug <mhaug@live.de> | 2022-06-01 16:57:38 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-06-01 16:57:38 +0200 |
| commit | a937462491a63f5cff3551b5bb8bc45fb350f0b6 (patch) | |
| tree | 7916fca31328fef3e21d3bd62eca132369da81b0 /tests | |
| parent | 665ed12825918bd02a6d6dbcb67860a83dd41600 (diff) | |
| parent | af10b08cc1bd5ef78c5c048a0cbc83b123f1ffd4 (diff) | |
Merge pull request #73 from typst/span-numbers
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/typeset.rs | 104 |
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; |
