diff --git a/.gitignore b/.gitignore
index 32eee3e97..f60c09f7d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,8 +1,15 @@
.vscode
+_things
+
/target
+bench/target
**/*.rs.bk
Cargo.lock
-bench/target
-tests/out
-_things
+
+tests/png
+tests/pdf
+tests/playground.typ
+tests/playground.png
+tests/playground.pdf
+
tarpaulin-report.html
diff --git a/tests/README.md b/tests/README.md
index 424c97d8d..fef134820 100644
--- a/tests/README.md
+++ b/tests/README.md
@@ -6,5 +6,5 @@
`oxipng -o max tests/ref/
` when creating or updating reference
images (note that `
` can be `*` to optimize all images).
- `res`: Resource files used by tests.
-- `out`: PNG and PDF files produced by tests.
-
+- `png`: PNG files produced by tests.
+- `pdf`: PDF files produced by tests.
diff --git a/tests/ref/func-font-fallback.png b/tests/ref/func-font-fallback.png
deleted file mode 100644
index b7c565b41..000000000
Binary files a/tests/ref/func-font-fallback.png and /dev/null differ
diff --git a/tests/ref/func-font-properties.png b/tests/ref/func-font-properties.png
deleted file mode 100644
index 3dab43f58..000000000
Binary files a/tests/ref/func-font-properties.png and /dev/null differ
diff --git a/tests/ref/func-font.png b/tests/ref/func-font.png
new file mode 100644
index 000000000..188414903
Binary files /dev/null and b/tests/ref/func-font.png differ
diff --git a/tests/ref/func-h-and-v.png b/tests/ref/func-h-and-v.png
index e977046f3..6f47ae09b 100644
Binary files a/tests/ref/func-h-and-v.png and b/tests/ref/func-h-and-v.png differ
diff --git a/tests/ref/func-image-fit.png b/tests/ref/func-image-fit.png
deleted file mode 100644
index b89e78fd1..000000000
Binary files a/tests/ref/func-image-fit.png and /dev/null differ
diff --git a/tests/ref/func-image-formats.png b/tests/ref/func-image-formats.png
deleted file mode 100644
index 45b23276b..000000000
Binary files a/tests/ref/func-image-formats.png and /dev/null differ
diff --git a/tests/ref/func-image.png b/tests/ref/func-image.png
new file mode 100644
index 000000000..e2b647bfe
Binary files /dev/null and b/tests/ref/func-image.png differ
diff --git a/tests/ref/func-page-body.png b/tests/ref/func-page-body.png
deleted file mode 100644
index 09f685c33..000000000
Binary files a/tests/ref/func-page-body.png and /dev/null differ
diff --git a/tests/ref/func-page-dirs.png b/tests/ref/func-page-dirs.png
deleted file mode 100644
index 2bf23ebcc..000000000
Binary files a/tests/ref/func-page-dirs.png and /dev/null differ
diff --git a/tests/ref/func-page-metrics.png b/tests/ref/func-page-metrics.png
deleted file mode 100644
index 2e8d626db..000000000
Binary files a/tests/ref/func-page-metrics.png and /dev/null differ
diff --git a/tests/ref/func-page.png b/tests/ref/func-page.png
new file mode 100644
index 000000000..9bde2dae6
Binary files /dev/null and b/tests/ref/func-page.png differ
diff --git a/tests/typ/func-font-error.typ b/tests/typ/func-font-error.typ
deleted file mode 100644
index b75a4fb7f..000000000
--- a/tests/typ/func-font-error.typ
+++ /dev/null
@@ -1,21 +0,0 @@
-// Test error cases of the `font` function.
-
-// Not one of the valid things for positional arguments.
-[font false]
-
-// Wrong types.
-[font style: bold, weight: "thin", serif: 0]
-
-// Weight out of range.
-[font weight: 2700]
-
-// Non-existing argument.
-[font something: "invalid"]
-
-// compare-ref: false
-// error: 4:7-4:12 unexpected argument
-// error: 7:14-7:18 expected font style, found font weight
-// error: 7:28-7:34 expected font weight, found string
-// error: 7:43-7:44 expected font family or array of font families, found integer
-// warning: 10:15-10:19 must be between 100 and 900
-// error: 13:7-13:27 unexpected argument
diff --git a/tests/typ/func-font-fallback.typ b/tests/typ/func-font-fallback.typ
deleted file mode 100644
index c6dd81f05..000000000
--- a/tests/typ/func-font-fallback.typ
+++ /dev/null
@@ -1,20 +0,0 @@
-// Test font fallback.
-
-// Source Sans Pro + Segoe UI Emoji.
-Emoji: 🏀
-
-// CMU Serif + Noto Emoji.
-[font "CMU Serif", "Noto Emoji"][
- Emoji: 🏀
-]
-
-// Class definitions.
-[font serif: ("CMU Serif", "Latin Modern Math", "Noto Emoji")]
-[font serif][
- Math: ∫ α + β ➗ 3
-]
-
-// Class definition reused.
-[font sans-serif: "Noto Emoji"]
-[font sans-serif: ("Archivo", sans-serif)]
-New sans-serif. 🚀
diff --git a/tests/typ/func-font-properties.typ b/tests/typ/func-font-properties.typ
deleted file mode 100644
index af8b88914..000000000
--- a/tests/typ/func-font-properties.typ
+++ /dev/null
@@ -1,20 +0,0 @@
-// Test configuring font properties.
-
-[font "PT Sans", 10pt]
-
-// Set same font size in three different ways.
-[font 20pt][A]
-[font 200%][A]
-[font 15pt + 50%][A]
-
-// Do nothing.
-[font][Normal]
-
-// Set style (is available).
-[font style: italic][Italic]
-
-// Set weight (is available).
-[font weight: bold][Bold]
-
-// Set stretch (not available, matching closest).
-[font stretch: ultra-condensed][Condensed]
diff --git a/tests/typ/func-font.typ b/tests/typ/func-font.typ
new file mode 100644
index 000000000..c73e3a1a6
--- /dev/null
+++ b/tests/typ/func-font.typ
@@ -0,0 +1,65 @@
+// Test configuring font properties.
+
+[font "PT Sans", 10pt]
+
+// Set same font size in three different ways.
+[font 20pt][A]
+[font 200%][A]
+[font 15pt + 50%][A]
+
+// Do nothing.
+[font][Normal]
+
+// Set style (is available).
+[font style: italic][Italic]
+
+// Set weight (is available).
+[font weight: bold][Bold]
+
+// Set stretch (not available, matching closest).
+[font stretch: ultra-condensed][Condensed]
+
+---
+// Test font fallback.
+
+// Source Sans Pro + Segoe UI Emoji.
+Emoji: 🏀
+
+// CMU Serif + Noto Emoji.
+[font "CMU Serif", "Noto Emoji"][
+ Emoji: 🏀
+]
+
+// Class definitions.
+[font serif: ("CMU Serif", "Latin Modern Math", "Noto Emoji")]
+[font serif][
+ Math: ∫ α + β ➗ 3
+]
+
+// Class definition reused.
+[font sans-serif: "Noto Emoji"]
+[font sans-serif: ("Archivo", sans-serif)]
+New sans-serif. 🚀
+
+---
+// Test error cases.
+//
+// ref: false
+// error: 3:7-3:12 unexpected argument
+// error: 6:14-6:18 expected font style, found font weight
+// error: 6:28-6:34 expected font weight, found string
+// error: 6:43-6:44 expected font family or array of font families, found integer
+// warning: 9:15-9:19 must be between 100 and 900
+// error: 12:7-12:27 unexpected argument
+
+// Not one of the valid things for positional arguments.
+[font false]
+
+// Wrong types.
+[font style: bold, weight: "thin", serif: 0]
+
+// Weight out of range.
+[font weight: 2700]
+
+// Non-existing argument.
+[font something: "invalid"]
diff --git a/tests/typ/func-h-and-v.typ b/tests/typ/func-h-and-v.typ
index 0587b3eda..7b8843c83 100644
--- a/tests/typ/func-h-and-v.typ
+++ b/tests/typ/func-h-and-v.typ
@@ -12,9 +12,6 @@ Add [h 10pt] [h 10pt] up
// Relative to font size.
Relative [h 100%] spacing
-// Missing spacing.
-Totally [h] ignored
-
// Swapped axes.
[page main-dir: rtl, cross-dir: ttb][
1 [h 1cm] 2
@@ -22,4 +19,10 @@ Totally [h] ignored
3 [v 1cm] 4 [v -1cm] 5
]
-// error: 16:11-16:11 missing argument: spacing
+---
+// Test error cases.
+//
+// error: 3:11-3:11 missing argument: spacing
+
+// Missing spacing.
+Totally [h] ignored
diff --git a/tests/typ/func-image-error.typ b/tests/typ/func-image-error.typ
deleted file mode 100644
index 155534200..000000000
--- a/tests/typ/func-image-error.typ
+++ /dev/null
@@ -1,11 +0,0 @@
-// Test error cases of the `image` function.
-
-// File does not exist.
-[image "path/does/not/exist"]
-
-// File exists, but is no image.
-[image "typ/image-error.typ"]
-
-// compare-ref: false
-// error: 4:8-4:29 failed to load image
-// error: 7:8-7:29 failed to load image
diff --git a/tests/typ/func-image-formats.typ b/tests/typ/func-image-formats.typ
deleted file mode 100644
index c12e36398..000000000
--- a/tests/typ/func-image-formats.typ
+++ /dev/null
@@ -1,8 +0,0 @@
-// Test loading different image formats.
-
-// Load an RGBA PNG image.
-[image "res/rhino.png"]
-[pagebreak]
-
-// Load an RGB JPEG image.
-[image "res/tiger.jpg"]
diff --git a/tests/typ/func-image-fit.typ b/tests/typ/func-image.typ
similarity index 57%
rename from tests/typ/func-image-fit.typ
rename to tests/typ/func-image.typ
index a9855aa4f..78a644c04 100644
--- a/tests/typ/func-image-fit.typ
+++ b/tests/typ/func-image.typ
@@ -1,3 +1,13 @@
+// Test loading different image formats.
+
+// Load an RGBA PNG image.
+[image "res/rhino.png"]
+[pagebreak]
+
+// Load an RGB JPEG image.
+[image "res/tiger.jpg"]
+
+---
// Test configuring the size and fitting behaviour of images.
// Fit to width of page.
@@ -21,3 +31,16 @@
[align bottom, right][
[image "res/tiger.jpg"]
]
+
+---
+// Test error cases.
+//
+// ref: false
+// error: 3:8-3:29 failed to load image
+// error: 6:8-6:29 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/func-page-body.typ b/tests/typ/func-page-body.typ
deleted file mode 100644
index bfa9775d2..000000000
--- a/tests/typ/func-page-body.typ
+++ /dev/null
@@ -1,11 +0,0 @@
-// Test a combination of pages with bodies and normal content.
-
-[page height: 50pt]
-
-[page][First]
-[page][Second]
-[pagebreak]
-Fourth
-[page][]
-Sixth
-[page][Seventh and last]
diff --git a/tests/typ/func-page-dirs.typ b/tests/typ/func-page-dirs.typ
deleted file mode 100644
index 47e8ae157..000000000
--- a/tests/typ/func-page-dirs.typ
+++ /dev/null
@@ -1,5 +0,0 @@
-// Test changing the layouting directions of pages.
-
-[page main-dir: btt, cross-dir: rtl]
-
-Right to left!
diff --git a/tests/typ/func-page-error.typ b/tests/typ/func-page-error.typ
deleted file mode 100644
index 21370fa8b..000000000
--- a/tests/typ/func-page-error.typ
+++ /dev/null
@@ -1,11 +0,0 @@
-// Test error cases of the `page` function.
-
-// Invalid paper.
-[page nonexistant]
-
-// Aligned axes.
-[page main-dir: ltr]
-
-// compare-ref: false
-// error: 4:7-4:18 unknown variable
-// error: 7:17-7:20 aligned axis
diff --git a/tests/typ/func-page-metrics.typ b/tests/typ/func-page.typ
similarity index 54%
rename from tests/typ/func-page-metrics.typ
rename to tests/typ/func-page.typ
index 3b54d13f8..7f87a414d 100644
--- a/tests/typ/func-page-metrics.typ
+++ b/tests/typ/func-page.typ
@@ -23,3 +23,37 @@
// Flip the page.
[page "a10", flip: true][Flipped]
+
+---
+// Test a combination of pages with bodies and normal content.
+
+[page height: 50pt]
+
+[page][First]
+[page][Second]
+[pagebreak]
+Fourth
+[page][]
+Sixth
+[page][Seventh and last]
+
+
+---
+// Test changing the layouting directions of pages.
+
+[page main-dir: btt, cross-dir: rtl]
+
+Right to left!
+
+---
+// Test error cases.
+//
+// ref: false
+// error: 3:7-3:18 unknown variable
+// error: 6:17-6:20 aligned axis
+
+// Invalid paper.
+[page nonexistant]
+
+// Aligned axes.
+[page main-dir: ltr]
diff --git a/tests/typ/func-rgb.typ b/tests/typ/func-rgb.typ
index 96c23ebdf..e88b19bf1 100644
--- a/tests/typ/func-rgb.typ
+++ b/tests/typ/func-rgb.typ
@@ -1,4 +1,11 @@
// Test the `rgb` function.
+//
+// warning: 9:6-9:9 must be between 0.0 and 1.0
+// warning: 9:11-9:15 must be between 0.0 and 1.0
+// error: 12:6-12:10 missing argument: blue component
+// error: 15:5-15:5 missing argument: red component
+// error: 15:5-15:5 missing argument: green component
+// error: 15:5-15:5 missing argument: blue component
// Check the output.
[rgb 0.0, 0.3, 0.7]
@@ -14,10 +21,3 @@
// Missing all components.
[rgb]
-
-// warning: 10:6-10:9 must be between 0.0 and 1.0
-// warning: 10:11-10:15 must be between 0.0 and 1.0
-// error: 13:6-13:10 missing argument: blue component
-// error: 16:5-16:5 missing argument: red component
-// error: 16:5-16:5 missing argument: green component
-// error: 16:5-16:5 missing argument: blue component
diff --git a/tests/typeset.rs b/tests/typeset.rs
index e586ae1a4..554c91497 100644
--- a/tests/typeset.rs
+++ b/tests/typeset.rs
@@ -27,8 +27,8 @@ use typst::typeset;
const TYP_DIR: &str = "typ";
const REF_DIR: &str = "ref";
-const PNG_DIR: &str = "out/png";
-const PDF_DIR: &str = "out/pdf";
+const PNG_DIR: &str = "png";
+const PDF_DIR: &str = "pdf";
const FONT_DIR: &str = "../fonts";
fn main() {
@@ -76,8 +76,26 @@ fn main() {
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");
+ ok &= test(
+ &name,
+ &src_path,
+ &png_path,
+ &pdf_path,
+ Some(&ref_path),
+ &env,
+ );
+ }
- ok &= test(&name, &src_path, &pdf_path, &png_path, &ref_path, &env);
+ let playground = Path::new("playground.typ");
+ if playground.exists() {
+ test(
+ "playground",
+ playground,
+ Path::new("playground.png"),
+ Path::new("playground.pdf"),
+ None,
+ &env,
+ );
}
if !ok {
@@ -118,38 +136,73 @@ impl TestFilter {
fn test(
name: &str,
src_path: &Path,
- pdf_path: &Path,
png_path: &Path,
- ref_path: &Path,
+ pdf_path: &Path,
+ ref_path: Option<&Path>,
env: &SharedEnv,
) -> bool {
println!("Testing {}.", name);
let src = fs::read_to_string(src_path).unwrap();
- let map = LineMap::new(&src);
- let (ref_diags, compare_ref) = parse_metadata(&src, &map);
+
+ let mut ok = true;
+ let mut frames = vec![];
+
+ for (i, part) in src.split("---").enumerate() {
+ let (part_ok, part_frames) = test_part(i, part, env);
+ ok &= part_ok;
+ frames.extend(part_frames);
+ }
+
+ let env = env.borrow();
+ if !frames.is_empty() {
+ let canvas = draw(&frames, &env, 2.0);
+ canvas.pixmap.save_png(png_path).unwrap();
+
+ let pdf_data = pdf::export(&frames, &env);
+ fs::write(pdf_path, pdf_data).unwrap();
+
+ if let Some(ref_path) = ref_path {
+ 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 test_part(i: usize, src: &str, env: &SharedEnv) -> (bool, Vec) {
+ let (src, compare_ref, map, ref_diags) = parse_metadata(&src, i);
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: frames,
+ output: mut frames,
feedback: Feedback { mut diags, .. },
} = typeset(&src, Rc::clone(env), state);
+
+ if !compare_ref {
+ frames.clear();
+ }
+
diags.sort_by_key(|d| d.span);
- let env = env.borrow();
- let canvas = draw(&frames, &env, 2.0);
- canvas.pixmap.save_png(png_path).unwrap();
-
- let pdf_data = pdf::export(&frames, &env);
- fs::write(pdf_path, pdf_data).unwrap();
-
let mut ok = true;
-
if diags != ref_diags {
- println!(" Does not match expected diagnostics. ❌");
+ println!(" Subtest {} does not match expected diagnostics. ❌", i);
ok = false;
for diag in &diags {
@@ -167,57 +220,61 @@ fn test(
}
}
- if compare_ref {
- 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
+ (ok, frames)
}
-fn parse_metadata(src: &str, map: &LineMap) -> (SpanVec, bool) {
+fn parse_metadata(src: &str, i: usize) -> (&str, bool, LineMap, SpanVec) {
let mut diags = vec![];
let mut compare_ref = true;
- for line in src.lines() {
- compare_ref &= !line.starts_with("// compare-ref: false");
+ let mut s = Scanner::new(src);
+ for k in 0 .. {
+ // Allow a newline directly after "---" (that is, if i > 0 and k == 0).
+ if !(i > 0 && k == 0) && !s.rest().starts_with("//") {
+ break;
+ }
- let (level, rest) = if let Some(rest) = line.strip_prefix("// error: ") {
- (Level::Error, rest)
- } else if let Some(rest) = line.strip_prefix("// warning: ") {
+ let line = s.eat_until(typst::parse::is_newline);
+ s.eat_merging_crlf();
+
+ compare_ref &= !line.starts_with("// ref: false");
+
+ let (level, rest) = if let Some(rest) = line.strip_prefix("// warning: ") {
(Level::Warning, rest)
+ } else if let Some(rest) = line.strip_prefix("// error: ") {
+ (Level::Error, 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()).with_span(start .. end));
+ diags.push((level, rest));
}
+ let src = s.rest();
+ let map = LineMap::new(src);
+
+ let mut diags: Vec<_> = diags
+ .into_iter()
+ .map(|(level, rest)| {
+ 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));
+ Diag::new(level, s.rest().trim()).with_span(start .. end)
+ })
+ .collect();
+
diags.sort_by_key(|d| d.span);
- (diags, compare_ref)
+ (src, compare_ref, map, diags)
}
fn print_diag(diag: &Spanned, map: &LineMap) {