summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/ref/code/array.pngbin3396 -> 1971 bytes
-rw-r--r--tests/ref/code/block-invalid.pngbin512 -> 0 bytes
-rw-r--r--tests/ref/code/block.pngbin3152 -> 1440 bytes
-rw-r--r--tests/ref/code/call-invalid.pngbin2975 -> 0 bytes
-rw-r--r--tests/ref/code/call-wide.pngbin2686 -> 0 bytes
-rw-r--r--tests/ref/code/call.pngbin6150 -> 3722 bytes
-rw-r--r--tests/ref/code/closure.pngbin0 -> 657 bytes
-rw-r--r--tests/ref/code/comment.pngbin1904 -> 1829 bytes
-rw-r--r--tests/ref/code/dict.pngbin1602 -> 884 bytes
-rw-r--r--tests/ref/code/for.pngbin4074 -> 2346 bytes
-rw-r--r--tests/ref/code/if.pngbin2731 -> 1838 bytes
-rw-r--r--tests/ref/code/import.pngbin4279 -> 1891 bytes
-rw-r--r--tests/ref/code/let.pngbin2245 -> 1465 bytes
-rw-r--r--tests/ref/code/while.pngbin1531 -> 811 bytes
-rw-r--r--tests/ref/insert/circle.pngbin13518 -> 13064 bytes
-rw-r--r--tests/ref/insert/square.pngbin7163 -> 7069 bytes
-rw-r--r--tests/ref/layout/spacing.pngbin3247 -> 2527 bytes
-rw-r--r--tests/ref/markup/escape.pngbin9849 -> 5578 bytes
-rw-r--r--tests/ref/markup/raw.pngbin7281 -> 6833 bytes
-rw-r--r--tests/ref/text/decorations.pngbin10865 -> 10821 bytes
-rw-r--r--tests/ref/text/whitespace.pngbin7160 -> 6882 bytes
-rw-r--r--tests/typ/code/array.typ1
-rw-r--r--tests/typ/code/block-invalid.typ38
-rw-r--r--tests/typ/code/block-scoping.typ45
-rw-r--r--tests/typ/code/block.typ143
-rw-r--r--tests/typ/code/call-invalid.typ39
-rw-r--r--tests/typ/code/call-wide.typ40
-rw-r--r--tests/typ/code/call.typ128
-rw-r--r--tests/typ/code/closure.typ31
-rw-r--r--tests/typ/code/for-pattern.typ35
-rw-r--r--tests/typ/code/for.typ91
-rw-r--r--tests/typ/code/if.typ10
-rw-r--r--tests/typ/code/import.typ27
-rw-r--r--tests/typ/code/importable/cycle1.typ1
-rw-r--r--tests/typ/code/importable/cycle2.typ1
-rw-r--r--tests/typ/code/include.typ13
-rw-r--r--tests/typ/code/let.typ48
-rw-r--r--tests/typ/code/ops-invalid.typ39
-rw-r--r--tests/typ/code/repr.typ3
-rw-r--r--tests/typ/code/while.typ21
-rw-r--r--tests/typ/insert/circle.typ6
-rw-r--r--tests/typ/insert/image.typ14
-rw-r--r--tests/typ/insert/square.typ11
-rw-r--r--tests/typ/layout/grid-3.typ18
-rw-r--r--tests/typ/layout/pad.typ3
-rw-r--r--tests/typ/layout/page.typ3
-rw-r--r--tests/typ/layout/pagebreak.typ3
-rw-r--r--tests/typ/layout/spacing.typ1
-rw-r--r--tests/typ/markup/escape.typ9
-rw-r--r--tests/typ/text/decorations.typ31
-rw-r--r--tests/typ/text/font.typ26
-rw-r--r--tests/typ/text/whitespace.typ6
-rw-r--r--tests/typ/utility/basics.typ3
-rw-r--r--tests/typ/utility/color.typ17
-rw-r--r--tests/typ/utility/math.typ2
-rw-r--r--tests/typeset.rs162
56 files changed, 507 insertions, 562 deletions
diff --git a/tests/ref/code/array.png b/tests/ref/code/array.png
index b1e20348..c90898c1 100644
--- a/tests/ref/code/array.png
+++ b/tests/ref/code/array.png
Binary files differ
diff --git a/tests/ref/code/block-invalid.png b/tests/ref/code/block-invalid.png
deleted file mode 100644
index d1e85402..00000000
--- a/tests/ref/code/block-invalid.png
+++ /dev/null
Binary files differ
diff --git a/tests/ref/code/block.png b/tests/ref/code/block.png
index 3e64d82c..afdd176b 100644
--- a/tests/ref/code/block.png
+++ b/tests/ref/code/block.png
Binary files differ
diff --git a/tests/ref/code/call-invalid.png b/tests/ref/code/call-invalid.png
deleted file mode 100644
index b2f62ac2..00000000
--- a/tests/ref/code/call-invalid.png
+++ /dev/null
Binary files differ
diff --git a/tests/ref/code/call-wide.png b/tests/ref/code/call-wide.png
deleted file mode 100644
index 2d5b4ffe..00000000
--- a/tests/ref/code/call-wide.png
+++ /dev/null
Binary files differ
diff --git a/tests/ref/code/call.png b/tests/ref/code/call.png
index fd2abbd8..1839c5d8 100644
--- a/tests/ref/code/call.png
+++ b/tests/ref/code/call.png
Binary files differ
diff --git a/tests/ref/code/closure.png b/tests/ref/code/closure.png
new file mode 100644
index 00000000..043d4a11
--- /dev/null
+++ b/tests/ref/code/closure.png
Binary files differ
diff --git a/tests/ref/code/comment.png b/tests/ref/code/comment.png
index bb8bf69a..e349b384 100644
--- a/tests/ref/code/comment.png
+++ b/tests/ref/code/comment.png
Binary files differ
diff --git a/tests/ref/code/dict.png b/tests/ref/code/dict.png
index 730ff6d8..7b7f4d8c 100644
--- a/tests/ref/code/dict.png
+++ b/tests/ref/code/dict.png
Binary files differ
diff --git a/tests/ref/code/for.png b/tests/ref/code/for.png
index de1f3cab..7178b594 100644
--- a/tests/ref/code/for.png
+++ b/tests/ref/code/for.png
Binary files differ
diff --git a/tests/ref/code/if.png b/tests/ref/code/if.png
index 48152e23..7b54203a 100644
--- a/tests/ref/code/if.png
+++ b/tests/ref/code/if.png
Binary files differ
diff --git a/tests/ref/code/import.png b/tests/ref/code/import.png
index 75d4adce..00595f8a 100644
--- a/tests/ref/code/import.png
+++ b/tests/ref/code/import.png
Binary files differ
diff --git a/tests/ref/code/let.png b/tests/ref/code/let.png
index e9c00064..9805b8ee 100644
--- a/tests/ref/code/let.png
+++ b/tests/ref/code/let.png
Binary files differ
diff --git a/tests/ref/code/while.png b/tests/ref/code/while.png
index a772fd59..0956fe45 100644
--- a/tests/ref/code/while.png
+++ b/tests/ref/code/while.png
Binary files differ
diff --git a/tests/ref/insert/circle.png b/tests/ref/insert/circle.png
index 8364d42b..7e44907b 100644
--- a/tests/ref/insert/circle.png
+++ b/tests/ref/insert/circle.png
Binary files differ
diff --git a/tests/ref/insert/square.png b/tests/ref/insert/square.png
index def2e664..c84e6f0e 100644
--- a/tests/ref/insert/square.png
+++ b/tests/ref/insert/square.png
Binary files differ
diff --git a/tests/ref/layout/spacing.png b/tests/ref/layout/spacing.png
index 2205809a..b2b8707d 100644
--- a/tests/ref/layout/spacing.png
+++ b/tests/ref/layout/spacing.png
Binary files differ
diff --git a/tests/ref/markup/escape.png b/tests/ref/markup/escape.png
index 686471c6..227b1eeb 100644
--- a/tests/ref/markup/escape.png
+++ b/tests/ref/markup/escape.png
Binary files differ
diff --git a/tests/ref/markup/raw.png b/tests/ref/markup/raw.png
index 05aeea13..f7bb2ab0 100644
--- a/tests/ref/markup/raw.png
+++ b/tests/ref/markup/raw.png
Binary files differ
diff --git a/tests/ref/text/decorations.png b/tests/ref/text/decorations.png
index e3ca1be5..5ae569f3 100644
--- a/tests/ref/text/decorations.png
+++ b/tests/ref/text/decorations.png
Binary files differ
diff --git a/tests/ref/text/whitespace.png b/tests/ref/text/whitespace.png
index 27a67586..764c7413 100644
--- a/tests/ref/text/whitespace.png
+++ b/tests/ref/text/whitespace.png
Binary files differ
diff --git a/tests/typ/code/array.typ b/tests/typ/code/array.typ
index 9e14bf16..fc8795c2 100644
--- a/tests/typ/code/array.typ
+++ b/tests/typ/code/array.typ
@@ -18,6 +18,7 @@
, rgb("002")
,)}
+---
// Error: 3 expected closing paren
{(}
diff --git a/tests/typ/code/block-invalid.typ b/tests/typ/code/block-invalid.typ
deleted file mode 100644
index 01df81d5..00000000
--- a/tests/typ/code/block-invalid.typ
+++ /dev/null
@@ -1,38 +0,0 @@
-// Test invalid code block syntax.
-
----
-// Multiple unseparated expressions in one line.
-
-// Error: 2-4 expected expression, found invalid token
-{1u}
-
-// Should output `1`.
-// Error: 3 expected semicolon or line break
-// Error: 4-5 cannot join integer with integer
-{1 2}
-
-// Should output `2`.
-// Error: 12 expected semicolon or line break
-// Error: 22 expected semicolon or line break
-{let x = -1 let y = 3 x + y}
-
-// Should output `3`.
-{
- // Error: 9-12 expected identifier, found string
- for "v"
-
- // Error: 10 expected keyword `in`
- for v let z = 1 + 2
-
- z
-}
-
----
-// Ref: false
-// Error: 2:1 expected closing brace
-{
-
----
-// Ref: false
-// Error: 1-2 unexpected closing brace
-}
diff --git a/tests/typ/code/block-scoping.typ b/tests/typ/code/block-scoping.typ
deleted file mode 100644
index 7970ee1b..00000000
--- a/tests/typ/code/block-scoping.typ
+++ /dev/null
@@ -1,45 +0,0 @@
-// Test scoping with blocks.
-// Ref: false
-
----
-// Block in template does not create a scope.
-{ let x = 1 }
-#test(x, 1)
-
----
-// Block in expression does create a scope.
-#let a = {
- let b = 1
- b
-}
-
-#test(a, 1)
-
-// Error: 2-3 unknown variable
-{b}
-
----
-// Double block creates a scope.
-{{
- import b from "target.typ"
- test(b, 1)
-}}
-
-// Error: 2-3 unknown variable
-{b}
-
----
-// Multiple nested scopes.
-{
- let a = "a1"
- {
- let a = "a2"
- {
- test(a, "a2")
- let a = "a3"
- test(a, "a3")
- }
- test(a, "a2")
- }
- test(a, "a1")
-}
diff --git a/tests/typ/code/block.typ b/tests/typ/code/block.typ
index 8c30fa64..ac289abf 100644
--- a/tests/typ/code/block.typ
+++ b/tests/typ/code/block.typ
@@ -1,58 +1,135 @@
// Test code blocks.
+// Ref: false
---
-All none
-
-// Nothing evaluates to none.
-{}
+// Ref: true
-// Let evaluates to none.
-{ let v = 0 }
+// Evaluates to join of none, [My ] and the two loop bodies.
+{
+ let parts = ("my fri", "end.")
+ [Hello, ]
+ for s in parts [{s}]
+}
-// Type is joined with trailing none, evaluates to string.
+// Evaluates to join of the templates and strings.
{
- type("")
- none
+ [How]
+ if true {
+ " are"
+ }
+ [ ]
+ if false [Nope]
+ [you] + "?"
}
---
+// Nothing evaluates to none.
+#test({}, none)
+
+// Let evaluates to none.
+#test({ let v = 0 }, none)
+
// Evaluates to single expression.
-{ "Hello" }
+#test({ "hello" }, "hello")
// Evaluates to string.
-{ let x = "Hel"; x + "lo" }
+#test({ let x = "m"; x + "y" }, "my")
+
+// Evaluated to int.
+#test({
+ let x = 1
+ let y = 2
+ x + y
+}, 3)
+
+// String is joined with trailing none, evaluates to string.
+#test({
+ type("")
+ none
+}, "string")
-// Evaluates to join of none, [He] and the two loop bodies.
+---
+// Some things can't be joined.
{
- let parts = ("l", "lo")
- [He]
- for s in parts [{s}]
+ [A]
+ // Error: 5-6 cannot join template with integer
+ 1
+ [B]
}
---
-// Evaluates to join of the templates and strings.
+// Block in template does not create a scope.
+{ let x = 1 }
+#test(x, 1)
+
+---
+// Block in expression does create a scope.
+#let a = {
+ let b = 1
+ b
+}
+
+#test(a, 1)
+
+// Error: 2-3 unknown variable
+{b}
+
+---
+// Double block creates a scope.
+{{
+ import b from "target.typ"
+ test(b, 1)
+}}
+
+// Error: 2-3 unknown variable
+{b}
+
+---
+// Multiple nested scopes.
{
- [Hey, ]
- if true {
- "there!"
+ let a = "a1"
+ {
+ let a = "a2"
+ {
+ test(a, "a2")
+ let a = "a3"
+ test(a, "a3")
+ }
+ test(a, "a2")
}
- [ ]
- if false [Nope]
- [How are ] + "you?"
+ test(a, "a1")
}
+---
+// Multiple unseparated expressions in one line.
+
+// Error: 2-4 expected expression, found invalid token
+{1u}
+
+// Should output `1`.
+// Error: 3 expected semicolon or line break
+{1 2}
+
+// Should output `2`.
+// Error: 12 expected semicolon or line break
+// Error: 22 expected semicolon or line break
+{let x = -1 let y = 3 x + y}
+
+// Should output `3`.
{
- [A]
- // Error: 5-6 cannot join template with integer
- 1
- [B]
+ // Error: 9-12 expected identifier, found string
+ for "v"
+
+ // Error: 10 expected keyword `in`
+ for v let z = 1 + 2
+
+ z
}
---
-// Works the same way in code environment.
-// Ref: false
-#test(3, {
- let x = 1
- let y = 2
- x + y
-})
+// Error: 2:1 expected closing brace
+{
+
+---
+// Error: 1-2 unexpected closing brace
+}
diff --git a/tests/typ/code/call-invalid.typ b/tests/typ/code/call-invalid.typ
deleted file mode 100644
index dd5897b8..00000000
--- a/tests/typ/code/call-invalid.typ
+++ /dev/null
@@ -1,39 +0,0 @@
-// Test invalid function calls.
-
----
-// Error: 7-8 expected expression, found colon
-#args(:)
-
-// Error: 10-12 expected expression, found end of block comment
-#args(a:1*/)
-
-// Error: 8 expected comma
-#args(1 2)
-
-// Error: 7-8 expected identifier
-// Error: 9 expected expression
-#args(1:)
-
-// Error: 7-8 expected identifier
-#args(1:2)
-
-// Error: 7-10 expected identifier
-{args((x):1)}
-
----
-#let x = "string"
-
-// Error: 1-3 expected function, found string
-#x()
-
-// Error: 2:1 expected closing bracket
-#args[`a]`
-
----
-// Error: 7 expected closing paren
-{args(}
-
----
-// Error: 2:1 expected quote
-// Error: 2:1 expected closing paren
-#args("]
diff --git a/tests/typ/code/call-wide.typ b/tests/typ/code/call-wide.typ
deleted file mode 100644
index 1ad4995d..00000000
--- a/tests/typ/code/call-wide.typ
+++ /dev/null
@@ -1,40 +0,0 @@
-// Test wide calls.
-
----
-// Test multiple wide calls in separate expressions.
-#font!(fill: eastern) - First
-#font!(fill: forest) - Second
-
----
-// Test in heading.
-= A #align!(right) B
-C
-
----
-// Test evaluation semantics.
-
-#let x = 1
-#let f(x, body) = (x, body)
-#f!(x)
-{ x = 2 }
-
----
-// Test multiple wide calls in one expression.
-// Ref: false
-
-#let f() = []
-#let g(x, y) = []
-
-// Error: 2-4 wide calls are only allowed directly in templates
-{f!()}
-
-// Test nested wide calls.
-// Error: 5-7 wide calls are only allowed directly in templates
-#g!(f!())
-
----
-// Test missing parentheses.
-// Ref: false
-
-// Error: 4 expected argument list
-#f!
diff --git a/tests/typ/code/call.typ b/tests/typ/code/call.typ
index eb5c6732..28ce860c 100644
--- a/tests/typ/code/call.typ
+++ b/tests/typ/code/call.typ
@@ -1,34 +1,64 @@
// Test function calls.
+// Ref: false
---
-// One argument.
-#args(bold)
+// Ref: true
-// One argument and trailing comma.
-#args(1,)
+// Ommitted space.
+#font(weight:bold)[Bold]
-// One named argument.
-#args(a:2)
+// Call return value of function with body.
+#let f(x, body) = (y) => [#x] + body + [#y]
+#f(1)[2](3)
-// Mixed arguments.
-{args(1, b: "2", 3)}
+// Don't parse this as a function.
+// Should output `<function test> (it)`.
+#test (it)
-// Should output `() + 2`.
-#args() + 2
+#let f(body) = body
+#f[A]
+#f()[A]
+#f([A])
---
-// Ref: false
+// Ref: true
+
+// Test multiple wide calls in separate expressions inside a template.
+[
+ #font!(fill: eastern) - First
+ #font!(fill: forest) - Second
+]
+
+// Test wide call in heading.
+= A #align!(right) B
+C
+
+---
+// Test wide call in expression.
+
+// Error: 2-4 wide calls are only allowed directly in templates
+{f!()}
+
+// Error: 5-7 wide calls are only allowed directly in templates
+#g!(f!())
+
+---
+// Test wide call evaluation semantics.
+#let x = 1
+#let f(x, body) = test(x, 1)
+#f!(x)
+{ x = 2 }
+
+---
+// Trailing comma.
+#test(1 + 1, 2,)
// Call function assigned to variable.
#let alias = type
#test(alias(alias), "function")
----
// Callee expressions.
{
- // Error: 5-9 expected function, found boolean
- true()
-
// Wrapped in parens.
test((type)("hi"), "string")
@@ -37,30 +67,60 @@
test(adder(2)(5), 7)
}
-#let f(x, body) = (y) => {
- [{x}] + body + [{y}]
-}
-
-// Call return value of function with body.
-#f(1)[2](3)
+---
+// Error: 2-6 expected function, found boolean
+{true()}
-// Don't allow this to be a closure.
-// Should output `x => "hi"`.
+---
#let x = "x"
-#x => "hi"
+
+// Error: 1-3 expected function, found string
+#x()
+
+---
+#let f(x) = x
+
+// Error: 1-6 expected function, found integer
+#f(1)(2)
+
+---
+#let f(x) = x
+
+// Error: 1-6 expected function, found template
+#f[1](2)
---
-// Different forms of template arguments.
+// Error: 7 expected argument list
+#func!
+
+// Error: 7-8 expected expression, found colon
+#func(:)
+
+// Error: 10-12 expected expression, found end of block comment
+#func(a:1*/)
-#let a = "a"
+// Error: 8 expected comma
+#func(1 2)
-#args(a) \
-#args[a] \
-#args(a, [b])
+// Error: 7-8 expected identifier
+// Error: 9 expected expression
+#func(1:)
-// Template can be argument or body depending on whitespace.
-#if "template" == type[b] [Sure ]
-#if "template" == type [Nope.] #else [thing.]
+// Error: 7-8 expected identifier
+#func(1:2)
-// Should output `<function args> (Okay.)`.
-#args (Okay.)
+// Error: 7-10 expected identifier
+{func((x):1)}
+
+---
+// Error: 2:1 expected closing bracket
+#func[`a]`
+
+---
+// Error: 7 expected closing paren
+{func(}
+
+---
+// Error: 2:1 expected quote
+// Error: 2:1 expected closing paren
+#func("]
diff --git a/tests/typ/code/closure.typ b/tests/typ/code/closure.typ
index 20a5f18d..75241f32 100644
--- a/tests/typ/code/closure.typ
+++ b/tests/typ/code/closure.typ
@@ -2,13 +2,22 @@
// Ref: false
---
+// Don't parse closure directly in template.
+// Ref: true
+#let x = "\"hi\""
+
+// Should output `"hi" => "bye"`.
+#x => "bye"
+
+---
// Basic closure without captures.
{
let adder = (x, y) => x + y
test(adder(2, 3), 5)
}
+---
// Pass closure as argument and return closure.
// Also uses shorthand syntax for a single argument.
{
@@ -19,6 +28,7 @@
test(h(2), 5)
}
+---
// Capture environment.
{
let mark = "?"
@@ -35,15 +45,7 @@
test(greet("Typst"), "Hi, Typst!")
}
-// Don't leak environment.
-{
- // Error: 18-19 unknown variable
- let func() = x
- let x = "hi"
-
- test(func(), error)
-}
-
+---
// Redefined variable.
{
let x = 1
@@ -55,6 +57,15 @@
}
---
+// Don't leak environment.
+{
+ // Error: 18-19 unknown variable
+ let func() = x
+ let x = "hi"
+ func()
+}
+
+---
// Too few arguments.
{
let types(x, y) = "[" + type(x) + ", " + type(y) + "]"
@@ -64,11 +75,11 @@
test(types("nope"), "[string, none]")
}
+---
// Too many arguments.
{
let f(x) = x + 1
// Error: 10-15 unexpected argument
- // Error: 17-24 unexpected argument
f(1, "two", () => x)
}
diff --git a/tests/typ/code/for-pattern.typ b/tests/typ/code/for-pattern.typ
deleted file mode 100644
index a6a7c16a..00000000
--- a/tests/typ/code/for-pattern.typ
+++ /dev/null
@@ -1,35 +0,0 @@
-// Test for loop patterns.
-// Ref: false
-
----
-#let out = ()
-
-// Values of array.
-#for v in (1, 2, 3) {
- out += (v,)
-}
-
-// Indices and values of array.
-#for i, v in ("1", "2", "3") {
- test(repr(i + 1), v)
-}
-
-// Values of dictionary.
-#for v in (a: 4, b: 5) {
- out += (v,)
-}
-
-// Keys and values of dictionary.
-#for k, v in (a: 6, b: 7) {
- out += (k,)
- out += (v,)
-}
-
-#test(out, (1, 2, 3, 4, 5, "a", 6, "b", 7))
-
----
-// Keys and values of strings.
-// Error: 6-10 mismatched pattern
-#for k, v in "hi" {
- dont-care
-}
diff --git a/tests/typ/code/for.typ b/tests/typ/code/for.typ
index e6bcf269..62cb0bb5 100644
--- a/tests/typ/code/for.typ
+++ b/tests/typ/code/for.typ
@@ -1,42 +1,23 @@
// Test for loops.
+// Ref: false
---
+// Ref: true
+
// Empty array.
#for x in () [Nope]
-// Array.
-#let sum = 0
-#for x in (1, 2, 3, 4, 5) {
- sum += x
-}
-
-#test(sum, 15)
-
// Dictionary is not traversed in insertion order.
-// Should output `age: 1, name: Typst,`.
+// Should output `Age: 2. Name: Typst.`.
#for k, v in (Name: "Typst", Age: 2) [
{k}: {v}.
]
-// String.
-{
- let first = true
- let out = for c in "abc" {
- if not first {
- ", "
- }
- c
- first = false
- }
- test(out, "a, b, c")
-}
-
----
// Block body.
-// Should output `[1st, 2nd, 3rd, 4th, 5th, 6th]`.
+// Should output `[1st, 2nd, 3rd, 4th, 5th]`.
{
"["
- for v in (1, 2, 3, 4, 5, 6) {
+ for v in (1, 2, 3, 4, 5) {
if v > 1 [, ]
[#v]
if v == 1 [st]
@@ -48,30 +29,60 @@
}
// Template body.
-// Should output `234`.
+// Should output `2345`.
#for v in (1, 2, 3, 4, 5, 6, 7) [#if v >= 2 and v <= 5 { repr(v) }]
---
-// Value of for loops.
-// Ref: false
+#let out = ()
+
+// Values of array.
+#for v in (1, 2, 3) {
+ out += (v,)
+}
+
+// Indices and values of array.
+#for i, v in ("1", "2", "3") {
+ test(repr(i + 1), v)
+}
+
+// Values of dictionary.
+#for v in (a: 4, b: 5) {
+ out += (v,)
+}
+
+// Keys and values of dictionary.
+#for k, v in (a: 6, b: 7) {
+ out += (k,)
+ out += (v,)
+}
+
+#test(out, (1, 2, 3, 4, 5, "a", 6, "b", 7))
+
+// Chars of string.
+#let first = true
+#let joined = for c in "abc" {
+ if not first { ", " }
+ first = false
+ c
+}
+
+#test(joined, "a, b, c")
+
+// Return value.
#test(for v in "" [], none)
#test(type(for v in "1" []), "template")
---
-// Ref: false
-
// Uniterable expression.
// Error: 11-15 cannot loop over boolean
#for v in true {}
-// Make sure that we don't complain twice.
-// Error: 11-18 cannot add integer and string
-#for v in 1 + "2" {}
-
-// Errors taint everything.
-#test(error, for v in (1, 2, 3) {
- if v < 2 [Ok] else {error}
-})
+---
+// Keys and values of strings.
+// Error: 6-10 mismatched pattern
+#for k, v in "hi" {
+ dont-care
+}
---
// Error: 5 expected identifier
@@ -89,19 +100,15 @@
// Error: 15 expected body
#for v in iter
-// Should output `v in iter`.
// Error: 5 expected identifier
#for
v in iter {}
-// Should output `A thing`.
// Error: 7-10 expected identifier, found string
A#for "v" thing
-// Should output `in iter`.
// Error: 6-9 expected identifier, found string
#for "v" in iter {}
-// Should output `+ b in iter`.
// Error: 7 expected keyword `in`
#for a + b in iter {}
diff --git a/tests/typ/code/if.typ b/tests/typ/code/if.typ
index dd5d23a0..db8b059e 100644
--- a/tests/typ/code/if.typ
+++ b/tests/typ/code/if.typ
@@ -39,9 +39,16 @@
"Four" + point
}
+// Template can be argument or body depending on whitespace.
+{
+ if "template" == type[b] [Fi] else [Nope]
+ if "template" == type [Nope] else [ve.]
+}
+
---
// Value of if expressions.
// Ref: false
+
{
let x = 1
let y = 2
@@ -61,13 +68,12 @@
}
---
-// Ref: false
-
// Condition must be boolean.
// If it isn't, neither branch is evaluated.
// Error: 5-14 expected boolean, found string
#if "a" + "b" { nope } #else { nope }
+---
// Make sure that we don't complain twice.
// Error: 5-12 cannot add integer and string
#if 1 + "2" {}
diff --git a/tests/typ/code/import.typ b/tests/typ/code/import.typ
index e1af8ceb..93d4d168 100644
--- a/tests/typ/code/import.typ
+++ b/tests/typ/code/import.typ
@@ -11,8 +11,7 @@
#let value = [foo]
// Import multiple things.
-// Error: 9-10 expected expression, found comma
-#import ,fn, value from "target.typ"
+#import fn, value from "target.typ"
#fn[Like and Subscribe!]
#value
@@ -24,10 +23,6 @@
#test(b, 1)
-// This should not exist yet
-// Error: 1-3 unknown variable
-#d
-
// A wildcard import.
#import * from "target.typ"
@@ -45,30 +40,35 @@
#import a, c, from "target.typ"
---
-// Test bad imports.
-// Ref: false
-
// Error: 19-21 file not found
#import name from ""
+---
// Error: 16-27 file not found
#import * from "lib/0.2.1"
+---
// Some non-text stuff.
// Error: 16-37 file is not valid utf-8
#import * from "../../res/rhino.png"
+---
// Unresolved import.
// Error: 9-21 unresolved import
#import non_existing from "target.typ"
-// Cyclic import.
-// Error: 16-41 cyclic import
-#import * from "./importable/cycle1.typ"
+---
+// Cyclic import of this very file.
+// Error: 16-30 cyclic import
+#import * from "./import.typ"
---
-// Test bad syntax.
+// Cyclic import in other file.
+#import * from "./importable/cycle1.typ"
+This is never reached.
+
+---
// Error: 8 expected import items
// Error: 8 expected keyword `from`
#import
@@ -100,7 +100,6 @@
#from "target.typ"
// Should output `target`.
-// Error: 1:16-2:2 file not found
// Error: 2:2 expected semicolon or line break
#import * from "target.typ
"target
diff --git a/tests/typ/code/importable/cycle1.typ b/tests/typ/code/importable/cycle1.typ
index ae755fa0..a9c00f5e 100644
--- a/tests/typ/code/importable/cycle1.typ
+++ b/tests/typ/code/importable/cycle1.typ
@@ -1,6 +1,5 @@
// Ref: false
-// Error: 16-28 cyclic import
#import * from "cycle2.typ"
#let inaccessible = "wow"
diff --git a/tests/typ/code/importable/cycle2.typ b/tests/typ/code/importable/cycle2.typ
index d4f94564..204da519 100644
--- a/tests/typ/code/importable/cycle2.typ
+++ b/tests/typ/code/importable/cycle2.typ
@@ -1,6 +1,5 @@
// Ref: false
-// Error: 16-28 cyclic import
#import * from "cycle1.typ"
#let val = "much cycle"
diff --git a/tests/typ/code/include.typ b/tests/typ/code/include.typ
index 166c3945..0d1abc08 100644
--- a/tests/typ/code/include.typ
+++ b/tests/typ/code/include.typ
@@ -6,18 +6,21 @@
// Include a file
#include "importable/chap1.typ"
-// The variables of the file should not appear in this scope.
-// Error: 1-6 unknown variable
-#name
-
// Expression as a file name.
#let chap2 = include "import" + "able/chap" + "2.typ"
-- _Intermission_ --
#chap2
+---
{
- // Expressions, code mode.
// Error: 21-43 file not found
let x = include "importable/chap3.typ"
}
+
+---
+#include "importable/chap1.typ"
+
+// The variables of the file should not appear in this scope.
+// Error: 1-6 unknown variable
+#name
diff --git a/tests/typ/code/let.typ b/tests/typ/code/let.typ
index 9079b541..3f3f9d35 100644
--- a/tests/typ/code/let.typ
+++ b/tests/typ/code/let.typ
@@ -1,38 +1,19 @@
// Test let bindings.
---
-// Ref: false
-
// Automatically initialized with none.
#let x
#test(x, none)
-// Error: 9 expected expression
-#let y =
-#test(y, none)
-
// Manually initialized with one.
#let z = 1
#test(z, 1)
----
// Syntax sugar for function definitions.
#let fill = conifer
#let rect(body) = rect(width: 2cm, fill: fill, pad(5pt, body))
#rect[Hi!]
-// Error: 13 expected body
-#let func(x)
-
-// Error: 2-6 unknown variable
-{func}
-
-// Error: 15 expected expression
-#let func(x) =
-
-// Error: 2-6 unknown variable
-{func}
-
---
// Termination.
@@ -47,20 +28,9 @@ One
#let v3 = 3;
Three
-// Terminated because expression ends.
-// Error: 12 expected semicolon or line break
-#let v4 = 4 Four
-
-// Terminated by semicolon even though we are in a paren group.
-// Error: 19 expected expression
-// Error: 19 expected closing paren
-#let v5 = (1, 2 + ; Five
-
#test(v1, 1)
#test(v2, 2)
#test(v3, 3)
-#test(v4, 4)
-#test(v5, (1, 2))
---
// Error: 5 expected identifier
@@ -72,13 +42,27 @@ Three
// Error: 6-9 expected identifier, found string
#let "v"
-// Should output `1`.
// Error: 7 expected semicolon or line break
#let v 1
// Error: 9 expected expression
#let v =
-// Should output a heading `1`.
// Error: 6-9 expected identifier, found string
#let "v" = 1
+
+// Terminated because expression ends.
+// Error: 12 expected semicolon or line break
+#let v4 = 4 Four
+
+// Terminated by semicolon even though we are in a paren group.
+// Error: 19 expected expression
+// Error: 19 expected closing paren
+#let v5 = (1, 2 + ; Five
+
+---
+// Error: 13 expected body
+#let func(x)
+
+// Error: 15 expected expression
+#let func(x) =
diff --git a/tests/typ/code/ops-invalid.typ b/tests/typ/code/ops-invalid.typ
index 149a60dd..5e56ff98 100644
--- a/tests/typ/code/ops-invalid.typ
+++ b/tests/typ/code/ops-invalid.typ
@@ -1,67 +1,84 @@
-// Test invalid expressions.
+// Test invalid operations.
// Ref: false
---
-// Missing expressions.
-
// Error: 3 expected expression
{-}
+---
// Error: 10 expected expression
#test({1+}, 1)
+---
// Error: 10 expected expression
#test({2*}, 2)
---
-// Mismatched types.
-
// Error: 2-12 cannot apply '+' to template
{+([] + [])}
+---
// Error: 2-5 cannot apply '-' to string
{-""}
+---
// Error: 2-8 cannot apply 'not' to array
{not ()}
+---
// Error: 2-12 cannot apply '<=' to relative and relative
{30% <= 40%}
+---
// Special messages for +, -, * and /.
// Error: 03-10 cannot add integer and string
+{(1 + "2", 40% - 1)}
+
+---
// Error: 12-19 cannot subtract integer from relative
-// Error: 21-29 cannot multiply integer with boolean
-// Error: 31-39 cannot divide integer by length
-{(1 + "2", 40% - 1, 2 * true, 3 / 12pt)}
+{(1234567, 40% - 1)}
+
+---
+// Error: 2-10 cannot multiply integer with boolean
+{2 * true}
-// Error: 14-22 cannot apply '+=' to integer and string
+---
+// Error: 2-10 cannot divide integer by length
+{3 / 12pt}
+
+---
+// Error: 14-22 cannot add integer and string
{ let x = 1; x += "2" }
+---
// Error: 13-14 expected argument list, found integer
{ test with 2 }
+---
// Error: 3-4 expected function, found integer
{ 1 with () }
+---
// Error: 3-10 cannot apply '..' to integer and string
{ 1 .. "" }
---
-// Bad left-hand sides of assignment.
-
// Error: 3-6 cannot assign to this expression
{ (x) = "" }
+---
// Error: 3-8 cannot assign to this expression
{ 1 + 2 += 3 }
+---
// Error: 3-4 unknown variable
{ z = 1 }
+---
// Error: 3-7 cannot assign to a constant
{ rect = "hi" }
+---
// Works if we define rect beforehand
// (since then it doesn't resolve to the standard library version anymore).
#let rect = ""
diff --git a/tests/typ/code/repr.typ b/tests/typ/code/repr.typ
index 3da86bf8..35a47e49 100644
--- a/tests/typ/code/repr.typ
+++ b/tests/typ/code/repr.typ
@@ -10,9 +10,6 @@
{ke-bab} \
{α}
-// Error: 2-3 unknown variable
-{_}
-
---
// Literal values.
{none} (empty) \
diff --git a/tests/typ/code/while.typ b/tests/typ/code/while.typ
index 306c1e45..2f0984d2 100644
--- a/tests/typ/code/while.typ
+++ b/tests/typ/code/while.typ
@@ -29,23 +29,16 @@
#test(type(while i < 1 [{ i += 1 }]), "template")
---
-// Ref: false
-
// Condition must be boolean.
// Error: 8-14 expected boolean, found template
#while [nope] [nope]
-// Make sure that we don't complain twice.
-// Error: 8-15 unknown variable
-#while nothing {}
-
-// Errors taint everything.
-#let i = 0
-#test(error, while i < 10 {
- i += 1
- if i < 5 [nope] else { error }
-})
-#test(i, 10)
+---
+// Make sure that we terminate and don't complain multiple times.
+#while true {
+ // Error: 5-9 unknown variable
+ nope
+}
---
// Error: 7 expected expression
@@ -57,11 +50,9 @@
// Error: 9 expected body
#while x
-// Should output `x`.
// Error: 7 expected expression
#while
x {}
-// Should output `something`.
// Error: 9 expected body
#while x something
diff --git a/tests/typ/insert/circle.typ b/tests/typ/insert/circle.typ
index 38fce645..8d76f4ef 100644
--- a/tests/typ/insert/circle.typ
+++ b/tests/typ/insert/circle.typ
@@ -39,9 +39,9 @@ Expanded by height.
---
// Radius wins over width and height.
// Error: 23-34 unexpected argument
-// Error: 36-49 unexpected argument
#circle(radius: 10pt, width: 50pt, height: 100pt, fill: eastern)
+---
// Width wins over height.
-// Error: 22-34 unexpected argument
-#circle(width: 20pt, height: 50pt, fill: eastern)
+// Error: 9-21 unexpected argument
+#circle(height: 50pt, width: 20pt, fill: eastern)
diff --git a/tests/typ/insert/image.typ b/tests/typ/insert/image.typ
index 35087c2e..84069949 100644
--- a/tests/typ/insert/image.typ
+++ b/tests/typ/insert/image.typ
@@ -10,12 +10,6 @@
// Load an RGB JPEG image.
#image("../../res/tiger.jpg")
-// Error: 8-29 file not found
-#image("path/does/not/exist")
-
-// Error: 8-21 failed to load image
-#image("./image.typ")
-
---
// Test configuring the size and fitting behaviour of images.
@@ -36,3 +30,11 @@
// Make sure the bounding-box of the image is correct.
#align(bottom, right, image("../../res/tiger.jpg", width: 60pt))
+
+---
+// Error: 8-29 file not found
+#image("path/does/not/exist")
+
+---
+// Error: 8-21 failed to load image
+#image("./image.typ")
diff --git a/tests/typ/insert/square.typ b/tests/typ/insert/square.typ
index d546773f..7d65b529 100644
--- a/tests/typ/insert/square.typ
+++ b/tests/typ/insert/square.typ
@@ -10,12 +10,6 @@ Auto-sized square. \
]
---
-// Length wins over width and height.
-// Error: 09-20 unexpected argument
-// Error: 22-34 unexpected argument
-#square(width: 10cm, height: 20cm, length: 1cm, fill: rgb("eb5278"))
-
----
// Test height overflow.
#page!(width: 75pt, height: 100pt)
#square(fill: conifer)[
@@ -28,3 +22,8 @@ Auto-sized square. \
#square(fill: conifer)[
But, soft! what light through yonder window breaks?
]
+
+---
+// Length wins over width and height.
+// Error: 09-20 unexpected argument
+#square(width: 10cm, height: 20cm, length: 1cm, fill: rgb("eb5278"))
diff --git a/tests/typ/layout/grid-3.typ b/tests/typ/layout/grid-3.typ
index 38572520..450ce60c 100644
--- a/tests/typ/layout/grid-3.typ
+++ b/tests/typ/layout/grid-3.typ
@@ -25,9 +25,9 @@
gutter-columns: (0pt, 10%),
image("../../res/rhino.png"),
align(right, rect(width: 100%, fill: eastern)[LoL]),
- "rofl",
- "\nA" * 3,
- "Ha!\n" * 3,
+ [rofl],
+ [\ A] * 3,
+ [Ha!\ ] * 3,
)
---
@@ -38,9 +38,9 @@
gutter-rows: (8pt,),
gutter-columns: (0pt, 10%),
[A], [B], [C],
- "Ha!\n" * 6,
- "rofl",
- "\nA" * 3,
+ [Ha!\ ] * 6,
+ [rofl],
+ [\ A] * 3,
[hello],
[darkness],
[my old]
@@ -54,10 +54,10 @@
gutter-rows: (10pt,),
gutter-columns: (0pt, 10%),
[A], [B], [C], [D],
- grid(columns: 2, [A], [B], "C\n"*3, [D]),
+ grid(columns: 2, [A], [B], [C\ ]*3, [D]),
align(right, rect(width: 100%, fill: eastern)[LoL]),
- "rofl",
- "E\n"*4,
+ [rofl],
+ [E\ ]*4,
)
---
diff --git a/tests/typ/layout/pad.typ b/tests/typ/layout/pad.typ
index d43cafc5..eba68af2 100644
--- a/tests/typ/layout/pad.typ
+++ b/tests/typ/layout/pad.typ
@@ -10,8 +10,7 @@
#rect(width: 20pt, height: 20pt, fill: rgb("eb5278"))
]
-// Error: 13-23 missing argument: body
-Hi #box(pad(left: 10pt)) there
+Hi #box(pad(left: 10pt)[]) there
---
#let pad(body) = pad(left: 10pt, right: 10pt, body)
diff --git a/tests/typ/layout/page.typ b/tests/typ/layout/page.typ
index d154d5f4..ba87ad51 100644
--- a/tests/typ/layout/page.typ
+++ b/tests/typ/layout/page.typ
@@ -22,9 +22,6 @@
// Ensure that specific margins override general margins.
#page(margins: 0pt, left: 20pt)[Overriden]
-// Error: 8-19 unknown variable
-#page!(nonexistant)
-
// Flipped predefined paper.
#page("a11", flip: true)[Flipped A11]
diff --git a/tests/typ/layout/pagebreak.typ b/tests/typ/layout/pagebreak.typ
index b13a1bfd..ff15d156 100644
--- a/tests/typ/layout/pagebreak.typ
+++ b/tests/typ/layout/pagebreak.typ
@@ -10,10 +10,7 @@ First of two
A
#box[
B
- // Error: 16 cannot modify page from here
#pagebreak()
-
- // Error: 11-15 cannot modify page from here
#page("a4")[]
]
C
diff --git a/tests/typ/layout/spacing.typ b/tests/typ/layout/spacing.typ
index bd38631e..ec520063 100644
--- a/tests/typ/layout/spacing.typ
+++ b/tests/typ/layout/spacing.typ
@@ -13,6 +13,7 @@ Add #h(10pt) #h(10pt) up
// Relative to font size.
Relative #h(100%) spacing
+---
// Missing spacing.
// Error: 12 missing argument: spacing
Totally #h() ignored
diff --git a/tests/typ/markup/escape.typ b/tests/typ/markup/escape.typ
index b0a809f9..c039e0b7 100644
--- a/tests/typ/markup/escape.typ
+++ b/tests/typ/markup/escape.typ
@@ -21,14 +21,15 @@
// Escaped escape sequence.
\u{41} vs. \\u\{41\}
+// Some code stuff in text.
+let f() , ; : | + - /= == 12 "string"
+
+---
// Unicode codepoint does not exist.
// Error: 1-11 invalid unicode escape sequence
\u{FFFFFF}
+---
// Unterminated.
// Error: 6 expected closing brace
\u{41*Bold*
-
----
-// Some code stuff in text.
-let f() , ; : | + - /= == 12 "string"
diff --git a/tests/typ/text/decorations.typ b/tests/typ/text/decorations.typ
index 3741dc19..83b04650 100644
--- a/tests/typ/text/decorations.typ
+++ b/tests/typ/text/decorations.typ
@@ -1,19 +1,34 @@
// Test text decorations.
---
-#strike[Statements dreamt up by the utterly deranged.]
-
-Sometimes, we work #strike(10pt, extent: 5%)[in secret].
-There might be #strike(stroke: rgb("abcdef88"), thickness: 10pt, extent: 5%)[redacted]
-things.
+// Basic strikethrough.
+#strike[
+ Statements dreamt up by the utterly deranged.
+]
+// Move underline down.
#underline(offset: 5pt)[Further below.]
----
+// Different color.
#underline(rgb("fc0030"))[Critical information is conveyed here.]
-#underline[Still important, but not #underline(0pt)[mission ]critical.]
+// Inherits font color.
#font(fill: rgb("fc0030"), underline[Change with the wind.])
----
+// Both over- and underline.
#overline(underline[Running amongst the wolves.])
+
+// Disable underline by setting it back to 0pt.
+#underline[Still important, but not #underline(0pt)[mission ]critical.]
+
+---
+#let redact = strike with (10pt, extent: 5%)
+#let highlight = strike with (
+ stroke: rgb("abcdef88"),
+ thickness: 10pt,
+ extent: 5%,
+)
+
+// Abuse thickness and transparency for redacting and highlighting stuff.
+Sometimes, we work #redact[in secret].
+There might be #highlight[redacted] things.
diff --git a/tests/typ/text/font.typ b/tests/typ/text/font.typ
index 0f64e244..cc906fbc 100644
--- a/tests/typ/text/font.typ
+++ b/tests/typ/text/font.typ
@@ -54,21 +54,25 @@ Emoji: 🐪, 🌋, 🏞
#font(monospace, monospace: ("Nope", "Latin Modern Math"))[Math.]
---
-// Ref: false
-
// Error: 7-12 unexpected argument
#font(false)[]
+---
// Error: 14-18 expected font style, found font weight
-// Error: 28-34 expected font weight, found string
-// Error: 43-44 expected string or array of strings, found integer
-#font(style: bold, weight: "thin", serif: 0)[]
+#font(style: bold, weight: "thin")[]
-// Error: 7-27 unexpected argument
-#font(something: "invalid")[]
+---
+// Error: 14-15 expected string or array of strings, found integer
+#font(serif: 0)[]
-// Error: 13-23 unexpected argument
-#font(12pt, size: 10pt)[]
+---
+// Error: 19-23 unexpected argument
+#font(size: 10pt, 12pt)[]
-// Error: 16-35 unexpected argument
-#font("Arial", family: "Helvetica")[]
+---
+// Error: 28-35 unexpected argument
+#font(family: "Helvetica", "Arial")[]
+
+---
+// Error: 7-27 unexpected argument
+#font(something: "invalid")[]
diff --git a/tests/typ/text/whitespace.typ b/tests/typ/text/whitespace.typ
index 418c3a12..c81513fa 100644
--- a/tests/typ/text/whitespace.typ
+++ b/tests/typ/text/whitespace.typ
@@ -2,16 +2,12 @@
---
// Spacing around let.
-
-// Error: 6 expected identifier
-A#let;B \
A#let x = 1;B #test(x, 1) \
A #let x = 2;B #test(x, 2) \
A#let x = 3; B #test(x, 3)
---
// Spacing around if-else.
-
A#if true [B]C \
A#if true [B] C \
A #if true{"B"}C \
@@ -21,7 +17,6 @@ A#if true [B] #else [] C
---
// Spacing around while loop.
-
#let c = true; A#while c [{c = false}B]C \
#let c = true; A#while c [{c = false}B] C \
#let c = true; A #while c { c = false; "B" }C \
@@ -29,7 +24,6 @@ A#if true [B] #else [] C
---
// Spacing around for loop.
-
A#for _ in (none,) [B]C \
A#for _ in (none,) [B] C \
A #for _ in (none,) {"B"}C
diff --git a/tests/typ/utility/basics.typ b/tests/typ/utility/basics.typ
index 75e06413..25cac039 100644
--- a/tests/typ/utility/basics.typ
+++ b/tests/typ/utility/basics.typ
@@ -3,14 +3,15 @@
---
// Test the `len` function.
-
#test(len(()), 0)
#test(len(("A", "B", "C")), 3)
#test(len("Hello World!"), 12)
#test(len((a: 1, b: 2)), 2)
+---
// Error: 6 missing argument: collection
#len()
+---
// Error: 6-10 expected string, array or dictionary
#len(12pt)
diff --git a/tests/typ/utility/color.typ b/tests/typ/utility/color.typ
index 8f4c0522..5b10477f 100644
--- a/tests/typ/utility/color.typ
+++ b/tests/typ/utility/color.typ
@@ -11,13 +11,14 @@
// Clamped.
#test(rgb(-30, 15.5, 0.5), rgb("00ff80"))
-// Error: 11-15 missing argument: blue component
-#test(rgb(0, 1), rgb("00ff00"))
+---
+// Error: 6-11 invalid color
+#rgb("lol")
-// Error: 11-16 invalid color
-#test(rgb("lol"), error)
+---
+// Error: 6 missing argument: red component
+#rgb()
-// Error: 11 missing argument: red component
-// Error: 11 missing argument: green component
-// Error: 11 missing argument: blue component
-#test(rgb(), black)
+---
+// Error: 6-10 missing argument: blue component
+#rgb(0, 1)
diff --git a/tests/typ/utility/math.typ b/tests/typ/utility/math.typ
index db234d9c..933f882f 100644
--- a/tests/typ/utility/math.typ
+++ b/tests/typ/utility/math.typ
@@ -8,8 +8,10 @@
#test(max(-3, 11), 11)
#test(min("hi"), "hi")
+---
// Error: 6 missing argument: value
#min()
+---
// Error: 11-18 cannot compare integer with string
#test(min(1, "hi"), error)
diff --git a/tests/typeset.rs b/tests/typeset.rs
index 78577098..39ff9643 100644
--- a/tests/typeset.rs
+++ b/tests/typeset.rs
@@ -1,4 +1,3 @@
-use std::cell::RefCell;
use std::env;
use std::ffi::OsStr;
use std::fs;
@@ -11,20 +10,17 @@ use ttf_parser::{GlyphId, OutlineBuilder};
use walkdir::WalkDir;
use typst::color::Color;
-use typst::diag::{Diag, DiagSet, Level};
-use typst::eval::{eval, Scope, Value};
+use typst::diag::{Error, TypResult};
+use typst::eval::{eval, Value};
use typst::exec::{exec, State};
use typst::geom::{self, Length, PathElement, Point, Sides, Size};
use typst::image::ImageId;
-use typst::layout::{layout, Element, Frame, Geometry, Paint, Text};
+use typst::layout::{layout, Element, Frame, Geometry, LayoutTree, Paint, Text};
use typst::loading::{FileId, FsLoader};
use typst::parse::{parse, LineMap, Scanner};
use typst::syntax::{Location, Pos};
use typst::Context;
-#[cfg(feature = "layout-cache")]
-use typst::layout::LayoutTree;
-
const TYP_DIR: &str = "./typ";
const REF_DIR: &str = "./ref";
const PNG_DIR: &str = "./png";
@@ -67,10 +63,22 @@ fn main() {
page.size = Size::new(Length::pt(120.0), Length::inf());
page.margins = Sides::splat(Some(Length::pt(10.0).into()));
- // We hook up some extra test helpers into the global scope.
+ // Hook up an assert function into the global scope.
let mut std = typst::library::new();
- let panics = Rc::new(RefCell::new(vec![]));
- register_helpers(&mut std, Rc::clone(&panics));
+ std.def_func("test", move |_, args| {
+ let lhs = args.expect::<Value>("left-hand side")?;
+ let rhs = args.expect::<Value>("right-hand side")?;
+ if lhs != rhs {
+ typst::bail!(
+ args.file,
+ args.span,
+ "Assertion failed: {:?} != {:?}",
+ lhs,
+ rhs
+ );
+ }
+ Ok(Value::None)
+ });
// Create loader and context.
let loader = FsLoader::new().with_path(FONT_DIR).wrap();
@@ -88,7 +96,6 @@ fn main() {
ok &= test(
&mut ctx,
loader.as_ref(),
- &panics,
&src_path,
&png_path,
&ref_path,
@@ -134,35 +141,9 @@ impl Args {
}
}
-type Panics = Rc<RefCell<Vec<Panic>>>;
-
-struct Panic {
- pos: Pos,
- lhs: Option<Value>,
- rhs: Option<Value>,
-}
-
-fn register_helpers(scope: &mut Scope, panics: Rc<RefCell<Vec<Panic>>>) {
- scope.def_const("error", Value::Error);
- scope.def_func("args", |_, args| {
- let repr = typst::pretty::pretty(args);
- args.items.clear();
- Value::template(move |ctx| ctx.push_monospace_text(&repr))
- });
- scope.def_func("test", move |ctx, args| {
- let lhs = args.expect::<Value>(ctx, "left-hand side");
- let rhs = args.expect::<Value>(ctx, "right-hand side");
- if lhs != rhs {
- panics.borrow_mut().push(Panic { pos: args.span.start, lhs, rhs });
- }
- Value::None
- });
-}
-
fn test(
ctx: &mut Context,
loader: &FsLoader,
- panics: &Panics,
src_path: &Path,
png_path: &Path,
ref_path: &Path,
@@ -171,8 +152,8 @@ fn test(
let name = src_path.strip_prefix(TYP_DIR).unwrap_or(src_path);
println!("Testing {}", name.display());
+ let file = loader.resolve(src_path).unwrap();
let src = fs::read_to_string(src_path).unwrap();
- let src_id = loader.resolve(src_path).unwrap();
let mut ok = true;
let mut frames = vec![];
@@ -196,7 +177,7 @@ fn test(
}
} else {
let (part_ok, compare_here, part_frames) =
- test_part(ctx, panics, src_id, part, i, compare_ref, lines);
+ test_part(ctx, file, part, i, compare_ref, lines);
ok &= part_ok;
compare_ever |= compare_here;
frames.extend(part_frames);
@@ -221,7 +202,7 @@ fn test(
println!(" Does not match reference image. ❌");
ok = false;
}
- } else {
+ } else if !frames.is_empty() {
println!(" Failed to open reference image. ❌");
ok = false;
}
@@ -236,71 +217,58 @@ fn test(
fn test_part(
ctx: &mut Context,
- panics: &Panics,
- src_id: FileId,
+ file: FileId,
src: &str,
i: usize,
compare_ref: bool,
lines: u32,
) -> (bool, bool, Vec<Rc<Frame>>) {
let map = LineMap::new(src);
- let (local_compare_ref, ref_diags) = parse_metadata(src, &map);
+ let (local_compare_ref, mut ref_errors) = parse_metadata(file, src, &map);
let compare_ref = local_compare_ref.unwrap_or(compare_ref);
- // Clear the module cache between tests.
- ctx.modules.clear();
-
- let ast = parse(src);
- let module = eval(ctx, src_id, Rc::new(ast.output));
- let tree = exec(ctx, &module.output.template);
- let mut frames = layout(ctx, &tree.output);
+ let mut ok = true;
- let mut diags = ast.diags;
- diags.extend(module.diags);
- diags.extend(tree.diags);
+ let result = typeset(ctx, file, src);
+ let (frames, mut errors) = match result {
+ #[allow(unused_variables)]
+ Ok((tree, mut frames)) => {
+ #[cfg(feature = "layout-cache")]
+ (ok &= test_incremental(ctx, i, &tree, &frames));
- let mut ok = true;
+ if !compare_ref {
+ frames.clear();
+ }
- for panic in panics.borrow().iter() {
- let line = map.location(panic.pos).unwrap().line;
- println!(" Assertion failed in line {} ❌", lines + line);
- if let (Some(lhs), Some(rhs)) = (&panic.lhs, &panic.rhs) {
- println!(" Left: {:?}", lhs);
- println!(" Right: {:?}", rhs);
- } else {
- println!(" Missing argument.");
+ (frames, vec![])
}
- ok = false;
- }
+ Err(errors) => (vec![], *errors),
+ };
- panics.borrow_mut().clear();
+ // TODO: Also handle errors from other files.
+ errors.retain(|error| error.file == file);
+ ref_errors.sort();
+ errors.sort();
- if diags != ref_diags {
- println!(" Subtest {} does not match expected diagnostics. ❌", i);
+ if errors != ref_errors {
+ println!(" Subtest {} does not match expected errors. ❌", i);
ok = false;
- for diag in &diags {
- if !ref_diags.contains(diag) {
+ for error in errors.iter() {
+ if error.file == file && !ref_errors.contains(error) {
print!(" Not annotated | ");
- print_diag(diag, &map, lines);
+ print_error(error, &map, lines);
}
}
- for diag in &ref_diags {
- if !diags.contains(diag) {
+ for error in ref_errors.iter() {
+ if !errors.contains(error) {
print!(" Not emitted | ");
- print_diag(diag, &map, lines);
+ print_error(error, &map, lines);
}
}
}
- #[cfg(feature = "layout-cache")]
- (ok &= test_incremental(ctx, i, &tree.output, &frames));
-
- if !compare_ref {
- frames.clear();
- }
-
(ok, compare_ref, frames)
}
@@ -350,9 +318,9 @@ fn test_incremental(
ok
}
-fn parse_metadata(src: &str, map: &LineMap) -> (Option<bool>, DiagSet) {
- let mut diags = DiagSet::new();
+fn parse_metadata(file: FileId, src: &str, map: &LineMap) -> (Option<bool>, Vec<Error>) {
let mut compare_ref = None;
+ let mut errors = vec![];
let lines: Vec<_> = src.lines().map(str::trim).collect();
for (i, line) in lines.iter().enumerate() {
@@ -364,10 +332,8 @@ fn parse_metadata(src: &str, map: &LineMap) -> (Option<bool>, DiagSet) {
compare_ref = Some(true);
}
- 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)
+ let rest = if let Some(rest) = line.strip_prefix("// Error: ") {
+ rest
} else {
continue;
};
@@ -391,18 +357,30 @@ fn parse_metadata(src: &str, map: &LineMap) -> (Option<bool>, DiagSet) {
let start = pos(&mut s);
let end = if s.eat_if('-') { pos(&mut s) } else { start };
- diags.insert(Diag::new(start .. end, level, s.rest().trim()));
+ errors.push(Error::new(file, start .. end, s.rest().trim()));
}
- (compare_ref, diags)
+ (compare_ref, errors)
+}
+
+fn typeset(
+ ctx: &mut Context,
+ file: FileId,
+ src: &str,
+) -> TypResult<(LayoutTree, Vec<Rc<Frame>>)> {
+ let ast = parse(file, src)?;
+ let module = eval(ctx, file, Rc::new(ast))?;
+ let tree = exec(ctx, &module.template);
+ let frames = layout(ctx, &tree);
+ Ok((tree, frames))
}
-fn print_diag(diag: &Diag, map: &LineMap, lines: u32) {
- let mut start = map.location(diag.span.start).unwrap();
- let mut end = map.location(diag.span.end).unwrap();
+fn print_error(error: &Error, map: &LineMap, lines: u32) {
+ let mut start = map.location(error.span.start).unwrap();
+ let mut end = map.location(error.span.end).unwrap();
start.line += lines;
end.line += lines;
- println!("{}: {}-{}: {}", diag.level, start, end, diag.message);
+ println!("Error: {}-{}: {}", start, end, error.message);
}
fn draw(ctx: &Context, frames: &[Rc<Frame>], dpi: f32) -> sk::Pixmap {