304 lines
5.8 KiB
Plaintext
304 lines
5.8 KiB
Plaintext
// Test binary expressions.
|
|
// Ref: false
|
|
|
|
---
|
|
// Test adding content.
|
|
// Ref: true
|
|
#([*Hello* ] + [world!])
|
|
|
|
---
|
|
// Test math operators.
|
|
|
|
// Test plus and minus.
|
|
#for v in (1, 3.14, 12pt, 45deg, 90%, 13% + 10pt, 6.3fr) {
|
|
// Test plus.
|
|
test(+v, v)
|
|
|
|
// Test minus.
|
|
test(-v, -1 * v)
|
|
test(--v, v)
|
|
|
|
// Test combination.
|
|
test(-++ --v, -v)
|
|
}
|
|
|
|
#test(-(4 + 2), 6-12)
|
|
|
|
// Addition.
|
|
#test(2 + 4, 6)
|
|
#test("a" + "b", "ab")
|
|
#test("a" + if false { "b" }, "a")
|
|
#test("a" + if true { "b" }, "ab")
|
|
#test(13 * "a" + "bbbbbb", "aaaaaaaaaaaaabbbbbb")
|
|
#test((1, 2) + (3, 4), (1, 2, 3, 4))
|
|
#test((a: 1) + (b: 2, c: 3), (a: 1, b: 2, c: 3))
|
|
|
|
---
|
|
// Error: 3-26 value is too large
|
|
#(9223372036854775807 + 1)
|
|
|
|
---
|
|
// Subtraction.
|
|
#test(1-4, 3*-1)
|
|
#test(4cm - 2cm, 2cm)
|
|
#test(1e+2-1e-2, 99.99)
|
|
|
|
// Multiplication.
|
|
#test(2 * 4, 8)
|
|
|
|
// Division.
|
|
#test(12pt/.4, 30pt)
|
|
#test(7 / 2, 3.5)
|
|
|
|
// Combination.
|
|
#test(3-4 * 5 < -10, true)
|
|
#test({ let x; x = 1 + 4*5 >= 21 and { x = "a"; x + "b" == "ab" }; x }, true)
|
|
|
|
// With block.
|
|
#test(if true {
|
|
1
|
|
} + 2, 3)
|
|
|
|
// Mathematical identities.
|
|
#let nums = (
|
|
1, 3.14,
|
|
12pt, 3em, 12pt + 3em,
|
|
45deg,
|
|
90%,
|
|
13% + 10pt, 5% + 1em + 3pt,
|
|
2.3fr,
|
|
)
|
|
|
|
#for v in nums {
|
|
// Test plus and minus.
|
|
test(v + v - v, v)
|
|
test(v - v - v, -v)
|
|
|
|
// Test plus/minus and multiplication.
|
|
test(v - v, 0 * v)
|
|
test(v + v, 2 * v)
|
|
|
|
// Integer addition does not give a float.
|
|
if type(v) != int {
|
|
test(v + v, 2.0 * v)
|
|
}
|
|
|
|
if type(v) != relative and ("pt" not in repr(v) or "em" not in repr(v)) {
|
|
test(v / v, 1.0)
|
|
}
|
|
}
|
|
|
|
// Make sure length, ratio and relative length
|
|
// - can all be added to / subtracted from each other,
|
|
// - multiplied with integers and floats,
|
|
// - divided by integers and floats.
|
|
#let dims = (10pt, 1em, 10pt + 1em, 30%, 50% + 3cm, 40% + 2em + 1cm)
|
|
#for a in dims {
|
|
for b in dims {
|
|
test(type(a + b), type(a - b))
|
|
}
|
|
|
|
for b in (7, 3.14) {
|
|
test(type(a * b), type(a))
|
|
test(type(b * a), type(a))
|
|
test(type(a / b), type(a))
|
|
}
|
|
}
|
|
|
|
// Test division of different numeric types with zero components.
|
|
#for a in (0pt, 0em, 0%) {
|
|
for b in (10pt, 10em, 10%) {
|
|
test((2 * b) / b, 2)
|
|
test((a + b * 2) / b, 2)
|
|
test(b / (b * 2 + a), 0.5)
|
|
}
|
|
}
|
|
|
|
---
|
|
// Test numbers with alternative bases.
|
|
#test(0x10, 16)
|
|
#test(0b1101, 13)
|
|
#test(0xA + 0xa, 0x14)
|
|
|
|
---
|
|
// Error: 2-7 invalid binary number: 0b123
|
|
#0b123
|
|
|
|
---
|
|
// Error: 2-8 invalid hexadecimal number: 0x123z
|
|
#0x123z
|
|
|
|
---
|
|
// Test that multiplying infinite numbers by certain units does not crash.
|
|
#(float("inf") * 1pt)
|
|
#(float("inf") * 1em)
|
|
#(float("inf") * (1pt + 1em))
|
|
|
|
---
|
|
// Test that trying to produce a NaN scalar (such as in lengths) does not crash.
|
|
#let infpt = float("inf") * 1pt
|
|
#test(infpt - infpt, 0pt)
|
|
#test(infpt + (-infpt), 0pt)
|
|
// TODO: this result is surprising
|
|
#test(infpt / float("inf"), 0pt)
|
|
|
|
---
|
|
// Test boolean operators.
|
|
|
|
// Test not.
|
|
#test(not true, false)
|
|
#test(not false, true)
|
|
|
|
// And.
|
|
#test(false and false, false)
|
|
#test(false and true, false)
|
|
#test(true and false, false)
|
|
#test(true and true, true)
|
|
|
|
// Or.
|
|
#test(false or false, false)
|
|
#test(false or true, true)
|
|
#test(true or false, true)
|
|
#test(true or true, true)
|
|
|
|
// Short-circuiting.
|
|
#test(false and dont-care, false)
|
|
#test(true or dont-care, true)
|
|
|
|
---
|
|
// Test equality operators.
|
|
|
|
// Most things compare by value.
|
|
#test(1 == "hi", false)
|
|
#test(1 == 1.0, true)
|
|
#test(30% == 30% + 0cm, true)
|
|
#test(1in == 0% + 72pt, true)
|
|
#test(30% == 30% + 1cm, false)
|
|
#test("ab" == "a" + "b", true)
|
|
#test(() == (1,), false)
|
|
#test((1, 2, 3) == (1, 2.0) + (3,), true)
|
|
#test((:) == (a: 1), false)
|
|
#test((a: 2 - 1.0, b: 2) == (b: 2, a: 1), true)
|
|
#test("a" != "a", false)
|
|
|
|
// Functions compare by identity.
|
|
#test(test == test, true)
|
|
#test((() => {}) == (() => {}), false)
|
|
|
|
// Content compares field by field.
|
|
#let t = [a]
|
|
#test(t == t, true)
|
|
#test([] == [], true)
|
|
#test([a] == [a], true)
|
|
#test(grid[a] == grid[a], true)
|
|
#test(grid[a] == grid[b], false)
|
|
|
|
---
|
|
// Test comparison operators.
|
|
|
|
#test(13 * 3 < 14 * 4, true)
|
|
#test(5 < 10, true)
|
|
#test(5 > 5, false)
|
|
#test(5 <= 5, true)
|
|
#test(5 <= 4, false)
|
|
#test(45deg < 1rad, true)
|
|
#test(10% < 20%, true)
|
|
#test(50% < 40% + 0pt, false)
|
|
#test(40% + 0pt < 50% + 0pt, true)
|
|
#test(1em < 2em, true)
|
|
|
|
---
|
|
// Test assignment operators.
|
|
|
|
#let x = 0
|
|
#(x = 10) #test(x, 10)
|
|
#(x -= 5) #test(x, 5)
|
|
#(x += 1) #test(x, 6)
|
|
#(x *= x) #test(x, 36)
|
|
#(x /= 2.0) #test(x, 18.0)
|
|
#(x = "some") #test(x, "some")
|
|
#(x += "thing") #test(x, "something")
|
|
|
|
---
|
|
// Test destructuring assignments.
|
|
|
|
#let a = none
|
|
#let b = none
|
|
#let c = none
|
|
#((a,) = (1,))
|
|
#test(a, 1)
|
|
|
|
#((_, a, b, _) = (1, 2, 3, 4))
|
|
#test(a, 2)
|
|
#test(b, 3)
|
|
|
|
#((a, b, ..c) = (1, 2, 3, 4, 5, 6))
|
|
#test(a, 1)
|
|
#test(b, 2)
|
|
#test(c, (3, 4, 5, 6))
|
|
|
|
#((a: a, b, x: c) = (a: 1, b: 2, x: 3))
|
|
#test(a, 1)
|
|
#test(b, 2)
|
|
#test(c, 3)
|
|
|
|
#let a = (1, 2)
|
|
#((a: a.at(0), b) = (a: 3, b: 4))
|
|
#test(a, (3, 2))
|
|
#test(b, 4)
|
|
|
|
#let a = (1, 2)
|
|
#((a.at(0), b) = (3, 4))
|
|
#test(a, (3, 2))
|
|
#test(b, 4)
|
|
|
|
#((a, ..b) = (1, 2, 3, 4))
|
|
#test(a, 1)
|
|
#test(b, (2, 3, 4))
|
|
|
|
#let a = (1, 2)
|
|
#((b, ..a.at(0)) = (1, 2, 3, 4))
|
|
#test(a, ((2, 3, 4), 2))
|
|
#test(b, 1)
|
|
|
|
---
|
|
// Error: 3-6 cannot mutate a constant: box
|
|
#(box = 1)
|
|
|
|
---
|
|
// Test `in` operator.
|
|
#test("hi" in "worship", true)
|
|
#test("hi" in ("we", "hi", "bye"), true)
|
|
#test("Hey" in "abHeyCd", true)
|
|
#test("Hey" in "abheyCd", false)
|
|
#test(5 in range(10), true)
|
|
#test(12 in range(10), false)
|
|
#test("" in (), false)
|
|
#test("key" in (key: "value"), true)
|
|
#test("value" in (key: "value"), false)
|
|
#test("Hey" not in "abheyCd", true)
|
|
#test("a" not
|
|
/* fun comment? */ in "abc", false)
|
|
|
|
---
|
|
// Error: 10 expected keyword `in`
|
|
#("a" not)
|
|
|
|
---
|
|
// Test `with` method.
|
|
|
|
// Apply positional arguments.
|
|
#let add(x, y) = x + y
|
|
#test(add.with(2)(3), 5)
|
|
#test(add.with(2).with(3)(), 5)
|
|
#test((add.with(2))(4), 6)
|
|
#test((add.with(2).with(3))(), 5)
|
|
|
|
// Make sure that named arguments are overridable.
|
|
#let inc(x, y: 1) = x + y
|
|
#test(inc(1), 2)
|
|
|
|
#let inc2 = inc.with(y: 2)
|
|
#test(inc2(2), 4)
|
|
#test(inc2(2, y: 4), 6)
|