diff options
| author | Laurenz <laurmaedje@gmail.com> | 2020-12-10 22:44:35 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2020-12-10 22:45:45 +0100 |
| commit | 1cbd5f3051ba90b3f673bc2f6319192d05381719 (patch) | |
| tree | 182134e9f355062a00a145fab3a988847c4ed13b /tests | |
| parent | fdc1b378a3eb3cf325592b801c43e2ec2478ddff (diff) | |
Refine test infrastructure ✅
- Tests diagnostics
- More and better separated image tests
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/README.md | 7 | ||||
| -rw-r--r-- | tests/cmp/coma.png | bin | 79107 -> 0 bytes | |||
| -rw-r--r-- | tests/cmp/image.png | bin | 281515 -> 0 bytes | |||
| -rw-r--r-- | tests/ref/empty.png | bin | 0 -> 120 bytes | |||
| -rw-r--r-- | tests/ref/example-coma.png | bin | 0 -> 27418 bytes | |||
| -rw-r--r-- | tests/ref/image-error.png | bin | 0 -> 120 bytes | |||
| -rw-r--r-- | tests/ref/image-fit.png | bin | 0 -> 190100 bytes | |||
| -rw-r--r-- | tests/ref/image-jpeg.png | bin | 0 -> 69754 bytes | |||
| -rw-r--r-- | tests/ref/image-png.png | bin | 0 -> 37986 bytes | |||
| -rw-r--r-- | tests/typ/empty.typ | 0 | ||||
| -rw-r--r-- | tests/typ/example-coma.typ (renamed from tests/typ/coma.typ) | 2 | ||||
| -rw-r--r-- | tests/typ/image-error.typ | 8 | ||||
| -rw-r--r-- | tests/typ/image-fit.typ | 21 | ||||
| -rw-r--r-- | tests/typ/image-jpeg.typ | 2 | ||||
| -rw-r--r-- | tests/typ/image-png.typ | 2 | ||||
| -rw-r--r-- | tests/typ/image.typ | 15 | ||||
| -rw-r--r-- | tests/typeset.rs | 193 |
17 files changed, 159 insertions, 91 deletions
diff --git a/tests/README.md b/tests/README.md index 89c31c89..7d9c3eda 100644 --- a/tests/README.md +++ b/tests/README.md @@ -1,8 +1,7 @@ # Tests - `typ`: Input files -- `pdf`: PDF files produced by tests -- `png`: PNG files produced by tests -- `cmp`: Reference images which the PNGs are compared to byte-wise to determine - whether the test passed or failed +- `ref`: Reference images which the output is compared with to determine + whether a test passed or failed - `res`: Resource files used by tests +- `out`: PNG and PDF files produced by tests diff --git a/tests/cmp/coma.png b/tests/cmp/coma.png Binary files differdeleted file mode 100644 index d0c524ec..00000000 --- a/tests/cmp/coma.png +++ /dev/null diff --git a/tests/cmp/image.png b/tests/cmp/image.png Binary files differdeleted file mode 100644 index 5bf744e9..00000000 --- a/tests/cmp/image.png +++ /dev/null diff --git a/tests/ref/empty.png b/tests/ref/empty.png Binary files differnew file mode 100644 index 00000000..812a3758 --- /dev/null +++ b/tests/ref/empty.png diff --git a/tests/ref/example-coma.png b/tests/ref/example-coma.png Binary files differnew file mode 100644 index 00000000..0c18b810 --- /dev/null +++ b/tests/ref/example-coma.png diff --git a/tests/ref/image-error.png b/tests/ref/image-error.png Binary files differnew file mode 100644 index 00000000..812a3758 --- /dev/null +++ b/tests/ref/image-error.png diff --git a/tests/ref/image-fit.png b/tests/ref/image-fit.png Binary files differnew file mode 100644 index 00000000..b89e78fd --- /dev/null +++ b/tests/ref/image-fit.png diff --git a/tests/ref/image-jpeg.png b/tests/ref/image-jpeg.png Binary files differnew file mode 100644 index 00000000..ef9e74cb --- /dev/null +++ b/tests/ref/image-jpeg.png diff --git a/tests/ref/image-png.png b/tests/ref/image-png.png Binary files differnew file mode 100644 index 00000000..4e0818d2 --- /dev/null +++ b/tests/ref/image-png.png diff --git a/tests/typ/empty.typ b/tests/typ/empty.typ new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/tests/typ/empty.typ diff --git a/tests/typ/coma.typ b/tests/typ/example-coma.typ index 839335b7..f841a122 100644 --- a/tests/typ/coma.typ +++ b/tests/typ/example-coma.typ @@ -1,3 +1,5 @@ +// Small integration test of syntax, page setup, box layout and alignment. + [page: width=450pt, height=300pt, margins=1cm] [box][ diff --git a/tests/typ/image-error.typ b/tests/typ/image-error.typ new file mode 100644 index 00000000..4fde4ab2 --- /dev/null +++ b/tests/typ/image-error.typ @@ -0,0 +1,8 @@ +// error: 5:9-5:30 failed to load image +// error: 8:9-8:30 failed to load image + +// File does not exist. +[image: "path/does/not/exist"] + +// File exists, but is no image. +[image: "typ/image-error.typ"] diff --git a/tests/typ/image-fit.typ b/tests/typ/image-fit.typ new file mode 100644 index 00000000..b735f058 --- /dev/null +++ b/tests/typ/image-fit.typ @@ -0,0 +1,21 @@ +// Fit to width of page. +[image: "res/rhino.png"] + +// Fit to height of page. +[page: width=270pt][ + [image: "res/rhino.png"] +] + +// Set width explicitly. +[image: "res/rhino.png", width=50pt] + +// Set height explicitly. +[image: "res/rhino.png", height=50pt] + +// Set width and height explicitly and force stretching. +[image: "res/rhino.png", width=25pt, height=50pt] + +// Make sure the bounding-box of the image is correct. +[align: bottom, right][ + [image: "res/tiger.jpg"] +] diff --git a/tests/typ/image-jpeg.typ b/tests/typ/image-jpeg.typ new file mode 100644 index 00000000..48cf1a0d --- /dev/null +++ b/tests/typ/image-jpeg.typ @@ -0,0 +1,2 @@ +// Load an RGB JPEG image. +[image: "res/tiger.jpg"] diff --git a/tests/typ/image-png.typ b/tests/typ/image-png.typ new file mode 100644 index 00000000..482591e9 --- /dev/null +++ b/tests/typ/image-png.typ @@ -0,0 +1,2 @@ +// Load an RGBA PNG image. +[image: "res/rhino.png"] diff --git a/tests/typ/image.typ b/tests/typ/image.typ deleted file mode 100644 index 6ae349a1..00000000 --- a/tests/typ/image.typ +++ /dev/null @@ -1,15 +0,0 @@ -[page: width=5cm, height=5cm, margins=0.25cm] - -[image: "res/tiger.jpg"] - -[pagebreak] - -# Tiger -[image: "res/tiger.jpg", width=2cm] -[image: "res/rhino.png", width=1cm] -[image: "res/rhino.png", height=2cm] - -[pagebreak] - -[align: center, bottom] -[image: "res/tiger.jpg", width=2cm, height=3.5cm] diff --git a/tests/typeset.rs b/tests/typeset.rs index 807215ed..037bd7ef 100644 --- a/tests/typeset.rs +++ b/tests/typeset.rs @@ -1,35 +1,35 @@ use std::cell::RefCell; use std::env; use std::ffi::OsStr; -use std::fs::{self, File}; +use std::fs; use std::path::Path; use std::rc::Rc; use fontdock::fs::{FsIndex, FsSource}; use image::{GenericImageView, Rgba}; -use memmap::Mmap; use tiny_skia::{ Canvas, Color, ColorU8, FillRule, FilterQuality, Paint, PathBuilder, Pattern, Pixmap, Rect, SpreadMode, Transform, }; use ttf_parser::OutlineBuilder; -use typst::diag::{Feedback, Pass}; +use typst::diag::{Diag, Feedback, Level, Pass}; use typst::env::{Env, ImageResource, ResourceLoader, SharedEnv}; use typst::eval::State; use typst::export::pdf; use typst::font::FontLoader; -use typst::geom::{Length, Point}; +use typst::geom::{Length, Point, Sides, Size}; use typst::layout::{BoxLayout, ImageElement, LayoutElement}; -use typst::parse::LineMap; +use typst::parse::{LineMap, Scanner}; use typst::shaping::Shaped; +use typst::syntax::{Location, Pos, SpanVec, SpanWith, Spanned}; use typst::typeset; -const FONT_DIR: &str = "../fonts"; const TYP_DIR: &str = "typ"; -const PDF_DIR: &str = "pdf"; -const PNG_DIR: &str = "png"; -const CMP_DIR: &str = "cmp"; +const REF_DIR: &str = "ref"; +const PNG_DIR: &str = "out/png"; +const PDF_DIR: &str = "out/pdf"; +const FONT_DIR: &str = "../fonts"; fn main() { env::set_current_dir(env::current_dir().unwrap().join("tests")).unwrap(); @@ -44,12 +44,8 @@ fn main() { } let name = src_path.file_stem().unwrap().to_string_lossy().to_string(); - let pdf_path = Path::new(PDF_DIR).join(&name).with_extension("pdf"); - let png_path = Path::new(PNG_DIR).join(&name).with_extension("png"); - let ref_path = Path::new(CMP_DIR).join(&name).with_extension("png"); - if filter.matches(&name) { - filtered.push((name, src_path, pdf_path, png_path, ref_path)); + filtered.push((name, src_path)); } } @@ -62,8 +58,8 @@ fn main() { println!("Running {} tests", len); } - fs::create_dir_all(PDF_DIR).unwrap(); fs::create_dir_all(PNG_DIR).unwrap(); + fs::create_dir_all(PDF_DIR).unwrap(); let mut index = FsIndex::new(); index.search_dir(FONT_DIR); @@ -76,29 +72,12 @@ fn main() { let mut ok = true; - for (name, src_path, pdf_path, png_path, ref_path) in filtered { - print!("Testing {}.", name); - test(&src_path, &pdf_path, &png_path, &env); - - let png_file = File::open(&png_path).unwrap(); - let ref_file = match File::open(&ref_path) { - Ok(file) => file, - Err(_) => { - println!(" Failed to open reference image. ❌"); - ok = false; - continue; - } - }; - - let a = unsafe { Mmap::map(&png_file).unwrap() }; - let b = unsafe { Mmap::map(&ref_file).unwrap() }; + for (name, src_path) in filtered { + let png_path = Path::new(PNG_DIR).join(&name).with_extension("png"); + let pdf_path = Path::new(PDF_DIR).join(&name).with_extension("pdf"); + let ref_path = Path::new(REF_DIR).join(&name).with_extension("png"); - if *a != *b { - println!(" Does not match reference image. ❌"); - ok = false; - } else { - println!(" Okay. ✔"); - } + ok &= test(&name, &src_path, &pdf_path, &png_path, &ref_path, &env); } if !ok { @@ -106,41 +85,6 @@ fn main() { } } -fn test(src_path: &Path, pdf_path: &Path, png_path: &Path, env: &SharedEnv) { - let src = fs::read_to_string(src_path).unwrap(); - let state = State::default(); - let Pass { - output: layouts, - feedback: Feedback { mut diags, .. }, - } = typeset(&src, Rc::clone(env), state); - - if !diags.is_empty() { - diags.sort(); - - let map = LineMap::new(&src); - for diag in diags { - let span = diag.span; - let start = map.location(span.start); - let end = map.location(span.end); - println!( - " {}: {}:{}-{}: {}", - diag.v.level, - src_path.display(), - start, - end, - diag.v.message, - ); - } - } - - let env = env.borrow(); - let canvas = draw(&layouts, &env, 2.0); - canvas.pixmap.save_png(png_path).unwrap(); - - let pdf_data = pdf::export(&layouts, &env); - fs::write(pdf_path, pdf_data).unwrap(); -} - struct TestFilter { filter: Vec<String>, perfect: bool, @@ -171,6 +115,111 @@ impl TestFilter { } } +fn test( + name: &str, + src_path: &Path, + pdf_path: &Path, + png_path: &Path, + ref_path: &Path, + env: &SharedEnv, +) -> bool { + println!("Testing {}.", name); + + let src = fs::read_to_string(src_path).unwrap(); + let map = LineMap::new(&src); + let ref_diags = parse_diags(&src, &map); + + let mut state = State::default(); + state.page.size = Size::uniform(Length::pt(120.0)); + state.page.margins = Sides::uniform(Some(Length::pt(10.0).into())); + + let Pass { + output: layouts, + feedback: Feedback { mut diags, .. }, + } = typeset(&src, Rc::clone(env), state); + diags.sort(); + + let env = env.borrow(); + let canvas = draw(&layouts, &env, 2.0); + canvas.pixmap.save_png(png_path).unwrap(); + + let pdf_data = pdf::export(&layouts, &env); + fs::write(pdf_path, pdf_data).unwrap(); + + let mut ok = true; + + if diags != ref_diags { + println!(" Does not match expected diagnostics. ❌"); + ok = false; + + for diag in &diags { + if ref_diags.binary_search(diag).is_err() { + print!(" Unexpected | "); + print_diag(diag, &map); + } + } + + for diag in &ref_diags { + if diags.binary_search(diag).is_err() { + print!(" Missing | "); + print_diag(diag, &map); + } + } + } + + if let Ok(ref_pixmap) = Pixmap::load_png(&ref_path) { + if canvas.pixmap != ref_pixmap { + println!(" Does not match reference image. ❌"); + ok = false; + } + } else { + println!(" Failed to open reference image. ❌"); + ok = false; + } + + if ok { + println!("\x1b[1ATesting {}. ✔", name); + } + + ok +} + +fn parse_diags(src: &str, map: &LineMap) -> SpanVec<Diag> { + let mut diags = vec![]; + + for line in src.lines() { + let (level, rest) = if let Some(rest) = line.strip_prefix("// error: ") { + (Level::Error, rest) + } else if let Some(rest) = line.strip_prefix("// warning: ") { + (Level::Warning, rest) + } else { + continue; + }; + + fn pos(s: &mut Scanner, map: &LineMap) -> Pos { + let (line, _, column) = (num(s), s.eat_assert(':'), num(s)); + map.pos(Location { line, column }).unwrap() + } + + fn num(s: &mut Scanner) -> u32 { + s.eat_while(|c| c.is_numeric()).parse().unwrap() + } + + let mut s = Scanner::new(rest); + let (start, _, end) = (pos(&mut s, map), s.eat_assert('-'), pos(&mut s, map)); + diags.push(Diag::new(level, s.rest().trim()).span_with(start .. end)); + } + + diags.sort(); + diags +} + +fn print_diag(diag: &Spanned<Diag>, map: &LineMap) { + let start = map.location(diag.span.start).unwrap(); + let end = map.location(diag.span.end).unwrap(); + println!("{}: {}-{}: {}", diag.v.level, start, end, diag.v.message,); +} + fn draw(layouts: &[BoxLayout], env: &Env, pixel_per_pt: f32) -> Canvas { let pad = Length::pt(5.0); |
